taskcluster-taskgraph 7.4.0__tar.gz → 8.0.1__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 (142) hide show
  1. {taskcluster-taskgraph-7.4.0/src/taskcluster_taskgraph.egg-info → taskcluster-taskgraph-8.0.1}/PKG-INFO +1 -1
  2. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1/src/taskcluster_taskgraph.egg-info}/PKG-INFO +1 -1
  3. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskcluster_taskgraph.egg-info/SOURCES.txt +2 -3
  4. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/__init__.py +1 -1
  5. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/decision.py +3 -0
  6. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/docker.py +26 -11
  7. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/main.py +32 -12
  8. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/optimize/strategies.py +10 -2
  9. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/parameters.py +3 -0
  10. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/transforms/from_deps.py +10 -9
  11. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/transforms/run/__init__.py +2 -1
  12. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/util/cached_tasks.py +1 -3
  13. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/util/docker.py +15 -4
  14. taskcluster-taskgraph-8.0.1/src/taskgraph/util/memoize.py +7 -0
  15. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/util/parameterization.py +5 -4
  16. taskcluster-taskgraph-8.0.1/src/taskgraph/util/set_name.py +34 -0
  17. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/util/taskcluster.py +2 -15
  18. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_decision.py +21 -7
  19. taskcluster-taskgraph-8.0.1/test/test_docker.py +55 -0
  20. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_main.py +39 -5
  21. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_optimize_strategies.py +33 -1
  22. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_parameters.py +6 -0
  23. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_transforms_from_deps.py +41 -1
  24. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_util_cached_tasks.py +2 -4
  25. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_util_parameterization.py +12 -1
  26. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_util_taskcluster.py +34 -10
  27. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_util_vcs.py +9 -11
  28. taskcluster-taskgraph-7.4.0/src/taskgraph/files_changed.py +0 -92
  29. taskcluster-taskgraph-7.4.0/src/taskgraph/util/memoize.py +0 -40
  30. taskcluster-taskgraph-7.4.0/test/test_files_changed.py +0 -110
  31. taskcluster-taskgraph-7.4.0/test/test_util_memoize.py +0 -66
  32. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/LICENSE +0 -0
  33. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/MANIFEST.in +0 -0
  34. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/README.rst +0 -0
  35. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/pyproject.toml +0 -0
  36. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/requirements/base.in +0 -0
  37. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/requirements/base.txt +0 -0
  38. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/requirements/dev.in +0 -0
  39. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/requirements/dev.txt +0 -0
  40. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/requirements/test.in +0 -0
  41. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/requirements/test.txt +0 -0
  42. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/setup.cfg +0 -0
  43. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/setup.py +0 -0
  44. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskcluster_taskgraph.egg-info/dependency_links.txt +0 -0
  45. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskcluster_taskgraph.egg-info/entry_points.txt +0 -0
  46. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskcluster_taskgraph.egg-info/requires.txt +0 -0
  47. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskcluster_taskgraph.egg-info/top_level.txt +0 -0
  48. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/actions/__init__.py +0 -0
  49. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/actions/add_new_jobs.py +0 -0
  50. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/actions/cancel.py +0 -0
  51. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/actions/cancel_all.py +0 -0
  52. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/actions/rebuild_cached_tasks.py +0 -0
  53. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/actions/registry.py +0 -0
  54. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/actions/retrigger.py +0 -0
  55. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/actions/util.py +0 -0
  56. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/config.py +0 -0
  57. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/create.py +0 -0
  58. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/filter_tasks.py +0 -0
  59. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/generator.py +0 -0
  60. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/graph.py +0 -0
  61. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/loader/__init__.py +0 -0
  62. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/loader/default.py +0 -0
  63. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/loader/transform.py +0 -0
  64. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/morph.py +0 -0
  65. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/optimize/__init__.py +0 -0
  66. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/optimize/base.py +0 -0
  67. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/run-task/fetch-content +0 -0
  68. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/run-task/hgrc +0 -0
  69. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/run-task/robustcheckout.py +0 -0
  70. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/run-task/run-task +0 -0
  71. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/target_tasks.py +0 -0
  72. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/task.py +0 -0
  73. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/taskgraph.py +0 -0
  74. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/transforms/__init__.py +0 -0
  75. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/transforms/base.py +0 -0
  76. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/transforms/cached_tasks.py +0 -0
  77. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/transforms/chunking.py +0 -0
  78. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/transforms/code_review.py +0 -0
  79. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/transforms/docker_image.py +0 -0
  80. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/transforms/fetch.py +0 -0
  81. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/transforms/notify.py +0 -0
  82. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/transforms/run/common.py +0 -0
  83. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/transforms/run/index_search.py +0 -0
  84. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/transforms/run/run_task.py +0 -0
  85. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/transforms/run/toolchain.py +0 -0
  86. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/transforms/task.py +0 -0
  87. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/transforms/task_context.py +0 -0
  88. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/util/__init__.py +0 -0
  89. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/util/archive.py +0 -0
  90. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/util/attributes.py +0 -0
  91. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/util/dependencies.py +0 -0
  92. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/util/hash.py +0 -0
  93. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/util/keyed_by.py +0 -0
  94. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/util/path.py +0 -0
  95. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/util/python_path.py +0 -0
  96. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/util/readonlydict.py +0 -0
  97. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/util/schema.py +0 -0
  98. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/util/shell.py +0 -0
  99. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/util/taskgraph.py +0 -0
  100. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/util/templates.py +0 -0
  101. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/util/time.py +0 -0
  102. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/util/treeherder.py +0 -0
  103. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/util/vcs.py +0 -0
  104. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/util/verify.py +0 -0
  105. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/util/workertypes.py +0 -0
  106. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/src/taskgraph/util/yaml.py +0 -0
  107. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_actions_rebuild_cached_tasks.py +0 -0
  108. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_actions_registry.py +0 -0
  109. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_create.py +0 -0
  110. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_generator.py +0 -0
  111. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_graph.py +0 -0
  112. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_morph.py +0 -0
  113. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_optimize.py +0 -0
  114. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_scripts_fetch_content.py +0 -0
  115. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_scripts_run_task.py +0 -0
  116. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_target_tasks.py +0 -0
  117. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_taskgraph.py +0 -0
  118. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_transform_chunking.py +0 -0
  119. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_transform_docker_image.py +0 -0
  120. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_transform_task_context.py +0 -0
  121. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_transforms_base.py +0 -0
  122. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_transforms_cached_tasks.py +0 -0
  123. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_transforms_fetch.py +0 -0
  124. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_transforms_notify.py +0 -0
  125. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_transforms_run.py +0 -0
  126. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_transforms_run_run_task.py +0 -0
  127. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_transforms_run_toolchain.py +0 -0
  128. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_transforms_task.py +0 -0
  129. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_util_archive.py +0 -0
  130. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_util_attributes.py +0 -0
  131. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_util_dependencies.py +0 -0
  132. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_util_docker.py +0 -0
  133. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_util_path.py +0 -0
  134. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_util_python_path.py +0 -0
  135. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_util_readonlydict.py +0 -0
  136. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_util_schema.py +0 -0
  137. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_util_templates.py +0 -0
  138. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_util_time.py +0 -0
  139. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_util_treeherder.py +0 -0
  140. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_util_verify.py +0 -0
  141. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_util_workertypes.py +0 -0
  142. {taskcluster-taskgraph-7.4.0 → taskcluster-taskgraph-8.0.1}/test/test_util_yaml.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: taskcluster-taskgraph
