Get Jupyter Notebook diff with Github Actions
Tags: actionshackathon, github, jupyter, datascience
Published: 2020-09-18 02:12:44

[Instructions]: # (To submit to the GitHub Actions x DEV Hackathon, please fill out all sections.)

Hello everyone! I'm Canas and this is my first post on DEV, hopefully it can be useful for people working in Data Science and Machine Learning :)

---

One of the known challenges of working with notebooks is that version control is not ideal, with few tools available that actually deal with this. This motivated me to try and lessen the burden for some engineers that work with these files using Github Actions, leveraging on an existing open source tool called [ndime](https://github.com/jupyter/nbdime).

### My Workflow
[Note]: # (Make sure to include the name of your GitHub Action and share where it's being used!)
The general idea is to make the Github Action post a comment on the PR that contains the changes to any notebook with respect to the target branch.

We will use the following existing actions to accomplish this:
- `checkout@v2`, for fetching the code
- `actions/setup-python@v1`, for installing python
- `peter-evans/create-or-update-comment@v1`, to create a comment on the PR with `nbdiff`'s output.

### Submission Category: 

[Note]: # (Maintainer Must-Haves, DIY Deployments, Interesting IoT, Phone Friendly, or Wacky Wildcards)
I guess this would fall in **Maintainer Must-Haves**, since it will provide much better context when notebooks are submitted in a shared repository (e.g., for researching or persisting experiments).

### Yaml File or Link to Code

You can see a working implementation in [this repository](https://github.com/Canas/test-nbdiff-github-action/tree/change).
- [YAML file](https://github.com/Canas/test-nbdiff-github-action/blob/change/.github/workflows/nbdiff.yaml)
- [PR with GH Action comment](https://github.com/Canas/test-nbdiff-github-action/pull/3)

[Note]: # (Our markdown editor supports pretty embeds. Try this syntax: `{% github link_to_your_repo %}` to share a GitHub repository)
```yaml
name: Generate notebook diff

on: ["pull_request"]

jobs:
  check-diff:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
        with:
          fetch-depth: 0

      - name: Fetch target branch
        run: git fetch origin ${{ github.event.pull_request.base.ref }}:${{ github.event.pull_request.base.ref }}

      - name: Setup Python
        uses: actions/setup-python@v1
        with:
          python-version: "3.6"

      - name: Install requirements
        run: pip3 install nbdime

      - name: Run and store diff
        run: |
          nbdiff ${{ github.event.pull_request.base.ref }} --no-color > diff.log
          sed -i '1s/^/\`\`\`diff\n&/' diff.log
          sed -i '$s/$/\n&\`\`\`/' diff.log

      - name: Get comment body
        id: get-comment-body
        run: |
          body=$(cat diff.log)
          body="${body//'%'/'%25'}"
          body="${body//$'\n'/'%0A'}"
          body="${body//$'\r'/'%0D'}"
          echo ::set-output name=body::$body

      - name: Create comment
        uses: peter-evans/create-or-update-comment@v1
        with:
          issue-number: ${{ github.event.pull_request.number }}
          body: ${{ steps.get-comment-body.outputs.body }}

```

In simple terms, we use `nbdiff` to generate a file called `diff.log`. After that, we use `sed` to append and prepend the markdown enclosing characters. In the next step, we take `diff.log` and do additional replacements that ensure that the PR comment [will not truncate newlines](https://github.community/t/set-output-truncates-multiline-strings/16852/3), which are then stored in the `body` variable. Finally, we pass the `body` variable to the `create-or-update-comment` action which will take care of posting our formatted output in the PR.

{% github https://github.com/Canas/test-nbdiff %}
*Be sure to checkout to the `change` branch if you want to see the actual file!

### Additional Resources / Info
Actions used:
- [checkout@v2](https://github.com/actions/checkout)
- [actions/setup-python@v1](https://github.com/actions/setup-python)
- [peter-evans/create-or-update-comment@v1](https://github.com/marketplace/actions/create-or-update-comment)

Libraries used:
- [nbdime](https://github.com/jupyter/nbdime)

Possible future work:
- Test and benchmark on large size notebooks
- Look for a way to deploy the web version of nbdime, `nbdiff-web`

[Note]: # (Be sure to include the DEV usernames of your collaborators, if any. )

[Reminder]: # (Submissions are due on September 12th (11:59 PM PDT) and winners will be announced on September 23!)