Skip to content

Commit 5a95dda

Browse files
committed
Apply review comments
1 parent 0fc2f14 commit 5a95dda

File tree

1 file changed

+93
-58
lines changed
  • src/ci/github-actions

1 file changed

+93
-58
lines changed

src/ci/github-actions/ci.py

Lines changed: 93 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,11 @@ def add_job_properties(jobs: List[Dict], prefix: str) -> List[Job]:
3434
"""
3535
modified_jobs = []
3636
for job in jobs:
37-
job = dict(job)
38-
job["image"] = get_job_image(job)
39-
job["name"] = f"{prefix} - {job['name']}"
40-
modified_jobs.append(job)
37+
# Create a copy of the `job` dictionary to avoid modifying `jobs`
38+
new_job = dict(job)
39+
new_job["image"] = get_job_image(new_job)
40+
new_job["name"] = f"{prefix} - {new_job['name']}"
41+
modified_jobs.append(new_job)
4142
return modified_jobs
4243

4344

@@ -46,11 +47,15 @@ def add_base_env(jobs: List[Job], environment: Dict[str, str]) -> List[Job]:
4647
Prepends `environment` to the `env` attribute of each job.
4748
The `env` of each job has higher precedence than `environment`.
4849
"""
50+
modified_jobs = []
4951
for job in jobs:
5052
env = environment.copy()
5153
env.update(job.get("env", {}))
52-
job["env"] = env
53-
return jobs
54+
55+
new_job = dict(job)
56+
new_job["env"] = env
57+
modified_jobs.append(new_job)
58+
return modified_jobs
5459

5560

5661
@dataclasses.dataclass
@@ -123,7 +128,9 @@ def find_run_type(ctx: GitHubCtx) -> Optional[WorkflowRunType]:
123128

124129
def calculate_jobs(run_type: WorkflowRunType, job_data: Dict[str, Any]) -> List[Job]:
125130
if isinstance(run_type, PRRunType):
126-
return add_base_env(add_job_properties(job_data["pr"], "PR"), job_data["envs"]["pr"])
131+
return add_base_env(
132+
add_job_properties(job_data["pr"], "PR"), job_data["envs"]["pr"]
133+
)
127134
elif isinstance(run_type, TryRunType):
128135
jobs = job_data["try"]
129136
custom_jobs = run_type.custom_jobs
@@ -188,95 +195,123 @@ def format_run_type(run_type: WorkflowRunType) -> str:
188195
raise AssertionError()
189196

190197

191-
def get_job_image(job) -> str:
198+
def get_job_image(job: Job) -> str:
192199
"""
193200
By default, the Docker image of a job is based on its name.
194201
However, it can be overridden by its IMAGE environment variable.
195202
"""
196-
return job.get("env", {}).get("IMAGE", job["name"])
203+
env = job.get("env", {})
204+
# Return the IMAGE environment variable if it exists, otherwise return the job name
205+
return env.get("IMAGE", job["name"])
197206

198207

199-
def run_workflow_locally(job_data: Dict[str, Any], job_name: str, pr_jobs: bool):
200-
DOCKER_DIR = Path(__file__).absolute().parent.parent / "docker"
208+
def is_linux_job(job: Job) -> bool:
209+
return "ubuntu" in job["os"]
201210

202-
jobs = job_data["pr"] if pr_jobs else job_data["auto"]
203-
jobs = [job for job in jobs if job.get("name") == job_name]
211+
212+
def find_linux_job(job_data: Dict[str, Any], job_name: str, pr_jobs: bool) -> Job:
213+
candidates = job_data["pr"] if pr_jobs else job_data["auto"]
214+
jobs = [job for job in candidates if job.get("name") == job_name]
204215
if len(jobs) == 0:
205-
raise Exception(f"Job `{job_name}` not found in {'pr' if pr_jobs else 'auto'} jobs")
216+
available_jobs = "\n".join(
217+
sorted(job["name"] for job in candidates if is_linux_job(job))
218+
)
219+
raise Exception(f"""Job `{job_name}` not found in {'pr' if pr_jobs else 'auto'} jobs.
220+
The following jobs are available:
221+
{available_jobs}""")
206222
assert len(jobs) == 1
223+
207224
job = jobs[0]
208-
if "ubuntu" not in job["os"]:
225+
if not is_linux_job(job):
209226
raise Exception("Only Linux jobs can be executed locally")
227+
return job
228+
229+
230+
def run_workflow_locally(job_data: Dict[str, Any], job_name: str, pr_jobs: bool):
231+
DOCKER_DIR = Path(__file__).absolute().parent.parent / "docker"
232+
233+
job = find_linux_job(job_data, job_name=job_name, pr_jobs=pr_jobs)
210234

