Github Workflow for Electron React Boilerplate with Auto Updates

Github Actions Electron React Boilerplate Workflow

Electron React Boilerplate is a great template repository for getting started with an Electron application. This article includes a Github workflow for packaging this application automatically and distribution via the auto update mechanism in electron-builder.

I had some trouble getting a release and packaging workflow going. This post contains an end to end workflow for bumping version numbers, generating change logs and packaging your application for all desktop platforms.

It is based on the workflow implemented by Zettlr and adapted for ERB.

Github Actions Workflow for Electron React Boilerplate project

Github Workflow for Electron React Boilerplate

.github/workflows/master.yml

name: Build

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# RATIONALE BEHIND THIS HUGE WORKFLOW
#
# GitHub Actions runs everything in a sandboxed VM, and we need to build
# each asset on its "home" operating system, both because macOS code
# signing, e.g., doesn't work on other platforms. Additionally, this way
# we don't need WINE and, if necessary at some point, can build any
# native dependencies.
#
# This workflow tries to use as few hacks and monkey patches as possible
# to perform the same workflow as the ./scripts/make.sh-file. Therefore
# we ONLY build the corresponding release on the build-VMs, and then
# upload the resulting artifact to the Workflow.
#
# After all artifacts from the three VMs have been successfully uploaded
# to the workflow run, we then download all of them on a fourth VM, where
# we generate the checksums, verify the integrity and finally create a
# new release draft where we upload everything in one step.
#
# Benefits: Native environments without the need to upload useless
# stuff to foreign places (data scarcity, DRY).
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# Only when we push to master, as this indicates a build
on:
  push:
    branches:
      - master

