Skip to content

Commit 13d1e06

Browse files
committed
Introduce a script for doing GHA pin bumps
1 parent 42c2d8f commit 13d1e06

File tree

3 files changed

+256
-107
lines changed

3 files changed

+256
-107
lines changed

.github/bin/bump_dependency.py

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
import argparse
2+
import os
3+
import re
4+
import subprocess
5+
import sys
6+
from datetime import datetime
7+
8+
9+
def get_remote_commit_sha(repo_url: str, branch: str) -> str:
10+
output = subprocess.check_output(
11+
["git", "ls-remote", repo_url, f"refs/heads/{branch}"], text=True
12+
)
13+
return output.split("\t")[0]
14+
15+
16+
def get_remote_latest_tag(repo_url: str, tag_pattern: str) -> str:
17+
output = subprocess.check_output(
18+
["git", "ls-remote", "--tags", repo_url], text=True
19+
)
20+
tags = []
21+
for line in output.split("\n"):
22+
if line.strip():
23+
parts = line.split("\t")
24+
if len(parts) == 2:
25+
ref = parts[1]
26+
if ref.startswith("refs/tags/") and not ref.endswith("^{}"):
27+
tag = ref.replace("refs/tags/", "")
28+
if re.match(tag_pattern + "$", tag):
29+
tags.append(tag)
30+
31+
def version_key(tag: str) -> tuple[int, ...]:
32+
version = tag.lstrip("v")
33+
return tuple(map(int, version.split(".")))
34+
35+
return sorted(tags, key=version_key)[-1]
36+
37+
38+
def get_current_version_from_file(file_path: str, pattern: str) -> str:
39+
with open(file_path) as f:
40+
content = f.read()
41+
42+
match = re.search(pattern, content)
43+
return match.group(1)
44+
45+
46+
def update_file_version(
47+
file_path: str, old_pattern: str, new_value: str, comment_pattern: str
48+
) -> None:
49+
with open(file_path) as f:
50+
content = f.read()
51+
52+
new_content = re.sub(old_pattern, new_value, content)
53+
54+
current_date = datetime.now().strftime("%b %d, %Y")
55+
new_content = re.sub(
56+
comment_pattern,
57+
lambda m: m.group(0).split(", as of")[0] + f", as of {current_date}.",
58+
new_content,
59+
)
60+
61+
with open(file_path, "w") as f:
62+
f.write(new_content)
63+
64+
65+
def generate_commit_message(
66+
repo_name: str,
67+
repo_url: str,
68+
old_version: str,
69+
new_version: str,
70+
is_tag: bool,
71+
commit_url_template: str,
72+
diff_url_template: str,
73+
) -> str:
74+
if is_tag:
75+
version_link = (
76+
f"[Tag: {new_version}]({repo_url}/releases/tag/{new_version})"
77+
)
78+
diff_url = diff_url_template.format(
79+
repo_url=repo_url, old_version=old_version, new_version=new_version
80+
)
81+
diff_link = f"[Diff]({diff_url})"
82+
description = "between the previously used tag and the new tag."
83+
else:
84+
commit_url = commit_url_template.format(
85+
repo_url=repo_url, version=new_version
86+
)
87+
version_link = f"[Commit: {new_version}]({commit_url})"
88+
diff_url = diff_url_template.format(
89+
repo_url=repo_url, old_version=old_version, new_version=new_version
90+
)
91+
diff_link = f"[Diff]({diff_url})"
92+
description = (
93+
"between the last commit hash merged to this repository "
94+
"and the new commit."
95+
)
96+
97+
return f"## {repo_name}\n{version_link}\n\n{diff_link} {description}"
98+
99+
100+
def main() -> int:
101+
parser = argparse.ArgumentParser(
102+
description="Bump a single dependency version"
103+
)
104+
parser.add_argument(
105+
"--name", required=True, help="Display name for the dependency"
106+
)
107+
parser.add_argument("--repo-url", required=True, help="Git repository URL")
108+
parser.add_argument(
109+
"--branch", default="main", help="Branch to check (default: main)"
110+
)
111+
parser.add_argument(
112+
"--file-path", required=True, help="File containing current version"
113+
)
114+
parser.add_argument(
115+
"--current-version-pattern",
116+
required=True,
117+
help="Regex to extract current version (group 1)",
118+
)
119+
parser.add_argument(
120+
"--update-pattern", required=True, help="Regex pattern for replacement"
121+
)
122+
parser.add_argument(
123+
"--comment-pattern",
124+
required=True,
125+
help="Regex pattern for comment update",
126+
)
127+
parser.add_argument(
128+
"--tag", action="store_true", help="Check tags instead of commits"
129+
)
130+
parser.add_argument(
131+
"--tag-pattern", default=r"v[0-9\.]*", help="Pattern for tag matching"
132+
)
133+
parser.add_argument(
134+
"--commit-url-template",
135+
default="{repo_url}/commit/{version}",
136+
help="Template for commit URLs",
137+
)
138+
parser.add_argument(
139+
"--diff-url-template",
140+
default="{repo_url}/compare/{old_version}...{new_version}",
141+
help="Template for diff URLs",
142+
)
143+
144+
args = parser.parse_args()
145+
146+
current_version = get_current_version_from_file(
147+
args.file_path, args.current_version_pattern
148+
)
149+
150+
if args.tag:
151+
latest_version = get_remote_latest_tag(args.repo_url, args.tag_pattern)
152+
else:
153+
latest_version = get_remote_commit_sha(args.repo_url, args.branch)
154+
155+
if current_version == latest_version:
156+
print(f"{args.name}: No update needed (current: {current_version})")
157+
with open(os.environ["GITHUB_OUTPUT"], "a") as f:
158+
f.write("HAS_UPDATES=false\n")
159+
return 0
160+
161+
print(
162+
f"{args.name}: Update available "
163+
f"({current_version} -> {latest_version})"
164+
)
165+
166+
replacement = args.update_pattern.replace("{new_version}", latest_version)
167+
update_file_version(
168+
args.file_path,
169+
args.current_version_pattern,
170+
replacement,
171+
args.comment_pattern,
172+
)
173+
174+
commit_msg = generate_commit_message(
175+
args.name,
176+
args.repo_url,
177+
current_version,
178+
latest_version,
179+
args.tag,
180+
args.commit_url_template,
181+
args.diff_url_template,
182+
)
183+
184+
with open(os.environ["GITHUB_OUTPUT"], "a") as f:
185+
f.write("COMMIT_MSG<<EOF\n")
186+
f.write(commit_msg)
187+
f.write("\nEOF\n")
188+
f.write("HAS_UPDATES=true\n")
189+
190+
return 0
191+
192+
193+
if __name__ == "__main__":
194+
sys.exit(main())

