Skip to content

Docs: add section on overriding config options with environment variables #31

Docs: add section on overriding config options with environment variables

Docs: add section on overriding config options with environment variables #31

Workflow file for this run

name: Sync main → develop
on:
pull_request:
types: [closed]
branches: [main]
workflow_dispatch:
inputs:
head_branch:
description: "Branch to merge FROM (default: main)."
required: false
default: "main"
base_branch:
description: "Branch to merge INTO (default: develop)."
required: false
default: "develop"
source_pr_number:
description: "If testing, the PR number to comment on (optional)."
required: false
test_mode:
description: "Bypass PR/push guards for manual testing"
required: false
default: "true"
permissions:
contents: write
pull-requests: write
issues: write
concurrency:
group: sync-main-into-develop
cancel-in-progress: false
jobs:
open-sync-pr:
if: |
github.actor != 'github-actions[bot]' && (
(
github.event_name == 'pull_request' && github.event.pull_request.merged == true
) || (
github.event_name == 'workflow_dispatch' && (inputs.test_mode == 'true')
)
)
runs-on: ubuntu-latest
env:
# Use inputs for dispatch (testing), defaults for normal triggers
HEAD_BRANCH: ${{ (github.event_name == 'workflow_dispatch' && inputs.head_branch) || 'main' }}
BASE_BRANCH: ${{ (github.event_name == 'workflow_dispatch' && inputs.base_branch) || 'develop' }}
SOURCE_PR: ${{ (github.event_name == 'pull_request' && github.event.pull_request.number) || inputs.source_pr_number || '' }}
GH_TOKEN: ${{ secrets.GH_PAT }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GH_PAT }}
- name: Configure git author
run: |
git config --local user.name "Apollo Bot"
git config --local user.email "[email protected]"
# Generate branch name from PR# when available, otherwise use first 7 commit SHA characters
- name: Compute branch/name metadata
id: meta
run: |
pr=${{ github.event.pull_request.number }}
echo "sync_branch=sync/main-into-develop-pr-${pr}" >> $GITHUB_OUTPUT
echo "sync_title=Sync main → develop (PR #${pr})" >> $GITHUB_OUTPUT
echo "sync_body=Auto-opened after merging \`${{ github.event.pull_request.head.ref }}\` into \`main\`. Source PR: #${pr}." >> $GITHUB_OUTPUT
echo "conflict_branch=conflict/main-into-develop-pr-${pr}" >> $GITHUB_OUTPUT
echo "conflict_title=Sync main → develop (resolve conflicts)" >> $GITHUB_OUTPUT
echo "conflict_body=Opened from a copy of \`main\` so conflicts can be resolved without pushing to a protected branch." >> $GITHUB_OUTPUT
# Short-lived sync branch from develop and merge main into it (do NOT rebase)
# use +e to stop errors from short-circuiting the script
- name: Prepare sync branch
id: prep
run: |
set -e
git fetch origin "${BASE_BRANCH}" "${HEAD_BRANCH}"
git switch -c "${{ steps.meta.outputs.sync_branch }}" "origin/${BASE_BRANCH}"
set +e
git merge --no-ff "origin/${HEAD_BRANCH}"
rc=$?
set -e
git add -A || true
git commit -m "WIP: merge ${HEAD_BRANCH} into ${BASE_BRANCH} via ${{ steps.meta.outputs.branch }}" || true
git push origin HEAD
right=$(git rev-list --count --right-only "origin/${BASE_BRANCH}...HEAD")
echo "merge_status=$rc" >> "$GITHUB_OUTPUT"
echo "sync_right=$right" >> "$GITHUB_OUTPUT"
echo "Merge exit=$rc, sync branch ahead-by=$right"
# If no merge conflicts and there are changes, open the PR targeting develop
- name: Open clean PR to develop
id: sync_pr
if: ${{ steps.prep.outputs.merge_status == '0' && steps.prep.outputs.sync_right != '0' }}
run: |
# Avoid duplicate PRs
existing=$(gh pr list --base "${BASE_BRANCH}" --head "${{ steps.meta.outputs.sync_branch }}" --state open --json number --jq '.[0].number' || true)
if [ -n "$existing" ] && [ "$existing" != "null" ]; then
echo "pr_number=$existing" >> "$GITHUB_OUTPUT"
url=$(gh pr view "$existing" --json url --jq .url)
echo "pr_url=$url" >> "$GITHUB_OUTPUT"
exit 0
fi
gh pr create \
--base "${BASE_BRANCH}" \
--head "${{ steps.meta.outputs.sync_branch }}" \
--title "${{ steps.meta.outputs.sync_title }}" \
--body "${{ steps.meta.outputs.sync_body }} (created via gh CLI)" \
--label back-merge \
--label automation
# Emit outputs for later steps
gh pr view --base "${BASE_BRANCH}" --head "${{ steps.meta.outputs.sync_branch }}" \
--json number,url | jq -r '"pr_number=\(.number)\npr_url=\(.url)"' >> "$GITHUB_OUTPUT"
# If the merge hit conflicts, open a DIRECT PR: HEAD_BRANCH -> BASE_BRANCH so conflicts can be resolved prior to merge
- name: Open conflict PR
id: conflict_pr
if: ${{ steps.prep.outputs.merge_status != '0' }}
run: |
set -e
git fetch origin "${HEAD_BRANCH}" "${BASE_BRANCH}"
git switch -c "${{ steps.meta.outputs.conflict_branch }}" "origin/${HEAD_BRANCH}"
git push -u origin HEAD
# Skip if no diff between conflict branch and base (should be unlikely)
right=$(git rev-list --right-only --count "origin/${BASE_BRANCH}...origin/${{ steps.meta.outputs.conflict_branch }}")
if [ "$right" -eq 0 ]; then
echo "No diff between ${HEAD_BRANCH} and ${BASE_BRANCH}; nothing to open."
exit 0
fi
# Reuse existing open PR if present
existing=$(gh pr list --base "${BASE_BRANCH}" --head "${{ steps.meta.outputs.conflict_branch }}" --state open --json number --jq '.[0].number' || true)
if [ -n "$existing" ] && [ "$existing" != "null" ]; then
echo "pr_number=$existing" >> "$GITHUB_OUTPUT"
url=$(gh pr view "$existing" --json url --jq .url)
echo "pr_url=$url" >> "$GITHUB_OUTPUT"
exit 0
fi
gh pr create \
--base "${BASE_BRANCH}" \
--head "${{ steps.meta.outputs.conflict_branch }}" \
--title "${{ steps.meta.outputs.conflict_title }}" \
--body "${{ steps.meta.outputs.conflict_body }}" \
--label back-merge \
--label automation \
--label conflicts
gh pr view --base "${BASE_BRANCH}" --head "${{ steps.meta.outputs.conflict_branch }}" \
--json number,url | jq -r '"pr_number=\(.number)\npr_url=\(.url)"' >> "$GITHUB_OUTPUT"
# Comment back on the ORIGINAL merged PR with a link to the sync PR
- name: Comment on source PR with sync PR link
if: ${{ env.SOURCE_PR != '' && (steps.sync_pr.outputs.pr_number != '' || steps.conflict_pr.outputs.pr_number != '') }}
uses: actions/github-script@v7
with:
script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
const issue_number = Number(process.env.SOURCE_PR);
const hadConflicts = '${{ steps.prep.outputs.merge_status }}' !== '0';
const syncUrl = '${{ steps.sync_pr.outputs.pr_url || steps.conflict_pr.outputs.pr_url }}';
const head = process.env.HEAD_BRANCH;
const base = process.env.BASE_BRANCH;
const status = hadConflicts ? 'conflicts ❗' : 'clean ✅';
const note = hadConflicts
? 'Opened from a copy of main so conflicts can be resolved safely.'
: 'Opened from a sync branch created off develop.';
const body = [
`Opened sync PR **${head} → ${base}**: ${syncUrl}`,
``,
`Merge status: **${status}**`,
note
].join('\n');
await github.rest.issues.createComment({ owner, repo, issue_number, body });