taskcluster-taskgraph 21.0.0__tar.gz → 23.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (270) hide show
  1. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/.pre-commit-config.yaml +3 -4
  2. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/.taskcluster.yml +0 -1
  3. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/CHANGELOG.md +27 -0
  4. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/PKG-INFO +1 -1
  5. taskcluster_taskgraph-23.0.0/docs/howto/define-schemas.rst +156 -0
  6. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/howto/index.rst +1 -0
  7. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/reference/migrations.rst +15 -0
  8. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/pyproject.toml +1 -2
  9. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/actions/registry.py +16 -1
  10. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/config.py +3 -0
  11. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/decision.py +1 -1
  12. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/parameters.py +95 -50
  13. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/run-task/fetch-content +4 -3
  14. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/run-task/run-task +1 -14
  15. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/taskgraph.py +0 -3
  16. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/transforms/from_deps.py +40 -40
  17. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/transforms/task.py +0 -5
  18. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/schema.py +81 -0
  19. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/vcs.py +36 -4
  20. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/self_taskgraph/custom_parameters.py +9 -6
  21. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/conftest.py +15 -2
  22. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_actions_registry.py +73 -0
  23. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_decision.py +3 -1
  24. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_main.py +27 -1
  25. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_parameters.py +8 -13
  26. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_scripts_fetch_content.py +80 -0
  27. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_scripts_run_task.py +0 -46
  28. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_taskgraph.py +2 -3
  29. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_util_schema.py +51 -0
  30. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_util_vcs.py +11 -9
  31. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/uv.lock +1 -1
  32. taskcluster_taskgraph-21.0.0/taskcluster/scripts/external_tools/tooltool.py +0 -1502
  33. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/.codespell-ignore-words.txt +0 -0
  34. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/.github/CODEOWNERS +0 -0
  35. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/.github/dependabot.yml +0 -0
  36. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/.github/workflows/codeql-analysis.yml +0 -0
  37. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/.github/workflows/pre-commit-autoupdate.yml +0 -0
  38. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/.github/workflows/pre-commit.yml +0 -0
  39. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/.github/workflows/pypi-publish.yml +0 -0
  40. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/.gitignore +0 -0
  41. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/.readthedocs.yaml +0 -0
  42. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/.yamllint +0 -0
  43. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/CODE_OF_CONDUCT.md +0 -0
  44. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/CONTRIBUTING.rst +0 -0
  45. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/LICENSE +0 -0
  46. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/Makefile +0 -0
  47. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/README.rst +0 -0
  48. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/concepts/index.rst +0 -0
  49. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/concepts/kind.rst +0 -0
  50. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/concepts/loading.rst +0 -0
  51. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/concepts/optimization.rst +0 -0
  52. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/concepts/overview.rst +0 -0
  53. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/concepts/scopes.rst +0 -0
  54. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/concepts/task-graphs.rst +0 -0
  55. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/concepts/transforms.rst +0 -0
  56. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/conf.py +0 -0
  57. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/contributing.rst +0 -0
  58. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/glossary.rst +0 -0
  59. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/howto/bootstrap-taskgraph.rst +0 -0
  60. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/howto/create-actions.rst +0 -0
  61. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/howto/create-tasks.rst +0 -0
  62. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/howto/debugging.rst +0 -0
  63. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/howto/docker.rst +0 -0
  64. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/howto/load-task-locally.rst +0 -0
  65. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/howto/resolve-keyed-by.rst +0 -0
  66. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/howto/run-locally.rst +0 -0
  67. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/howto/send-notifications.rst +0 -0
  68. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/howto/use-fetches.rst +0 -0
  69. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/index.rst +0 -0
  70. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/reference/cli.rst +0 -0
  71. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/reference/index.rst +0 -0
  72. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/reference/optimization-strategies.rst +0 -0
  73. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/reference/parameters.rst +0 -0
  74. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/reference/source/modules.rst +0 -0
  75. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/reference/source/taskgraph.actions.rst +0 -0
  76. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/reference/source/taskgraph.loader.rst +0 -0
  77. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/reference/source/taskgraph.optimize.rst +0 -0
  78. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/reference/source/taskgraph.rst +0 -0
  79. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/reference/source/taskgraph.transforms.rst +0 -0
  80. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/reference/source/taskgraph.transforms.run.rst +0 -0
  81. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/reference/source/taskgraph.util.rst +0 -0
  82. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/reference/transforms/chunking.rst +0 -0
  83. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/reference/transforms/from_deps.rst +0 -0
  84. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/reference/transforms/index.rst +0 -0
  85. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/reference/transforms/matrix.rst +0 -0
  86. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/reference/transforms/task_context.rst +0 -0
  87. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/tutorials/connecting-taskcluster.rst +0 -0
  88. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/tutorials/creating-a-task-graph.rst +0 -0
  89. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/tutorials/example-taskcluster.yml +0 -0
  90. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/tutorials/getting-started.rst +0 -0
  91. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/docs/tutorials/index.rst +0 -0
  92. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/make.bat +0 -0
  93. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/packages/pytest-taskgraph/README.md +0 -0
  94. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/packages/pytest-taskgraph/pyproject.toml +0 -0
  95. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/packages/pytest-taskgraph/src/pytest_taskgraph/__init__.py +0 -0
  96. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/packages/pytest-taskgraph/src/pytest_taskgraph/fixtures/gen.py +0 -0
  97. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/packages/pytest-taskgraph/src/pytest_taskgraph/fixtures/vcs.py +0 -0
  98. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/packages/sphinx-taskgraph/README.md +0 -0
  99. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/packages/sphinx-taskgraph/pyproject.toml +0 -0
  100. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/packages/sphinx-taskgraph/src/sphinx_taskgraph/__init__.py +0 -0
  101. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/packages/sphinx-taskgraph/src/sphinx_taskgraph/autoschema.py +0 -0
  102. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/__init__.py +0 -0
  103. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/actions/__init__.py +0 -0
  104. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/actions/add_new_jobs.py +0 -0
  105. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/actions/cancel.py +0 -0
  106. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/actions/cancel_all.py +0 -0
  107. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/actions/rebuild_cached_tasks.py +0 -0
  108. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/actions/retrigger.py +0 -0
  109. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/actions/util.py +0 -0
  110. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/create.py +0 -0
  111. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/docker.py +0 -0
  112. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/filter_tasks.py +0 -0
  113. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/generator.py +0 -0
  114. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/graph.py +0 -0
  115. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/loader/__init__.py +0 -0
  116. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/loader/default.py +0 -0
  117. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/loader/transform.py +0 -0
  118. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/main.py +0 -0
  119. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/morph.py +0 -0
  120. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/optimize/__init__.py +0 -0
  121. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/optimize/base.py +0 -0
  122. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/optimize/strategies.py +0 -0
  123. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/run-task/hgrc +0 -0
  124. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/run-task/robustcheckout.py +0 -0
  125. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/target_tasks.py +0 -0
  126. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/task.py +0 -0
  127. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/transforms/__init__.py +0 -0
  128. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/transforms/base.py +0 -0
  129. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/transforms/cached_tasks.py +0 -0
  130. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/transforms/chunking.py +0 -0
  131. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/transforms/code_review.py +0 -0
  132. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/transforms/docker_image.py +0 -0
  133. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/transforms/fetch.py +0 -0
  134. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/transforms/matrix.py +0 -0
  135. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/transforms/notify.py +0 -0
  136. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/transforms/run/__init__.py +0 -0
  137. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/transforms/run/common.py +0 -0
  138. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/transforms/run/index_search.py +0 -0
  139. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/transforms/run/run_task.py +0 -0
  140. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/transforms/run/toolchain.py +0 -0
  141. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/transforms/task_context.py +0 -0
  142. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/__init__.py +0 -0
  143. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/archive.py +0 -0
  144. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/attributes.py +0 -0
  145. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/cached_tasks.py +0 -0
  146. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/caches.py +0 -0
  147. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/copy.py +0 -0
  148. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/dependencies.py +0 -0
  149. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/docker.py +0 -0
  150. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/hash.py +0 -0
  151. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/json.py +0 -0
  152. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/keyed_by.py +0 -0
  153. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/parameterization.py +0 -0
  154. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/path.py +0 -0
  155. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/python_path.py +0 -0
  156. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/readonlydict.py +0 -0
  157. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/set_name.py +0 -0
  158. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/shell.py +0 -0
  159. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/taskcluster.py +0 -0
  160. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/taskgraph.py +0 -0
  161. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/templates.py +0 -0
  162. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/time.py +0 -0
  163. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/treeherder.py +0 -0
  164. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/verify.py +0 -0
  165. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/workertypes.py +0 -0
  166. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/src/taskgraph/util/yaml.py +0 -0
  167. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/config.yml +0 -0
  168. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/docker/REGISTRY +0 -0
  169. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/docker/decision/Dockerfile +0 -0
  170. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/docker/decision/HASH +0 -0
  171. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/docker/decision/README.md +0 -0
  172. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/docker/decision/VERSION +0 -0
  173. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/docker/decision/system-setup.sh +0 -0
  174. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/docker/fetch/Dockerfile +0 -0
  175. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/docker/image_builder/README.rst +0 -0
  176. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/docker/index-task/Dockerfile +0 -0
  177. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/docker/index-task/README +0 -0
  178. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/docker/index-task/insert-indexes.js +0 -0
  179. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/docker/index-task/package.json +0 -0
  180. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/docker/index-task/yarn.lock +0 -0
  181. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/docker/python/Dockerfile +0 -0
  182. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/docker/run-task/Dockerfile +0 -0
  183. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/docker/run-task/system-setup.sh +0 -0
  184. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/docker/skopeo/Dockerfile +0 -0
  185. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/docker/skopeo/policy.json +0 -0
  186. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/docker/skopeo/push_image.sh +0 -0
  187. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/kinds/check/kind.yml +0 -0
  188. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/kinds/codecov/kind.yml +0 -0
  189. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/kinds/complete/kind.yml +0 -0
  190. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/kinds/doc/kind.yml +0 -0
  191. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/kinds/docker-image/kind.yml +0 -0
  192. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/kinds/fetch/kind.yml +0 -0
  193. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/kinds/push-image/kind.yml +0 -0
  194. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/kinds/test/kind.yml +0 -0
  195. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/kinds/test/linux.yml +0 -0
  196. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/kinds/test/windows.yml +0 -0
  197. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/scripts/codecov-upload.py +0 -0
  198. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/self_taskgraph/__init__.py +0 -0
  199. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/self_taskgraph/custom_target_tasks.py +0 -0
  200. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/self_taskgraph/transforms/add_pr_route.py +0 -0
  201. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/self_taskgraph/transforms/push_image.py +0 -0
  202. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/test/params/main-repo-pull-request-untrusted.yml +0 -0
  203. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/test/params/main-repo-pull-request.yml +0 -0
  204. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/test/params/main-repo-push.yml +0 -0
  205. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/test/params/main-repo-release-pytest-taskgraph.yml +0 -0
  206. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/taskcluster/test/params/main-repo-release-taskcluster-taskgraph.yml +0 -0
  207. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/template/cookiecutter.json +0 -0
  208. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/template/hooks/post_gen_project.py +0 -0
  209. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/template/{{cookiecutter.project_name}}/taskcluster/config.yml +0 -0
  210. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/template/{{cookiecutter.project_name}}/taskcluster/docker/linux/Dockerfile +0 -0
  211. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/template/{{cookiecutter.project_name}}/taskcluster/kinds/docker-image/kind.yml +0 -0
  212. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/template/{{cookiecutter.project_name}}/taskcluster/kinds/hello/kind.yml +0 -0
  213. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/template/{{cookiecutter.project_name}}/taskcluster/{{cookiecutter.project_slug}}_taskgraph/transforms/hello.py +0 -0
  214. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/template/{{cookiecutter.project_name}}/taskcluster.github.yml +0 -0
  215. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/__init__.py +0 -0
  216. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/automationrelevance.json +0 -0
  217. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/data/task_context.yml +0 -0
  218. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/data/taskcluster/config.yml +0 -0
  219. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/data/taskcluster/docker/hello-world/Dockerfile +0 -0
  220. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/data/taskcluster/docker/hello-world-tag/Dockerfile +0 -0
  221. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/data/taskcluster/docker/hello-world-tag/REGISTRY +0 -0
  222. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/data/taskcluster/docker/hello-world-tag/VERSION +0 -0
  223. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/data/taskcluster/kinds/docker-image/kind.yml +0 -0
  224. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/data/taskcluster/scripts/toolchain/run.ps1 +0 -0
  225. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/data/taskcluster/scripts/toolchain/run.sh +0 -0
  226. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/data/taskcluster/test_taskgraph/transforms/foo.py +0 -0
  227. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/data/testmod/thing.py +0 -0
  228. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/mockedopen.py +0 -0
  229. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_actions_rebuild_cached_tasks.py +0 -0
  230. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_config.py +0 -0
  231. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_create.py +0 -0
  232. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_docker.py +0 -0
  233. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_generator.py +0 -0
  234. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_graph.py +0 -0
  235. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_morph.py +0 -0
  236. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_optimize.py +0 -0
  237. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_optimize_strategies.py +0 -0
  238. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_target_tasks.py +0 -0
  239. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_transform_chunking.py +0 -0
  240. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_transform_docker_image.py +0 -0
  241. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_transform_task_context.py +0 -0
  242. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_transforms_base.py +0 -0
  243. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_transforms_cached_tasks.py +0 -0
  244. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_transforms_fetch.py +0 -0
  245. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_transforms_from_deps.py +0 -0
  246. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_transforms_matrix.py +0 -0
  247. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_transforms_notify.py +0 -0
  248. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_transforms_run.py +0 -0
  249. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_transforms_run_run_task.py +0 -0
  250. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_transforms_run_toolchain.py +0 -0
  251. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_transforms_task.py +0 -0
  252. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_util_archive.py +0 -0
  253. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_util_attributes.py +0 -0
  254. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_util_cached_tasks.py +0 -0
  255. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_util_copy.py +0 -0
  256. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_util_dependencies.py +0 -0
  257. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_util_docker.py +0 -0
  258. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_util_json.py +0 -0
  259. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_util_keyed_by.py +0 -0
  260. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_util_parameterization.py +0 -0
  261. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_util_path.py +0 -0
  262. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_util_python_path.py +0 -0
  263. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_util_readonlydict.py +0 -0
  264. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_util_taskcluster.py +0 -0
  265. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_util_templates.py +0 -0
  266. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_util_time.py +0 -0
  267. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_util_treeherder.py +0 -0
  268. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_util_verify.py +0 -0
  269. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_util_workertypes.py +0 -0
  270. {taskcluster_taskgraph-21.0.0 → taskcluster_taskgraph-23.0.0}/test/test_util_yaml.py +0 -0