# We need two jobs: First a build-job, running on a matrix
# to build all necessary releases, which also uploads all
# resulting assets to the workflow. And then, we download
# them onto a separate VM running the release-job to verify
# the checksums and create a draft release.
jobs:
  release_management:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v1
      - name: Setting up Node
        uses: actions/setup-node@v1
        with:
          node-version: '10.15.1'
      - name: Preparing release
        run: |
          git config --local user.email "action@github.com"
          git config --local user.name "GitHub Action"
          pushd ./app
            npx standard-version -a --no-verify --prerelease alpha --skip.commit --skip.tag --skip.changelog
            echo ::set-env name=PACKAGE_VERSION::$(node -p -e "require('./package.json').version")
          popd
          npx standard-version -a --no-verify --prerelease alpha --skip.commit --skip.tag
        env:
          CI: true
      # - name: Push to master
      #   uses: ad-m/github-push-action@v0.5.0
      #   with:
      #     github_token: $
      # - name: Merge back to develop
      #   uses: ad-m/github-push-action@v0.5.0
      #   with:
      #     github_token: $
      #     branch: develop
  build:
    needs: [release_management]

    # The build job needs to be built on Win, Linux, and macOS
    # Win32 --> build NSIS
    # macOS --> build DMG
    # Linux --> build DEB, RPM, and AppImage
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]

    # Define the operating system
    runs-on: $

    steps:
      # Clone the repository
      - uses: actions/checkout@v2
      # Setup node
      - name: Setup NodeJS 12.x
        uses: actions/setup-node@v1
        with:
          node-version: '10.15.0'

      # Save the current package.json's version value
      # as the output from this step so that we can
      # reference it later on.
      - name: Emit pkgver
        id: pkg
        run: |
          appver=$(node -p -e "require('./app/package.json').version")
          pkgver=$(node -p -e "require('./package.json').version")
          echo ::set-output name=version::$appver
          echo ::set-output name=package_version::$pkgver
        shell: bash
      # On Windows server, we have to create the handlebars-directory
      # manually, because the node-process always crashes when it
      # attempts literally the same thing.
      - name: Manually create the handlebars-directory (Windows only)
        if: matrix.os == 'windows-latest'
        run: New-Item -Path "./source/common/assets" -Name "handlebars" -ItemType "directory" # Hello, PowerShell ._.

      # Perform all necessary pre-build steps (LESS, handlebars, and so forth)
      - name: Set up build environment and compile the assets
        run: |
          npm install
          yarn
      # Now we're set to finally release the beast!
      # WINDOWS ==============================================================
      - name: Build Windows Installer
        if: matrix.os == 'windows-latest' # Only if the job runs on Windows
        run: yarn package-win
      - name: Cache Windows Exe release
        if: matrix.os == 'windows-latest' # Only if the job runs on Windows
        uses: actions/upload-artifact@v1
        with:
          name: Notorious-$.exe
          path: ./release/Notorious Setup $.exe
      - name: Cache Windows MSI release
        if: matrix.os == 'windows-latest' # Only if the job runs on Windows
        uses: actions/upload-artifact@v1
        with:
          name: Notorious-$.msi
          path: ./release/Notorious $.msi
      # MACOS ================================================================
      # - name: Build macOS DMG file
      #   if: matrix.os == 'macos-latest' # Only if the job runs on macOS
      #   run: APPLE_ID=$ APPLE_ID_PASS=$ CSC_LINK=$  CSC_KEY_PASSWORD=$ npm run release:mac
      # - name: Cache macOS release
      #   if: matrix.os == 'macos-latest' # Only if the job runs on macOS
      #   uses: actions/upload-artifact@v1
      #   with:
      #     name: Notorious-$.dmg
      #     path: ./release/Notorious-$.dmg
      # LINUX ================================================================
      - name: Build Linux targets
        if: matrix.os == 'ubuntu-latest'
        run: yarn package-linux
      - name: Cache Linux Debian release
        if: matrix.os == 'ubuntu-latest'
        uses: actions/upload-artifact@v1
        with:
          name: Notorious-$-amd64.deb
          path: ./release/notorious_$_amd64.deb
      - name: Cache Linux Fedora release
        if: matrix.os == 'ubuntu-latest'
        uses: actions/upload-artifact@v1
        with:
          name: Notorious-$-x86_64.rpm
          path: ./release/notorious-$.x86_64.rpm
      - name: Cache Linux AppImage (x32) release
        if: matrix.os == 'ubuntu-latest'
        uses: actions/upload-artifact@v1
        with:
          name: Notorious-$-i386.AppImage
          path: ./release/Notorious-$.AppImage
      # - name: Cache Linux AppImage (x64) release
      #   if: matrix.os == 'ubuntu-latest'
      #   uses: actions/upload-artifact@v1
      #   with:
      #     name: Notorious-$-x86_64.AppImage
      #     path: ./release/Notorious-$.x86_64.AppImage


  # As soon as the build matrix has completed correctly, this job will
  # commence, creating a new draft release, downloading all assets from
  # the previous job, verifying the checksum integrity, and uploading that
  # whole mess to the draft release.
  prepare_release:
    needs: [build] # Make sure (and wait until) the build has succeeded
    runs-on: ubuntu-latest
    steps:
      # Clone the repository to get the ./scripts/get-pkg-version.js and the ./package.json
      - uses: actions/checkout@v2
      # Setup node to run the retrieval script
      - name: Setup NodeJS 12.x
        uses: actions/setup-node@v1
        with:
          node-version: '10.15.0'
      - name: Retrieve the current package version
        id: pkg
        run: |
          pkgver=$(node -p -e "require('./app/package.json').version")

          echo ::set-output name=version::$pkgver
      # Now, download all resulting assets from the previous steps.
      - name: Download the Windows asset
        uses: actions/download-artifact@v1
        with:
          name: Notorious-$.exe
          path: .
      # - name: Download the macOS asset
      #   uses: actions/download-artifact@v1
      #   with:
      #     name: Notorious-$.dmg
      #     path: .
      - name: Download the Debian asset
        uses: actions/download-artifact@v1
        with:
          name: Notorious-$-amd64.deb
          path: .
      - name: Download the Fedora asset
        uses: actions/download-artifact@v1
        with:
          name: Notorious-$-x86_64.rpm
          path: .
      - name: Download the AppImage (x32) asset
        uses: actions/download-artifact@v1
        with:
          name: Notorious-$-i386.AppImage
          path: .
      # - name: Download the AppImage (x64) asset
      #   uses: actions/download-artifact@v1
      #   with:
      #     name: Notorious-$-x86_64.AppImage
      #     path: .
      # Now we are set, we have all five release assets on the VM. It's time to create the
      # SHA-checksums file and then upload everything!
      - name: Generate SHA256 checksums
        run: |
          ls -la
          sha256sum "Notorious Setup $.exe" > "SHA256SUMS.txt"
          # sha256sum "Notorious-$.dmg" >> "SHA256SUMS.txt"
          sha256sum "notorious_$_amd64.deb" >> "SHA256SUMS.txt"
          sha256sum "notorious-$.x86_64.rpm" >> "SHA256SUMS.txt"
          sha256sum "Notorious-$.AppImage" >> "SHA256SUMS.txt"

        # sha256sum "Notorious-$-x86_64.AppImage" >> "SHA256SUMS.txt"
      - name: Verify checksums
        run: |
          ls -la
          sha256sum -c SHA256SUMS.txt
      # Create a new release draft
      - name: Create a new release draft
        id: create_release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: $
        with:
          tag_name: v$ # tag_name is required, but can be overridden during edit
          release_name: Release v$ # release_name is required
          body: If you can read this, we have forgotten to fill in the changelog. Sorry!
          draft: true # Always create as draft, so that we can populate the remaining values easily


      # And finally, upload that shit
      - name: Upload Windows asset
        uses: actions/upload-release-asset@v1.0.1
        env:
          GITHUB_TOKEN: $
        with:
          upload_url: $
          asset_path: ./Notorious Setup $.exe
          asset_name: Notorious-$.exe
          asset_content_type: application/x-msdownload


      # - name: Upload macOS asset
      #   uses: actions/upload-release-asset@v1.0.1
      #   env:
      #     GITHUB_TOKEN: $
      #   with:
      #     upload_url: $
      #     asset_path: ./Notorious-$.dmg
      #     asset_name: Notorious-$.dmg
      #     asset_content_type: application/octet-stream


      - name: Upload Debian asset
        uses: actions/upload-release-asset@v1.0.1
        env:
          GITHUB_TOKEN: $
        with:
          upload_url: $
          asset_path: ./notorious_$_amd64.deb
          asset_name: Notorious-$-amd64.deb
          asset_content_type: application/octet-stream


      - name: Upload Fedora asset
        uses: actions/upload-release-asset@v1.0.1
        env:
          GITHUB_TOKEN: $
        with:
          upload_url: $
          asset_path: ./notorious-$.x86_64.rpm
          asset_name: Notorious-$-x86_64.rpm
          asset_content_type: application/octet-stream


      - name: Upload AppImage (x32) asset
        uses: actions/upload-release-asset@v1.0.1
        env:
          GITHUB_TOKEN: $
        with:
          upload_url: $
          asset_path: ./Notorious-$.AppImage
          asset_name: Notorious-$-i386.AppImage
          asset_content_type: application/octet-stream


      # - name: Upload AppImage (x64) asset
      #   uses: actions/upload-release-asset@v1.0.1
      #   env:
      #     GITHUB_TOKEN: $
      #   with:
      #     upload_url: $
      #     asset_path: ./Notorious-$-x86_64.AppImage
      #     asset_name: Notorious-$-x86_64.AppImage
      #     asset_content_type: application/octet-stream

      - name: Upload the checksums
        uses: actions/upload-release-asset@v1.0.1
        env:
          GITHUB_TOKEN: $
        with:
          upload_url: $
          asset_path: ./SHA256SUMS.txt
          asset_name: SHA256SUMS.txt
          asset_content_type: text/plain

Conclusion

If you found this article useful, please also check out this workflow for releasing python based Home Assistant components.

Related posts

How to Optimize Docker Builds with Nexus OSS for Apt, Maven, Docker and NPM Dependencies

Docker could not find an available, non-overlapping IP address pool

Fully Automated Github Workflow for Home Assistant components

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Read More