17

I'm using Nx for monorepo support on a new project. One of the benefits of Nx is that it can determine which apps in the monorepo are affected by a range of changes (start commit, end commit). So if you have a bunch of apps, you only have to build, test, and deploy the apps that are actually affected by the changes instead of the entire monorepo.

I'd like to setup a GitHub Action workflow to deploy only the affected apps on push or merge to master. However, I'm having trouble figuring out how to get the "start commit" for the range of changes. In other words, how do I get the commit hash of the last deploy?

GitHub provides an env variable GITHUB_SHA but that's the commit that triggered the workflow (i.e. the "end commit"). It also provides GITHUB_BASE_REF but that only works on workflows running from a forked repo comparing to the head repo.

CircleCI has pipeline.git.base_revision for this purpose. Do GitHub Actions have something similar?

Rich McCluskey
  • 1,871
  • 2
  • 18
  • 30

2 Answers2

37

For pull request events the ref and sha for the base can be found in the github context as follows.

${{ github.event.pull_request.base.ref }}
${{ github.event.pull_request.base.sha }}

For push events there are base_ref and before parameters.

${{ github.event.base_ref }}
${{ github.event.before }}

before is the last git sha pushed to origin on branch base_ref. Note that if this is the first commit on a new branch, base_ref and before will have null/default values as shown below.

##[debug]  "event": {
##[debug]    "after": "727f7aec97c394083d769029e5f619e9b094a235",
##[debug]    "base_ref": null,
##[debug]    "before": "0000000000000000000000000000000000000000",
...

By the way, you can dump the github context and check the available parameters by adding this step to your workflow:

      - name: Dump GitHub context
        env:
          GITHUB_CONTEXT: ${{ toJson(github) }}
        run: echo "$GITHUB_CONTEXT"
peterevans
  • 34,297
  • 7
  • 84
  • 83
  • 1
    Thanks for the helpful tip about dumping the github context! I tried that out and interestingly it had a value for `github.event.before` on push to master. I even tried pushing two commits at once and the before value was correct. Not sure why that didn't work for you but this is exactly what I was looking for! – Rich McCluskey May 18 '20 at 04:21
  • @RichMcCluskey Glad you found a solution. Not sure why `before` didn't have a value when I tested. I've updated the answer slightly for anyone finding this in future. – peterevans May 18 '20 at 05:24
  • 1
    Follow up... I noticed that the first push of a new branch will be missing the `before` commit as shown in your example. I guess that makes sense since the branch is new and didn't exist before. In that case I can just compare against master to find the range of commits. – Rich McCluskey May 18 '20 at 16:47
  • I'm trying to do a git diff and grep files to see if a particular file/folder is in list of changed files. I configured `GITHUB_PUSH_AFTER: ${{ github.event.after }}` and `GITHUB_PUSH_BEFORE: ${{ github.event.before }}` as env variables and used them `git diff --name-only $GITHUB_PUSH_BEFORE $GITHUB_PUSH_AFTER | grep -E package.json`. But it throws `fatal: bad object 85f59cd997ddeab6d808e215863e30bd30d081a5`. `85f59c...` is value in `GITHUB_PUSH_BEFORE`. Tried the same values in my local machine and they worked out well – Rohit Reddy Abbadi May 29 '20 at 03:06
  • 1
    @RohitReddyAbbadi I think by default GitHub workflows only partially clone the repo at the HEAD commit, so you might have to do a fetch first in your workflow – Rich McCluskey Jun 03 '20 at 17:43
  • 3
    @RohitReddyAbbadi Try adding `fetch-depth: 0` to `actions/checkout`. That fetches all history for tags and branches. See [here](https://github.com/actions/checkout#fetch-all-history-for-all-tags-and-branches) – peterevans Jun 03 '20 at 23:00
  • Thanks for your tip, can you also tell how to detect pushing a new branch to origin properly? it feels not right to me to use `if` with `base_ref == null` or `before == 000000000...0`. – Alan Zhang Jan 17 '22 at 06:30
  • adding `fetch-depth: 0` was important for me. Without it I kept getting an invalid revision when trying to interact with the commit. – j3ko Apr 25 '23 at 08:56
-1

GitHub provides GITHUB_BASE_REF and the github.base_ref context that contain the base branch.

If you're interested in the latest revision of that branch, you can run git rev-parse $GITHUB_BASE_REF to find it. If you're interested in the point at which the branches forked, you can run git merge-base $GITHUB_BASE_REF $GITHUB_SHA to find it.

Do note that it's possible to break other projects with incompatible API changes and such without making any code changes to them, so while it will be faster to test only the apps that have changed, you may find that doing so will result in unexpected breakage.

bk2204
  • 64,793
  • 6
  • 84
  • 100
  • FYI, Nx determines which projects to rebuild by understanding dependencies imported to them, and by configuration to say what depends on what if there's no direct code import. It's not just based on where the changes are :) – Rich McCluskey May 18 '20 at 02:02
  • 3
    Unfortunately this answer doesn't work. The docs say that `GITHUB_BASE_REF` and `github.base_ref` are only set for forked repositories. Mine isn't forked. I also tested it and verified the docs are correct. – Rich McCluskey May 18 '20 at 02:18