@@ -13,13 +13,13 @@ repos:
13
13
  exclude: template
14
14
  - id: check-added-large-files
15
15
  - repo: https://github.com/astral-sh/ruff-pre-commit
16
- rev: v0.15.8
16
+ rev: v0.15.12
17
17
  hooks:
18
18
  - id: ruff
19
19
  args: [--fix, --exit-non-zero-on-fix]
20
20
  - id: ruff-format
21
21
  - repo: https://github.com/astral-sh/uv-pre-commit
22
- rev: 0.11.2
22
+ rev: 0.11.8
23
23
  hooks:
24
24
  - id: uv-lock
25
25
  - repo: https://github.com/adrienverge/yamllint.git
@@ -48,6 +48,5 @@ exclude: |
48
48
  (?x)^(
49
49
  src/taskgraph/run-task/fetch-content |
50
50
  src/taskgraph/run-task/robustcheckout.py |
51
- src/taskgraph/run-task/run-task |
52
- taskcluster/scripts/external_tools
51
+ src/taskgraph/run-task/run-task
53
52
  )
@@ -226,7 +226,6 @@ tasks:
226
226
  - $if: 'isPullRequest'
227
227
  then:
228
228
  TASKGRAPH_PULL_REQUEST_NUMBER: '${event.pull_request.number}'
