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

Commit 6ad3b46

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

File tree

1 file changed

+199
-0
lines changed

1 file changed

+199
-0
lines changed

scripts/images_containers_manifest.py

+199
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
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+
})
41+
except:
42+
traceback.print_exc(file=sys.stderr)
43+
44+
def path_to_image_name(path, root_path):
45+
# Stem as image name
46+
if path.stem != "Dockerfile":
47+
return path.stem
48+
# Non-top level no stem as image name (filename is Dockerfile)
49+
hyphen_dir_path = str(path.parent.relative_to(root_path)).replace(os.sep, "-").replace(".", "").replace("_", "-")
50+
if hyphen_dir_path != ".":
51+
return hyphen_dir_path
52+
# Top level dir Dockerfile use top level dirname
53+
return str(root_path.resolve().name)
54+
55+
# Pull request file change delta filter using GitHub API
56+
prefixes = json.loads(os.environ["PREFIX"])
57+
no_delta_prefixes = json.loads(os.environ["NO_DELTA_PREFIX"])
58+
owner, repository = os.environ["OWNER_REPOSITORY"].split("/", maxsplit=1)
59+
base = None
60+
env_vars = ["BASE", "BASE_REF"]
61+
for env_var in env_vars:
62+
if env_var in os.environ and os.environ[env_var].strip():
63+
# Set if present and not blank
64+
base = os.environ[env_var]
65+
66+
# Empty manifest (list of manifests for each build file) in case not triggered
67+
# from on file change (workflow changed or dispatched).
68+
manifest = []
69+
# Path to root of repo
70+
root_path = pathlib.Path(os.environ["ROOT_PATH"])
71+
# Grab commit from git
72+
commit = os.environ["COMMIT"]
73+
if base is None:
74+
print(f"::notice file={__file__},line=1,endLine=1,title=nobase::None of {env_vars!r} found in os.environ", file=sys.stderr)
75+
76+
else:
77+
compare_url = os.environ["COMPARE_URL"]
78+
compare_url = compare_url.replace("{base}", base)
79+
compare_url = compare_url.replace("{head}", os.environ["HEAD"])
80+
with urllib.request.urlopen(
81+
urllib.request.Request(
82+
compare_url,
83+
headers={
84+
"Authorization": "bearer " + os.environ["GH_ACCESS_TOKEN"],
85+
},
86+
)
87+
) as response:
88+
response_json = json.load(response)
89+
# Print for debug
90+
print(json.dumps({
91+
"@context": {
92+
"@vocab": "github_delta_response_json",
93+
},
94+
"include": manifest,
95+
}, sort_keys=True, indent=4), file=sys.stderr)
96+
# Build the most recent commit
97+
commit = response_json["commits"][-1]["sha"]
98+
manifest = list(itertools.chain(*(
99+
[
100+
[
101+
{
102+
"image_name": path_to_image_name(path, root_path),
103+
"dockerfile": str(path.relative_to(root_path)),
104+
"owner": owner,
105+
"repository": repository,
106+
"branch": os.environ["BRANCH"],
107+
"commit": commit,
108+
}
109+
for path in [
110+
(print(compare_file) or pathlib.Path(compare_file["filename"]))
111+
for compare_file in response_json["files"]
112+
if (
113+
any([
114+
compare_file["filename"].startswith(prefix_path)
115+
for prefix_path in json.loads(os.environ["PREFIX"])
116+
]) and compare_file["filename"].endswith("Dockerfile")
117+
)
118+
]
119+
]
120+
] + [
121+
[
122+
json.loads(path.read_text())
123+
for path in [
124+
(print(compare_file) or pathlib.Path(compare_file["filename"]))
125+
for compare_file in response_json["files"]
126+
if (
127+
any([
128+
compare_file["filename"].startswith(prefix_path)
129+
for prefix_path in json.loads(os.environ["PREFIX"])
130+
]) and compare_file["filename"].endswith("manifest.json")
131+
)
132+
]
133+
]
134+
]
135+
)))
136+
137+
# Build everything if we aren't sure why we got here
138+
if not manifest:
139+
manifest = list(itertools.chain(*(
140+
[
141+
[
142+
{
143+
"image_name": path_to_image_name(path, root_path),
144+
"dockerfile": str(path.relative_to(root_path)),
145+
"owner": owner,
146+
"repository": repository,
147+
"branch": os.environ["BRANCH"],
148+
"commit": commit,
149+
}
150+
for path in prefix_path.glob("*Dockerfile")
151+
]
152+
for prefix_path in map(pathlib.Path, prefixes)
153+
if any(
154+
str(prefix_path.relative_to(root_path)) in no_delta_prefix
155+
for no_delta_prefix in no_delta_prefixes
156+
)
157+
] + [
158+
[
159+
json.loads(path.read_text())
160+
for path in prefix_path.glob("*manifest.json")
161+
]
162+
for prefix_path in map(pathlib.Path, prefixes)
163+
if any(
164+
str(prefix_path.relative_to(root_path)) in no_delta_prefix
165+
for no_delta_prefix in no_delta_prefixes
166+
)
167+
]
168+
)))
169+
170+
# Add proxies or other runtime args/env vars
171+
for i in manifest:
172+
build_args = {}
173+
if "build_args" in i:
174+
build_args = dict(json.loads(i["build_args"]))
175+
for env_var in [
176+
"HTTP_PROXY",
177+
"HTTPS_PROXY",
178+
"NO_PROXY",
179+
]:
180+
if not env_var in os.environ:
181+
continue
182+
build_args[env_var] = os.environ[env_var]
183+
i["build_args"] = json.dumps(list(build_args.items()))
184+
185+
github_actions_manifest = {
186+
"include": manifest,
187+
}
188+
json_ld_manifest = {
189+
"@context": {
190+
"@vocab": os.environ["SCHEMA"],
191+
},
192+
**github_actions_manifest,
193+
}
194+
print(json.dumps(json_ld_manifest, sort_keys=True, indent=os.environ.get("JSON_INDENT", None)))
195+
196+
if "GITHUB_OUTPUT" in os.environ:
197+
with open(os.environ["GITHUB_OUTPUT"], "a") as fileobj:
198+
fileobj.write(f"manifest={json.dumps(manifest)}\n")
199+
fileobj.write(f'github_actions_manifest={json.dumps(github_actions_manifest)}\n')

0 commit comments

Comments
 (0)