taskcluster-taskgraph 17.2.0__tar.gz → 17.3.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 (267) hide show
  1. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/.pre-commit-config.yaml +6 -4
  2. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/CHANGELOG.md +20 -0
  3. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/PKG-INFO +2 -2
  4. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/packages/pytest-taskgraph/src/pytest_taskgraph/fixtures/gen.py +14 -1
  5. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/pyproject.toml +2 -2
  6. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/actions/cancel.py +2 -10
  7. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/actions/cancel_all.py +2 -10
  8. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/docker.py +30 -12
  9. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/graph.py +6 -2
  10. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/main.py +22 -0
  11. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/optimize/base.py +1 -0
  12. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/run-task/run-task +5 -4
  13. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/transforms/cached_tasks.py +14 -21
  14. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/transforms/task.py +2 -138
  15. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/taskcluster.py +3 -7
  16. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/verify.py +130 -0
  17. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/kinds/codecov/kind.yml +3 -0
  18. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/kinds/complete/kind.yml +6 -0
  19. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/kinds/test/kind.yml +3 -1
  20. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_docker.py +7 -4
  21. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_graph.py +21 -0
  22. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_main.py +42 -2
  23. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_optimize.py +9 -3
  24. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_transforms_cached_tasks.py +15 -8
  25. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_transforms_task.py +0 -81
  26. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_util_verify.py +89 -14
  27. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/uv.lock +5 -5
  28. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/.codespell-ignore-words.txt +0 -0
  29. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/.github/CODEOWNERS +0 -0
  30. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/.github/dependabot.yml +0 -0
  31. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/.github/workflows/codeql-analysis.yml +0 -0
  32. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/.github/workflows/pre-commit-autoupdate.yml +0 -0
  33. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/.github/workflows/pre-commit.yml +0 -0
  34. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/.github/workflows/pypi-publish.yml +0 -0
  35. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/.gitignore +0 -0
  36. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/.readthedocs.yaml +0 -0
  37. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/.taskcluster.yml +0 -0
  38. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/.yamllint +0 -0
  39. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/CODE_OF_CONDUCT.md +0 -0
  40. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/CONTRIBUTING.rst +0 -0
  41. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/LICENSE +0 -0
  42. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/Makefile +0 -0
  43. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/README.rst +0 -0
  44. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/concepts/index.rst +0 -0
  45. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/concepts/kind.rst +0 -0
  46. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/concepts/loading.rst +0 -0
  47. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/concepts/optimization.rst +0 -0
  48. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/concepts/overview.rst +0 -0
  49. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/concepts/scopes.rst +0 -0
  50. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/concepts/task-graphs.rst +0 -0
  51. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/concepts/transforms.rst +0 -0
  52. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/conf.py +0 -0
  53. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/contributing.rst +0 -0
  54. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/glossary.rst +0 -0
  55. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/howto/bootstrap-taskgraph.rst +0 -0
  56. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/howto/create-actions.rst +0 -0
  57. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/howto/create-tasks.rst +0 -0
  58. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/howto/debugging.rst +0 -0
  59. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/howto/docker.rst +0 -0
  60. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/howto/index.rst +0 -0
  61. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/howto/load-task-locally.rst +0 -0
  62. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/howto/resolve-keyed-by.rst +0 -0
  63. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/howto/run-locally.rst +0 -0
  64. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/howto/send-notifications.rst +0 -0
  65. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/howto/use-fetches.rst +0 -0
  66. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/index.rst +0 -0
  67. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/reference/cli.rst +0 -0
  68. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/reference/index.rst +0 -0
  69. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/reference/migrations.rst +0 -0
  70. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/reference/optimization-strategies.rst +0 -0
  71. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/reference/parameters.rst +0 -0
  72. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/reference/source/modules.rst +0 -0
  73. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/reference/source/taskgraph.actions.rst +0 -0
  74. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/reference/source/taskgraph.loader.rst +0 -0
  75. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/reference/source/taskgraph.optimize.rst +0 -0
  76. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/reference/source/taskgraph.rst +0 -0
  77. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/reference/source/taskgraph.transforms.rst +0 -0
  78. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/reference/source/taskgraph.transforms.run.rst +0 -0
  79. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/reference/source/taskgraph.util.rst +0 -0
  80. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/reference/transforms/chunking.rst +0 -0
  81. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/reference/transforms/from_deps.rst +0 -0
  82. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/reference/transforms/index.rst +0 -0
  83. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/reference/transforms/matrix.rst +0 -0
  84. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/reference/transforms/task_context.rst +0 -0
  85. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/tutorials/connecting-taskcluster.rst +0 -0
  86. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/tutorials/creating-a-task-graph.rst +0 -0
  87. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/tutorials/example-taskcluster.yml +0 -0
  88. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/tutorials/getting-started.rst +0 -0
  89. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/docs/tutorials/index.rst +0 -0
  90. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/make.bat +0 -0
  91. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/packages/pytest-taskgraph/README.md +0 -0
  92. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/packages/pytest-taskgraph/pyproject.toml +0 -0
  93. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/packages/pytest-taskgraph/src/pytest_taskgraph/__init__.py +0 -0
  94. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/packages/pytest-taskgraph/src/pytest_taskgraph/fixtures/vcs.py +0 -0
  95. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/packages/sphinx-taskgraph/README.md +0 -0
  96. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/packages/sphinx-taskgraph/pyproject.toml +0 -0
  97. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/packages/sphinx-taskgraph/src/sphinx_taskgraph/__init__.py +0 -0
  98. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/packages/sphinx-taskgraph/src/sphinx_taskgraph/autoschema.py +0 -0
  99. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/__init__.py +0 -0
  100. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/actions/__init__.py +0 -0
  101. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/actions/add_new_jobs.py +0 -0
  102. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/actions/rebuild_cached_tasks.py +0 -0
  103. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/actions/registry.py +0 -0
  104. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/actions/retrigger.py +0 -0
  105. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/actions/util.py +0 -0
  106. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/config.py +0 -0
  107. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/create.py +0 -0
  108. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/decision.py +0 -0
  109. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/filter_tasks.py +0 -0
  110. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/generator.py +0 -0
  111. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/loader/__init__.py +0 -0
  112. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/loader/default.py +0 -0
  113. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/loader/transform.py +0 -0
  114. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/morph.py +0 -0
  115. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/optimize/__init__.py +0 -0
  116. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/optimize/strategies.py +0 -0
  117. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/parameters.py +0 -0
  118. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/run-task/fetch-content +0 -0
  119. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/run-task/hgrc +0 -0
  120. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/run-task/robustcheckout.py +0 -0
  121. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/target_tasks.py +0 -0
  122. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/task.py +0 -0
  123. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/taskgraph.py +0 -0
  124. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/transforms/__init__.py +0 -0
  125. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/transforms/base.py +0 -0
  126. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/transforms/chunking.py +0 -0
  127. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/transforms/code_review.py +0 -0
  128. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/transforms/docker_image.py +0 -0
  129. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/transforms/fetch.py +0 -0
  130. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/transforms/from_deps.py +0 -0
  131. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/transforms/matrix.py +0 -0
  132. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/transforms/notify.py +0 -0
  133. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/transforms/run/__init__.py +0 -0
  134. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/transforms/run/common.py +0 -0
  135. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/transforms/run/index_search.py +0 -0
  136. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/transforms/run/run_task.py +0 -0
  137. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/transforms/run/toolchain.py +0 -0
  138. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/transforms/task_context.py +0 -0
  139. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/__init__.py +0 -0
  140. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/archive.py +0 -0
  141. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/attributes.py +0 -0
  142. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/cached_tasks.py +0 -0
  143. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/caches.py +0 -0
  144. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/copy.py +0 -0
  145. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/dependencies.py +0 -0
  146. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/docker.py +0 -0
  147. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/hash.py +0 -0
  148. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/json.py +0 -0
  149. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/keyed_by.py +0 -0
  150. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/parameterization.py +0 -0
  151. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/path.py +0 -0
  152. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/python_path.py +0 -0
  153. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/readonlydict.py +0 -0
  154. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/schema.py +0 -0
  155. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/set_name.py +0 -0
  156. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/shell.py +0 -0
  157. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/taskgraph.py +0 -0
  158. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/templates.py +0 -0
  159. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/time.py +0 -0
  160. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/treeherder.py +0 -0
  161. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/vcs.py +0 -0
  162. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/workertypes.py +0 -0
  163. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/src/taskgraph/util/yaml.py +0 -0
  164. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/config.yml +0 -0
  165. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/docker/REGISTRY +0 -0
  166. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/docker/decision/Dockerfile +0 -0
  167. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/docker/decision/HASH +0 -0
  168. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/docker/decision/README.md +0 -0
  169. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/docker/decision/VERSION +0 -0
  170. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/docker/decision/system-setup.sh +0 -0
  171. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/docker/fetch/Dockerfile +0 -0
  172. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/docker/image_builder/README.rst +0 -0
  173. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/docker/index-task/Dockerfile +0 -0
  174. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/docker/index-task/README +0 -0
  175. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/docker/index-task/insert-indexes.js +0 -0
  176. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/docker/index-task/package.json +0 -0
  177. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/docker/index-task/yarn.lock +0 -0
  178. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/docker/python/Dockerfile +0 -0
  179. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/docker/run-task/Dockerfile +0 -0
  180. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/docker/run-task/system-setup.sh +0 -0
  181. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/docker/skopeo/Dockerfile +0 -0
  182. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/docker/skopeo/policy.json +0 -0
  183. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/docker/skopeo/push_image.sh +0 -0
  184. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/kinds/check/kind.yml +0 -0
  185. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/kinds/doc/kind.yml +0 -0
  186. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/kinds/docker-image/kind.yml +0 -0
  187. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/kinds/fetch/kind.yml +0 -0
  188. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/kinds/push-image/kind.yml +0 -0
  189. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/scripts/codecov-upload.py +0 -0
  190. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/scripts/external_tools/tooltool.py +0 -0
  191. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/self_taskgraph/__init__.py +0 -0
  192. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/self_taskgraph/custom_parameters.py +0 -0
  193. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/self_taskgraph/custom_target_tasks.py +0 -0
  194. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/self_taskgraph/transforms/add_pr_route.py +0 -0
  195. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/self_taskgraph/transforms/push_image.py +0 -0
  196. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/test/params/main-repo-pull-request-untrusted.yml +0 -0
  197. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/test/params/main-repo-pull-request.yml +0 -0
  198. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/test/params/main-repo-push.yml +0 -0
  199. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/test/params/main-repo-release-pytest-taskgraph.yml +0 -0
  200. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/taskcluster/test/params/main-repo-release-taskcluster-taskgraph.yml +0 -0
  201. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/template/cookiecutter.json +0 -0
  202. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/template/hooks/post_gen_project.py +0 -0
  203. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/template/{{cookiecutter.project_name}}/taskcluster/config.yml +0 -0
  204. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/template/{{cookiecutter.project_name}}/taskcluster/docker/linux/Dockerfile +0 -0
  205. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/template/{{cookiecutter.project_name}}/taskcluster/kinds/docker-image/kind.yml +0 -0
  206. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/template/{{cookiecutter.project_name}}/taskcluster/kinds/hello/kind.yml +0 -0
  207. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/template/{{cookiecutter.project_name}}/taskcluster/{{cookiecutter.project_slug}}_taskgraph/transforms/hello.py +0 -0
  208. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/template/{{cookiecutter.project_name}}/taskcluster.github.yml +0 -0
  209. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/__init__.py +0 -0
  210. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/automationrelevance.json +0 -0
  211. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/conftest.py +0 -0
  212. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/data/task_context.yml +0 -0
  213. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/data/taskcluster/config.yml +0 -0
  214. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/data/taskcluster/docker/hello-world/Dockerfile +0 -0
  215. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/data/taskcluster/docker/hello-world-tag/Dockerfile +0 -0
  216. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/data/taskcluster/docker/hello-world-tag/REGISTRY +0 -0
  217. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/data/taskcluster/docker/hello-world-tag/VERSION +0 -0
  218. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/data/taskcluster/kinds/docker-image/kind.yml +0 -0
  219. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/data/taskcluster/scripts/toolchain/run.ps1 +0 -0
  220. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/data/taskcluster/scripts/toolchain/run.sh +0 -0
  221. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/data/taskcluster/test_taskgraph/transforms/foo.py +0 -0
  222. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/data/testmod/thing.py +0 -0
  223. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/mockedopen.py +0 -0
  224. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_actions_rebuild_cached_tasks.py +0 -0
  225. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_actions_registry.py +0 -0
  226. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_config.py +0 -0
  227. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_create.py +0 -0
  228. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_decision.py +0 -0
  229. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_generator.py +0 -0
  230. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_morph.py +0 -0
  231. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_optimize_strategies.py +0 -0
  232. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_parameters.py +0 -0
  233. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_scripts_fetch_content.py +0 -0
  234. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_scripts_run_task.py +0 -0
  235. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_target_tasks.py +0 -0
  236. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_taskgraph.py +0 -0
  237. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_transform_chunking.py +0 -0
  238. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_transform_docker_image.py +0 -0
  239. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_transform_task_context.py +0 -0
  240. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_transforms_base.py +0 -0
  241. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_transforms_fetch.py +0 -0
  242. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_transforms_from_deps.py +0 -0
  243. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_transforms_matrix.py +0 -0
  244. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_transforms_notify.py +0 -0
  245. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_transforms_run.py +0 -0
  246. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_transforms_run_run_task.py +0 -0
  247. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_transforms_run_toolchain.py +0 -0
  248. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_util_archive.py +0 -0
  249. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_util_attributes.py +0 -0
  250. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_util_cached_tasks.py +0 -0
  251. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_util_copy.py +0 -0
  252. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_util_dependencies.py +0 -0
  253. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_util_docker.py +0 -0
  254. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_util_json.py +0 -0
  255. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_util_keyed_by.py +0 -0
  256. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_util_parameterization.py +0 -0
  257. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_util_path.py +0 -0
  258. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_util_python_path.py +0 -0
  259. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_util_readonlydict.py +0 -0
  260. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_util_schema.py +0 -0
  261. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_util_taskcluster.py +0 -0
  262. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_util_templates.py +0 -0
  263. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_util_time.py +0 -0
  264. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_util_treeherder.py +0 -0
  265. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_util_vcs.py +0 -0
  266. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.0}/test/test_util_workertypes.py +0 -0
  267. {taskcluster_taskgraph-17.2.0 → taskcluster_taskgraph-17.3.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.13.2
16
+ rev: v0.14.3
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.8.22
22
+ rev: 0.9.7
23
23
  hooks:
24
24
  - id: uv-lock
25
25
  - repo: https://github.com/adrienverge/yamllint.git
@@ -37,15 +37,17 @@ repos:
37
37
  test/test_util_path.py
38
38
  )$