3
- Version: 7.4.0
3
+ Version: 8.0.1
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: 7.4.0
3
+ Version: 8.0.1
4
4
  Summary: Build taskcluster taskgraphs
5
5
  Home-page: https://github.com/taskcluster/taskgraph
6
6
  Classifier: Development Status :: 5 - Production/Stable
@@ -20,7 +20,6 @@ src/taskgraph/config.py
20
20
  src/taskgraph/create.py
21
21
  src/taskgraph/decision.py
22
22
  src/taskgraph/docker.py
23
- src/taskgraph/files_changed.py
24
23
  src/taskgraph/filter_tasks.py
25
24
  src/taskgraph/generator.py
26
25
  src/taskgraph/graph.py
@@ -78,6 +77,7 @@ src/taskgraph/util/path.py
78
77
  src/taskgraph/util/python_path.py
79
78
  src/taskgraph/util/readonlydict.py
80
79
  src/taskgraph/util/schema.py
80
+ src/taskgraph/util/set_name.py
81
81
  src/taskgraph/util/shell.py
82
82
  src/taskgraph/util/taskcluster.py
83
83
  src/taskgraph/util/taskgraph.py
@@ -92,7 +92,7 @@ test/test_actions_rebuild_cached_tasks.py
92
92
  test/test_actions_registry.py
93
93
  test/test_create.py
94
94
  test/test_decision.py
95
- test/test_files_changed.py
95
+ test/test_docker.py
96
96
  test/test_generator.py
97
97
  test/test_graph.py
98
98
  test/test_main.py
@@ -121,7 +121,6 @@ test/test_util_attributes.py
121
121
  test/test_util_cached_tasks.py
122
122
  test/test_util_dependencies.py
