taskcluster-taskgraph 7.2.1__tar.gz → 7.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 (141) hide show
  1. taskcluster-taskgraph-7.3.0/PKG-INFO +112 -0
  2. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/setup.py +4 -0
  3. taskcluster-taskgraph-7.3.0/src/taskcluster_taskgraph.egg-info/PKG-INFO +112 -0
  4. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskcluster_taskgraph.egg-info/SOURCES.txt +1 -0
  5. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/__init__.py +1 -1
  6. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/actions/add_new_jobs.py +1 -1
  7. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/actions/rebuild_cached_tasks.py +1 -1
  8. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/actions/registry.py +20 -8
  9. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/actions/retrigger.py +6 -4
  10. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/actions/util.py +11 -4
  11. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/util/archive.py +46 -6
  12. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_actions_registry.py +11 -5
  13. taskcluster-taskgraph-7.3.0/test/test_util_archive.py +174 -0
  14. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_util_docker.py +0 -7
  15. taskcluster-taskgraph-7.2.1/PKG-INFO +0 -16
  16. taskcluster-taskgraph-7.2.1/src/taskcluster_taskgraph.egg-info/PKG-INFO +0 -16
  17. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/LICENSE +0 -0
  18. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/MANIFEST.in +0 -0
  19. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/README.rst +0 -0
  20. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/pyproject.toml +0 -0
  21. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/requirements/base.in +0 -0
  22. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/requirements/base.txt +0 -0
  23. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/requirements/dev.in +0 -0
  24. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/requirements/dev.txt +0 -0
  25. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/requirements/test.in +0 -0
  26. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/requirements/test.txt +0 -0
  27. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/setup.cfg +0 -0
  28. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskcluster_taskgraph.egg-info/dependency_links.txt +0 -0
  29. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskcluster_taskgraph.egg-info/entry_points.txt +0 -0
  30. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskcluster_taskgraph.egg-info/requires.txt +0 -0
  31. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskcluster_taskgraph.egg-info/top_level.txt +0 -0
  32. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/actions/__init__.py +0 -0
  33. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/actions/cancel.py +0 -0
  34. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/actions/cancel_all.py +0 -0
  35. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/config.py +0 -0
  36. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/create.py +0 -0
  37. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/decision.py +0 -0
  38. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/docker.py +0 -0
  39. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/files_changed.py +0 -0
  40. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/filter_tasks.py +0 -0
  41. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/generator.py +0 -0
  42. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/graph.py +0 -0
  43. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/loader/__init__.py +0 -0
  44. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/loader/default.py +0 -0
  45. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/loader/transform.py +0 -0
  46. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/main.py +0 -0
  47. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/morph.py +0 -0
  48. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/optimize/__init__.py +0 -0
  49. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/optimize/base.py +0 -0
  50. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/optimize/strategies.py +0 -0
  51. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/parameters.py +0 -0
  52. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/run-task/fetch-content +0 -0
  53. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/run-task/hgrc +0 -0
  54. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/run-task/robustcheckout.py +0 -0
  55. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/run-task/run-task +0 -0
  56. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/target_tasks.py +0 -0
  57. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/task.py +0 -0
  58. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/taskgraph.py +0 -0
  59. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/transforms/__init__.py +0 -0
  60. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/transforms/base.py +0 -0
  61. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/transforms/cached_tasks.py +0 -0
  62. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/transforms/chunking.py +0 -0
  63. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/transforms/code_review.py +0 -0
  64. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/transforms/docker_image.py +0 -0
  65. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/transforms/fetch.py +0 -0
  66. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/transforms/from_deps.py +0 -0
  67. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/transforms/notify.py +0 -0
  68. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/transforms/run/__init__.py +0 -0
  69. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/transforms/run/common.py +0 -0
  70. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/transforms/run/index_search.py +0 -0
  71. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/transforms/run/run_task.py +0 -0
  72. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/transforms/run/toolchain.py +0 -0
  73. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/transforms/task.py +0 -0
  74. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/transforms/task_context.py +0 -0
  75. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/util/__init__.py +0 -0
  76. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/util/attributes.py +0 -0
  77. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/util/cached_tasks.py +0 -0
  78. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/util/dependencies.py +0 -0
  79. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/util/docker.py +0 -0
  80. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/util/hash.py +0 -0
  81. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/util/keyed_by.py +0 -0
  82. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/util/memoize.py +0 -0
  83. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/util/parameterization.py +0 -0
  84. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/util/path.py +0 -0
  85. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/util/python_path.py +0 -0
  86. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/util/readonlydict.py +0 -0
  87. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/util/schema.py +0 -0
  88. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/util/shell.py +0 -0
  89. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/util/taskcluster.py +0 -0
  90. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/util/taskgraph.py +0 -0
  91. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/util/templates.py +0 -0
  92. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/util/time.py +0 -0
  93. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/util/treeherder.py +0 -0
  94. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/util/vcs.py +0 -0
  95. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/util/verify.py +0 -0
  96. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/util/workertypes.py +0 -0
  97. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/src/taskgraph/util/yaml.py +0 -0
  98. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_actions_rebuild_cached_tasks.py +0 -0
  99. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_create.py +0 -0
  100. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_decision.py +0 -0
  101. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_files_changed.py +0 -0
  102. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_generator.py +0 -0
  103. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_graph.py +0 -0
  104. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_main.py +0 -0
  105. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_morph.py +0 -0
  106. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_optimize.py +0 -0
  107. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_optimize_strategies.py +0 -0
  108. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_parameters.py +0 -0
  109. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_scripts_fetch_content.py +0 -0
  110. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_scripts_run_task.py +0 -0
  111. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_target_tasks.py +0 -0
  112. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_taskgraph.py +0 -0
  113. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_transform_chunking.py +0 -0
  114. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_transform_docker_image.py +0 -0
  115. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_transform_task_context.py +0 -0
  116. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_transforms_base.py +0 -0
  117. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_transforms_cached_tasks.py +0 -0
  118. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_transforms_fetch.py +0 -0
  119. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_transforms_from_deps.py +0 -0
  120. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_transforms_notify.py +0 -0
  121. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_transforms_run.py +0 -0
  122. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_transforms_run_run_task.py +0 -0
  123. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_transforms_run_toolchain.py +0 -0
  124. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_transforms_task.py +0 -0
  125. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_util_attributes.py +0 -0
  126. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_util_cached_tasks.py +0 -0
  127. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_util_dependencies.py +0 -0
  128. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_util_memoize.py +0 -0
  129. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_util_parameterization.py +0 -0
  130. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_util_path.py +0 -0
  131. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_util_python_path.py +0 -0
  132. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_util_readonlydict.py +0 -0
  133. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_util_schema.py +0 -0
  134. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_util_taskcluster.py +0 -0
  135. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_util_templates.py +0 -0
  136. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_util_time.py +0 -0
  137. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_util_treeherder.py +0 -0
  138. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_util_vcs.py +0 -0
  139. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_util_verify.py +0 -0
  140. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_util_workertypes.py +0 -0
  141. {taskcluster-taskgraph-7.2.1 → taskcluster-taskgraph-7.3.0}/test/test_util_yaml.py +0 -0
