In the search of a proper way to lint our pull request (changes only). I came across some Github Actions that all require you to share your Github token. With some knowledge of git I immediately thought, why not solve this with git diff
and some shell commands, thus without the use of a Github token. Git is present by default in the action containers anyway. Eventually I came up with the following solution. All this requires is a checkout of the codebase, with a step provided by github itself: actions/checkout@v2.
Get the commit-sha's to compare
In order to get the commit sha that the pull request was based off, we can use the Github's context, available in all actions. Here we have acces to github.event.pull_request.base.sha
and github.sha
.
Only include files that are still present
To only get the files that are changed and still present we can add the argument --diff-filter=ACMRT
. This will only return files that are added, copied, modified, renamed or changed. In order to get the filenames only we also add --name-only
.
Remove newlines
In order to get the output in a single line, without newlines, we can pipe the output to xargs: COMMAND | xargs
.
Filter by filetype (optional)
To get changed files grouped by filetype we can also pipe grep using a regex as such: COMMAND | grep .ts$
.
The finished command
Combining these arguments, we get something like this:
git diff --name-only --diff-filter=ACMRT ${{ github.event.pull_request.base.sha }} ${{ github.sha }} | grep .css$ | xargs
.
Using the changed files in an actions workflow
To be able to use the files in another job, we have to use outputs. Here is a full workflow example.
jobs:
changedfiles:
runs-on: ubuntu-latest
# Map a step output to a job output
outputs:
all: ${{ steps.changes.outputs.all}}
ts: ${{ steps.changes.outputs.ts }}
steps:
# Make sure we have some code to diff.
- name: Checkout repository
uses: actions/checkout@v2
- name: Get changed files
id: changes
# Set outputs using the command.
run: |
echo "::set-output name=all::$(git diff --name-only --diff-filter=ACMRT ${{ github.event.pull_request.base.sha }} ${{ github.sha }} | xargs)"
echo "::set-output name=ts::$(git diff --name-only --diff-filter=ACMRT ${{ github.event.pull_request.base.sha }} ${{ github.sha }} | grep .ts$ | xargs)"
lint:
runs-on: ubuntu-latest
# require the first job to have ran
needs: changedfiles
# only run there are changed files
if: ${{needs.changedfiles.outputs.ts}}
steps:
- name: echo changed files
run: echo ${{needs.changedfiles.outputs.ts}}
Top comments (6)
When I try that, I always get:
That sha is the
github.event.pull_request.base.sha
thing.It's because you fetch only latest commit. You can solve this issue by setting
fetch-depth
to 0 to retrieve full git history.To elaborate on Anton Orlov's answer regarding
fetch-depth
.To have
git
diff the current HEAD (depth:1) against the previous commit (depth:2), then one needs to have at leastfetch-depth: 2
, and if one wants to diff against deeper history one must set the depth accordingly. Many git work flows only fetch adepth:1
as an optimization, to avoid expensive IO copying entire repos when only the single commit is needed.Is there a version of this that will work when you just run a push? For example, if you push straight into master it'll simply compare the current revision to the last one? I imagine you'd have to replace
github.event.pull_request.base.sha
and maybegithub.sha
, but for the life of me I don't know what to replace them with.I'm getting error as
Run echo "::set-output name=all::$(git diff --name-only --diff-filter=ACMRT 91d2a5a7769c5ba847074bf19683a938f9135ab7 a0827f508c826ff2e55274efa0d8b860b46398f9 | xargs)"
shell: /bin/bash -e {0}
error: Could not access '91d2a5a7769c5ba847074bf19683a938f9135ab7'
error: Could not access '91d2a5a7769c5ba847074bf19683a938f9135ab7'
I had this same error and I resolved it by updating the git version. You need git version 2.something on your runner. If you are running centos7 then the yum repo gives you version 1.something so you will have to install git from source. See: computingforgeeks.com/how-to-insta...
Even if your runner isnt running centos7, the solution will likely be installing the latest version of git on the runner.