229
- TASKGRAPH_EXTRA_REFS: {$json: ["refs/notes/decision-parameters"]}
230
229
  - $if: 'tasks_for == "action" || tasks_for == "pr-action"'
231
230
  then:
232
231
  ACTION_TASK_GROUP_ID: '${action.taskGroupId}' # taskGroupId of the target task
@@ -1,5 +1,32 @@
1
1
  # Change Log
2
2
 
3
+ ## [23.0.0] - 2026-05-04
4
+
5
+ ### Added
6
+
7
+ - Support for defining schemas as dicts (in addition to the class-based approach)
8
+ - New `disabled_actions` graph configuration to prevent specific actions from being generated
9
+
10
+ ### Changed
11
+
12
+ - BREAKING CHANGE: Converted parameter schema from voluptuous to msgspec
13
+
14
+ ### Fixed
15
+
16
+ - `taskgraph full -J --tasks <regex>` now displays full dependencies instead of a filtered subset
17
+ - `fetch-content` now percent-encodes artifact names, fixing downloads of artifacts containing spaces or other special characters
18
+
19
+ ## [22.0.0] - 2026-04-16
20
+
21
+ ### Fixed
22
+
23
+ - Decision task now fetches `refs/notes/decision-parameters` itself
24
+
25
+ ### Removed
26
+
27
+ - BREAKING CHANGE: Removed ability for `run-task` to fetch arbitrary extra refs
28
+ - BREAKING CHANGE: Removed docker-worker feature: relengapi-proxy
29
+
3
30
  ## [21.0.0] - 2026-04-13
