From 9dac0c2535798db5645fd165bbfa2227cabaf428 Mon Sep 17 00:00:00 2001 From: Alexander Harding Date: Thu, 14 Nov 2024 18:12:27 -0600 Subject: [PATCH 1/2] ci: f-droid env not matching github actions env --- .github/workflows/build_release.yml | 53 ++++++------------- .github/workflows/release.yml | 41 ++++++++++---- CONTRIBUTING.md | 43 +++++++++++++-- src/core/AppCrash.tsx | 8 +-- .../settings/general/other/backup/helpers.ts | 2 +- src/features/tips/TipDialog.tsx | 2 +- src/routes/pages/settings/UpdateAppPage.tsx | 2 +- .../pages/settings/about/AppDetails.tsx | 7 +-- src/vite-env.d.ts | 19 ------- vite.config.ts | 7 +-- 10 files changed, 98 insertions(+), 86 deletions(-) diff --git a/.github/workflows/build_release.yml b/.github/workflows/build_release.yml index cc58ba90a7..8079e8e11a 100644 --- a/.github/workflows/build_release.yml +++ b/.github/workflows/build_release.yml @@ -6,9 +6,6 @@ on: is_main_build: type: boolean required: true - app_build: - type: string - required: true push: tags: - "[0-9]+.[0-9]+.[0-9]+" @@ -20,31 +17,17 @@ concurrency: group: release jobs: - # get app build env from git commit message - app_build: - runs-on: ubuntu-latest - env: - COMMIT_MSG: ${{ github.event.head_commit.message }} - steps: - - if: inputs.is_main_build != true - run: | - # get app build in parentheses from commit message - APP_BUILD=$(echo "$COMMIT_MSG" | sed -n 's/.*(\([0-9]*\)).*/\1/p') - # verify app_build is a number - if echo "$APP_BUILD" | grep -qE '^[0-9]+$'; then - echo "app_build=$APP_BUILD" >> $GITHUB_OUTPUT - fi - outputs: - app_build: ${{ inputs.app_build || steps.app_build.outputs.app_build }} - build_web: - needs: app_build runs-on: ubuntu-latest - env: - APP_BUILD: ${{ needs.app_build.outputs.app_build }} steps: - uses: actions/checkout@v4 + - name: Download bumped version artifacts + if: inputs.is_main_build + uses: actions/download-artifact@v4 + with: + name: release-data + - uses: actions/setup-node@v4 with: node-version: 22 @@ -78,11 +61,8 @@ jobs: path: Voyager-Web-${{ env.APP_GIT_REF }}.zip build_ios: - needs: app_build environment: deploy runs-on: macos-15 - env: - APP_BUILD: ${{ needs.app_build.outputs.app_build }} steps: - uses: actions/checkout@v4 @@ -90,7 +70,7 @@ jobs: if: inputs.is_main_build uses: actions/download-artifact@v4 with: - name: trapeze-artifacts + name: release-data - uses: actions/setup-node@v4 with: @@ -137,10 +117,7 @@ jobs: path: Voyager-iOS-${{ env.APP_GIT_REF }}.ipa build_android: - needs: app_build runs-on: ubuntu-latest - env: - APP_BUILD: ${{ needs.app_build.outputs.app_build }} steps: - uses: actions/checkout@v4 @@ -148,7 +125,7 @@ jobs: if: inputs.is_main_build uses: actions/download-artifact@v4 with: - name: trapeze-artifacts + name: release-data - uses: actions/setup-node@v4 with: @@ -188,11 +165,8 @@ jobs: path: Voyager-Android-${{ env.APP_GIT_REF }}.apk build_android_play: - needs: app_build environment: deploy runs-on: ubuntu-latest - env: - APP_BUILD: ${{ needs.app_build.outputs.app_build }} steps: - uses: actions/checkout@v4 @@ -200,7 +174,7 @@ jobs: if: inputs.is_main_build uses: actions/download-artifact@v4 with: - name: trapeze-artifacts + name: release-data - uses: actions/setup-node@v4 with: @@ -275,10 +249,15 @@ jobs: name: Voyager-Android-${{ env.APP_GIT_REF }}.apk path: artifacts/android + # https://github.com/softprops/action-gh-release/pull/372#issuecomment-1642643937 + - name: Changelog + id: build_changelog + uses: mikepenz/release-changelog-builder-action@a57c1b7c90e56d9c8b26a6ed5d1eed159369e117 # v5.0.0 + - name: Release - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@01570a1f39cb168c169c802c3bceb9e93fb10974 # v2.1.0 with: - generate_release_notes: true + body: ${{ steps.build_changelog.outputs.changelog }} files: | artifacts/ios/* artifacts/android/* diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4f2403880d..53384cccce 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,7 +26,7 @@ jobs: run: | APP_BUILD=$((${{ github.run_number }} + $APP_BUILD_OFFSET)) echo "app_build=$APP_BUILD" >> $GITHUB_OUTPUT - echo Current build number: $APP_BUILD + echo "App build number: \`$APP_BUILD\`" >> $GITHUB_STEP_SUMMARY outputs: app_build: ${{ steps.calculate.outputs.app_build }} @@ -46,6 +46,7 @@ jobs: run: | CURRENT_APP_VERSION=$(node -p "require('./package.json').version") echo "app_version=$CURRENT_APP_VERSION" >> $GITHUB_OUTPUT + echo "current app version: $CURRENT_APP_VERSION" - name: Verify provided version not already released if: inputs.release_behavior == 'publish_release' @@ -75,14 +76,38 @@ jobs: APP_BUILD: ${{ needs.app_build.outputs.app_build }} APP_VERSION: ${{ needs.app_version.outputs.app_version }} + - name: Add build metadata + run: | + echo """ + APP_BUILD=${{ needs.app_build.outputs.app_build }} + APP_GIT_REF=${{ inputs.release_behavior != 'publish_release' && github.sha || needs.app_version.outputs.app_version }} + APP_VERSION=${{ needs.app_version.outputs.app_version }} + """ > .env + echo "wrote .env:" + cat .env + + - name: Determine changed files + id: determine_changes + run: | + git add . + echo "will upload the following files:" + git --no-pager diff HEAD --name-only + + echo "all modifications:" + git --no-pager diff HEAD + + { + echo 'files<> "$GITHUB_ENV" + - name: Upload bumped version artifacts uses: actions/upload-artifact@v4 with: - name: trapeze-artifacts - retention-days: 3 - path: | - android - ios + name: release-data + path: ${{ steps.determine_changes.outputs.files }} + include-hidden-files: true # needed for .env dispatch_beta_release: if: inputs.release_behavior != 'publish_release' @@ -108,7 +133,7 @@ jobs: - name: Download bumped version artifacts uses: actions/download-artifact@v4 with: - name: trapeze-artifacts + name: release-data - name: Import GPG key uses: crazy-max/ghaction-import-gpg@cb9bde2e2525e640591a934b1fd28eef1dcaf5e5 # v6.2.0 @@ -125,7 +150,6 @@ jobs: # 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/${{ needs.app_version.outputs.app_version }}" git config --global user.email "voyager.ci.noreply@harding.dev" git config --global user.name "Voyager CI" git add . @@ -133,5 +157,4 @@ jobs: TAG_NAME="${{ needs.app_version.outputs.app_version }}" echo "Creating tag: $TAG_NAME" git tag -s "$TAG_NAME" -m "release: ${{ needs.app_version.outputs.app_version }} (${{ needs.app_build.outputs.app_build }})" - git push origin "release/${{ needs.app_version.outputs.app_version }}" git push origin "$TAG_NAME" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 12d4b259dc..c710bbae74 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -102,6 +102,27 @@ Voyager uses Github Actions for Apple App Store and Android Play Store builds, w 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. +> [!IMPORTANT] +> Release tags are detached from main so that CI can commit build metadata for fdroid. +> +> You can visualize where release tags have diverged from main like this: +> +> ```sh +> git log --graph --oneline --tags +> ``` +> +> To see all commits between a release tag and main, you can use the following (replace `MY_RELEASE_TAG`): +> +> ```sh +> git log main..MY_RELEASE_TAG +> ``` +> +> To determine the exact commit where a release tag diverged from main, you can use the following (replace `MY_RELEASE_TAG`): +> +> ```sh +> git rev-parse $(git rev-list --exclude-first-parent-only ^main MY_RELEASE_TAG| tail -1)^ +> ``` + #### Start the release process 1. Make sure the version is incremented. Increment in `package.json` and push (if necessary) @@ -113,10 +134,19 @@ Note: F-droid and Github Releases binaries are built with `BUILD_FOSS_ONLY=true` #### 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 +2. Upload `release-data` artifact with trapeze changes and `.env` file + +Then, it will fork depending on the `release_behavior` (e.g. building on main or publishing a release): + +##### Building on main + +1. Dispatch the `build_release` workflow with `is_main_build=true` + +##### Publishing a release + +2. Commit the `release-data` +3. Tag the release (e.g. `1.0.0`) +4. As a side-effect of tagging, trigger the `build_release` workflow #### The `build_release` workflow will: @@ -125,8 +155,11 @@ Note: F-droid and Github Releases binaries are built with `BUILD_FOSS_ONLY=true` 3. Build iOS artifact — `Voyager-iOS-.ipa` 4. Build FOSS-only Android — `Voyager-Android-.apk` 5. Upload to the Apple App Store and Google Play Store -6. Create a Github Release with the artifacts +6. Deploy PWA to [beta.vger.app](https://beta.vger.app) (testing track) or [vger.app](https://vger.app) (release track) +7. 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. + +This is the main reason why each release tags trapeze changes (and build metadata) as a new commit. It also makes it easier for anyone to verify reproducibility. diff --git a/src/core/AppCrash.tsx b/src/core/AppCrash.tsx index a36b6a19e3..b50905ad85 100644 --- a/src/core/AppCrash.tsx +++ b/src/core/AppCrash.tsx @@ -53,10 +53,10 @@ export default function AppCrash({ error }: FallbackProps) { - Logged in? \`${loggedIn}\` - Native app? \`${isNative()}\` - Installed to home screen? \`${isInstalled()}\` - - APP_VERSION: \`${APP_VERSION}\` - - APP_BUILD: \`${APP_BUILD}\` - - APP_GIT_REF: \`${APP_GIT_REF}\` - - BUILD_FOSS_ONLY: \`${BUILD_FOSS_ONLY}\` + - APP_VERSION: \`${import.meta.env.APP_VERSION}\` + - APP_BUILD: \`${import.meta.env.APP_BUILD}\` + - APP_GIT_REF: \`${import.meta.env.APP_GIT_REF}\` + - BUILD_FOSS_ONLY: \`${import.meta.env.BUILD_FOSS_ONLY}\` - User agent: \`${navigator.userAgent}\` ### Crash data diff --git a/src/features/settings/general/other/backup/helpers.ts b/src/features/settings/general/other/backup/helpers.ts index fbc1c05273..1382c57076 100644 --- a/src/features/settings/general/other/backup/helpers.ts +++ b/src/features/settings/general/other/backup/helpers.ts @@ -7,7 +7,7 @@ import { LOCALSTORAGE_KEYS, get, set } from "../../../syncStorage"; const BASE_BACKUP_JSON = { voyagerBackupVersion: 1, - voyagerAppVersion: APP_VERSION, + voyagerAppVersion: import.meta.env.APP_VERSION, } as const; type Backup = typeof BASE_BACKUP_JSON & { diff --git a/src/features/tips/TipDialog.tsx b/src/features/tips/TipDialog.tsx index e195185759..8528627bcb 100644 --- a/src/features/tips/TipDialog.tsx +++ b/src/features/tips/TipDialog.tsx @@ -60,7 +60,7 @@ export default function TipDialog({ onDismiss }: TipProps) { Your support means a lot! - {BUILD_FOSS_ONLY || !isNative() ? ( + {import.meta.env.BUILD_FOSS_ONLY || !isNative() ? ( ) : ( diff --git a/src/routes/pages/settings/UpdateAppPage.tsx b/src/routes/pages/settings/UpdateAppPage.tsx index 9536534165..d0182c2125 100644 --- a/src/routes/pages/settings/UpdateAppPage.tsx +++ b/src/routes/pages/settings/UpdateAppPage.tsx @@ -108,7 +108,7 @@ export default function UpdateAppPage() { Current version - {APP_VERSION} + {import.meta.env.APP_VERSION} { if (import.meta.env.DEV) return Development; // If the app version is different from the git ref (tag), it's a pre-release - if (APP_GIT_REF !== APP_VERSION) + if (import.meta.env.APP_GIT_REF !== import.meta.env.APP_VERSION) return ( - Beta Track — [{APP_BUILD}] {APP_GIT_REF.slice(0, 7)} + Beta Track — [{import.meta.env.APP_BUILD}]{" "} + {import.meta.env.APP_GIT_REF.slice(0, 7)} ); })(); @@ -39,7 +40,7 @@ export default function AppDetails() {
- Voyager {APP_VERSION} + Voyager {import.meta.env.APP_VERSION} {buildInfo && }
diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index eddd8b10a3..f40765cdae 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -1,22 +1,3 @@ /// /// /// - -/** - * Version from package.json - */ -declare const APP_VERSION: string; - -/** - * Only available for main builds (not releases) - * - * @example 123 - */ -declare const APP_BUILD: number | undefined; - -/** - * Git sha if main build, otherwise tag name - */ -declare const APP_GIT_REF: string; - -declare const BUILD_FOSS_ONLY: boolean; diff --git a/vite.config.ts b/vite.config.ts index 2a3336a1f1..84b058bf9f 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -59,6 +59,7 @@ export default defineConfig({ modernPolyfills: ["es.array.at", "es.object.has-own"], }), ], + envPrefix: ["VITE_", "APP_", "BUILD_FOSS_ONLY"], // TODO: Outdated clients trying to access stale codesplit js chucks // break. This breaks iOS transitions. // Put everything into one chunk for now. @@ -87,12 +88,6 @@ export default defineConfig({ }, }, }, - define: { - APP_VERSION: JSON.stringify(process.env.npm_package_version), - APP_BUILD: JSON.stringify(process.env.APP_BUILD ?? ""), - APP_GIT_REF: JSON.stringify(process.env.APP_GIT_REF ?? ""), - BUILD_FOSS_ONLY: !!process.env.BUILD_FOSS_ONLY, - }, test: { exclude: ["**/e2e/**", "**/node_modules/**"], globals: true, From f3015c1cdca9ddb95bac14fcc75344d9cc37c7f6 Mon Sep 17 00:00:00 2001 From: Alexander Harding Date: Thu, 14 Nov 2024 18:30:23 -0600 Subject: [PATCH 2/2] cleanup --- .github/workflows/build_release.yml | 24 ++++++++++++------------ .github/workflows/release.yml | 6 +++--- eslint.config.js | 10 ---------- fastlane/Fastfile | 2 +- vite.config.ts | 9 ++++++++- 5 files changed, 24 insertions(+), 27 deletions(-) diff --git a/.github/workflows/build_release.yml b/.github/workflows/build_release.yml index 8079e8e11a..2de38558eb 100644 --- a/.github/workflows/build_release.yml +++ b/.github/workflows/build_release.yml @@ -11,7 +11,7 @@ on: - "[0-9]+.[0-9]+.[0-9]+" env: - APP_GIT_REF: ${{ inputs.is_main_build && github.sha || github.ref_name }} + BUILD_LABEL: ${{ inputs.is_main_build && github.sha || github.ref_name }} concurrency: group: release @@ -52,13 +52,13 @@ jobs: - name: Compress artifacts run: | - zip -r Voyager-Web-$APP_GIT_REF.zip dist + zip -r Voyager-Web-$BUILD_LABEL.zip dist - name: Upload artifacts uses: actions/upload-artifact@v4 with: - name: Voyager-Web-${{ env.APP_GIT_REF }}.zip - path: Voyager-Web-${{ env.APP_GIT_REF }}.zip + name: Voyager-Web-${{ env.BUILD_LABEL }}.zip + path: Voyager-Web-${{ env.BUILD_LABEL }}.zip build_ios: environment: deploy @@ -113,8 +113,8 @@ jobs: - name: Upload iOS IPA as artifact uses: actions/upload-artifact@v4 with: - name: Voyager-iOS-${{ env.APP_GIT_REF }}.ipa - path: Voyager-iOS-${{ env.APP_GIT_REF }}.ipa + name: Voyager-iOS-${{ env.BUILD_LABEL }}.ipa + path: Voyager-iOS-${{ env.BUILD_LABEL }}.ipa build_android: runs-on: ubuntu-latest @@ -156,13 +156,13 @@ jobs: 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-${{ env.APP_GIT_REF }}.apk + - run: mv android/app/build/outputs/apk/release/app-release.apk Voyager-Android-${{ env.BUILD_LABEL }}.apk - name: Send to Artifacts uses: actions/upload-artifact@v4 with: - name: Voyager-Android-${{ env.APP_GIT_REF }}.apk - path: Voyager-Android-${{ env.APP_GIT_REF }}.apk + name: Voyager-Android-${{ env.BUILD_LABEL }}.apk + path: Voyager-Android-${{ env.BUILD_LABEL }}.apk build_android_play: environment: deploy @@ -234,19 +234,19 @@ jobs: - name: Download dist artifacts uses: actions/download-artifact@v4 with: - name: Voyager-Web-${{ env.APP_GIT_REF }}.zip + name: Voyager-Web-${{ env.BUILD_LABEL }}.zip path: artifacts/web - name: Download iOS Artifact uses: actions/download-artifact@v4 with: - name: Voyager-iOS-${{ env.APP_GIT_REF }}.ipa + name: Voyager-iOS-${{ env.BUILD_LABEL }}.ipa path: artifacts/ios - name: Download Android Artifact uses: actions/download-artifact@v4 with: - name: Voyager-Android-${{ env.APP_GIT_REF }}.apk + name: Voyager-Android-${{ env.BUILD_LABEL }}.apk path: artifacts/android # https://github.com/softprops/action-gh-release/pull/372#issuecomment-1642643937 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 53384cccce..ec80d82dba 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -44,9 +44,9 @@ jobs: - name: Get current version from package.json id: app_version run: | - CURRENT_APP_VERSION=$(node -p "require('./package.json').version") - echo "app_version=$CURRENT_APP_VERSION" >> $GITHUB_OUTPUT - echo "current app version: $CURRENT_APP_VERSION" + APP_VERSION=$(node -p "require('./package.json').version") + echo "app_version=$APP_VERSION" >> $GITHUB_OUTPUT + echo "current app version: $APP_VERSION" - name: Verify provided version not already released if: inputs.release_behavior == 'publish_release' diff --git a/eslint.config.js b/eslint.config.js index b31c206bd8..06025802cd 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -34,16 +34,6 @@ export default tseslint.config( "react-compiler/react-compiler": ["error", compilerOptions], }, }, - { - files: ["src/**"], - - languageOptions: { - globals: { - APP_VERSION: true, - BUILD_FOSS_ONLY: true, - }, - }, - }, { plugins: { perfectionist: perfectionistPlugin, diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 7888de723d..1b0aaf80d5 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -17,7 +17,7 @@ default_platform(:ios) ENV['app_identifier'] = 'app.vger.voyager' ENV['app_name_sanitized'] = 'App' -ENV['ios_output'] = "Voyager-iOS-#{ENV['APP_GIT_REF']}.ipa" +ENV['ios_output'] = "Voyager-iOS-#{ENV['BUILD_LABEL']}.ipa" platform :ios do before_all do diff --git a/vite.config.ts b/vite.config.ts index 84b058bf9f..486be95774 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -59,7 +59,14 @@ export default defineConfig({ modernPolyfills: ["es.array.at", "es.object.has-own"], }), ], - envPrefix: ["VITE_", "APP_", "BUILD_FOSS_ONLY"], + envPrefix: [ + "VITE_", + "BUILD_FOSS_ONLY", + // Keep these explicit. Do not simplify to `APP_`. + "APP_BUILD", + "APP_VERSION", + "APP_GIT_REF", + ], // TODO: Outdated clients trying to access stale codesplit js chucks // break. This breaks iOS transitions. // Put everything into one chunk for now.