Imprive formatting and package.json to include additional files #27
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build Appling | |
| on: | |
| push: | |
| branches: | |
| - main | |
| - dev | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: 'Version tag' | |
| required: true | |
| type: string | |
| jobs: | |
| version: | |
| runs-on: ubuntu-22.04 | |
| if: github.repository_owner == 'tetherto' | |
| outputs: | |
| version: ${{ steps.meta.outputs.VERSION }} | |
| strategy: | |
| matrix: | |
| arch: | |
| - x64 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Read & validate version | |
| id: meta | |
| run: | | |
| set -euo pipefail | |
| VERSION=$(jq -r '.version' package.json) | |
| echo "VERSION=$VERSION" | |
| if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | |
| echo "❌ Error: package.json version ('$VERSION') is not semantic versioning (MAJOR.MINOR.PATCH)." | |
| exit 1 | |
| fi | |
| TAG="v$VERSION" | |
| echo "TAG=$TAG" | |
| echo "VERSION=$VERSION" >> "$GITHUB_OUTPUT" | |
| echo "TAG=$TAG" >> "$GITHUB_OUTPUT" | |
| linux: | |
| needs: [version] | |
| strategy: | |
| matrix: | |
| include: | |
| - arch: x64 | |
| runs_on: ubuntu-22.04 | |
| - arch: arm64 | |
| runs_on: ubuntu-22.04-arm | |
| runs-on: ${{ matrix.runs_on }} | |
| defaults: | |
| run: | |
| working-directory: ./appling | |
| env: | |
| SLACK_WEBHOOK_URL_PATH: ${{ secrets.SLACK_WEBHOOK_URL_PATH }} | |
| GOOGLE_FORM_KEY: ${{ secrets.GOOGLE_FORM_KEY }} | |
| GOOGLE_FORM_MAPPING_TIMESTAMP: ${{ secrets.GOOGLE_FORM_MAPPING_TIMESTAMP }} | |
| GOOGLE_FORM_MAPPING_TOPIC: ${{ secrets.GOOGLE_FORM_MAPPING_TOPIC }} | |
| GOOGLE_FORM_MAPPING_APP: ${{ secrets.GOOGLE_FORM_MAPPING_APP }} | |
| GOOGLE_FORM_MAPPING_OPERATING_SYSTEM: ${{ secrets.GOOGLE_FORM_MAPPING_OPERATING_SYSTEM }} | |
| GOOGLE_FORM_MAPPING_DEVICE_MODEL: ${{ secrets.GOOGLE_FORM_MAPPING_DEVICE_MODEL }} | |
| GOOGLE_FORM_MAPPING_MESSAGE: ${{ secrets.GOOGLE_FORM_MAPPING_MESSAGE }} | |
| GOOGLE_FORM_MAPPING_APP_VERSION: ${{ secrets.GOOGLE_FORM_MAPPING_APP_VERSION }} | |
| TEST_SLACK_WEBHOOK_URL_PATH: ${{ secrets.TEST_SLACK_WEBHOOK_URL_PATH }} | |
| TEST_GOOGLE_FORM_KEY: ${{ secrets.TEST_GOOGLE_FORM_KEY }} | |
| TEST_GOOGLE_FORM_MAPPING_TIMESTAMP: ${{ secrets.TEST_GOOGLE_FORM_MAPPING_TIMESTAMP }} | |
| TEST_GOOGLE_FORM_MAPPING_TOPIC: ${{ secrets.TEST_GOOGLE_FORM_MAPPING_TOPIC }} | |
| TEST_GOOGLE_FORM_MAPPING_APP: ${{ secrets.TEST_GOOGLE_FORM_MAPPING_APP }} | |
| TEST_GOOGLE_FORM_MAPPING_OPERATING_SYSTEM: ${{ secrets.TEST_GOOGLE_FORM_MAPPING_OPERATING_SYSTEM }} | |
| TEST_GOOGLE_FORM_MAPPING_DEVICE_MODEL: ${{ secrets.TEST_GOOGLE_FORM_MAPPING_DEVICE_MODEL }} | |
| TEST_GOOGLE_FORM_MAPPING_MESSAGE: ${{ secrets.TEST_GOOGLE_FORM_MAPPING_MESSAGE }} | |
| TEST_GOOGLE_FORM_MAPPING_APP_VERSION: ${{ secrets.TEST_GOOGLE_FORM_MAPPING_APP_VERSION }} | |
| APP_FILE: ${{ github.ref_name == 'refs/heads/main' && 'app' || 'app.dev' }}.cjs | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| registry-url: 'https://npm.pkg.github.com' | |
| scope: '@tetherto' | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y curl ca-certificates build-essential git libgtk-4-dev pkg-config fuse file | |
| # sudo apt-get install -y clang pkg-config libgtk-4-dev clang-tools fuse file | |
| wget https://apt.llvm.org/llvm.sh | |
| chmod +x llvm.sh | |
| sudo ./llvm.sh 20 | |
| npm install --global bare-build | |
| npm install | |
| - name: Build Linux AppImage | |
| run: | | |
| bare-build --target=linux-${{ matrix.arch }} --package --icon lib/icons/linux/icon.png ${{ env.APP_FILE }} | |
| - name: Find & rename AppImage file | |
| id: find_file | |
| run: | | |
| set -euo pipefail | |
| APPIMAGE_PATH=$(find "$GITHUB_WORKSPACE" -name "*.AppImage" -type f | head -n 1) | |
| echo "Original AppImage: $APPIMAGE_PATH" | |
| NEW_NAME="PearPass-Desktop-Linux-${{ matrix.arch }}-v${{ needs.version.outputs.version }}.AppImage" | |
| NEW_PATH="$GITHUB_WORKSPACE/$NEW_NAME" | |
| mv "$APPIMAGE_PATH" "$NEW_PATH" | |
| echo "Renamed AppImage to: $NEW_PATH" | |
| echo "APPIMAGE_PATH=$NEW_PATH" >> "$GITHUB_OUTPUT" | |
| TIMESTAMP=$(date +%Y%m%d-%H%M%S) | |
| echo "TIMESTAMP=$TIMESTAMP" >> $GITHUB_OUTPUT | |
| - uses: actions/upload-artifact@v4 | |
| if: ${{ steps.find_file.outputs.APPIMAGE_PATH != '' }} | |
| with: | |
| name: PearPass-Desktop-Linux-${{ matrix.arch }}-v${{ needs.version.outputs.version }}.AppImage | |
| path: "${{ steps.find_file.outputs.APPIMAGE_PATH }}" | |
| macos: | |
| runs-on: macos-14 | |
| needs: [version] | |
| strategy: | |
| matrix: | |
| arch: | |
| - x64 | |
| - arm64 | |
| defaults: | |
| run: | |
| working-directory: ./appling | |
| env: | |
| # Apple code signing identity - used for app, installer, and DMG signing | |
| APPLE_SIGNING_IDENTITY: "959D2C8BB8323AEF9C2367ACA2F854AE4D7DE458" | |
| SLACK_WEBHOOK_URL_PATH: ${{ secrets.SLACK_WEBHOOK_URL_PATH }} | |
| GOOGLE_FORM_KEY: ${{ secrets.GOOGLE_FORM_KEY }} | |
| GOOGLE_FORM_MAPPING_TIMESTAMP: ${{ secrets.GOOGLE_FORM_MAPPING_TIMESTAMP }} | |
| GOOGLE_FORM_MAPPING_TOPIC: ${{ secrets.GOOGLE_FORM_MAPPING_TOPIC }} | |
| GOOGLE_FORM_MAPPING_APP: ${{ secrets.GOOGLE_FORM_MAPPING_APP }} | |
| GOOGLE_FORM_MAPPING_OPERATING_SYSTEM: ${{ secrets.GOOGLE_FORM_MAPPING_OPERATING_SYSTEM }} | |
| GOOGLE_FORM_MAPPING_DEVICE_MODEL: ${{ secrets.GOOGLE_FORM_MAPPING_DEVICE_MODEL }} | |
| GOOGLE_FORM_MAPPING_MESSAGE: ${{ secrets.GOOGLE_FORM_MAPPING_MESSAGE }} | |
| GOOGLE_FORM_MAPPING_APP_VERSION: ${{ secrets.GOOGLE_FORM_MAPPING_APP_VERSION }} | |
| TEST_SLACK_WEBHOOK_URL_PATH: ${{ secrets.TEST_SLACK_WEBHOOK_URL_PATH }} | |
| TEST_GOOGLE_FORM_KEY: ${{ secrets.TEST_GOOGLE_FORM_KEY }} | |
| TEST_GOOGLE_FORM_MAPPING_TIMESTAMP: ${{ secrets.TEST_GOOGLE_FORM_MAPPING_TIMESTAMP }} | |
| TEST_GOOGLE_FORM_MAPPING_TOPIC: ${{ secrets.TEST_GOOGLE_FORM_MAPPING_TOPIC }} | |
| TEST_GOOGLE_FORM_MAPPING_APP: ${{ secrets.TEST_GOOGLE_FORM_MAPPING_APP }} | |
| TEST_GOOGLE_FORM_MAPPING_OPERATING_SYSTEM: ${{ secrets.TEST_GOOGLE_FORM_MAPPING_OPERATING_SYSTEM }} | |
| TEST_GOOGLE_FORM_MAPPING_DEVICE_MODEL: ${{ secrets.TEST_GOOGLE_FORM_MAPPING_DEVICE_MODEL }} | |
| TEST_GOOGLE_FORM_MAPPING_MESSAGE: ${{ secrets.TEST_GOOGLE_FORM_MAPPING_MESSAGE }} | |
| TEST_GOOGLE_FORM_MAPPING_APP_VERSION: ${{ secrets.TEST_GOOGLE_FORM_MAPPING_APP_VERSION }} | |
| APP_FILE: ${{ github.ref_name == 'refs/heads/main' && 'app' || 'app.dev' }}.cjs | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| registry-url: 'https://npm.pkg.github.com' | |
| scope: '@tetherto' | |
| - name: Install dependencies | |
| run: | | |
| npm install --global bare-build | |
| npm install | |
| - name: Audit dependencies | |
| run: | | |
| npm audit --production --audit-level=high || echo "::warning::npm audit found vulnerabilities" | |
| - name: Install the Apple certificate and provisioning profile | |
| env: | |
| BUILD_CERTIFICATE_BASE64: ${{ secrets.APPLE_DISTRIBUTION_CERTIFICATE }} | |
| P12_PASSWORD: ${{ secrets.APPLE_P12_PASSWORD }} | |
| BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.APPLE_PROVISIONING_PROFILE }} | |
| KEYCHAIN_PASSWORD: ${{ secrets.APPLE_KEYCHAIN_PASSWORD }} | |
| APIKEY_BASE64: ${{ secrets.APPLE_APIKEY }} | |
| run: | | |
| # create variables | |
| CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 | |
| PP_PATH=$RUNNER_TEMP/build_pp.provisionprofile | |
| KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db | |
| APIKEY_PATH=$RUNNER_TEMP/AuthKey.p8 | |
| # import certificate and provisioning profile from secrets | |
| echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH | |
| echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_PATH | |
| echo -n "$APIKEY_BASE64" | base64 --decode -o $APIKEY_PATH | |
| # create temporary keychain | |
| security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH | |
| security set-keychain-settings -lut 21600 $KEYCHAIN_PATH | |
| security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH | |
| # import certificate to keychain | |
| security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH | |
| security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH | |
| security list-keychain -d user -s $KEYCHAIN_PATH | |
| # add notarytool credentials | |
| xcrun notarytool store-credentials "pearpass" --key "$APIKEY_PATH" --key-id S3AG2UXSC5 --issuer 2067dae8-140d-4016-9a2b-d6ea80a20708 | |
| # apply provisioning profile | |
| mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles | |
| cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles | |
| - name: Build macOS app | |
| run: | | |
| bare-build \ | |
| --identifier "com.pears.pass" \ | |
| --target=darwin-${{ matrix.arch }} \ | |
| --icon lib/icons/darwin/icon.png \ | |
| --sign \ | |
| --identity "$APPLE_SIGNING_IDENTITY" \ | |
| --application-identity "$APPLE_SIGNING_IDENTITY" \ | |
| --installer-identity "$APPLE_SIGNING_IDENTITY" \ | |
| --keychain "pearpass" \ | |
| --entitlements entitlements.plist \ | |
| --hardened-runtime \ | |
| ${{ env.APP_FILE }} | |
| - name: Find App file | |
| id: find_file | |
| run: | | |
| set -euo pipefail | |
| APP_PATH=$(find "$GITHUB_WORKSPACE" -name "*.app" -type d | head -n 1) | |
| echo "Found app at: $APP_PATH" | |
| echo "APP_PATH=$APP_PATH" >> "$GITHUB_OUTPUT" | |
| TIMESTAMP=$(date +%Y%m%d-%H%M%S) | |
| echo "TIMESTAMP=$TIMESTAMP" >> $GITHUB_OUTPUT | |
| - name: Create DMG | |
| id: create_dmg | |
| if: ${{ steps.find_file.outputs.APP_PATH != '' }} | |
| run: | | |
| set -euo pipefail | |
| npm install --global create-dmg | |
| APP_PATH="${{ steps.find_file.outputs.APP_PATH }}" | |
| VERSION="${{ needs.version.outputs.version }}" | |
| ARCH="${{ matrix.arch }}" | |
| create-dmg --identity="$APPLE_SIGNING_IDENTITY" --no-version-in-filename "$APP_PATH" | |
| # Find the DMG that was just created in the current working directory (./appling) | |
| RAW_DMG=$(ls ./*.dmg | head -n 1) | |
| echo "Raw DMG from create-dmg: $RAW_DMG" | |
| DMG_NAME="PearPass-Desktop-MacOS-${ARCH}-v${VERSION}.dmg" | |
| mv "$RAW_DMG" "$DMG_NAME" | |
| DMG_PATH="$PWD/$DMG_NAME" | |
| echo "Renamed DMG to: $DMG_PATH" | |
| echo "DMG_PATH=$DMG_PATH" >> "$GITHUB_OUTPUT" | |
| - name: Notarize DMG | |
| if: ${{ steps.create_dmg.outputs.DMG_PATH != '' }} | |
| run: | | |
| xcrun notarytool submit "${{ steps.create_dmg.outputs.DMG_PATH }}" --keychain-profile "pearpass" --wait | |
| - name: Staple DMG | |
| if: ${{ steps.create_dmg.outputs.DMG_PATH != '' }} | |
| run: | | |
| xcrun stapler staple "${{ steps.create_dmg.outputs.DMG_PATH }}" | |
| xcrun stapler validate "${{ steps.create_dmg.outputs.DMG_PATH }}" | |
| - uses: actions/upload-artifact@v4 | |
| if: ${{ steps.create_dmg.outputs.DMG_PATH != '' }} | |
| with: | |
| name: PearPass-Desktop-MacOS-${{ matrix.arch }}-v${{ needs.version.outputs.version }}.dmg | |
| path: ${{ steps.create_dmg.outputs.DMG_PATH }} | |
| - name: Clean up keychain and provisioning profile | |
| if: ${{ always() }} | |
| run: | | |
| security delete-keychain $RUNNER_TEMP/app-signing.keychain-db | |
| rm ~/Library/MobileDevice/Provisioning\ Profiles/build_pp.provisionprofile | |
| release: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| needs: [version, linux, macos] | |
| if: github.ref == 'refs/heads/main' | |
| steps: | |
| - name: Download artifacts | |
| uses: actions/download-artifact@v5 | |
| with: | |
| path: artifacts/ | |
| merge-multiple: true | |
| - name: Create Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: v${{ needs.version.outputs.version }} | |
| name: PearPass-Desktop-v${{ needs.version.outputs.version }} | |
| files: artifacts/** |