Skip to content

Commit 2149d48

Browse files
authored
Merge pull request #40 from mavlink/feat/release-workflow
feat: add release workflow with Homebrew and .deb packaging
2 parents 03fd335 + 26ea7ed commit 2149d48

File tree

9 files changed

+592
-8
lines changed

9 files changed

+592
-8
lines changed

.github/workflows/release.yml

Lines changed: 363 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,363 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
# ── Job 1: Create source tarball and draft release ─────────────────────────
13+
source-tarball:
14+
name: Source tarball
15+
runs-on: ubuntu-latest
16+
outputs:
17+
version: ${{ steps.version.outputs.version }}
18+
tarball_sha256: ${{ steps.tarball.outputs.sha256 }}
19+
20+
steps:
21+
- uses: actions/checkout@v4
22+
with:
23+
submodules: true
24+
25+
- name: Extract version from tag
26+
id: version
27+
run: echo "version=${GITHUB_REF#refs/tags/v}" >> "$GITHUB_OUTPUT"
28+
29+
- name: Create source tarball
30+
id: tarball
31+
run: |
32+
VERSION=${{ steps.version.outputs.version }}
33+
tar czf mavsim-viewer-${VERSION}.tar.gz \
34+
--exclude='.git' \
35+
--exclude='tests/fixtures/*.ulg' \
36+
--exclude='build' \
37+
--transform="s,^\.,mavsim-viewer-${VERSION}," \
38+
.
39+
SHA=$(sha256sum mavsim-viewer-${VERSION}.tar.gz | awk '{print $1}')
40+
echo "sha256=${SHA}" >> "$GITHUB_OUTPUT"
41+
echo "Tarball SHA256: ${SHA}"
42+
43+
- name: Create draft release
44+
run: |
45+
gh release create ${{ github.ref_name }} \
46+
--draft \
47+
--title "${{ github.ref_name }}" \
48+
--generate-notes
49+
env:
50+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
51+
52+
- name: Upload source tarball
53+
run: |
54+
VERSION=${{ steps.version.outputs.version }}
55+
gh release upload ${{ github.ref_name }} mavsim-viewer-${VERSION}.tar.gz
56+
env:
57+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
58+
59+
# ── Job 2a: macOS arm64 bottle ─────────────────────────────────────────────
60+
bottle-arm64:
61+
name: Bottle (arm64)
62+
needs: source-tarball
63+
runs-on: macos-14
64+
outputs:
65+
bottle_sha256: ${{ steps.bottle.outputs.sha256 }}
66+
bottle_tag: ${{ steps.bottle.outputs.tag }}
67+
68+
steps:
69+
- name: Set up tap with formula
70+
env:
71+
VERSION: ${{ needs.source-tarball.outputs.version }}
72+
TARBALL_SHA: ${{ needs.source-tarball.outputs.tarball_sha256 }}
73+
TAG: ${{ github.ref_name }}
74+
run: |
75+
FORMULA_DIR="$(brew --repo)/Library/Taps/mavlink/homebrew-tap/Formula"
76+
mkdir -p "$FORMULA_DIR"
77+
python3 -c "
78+
import os
79+
formula = '''class MavsimViewer < Formula
80+
desc \"3D MAVLink vehicle viewer for SITL simulation\"
81+
homepage \"https://github.com/mavlink/mavsim-viewer\"
82+
url \"https://github.com/mavlink/mavsim-viewer/releases/download/{tag}/mavsim-viewer-{version}.tar.gz\"
83+
sha256 \"{sha}\"
84+
license \"BSD-3-Clause\"
85+
86+
depends_on \"cmake\" => :build
87+
88+
def install
89+
system \"cmake\", \"-S\", \".\", \"-B\", \"build\", \"-DCMAKE_BUILD_TYPE=Release\", *std_cmake_args
90+
system \"cmake\", \"--build\", \"build\"
91+
system \"cmake\", \"--install\", \"build\", \"--prefix\", prefix
92+
end
93+
94+
test do
95+
assert_predicate bin/\"mavsim-viewer\", :executable?
96+
end
97+
end
98+
'''.format(
99+
tag=os.environ['TAG'],
100+
version=os.environ['VERSION'],
101+
sha=os.environ['TARBALL_SHA'],
102+
)
103+
with open(os.environ['FORMULA_DIR'] + '/mavsim-viewer.rb', 'w') as f:
104+
f.write(formula)
105+
" FORMULA_DIR="$FORMULA_DIR"
106+
107+
- name: Build bottle
108+
run: brew install --build-bottle mavlink/tap/mavsim-viewer
109+
110+
- name: Package bottle
111+
id: bottle
112+
run: |
113+
TAG=${{ github.ref_name }}
114+
brew bottle \
115+
--json \
116+
--root-url="https://github.com/mavlink/mavsim-viewer/releases/download/${TAG}" \
117+
mavlink/tap/mavsim-viewer
118+
119+
BOTTLE_JSON=$(ls mavsim-viewer--*.bottle.json)
120+
BOTTLE_FILE=$(ls mavsim-viewer--*.bottle.tar.gz)
121+
CLEAN_NAME=$(echo "$BOTTLE_FILE" | sed 's/--/-/')
122+
mv "$BOTTLE_FILE" "$CLEAN_NAME"
123+
124+
BOTTLE_SHA=$(python3 -c "
125+
import json, sys
126+
data = json.load(open(sys.argv[1]))
127+
tags = data['mavsim-viewer']['bottle']['tags']
128+
tag = list(tags.keys())[0]
129+
print(tags[tag]['sha256'])
130+
" "$BOTTLE_JSON")
131+
132+
BOTTLE_TAG=$(python3 -c "
133+
import json, sys
134+
data = json.load(open(sys.argv[1]))
135+
tags = data['mavsim-viewer']['bottle']['tags']
136+
print(list(tags.keys())[0])
137+
" "$BOTTLE_JSON")
138+
139+
echo "sha256=${BOTTLE_SHA}" >> "$GITHUB_OUTPUT"
140+
echo "tag=${BOTTLE_TAG}" >> "$GITHUB_OUTPUT"
141+
echo "file=${CLEAN_NAME}" >> "$GITHUB_OUTPUT"
142+
143+
- name: Upload bottle to release
144+
run: gh release upload ${{ github.ref_name }} ${{ steps.bottle.outputs.file }}
145+
env:
146+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
147+
148+
# ── Job 2b: macOS x86_64 bottle ───────────────────────────────────────────
149+
bottle-x86_64:
150+
name: Bottle (x86_64)
151+
needs: source-tarball
152+
runs-on: macos-13
153+
outputs:
154+
bottle_sha256: ${{ steps.bottle.outputs.sha256 }}
155+
bottle_tag: ${{ steps.bottle.outputs.tag }}
156+
157+
steps:
158+
- name: Set up tap with formula
159+
env:
160+
VERSION: ${{ needs.source-tarball.outputs.version }}
161+
TARBALL_SHA: ${{ needs.source-tarball.outputs.tarball_sha256 }}
162+
TAG: ${{ github.ref_name }}
163+
run: |
164+
FORMULA_DIR="$(brew --repo)/Library/Taps/mavlink/homebrew-tap/Formula"
165+
mkdir -p "$FORMULA_DIR"
166+
python3 -c "
167+
import os
168+
formula = '''class MavsimViewer < Formula
169+
desc \"3D MAVLink vehicle viewer for SITL simulation\"
170+
homepage \"https://github.com/mavlink/mavsim-viewer\"
171+
url \"https://github.com/mavlink/mavsim-viewer/releases/download/{tag}/mavsim-viewer-{version}.tar.gz\"
172+
sha256 \"{sha}\"
173+
license \"BSD-3-Clause\"
174+
175+
depends_on \"cmake\" => :build
176+
177+
def install
178+
system \"cmake\", \"-S\", \".\", \"-B\", \"build\", \"-DCMAKE_BUILD_TYPE=Release\", *std_cmake_args
179+
system \"cmake\", \"--build\", \"build\"
180+
system \"cmake\", \"--install\", \"build\", \"--prefix\", prefix
181+
end
182+
183+
test do
184+
assert_predicate bin/\"mavsim-viewer\", :executable?
185+
end
186+
end
187+
'''.format(
188+
tag=os.environ['TAG'],
189+
version=os.environ['VERSION'],
190+
sha=os.environ['TARBALL_SHA'],
191+
)
192+
with open(os.environ['FORMULA_DIR'] + '/mavsim-viewer.rb', 'w') as f:
193+
f.write(formula)
194+
" FORMULA_DIR="$FORMULA_DIR"
195+
196+
- name: Build bottle
197+
run: brew install --build-bottle mavlink/tap/mavsim-viewer
198+
199+
- name: Package bottle
200+
id: bottle
201+
run: |
202+
TAG=${{ github.ref_name }}
203+
brew bottle \
204+
--json \
205+
--root-url="https://github.com/mavlink/mavsim-viewer/releases/download/${TAG}" \
206+
mavlink/tap/mavsim-viewer
207+
208+
BOTTLE_JSON=$(ls mavsim-viewer--*.bottle.json)
209+
BOTTLE_FILE=$(ls mavsim-viewer--*.bottle.tar.gz)
210+
CLEAN_NAME=$(echo "$BOTTLE_FILE" | sed 's/--/-/')
211+
mv "$BOTTLE_FILE" "$CLEAN_NAME"
212+
213+
BOTTLE_SHA=$(python3 -c "
214+
import json, sys
215+
data = json.load(open(sys.argv[1]))
216+
tags = data['mavsim-viewer']['bottle']['tags']
217+
tag = list(tags.keys())[0]
218+
print(tags[tag]['sha256'])
219+
" "$BOTTLE_JSON")
220+
221+
BOTTLE_TAG=$(python3 -c "
222+
import json, sys
223+
data = json.load(open(sys.argv[1]))
224+
tags = data['mavsim-viewer']['bottle']['tags']
225+
print(list(tags.keys())[0])
226+
" "$BOTTLE_JSON")
227+
228+
echo "sha256=${BOTTLE_SHA}" >> "$GITHUB_OUTPUT"
229+
echo "tag=${BOTTLE_TAG}" >> "$GITHUB_OUTPUT"
230+
echo "file=${CLEAN_NAME}" >> "$GITHUB_OUTPUT"
231+
232+
- name: Upload bottle to release
233+
run: gh release upload ${{ github.ref_name }} ${{ steps.bottle.outputs.file }}
234+
env:
235+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
236+
237+
# ── Job 2c: Linux amd64 .deb ──────────────────────────────────────────────
238+
deb-amd64:
239+
name: Deb (amd64)
240+
needs: source-tarball
241+
runs-on: ubuntu-latest
242+
243+
steps:
244+
- uses: actions/checkout@v4
245+
with:
246+
submodules: true
247+
248+
- name: Install build dependencies
249+
run: |
250+
sudo apt-get update
251+
sudo apt-get install -y libgl1-mesa-dev libx11-dev libxrandr-dev \
252+
libxinerama-dev libxcursor-dev libxi-dev
253+
254+
- name: Configure
255+
run: |
256+
cmake -B build \
257+
-DCMAKE_BUILD_TYPE=Release \
258+
-DCMAKE_INSTALL_PREFIX=/usr \
259+
-DMAVSIM_VERSION=${{ needs.source-tarball.outputs.version }}
260+
261+
- name: Build
262+
run: cmake --build build --config Release
263+
264+
- name: Package .deb
265+
run: cd build && cpack -G DEB
266+
267+
- name: Smoke test
268+
run: |
269+
sudo dpkg -i build/*.deb
270+
which mavsim-viewer
271+
ls /usr/share/mavsim-viewer/models/
272+
ls /usr/share/mavsim-viewer/shaders/
273+
ls /usr/share/mavsim-viewer/fonts/
274+
275+
- name: Upload .deb to release
276+
run: gh release upload ${{ github.ref_name }} build/*.deb
277+
env:
278+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
279+
280+
# ── Job 3: Publish the release ─────────────────────────────────────────────
281+
publish-release:
282+
name: Publish release
283+
needs: [bottle-arm64, bottle-x86_64, deb-amd64]
284+
runs-on: ubuntu-latest
285+
286+
steps:
287+
- name: Mark release as published
288+
run: |
289+
gh release edit ${{ github.ref_name }} \
290+
--repo ${{ github.repository }} \
291+
--draft=false
292+
env:
293+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
294+
295+
# ── Job 4: Update Homebrew tap ─────────────────────────────────────────────
296+
update-tap:
297+
name: Update Homebrew tap
298+
needs: [source-tarball, bottle-arm64, bottle-x86_64, publish-release]
299+
runs-on: ubuntu-latest
300+
301+
steps:
302+
- name: Update formula in tap
303+
env:
304+
VERSION: ${{ needs.source-tarball.outputs.version }}
305+
TAG: ${{ github.ref_name }}
306+
TARBALL_SHA: ${{ needs.source-tarball.outputs.tarball_sha256 }}
307+
ARM64_SHA: ${{ needs.bottle-arm64.outputs.bottle_sha256 }}
308+
ARM64_TAG: ${{ needs.bottle-arm64.outputs.bottle_tag }}
309+
X86_SHA: ${{ needs.bottle-x86_64.outputs.bottle_sha256 }}
310+
X86_TAG: ${{ needs.bottle-x86_64.outputs.bottle_tag }}
311+
TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
312+
run: |
313+
git clone https://x-access-token:${TAP_TOKEN}@github.com/mavlink/homebrew-tap.git tap
314+
mkdir -p tap/Formula
315+
316+
python3 -c "
317+
import os
318+
formula = '''class MavsimViewer < Formula
319+
desc \"3D MAVLink vehicle viewer for SITL simulation\"
320+
homepage \"https://github.com/mavlink/mavsim-viewer\"
321+
url \"https://github.com/mavlink/mavsim-viewer/releases/download/{tag}/mavsim-viewer-{version}.tar.gz\"
322+
sha256 \"{tarball_sha}\"
323+
license \"BSD-3-Clause\"
324+
325+
bottle do
326+
root_url \"https://github.com/mavlink/mavsim-viewer/releases/download/{tag}\"
327+
sha256 cellar: :any_skip_relocation, {arm64_tag}: \"{arm64_sha}\"
328+
sha256 cellar: :any_skip_relocation, {x86_tag}: \"{x86_sha}\"
329+
end
330+
331+
depends_on \"cmake\" => :build
332+
333+
def install
334+
system \"cmake\", \"-S\", \".\", \"-B\", \"build\",
335+
\"-DCMAKE_BUILD_TYPE=Release\",
336+
*std_cmake_args
337+
system \"cmake\", \"--build\", \"build\"
338+
system \"cmake\", \"--install\", \"build\", \"--prefix\", prefix
339+
end
340+
341+
test do
342+
assert_predicate bin/\"mavsim-viewer\", :executable?
343+
end
344+
end
345+
'''.format(
346+
tag=os.environ['TAG'],
347+
version=os.environ['VERSION'],
348+
tarball_sha=os.environ['TARBALL_SHA'],
349+
arm64_sha=os.environ['ARM64_SHA'],
350+
arm64_tag=os.environ['ARM64_TAG'],
351+
x86_sha=os.environ['X86_SHA'],
352+
x86_tag=os.environ['X86_TAG'],
353+
)
354+
with open('tap/Formula/mavsim-viewer.rb', 'w') as f:
355+
f.write(formula)
356+
"
357+
358+
cd tap
359+
git config user.name "github-actions[bot]"
360+
git config user.email "github-actions[bot]@users.noreply.github.com"
361+
git add Formula/mavsim-viewer.rb
362+
git commit -m "mavsim-viewer ${VERSION}"
363+
git push

0 commit comments

Comments
 (0)