Skip to content

Instantly share code, notes, and snippets.

@jeromedalbert
Forked from hopsoft/README.md
Created May 19, 2022 20:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeromedalbert/cabc301b63b86c183475bcdbf7f9e911 to your computer and use it in GitHub Desktop.
Save jeromedalbert/cabc301b63b86c183475bcdbf7f9e911 to your computer and use it in GitHub Desktop.
Smart Heroku Review Apps managed by GitHub Actions

Smart 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. Watch the demo to learn more.

Demo Video

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

Triggers

Create/Update Review App

  • Pull Request opened - only when labeled with review-app
  • Pull Request reopened - only when labeled with review-app
  • Pull Request synchronize (push) - only when labeled with review-app
  • Pull Request labeled

Destroy Review App

  • Pull Request labeled - only when labeled with review-app

Dependencies

Create or Update Heroku Review App

.github/workflows/heroku_review_app_create.yml

Steps

  1. Login to Heroku
  2. Set Heroku Review App name
  3. Get Heroku Review App info
  4. Set exists ENV vars
  5. Check out PR code from GitHub
  6. Create GitHub deployment
  7. Create Heroku Review App
  8. Set Heroku Review App environment
  9. Add Heroku Review App to pipeline
  10. Add Heroku git remote
  11. Push PR branch to Heroku
  12. Initialize the Heroku Review App database
  13. Migrate and seed the Heroku Review App database
  14. Update deployment status on GitHub to success

Destroy Heroku Review App

.github/workflows/heroku_review_app_destroy.yml

Steps

  1. Login to Heroku
  2. Set Heroku Review App name
  3. Get Heroku Review App info
  4. Set exists ENV vars
  5. Destroy Heroku Review App
  6. Remove GitHub label
  7. Comment on Pull Request

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

⚠️ You'll need to setup environment variables that Heroku depends on as Action Secrets and copy these over in the Set Heroku Review App environment step.


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:
- labeled
- 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
GITHUB_LABEL: review-app
HEROKU_PIPELINE_NAME: review-apps
HEROKU_REVIEW_APP_ADDONS: --addons=heroku-postgresql:hobby-dev
jobs:
heroku_review_app_check:
name: Create or Update Heroku Review App
runs-on: ubuntu-latest
if: github.event.pull_request.state != 'closed'
steps:
- name: Login to Heroku
uses: akhileshns/heroku-deploy@v3.12.12
with:
heroku_api_key: ${{ secrets.HEROKU_API_KEY }}
heroku_email: ${{ secrets.HEROKU_EMAIL }}
justlogin: true
- name: Set Heroku Review App name
run: echo HEROKU_APP_NAME="${{ env.HEROKU_PIPELINE_NAME }}-review-app-${{ github.event.number }}" >> $GITHUB_ENV
- name: Get Heroku Review App info
id: heroku_apps_info
continue-on-error: true
run: heroku apps:info -a ${{ env.HEROKU_APP_NAME }}
- name: Set exists ENV vars
run: |
echo HEROKU_APP_EXISTS="${{ steps.heroku_apps_info.outcome == 'success' }}" >> $GITHUB_ENV
echo GITHUB_LABEL_EXISTS="${{ contains(github.event.pull_request.labels.*.name, env.GITHUB_LABEL) }}" >> $GITHUB_ENV
- name: Check out PR code from GitHub
if: env.GITHUB_LABEL_EXISTS == 'true'
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
id: deployment
if: env.GITHUB_LABEL_EXISTS == 'true'
uses: chrnorm/deployment-action@releases/v1
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: Create Heroku Review App
id: heroku_review_app_create
if: env.GITHUB_LABEL_EXISTS == 'true' && env.HEROKU_APP_EXISTS == 'false'
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
id: heroku_review_app_env
if: env.GITHUB_LABEL_EXISTS == 'true'
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: steps.heroku_review_app_create.outcome == 'success'
run: heroku pipelines:add ${{ env.HEROKU_PIPELINE_NAME }} --app=${{ env.HEROKU_APP_NAME }} --stage=development
- name: Add Heroku git remote
id: heroku_git_remote
if: env.GITHUB_LABEL_EXISTS == 'true'
run: heroku git:remote --app=${{ env.HEROKU_APP_NAME }}
- name: Push PR branch to Heroku
id: heroku_git_push
if: steps.heroku_git_remote.outcome == 'success'
run: git push heroku ${{ github.head_ref }}:main --force
- name: Initialize the Heroku Review App database
if: steps.heroku_review_app_create.outcome == 'success' && steps.heroku_git_push.outcome == 'success'
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
if: steps.heroku_git_push.outcome == 'success'
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 to success
if: steps.heroku_git_push.outcome == 'success'
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
- unlabeled
# 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:
GITHUB_LABEL: review-app
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: Login to Heroku
uses: akhileshns/heroku-deploy@v3.12.12
with:
heroku_api_key: ${{ secrets.HEROKU_API_KEY }}
heroku_email: ${{ secrets.HEROKU_EMAIL }}
justlogin: true
- name: Set Heroku Review App name
run: echo HEROKU_APP_NAME="${{ env.HEROKU_PIPELINE_NAME }}-review-app-${{ github.event.number }}" >> $GITHUB_ENV
- name: Get Heroku Review App info
id: heroku_apps_info
continue-on-error: true
run: heroku apps:info -a ${{ env.HEROKU_APP_NAME }}
- name: Set exists ENV vars
run: |
echo HEROKU_APP_EXISTS="${{ steps.heroku_apps_info.outcome == 'success' }}" >> $GITHUB_ENV
echo GITHUB_LABEL_EXISTS="${{ contains(github.event.pull_request.labels.*.name, env.GITHUB_LABEL) }}" >> $GITHUB_ENV
- name: Destroy Heroku Review App
if: env.HEROKU_APP_EXISTS == 'true'
run: heroku apps:destroy --app=${{ env.HEROKU_APP_NAME }} --confirm=${{ env.HEROKU_APP_NAME }}
- name: Remove GitHub label
uses: actions-ecosystem/action-remove-labels@v1
if: env.GITHUB_LABEL_EXISTS == 'true'
with:
labels: ${{ env.GITHUB_LABEL }}
- name: Comment on PR
uses: thollander/actions-comment-pull-request@v1
if: env.HEROKU_APP_EXISTS == 'true'
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