Skip to content

Commit c6bb398

Browse files
Merge pull request #4 from EmbeddedAndroid/auto-update-action
ci: auto-update workflow for new VSCode releases
2 parents 697392e + a97e3fd commit c6bb398

1 file changed

Lines changed: 224 additions & 0 deletions

File tree

.github/workflows/auto-update.yml

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
name: auto-update
2+
3+
# Daily check against Microsoft's stable channel for a new VSCode
4+
# release. If the SHA on the latest-redirect doesn't match what the
5+
# recipe pins, open a PR that bumps the recipe (per-arch SRCREVs,
6+
# tarball timestamps, sha256 checksums, and the LICENSES.chromium.html
7+
# md5) and renames the file to vscode_<new-version>.bb.
8+
#
9+
# The PR is left for human review before merging -- automated bumps
10+
# of opaque binary blobs are exactly the case where a human eye on
11+
# the diff is valuable.
12+
13+
on:
14+
schedule:
15+
# 10:42 UTC daily. Microsoft typically publishes stable releases
16+
# mid-month around 17:00-22:00 UTC; a morning-UTC poll picks them
17+
# up the next day reliably without piling on right after release.
18+
- cron: '42 10 * * *'
19+
workflow_dispatch:
20+
21+
permissions:
22+
contents: write
23+
pull-requests: write
24+
25+
jobs:
26+
check-and-update:
27+
runs-on: ubuntu-22.04
28+
steps:
29+
- uses: actions/checkout@v4
30+
with:
31+
# Need full history so we can detect whether an auto-update
32+
# branch with the new version already exists.
33+
fetch-depth: 0
34+
35+
- name: Resolve Microsoft's latest stable URLs
36+
id: resolve
37+
run: |
38+
set -eo pipefail
39+
for arch in x64 arm64 armhf; do
40+
url=$(curl -sLI "https://update.code.visualstudio.com/latest/linux-$arch/stable" \
41+
| awk 'BEGIN{IGNORECASE=1} /^location:/{print $2}' \
42+
| tr -d '\r' | tail -1)
43+
if [ -z "$url" ]; then
44+
echo "::error::failed to resolve URL for $arch"
45+
exit 1
46+
fi
47+
# URL pattern: .../stable/<sha>/code-stable-<arch>-<timestamp>.tar.gz
48+
sha=$(echo "$url" | awk -F/ '{print $(NF-1)}')
49+
ts=$(echo "$url" | awk -F/ '{print $NF}' | sed -E "s/code-stable-${arch}-([0-9]+)\.tar\.gz/\1/")
50+
echo "$arch url: $url"
51+
echo "$arch sha: $sha"
52+
echo "$arch ts: $ts"
53+
echo "url_$arch=$url" >> "$GITHUB_OUTPUT"
54+
echo "sha_$arch=$sha" >> "$GITHUB_OUTPUT"
55+
echo "ts_$arch=$ts" >> "$GITHUB_OUTPUT"
56+
done
57+
58+
- name: Read current recipe state
59+
id: current
60+
run: |
61+
set -eo pipefail
62+
recipe=$(ls recipes-devtools/vscode/vscode_*.bb)
63+
ver=$(basename "$recipe" .bb | sed 's/^vscode_//')
64+
cur_sha=$(awk -F'"' '/^GIT_SHA[[:space:]]*=/ { print $2; exit }' "$recipe")
65+
echo "recipe=$recipe" >> "$GITHUB_OUTPUT"
66+
echo "version=$ver" >> "$GITHUB_OUTPUT"
67+
echo "git_sha=$cur_sha" >> "$GITHUB_OUTPUT"
68+
echo "Current: $recipe / version=$ver / GIT_SHA=$cur_sha"
69+
70+
- name: Skip if upstream SHA matches current recipe
71+
id: gate
72+
run: |
73+
set -eo pipefail
74+
# All three arches publish in lockstep under the same SHA;
75+
# if any of them diverge the recipe layout doesn't support
76+
# it anyway, so use x64 as the canonical signal.
77+
if [ "${{ steps.resolve.outputs.sha_x64 }}" = "${{ steps.current.outputs.git_sha }}" ]; then
78+
echo "Already at latest stable SHA ${{ steps.current.outputs.git_sha }}; nothing to do."
79+
echo "needs_update=false" >> "$GITHUB_OUTPUT"
80+
exit 0
81+
fi
82+
echo "Upstream has new SHA: ${{ steps.resolve.outputs.sha_x64 }} (recipe pins ${{ steps.current.outputs.git_sha }})"
83+
echo "needs_update=true" >> "$GITHUB_OUTPUT"
84+
85+
- name: Fetch tarballs and compute checksums + license md5
86+
if: steps.gate.outputs.needs_update == 'true'
87+
id: checksums
88+
run: |
89+
set -eo pipefail
90+
mkdir -p /tmp/vscode-tarballs
91+
for arch in x64 arm64 armhf; do
92+
url_var="url_$arch"
93+
url="${{ steps.resolve.outputs.url_x64 }}"
94+
# Re-resolve per-arch URL via output (matrix-style)
95+
case $arch in
96+
x64) url="${{ steps.resolve.outputs.url_x64 }}" ;;
97+
arm64) url="${{ steps.resolve.outputs.url_arm64 }}" ;;
98+
armhf) url="${{ steps.resolve.outputs.url_armhf }}" ;;
99+
esac
100+
echo "Downloading $arch from $url"
101+
curl -sLo "/tmp/vscode-tarballs/$arch.tgz" "$url"
102+
sum=$(sha256sum "/tmp/vscode-tarballs/$arch.tgz" | cut -d' ' -f1)
103+
echo "sha256_$arch=$sum" >> "$GITHUB_OUTPUT"
104+
echo "$arch: $sum"
105+
done
106+
107+
# All three tarballs ship the same LICENSES.chromium.html;
108+
# extract from x64 (cheapest) and md5 it.
109+
mkdir -p /tmp/vscode-extract
110+
tar xzf /tmp/vscode-tarballs/x64.tgz -C /tmp/vscode-extract \
111+
VSCode-linux-x64/LICENSES.chromium.html
112+
lic_md5=$(md5sum /tmp/vscode-extract/VSCode-linux-x64/LICENSES.chromium.html \
113+
| cut -d' ' -f1)
114+
echo "license_md5=$lic_md5" >> "$GITHUB_OUTPUT"
115+
echo "LICENSES.chromium.html md5: $lic_md5"
116+
117+
- name: Discover new version string
118+
if: steps.gate.outputs.needs_update == 'true'
119+
id: version
120+
run: |
121+
set -eo pipefail
122+
# Microsoft's `/api/update/.../stable/VERSION/.../release-notes` is one
123+
# source of the human-readable version. Simpler: parse the binary's
124+
# ProductDevelopment from package.json inside the tarball.
125+
mkdir -p /tmp/vscode-extract-meta
126+
tar xzf /tmp/vscode-tarballs/x64.tgz -C /tmp/vscode-extract-meta \
127+
VSCode-linux-x64/resources/app/package.json
128+
ver=$(python3 -c "import json; print(json.load(open('/tmp/vscode-extract-meta/VSCode-linux-x64/resources/app/package.json'))['version'])")
129+
echo "Detected version: $ver"
130+
echo "version=$ver" >> "$GITHUB_OUTPUT"
131+
132+
- name: Bail if a branch for this version already exists
133+
if: steps.gate.outputs.needs_update == 'true'
134+
id: branch_check
135+
run: |
136+
set -eo pipefail
137+
branch="auto-update/vscode-${{ steps.version.outputs.version }}"
138+
if git ls-remote --heads origin "$branch" | grep -q "$branch"; then
139+
echo "::warning::branch $branch already exists upstream; skipping (assume PR already pending)"
140+
echo "skip=true" >> "$GITHUB_OUTPUT"
141+
else
142+
echo "skip=false" >> "$GITHUB_OUTPUT"
143+
echo "branch=$branch" >> "$GITHUB_OUTPUT"
144+
fi
145+
146+
- name: Update recipe in-place
147+
if: steps.gate.outputs.needs_update == 'true' && steps.branch_check.outputs.skip != 'true'
148+
run: |
149+
set -eo pipefail
150+
old_recipe="${{ steps.current.outputs.recipe }}"
151+
new_recipe="recipes-devtools/vscode/vscode_${{ steps.version.outputs.version }}.bb"
152+
git mv "$old_recipe" "$new_recipe"
153+
154+
# In-place value substitutions. Avoid sed -i's BSD/GNU split
155+
# by using Python.
156+
python3 - <<PYEOF
157+
import re, pathlib
158+
p = pathlib.Path("$new_recipe")
159+
s = p.read_text()
160+
subs = [
161+
(r'^GIT_SHA = "[^"]*"',
162+
'GIT_SHA = "${{ steps.resolve.outputs.sha_x64 }}"'),
163+
(r'^TIMESTAMP-x64 = "[^"]*"',
164+
'TIMESTAMP-x64 = "${{ steps.resolve.outputs.ts_x64 }}"'),
165+
(r'^TIMESTAMP-arm64 = "[^"]*"',
166+
'TIMESTAMP-arm64 = "${{ steps.resolve.outputs.ts_arm64 }}"'),
167+
(r'^TIMESTAMP-armhf = "[^"]*"',
168+
'TIMESTAMP-armhf = "${{ steps.resolve.outputs.ts_armhf }}"'),
169+
(r'^SRC_URI\[vscode-x64\.sha256sum\][^=]*=\s*"[^"]*"',
170+
'SRC_URI[vscode-x64.sha256sum] = "${{ steps.checksums.outputs.sha256_x64 }}"'),
171+
(r'^SRC_URI\[vscode-arm64\.sha256sum\][^=]*=\s*"[^"]*"',
172+
'SRC_URI[vscode-arm64.sha256sum] = "${{ steps.checksums.outputs.sha256_arm64 }}"'),
173+
(r'^SRC_URI\[vscode-armhf\.sha256sum\][^=]*=\s*"[^"]*"',
174+
'SRC_URI[vscode-armhf.sha256sum] = "${{ steps.checksums.outputs.sha256_armhf }}"'),
175+
(r'LICENSES\.chromium\.html;md5=[0-9a-f]+',
176+
'LICENSES.chromium.html;md5=${{ steps.checksums.outputs.license_md5 }}'),
177+
]
178+
for pat, repl in subs:
179+
s, n = re.subn(pat, repl, s, count=1, flags=re.MULTILINE)
180+
if n == 0:
181+
raise SystemExit(f"pattern not matched: {pat}")
182+
p.write_text(s)
183+
PYEOF
184+
185+
echo "--- diff ---"
186+
git diff -- "$new_recipe" || true
187+
188+
- name: Commit + push branch + open PR
189+
if: steps.gate.outputs.needs_update == 'true' && steps.branch_check.outputs.skip != 'true'
190+
env:
191+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
192+
run: |
193+
set -eo pipefail
194+
git config user.name "github-actions[bot]"
195+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
196+
branch="${{ steps.branch_check.outputs.branch }}"
197+
git checkout -b "$branch"
198+
git add -A
199+
git commit -m "vscode: bump to ${{ steps.version.outputs.version }}
200+
201+
Microsoft released VSCode ${{ steps.version.outputs.version }} (SHA
202+
${{ steps.resolve.outputs.sha_x64 }}). Per-arch tarball timestamps:
203+
x64 ${{ steps.resolve.outputs.ts_x64 }}
204+
arm64 ${{ steps.resolve.outputs.ts_arm64 }}
205+
armhf ${{ steps.resolve.outputs.ts_armhf }}
206+
sha256 checksums and LICENSES.chromium.html md5 refreshed."
207+
git push -u origin "$branch"
208+
gh pr create \
209+
--base main --head "$branch" \
210+
--title "vscode: bump to ${{ steps.version.outputs.version }}" \
211+
--body "Automated bump generated by .github/workflows/auto-update.yml.
212+
213+
Upstream details:
214+
- SHA: \`${{ steps.resolve.outputs.sha_x64 }}\`
215+
- Version: \`${{ steps.version.outputs.version }}\`
216+
217+
Per-arch tarballs:
218+
- x64: \`${{ steps.resolve.outputs.url_x64 }}\`
219+
- arm64: \`${{ steps.resolve.outputs.url_arm64 }}\`
220+
- armhf: \`${{ steps.resolve.outputs.url_armhf }}\`
221+
222+
sha256 checksums refreshed; LICENSES.chromium.html md5 re-extracted from the new x64 tarball.
223+
224+
CI will run the multi-arch parse + fetch matrix and the end-to-end scarthgap build. Eyeball the diff before merging since this is a proprietary binary bump."

0 commit comments

Comments
 (0)