Skip to content

Commit d2b422c

Browse files
authored
Merge pull request #15 from static-php/download
only run what's necessary
2 parents 5a1fb5c + 4171f49 commit d2b422c

1 file changed

Lines changed: 167 additions & 33 deletions

File tree

.github/workflows/spc-download.yml

Lines changed: 167 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ on:
44
schedule:
55
- cron: '0 0 * * *'
66
workflow_dispatch:
7+
inputs:
8+
force_full:
9+
description: "Force a full rebuild of all PHP versions regardless of detected changes"
10+
type: boolean
11+
required: false
12+
default: false
713

814
permissions:
915
contents: read
@@ -18,18 +24,11 @@ jobs:
1824
env:
1925
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2026
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
27+
PHP_MINORS: "8.2 8.3 8.4 8.5"
2128
steps:
22-
- name: Set architecture variables
29+
- name: Install PHP and composer
2330
run: |
24-
if [[ "${{ matrix.arch }}" == "arm64" ]]; then
25-
echo "RPM_ARCH=aarch64" >> $GITHUB_ENV
26-
else
27-
echo "RPM_ARCH=x86_64" >> $GITHUB_ENV
28-
fi
29-
30-
- name: Install composer
31-
run: |
32-
sudo curl -L https://files.henderkes.com/${RPM_ARCH}-linux/php -o /usr/local/bin/php
31+
sudo curl -L https://files.henderkes.com/x86_64-linux/php -o /usr/local/bin/php
3332
sudo chmod +x /usr/local/bin/php
3433
sudo curl -sS https://raw.githubusercontent.com/composer/getcomposer.org/f3108f64b4e1c1ce6eb462b159956461592b3e3e/web/installer | php -- --quiet
3534
sudo mv composer.phar /usr/local/bin/composer
@@ -42,41 +41,176 @@ jobs:
4241
- name: Composer install
4342
run: composer install
4443

