Skip to content

feat: deploy web app to staging environment (#1560) #1092

feat: deploy web app to staging environment (#1560)

feat: deploy web app to staging environment (#1560) #1092

name: Package Installers
on:
push:
branches: [ master ]
paths-ignore:
- '**.md'
pull_request:
branches: [ master ]
paths-ignore:
- '**.md'
release:
types: [ prereleased, released ]
workflow_dispatch:
env:
MACOS_APP_NAME: "GTFS Validator"
MACOS_NOTARIZATION_NAME: "notarization.zip"
MACOS_TARGET_PATH: "app/pkg/build/jpackage/GTFS Validator.app"
MACOS_TARGET_DEST_PATH: "app/pkg/build/jpackage"
MACOS_CERTIFICATE: ${{ secrets.MACOS_DEVELOPER_ID_APPLICATION_CERTIFICATE_P12_BASE64 }}
MACOS_CERTIFICATE_PWD: ${{ secrets.MACOS_DEVELOPER_ID_APPLICATION_CERTIFICATE_PASSWORD }}
MACOS_CERTIFICATE_NAME: ${{ secrets.MACOS_DEVELOPER_ID_APPLICATION_CERTIFICATE_NAME }}
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }}
MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.MACOS_NOTARIZATION_USERNAME }}
MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.MACOS_NOTARIZATION_TEAM_ID }}
MACOS_NOTARIZATION_PWD: ${{ secrets.MACOS_NOTARIZATION_PASSWORD }}
jobs:
validate_gradle_wrapper:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: gradle/wrapper-validation-action@v1
build_push:
needs: [ validate_gradle_wrapper ]
name: Build and upload packaged app
runs-on: ${{ matrix.os }}
strategy:
# Adding fail-fast: false so at least some artifacts gets uploaded if others fail
fail-fast: false
matrix:
os: [ macos-latest, windows-latest, ubuntu-latest ]
steps:
- uses: actions/checkout@v3
with:
# We need to download all tags so that the axion-release-plugin
# can resolve the most recent version tag.
fetch-depth: 0
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
# We need a recent version of Java with jpackage included.
java-version: '17.0.7'
# We use the zulu distribution, which is an OpenJDK distro.
distribution: 'zulu'
# We create a code-signing keychain on MacOS before building and packaging the app, as the
# app will be signed as part of the jpackage build phase.
- name: "MacOS - Import Certificate: Developer ID Application"
id: codesign
if: matrix.os == 'macos-latest' && (github.event_name == 'push' || github.event_name == 'release')
run: |
# Turn our base64-encoded certificate back to a regular .p12 file
echo $MACOS_CERTIFICATE | base64 --decode > certificate.p12
# We need to create a new keychain, otherwise using the certificate will prompt with a UI dialog asking for the certificate password, which we can't use in a headless CI environment
security create-keychain -p "${MACOS_CI_KEYCHAIN_PWD}" build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p "${MACOS_CI_KEYCHAIN_PWD}" build.keychain
security import certificate.p12 -k build.keychain -P "${MACOS_CERTIFICATE_PWD}" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "${MACOS_CI_KEYCHAIN_PWD}" build.keychain
- name: "Package GUI app installer with Gradle"
uses: gradle/gradle-build-action@v2
with:
arguments: |
jpackage
-Psign-app=${{github.event_name == 'push' || github.event_name == 'release'}}
# On MacOS, we now submit the app for "notarization", where Apple will scan the app for
# malware and other issues. This step can take a few minutes or more; the action will wait
# until the report is available.
- name: "MacOS - Notarize & Staple Release Build"
if: matrix.os == 'macos-latest' && (github.event_name == 'push' || github.event_name == 'release')
id: notarize_staple_macos_app
run: |
# Store the notarization credentials so that we can prevent a UI password dialog from blocking the CI
echo "Create keychain profile"
xcrun notarytool store-credentials "notarytool-profile" --apple-id "${MACOS_NOTARIZATION_APPLE_ID}" --team-id "${MACOS_NOTARIZATION_TEAM_ID}" --password "${MACOS_NOTARIZATION_PWD}"
# We can't notarize an app bundle directly, but we need to compress it as an archive.
# Therefore, we create a zip file containing our app bundle, so that we can send it to the
# notarization service
echo "Creating temp notarization archive"
ditto -c -k --keepParent "${{ env.MACOS_TARGET_PATH }}" ${{ env.MACOS_NOTARIZATION_NAME }}
# Here we send the notarization request to the Apple's Notarization service, waiting for the result.
# This typically takes a few seconds inside a CI environment, but it might take more depending on the App
# characteristics. Visit the Notarization docs for more information and strategies on how to optimize it if
# you're curious
echo "Notarize app"
xcrun notarytool submit "${{ env.MACOS_NOTARIZATION_NAME }}" --keychain-profile "notarytool-profile" --wait
# Finally, we need to "attach the staple" to our executable, which will allow our app to be
# validated by macOS even when an internet connection is not available.
echo "Attach staple"
xcrun stapler staple "${{ env.MACOS_TARGET_PATH }}"
# Now that we have a notarized app, we can package it.
- name: "Mac OS - Package the app"
if: matrix.os == 'macos-latest'
shell: bash
run: |
appVersion=$(./gradlew cV -q -Prelease.quiet)
appVersion=${appVersion//-SNAPSHOT/}
jpackage \
--type dmg \
--name "${{ env.MACOS_APP_NAME }}" \
--app-version ${appVersion} \
--app-image "${{ env.MACOS_TARGET_PATH }}" \
--dest ${{ env.MACOS_TARGET_DEST_PATH }}
jpackage \
--type pkg \
--name 'GTFS Validator' \
--app-version ${appVersion} \
--app-image "${{ env.MACOS_TARGET_PATH }}" \
--dest ${{ env.MACOS_TARGET_DEST_PATH }}
- name: "Upload Installer"
uses: actions/upload-artifact@v3
with:
name: Installer - ${{matrix.os}}
path: |
${{ env.MACOS_TARGET_DEST_PATH }}/*.msi
${{ env.MACOS_TARGET_DEST_PATH }}/*.dmg
${{ env.MACOS_TARGET_DEST_PATH }}/*.pkg
${{ env.MACOS_TARGET_DEST_PATH }}/*.deb
- name: "Upload assets to release"
if: github.event_name == 'prerelease' || github.event_name == 'release'
env:
OS_NAME: '${{ matrix.os }}'
uses: actions/github-script@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
console.log(`Running on OS ${process.env.OS_NAME}`);
console.log(`Uploading asset to release ID ${context.payload.release.id}`);
const os = process.env.OS_NAME.split('-')[0]
const fs = require('fs').promises;
const { repo: { owner, repo }, sha } = context;
for (let file of await fs.readdir('./app/pkg/build/jpackage')) {
const extension = file.split('.').pop()
if (extension != "msi" && extension != "dmg" && extension != "pkg" && extension != "deb")
continue;
console.log('Uploading', file);
await github.repos.uploadReleaseAsset({
owner, repo,
release_id: context.payload.release.id,
name: `Installer ${os}.${extension}`,
data: await fs.readFile(`./app/pkg/build/jpackage/${file}`)
});
}