211235
custom_env = {}
212-
custom_env["DEPLOY"] = "1"
236+
# Replicate src/ci/scripts/setup-environment.sh
237+
# Adds custom environment variables to the job
238+
if job_name.startswith("dist-"):
239+
if job_name.endswith("-alt"):
240+
custom_env["DEPLOY_ALT"] = "1"
241+
else:
242+
custom_env["DEPLOY"] = "1"
213243
custom_env.update({k: str(v) for (k, v) in job.get("env", {}).items()})
214244

215-
args = [
216-
str(DOCKER_DIR / "run.sh"),
217-
get_job_image(job)
218-
]
245+
args = [str(DOCKER_DIR / "run.sh"), get_job_image(job)]
219246
env_formatted = [f"{k}={v}" for (k, v) in sorted(custom_env.items())]
220247
print(f"Executing `{' '.join(env_formatted)} {' '.join(args)}`")
221248

222249
env = os.environ.copy()
223250
env.update(custom_env)
224251

225-
process = subprocess.Popen(args, env=env)
226-
try:
227-
process.wait()
228-
except KeyboardInterrupt:
229-
process.kill()
252+
subprocess.run(args, env=env)
230253

231254

232-
if __name__ == "__main__":
233-
logging.basicConfig(level=logging.INFO)
255+
def calculate_job_matrix(job_data: Dict[str, Any]):
256+
github_ctx = get_github_ctx()
234257

235-
with open(JOBS_YAML_PATH) as f:
236-
data = yaml.safe_load(f)
258+
run_type = find_run_type(github_ctx)
259+
logging.info(f"Job type: {run_type}")
237260

261+
with open(CI_DIR / "channel") as f:
262+
channel = f.read().strip()
263+
264+
jobs = []
265+
if run_type is not None:
266+
jobs = calculate_jobs(run_type, job_data)
267+
jobs = skip_jobs(jobs, channel)
268+
269+
if not jobs:
270+
raise Exception("Scheduled job list is empty, this is an error")
271+
272+
run_type = format_run_type(run_type)
273+
274+
logging.info(f"Output:\n{yaml.dump(dict(jobs=jobs, run_type=run_type), indent=4)}")
275+
print(f"jobs={json.dumps(jobs)}")
276+
print(f"run_type={run_type}")
277+
278+
279+
def create_cli_parser():
238280
parser = argparse.ArgumentParser(
239-
prog="ci.py",
240-
description="Generate or run CI workflows"
281+
prog="ci.py", description="Generate or run CI workflows"
282+
)
283+
subparsers = parser.add_subparsers(
284+
help="Command to execute", dest="command", required=True
285+
)
286+
subparsers.add_parser(
287+
"calculate-job-matrix",
288+
help="Generate a matrix of jobs that should be executed in CI",
289+
)
290+
run_parser = subparsers.add_parser(
291+
"run-local", help="Run a CI jobs locally (on Linux)"
241292
)
242-
generate_matrix = argparse.ArgumentParser()
243-
subparsers = parser.add_subparsers(help="Command to execute", dest="command", required=True)
244-
subparsers.add_parser("calculate-job-matrix")
245-
run_parser = subparsers.add_parser("run-local")
246293
run_parser.add_argument(
247294
"job_name",
248295
help="CI job that should be executed. By default, a merge (auto) "
249-
"job with the given name will be executed"
296+
"job with the given name will be executed",
250297
)
251298
run_parser.add_argument(
252-
"--pr",
253-
action="store_true",
254-
help="Run a PR job instead of an auto job"
299+
"--pr", action="store_true", help="Run a PR job instead of an auto job"
255300
)
256-
args = parser.parse_args()
257-
258-
if args.command == "calculate-job-matrix":
259-
github_ctx = get_github_ctx()
301+
return parser
260302

261-
run_type = find_run_type(github_ctx)
262-
logging.info(f"Job type: {run_type}")
263303

264-
with open(CI_DIR / "channel") as f:
265-
channel = f.read().strip()
266-
267-
jobs = []
268-
if run_type is not None:
269-
jobs = calculate_jobs(run_type, data)
270-
jobs = skip_jobs(jobs, channel)
304+
if __name__ == "__main__":
305+
logging.basicConfig(level=logging.INFO)
271306

272-
if not jobs:
273-
raise Exception("Scheduled job list is empty, this is an error")
307+
with open(JOBS_YAML_PATH) as f:
308+
data = yaml.safe_load(f)
274309

275-
run_type = format_run_type(run_type)
310+
parser = create_cli_parser()
311+
args = parser.parse_args()
276312

277-
logging.info(f"Output:\n{yaml.dump(dict(jobs=jobs, run_type=run_type), indent=4)}")
278-
print(f"jobs={json.dumps(jobs)}")
279-
print(f"run_type={run_type}")
313+
if args.command == "calculate-job-matrix":
314+
calculate_job_matrix(data)
280315
elif args.command == "run-local":
281316
run_workflow_locally(data, args.job_name, args.pr)
282317
else:

0 commit comments

Comments
 (0)