-
Notifications
You must be signed in to change notification settings - Fork 7
147 lines (133 loc) · 6.08 KB
/
Copy pathrelease.yml
File metadata and controls
147 lines (133 loc) · 6.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
name: Release
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: write
pull-requests: write
# Serialize releases: two quick pushes to main must not run release-please
# concurrently and race on the release PR / tag.
concurrency:
group: release
cancel-in-progress: false
jobs:
release-please:
runs-on: ubuntu-latest
timeout-minutes: 10
outputs:
release_created: ${{ steps.release.outputs.release_created }}
version: ${{ steps.release.outputs.version }}
tag_name: ${{ steps.release.outputs.tag_name }}
steps:
# Mint a GitHub App installation token so release-please's PR/branch
# pushes are authored by the App, not GITHUB_TOKEN. Pushes made with
# GITHUB_TOKEN do not trigger workflows (anti-recursion), which left
# the release PR's required status checks stuck "Expected" and
# unmergeable. An App token makes those checks run automatically.
# Scope it to exactly what release-please needs (contents + PRs).
- uses: actions/create-github-app-token@v3
id: app-token
with:
client-id: ${{ secrets.RELEASE_PLEASE_APP_CLIENT_ID }}
private-key: ${{ secrets.RELEASE_PLEASE_APP_PRIVATE_KEY }}
permission-contents: write
permission-pull-requests: write
- uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5
id: release
with:
token: ${{ steps.app-token.outputs.token }}
config-file: release-please-config.json
manifest-file: .release-please-manifest.json
build-plugin:
needs: release-please
if: ${{ needs.release-please.outputs.release_created || github.event_name == 'workflow_dispatch' }}
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Setup Node
uses: actions/setup-node@v7
with:
node-version: "24"
- name: Setup pnpm
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Download Decky CLI
run: |
mkdir -p /tmp/decky-cli
curl -L -o /tmp/decky-cli/decky "https://github.com/SteamDeckHomebrew/cli/releases/download/0.0.8/decky-linux-x86_64"
# Pin the Decky CLI binary by SHA-256: it runs under sudo to build the
# zip every user installs, so it is the pipeline's highest-leverage
# supply-chain link. The hash is GitHub's own asset digest for tag 0.0.8
# (gh api repos/SteamDeckHomebrew/cli/releases). A re-tagged or swapped
# asset now fails the build instead of poisoning a release.
echo "6777e356508c1ce887f8e61b0fa4954bb48b32e6d97341eef68ea4e0d6ead9a0 /tmp/decky-cli/decky" | sha256sum -c -
chmod +x /tmp/decky-cli/decky
echo "/tmp/decky-cli" >> $GITHUB_PATH
- name: Package plugin
run: |
sudo $(which decky) plugin build -o /tmp/output -s directory $GITHUB_WORKSPACE
sudo chown -R $(whoami) .
- name: Determine tag name
id: tag
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG_NAME: ${{ needs.release-please.outputs.tag_name }}
run: |
if [ -n "$TAG_NAME" ]; then
echo "tag=$TAG_NAME" >> "$GITHUB_OUTPUT"
else
echo "tag=$(gh release list --limit 1 --json tagName -q '.[0].tagName')" >> "$GITHUB_OUTPUT"
fi
- name: Smoke-test release zip
run: |
BUILT_ZIP=$(ls /tmp/output/*.zip | head -1)
echo "Checking $BUILT_ZIP for required entries..."
# bootstrap RAISES without 001_initial.sql (plugin fully inert), and the
# bios_registry is the most fatal defaults/ omission, previously uncovered
# by this smoke test. The Decky CLI FLATTENS the repo's defaults/ dir into
# the plugin root at package time, so the registry ships as
# bios_registry.json (no defaults/ prefix) — which is exactly where the
# runtime reads it (firmware.py). Emulator resolution now reads the live
# es_systems.xml directly (#1210), so no core snapshot ships.
# py_modules/native/libgavel-x86_64-linux.so is the compiled save-sync 409 kernel;
# bootstrap RAISES (no Python fallback) if it's missing, so a Decky CLI
# packaging change that drops it must fail the release here.
for required in main.py plugin.json package.json dist/index.js py_modules/bootstrap.py bin/rom-launcher \
py_modules/db/migrations/001_initial.sql py_modules/db/migrations/002_add_emulator_override.sql \
bios_registry.json py_modules/native/libgavel-x86_64-linux.so; do
if ! unzip -l "$BUILT_ZIP" | grep -qE "/$required\b"; then
echo "ERROR: release zip is missing $required"
unzip -l "$BUILT_ZIP"
exit 1
fi
done
# bin/rom-launcher must stay executable — Steam launches it directly,
# and a Decky CLI version bump could silently drop the exec bit.
LAUNCHER_PERMS=$(unzip -Z "$BUILT_ZIP" | grep -E '/bin/rom-launcher$' | awk '{print $1}')
if [[ "$LAUNCHER_PERMS" != *x* ]]; then
echo "ERROR: bin/rom-launcher is not executable in the zip (perms: '$LAUNCHER_PERMS')"
unzip -Z "$BUILT_ZIP" | grep -E '/bin/rom-launcher$' || true
exit 1
fi
if unzip -l "$BUILT_ZIP" | grep -qE '\.map\b'; then
echo "ERROR: release zip contains source maps — should have been stripped"
exit 1
fi
echo "Smoke test passed."
- name: Upload release asset
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ steps.tag.outputs.tag }}
run: |
BUILT_ZIP=$(ls /tmp/output/*.zip | head -1)
DEST="/tmp/output/decky-romm-sync.zip"
if [ "$BUILT_ZIP" != "$DEST" ]; then
cp "$BUILT_ZIP" "$DEST"
fi
gh release upload "$TAG" \
"$DEST" \
--clobber