taskcluster-taskgraph 19.2.0__tar.gz → 20.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/.pre-commit-config.yaml +3 -3
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/CHANGELOG.md +19 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/PKG-INFO +1 -1
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/reference/migrations.rst +8 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/pyproject.toml +1 -1
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/generator.py +46 -26
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/run-task/run-task +4 -4
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/transforms/task.py +4 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/schema.py +89 -24
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/vcs.py +5 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/config.yml +1 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/kinds/test/linux.yml +20 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_generator.py +30 -2
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_scripts_run_task.py +2 -2
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_util_schema.py +52 -17
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_util_vcs.py +54 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/uv.lock +2 -2
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/.codespell-ignore-words.txt +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/.github/CODEOWNERS +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/.github/dependabot.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/.github/workflows/codeql-analysis.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/.github/workflows/pre-commit-autoupdate.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/.github/workflows/pre-commit.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/.github/workflows/pypi-publish.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/.gitignore +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/.readthedocs.yaml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/.taskcluster.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/.yamllint +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/CODE_OF_CONDUCT.md +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/CONTRIBUTING.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/LICENSE +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/Makefile +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/README.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/concepts/index.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/concepts/kind.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/concepts/loading.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/concepts/optimization.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/concepts/overview.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/concepts/scopes.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/concepts/task-graphs.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/concepts/transforms.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/conf.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/contributing.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/glossary.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/howto/bootstrap-taskgraph.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/howto/create-actions.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/howto/create-tasks.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/howto/debugging.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/howto/docker.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/howto/index.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/howto/load-task-locally.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/howto/resolve-keyed-by.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/howto/run-locally.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/howto/send-notifications.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/howto/use-fetches.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/index.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/reference/cli.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/reference/index.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/reference/optimization-strategies.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/reference/parameters.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/reference/source/modules.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/reference/source/taskgraph.actions.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/reference/source/taskgraph.loader.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/reference/source/taskgraph.optimize.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/reference/source/taskgraph.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/reference/source/taskgraph.transforms.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/reference/source/taskgraph.transforms.run.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/reference/source/taskgraph.util.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/reference/transforms/chunking.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/reference/transforms/from_deps.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/reference/transforms/index.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/reference/transforms/matrix.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/reference/transforms/task_context.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/tutorials/connecting-taskcluster.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/tutorials/creating-a-task-graph.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/tutorials/example-taskcluster.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/tutorials/getting-started.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/docs/tutorials/index.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/make.bat +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/packages/pytest-taskgraph/README.md +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/packages/pytest-taskgraph/pyproject.toml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/packages/pytest-taskgraph/src/pytest_taskgraph/__init__.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/packages/pytest-taskgraph/src/pytest_taskgraph/fixtures/gen.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/packages/pytest-taskgraph/src/pytest_taskgraph/fixtures/vcs.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/packages/sphinx-taskgraph/README.md +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/packages/sphinx-taskgraph/pyproject.toml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/packages/sphinx-taskgraph/src/sphinx_taskgraph/__init__.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/packages/sphinx-taskgraph/src/sphinx_taskgraph/autoschema.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/__init__.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/actions/__init__.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/actions/add_new_jobs.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/actions/cancel.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/actions/cancel_all.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/actions/rebuild_cached_tasks.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/actions/registry.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/actions/retrigger.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/actions/util.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/config.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/create.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/decision.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/docker.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/filter_tasks.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/graph.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/loader/__init__.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/loader/default.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/loader/transform.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/main.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/morph.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/optimize/__init__.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/optimize/base.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/optimize/strategies.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/parameters.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/run-task/fetch-content +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/run-task/hgrc +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/run-task/robustcheckout.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/target_tasks.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/task.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/taskgraph.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/transforms/__init__.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/transforms/base.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/transforms/cached_tasks.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/transforms/chunking.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/transforms/code_review.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/transforms/docker_image.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/transforms/fetch.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/transforms/from_deps.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/transforms/matrix.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/transforms/notify.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/transforms/run/__init__.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/transforms/run/common.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/transforms/run/index_search.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/transforms/run/run_task.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/transforms/run/toolchain.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/transforms/task_context.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/__init__.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/archive.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/attributes.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/cached_tasks.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/caches.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/copy.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/dependencies.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/docker.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/hash.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/json.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/keyed_by.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/parameterization.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/path.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/python_path.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/readonlydict.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/set_name.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/shell.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/taskcluster.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/taskgraph.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/templates.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/time.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/treeherder.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/verify.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/workertypes.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/util/yaml.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/docker/REGISTRY +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/docker/decision/Dockerfile +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/docker/decision/HASH +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/docker/decision/README.md +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/docker/decision/VERSION +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/docker/decision/system-setup.sh +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/docker/fetch/Dockerfile +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/docker/image_builder/README.rst +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/docker/index-task/Dockerfile +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/docker/index-task/README +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/docker/index-task/insert-indexes.js +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/docker/index-task/package.json +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/docker/index-task/yarn.lock +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/docker/python/Dockerfile +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/docker/run-task/Dockerfile +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/docker/run-task/system-setup.sh +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/docker/skopeo/Dockerfile +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/docker/skopeo/policy.json +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/docker/skopeo/push_image.sh +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/kinds/check/kind.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/kinds/codecov/kind.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/kinds/complete/kind.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/kinds/doc/kind.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/kinds/docker-image/kind.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/kinds/fetch/kind.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/kinds/push-image/kind.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/kinds/test/kind.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/kinds/test/windows.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/scripts/codecov-upload.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/scripts/external_tools/tooltool.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/self_taskgraph/__init__.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/self_taskgraph/custom_parameters.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/self_taskgraph/custom_target_tasks.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/self_taskgraph/transforms/add_pr_route.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/self_taskgraph/transforms/push_image.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/test/params/main-repo-pull-request-untrusted.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/test/params/main-repo-pull-request.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/test/params/main-repo-push.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/test/params/main-repo-release-pytest-taskgraph.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/test/params/main-repo-release-taskcluster-taskgraph.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/template/cookiecutter.json +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/template/hooks/post_gen_project.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/template/{{cookiecutter.project_name}}/taskcluster/config.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/template/{{cookiecutter.project_name}}/taskcluster/docker/linux/Dockerfile +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/template/{{cookiecutter.project_name}}/taskcluster/kinds/docker-image/kind.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/template/{{cookiecutter.project_name}}/taskcluster/kinds/hello/kind.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/template/{{cookiecutter.project_name}}/taskcluster/{{cookiecutter.project_slug}}_taskgraph/transforms/hello.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/template/{{cookiecutter.project_name}}/taskcluster.github.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/__init__.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/automationrelevance.json +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/conftest.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/data/task_context.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/data/taskcluster/config.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/data/taskcluster/docker/hello-world/Dockerfile +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/data/taskcluster/docker/hello-world-tag/Dockerfile +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/data/taskcluster/docker/hello-world-tag/REGISTRY +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/data/taskcluster/docker/hello-world-tag/VERSION +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/data/taskcluster/kinds/docker-image/kind.yml +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/data/taskcluster/scripts/toolchain/run.ps1 +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/data/taskcluster/scripts/toolchain/run.sh +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/data/taskcluster/test_taskgraph/transforms/foo.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/data/testmod/thing.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/mockedopen.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_actions_rebuild_cached_tasks.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_actions_registry.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_config.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_create.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_decision.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_docker.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_graph.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_main.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_morph.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_optimize.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_optimize_strategies.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_parameters.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_scripts_fetch_content.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_target_tasks.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_taskgraph.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_transform_chunking.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_transform_docker_image.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_transform_task_context.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_transforms_base.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_transforms_cached_tasks.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_transforms_fetch.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_transforms_from_deps.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_transforms_matrix.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_transforms_notify.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_transforms_run.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_transforms_run_run_task.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_transforms_run_toolchain.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_transforms_task.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_util_archive.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_util_attributes.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_util_cached_tasks.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_util_copy.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_util_dependencies.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_util_docker.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_util_json.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_util_keyed_by.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_util_parameterization.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_util_path.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_util_python_path.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_util_readonlydict.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_util_taskcluster.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_util_templates.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_util_time.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_util_treeherder.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_util_verify.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_util_workertypes.py +0 -0
- {taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/test/test_util_yaml.py +0 -0
|
@@ -13,13 +13,13 @@ repos:
|
|
|
13
13
|
exclude: template
|
|
14
14
|
- id: check-added-large-files
|
|
15
15
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
16
|
-
rev: v0.
|
|
16
|
+
rev: v0.15.4
|
|
17
17
|
hooks:
|
|
18
18
|
- id: ruff
|
|
19
19
|
args: [--fix, --exit-non-zero-on-fix]
|
|
20
20
|
- id: ruff-format
|
|
21
21
|
- repo: https://github.com/astral-sh/uv-pre-commit
|
|
22
|
-
rev: 0.
|
|
22
|
+
rev: 0.10.7
|
|
23
23
|
hooks:
|
|
24
24
|
- id: uv-lock
|
|
25
25
|
- repo: https://github.com/adrienverge/yamllint.git
|
|
@@ -37,7 +37,7 @@ repos:
|
|
|
37
37
|
test/test_util_path.py
|
|
38
38
|
)$
|
|
39
39
|
- repo: https://github.com/compilerla/conventional-pre-commit
|
|
40
|
-
rev: v4.
|
|
40
|
+
rev: v4.4.0
|
|
41
41
|
hooks:
|
|
42
42
|
- id: conventional-pre-commit
|
|
43
43
|
stages: [commit-msg]
|
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## [20.0.0] - 2026-03-17
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Support for generic-worker's `hide-cmd-window` feature
|
|
8
|
+
- Ability to process kinds concurrently with threading
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- BREAKING CHANGE: Binaries installed as part of `PIP_REQUIREMENTS` by `run-task` now end up in `~/.local/bin`
|
|
13
|
+
- Exception when base revision is the null revision
|
|
14
|
+
- Ability to use `optionally_keyed_by` with underlying dict using msgspec
|
|
15
|
+
|
|
16
|
+
## [19.2.1] - 2026-02-19
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- Loosen `optionally_keyed_by` constraints for msgspec compatibility
|
|
21
|
+
|
|
3
22
|
## [19.2.0] - 2026-02-18
|
|
4
23
|
|
|
5
24
|
### Fixed
|
|
@@ -3,6 +3,14 @@ Migration Guide
|
|
|
3
3
|
|
|
4
4
|
This page can help when migrating Taskgraph across major versions.
|
|
5
5
|
|
|
6
|
+
19.x -> 20.x
|
|
7
|
+
------------
|
|
8
|
+
|
|
9
|
+
* Binaries belonging to packages that get installed by `run-task` as part of
|
|
10
|
+
the `PIP_REQUIREMENTS` variable, are now installed to `~/.local/bin` instead
|
|
11
|
+
of `~/.local/lib/<python>/site-packages/bin`. Update any task commands that hardcode
|
|
12
|
+
the binary path accordingly.
|
|
13
|
+
|
|
6
14
|
18.x -> 19.x
|
|
7
15
|
------------
|
|
8
16
|
|
|
@@ -11,6 +11,7 @@ import platform
|
|
|
11
11
|
from concurrent.futures import (
|
|
12
12
|
FIRST_COMPLETED,
|
|
13
13
|
ProcessPoolExecutor,
|
|
14
|
+
ThreadPoolExecutor,
|
|
14
15
|
wait,
|
|
15
16
|
)
|
|
16
17
|
from dataclasses import dataclass
|
|
@@ -312,15 +313,13 @@ class TaskGraphGenerator:
|
|
|
312
313
|
|
|
313
314
|
return all_tasks
|
|
314
315
|
|
|
315
|
-
def _load_tasks_parallel(self, kinds, kind_graph, parameters):
|
|
316
|
+
def _load_tasks_parallel(self, kinds, kind_graph, parameters, executor):
|
|
316
317
|
all_tasks = {}
|
|
317
318
|
futures_to_kind = {}
|
|
318
319
|
futures = set()
|
|
319
320
|
edges = set(kind_graph.edges)
|
|
320
321
|
|
|
321
|
-
with
|
|
322
|
-
mp_context=multiprocessing.get_context("fork")
|
|
323
|
-
) as executor:
|
|
322
|
+
with executor:
|
|
324
323
|
|
|
325
324
|
def submit_ready_kinds():
|
|
326
325
|
"""Create the next batch of tasks for kinds without dependencies."""
|
|
@@ -434,29 +433,50 @@ class TaskGraphGenerator:
|
|
|
434
433
|
yield "kind_graph", kind_graph
|
|
435
434
|
|
|
436
435
|
logger.info("Generating full task set")
|
|
437
|
-
|
|
438
|
-
# processing
|
|
436
|
+
|
|
437
|
+
# The next block deals with enabling parallel kind processing, which
|
|
438
|
+
# currently has different support on different platforms. In summary:
|
|
439
|
+
# * Parallel kind processing is supported and enabled by default on
|
|
440
|
+
# Linux. We use multiple processes by default, but experimental
|
|
441
|
+
# support for multiple threads can be enabled instead.
|
|
442
|
+
# * On other platforms, we have experimental support for parallel
|
|
443
|
+
# kind processing with multiple threads.
|
|
439
444
|
#
|
|
440
|
-
#
|
|
441
|
-
#
|
|
442
|
-
#
|
|
443
|
-
#
|
|
444
|
-
#
|
|
445
|
-
#
|
|
446
|
-
#
|
|
447
|
-
#
|
|
448
|
-
#
|
|
449
|
-
#
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
445
|
+
# On all platforms serial kind processing can be enabled by setting
|
|
446
|
+
# TASKGRAPH_SERIAL in the environment.
|
|
447
|
+
#
|
|
448
|
+
# On all platforms, multiple threads can be enabled by setting
|
|
449
|
+
# TASKGRAPH_USE_THREADS in the environment. Taskgraph must be running
|
|
450
|
+
# from a free-threaded Python build to see any performance benefits.
|
|
451
|
+
#
|
|
452
|
+
# In the long term, the goal is turn enabled parallel kind processing for
|
|
453
|
+
# all platforms by default using threads, and remove support for multiple
|
|
454
|
+
# processes altogether.
|
|
455
|
+
def load_tasks():
|
|
456
|
+
if platform.system() == "Linux":
|
|
457
|
+
if os.environ.get("TASKGRAPH_SERIAL"):
|
|
458
|
+
return self._load_tasks_serial(kinds, kind_graph, parameters)
|
|
459
|
+
elif os.environ.get("TASKGRAPH_USE_THREADS"):
|
|
460
|
+
executor = ThreadPoolExecutor(max_workers=os.process_cpu_count())
|
|
461
|
+
else:
|
|
462
|
+
executor = ProcessPoolExecutor(
|
|
463
|
+
mp_context=multiprocessing.get_context("fork")
|
|
464
|
+
)
|
|
465
|
+
return self._load_tasks_parallel(
|
|
466
|
+
kinds, kind_graph, parameters, executor
|
|
467
|
+
)
|
|
468
|
+
else:
|
|
469
|
+
if os.environ.get("TASKGRAPH_SERIAL") or not os.environ.get(
|
|
470
|
+
"TASKGRAPH_USE_THREADS"
|
|
471
|
+
):
|
|
472
|
+
return self._load_tasks_serial(kinds, kind_graph, parameters)
|
|
473
|
+
else:
|
|
474
|
+
executor = ThreadPoolExecutor(max_workers=os.process_cpu_count())
|
|
475
|
+
return self._load_tasks_parallel(
|
|
476
|
+
kinds, kind_graph, parameters, executor
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
all_tasks = load_tasks()
|
|
460
480
|
|
|
461
481
|
full_task_set = TaskGraph(all_tasks, Graph(frozenset(all_tasks), frozenset()))
|
|
462
482
|
yield self.verify("full_task_set", full_task_set, graph_config, parameters)
|
{taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/run-task/run-task
RENAMED
|
@@ -1044,8 +1044,8 @@ def install_pip_requirements(repositories):
|
|
|
1044
1044
|
|
|
1045
1045
|
# TODO: Stop using system Python (#381)
|
|
1046
1046
|
if shutil.which("uv"):
|
|
1047
|
-
|
|
1048
|
-
[sys.executable, "-msite", "--user-
|
|
1047
|
+
user_base_dir = subprocess.run(
|
|
1048
|
+
[sys.executable, "-msite", "--user-base"], capture_output=True, text=True
|
|
1049
1049
|
).stdout.strip()
|
|
1050
1050
|
cmd = [
|
|
1051
1051
|
"uv",
|
|
@@ -1053,8 +1053,8 @@ def install_pip_requirements(repositories):
|
|
|
1053
1053
|
"install",
|
|
1054
1054
|
"--python",
|
|
1055
1055
|
sys.executable,
|
|
1056
|
-
"--
|
|
1057
|
-
|
|
1056
|
+
"--prefix",
|
|
1057
|
+
user_base_dir,
|
|
1058
1058
|
]
|
|
1059
1059
|
else:
|
|
1060
1060
|
cmd = [sys.executable, "-mpip", "install", "--user", "--break-system-packages"]
|
{taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/src/taskgraph/transforms/task.py
RENAMED
|
@@ -569,6 +569,7 @@ class GenericWorkerPayloadSchema(Schema, forbid_unknown_fields=False, kw_only=Tr
|
|
|
569
569
|
# feature for task to run as current OS user
|
|
570
570
|
run_task_as_current_user: Optional[bool] = None
|
|
571
571
|
taskcluster_proxy: Optional[bool] = None
|
|
572
|
+
hide_cmd_window: Optional[bool] = None
|
|
572
573
|
# Whether any artifacts are assigned to this worker
|
|
573
574
|
skip_artifacts: Optional[bool] = None
|
|
574
575
|
|
|
@@ -681,6 +682,9 @@ def build_generic_worker_payload(config, task, task_def):
|
|
|
681
682
|
"generic-worker:run-task-as-current-user:{}".format(task["worker-type"]),
|
|
682
683
|
)
|
|
683
684
|
|
|
685
|
+
if worker.get("hide-cmd-window"):
|
|
686
|
+
features["hideCmdWindow"] = True
|
|
687
|
+
|
|
684
688
|
if features:
|
|
685
689
|
task_def["payload"]["features"] = features
|
|
686
690
|
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
import pprint
|
|
6
6
|
import re
|
|
7
|
+
import threading
|
|
7
8
|
from collections.abc import Mapping
|
|
8
|
-
from
|
|
9
|
-
from typing import Literal, Optional, Union
|
|
9
|
+
from typing import Annotated, Any, Literal, Optional, Union, get_args, get_origin
|
|
10
10
|
|
|
11
11
|
import msgspec
|
|
12
12
|
import voluptuous
|
|
@@ -14,6 +14,8 @@ import voluptuous
|
|
|
14
14
|
import taskgraph
|
|
15
15
|
from taskgraph.util.keyed_by import evaluate_keyed_by, iter_dot_path
|
|
16
16
|
|
|
17
|
+
_schema_creation_lock = threading.RLock()
|
|
18
|
+
|
|
17
19
|
# Common type definitions that are used across multiple schemas
|
|
18
20
|
TaskPriority = Literal[
|
|
19
21
|
"highest", "very-high", "high", "medium", "low", "very-low", "lowest"
|
|
@@ -67,11 +69,37 @@ def validate_schema(schema, obj, msg_prefix):
|
|
|
67
69
|
raise Exception(f"{msg_prefix}\n{str(exc)}\n{pprint.pformat(obj)}")
|
|
68
70
|
|
|
69
71
|
|
|
70
|
-
|
|
71
|
-
"""
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
class OptionallyKeyedBy:
|
|
73
|
+
"""Metadata class for optionally_keyed_by fields in msgspec schemas."""
|
|
74
|
+
|
|
75
|
+
def __init__(self, *fields, wrapped_type):
|
|
76
|
+
self.fields = {f"by-{field}" for field in fields}
|
|
77
|
+
self.wrapped_type = wrapped_type
|
|
78
|
+
|
|
79
|
+
def uses_keyed_by(self, obj) -> bool:
|
|
80
|
+
if not isinstance(obj, dict) or len(obj) != 1:
|
|
81
|
+
return False
|
|
82
|
+
|
|
83
|
+
key = list(obj)[0]
|
|
84
|
+
if key not in self.fields:
|
|
85
|
+
return False
|
|
86
|
+
|
|
87
|
+
return True
|
|
88
|
+
|
|
89
|
+
def validate(self, obj) -> None:
|
|
90
|
+
if not self.uses_keyed_by(obj):
|
|
91
|
+
# Not using keyed by, validate directly against wrapped type
|
|
92
|
+
msgspec.convert(obj, self.wrapped_type)
|
|
93
|
+
return
|
|
94
|
+
|
|
95
|
+
# First validate the outer keyed-by dict
|
|
96
|
+
msgspec.convert(obj, dict[str, dict])
|
|
97
|
+
|
|
98
|
+
# Next validate each inner value. We call self.validate recursively to
|
|
99
|
+
# support nested `by-*` keys.
|
|
100
|
+
keyed_by_dict = list(obj.values())[0]
|
|
101
|
+
for value in keyed_by_dict.values():
|
|
102
|
+
self.validate(value)
|
|
75
103
|
|
|
76
104
|
|
|
77
105
|
def optionally_keyed_by(*arguments, use_msgspec=False):
|
|
@@ -83,11 +111,15 @@ def optionally_keyed_by(*arguments, use_msgspec=False):
|
|
|
83
111
|
use_msgspec: If True, return msgspec type hints; if False, return voluptuous validator
|
|
84
112
|
"""
|
|
85
113
|
if use_msgspec:
|
|
86
|
-
# msgspec implementation -
|
|
114
|
+
# msgspec implementation - use Annotated[Any, OptionallyKeyedBy]
|
|
87
115
|
_type = arguments[-1]
|
|
116
|
+
if _type is object:
|
|
117
|
+
return object
|
|
88
118
|
fields = arguments[:-1]
|
|
89
|
-
|
|
90
|
-
|
|
119
|
+
wrapper = OptionallyKeyedBy(*fields, wrapped_type=_type)
|
|
120
|
+
# Annotating Any allows msgspec to accept any value without validation.
|
|
121
|
+
# The actual validation then happens in Schema.__post_init__
|
|
122
|
+
return Annotated[Any, wrapper]
|
|
91
123
|
else:
|
|
92
124
|
# voluptuous implementation - return validator function
|
|
93
125
|
schema = arguments[-1]
|
|
@@ -251,28 +283,36 @@ class LegacySchema(voluptuous.Schema):
|
|
|
251
283
|
"""
|
|
252
284
|
Operates identically to voluptuous.Schema, but applying some taskgraph-specific checks
|
|
253
285
|
in the process.
|
|
286
|
+
|
|
287
|
+
voluptuous.Schema's `_compile` method is thread-unsafe. Any usage (whether direct or
|
|
288
|
+
indirect) of it must be protected by a lock.
|
|
254
289
|
"""
|
|
255
290
|
|
|
256
291
|
def __init__(self, *args, check=True, **kwargs):
|
|
257
|
-
|
|
292
|
+
with _schema_creation_lock:
|
|
293
|
+
# this constructor may call `_compile`
|
|
294
|
+
super().__init__(*args, **kwargs)
|
|
258
295
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
296
|
+
self.check = check
|
|
297
|
+
if not taskgraph.fast and self.check:
|
|
298
|
+
check_schema(self)
|
|
262
299
|
|
|
263
300
|
def extend(self, *args, **kwargs):
|
|
264
|
-
|
|
301
|
+
with _schema_creation_lock:
|
|
302
|
+
# `extend` may create a new Schema object, which may call `_compile`
|
|
303
|
+
schema = super().extend(*args, **kwargs)
|
|
265
304
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
305
|
+
if self.check:
|
|
306
|
+
check_schema(schema)
|
|
307
|
+
# We want twice extend schema to be checked too.
|
|
308
|
+
schema.__class__ = LegacySchema
|
|
309
|
+
return schema
|
|
271
310
|
|
|
272
311
|
def _compile(self, schema):
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
312
|
+
with _schema_creation_lock:
|
|
313
|
+
if taskgraph.fast:
|
|
314
|
+
return
|
|
315
|
+
return super()._compile(schema)
|
|
276
316
|
|
|
277
317
|
def __getitem__(self, item):
|
|
278
318
|
return self.schema[item] # type: ignore
|
|
@@ -305,6 +345,31 @@ class Schema(
|
|
|
305
345
|
foo: str
|
|
306
346
|
"""
|
|
307
347
|
|
|
348
|
+
def __post_init__(self):
|
|
349
|
+
if taskgraph.fast:
|
|
350
|
+
return
|
|
351
|
+
|
|
352
|
+
# Validate fields that use optionally_keyed_by. We need to validate this
|
|
353
|
+
# manually because msgspec doesn't support union types with multiple
|
|
354
|
+
# dicts. Any fields that use `optionally_keyed_by("foo", dict)` would
|
|
355
|
+
# otherwise raise an exception.
|
|
356
|
+
for field_name, field_type in self.__class__.__annotations__.items():
|
|
357
|
+
origin = get_origin(field_type)
|
|
358
|
+
args = get_args(field_type)
|
|
359
|
+
|
|
360
|
+
if (
|
|
361
|
+
origin is not Annotated
|
|
362
|
+
or len(args) < 2
|
|
363
|
+
or not isinstance(args[1], OptionallyKeyedBy)
|
|
364
|
+
):
|
|
365
|
+
# Not using `optionally_keyed_by`
|
|
366
|
+
continue
|
|
367
|
+
|
|
368
|
+
keyed_by = args[1]
|
|
369
|
+
obj = getattr(self, field_name)
|
|
370
|
+
|
|
371
|
+
keyed_by.validate(obj)
|
|
372
|
+
|
|
308
373
|
@classmethod
|
|
309
374
|
def validate(cls, data):
|
|
310
375
|
"""Validate data against this schema."""
|
|
@@ -312,7 +377,7 @@ class Schema(
|
|
|
312
377
|
return data
|
|
313
378
|
|
|
314
379
|
try:
|
|
315
|
-
|
|
380
|
+
msgspec.convert(data, cls)
|
|
316
381
|
except (msgspec.ValidationError, msgspec.DecodeError) as e:
|
|
317
382
|
raise msgspec.ValidationError(str(e))
|
|
318
383
|
|
|
@@ -505,6 +505,11 @@ class GitRepository(Repository):
|
|
|
505
505
|
cmd.append("--cached")
|
|
506
506
|
elif mode == "all":
|
|
507
507
|
cmd.append("HEAD")
|
|
508
|
+
elif base == self.NULL_REVISION:
|
|
509
|
+
# When base is NULL_REVISION (e.g new branches on Github), diff
|
|
510
|
+
# from the empty tree to show all files present at rev. Use Git's
|
|
511
|
+
# well-known empty tree hash.
|
|
512
|
+
cmd = ["diff", "4b825dc642cb6eb9a060e54bf8d69288fbee4904", rev]
|
|
508
513
|
elif self.is_shallow:
|
|
509
514
|
# In shallow clones, `git log` won't have the history necessary to
|
|
510
515
|
# determine the files changed. Using `git diff` finds the
|
{taskcluster_taskgraph-19.2.0 → taskcluster_taskgraph-20.0.0}/taskcluster/kinds/test/linux.yml
RENAMED
|
@@ -50,6 +50,26 @@ unit:
|
|
|
50
50
|
command: >-
|
|
51
51
|
uv run coverage run --data-file /builds/worker/artifacts/coverage --context=py{matrix[python]} -m pytest -vv
|
|
52
52
|
|
|
53
|
+
unit-multithread:
|
|
54
|
+
description: "Run unit tests with py{matrix[python]} on Linux with multithreading enabled"
|
|
55
|
+
matrix:
|
|
56
|
+
set-name: "unit-multithread-py{matrix[python]}"
|
|
57
|
+
substitution-fields: [description, run.command, treeherder, worker, attributes]
|
|
58
|
+
python: ["314t"]
|
|
59
|
+
worker:
|
|
60
|
+
docker-image: {in-tree: python}
|
|
61
|
+
env:
|
|
62
|
+
TASKGRAPH_USE_THREADS: "1"
|
|
63
|
+
artifacts:
|
|
64
|
+
- type: file
|
|
65
|
+
path: "/builds/worker/artifacts/coverage"
|
|
66
|
+
name: "public/coverage.py{matrix[python]}"
|
|
67
|
+
treeherder:
|
|
68
|
+
symbol: unit-multithread(py{matrix[python]})
|
|
69
|
+
run:
|
|
70
|
+
command: >-
|
|
71
|
+
uv run coverage run --data-file /builds/worker/artifacts/coverage --context=py{matrix[python]} -m pytest -vv
|
|
72
|
+
|
|
53
73
|
integration:
|
|
54
74
|
description: "Run unit tests with py{matrix[python]} on Linux with resolution {matrix[resolution]}"
|
|
55
75
|
attributes:
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
4
4
|
|
|
5
5
|
|
|
6
|
+
import os
|
|
6
7
|
import platform
|
|
7
8
|
from concurrent.futures import ProcessPoolExecutor
|
|
8
9
|
|
|
@@ -14,9 +15,13 @@ from taskgraph.generator import Kind, load_tasks_for_kind, load_tasks_for_kinds
|
|
|
14
15
|
from taskgraph.loader.default import loader as default_loader
|
|
15
16
|
|
|
16
17
|
linuxonly = pytest.mark.skipif(
|
|
17
|
-
platform.system() != "Linux",
|
|
18
|
+
platform.system() != "Linux" or os.environ.get("TASKGRAPH_USE_THREADS"),
|
|
18
19
|
reason="requires Linux and 'fork' multiprocessing support",
|
|
19
20
|
)
|
|
21
|
+
threadsonly = pytest.mark.skipif(
|
|
22
|
+
not os.environ.get("TASKGRAPH_USE_THREADS"),
|
|
23
|
+
reason="requires multithreading to be enabled",
|
|
24
|
+
)
|
|
20
25
|
|
|
21
26
|
|
|
22
27
|
class FakePPE(ProcessPoolExecutor):
|
|
@@ -27,8 +32,16 @@ class FakePPE(ProcessPoolExecutor):
|
|
|
27
32
|
return super().submit(kind_load_tasks, *args)
|
|
28
33
|
|
|
29
34
|
|
|
35
|
+
class FakeTPE(ProcessPoolExecutor):
|
|
36
|
+
loaded_kinds = []
|
|
37
|
+
|
|
38
|
+
def submit(self, kind_load_tasks, *args):
|
|
39
|
+
self.loaded_kinds.append(kind_load_tasks.__self__.name)
|
|
40
|
+
return super().submit(kind_load_tasks, *args)
|
|
41
|
+
|
|
42
|
+
|
|
30
43
|
@linuxonly
|
|
31
|
-
def
|
|
44
|
+
def test_kind_ordering_multiprocess(mocker, maketgg):
|
|
32
45
|
"When task kinds depend on each other, they are loaded in postorder"
|
|
33
46
|
mocked_ppe = mocker.patch.object(generator, "ProcessPoolExecutor", new=FakePPE)
|
|
34
47
|
tgg = maketgg(
|
|
@@ -42,6 +55,21 @@ def test_kind_ordering(mocker, maketgg):
|
|
|
42
55
|
assert mocked_ppe.loaded_kinds == ["_fake1", "_fake2", "_fake3"]
|
|
43
56
|
|
|
44
57
|
|
|
58
|
+
@threadsonly
|
|
59
|
+
def test_kind_ordering_multithread(mocker, maketgg):
|
|
60
|
+
"When task kinds depend on each other, they are loaded in postorder"
|
|
61
|
+
mocked_tpe = mocker.patch.object(generator, "ThreadPoolExecutor", new=FakeTPE)
|
|
62
|
+
tgg = maketgg(
|
|
63
|
+
kinds=[
|
|
64
|
+
("_fake3", {"kind-dependencies": ["_fake2", "_fake1"]}),
|
|
65
|
+
("_fake2", {"kind-dependencies": ["_fake1"]}),
|
|
66
|
+
("_fake1", {"kind-dependencies": []}),
|
|
67
|
+
]
|
|
68
|
+
)
|
|
69
|
+
tgg._run_until("full_task_set")
|
|
70
|
+
assert mocked_tpe.loaded_kinds == ["_fake1", "_fake2", "_fake3"]
|
|
71
|
+
|
|
72
|
+
|
|
45
73
|
def test_full_task_set(maketgg):
|
|
46
74
|
"The full_task_set property has all tasks"
|
|
47
75
|
tgg = maketgg()
|
|
@@ -284,32 +284,67 @@ class TestValidateSchemaDictHandler(unittest.TestCase):
|
|
|
284
284
|
|
|
285
285
|
|
|
286
286
|
def test_optionally_keyed_by():
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
}
|
|
287
|
+
class TestSchema(Schema):
|
|
288
|
+
field: optionally_keyed_by("foo", str, use_msgspec=True) # type: ignore
|
|
289
|
+
|
|
290
|
+
TestSchema.validate({"field": "baz"})
|
|
291
|
+
TestSchema.validate({"field": {"by-foo": {"a": "b", "c": "d"}}})
|
|
292
|
+
|
|
293
|
+
with pytest.raises(msgspec.ValidationError):
|
|
294
|
+
TestSchema.validate({"field": 1})
|
|
295
|
+
|
|
296
|
+
with pytest.raises(msgspec.ValidationError):
|
|
297
|
+
TestSchema.validate({"field": {"by-bar": "a"}})
|
|
292
298
|
|
|
293
299
|
with pytest.raises(msgspec.ValidationError):
|
|
294
|
-
|
|
300
|
+
TestSchema.validate({"field": {"by-bar": {1: "b"}}})
|
|
295
301
|
|
|
296
302
|
with pytest.raises(msgspec.ValidationError):
|
|
297
|
-
|
|
303
|
+
TestSchema.validate({"field": {"by-bar": {"a": "b"}}})
|
|
304
|
+
|
|
305
|
+
with pytest.raises(msgspec.ValidationError):
|
|
306
|
+
TestSchema.validate({"field": {"by-foo": {"a": 1, "c": "d"}}})
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def test_optionally_keyed_by_multiple_keys():
|
|
310
|
+
class TestSchema(Schema):
|
|
311
|
+
field: optionally_keyed_by("foo", "bar", str, use_msgspec=True) # type: ignore
|
|
312
|
+
|
|
313
|
+
TestSchema.validate({"field": {"by-foo": {"a": "b"}}})
|
|
314
|
+
TestSchema.validate({"field": {"by-bar": {"x": "y"}}})
|
|
315
|
+
TestSchema.validate({"field": {"by-foo": {"a": {"by-bar": {"x": "y"}}}}})
|
|
316
|
+
|
|
317
|
+
# Test invalid keyed-by field
|
|
318
|
+
with pytest.raises(msgspec.ValidationError):
|
|
319
|
+
TestSchema.validate({"field": {"by-unknown": {"a": "b"}}})
|
|
320
|
+
|
|
321
|
+
with pytest.raises(msgspec.ValidationError):
|
|
322
|
+
TestSchema.validate({"field": {"by-foo": {"a": {"by-bar": {"x": 1}}}}})
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def test_optionally_keyed_by_object_passthrough():
|
|
326
|
+
"""When the type argument is `object`, optionally_keyed_by returns object directly."""
|
|
327
|
+
typ = optionally_keyed_by("foo", object, use_msgspec=True)
|
|
328
|
+
assert typ is object
|
|
329
|
+
# object accepts anything via msgspec.convert
|
|
330
|
+
assert msgspec.convert("hello", typ) == "hello"
|
|
331
|
+
assert msgspec.convert(42, typ) == 42
|
|
332
|
+
assert msgspec.convert({"by-foo": {"a": "b"}}, typ) == {"by-foo": {"a": "b"}}
|
|
333
|
+
assert msgspec.convert({"arbitrary": "dict"}, typ) == {"arbitrary": "dict"}
|
|
334
|
+
|
|
298
335
|
|
|
336
|
+
def test_optionally_keyed_by_dict():
|
|
337
|
+
class TestSchema(Schema):
|
|
338
|
+
field: optionally_keyed_by("foo", dict[str, str], use_msgspec=True) # type: ignore
|
|
299
339
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
assert msgspec.convert("baz", typ) == "baz"
|
|
303
|
-
assert msgspec.convert({"by-foo": {"a": "b", "c": "d"}}, typ) == {
|
|
304
|
-
"by-foo": {"a": "b", "c": "d"}
|
|
305
|
-
}
|
|
306
|
-
assert msgspec.convert({"by-bar": {"x": "y"}}, typ) == {"by-bar": {"x": "y"}}
|
|
340
|
+
TestSchema.validate({"field": {"by-foo": {"a": {"x": "y"}}}})
|
|
341
|
+
TestSchema.validate({"field": {"a": "b"}})
|
|
307
342
|
|
|
308
343
|
with pytest.raises(msgspec.ValidationError):
|
|
309
|
-
|
|
344
|
+
TestSchema.validate({"field": {"a": 1}})
|
|
310
345
|
|
|
311
346
|
with pytest.raises(msgspec.ValidationError):
|
|
312
|
-
|
|
347
|
+
TestSchema.validate({"field": {"by-foo": {"a": {"x": 1}}}})
|
|
313
348
|
|
|
314
349
|
with pytest.raises(msgspec.ValidationError):
|
|
315
|
-
|
|
350
|
+
TestSchema.validate({"field": {"by-foo": {"a": "b"}}})
|