Skip to content
Nowlark
Guides menu

Approve a GitHub deploy from your iPhone

Your workflow pauses before production and asks on your iPhone. Approve and it deploys; deny or ignore it and nothing ships.

N
DEPLOY · nowDeploy acme/shop to production?3f2c9a1 by sam
ApproveDeny
The workflow waits for your tap. Approve needs your iPhone unlocked; Deny does not.

What you need#

  • Nowlark on your iPhone, and your key from Settings › Connect an App › Create Your Key. Copy it when it is shown, because it is shown once. It starts nlk_.
  • A GitHub repository that uses GitHub Actions. The question is one job with curl and jq, no marketplace action.

1. Store your key as a secret#

In the repository, open Settings, then Secrets and variables › Actions, and click New repository secret. Set Name to NOWLARK_API_KEY, paste your key into Secret, and click Add secret.

2. Add the approval job#

Save this as .github/workflows/deploy.yml, put your own deploy steps in the deploy job, and commit it to your default branch:

name: Deploy
on:
  workflow_dispatch:

jobs:
  approve:
    runs-on: ubuntu-latest
    timeout-minutes: 35
    steps:
      - name: Ask on my iPhone
        env:
          NOWLARK_API_KEY: ${{ secrets.NOWLARK_API_KEY }}
        run: |
          body=$(jq -n --arg repo "${{ github.repository }}" \
                       --arg sha "${{ github.sha }}" --arg who "${{ github.actor }}" \
            '{source:"Deploy", title:"Deploy \($repo) to production?",
              body:"\($sha[0:7]) by \($who)", priority:1,
              replies:"approve_deny", reply_within:1800}')
          id=$(curl -sf https://nowlark.com/v1/notify \
            -H "Authorization: Bearer $NOWLARK_API_KEY" \
            -H "Content-Type: application/json" -d "$body" | jq -r .id)
          while true; do
            r=$(curl -sf "https://nowlark.com/v1/receipts/$id" \
              -H "Authorization: Bearer $NOWLARK_API_KEY") || { sleep 10; continue; }
            case $(jq -r .reply_state <<<"$r") in
              answered) [ "$(jq -r .reply <<<"$r")" = approve ] && exit 0
                        echo "Denied on the phone"; exit 1 ;;
              expired)  echo "Nobody answered in 30 minutes"; exit 1 ;;
            esac
            sleep 10
          done

  deploy:
    needs: approve
    runs-on: ubuntu-latest
    steps:
      - run: echo "Deploying"   # your deploy steps go here

The approve job sends the question and then checks every 10 seconds for your answer, trying again if a check does not get through. The deploy job only starts when the answer is Approve.

3. Run it#

Open the Actions tab, choose Deploy, and click Run workflow. Within seconds your iPhone shows the question. Press and hold it to see Approve and Deny.

You The workflow
Tap Approve
The approve job succeeds and the deploy job runs.
Tap Deny
The run fails with "Denied on the phone". Nothing is deployed.
Do nothing for 30 minutes
The run fails with "Nobody answered in 30 minutes". Nothing is deployed.

The first answer counts, so a second tap from another device cannot change it.

Good to know#

  • While it waits, the approve job is a running job, so a question left unanswered for the full 30 minutes uses 30 minutes of Actions time. Shorten it by lowering reply_within (in seconds) and timeout-minutes together.
  • Replies covers the other answer sets (Yes and No, and a Later button) and how a server can get the answer as a signed callback instead of asking for it.

Get Nowlark free