.github/workflows/boring-open-awslc-bump.yml

Lines changed: 38 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -17,75 +17,48 @@ jobs:
1717
with:
1818
# Needed so we can push back to the repo
1919
persist-credentials: true
20-
- id: check-sha-boring
20+
- id: bump-boringssl
2121
run: |
22-
SHA=$(git ls-remote https://boringssl.googlesource.com/boringssl refs/heads/main | cut -f1)
23-
LAST_COMMIT=$(grep boringssl .github/workflows/ci.yml | grep TYPE | grep -oE '[a-f0-9]{40}')
24-
if ! grep -q "$SHA" .github/workflows/ci.yml; then
25-
echo "COMMIT_SHA=${SHA}" >> $GITHUB_OUTPUT
26-
echo "COMMIT_MSG<<EOF" >> $GITHUB_OUTPUT
27-
echo -e "## BoringSSL\n[Commit: ${SHA}](https://boringssl.googlesource.com/boringssl/+/${SHA})\n\n[Diff](https://boringssl.googlesource.com/boringssl/+/${LAST_COMMIT}..${SHA}) between the last commit hash merged to this repository and the new commit." >> $GITHUB_OUTPUT
28-
echo "EOF" >> $GITHUB_OUTPUT
29-
30-
fi
31-
- id: check-sha-openssl
32-
run: |
33-
SHA=$(git ls-remote https://github.com/openssl/openssl refs/heads/master | cut -f1)
34-
LAST_COMMIT=$(grep openssl .github/workflows/ci.yml | grep TYPE | grep -oE '[a-f0-9]{40}')
35-
if ! grep -q "$SHA" .github/workflows/ci.yml; then
36-
echo "COMMIT_SHA=${SHA}" >> $GITHUB_OUTPUT
37-
echo "COMMIT_MSG<<EOF" >> $GITHUB_OUTPUT
38-
echo -e "## OpenSSL\n[Commit: ${SHA}](https://github.com/openssl/openssl/commit/${SHA})\n\n[Diff](https://github.com/openssl/openssl/compare/${LAST_COMMIT}...${SHA}) between the last commit hash merged to this repository and the new commit." >> $GITHUB_OUTPUT
39-
echo "EOF" >> $GITHUB_OUTPUT
40-
fi
41-
- id: check-tag-aws-lc
42-
run: |
43-
# Get the latest tag from AWS-LC repository
44-
LATEST_TAG=$(git ls-remote --tags https://github.com/aws/aws-lc.git | grep -o 'refs/tags/v[0-9\.]*$' | sort -V | tail -1 | sed 's|refs/tags/||')
45-
CURRENT_TAG=$(grep aws-lc .github/workflows/ci.yml | grep VERSION | grep -o 'v[0-9\.]*')
46-
47-
if [ "$LATEST_TAG" != "$CURRENT_TAG" ]; then
48-
echo "NEW_TAG=${LATEST_TAG}" >> $GITHUB_OUTPUT
49-
echo "COMMIT_MSG<<EOF" >> $GITHUB_OUTPUT
50-
echo -e "## AWS-LC\n[Tag: ${LATEST_TAG}](https://github.com/aws/aws-lc/releases/tag/${LATEST_TAG})\n\n[Diff](https://github.com/aws/aws-lc/compare/${CURRENT_TAG}...${LATEST_TAG}) between the previously used tag and the new tag." >> $GITHUB_OUTPUT
51-
echo "EOF" >> $GITHUB_OUTPUT
52-
fi
53-
- name: Update boring
54-
run: |
55-
set -xe
56-
CURRENT_DATE=$(date "+%b %d, %Y")
57-
sed -E -i "s/Latest commit on the BoringSSL main branch.*/Latest commit on the BoringSSL main branch, as of ${CURRENT_DATE}./" .github/workflows/ci.yml
58-
sed -E -i "s/TYPE: \"boringssl\", VERSION: \"[0-9a-f]{40}\"/TYPE: \"boringssl\", VERSION: \"${COMMIT_SHA}\"/" .github/workflows/ci.yml
59-
git status
60-
if: steps.check-sha-boring.outputs.COMMIT_SHA
61-
env:
62-
COMMIT_SHA: ${{ steps.check-sha-boring.outputs.COMMIT_SHA }}
63-
- name: Update OpenSSL
22+
python3 .github/bin/bump_dependency.py \
23+
--name "BoringSSL" \
24+
--repo-url "https://boringssl.googlesource.com/boringssl" \
25+
--branch "main" \
26+
--file-path ".github/workflows/ci.yml" \
27+
--current-version-pattern 'TYPE: "boringssl", VERSION: "([a-f0-9]{40})"' \
28+
--update-pattern 'TYPE: "boringssl", VERSION: "{new_version}"' \
29+
--comment-pattern 'Latest commit on the BoringSSL main branch.*?\.' \
30+
--commit-url-template "{repo_url}/+/{version}" \
31+
--diff-url-template "{repo_url}/+/{old_version}..{new_version}"
32+
- id: bump-openssl
6433
run: |
65-
set -xe
66-
CURRENT_DATE=$(date "+%b %d, %Y")
67-
sed -E -i "s/Latest commit on the OpenSSL master branch.*/Latest commit on the OpenSSL master branch, as of ${CURRENT_DATE}./" .github/workflows/ci.yml
68-
sed -E -i "s/TYPE: \"openssl\", VERSION: \"[0-9a-f]{40}\"/TYPE: \"openssl\", VERSION: \"${COMMIT_SHA}\"/" .github/workflows/ci.yml
69-
git status
70-
if: steps.check-sha-openssl.outputs.COMMIT_SHA
71-
env:
72-
COMMIT_SHA: ${{ steps.check-sha-openssl.outputs.COMMIT_SHA }}
73-
- name: Update AWS-LC
34+
python3 .github/bin/bump_dependency.py \
35+
--name "OpenSSL" \
36+
--repo-url "https://github.com/openssl/openssl" \
37+
--branch "master" \
38+
--file-path ".github/workflows/ci.yml" \
39+
--current-version-pattern 'TYPE: "openssl", VERSION: "([a-f0-9]{40})"' \
40+
--update-pattern 'TYPE: "openssl", VERSION: "{new_version}"' \
41+
--comment-pattern 'Latest commit on the OpenSSL master branch.*?\.'
42+
- id: bump-awslc
7443
run: |
75-
set -xe
76-
CURRENT_DATE=$(date "+%b %d, %Y")
77-
sed -E -i "s/Latest tag of AWS-LC main branch, as of .*/Latest tag of AWS-LC main branch, as of ${CURRENT_DATE}./" .github/workflows/ci.yml
78-
sed -E -i "s/TYPE: \"aws-lc\", VERSION: \"v[0-9\.]*\"/TYPE: \"aws-lc\", VERSION: \"${NEW_TAG}\"/" .github/workflows/ci.yml
79-
git status
80-
if: steps.check-tag-aws-lc.outputs.NEW_TAG
81-
env:
82-
NEW_TAG: ${{ steps.check-tag-aws-lc.outputs.NEW_TAG }}
44+
python3 .github/bin/bump_dependency.py \
45+
--name "AWS-LC" \
46+
--repo-url "https://github.com/aws/aws-lc" \
47+
--branch "main" \
48+
--file-path ".github/workflows/ci.yml" \
49+
--current-version-pattern 'TYPE: "aws-lc", VERSION: "(v[0-9\.]*)"' \
50+
--update-pattern 'TYPE: "aws-lc", VERSION: "{new_version}"' \
51+
--comment-pattern 'Latest tag of AWS-LC main branch, as of .*?\.' \
52+
--tag \
53+
--tag-pattern 'v[0-9\.]*'
54+
- name: Check for updates
55+
run: git status
8356
- uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a # v2.1.0
8457
id: generate-token
8558
with:
8659
app_id: ${{ secrets.BORINGBOT_APP_ID }}
8760
private_key: ${{ secrets.BORINGBOT_PRIVATE_KEY }}
88-
if: steps.check-sha-boring.outputs.COMMIT_SHA || steps.check-sha-openssl.outputs.COMMIT_SHA || steps.check-tag-aws-lc.outputs.NEW_TAG
61+
if: steps.bump-boringssl.outputs.HAS_UPDATES == 'true' || steps.bump-openssl.outputs.HAS_UPDATES == 'true' || steps.bump-awslc.outputs.HAS_UPDATES == 'true'
8962
- name: Create Pull Request
9063
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
9164
with:
@@ -94,8 +67,8 @@ jobs:
9467
title: "Bump BoringSSL, OpenSSL, AWS-LC in CI"
9568
author: "pyca-boringbot[bot] <pyca-boringbot[bot][email protected]>"
9669
body: |
97-
${{ steps.check-sha-boring.outputs.COMMIT_MSG }}
98-
${{ steps.check-sha-openssl.outputs.COMMIT_MSG }}
99-
${{ steps.check-tag-aws-lc.outputs.COMMIT_MSG }}
70+
${{ steps.bump-boringssl.outputs.COMMIT_MSG }}
71+
${{ steps.bump-openssl.outputs.COMMIT_MSG }}
72+
${{ steps.bump-awslc.outputs.COMMIT_MSG }}
10073
token: ${{ steps.generate-token.outputs.token }}
101-
if: steps.check-sha-boring.outputs.COMMIT_SHA || steps.check-sha-openssl.outputs.COMMIT_SHA || steps.check-tag-aws-lc.outputs.NEW_TAG
74+
if: steps.bump-boringssl.outputs.HAS_UPDATES == 'true' || steps.bump-openssl.outputs.HAS_UPDATES == 'true' || steps.bump-awslc.outputs.HAS_UPDATES == 'true'

0 commit comments

Comments
 (0)