Skip to content
This repository was archived by the owner on Aug 25, 2024. It is now read-only.

Commit 990014f

Browse files
committed
scripts: images containers manifest: Build json from dirs
Related: #1273 Signed-off-by: John Andersen <[email protected]>
1 parent 7f98408 commit 990014f

File tree

1 file changed

+205
-0
lines changed

1 file changed

+205
-0
lines changed

scripts/images_containers_manifest.py

+205
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
#!/usr/bin/env python
2+
# This file generates a manifest for building container images
3+
# Usage: JSON_INDENT=" " nodemon -e py,Dockerfile,HEAD --exec 'clear; python scripts/images_containers_manifest.py; test 1'
4+
import os
5+
import sys
6+
import json
7+
import pathlib
8+
import itertools
9+
import traceback
10+
import subprocess
11+
import urllib.request
12+
13+
# For running under GitHub actions within a container
14+
if "GITHUB_WORKSPACE" in os.environ:
15+
subprocess.check_call(["git", "config", "--global", "--add", "safe.directory", os.environ["GITHUB_WORKSPACE"]])
16+
17+
try:
18+
os.environ.update({
19+
"COMMIT": subprocess.check_output(["git", "log", "-n", "1", "--format=%H"]).decode().strip(),
20+
})
21+
except:
22+
traceback.print_exc(file=sys.stderr)
23+
24+
try:
25+
os.environ.update({
26+
"ROOT_PATH": str(pathlib.Path(subprocess.check_output(["git", "rev-parse", "--show-toplevel"]).decode().strip()).relative_to(os.getcwd())),
27+
"SCHEMA": "https://github.com/intel/dffml/raw/c82f7ddd29a00d24217c50370907c281c4b5b54d/schema/github/actions/build/images/containers/0.0.0.schema.json",
28+
"OWNER_REPOSITORY": "/".join(subprocess.check_output(["git", "remote", "get-url", "origin"]).decode().strip().replace(".git", "").split("/")[-2:]),
29+
"BRANCH": subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"]).decode().strip(),
30+
"PREFIX": os.environ.get("PREFIX", json.dumps([
31+
".",
32+
"scripts",
33+
"dffml/skel/operations",
34+
])),
35+
"NO_DELTA_PREFIX": os.environ.get("NO_DELTA_PREFIX", json.dumps([
36+
".",
37+
"scripts",
38+
"dffml/skel/operations",
39+
])),
40+
"EXCLUDE": os.environ.get("EXCLUDE", json.dumps([
41+
".github/actions",
42+
])),
43+
})
44+
except:
45+
traceback.print_exc(file=sys.stderr)
46+
47+
def path_to_image_name(path, root_path):
48+
# Stem as image name
49+
if path.stem != "Dockerfile":
50+
return path.stem
51+
# Non-top level no stem as image name (filename is Dockerfile)
52+
hyphen_dir_path = str(path.parent.relative_to(root_path)).replace(os.sep, "-").replace(".", "").replace("_", "-")
53+
if hyphen_dir_path != ".":
54+
return hyphen_dir_path
55+
# Top level dir Dockerfile use top level dirname
56+
return str(root_path.resolve().name)
57+
58+
# Pull request file change delta filter using GitHub API
59+
prefixes = json.loads(os.environ["PREFIX"])
60+
no_delta_prefixes = json.loads(os.environ["NO_DELTA_PREFIX"])
61+
exclude = json.loads(os.environ.get("EXCLUDE", '[]'))
62+
owner, repository = os.environ["OWNER_REPOSITORY"].split("/", maxsplit=1)
63+
base = None
64+
env_vars = ["BASE", "BASE_REF"]
65+
for env_var in env_vars:
66+
if env_var in os.environ and os.environ[env_var].strip():
67+
# Set if present and not blank
68+
base = os.environ[env_var]
69+
70+
# Empty manifest (list of manifests for each build file) in case not triggered
71+
# from on file change (workflow changed or dispatched).
72+
manifest = []
73+
# Path to root of repo
74+
root_path = pathlib.Path(os.environ["ROOT_PATH"])
75+
# Grab commit from git
76+
commit = os.environ["COMMIT"]
77+
if base is None:
78+
print(f"::notice file={__file__},line=1,endLine=1,title=nobase::None of {env_vars!r} found in os.environ", file=sys.stderr)
79+
80+
else:
81+
compare_url = os.environ["COMPARE_URL"]
82+
compare_url = compare_url.replace("{base}", base)
83+
compare_url = compare_url.replace("{head}", os.environ["HEAD"])
84+
with urllib.request.urlopen(
85+
urllib.request.Request(
86+
compare_url,
87+
headers={
88+
"Authorization": "bearer " + os.environ["GH_ACCESS_TOKEN"],
89+
},
90+
)
91+
) as response:
92+
response_json = json.load(response)
93+
# Print for debug
94+
print(json.dumps({
95+
"@context": {
96+
"@vocab": "github_delta_response_json",
97+
},
98+
"include": manifest,
99+
}, sort_keys=True, indent=4), file=sys.stderr)
100+
# Build the most recent commit
101+
commit = response_json["commits"][-1]["sha"]
102+
manifest = list(itertools.chain(*(
103+
[
104+
[
105+
{
106+
"image_name": path_to_image_name(path, root_path),
107+
"dockerfile": str(path.relative_to(root_path)),
108+
"owner": owner,
109+
"repository": repository,
110+
"branch": os.environ["BRANCH"],
111+
"commit": commit,
112+
}
113+
for path in [
114+
(print(compare_file) or pathlib.Path(compare_file["filename"]))
115+
for compare_file in response_json["files"]
116+
if (
117+
any([
118+
compare_file["filename"].startswith(prefix_path)
119+
for prefix_path in json.loads(os.environ["PREFIX"])
120+
]) and compare_file["filename"].endswith("Dockerfile")
121+
)
122+
]
123+
if str(path.parent.relative_to(root_path)) not in exclude
124+
]
125+
] + [
126+
[
127+
json.loads(path.read_text())
128+
for path in [
129+
(print(compare_file) or pathlib.Path(compare_file["filename"]))
130+
for compare_file in response_json["files"]
131+
if (
132+
any([
133+
compare_file["filename"].startswith(prefix_path)
134+
for prefix_path in json.loads(os.environ["PREFIX"])
135+
]) and compare_file["filename"].endswith("manifest.json")
136+
)
137+
]
138+
]
139+
]
140+
)))
141+
142+
# Build everything if we aren't sure why we got here
143+
if not manifest:
144+
manifest = list(itertools.chain(*(
145+
[
146+
[
147+
{
148+
"image_name": path_to_image_name(path, root_path),
149+
"dockerfile": str(path.relative_to(root_path)),
150+
"owner": owner,
151+
"repository": repository,
152+
"branch": os.environ["BRANCH"],
153+
"commit": commit,
154+
}
155+
for path in prefix_path.glob("*Dockerfile")
156+
if str(path.parent.relative_to(root_path)) not in exclude
157+
]
158+
for prefix_path in map(pathlib.Path, prefixes)
159+
if any(
160+
str(prefix_path.relative_to(root_path)) in no_delta_prefix
161+
for no_delta_prefix in no_delta_prefixes
162+
)
163+
] + [
164+
[
165+
json.loads(path.read_text())
166+
for path in prefix_path.glob("*manifest.json")
167+
]
168+
for prefix_path in map(pathlib.Path, prefixes)
169+
if any(
170+
str(prefix_path.relative_to(root_path)) in no_delta_prefix
171+
for no_delta_prefix in no_delta_prefixes
172+
)
173+
]
174+
)))
175+
176+
# Add proxies or other runtime args/env vars
177+
for i in manifest:
178+
build_args = {}
179+
if "build_args" in i:
180+
build_args = dict(json.loads(i["build_args"]))
181+
for env_var in [
182+
"HTTP_PROXY",
183+
"HTTPS_PROXY",
184+
"NO_PROXY",
185+
]:
186+
if not env_var in os.environ:
187+
continue
188+
build_args[env_var] = os.environ[env_var]
189+
i["build_args"] = json.dumps(list(build_args.items()))
190+
191+
github_actions_manifest = {
192+
"include": manifest,
193+
}
194+
json_ld_manifest = {
195+
"@context": {
196+
"@vocab": os.environ["SCHEMA"],
197+
},
198+
**github_actions_manifest,
199+
}
200+
print(json.dumps(json_ld_manifest, sort_keys=True, indent=os.environ.get("JSON_INDENT", None)))
201+
202+
if "GITHUB_OUTPUT" in os.environ:
203+
with open(os.environ["GITHUB_OUTPUT"], "a") as fileobj:
204+
fileobj.write(f"manifest={json.dumps(manifest)}\n")
205+
fileobj.write(f'github_actions_manifest={json.dumps(github_actions_manifest)}\n')

0 commit comments

Comments
 (0)