From dd591007c816ee03b6573af0d72354f7d8d08aa1 Mon Sep 17 00:00:00 2001 From: Andrew Halberstadt Date: Wed, 18 Jun 2025 12:51:24 -0400 Subject: [PATCH 1/2] docs: use `ALLOW_EXTRA` instead of `Extra: object` This will render the schema in the reference docs better, as I didn't bother implementing any handling for `Extra: object`. --- src/taskgraph/config.py | 6 +++--- src/taskgraph/transforms/from_deps.py | 4 ++-- src/taskgraph/transforms/matrix.py | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/taskgraph/config.py b/src/taskgraph/config.py index ef13f3d22..1f698cbc5 100644 --- a/src/taskgraph/config.py +++ b/src/taskgraph/config.py @@ -9,7 +9,7 @@ from dataclasses import dataclass from typing import Dict -from voluptuous import All, Any, Extra, Length, Optional, Required +from voluptuous import ALLOW_EXTRA, All, Any, Extra, Length, Optional, Required from .util import path from .util.caches import CACHES @@ -101,8 +101,8 @@ Length(min=1), ), }, - Extra: object, - } + }, + extra=ALLOW_EXTRA, ) diff --git a/src/taskgraph/transforms/from_deps.py b/src/taskgraph/transforms/from_deps.py index 31a967a66..bfb25e6b4 100644 --- a/src/taskgraph/transforms/from_deps.py +++ b/src/taskgraph/transforms/from_deps.py @@ -14,7 +14,7 @@ from copy import deepcopy from textwrap import dedent -from voluptuous import Any, Extra, Optional, Required +from voluptuous import ALLOW_EXTRA, Any, Extra, Optional, Required from taskgraph.transforms.base import TransformSequence from taskgraph.transforms.run import fetches_schema @@ -109,8 +109,8 @@ ), ): {str: [fetches_schema]}, }, - Extra: object, }, + extra=ALLOW_EXTRA, ) transforms = TransformSequence() diff --git a/src/taskgraph/transforms/matrix.py b/src/taskgraph/transforms/matrix.py index 11718b011..476507284 100644 --- a/src/taskgraph/transforms/matrix.py +++ b/src/taskgraph/transforms/matrix.py @@ -10,7 +10,7 @@ from copy import deepcopy from textwrap import dedent -from voluptuous import Extra, Optional, Required +from voluptuous import ALLOW_EXTRA, Extra, Optional, Required from taskgraph.transforms.base import TransformSequence from taskgraph.util.schema import Schema @@ -58,8 +58,8 @@ ): [str], Extra: [str], }, - Extra: object, }, + extra=ALLOW_EXTRA, ) transforms = TransformSequence() From efa66f99a19fa189c618994113d789b83093d79b Mon Sep 17 00:00:00 2001 From: Andrew Halberstadt Date: Wed, 18 Jun 2025 12:56:23 -0400 Subject: [PATCH 2/2] docs: convert schema comments into descriptions This way they'll be rendered in the docs. --- src/taskgraph/transforms/docker_image.py | 86 +++-- src/taskgraph/transforms/fetch.py | 51 ++- src/taskgraph/transforms/from_deps.py | 2 +- src/taskgraph/transforms/run/__init__.py | 111 +++++-- src/taskgraph/transforms/run/run_task.py | 114 +++++-- src/taskgraph/transforms/run/toolchain.py | 96 ++++-- src/taskgraph/transforms/task.py | 372 ++++++++++++++++------ 7 files changed, 636 insertions(+), 196 deletions(-) diff --git a/src/taskgraph/transforms/docker_image.py b/src/taskgraph/transforms/docker_image.py index 33294610a..2b924dbbc 100644 --- a/src/taskgraph/transforms/docker_image.py +++ b/src/taskgraph/transforms/docker_image.py @@ -5,6 +5,7 @@ import logging import os import re +from textwrap import dedent from voluptuous import Optional, Required @@ -33,29 +34,78 @@ #: Schema for docker_image transforms docker_image_schema = Schema( { - # Name of the docker image. - Required("name"): str, - # Name of the parent docker image. - Optional("parent"): str, - # Treeherder symbol. - Optional("symbol"): str, - # relative path (from config.path) to the file the docker image was defined - # in. - Optional("task-from"): str, - # Arguments to use for the Dockerfile. - Optional("args"): {str: str}, - # Name of the docker image definition under taskcluster/docker, when - # different from the docker image name. - Optional("definition"): str, - # List of package tasks this docker image depends on. - Optional("packages"): [str], + Required( + "name", + description=dedent( + """ + Name of the docker image. + """ + ).lstrip(), + ): str, + Optional( + "parent", + description=dedent( + """ + Name of the parent docker image. + """ + ).lstrip(), + ): str, + Optional( + "symbol", + description=dedent( + """ + Treeherder symbol. + """ + ).lstrip(), + ): str, + Optional( + "task-from", + description=dedent( + """ + Relative path (from config.path) to the file the docker image was defined in. + """ + ).lstrip(), + ): str, + Optional( + "args", + description=dedent( + """ + Arguments to use for the Dockerfile. + """ + ).lstrip(), + ): {str: str}, + Optional( + "definition", + description=dedent( + """ + Name of the docker image definition under taskcluster/docker, when + different from the docker image name. + """ + ).lstrip(), + ): str, + Optional( + "packages", + description=dedent( + """ + List of package tasks this docker image depends on. + """ + ).lstrip(), + ): [str], Optional( "index", - description="information for indexing this build so its artifacts can be discovered", + description=dedent( + """ + Information for indexing this build so its artifacts can be discovered. + """ + ).lstrip(), ): task_description_schema["index"], Optional( "cache", - description="Whether this image should be cached based on inputs.", + description=dedent( + """ + Whether this image should be cached based on inputs. + """ + ).lstrip(), ): bool, } ) diff --git a/src/taskgraph/transforms/fetch.py b/src/taskgraph/transforms/fetch.py index 98f520d97..797ab71e2 100644 --- a/src/taskgraph/transforms/fetch.py +++ b/src/taskgraph/transforms/fetch.py @@ -9,6 +9,7 @@ import os import re from dataclasses import dataclass +from textwrap import dedent from typing import Callable from voluptuous import Extra, Optional, Required @@ -26,25 +27,51 @@ #: Schema for fetch transforms FETCH_SCHEMA = Schema( { - # Name of the task. - Required("name"): str, - # Relative path (from config.path) to the file the task was defined - # in. - Optional("task-from"): str, - # Description of the task. - Required("description"): str, + Required( + "name", + description=dedent( + """ + Name of the task. + """.lstrip() + ), + ): str, + Optional( + "task-from", + description=dedent( + """ + Relative path (from config.path) to the file the task was defined + in. + """.lstrip() + ), + ): str, + Required( + "description", + description=dedent( + """ + Description of the task. + """.lstrip() + ), + ): str, Optional("expires-after"): str, Optional("docker-image"): object, Optional( "fetch-alias", - description="An alias that can be used instead of the real fetch task name in " - "fetch stanzas for tasks.", + description=dedent( + """ + An alias that can be used instead of the real fetch task name in + fetch stanzas for tasks. + """.lstrip() + ), ): str, Optional( "artifact-prefix", - description="The prefix of the taskcluster artifact being uploaded. " - "Defaults to `public/`; if it starts with something other than " - "`public/` the artifact will require scopes to access.", + description=dedent( + """ + The prefix of the taskcluster artifact being uploaded. + Defaults to `public/`; if it starts with something other than + `public/` the artifact will require scopes to access. + """.lstrip() + ), ): str, Optional("attributes"): {str: object}, Required("fetch"): { diff --git a/src/taskgraph/transforms/from_deps.py b/src/taskgraph/transforms/from_deps.py index bfb25e6b4..cf89a2a56 100644 --- a/src/taskgraph/transforms/from_deps.py +++ b/src/taskgraph/transforms/from_deps.py @@ -14,7 +14,7 @@ from copy import deepcopy from textwrap import dedent -from voluptuous import ALLOW_EXTRA, Any, Extra, Optional, Required +from voluptuous import ALLOW_EXTRA, Any, Optional, Required from taskgraph.transforms.base import TransformSequence from taskgraph.transforms.run import fetches_schema diff --git a/src/taskgraph/transforms/run/__init__.py b/src/taskgraph/transforms/run/__init__.py index e2706bd32..c3a151c37 100644 --- a/src/taskgraph/transforms/run/__init__.py +++ b/src/taskgraph/transforms/run/__init__.py @@ -11,6 +11,7 @@ import copy import logging +from textwrap import dedent from voluptuous import Exclusive, Extra, Optional, Required @@ -39,13 +40,28 @@ #: Schema for a run transforms run_description_schema = Schema( { - # The name of the task and the task's label. At least one must be specified, - # and the label will be generated from the name if necessary, by prepending - # the kind. - Optional("name"): str, - Optional("label"): str, + Optional( + "name", + description=dedent( + """ + The name of the task. At least one of 'name' or 'label' must be + specified. If 'label' is not provided, it will be generated from + the 'name' by prepending the kind. + """ + ), + ): str, + Optional( + "label", + description=dedent( + """ + The label of the task. At least one of 'name' or 'label' must be + specified. If 'label' is not provided, it will be generated from + the 'name' by prepending the kind. + """ + ), + ): str, # the following fields are passed directly through to the task description, - # possibly modified by the run implementation. See + # possibly modified by the run implementation. See # taskcluster/taskgraph/transforms/task.py for the schema details. Required("description"): task_description_schema["description"], Optional("priority"): task_description_schema["priority"], @@ -72,37 +88,80 @@ "optimization" ], Optional("needs-sccache"): task_description_schema["needs-sccache"], - # The "when" section contains descriptions of the circumstances under which - # this task should be included in the task graph. This will be converted - # into an optimization, so it cannot be specified in a run description that - # also gives 'optimization'. - Exclusive("when", "optimization"): { - # This task only needs to be run if a file matching one of the given - # patterns has changed in the push. The patterns use the mozpack - # match function (python/mozbuild/mozpack/path.py). - Optional("files-changed"): [str], + Exclusive( + "when", + "optimization", + description=dedent( + """ + The "when" section contains descriptions of the circumstances under + which this task should be included in the task graph. This will be + converted into an optimization, so it cannot be specified in a run + description that also gives 'optimization'. + """ + ), + ): { + Optional( + "files-changed", + description=dedent( + """ + This task only needs to be run if a file matching one of the given + patterns has changed in the push. The patterns use the mozpack + match function (python/mozbuild/mozpack/path.py). + """ + ), + ): [str], }, - # A list of artifacts to install from 'fetch' tasks. - Optional("fetches"): { + Optional( + "fetches", + description=dedent( + """ + A list of artifacts to install from 'fetch' tasks. + """ + ), + ): { str: [ str, fetches_schema, ], }, - # A description of how to run this task. - "run": { - # The key to a run implementation in a peer module to this one - "using": str, - # Base work directory used to set up the task. - Optional("workdir"): str, + Required( + "run", + description=dedent( + """ + A description of how to run this task. + """ + ), + ): { + Required( + "using", + description=dedent( + """ + The key to a run implementation in a peer module to this one. + """ + ), + ): str, + Optional( + "workdir", + description=dedent( + """ + Base work directory used to set up the task. + """ + ), + ): str, # Any remaining content is verified against that run implementation's # own schema. Extra: object, }, Required("worker-type"): task_description_schema["worker-type"], - # This object will be passed through to the task description, with additions - # provided by the task's run-using function - Optional("worker"): dict, + Required( + "worker", + description=dedent( + """ + This object will be passed through to the task description, with additions + provided by the task's run-using function. + """ + ), + ): dict, } ) diff --git a/src/taskgraph/transforms/run/run_task.py b/src/taskgraph/transforms/run/run_task.py index 1cd46ac82..0429ccae7 100644 --- a/src/taskgraph/transforms/run/run_task.py +++ b/src/taskgraph/transforms/run/run_task.py @@ -7,6 +7,7 @@ import dataclasses import os +from textwrap import dedent from voluptuous import Any, Optional, Required @@ -29,36 +30,95 @@ #: Schema for run.using run_task run_task_schema = Schema( { - Required("using"): "run-task", - # Which caches to use. May take a boolean in which case either all - # (True) or no (False) caches will be used. Alternatively, it can - # accept a list of caches to enable. Defaults to only the checkout cache - # enabled. - Optional("use-caches", "caches"): Any(bool, list(CACHES.keys())), - # if true (the default), perform a checkout on the worker - Required("checkout"): Any(bool, {str: dict}), + Required( + "using", + description=dedent( + """ + Specifies the task type. Must be 'run-task'. + """.lstrip() + ), + ): "run-task", + Optional( + "use-caches", + description=dedent( + """ + Specifies which caches to use. May take a boolean in which case either all + (True) or no (False) caches will be used. Alternatively, it can accept a + list of caches to enable. Defaults to only the checkout cache enabled. + """.lstrip() + ), + ): Any(bool, list(CACHES.keys())), + Required( + "checkout", + description=dedent( + """ + If true (the default), perform a checkout on the worker. Can also be a + dictionary specifying explicit checkouts. + """.lstrip() + ), + ): Any(bool, {str: dict}), Optional( "cwd", - description="Path to run command in. If a checkout is present, the path " - "to the checkout will be interpolated with the key `checkout`", + description=dedent( + """ + Path to run command in. If a checkout is present, the path to the checkout + will be interpolated with the key `checkout`. + """.lstrip() + ), ): str, - # The sparse checkout profile to use. Value is the filename relative to the - # directory where sparse profiles are defined (build/sparse-profiles/). - Required("sparse-profile"): Any(str, None), - # The command arguments to pass to the `run-task` script, after the - # checkout arguments. If a list, it will be passed directly; otherwise - # it will be included in a single argument to the command specified by - # `exec-with`. - Required("command"): Any([taskref_or_string], taskref_or_string), - # What to execute the command with in the event command is a string. - Optional("exec-with"): Any(*list(EXEC_COMMANDS)), - # Command used to invoke the `run-task` script. Can be used if the script - # or Python installation is in a non-standard location on the workers. - Optional("run-task-command"): list, - # Base work directory used to set up the task. - Required("workdir"): str, - # Whether to run as root. (defaults to False) - Optional("run-as-root"): bool, + Required( + "sparse-profile", + description=dedent( + """ + The sparse checkout profile to use. Value is the filename relative to the + directory where sparse profiles are defined (build/sparse-profiles/). + """.lstrip() + ), + ): Any(str, None), + Required( + "command", + description=dedent( + """ + The command arguments to pass to the `run-task` script, after the checkout + arguments. If a list, it will be passed directly; otherwise it will be + included in a single argument to the command specified by `exec-with`. + """.lstrip() + ), + ): Any([taskref_or_string], taskref_or_string), + Optional( + "exec-with", + description=dedent( + """ + Specifies what to execute the command with in the event the command is a + string. + """.lstrip() + ), + ): Any(*list(EXEC_COMMANDS)), + Optional( + "run-task-command", + description=dedent( + """ + Command used to invoke the `run-task` script. Can be used if the script + or Python installation is in a non-standard location on the workers. + """.lstrip() + ), + ): list, + Required( + "workdir", + description=dedent( + """ + Base work directory used to set up the task. + """.lstrip() + ), + ): str, + Optional( + "run-as-root", + description=dedent( + """ + Whether to run as root. Defaults to False. + """.lstrip() + ), + ): bool, } ) diff --git a/src/taskgraph/transforms/run/toolchain.py b/src/taskgraph/transforms/run/toolchain.py index 6730ac3b2..99b57adfc 100644 --- a/src/taskgraph/transforms/run/toolchain.py +++ b/src/taskgraph/transforms/run/toolchain.py @@ -5,6 +5,8 @@ Support for running toolchain-building tasks via dedicated scripts """ +from textwrap import dedent + from voluptuous import ALLOW_EXTRA, Any, Optional, Required import taskgraph @@ -24,33 +26,85 @@ #: Schema for run.using toolchain toolchain_run_schema = Schema( { - Required("using"): "toolchain-script", - # The script (in taskcluster/scripts/misc) to run. - Required("script"): str, - # Arguments to pass to the script. - Optional("arguments"): [str], - # Sparse profile to give to checkout using `run-task`. If given, - # a filename in `build/sparse-profiles`. Defaults to - # "toolchain-build", i.e., to - # `build/sparse-profiles/toolchain-build`. If `None`, instructs - # `run-task` to not use a sparse profile at all. - Required("sparse-profile"): Any(str, None), - # Paths/patterns pointing to files that influence the outcome of a - # toolchain build. - Optional("resources"): [str], - # Path to the artifact produced by the toolchain task - Required("toolchain-artifact"): str, + Required( + "using", + description=dedent( + """ + Specifies the run type. Must be "toolchain-script". + """ + ), + ): "toolchain-script", + Required( + "script", + description=dedent( + """ + The script (in taskcluster/scripts/misc) to run. + """ + ), + ): str, + Optional( + "arguments", + description=dedent( + """ + Arguments to pass to the script. + """ + ), + ): [str], + Required( + "sparse-profile", + description=dedent( + """ + Sparse profile to give to checkout using `run-task`. If given, + a filename in `build/sparse-profiles`. Defaults to + "toolchain-build", i.e., to + `build/sparse-profiles/toolchain-build`. If `None`, instructs + `run-task` to not use a sparse profile at all. + """ + ), + ): Any(str, None), + Optional( + "resources", + description=dedent( + """ + Paths/patterns pointing to files that influence the outcome of + a toolchain build. + """ + ), + ): [str], + Required( + "toolchain-artifact", + description=dedent( + """ + Path to the artifact produced by the toolchain task. + """ + ), + ): str, Optional( "toolchain-alias", - description="An alias that can be used instead of the real toolchain task name in " - "fetch stanzas for tasks.", + description=dedent( + """ + An alias that can be used instead of the real toolchain task name in + fetch stanzas for tasks. + """ + ), ): Any(str, [str]), Optional( "toolchain-env", - description="Additional env variables to add to the worker when using this toolchain", + description=dedent( + """ + Additional env variables to add to the worker when using this + toolchain. + """ + ), ): {str: object}, - # Base work directory used to set up the task. - Required("workdir"): str, + Optional( + "workdir", + description=dedent( + """ + Base work directory used to set up the task. + """ + ), + ): str, }, extra=ALLOW_EXTRA, ) diff --git a/src/taskgraph/transforms/task.py b/src/taskgraph/transforms/task.py index 38c1835c5..aa62b1b0d 100644 --- a/src/taskgraph/transforms/task.py +++ b/src/taskgraph/transforms/task.py @@ -15,6 +15,7 @@ import time from copy import deepcopy from dataclasses import dataclass +from textwrap import dedent from typing import Callable from voluptuous import All, Any, Extra, NotIn, Optional, Required @@ -51,18 +52,49 @@ def _run_task_suffix(): #: Schema for the task transforms task_description_schema = Schema( { - # the label for this task - Required("label"): str, - # description of the task (for metadata) - Required("description"): str, - # attributes for this task - Optional("attributes"): {str: object}, - # relative path (from config.path) to the file task was defined in - Optional("task-from"): str, - # dependencies of this task, keyed by name; these are passed through - # verbatim and subject to the interpretation of the Task's get_dependencies - # method. - Optional("dependencies"): { + Required( + "label", + description=dedent( + """ + The label for this task. + """.lstrip() + ), + ): str, + Required( + "description", + description=dedent( + """ + Description of the task (for metadata). + """.lstrip() + ), + ): str, + Optional( + "attributes", + description=dedent( + """ + Attributes for this task. + """.lstrip() + ), + ): {str: object}, + Optional( + "task-from", + description=dedent( + """ + Relative path (from config.path) to the file task was defined + in. + """.lstrip() + ), + ): str, + Optional( + "dependencies", + description=dedent( + """ + Dependencies of this task, keyed by name; these are passed + through verbatim and subject to the interpretation of the + Task's get_dependencies method. + """.lstrip() + ), + ): { All( str, NotIn( @@ -71,7 +103,14 @@ def _run_task_suffix(): ), ): object, }, - Optional("priority"): Any( + Optional( + "priority", + description=dedent( + """ + Priority of the task. + """.lstrip() + ), + ): Any( "highest", "very-high", "high", @@ -80,61 +119,146 @@ def _run_task_suffix(): "very-low", "lowest", ), - # Soft dependencies of this task, as a list of tasks labels - Optional("soft-dependencies"): [str], - # Dependencies that must be scheduled in order for this task to run. - Optional("if-dependencies"): [str], - Optional("requires"): Any("all-completed", "all-resolved"), - # expiration and deadline times, relative to task creation, with units - # (e.g., "14 days"). Defaults are set based on the project. - Optional("expires-after"): str, - Optional("deadline-after"): str, - # custom routes for this task; the default treeherder routes will be added - # automatically - Optional("routes"): [str], - # custom scopes for this task; any scopes required for the worker will be - # added automatically. The following parameters will be substituted in each - # scope: - # {level} -- the scm level of this push - # {project} -- the project of this push - Optional("scopes"): [str], - # Tags - Optional("tags"): {str: str}, - # custom "task.extra" content - Optional("extra"): {str: object}, - # treeherder-related information; see - # https://schemas.taskcluster.net/taskcluster-treeherder/v1/task-treeherder-config.json - # This may be provided in one of two ways: - # 1) A simple `true` will cause taskgraph to generate the required information - # 2) A dictionary with one or more of the required keys. Any key not present - # will use a default as described below. - # If not specified, no treeherder extra information or routes will be - # added to the task - Optional("treeherder"): Any( + Optional( + "soft-dependencies", + description=dedent( + """ + Soft dependencies of this task, as a list of task labels. + """.lstrip() + ), + ): [str], + Optional( + "if-dependencies", + description=dedent( + """ + Dependencies that must be scheduled in order for this task to run. + """.lstrip() + ), + ): [str], + Optional( + "requires", + description=dedent( + """ + Specifies the condition for task execution. + """.lstrip() + ), + ): Any("all-completed", "all-resolved"), + Optional( + "expires-after", + description=dedent( + """ + Expiration time relative to task creation, with units (e.g., + '14 days'). Defaults are set based on the project. + """.lstrip() + ), + ): str, + Optional( + "deadline-after", + description=dedent( + """ + Deadline time relative to task creation, with units (e.g., + '14 days'). Defaults are set based on the project. + """.lstrip() + ), + ): str, + Optional( + "routes", + description=dedent( + """ + Custom routes for this task; the default treeherder routes will + be added automatically. + """.lstrip() + ), + ): [str], + Optional( + "scopes", + description=dedent( + """ + Custom scopes for this task; any scopes required for the worker + will be added automatically. The following parameters will be + substituted in each scope: + + {level} -- the scm level of this push + {project} -- the project of this push. + """.lstrip() + ), + ): [str], + Optional( + "tags", + description=dedent( + """ + Tags for this task. + """.lstrip() + ), + ): {str: str}, + Optional( + "extra", + description=dedent( + """ + Custom 'task.extra' content. + """.lstrip() + ), + ): {str: object}, + Optional( + "treeherder", + description=dedent( + """ + Treeherder-related information. Can be a simple `true` to + auto-generate information or a dictionary with specific keys. + """.lstrip() + ), + ): Any( True, { - # either a bare symbol, or "grp(sym)". - # The default symbol is the uppercased first letter of each - # section of the kind (delimited by "-") all smooshed together. - # Eg: "test" becomes "T", "docker-image" becomes "DI", etc. - "symbol": Optional(str), - # the task kind - # If "build" or "test" is found in the kind name, this defaults - # to the appropriate value. Otherwise, defaults to "other" - "kind": Optional(Any("build", "test", "other")), - # tier for this task - # Defaults to 1 - "tier": Optional(int), - # task platform, in the form platform/collection, used to set - # treeherder.machine.platform and treeherder.collection or - # treeherder.labels - # Defaults to "default/opt" - "platform": Optional(str), + "symbol": Optional( + str, + description=dedent( + """ + Either a bare symbol, or 'grp(sym)'. Defaults to the + uppercased first letter of each section of the kind + (delimited by '-') all smooshed together. + """.lstrip() + ), + ), + "kind": Optional( + Any("build", "test", "other"), + description=dedent( + """ + The task kind. Defaults to 'build', 'test', or 'other' + based on the kind name. + """.lstrip() + ), + ), + "tier": Optional( + int, + description=dedent( + """ + Tier for this task. Defaults to 1. + """.lstrip() + ), + ), + "platform": Optional( + str, + description=dedent( + """ + Task platform in the form platform/collection, used to + set treeherder.machine.platform and + treeherder.collection or treeherder.labels Defaults to + 'default/opt'. + """.lstrip() + ), + ), }, ), - # information for indexing this build so its artifacts can be discovered; - # if omitted, the build will not be indexed. - Optional("index"): { + Optional( + "index", + description=dedent( + """ + Information for indexing this build so its artifacts can be + discovered. If omitted, the build will not be indexed. + """.lstrip() + ), + ): { # the name of the product this build produces "product": str, # the names to use for this task in the TaskCluster index @@ -159,39 +283,105 @@ def _run_task_suffix(): "build_date", ), }, - # The `run_on_projects` attribute, defaulting to "all". This dictates the - # projects on which this task should be included in the target task set. - # See the attributes documentation for details. - Optional("run-on-projects"): optionally_keyed_by("build-platform", [str]), - Optional("run-on-tasks-for"): [str], - Optional("run-on-git-branches"): [str], - # The `shipping_phase` attribute, defaulting to None. This specifies the - # release promotion phase that this task belongs to. - Optional("shipping-phase"): Any( + Optional( + "run-on-projects", + description=dedent( + """ + The `run_on_projects` attribute, defaulting to 'all'. Dictates + the projects on which this task should be included in the + target task set. See the attributes documentation for details. + """.lstrip() + ), + ): optionally_keyed_by("build-platform", [str]), + Optional( + "run-on-tasks-for", + description=dedent( + """ + Specifies tasks for which this task should run. + """.lstrip() + ), + ): [str], + Optional( + "run-on-git-branches", + description=dedent( + """ + Specifies git branches for which this task should run. + """.lstrip() + ), + ): [str], + Optional( + "shipping-phase", + description=dedent( + """ + The `shipping_phase` attribute, defaulting to None. Specifies + the release promotion phase that this task belongs to. + """.lstrip() + ), + ): Any( None, "build", "promote", "push", "ship", ), - # The `always-target` attribute will cause the task to be included in the - # target_task_graph regardless of filtering. Tasks included in this manner - # will be candidates for optimization even when `optimize_target_tasks` is - # False, unless the task was also explicitly chosen by the target_tasks - # method. - Required("always-target"): bool, - # Optimization to perform on this task during the optimization phase. - # Optimizations are defined in taskcluster/taskgraph/optimize.py. - Required("optimization"): OptimizationSchema, - # the provisioner-id/worker-type for the task. The following parameters will - # be substituted in this string: - # {level} -- the scm level of this push - "worker-type": str, - # Whether the task should use sccache compiler caching. - Required("needs-sccache"): bool, - # information specific to the worker implementation that will run this task - Optional("worker"): { - Required("implementation"): str, + Required( + "always-target", + description=dedent( + """ + The `always-target` attribute will cause the task to be + included in the target_task_graph regardless of filtering. + + Tasks included in this manner will be candidates for + optimization even when `optimize_target_tasks` is False, unless + the task was also explicitly chosen by the target_tasks method. + """.lstrip() + ), + ): bool, + Required( + "optimization", + description=dedent( + """ + Optimization to perform on this task during the optimization + phase. Defined in taskcluster/taskgraph/optimize.py. + """.lstrip() + ), + ): OptimizationSchema, + Required( + "worker-type", + description=dedent( + """ + The provisioner-id/worker-type for the task. The following + parameters will be substituted in this string: + + {level} -- the scm level of this push. + """.lstrip() + ), + ): str, + Required( + "needs-sccache", + description=dedent( + """ + Whether the task should use sccache compiler caching. + """.lstrip() + ), + ): bool, + Optional( + "worker", + description=dedent( + """ + Information specific to the worker implementation that will run + this task. + """.lstrip() + ), + ): { + Required( + "implementation", + description=dedent( + """ + The worker implementation type. + """.lstrip() + ), + ): str, Extra: object, }, }