4
31
 
5
32
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: taskcluster-taskgraph
3
- Version: 21.0.0
3
+ Version: 23.0.0
4
4
  Summary: Build taskcluster taskgraphs
5
5
  Project-URL: Repository, https://github.com/taskcluster/taskgraph
6
6
  Project-URL: Issues, https://github.com/taskcluster/taskgraph/issues
@@ -0,0 +1,156 @@
1
+ Define Schemas
2
+ ==============
3
+
4
+ :doc:`Transforms </concepts/transforms>` can define schemas to validate task data at each step of the
5
+ pipeline. Taskgraph uses `msgspec`_ under the hood, and provides a
6
+ :class:`~taskgraph.util.schema.Schema` base class that integrates with
7
+ :meth:`TransformSequence.add_validate() <taskgraph.transforms.base.TransformSequence.add_validate>`.
8
+
9
+ There are two ways to define a schema: the **class based** approach and the
10
+ **dict based** approach. Both produce equivalent results; which one you prefer
11
+ is a matter of style.
12
+
13
+ .. _msgspec: https://jcristharif.com/msgspec/
14
+
15
+
16
+ Class Based Schemas
17
+ -------------------
18
+
19
+ Subclass :class:`~taskgraph.util.schema.Schema` and declare fields as class
20
+ attributes with type annotations:
21
+
22
+ .. code-block:: python
23
+
24
+ from typing import Optional
25
+ from taskgraph.transforms.base import TransformSequence
26
+ from taskgraph.util.schema import Schema
27
+
28
+ class MySubConfig(Schema):
29
+ total_num: int
30
+ fields: list[str] = []
31
+
32
+ class MySchema(Schema, forbid_unknown_fields=False):
33
+ config: Optional[MySubConfig] = None
34
+
35
+ transforms = TransformSequence()
36
+ transforms.add_validate(MySchema)
37
+
38
+ A few things to note:
39
+
40
+ - Field names use ``snake_case`` in Python but are **automatically renamed to
41
+ ``kebab-case``** in YAML. So ``total_num`` in Python matches
42
+ ``total-num`` in YAML.
43
+ - ``Optional[T]`` fields default to ``None`` unless you supply an explicit
44
+ default.
45
+ - Fields without a default are **required**.
46
+ - ``forbid_unknown_fields=True`` (the default) causes validation to fail if the
47
+ task data contains keys that are not declared in the schema. Set it to
48
+ ``False`` on outer schemas so that fields belonging to later transforms are
49
+ not rejected.
50
+
51
+
52
+ Dict Based Schemas
53
+ ------------------
54
+
55
+ Call :meth:`Schema.from_dict() <taskgraph.util.schema.Schema.from_dict>` with a
56
+ dictionary mapping field names to ``type`` or ``(type, default)`` tuples:
57
+
58
+ .. code-block:: python
59
+
60
+ from typing import Optional, Union
61
+ from taskgraph.transforms.base import TransformSequence
62
+ from taskgraph.util.schema import Schema
63
+
64
+ MySchema = Schema.from_dict(
65
+ {
66
+ "config": Schema.from_dict(
67
+ {
68
+ "total-num": int,
69
+ "fields": list[str] = []
70
+ },
71
+ optional=True,
72
+ ),
73
+ },
74
+ forbid_unknown_fields=False,
75
+ )
76
+
77
+ transforms = TransformSequence()
78
+ transforms.add_validate(MySchema)
79
+
80
+ This example is equivalent to the first example. One advantage with the dict based approach
81
+ is that you can write keys in **kebab-case** directly.
82
+
83
+ Field specifications follow these rules:
84
+
85
+ - A bare type (e.g. ``str``) means the field is required.
86
+ - ``Optional[T]`` means the field is optional and defaults to ``None``.
87
+ - A ``(type, default)`` tuple supplies an explicit default, e.g.
88
+ ``(list[str], [])``.
89
+
90
+ Keyword arguments to ``from_dict`` are forwarded to ``msgspec.defstruct``.
91
+ The most commonly used ones are ``name`` (for better error messages) and
92
+ ``forbid_unknown_fields``.
93
+
94
+ .. note::
95
+ ``Schema.from_dict`` does **not** apply ``rename="kebab"`` automatically,
96
+ because you can express the kebab-case names directly in the dict keys.
97
+ Underscores in dict keys stay as underscores and dashes become valid
98
+ kebab-case field names.
99
+
100
+
101
+ Nesting Schemas
102
+ ---------------
103
+
104
+ Both approaches support nesting:
105
+
106
+ .. code-block:: python
107
+
108
+ # Class-based nesting
109
+ class Inner(Schema):
110
+ value: str
111
+
112
+ class Outer(Schema, forbid_unknown_fields=False, kw_only=True):
113
+ inner: Optional[Inner] = None
114
+
115
+ # Dict-based nesting
116
+ Outer = Schema.from_dict(
117
+ {
118
+ "inner": Schema.from_dict({"value": str}, optional=True),
119
+ },
120
+ forbid_unknown_fields=False,
121
+ )
122
+
123
+ Pass ``optional=True`` to ``from_dict`` to make the whole nested schema
124
+ optional. This is necessary as function calls are not allowed in type
125
+ annotations, so ``Optional[Schema.from_dict(...)]`` is not valid Python.
126
+
127
+
128
+ Mutually Exclusive Fields
129
+ -------------------------
130
+
131
+ Use the ``exclusive`` keyword to declare groups of fields where at most one
132
+ may be set at a time:
133
+
134
+ .. code-block:: python
135
+
136
+ # Class-based
137
+ class MySchema(Schema, exclusive=[["field_a", "field_b"]]):
138
+ field_a: Optional[str] = None
139
+ field_b: Optional[str] = None
140
+
141
+ # Dict-based
142
+ MySchema = Schema.from_dict(
143
+ {
144
+ "field-a": Optional[str],
145
+ "field-b": Optional[str],
146
+ },
147
+ exclusive=[["field_a", "field_b"]],
148
+ )
149
+
150
+ ``exclusive`` takes a list of groups, where each group is a list of field
151
+ names (Python ``snake_case``). A validation error is raised if more than one
152
+ field in a group is set.
153
+
154
+ .. note::
155
+ When using ``exclusive`` with the dict-based approach, refer to fields by
156
+ their Python attribute names (``snake_case``), not their YAML keys.
@@ -10,6 +10,7 @@ A collection of how-to guides.
10
10
  run-locally