123
123
  test/test_util_docker.py
124
- test/test_util_memoize.py
125
124
  test/test_util_parameterization.py
126
125
  test/test_util_path.py
127
126
  test/test_util_python_path.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.4.0"
5
+ __version__ = "8.0.1"
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
@@ -185,6 +185,9 @@ def get_decision_parameters(graph_config, options):
185
185
 
186
186
  # Define default filter list, as most configurations shouldn't need
187
187
  # custom filters.
188
+ parameters["files_changed"] = repo.get_changed_files(
189
+ rev=parameters["head_rev"], base_rev=parameters["base_rev"]
190
+ )
188
191
  parameters["filters"] = [
189
192
  "target_tasks_method",
190
193
  ]
@@ -18,6 +18,22 @@ except ImportError as e:
18
18
  from taskgraph.util import docker
19
19
  from taskgraph.util.taskcluster import get_artifact_url, get_session
20
20
 
21
+ DEPLOY_WARNING = """
22
+ *****************************************************************
23
+ WARNING: Image is not suitable for deploying/pushing.
24
+
25
+ To automatically tag the image the following files are required:
26
+ - {image_dir}/REGISTRY
27
+ - {image_dir}/VERSION
28
+
29
+ The REGISTRY file contains the Docker registry hosting the image.
30
+ A default REGISTRY file may also be defined in the parent docker
31
+ directory.
32
+
33
+ The VERSION file contains the version of the image.
34
+ *****************************************************************
35
+ """
36
+
21
37
 
22
38
  def get_image_digest(image_name):
23
39
  from taskgraph.generator import load_tasks_for_kind
@@ -105,19 +121,18 @@ def build_image(name, tag, args=None):
105
121
 
106
122
  buf = BytesIO()
107
123
  docker.stream_context_tar(".", image_dir, buf, "", args)
108
- subprocess.run(
109
- ["docker", "image", "build", "--no-cache", "-t", tag, "-"], input=buf.getvalue()
110
- )
124
+ cmdargs = ["docker", "image", "build", "--no-cache", "-"]
125
+ if tag:
126
+ cmdargs.insert(-1, f"-t={tag}")
127
+ subprocess.run(cmdargs, input=buf.getvalue())
111
128
 
112
- print(f"Successfully built {name} and tagged with {tag}")
129
+ msg = f"Successfully built {name}"
130
+ if tag:
131
+ msg += f" and tagged with {tag}"
132
+ print(msg)
113
133
 
114
- if tag.endswith(":latest"):
115
- print("*" * 50)
116
- print("WARNING: no VERSION file found in image directory.")
117
- print("Image is not suitable for deploying/pushing.")
118
- print("Create an image suitable for deploying/pushing by creating")
119
- print("a VERSION file in the image directory.")
120
- print("*" * 50)
134
+ if not tag or tag.endswith(":latest"):
135
+ print(DEPLOY_WARNING.format(image_dir=os.path.relpath(image_dir), image=name))
121
136
 
122
137
 
123
138
  def load_image(url, imageName=None, imageTag=None):
@@ -96,7 +96,7 @@ def get_filtered_taskgraph(taskgraph, tasksregex, exclude_keys):
96
96
  for key in exclude_keys:
97
97
  obj = task
98
98
  attrs = key.split(".")
99
- while attrs[0] in obj:
99
+ while obj and attrs[0] in obj:
100
100
  if len(attrs) == 1:
101
101
  del obj[attrs[0]]
102
102
  break
@@ -121,7 +121,7 @@ def get_taskgraph_generator(root, parameters):
121
121
  return TaskGraphGenerator(root_dir=root, parameters=parameters)
122
122
 
123
123
 
124
- def format_taskgraph(options, parameters, logfile=None):
124
+ def format_taskgraph(options, parameters, overrides, logfile=None):
125
125
  import taskgraph
126
126
  from taskgraph.parameters import parameters_loader
127
127
 
@@ -139,7 +139,7 @@ def format_taskgraph(options, parameters, logfile=None):
139
139
  if isinstance(parameters, str):
140
140
  parameters = parameters_loader(
141
141
  parameters,
142
- overrides={"target-kinds": options.get("target_kinds")},
142
+ overrides=overrides,
143
143
  strict=False,
144
144
  )
145
145
 
@@ -173,7 +173,7 @@ def dump_output(out, path=None, params_spec=None):
173
173
  print(out + "\n", file=fh)
174
174
 
175
175
 
176
- def generate_taskgraph(options, parameters, logdir):
176
+ def generate_taskgraph(options, parameters, overrides, logdir):
177
177
  from taskgraph.parameters import Parameters
178
178
 
