GitHub Automation with Mint

Before implementing a GitHub Automation workflow, see the getting started guide.

In this guide, you will set up a private GitHub App to automate the process of performing a routine code update and creating or updating a pull request.

GitHub Automation can be combined with cron schedules to automate tasks like dependency updates.

Set up GitHub App

During initial setup, you've already installed the Mint GitHub App.

To update code and open a pull request, you will create a new, private GitHub App owned by your GitHub organization or user, then give it additional permissions. In Mint, all private GitHub Apps are added to a vault to control access to its elevated permissions.

To begin, go to Vaults and select or create the vault to contain the private GitHub App. Select GitHub Apps and Add GitHub App.

Enter the GitHub organization slug or select that you'd like to create the app in your personal GitHub account. A private GitHub app can only be installed by its owner and won't be available to other organizations (GitHub or Mint).

You'll be sent to GitHub to complete creation of the app. Enter an app name, which must be globally unique, and Continue.

Once returned to Mint, select the three-dot menu for your new GitHub App and Manage App then Permissions and Events to add necessary permissions.

For this guide, expand Repository permissions and change:

  • Contents: Read and write to allow pushing updates to branches
  • Pull requests: Read and write to allow creating new pull requests

Return to the Mint vault with your GitHub App, select the three-dot menu and Install. Once you accept the installation on GitHub, you'll return to Mint and see the app is now installed. Remember to select repositories for which this app should have access.

Capture the vault name and GitHub App Slug for use in the next step.

Shared Mint run configuration

In this example, we're going to assume the following:

  • Vault name is YOUR_VAULT
  • GitHub App Slug is YOUR-GITHUB-APP-SLUG
  • GitHub repository is at https://github.com/YOUR-ORG/YOUR-REPO.git

Open a pull request

With the assumptions made in Shared Mint run configuration, let's make a very simple workflow that opens a new GitHub pull request.

Create a new Mint configuration at .mint/update-timestamp.yml with the contents:

tasks:
  - key: github-cli
    call: github/install-cli 1.0.0

  - key: code
    call: mint/git-clone 1.2.2
    with:
      repository: https://github.com/YOUR-ORG/YOUR-REPO.git
      ref: ${{ init.commit-sha }}
      preserve-git-dir: true
      github-access-token: ${{ vaults.YOUR_VAULT.github-apps.YOUR-GITHUB-APP-SLUG.token }}

  - key: update-code
    use: code
    cache: false
    run: |
      git checkout -b "update-timestamp-$(date +%s)"
      date -Iseconds > timestamp.txt
      git add timestamp.txt
      git commit -m "Update timestamp."
      git push -u origin "$(git rev-parse --abbrev-ref HEAD)"
    env:
      GITHUB_TOKEN: ${{ vaults.YOUR_VAULT.github-apps.YOUR-GITHUB-APP-SLUG.token }}

  - key: create-pr
    use: [github-cli, update-code]
    run: gh pr create --fill
    env:
      GITHUB_TOKEN: ${{ vaults.YOUR_VAULT.github-apps.YOUR-GITHUB-APP-SLUG.token }}

On every run, we'll create a new branch, update timestamp.txt, and open a pull request.

Test this configuration from your local machine with:

mint run --file .mint/update-timestamp.yml --init commit-sha=main

Update or open a pull request

With the assumptions made in Shared Mint run configuration, let's make a workflow that can update an existing pull request, or create a pull request if one doesn't exist. We'll filter so we only update a pull request created by your private GitHub App.

In this example, the Mint configuration will:

  • Update a file with the latest 4-week U.S. Treasury Bill auction result
  • If there are new results and there is no open pull request created by this app, open a new pull request
  • If there are new results and there is an open pull request created by this app, push a new commit to the pull request branch
  • Otherwise, do nothing

Create a new Mint configuration at .mint/update-auction.yml with the contents:

