From 80ad040521989dc2472a3ada05898ba089a5fc07 Mon Sep 17 00:00:00 2001 From: flouthoc Date: Tue, 23 Sep 2025 09:31:13 -0700 Subject: [PATCH] .github: unify opendownstream workflow opendownstream workflow should open PR's for both `podman` and `buildah`. Signed-off-by: flouthoc --- .github/actions/sync-downstream/action.yml | 162 ++++++++++++++++++ .github/workflows/README.md | 34 ++++ .../workflows/opendownstream-pr-unified.yml | 81 +++++++++ .github/workflows/opendownstream-pr.yml | 152 ---------------- 4 files changed, 277 insertions(+), 152 deletions(-) create mode 100644 .github/actions/sync-downstream/action.yml create mode 100644 .github/workflows/README.md create mode 100644 .github/workflows/opendownstream-pr-unified.yml delete mode 100644 .github/workflows/opendownstream-pr.yml diff --git a/.github/actions/sync-downstream/action.yml b/.github/actions/sync-downstream/action.yml new file mode 100644 index 0000000000..e7ab9013d0 --- /dev/null +++ b/.github/actions/sync-downstream/action.yml @@ -0,0 +1,162 @@ +name: 'Sync to Downstream Repository' +description: 'Reusable action to sync container-libs changes to downstream repositories' + +inputs: + target-repo: + description: 'Target repository name (e.g., buildah, podman)' + required: true + forked-repo: + description: 'Forked repository path (e.g., podmanbot/buildah)' + required: true + upstream-repo: + description: 'Upstream repository path (e.g., containers/buildah)' + required: true + token: + description: 'GitHub token for pushing to forked repo' + required: true + pr-number: + description: 'PR number from container-libs' + required: true + pr-url: + description: 'PR URL from container-libs' + required: true + pr-title: + description: 'PR title from container-libs' + required: true + pr-sha: + description: 'PR head SHA from container-libs' + required: true + pr-repo-full-name: + description: 'Full name of the PR head repository' + required: true + +outputs: + pr-url: + description: 'URL of the created/updated downstream PR' + value: ${{ steps.create_pr.outputs.pr_url }} + pr-action: + description: 'Action taken (created/updated)' + value: ${{ steps.create_pr.outputs.pr_action }} + skip-pr: + description: 'Whether PR creation was skipped due to no changes' + value: ${{ steps.vendor.outputs.skip_pr }} + +runs: + using: 'composite' + steps: + - name: 'Checkout forked repository' + uses: actions/checkout@v5 + with: + repository: ${{ inputs.forked-repo }} + path: ${{ inputs.target-repo }} + fetch-depth: '1' + token: ${{ inputs.token }} + + - name: 'Vendor Code from container-libs' + id: vendor + shell: bash + run: | + echo "Using commit SHA: ${{ inputs.pr-sha }}" + + cd ${{ inputs.target-repo }} + # Create a unique branch name based on the container-libs PR number + BRANCH_NAME="sync/container-libs-${{ inputs.pr-number }}" + git switch -c $BRANCH_NAME + git remote add upstream https://github.com/${{ inputs.upstream-repo }}.git + git fetch upstream + git rebase upstream/main + + # Function to update module and verify + update_module() { + local module=$1 + echo "Updating module: $module" + go mod edit -replace ${module}=github.com/${{ inputs.pr-repo-full-name }}/${module#go.podman.io/}@${{ inputs.pr-sha }} + GOWORK=off go mod tidy + } + + # Update all required modules + update_module "go.podman.io/common" + update_module "go.podman.io/storage" + update_module "go.podman.io/image/v5" + GOWORK=off go mod vendor + GOWORK=off go mod verify + + echo "Updated go.mod:" + cat go.mod + + echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_OUTPUT + + - name: 'Commit and Push changes' + id: commit + shell: bash + run: | + cd ${{ inputs.target-repo }} + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + BRANCH_NAME="sync/container-libs-${{ inputs.pr-number }}" + git switch $BRANCH_NAME + + # Check if there are any changes to commit + if git diff --quiet && git diff --cached --quiet; then + echo "No changes to commit, skipping..." + echo "skip_pr=true" >> $GITHUB_OUTPUT + exit 0 + fi + + git add . + git commit -m "dnm: Vendor changes from containers/container-libs#${{ inputs.pr-number }}" + + # Force push to update the branch if the action re-runs on 'synchronize' + git push origin $BRANCH_NAME --force + + # Verify the branch exists remotely + if ! git ls-remote --heads origin $BRANCH_NAME | grep -q $BRANCH_NAME; then + echo "Failed to push branch $BRANCH_NAME" + exit 1 + fi + + echo "skip_pr=false" >> $GITHUB_OUTPUT + + - name: 'Create or Update Pull Request' + id: create_pr + if: steps.commit.outputs.skip_pr != 'true' + shell: bash + env: + GH_TOKEN: ${{ inputs.token }} + run: | + cd ${{ inputs.target-repo }} + + BRANCH_NAME="sync/container-libs-${{ inputs.pr-number }}" + PR_TITLE="Sync: ${{ inputs.pr-title }}" + PR_BODY="This PR automatically vendors changes from [container-libs#${{ inputs.pr-number }}](${{ inputs.pr-url }})." + + # Check if PR already exists for this branch + echo "Searching for existing PR with branch: $BRANCH_NAME" + + EXISTING_PR_URL=$(gh pr list --repo ${{ inputs.upstream-repo }} --head "$BRANCH_NAME" --json url --jq '.[0].url // empty' 2>/dev/null || echo "") + + if [ -n "$EXISTING_PR_URL" ]; then + echo "Found existing PR: $EXISTING_PR_URL" + # Update existing PR title and body + gh pr edit $EXISTING_PR_URL \ + --title "$PR_TITLE" \ + --body "$PR_BODY" + echo "Updated existing PR: $EXISTING_PR_URL" + echo "pr_url=$EXISTING_PR_URL" >> $GITHUB_OUTPUT + echo "pr_action=updated" >> $GITHUB_OUTPUT + else + # Create new PR + FORK_OWNER=$(echo "${{ inputs.forked-repo }}" | cut -d'/' -f1) + echo "Creating new PR with head: $FORK_OWNER:$BRANCH_NAME" + NEW_PR_URL=$(gh pr create \ + --repo ${{ inputs.upstream-repo }} \ + --draft \ + --base main \ + --head "$FORK_OWNER:$BRANCH_NAME" \ + --title "$PR_TITLE" \ + --body "$PR_BODY") + echo "Created new PR: $NEW_PR_URL" + echo "pr_url=$NEW_PR_URL" >> $GITHUB_OUTPUT + echo "pr_action=created" >> $GITHUB_OUTPUT + fi diff --git a/.github/workflows/README.md b/.github/workflows/README.md new file mode 100644 index 0000000000..7cc74075ab --- /dev/null +++ b/.github/workflows/README.md @@ -0,0 +1,34 @@ +# Downstream Repository Sync Workflow + +This directory contains a GitHub Actions workflow that automatically creates pull requests in downstream repositories (buildah and podman) when changes are made to container-libs. + +## Architecture + +### Reusable Components + +1. **Composite Action** (`.github/actions/sync-downstream/action.yml`) + - Reusable action that handles the common sync logic + - Parameterized to work with any downstream repository + - Eliminates code duplication and enables easy addition of new repositories + +### Unified Workflow + +**Unified Workflow** (`opendownstream-pr-unified.yml`) +- Handles both buildah and podman repositories in parallel +- Uses the reusable composite action for consistent behavior +- Efficient execution with simultaneous syncs to both downstream repositories + +## How It Works + +1. **Trigger**: Activated on pull requests to the `main` branch that modify Go files (excluding tests and vendor) + +2. **Process**: + - Checkout the forked repository (podmanbot/buildah or podmanbot/podman) + - Create a branch named `sync/container-libs-{PR_NUMBER}` + - Update Go modules to use the PR's changes via replace directives + - Run `go mod tidy` and `go mod vendor` + - Commit and push changes + - Create or update a draft PR in the upstream repository + +3. **Output**: Comments on the original container-libs PR with links to created downstream PRs + diff --git a/.github/workflows/opendownstream-pr-unified.yml b/.github/workflows/opendownstream-pr-unified.yml new file mode 100644 index 0000000000..b4ca28df7b --- /dev/null +++ b/.github/workflows/opendownstream-pr-unified.yml @@ -0,0 +1,81 @@ +name: 'Open downstream PRs - Unified' + +on: + pull_request_target: + branches: + - 'main' + paths: + - '**/*.go' + - '!vendor/**' + - '!**/*_test.go' + +jobs: + sync-buildah: + runs-on: ubuntu-latest + steps: + - name: 'Checkout Self' + uses: actions/checkout@v5 + + - name: 'Setup Go' + uses: actions/setup-go@v6 + with: + go-version: 'stable' + + - name: 'Sync to Buildah' + id: sync_buildah + uses: ./.github/actions/sync-downstream + with: + target-repo: 'buildah' + forked-repo: 'podmanbot/buildah' + upstream-repo: 'containers/buildah' + token: ${{ secrets.VENDOR_TOKEN_PODMANBOT }} + pr-number: ${{ github.event.pull_request.number }} + pr-url: ${{ github.event.pull_request.html_url }} + pr-title: ${{ github.event.pull_request.title }} + pr-sha: ${{ github.event.pull_request.head.sha }} + pr-repo-full-name: ${{ github.event.pull_request.head.repo.full_name }} + + - name: 'Comment on container-libs PR with buildah link' + if: steps.sync_buildah.outputs.skip-pr != 'true' && steps.sync_buildah.outputs.pr-action == 'created' + env: + GH_TOKEN: ${{ secrets.VENDOR_TOKEN_PODMANBOT }} + run: | + COMMENT_BODY="✅ A new PR has been created in buildah to vendor these changes: **${{ steps.sync_buildah.outputs.pr-url }}**" + gh pr comment ${{ github.event.pull_request.number }} \ + --repo ${{ github.repository }} \ + --body "$COMMENT_BODY" + + sync-podman: + runs-on: ubuntu-latest + steps: + - name: 'Checkout Self' + uses: actions/checkout@v5 + + - name: 'Setup Go' + uses: actions/setup-go@v6 + with: + go-version: 'stable' + + - name: 'Sync to Podman' + id: sync_podman + uses: ./.github/actions/sync-downstream + with: + target-repo: 'podman' + forked-repo: 'podmanbot/podman' + upstream-repo: 'containers/podman' + token: ${{ secrets.VENDOR_TOKEN_PODMANBOT }} + pr-number: ${{ github.event.pull_request.number }} + pr-url: ${{ github.event.pull_request.html_url }} + pr-title: ${{ github.event.pull_request.title }} + pr-sha: ${{ github.event.pull_request.head.sha }} + pr-repo-full-name: ${{ github.event.pull_request.head.repo.full_name }} + + - name: 'Comment on container-libs PR with podman link' + if: steps.sync_podman.outputs.skip-pr != 'true' && steps.sync_podman.outputs.pr-action == 'created' + env: + GH_TOKEN: ${{ secrets.VENDOR_TOKEN_PODMANBOT }} + run: | + COMMENT_BODY="✅ A new PR has been created in podman to vendor these changes: **${{ steps.sync_podman.outputs.pr-url }}**" + gh pr comment ${{ github.event.pull_request.number }} \ + --repo ${{ github.repository }} \ + --body "$COMMENT_BODY" diff --git a/.github/workflows/opendownstream-pr.yml b/.github/workflows/opendownstream-pr.yml deleted file mode 100644 index 3450a7f806..0000000000 --- a/.github/workflows/opendownstream-pr.yml +++ /dev/null @@ -1,152 +0,0 @@ -name: 'Open downstream PRs' - -on: - pull_request_target: - branches: - - 'main' - paths: - - '**/*.go' - - '!vendor/**' - - '!**/*_test.go' - -jobs: - sync: - runs-on: ubuntu-latest - steps: - - name: 'Checkout Self' - uses: actions/checkout@v5 - # This checks out the code from the PR branch itself - - - name: 'Setup Go' - uses: actions/setup-go@v6 - with: - go-version: 'stable' - - - name: 'Checkout forked buildah' - uses: actions/checkout@v5 - with: - repository: 'podmanbot/buildah' # The target repository - path: 'buildah' # Checkout into a sub-directory - fetch-depth: '1' - token: ${{ secrets.VENDOR_TOKEN_PODMANBOT }} # We need to push into pobmanbot/buildah - - - name: 'Vendor Code from this repo to buildah' - run: | - # Get the current commit SHA from the PR - COMMIT_SHA="${{ github.event.pull_request.head.sha }}" - echo "Using commit SHA: $COMMIT_SHA" - - cd buildah - # Create a unique branch name based on the container-libs PR number - BRANCH_NAME="sync/container-libs-${{ github.event.pull_request.number }}" - git switch -c $BRANCH_NAME - git remote add upstream https://github.com/containers/buildah.git - git fetch upstream - git rebase upstream/main - - # Function to update module and verify - update_module() { - local module=$1 - echo "Updating module: $module" - go mod edit -replace ${module}=github.com/${{ github.event.pull_request.head.repo.full_name }}/${module#go.podman.io/}@${COMMIT_SHA} - GOWORK=off go mod tidy - } - - # Update all required modules - update_module "go.podman.io/common" - update_module "go.podman.io/storage" - update_module "go.podman.io/image/v5" - GOWORK=off go mod vendor - GOWORK=off go mod verify - - echo "Updated go.mod:" - cat go.mod - - - name: 'Commit and Push to buildah' - run: | - cd buildah - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - BRANCH_NAME="sync/container-libs-${{ github.event.pull_request.number }}" - git switch $BRANCH_NAME - - # Check if there are any changes to commit - if git diff --quiet && git diff --cached --quiet; then - echo "No changes to commit, skipping..." - echo "SKIP_PR=true" >> $GITHUB_ENV - exit 0 - fi - - git add . - git commit -m "dnm: Vendor changes from containers/container-libs#${{ github.event.pull_request.number }}" - - # Force push to update the branch if the action re-runs on 'synchronize' - git push origin $BRANCH_NAME --force - - # Verify the branch exists remotely - if ! git ls-remote --heads origin $BRANCH_NAME | grep -q $BRANCH_NAME; then - echo "Failed to push branch $BRANCH_NAME" - exit 1 - fi - - echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV - - - name: 'Create or Update Pull Request in Buildah' - id: create_pr - if: env.SKIP_PR != 'true' - env: - GH_TOKEN: ${{ secrets.VENDOR_TOKEN_PODMANBOT }} - SELF_REPO_PR_NUMBER: ${{ github.event.pull_request.number }} - SELF_REPO_PR_URL: ${{ github.event.pull_request.html_url }} - SELF_REPO_PR_TITLE: ${{ github.event.pull_request.title }} - run: | - cd buildah - - BRANCH_NAME="sync/container-libs-${{ github.event.pull_request.number }}" - PR_TITLE="Sync: ${{ env.SELF_REPO_PR_TITLE }}" - PR_BODY="This PR automatically vendors changes from [container-libs#${{ env.SELF_REPO_PR_NUMBER }}](${{ env.SELF_REPO_PR_URL }})." - - # Check if PR already exists for this branch - echo "Searching for existing PR with branch: $BRANCH_NAME" - - EXISTING_PR_URL=$(gh pr list --repo containers/buildah --head "$BRANCH_NAME" --json url --jq '.[0].url // empty' 2>/dev/null || echo "") - - if [ -n "$EXISTING_PR_URL" ]; then - echo "Found existing PR: $EXISTING_PR_URL" - # Update existing PR title and body - gh pr edit $EXISTING_PR_URL \ - --title "$PR_TITLE" \ - --body "$PR_BODY" - echo "Updated existing PR: $EXISTING_PR_URL" - echo "pr_url=$EXISTING_PR_URL" >> $GITHUB_OUTPUT - echo "pr_action=updated" >> $GITHUB_OUTPUT - else - # Create new PR - echo "Creating new PR with head: podmanbot:$BRANCH_NAME" - NEW_PR_URL=$(gh pr create \ - --repo containers/buildah \ - --draft \ - --base main \ - --head "podmanbot:$BRANCH_NAME" \ - --title "$PR_TITLE" \ - --body "$PR_BODY") - echo "Created new PR: $NEW_PR_URL" - echo "pr_url=$NEW_PR_URL" >> $GITHUB_OUTPUT - echo "pr_action=created" >> $GITHUB_OUTPUT - fi - - - name: 'Comment on container-libs PR with the link to buildah PR' - if: env.SKIP_PR != 'true' - env: - GH_TOKEN: ${{ secrets.VENDOR_TOKEN_PODMANBOT }} - SELF_REPO_PR_NUMBER: ${{ github.event.pull_request.number }} - TARGET_REPO_PR_URL: ${{ steps.create_pr.outputs.pr_url }} - PR_ACTION: ${{ steps.create_pr.outputs.pr_action }} - run: | - if [ "${{ env.PR_ACTION }}" = "created" ]; then - COMMENT_BODY="✅ A new PR has been created in buildah to vendor these changes: **${{ env.TARGET_REPO_PR_URL }}**" - gh pr comment ${{ env.SELF_REPO_PR_NUMBER }} \ - --repo ${{ github.repository }} \ - --body "$COMMENT_BODY" - fi