diff --git a/.github/workflows/sync-upstream-cli.yml b/.github/workflows/sync-upstream-cli.yml new file mode 100644 index 00000000000..bc3298b86d1 --- /dev/null +++ b/.github/workflows/sync-upstream-cli.yml @@ -0,0 +1,174 @@ +# Reusable workflow for syncing CLI reference YAML from upstream repositories. +# +# Upstream repos call this after generating their CLI reference YAML files. +# The workflow copies the YAML to data/cli// and opens a PR. +# +# Uses the same input names as validate-upstream.yml so upstream repos +# can share the generate step and swap validate/sync based on trigger. +# +# Auth: uses a GitHub App (docker-docs-sync) installed on docker/docs. +# The calling workflow mints a short-lived token and passes it as a secret. +# App credentials are stored as org secrets (DOCS_SYNC_APP_ID, DOCS_SYNC_APP_PRIVATE_KEY). +# +# Example caller (e.g., in docker/buildx .github/workflows/docs-release.yml): +# +# jobs: +# docs-yaml: +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v5 +# - run: make generate-yaml-docs +# - uses: actions/upload-artifact@v4 +# with: +# name: cli-yaml +# path: docs/yaml/*.yaml +# +# # Mint a short-lived token from the GitHub App +# token: +# runs-on: ubuntu-latest +# outputs: +# token: ${{ steps.app.outputs.token }} +# steps: +# - uses: actions/create-github-app-token@v2 +# id: app +# with: +# app-id: ${{ vars.DOCS_SYNC_APP_ID }} +# private-key: ${{ secrets.DOCS_SYNC_APP_PRIVATE_KEY }} +# owner: docker +# repositories: docs +# +# # On PR — validate that docs still build +# validate: +# needs: docs-yaml +# uses: docker/docs/.github/workflows/validate-upstream.yml@main +# with: +# module-name: docker/buildx +# data-files-id: cli-yaml +# data-files-folder: buildx +# +# # On release — sync to docker/docs +# sync: +# needs: [docs-yaml, token] +# uses: docker/docs/.github/workflows/sync-upstream-cli.yml@main +# with: +# data-files-id: cli-yaml +# data-files-folder: buildx +# version: ${{ github.ref_name }} +# secrets: +# token: ${{ needs.token.outputs.token }} + +name: sync-upstream-cli + +on: + workflow_call: + inputs: + data-files-folder: + description: "Subfolder under data/cli/ (e.g., buildx, compose, model). Same as validate-upstream." + required: true + type: string + data-files-id: + description: "Name of the uploaded artifact containing YAML reference files. Same as validate-upstream." + required: true + type: string + version: + description: "Version string for commit message and PR title (e.g., v0.33.0)" + required: true + type: string + secrets: + token: + description: "GitHub token with contents:write and pull-requests:write on docker/docs" + required: true + +jobs: + sync: + runs-on: ubuntu-24.04 + env: + BRANCH: "bot/sync-${{ inputs.data-files-folder }}-cli" + steps: + - name: Checkout docker/docs + uses: actions/checkout@v5 + with: + repository: docker/docs + token: ${{ secrets.token }} + fetch-depth: 0 + + - name: Download data files + uses: actions/download-artifact@v4 + with: + name: ${{ inputs.data-files-id }} + path: /tmp/cli-data + + - name: Copy data files + run: | + mkdir -p "data/cli/${{ inputs.data-files-folder }}" + rm -f "data/cli/${{ inputs.data-files-folder }}"/*.yaml + cp /tmp/cli-data/*.yaml "data/cli/${{ inputs.data-files-folder }}/" + + - name: Check for changes + id: diff + run: | + git add "data/cli/${{ inputs.data-files-folder }}/" + if git diff --cached --quiet; then + echo "changes=false" >> "$GITHUB_OUTPUT" + echo "No changes detected" >> "$GITHUB_STEP_SUMMARY" + else + echo "changes=true" >> "$GITHUB_OUTPUT" + echo '```' >> "$GITHUB_STEP_SUMMARY" + git diff --cached --stat >> "$GITHUB_STEP_SUMMARY" + echo '```' >> "$GITHUB_STEP_SUMMARY" + fi + + - name: Commit and push + if: steps.diff.outputs.changes == 'true' + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git checkout -b "$BRANCH" + git commit -m "cli(${{ inputs.data-files-folder }}): sync docs ${{ inputs.version }}" + git push -u origin "$BRANCH" --force + + - name: Create or update PR + if: steps.diff.outputs.changes == 'true' + env: + GH_TOKEN: ${{ secrets.token }} + run: | + TITLE="cli(${{ inputs.data-files-folder }}): sync docs ${{ inputs.version }}" + + EXISTING=$(gh pr list --repo docker/docs --state open \ + --head "$BRANCH" --json url --jq '.[0].url // empty') + + if [ -n "$EXISTING" ]; then + echo "Updating existing PR: $EXISTING" >> "$GITHUB_STEP_SUMMARY" + gh pr edit "$EXISTING" --repo docker/docs \ + --title "$TITLE" \ + --body "$(cat <> "$GITHUB_STEP_SUMMARY" + gh pr create --repo docker/docs \ + --title "$TITLE" \ + --base main \ + --head "$BRANCH" \ + --body "$(cat <