39
39
  - repo: https://github.com/compilerla/conventional-pre-commit
40
- rev: v4.2.0
40
+ rev: v4.3.0
41
41
  hooks:
42
42
  - id: conventional-pre-commit
43
43
  stages: [commit-msg]
44
- # TODO remove 'fetch-content' once Gecko no longer needs to use it with Python 3.8
44
+ # TODO remove 'fetch-content' and 'run-task' once Gecko no longer needs to use
45
+ # them with Python 3.8:
45
46
  # https://bugzilla.mozilla.org/show_bug.cgi?id=1990567#c7
46
47
  exclude: |
47
48
  (?x)^(
48
49
  src/taskgraph/run-task/fetch-content |
49
50
  src/taskgraph/run-task/robustcheckout.py |
51
+ src/taskgraph/run-task/run-task |
50
52
  taskcluster/scripts/external_tools
51
53
  )
@@ -1,5 +1,25 @@
1
1
  # Change Log
2
2
 
3
+ ## [17.3.0] - 2025-11-07
4
+
5
+ ### Added
6
+
7
+ - Support for local volumes to `taskgraph load-task -v host_path:container_path`
8
+
9
+ ### Fixed
10
+
11
+ - `load-task` now takes run-task-{hg,git} into account when checking for run-task
12
+ - Properly detect dependency cycles in the `cached_tasks` transform and raise
13
+ an exception instead of it being an infinite loop
14
+
15
+ ## [17.2.1] - 2025-10-31
16
+
17
+ ### Fixed
18
+
19
+ - Exception when using `run-task` script on Windows
20
+ - `run-task` script temporarily supports Python 3.8 again
21
+ - Optimization phase updates `dependencies` property in `Task` objects
22
+
3
23
  ## [17.2.0] - 2025-10-30
