Skip to content

Commit 4685661

Browse files
committed
feat(image): pre-cache GitHub Actions and add nightly refresh
Preload frequently used GitHub Actions from manifest-defined refs into the runner image so jobs start faster and rely less on network fetches. Add a nightly workflow that forces a release-path rebuild when no unreleased commits exist, keeping major-tagged action refs fresh. Made-with: Cursor
1 parent b19907d commit 4685661

5 files changed

Lines changed: 115 additions & 0 deletions

File tree

.github/workflows/nightly.yaml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Nightly rebuild
2+
3+
on:
4+
schedule:
5+
- cron: "17 3 * * *"
6+
workflow_dispatch:
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
ensure-release:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v6
16+
with:
17+
fetch-depth: 0
18+
persist-credentials: true
19+
20+
- name: Force minor bump if no unreleased commits
21+
shell: bash
22+
run: |
23+
set -euo pipefail
24+
25+
git config user.name 'github-actions[bot]'
26+
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
27+
28+
last_tag="$(git describe --tags --abbrev=0 2>/dev/null || echo '')"
29+
if [ -n "${last_tag}" ] && [ "$(git rev-list "${last_tag}..HEAD" --count)" -eq 0 ]; then
30+
git commit --allow-empty -m 'feat: nightly rebuild to refresh base image and cached actions'
31+
git push origin HEAD:main
32+
fi

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22

33
### Added
44

5+
* **ci:** add nightly rebuild workflow to force daily semantic-release/image refreshes when no unreleased commits exist
6+
57
### Changed
68

79
- **release:** configure semantic-release to treat `chore` commits as minor releases and include them in generated release notes
10+
- **image:** pre-cache commonly used GitHub Actions from `manifest.yaml` into the runner `_work/_actions` directory during image build
811

912
### Fixed
1013

Containerfile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,5 +136,12 @@ RUN curl -sSL https://install.python-poetry.org | python3 -
136136
# hadolint ignore=DL4006
137137
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
138138

139+
# Pre-cache selected GitHub Actions used by project workflows.
140+
COPY --chown=runner:runner manifest.yaml /tmp/manifest.yaml
141+
COPY --chown=runner:runner scripts/cache_actions.sh /tmp/cache_actions.sh
142+
RUN chmod +x /tmp/cache_actions.sh \
143+
&& /tmp/cache_actions.sh /tmp/manifest.yaml \
144+
&& rm -f /tmp/manifest.yaml /tmp/cache_actions.sh
145+
139146
# Add user tool paths to interactive shell PATH
140147
RUN echo "export PATH=\"/usr/local/bin:${APP_HOME}/.uv/bin:${APP_HOME}/.poetry/bin:${APP_HOME}/.local/bin:\$PATH\"" >> ~/.bashrc

manifest.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,12 @@ build:
2020
- org.opencontainers.image.licenses="MIT"
2121
- org.opencontainers.image.authors="Deerhide"
2222
- org.opencontainers.image.vendor="Deerhide"
23+
cache:
24+
actions:
25+
- actions/checkout@v6
26+
- wagoid/commitlint-github-action@v6
27+
- cycjimmy/semantic-release-action@v6
28+
- actions/cache@v5
29+
- actions/upload-artifact@v7
30+
- actions/download-artifact@v8
31+
- actions/cache/restore@v5

scripts/cache_actions.sh

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#!/usr/bin/env bash
2+
3+
set -euo pipefail
4+
5+
manifest_path="${1:-manifest.yaml}"
6+
actions_root="${ACTIONS_CACHE_ROOT:-/home/runner/_work/_actions}"
7+
8+
if ! command -v yq >/dev/null 2>&1; then
9+
echo "Error: yq is required but not installed." >&2
10+
exit 1
11+
fi
12+
13+
if [[ ! -f "${manifest_path}" ]]; then
14+
echo "Error: manifest file not found at ${manifest_path}" >&2
15+
exit 1
16+
fi
17+
18+
mkdir -p "${actions_root}"
19+
20+
declare -A seen_actions=()
21+
22+
while IFS= read -r action_ref; do
23+
[[ -z "${action_ref}" ]] && continue
24+
25+
if [[ "${action_ref}" != *@* ]]; then
26+
echo "Error: invalid action entry '${action_ref}', expected owner/repo[/path]@ref" >&2
27+
exit 1
28+
fi
29+
30+
repo_with_optional_path="${action_ref%@*}"
31+
ref="${action_ref##*@}"
32+
33+
if [[ "${repo_with_optional_path}" != */* ]]; then
34+
echo "Error: invalid action repo '${repo_with_optional_path}' in '${action_ref}'" >&2
35+
exit 1
36+
fi
37+
38+
owner="${repo_with_optional_path%%/*}"
39+
remainder="${repo_with_optional_path#*/}"
40+
repo="${remainder%%/*}"
41+
42+
if [[ -z "${owner}" || -z "${repo}" || -z "${ref}" ]]; then
43+
echo "Error: invalid action entry '${action_ref}'" >&2
44+
exit 1
45+
fi
46+
47+
cache_key="${owner}/${repo}@${ref}"
48+
if [[ -n "${seen_actions[${cache_key}]:-}" ]]; then
49+
continue
50+
fi
51+
seen_actions["${cache_key}"]=1
52+
53+
dest_dir="${actions_root}/${owner}/${repo}/${ref}"
54+
archive_url="https://codeload.github.com/${owner}/${repo}/tar.gz/${ref}"
55+
56+
rm -rf "${dest_dir}"
57+
mkdir -p "${dest_dir}"
58+
59+
echo "Caching ${cache_key}"
60+
curl -fsSL "${archive_url}" \
61+
| tar -xz --strip-components=1 -C "${dest_dir}"
62+
63+
touch "${dest_dir}/.completed"
64+
done < <(yq e -r '.cache.actions[]' "${manifest_path}")

0 commit comments

Comments
 (0)