Skip to content

Commit e98491e

Browse files
committed
ci: add the ability to rebuild all app images on demand
Useful if the base has changed
1 parent e442803 commit e98491e

File tree

2 files changed

+211
-0
lines changed

2 files changed

+211
-0
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#!/usr/bin/env bash
2+
3+
shopt -s lastpipe
4+
5+
[[ -n "${DEBUG:-}" ]] && set -x
6+
7+
declare -a changes_array
8+
9+
while read -r metadata; do
10+
if [[ ! -f "$metadata" ]]; then
11+
echo "⚠️ Skipping invalid file: $metadata"
12+
continue
13+
fi
14+
15+
if jq -e '.base == true' "$metadata" > /dev/null; then
16+
app="$(jq --raw-output '.app' "$metadata")"
17+
echo "⏭️ Skipping base image app: ${app}"
18+
continue
19+
fi
20+
21+
app="$(jq --raw-output '.app' "$metadata")"
22+
23+
echo "πŸ” Collecting app: ${app}"
24+
25+
while read -r channel_info; do
26+
channel="$(jq --raw-output '.name' <<< "$channel_info")"
27+
changes_array+=("$(jo app="$app" channel="$channel")")
28+
done < <(jq --raw-output -c '.channels | .[]' "$metadata")
29+
done < <(find ./apps -name metadata.json)
30+
31+
output="$(jo -a "${changes_array[@]}")"
32+
33+
echo "βœ… Manual rebuild forced. Including all apps/channels:"
34+
echo "$output"
35+
echo "changes=${output}" >> "$GITHUB_OUTPUT"
36+
37+
image_list="$(printf '%s\n' "${changes_array[@]}" \
38+
| jq -R -s -c 'split("\n") | map(select(length > 0)) | map(fromjson | "\(.app):\(.channel)")')"
39+
40+
echo "images=${image_list}" >> "$GITHUB_OUTPUT"
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
---
2+
name: "Manual: Release All App Images"
3+
4+
on:
5+
workflow_dispatch:
6+
inputs:
7+
dryRun:
8+
description: "Only print changes, don't build or push"
9+
required: false
10+
default: false
11+
type: boolean
12+
13+
env:
14+
TOKEN: ${{ secrets.GITHUB_TOKEN }}
15+
DRY_RUN: ${{ github.event.inputs.dryRun }}
16+
17+
jobs:
18+
generate-build-matrix:
19+
name: Generate matrix for building images
20+
runs-on: ubuntu-latest
21+
outputs:
22+
matrix: ${{ steps.updates.outputs.changes }}
23+
images: ${{ steps.updates.outputs.images }}
24+
steps:
25+
- uses: actions/checkout@v3
26+
with:
27+
token: ${{ env.TOKEN }}
28+
29+
- name: Install tools
30+
run: |
31+
sudo apt-get update
32+
sudo apt-get -y install moreutils jo
33+
34+
- name: Fetch all apps
35+
id: updates
36+
run: ./.github/scripts/rebuild-all.sh
37+
38+
images-build:
39+
name: Build and push images
40+
runs-on: ubuntu-latest
41+
needs: [generate-build-matrix]
42+
if: |
43+
always()
44+
&& contains(needs.*.result, 'success')
45+
&& !contains(needs.*.result, 'failure')
46+
&& !cancelled()
47+
&& needs.generate-build-matrix.outputs.matrix != '[]'
48+
strategy:
49+
matrix:
50+
image: ${{ fromJson(needs.generate-build-matrix.outputs.matrix) }}
51+
fail-fast: false
52+
steps:
53+
- name: Dry run summary
54+
if: ${{ env.DRY_RUN == 'true' }}
55+
run: |
56+
echo "DRY RUN ENABLED – no images will be built or pushed"
57+
echo "Matrix:"
58+
echo '${{ needs.generate-build-matrix.outputs.matrix }}'
59+
60+
- name: Checkout
61+
uses: actions/checkout@v3
62+
63+
- name: Extract build metadata
64+
id: vars
65+
uses: ./.github/actions/setup-vars
66+
with:
67+
app: ${{ matrix.image.app }}
68+
channel: ${{ matrix.image.channel }}
69+
70+
- name: Validate metadata
71+
uses: ./.github/actions/validate-cue
72+
with:
73+
app: ${{ matrix.image.app }}
74+
75+
- name: Build test image
76+
if: ${{ env.DRY_RUN != 'true' }}
77+
uses: ./.github/actions/build-test-image
78+
with:
79+
app: ${{ matrix.image.app }}
80+
channel: ${{ matrix.image.channel }}
81+
upstream_version: ${{ steps.vars.outputs.chan_upstream_version }}
82+
dockerfile: ${{ steps.vars.outputs.chan_dockerfile }}
83+
tag_testing: ${{ steps.vars.outputs.chan_tag_testing }}
84+
85+
- name: Run Goss tests
86+
if: ${{ env.DRY_RUN != 'true' && steps.vars.outputs.chan_tests_enabled == 'true' }}
87+
uses: ./.github/actions/run-goss-tests
88+
with:
89+
tag_testing: ${{ steps.vars.outputs.chan_tag_testing }}
90+
goss_config: ${{ steps.vars.outputs.chan_goss_config }}
91+
goss_args: ${{ steps.vars.outputs.chan_goss_args }}
92+
93+
- name: Build and push release image
94+
if: ${{ env.DRY_RUN != 'true' }}
95+
uses: ./.github/actions/build-release-image
96+
with:
97+
app: ${{ matrix.image.app }}
98+
channel: ${{ matrix.image.channel }}
99+
upstream_version: ${{ steps.vars.outputs.chan_upstream_version }}
100+
dockerfile: ${{ steps.vars.outputs.chan_dockerfile }}
101+
label_type: ${{ steps.vars.outputs.chan_label_type }}
102+
build_date: ${{ steps.vars.outputs.chan_build_date }}
103+
tag_rolling: ${{ steps.vars.outputs.chan_tag_rolling }}
104+
tag_version: ${{ steps.vars.outputs.chan_tag_version }}
105+
platforms: ${{ steps.vars.outputs.chan_platforms }}
106+
token: ${{ secrets.GH_PAT }}
107+
108+
notify-success:
109+
runs-on: ubuntu-latest
110+
needs: [generate-build-matrix, images-build]
111+
if: |
112+
always()
113+
&& contains(needs.*.result, 'success')
114+
&& !contains(needs.*.result, 'failure')
115+
&& !cancelled()
116+
&& needs.generate-build-matrix.outputs.matrix != '[]'
117+
steps:
118+
- name: Checkout
119+
uses: actions/checkout@v3
120+
121+
- name: Notify success
122+
uses: ./.github/actions/notifications
123+
with:
124+
title: "Scheduled Release Complete"
125+
tags: '${{ secrets.APPRISE_TAGS }}'
126+
apprise_configuration: '${{ secrets.APPRISE_CONFIG }}'
127+
body: |
128+
βœ… **Image Rebuilds Complete**
129+
130+
The following images were successfully rebuilt:
131+
132+
- ${{ join(fromJson(needs.generate-build-matrix.outputs.images || '[]'), '\n- ') }}
133+
134+
---
135+
πŸ• Triggered by automated schedule
136+
πŸ“… Date: ${{ github.event.head_commit.timestamp }}
137+
πŸ”— Commit: [${{ github.event.head_commit.message }}](${{ github.event.head_commit.url }})
138+
πŸ”— Workflow: [${{ github.workflow }}](${{ github.run_url }})
139+
πŸ”— Repository: [${{ github.repository }}](${{ github.event.repository.html_url }})
140+
141+
notify-failure:
142+
runs-on: ubuntu-latest
143+
needs: [generate-build-matrix, images-build]
144+
if: |
145+
always()
146+
&& contains(needs.*.result, 'failure')
147+
&& !cancelled()
148+
&& needs.generate-build-matrix.outputs.matrix != '[]'
149+
steps:
150+
- name: Checkout
151+
uses: actions/checkout@v3
152+
153+
- name: Notify failure
154+
uses: ./.github/actions/notifications
155+
with:
156+
title: "Scheduled Release Failed"
157+
tags: '${{ secrets.APPRISE_TAGS }}'
158+
apprise_configuration: '${{ secrets.APPRISE_CONFIG }}'
159+
body: |
160+
❌ **Image Rebuilds Failed**
161+
162+
The following images failed to rebuild:
163+
164+
- ${{ join(fromJson(needs.generate-build-matrix.outputs.images || '[]'), '\n- ') }}
165+
166+
---
167+
πŸ• Triggered by automated schedule
168+
πŸ“… Date: ${{ github.event.head_commit.timestamp }}
169+
πŸ”— Commit: [${{ github.event.head_commit.message }}](${{ github.event.head_commit.url }})
170+
πŸ”— Workflow: [${{ github.workflow }}](${{ github.run_url }})
171+
πŸ”— Repository: [${{ github.repository }}](${{ github.event.repository.html_url }})

0 commit comments

Comments
Β (0)