tasks:
  - key: jq
    run: |
      sudo apt-get update
      sudo apt-get install jq
      sudo apt-get clean

  - key: github-cli
    call: github/install-cli 1.0.0

  - key: code
    call: mint/git-clone 1.2.2
    with:
      repository: https://github.com/YOUR-ORG/YOUR-REPO.git
      ref: ${{ init.commit-sha }}
      preserve-git-dir: true
      github-access-token: ${{ vaults.YOUR_VAULT.github-apps.YOUR-GITHUB-APP-SLUG.token }}

  - key: update-code
    use: [jq, github-cli, code]
    cache: false
    run: |
      # Capture the last open pull request made by this app in this repository.
      # The gh cli will detect the current repository and automatically filter to it.
      # Checkout its branch or create a new one.
      pr_number="$(gh pr list --author '@me' --json number --jq 'max_by(.number) | .number')"
      printf "$pr_number" > "$MINT_VALUES/existing-pr"
      if [ -n "$pr_number" ]; then
        gh pr checkout "$pr_number"
      else
        git checkout -b "update-auction-results-$(date +%s)"
      fi

      # Download the latest auction results.
      treasury_url="https://api.fiscaldata.treasury.gov/services/api/fiscal_service/v1/accounting/od/auctions_query?fields=auction_date,high_investment_rate,cusip&filter=security_term:eq:4-Week,auction_date:gte:$(date -d '-28 days' -I),auction_date:lte:$(date -I)"
      curl "$treasury_url" | jq '.data | max_by(.auction_date)' > 4-week.json

      # Commit and push changes.
      if [ -n "$(git status --porcelain)" ]; then
        printf "true" > "$MINT_VALUES/has-changes"
        git add 4-week.json
        git commit -m "Update Treasury auction results."
        git push -u origin "$(git rev-parse --abbrev-ref HEAD)"
      else
        printf "false" > "$MINT_VALUES/has-changes"
      fi
    outputs:
      values: [existing-pr, has-changes]
    env:
      GITHUB_TOKEN: ${{ vaults.YOUR_VAULT.github-apps.YOUR-GITHUB-APP-SLUG.token }}

  - key: create-pr
    use: update-code
    if: ${{ tasks.update-code.values.has-changes == "true" && tasks.update-code.values.existing-pr == "" }}
    run: gh pr create --fill
    env:
      GITHUB_TOKEN: ${{ vaults.YOUR_VAULT.github-apps.YOUR-GITHUB-APP-SLUG.token }}

If an open pull request created by your private GitHub App was found, pushing to its branch will update the pull request. Otherwise, we'll conditionally run create-pr to open a new pull request using an if condition.

Test this configuration from your local machine with:

mint run --file .mint/update-auction.yml --init commit-sha=main

Comment on a pull request

In this example, we'll create a workflow that runs when pull requests are opened or updated, calculate the approximate working directory size on disk, and output its results in pull request comment.

An on event trigger is included, but that only applies when this Mint configuration has been pushed into your default GitHub branch. We'll just manually run this.

Create a new Mint configuration at .mint/pull-request-size.yml with the contents:

on:
  github:
    pull_request:
      init:
        commit-sha: ${{ event.github.pull_request.pull_request.head.sha }}
        pr-number: ${{ event.github.pull_request.number }}

tasks:
  - key: github-cli
    call: github/install-cli 1.0.0

  - key: code
    call: mint/git-clone 1.2.2
    with:
      repository: https://github.com/YOUR-ORG/YOUR-REPO.git
      ref: ${{ init.commit-sha }}
      preserve-git-dir: true
      github-access-token: ${{ vaults.YOUR_VAULT.github-apps.YOUR-GITHUB-APP-SLUG.token }}

  - key: pr-comment
    use: [github-cli, code]
    run: |
      wd_size="$(du -sh --apparent-size --exclude=.git | awk '{ print $1 }')"
      message="The working directory size is now: $wd_size"

      # The gh cli doesn't support edit-or-create for comments.
      gh pr comment "$PR_NUMBER" --edit-last --body "$message" \
        || gh pr comment "$PR_NUMBER" --body "$message" \
    env:
      GITHUB_TOKEN: ${{ vaults.YOUR_VAULT.github-apps.YOUR-GITHUB-APP-SLUG.token }}
      PR_NUMBER: ${{ init.pr-number }}

We can exercise it locally by manually creating a pull request in this repository and running the workflow with init parameters.

We'll assume the pull request branch name is MY-BRANCH and its number is 98765:

mint run --file .mint/pull-request-size.yml --init commit-sha=MY-BRANCH --init pr-number=98765