Skip to content

Commit

Permalink
chore: New release strategy (#1701)
Browse files Browse the repository at this point in the history
  • Loading branch information
aeharding authored Nov 12, 2024
1 parent 0a0650b commit 9b14ddb
Show file tree
Hide file tree
Showing 17 changed files with 1,490 additions and 1,575 deletions.
51 changes: 41 additions & 10 deletions .github/workflows/cd.yml → .github/workflows/build_release.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
name: Build Apps, Deploy Web and Create Release
name: Build, deploy and release

on:
push:
tags:
- "[0-9]+.[0-9]+.[0-9]+"
- "test-[0-9]+.[0-9]+.[0-9]+"

jobs:
build_web:
runs-on: ubuntu-latest

concurrency:
group: "build_web"
steps:
- uses: actions/checkout@v4
- run: corepack enable

- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm

- run: corepack enable

- name: 📦 Install dependencies
run: pnpm install --frozen-lockfile
Expand All @@ -24,6 +27,7 @@ jobs:
run: pnpm build

- name: Upload dist bundle to S3
if: github.ref_name != 'test*'
uses: jakejarvis/[email protected]
with:
args: --acl public-read --follow-symlinks --delete
Expand All @@ -44,33 +48,43 @@ jobs:
path: Voyager-Web-${{ github.ref_name }}.zip

build_ios:
environment: deploy
runs-on: macos-latest
concurrency:
group: "build_ios"
cancel-in-progress: true
steps:
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest-stable
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 22

- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest-stable

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: "3.3"

- name: Install Fastlane
run: |
gem install bundler
bundle install
- run: corepack enable

- run: pnpm i --frozen-lockfile

- name: Build (Ionic)
run: pnpm exec ionic cap sync
env:
CI_PLATFORM: ios

- name: Deploy to TestFlight
if: github.ref_name != 'test*'
run: |
echo "$APP_STORE_CONNECT_KEY" > authkey.json
bundle exec fastlane deploy
Expand All @@ -80,6 +94,7 @@ jobs:
MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }}
APP_STORE_CONNECT_KEY: ${{ secrets.APP_STORE_CONNECT_KEY }}
COMMIT_MSG: ${{ github.event.commits[0].message }}

- name: Upload iOS IPA as artifact
uses: actions/upload-artifact@v4
with:
Expand All @@ -88,21 +103,23 @@ jobs:

build_android:
runs-on: ubuntu-latest
concurrency:
group: "build_android"
cancel-in-progress: true
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 22

- run: corepack enable

- run: pnpm i --frozen-lockfile

- name: Build (Ionic)
run: pnpm exec ionic cap sync
env:
BUILD_FOSS_ONLY: 1
CI_PLATFORM: android

- name: Set up JDK 11
uses: actions/setup-java@v4
with:
Expand All @@ -117,59 +134,73 @@ jobs:
env:
ANDROID_KEYSTORE: ${{ secrets.ANDROID_KEYSTORE }}
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}

- run: mv android/app/build/outputs/apk/release/app-release.apk Voyager-Android-${{ github.ref_name }}.apk

- name: Send to Artifacts
uses: actions/upload-artifact@v4
with:
name: Voyager-Android-${{ github.ref_name }}.apk
path: Voyager-Android-${{ github.ref_name }}.apk

build_android_play:
environment: deploy
runs-on: ubuntu-latest
concurrency:
group: "build_android_play"
cancel-in-progress: true
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 22

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: "3.3"

- name: Install Fastlane
run: |
gem install bundler
bundle install
- run: corepack enable

- run: pnpm i --frozen-lockfile

- name: Build (Ionic)
run: pnpm exec ionic cap sync
env:
CI_PLATFORM: android

- name: Set up JDK 11
uses: actions/setup-java@v4
with:
java-version: "17"
distribution: "corretto"
cache: gradle

- name: Build (Android)
run: |
echo $ANDROID_KEYSTORE | base64 --decode > android/app/release-ci.keystore
env:
ANDROID_KEYSTORE: ${{ secrets.ANDROID_KEYSTORE }}

- name: Setup service account
run: echo $GOOGLE_SERVICE_ACCOUNT | base64 --decode > android/pc-api.json
env:
GOOGLE_SERVICE_ACCOUNT: ${{ secrets.GOOGLE_SERVICE_ACCOUNT }}

- name: Run Fastlane
run: bundle exec fastlane android deploy
env:
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}

create_release:
needs: [build_web, build_ios, build_android_play, build_android]
if: startsWith(github.ref_name, 'test-') != true
runs-on: ubuntu-latest

permissions:
Expand Down
4 changes: 1 addition & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
name: ci

permissions: {}

