-
Notifications
You must be signed in to change notification settings - Fork 1
Add shared workflow for Heroku container deploys #42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
e76a42e
Add shared workflow for Heroku container deploys
baelter d7c7598
Use docker actions for buildx caching and secure login (#43)
dentarg 0911466
Build per process type to get correct CMD per image
baelter f1cb5b5
Remove Ruby-specific RUBY_VERSION logic from shared workflow
baelter 6f3aab2
Add standalone deploy script for when GitHub Actions is unavailable
baelter 85dd164
Auto-detect .*-version files as build args
baelter 526c07f
Harden workflow security and fix shell quoting
baelter File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,129 @@ | ||
| name: Heroku container deploy | ||
|
|
||
| on: | ||
| workflow_call: | ||
| inputs: | ||
| heroku-app: | ||
| description: "The Heroku app name" | ||
| default: ${{ github.event.repository.name }} | ||
| required: false | ||
| type: string | ||
| branch: | ||
| description: "The branch to deploy" | ||
| default: ${{ github.event.repository.default_branch }} | ||
| required: false | ||
| type: string | ||
| targets: | ||
| description: "Space-separated Dockerfile targets to build and push (e.g. 'web worker release')" | ||
| required: true | ||
| type: string | ||
| secrets: | ||
| heroku-key: | ||
| description: "Heroku API key (OAuth token)" | ||
| required: true | ||
| build-args: | ||
| description: "Docker build args (newline-separated KEY=VALUE pairs, typically for private dependency auth)" | ||
| required: false | ||
|
|
||
| jobs: | ||
| deploy: | ||
| if: | | ||
| (github.event.workflow_run.conclusion == 'success' && | ||
| github.event.workflow_run.head_branch == inputs.branch) || | ||
| (github.event_name == 'workflow_dispatch' && github.ref_name == inputs.branch) | ||
| concurrency: ${{ inputs.heroku-app || github.event.repository.name }} | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 15 | ||
| steps: | ||
| - name: Create deployment in GitHub | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| BRANCH: ${{ inputs.branch }} | ||
| APP: ${{ inputs.heroku-app || github.event.repository.name }} | ||
| REPO: ${{ github.repository }} | ||
| run: | | ||
| deploymentId=$(jq -n \ | ||
| --arg ref "$BRANCH" \ | ||
| --arg env "$APP" \ | ||
| '{ref: $ref, auto_merge: false, environment: $env, | ||
| description: "Heroku container deploy from GitHub Actions", | ||
| required_contexts: []}' \ | ||
| | gh api "repos/$REPO/deployments" \ | ||
| --method POST \ | ||
| --header "Accept: application/vnd.github.v3+json" \ | ||
| --input - \ | ||
| --jq '.id') | ||
| echo "DEPLOYMENT_ID=$deploymentId" >> "$GITHUB_ENV" | ||
|
|
||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | ||
| with: | ||
| ref: ${{ inputs.branch }} | ||
| persist-credentials: false | ||
|
|
||
| - name: Log in to Heroku Container Registry | ||
| uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 | ||
| with: | ||
| registry: registry.heroku.com | ||
| username: _ | ||
| password: ${{ secrets.heroku-key }} | ||
|
|
||
| - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 | ||
|
|
||
| - name: Build and push per target | ||
| env: | ||
| APP: ${{ inputs.heroku-app || github.event.repository.name }} | ||
| TARGETS: ${{ inputs.targets }} | ||
| BUILD_ARGS: ${{ secrets.build-args }} | ||
| run: | | ||
| build_arg_flags=() | ||
| while IFS= read -r line; do | ||
| [ -n "$line" ] && build_arg_flags+=(--build-arg "$line") | ||
| done <<< "$BUILD_ARGS" | ||
|
|
||
| for vfile in .*-version; do | ||
| [ -f "$vfile" ] || continue | ||
| name="${vfile#.}" | ||
| name="${name%-version}" | ||
| arg_name="$(echo "$name" | tr '[:lower:]-' '[:upper:]_')_VERSION" | ||
| build_arg_flags+=(--build-arg "$arg_name=$(tr -d '[:space:]' < "$vfile")") | ||
| done | ||
|
|
||
| for target in $TARGETS; do | ||
| docker buildx build \ | ||
| --target "$target" \ | ||
| --tag "registry.heroku.com/$APP/$target" \ | ||
| --cache-from type=gha \ | ||
| --cache-to type=gha,mode=max \ | ||
| --provenance=false \ | ||
| --push \ | ||
| "${build_arg_flags[@]}" \ | ||
| . | ||
| done | ||
|
|
||
| - name: Install Heroku CLI | ||
| run: curl -fsSL https://cli-assets.heroku.com/install.sh | sh | ||
|
|
||
| - name: Release | ||
| env: | ||
| HEROKU_API_KEY: ${{ secrets.heroku-key }} | ||
| APP: ${{ inputs.heroku-app || github.event.repository.name }} | ||
| TARGETS: ${{ inputs.targets }} | ||
| run: heroku container:release $TARGETS -a "$APP" | ||
|
|
||
| - name: Create deployment status in GitHub | ||
| if: always() && env.DEPLOYMENT_ID | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| REPO: ${{ github.repository }} | ||
| RUN_ID: ${{ github.run_id }} | ||
| APP: ${{ inputs.heroku-app || github.event.repository.name }} | ||
| JOB_STATUS: ${{ job.status }} | ||
| run: | | ||
| state="$JOB_STATUS" | ||
| [ "$state" = "cancelled" ] && state="error" | ||
| gh api "repos/$REPO/deployments/$DEPLOYMENT_ID/statuses" \ | ||
| --method POST \ | ||
| --header "Accept: application/vnd.github.v3+json" \ | ||
| --field "state=$state" \ | ||
| --field "log_url=https://github.com/$REPO/actions/runs/$RUN_ID" \ | ||
| --field "environment_url=https://$APP.herokuapp.com/" | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
|
|
||
| # Deploy Docker images to Heroku's container registry. | ||
| # Standalone fallback for when GitHub Actions is unavailable. | ||
| # | ||
| # Usage: | ||
| # bin/heroku-container-deploy <app> <targets...> | ||
| # bin/heroku-container-deploy my-app web worker release | ||
| # | ||
| # Build args (for private dependencies) are passed via environment: | ||
| # BUNDLE_GITHUB__COM=x-access-token:ghp_xxx bin/heroku-container-deploy my-app web worker | ||
| # | ||
| # Requires: docker, heroku CLI, HEROKU_API_KEY env var | ||
|
|
||
| if [ $# -lt 2 ]; then | ||
| echo "Usage: $0 <app> <targets...>" >&2 | ||
| echo "Example: $0 my-app web worker release" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| APP="$1" | ||
| shift | ||
| TARGETS=("$@") | ||
|
|
||
| : "${HEROKU_API_KEY:?Set HEROKU_API_KEY}" | ||
|
|
||
| echo "Logging in to Heroku container registry..." | ||
| echo "$HEROKU_API_KEY" | docker login -u _ --password-stdin registry.heroku.com | ||
|
|
||
| build_arg_flags=() | ||
| for var in BUNDLE_GITHUB__COM BUNDLE_RUBYGEMS__PKG__GITHUB__COM NPM_TOKEN RUBY_VERSION; do | ||
| if [ -n "${!var:-}" ]; then | ||
| build_arg_flags+=(--build-arg "$var=${!var}") | ||
| fi | ||
| done | ||
|
|
||
| for target in "${TARGETS[@]}"; do | ||
| echo "Building and pushing target: $target" | ||
| docker build \ | ||
| --target "$target" \ | ||
| --tag "registry.heroku.com/$APP/$target" \ | ||
| --provenance=false \ | ||
| "${build_arg_flags[@]}" \ | ||
| . | ||
| docker push "registry.heroku.com/$APP/$target" | ||
| done | ||
|
|
||
| echo "Releasing: ${TARGETS[*]}" | ||
| heroku container:release "${TARGETS[@]}" -a "$APP" | ||
|
|
||
| echo "Done. https://$APP.herokuapp.com/" |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.