Quick tip: Get in control by using your GitHub context
GitHib actions and workflows are very powerful by nature. They help me to build and deploy my Azure environments, without having me to do all the tedious and errorprone work. I create a pull request, have it peer reviewed and once approved my environments are provisoned the way I envisioned it. This is also the case at my current assignment for a large organization. Last year the organization decided that a new change management system (which name I refuse to pronounce) should handle all changes. This means that every step in the process needs to be documented and approved conform ITIL processes.
This collides with all DevOps principles in which teams are responsible for building and running their own code. Instead we are warped back into time, back to release calendars, back to a situation in which organizations release code a couple of times per year. While in the DevOps world we do many releases per day. *sigh*
Anyway it is the status quo and we have to comply. Engineers wouldn’t be engineers if they wouldn’t try to find a way to automate the hack out of it, thus finding a way to create automated changes, risk assessments and approvals.
As we are working with GitHub workflows, we set up a way of working in which we build our specific code in branches, create pull requests and have the code merged back to the main branch. We have triggers on the workflows that ensure that the code gets validated, built and deployed at every push and pull request.
This means that each time the code gets merged back to main, a new release is created. In case of a specific label applied on the pull request we want to trigger an specific action that handles the change management proces. For this example I created the label “test”.
This is where the GitHub context comes in handy.
Github context
In a GitHub workflow, you can use variables and objects of all sorts. One of those objects is the GitHub context, that you can call by using $github. The Github context is a rich object that contains all information on the Pull Request, Workflow etc. You can check out the context by echoing it to the display while running the workflow. To see the actual contents you need to convert it to a Json representation, such as in the code below.
jobs:
draft_release:
name: Create draft release
runs-on: ubuntu-latest
steps:
- name: Create draft release and label PR
id: create_draft
...
- name: dump context
run: echo '${{ toJSON(github.event.pull_request) }}'
Atter running the specific job, you can check the contents of the context.
In our case we are interested to find all labels attached to the Pull Request. Looking through the Json, I find a labels array, containing multiple labels. To show them I alter my code in the workflow and run it again.
jobs:
draft_release:
name: Create draft release
runs-on: ubuntu-latest
steps:
- name: Create draft release and label PR
id: create_draft
...
- name: dump context
run: echo '${{ toJSON(github.event.pull_request.labels.*.name) }}'
Get into control
Now that I can access the labels (or other fields), I can do what I want to do! In my case I want to execute an action only if a particular label is set.
I extend the code in my workflow by placing an if
condition on a step. In this condition I check if the labels array contains the “test” label.
jobs:
draft_release:
name: Create draft release
runs-on: ubuntu-latest
steps:
- name: Create draft release and label PR
id: create_draft
...
- name: dump context
...
- name: Do my check
if: ${{ contains(github.event.issue.labels.*.name, 'test' ) }}
run: echo "Hello world!"
I run the workflow again, and see that the action gets executed.
I change the condition to check for a label that doesn’t exist. And run the workflow again… This time, the action is skipped.
jobs:
draft_release:
name: Create draft release
runs-on: ubuntu-latest
steps:
- name: Create draft release and label PR
id: create_draft
...
- name: dump context
run: echo '${{ toJSON(github.event.pull_request) }}'
- name: Do my check
if: ${{ contains(github.event.issue.labels.*.name, 'another test' ) }}
run: echo "Nothing to see... move on!"
Such simple mechanism, though so powerful. By working with the context, I gained super powers when it comes to controlling my workflow.
Happy times ahead!