44+
- name: Restore previous state
45+
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
46+
with:
47+
path: .download-state
48+
key: spc-downloads-lock
49+
50+
- name: Seed empty state if missing
51+
run: |
52+
set -euo pipefail
53+
mkdir -p .download-state
54+
[[ -f .download-state/lock.prev.json ]] || echo '{}' > .download-state/lock.prev.json
55+
[[ -f .download-state/meta.prev.json ]] || echo '{}' > .download-state/meta.prev.json
56+
4557
- name: Download extensions
4658
run: |
4759
php vendor/bin/spc download --shallow-clone -e amqp,apcu,ast,bcmath,brotli,bz2,calendar,ctype,curl,dba,decimal,deepclone,dio,dom,ds,ev,event,excimer,exif,ffi,fileinfo,filter,ftp,gd,gettext,gmp,gmssl,grpc,iconv,igbinary,imagick,inotify,intl,ldap,libxml,lz4,maxminddb,mbregex,mbstring,memcache,memcached,mongodb,msgpack,mysqli,mysqlnd,mysqlnd_parsec,mysqlnd_ed25519,odbc,opcache,openssl,opentelemetry,parallel,password-argon2,pcov,pcntl,pdo,pdo_mysql,pdo_odbc,pdo_pgsql,pdo_sqlite,pdo_sqlsrv,pgsql,phar,posix,protobuf,rar,rdkafka,readline,redis,session,shmop,simdjson,simplexml,snappy,soap,sockets,sodium,spx,sqlite3,sqlsrv,ssh2,swoole,sysvmsg,sysvsem,sysvshm,tidy,tokenizer,trader,uuid,uv,xdebug,xhprof,xlswriter,xml,xmlreader,xmlwriter,xsl,xz,yac,yaml,zip,zlib,zstd
4860
61+
- name: Probe latest PHP versions
62+
id: probe-php
63+
run: |
64+
set -euo pipefail
65+
new='{}'
66+
for v in $PHP_MINORS; do
67+
latest=$(curl -fsSL "https://www.php.net/releases/index.php?json=&max=1&version=${v}" \
68+
| jq -r 'keys[0] // empty')
69+
if [[ -z "$latest" ]]; then
70+
echo "::error::Failed to fetch latest PHP version for ${v}"
71+
exit 1
72+
fi
73+
echo "PHP ${v} latest: ${latest}"
74+
new=$(jq --arg v "$v" --arg l "$latest" '. + {($v): $l}' <<< "$new")
75+
done
76+
mkdir -p downloads
77+
jq --argjson v "$new" -n '{php_versions: $v}' > downloads/.spc-meta.json
78+
79+
- name: Diff state and compute triggers
80+
id: diff
81+
env:
82+
FORCE_FULL: ${{ inputs.force_full }}
83+
run: |
84+
set -euo pipefail
85+
86+
EXT_JSON=vendor/crazywhalecc/static-php-cli/config/ext.json
87+
src_to_ext=$(jq -c '
88+
to_entries
89+
| map(select(.value.source != null))
90+
| map({(.value.source): .key})
91+
| add // {}
92+
' "$EXT_JSON")
93+
echo "Source->ext map size: $(jq 'length' <<< "$src_to_ext")"
94+
95+
changed_sources=$(jq -nc \
96+
--slurpfile prev .download-state/lock.prev.json \
97+
--slurpfile cur downloads/.lock.json '
98+
($prev[0] // {}) as $p | ($cur[0] // {}) as $c |
99+
[ ($c | keys[]) as $k
100+
| select(($p[$k].hash // "") != ($c[$k].hash // "")) ]
101+
')
102+
echo "Changed source keys: $(jq -c . <<< "$changed_sources")"
103+
104+
changed_exts=$(jq -nc --argjson s "$changed_sources" --argjson m "$src_to_ext" '
105+
$s | map($m[.]) | map(select(. != null)) | unique
106+
')
107+
pkgs=$(jq -r 'join(",")' <<< "$changed_exts")
108+
echo "Changed packages: ${pkgs:-<none>}"
109+
110+
full_versions=$(jq -nrc \
111+
--slurpfile prev .download-state/meta.prev.json \
112+
--slurpfile cur downloads/.spc-meta.json '
113+
(($prev[0].php_versions) // {}) as $p |
114+
(($cur[0].php_versions) // {}) as $c |
115+
[ ($c | keys[]) as $k | select($c[$k] != ($p[$k] // "")) ]
116+
')
117+
echo "PHP minors with bumped php-src: $(jq -c . <<< "$full_versions")"
118+
119+
all_minors=$(jq -nc --arg s "$PHP_MINORS" '$s | split(" ")')
120+
if [[ "$FORCE_FULL" == "true" ]]; then
121+
echo "force_full input set -> rebuilding all PHP versions"
122+
full_versions="$all_minors"
123+
fi
124+
125+
full_csv=$(jq -r 'join(",")' <<< "$full_versions")
126+
127+
partial_csv=""
128+
if [[ -n "$pkgs" ]]; then
129+
partial_csv=$(jq -nrc \
130+
--argjson all "$all_minors" \
131+
--argjson full "$full_versions" '
132+
$all - $full | join(",")
133+
')
134+
fi
135+
136+
any="false"
137+
if [[ -n "$pkgs" || -n "$full_csv" ]]; then
138+
any="true"
139+
fi
140+
141+
echo "full_php=$full_csv" | tee -a $GITHUB_OUTPUT
142+
echo "partial_php=$partial_csv" | tee -a $GITHUB_OUTPUT
143+
echo "changed_packages=$pkgs" | tee -a $GITHUB_OUTPUT
144+
echo "any_change=$any" | tee -a $GITHUB_OUTPUT
145+
146+
{
147+
echo "## spc-download summary"
148+
echo "- Full rebuild PHP versions: ${full_csv:-<none>}"
149+
echo "- Partial rebuild PHP versions: ${partial_csv:-<none>}"
150+
echo "- Changed packages: ${pkgs:-<none>}"
151+
echo "- Any change: $any"
152+
} >> "$GITHUB_STEP_SUMMARY"
153+
154+
- name: Persist current state for next run
155+
if: hashFiles('downloads/.lock.json') != ''
156+
run: |
157+
set -euo pipefail
158+
cp downloads/.lock.json .download-state/lock.prev.json
159+
cp downloads/.spc-meta.json .download-state/meta.prev.json
160+
161+
- name: Delete previous state cache
162+
if: hashFiles('downloads/.lock.json') != ''
163+
continue-on-error: true
164+
env:
165+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
166+
run: |
167+
gh api -X DELETE \
168+
"/repos/$GITHUB_REPOSITORY/actions/caches?key=spc-downloads-lock" \
169+
2>/dev/null || true
170+
171+
- name: Save state cache
172+
if: hashFiles('downloads/.lock.json') != ''
173+
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
174+
with:
175+
path: .download-state
176+
key: spc-downloads-lock
177+
49178
- name: Create tarball (keep permissions)
179+
if: steps.diff.outputs.any_change == 'true'
50180
run: |
51181
tar -czf downloads.tar.gz -C downloads .
52182
53183
- name: Upload downloads directory
184+
if: steps.diff.outputs.any_change == 'true'
54185
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
55186
with:
56187
name: downloads-tarball
57188
path: downloads.tar.gz
58-
retention-days: 2
189+
retention-days: 14
59190

60-
- name: Trigger build-rpm-modular-packages workflow
61-
if: success()
62-
run: gh workflow run build-rpm-modular-packages.yml
191+
- name: Trigger downstream workflows
192+
if: steps.diff.outputs.any_change == 'true'
63193
env:
64-
GH_TOKEN: ${{ secrets.GH_PAT }} # use our own user as the triggering user
65-
66-
#- name: Trigger build-gcc-deb-packages workflow
67-
# if: success()
68-
# run: gh workflow run build-gcc-deb-packages.yml
69-
# env:
70-
# GH_TOKEN: ${{ secrets.GH_PAT }} # use our own user as the triggering user
71-
72-
- name: Trigger build-deb-forgejo workflow
73-
if: success()
74-
run: gh workflow run build-deb-forgejo.yml
75-
env:
76-
GH_TOKEN: ${{ secrets.GH_PAT }} # use our own user as the triggering user
77-
78-
- name: Trigger build-apk-forgejo workflow
79-
if: success()
80-
run: gh workflow run build-apk-forgejo.yml
81-
env:
82-
GH_TOKEN: ${{ secrets.GH_PAT }} # use our own user as the triggering user
194+
GH_TOKEN: ${{ secrets.GH_PAT }}
195+
FULL_PHP: ${{ steps.diff.outputs.full_php }}
196+
PARTIAL_PHP: ${{ steps.diff.outputs.partial_php }}
197+
CHANGED_PACKAGES: ${{ steps.diff.outputs.changed_packages }}
198+
run: |
199+
set -euo pipefail
200+
workflows=(
201+
build-rpm-modular-packages.yml
202+
build-deb-forgejo.yml
203+
build-apk-forgejo.yml
204+
)
205+
for wf in "${workflows[@]}"; do
206+
if [[ -n "$FULL_PHP" ]]; then
207+
echo ">> $wf : full rebuild for $FULL_PHP"
208+
gh workflow run "$wf" -f php_versions="$FULL_PHP"
209+
fi
210+
if [[ -n "$CHANGED_PACKAGES" && -n "$PARTIAL_PHP" ]]; then
211+
echo ">> $wf : partial rebuild for $PARTIAL_PHP, packages=$CHANGED_PACKAGES"
212+
gh workflow run "$wf" \
213+
-f php_versions="$PARTIAL_PHP" \
214+
-f packages="$CHANGED_PACKAGES"
215+
fi
216+
done

0 commit comments

Comments
 (0)