mirror of
https://github.com/ansible/awx.git
synced 2026-10-29 22:03:20 -02:30
In particular, this brings two important changes: - rather than opening a new PR every time it runs, it uses a stable branch name updating its content instead; this means that at most there is one open PR per target branch - a new secret "OPENAPI_SPEC_PR_REVIEW_TEAM" is introduced to specify the name of the github team to notify when creating new PRs; this helps to make sure that PRs are reviewed
234 lines
8.7 KiB
YAML
234 lines
8.7 KiB
YAML
# Sync OpenAPI Spec on Merge
|
|
#
|
|
# This workflow runs when code is merged to the devel branch.
|
|
# It runs the dev environment to generate the OpenAPI spec, then syncs it to
|
|
# the central spec repository.
|
|
#
|
|
# FLOW: PR merged → push to branch → dev environment runs → spec synced to central repo
|
|
#
|
|
# NOTE: This is an inlined version for testing with private forks.
|
|
# Production version will use a reusable workflow from the org repos.
|
|
name: Sync OpenAPI Spec on Merge
|
|
env:
|
|
LC_ALL: "C.UTF-8"
|
|
DEV_DOCKER_OWNER: ${{ github.repository_owner }}
|
|
on:
|
|
push:
|
|
branches:
|
|
- devel
|
|
- 'stable-2.[6-9]'
|
|
- 'stable-2.[1-9][0-9]'
|
|
workflow_dispatch: # Allow manual triggering for testing
|
|
jobs:
|
|
sync-openapi-spec:
|
|
if: |
|
|
github.event_name == 'workflow_dispatch' ||
|
|
(github.repository == 'ansible/awx' && (github.ref_name == 'devel' || startsWith(github.ref_name, 'feature_'))) ||
|
|
(github.repository == 'ansible/tower' && (startsWith(github.ref_name, 'stable-') || startsWith(github.ref_name, 'release_')))
|
|
name: Sync OpenAPI spec to central repo
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
packages: write
|
|
contents: read
|
|
steps:
|
|
- name: Checkout Controller repository
|
|
uses: actions/checkout@v4
|
|
with:
|
|
show-progress: false
|
|
|
|
- name: Build awx_devel image to use for schema gen
|
|
uses: ./.github/actions/awx_devel_image
|
|
with:
|
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
private-github-key: ${{ secrets.PRIVATE_GITHUB_KEY }}
|
|
|
|
- name: Generate API Schema
|
|
env:
|
|
REF_NAME: ${{ github.ref_name }}
|
|
BASE_REF: ${{ github.base_ref }}
|
|
run: |
|
|
DEV_DOCKER_TAG_BASE=ghcr.io/${OWNER_LC} \
|
|
COMPOSE_TAG=${BASE_REF:-${REF_NAME}} \
|
|
docker run -u $(id -u) --rm -v ${{ github.workspace }}:/awx_devel/:Z \
|
|
--workdir=/awx_devel `make print-DEVEL_IMAGE_NAME` /start_tests.sh genschema
|
|
|
|
- name: Verify spec file exists
|
|
run: |
|
|
SPEC_FILE="./schema.json"
|
|
if [ ! -f "$SPEC_FILE" ]; then
|
|
echo "❌ Spec file not found at $SPEC_FILE"
|
|
echo "Contents of workspace:"
|
|
ls -la .
|
|
exit 1
|
|
fi
|
|
echo "✅ Found spec file at $SPEC_FILE"
|
|
|
|
- name: Checkout spec repo
|
|
id: checkout_spec_repo
|
|
continue-on-error: true
|
|
uses: actions/checkout@v4
|
|
with:
|
|
repository: ansible-automation-platform/aap-openapi-specs
|
|
ref: ${{ github.ref_name }}
|
|
path: spec-repo
|
|
token: ${{ secrets.OPENAPI_SPEC_SYNC_TOKEN }}
|
|
|
|
- name: Fail if branch doesn't exist
|
|
if: steps.checkout_spec_repo.outcome == 'failure'
|
|
env:
|
|
REF_NAME: ${{ github.ref_name }}
|
|
run: |
|
|
echo "##[error]❌ Branch '${REF_NAME}' does not exist in the central spec repository."
|
|
echo "##[error]Expected branch: ${REF_NAME}"
|
|
echo "##[error]This branch must be created in the spec repo before specs can be synced."
|
|
exit 1
|
|
|
|
- name: Compare specs
|
|
id: compare
|
|
run: |
|
|
COMPONENT_SPEC="./schema.json"
|
|
SPEC_REPO_FILE="spec-repo/controller.json"
|
|
|
|
# Check if spec file exists in spec repo
|
|
if [ ! -f "$SPEC_REPO_FILE" ]; then
|
|
echo "Spec file doesn't exist in spec repo - will create new file"
|
|
echo "has_diff=true" >> $GITHUB_OUTPUT
|
|
echo "is_new_file=true" >> $GITHUB_OUTPUT
|
|
else
|
|
# Compare files
|
|
if diff -q "$COMPONENT_SPEC" "$SPEC_REPO_FILE" > /dev/null; then
|
|
echo "✅ No differences found - specs are identical"
|
|
echo "has_diff=false" >> $GITHUB_OUTPUT
|
|
else
|
|
echo "📝 Differences found - spec has changed"
|
|
echo "has_diff=true" >> $GITHUB_OUTPUT
|
|
echo "is_new_file=false" >> $GITHUB_OUTPUT
|
|
fi
|
|
fi
|
|
|
|
- name: Update spec file
|
|
if: steps.compare.outputs.has_diff == 'true'
|
|
run: |
|
|
cp "./schema.json" "spec-repo/controller.json"
|
|
echo "✅ Updated spec-repo/controller.json"
|
|
|
|
- name: Create or update PR in spec repo
|
|
if: steps.compare.outputs.has_diff == 'true'
|
|
working-directory: spec-repo
|
|
env:
|
|
GH_TOKEN: ${{ secrets.OPENAPI_SPEC_SYNC_TOKEN }}
|
|
GPG_PRIVATE_KEY: ${{ secrets.OPENAPI_SPEC_SYNC_GPG_PRIVATE_KEY }}
|
|
SPEC_REPO: ansible-automation-platform/aap-openapi-specs
|
|
SPEC_PR_REVIEW_TEAM: ${{ secrets.OPENAPI_SPEC_PR_REVIEW_TEAM }}
|
|
SPEC_BRANCH: ${{ github.ref_name }}
|
|
SOURCE_COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
|
run: |
|
|
# Import GPG key and configure git for signed commits
|
|
echo "$GPG_PRIVATE_KEY" | gpg --batch --import 2>/dev/null
|
|
GPG_KEY_ID=$(gpg --list-secret-keys --keyid-format long 2>/dev/null | grep sec | head -1 | awk '{print $2}' | cut -d'/' -f2)
|
|
if [ -z "$GPG_KEY_ID" ]; then
|
|
echo "❌ Failed to import GPG key or extract key ID"
|
|
exit 1
|
|
fi
|
|
git config user.name "aap-api-bot"
|
|
git config user.email "aap-api-bot@redhat.com"
|
|
git config commit.gpgsign true
|
|
git config user.signingkey "$GPG_KEY_ID"
|
|
|
|
# Configure git to use the token for push
|
|
git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${SPEC_REPO}.git"
|
|
|
|
# Use a stable branch name so we can reuse it across runs
|
|
BRANCH_NAME="auto/update-controller-${SPEC_BRANCH}"
|
|
|
|
# Check if there's already an open PR from this branch
|
|
EXISTING_PR=$(gh pr list \
|
|
--repo "$SPEC_REPO" \
|
|
--head "$BRANCH_NAME" \
|
|
--base "$SPEC_BRANCH" \
|
|
--state open \
|
|
--json number \
|
|
--jq '.[0].number // empty')
|
|
|
|
if [ -n "$EXISTING_PR" ]; then
|
|
echo "📝 Found existing PR #${EXISTING_PR} - will update it"
|
|
else
|
|
echo "📝 No existing PR found - will create a new one"
|
|
# Clean up stale remote branch from a previously merged PR
|
|
git push origin --delete "$BRANCH_NAME" 2>/dev/null || true
|
|
fi
|
|
|
|
git checkout -b "$BRANCH_NAME"
|
|
|
|
# Add and commit changes
|
|
git add "controller.json"
|
|
|
|
if [ "${{ steps.compare.outputs.is_new_file }}" == "true" ]; then
|
|
COMMIT_MSG="Add Controller OpenAPI spec for ${SPEC_BRANCH}"
|
|
else
|
|
COMMIT_MSG="Update Controller OpenAPI spec for ${SPEC_BRANCH}"
|
|
fi
|
|
|
|
git commit -m "$COMMIT_MSG
|
|
|
|
Synced from ${{ github.repository }}@${{ github.sha }}
|
|
Source branch: ${SPEC_BRANCH}
|
|
Spec repo branch: ${SPEC_BRANCH}
|
|
|
|
Co-Authored-By: github-actions[bot] <github-actions[bot]@users.noreply.github.com>"
|
|
|
|
# Push branch
|
|
git push --force origin "$BRANCH_NAME"
|
|
|
|
# Create PR (commit message passed via env var to avoid script injection)
|
|
PR_TITLE="[${SPEC_BRANCH}] Update Controller spec from merged commit"
|
|
PR_BODY=$(cat <<EOF
|
|
## Summary
|
|
Automated OpenAPI spec sync from component repository merge.
|
|
|
|
**Source:** ${{ github.repository }}@${{ github.sha }}
|
|
**Source Branch:** \`${SPEC_BRANCH}\`
|
|
**Spec Repo Branch:** \`${SPEC_BRANCH}\`
|
|
**Component:** \`Controller\`
|
|
**Spec File:** \`controller.json\`
|
|
|
|
## Changes
|
|
$(if [ "${{ steps.compare.outputs.is_new_file }}" == "true" ]; then echo "- 🆕 New spec file created"; else echo "- 📝 Spec file updated with latest changes"; fi)
|
|
|
|
## Source Commit
|
|
\`\`\`
|
|
${SOURCE_COMMIT_MESSAGE}
|
|
\`\`\`
|
|
|
|
---
|
|
🤖 This PR was automatically generated by the OpenAPI spec sync workflow.
|
|
EOF
|
|
)
|
|
|
|
if [ -n "$EXISTING_PR" ]; then
|
|
gh pr edit "$EXISTING_PR" \
|
|
--repo "$SPEC_REPO" \
|
|
--body "$PR_BODY"
|
|
echo "✅ Updated existing PR #${EXISTING_PR}"
|
|
else
|
|
gh pr create \
|
|
--repo "$SPEC_REPO" \
|
|
--title "$PR_TITLE" \
|
|
--body "$PR_BODY" \
|
|
--base "$SPEC_BRANCH" \
|
|
--head "$BRANCH_NAME" \
|
|
--reviewer "$SPEC_PR_REVIEW_TEAM"
|
|
echo "✅ Created PR in spec repo"
|
|
fi
|
|
|
|
- name: Report results
|
|
if: always()
|
|
env:
|
|
HAS_DIFF: ${{ steps.compare.outputs.has_diff }}
|
|
run: |
|
|
if [ "${HAS_DIFF}" == "true" ]; then
|
|
echo "📝 Spec sync completed - PR created in spec repo"
|
|
else
|
|
echo "✅ Spec sync completed - no changes needed"
|
|
fi
|