9
from typing import Any, Dict, List
14
REPO_ROOT = pathlib.Path(__file__).parent.parent.parent
15
CONFIG_YML = REPO_ROOT / ".circleci" / "config.yml"
16
WORKFLOWS_DIR = REPO_ROOT / ".github" / "workflows"
32
workflows: Dict[str, Any],
36
past_jobs: Dict[str, Any],
39
Add job 'job' under 'type' and 'workflow_name' to 'workflow' in place. Also
40
add any dependencies (they must already be in 'past_jobs')
42
if workflow_name not in workflows:
43
workflows[workflow_name] = {"when": "always", "jobs": []}
45
requires = job.get("requires", None)
46
if requires is not None:
47
for requirement in requires:
48
dependency = past_jobs[requirement]
51
dependency["workflow_name"],
57
workflows[workflow_name]["jobs"].append({type: job})
60
def get_filtered_circleci_config(
61
workflows: Dict[str, Any], relevant_jobs: List[str]
64
Given an existing CircleCI config, remove every job that's not listed in
67
new_workflows: Dict[str, Any] = {}
68
past_jobs: Dict[str, Any] = {}
69
for workflow_name, workflow in workflows.items():
70
if workflow_name not in WORKFLOWS_TO_CHECK:
74
for job_dict in workflow["jobs"]:
75
for type, job in job_dict.items():
78
print("Skipping", type)
80
if job["name"] in relevant_jobs:
83
add_job(new_workflows, workflow_name, type, job, past_jobs)
86
past_jobs[job["name"]] = {
87
"workflow_name": workflow_name,
95
def commit_ci(files: List[str], message: str) -> None:
98
stdout = subprocess.run(
99
["git", "status", "--porcelain"], stdout=subprocess.PIPE
101
for line in stdout.split("\n"):
106
f"Refusing to commit while other changes are already staged: {line}"
110
subprocess.run(["git", "add"] + files)
111
subprocess.run(["git", "commit", "-m", message])
114
if __name__ == "__main__":
115
parser = argparse.ArgumentParser(
116
description="make .circleci/config.yml only have a specific set of jobs and delete GitHub actions"
118
parser.add_argument("--job", action="append", help="job name", default=[])
120
"--filter-gha", help="keep only these github actions (glob match)", default=""
125
help="add change to git with to a do-not-merge commit",
127
args = parser.parse_args()
129
touched_files = [CONFIG_YML]
130
with open(CONFIG_YML) as f:
131
config_yml = yaml.safe_load(f.read())
133
config_yml["workflows"] = get_filtered_circleci_config(
134
config_yml["workflows"], args.job
137
with open(CONFIG_YML, "w") as f:
138
yaml.dump(config_yml, f)
141
for relative_file in WORKFLOWS_DIR.iterdir():
142
path = REPO_ROOT.joinpath(relative_file)
143
if not fnmatch.fnmatch(path.name, args.filter_gha):
144
touched_files.append(path)
145
path.resolve().unlink()
148
jobs_str = "\n".join([f" * {job}" for job in args.job])
149
message = textwrap.dedent(
151
[skip ci][do not merge] Edit config.yml to filter specific jobs
153
Filter CircleCI to only run:
156
See [Run Specific CI Jobs](https://github.com/pytorch/pytorch/blob/master/CONTRIBUTING.md#run-specific-ci-jobs) for details.
159
commit_ci([str(f.relative_to(REPO_ROOT)) for f in touched_files], message)