4
24
 
5
25
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: taskcluster-taskgraph
3
- Version: 17.2.0
3
+ Version: 17.3.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
@@ -26,7 +26,7 @@ Requires-Dist: redo>=2.0
26
26
  Requires-Dist: requests>=2.25
27
27
  Requires-Dist: slugid>=2.0
28
28
  Requires-Dist: taskcluster-urls>=11.0
29
- Requires-Dist: taskcluster>=91.0
29
+ Requires-Dist: taskcluster<92.0,>=91.0
30
30
  Requires-Dist: voluptuous>=0.12.1
31
31
  Provides-Extra: load-image
32
32
  Requires-Dist: zstandard; extra == 'load-image'
@@ -32,8 +32,12 @@ def fake_loader(kind, path, config, parameters, loaded_tasks, write_artifacts):
32
32
  "i": i,
33
33
  "metadata": {"name": f"{kind}-t-{i}"},
34
34
  "deadline": "soon",
35
+ "workerType": "linux",
36
+ "provisionerId": "prov",
35
37
  },
36
38
  "dependencies": dependencies,
39
+ "if-dependencies": [],
40
+ "soft-dependencies": [],
37
41
  }
38
42
  if "task-defaults" in config:
39
43
  task = merge(config["task-defaults"], task)
@@ -250,6 +254,7 @@ def make_task(
250
254
  task_id=None,
251
255
  dependencies=None,
252
256
  if_dependencies=None,
257
+ soft_dependencies=None,
253
258
  attributes=None,
254
259
  ):