179
179
  def logfile(spec):
@@ -189,14 +189,16 @@ def generate_taskgraph(options, parameters, logdir):
189
189
  # tracebacks a little more readable and avoids additional process overhead.
190
190
  if len(parameters) == 1:
191
191
  spec = parameters[0]
192
- out = format_taskgraph(options, spec, logfile(spec))
192
+ out = format_taskgraph(options, spec, overrides, logfile(spec))
193
193
  dump_output(out, options["output_file"])
194
194
  return 0
195
195
 
196
196
  futures = {}
197
197
  with ProcessPoolExecutor(max_workers=options["max_workers"]) as executor:
198
198
  for spec in parameters:
199
- f = executor.submit(format_taskgraph, options, spec, logfile(spec))
199
+ f = executor.submit(
200
+ format_taskgraph, options, spec, overrides, logfile(spec)
201
+ )
200
202
  futures[f] = spec
201
203
 
202
204
  returncode = 0
@@ -293,6 +295,15 @@ def generate_taskgraph(options, parameters, logdir):
293
295
  "generations will happen from the same invocation (one per parameters "
294
296
  "specified).",
295
297
  )
298
+ @argument(
299
+ "--force-local-files-changed",
300
+ default=False,
301
+ action="store_true",
302
+ help="Compute the 'files-changed' parameter from local version control, "
303
+ "even when explicitly using a parameter set that already has it defined. "
304
+ "Note that this is already the default behaviour when no parameters are "
305
+ "specified.",
306
+ )
296
307
  @argument(
297
308
  "--no-optimize",
298
309
  dest="optimize",
@@ -367,9 +378,11 @@ def show_taskgraph(options):
367
378
  diffdir = None
368
379
  output_file = options["output_file"]
369
380
 
370
- if options["diff"]:
381
+ if options["diff"] or options["force_local_files_changed"]:
371
382
  repo = get_repository(os.getcwd())
372
383
 
384
+ if options["diff"]:
385
+ assert repo is not None
373
386
  if not repo.working_directory_clean():
374
387
  print(
375
388
  "abort: can't diff taskgraph with dirty working directory",
@@ -393,15 +406,22 @@ def show_taskgraph(options):
393
406
  )
394
407
  print(f"Generating {options['graph_attr']} @ {cur_rev}", file=sys.stderr)
395
408
 
409
+ overrides = {
410
+ "target-kinds": options.get("target_kinds"),
411
+ }
396
412
  parameters: List[Any[str, Parameters]] = options.pop("parameters")
397
413
  if not parameters:
398
- overrides = {
399
- "target-kinds": options.get("target_kinds"),
400
- }
401
414
  parameters = [
402
415
  parameters_loader(None, strict=False, overrides=overrides)
403
416
  ] # will use default values
404
417
 
418
+ # This is the default behaviour anyway, so no need to re-compute.
419
+ options["force_local_files_changed"] = False
420
+
421
+ elif options["force_local_files_changed"]:
422
+ assert repo is not None
423
+ overrides["files-changed"] = sorted(repo.get_changed_files("AM"))
424
+
405
425
  for param in parameters[:]:
406
426
  if isinstance(param, str) and os.path.isdir(param):
407
427
  parameters.remove(param)
@@ -427,7 +447,7 @@ def show_taskgraph(options):
427
447
  # to setup its `mach` based logging.
428
448
  setup_logging()
429
449
 
430
- ret = generate_taskgraph(options, parameters, logdir)
450
+ ret = generate_taskgraph(options, parameters, overrides, logdir)
431
451
 
432
452
  if options["diff"]:
433
453
  assert diffdir is not None
@@ -451,7 +471,7 @@ def show_taskgraph(options):
451
471
  diffdir, f"{options['graph_attr']}_{base_rev_file}"
452
472
  )
453
473
  print(f"Generating {options['graph_attr']} @ {base_rev}", file=sys.stderr)
454
- ret |= generate_taskgraph(options, parameters, logdir)
474
+ ret |= generate_taskgraph(options, parameters, overrides, logdir)
455
475
  finally:
456
476
  repo.update(cur_rev)
457
477
 
@@ -1,8 +1,8 @@
1
1
  import logging
2
2
  from datetime import datetime
3
3
 
4
- from taskgraph import files_changed
5
4
  from taskgraph.optimize.base import OptimizationStrategy, register_strategy
5
+ from taskgraph.util.path import match as match_path
6
6
  from taskgraph.util.taskcluster import find_task_id, status_task
7
7
 
8
8
  logger = logging.getLogger(__name__)
@@ -48,12 +48,20 @@ class IndexSearch(OptimizationStrategy):
48
48
 
