taskcluster-taskgraph 5.7.0__tar.gz → 6.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 (135) hide show
  1. {taskcluster-taskgraph-5.7.0/src/taskcluster_taskgraph.egg-info → taskcluster-taskgraph-6.0.0}/PKG-INFO +1 -1
  2. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0/src/taskcluster_taskgraph.egg-info}/PKG-INFO +1 -1
  3. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskcluster_taskgraph.egg-info/SOURCES.txt +2 -0
  4. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/__init__.py +1 -1
  5. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/transforms/from_deps.py +4 -2
  6. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/transforms/job/run_task.py +1 -43
  7. taskcluster-taskgraph-6.0.0/src/taskgraph/transforms/task_context.py +121 -0
  8. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/util/dependencies.py +3 -0
  9. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/util/templates.py +30 -0
  10. taskcluster-taskgraph-6.0.0/test/test_transform_task_context.py +84 -0
  11. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_transforms_job.py +0 -47
  12. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_transforms_job_run_task.py +1 -7
  13. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/LICENSE +0 -0
  14. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/MANIFEST.in +0 -0
  15. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/README.rst +0 -0
  16. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/pyproject.toml +0 -0
  17. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/requirements/base.in +0 -0
  18. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/requirements/base.txt +0 -0
  19. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/requirements/dev.in +0 -0
  20. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/requirements/dev.txt +0 -0
  21. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/requirements/test.in +0 -0
  22. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/requirements/test.txt +0 -0
  23. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/setup.cfg +0 -0
  24. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/setup.py +0 -0
  25. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskcluster_taskgraph.egg-info/dependency_links.txt +0 -0
  26. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskcluster_taskgraph.egg-info/entry_points.txt +0 -0
  27. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskcluster_taskgraph.egg-info/requires.txt +1 -1
  28. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskcluster_taskgraph.egg-info/top_level.txt +0 -0
  29. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/actions/__init__.py +0 -0
  30. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/actions/add_new_jobs.py +0 -0
  31. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/actions/cancel.py +0 -0
  32. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/actions/cancel_all.py +0 -0
  33. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/actions/rebuild_cached_tasks.py +0 -0
  34. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/actions/registry.py +0 -0
  35. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/actions/retrigger.py +0 -0
  36. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/actions/util.py +0 -0
  37. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/config.py +0 -0
  38. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/create.py +0 -0
  39. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/decision.py +0 -0
  40. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/docker.py +0 -0
  41. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/files_changed.py +0 -0
  42. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/filter_tasks.py +0 -0
  43. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/generator.py +0 -0
  44. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/graph.py +0 -0
  45. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/loader/__init__.py +0 -0
  46. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/loader/default.py +0 -0
  47. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/loader/transform.py +0 -0
  48. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/main.py +0 -0
  49. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/morph.py +0 -0
  50. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/optimize/__init__.py +0 -0
  51. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/optimize/base.py +0 -0
  52. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/optimize/strategies.py +0 -0
  53. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/parameters.py +0 -0
  54. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/run-task/fetch-content +0 -0
  55. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/run-task/hgrc +0 -0
  56. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/run-task/robustcheckout.py +0 -0
  57. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/run-task/run-task +0 -0
  58. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/target_tasks.py +0 -0
  59. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/task.py +0 -0
  60. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/taskgraph.py +0 -0
  61. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/transforms/__init__.py +0 -0
  62. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/transforms/base.py +0 -0
  63. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/transforms/cached_tasks.py +0 -0
  64. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/transforms/code_review.py +0 -0
  65. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/transforms/docker_image.py +0 -0
  66. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/transforms/fetch.py +0 -0
  67. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/transforms/job/__init__.py +0 -0
  68. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/transforms/job/common.py +0 -0
  69. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/transforms/job/index_search.py +0 -0
  70. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/transforms/job/toolchain.py +0 -0
  71. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/transforms/notify.py +0 -0
  72. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/transforms/task.py +0 -0
  73. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/util/__init__.py +0 -0
  74. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/util/archive.py +0 -0
  75. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/util/attributes.py +0 -0
  76. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/util/cached_tasks.py +0 -0
  77. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/util/decision.py +0 -0
  78. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/util/docker.py +0 -0
  79. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/util/hash.py +0 -0
  80. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/util/keyed_by.py +0 -0
  81. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/util/memoize.py +0 -0
  82. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/util/parameterization.py +0 -0
  83. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/util/path.py +0 -0
  84. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/util/python_path.py +0 -0
  85. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/util/readonlydict.py +0 -0
  86. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/util/schema.py +0 -0
  87. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/util/shell.py +0 -0
  88. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/util/taskcluster.py +0 -0
  89. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/util/taskgraph.py +0 -0
  90. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/util/time.py +0 -0
  91. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/util/treeherder.py +0 -0
  92. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/util/vcs.py +0 -0
  93. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/util/verify.py +0 -0
  94. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/util/workertypes.py +0 -0
  95. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/src/taskgraph/util/yaml.py +0 -0
  96. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_actions_rebuild_cached_tasks.py +0 -0
  97. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_actions_registry.py +0 -0
  98. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_create.py +0 -0
  99. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_decision.py +0 -0
  100. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_files_changed.py +0 -0
  101. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_generator.py +0 -0
  102. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_graph.py +0 -0
  103. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_main.py +0 -0
  104. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_morph.py +0 -0
  105. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_optimize.py +0 -0
  106. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_optimize_strategies.py +0 -0
  107. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_parameters.py +0 -0
  108. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_scripts_fetch_content.py +0 -0
  109. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_scripts_run_task.py +0 -0
  110. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_target_tasks.py +0 -0
  111. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_taskgraph.py +0 -0
  112. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_transform_docker_image.py +0 -0
  113. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_transforms_base.py +0 -0
  114. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_transforms_fetch.py +0 -0
  115. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_transforms_from_deps.py +0 -0
  116. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_transforms_job_toolchain.py +0 -0
  117. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_transforms_notify.py +0 -0
  118. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_transforms_task.py +0 -0
  119. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_util_attributes.py +0 -0
  120. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_util_dependencies.py +0 -0
  121. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_util_docker.py +0 -0
  122. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_util_memoize.py +0 -0
  123. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_util_parameterization.py +0 -0
  124. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_util_path.py +0 -0
  125. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_util_python_path.py +0 -0
  126. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_util_readonlydict.py +0 -0
  127. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_util_schema.py +0 -0
  128. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_util_taskcluster.py +0 -0
  129. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_util_templates.py +0 -0
  130. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_util_time.py +0 -0
  131. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_util_treeherder.py +0 -0
  132. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_util_vcs.py +0 -0
  133. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_util_verify.py +0 -0
  134. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.0.0}/test/test_util_workertypes.py +0 -0
  135. {taskcluster-taskgraph-5.7.0 → taskcluster-taskgraph-6.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: 5.7.0
3
+ Version: 6.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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: taskcluster-taskgraph
3
- Version: 5.7.0
3
+ Version: 6.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
@@ -57,6 +57,7 @@ src/taskgraph/transforms/fetch.py
57
57
  src/taskgraph/transforms/from_deps.py
58
58
  src/taskgraph/transforms/notify.py
59
59
  src/taskgraph/transforms/task.py
60
+ src/taskgraph/transforms/task_context.py
60
61
  src/taskgraph/transforms/job/__init__.py
61
62
  src/taskgraph/transforms/job/common.py
62
63
  src/taskgraph/transforms/job/index_search.py
@@ -104,6 +105,7 @@ test/test_scripts_run_task.py
104
105
  test/test_target_tasks.py
105
106
  test/test_taskgraph.py
106
107
  test/test_transform_docker_image.py
108
+ test/test_transform_task_context.py
107
109
  test/test_transforms_base.py
108
110
  test/test_transforms_fetch.py
109
111
  test/test_transforms_from_deps.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__ = "5.7.0"
5
+ __version__ = "6.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
@@ -18,7 +18,7 @@ from voluptuous import Any, Extra, Optional, Required
18
18
  from taskgraph.transforms.base import TransformSequence
19
19
  from taskgraph.util.attributes import attrmatch
20
20
  from taskgraph.util.dependencies import GROUP_BY_MAP
21
- from taskgraph.util.schema import Schema
21
+ from taskgraph.util.schema import Schema, validate_schema
22
22
 
23
23
  FROM_DEPS_SCHEMA = Schema(
24
24
  {
@@ -139,7 +139,9 @@ def from_deps(config, tasks):
139
139
  group_by, arg = group_by.popitem()
140
140
  func = GROUP_BY_MAP[group_by]
141
141
  if func.schema:
142
- func.schema(arg)
142
+ validate_schema(
143
+ func.schema, arg, f"Invalid group-by {group_by} argument"
144
+ )
143
145
  groups = func(config, deps, arg)
144
146
  else:
145
147
  func = GROUP_BY_MAP[group_by]
@@ -8,14 +8,13 @@ Support for running jobs that are invoked via the `run-task` script.
8
8
  import dataclasses
9
9
  import os
10
10
 
11
- from voluptuous import Any, Extra, Optional, Required
11
+ from voluptuous import Any, Optional, Required
12
12
 
13
13
  from taskgraph.transforms.job import run_job_using
14
14
  from taskgraph.transforms.job.common import support_vcs_checkout
15
15
  from taskgraph.transforms.task import taskref_or_string
16
16
  from taskgraph.util import path, taskcluster
17
17
  from taskgraph.util.schema import Schema
18
- from taskgraph.util.yaml import load_yaml
19
18
 
20
19
  EXEC_COMMANDS = {
21
20
  "bash": ["bash", "-cx"],
@@ -46,16 +45,6 @@ run_task_schema = Schema(
46
45
  # it will be included in a single argument to the command specified by
47
46
  # `exec-with`.
48
47
  Required("command"): Any([taskref_or_string], taskref_or_string),
49
- # Context to substitute into the command using format string
50
- # substitution (e.g {value}). This is useful if certain aspects of the
51
- # command need to be generated in transforms.
52
- Optional("command-context"): {
53
- # If present, loads a set of context variables from an unnested yaml
54
- # file. If a value is present in both the provided file and directly
55
- # in command-context, the latter will take priority.
56
- Optional("from-file"): str,
57
- Extra: object,
58
- },
59
48
  # What to execute the command with in the event command is a string.
60
49
  Optional("exec-with"): Any(*list(EXEC_COMMANDS)),
61
50
  # Command used to invoke the `run-task` script. Can be used if the script
@@ -137,25 +126,6 @@ def script_url(config, script):
137
126
  return f"{tc_url}/api/queue/v1/task/{task_id}/artifacts/public/{script}"
138
127
 
139
128
 
140
- def substitute_command_context(command_context, command):
141
- from_file = command_context.pop("from-file", None)
142
- full_context = {}
143
- if from_file:
144
- full_context = load_yaml(from_file)
145
- else:
146
- full_context = {}
147
-
148
- full_context.update(command_context)
149
-
150
- if isinstance(command, list):
151
- for i in range(len(command)):
152
- command[i] = command[i].format(**full_context)
153
- else:
154
- command = command.format(**full_context)
155
-
156
- return command
157
-
158
-
159
129
  @run_job_using(
160
130
  "docker-worker", "run-task", schema=run_task_schema, defaults=worker_defaults
161
131
  )
@@ -177,13 +147,6 @@ def docker_worker_run_task(config, job, taskdesc):
177
147
 
178
148
  run_command = run["command"]
179
149
 
180
- if run.get("command-context"):
181
- run_command = substitute_command_context(
182
- run.get("command-context"), run["command"]
183
- )
184
- else:
185
- run_command = run["command"]
186
-
187
150
  # dict is for the case of `{'task-reference': str}`.
188
151
  if isinstance(run_command, str) or isinstance(run_command, dict):
189
152
  exec_cmd = EXEC_COMMANDS[run.pop("exec-with", "bash")]
@@ -250,11 +213,6 @@ def generic_worker_run_task(config, job, taskdesc):
250
213
  exec_cmd = EXEC_COMMANDS[run.pop("exec-with", "bash")]
251
214
  run_command = exec_cmd + [run_command]
252
215
 
253
- if run.get("command-context"):
254
- run_command = substitute_command_context(
255
- run.get("command-context"), run_command
256
- )
257
-
258
216
  if run["run-as-root"]:
259
217
  command.extend(("--user", "root", "--group", "root"))
260
218
  command.append("--")
@@ -0,0 +1,121 @@
1
+ from textwrap import dedent
2
+
3
+ from voluptuous import ALLOW_EXTRA, Any, Optional, Required
4
+
5
+ from taskgraph.transforms.base import TransformSequence
6
+ from taskgraph.util.schema import Schema
7
+ from taskgraph.util.templates import deep_get, substitute
8
+ from taskgraph.util.yaml import load_yaml
9
+
10
+ SCHEMA = Schema(
11
+ {
12
+ Required(
13
+ "task-context",
14
+ description=dedent(
15
+ """
16
+ `task-context` can be used to substitute values into any field in a
17
+ task with data that is not known until `taskgraph` runs.
18
+
19
+ This data can be provided via `from-parameters` or `from-file`,
20
+ which can pull in values from parameters and a defined yml file
21
+ respectively.
22
+
23
+ Data may also be provided directly in the `from-object` section of
24
+ `task-context`. This can be useful in `kinds` that define most of
25
+ their contents in `task-defaults`, but have some values that may
26
+ differ for various concrete `tasks` in the `kind`.
27
+
28
+ If the same key is found in multiple places the order of precedence
29
+ is as follows:
30
+ - Parameters
31
+ - `from-object` keys
32
+ - File
33
+
34
+ That is to say: parameters will always override anything else.
35
+
36
+ """.lstrip(),
37
+ ),
38
+ ): {
39
+ Optional(
40
+ "from-parameters",
41
+ description=dedent(
42
+ """
43
+ Retrieve task context values from parameters. A single
44
+ parameter may be provided or a list of parameters in
45
+ priority order. The latter can be useful in implementing a
46
+ "default" value if some other parameter is not provided.
47
+ """.lstrip()
48
+ ),
49
+ ): {str: Any([str], str)},
50
+ Optional(
51
+ "from-file",
52
+ description=dedent(
53
+ """
54
+ Retrieve task context values from a yaml file. The provided
55
+ file should usually only contain top level keys and values
56
+ (eg: nested objects will not be interpolated - they will be
57
+ substituted as text representations of the object).
58
+ """.lstrip()
59
+ ),
60
+ ): str,
61
+ Optional(
62
+ "from-object",
63
+ description="Key/value pairs to be used as task context",
64
+ ): object,
65
+ Required(
66
+ "substitution-fields",
67
+ description=dedent(
68
+ """
69
+ A list of fields in the task to substitute the provided values
70
+ into.
71
+ """.lstrip()
72
+ ),
73
+ ): [str],
74
+ },
75
+ },
76
+ extra=ALLOW_EXTRA,
77
+ )
78
+
79
+ transforms = TransformSequence()
80
+ transforms.add_validate(SCHEMA)
81
+
82
+
83
+ @transforms.add
84
+ def render_task(config, jobs):
85
+ for job in jobs:
86
+ sub_config = job.pop("task-context")
87
+ params_context = {}
88
+ for var, path in sub_config.pop("from-parameters", {}).items():
89
+ if isinstance(path, str):
90
+ params_context[var] = deep_get(config.params, path)
91
+ else:
92
+ for choice in path:
93
+ value = deep_get(config.params, choice)
94
+ if value is not None:
95
+ params_context[var] = value
96
+ break
97
+
98
+ file_context = {}
99
+ from_file = sub_config.pop("from-file", None)
100
+ if from_file:
101
+ file_context = load_yaml(from_file)
102
+
103
+ fields = sub_config.pop("substitution-fields")
104
+
105
+ subs = {}
106
+ subs.update(file_context)
107
+ # We've popped away the configuration; everything left in `sub_config` is
108
+ # substitution key/value pairs.
109
+ subs.update(sub_config.pop("from-object", {}))
110
+ subs.update(params_context)
111
+
112
+ # Now that we have our combined context, we can substitute.
113
+ for field in fields:
114
+ container, subfield = job, field
115
+ while "." in subfield:
116
+ f, subfield = subfield.split(".", 1)
117
+ container = container[f]
118
+
119
+ container[subfield] = substitute(container[subfield], **subs)
120
+
121
+ yield job
@@ -14,6 +14,9 @@ GROUP_BY_MAP = {}
14
14
 
15
15
  def group_by(name, schema=None):
16
16
  def wrapper(func):
17
+ assert (
18
+ name not in GROUP_BY_MAP
19
+ ), f"duplicate group_by function name {name} ({func} and {GROUP_BY_MAP[name]})"
17
20
  GROUP_BY_MAP[name] = func
18
21
  func.schema = schema
19
22
  return func
@@ -48,3 +48,33 @@ def merge(*objects):
48
48
  if len(objects) == 1:
49
49
  return copy.deepcopy(objects[0])
50
50
  return merge_to(objects[-1], merge(*objects[:-1]))
51
+
52
+
53
+ def deep_get(dict_, field):
54
+ container, subfield = dict_, field
55
+ while "." in subfield:
56
+ f, subfield = subfield.split(".", 1)
57
+ if f not in container:
58
+ return None
59
+
60
+ container = container[f]
61
+
62
+ return container.get(subfield)
63
+
64
+
65
+ def substitute(item, **subs):
66
+ if isinstance(item, list):
67
+ for i in range(len(item)):
68
+ item[i] = substitute(item[i], **subs)
69
+ elif isinstance(item, dict):
70
+ new_dict = {}
71
+ for k, v in item.items():
72
+ k = k.format(**subs)
73
+ new_dict[k] = substitute(v, **subs)
74
+ item = new_dict
75
+ elif isinstance(item, str):
76
+ item = item.format(**subs)
77
+ else:
78
+ item = item
79
+
80
+ return item
@@ -0,0 +1,84 @@
1
+ """
2
+ Tests for the 'fetch' transforms.
3
+ """
4
+
5
+ import os.path
6
+ from copy import deepcopy
7
+ from pprint import pprint
8
+
9
+ from taskgraph.transforms import task_context
10
+ from taskgraph.transforms.base import TransformConfig
11
+
12
+ from .conftest import FakeParameters
13
+
14
+ here = os.path.abspath(os.path.dirname(__file__))
15
+
16
+ TASK_DEFAULTS = {
17
+ "description": "fake description {object} {file} {param} {object_and_file}"
18
+ "{object_and_param} {file_and_param} {object_file_and_param} {param_fallback}",
19
+ "name": "fake-task-name",
20
+ "task-context": {
21
+ "from-parameters": {
22
+ "param": "param",
23
+ "object_and_param": "object_and_param",
24
+ "file_and_param": "file_and_param",
25
+ "object_file_and_param": "object_file_and_param",
26
+ "param_fallback": ["missing-param", "default"],
27
+ },
28
+ "from-file": f"{here}/data/task_context.yml",
29
+ "from-object": {
30
+ "object": "object",
31
+ "object_and_param": "shouldn't be used",
32
+ "object_and_file": "object-overrides-file",
33
+ "object_file_and_param": "shouldn't be used",
34
+ },
35
+ "substitution-fields": [
36
+ "description",
37
+ ],
38
+ },
39
+ }
40
+
41
+
42
+ def test_transforms(request, run_transform, graph_config):
43
+ task = deepcopy(TASK_DEFAULTS)
44
+
45
+ params = FakeParameters(
46
+ {
47
+ "param": "param",
48
+ "object_and_param": "param-overrides-object",
49
+ "file_and_param": "param-overrides-file",
50
+ "object_file_and_param": "param-overrides-all",
51
+ "default": "default",
52
+ "base_repository": "http://hg.example.com",
53
+ "build_date": 0,
54
+ "build_number": 1,
55
+ "enable_always_target": True,
56
+ "head_repository": "http://hg.example.com",
57
+ "head_rev": "abcdef",
58
+ "head_ref": "default",
59
+ "level": "1",
60
+ "moz_build_date": 0,
61
+ "next_version": "1.0.1",
62
+ "owner": "some-owner",
63
+ "project": "some-project",
64
+ "pushlog_id": 1,
65
+ "repository_type": "hg",
66
+ "target_tasks_method": "test_method",
67
+ "tasks_for": "hg-push",
68
+ "try_mode": None,
69
+ "version": "1.0.0",
70
+ },
71
+ )
72
+ transform_config = TransformConfig(
73
+ "test", str(here), {}, params, {}, graph_config, write_artifacts=False
74
+ )
75
+
76
+ task = run_transform(task_context.transforms, task, config=transform_config)[0]
77
+ print("Dumping task:")
78
+ pprint(task, indent=2)
79
+
80
+ assert (
81
+ task["description"]
82
+ == "fake description object file param object-overrides-file"
83
+ "param-overrides-object param-overrides-file param-overrides-all default"
84
+ )
@@ -14,15 +14,12 @@ from unittest.mock import patch
14
14
  import pytest
15
15
 
16
16
  # prevent pytest thinking this is a test
17
- from taskcluster_urls import test_root_url as _test_root_url
18
-
19
17
  from taskgraph.task import Task
20
18
  from taskgraph.transforms import job
21
19
  from taskgraph.transforms.job import run_task # noqa: F401
22
20
  from taskgraph.transforms.job.common import add_cache
23
21
  from taskgraph.transforms.task import payload_builders
24
22
  from taskgraph.util.schema import Schema, validate_schema
25
- from taskgraph.util.taskcluster import get_root_url
26
23
  from taskgraph.util.templates import merge
27
24
 
28
25
  here = os.path.abspath(os.path.dirname(__file__))
@@ -88,50 +85,6 @@ def test_worker_caches(task, transform):
88
85
  validate_schema(partial_schema, taskdesc["worker"][key], "validation error")
89
86
 
90
87
 
91
- @pytest.mark.parametrize(
92
- "workerfn", [fn for fn, *_ in job.registry["run-task"].values()]
93
- )
94
- @pytest.mark.parametrize(
95
- "task",
96
- (
97
- {
98
- "worker-type": "t-linux",
99
- "run": {
100
- "checkout": True,
101
- "comm-checkout": False,
102
- "command": "echo '{output}'",
103
- "command-context": {"output": "hello", "extra": None},
104
- "run-as-root": False,
105
- "sparse-profile": False,
106
- "tooltool-downloads": False,
107
- },
108
- },
109
- ),
110
- )
111
- def test_run_task_command_context(task, transform, workerfn, monkeypatch):
112
- if "TASKCLUSTER_ROOT_URL" not in os.environ:
113
- monkeypatch.setenv("TASKCLUSTER_ROOT_URL", _test_root_url())
114
- # Clear memoized function
115
- get_root_url.clear()
116
-
117
- config, job_, taskdesc, _ = transform(task)
118
- job_ = deepcopy(job_)
119
-
120
- def assert_cmd(expected):
121
- cmd = taskdesc["worker"]["command"]
122
- while isinstance(cmd, list):
123
- cmd = cmd[-1]
124
- assert cmd == expected
125
-
126
- workerfn(config, job_, taskdesc)
127
- assert_cmd("echo 'hello'")
128
-
129
- job_copy = job_.copy()
130
- del job_copy["run"]["command-context"]
131
- workerfn(config, job_copy, taskdesc)
132
- assert_cmd("echo '{output}'")
133
-
134
-
135
88
  def assert_use_fetches_toolchain_env(task):
136
89
  assert task["worker"]["env"]["FOO"] == "1"
137
90
 
@@ -20,13 +20,7 @@ TASK_DEFAULTS = {
20
20
  "os": "linux",
21
21
  "env": {},
22
22
  },
23
- "run": {
24
- "using": "run-task",
25
- "command": "echo hello {extra_string}",
26
- "command-context": {
27
- "from-file": f"{here}/data/command_context.yaml",
28
- },
29
- },
23
+ "run": {"using": "run-task", "command": "echo hello world"},
30
24
  }
31
25
 
32
26
 
@@ -1,8 +1,8 @@
1
+ PyYAML>=5.3.1
1
2
  appdirs>=1.4
2
3
  cookiecutter~=2.1
3
4
  json-e>=2.7
4
5
  mozilla-repo-urls
5
- PyYAML>=5.3.1
6
6
  redo>=2.0
7
7
  requests>=2.25
8
8
  requests_unixsocket>=0.2