Merge pull request #1172 from ZoneMinder/dependabot/npm_and_yarn/xmld… #63
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: CI/CD Pipeline | |
| on: | |
| push: | |
| branches: [ master ] | |
| tags: [ 'v*' ] | |
| pull_request: | |
| branches: [ master ] | |
| jobs: | |
| security-audit: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| cache: 'npm' | |
| - run: npm ci | |
| - run: npm audit --audit-level=moderate || true | |
| - run: npm run lint || true | |
| test: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| cache: 'npm' | |
| - run: npm ci | |
| - run: npm test || echo "No tests configured yet" | |
| build-android: | |
| runs-on: ubuntu-latest | |
| needs: [security-audit, test] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| cache: 'npm' | |
| - uses: actions/setup-java@v4 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '17' | |
| - run: npm ci | |
| - run: npx cordova platform add android | |
| - run: npx cordova build android --debug | |
| build-ios: | |
| runs-on: macos-latest | |
| needs: [security-audit, test] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - run: npm ci | |
| - run: npx cordova platform add ios | |
| - name: Build iOS debug | |
| run: > | |
| npx cordova build ios --debug | |
| --buildFlag="CODE_SIGNING_ALLOWED=NO" | |
| --buildFlag="IPHONEOS_DEPLOYMENT_TARGET=15.0" | |
| --buildFlag="DEBUG_INFORMATION_FORMAT=dwarf" | |
| release-android: | |
| runs-on: ubuntu-latest | |
| needs: [security-audit, test] | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| cache: 'npm' | |
| - uses: actions/setup-java@v4 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '17' | |
| - name: Decode signing keystore | |
| env: | |
| ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} | |
| run: echo -n "$ANDROID_KEYSTORE_BASE64" | base64 --decode > $RUNNER_TEMP/upload-keystore.jks | |
| - run: npm ci | |
| - name: Generate build configuration | |
| env: | |
| KEYSTORE_PATH: ${{ runner.temp }}/upload-keystore.jks | |
| KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} | |
| KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} | |
| KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }} | |
| run: | | |
| node -e " | |
| var c = {android:{release:{ | |
| keystore: process.env.KEYSTORE_PATH, | |
| storePassword: process.env.KEYSTORE_PASSWORD, | |
| alias: process.env.KEY_ALIAS, | |
| password: process.env.KEY_PASSWORD, | |
| keystoreType: 'jks' | |
| }}}; | |
| require('fs').writeFileSync('build.json', JSON.stringify(c, null, 2)); | |
| " | |
| - name: Build signed AAB | |
| run: | | |
| npx cordova platform add android | |
| npx cordova build android --release --buildConfig=build.json -- --packageType=bundle | |
| - name: Upload AAB artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: zmNinja-android-${{ github.ref_name }} | |
| path: platforms/android/app/build/outputs/bundle/release/*.aab | |
| - name: Upload to Google Play | |
| uses: r0adkll/upload-google-play@v1 | |
| with: | |
| serviceAccountJsonPlainText: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_JSON }} | |
| packageName: com.zoneminder.zmNinja | |
| releaseFiles: platforms/android/app/build/outputs/bundle/release/*.aab | |
| track: internal | |
| status: completed | |
| - name: Clean up keystore | |
| if: always() | |
| run: rm -f $RUNNER_TEMP/upload-keystore.jks | |
| release-ios: | |
| runs-on: macos-latest | |
| needs: [security-audit, test] | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Install Apple certificate and provisioning profiles | |
| env: | |
| BUILD_CERTIFICATE_BASE64: ${{ secrets.IOS_DISTRIBUTION_CERTIFICATE_BASE64 }} | |
| P12_PASSWORD: ${{ secrets.IOS_DISTRIBUTION_CERTIFICATE_PASSWORD }} | |
| APP_PROVISION_PROFILE_BASE64: ${{ secrets.IOS_APP_PROVISION_PROFILE_BASE64 }} | |
| EXT_PROVISION_PROFILE_BASE64: ${{ secrets.IOS_NOTIFICATION_EXT_PROVISION_PROFILE_BASE64 }} | |
| run: | | |
| CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 | |
| APP_PP_PATH=$RUNNER_TEMP/app.mobileprovision | |
| EXT_PP_PATH=$RUNNER_TEMP/extension.mobileprovision | |
| KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db | |
| # Decode secrets | |
| echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH | |
| echo -n "$APP_PROVISION_PROFILE_BASE64" | base64 --decode -o $APP_PP_PATH | |
| echo -n "$EXT_PROVISION_PROFILE_BASE64" | base64 --decode -o $EXT_PP_PATH | |
| # Create and configure temporary keychain | |
| security create-keychain -p "" $KEYCHAIN_PATH | |
| security set-keychain-settings -lut 21600 $KEYCHAIN_PATH | |
| security unlock-keychain -p "" $KEYCHAIN_PATH | |
| # Import certificate | |
| 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_PATH | |
| security list-keychain -d user -s $KEYCHAIN_PATH | |
| # Install provisioning profiles by UUID | |
| mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles | |
| APP_PP_UUID=$(/usr/libexec/PlistBuddy -c "Print UUID" /dev/stdin <<< "$(security cms -D -i $APP_PP_PATH)") | |
| cp $APP_PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles/$APP_PP_UUID.mobileprovision | |
| EXT_PP_UUID=$(/usr/libexec/PlistBuddy -c "Print UUID" /dev/stdin <<< "$(security cms -D -i $EXT_PP_PATH)") | |
| cp $EXT_PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles/$EXT_PP_UUID.mobileprovision | |
| # Export UUIDs for build configuration | |
| echo "APP_PP_UUID=$APP_PP_UUID" >> $GITHUB_ENV | |
| echo "EXT_PP_UUID=$EXT_PP_UUID" >> $GITHUB_ENV | |
| - run: npm ci | |
| - name: Generate build configuration | |
| run: | | |
| node -e " | |
| var c = {ios:{release:{ | |
| codeSignIdentity: 'Apple Distribution', | |
| developmentTeam: 'P97TSUFFDX', | |
| packageType: 'app-store', | |
| provisioningProfile: process.env.APP_PP_UUID | |
| }}}; | |
| require('fs').writeFileSync('build.json', JSON.stringify(c, null, 2)); | |
| " | |
| - name: Build iOS release | |
| run: | | |
| npx cordova platform add ios | |
| npx cordova build ios --release --device --buildConfig=build.json | |
| - name: Upload IPA artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: zmNinja-ios-${{ github.ref_name }} | |
| path: platforms/ios/build/**/*.ipa | |
| - name: Decode App Store Connect API key | |
| env: | |
| API_KEY_BASE64: ${{ secrets.APP_STORE_CONNECT_API_KEY_BASE64 }} | |
| run: | | |
| mkdir -p $RUNNER_TEMP/private_keys | |
| echo -n "$API_KEY_BASE64" | base64 --decode > $RUNNER_TEMP/private_keys/AuthKey_${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}.p8 | |
| - name: Upload to App Store Connect | |
| env: | |
| API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }} | |
| API_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_ISSUER_ID }} | |
| run: | | |
| IPA_PATH=$(find platforms/ios/build -name "*.ipa" -print -quit) | |
| xcrun altool --upload-app \ | |
| --type ios \ | |
| --file "$IPA_PATH" \ | |
| --apiKey "$API_KEY_ID" \ | |
| --apiIssuer "$API_ISSUER_ID" | |
| - name: Clean up keychain and keys | |
| if: always() | |
| run: | | |
| security delete-keychain $RUNNER_TEMP/app-signing.keychain-db | |
| rm -rf $RUNNER_TEMP/private_keys | |
| dependency-review: | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'pull_request' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/dependency-review-action@v4 |