scriptworker 63.0.0__tar.gz → 63.1.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.
- {scriptworker-63.0.0 → scriptworker-63.1.0}/HISTORY.rst +17 -0
- {scriptworker-63.0.0 → scriptworker-63.1.0}/PKG-INFO +1 -1
- {scriptworker-63.0.0 → scriptworker-63.1.0}/pyproject.toml +18 -31
- {scriptworker-63.0.0 → scriptworker-63.1.0}/src/scriptworker/artifacts.py +3 -0
- {scriptworker-63.0.0 → scriptworker-63.1.0}/src/scriptworker/context.py +10 -0
- {scriptworker-63.0.0 → scriptworker-63.1.0}/src/scriptworker/cot/verify.py +17 -9
- {scriptworker-63.0.0 → scriptworker-63.1.0}/src/scriptworker/ed25519.py +4 -2
- {scriptworker-63.0.0 → scriptworker-63.1.0}/src/scriptworker/github.py +2 -2
- {scriptworker-63.0.0 → scriptworker-63.1.0}/src/scriptworker/task.py +11 -2
- {scriptworker-63.0.0 → scriptworker-63.1.0}/src/scriptworker/task_process.py +1 -1
- {scriptworker-63.0.0 → scriptworker-63.1.0}/src/scriptworker/utils.py +23 -10
- {scriptworker-63.0.0 → scriptworker-63.1.0}/src/scriptworker/worker.py +1 -1
- {scriptworker-63.0.0 → scriptworker-63.1.0}/tox.ini +3 -12
- {scriptworker-63.0.0 → scriptworker-63.1.0}/.gitignore +0 -0
- {scriptworker-63.0.0 → scriptworker-63.1.0}/CONTRIBUTING.rst +0 -0
- {scriptworker-63.0.0 → scriptworker-63.1.0}/LICENSE +0 -0
- {scriptworker-63.0.0 → scriptworker-63.1.0}/README.rst +0 -0
- {scriptworker-63.0.0 → scriptworker-63.1.0}/renovate.json +0 -0
- {scriptworker-63.0.0 → scriptworker-63.1.0}/scripts/gen_ed25519_key.py +0 -0
- {scriptworker-63.0.0 → scriptworker-63.1.0}/scriptworker.yaml.tmpl +0 -0
- {scriptworker-63.0.0 → scriptworker-63.1.0}/src/scriptworker/__init__.py +0 -0
- {scriptworker-63.0.0 → scriptworker-63.1.0}/src/scriptworker/client.py +0 -0
- {scriptworker-63.0.0 → scriptworker-63.1.0}/src/scriptworker/config.py +0 -0
- {scriptworker-63.0.0 → scriptworker-63.1.0}/src/scriptworker/constants.py +0 -0
- {scriptworker-63.0.0 → scriptworker-63.1.0}/src/scriptworker/cot/__init__.py +0 -0
- {scriptworker-63.0.0 → scriptworker-63.1.0}/src/scriptworker/cot/generate.py +0 -0
- {scriptworker-63.0.0 → scriptworker-63.1.0}/src/scriptworker/data/cot_v1_schema.json +0 -0
- {scriptworker-63.0.0 → scriptworker-63.1.0}/src/scriptworker/data/scriptworker_task_schema.json +0 -0
- {scriptworker-63.0.0 → scriptworker-63.1.0}/src/scriptworker/exceptions.py +0 -0
- {scriptworker-63.0.0 → scriptworker-63.1.0}/src/scriptworker/log.py +0 -0
|
@@ -4,6 +4,23 @@ Change Log
|
|
|
4
4
|
All notable changes to this project will be documented in this file.
|
|
5
5
|
This project adheres to `Semantic Versioning <http://semver.org/>`__.
|
|
6
6
|
|
|
7
|
+
63.1.0 - 2026-05-26
|
|
8
|
+
-------------------
|
|
9
|
+
|
|
10
|
+
Added
|
|
11
|
+
~~~~~
|
|
12
|
+
- The TASKCLUSTER_CREDENTIALS_FD environment variable is passed to scripts, and
|
|
13
|
+
the referenced file descriptor (a memfd) contains temporary taskcluster
|
|
14
|
+
credentials using the task's scopes, updated after each reclaimTask
|
|
15
|
+
|
|
16
|
+
63.0.1 - 2026-04-27
|
|
17
|
+
-------------------
|
|
18
|
+
|
|
19
|
+
Fixed
|
|
20
|
+
~~~~~
|
|
21
|
+
|
|
22
|
+
- File corruption caused by parallel downloads (#792)
|
|
23
|
+
|
|
7
24
|
63.0.0 - 2026-04-09
|
|
8
25
|
-------------------
|
|
9
26
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "scriptworker"
|
|
3
|
-
version = "63.
|
|
3
|
+
version = "63.1.0"
|
|
4
4
|
description = "Taskcluster scriptworker"
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "Mozilla Release Engineering", email = "releng@mozilla.com" },
|
|
@@ -43,11 +43,8 @@ dev = [
|
|
|
43
43
|
"tox-uv",
|
|
44
44
|
"aiohttp>=3",
|
|
45
45
|
"asyncio_extras",
|
|
46
|
-
"black",
|
|
47
46
|
"coveralls",
|
|
48
|
-
"
|
|
49
|
-
"flake8_docstrings",
|
|
50
|
-
"isort>=5",
|
|
47
|
+
"ruff",
|
|
51
48
|
"mock",
|
|
52
49
|
"pytest",
|
|
53
50
|
"pytest-asyncio",
|
|
@@ -85,34 +82,24 @@ verify_cot = "scriptworker.cot.verify:verify_cot_cmdln"
|
|
|
85
82
|
create_test_workdir = "scriptworker.cot.verify:create_test_workdir"
|
|
86
83
|
verify_ed25519_signature = "scriptworker.ed25519:verify_ed25519_signature_cmdln"
|
|
87
84
|
|
|
88
|
-
[tool.
|
|
85
|
+
[tool.ruff]
|
|
89
86
|
line-length = 160
|
|
90
|
-
target-version =
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
| buck-out
|
|
104
|
-
| build
|
|
105
|
-
| dist
|
|
106
|
-
| ui
|
|
107
|
-
)/
|
|
108
|
-
'''
|
|
87
|
+
target-version = "py311"
|
|
88
|
+
extend-exclude = [
|
|
89
|
+
"docs"
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
[tool.ruff.lint]
|
|
93
|
+
# F = pyflakes, E/W = pycodestyle, I = isort, D = pydocstyle
|
|
94
|
+
select = ["F", "E", "W", "I", "D"]
|
|
95
|
+
|
|
96
|
+
[tool.ruff.lint.per-file-ignores]
|
|
97
|
+
"tests/**" = ["D"]
|
|
98
|
+
"tests/test_github.py" = ["D", "E501"] # ignore long lines in test_github.py
|
|
99
|
+
|
|
109
100
|
|
|
110
|
-
[tool.
|
|
111
|
-
|
|
112
|
-
include_trailing_comma = true
|
|
113
|
-
force_grid_wrap = 0
|
|
114
|
-
use_parentheses = true
|
|
115
|
-
line_length = 160
|
|
101
|
+
[tool.ruff.lint.pydocstyle]
|
|
102
|
+
convention = "pep257"
|
|
116
103
|
|
|
117
104
|
[tool.pytest.ini_options]
|
|
118
105
|
asyncio_mode = "auto"
|
|
@@ -225,6 +225,7 @@ def get_artifact_url(context, task_id, path):
|
|
|
225
225
|
|
|
226
226
|
# list_latest_artifacts {{{1
|
|
227
227
|
async def list_latest_artifacts(queue, task_id):
|
|
228
|
+
"""List all artifacts for the latest run of a task, following pagination."""
|
|
228
229
|
artifacts = []
|
|
229
230
|
|
|
230
231
|
def pagination_handler(response):
|
|
@@ -235,6 +236,7 @@ async def list_latest_artifacts(queue, task_id):
|
|
|
235
236
|
|
|
236
237
|
|
|
237
238
|
async def retry_list_latest_artifacts(queue, task_id, exception=TaskclusterFailure, **kwargs):
|
|
239
|
+
"""Retry ``list_latest_artifacts`` on transient Taskcluster failures."""
|
|
238
240
|
kwargs.setdefault("retry_exceptions", tuple(set([TaskclusterFailure, exception])))
|
|
239
241
|
return await retry_async(list_latest_artifacts, args=(queue, task_id), **kwargs)
|
|
240
242
|
|
|
@@ -442,6 +444,7 @@ def assert_is_parent(path, parent_dir):
|
|
|
442
444
|
|
|
443
445
|
|
|
444
446
|
def get_artifacts_matching_glob(context, task_id, pattern):
|
|
447
|
+
"""Return paths of downloaded artifacts matching ``pattern`` under the task's cot/<id> dir."""
|
|
445
448
|
parent_dir = os.path.abspath(os.path.join(context.config["work_dir"], "cot", task_id))
|
|
446
449
|
matching = []
|
|
447
450
|
for root, _, files in os.walk(parent_dir):
|
|
@@ -59,6 +59,7 @@ class Context(object):
|
|
|
59
59
|
|
|
60
60
|
config: Optional[Dict[str, Any]] = None
|
|
61
61
|
credentials_timestamp: Optional[int] = None
|
|
62
|
+
credentials_fd: int = -1
|
|
62
63
|
proc: Optional[task_process.TaskProcess] = None
|
|
63
64
|
queue: Optional[Queue] = None
|
|
64
65
|
session: Optional[aiohttp.ClientSession] = None
|
|
@@ -98,6 +99,8 @@ class Context(object):
|
|
|
98
99
|
if claim_task:
|
|
99
100
|
self.task = claim_task["task"]
|
|
100
101
|
self.verify_task()
|
|
102
|
+
# flags=0 to let the child inherit this fd
|
|
103
|
+
self.credentials_fd = os.memfd_create("scriptworker_temp_creds", flags=0)
|
|
101
104
|
self.temp_credentials = claim_task["credentials"]
|
|
102
105
|
path = os.path.join(self.config["work_dir"], "task.json")
|
|
103
106
|
assert self.task
|
|
@@ -105,6 +108,8 @@ class Context(object):
|
|
|
105
108
|
else:
|
|
106
109
|
self.temp_credentials = None
|
|
107
110
|
self.task = None
|
|
111
|
+
os.close(self.credentials_fd)
|
|
112
|
+
self.credentials_fd = -1
|
|
108
113
|
|
|
109
114
|
def verify_task(self) -> None:
|
|
110
115
|
"""Run some task sanity checks on ``self.task``."""
|
|
@@ -193,6 +198,10 @@ class Context(object):
|
|
|
193
198
|
def temp_credentials(self, credentials: Optional[Dict[str, Any]]) -> None:
|
|
194
199
|
self._temp_credentials = credentials
|
|
195
200
|
self.temp_queue = self.create_queue(self.temp_credentials)
|
|
201
|
+
if credentials:
|
|
202
|
+
data = json.dumps(credentials, indent=2, sort_keys=True).encode("ascii")
|
|
203
|
+
# use pwrite so we don't confuse the child by changing the file offset
|
|
204
|
+
assert os.pwrite(self.credentials_fd, data, 0) == len(data)
|
|
196
205
|
|
|
197
206
|
def write_json(self, path: str, contents: Dict[str, Any], message: str) -> None:
|
|
198
207
|
"""Write json to disk.
|
|
@@ -261,6 +270,7 @@ class Context(object):
|
|
|
261
270
|
|
|
262
271
|
@property
|
|
263
272
|
def download_semaphore(self) -> asyncio.BoundedSemaphore:
|
|
273
|
+
"""Return a lazily-built semaphore limiting concurrent downloads to ``max_concurrent_downloads``."""
|
|
264
274
|
assert self.config
|
|
265
275
|
if self._download_semaphore is None:
|
|
266
276
|
try:
|
|
@@ -180,7 +180,8 @@ class ChainOfTrust(object):
|
|
|
180
180
|
|
|
181
181
|
def is_scope_in_restricted_scopes(self, scope, restricted_scopes):
|
|
182
182
|
"""Determine if a scope matches in a list of restricted_scopes.
|
|
183
|
-
|
|
183
|
+
|
|
184
|
+
If one of the restricted scopes ends with '*', find a partial match.
|
|
184
185
|
|
|
185
186
|
Returns:
|
|
186
187
|
String: string of matching restricted_scope, if no match ""
|
|
@@ -728,8 +729,10 @@ async def download_cot_artifact(chain, task_id, path):
|
|
|
728
729
|
link = chain.get_link(task_id)
|
|
729
730
|
log.debug("Verifying {} is in {} cot artifacts...".format(path, task_id))
|
|
730
731
|
if not link.cot:
|
|
731
|
-
log.warning(
|
|
732
|
-
|
|
732
|
+
log.warning(
|
|
733
|
+
'Chain of Trust for "{}" in {} does not exist. See above log for more details. \
|
|
734
|
+
Skipping download of this artifact'.format(path, task_id)
|
|
735
|
+
)
|
|
733
736
|
return
|
|
734
737
|
|
|
735
738
|
if path not in link.cot["artifacts"]:
|
|
@@ -1094,8 +1097,9 @@ async def _get_additional_hg_push_jsone_context(parent_link, decision_link):
|
|
|
1094
1097
|
allowed_comments.append(push_comment[try_idx:].split("\n")[0])
|
|
1095
1098
|
if decision_comment not in allowed_comments:
|
|
1096
1099
|
raise CoTError(
|
|
1097
|
-
"Decision task {} comment doesn't match the push comment!\n"
|
|
1098
|
-
|
|
1100
|
+
"Decision task {} comment doesn't match the push comment!\nDecision comment: \n{}\nPush comment: \n{}".format(
|
|
1101
|
+
decision_link.name, decision_comment, push_comment
|
|
1102
|
+
)
|
|
1099
1103
|
)
|
|
1100
1104
|
return {
|
|
1101
1105
|
"push": {
|
|
@@ -2113,7 +2117,8 @@ def verify_cot_cmdln(args=None, event_loop=None):
|
|
|
2113
2117
|
|
|
2114
2118
|
"""
|
|
2115
2119
|
args = args or sys.argv[1:]
|
|
2116
|
-
parser = argparse.ArgumentParser(
|
|
2120
|
+
parser = argparse.ArgumentParser(
|
|
2121
|
+
description="""Verify a given task's chain of trust.
|
|
2117
2122
|
|
|
2118
2123
|
Given a task's `task_id`, get its task definition, then trace its chain of
|
|
2119
2124
|
trust back to the tree. This doesn't verify chain of trust artifact signatures,
|
|
@@ -2125,7 +2130,8 @@ To use, first either set your taskcluster creds in your env http://bit.ly/2eDMa6
|
|
|
2125
2130
|
or in the CREDS_FILES http://bit.ly/2fVMu0A
|
|
2126
2131
|
|
|
2127
2132
|
If you are verifying against a private github repo, please also set in environment
|
|
2128
|
-
SCRIPTWORKER_GITHUB_OAUTH_TOKEN to an OAUTH token with read permissions to the repo"""
|
|
2133
|
+
SCRIPTWORKER_GITHUB_OAUTH_TOKEN to an OAUTH token with read permissions to the repo"""
|
|
2134
|
+
)
|
|
2129
2135
|
parser.add_argument("task_id", help="the task id to test")
|
|
2130
2136
|
parser.add_argument("--task-type", help="the task type to test", choices=sorted(get_valid_task_types().keys()), required=True)
|
|
2131
2137
|
parser.add_argument("--cleanup", help="clean up the temp dir afterwards", dest="cleanup", action="store_true", default=False)
|
|
@@ -2192,13 +2198,15 @@ def create_test_workdir(args=None, event_loop=None):
|
|
|
2192
2198
|
|
|
2193
2199
|
"""
|
|
2194
2200
|
args = args or sys.argv[1:]
|
|
2195
|
-
parser = argparse.ArgumentParser(
|
|
2201
|
+
parser = argparse.ArgumentParser(
|
|
2202
|
+
description="""Populate a test `work_dir`.
|
|
2196
2203
|
|
|
2197
2204
|
Given a scriptworker task's `task_id`, get its task definition, write it to
|
|
2198
2205
|
`./work/task.json`, then download its `upstreamArtifacts` and put them in
|
|
2199
2206
|
`./work/cot/TASK_ID/PATH`.
|
|
2200
2207
|
|
|
2201
|
-
This is helpful in manually testing a *script run."""
|
|
2208
|
+
This is helpful in manually testing a *script run."""
|
|
2209
|
+
)
|
|
2202
2210
|
parser.add_argument("--path", help="relative path to the work_dir", default="work")
|
|
2203
2211
|
parser.add_argument("--overwrite", help="overwrite an existing work_dir", action="store_true")
|
|
2204
2212
|
parser.add_argument("task_id", help="the task id to test")
|
|
@@ -141,11 +141,13 @@ def verify_ed25519_signature_cmdln(args=None, exception=SystemExit):
|
|
|
141
141
|
|
|
142
142
|
"""
|
|
143
143
|
args = args or sys.argv[1:]
|
|
144
|
-
parser = argparse.ArgumentParser(
|
|
144
|
+
parser = argparse.ArgumentParser(
|
|
145
|
+
description="""Verify an ed25519 signature from the command line.
|
|
145
146
|
|
|
146
147
|
Given a file and its detached signature, verify that it has been signed with
|
|
147
148
|
a valid key. This key can be specified on the command line; otherwise we'll
|
|
148
|
-
default to ``config['ed25519_public_keys']``."""
|
|
149
|
+
default to ``config['ed25519_public_keys']``."""
|
|
150
|
+
)
|
|
149
151
|
parser.add_argument("--pubkey", help="path to a base64-encoded ed25519 pubkey, optional")
|
|
150
152
|
parser.add_argument("file_path")
|
|
151
153
|
parser.add_argument("sig_path")
|
|
@@ -121,7 +121,7 @@ class GitHubRepository:
|
|
|
121
121
|
if any(vcs_rule.get("require_secret") for vcs_rule in context.config["trusted_vcs_rules"]):
|
|
122
122
|
# This check uses unofficial API on github, which we can't easily
|
|
123
123
|
# check for private repos, assume its true in the private case.
|
|
124
|
-
log.info("has_commit_landed_on_repository() not implemented for private
|
|
124
|
+
log.info("has_commit_landed_on_repository() not implemented for private repositories, assume True")
|
|
125
125
|
return True
|
|
126
126
|
|
|
127
127
|
# Revision may be a tag name. `branch_commits` doesn't work on tags
|
|
@@ -293,7 +293,7 @@ def is_github_repo_owner_the_official_one(context, repo_owner):
|
|
|
293
293
|
official_repo_owner = context.config["official_github_repos_owner"]
|
|
294
294
|
if not official_repo_owner:
|
|
295
295
|
raise ConfigError(
|
|
296
|
-
|
|
296
|
+
'This worker does not have a defined owner for official GitHub repositories. Given "official_github_repos_owner": {}'.format(official_repo_owner)
|
|
297
297
|
)
|
|
298
298
|
|
|
299
299
|
return official_repo_owner == repo_owner
|
|
@@ -117,7 +117,7 @@ def get_run_id(claim_task):
|
|
|
117
117
|
|
|
118
118
|
# get_task_maxruntime {{{1
|
|
119
119
|
def get_task_maxruntime(task_def, max_timeout):
|
|
120
|
-
"""Given a task definition, return the lower of max_timeout and maxRunTime if set"""
|
|
120
|
+
"""Given a task definition, return the lower of max_timeout and maxRunTime if set."""
|
|
121
121
|
max_run_time = task_def["payload"].get("maxRunTime")
|
|
122
122
|
if max_run_time is None:
|
|
123
123
|
return max_timeout
|
|
@@ -672,7 +672,16 @@ async def run_task(context, to_cancellable_process):
|
|
|
672
672
|
env["TASK_ID"] = context.task_id or "None"
|
|
673
673
|
env["RUN_ID"] = str(get_run_id(context.claim_task))
|
|
674
674
|
env["TASKCLUSTER_ROOT_URL"] = context.config["taskcluster_root_url"]
|
|
675
|
-
|
|
675
|
+
env["TASKCLUSTER_CREDENTIALS_FD"] = str(context.credentials_fd)
|
|
676
|
+
kwargs = {
|
|
677
|
+
"stdout": PIPE,
|
|
678
|
+
"stderr": PIPE,
|
|
679
|
+
"stdin": None,
|
|
680
|
+
"close_fds": True,
|
|
681
|
+
"preexec_fn": lambda: os.setsid(),
|
|
682
|
+
"env": env,
|
|
683
|
+
"pass_fds": (context.credentials_fd,),
|
|
684
|
+
} # pragma: no branch
|
|
676
685
|
|
|
677
686
|
timeout = get_task_maxruntime(context.task, context.config["task_max_timeout"])
|
|
678
687
|
subprocess = await asyncio.create_subprocess_exec(*context.config["task_script"], **kwargs)
|
|
@@ -16,6 +16,7 @@ import random
|
|
|
16
16
|
import re
|
|
17
17
|
import shutil
|
|
18
18
|
import time
|
|
19
|
+
import uuid
|
|
19
20
|
from copy import deepcopy
|
|
20
21
|
from typing import IO, TYPE_CHECKING, Any, Awaitable, Callable, Dict, Match, Optional, Sequence, Tuple, Type, Union, cast, overload # noqa
|
|
21
22
|
from urllib.parse import unquote, urlparse
|
|
@@ -41,6 +42,7 @@ log = logging.getLogger(__name__)
|
|
|
41
42
|
|
|
42
43
|
# scriptworker_session {{{1
|
|
43
44
|
def scriptworker_session(*args, **kwargs):
|
|
45
|
+
"""Return an ``aiohttp.ClientSession`` with the scriptworker User-Agent header set."""
|
|
44
46
|
kwargs.setdefault("headers", {}).setdefault("User-Agent", f"scriptworker {scriptworker.__version__}")
|
|
45
47
|
return aiohttp.ClientSession(*args, **kwargs)
|
|
46
48
|
|
|
@@ -680,12 +682,21 @@ async def download_file(context, url, abs_filename, session=None, chunk_size=128
|
|
|
680
682
|
await _log_download_error(resp, "Failed to download %(url)s: %(status)s; body=%(body)s")
|
|
681
683
|
raise DownloadError("{} status {} is not 200!".format(loggable_url, resp.status))
|
|
682
684
|
makedirs(parent_dir)
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
685
|
+
tmp_filename = "{}.{}.part".format(abs_filename, uuid.uuid4().hex)
|
|
686
|
+
try:
|
|
687
|
+
with open(tmp_filename, "wb") as fd:
|
|
688
|
+
while True:
|
|
689
|
+
chunk = await resp.content.read(chunk_size)
|
|
690
|
+
if not chunk:
|
|
691
|
+
break
|
|
692
|
+
fd.write(chunk)
|
|
693
|
+
os.replace(tmp_filename, abs_filename)
|
|
694
|
+
except Exception:
|
|
695
|
+
try:
|
|
696
|
+
os.unlink(tmp_filename)
|
|
697
|
+
except OSError:
|
|
698
|
+
pass
|
|
699
|
+
raise
|
|
689
700
|
log.info("Done")
|
|
690
701
|
|
|
691
702
|
|
|
@@ -865,8 +876,9 @@ def remove_empty_keys(values, remove=({}, None, [], "null")):
|
|
|
865
876
|
|
|
866
877
|
# add_projectid {{{1
|
|
867
878
|
def add_projectid(task_def):
|
|
868
|
-
"""Add a projectId property to a task, if none already exists
|
|
869
|
-
|
|
879
|
+
"""Add a projectId property to a task, if none already exists.
|
|
880
|
+
|
|
881
|
+
Uses the Taskcluster default value of 'none'.
|
|
870
882
|
|
|
871
883
|
Args:
|
|
872
884
|
task_def (dict): the task definition
|
|
@@ -879,8 +891,9 @@ def add_projectid(task_def):
|
|
|
879
891
|
|
|
880
892
|
# add_taskqueueid {{{1
|
|
881
893
|
def add_taskqueueid(task_def):
|
|
882
|
-
"""Add a taskQueueId property to a task, if none already exists
|
|
883
|
-
|
|
894
|
+
"""Add a taskQueueId property to a task, if none already exists.
|
|
895
|
+
|
|
896
|
+
Builds the value from the provisionerId and workerType, then removes those two properties.
|
|
884
897
|
|
|
885
898
|
Args:
|
|
886
899
|
task_def (dict): the task definition
|
|
@@ -54,25 +54,16 @@ commands=
|
|
|
54
54
|
|
|
55
55
|
[testenv:check]
|
|
56
56
|
skip_install = true
|
|
57
|
+
deps = ruff
|
|
57
58
|
commands =
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
flake8 {toxinidir}
|
|
59
|
+
ruff check {toxinidir}
|
|
60
|
+
ruff format --check {toxinidir}
|
|
61
61
|
|
|
62
62
|
[testenv:mypy]
|
|
63
63
|
commands =
|
|
64
64
|
mypy --config {toxinidir}/mypi.ini {toxinidir}/src
|
|
65
65
|
|
|
66
66
|
|
|
67
|
-
[flake8]
|
|
68
|
-
max-line-length = 160
|
|
69
|
-
# test_github.py ignored because of https://gitlab.com/pycqa/flake8/issues/375
|
|
70
|
-
exclude = .ropeproject,.tox,sandbox,docs,.eggs,*.egg,*.egg-info,setup.py,build/,tests/test_github.py,.venv
|
|
71
|
-
per-file-ignores =
|
|
72
|
-
# Ignore documentation issues in tests
|
|
73
|
-
tests:*:D
|
|
74
|
-
show-source = True
|
|
75
|
-
|
|
76
67
|
[pytest]
|
|
77
68
|
norecursedirs = .tox .git .hg sandbox .eggs build
|
|
78
69
|
python_files = test_*.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scriptworker-63.0.0 → scriptworker-63.1.0}/src/scriptworker/data/scriptworker_task_schema.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|