Skip to content

Instantly share code, notes, and snippets.

@hopsoft
Last active August 8, 2022 20:13
Show Gist options
  • Save hopsoft/a63658a764ac04953fb91723c85d8139 to your computer and use it in GitHub Desktop.
Save hopsoft/a63658a764ac04953fb91723c85d8139 to your computer and use it in GitHub Desktop.
Heroku Review Apps managed by GitHub Actions

Heroku Review Apps managed by GitHub Actions

This gist aims to provide a simple solution for managing Heroku Review Apps with GitHub Actions due to the security incident that continues to disrupt Heroku's GitHub integration.

.github
├── workflows
│   ├── heroku_review_app_create.yml
│   └── heroku_review_app_destroy.yml

Triggers

  • Pull Request opened - create/update review app
  • Pull Request reopened - create/update review app
  • Pull Request synchronize (push) - update review app
  • Pull Request closed - destroy review app

Dependencies

Create/Update Heroku Review App

Creates a Heroku Review App on PR open or reopen, also updates the Review App on any push to the PR

.github/workflows/heroku_review_app_create.yml

Steps

  1. Set dynamic env vars - Allows us to reuse/compose global env vars
  2. Check out PR code from GitHub
  3. Create GitHub deployment - Wire up the github deployment so links to view deployment are valid on the PR
  4. Login to Heroku
  5. Create Heroku Review App
  6. Set Heroku Review App environment - Setup Heroku env vars (copy GitHub secrets etc...)
  7. Add Heroku Review App to pipeline
  8. Add Heroku git remote
  9. Push PR branch to Heroku
  10. Initialize the Heroku Review App database
  11. Migrate and seed the Heroku Review App database - Migrations must work and seeds must be idempotent
  12. Update deployment status on GitHub - Updates the PR with a link to the Review App deployment

Destroy Heroku Review App

.github/workflows/heroku_review_app_destroy.yml

Steps

  1. Set dynamic env vars - Allows us to reuse/compose global env vars
  2. Login to Heroku
  3. Destroy Heroku Review App
  4. Comment on PR

GitHub Secrets

You'll need to configure your GitHub repo with the following Action secrets. NOTE: This is the minimal set.

  • HEROKU_API_KEY - Your Heroku user's API key
  • HEROKU_EMAIL - Your Heroku user's email address
  • RAILS_MASTER_KEY - [optional] The Rails master key used for encrypted credentials

This effort is sponsored by Orbit.love (mission control for your community).

# SEE: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows
on:
pull_request:
types:
- opened
- reopened
- synchronize
# SEE: https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
permissions:
contents: read
deployments: write
pull-requests: read
# Update these variables for your project
env:
GITHUB_DEPLOYMENT_ENVIRONMENT: heroku-review-app
HEROKU_REVIEW_APP_ADDONS: --addons=heroku-postgresql:hobby-dev
HEROKU_PIPELINE_NAME: review-apps
jobs:
# Creates a Heroku Review App on PR open or reopen, also updates the Review App on any push to the PR
heroku_review_app_deploy:
name: Create/Update Heroku Review App
runs-on: ubuntu-latest
if: github.event.pull_request.state != 'closed'
steps:
# Allows us to reuse/compose global env vars
- name: Set dynamic env vars
run: echo "HEROKU_APP_NAME=${{ env.HEROKU_PIPELINE_NAME }}-review-app-${{ github.event.number }}" >> $GITHUB_ENV
- name: Check out PR code from GitHub
uses: actions/checkout@v3
with:
fetch-depth: 0
ref: ${{ github.head_ref }}
# Wire up the github deployment so links to `view deployment` are valid on the PR
- name: Create GitHub deployment
uses: chrnorm/deployment-action@releases/v1
id: deployment
with:
initial_status: in_progress
token: ${{ github.token }}
target_url: https://${{ env.HEROKU_APP_NAME}}.herokuapp.com/
environment: ${{ env.GITHUB_DEPLOYMENT_ENVIRONMENT }}
ref: ${{ github.head_ref }}
- name: Login to Heroku
uses: akhileshns/heroku-deploy@v3.12.12
with:
heroku_app_name: ${{ env.HEROKU_APP_NAME }}
heroku_api_key: ${{ secrets.HEROKU_API_KEY }}
heroku_email: ${{ secrets.HEROKU_EMAIL }}
justlogin: true
- name: Create Heroku Review App
if: github.event.action != 'synchronize'
run: heroku apps:create ${{ env.HEROKU_APP_NAME }} ${{ env.HEROKU_REVIEW_APP_ADDONS }}
# Setup Heroku env vars (copy GitHub secrets etc...)
- name: Set Heroku Review App environment
run: >-
heroku config:set
--app=${{ env.HEROKU_APP_NAME }}
RAILS_MASTER_KEY='${{ secrets.RAILS_MASTER_KEY }}'
EXAMPLE='${{ secrets.example }}'
- name: Add Heroku Review App to pipeline
if: github.event.action != 'synchronize'
run: heroku pipelines:add ${{ env.HEROKU_PIPELINE_NAME }} --app=${{ env.HEROKU_APP_NAME }} --stage=development
- name: Add Heroku git remote
run: heroku git:remote --app=${{ env.HEROKU_APP_NAME }}
- name: Push PR branch to Heroku
run: git push heroku ${{ github.head_ref }}:main --force
- name: Initialize the Heroku Review App database
if: github.event.action != 'synchronize'
run: heroku run rails db:schema:load --app=${{ env.HEROKU_APP_NAME }}
# Migrations must work and seeds must be idempotent
- name: Migrate and seed the Heroku Review App database
run: heroku run rails db:migrate db:seed --app=${{ env.HEROKU_APP_NAME }}
# Updates the PR with a link to the Review App deployment
- name: Update deployment status on GitHub
uses: chrnorm/deployment-status@releases/v1
with:
token: ${{ github.token }}
target_url: https://${{ env.HEROKU_APP_NAME }}.herokuapp.com/
environment_url: https://${{ env.HEROKU_APP_NAME }}.herokuapp.com/
state: success
deployment_id: ${{ steps.deployment.outputs.deployment_id }}
# SEE: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows
on:
pull_request:
types:
- closed
# SEE: https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
permissions:
pull-requests: write
# Update these variables for your project
env:
HEROKU_REVIEW_APP_ADDONS: --addons=heroku-postgresql:hobby-dev
HEROKU_PIPELINE_NAME: review-apps
jobs:
# Destroys the PR's Review App on Heroku
heroku_review_app_destroy:
name: Destroy Heroku Review App
runs-on: ubuntu-latest
steps:
- name: Set dynamic env vars
run: echo "HEROKU_APP_NAME=${{ env.HEROKU_PIPELINE_NAME }}-review-app-${{ github.event.number }}" >> $GITHUB_ENV
- name: Login to Heroku
uses: akhileshns/heroku-deploy@v3.12.12
with:
heroku_api_key: ${{ secrets.HEROKU_API_KEY }}
heroku_app_name: ${{ env.HEROKU_APP_NAME }}
heroku_email: ${{ secrets.HEROKU_EMAIL }}
justlogin: true
- name: Destroy Heroku Review App
run: heroku apps:destroy --app=${{ env.HEROKU_APP_NAME }} --confirm=${{ env.HEROKU_APP_NAME }}
- name: Comment on PR
uses: thollander/actions-comment-pull-request@v1
with:
message: ":warning: The Heroku Review App **${{ env.HEROKU_APP_NAME }}** has been destroyed."
GITHUB_TOKEN: ${{ github.token }}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment