Skip to content

Commit 4c9c586

Browse files
committed
feat: add GitHub Actions workflow for deploying web installer
1 parent 7a1a99c commit 4c9c586

1 file changed

Lines changed: 195 additions & 0 deletions

File tree

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
name: Deploy to Web Installer
2+
3+
on:
4+
workflow_run:
5+
workflows: ["Build Firmware"]
6+
types: [completed]
7+
branches: [beta]
8+
workflow_dispatch:
9+
inputs:
10+
tag:
11+
description: 'Release tag to deploy (e.g. v1.2.3)'
12+
required: true
13+
dry_run:
14+
description: 'Dry run — build manifest and print changes without pushing'
15+
type: boolean
16+
default: true
17+
18+
jobs:
19+
deploy:
20+
# Only run when the build succeeded AND it was triggered by a release
21+
if: >
22+
github.event_name == 'workflow_dispatch' ||
23+
(github.event.workflow_run.conclusion == 'success' &&
24+
github.event.workflow_run.event == 'release')
25+
26+
runs-on: ubuntu-latest
27+
28+
steps:
29+
- name: Get release tag
30+
id: tag
31+
env:
32+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
33+
run: |
34+
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
35+
TAG="${{ inputs.tag }}"
36+
else
37+
TAG=$(gh api repos/${{ github.repository }}/releases/latest --jq '.tag_name')
38+
fi
39+
echo "TAG=$TAG" >> $GITHUB_OUTPUT
40+
DIR=$(echo "$TAG" | tr '/ ' '__')
41+
echo "DIR=release_${DIR}" >> $GITHUB_OUTPUT
42+
echo "DRY_RUN=${{ inputs.dry_run || 'false' }}" >> $GITHUB_OUTPUT
43+
44+
- name: Download release assets
45+
env:
46+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
47+
run: |
48+
TAG="${{ steps.tag.outputs.TAG }}"
49+
mkdir -p bin_staging
50+
51+
# Download only the *-full.bin assets (merged binaries ready to flash from 0x0)
52+
gh release download "$TAG" \
53+
--repo ${{ github.repository }} \
54+
--pattern "*-full.bin" \
55+
--dir bin_staging
56+
57+
ls -la bin_staging/
58+
59+
- name: Rename binaries to web installer convention
60+
run: |
61+
TAG="${{ steps.tag.outputs.TAG }}"
62+
DIR="${{ steps.tag.outputs.DIR }}"
63+
mkdir -p "web_bin/${DIR}"
64+
65+
# Map PlatformIO env names → chipFamily names used in manifest.json
66+
# Convention: esp32_<tag>_merged.bin (matching existing releases)
67+
declare -A CHIP_MAP=(
68+
["ESP32"]="esp32"
69+
["ESP32-S3"]="esp32_s3"
70+
["ESP32-S3-USB"]="esp32_s3_usb"
71+
["ESP32-C3"]="esp32_c3"
72+
["ESP32-LILYGO_SX1280"]="esp32_lilygo_sx1280"
73+
)
74+
75+
for ENV in "${!CHIP_MAP[@]}"; do
76+
SRC="bin_staging/tinygs-${ENV}-${TAG}-full.bin"
77+
DST="web_bin/${DIR}/${CHIP_MAP[$ENV]}_${TAG}_merged.bin"
78+
if [[ -f "$SRC" ]]; then
79+
cp "$SRC" "$DST"
80+
echo "Copied: $SRC → $DST"
81+
else
82+
echo "WARNING: $SRC not found, skipping"
83+
fi
84+
done
85+
86+
ls -la "web_bin/${DIR}/"
87+
88+
- name: Generate manifest.json
89+
run: |
90+
TAG="${{ steps.tag.outputs.TAG }}"
91+
DIR="${{ steps.tag.outputs.DIR }}"
92+
93+
# Map env name → ESP Web Tools chipFamily string
94+
# https://esphome.github.io/esp-web-tools/
95+
declare -A FAMILY_MAP=(
96+
["ESP32"]="ESP32"
97+
["ESP32-S3"]="ESP32-S3"
98+
["ESP32-S3-USB"]="ESP32-S3"
99+
["ESP32-C3"]="ESP32-C3"
100+
["ESP32-LILYGO_SX1280"]="ESP32-S3"
101+
)
102+
declare -A CHIP_MAP=(
103+
["ESP32"]="esp32"
104+
["ESP32-S3"]="esp32_s3"
105+
["ESP32-S3-USB"]="esp32_s3_usb"
106+
["ESP32-C3"]="esp32_c3"
107+
["ESP32-LILYGO_SX1280"]="esp32_lilygo_sx1280"
108+
)
109+
110+
# Build the builds array, only for binaries that actually exist
111+
BUILDS="["
112+
FIRST=true
113+
for ENV in ESP32 ESP32-S3 ESP32-S3-USB ESP32-C3 ESP32-LILYGO_SX1280; do
114+
BIN="${CHIP_MAP[$ENV]}_${TAG}_merged.bin"
115+
if [[ -f "web_bin/${DIR}/${BIN}" ]]; then
116+
[[ "$FIRST" == "false" ]] && BUILDS+=","
117+
BUILDS+="{\"chipFamily\":\"${FAMILY_MAP[$ENV]}\",\"parts\":[{\"path\":\"${BIN}\",\"offset\":0}]}"
118+
FIRST=false
119+
fi
120+
done
121+
BUILDS+="]"
122+
123+
cat > "web_bin/${DIR}/manifest.json" <<EOF
124+
{
125+
"name": "tinyGS",
126+
"version": "${TAG}",
127+
"new_install_prompt_erase": true,
128+
"builds": ${BUILDS}
129+
}
130+
EOF
131+
132+
echo "Generated manifest:"
133+
cat "web_bin/${DIR}/manifest.json"
134+
135+
- name: Checkout web installer repository
136+
uses: actions/checkout@v4
137+
with:
138+
repository: ${{ secrets.WEB_INSTALLER_REPO }}
139+
token: ${{ secrets.WEB_INSTALLER_TOKEN }}
140+
path: web_installer_repo
141+
142+
- name: Copy new release into web installer
143+
run: |
144+
DIR="${{ steps.tag.outputs.DIR }}"
145+
mkdir -p "web_installer_repo/bin/${DIR}"
146+
cp -r "web_bin/${DIR}/." "web_installer_repo/bin/${DIR}/"
147+
148+
- name: Update index.html with new release option
149+
run: |
150+
TAG="${{ steps.tag.outputs.TAG }}"
151+
DIR="${{ steps.tag.outputs.DIR }}"
152+
INDEX="web_installer_repo/index.html"
153+
154+
# Insert new <option> after the <optgroup label="Release"> line
155+
# Uses the same format as existing entries
156+
NEW_OPTION=" <option data-manifest=\"/bin/${DIR}/manifest.json\"\n data-ethernet=\"/bin/${DIR}/manifest.json\"\n value=\"${TAG}\">${TAG}</option>"
157+
158+
# Only insert if not already present
159+
if ! grep -q "${DIR}" "$INDEX"; then
160+
sed -i "s|<optgroup label=\"Release\">|<optgroup label=\"Release\">\n${NEW_OPTION}|" "$INDEX"
161+
echo "Inserted option for ${TAG} into index.html"
162+
else
163+
echo "Option for ${TAG} already present in index.html"
164+
fi
165+
166+
- name: Commit and push to web installer
167+
run: |
168+
TAG="${{ steps.tag.outputs.TAG }}"
169+
DIR="${{ steps.tag.outputs.DIR }}"
170+
cd web_installer_repo
171+
git config user.name "github-actions[bot]"
172+
git config user.email "github-actions[bot]@users.noreply.github.com"
173+
git add "bin/${DIR}/" index.html
174+
git diff --cached --quiet || git commit -m "chore: add firmware release ${TAG}"
175+
if [[ "${{ steps.tag.outputs.DRY_RUN }}" == "true" ]]; then
176+
echo "DRY RUN: skipping git push"
177+
git show --stat HEAD
178+
else
179+
git push
180+
fi
181+
182+
- name: Create release in web installer repository
183+
env:
184+
GH_TOKEN: ${{ secrets.WEB_INSTALLER_TOKEN }}
185+
run: |
186+
TAG="${{ steps.tag.outputs.TAG }}"
187+
if [[ "${{ steps.tag.outputs.DRY_RUN }}" == "true" ]]; then
188+
echo "DRY RUN: skipping release creation for ${TAG} in tinygs/tinygs_web_installer"
189+
else
190+
gh release create "$TAG" \
191+
--repo "${{ secrets.WEB_INSTALLER_REPO }}" \
192+
--title "TinyGS ${TAG}" \
193+
--notes "Automated firmware release ${TAG} from [tinyGS](https://github.com/${{ github.repository }}/releases/tag/${TAG})." \
194+
|| echo "Release ${TAG} already exists in web installer, skipping"
195+
fi

0 commit comments

Comments
 (0)