11
11
  debugging
12
12
  bootstrap-taskgraph
13
+ define-schemas
13
14
  resolve-keyed-by
14
15
  use-fetches
15
16
  docker
@@ -3,6 +3,21 @@ Migration Guide
3
3
 
4
4
  This page can help when migrating Taskgraph across major versions.
5
5
 
6
+ 22.x -> 23.x
7
+ ------------
8
+
9
+ * :func:`taskgraph.parameters.extend_parameters_schema` now requires a msgspec
10
+ ``Schema`` subclass instead of a voluptuous schema dict. Convert any custom
11
+ parameter schemas to msgspec.
12
+
13
+ 21.x -> 22.x
14
+ ------------
15
+
16
+ * If you have tasks using `docker-worker`'s `relengapi-proxy` feature, it is no
17
+ longer supported. Remove all references to it in your task definitions.
18
+ * Remove references to `<REPO>_EXTRA_REFS` in all `run-task` based tasks. These
19
+ refs must now be fetched as part of the task payload.
20
+
6
21
  20.x -> 21.x
7
22
  ------------
8
23
 
@@ -1,7 +1,7 @@
1
1
  ### Project
2
2
  [project]
3
3
  name = "taskcluster-taskgraph"
4
- version = "21.0.0"
4
+ version = "23.0.0"
5
5
  description = "Build taskcluster taskgraphs"
6
6
  readme = "README.rst"
