Get changed files in github actions
Tags: githubactions, workflow, github, changes
Published: 2021-02-24 12:22:40

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](https://github.com/trilom/file-changes-action/blob/a6ca26c14274c33b15e6499323aac178af06ad4b/src/GithubHelper.ts#L127). 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](https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu2004-README.md) 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](https://github.com/actions/checkout).

#### 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](https://docs.github.com/en/free-pro-team@latest/actions/reference/context-and-expression-syntax-for-github-actions#contexts), 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](https://man7.org/linux/man-pages/man1/xargs.1.html): `COMMAND | xargs`.


#### Filter by filetype (optional)
To get changed files grouped by filetype we can also pipe [grep](https://man7.org/linux/man-pages/man1/grep.1.html) 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](https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions#jobsjob_idoutputs). Here is a full workflow example.
```yaml
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}}
    
```