@@ -0,0 +1,112 @@
1
+ Metadata-Version: 2.1
2
+ Name: taskcluster-taskgraph
3
+ Version: 7.3.0
4
+ Summary: Build taskcluster taskgraphs
5
+ Home-page: https://github.com/taskcluster/taskgraph
6
+ Classifier: Development Status :: 5 - Production/Stable
7
+ Classifier: Environment :: Console
8
+ Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)
9
+ Classifier: Programming Language :: Python :: 3.8
10
+ Classifier: Programming Language :: Python :: 3.9
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Topic :: Software Development
15
+ Provides-Extra: load-image
16
+ License-File: LICENSE
17
+
18
+
19
+ .. image:: https://firefox-ci-tc.services.mozilla.com/api/github/v1/repository/taskcluster/taskgraph/main/badge.svg
20
+ :target: https://firefox-ci-tc.services.mozilla.com/api/github/v1/repository/taskcluster/taskgraph/main/latest
21
+ :alt: Task Status
22
+
23
+ .. image:: https://results.pre-commit.ci/badge/github/taskcluster/taskgraph/main.svg
24
+ :target: https://results.pre-commit.ci/latest/github/taskcluster/taskgraph/main
25
+ :alt: pre-commit.ci status
26
+
27
+ .. image:: https://codecov.io/gh/taskcluster/taskgraph/branch/main/graph/badge.svg?token=GJIV52ZQNP
28
+ :target: https://codecov.io/gh/taskcluster/taskgraph
29
+ :alt: Code Coverage
30
+
31
+ .. image:: https://badge.fury.io/py/taskcluster-taskgraph.svg
32
+ :target: https://badge.fury.io/py/taskcluster-taskgraph
33
+ :alt: Pypi Version
34
+
35
+ .. image:: https://readthedocs.org/projects/taskcluster-taskgraph/badge/?version=latest
36
+ :target: https://taskcluster-taskgraph.readthedocs.io/en/latest/?badge=latest
37
+ :alt: Documentation Status
38
+
39
+ .. image:: https://img.shields.io/badge/license-MPL%202.0-orange.svg
40
+ :target: http://mozilla.org/MPL/2.0
41
+ :alt: License
42
+
43
+ Taskgraph
44
+ =========
45
+
46
+ Taskgraph is a Python library to generate graphs of tasks for the `Taskcluster
47
+ CI`_ service. It is the recommended approach for configuring tasks once your
48
+ project outgrows a single `.taskcluster.yml`_ file and is what powers the over
49
+ 30,000 tasks and counting that make up Firefox's CI.
50
+
51
+ For more information and usage instructions, `see the docs`_.
52
+
53
+ How It Works
54
+ ------------
55
+
56
+ Taskgraph leverages the fact that Taskcluster is a generic task execution
57
+ platform. This means that tasks can be scheduled via its `comprehensive API`_,
58
+ and aren't limited to being triggered in response to supported events.
59
+
60
+ Taskgraph leverages this execution platform to allow CI systems to scale to any
61
+ size or complexity.
62
+
63
+ 1. A *decision task* is created via Taskcluster's normal `.taskcluster.yml`_
64
+ file. This task invokes ``taskgraph``.
65
+ 2. Taskgraph evaluates a series of yaml based task definitions (similar to
66
+ those other CI offerings provide).
67
+ 3. Taskgraph applies transforms on top of these task definitions. Transforms
68
+ are Python functions that can programmatically alter or even clone a task
69
+ definition.
70
+ 4. Taskgraph applies some optional optimization logic to remove unnecessary
71
+ tasks.
72
+ 5. Taskgraph submits the resulting *task graph* to Taskcluster via its API.
73
+
74
+ Taskgraph's combination of declarative task configuration combined with
75
+ programmatic alteration are what allow it to support CI systems of any scale.
76
+ Taskgraph is the library that powers the 30,000+ tasks making up `Firefox's
77
+ CI`_.
78
+
79
+ .. _Taskcluster CI: https://taskcluster.net/
80
+ .. _comprehensive API: https://docs.taskcluster.net/docs/reference/platform/queue/api
81
+ .. _.taskcluster.yml: https://docs.taskcluster.net/docs/reference/integrations/github/taskcluster-yml-v1
82
+ .. _Firefox's CI: https://treeherder.mozilla.org/jobs?repo=mozilla-central
83
+ .. _see the docs: https://taskcluster-taskgraph.readthedocs.io
84
+
85
+ Installation
86
+ ------------
87
+
88
+ Taskgraph supports Python 3.8 and up, and can be installed from Pypi:
89
+
90
+ .. code-block::
91
+
92
+ pip install taskcluster-taskgraph
93
+
94
+
95
+ Alternatively, the repo can be cloned and installed directly:
96
+
97
+ .. code-block::
98
+
99
+ git clone https://github.com/taskcluster/taskgraph
100
+ cd taskgraph
101
+ python setup.py install
102
+
103
+ In both cases, it's recommended to use a Python `virtual environment`_.
104
+
105
+ .. _virtual environment: https://docs.python.org/3/tutorial/venv.html
106
+
107
+ Get Involved
108
+ ------------
109
+
110
+ If you'd like to get involved, please see our `contributing docs`_!
111
+
112
+ .. _contributing docs: https://github.com/taskcluster/taskgraph/blob/main/CONTRIBUTING.rst
@@ -13,10 +13,14 @@ with open(version_file) as fh:
13
13
  with open(os.path.join(project_dir, "requirements/base.in")) as fp:
