Skip to content

Release nightly

Release nightly #65

name: Release nightly
on:
push:
branches:
- "**"
pull_request:
branches:
- main
schedule:
- cron: 0 2 * * *
workflow_dispatch: {}
concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}
cancel-in-progress: true
permissions:
contents: write
jobs:
make-draft-release:
name: make draft release
runs-on: ubuntu-20.04
steps:
- name: Get current date
id: date
run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_ENV
- name: Checkout
uses: actions/checkout@v4
- name: Delete existing nightly build
if: github.ref_name == 'main' && github.event_name != 'pull_request'
run: |
gh release delete nightly-$date \
--yes \
--cleanup-tag \
|| true
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create nightly build draft
if: github.ref_name == 'main' && github.event_name != 'pull_request'
run: |
gh release create nightly-$date \
--draft \
--title "Nightly build $date"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
outputs:
date: ${{ env.date }}
build-app:
name: build app
needs:
- make-draft-release
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-20.04
arch: arm64
concurrency: linux-arm64
- os: ubuntu-20.04
arch: x64
concurrency: linux-amd64
- os: macos-14
arch: arm64
concurrency: macos
- os: macos-14
arch: x64
concurrency: macos
- os: windows-2022
arch: x64
concurrency: windows
runs-on: ${{ matrix.os }}
environment: ${{ github.ref_name == 'main' && 'test-signing' || null }}
concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ matrix.concurrency }}
steps:
- name: Checkout freelensapp/freelens
uses: actions/checkout@v4
with:
repository: freelensapp/freelens
ref: main
- name: Checkout
uses: actions/checkout@v4
with:
path: tmp/nightly-builds
- name: Save current revision
id: current_revision
run: echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
- name: Setup node
uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
- name: Get npm cache directory
shell: bash
run: echo "npm_cache_dir=$(npm config get cache)" >> ${GITHUB_ENV}
- name: Use npm cache
uses: actions/cache@v4
with:
path: ${{ env.npm_cache_dir }}
key: ${{ matrix.os }}-${{ matrix.arch }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ matrix.os }}-${{ matrix.arch }}-node-
- name: Install dependencies (Linux)
if: runner.os == 'Linux'
uses: nick-fields/retry@v3
with:
timeout_minutes: 20
max_attempts: 3
retry_on: any
command: |
sudo apt-get install -y --no-install-recommends \
gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
- name: Install dependencies (macOS)
if: runner.os == 'macOS'
uses: nick-fields/retry@v3
with:
timeout_minutes: 20
max_attempts: 3
retry_on: any
command: brew install bash python-setuptools
- name: Install dependencies (Windows)
if: runner.os == 'Windows'
uses: nick-fields/retry@v3
with:
timeout_minutes: 20
max_attempts: 3
retry_on: any
command: choco install yq
- name: Tweak package for nightly build
shell: bash
run: |
yq -pj -oj -i ".version += \"-$tag\"" freelens/package.json
cp -f tmp/nightly-builds/apt/* freelens/build/apt
yq -pj -oj -i '.build.deb.fpm += ["./build/apt/freelens-nightly-builds.asc=/etc/apt/keyrings/freelens-nightly-builds.asc", "./build/apt/freelens-nightly-builds.sources=/etc/apt/sources.list.d/freelens-nightly-builds.sources"]' freelens/package.json
env:
tag: nightly-${{ needs.make-draft-release.outputs.date }}
- name: Install NPM dependencies
uses: nick-fields/retry@v3
with:
timeout_minutes: 20
max_attempts: 3
retry_on: any
command: npm ci
- name: Rebuild for arch (Linux arm64)
if: runner.os == 'Linux' && matrix.arch == 'arm64'
run: npm run rebuild -- -- -a arm64
env:
CC: aarch64-linux-gnu-gcc
CXX: aarch64-linux-gnu-g++
- name: Monkey patch FPM arguments for RPM (Linux arm64)
if: runner.os == 'Linux' && matrix.arch == 'arm64'
run: |
sed -i 's/\? "aarch64" : "arm64"/|| targetName === "rpm" &/' node_modules/builder-util/out/arch.js
- name: Rebuild for arch (macOS x64)
if: runner.os == 'macOS' && matrix.arch == 'x64'
run: npm run rebuild -- -- -a x64
- name: Build NPM packages (macOS x64, Linux arm64)
if: runner.os == 'macOS' && matrix.arch == 'x64' || runner.os == 'Linux' && matrix.arch == 'arm64'
run: npm run build
env:
DOWNLOAD_ALL_ARCHITECTURES: "true"
- name: Build NPM packages (macOS arm64, Linux x64, Windows)
if: runner.os == 'macOS' && matrix.arch == 'arm64' || runner.os == 'Linux' && matrix.arch == 'x64' || runner.os == 'Windows'
run: npm run build
- name: Build Electron app (macOS)
if: runner.os == 'macOS'
uses: nick-fields/retry@v3
with:
timeout_minutes: 20
max_attempts: 3
retry_on: any
command: |
for var in APPLEID APPLEIDPASS APPLETEAMID CSC_LINK CSC_KEY_PASSWORD CSC_INSTALLER_LINK CSC_INSTALLER_KEY_PASSWORD; do
test -n "${!var}" || unset $var
done
npm run build:app -- -- -- \
dmg pkg \
--publish never \
--${{ matrix.arch }}
env:
APPLEID: ${{ secrets.APPLEID }}
APPLEIDPASS: ${{ secrets.APPLEIDPASS }}
APPLETEAMID: ${{ secrets.APPLETEAMID }}
CSC_LINK: ${{ secrets.CSC_LINK }}
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
CSC_INSTALLER_LINK: ${{ secrets.CSC_INSTALLER_LINK }}
CSC_INSTALLER_KEY_PASSWORD: ${{ secrets.CSC_INSTALLER_KEY_PASSWORD }}
- name: Notarize PKG (macOS)
if: runner.os == 'macOS'
uses: nick-fields/retry@v3
with:
timeout_minutes: 20
max_attempts: 3
retry_on: any
command: |
if [[ -n $APPLEID && -n $APPLEIDPASS && -n $APPLETEAMID ]]; then
pkgname=$(ls -1 freelens/dist/Freelens*.pkg | head -n1)
auth="--apple-id $APPLEID --password $APPLEIDPASS --team-id $APPLETEAMID"
xcrun notarytool submit $pkgname $auth --wait 2>&1 | tee freelens/dist/notarytool.log
uuid=$(awk '/id: / { print $2; exit; }' freelens/dist/notarytool.log)
sleep 60
if [[ -n $uuid ]]; then
xcrun notarytool log $uuid $auth
xcrun stapler staple $pkgname
fi
fi
env:
APPLEID: ${{ secrets.APPLEID }}
APPLEIDPASS: ${{ secrets.APPLEIDPASS }}
APPLETEAMID: ${{ secrets.APPLETEAMID }}
- name: Build Electron app (Linux)
if: runner.os == 'Linux'
run: |
npm run build:app -- -- -- \
AppImage deb rpm \
--publish never \
--${{ matrix.arch }}
- name: Build Electron app (Windows x64)
if: runner.os == 'Windows' && matrix.arch == 'x64'
shell: bash
run: |
for var in CSC_LINK CSC_KEY_PASSWORD; do
test -n "${!var}" || unset $var
done
npm run build:app -- -- -- \
msi nsis \
--publish never \
--${{ matrix.arch }}
env:
CSC_LINK: ${{ secrets.WIN_CSC_LINK }}
CSC_KEY_PASSWORD: ${{ secrets.WIN_CSC_KEY_PASSWORD }}
- name: Azure Trusted Signing (Windows x64)
if: runner.os == 'Windows' && matrix.arch == 'x64' && github.ref_name == 'main' && github.event_name != 'pull_request'
uses: azure/trusted-signing-action@v0.5.1
with:
azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
endpoint: ${{ vars.AZURE_ENDPOINT }}
trusted-signing-account-name: ${{ vars.AZURE_CODE_SIGNING_NAME }}
certificate-profile-name: ${{ vars.AZURE_CERT_PROFILE_NAME }}
files-folder: ${{ github.workspace }}\freelens\dist
files-folder-filter: exe,msi
- name: Tweak binaries
shell: bash
run: |
find . -name '*pty.node' -print0 | xargs -0 file
rm -f freelens/dist/*.blockmap
- name: Normalize filenames before upload
shell: bash
run: |
perl << 'END'
chdir "freelens/dist" or die $!;
my %arch = (x64 => "amd64", arm64 => "arm64");
my $arch = $arch{$ENV{ARCH}};
while (<Freelens*>) {
my $src = $_;
s/ Setup /-/;
s/[ _]/-/g;
if (/\.(dmg|exe|msi|pkg)$/ && !/-(amd64|arm64)\./) {
s/\.(dmg|exe|msi|pkg)$/-$arch.$1/;
}
s/[.-](aarch64|arm64)/-arm64/;
s/[.-](amd64|x86-64)/-amd64/;
s/-(amd64|arm64).(dmg|pkg)$/-macos-$1.$2/;
s/-(amd64|arm64).(AppImage|deb|flatpak|rpm|snap)$/-linux-$1.$2/;
s/-(amd64|arm64).(exe|msi|)$/-windows-$1.$2/;
my $dst = $_;
if ($src ne $dst) {
print "rename $src to $dst\n";
rename $src, $dst or die $!;
}
}
END
env:
ARCH: ${{ matrix.arch }}
- name: Make checksums for binaries (Linux, Windows)
if: runner.os == 'Linux' || runner.os == 'Windows'
shell: bash
run: |
for f in freelens/dist/Freelens*.*; do
sha256sum "$f" | tee "$f.sha256"
done
- name: Make checksums for binaries (macOS)
if: runner.os == 'macOS'
shell: bash
run: |
for f in freelens/dist/Freelens*.*; do
shasum -a 256 "$f" | tee "$f.sha256"
done
- name: List files before upload
shell: bash
run: |
for f in freelens/dist/Freelens*.*; do
echo "$(ls -l "$f")" "|" "$(file -b "$f")"
done
- name: Upload files
if: github.ref_name == 'main' && github.event_name != 'pull_request'
shell: bash
run: |
gh release upload $tag \
freelens/dist/Freelens*.* \
--repo freelensapp/freelens-nightly-builds
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
tag: nightly-${{ needs.make-draft-release.outputs.date }}
outputs:
sha: ${{ steps.current_revision.outputs.sha }}
add-notes-to-release:
name: add notes to release
if: github.ref_name == 'main' && github.event_name != 'pull_request'
needs:
- make-draft-release
- build-app
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Add notes to nightly build
run: |
gh release edit nightly-${{ needs.make-draft-release.outputs.date }} \
--notes="Based on https://github.com/freelensapp/freelens/commit/${{ needs.build-app.outputs.sha }}"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
publish-release:
name: publish release
if: github.ref_name == 'main' && github.event_name != 'pull_request'
needs:
- make-draft-release
- build-app
- add-notes-to-release
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Publish nightly build
run: |
gh release edit $tag \
--draft=false
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
tag: nightly-${{ needs.make-draft-release.outputs.date }}
- name: Delete old nightly builds
uses: nick-fields/retry@v3
with:
timeout_minutes: 3
max_attempts: 3
retry_on: any
command: |
gh release list --json tagName --jq '.[].tagName' | \
sort -r | \
sed 1,10d | \
xargs -IX -rn1 \
gh release delete X --cleanup-tag --yes
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
release-apt-repository:
name: release APT repository
if: github.ref_name == 'main' && github.event_name != 'pull_request'
needs:
- make-draft-release
- publish-release
runs-on: ubuntu-24.04
environment: apt-signing
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: GPG configuration
run: |
mkdir -p -m 0700 $HOME/.gnupg
echo "use-agent" > $HOME/.gnupg/gpg.conf
echo "pinentry-program $GITHUB_WORKSPACE/.github/scripts/pinentry.sh" > $HOME/.gnupg/gpg-agent.conf
echo "$GPG_PASSPHRASE" > $HOME/.gnupg/passphrase
gpgconf --launch gpg-agent
echo "$GPG_PRIVATE_KEY" | gpg --import
echo "$GPG_KEY_ID:6:" | gpg --import-ownertrust
env:
GPG_KEY_ID: ${{ vars.GPG_KEY_ID }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
- name: Release APT repository
run: |
set -x
gh release download $tag -p "*.deb" -D tmp
pushd tmp
apt-ftparchive packages . | tee Packages | xz > Packages.xz
apt-ftparchive release . > Release
gpg --clearsign -o InRelease Release
gpg --armor --detach-sign --sign -o Release.gpg Release
gh release upload $tag InRelease Packages Packages.xz Release Release.gpg --clobber
popd
env:
tag: nightly-${{ needs.make-draft-release.outputs.date }}
GH_TOKEN: ${{ secrets.GH_TOKEN }}