Skip to content

Commit a32a319

Browse files
Add release workflow
1 parent a8d4419 commit a32a319

File tree

3 files changed

+334
-0
lines changed

3 files changed

+334
-0
lines changed

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
### Motivation
2+
3+
<!-- Why this pull request? -->
4+
5+
### Change description
6+
7+
<!-- What does your code do? -->
8+
9+
### Additional Notes
10+
11+
<!-- Link any useful metadata: Jira task, GitHub issue, ... -->
12+
13+
### Reviewer checklist
14+
15+
- [ ] PR addresses a single concern.
16+
- [ ] PR title and description are properly filled.
17+
- [ ] Changes will be merged in `main`.
18+
- [ ] Changes are covered by tests.
19+
- [ ] Logging is meaningful in case of troubleshooting.

.github/workflows/release.yml

Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
name: Release Arduino Flasher CLI
2+
3+
on:
4+
push:
5+
tags:
6+
- "*" # Trigger on all tags
7+
8+
env:
9+
GO_VERSION: "1.25.1"
10+
PROJECT_NAME: "arduino-flasher-cli"
11+
GITHUB_TOKEN: ${{ secrets.ARDUINOBOT_TOKEN }}
12+
GITHUB_USERNAME: ArduinoBot
13+
DIST_DIR: build
14+
15+
jobs:
16+
build:
17+
strategy:
18+
matrix:
19+
runon: [ubuntu-24.04]
20+
os: [linux, darwin]
21+
arch: [amd64, arm64]
22+
include:
23+
- runon: windows-2025
24+
os: windows
25+
arch: amd64
26+
runs-on: ${{ matrix.runon }}
27+
outputs:
28+
release: ${{ steps.set-version.outputs.RELEASE_NAME }}
29+
defaults:
30+
run:
31+
shell: bash
32+
steps:
33+
- name: Tag version
34+
run: |
35+
echo "VERSION=${GITHUB_REF##*/}" >> $GITHUB_ENV
36+
echo "RELEASE_NAME=${{ env.PROJECT_NAME }}-${VERSION}-${{ matrix.os }}-${{ matrix.arch }}" >> $GITHUB_ENV
37+
env:
38+
GITHUB_REF: ${{ github.ref }}
39+
40+
- name: Set Windows version
41+
id: set-version
42+
run: |
43+
echo "RELEASE_NAME=${{ env.RELEASE_NAME }}" >> $GITHUB_OUTPUT
44+
if: matrix.os == 'windows'
45+
46+
- name: Checkout
47+
uses: actions/checkout@v4
48+
with:
49+
fetch-depth: 0
50+
51+
- name: Set up Go
52+
uses: actions/setup-go@v5
53+
with:
54+
go-version: ${{ env.GO_VERSION }}
55+
56+
- name: Install Taskfile
57+
uses: arduino/setup-task@v2
58+
with:
59+
version: "3.x"
60+
repo-token: ${{ secrets.GITHUB_TOKEN }}
61+
62+
- name: Configure Git for private repo cloning
63+
run: |
64+
git config --global url."https://${{ env.GITHUB_USERNAME }}:${{ env.GITHUB_TOKEN }}@github.com".insteadOf "https://github.com"
65+
66+
- name: Build Binary
67+
run: |
68+
task arduino-flasher-cli:build
69+
env:
70+
GOARCH: ${{ matrix.arch }}
71+
GOOS: ${{ matrix.os }}
72+
73+
- name: Prepare Build Artifacts (!windows)
74+
working-directory: ./${{ env.DIST_DIR }}
75+
run: tar -czf ${{ env.RELEASE_NAME }}.tar.gz arduino-flasher-cli -C ../arduino-flasher-cli LICENSE
76+
if: matrix.os != 'windows'
77+
- name: Prepare Build Artifacts (windows)
78+
working-directory: ./${{ env.DIST_DIR }}
79+
run: 7z a -tzip ${{ env.RELEASE_NAME }}.zip arduino-flasher-cli.exe ../arduino-flasher-cli/LICENSE
80+
if: matrix.os == 'windows'
81+
82+
- name: Upload artifacts
83+
uses: actions/upload-artifact@v4
84+
with:
85+
name: ${{ env.PROJECT_NAME }}-${{ matrix.os }}-${{ matrix.arch }}
86+
path: |
87+
${{ env.DIST_DIR }}/${{ env.RELEASE_NAME }}.tar.gz
88+
${{ env.DIST_DIR }}/${{ env.RELEASE_NAME }}.zip
89+
if-no-files-found: error
90+
91+
sign-windows-executable:
92+
runs-on: windows-sign-pc
93+
needs: build
94+
95+
defaults:
96+
run:
97+
shell: bash
98+
99+
env:
100+
RELEASE_NAME: ${{ needs.build.outputs.release }}
101+
INSTALLER_CERT_WINDOWS_CER: "/tmp/cert.cer"
102+
# We are hardcoding the path for signtool because is not present on the windows PATH env var by default.
103+
# Keep in mind that this path could change when upgrading to a new runner version
104+
SIGNTOOL_PATH: "C:/Program Files (x86)/Windows Kits/10/bin/10.0.19041.0/x86/signtool.exe"
105+
SEVENZ_PATH: "C:/ProgramData/chocolatey/tools/7z.exe"
106+
107+
steps:
108+
- name: Download artifacts
109+
uses: actions/download-artifact@v5
110+
with:
111+
name: ${{ env.PROJECT_NAME }}-windows-amd64
112+
113+
- name: Save Win signing certificate to file
114+
run: echo "${{ secrets.INSTALLER_CERT_WINDOWS_CER }}" | base64 --decode > ${{ env.INSTALLER_CERT_WINDOWS_CER}}
115+
116+
- name: Extract build
117+
run: |
118+
${{ env.SEVENZ_PATH }} x ${{ env.RELEASE_NAME }}.zip -aoa
119+
rm ${{ env.RELEASE_NAME }}.zip
120+
121+
- name: Sign executable
122+
env:
123+
CERT_PASSWORD: ${{ secrets.INSTALLER_CERT_WINDOWS_PASSWORD }}
124+
CONTAINER_NAME: ${{ secrets.INSTALLER_CERT_WINDOWS_CONTAINER }}
125+
# https://stackoverflow.com/questions/17927895/automate-extended-validation-ev-code-signing-with-safenet-etoken
126+
run: |
127+
"${{ env.SIGNTOOL_PATH }}" sign -d "Arduino Flasher CLI" -f ${{ env.INSTALLER_CERT_WINDOWS_CER}} -csp "eToken Base Cryptographic Provider" -k "[{{${{ env.CERT_PASSWORD }}}}]=${{ env.CONTAINER_NAME }}" -fd sha256 -tr http://timestamp.digicert.com -td SHA256 -v "arduino-flasher-cli.exe"
128+
129+
- name: Prepare Build Artifacts
130+
run: |
131+
${{ env.SEVENZ_PATH }} a -tzip ${{ env.RELEASE_NAME }}.zip arduino-flasher-cli.exe LICENSE
132+
133+
- name: Upload artifacts
134+
uses: actions/upload-artifact@v4
135+
with:
136+
name: ${{ env.PROJECT_NAME }}-windows-amd64
137+
path: ${{ env.RELEASE_NAME }}.zip
138+
if-no-files-found: error
139+
overwrite: true
140+
141+
# This step is needed because the self hosted runner does not delete files automatically
142+
- name: Cleanup
143+
run: rm ${{ env.RELEASE_NAME }}.zip LICENSE arduino-flasher-cli.exe
144+
145+
notarize-macos:
146+
name: Notarize macOS
147+
runs-on: macos-15
148+
needs: build
149+
permissions:
150+
contents: read
151+
152+
env:
153+
GON_CONFIG_PATH: gon.config.hcl
154+
155+
strategy:
156+
matrix:
157+
build: [darwin-amd64, darwin-arm64]
158+
steps:
159+
- name: Set environment variables
160+
run: |
161+
TAG_NAME="${GITHUB_REF##*/}"
162+
VERSION="${TAG_NAME#flasher-}"
163+
echo "PACKAGE_FILENAME=${{ env.PROJECT_NAME }}-${VERSION}-${{ matrix.build }}.tar.gz" >>$GITHUB_ENV
164+
165+
- name: Checkout repository
166+
uses: actions/checkout@v5
167+
168+
- name: Download artifacts
169+
uses: actions/download-artifact@v5
170+
with:
171+
name: ${{ env.PROJECT_NAME }}-${{ matrix.build }}
172+
path: ${{ env.DIST_DIR }}
173+
174+
- name: Extract build
175+
working-directory: ${{ env.DIST_DIR }}
176+
run: |
177+
tar -xvf ${{ env.PACKAGE_FILENAME }}
178+
179+
- name: Import Code-Signing Certificates
180+
env:
181+
KEYCHAIN: "sign.keychain"
182+
INSTALLER_CERT_MAC_PATH: "/tmp/ArduinoCerts2020.p12"
183+
# Arbitrary password for a keychain that exists only for the duration of the job, so not secret
184+
KEYCHAIN_PASSWORD: keychainpassword
185+
run: |
186+
echo "${{ secrets.INSTALLER_CERT_MAC_P12 }}" | base64 --decode >"${{ env.INSTALLER_CERT_MAC_PATH }}"
187+
188+
security create-keychain \
189+
-p "${{ env.KEYCHAIN_PASSWORD }}" \
190+
"${{ env.KEYCHAIN }}"
191+
192+
security default-keychain \
193+
-s "${{ env.KEYCHAIN }}"
194+
195+
security unlock-keychain \
196+
-p "${{ env.KEYCHAIN_PASSWORD }}" \
197+
"${{ env.KEYCHAIN }}"
198+
199+
security import \
200+
"${{ env.INSTALLER_CERT_MAC_PATH }}" \
201+
-k "${{ env.KEYCHAIN }}" \
202+
-f pkcs12 \
203+
-A \
204+
-T "/usr/bin/codesign" \
205+
-P "${{ secrets.INSTALLER_CERT_MAC_PASSWORD }}"
206+
207+
security set-key-partition-list \
208+
-S apple-tool:,apple: \
209+
-s \
210+
-k "${{ env.KEYCHAIN_PASSWORD }}" \
211+
"${{ env.KEYCHAIN }}"
212+
213+
- name: Install gon for code signing and app notarization
214+
run: |
215+
wget \
216+
-q https://github.com/Bearer/gon/releases/download/v0.0.27/gon_macos.zip
217+
218+
unzip \
219+
gon_macos.zip \
220+
-d /usr/local/bin
221+
222+
- name: Write gon config to file
223+
# gon does not allow env variables in config file (https://github.com/mitchellh/gon/issues/20)
224+
run: |
225+
cat >"${{ env.GON_CONFIG_PATH }}" \
226+
<<EOF
227+
# See: https://github.com/Bearer/gon#configuration-file
228+
source = ["${{ env.DIST_DIR }}/${{ env.PROJECT_NAME }}"]
229+
bundle_id = "cc.arduino.${{ env.PROJECT_NAME }}"
230+
231+
sign {
232+
application_identity = "Developer ID Application: ARDUINO SA (7KT7ZWMCJT)"
233+
}
234+
235+
# Ask Gon for zip output to force notarization process to take place.
236+
# The CI will ignore the zip output, using the signed binary only.
237+
zip {
238+
output_path = "unused.zip"
239+
}
240+
EOF
241+
242+
- name: Sign and notarize binary
243+
env:
244+
AC_USERNAME: ${{ secrets.AC_USERNAME }}
245+
AC_PASSWORD: ${{ secrets.AC_PASSWORD }}
246+
AC_PROVIDER: ${{ secrets.AC_PROVIDER }}
247+
run: |
248+
gon "${{ env.GON_CONFIG_PATH }}"
249+
250+
- name: Re-package binary
251+
working-directory: ${{ env.DIST_DIR }}
252+
# Repackage the signed binary replaced in place by Gon (ignoring the output zip file)
253+
run: |
254+
# GitHub's upload/download-artifact actions don't preserve file permissions,
255+
# so we need to add execution permission back until the action is made to do this.
256+
chmod \
257+
+x \
258+
"${{ env.PROJECT_NAME }}"
259+
260+
tar -czf ${{ env.PACKAGE_FILENAME }} ${{ env.PROJECT_NAME }} LICENSE
261+
262+
- name: Replace artifact with notarized build
263+
uses: actions/upload-artifact@v4
264+
with:
265+
if-no-files-found: error
266+
name: ${{ env.PROJECT_NAME }}-${{ matrix.build }}
267+
overwrite: true
268+
path: ${{ env.DIST_DIR }}/${{ env.PACKAGE_FILENAME }}
269+
270+
create-release:
271+
runs-on: ubuntu-24.04
272+
needs: [build, sign-windows-executable, notarize-macos]
273+
steps:
274+
- name: Checkout
275+
uses: actions/checkout@v4
276+
with:
277+
fetch-depth: 0 # fetch all history for the create changelog step to work properly
278+
279+
- name: Download artifact
280+
uses: actions/download-artifact@v5
281+
with:
282+
merge-multiple: true
283+
path: ${{ env.DIST_DIR }}
284+
285+
- name: Upload artifacts index
286+
uses: ncipollo/release-action@v1
287+
with:
288+
token: ${{ secrets.GITHUB_TOKEN }}
289+
draft: false
290+
prerelease: true
291+
artifacts: ${{ env.DIST_DIR }}/*

Taskfile.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
version: "3"
2+
3+
vars:
4+
VERSION: # if version is not passed we hack the semver by encoding the commit as pre-release
5+
sh: echo "${VERSION:-0.0.0-$(git rev-parse --short HEAD)}"
6+
7+
tasks:
8+
arduino-flasher-cli:build:
9+
deps:
10+
- arduino-flasher-cli:artifacts
11+
desc: "Build the arduino-flasher-cli locally"
12+
dir: arduino-flasher-cli
13+
vars:
14+
VERSION: "{{.VERSION }}"
15+
cmds:
16+
- cmd: go build -ldflags "-X main.Version={{.VERSION}}" -v -o ../build/arduino-flasher-cli .
17+
platforms: [linux, darwin]
18+
- cmd: go build -ldflags "-X main.Version={{.VERSION}}" -v -o ../build/arduino-flasher-cli.exe .
19+
platforms: [windows]
20+
21+
arduino-flasher-cli:artifacts:
22+
desc: Prepare the arduino-flasher-cli artifacts
23+
internal: true
24+
cmd: sh ./arduino-flasher-cli/updater/artifacts/download_resources.sh

0 commit comments

Comments
 (0)