taskcluster-taskgraph 8.2.0__tar.gz → 9.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 (140) hide show
  1. {taskcluster-taskgraph-8.2.0/src/taskcluster_taskgraph.egg-info → taskcluster-taskgraph-9.0.0}/PKG-INFO +1 -1
  2. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/pyproject.toml +4 -2
  3. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0/src/taskcluster_taskgraph.egg-info}/PKG-INFO +1 -1
  4. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskcluster_taskgraph.egg-info/SOURCES.txt +2 -1
  5. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/__init__.py +1 -1
  6. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/actions/registry.py +4 -4
  7. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/docker.py +2 -2
  8. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/transforms/base.py +2 -2
  9. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/transforms/cached_tasks.py +7 -0
  10. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/transforms/fetch.py +3 -8
  11. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/transforms/run/toolchain.py +5 -5
  12. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/transforms/task.py +7 -9
  13. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/util/archive.py +2 -2
  14. taskcluster-taskgraph-9.0.0/src/taskgraph/util/copy.py +47 -0
  15. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/util/docker.py +6 -6
  16. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/util/hash.py +5 -5
  17. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/util/taskcluster.py +4 -5
  18. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/util/templates.py +15 -6
  19. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/util/verify.py +19 -1
  20. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/util/workertypes.py +3 -3
  21. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_actions_registry.py +1 -2
  22. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_transforms_cached_tasks.py +50 -0
  23. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_transforms_run_toolchain.py +17 -0
  24. taskcluster-taskgraph-9.0.0/test/test_util_copy.py +34 -0
  25. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_util_templates.py +21 -1
  26. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_util_verify.py +38 -0
  27. taskcluster-taskgraph-8.2.0/src/taskgraph/util/memoize.py +0 -7
  28. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/LICENSE +0 -0
  29. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/MANIFEST.in +0 -0
  30. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/README.rst +0 -0
  31. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/requirements/base.in +0 -0
  32. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/requirements/base.txt +0 -0
  33. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/requirements/dev.in +0 -0
  34. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/requirements/dev.txt +0 -0
  35. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/requirements/test.in +0 -0
  36. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/requirements/test.txt +0 -0
  37. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/setup.cfg +0 -0
  38. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/setup.py +0 -0
  39. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskcluster_taskgraph.egg-info/dependency_links.txt +0 -0
  40. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskcluster_taskgraph.egg-info/entry_points.txt +0 -0
  41. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskcluster_taskgraph.egg-info/requires.txt +0 -0
  42. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskcluster_taskgraph.egg-info/top_level.txt +0 -0
  43. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/actions/__init__.py +0 -0
  44. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/actions/add_new_jobs.py +0 -0
  45. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/actions/cancel.py +0 -0
  46. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/actions/cancel_all.py +0 -0
  47. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/actions/rebuild_cached_tasks.py +0 -0
  48. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/actions/retrigger.py +0 -0
  49. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/actions/util.py +0 -0
  50. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/config.py +0 -0
  51. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/create.py +0 -0
  52. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/decision.py +0 -0
  53. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/filter_tasks.py +0 -0
  54. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/generator.py +0 -0
  55. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/graph.py +0 -0
  56. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/loader/__init__.py +0 -0
  57. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/loader/default.py +0 -0
  58. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/loader/transform.py +0 -0
  59. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/main.py +0 -0
  60. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/morph.py +0 -0
  61. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/optimize/__init__.py +0 -0
  62. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/optimize/base.py +0 -0
  63. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/optimize/strategies.py +0 -0
  64. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/parameters.py +0 -0
  65. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/run-task/fetch-content +0 -0
  66. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/run-task/hgrc +0 -0
  67. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/run-task/robustcheckout.py +0 -0
  68. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/run-task/run-task +0 -0
  69. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/target_tasks.py +0 -0
  70. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/task.py +0 -0
  71. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/taskgraph.py +0 -0
  72. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/transforms/__init__.py +0 -0
  73. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/transforms/chunking.py +0 -0
  74. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/transforms/code_review.py +0 -0
  75. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/transforms/docker_image.py +0 -0
  76. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/transforms/from_deps.py +0 -0
  77. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/transforms/notify.py +0 -0
  78. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/transforms/run/__init__.py +0 -0
  79. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/transforms/run/common.py +0 -0
  80. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/transforms/run/index_search.py +0 -0
  81. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/transforms/run/run_task.py +0 -0
  82. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/transforms/task_context.py +0 -0
  83. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/util/__init__.py +0 -0
  84. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/util/attributes.py +0 -0
  85. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/util/cached_tasks.py +0 -0
  86. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/util/dependencies.py +0 -0
  87. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/util/keyed_by.py +0 -0
  88. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/util/parameterization.py +0 -0
  89. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/util/path.py +0 -0
  90. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/util/python_path.py +0 -0
  91. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/util/readonlydict.py +0 -0
  92. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/util/schema.py +0 -0
  93. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/util/set_name.py +0 -0
  94. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/util/shell.py +0 -0
  95. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/util/taskgraph.py +0 -0
  96. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/util/time.py +0 -0
  97. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/util/treeherder.py +0 -0
  98. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/util/vcs.py +0 -0
  99. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/src/taskgraph/util/yaml.py +0 -0
  100. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_actions_rebuild_cached_tasks.py +0 -0
  101. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_create.py +0 -0
  102. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_decision.py +0 -0
  103. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_docker.py +0 -0
  104. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_generator.py +0 -0
  105. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_graph.py +0 -0
  106. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_main.py +0 -0
  107. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_morph.py +0 -0
  108. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_optimize.py +0 -0
  109. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_optimize_strategies.py +1 -1
  110. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_parameters.py +0 -0
  111. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_scripts_fetch_content.py +0 -0
  112. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_scripts_run_task.py +0 -0
  113. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_target_tasks.py +0 -0
  114. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_taskgraph.py +0 -0
  115. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_transform_chunking.py +0 -0
  116. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_transform_docker_image.py +0 -0
  117. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_transform_task_context.py +0 -0
  118. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_transforms_base.py +0 -0
  119. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_transforms_fetch.py +0 -0
  120. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_transforms_from_deps.py +0 -0
  121. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_transforms_notify.py +0 -0
  122. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_transforms_run.py +0 -0
  123. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_transforms_run_run_task.py +0 -0
  124. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_transforms_task.py +0 -0
  125. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_util_archive.py +0 -0
  126. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_util_attributes.py +0 -0
  127. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_util_cached_tasks.py +0 -0
  128. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_util_dependencies.py +0 -0
  129. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_util_docker.py +0 -0
  130. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_util_parameterization.py +0 -0
  131. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_util_path.py +0 -0
  132. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_util_python_path.py +0 -0
  133. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_util_readonlydict.py +0 -0
  134. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_util_schema.py +0 -0
  135. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_util_taskcluster.py +0 -0
  136. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_util_time.py +0 -0
  137. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_util_treeherder.py +0 -0
  138. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_util_vcs.py +0 -0
  139. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_util_workertypes.py +0 -0
  140. {taskcluster-taskgraph-8.2.0 → taskcluster-taskgraph-9.0.0}/test/test_util_yaml.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: taskcluster-taskgraph
