GitHub Actions

They're Not Azure Pipelines

by JamesQMurphy | November 8, 2019

You know what the best thing about being wrong (and admitting to it) is? You usually learn a whole lot more than you would have, had you been right.

I was wrong about GitHub Actions being just "Azure Pipelines baked right into GitHub". In my defense, I jumped to that conclusion after hearing that parts of it were forked from Azure DevOps. But after attending Edward Thomson's presentation about GitHub Actions at Microsoft Ignite 2019, I learned a great deal about how GitHub Action started and how it evolved to what it is today.

Edward Thomson giving presentation at Microsoft Ignite 2019

GitHub Actions started off as an alternative to GitHub apps. The initial goal was to allow developers to extend GitHub, just like you can with GitHub Apps. But with GitHub Apps, you need to supply the services yourself (serverless or otherwise). GitHub Actions, on the other hand, run on GitHub's servers, meaning that you don't need to set up your own infrastructure. GitHub Actions was perfect for doing "the little things" to maintain a repo, such as sending a Code of Conduct to new contributors.

But according to Edward Thomson, as GitHub Actions took off, the demand for more horsepower became apparent. People wanted to do Continuous Integration/Continuous Deployment (CI/CD) under GitHub actions, and building things takes CPU cycles. Furthermore, there were cases where it wasn't just a matter of compute power. For example, to build anything Apple, you need to do it on a Macintosh (with XCode installed).

Enter GitHub Actions Version 2, with actual hosted agents (and containers). Like Azure Pipelines, you can run GitHub Actions on Linux, Windows, or MacOS agents.

The Challenge I Gave (And Accepted)

In my previous post I challenged myself to convert my existing Azure DevOps Pipeline into GitHub Actions. So how did that work out?

Overall, not too badly. I did setup a Continuous Integration (CI) action that successfully built the website when a commit was pushed to specific branches. Like its Azure DevOps Pipeline counterpart, it runs on an Ubuntu Linux image. Here's what worked:

  • Compiling The Application: The Action installs the Amazon.Lambda.Tools package first, then runs the dotnet-lambda tool to generate the Zip file.
  • Publishing The Artifact: This is a built-in GitHub Action located here.
  • Validating The Build Number: While I couldn't actually use the build number (more on that in a second), I could validate it using a slightly-modified version of my validate-build-against-branch.ps1 script, originally described in my post on build numbering.

Unfortunately, there were some differences that prevented me from completely switching over, at least in the span of a few days:

  • Build Numbers: GitHub Actions simply does not have the concept of build numbers. You can't even change the name of the Action. (I've got a crazy idea to try working around this using matrix builds, since the matrix value appears in the name of the build.)
  • No Build Variables: In GitHub Actions, there are no build variables per se. You can set environment variables, but only at the beginning of your Action, so you can't dynamically produce a value and pass it to future steps. However, custom GitHub Actions can have output values, so I could theoretically write a build number Action and use the output of the Action whenever I need it.

Here is my current YAML file that contains the build Action:

name: Trying GitHub Actions

on:
  push:
    branches: 
      - master
      - features/try-github-actions
      - features/try-github-actions-*

env:
  VERSION_MAJOR: 0
  VERSION_MINOR: 2
  VERSION_PATCH: 23
  JQM_COMPAREBRANCH: features/try-github-actions
  JQM_VERSIONFILE: .github/workflows/build.yml

jobs:
  build:
    env:
      BUILDCONFIGURATION: 'Release'
      JQM_PACKAGENAME: JamesQMurphy.Web.zip
      JQM_ARTIFACTFOLDER: a
      JQM_CLOUDFORMATIONFILENAME: '*.yaml'
      JQM_TOOLINSTALLDIR: build/bin

    runs-on: ubuntu-latest

    steps:
    - name: Checkout Action
      uses: actions/checkout@v1
      
    - name: Setup .NET Core
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: 2.2.108

    - name: Validate build version
      run: pwsh $GITHUB_WORKSPACE/.github/workflows/validate-build-against-branch.ps1

    - name: Install Amazon.Lambda.Tools
      run: dotnet tool install Amazon.Lambda.Tools --tool-path $JQM_TOOLINSTALLDIR

    - name: Run dotnet-lambda package
      run: ./dotnet-lambda package -c $BUILDCONFIGURATION -pl $GITHUB_WORKSPACE/src/JamesQMurphy.Web -o $GITHUB_WORKSPACE/$JQM_ARTIFACTFOLDER/$JQM_PACKAGENAME --msbuild-parameters "--self-contained true --runtime rhel-x64"
      working-directory: ${{ env.JQM_TOOLINSTALLDIR }}

    - name: Copy Cloudformation files
      run: cp -r deploy/$JQM_CLOUDFORMATIONFILE $GITHUB_WORKSPACE/$JQM_ARTIFACTFOLDER

    - name: Upload package 
      uses: actions/upload-artifact@master
      with:
        name: deploy
        path: ${{ env.JQM_ARTIFACTFOLDER }}

GitHub Is Not Azure DevOps, Either

In my last post, I also considered the roles of GitHub versus Azure DevOps, since they now share one more thing in common. But they do serve different purposes. GitHub is geared for Open Source projects, and from what I have been hearing here at Ignite, GitHub will (and must) remain neutral. It is not Azure DevOps, which is why you will only find the Azure tooling in the same place as all the other tooling -- right alongside AWS, Docker, and all the other third-party sites. Azure DevOps can promote the heck out of Microsoft Azure (which is probably why they renamed it in the first place), but GitHub is, always has been, and always will be a neutral place for open source projects.