14
14
  requirements = fp.read().splitlines()
15
15
 
16
+ with open(os.path.join(project_dir, "README.rst")) as fh:
17
+ long_description = fh.read()
18
+
16
19
  setup(
17
20
  name="taskcluster-taskgraph",
18
21
  version=namespace["__version__"],
19
22
  description="Build taskcluster taskgraphs",
23
+ long_description=long_description,
20
24
  url="https://github.com/taskcluster/taskgraph",
21
25
  packages=find_packages("src"),
22
26
  package_dir={"": "src"},
@@ -0,0 +1,112 @@
1
+ Metadata-Version: 2.1
2
+ Name: taskcluster-taskgraph
3
+ Version: 7.3.0
4
+ Summary: Build taskcluster taskgraphs
5
+ Home-page: https://github.com/taskcluster/taskgraph
6
+ Classifier: Development Status :: 5 - Production/Stable
7
+ Classifier: Environment :: Console
8
+ Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)
9
+ Classifier: Programming Language :: Python :: 3.8
10
+ Classifier: Programming Language :: Python :: 3.9
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Topic :: Software Development
15
+ Provides-Extra: load-image
16
+ License-File: LICENSE
17
+
18
+
19
+ .. image:: https://firefox-ci-tc.services.mozilla.com/api/github/v1/repository/taskcluster/taskgraph/main/badge.svg
20
+ :target: https://firefox-ci-tc.services.mozilla.com/api/github/v1/repository/taskcluster/taskgraph/main/latest
21
+ :alt: Task Status
22
+
23
+ .. image:: https://results.pre-commit.ci/badge/github/taskcluster/taskgraph/main.svg
24
+ :target: https://results.pre-commit.ci/latest/github/taskcluster/taskgraph/main
25
+ :alt: pre-commit.ci status
26
+
27
+ .. image:: https://codecov.io/gh/taskcluster/taskgraph/branch/main/graph/badge.svg?token=GJIV52ZQNP
28
+ :target: https://codecov.io/gh/taskcluster/taskgraph
29
+ :alt: Code Coverage
30
+
31
+ .. image:: https://badge.fury.io/py/taskcluster-taskgraph.svg
32
+ :target: https://badge.fury.io/py/taskcluster-taskgraph
33
+ :alt: Pypi Version
34
+
35
+ .. image:: https://readthedocs.org/projects/taskcluster-taskgraph/badge/?version=latest
36
+ :target: https://taskcluster-taskgraph.readthedocs.io/en/latest/?badge=latest
37
+ :alt: Documentation Status
38
+
39
+ .. image:: https://img.shields.io/badge/license-MPL%202.0-orange.svg
40
+ :target: http://mozilla.org/MPL/2.0
41
+ :alt: License
42
+
43
+ Taskgraph
44
+ =========
45
+
46
+ Taskgraph is a Python library to generate graphs of tasks for the `Taskcluster
47
+ CI`_ service. It is the recommended approach for configuring tasks once your
48
+ project outgrows a single `.taskcluster.yml`_ file and is what powers the over
49
+ 30,000 tasks and counting that make up Firefox's CI.
50
+
51
+ For more information and usage instructions, `see the docs`_.
52
+
53
+ How It Works
54
+ ------------
55
+
56
+ Taskgraph leverages the fact that Taskcluster is a generic task execution
57
+ platform. This means that tasks can be scheduled via its `comprehensive API`_,
58
+ and aren't limited to being triggered in response to supported events.
59
+
60
+ Taskgraph leverages this execution platform to allow CI systems to scale to any
61
+ size or complexity.
62
+
63
+ 1. A *decision task* is created via Taskcluster's normal `.taskcluster.yml`_
64
+ file. This task invokes ``taskgraph``.
65
+ 2. Taskgraph evaluates a series of yaml based task definitions (similar to
66
+ those other CI offerings provide).
67
+ 3. Taskgraph applies transforms on top of these task definitions. Transforms
68
+ are Python functions that can programmatically alter or even clone a task
69
+ definition.
70
+ 4. Taskgraph applies some optional optimization logic to remove unnecessary
71
+ tasks.
72
+ 5. Taskgraph submits the resulting *task graph* to Taskcluster via its API.
73
+
74
+ Taskgraph's combination of declarative task configuration combined with
75
+ programmatic alteration are what allow it to support CI systems of any scale.
76
+ Taskgraph is the library that powers the 30,000+ tasks making up `Firefox's
77
+ CI`_.
78
+
79
+ .. _Taskcluster CI: https://taskcluster.net/
80
+ .. _comprehensive API: https://docs.taskcluster.net/docs/reference/platform/queue/api
81
+ .. _.taskcluster.yml: https://docs.taskcluster.net/docs/reference/integrations/github/taskcluster-yml-v1
82
+ .. _Firefox's CI: https://treeherder.mozilla.org/jobs?repo=mozilla-central
83
+ .. _see the docs: https://taskcluster-taskgraph.readthedocs.io
84
+
85
+ Installation
86
+ ------------
87
+
88
+ Taskgraph supports Python 3.8 and up, and can be installed from Pypi:
89
+
90
+ .. code-block::
91
+
92
+ pip install taskcluster-taskgraph
93
+
94
+
95
+ Alternatively, the repo can be cloned and installed directly:
96
+
97
+ .. code-block::
98
+
99
+ git clone https://github.com/taskcluster/taskgraph
100
+ cd taskgraph
101
+ python setup.py install
102
+
103
+ In both cases, it's recommended to use a Python `virtual environment`_.
104
+
105
+ .. _virtual environment: https://docs.python.org/3/tutorial/venv.html
106
+
107
+ Get Involved
108
+ ------------
109
+
110
+ If you'd like to get involved, please see our `contributing docs`_!
111
+
112
+ .. _contributing docs: https://github.com/taskcluster/taskgraph/blob/main/CONTRIBUTING.rst
@@ -116,6 +116,7 @@ test/test_transforms_run.py
116
116
  test/test_transforms_run_run_task.py