49
49
  @register_strategy("skip-unless-changed")
50
50
  class SkipUnlessChanged(OptimizationStrategy):
51
+
52
+ def check(self, files_changed, patterns):
53
+ for pattern in patterns:
54
+ for path in files_changed:
55
+ if match_path(path, pattern):
56
+ return True
57
+ return False
58
+
51
59
  def should_remove_task(self, task, params, file_patterns):
52
60
  # pushlog_id == -1 - this is the case when run from a cron.yml job or on a git repository
53
61
  if params.get("repository_type") == "hg" and params.get("pushlog_id") == -1:
54
62
  return False
55
63
 
56
- changed = files_changed.check(params, file_patterns)
64
+ changed = self.check(params["files_changed"], file_patterns)
57
65
  if not changed:
58
66
  logger.debug(
59
67
  f'no files found matching a pattern in `skip-unless-changed` for "{task.label}"'
@@ -40,6 +40,7 @@ base_schema = Schema(
40
40
  Required("do_not_optimize"): [str],
41
41
  Required("enable_always_target"): Any(bool, [str]),
42
42
  Required("existing_tasks"): {str: str},
43
+ Required("files_changed"): [str],
43
44
  Required("filters"): [str],
44
45
  Required("head_ref"): str,
45
46
  Required("head_repository"): str,
@@ -86,6 +87,7 @@ def _get_defaults(repo_root=None):
86
87
  # Use fake values if no repo is detected.
87
88
  repo = Mock(branch="", head_rev="", tool="git")
88
89
  repo.get_url.return_value = ""
90
+ repo.get_changed_files.return_value = []
89
91
 
90
92
  try:
91
93
  repo_url = repo.get_url()
@@ -108,6 +110,7 @@ def _get_defaults(repo_root=None):
108
110
  "do_not_optimize": [],
109
111
  "enable_always_target": True,
110
112
  "existing_tasks": {},
113
+ "files_changed": repo.get_changed_files("AM"),
111
114
  "filters": ["target_tasks_method"],
112
115
  "head_ref": repo.branch or repo.head_rev,
113
116
  "head_repository": repo_url,
@@ -20,6 +20,7 @@ from taskgraph.transforms.run import fetches_schema
20
20
  from taskgraph.util.attributes import attrmatch
21
21
  from taskgraph.util.dependencies import GROUP_BY_MAP, get_dependencies
22
22
  from taskgraph.util.schema import Schema, validate_schema
23
+ from taskgraph.util.set_name import SET_NAME_MAP
23
24
 
24
25
  FROM_DEPS_SCHEMA = Schema(
25
26
  {
@@ -41,12 +42,14 @@ FROM_DEPS_SCHEMA = Schema(
41
42
  "set-name",
42
43
  description=dedent(
43
44
  """
44
- When True, `from_deps` will derive a name for the generated
45
- tasks from the name of the primary dependency. Defaults to
46
- True.
45
+ UPDATE ME AND DOCS
47
46
  """.lstrip()
48
47
  ),
49
- ): bool,
48
+ ): Any(
49
+ None,
50
+ *SET_NAME_MAP,
51
+ {Any(*SET_NAME_MAP): object},
52
+ ),
50
53
  Optional(
51
54
  "with-attributes",
52
55
  description=dedent(
@@ -170,7 +173,7 @@ def from_deps(config, tasks):
170
173
  groups = func(config, deps)
171
174
 
172
175
  # Split the task, one per group.
173
- set_name = from_deps.get("set-name", True)
176
+ set_name = from_deps.get("set-name", "strip-kind")
174
177
  copy_attributes = from_deps.get("copy-attributes", False)
175
178
  unique_kinds = from_deps.get("unique-kinds", True)
176
179
  fetches = from_deps.get("fetches", [])
@@ -203,10 +206,8 @@ def from_deps(config, tasks):
203
206
  primary_dep = [dep for dep in group if dep.kind == primary_kind][0]
204
207
 
205
208
  if set_name:
206
- if primary_dep.label.startswith(primary_kind):
207
- new_task["name"] = primary_dep.label[len(primary_kind) + 1 :]
208
- else:
209
- new_task["name"] = primary_dep.label
209
+ func = SET_NAME_MAP[set_name]
210
+ new_task["name"] = func(config, deps, primary_dep, primary_kind)
210
211
 
211
212
  if copy_attributes:
212
213
  attrs = new_task.setdefault("attributes", {})
@@ -167,7 +167,8 @@ def add_resource_monitor(config, tasks):
167
167
  config.graph_config, task["worker-type"]
168
168
  )
169
169
  # Normalise worker os so that linux-bitbar and similar use linux tools.
170
- worker_os = worker_os.split("-")[0]
170
+ if worker_os:
171
+ worker_os = worker_os.split("-")[0]
171
172
  if "win7" in task["worker-type"]:
172
173
  arch = "32"
173
174
  else:
@@ -7,9 +7,7 @@ import hashlib
7
7
  import time
8
8
 
9
9
  TARGET_CACHE_INDEX = "{cache_prefix}.cache.level-{level}.{type}.{name}.hash.{digest}"
10
- TARGET_PR_CACHE_INDEX = (
11
- "{cache_prefix}.cache.head.{head_ref}.{type}.{name}.hash.{digest}"
12
- )
10
+ TARGET_PR_CACHE_INDEX = "{cache_prefix}.cache.pr.{type}.{name}.hash.{digest}"
13
11
  EXTRA_CACHE_INDEXES = [
14
12
  "{cache_prefix}.cache.level-{level}.{type}.{name}.latest",
15
13
  "{cache_prefix}.cache.level-{level}.{type}.{name}.pushdate.{build_date_long}",
@@ -7,6 +7,7 @@ import hashlib
7
7
  import io
8
8
  import os
9
9
  import re
10
+ from typing import Optional
10
11
 
11
12
  from taskgraph.util.archive import create_tar_gz_from_files
12
13
  from taskgraph.util.memoize import memoize
@@ -16,17 +17,27 @@ IMAGE_DIR = os.path.join(".", "taskcluster", "docker")
16
17
  from .yaml import load_yaml
17
18
 
18
19
 
19
- def docker_image(name, by_tag=False):
20
+ def docker_image(name: str, by_tag: bool = False) -> Optional[str]:
20
21
  """
21
22
  Resolve in-tree prebuilt docker image to ``<registry>/<repository>@sha256:<digest>``,
22
23
  or ``<registry>/<repository>:<tag>`` if `by_tag` is `True`.
24
+
25
+ Args:
26
+ name (str): The image to build.
27
+ by_tag (bool): If True, will apply a tag based on VERSION file.
28
+ Otherwise will apply a hash based on HASH file.
29
+ Returns:
30
+ Optional[str]: Image if it can be resolved, otherwise None.
23
31
  """
24
32
  try:
25
33
  with open(os.path.join(IMAGE_DIR, name, "REGISTRY")) as f:
26
34
  registry = f.read().strip()
27
35
  except OSError:
28
- with open(os.path.join(IMAGE_DIR, "REGISTRY")) as f:
29
- registry = f.read().strip()
36
+ try:
37
+ with open(os.path.join(IMAGE_DIR, "REGISTRY")) as f:
38
+ registry = f.read().strip()
39
+ except OSError:
40
+ return None
30
41
 
31
42
  if not by_tag:
32
43
  hashfile = os.path.join(IMAGE_DIR, name, "HASH")
@@ -34,7 +45,7 @@ def docker_image(name, by_tag=False):
34
45
  with open(hashfile) as f:
35
46
  return f"{registry}/{name}@{f.read().strip()}"
36
47
  except OSError:
37
- raise Exception(f"Failed to read HASH file {hashfile}")
48
+ return None
38
49
 
39
50
  try:
40
51
  with open(os.path.join(IMAGE_DIR, name, "VERSION")) as f:
@@ -0,0 +1,7 @@
1
+ # This Source Code Form is subject to the terms of the Mozilla Public
2
+ # License, v. 2.0. If a copy of the MPL was not distributed with this file,
3
+ # You can obtain one at http://mozilla.org/MPL/2.0/.
4
+
5
+ import functools
6
+
7
+ memoize = functools.lru_cache(maxsize=None) # backwards compatibility shim
@@ -83,10 +83,11 @@ def resolve_task_references(label, task_def, task_id, decision_task_id, dependen
83
83
  f"task '{label}' has no dependency named '{dependency}'"
84
84
  )
85
85
 
86
- assert artifact_name.startswith(
87
- "public/"
88
- ), f"artifact-reference only supports public artifacts, not `{artifact_name}`"
89
- return get_artifact_url(task_id, artifact_name)
86
+ use_proxy = False
87
+ if not artifact_name.startswith("public/"):
88
+ use_proxy = True
89
+
90
+ return get_artifact_url(task_id, artifact_name, use_proxy=use_proxy)
90
91
 
91
92
  return ARTIFACT_REFERENCE_PATTERN.sub(repl, val)
92
93
 
@@ -0,0 +1,34 @@
1
+ # This Source Code Form is subject to the terms of the Mozilla Public
2
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
+
5
+ # Define a collection of set_name functions
6
+ # Note: this is stored here instead of where it is used in the `from_deps`
7
+ # transform to give consumers a chance to register their own `set_name`
8
+ # handlers before the `from_deps` schema is created.
9
+ SET_NAME_MAP = {}
10
+
11
+
12
+ def set_name(name, schema=None):
13
+ def wrapper(func):
14
+ assert (
15
+ name not in SET_NAME_MAP
16
+ ), f"duplicate set_name function name {name} ({func} and {SET_NAME_MAP[name]})"
17
+ SET_NAME_MAP[name] = func
18
+ func.schema = schema
19
+ return func
20
+
21
+ return wrapper
22
+
23
+
24
+ @set_name("strip-kind")
25
+ def set_name_strip_kind(config, tasks, primary_dep, primary_kind):
26
+ if primary_dep.label.startswith(primary_kind):
27
+ return primary_dep.label[len(primary_kind) + 1 :]
28
+ else:
29
+ return primary_dep.label
30
+
31
+
32
+ @set_name("retain-kind")
33
+ def set_name_retain_kind(config, tasks, primary_dep, primary_kind):
34
+ return primary_dep.label
@@ -140,22 +140,9 @@ def _handle_artifact(path, response):
140
140
 
141
141
  def get_artifact_url(task_id, path, use_proxy=False):
142
142
  artifact_tmpl = liburls.api(
143
- get_root_url(False), "queue", "v1", "task/{}/artifacts/{}"
143
+ get_root_url(use_proxy), "queue", "v1", "task/{}/artifacts/{}"
144
144
  )
145
- data = artifact_tmpl.format(task_id, path)
146
- if use_proxy:
147
- # Until Bug 1405889 is deployed, we can't download directly
148
- # from the taskcluster-proxy. Work around by using the /bewit
149
- # endpoint instead.
150
- # The bewit URL is the body of a 303 redirect, which we don't
151
- # want to follow (which fetches a potentially large resource).
152
- response = _do_request(
153
- os.environ["TASKCLUSTER_PROXY_URL"] + "/bewit",
154
- data=data,
155
- allow_redirects=False,
156
- )
157
- return response.text
158
- return data
145
+ return artifact_tmpl.format(task_id, path)
159
146
 
160
147
 
161
148
  def get_artifact(task_id, path, use_proxy=False):
@@ -46,12 +46,16 @@ class TestDecision(unittest.TestCase):
46
46
  decision.ARTIFACTS_DIR = Path("artifacts")
47
47
 
48
48
 
49
+ @unittest.mock.patch.object(
50
+ GitRepository,
51
+ "get_changed_files",
52
+ )
49
53
  class TestGetDecisionParameters(unittest.TestCase):
50
54
  def setUp(self):
51
55
  self.options = {
52
56
  "base_repository": "https://hg.mozilla.org/mozilla-unified",
53
57
  "head_repository": "https://hg.mozilla.org/mozilla-central",
54
- "head_rev": "abcd",
58
+ "head_rev": "bbbb",
55
59
  "head_ref": "default",
56
60
  "head_tag": "v0.0.1",
57
61
  "project": "mozilla-central",
@@ -66,11 +70,11 @@ class TestGetDecisionParameters(unittest.TestCase):
66
70
  self.old_determine_more_accurate_base_rev = (
67
71
  decision._determine_more_accurate_base_rev
68
72
  )
69
- decision._determine_more_accurate_base_rev = lambda *_, **__: "abcd"
73
+ decision._determine_more_accurate_base_rev = lambda *_, **__: "aaaa"
70
74
  self.old_determine_more_accurate_base_ref = (
71
75
  decision._determine_more_accurate_base_ref
72
76
  )
73
- decision._determine_more_accurate_base_ref = lambda *_, **__: "abcd"
77
+ decision._determine_more_accurate_base_ref = lambda *_, **__: "aaaa"
74
78
 
75
79
  def tearDown(self):
76
80
  decision._determine_more_accurate_base_rev = (
@@ -80,14 +84,18 @@ class TestGetDecisionParameters(unittest.TestCase):
80
84
  self.old_determine_more_accurate_base_ref
81
85
  )
82
86
 
83
- def test_simple_options(self):
87
+ def test_simple_options(self, mock_files_changed):
88
+ mock_files_changed.return_value = ["foo.txt"]
84
89
  params = decision.get_decision_parameters(FAKE_GRAPH_CONFIG, self.options)
90
+ mock_files_changed.assert_called_once_with(rev="bbbb", base_rev="aaaa")
85
91
  self.assertEqual(params["build_date"], 1503691511)
86
92
  self.assertEqual(params["head_tag"], "v0.0.1")
87
93
  self.assertEqual(params["pushlog_id"], "143")
88
94
  self.assertEqual(params["moz_build_date"], "20170825200511")
95
+ self.assertEqual(params["files_changed"], ["foo.txt"])
89
96
 
90
- def test_no_email_owner(self):
97
+ def test_no_email_owner(self, mock_files_changed):
98
+ mock_files_changed.return_value = ["foo.txt"]
91
99
  self.options["owner"] = "ffxbld"
92
100
  params = decision.get_decision_parameters(FAKE_GRAPH_CONFIG, self.options)
93
101
  self.assertEqual(params["owner"], "ffxbld@noreply.mozilla.org")
@@ -102,11 +110,14 @@ class TestGetDecisionParameters(unittest.TestCase):
102
110
  "get_commit_message",
103
111
  unittest.mock.MagicMock(return_value="Add Foo"),
104
112
  )
105
- def test_regular_commit_message_yields_default_target_tasks_method(self):
113
+ def test_regular_commit_message_yields_default_target_tasks_method(
114
+ self, mock_files_changed
115
+ ):
106
116
  """
107
117
  Ensures `target_tasks_method` is `default` when the commit message does not contain
108
118
  `DONTBUILD`.
109
119
  """
120
+ mock_files_changed.return_value = ["foo.txt"]
110
121
  self.options["tasks_for"] = "github-push"
111
122
  params = decision.get_decision_parameters(FAKE_GRAPH_CONFIG, self.options)
112
123
  self.assertEqual(params["target_tasks_method"], "default")
@@ -125,10 +136,13 @@ class TestGetDecisionParameters(unittest.TestCase):
125
136
  "get_commit_message",
126
137
  unittest.mock.MagicMock(return_value="DONTBUILD"),
127
138
  )
128
- def test_dontbuild_commit_message_yields_default_target_tasks_method(self):
139
+ def test_dontbuild_commit_message_yields_default_target_tasks_method(
140
+ self, mock_files_changed
141
+ ):
129
142
  """
130
143
  Ensures `target_tasks_method` is `nothing` when the commit message contains `DONTBUILD`.
131
144
  """
145
+ mock_files_changed.return_value = ["foo.txt"]
132
146
  self.options["tasks_for"] = "github-release"
133
147
  params = decision.get_decision_parameters(FAKE_GRAPH_CONFIG, self.options)
134
148
  self.assertNotEqual(params["target_tasks_method"], "nothing")
@@ -0,0 +1,55 @@
1
+ import pytest
2
+
3
+ from taskgraph import docker
4
+
5
+
6
+ @pytest.fixture(autouse=True, scope="module")
7
+ def mock_docker_path(module_mocker, datadir):
8
+ module_mocker.patch(
9
+ "taskgraph.util.docker.IMAGE_DIR", str(datadir / "taskcluster" / "docker")
10
+ )
11
+
12
+
13
+ @pytest.fixture
14
+ def mock_docker_build(mocker):
15
+ def side_effect(topsrcdir, context_dir, out_file, image_name=None, args=None):
16
+ out_file.write(b"xyz")
17
+
18
+ m_stream = mocker.patch.object(docker.docker, "stream_context_tar")
19
+ m_stream.side_effect = side_effect
20
+
21
+ m_run = mocker.patch.object(docker.subprocess, "run")
22
+ return (m_stream, m_run)
23
+
24
+
25
+ def test_build_image(capsys, mock_docker_build):
26
+ m_stream, m_run = mock_docker_build
27
+ image = "hello-world-tag"
28
+ tag = f"test/{image}:1.0"
29
+
30
+ assert docker.build_image(image, None) is None
31
+ m_stream.assert_called_once()
32
+ m_run.assert_called_once_with(
33
+ ["docker", "image", "build", "--no-cache", f"-t={tag}", "-"],
34
+ input=b"xyz",
35
+ )
36
+
37
+ out, _ = capsys.readouterr()
38
+ assert f"Successfully built {image} and tagged with {tag}" in out
39
+ assert "Image is not suitable for deploying/pushing" not in out
40
+
41
+
42
+ def test_build_image_no_tag(capsys, mock_docker_build):
43
+ m_stream, m_run = mock_docker_build
44
+ image = "hello-world"
45
+
46
+ assert docker.build_image(image, None) is None
47
+ m_stream.assert_called_once()
48
+ m_run.assert_called_once_with(
49
+ ["docker", "image", "build", "--no-cache", "-"],
50
+ input=b"xyz",
51
+ )
52
+
53
+ out, _ = capsys.readouterr()
54
+ assert f"Successfully built {image}" in out
55
+ assert "Image is not suitable for deploying/pushing" in out