Skip to content

Commit 5bfc5bb

Browse files
committed
Merge remote-tracking branch 'upstream/main'
2 parents 2c5e719 + 6118da9 commit 5bfc5bb

File tree

2 files changed

+149
-0
lines changed

2 files changed

+149
-0
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
---
2+
name: Update commit-latest.env on params-latest.env change
3+
4+
"on":
5+
workflow_dispatch:
6+
push:
7+
branches:
8+
- main
9+
- rhoai-*
10+
paths:
11+
- 'manifests/base/params-latest.env'
12+
13+
jobs:
14+
sync-commit:
15+
runs-on: ubuntu-latest
16+
permissions:
17+
contents: write
18+
steps:
19+
- name: Checkout repository
20+
uses: actions/checkout@v4
21+
with:
22+
token: ${{ secrets.GITHUB_TOKEN }}
23+
24+
- name: Update manifests/base/commit-latest.env
25+
id: update_env
26+
run: |
27+
python3 scripts/update-commit-latest-env.py
28+
29+
- name: Commit and push changes
30+
run: |
31+
git config --global user.name 'github-actions[bot]'
32+
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
33+
34+
# Check for changes before committing
35+
if ! git diff --quiet manifests/base/commit-latest.env; then
36+
git add manifests/base/commit-latest.env
37+
git commit -m "ci: update commit SHAs for image digests changes"
38+
git push
39+
else
40+
echo "No effective changes in manifests/base/commit-latest.env, skipping commit."
41+
fi

scripts/update-commit-latest-env.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
from __future__ import annotations
2+
3+
import asyncio
4+
import json
5+
import logging
6+
import pathlib
7+
import re
8+
import sys
9+
import typing
10+
11+
PROJECT_ROOT = pathlib.Path(__file__).parent.parent
12+
13+
14+
async def get_image_vcs_ref(image_url: str) -> tuple[str, str | None]:
15+
"""
16+
Asynchronously inspects a container image's configuration using skopeo
17+
and extracts the 'vcs-ref' label.
18+
19+
Args:
20+
image_url: The full URL of the image to inspect
21+
(e.g., 'quay.io/opendatahub/workbench-images@sha256:...').
22+
23+
Returns:
24+
A tuple containing the original image_url and the value of the 'vcs-ref'
25+
label if found, otherwise None.
26+
"""
27+
# Using 'docker://' prefix is required for skopeo to identify the transport.
28+
full_image_url = f"docker://{image_url}"
29+
30+
# Use 'inspect --config' which is much faster as it only fetches the config blob.
31+
command = ["skopeo", "inspect", "--retry-times=5", "--config", full_image_url]
32+
33+
logging.info(f"Starting config inspection for: {image_url}")
34+
35+
try:
36+
# Create an asynchronous subprocess
37+
process = await asyncio.create_subprocess_exec(
38+
*command,
39+
stdout=asyncio.subprocess.PIPE,
40+
stderr=asyncio.subprocess.PIPE
41+
)
42+
43+
# Wait for the command to complete and capture output
44+
stdout, stderr = await process.communicate()
45+
46+
# Check for errors
47+
if process.returncode != 0:
48+
logging.error(f"Skopeo command failed for {image_url} with exit code {process.returncode}.")
49+
logging.error(f"Stderr: {stderr.decode().strip()}")
50+
return image_url, None
51+
52+
# Decode and parse the JSON output from stdout
53+
# The output of 'inspect --config' is the image config JSON directly.
54+
image_config = json.loads(stdout.decode())
55+
56+
# Safely extract the 'vcs-ref' label from the config's 'Labels'
57+
vcs_ref = image_config.get("config", {}).get("Labels", {}).get("vcs-ref")
58+
59+
if vcs_ref:
60+
logging.info(f"Successfully found 'vcs-ref' for {image_url}: {vcs_ref}")
61+
else:
62+
logging.warning(f"'vcs-ref' label not found for {image_url}.")
63+
64+
return image_url, vcs_ref
65+
66+
except FileNotFoundError:
67+
logging.error("The 'skopeo' command was not found. Please ensure it is installed and in your PATH.")
68+
return image_url, None
69+
except json.JSONDecodeError:
70+
logging.error(f"Failed to parse skopeo output as JSON for {image_url}.")
71+
return image_url, None
72+
except Exception as e:
73+
logging.error(f"An unexpected error occurred while processing {image_url}: {e}")
74+
return image_url, None
75+
76+
77+
async def inspect(images_to_inspect: typing.Iterable[str]) -> list[tuple[str, str | None]]:
78+
"""
79+
Main function to orchestrate the concurrent inspection of multiple images.
80+
"""
81+
tasks = [get_image_vcs_ref(image) for image in images_to_inspect]
82+
return await asyncio.gather(*tasks)
83+
84+
85+
async def main():
86+
with open(PROJECT_ROOT / "manifests/base/params-latest.env", "rt") as file:
87+
images_to_inspect: list[list[str]] = [line.strip().split('=', 1) for line in file.readlines()
88+
if line.strip() and not line.strip().startswith("#")]
89+
90+
results = await inspect(value for _, value in images_to_inspect)
91+
if any(commit_hash is None for variable, commit_hash in results):
92+
logging.error("Failed to get commit hash for some images. Quitting, please try again to try again, like.")
93+
sys.exit(1)
94+
95+
output = []
96+
for image, result in zip(images_to_inspect, results, strict=True):
97+
variable, image_digest = image
98+
_, commit_hash = result
99+
output.append((re.sub(r'-n$', "-commit-n", variable), commit_hash[:7]))
100+
101+
with open(PROJECT_ROOT / "manifests/base/commit-latest.env", "wt") as file:
102+
for line in output:
103+
print(*line, file=file, sep="=", end="\n")
104+
105+
106+
if __name__ == '__main__':
107+
logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s')
108+
asyncio.run(main())

0 commit comments

Comments
 (0)