From 73d748131f9c27281a0c534d9bcbf93b456b2599 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Wed, 15 Apr 2026 14:42:08 +0200 Subject: [PATCH 1/3] ci: add reusable workflow for syncing upstream CLI reference docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a generic reusable workflow that upstream repos can call to push CLI reference YAML to data/cli// and open a PR. This is an RFC — see the PR description for full context on the motivation and migration plan. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/sync-upstream-cli.yml | 143 ++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 .github/workflows/sync-upstream-cli.yml diff --git a/.github/workflows/sync-upstream-cli.yml b/.github/workflows/sync-upstream-cli.yml new file mode 100644 index 00000000000..410d5e9c645 --- /dev/null +++ b/.github/workflows/sync-upstream-cli.yml @@ -0,0 +1,143 @@ +# 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. +# +# Example caller (in upstream repo): +# +# jobs: +# generate: +# 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 +# +# sync: +# needs: generate +# uses: docker/docs/.github/workflows/sync-upstream-cli.yml@main +# with: +# tool: buildx +# version: ${{ github.ref_name }} +# data-files-id: cli-yaml +# secrets: +# token: ${{ secrets.DOCS_GITHUB_TOKEN }} + +name: sync-upstream-cli + +on: + workflow_call: + inputs: + tool: + description: "CLI tool name — subfolder under data/cli/ (e.g., buildx, compose, model)" + required: true + type: string + version: + description: "Version string for commit message and PR title (e.g., v0.33.0)" + required: true + type: string + data-files-id: + description: "Name of the uploaded artifact containing YAML reference files" + 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.tool }}-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.tool }}" + rm -f "data/cli/${{ inputs.tool }}"/*.yaml + cp /tmp/cli-data/*.yaml "data/cli/${{ inputs.tool }}/" + + - name: Check for changes + id: diff + run: | + git add "data/cli/${{ inputs.tool }}/" + 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.tool }}): 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.tool }}): 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 < Date: Wed, 15 Apr 2026 14:45:43 +0200 Subject: [PATCH 2/3] ci: align input names with validate-upstream.yml Use `data-files-folder` and `data-files-id` to match the existing validate-upstream workflow, so upstream repos can share the generate step and swap validate/sync based on trigger. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/sync-upstream-cli.yml | 49 +++++++++++++++---------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/.github/workflows/sync-upstream-cli.yml b/.github/workflows/sync-upstream-cli.yml index 410d5e9c645..74fc34b1ffa 100644 --- a/.github/workflows/sync-upstream-cli.yml +++ b/.github/workflows/sync-upstream-cli.yml @@ -1,9 +1,10 @@ # 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. +# The workflow copies the YAML to data/cli// and opens a PR. # -# Example caller (in upstream repo): +# Uses the same input names as validate-upstream.yml so upstream repos +# can share the generate step and swap validate/sync based on trigger: # # jobs: # generate: @@ -16,13 +17,23 @@ # name: cli-yaml # path: docs/yaml/*.yaml # +# # On PR — validate that docs still build +# validate: +# needs: generate +# 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: generate # uses: docker/docs/.github/workflows/sync-upstream-cli.yml@main # with: -# tool: buildx -# version: ${{ github.ref_name }} # data-files-id: cli-yaml +# data-files-folder: buildx +# version: ${{ github.ref_name }} # secrets: # token: ${{ secrets.DOCS_GITHUB_TOKEN }} @@ -31,16 +42,16 @@ name: sync-upstream-cli on: workflow_call: inputs: - tool: - description: "CLI tool name — subfolder under data/cli/ (e.g., buildx, compose, model)" + data-files-folder: + description: "Subfolder under data/cli/ (e.g., buildx, compose, model). Same as validate-upstream." required: true type: string - version: - description: "Version string for commit message and PR title (e.g., v0.33.0)" + data-files-id: + description: "Name of the uploaded artifact containing YAML reference files. Same as validate-upstream." required: true type: string - data-files-id: - description: "Name of the uploaded artifact containing YAML reference files" + version: + description: "Version string for commit message and PR title (e.g., v0.33.0)" required: true type: string secrets: @@ -52,7 +63,7 @@ jobs: sync: runs-on: ubuntu-24.04 env: - BRANCH: "bot/sync-${{ inputs.tool }}-cli" + BRANCH: "bot/sync-${{ inputs.data-files-folder }}-cli" steps: - name: Checkout docker/docs uses: actions/checkout@v5 @@ -69,14 +80,14 @@ jobs: - name: Copy data files run: | - mkdir -p "data/cli/${{ inputs.tool }}" - rm -f "data/cli/${{ inputs.tool }}"/*.yaml - cp /tmp/cli-data/*.yaml "data/cli/${{ inputs.tool }}/" + 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.tool }}/" + 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" @@ -93,7 +104,7 @@ jobs: 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.tool }}): sync docs ${{ inputs.version }}" + git commit -m "cli(${{ inputs.data-files-folder }}): sync docs ${{ inputs.version }}" git push -u origin "$BRANCH" --force - name: Create or update PR @@ -101,7 +112,7 @@ jobs: env: GH_TOKEN: ${{ secrets.token }} run: | - TITLE="cli(${{ inputs.tool }}): sync docs ${{ inputs.version }}" + 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') @@ -117,7 +128,7 @@ jobs: | | | |---|---| - | **Tool** | \`${{ inputs.tool }}\` | + | **Tool** | \`${{ inputs.data-files-folder }}\` | | **Version** | \`${{ inputs.version }}\` | | **Source** | ${{ github.repository }}@\`$(echo ${{ github.sha }} | head -c 12)\` | EOF @@ -135,7 +146,7 @@ jobs: | | | |---|---| - | **Tool** | \`${{ inputs.tool }}\` | + | **Tool** | \`${{ inputs.data-files-folder }}\` | | **Version** | \`${{ inputs.version }}\` | | **Source** | ${{ github.repository }}@\`$(echo ${{ github.sha }} | head -c 12)\` | EOF From c0a799b7ffa729bdfa987a73f427f4edb3aa4e13 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Wed, 15 Apr 2026 15:38:48 +0200 Subject: [PATCH 3/3] ci: update example to use GitHub App token pattern The calling workflow mints a short-lived token via actions/create-github-app-token and passes it as a plain secret. This avoids needing App credentials inside the reusable workflow. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/sync-upstream-cli.yml | 30 ++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/.github/workflows/sync-upstream-cli.yml b/.github/workflows/sync-upstream-cli.yml index 74fc34b1ffa..bc3298b86d1 100644 --- a/.github/workflows/sync-upstream-cli.yml +++ b/.github/workflows/sync-upstream-cli.yml @@ -4,10 +4,16 @@ # 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: +# 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: -# generate: +# docs-yaml: # runs-on: ubuntu-latest # steps: # - uses: actions/checkout@v5 @@ -17,9 +23,23 @@ # 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: generate +# needs: docs-yaml # uses: docker/docs/.github/workflows/validate-upstream.yml@main # with: # module-name: docker/buildx @@ -28,14 +48,14 @@ # # # On release — sync to docker/docs # sync: -# needs: generate +# 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: ${{ secrets.DOCS_GITHUB_TOKEN }} +# token: ${{ needs.token.outputs.token }} name: sync-upstream-cli