117
117
  test/test_transforms_run_toolchain.py
118
118
  test/test_transforms_task.py
119
+ test/test_util_archive.py
119
120
  test/test_util_attributes.py
120
121
  test/test_util_cached_tasks.py
121
122
  test/test_util_dependencies.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__ = "7.2.1"
5
+ __version__ = "7.3.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
@@ -40,7 +40,7 @@ from taskgraph.actions.util import (
40
40
  )
41
41
  def add_new_jobs_action(parameters, graph_config, input, task_group_id, task_id):
42
42
  decision_task_id, full_task_graph, label_to_taskid = fetch_graph_and_labels(
43
- parameters, graph_config
43
+ parameters, graph_config, task_group_id=task_group_id
44
44
  )
45
45
 
46
46
  to_run = []
@@ -18,7 +18,7 @@ def rebuild_cached_tasks_action(
18
18
  parameters, graph_config, input, task_group_id, task_id
19
19
  ):
20
20
  decision_task_id, full_task_graph, label_to_taskid = fetch_graph_and_labels(
21
- parameters, graph_config
21
+ parameters, graph_config, task_group_id=task_group_id
22
22
  )
23
23
  cached_tasks = [
24
24
  label
@@ -163,11 +163,11 @@ def register_callback_action(
163
163
  actionPerm = "generic" if generic else cb_name
164
164
 
165
165
  # gather up the common decision-task-supplied data for this action
166
- repo_param = "head_repository"
167
166
  repository = {
168
- "url": parameters[repo_param],
167
+ "url": parameters["head_repository"],
169
168
  "project": parameters["project"],
170
169
  "level": parameters["level"],
170
+ "base_url": parameters["base_repository"],
171
171
  }
172
172
 
173
173
  revision = parameters["head_rev"]
@@ -179,6 +179,9 @@ def register_callback_action(
179
179
  branch = parameters.get("head_ref")
180
180
  if branch:
181
181
  push["branch"] = branch
182
+ base_branch = parameters.get("base_ref")
183
+ if base_branch and branch != base_branch:
184
+ push["base_branch"] = base_branch
182
185
 
183
186
  action = {
184
187
  "name": name,
@@ -213,11 +216,16 @@ def register_callback_action(
213
216
  if "/" in actionPerm:
214
217
  raise Exception("`/` is not allowed in action names; use `-`")
215
218
 
219
+ if parameters["tasks_for"].startswith("github-pull-request"):
220
+ hookId = f"in-tree-pr-action-{level}-{actionPerm}/{tcyml_hash}"
221
+ else:
222
+ hookId = f"in-tree-action-{level}-{actionPerm}/{tcyml_hash}"
223
+
216
224
  rv.update(
217
225
  {
218
226
  "kind": "hook",
219
227
  "hookGroupId": f"project-{trustDomain}",
220
- "hookId": f"in-tree-action-{level}-{actionPerm}/{tcyml_hash}",
228
+ "hookId": hookId,
221
229
  "hookPayload": {
222
230
  # provide the decision-task parameters as context for triggerHook
223
231
  "decision": {
@@ -293,16 +301,20 @@ def sanity_check_task_scope(callback, parameters, graph_config):
293
301
 
294
302
  actionPerm = "generic" if action.generic else action.cb_name
295
303
 
296
- repo_param = "head_repository"
297
- raw_url = parameters[repo_param]
304
+ raw_url = parameters["base_repository"]
298
305
  parsed_url = parse(raw_url)
299
- expected_scope = f"assume:{parsed_url.taskcluster_role_prefix}:action:{actionPerm}"
306
+ action_scope = f"assume:{parsed_url.taskcluster_role_prefix}:action:{actionPerm}"
307
+ pr_action_scope = (
308
+ f"assume:{parsed_url.taskcluster_role_prefix}:pr-action:{actionPerm}"
309
+ )
300
310
 
301
311
  # the scope should appear literally; no need for a satisfaction check. The use of
302
312
  # get_current_scopes here calls the auth service through the Taskcluster Proxy, giving
303
313
  # the precise scopes available to this task.
304
- if expected_scope not in taskcluster.get_current_scopes():
305
- raise ValueError(f"Expected task scope {expected_scope} for this action")
314
+ if not set((action_scope, pr_action_scope)) & set(taskcluster.get_current_scopes()):
315
+ raise ValueError(
316
+ f"Expected task scope {action_scope} or {pr_action_scope} for this action"
317
+ )
306
318
 
307
319
 
308
320
  def trigger_action_callback(
@@ -65,7 +65,9 @@ def retrigger_decision_action(parameters, graph_config, input, task_group_id, ta
65
65
  # absolute timestamps relative to the current time.
66
66
  task = taskcluster.get_task_definition(task_id)
67
67
  task = relativize_datestamps(task)
68
- create_task_from_def(slugid(), task, parameters["level"])
68
+ create_task_from_def(
69
+ slugid(), task, parameters["level"], graph_config["trust-domain"]
70
+ )
69
71
 
70
72
 
71
73
  @register_callback_action(
@@ -142,7 +144,7 @@ def retrigger_decision_action(parameters, graph_config, input, task_group_id, ta
142
144
  )
143
145
  def retrigger_action(parameters, graph_config, input, task_group_id, task_id):
144
146
  decision_task_id, full_task_graph, label_to_taskid = fetch_graph_and_labels(
145
- parameters, graph_config
147
+ parameters, graph_config, task_group_id=task_group_id
146
148
  )
147
149
 
148
150
  task = taskcluster.get_task_definition(task_id)
@@ -199,7 +201,7 @@ def rerun_action(parameters, graph_config, input, task_group_id, task_id):
199
201
  task = taskcluster.get_task_definition(task_id)
200
202
  parameters = dict(parameters)
201
203
  decision_task_id, full_task_graph, label_to_taskid = fetch_graph_and_labels(
202
- parameters, graph_config
204
+ parameters, graph_config, task_group_id=task_group_id
203
205
  )
204
206
  label = task["metadata"]["name"]
205
207
  if task_id not in label_to_taskid.values():
@@ -257,7 +259,7 @@ def _rerun_task(task_id, label):
257
259
  )
258
260
  def retrigger_multiple(parameters, graph_config, input, task_group_id, task_id):
259
261
  decision_task_id, full_task_graph, label_to_taskid = fetch_graph_and_labels(
260
- parameters, graph_config
262
+ parameters, graph_config, task_group_id=task_group_id
261
263
  )
262
264
 
263
265
  suffixes = []
@@ -32,8 +32,15 @@ def get_parameters(decision_task_id):
32
32
  return get_artifact(decision_task_id, "public/parameters.yml")
33
33
 
34
34
 
35
- def fetch_graph_and_labels(parameters, graph_config):
36
- decision_task_id = find_decision_task(parameters, graph_config)
35
+ def fetch_graph_and_labels(parameters, graph_config, task_group_id=None):
36
+ try:
37
+ # Look up the decision_task id in the index
38
+ decision_task_id = find_decision_task(parameters, graph_config)
39
+ except KeyError:
40
+ if not task_group_id:
41
+ raise
42
+ # Not found (e.g. from github-pull-request), fall back to the task group id.
43
+ decision_task_id = task_group_id
37
44
 
38
45
  # First grab the graph and labels generated during the initial decision task
39
46
  full_task_graph = get_artifact(decision_task_id, "public/full-task-graph.json")
@@ -90,7 +97,7 @@ def fetch_graph_and_labels(parameters, graph_config):
90
97
  return (decision_task_id, full_task_graph, label_to_taskid)
91
98
 
92
99
 
93
- def create_task_from_def(task_id, task_def, level):
100
+ def create_task_from_def(task_id, task_def, level, trust_domain):
94
101
  """Create a new task from a definition rather than from a label
95
102
  that is already in the full-task-graph. The task definition will
96
103
  have {relative-datestamp': '..'} rendered just like in a decision task.
@@ -98,7 +105,7 @@ def create_task_from_def(task_id, task_def, level):
98
105
  It is useful if you want to "edit" the full_task_graph and then hand
99
106
  it to this function. No dependencies will be scheduled. You must handle
100
107
  this yourself. Seeing how create_tasks handles it might prove helpful."""
101
- task_def["schedulerId"] = f"gecko-level-{level}"
108
+ task_def["schedulerId"] = f"{trust_domain}-level-{level}"
102
109
  label = task_def["metadata"]["name"]
103
110
  session = get_session()
104
111
  create.create_task(session, task_id, label, task_def)
@@ -12,6 +12,40 @@ import tarfile
12
12
  DEFAULT_MTIME = 1451606400
13
13
 
14
14
 
15
+ # Python 3.9 contains this change:
16
+ # https://github.com/python/cpython/commit/674935b8caf33e47c78f1b8e197b1b77a04992d2
17
+ # which changes the output of tar creation compared to earlier versions.
18
+ # As this code is used to generate tar files that are meant to be deterministic
19
+ # across versions of python (specifically, it's used as part of computing the hash
20
+ # of docker images, which needs to be identical between CI (which uses python 3.8),
21
+ # and developer environments (using arbitrary versions of python, at this point,
22
+ # most probably more recent than 3.9)).
23
+ # What we do is subblass TarInfo so that if used on python >= 3.9, it reproduces the
24
+ # behavior from python < 3.9.
25
+ # Here's how it goes:
26
+ # - the behavior in python >= 3.9 is the same as python < 3.9 when the type encoded
27
+ # in the tarinfo is CHRTYPE or BLKTYPE.
28
+ # - the value of the type is only compared in the context of choosing which behavior
29
+ # to take
30
+ # - we replace the type with the same value (so that using the value has no changes)
31
+ # but that pretends to be the same as CHRTYPE so that the condition that enables the
32
+ # old behavior is taken.
33
+ class HackedType(bytes):
34
+ def __eq__(self, other):
35
+ if other == tarfile.CHRTYPE:
36
+ return True
37
+ return self == other
38
+
39
+
40
+ class TarInfo(tarfile.TarInfo):
41
+ @staticmethod
42
+ def _create_header(info, format, encoding, errors):
43
+ info["type"] = HackedType(info["type"])
44
+ # ignore type checking because it looks like pyright complains because we're calling a
45
+ # non-public method
46
+ return tarfile.TarInfo._create_header(info, format, encoding, errors) # type: ignore
47
+
48
+
15
49
  def create_tar_from_files(fp, files):
16
50
  """Create a tar file deterministically.
17
51
 
@@ -25,15 +59,23 @@ def create_tar_from_files(fp, files):
25
59
 
26
60
  FUTURE accept a filename argument (or create APIs to write files)
27
61
  """
28
- with tarfile.open(name="", mode="w", fileobj=fp, dereference=True) as tf:
62
+ # The format is explicitly set to tarfile.GNU_FORMAT, because this default format
63
+ # has been changed in Python 3.8.
64
+ with tarfile.open(
65
+ name="", mode="w", fileobj=fp, dereference=True, format=tarfile.GNU_FORMAT
66
+ ) as tf:
29
67
  for archive_path, f in sorted(files.items()):
30
68
  if isinstance(f, str):
31
- mode = os.stat(f).st_mode
69
+ s = os.stat(f)
70
+ mode = s.st_mode
71
+ size = s.st_size
32
72
  f = open(f, "rb")
33
73
  else:
34
74
  mode = 0o0644
75
+ size = len(f.read())
76
+ f.seek(0)
35
77
 
36
- ti = tarfile.TarInfo(archive_path)
78
+ ti = TarInfo(archive_path)
37
79
  ti.mode = mode
38
80
  ti.type = tarfile.REGTYPE
39
81
 
@@ -56,9 +98,7 @@ def create_tar_from_files(fp, files):
56
98
  # Set mtime to a constant value.
57
99
  ti.mtime = DEFAULT_MTIME
58
100
 
59
- f.seek(0, 2)
60
- ti.size = f.tell()
61
- f.seek(0, 0)
101
+ ti.size = size
62
102
  # tarfile wants to pass a size argument to read(). So just
63
103
  # wrap/buffer in a proper file object interface.
64
104
  tf.addfile(ti, f)
@@ -12,34 +12,40 @@ from taskgraph.actions import registry
12
12
  ("non-existing-action", {}, [], pytest.raises(ValueError)),
13
13
  (
14
14
  "retrigger",
15
- {"head_repository": "https://some.git.repo"},
15
+ {"base_repository": "https://some.git.repo"},
16
16
  [],
17
17
  pytest.raises(InvalidRepoUrlError),
18
18
  ),
19
19
  (
20
20
  "retrigger",
21
- {"head_repository": "https://hg.mozilla.org/try"},
21
+ {"base_repository": "https://hg.mozilla.org/try"},
22
22
  ["unrelated:scope"],
23
23
  pytest.raises(ValueError),
24
24
  ),
25
25
  (
26
26
  "retrigger",
27
- {"head_repository": "https://hg.mozilla.org/mozilla-central"},
27
+ {"base_repository": "https://hg.mozilla.org/mozilla-central"},
28
28
  ["assume:repo:hg.mozilla.org/mozilla-central:action:generic"],
29
29
  does_not_raise(),
30
30
  ),
31
31
  (
32
32
  "retrigger",
33
- {"head_repository": "https://github.com/taskcluster/taskgraph"},
33
+ {"base_repository": "https://github.com/taskcluster/taskgraph"},
34
34
  ["assume:repo:github.com/taskcluster/taskgraph:action:generic"],
35
35
  does_not_raise(),
36
36
  ),
37
37
  (
38
38
  "retrigger",
39
- {"head_repository": "git@github.com:mozilla-mobile/firefox-android.git"},
39
+ {"base_repository": "git@github.com:mozilla-mobile/firefox-android.git"},
40
40
  ["assume:repo:github.com/mozilla-mobile/firefox-android:action:generic"],
41
41
  does_not_raise(),
42
42
  ),
43
+ (
44
+ "retrigger",
45
+ {"base_repository": "git@github.com:mozilla-mobile/firefox-android.git"},
46
+ ["assume:repo:github.com/mozilla-mobile/firefox-android:pr-action:generic"],
47
+ does_not_raise(),
48
+ ),
43
49
  ),
44
50
  )
45
51
  def test_sanity_check_task_scope(