Build and Publish #1301
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 and Publish | |
| # This workflow is triggered on pushes to the main branch, pull requests and manual triggers | |
| # 1. version - An initial step to be used by other steps - bumps the version code and string based on the run number and package.json | |
| # 2. android - Builds the Android app and uploads it to Google Play (if requested) | |
| # 3. docker - Builds the Docker image and pushes it to GitHub Container Registry | |
| # 4. ios - Builds the iOS app and uploads it to App Store (if requested) | |
| # 5. tag - Tags the built commit with the version string | |
| # 6. github-release - Creates a Github release with the apps' binaries (if requested) | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| publishandroid: | |
| description: 'Publish to Google play' | |
| required: false | |
| default: 'false' | |
| type: boolean | |
| publishios: | |
| description: 'Publish to App Store' | |
| required: false | |
| default: 'false' | |
| type: boolean | |
| production: | |
| description: 'Publish to production' | |
| required: false | |
| default: 'false' | |
| type: boolean | |
| jobs: | |
| version: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7.0.1 | |
| - name: Setup node | |
| uses: actions/setup-node@v7.0.0 | |
| with: | |
| node-version-file: IsraelHiking.Web/.nvmrc | |
| - name: Get version | |
| id: get-version | |
| run: | | |
| version=$(node -p "require('./IsraelHiking.Web/package.json').version") | |
| echo "major=${version%%.*}" >> "$GITHUB_OUTPUT" | |
| echo "minor=$(echo "$version" | cut -d. -f2)" >> "$GITHUB_OUTPUT" | |
| - name: Set version code and string | |
| id: version-code | |
| env: | |
| MAJOR: ${{ steps.get-version.outputs.major }} | |
| MINOR: ${{ steps.get-version.outputs.minor }} | |
| PATCH: ${{ github.run_number }} | |
| run: | | |
| version_string=$MAJOR.$MINOR.$(($PATCH % 1000)) | |
| version_code=$(($MAJOR * 100000 + $MINOR * 1000 + $PATCH % 1000)) | |
| echo "version_code=$version_code" >> $GITHUB_OUTPUT | |
| echo "version_string=$version_string" >> $GITHUB_OUTPUT | |
| commit_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/commit/$GITHUB_SHA" | |
| { | |
| echo "### Build and Publish $version_string" | |
| echo "" | |
| echo "| --- | --- |" | |
| echo "| Version | \`$version_string\` |" | |
| echo "| Commit | [\`$(git rev-parse --short HEAD)\`]($commit_url) - $(git log -1 --pretty=%s) |" | |
| echo "| Ref | \`$GITHUB_REF_NAME\` |" | |
| } >> $GITHUB_STEP_SUMMARY | |
| - name: Get all milestones | |
| id: get_milestones | |
| uses: octokit/request-action@v3.0.0 | |
| with: | |
| route: GET /repos/${{ github.repository }}/milestones?state=open | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Extract milestone ID | |
| id: extract | |
| run: | | |
| echo '${{ steps.get_milestones.outputs.data }}' | jq '.[] | select(.title == "Next Release") | .number' > id.txt | |
| milestone_id=$(cat id.txt) | |
| echo "milestone_id=$milestone_id" >> $GITHUB_OUTPUT | |
| shell: bash | |
| outputs: | |
| version_code: ${{ steps.version-code.outputs.version_code }} | |
| version_string: ${{ steps.version-code.outputs.version_string }} | |
| milestone_id: ${{ steps.extract.outputs.milestone_id }} | |
| android: | |
| runs-on: ubuntu-latest | |
| needs: version | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7.0.1 | |
| - name: Setup node | |
| uses: actions/setup-node@v7.0.0 | |
| with: | |
| node-version-file: IsraelHiking.Web/.nvmrc | |
| - name: Setup Java | |
| uses: actions/setup-java@v5.6.0 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '21' | |
| - name: Setup Ruby | |
| uses: ruby/setup-ruby@v1 | |
| with: | |
| ruby-version: '3.4.1' | |
| working-directory: IsraelHiking.Web/android | |
| bundler-cache: true | |
| - name: Build UI and set version | |
| run: | | |
| cd IsraelHiking.Web | |
| npm ci | |
| npm run set-version ${{ needs.version.outputs.version_string }} ${{ needs.version.outputs.version_code }} | |
| npm run build:mobile -- --no-progress | |
| npx cap sync android | |
| - name: Build Android Release | |
| if: ${{ github.secret_source == 'Actions' }} | |
| run: | | |
| cd IsraelHiking.Web/android | |
| bundle exec fastlane build_aab | |
| bundle exec fastlane build_apk | |
| env: | |
| STORE_PASSWORD: ${{ secrets.MAPEAK_STORE_PASSWORD }} | |
| PASSWORD: ${{ secrets.MAPEAK_PASSWORD }} | |
| KEYSTORE_PATH: ${{ github.workspace }}/IsraelHiking.Web/android/app/Mapeak.jks | |
| - name: Upload aab artifacts | |
| if: ${{ github.secret_source == 'Actions' }} | |
| uses: actions/upload-artifact@v7.0.1 | |
| with: | |
| name: Mapeak_signed_${{ needs.version.outputs.version_string }}.aab | |
| path: IsraelHiking.Web/android/app/build/outputs/bundle/release/app-release.aab | |
| - name: Upload apk artifacts | |
| if: ${{ github.secret_source == 'Actions' }} | |
| uses: actions/upload-artifact@v7.0.1 | |
| with: | |
| name: Mapeak_signed_${{ needs.version.outputs.version_string }}.apk | |
| path: IsraelHiking.Web/android/app/build/outputs/apk/release/app-release.apk | |
| - name: Publish to Google Play | |
| if: ${{ github.event.inputs.publishandroid == 'true' }} | |
| run: | | |
| cd IsraelHiking.Web/android | |
| bundle exec fastlane upload | |
| env: | |
| GOOGLE_PLAY_SERVICE_ACCOUNT_JSON: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_JSON }} | |
| - name: Promote to production | |
| if: ${{ github.event.inputs.publishandroid == 'true' && github.event.inputs.production == 'true' }} | |
| run: | | |
| cd IsraelHiking.Web/android | |
| bundle exec fastlane promote | |
| env: | |
| GOOGLE_PLAY_SERVICE_ACCOUNT_JSON: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_JSON }} | |
| docker: | |
| runs-on: ubuntu-latest | |
| needs: version | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7.0.1 | |
| - name: Login to GitHub Container Registry | |
| if: ${{ github.secret_source == 'Actions' }} | |
| uses: docker/login-action@v4 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build Docker image | |
| run: | | |
| docker build . -t ghcr.io/israelhikingmap/website-mapeak:$VERSION --build-arg VERSION=$VERSION | |
| env: | |
| VERSION: ${{ needs.version.outputs.version_string }} | |
| - name: Push Docker image | |
| if: ${{ github.secret_source == 'Actions' }} | |
| run: | | |
| docker push ghcr.io/israelhikingmap/website-mapeak:$VERSION | |
| env: | |
| VERSION: ${{ needs.version.outputs.version_string }} | |
| ios: | |
| runs-on: macos-26 | |
| needs: version | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7.0.1 | |
| - name: Setup node | |
| uses: actions/setup-node@v7.0.0 | |
| with: | |
| node-version-file: IsraelHiking.Web/.nvmrc | |
| - name: Setup Ruby | |
| uses: ruby/setup-ruby@v1 | |
| with: | |
| ruby-version: '3.4.1' | |
| working-directory: IsraelHiking.Web/ios/App | |
| bundler-cache: true | |
| - name: Set up Git to use PAT for private match repo | |
| run: | | |
| git config --global url."https://x-access-token:${{ secrets.FASTLANE_MATCH_PAT }}@github.com/IsraelHikingMap/fastlane-match".insteadOf "https://github.com/IsraelHikingMap/fastlane-match" | |
| - name: Build UI | |
| run: | | |
| cd IsraelHiking.Web | |
| npm ci | |
| npm run set-version ${{ needs.version.outputs.version_string }} ${{ needs.version.outputs.version_code }} | |
| npm run build:mobile -- --no-progress | |
| npx cap sync ios | |
| - name: Build iOS with signing | |
| if: ${{ github.secret_source == 'Actions' }} | |
| run: | | |
| cd IsraelHiking.Web/ios/App | |
| bundle exec fastlane build_ios | |
| env: | |
| MATCH_PASSWORD: ${{ secrets.PASSWORD }} | |
| - name: Upload ipa artifacts | |
| if: ${{ github.secret_source == 'Actions' }} | |
| uses: actions/upload-artifact@v7.0.1 | |
| with: | |
| name: Mapeak_signed_${{ needs.version.outputs.version_string }}.ipa | |
| path: IsraelHiking.Web/ios/App/App.ipa | |
| - name: Upload to testers | |
| if: ${{ github.event.inputs.publishios == 'true' && github.event.inputs.production == 'false' }} | |
| run: | | |
| cd IsraelHiking.Web/ios/App | |
| bundle exec fastlane upload_to_testers | |
| env: | |
| APPSTORE_CONNECT_API_KEY: ${{ secrets.APPSTORE_CONNECT_API_KEY }} | |
| - name: Upload and send for review | |
| if: ${{ github.event.inputs.publishios == 'true' && github.event.inputs.production == 'true' }} | |
| run: | | |
| cd IsraelHiking.Web/ios/App | |
| bundle exec fastlane upload_to_production | |
| env: | |
| APPSTORE_CONNECT_API_KEY: ${{ secrets.APPSTORE_CONNECT_API_KEY }} | |
| tag: | |
| if: ${{ github.ref == 'refs/heads/main' }} | |
| runs-on: ubuntu-latest | |
| needs: [version, ios, android] | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7.0.1 | |
| - name: Tag commit and push | |
| env: | |
| VERSION: ${{ needs.version.outputs.version_string }} | |
| run: | | |
| git tag "v$VERSION" | |
| git push origin "v$VERSION" | |
| tag_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/tree/v$VERSION" | |
| commit_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/commit/$GITHUB_SHA" | |
| echo "Tagged [\`v$VERSION\`]($tag_url) at [\`$(git rev-parse --short HEAD)\`]($commit_url)" >> $GITHUB_STEP_SUMMARY | |
| github-release: | |
| if: ${{ github.event.inputs.production == 'true' && github.ref == 'refs/heads/main' }} | |
| runs-on: ubuntu-latest | |
| needs: [version, ios, android, tag] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7.0.1 | |
| - name: Download artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| path: ${{ github.workspace }}/artifacts | |
| merge-multiple: true | |
| - name: Rename artifacts | |
| run: | | |
| mv ${{ github.workspace }}/artifacts/*.ipa ${{ github.workspace }}/Mapeak_signed_${{ needs.version.outputs.version_string }}.ipa | |
| mv ${{ github.workspace }}/artifacts/*.aab ${{ github.workspace }}/Mapeak_signed_${{ needs.version.outputs.version_string }}.aab | |
| mv ${{ github.workspace }}/artifacts/*.apk ${{ github.workspace }}/Mapeak_signed_${{ needs.version.outputs.version_string }}.apk | |
| - name: Rename and close milestone | |
| uses: octokit/request-action@v3.0.0 | |
| with: | |
| route: PATCH /repos/${{ github.repository }}/milestones/${{ needs.version.outputs.milestone_id }} | |
| title: Version ${{ needs.version.outputs.version_string }} | |
| state: closed | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Create new "Next Release" milestone | |
| uses: octokit/request-action@v3.0.0 | |
| with: | |
| route: POST /repos/${{ github.repository }}/milestones | |
| title: Next Release | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Create release | |
| uses: softprops/action-gh-release@v3 | |
| with: | |
| tag_name: v${{ needs.version.outputs.version_string }} | |
| name: v${{ needs.version.outputs.version_string }} | |
| body: | | |
| See [Milestone ${{ needs.version.outputs.version_string }}](https://github.com/${{ github.repository }}/milestone/${{ needs.version.outputs.milestone_id }}?closed=1) | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| files: | | |
| Mapeak_signed_${{ needs.version.outputs.version_string }}.ipa | |
| Mapeak_signed_${{ needs.version.outputs.version_string }}.aab | |
| Mapeak_signed_${{ needs.version.outputs.version_string }}.apk |