3
- Version: 8.2.0
3
+ Version: 9.0.0
4
4
  Summary: Build taskcluster taskgraphs
5
5
  Home-page: https://github.com/taskcluster/taskgraph
6
6
  Classifier: Development Status :: 5 - Production/Stable
@@ -13,6 +13,9 @@ branch = true
13
13
  source = ["src/taskgraph/", "taskgraph", "src/taskgraph/run-task/"]
14
14
 
15
15
  [tool.ruff]
16
+ target-version = "py38"
17
+
18
+ [tool.ruff.lint]
16
19
  select = [
17
20
  "E", "W", # pycodestyle
18
21
  "F", # pyflakes
@@ -25,9 +28,8 @@ ignore = [
25
28
  "E501", # let black handle line-length
26
29
  "E741",
27
30
  ]
28
- target-version = "py38"
29
31
 
30
- [tool.ruff.isort]
32
+ [tool.ruff.lint.isort]
31
33
  known-first-party = ["taskgraph"]
32
34
 
33
35
  [tool.pyright]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: taskcluster-taskgraph
3
- Version: 8.2.0
3
+ Version: 9.0.0
4
4
  Summary: Build taskcluster taskgraphs
5
5
  Home-page: https://github.com/taskcluster/taskgraph
6
6
  Classifier: Development Status :: 5 - Production/Stable
@@ -67,11 +67,11 @@ src/taskgraph/util/__init__.py
67
67
  src/taskgraph/util/archive.py
68
68
  src/taskgraph/util/attributes.py
69
69
  src/taskgraph/util/cached_tasks.py
70
+ src/taskgraph/util/copy.py
70
71
  src/taskgraph/util/dependencies.py
71
72
  src/taskgraph/util/docker.py
72
73
  src/taskgraph/util/hash.py
73
74
  src/taskgraph/util/keyed_by.py
74
- src/taskgraph/util/memoize.py
75
75
  src/taskgraph/util/parameterization.py
76
76
  src/taskgraph/util/path.py
77
77
  src/taskgraph/util/python_path.py
@@ -119,6 +119,7 @@ test/test_transforms_task.py
119
119
  test/test_util_archive.py
120
120
  test/test_util_attributes.py
121
121
  test/test_util_cached_tasks.py
122
+ test/test_util_copy.py
122
123
  test/test_util_dependencies.py
123
124
  test/test_util_docker.py
124
125
  test/test_util_parameterization.py
@@ -2,7 +2,7 @@
2
2
  # License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  # file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
4
 
5
- __version__ = "8.2.0"
5
+ __version__ = "9.0.0"
6
6
 
7
7
  # Maximum number of dependencies a single task can have
8
8
  # https://docs.taskcluster.net/reference/platform/taskcluster-queue/references/api#createTask
@@ -3,6 +3,7 @@
3
3
  # file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
4
 
5
5
 
6
+ import functools
6
7
  import json
7
8
  from collections import namedtuple
8
9
  from types import FunctionType
@@ -13,7 +14,6 @@ from taskgraph import create
13
14
  from taskgraph.config import load_graph_config
14
15
  from taskgraph.parameters import Parameters
15
16
  from taskgraph.util import hash, taskcluster, yaml
16
- from taskgraph.util.memoize import memoize
17
17
  from taskgraph.util.python_path import import_sibling_modules
18
18
 
19
19
  actions = []
@@ -31,13 +31,13 @@ def is_json(data):
31
31
  return True
32
32
 
33
33
 
34
- @memoize
34
+ @functools.lru_cache(maxsize=None)
35
35
  def read_taskcluster_yml(filename):
36
- """Load and parse .taskcluster.yml, memoized to save some time"""
36
+ """Load and parse .taskcluster.yml, cached to save some time"""
37
37
  return yaml.load_yaml(filename)
38
38
 
39
39
 
40
- @memoize
40
+ @functools.lru_cache(maxsize=None)
41
41
  def hash_taskcluster_yml(filename):
42
42
  """
43
43
  Generate a hash of the given .taskcluster.yml. This is the first 10 digits
@@ -102,7 +102,7 @@ def build_context(name, outputFile, args=None):
102
102
 
103
103
  image_dir = docker.image_path(name)
104
104
  if not os.path.isdir(image_dir):
105
- raise Exception("image directory does not exist: %s" % image_dir)
105
+ raise Exception(f"image directory does not exist: {image_dir}")
106
106
 
107
107
  docker.create_context_tar(".", image_dir, outputFile, args)
108
108
 
@@ -117,7 +117,7 @@ def build_image(name, tag, args=None):
117
117
 
118
118
  image_dir = docker.image_path(name)
119
119
  if not os.path.isdir(image_dir):
120
- raise Exception("image directory does not exist: %s" % image_dir)
120
+ raise Exception(f"image directory does not exist: {image_dir}")
121
121
 
122
122
  tag = tag or docker.docker_image(name, by_tag=True)
123
123
 
@@ -3,6 +3,7 @@
3
3
  # file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
4
 
5
5
 
6
+ import functools
6
7
  import re
7
8
  from dataclasses import dataclass, field
8
9
  from typing import Dict, List, Union
@@ -11,7 +12,6 @@ from taskgraph.task import Task
11
12
 
12
13
  from ..config import GraphConfig
13
14
  from ..parameters import Parameters
14
- from ..util.memoize import memoize
15
15
  from ..util.schema import Schema, validate_schema
16
16
 
17
17
 
@@ -58,7 +58,7 @@ class TransformConfig:
58
58
  write_artifacts: bool
59
59
 
60
60
  @property
61
- @memoize
61
+ @functools.lru_cache(maxsize=None)
62
62
  def repo_configs(self):
63
63
  repositories = self.graph_config["taskgraph"]["repositories"]
64
64
  if len(repositories) == 1:
@@ -77,7 +77,14 @@ def cache_task(config, tasks):
77
77
  task["label"], p
78
78
  )
79
79
  )
80
+
80
81
  digest_data = cache["digest-data"] + sorted(dependency_digests)
82
+
83
+ # Chain of trust affects task artifacts therefore it should influence
84
+ # cache digest.
85
+ if task.get("worker", {}).get("chain-of-trust"):
86
+ digest_data.append(str(task["worker"]["chain-of-trust"]))
87
+
81
88
  add_optimization(
82
89
  config,
83
90
  task,
@@ -128,7 +128,7 @@ def make_task(config, tasks):
128
128
  "name": name,
129
129
  "description": task["description"],
130
130
  "expires-after": task.get("expires-after", expires),
131
- "label": "fetch-%s" % name,
131
+ "label": f"fetch-{name}",
132
132
  "run-on-projects": [],
133
133
  "run": {
134
134
  "using": "run-task",
@@ -265,12 +265,7 @@ def create_fetch_url_task(config, name, fetch):
265
265
  for k, v in fetch["headers"].items():
266
266
  command.extend(["-H", f"{k}:{v}"])
267
267
 
268
- command.extend(
269
- [
270
- fetch["url"],
271
- "/builds/worker/artifacts/%s" % artifact_name,
272
- ]
273
- )
268
+ command.extend([fetch["url"], f"/builds/worker/artifacts/{artifact_name}"])
274
269
 
275
270
  return {
276
271
  "command": command,
@@ -316,7 +311,7 @@ def create_git_fetch_task(config, name, fetch):
316
311
  path_prefix,
317
312
  fetch["repo"],
318
313
  fetch["revision"],
319
- "/builds/worker/artifacts/%s" % artifact_name,
314
+ f"/builds/worker/artifacts/{artifact_name}",
320
315
  ]
321
316
 
322
317
  ssh_key = fetch.get("ssh-key")
@@ -14,6 +14,7 @@ from taskgraph.transforms.run.common import (
14
14
  generic_worker_add_artifacts,
15
15
  get_vcsdir_name,
16
16
  )
17
+ from taskgraph.util import path as mozpath
17
18
  from taskgraph.util.hash import hash_paths
18
19
  from taskgraph.util.schema import Schema
19
20
  from taskgraph.util.shell import quote as shell_quote
@@ -57,7 +58,8 @@ toolchain_run_schema = Schema(
57
58
  def get_digest_data(config, run, taskdesc):
58
59
  files = list(run.pop("resources", []))
59
60
  # The script
60
- files.append("taskcluster/scripts/toolchain/{}".format(run["script"]))
61
+ script = mozpath.join("taskcluster/scripts/toolchain/", run["script"])
62
+ files.append(mozpath.normpath(script))
61
63
 
62
64
  # Accumulate dependency hashes for index generation.
63
65
  data = [hash_paths(config.graph_config.vcs_root, files)]
@@ -126,16 +128,14 @@ def common_toolchain(config, task, taskdesc, is_docker):
126
128
  "digest-data": get_digest_data(config, run, taskdesc),
127
129
  }
128
130
 
129
- script = run.pop("script")
131
+ script = mozpath.join("taskcluster/scripts/toolchain/", run.pop("script"))
130
132
  run["using"] = "run-task"
131
133
  run["cwd"] = "{checkout}/.."
132
134
 
133
135
  if script.endswith(".ps1"):
134
136
  run["exec-with"] = "powershell"
135
137
 
136
- command = [f"{srcdir}/taskcluster/scripts/toolchain/{script}"] + run.pop(
137
- "arguments", []
138
- )
138
+ command = [f"{srcdir}/{mozpath.normpath(script)}"] + run.pop("arguments", [])
139
139
 
140
140
  if not is_docker:
141
141
  # Don't quote the first item in the command because it purposely contains
@@ -9,6 +9,7 @@ complexities of worker implementations, scopes, and treeherder annotations.
9
9
  """
10
10
 
11
11
 
12
+ import functools
12
13
  import hashlib
13
14
  import os
14
15
  import re
@@ -23,7 +24,6 @@ from taskgraph import MAX_DEPENDENCIES
23
24
  from taskgraph.transforms.base import TransformSequence
24
25
  from taskgraph.util.hash import hash_path
25
26
  from taskgraph.util.keyed_by import evaluate_keyed_by
26
- from taskgraph.util.memoize import memoize
27
27
  from taskgraph.util.schema import (
28
28
  OptimizationSchema,
29
29
  Schema,
@@ -43,7 +43,7 @@ RUN_TASK = os.path.join(
43
43
  )
44
44
 
45
45
 
46
- @memoize
46
+ @functools.lru_cache(maxsize=None)
47
47
  def _run_task_suffix():
48
48
  """String to append to cache names under control of run-task."""
49
49
  return hash_path(RUN_TASK)[0:20]
@@ -214,14 +214,14 @@ def get_branch_rev(config):
214
214
  return config.params["head_rev"]
215
215
 
216
216
 
217
- @memoize
217
+ @functools.lru_cache(maxsize=None)
218
218
  def get_default_priority(graph_config, project):
219
219
  return evaluate_keyed_by(
220
220
  graph_config["task-priority"], "Graph Config", {"project": project}
221
221
  )
222
222
 
223
223
 
224
- @memoize
224
+ @functools.lru_cache(maxsize=None)
225
225
  def get_default_deadline(graph_config, project):
226
226
  return evaluate_keyed_by(
227
227
  graph_config["task-deadline-after"], "Graph Config", {"project": project}
@@ -380,10 +380,10 @@ def build_docker_worker_payload(config, task, task_def):
380
380
  for v in sorted(volumes):
381
381
  if v in worker["volumes"]:
382
382
  raise Exception(
383
- "volume %s already defined; "
383
+ f"volume {v} already defined; "
384
384
  "if it is defined in a Dockerfile, "
385
385
  "it does not need to be specified in the "
386
- "worker definition" % v
386
+ "worker definition"
387
387
  )
388
388
 
389
389
  worker["volumes"].append(v)
@@ -544,9 +544,7 @@ def build_docker_worker_payload(config, task, task_def):
544
544
  suffix=suffix,
545
545
  )
546
546
  caches[name] = cache["mount-point"]
547
- task_def["scopes"].append(
548
- {"task-reference": "docker-worker:cache:%s" % name}
549
- )
547
+ task_def["scopes"].append({"task-reference": f"docker-worker:cache:{name}"})
550
548
 
551
549
  # Assertion: only run-task is interested in this.
552
550
  if run_task:
@@ -80,14 +80,14 @@ def create_tar_from_files(fp, files):
80
80
  ti.type = tarfile.REGTYPE
81
81
 
82
82
  if not ti.isreg():
83
- raise ValueError("not a regular file: %s" % f)
83
+ raise ValueError(f"not a regular file: {f}")
84
84
 
85
85
  # Disallow setuid and setgid bits. This is an arbitrary restriction.
86
86
  # However, since we set uid/gid to root:root, setuid and setgid
87
87
  # would be a glaring security hole if the archive were
88
88
  # uncompressed as root.
89
89
  if ti.mode & (stat.S_ISUID | stat.S_ISGID):
90
- raise ValueError("cannot add file with setuid or setgid set: " "%s" % f)
90
+ raise ValueError(f"cannot add file with setuid or setgid set: {f}")
91
91
 
92
92
  # Set uid, gid, username, and group as deterministic values.
93
93
  ti.uid = 0
@@ -0,0 +1,47 @@
1
+ from typing import Any
2
+
3
+ from taskgraph.task import Task
4
+ from taskgraph.util.readonlydict import ReadOnlyDict
5
+
6
+ immutable_types = {int, float, bool, str, type(None), ReadOnlyDict}
7
+
8
+
9
+ def deepcopy(obj: Any) -> Any:
10
+ """Perform a deep copy of an object with a tree like structure.
11
+
12
+ This is a re-implementation of Python's `copy.deepcopy` function with a few key differences:
13
+
14
+ 1. Unlike the stdlib, this does *not* support copying graph-like structure,
15
+ which allows it to be more efficient than deepcopy on tree-like structures
16
+ (such as Tasks).
17
+ 2. This special cases support for `taskgraph.task.Task` objects.
18
+
19
+ Args:
20
+ obj: The object to deep copy.
21
+
22
+ Returns:
23
+ A deep copy of the object.
24
+ """
25
+ ty = type(obj)
26
+ if ty in immutable_types:
27
+ return obj
28
+ if ty is dict:
29
+ return {k: deepcopy(v) for k, v in obj.items()}
30
+ if ty is list:
31
+ return [deepcopy(elt) for elt in obj]
32
+ if ty is Task:
33
+ task = Task(
34
+ kind=deepcopy(obj.kind),
35
+ label=deepcopy(obj.label),
36
+ attributes=deepcopy(obj.attributes),
37
+ task=deepcopy(obj.task),
38
+ description=deepcopy(obj.description),
39
+ optimization=deepcopy(obj.optimization),
40
+ dependencies=deepcopy(obj.dependencies),
41
+ soft_dependencies=deepcopy(obj.soft_dependencies),
42
+ if_dependencies=deepcopy(obj.if_dependencies),
43
+ )
44
+ if obj.task_id:
45
+ task.task_id = obj.task_id
46
+ return task
47
+ raise NotImplementedError(f"copying '{ty}' from '{obj}'")
@@ -3,6 +3,7 @@
3
3
  # file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
4
 
5
5
 
6
+ import functools
6
7
  import hashlib
7
8
  import io
8
9
  import os
@@ -10,7 +11,6 @@ import re
10
11
  from typing import Optional
11
12
 
12
13
  from taskgraph.util.archive import create_tar_gz_from_files
13
- from taskgraph.util.memoize import memoize
14
14
 
15
15
  IMAGE_DIR = os.path.join(".", "taskcluster", "docker")
16
16
 
@@ -177,15 +177,15 @@ def stream_context_tar(topsrcdir, context_dir, out_file, image_name=None, args=N
177
177
 
178
178
  p = line[len("# %include ") :].strip()
179
179
  if os.path.isabs(p):
180
- raise Exception("extra include path cannot be absolute: %s" % p)
180
+ raise Exception(f"extra include path cannot be absolute: {p}")
181
181
 
182
182
  fs_path = os.path.normpath(os.path.join(topsrcdir, p))
183
183
  # Check for filesystem traversal exploits.
184
184
  if not fs_path.startswith(topsrcdir):
185
- raise Exception("extra include path outside topsrcdir: %s" % p)
185
+ raise Exception(f"extra include path outside topsrcdir: {p}")
186
186
 
187
187
  if not os.path.exists(fs_path):
188
- raise Exception("extra include path does not exist: %s" % p)
188
+ raise Exception(f"extra include path does not exist: {p}")
189
189
 
190
190
  if os.path.isdir(fs_path):
191
191
  for root, dirs, files in os.walk(fs_path):
@@ -205,7 +205,7 @@ def stream_context_tar(topsrcdir, context_dir, out_file, image_name=None, args=N
205
205
  return writer.hexdigest()
206
206
 
207
207
 
208
- @memoize
208
+ @functools.lru_cache(maxsize=None)
209
209
  def image_paths():
210
210
  """Return a map of image name to paths containing their Dockerfile."""
211
211
  config = load_yaml("taskcluster", "kinds", "docker-image", "kind.yml")
@@ -222,7 +222,7 @@ def image_path(name):
222
222
  return os.path.join(IMAGE_DIR, name)
223
223
 
224
224
 
225
- @memoize
225
+ @functools.lru_cache(maxsize=None)
226
226
  def parse_volumes(image):
227
227
  """Parse VOLUME entries from a Dockerfile for an image."""
228
228
  volumes = set()
@@ -2,14 +2,14 @@
2
2
  # License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  # file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
4
 
5
+ import functools
5
6
  import hashlib
6
7
  from pathlib import Path
7
8
 
8
9
  from taskgraph.util import path as mozpath
9
- from taskgraph.util.memoize import memoize
10
10
 
11
11
 
12
- @memoize
12
+ @functools.lru_cache(maxsize=None)
13
13
  def hash_path(path):
14
14
  """Hash a single file.
15
15
 
@@ -36,7 +36,7 @@ def hash_paths(base_path, patterns):
36
36
  if matches:
37
37
  found.update(matches)
38
38
  else:
39
- raise Exception("%s did not match anything" % pattern)
39
+ raise Exception(f"{pattern} did not match anything")
40
40
  for path in sorted(found):
41
41
  h.update(
42
42
  f"{hash_path(mozpath.abspath(mozpath.join(base_path, path)))} {mozpath.normsep(path)}\n".encode()
@@ -44,13 +44,13 @@ def hash_paths(base_path, patterns):
44
44
  return h.hexdigest()
45
45
 
46
46
 
47
- @memoize
47
+ @functools.lru_cache(maxsize=None)
48
48
  def _find_matching_files(base_path, pattern):
49
49
  files = _get_all_files(base_path)
50
50
  return [path for path in files if mozpath.match(path, pattern)]
51
51
 
52
52
 
53
- @memoize
53
+ @functools.lru_cache(maxsize=None)
54
54
  def _get_all_files(base_path):
55
55
  return [
56
56
  mozpath.normsep(str(path))
@@ -16,7 +16,6 @@ from requests.packages.urllib3.util.retry import Retry
16
16
 
17
17
  from taskgraph.task import Task
18
18
  from taskgraph.util import yaml
19
- from taskgraph.util.memoize import memoize
20
19
 
21
20
  logger = logging.getLogger(__name__)
22
21
 
@@ -31,7 +30,7 @@ PRODUCTION_TASKCLUSTER_ROOT_URL = None
31
30
  CONCURRENCY = 50
32
31
 
33
32
 
34
- @memoize
33
+ @functools.lru_cache(maxsize=None)
35
34
  def get_root_url(use_proxy):
36
35
  """Get the current TASKCLUSTER_ROOT_URL.
37
36
 
@@ -106,7 +105,7 @@ def requests_retry_session(
106
105
  return session
107
106
 
108
107
 
109
- @memoize
108
+ @functools.lru_cache(maxsize=None)
110
109
  def get_session():
111
110
  return requests_retry_session(retries=5)
112
111
 
@@ -277,7 +276,7 @@ def get_task_url(task_id, use_proxy=False):
277
276
  return task_tmpl.format(task_id)
278
277
 
279
278
 
280
- @memoize
279
+ @functools.lru_cache(maxsize=None)
281
280
  def get_task_definition(task_id, use_proxy=False):
282
281
  response = _do_request(get_task_url(task_id, use_proxy))
283
282
  return response.json()
@@ -446,7 +445,7 @@ def list_task_group_incomplete_tasks(task_group_id):
446
445
  break
447
446
 
448
447
 
449
- @memoize
448
+ @functools.lru_cache(maxsize=None)
450
449
  def _get_deps(task_ids, use_proxy):
451
450
  upstream_tasks = {}
452
451
  for task_id in task_ids:
@@ -2,8 +2,7 @@
2
2
  # License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  # file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
4
 
5
-
6
- import copy
5
+ from taskgraph.util.copy import deepcopy
7
6
 
8
7
 
9
8
  def merge_to(source, dest):
@@ -18,9 +17,19 @@ def merge_to(source, dest):
18
17
  """
19
18
 
20
19
  for key, value in source.items():
20
+ if (
21
+ isinstance(value, dict)
22
+ and len(value) == 1
23
+ and list(value)[0].startswith("by-")
24
+ ):
25
+ # Do not merge by-* values as it will almost certainly not do what
26
+ # the user expects.
27
+ dest[key] = value
28
+ continue
29
+
21
30
  # Override mismatching or empty types
22
31
  if type(value) != type(dest.get(key)): # noqa
23
- dest[key] = source[key]
32
+ dest[key] = value
24
33
  continue
25
34
 
26
35
  # Merge dict
@@ -29,10 +38,10 @@ def merge_to(source, dest):
29
38
  continue
30
39
 
31
40
  if isinstance(value, list):
32
- dest[key] = dest[key] + source[key]
41
+ dest[key] = dest[key] + value
33
42
  continue
34
43
 
35
- dest[key] = source[key]
44
+ dest[key] = value
36
45
 
37
46
  return dest
38
47
 
@@ -46,7 +55,7 @@ def merge(*objects):
46
55
  Returns the result without modifying any arguments.
47
56
  """
48
57
  if len(objects) == 1:
49
- return copy.deepcopy(objects[0])
58
+ return deepcopy(objects[0])
50
59
  return merge_to(objects[-1], merge(*objects[:-1]))
51
60
 
52
61
 
@@ -5,6 +5,7 @@
5
5
 
6
6
  import logging
7
7
  import sys
8
+ import warnings
8
9
  from abc import ABC, abstractmethod
9
10
  from dataclasses import dataclass, field
10
11
  from typing import Callable, Dict, List, Union
@@ -192,7 +193,17 @@ def verify_routes_notification_filters(
192
193
  if task is None:
193
194
  return
194
195
  route_prefix = "notify."
195
- valid_filters = ("on-any", "on-completed", "on-failed", "on-exception")
196
+ valid_filters = (
197
+ "on-any",
198
+ "on-completed",
199
+ "on-defined",
200
+ "on-failed",
201
+ "on-exception",
202
+ "on-pending",
203
+ "on-resolved",
204
+ "on-running",
205
+ "on-transition",
206
+ )
196
207
  task_dict = task.task
197
208
  routes = task_dict.get("routes", [])
198
209
 
@@ -204,6 +215,13 @@ def verify_routes_notification_filters(
204
215
  raise Exception(
205
216
  f"{task.label} has invalid notification filter ({route_filter})"
206
217
  )
218
+ if route_filter == "on-any":
219
+ warnings.warn(
220
+ DeprecationWarning(
221
+ f"notification filter '{route_filter}' is deprecated. Use "
222
+ "'on-transition' or 'on-resolved'."
223
+ )
224
+ )
207
225
 
208
226
 
209
227
  @verifications.add("full_task_graph")
@@ -2,10 +2,10 @@
2
2
  # License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  # file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
4
 
5
+ import functools
5
6
  from dataclasses import dataclass
6
7
 
7
8
  from .keyed_by import evaluate_keyed_by
8
- from .memoize import memoize
9
9
 
10
10
 
11
11
  @dataclass
@@ -29,7 +29,7 @@ _BUILTIN_TYPES = {
29
29
  }
30
30
 
31
31
 
32
- @memoize
32
+ @functools.lru_cache(maxsize=None)
33
33
  def worker_type_implementation(graph_config, worker_type):
34
34
  """Get the worker implementation and OS for the given workerType, where the
35
35
  OS represents the host system, not the target OS, in the case of
@@ -46,7 +46,7 @@ def worker_type_implementation(graph_config, worker_type):
46
46
  return worker_config["implementation"], worker_config.get("os")
47
47
 
48
48
 
49
- @memoize
49
+ @functools.lru_cache(maxsize=None)
50
50
  def get_worker_type(graph_config, alias, level):
51
51
  """
52
52
  Get the worker type based, evaluating aliases from the graph config.
@@ -1,9 +1,8 @@
1
- from test import does_not_raise
2
-
3
1
  import pytest
4
2
  from mozilla_repo_urls import InvalidRepoUrlError
5
3
 
6
4
  from taskgraph.actions import registry
5
+ from test import does_not_raise
7
6
 
8
7
 
9
8
  @pytest.mark.parametrize(