7
7
  authors = [
@@ -94,7 +94,6 @@ source = ["src/taskgraph/", "src/taskgraph/run-task/", "packages", "test"]
94
94
  ### Lint and Format
95
95
  [tool.ruff]
96
96
  extend-exclude = [
97
- "taskcluster/scripts/external_tools",
98
97
  "src/taskgraph/run-task/robustcheckout.py"
99
98
  ]
100
99
  line-length = 88
@@ -273,12 +273,27 @@ def render_actions_json(parameters, graph_config, decision_task_id):
273
273
  artifact.
274
274
  """
275
275
  assert isinstance(parameters, Parameters), "requires instance of Parameters"
276
+
277
+ all_actions = _get_actions(graph_config)
278
+ disabled = set(graph_config["taskgraph"].get("disabled-actions") or [])
279
+ known_cb_names = {action.cb_name for action in all_actions}
280
+ unknown = disabled - known_cb_names
281
+ if unknown:
282
+ raise ValueError(
283
+ "Unknown action(s) in `taskgraph.disabled-actions`: "
284
+ f"{sorted(unknown)}. Known actions: {sorted(known_cb_names)}"
285
+ )
286
+
276
287
  actions = []
277
- for action in sorted(_get_actions(graph_config), key=lambda action: action.order):
288
+ for action in sorted(all_actions, key=lambda action: action.order):
289
+ if action.cb_name in disabled:
290
+ continue
291
+
278
292
  action = action.action_builder(parameters, graph_config, decision_task_id)
279
293
  if action:
280
294
  assert is_json(action), "action must be a JSON compatible object"
281
295
  actions.append(action)
296
+
282
297
  return {
283
298
  "version": 1,
284
299
  "variables": {},
@@ -57,6 +57,9 @@ class TaskgraphConfig(Schema):
57
57
  index_path_regexes: Optional[list[str]] = None
58
58
  # Configuration related to the 'run' transforms.
59
59
  run: Optional[RunConfig] = None
60
+ # List of action `cb_name`s to omit from `actions.json`,
61
+ # e.g. `["retrigger", "retrigger-disabled", "rerun"]`.
62
+ disabled_actions: Optional[list[str]] = None
60
63
 
61
64
  def __post_init__(self):
62
65
  # Validate repositories has at least 1 entry (was All(..., Length(min=1)))
@@ -267,7 +267,7 @@ def get_decision_parameters(graph_config, options):
267
267
  # load extra parameters from vcs note if able
268
268
  note_ref = "refs/notes/decision-parameters"
269
269
  if options.get("allow_parameter_override") and (
270
- note_params := repo.get_note(note_ref)
270
+ note_params := repo.get_note(note_ref, parameters["head_repository"])
271
271
  ):
272
272
  try:
273
273
  note_params = json.loads(note_params)
@@ -10,16 +10,17 @@ from datetime import datetime
10
10
  from io import BytesIO
11
11
  from pprint import pformat
12
12
  from subprocess import CalledProcessError
13
+ from typing import Optional, Union
13
14
  from unittest.mock import Mock
14
15
  from urllib.parse import urlparse
15
16
  from urllib.request import urlopen
16
17
 
17
18
  import mozilla_repo_urls
18
- from voluptuous import ALLOW_EXTRA, Any, Optional, Required, Schema
19
+ import msgspec
19
20
 
20
21
  from taskgraph.util import json, yaml
21
22
  from taskgraph.util.readonlydict import ReadOnlyDict
22
- from taskgraph.util.schema import validate_schema
23
+ from taskgraph.util.schema import Schema, validate_schema
23
24
  from taskgraph.util.taskcluster import find_task_id, get_artifact_url
24
25
  from taskgraph.util.vcs import get_repository
25
26
 
@@ -30,43 +31,50 @@ class ParameterMismatch(Exception):
30
31
 
31
32
  #: Schema for base parameters.
32
33
  #: Please keep this list sorted and in sync with docs/reference/parameters.rst
33
- base_schema = Schema(
34
+ base_schema = Schema.from_dict(
34
35
  {
35
- Required("base_repository"): str,
36
- Optional("base_ref"): str,
37
- Required("base_rev"): str,
38
- Required("build_date"): int,
39
- Required("build_number"): int,
40
- Required("do_not_optimize"): [str],
41
- Required("enable_always_target"): Any(bool, [str]),
42
- Required("existing_tasks"): {str: str},
43
- Required("files_changed"): [str],
44
- Required("filters"): [str],
45
- Required("head_ref"): str,
46
- Required("head_repository"): str,
47
- Required("head_rev"): str,
48
- Required("head_tag"): str,
49
- Required("level"): str,
50
- Required("moz_build_date"): str,
51
- Required("next_version"): Any(str, None),
52
- Required("optimize_strategies"): Any(str, None),
53
- Required("optimize_target_tasks"): bool,
54
- Required("owner"): str,
55
- Required("project"): str,
56
- Required("pushdate"): int,
57
- Required("pushlog_id"): str,
58
- Required("repository_type"): str,
36
+ "base_repository": str,
37
+ "base_ref": Optional[str],
38
+ "base_rev": str,
39
+ "build_date": int,
40
+ "build_number": int,
41
+ "do_not_optimize": list[str],
42
+ "enable_always_target": Union[bool, list[str]],
43
+ "existing_tasks": dict[str, str],
44
+ "files_changed": list[str],
45
+ "filters": list[str],
46
+ "head_ref": str,
47
+ "head_repository": str,
48
+ "head_rev": str,
49
+ "head_tag": str,
50
+ "level": str,
51
+ "moz_build_date": str,
52
+ "next_version": Optional[str],
53
+ "optimize_strategies": Optional[str],
54
+ "optimize_target_tasks": bool,
55
+ "owner": str,
56
+ "project": str,
57
+ "pushdate": int,
58
+ "pushlog_id": str,
59
+ "repository_type": str,
59
60
  # target-kinds is not included, since it should never be
60
61
  # used at run-time
61
- Required("target_tasks_method"): str,
62
- Required("tasks_for"): str,
63
- Required("version"): Any(str, None),
64
- Optional("code-review"): {
65
- Required("phabricator-build-target"): str,
66
- },
67
- }
62
+ "target_tasks_method": str,
63
+ "tasks_for": str,
64
+ "version": Optional[str],
65
+ "code-review": Schema.from_dict(
66
+ {"phabricator-build-target": str},
67
+ name="CodeReviewConfig",
68
+ optional=True,
69
+ ),
70
+ },
71
+ name="BaseParametersSchema",
72
+ forbid_unknown_fields=False,
73
+ kw_only=True,
68
74
  )
69
75
 
76
+ _parameter_extensions: list = []
77
+
70
78
 
71
79
  def get_contents(path):
72
80
  with open(path) as fh:
@@ -83,11 +91,21 @@ def _get_defaults(repo_root=None):
83
91
  repo_path = repo_root or os.getcwd()
84
92
  try:
85
93
  repo = get_repository(repo_path)
86
- except RuntimeError:
87
- # Use fake values if no repo is detected.
88
- repo = Mock(branch="", head_rev="", tool="git")
94
+ # Resolve git-backed attributes eagerly so any subprocess failures
95
+ # (e.g. Windows "dubious ownership" when safe.directory isn't honored)
96
+ # are caught by the except below instead of escaping later.
97
+ branch = repo.branch
98
+ head_rev = repo.head_rev
99
+ tool = repo.tool
100
+ files_changed = repo.get_changed_files("AM")
101
+ except (RuntimeError, CalledProcessError):
102
+ # Use fake values if no repo is detected or git refuses to operate.
103
+ repo = Mock()
89
104
  repo.get_url.return_value = ""
90
- repo.get_changed_files.return_value = []
105
+ branch = ""
106
+ head_rev = ""
107
+ tool = "git"
108
+ files_changed = []
91
109
 
92
110
  try:
93
111
  repo_url = repo.get_url()
@@ -110,11 +128,11 @@ def _get_defaults(repo_root=None):
110
128
  "do_not_optimize": [],
111
129
  "enable_always_target": True,
112
130
  "existing_tasks": {},
113
- "files_changed": lambda: repo.get_changed_files("AM"),
131
+ "files_changed": files_changed,
114
132
  "filters": ["target_tasks_method"],
115
- "head_ref": repo.branch or repo.head_rev,
133
+ "head_ref": branch or head_rev,
116
134
  "head_repository": repo_url,
117
- "head_rev": repo.head_rev,
135
+ "head_rev": head_rev,
118
136
  "head_tag": "",
119
137
  "level": "3",
120
138
  "moz_build_date": datetime.now().strftime("%Y%m%d%H%M%S"),
@@ -125,7 +143,7 @@ def _get_defaults(repo_root=None):
125
143
  "project": project,
126
144
  "pushdate": int(time.time()),
127
145
  "pushlog_id": "0",
128
- "repository_type": repo.tool,
146
+ "repository_type": tool,
129
147
  "target_tasks_method": "default",
130
148
  "tasks_for": "",
131
149
  "version": get_version(repo_path),
@@ -143,19 +161,27 @@ def extend_parameters_schema(schema, defaults_fn=None):
143
161
  graph-configuration.
144
162
 
145
163
  Args:
146
- schema (Schema): The voluptuous.Schema object used to describe extended
147
- parameters.
164
+ schema: A msgspec ``Schema`` subclass describing extended parameters.
148
165
  defaults_fn (function): A function which takes no arguments and returns a
149
166
  dict mapping parameter name to default value in the
150
167
  event strict=False (optional).
151
168
  """
152
- global base_schema
153
169
  global defaults_functions
154
- base_schema = base_schema.extend(schema)
170
+ if not (isinstance(schema, type) and issubclass(schema, msgspec.Struct)):
171
+ raise TypeError(
172
+ "extend_parameters_schema requires a msgspec Schema subclass; "
173
+ f"got {type(schema).__name__}"
174
+ )
175
+ _parameter_extensions.append(schema)
155
176
  if defaults_fn:
156
177
  defaults_functions.append(defaults_fn)
157
178
 
158
179
 
180
+ def _schema_key_names(schema) -> set:
181
+ """Return the data-level field names declared by a parameters schema."""
182
+ return {f.encode_name for f in msgspec.structs.fields(schema)}
183
+
184
+
159
185
  class Parameters(ReadOnlyDict):
160
186
  """An immutable dictionary with nicer KeyError messages on failure"""
161
187
 
@@ -214,11 +240,30 @@ class Parameters(ReadOnlyDict):
214
240
  return kwargs
215
241
 
216
242
  def check(self):
217
- schema = (
218
- base_schema if self.strict else base_schema.extend({}, extra=ALLOW_EXTRA)
219
- )
243
+ data = dict(self.copy())
220
244
  try:
221
- validate_schema(schema, self.copy(), "Invalid parameters:")
245
+ # Validate core fields against just the subset of data owned by the
246
+ # base schema. Extension keys are validated separately below, and a
247
+ # strict-mode check rejects anything unknown to either.
248
+ base_keys = _schema_key_names(base_schema)
249
+ base_data = {k: v for k, v in data.items() if k in base_keys}
250
+ validate_schema(base_schema, base_data, "Invalid parameters:")
251
+
252
+ # Validate each registered extension against the keys it declares.
253
+ allowed = set(base_keys)
254
+ for ext in _parameter_extensions:
255
+ ext_keys = _schema_key_names(ext)
256
+ allowed |= ext_keys
257
+ ext_data = {k: data[k] for k in ext_keys if k in data}
258
+ validate_schema(ext, ext_data, "Invalid parameters:")
259
+
260
+ # Strict mode: reject any data key not covered by base or extensions.
261
+ if self.strict:
262
+ unknown = sorted(set(data) - allowed)
263
+ if unknown:
264
+ raise Exception(
265
+ "Invalid parameters:\nunknown keys: " + ", ".join(unknown)
266
+ )
222
267
  except Exception as e:
223
268
  raise ParameterMismatch(str(e))
224
269
 
@@ -626,7 +626,7 @@ def fetch_and_extract(url, dest_dir, extract=True, sha256=None, size=None):
626
626
  the destination directory.
627
627
  """
628
628
 
629
- basename = urllib.parse.urlparse(url).path.split("/")[-1]
629
+ basename = urllib.parse.unquote(urllib.parse.urlparse(url).path.split("/")[-1])
630
630
  dest_path = dest_dir / basename
631
631
 
632
632
  download_to_path(url, dest_path, sha256=sha256, size=size)
@@ -920,16 +920,17 @@ def command_task_artifacts(args):
920
920
  sha256 = None
921
921
  if fetch.get("verify-hash"):
922
922
  sha256 = get_hash(fetch, root_url)
923
+ encoded_artifact = urllib.parse.quote(fetch["artifact"])
923
924
  if fetch["artifact"].startswith("public/"):
924
925
  path = "task/{task}/artifacts/{artifact}".format(
925
- task=fetch["task"], artifact=fetch["artifact"]
926
+ task=fetch["task"], artifact=encoded_artifact
926
927
  )
927
928
  url = api(root_url, "queue", "v1", path)
928
929
  else:
929
930
  url = ("{proxy_url}/api/queue/v1/task/{task}/artifacts/{artifact}").format(
930
931
  proxy_url=os.environ["TASKCLUSTER_PROXY_URL"],
931
932
  task=fetch["task"],
932
- artifact=fetch["artifact"],
933
+ artifact=encoded_artifact,
933
934
  )
934
935
  downloads.append((url, extdir, fetch["extract"], sha256))
935
936
 
@@ -31,7 +31,7 @@ import time
31
31
  import urllib.error
32
32
  import urllib.request
33
33
  from pathlib import Path
34
- from typing import Dict, List, Optional
34
+ from typing import Dict, Optional
35
35
 
36
36
  SECRET_BASEURL_TPL = "{}/secrets/v1/secret/{{}}".format(
37
37
  os.environ.get("TASKCLUSTER_PROXY_URL", "http://taskcluster").rstrip("/")
@@ -640,7 +640,6 @@ def git_checkout(
640
640
  ssh_key_file: Optional[Path],
641
641
  ssh_known_hosts_file: Optional[Path],
642
642
  shallow: bool = False,
643
- extra_refs: Optional[List[str]] = None,
644
643
  ):
645
644
  assert head_ref or head_rev
646
645
 
@@ -735,14 +734,6 @@ def git_checkout(
735
734
  env=env,
736
735
  )
737
736
 
738
- if extra_refs:
739
- git_fetch(
740
- destination_path,
741
- *[f"{ref}:{ref}" for ref in extra_refs],
742
- remote=head_repo,
743
- env=env,
744
- )
745
-
746
737
  args = [
747
738
  "git",
748
739
  "checkout",
@@ -941,8 +932,6 @@ def collect_vcs_options(args, project, name):
941
932
  head_rev = os.environ.get(f"{env_prefix}_HEAD_REV")
942
933
  pip_requirements = os.environ.get(f"{env_prefix}_PIP_REQUIREMENTS")
943
934
  private_key_secret = os.environ.get(f"{env_prefix}_SSH_SECRET_NAME")
944
- if extra_refs := os.environ.get(f"{env_prefix}_EXTRA_REFS"):
945
- extra_refs = json.loads(extra_refs)
946
935
 
947
936
  store_path = os.environ.get("HG_STORE_PATH")
948
937
 
@@ -976,7 +965,6 @@ def collect_vcs_options(args, project, name):
976
965
  "ssh-secret-name": private_key_secret,
977
966
  "pip-requirements": pip_requirements,
978
967
  "shallow-clone": shallow_clone,
979
- "extra-refs": extra_refs,
980
968
  }
981
969
 
982
970
 
@@ -1026,7 +1014,6 @@ def vcs_checkout_from_args(options):
1026
1014
  ssh_key_file,
1027
1015
  ssh_known_hosts_file,
1028
1016
  shallow=options.get("shallow-clone", False),
1029
- extra_refs=options.get("extra-refs"),
1030
1017
  )
1031
1018
  elif options["repo-type"] == "hg":
1032
1019
  revision = hg_checkout(
@@ -44,13 +44,10 @@ class TaskGraph:
44
44
 
45
45
  def to_json(self):
46
46
  "Return a JSON-able object representing the task graph, as documented"
47
- named_links_dict = self.graph.named_links_dict()
48
47
  # this dictionary may be keyed by label or by taskid, so let's just call it 'key'
49
48
  tasks = {}
50
49
  for key in self.graph.visit_postorder():
51
50
  tasks[key] = self.tasks[key].to_json()
52
- # overwrite dependencies with the information in the taskgraph's edges.
53
- tasks[key]["dependencies"] = named_links_dict.get(key, {})
54
51
  return tasks
55
52
 
56
53
  @classmethod