on:
push:
branches:
Expand All @@ -11,7 +9,7 @@ on:
branches:
- main
- release/*
workflow_dispatch: {}
workflow_dispatch:

jobs:
ci:
Expand Down
100 changes: 100 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
name: Cut a release

on:
workflow_dispatch:
# -- TESTING ONLY --
# push:
# branches:
# - inherit # todo remove, can't workflow_dispatch from branch

env:
APP_BUILD_OFFSET: 300
TAG_PREFIX: # test-
RELEASE_BRANCH_PREFIX: # test-release

jobs:
app_build_number:
name: Calculate app build number
runs-on: ubuntu-latest
steps:
- id: calculate
run: |
APP_BUILD=$((${{ github.run_number }} + $APP_BUILD_OFFSET))
echo "app_build=$APP_BUILD" >> $GITHUB_OUTPUT
echo Current build number: $APP_BUILD
outputs:
app_build: ${{ steps.calculate.outputs.app_build }}

validate_version:
needs: app_build_number
name: Validate version
runs-on: ubuntu-latest
outputs:
version: ${{ steps.get_current_version.outputs.version }}
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 22

- name: Get current version from package.json
id: get_current_version
run: |
CURRENT_APP_VERSION=$(node -p "require('./package.json').version")
echo "version=$CURRENT_APP_VERSION" >> $GITHUB_OUTPUT
- name: Verify provided version not already released
run: |
git fetch --tags
TAG_NAME="$TAG_PREFIX${{ steps.get_current_version.outputs.version }}"
if git rev-parse "$TAG_NAME" >/dev/null 2>&1; then
echo "Error: Tag $TAG_NAME already exists"
exit 1
fi
push_release:
needs: [validate_version, app_build_number]
name: Add version to apps, push release branch and tag
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
with:
persist-credentials: false # Don't clobber the PAT below

- run: corepack enable

- name: 📦 Install dependencies
run: pnpm install --frozen-lockfile

- name: Run trapeze (update iOS and Android version/code)
run: pnpm exec trapeze run trapeze.yaml -y
env:
APP_BUILD: ${{ needs.app_build_number.outputs.app_build }}
APP_VERSION: ${{ needs.validate_version.outputs.version }}

- name: Import GPG key
uses: crazy-max/ghaction-import-gpg@cb9bde2e2525e640591a934b1fd28eef1dcaf5e5 # v6.2.0
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}
git_user_signingkey: true
git_commit_gpgsign: true

- name: Commit and push release
env:
PAT_TOKEN: ${{ secrets.PAT_TOKEN }}
# Github doesn't trigger subsequent workflows unless push with a PAT
run: |
git remote set-url origin "https://${PAT_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
git checkout -b "$RELEASE_BRANCH_PREFIX/${{ needs.validate_version.outputs.version }}"
git config --global user.email "[email protected]"
git config --global user.name "Voyager CI"
git add .
git commit -S -m "Release ${{ needs.validate_version.outputs.version }} (${{ needs.app_build_number.outputs.app_build }})"
TAG_NAME="${TAG_PREFIX}${{ needs.validate_version.outputs.version }}"
echo "Creating tag: $TAG_NAME"
git tag "$TAG_NAME"
git push origin "$RELEASE_BRANCH_PREFIX/${{ needs.validate_version.outputs.version }}"
git push origin "$TAG_NAME"
5 changes: 0 additions & 5 deletions .release-it.json

This file was deleted.

37 changes: 29 additions & 8 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,16 +96,37 @@ pnpm test

### 🚀 Releasing

To release a new version:

```sh
BUILD=123; npx release-it
```

Make sure the build number is incremental. This is used for F-droid.

Voyager uses Github Actions for Apple App Store and Android Play Store builds, where logs may be inspected.

**Voyager's Android and iOS builds are reproducible**! In fact, [F-droid independently builds Voyager](https://gitlab.com/fdroid/fdroiddata/-/blob/master/metadata/app.vger.voyager.yml) and verifies the same compiled APK is provided in Github Releases.

Note: F-droid and Github Releases binaries are built with `BUILD_FOSS_ONLY=true`. This removes all nonfree dependencies, currently just Google Play in-app purchases.

#### Start the release process

1. Make sure the version is incremented. Increment in `package.json` and push (if necessary)
2. Trigger the `release` workflow in Github Actions from the relevant commit

> [!TIP]
> Shorthand: `pnpm release` (relies on [`gh`](https://cli.github.com))
#### The `release` workflow will:

1. Set the build number to the current Github run number (and detect the version from `package.json`)
2. Commit the version bump
3. Create a release branch (e.g. `release/1.0.0`)
4. Tag the release (e.g. `1.0.0`)
5. As a side-effect of tagging, trigger the `build_release` workflow

#### The `build_release` workflow will:

1. Build web app — `Voyager-Web-<version>.zip`
2. Build non-FOSS Google Play Android — **no artifact**
3. Build iOS artifact — `Voyager-iOS-<version>.ipa`
4. Build FOSS-only Android — `Voyager-Android-<version>.apk`
5. Upload to the Apple App Store and Google Play Store
6. Create a Github Release with the artifacts

#### several_days_later_spongebob_meme.jpg

In a few days, F-droid will scan the repo for new tags and [independently build](https://gitlab.com/fdroid/fdroiddata/-/blob/master/metadata/app.vger.voyager.yml) the FOSS-only Android native app. It will verify reproducibility against Github Releases, and then publish the app.
5 changes: 3 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ COPY patches ./patches
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile

# Copy all source files
COPY prebuild.sh disable_in_app_purchases.sh index.html vite.config.ts manifest.json tsconfig.json compilerOptions.js ./
COPY index.html vite.config.ts manifest.json tsconfig.json compilerOptions.js ./
COPY public ./public
COPY scripts ./scripts
COPY src ./src

# Build
Expand All @@ -39,7 +40,7 @@ FROM docker.io/library/nginx AS runner

ARG UID=911 GID=911

COPY generate_config.sh /docker-entrypoint.d/generate_config.sh
COPY scripts/docker_generate_config.sh /docker-entrypoint.d/generate_config.sh

COPY nginx.conf.template /etc/nginx/templates/default.conf.template

Expand Down
2 changes: 0 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ android {
applicationId "app.vger.voyager"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 268
versionName "2.19.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
aaptOptions {
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
Expand Down
Loading

0 comments on commit 9b14ddb

Please sign in to comment.