-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathcircleci_process.py
More file actions
126 lines (107 loc) · 3.37 KB
/
circleci_process.py
File metadata and controls
126 lines (107 loc) · 3.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#!/usr/bin/env python3
"""
circleci_process.py
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A *pre-commit* hook that runs `circleci config process` on one or more
CircleCI configuration files.
Exit code:
* 0 - all configs processed successfully
* 1+ - at least one config failed
"""
from __future__ import annotations
import argparse
import os
import shutil
import subprocess
import sys
from pathlib import Path
def run_process(
config_path: Path,
org_slug: str | None,
org_id: str | None,
pipeline_params: str | None,
verbose: bool,
) -> int:
"""Run `circleci config process` and return its exit code."""
cmd: list[str] = ["circleci", "config", "process", str(config_path)]
if org_slug:
cmd.append(f"--org-slug={org_slug}")
if org_id:
cmd.append(f"--org-id={org_id}")
if pipeline_params:
cmd.append(f"--pipeline-parameters={pipeline_params}")
if verbose:
cmd.append("--verbose")
completed = subprocess.run(cmd, text=True, capture_output=True, check=False)
if completed.returncode == 0:
# Hide verbose CircleCI output on success
print(f"✅ CircleCI configuration passed processing: {config_path}")
else:
# Re-emit CircleCI output so the user can see the problem
sys.stderr.write(completed.stdout + completed.stderr)
return completed.returncode
def parse_args() -> argparse.Namespace: # noqa: D401
"""Return parsed CLI arguments."""
parser = argparse.ArgumentParser(
description=(
"Run `circleci config process` against the given file(s) inside pre-commit."
),
)
parser.add_argument(
"--org-slug",
help="organization slug (e.g. github/example-org) for private orbs",
)
parser.add_argument(
"--org-id",
help="organization ID for private orbs",
)
parser.add_argument(
"--pipeline-parameters",
help=(
"YAML/JSON string or file path with pipeline parameters "
'(e.g. \'{"foo": "bar"}\' or params.yml)'
),
)
parser.add_argument(
"--verbose",
action="store_true",
help="pass --verbose through to the CircleCI CLI "
"(for failing operations in that implementation)",
)
parser.add_argument(
"filenames",
nargs="+",
help="config files to check",
)
return parser.parse_args()
def main() -> None:
"""Entry-point for the pre-commit hook."""
args = parse_args()
# Check if running in CircleCI environment
if os.getenv("CIRCLECI"):
print("CircleCI environment detected, skipping processing.")
sys.exit(0)
# Check if CircleCI CLI is installed
if not shutil.which("circleci"):
print(
"CircleCI CLI not found. Install: "
"https://circleci.com/docs/2.0/local-cli/#installation"
)
sys.exit(1)
exit_code = 0
for file_name in args.filenames:
path = Path(file_name)
if not path.exists():
print(f"⚠️ Skipping missing file: {path}", file=sys.stderr)
continue
ret = run_process(
config_path=path,
org_slug=args.org_slug,
org_id=args.org_id,
pipeline_params=args.pipeline_parameters,
verbose=args.verbose,
)
exit_code = max(exit_code, ret)
sys.exit(exit_code)
if __name__ == "__main__":
main()