255
260
  task_def = task_def or {
@@ -258,7 +263,9 @@ def make_task(
258
263
  }
259
264
  task = Task(
260
265
  attributes=attributes or {},
266
+ dependencies=dependencies or {},
261
267
  if_dependencies=if_dependencies or [],
268
+ soft_dependencies=soft_dependencies or [],
262
269
  kind=kind,
263
270
  label=label,
264
271
  task=task_def,
@@ -266,7 +273,13 @@ def make_task(
266
273
  task.optimization = optimization
267
274
  task.task_id = task_id
268
275
  if dependencies is not None:
269
- task.task["dependencies"] = sorted(dependencies)
276
+ # The dependencies dict is converted from a dict to a list during the
277
+ # optimization phase. This is pretty confusing and means this utility
278
+ # might break assumptions about the format of 'dependencies'.
279
+ if isinstance(dependencies, dict):
280
+ task.task["dependencies"] = sorted(dependencies.values())
281
+ else:
282
+ task.task["dependencies"] = sorted(dependencies)
270
283
  return task
271
284
 
272
285
 
@@ -1,7 +1,7 @@
1
1
  ### Project
2
2
  [project]
3
3
  name = "taskcluster-taskgraph"
4
- version = "17.2.0"
4
+ version = "17.3.0"
5
5
  description = "Build taskcluster taskgraphs"
6
6
  readme = "README.rst"
7
7
  authors = [
@@ -29,7 +29,7 @@ dependencies = [
29
29
  "redo>=2.0",
30
30
  "requests>=2.25",
31
31
  "slugid>=2.0",
32
- "taskcluster>=91.0",
32
+ "taskcluster>=91.0,<92.0",
33
33
  "taskcluster-urls>=11.0",
34
34
  "voluptuous>=0.12.1",
35
35
  ]
@@ -5,8 +5,6 @@
5
5
 
6
6
  import logging
7
7
 
8
- import requests
9
-
10
8
  from taskcluster import TaskclusterRestFailure
11
9
  from taskgraph.util.taskcluster import cancel_task
12
10
 
@@ -28,14 +26,8 @@ def cancel_action(parameters, graph_config, input, task_group_id, task_id):
28
26
  # only cancel tasks with the level-specific schedulerId.
29
27
  try:
30
28
  cancel_task(task_id)
31
- except (requests.HTTPError, TaskclusterRestFailure) as e:
32
- status_code = None
33
- if isinstance(e, requests.HTTPError):
34
- status_code = e.response.status_code if e.response else None
35
- elif isinstance(e, TaskclusterRestFailure):
36
- status_code = e.status_code
37
-
38
- if status_code == 409:
29
+ except TaskclusterRestFailure as e:
30
+ if e.status_code == 409:
39
31
  # A 409 response indicates that this task is past its deadline. It
40
32
  # cannot be cancelled at this time, but it's also not running
41
33
  # anymore, so we can ignore this error.
@@ -7,8 +7,6 @@ import logging
7
7
  import os
8
8
  from concurrent import futures
9
9
 
10
- import requests
11
-
12
10
  from taskcluster import TaskclusterRestFailure
13
11
  from taskgraph.util.taskcluster import (
14
12
  CONCURRENCY,
@@ -37,14 +35,8 @@ def cancel_all_action(parameters, graph_config, input, task_group_id, task_id):
37
35
  logger.info(f"Cancelling task {task_id}")
38
36
  try:
39
37
  cancel_task(task_id)
40
- except (requests.HTTPError, TaskclusterRestFailure) as e:
41
- status_code = None
42
- if isinstance(e, requests.HTTPError):
43
- status_code = e.response.status_code if e.response else None
44
- elif isinstance(e, TaskclusterRestFailure):
45
- status_code = e.status_code
46
-
47
- if status_code == 409:
38
+ except TaskclusterRestFailure as e:
39
+ if e.status_code == 409:
48
40
  # A 409 response indicates that this task is past its deadline. It
49
41
  # cannot be cancelled at this time, but it's also not running
50
42
  # anymore, so we can ignore this error.
@@ -38,6 +38,7 @@ from taskgraph.util.taskcluster import (
38
38
  )
39
39
 
40
40
  logger = logging.getLogger(__name__)
41
+ RUN_TASK_RE = re.compile(r"run-task(-(git|hg))?$")
41
42
 
42
43
 
43
44
  def get_image_digest(image_name: str) -> str:
@@ -188,11 +189,11 @@ def build_image(
188
189
 
189
190
  output_dir = temp_dir / "out"
190
191
  output_dir.mkdir()
191
- volumes = {
192
+ volumes = [
192
193
  # TODO write artifacts to tmpdir
193
- str(output_dir): "/workspace/out",
194
- str(image_context): "/workspace/context.tar.gz",
195
- }
194
+ (str(output_dir), "/workspace/out"),
195
+ (str(image_context), "/workspace/context.tar.gz"),
196
+ ]
196
197
 
197
198
  assert label in image_tasks
198
199
  task = image_tasks[label]
@@ -211,7 +212,7 @@ def build_image(
211
212
  parent = task.dependencies["parent"][len("docker-image-") :]
212
213
  parent_tar = temp_dir / "parent.tar"
213
214
  build_image(graph_config, parent, save_image=str(parent_tar))
214
- volumes[str(parent_tar)] = "/workspace/parent.tar"
215
+ volumes.append((str(parent_tar), "/workspace/parent.tar"))
215
216
 
216
217
  task_def["payload"]["env"]["CHOWN_OUTPUT"] = f"{os.getuid()}:{os.getgid()}"
217
218
  load_task(
@@ -418,6 +419,11 @@ def _resolve_image(image: Union[str, dict[str, str]], graph_config: GraphConfig)
418
419
  return load_image_by_task_id(image_task_id)
419
420
 
420
421
 
422
+ def _is_run_task(task_def: dict[str, str]):
423
+ cmd = task_def["payload"].get("command") # type: ignore
424
+ return cmd and re.search(RUN_TASK_RE, cmd[0])
425
+
426
+
421
427
  def load_task(
422
428
  graph_config: GraphConfig,
423
429
  task: Union[str, dict[str, Any]],
@@ -425,7 +431,7 @@ def load_task(
425
431
  user: Optional[str] = None,
426
432
  custom_image: Optional[str] = None,
427
433
  interactive: Optional[bool] = False,
428
- volumes: Optional[dict[str, str]] = None,
434
+ volumes: Optional[list[tuple[str, str]]] = None,
429
435
  ) -> int:
430
436
  """Load and run a task interactively in a Docker container.
431
437
 
@@ -465,9 +471,9 @@ def load_task(
465
471
 
466
472
  return 1
467
473
 
468
- task_command = task_def["payload"].get("command") # type: ignore
469
- if interactive and (not task_command or not task_command[0].endswith("run-task")):
470
- logger.error("Only tasks using `run-task` are supported with interactive!")
474
+ is_run_task = _is_run_task(task_def)
475
+ if interactive and not is_run_task:
476
+ logger.error("Only tasks using `run-task` are supported with --interactive!")
471
477
  return 1
472
478
 
473
479
  try:
@@ -477,6 +483,7 @@ def load_task(
477
483
  logger.exception(e)
478
484
  return 1
479
485
 
486
+ task_command = task_def["payload"].get("command") # type: ignore
480
487
  exec_command = task_cwd = None
481
488
  if interactive:
482
489
  # Remove the payload section of the task's command. This way run-task will
@@ -523,9 +530,20 @@ def load_task(
523
530
  env.update(task_def["payload"].get("env", {})) # type: ignore
524
531
 
525
532
  # run-task expects the worker to mount a volume for each path defined in
526
- # TASKCLUSTER_CACHES, delete them to avoid needing to do the same.
533
+ # TASKCLUSTER_CACHES; delete them to avoid needing to do the same, unless
534
+ # they're passed in as volumes.
527
535
  if "TASKCLUSTER_CACHES" in env:
528
- del env["TASKCLUSTER_CACHES"]
536
+ if volumes:
537
+ caches = env["TASKCLUSTER_CACHES"].split(";")
538
+ caches = [
539
+ cache for cache in caches if any(path == cache for _, path in volumes)
540
+ ]
541
+ else:
542
+ caches = []
543
+ if caches:
544
+ env["TASKCLUSTER_CACHES"] = ";".join(caches)
545
+ else:
546
+ del env["TASKCLUSTER_CACHES"]
529
547
 
530
548
  envfile = None
531
549
  initfile = None
@@ -570,7 +588,7 @@ def load_task(
570
588
  command.extend(["-v", f"{initfile.name}:/builds/worker/.bashrc"])
571
589
 
572
590
  if volumes:
573
- for k, v in volumes.items():
591
+ for k, v in volumes:
574
592
  command.extend(["-v", f"{k}:{v}"])
575
593
 
576
594
  command.append(image_tag)
@@ -97,14 +97,18 @@ class Graph(_Graph):
97
97
  indegree[dependent] -= 1
98
98
  if indegree[dependent] == 0:
99
99
  queue.append(dependent)
100
+ loopy_nodes = {node for node, degree in indegree.items() if degree > 0}
101
+ if loopy_nodes:
102
+ raise Exception(
103
+ f"Dependency loop detected involving the following nodes: {loopy_nodes}"
104
+ )
100
105
 
101
106
  def visit_postorder(self):
102
107
  """
103
108
  Generate a sequence of nodes in postorder, such that every node is
104
109
  visited *after* any nodes it links to.
105
110
 
106
- Behavior is undefined (read: it will hang) if the graph contains a
107
- cycle.
111
+ Raises an exception if the graph contains a cycle.
108
112
  """
109
113
  return self._visit(False)
110
114
 
@@ -792,6 +792,14 @@ def image_digest(args):
792
792
  default="taskcluster",
793
793
  help="Relative path to the root of the Taskgraph definition.",
794
794
  )
795
+ @argument(
796
+ "--volume",
797
+ "-v",
798
+ metavar="HOST_DIR:CONTAINER_DIR",
799
+ default=[],
800
+ action="append",
801
+ help="Mount local path into the container.",
802
+ )
795
803
  def load_task(args):
796
804
  from taskgraph.config import load_graph_config # noqa: PLC0415
797
805
  from taskgraph.docker import load_task # noqa: PLC0415
@@ -806,6 +814,19 @@ def load_task(args):
806
814
  except ValueError:
807
815
  args["task"] = data # assume it is a taskId
808
816
 
817
+ volumes = []
818
+ for vol in args["volume"]:
819
+ if ":" not in vol:
820
+ raise ValueError(
821
+ "Invalid volume specification '{vol}', expected HOST_DIR:CONTAINER_DIR"
822
+ )
823
+ k, v = vol.split(":", 1)
824
+ if not k or not v:
825
+ raise ValueError(
826
+ "Invalid volume specification '{vol}', expected HOST_DIR:CONTAINER_DIR"
827
+ )
828
+ volumes.append((k, v))
829
+
809
830
  root = args["root"]
810
831
  graph_config = load_graph_config(root)
811
832
  return load_task(
@@ -815,6 +836,7 @@ def load_task(args):
815
836
  remove=args["remove"],
816
837
  user=args["user"],
817
838
  custom_image=args["image"],
839
+ volumes=volumes,
818
840
  )
819
841
 
820
842
 
@@ -437,6 +437,7 @@ def get_subgraph(
437
437
  )
438
438
  deps = task.task.setdefault("dependencies", [])
439
439
  deps.extend(sorted(named_task_dependencies.values()))
440
+ task.dependencies.update(named_task_dependencies)
440
441
  tasks_by_taskid[task.task_id] = task
441
442
 
442
443
  # resolve edges to taskIds
@@ -16,12 +16,10 @@ current time to improve log usefulness.
16
16
  import argparse
17
17
  import datetime
18
18
  import errno
19
- import grp
20
19
  import io
21
20
  import json
22
21
  import os
23
22
  import platform
24
- import pwd
25
23
  import re
26
24
  import shutil
27
25
  import socket
@@ -33,7 +31,7 @@ import time
33
31
  import urllib.error
34
32
  import urllib.request
35
33
  from pathlib import Path
36
- from typing import Optional
34
+ from typing import Dict, Optional
37
35
 
38
36
  SECRET_BASEURL_TPL = "{}/secrets/v1/secret/{{}}".format(
39
37
  os.environ.get("TASKCLUSTER_PROXY_URL", "http://taskcluster").rstrip("/")
@@ -311,6 +309,9 @@ def run_command(prefix, args, *, extra_env=None, cwd=None):
311
309
 
312
310
 
313
311
  def get_posix_user_group(user, group):
312
+ import grp # noqa: PLC0415
313
+ import pwd # noqa: PLC0415
314
+
314
315
  try:
315
316
  user_record = pwd.getpwnam(user)
316
317
  except KeyError:
@@ -572,7 +573,7 @@ def git_fetch(
572
573
  remote: str = "origin",
573
574
  tags: bool = False,
574
575
  shallow: bool = False,
575
- env: Optional[dict[str, str]] = None,
576
+ env: Optional[Dict[str, str]] = None,
576
577
  ):
577
578
  args = ["git", "fetch"]
578
579
  if tags:
@@ -3,9 +3,8 @@
3
3
  # file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
4
 
5
5
 
6
- from collections import deque
7
-
8
6
  import taskgraph
7
+ from taskgraph.graph import Graph
9
8
  from taskgraph.transforms.base import TransformSequence
10
9
  from taskgraph.util.cached_tasks import add_optimization
11
10
 
@@ -15,25 +14,19 @@ transforms = TransformSequence()
15
14
  def order_tasks(config, tasks):
16
15
  """Iterate image tasks in an order where parent tasks come first."""
17
16
  kind_prefix = config.kind + "-"
18
-
19
- pending = deque(tasks)
20
- task_labels = {task["label"] for task in pending}
21
- emitted = set()
22
- while True:
23
- try:
24
- task = pending.popleft()
25
- except IndexError:
26
- break
27
- parents = {
28
- task
29
- for task in task.get("dependencies", {}).values()
30
- if task.startswith(kind_prefix)
31
- }
32
- if parents and not emitted.issuperset(parents & task_labels):
33
- pending.append(task)
34
- continue
35
- emitted.add(task["label"])
36
- yield task
17
+ pending = {task["label"]: task for task in tasks}
18
+ nodes = set(pending)
19
+ edges = {
20
+ (label, dep, "")
21
+ for label in pending
22
+ for dep in pending[label].get("dependencies", {}).values()
23
+ if dep.startswith(kind_prefix)
24
+ }
25
+ graph = Graph(nodes, edges)
26
+
27
+ for label in graph.visit_postorder():
28
+ yield pending.pop(label)
29
+ assert not pending
37
30
 
38
31
 
39
32
  def format_task_digest(cached_task):
@@ -11,7 +11,6 @@ complexities of worker implementations, scopes, and treeherder annotations.
11
11
  import functools
12
12
  import hashlib
13
13
  import os
14
- import re
15
14
  import time
16
15
  from copy import deepcopy
17
16
  from dataclasses import dataclass
@@ -20,7 +19,6 @@ from typing import Callable
20
19
 
21
20
  from voluptuous import All, Any, Extra, NotIn, Optional, Required
22
21
 
23
- from taskgraph import MAX_DEPENDENCIES
24
22
  from taskgraph.transforms.base import TransformSequence
25
23
  from taskgraph.util.hash import hash_path
26
24
  from taskgraph.util.keyed_by import evaluate_keyed_by
@@ -44,7 +42,7 @@ RUN_TASK = os.path.join(
44
42
 
45
43
 
46
44
  @functools.cache
47
- def _run_task_suffix():
45
+ def run_task_suffix():
48
46
  """String to append to cache names under control of run-task."""
49
47
  return hash_path(RUN_TASK)[0:20]
50
48
 
@@ -715,7 +713,7 @@ def build_docker_worker_payload(config, task, task_def):
715
713
  cache_version = "v3"
716
714
 
717
715
  if run_task:
718
- suffix = f"{cache_version}-{_run_task_suffix()}"
716
+ suffix = f"{cache_version}-{run_task_suffix()}"
719
717
 
720
718
  if out_of_tree_image:
721
719
  name_hash = hashlib.sha256(
@@ -763,8 +761,6 @@ def build_docker_worker_payload(config, task, task_def):
763
761
  if capabilities:
764
762
  payload["capabilities"] = capabilities
765
763
 
766
- check_caches_are_volumes(task)
767
-
768
764
 
769
765
  @payload_builder(
770
766
  "generic-worker",
@@ -1457,135 +1453,3 @@ def chain_of_trust(config, tasks):
1457
1453
  "task-reference": "<docker-image>"
1458
1454
  }
1459
1455
  yield task
1460
-
1461
-
1462
- @transforms.add
1463
- def check_task_identifiers(config, tasks):
1464
- """Ensures that all tasks have well defined identifiers:
1465
- ``^[a-zA-Z0-9_-]{1,38}$``
1466
- """
1467
- e = re.compile("^[a-zA-Z0-9_-]{1,38}$")
1468
- for task in tasks:
1469
- for attrib in ("workerType", "provisionerId"):
1470
- if not e.match(task["task"][attrib]):
1471
- raise Exception(
1472
- "task {}.{} is not a valid identifier: {}".format(
1473
- task["label"], attrib, task["task"][attrib]
1474
- )
1475
- )
1476
- yield task
1477
-
1478
-
1479
- @transforms.add
1480
- def check_task_dependencies(config, tasks):
1481
- """Ensures that tasks don't have more than 100 dependencies."""
1482
- for task in tasks:
1483
- number_of_dependencies = (
1484
- len(task["dependencies"])
1485
- + len(task["if-dependencies"])
1486
- + len(task["soft-dependencies"])
1487
- )
1488
- if number_of_dependencies > MAX_DEPENDENCIES:
1489
- raise Exception(
1490
- "task {}/{} has too many dependencies ({} > {})".format(
1491
- config.kind,
1492
- task["label"],
1493
- number_of_dependencies,
1494
- MAX_DEPENDENCIES,
1495
- )
1496
- )
1497
- yield task
1498
-
1499
-
1500
- def check_caches_are_volumes(task):
1501
- """Ensures that all cache paths are defined as volumes.
1502
-
1503
- Caches and volumes are the only filesystem locations whose content
1504
- isn't defined by the Docker image itself. Some caches are optional
1505
- depending on the task environment. We want paths that are potentially
1506
- caches to have as similar behavior regardless of whether a cache is
1507
- used. To help enforce this, we require that all paths used as caches
1508
- to be declared as Docker volumes. This check won't catch all offenders.
1509
- But it is better than nothing.
1510
- """
1511
- volumes = set(task["worker"]["volumes"])
1512
- paths = {c["mount-point"] for c in task["worker"].get("caches", [])}
1513
- missing = paths - volumes
1514
-
1515
- if not missing:
1516
- return
1517
-
1518
- raise Exception(
1519
- "task {} (image {}) has caches that are not declared as "
1520
- "Docker volumes: {} "
1521
- "(have you added them as VOLUMEs in the Dockerfile?)".format(
1522
- task["label"], task["worker"]["docker-image"], ", ".join(sorted(missing))
1523
- )
1524
- )
1525
-
1526
-
1527
- @transforms.add
1528
- def check_run_task_caches(config, tasks):
1529
- """Audit for caches requiring run-task.
1530
-
1531
- run-task manages caches in certain ways. If a cache managed by run-task
1532
- is used by a non run-task task, it could cause problems. So we audit for
1533
- that and make sure certain cache names are exclusive to run-task.
1534
-
1535
- IF YOU ARE TEMPTED TO MAKE EXCLUSIONS TO THIS POLICY, YOU ARE LIKELY
1536
- CONTRIBUTING TECHNICAL DEBT AND WILL HAVE TO SOLVE MANY OF THE PROBLEMS
1537
- THAT RUN-TASK ALREADY SOLVES. THINK LONG AND HARD BEFORE DOING THAT.
1538
- """
1539
- re_reserved_caches = re.compile(
1540
- """^
1541
- (checkouts|tooltool-cache)
1542
- """,
1543
- re.VERBOSE,
1544
- )
1545
-
1546
- cache_prefix = "{trust_domain}-level-{level}-".format(
1547
- trust_domain=config.graph_config["trust-domain"],
1548
- level=config.params["level"],
1549
- )
1550
-
1551
- suffix = _run_task_suffix()
1552
-
1553
- for task in tasks:
1554
- payload = task["task"].get("payload", {})
1555
- command = payload.get("command") or [""]
1556
-
1557
- main_command = command[0] if isinstance(command[0], str) else ""
1558
- run_task = main_command.endswith("run-task")
1559
-
1560
- for cache in payload.get("cache", {}).get(
1561
- "task-reference", payload.get("cache", {})
1562
- ):
1563
- if not cache.startswith(cache_prefix):
1564
- raise Exception(
1565
- "{} is using a cache ({}) which is not appropriate "
1566
- "for its trust-domain and level. It should start with {}.".format(
1567
- task["label"], cache, cache_prefix
1568
- )
1569
- )
1570
-
1571
- cache = cache[len(cache_prefix) :]
1572
-
1573
- if not re_reserved_caches.match(cache):
1574
- continue
1575
-
1576
- if not run_task:
1577
- raise Exception(
1578
- f"{task['label']} is using a cache ({cache}) reserved for run-task "
1579
- "change the task to use run-task or use a different "
1580
- "cache name"
1581
- )
1582
-
1583
- if suffix not in cache:
1584
- raise Exception(
1585
- f"{task['label']} is using a cache ({cache}) reserved for run-task "
1586
- "but the cache name is not dependent on the contents "
1587
- "of run-task; change the cache name to conform to the "
1588
- "naming requirements"
1589
- )
1590
-
1591
- yield task
@@ -467,15 +467,11 @@ def get_ancestors(task_ids: Union[list[str], str]) -> dict[str, str]:
467
467
  for task_id in task_ids:
468
468
  try:
469
469
  task_def = get_task_definition(task_id)
470
- except (requests.HTTPError, taskcluster.TaskclusterRestFailure) as e:
470
+ except taskcluster.TaskclusterRestFailure as e:
471
471
  # Task has most likely expired, which means it's no longer a
472
472
  # dependency for the purposes of this function.
473
- if isinstance(e, requests.HTTPError):
474
- if e.response and e.response.status_code == 404:
475
- continue
476
- elif isinstance(e, taskcluster.TaskclusterRestFailure):
477
- if e.status_code == 404:
478
- continue
473
+ if e.status_code == 404:
474
+ continue
479
475
  raise e
480
476
 
481
477
  dependencies = task_def.get("dependencies", [])