Add docs-changelog-commit and docs-changelog-generate workflows and accompanying actions#21
Add docs-changelog-commit and docs-changelog-generate workflows and accompanying actions#21
Conversation
…ccompanying actions
reakaleek
left a comment
There was a problem hiding this comment.
I think we should put these actions in a top-level changelog folder.
IMO, that the commands are based on docs-builder is an implementation detail that could change in the future.
Nevertheless, GJ.
| group: changelog-commit-${{ github.event.workflow_run.head_branch || github.run_id }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: |
There was a problem hiding this comment.
IMO, I would like to see a reusable workflow, where you can add in input and decide, if you want a commit or a comment.
There was a problem hiding this comment.
Not saying you need the comment logic today. But the ability to easily extend it without the need to change the consumer workflow.
There was a problem hiding this comment.
Gonna test a bit more on the playground to make sure it's ok, but I believe it's done.
|
The changelog we commit should be minimal: https://github.com/elastic/docs-eng-playground/pull/48/changes/9d141c10e4994b69e91454bcf059b0045be34a0f We can embedd a single line comment to the docs perhaps? |
| @@ -0,0 +1,38 @@ | |||
| name: Changelog | |||
There was a problem hiding this comment.
| name: Changelog | |
| name: Changelog generate |
| on: | ||
| workflow_call: | ||
| inputs: | ||
| config: |
There was a problem hiding this comment.
Our onboarding guides should leave this out, treat as expert option.
Still sets it explicitly
| description: 'Path to changelog.yml configuration file' | ||
| type: string | ||
| default: 'docs/changelog.yml' | ||
| strip-title-prefix: |
There was a problem hiding this comment.
I think this default is different from the CLI?
I think it makes sense for this to be true? cc @lcawl
| description: 'Remove [Prefix]: from PR titles' | ||
| type: boolean | ||
| default: false | ||
| changelog-dir: |
There was a problem hiding this comment.
This should not be settable here, folks need to use the config to set this.
There was a problem hiding this comment.
Correct, folks can configure the changelog directory in the config file's bundle.directory per https://github.com/elastic/docs-builder/blob/main/config/changelog.example.yml
changelog/generate/action.yml
Outdated
| --output /tmp/changelog-staging \ | ||
| --config "$CONFIG_FILE" \ | ||
| --title "$PR_TITLE" \ | ||
| --type "$PR_TYPE" |
There was a problem hiding this comment.
remove this, let changelog add do the logic to figure it out.
changelog/commit/action.yml
Outdated
| github-token: | ||
| description: 'GitHub token with contents:write and pull-requests:write' | ||
| default: '${{ github.token }}' | ||
| artifact-name: |
There was a problem hiding this comment.
Should this be configurable? its always a fixed name no?
changelog/submit/action.yml
Outdated
| commit it to the PR branch (or post as comment), and update the PR. | ||
|
|
||
| inputs: | ||
| run-id: |
There was a problem hiding this comment.
Should this be configurable? e.g when do we not want the default?
| mkdir -p "$CHANGELOG_DIR" | ||
| cp "/tmp/changelog-result/${PR_NUMBER}.yaml" "$CHANGELOG_FILE" | ||
|
|
||
| git config user.name "github-actions[bot]" |
There was a problem hiding this comment.
do these need to be set? is it not the default already?
| // Runs before any expensive operations (checkout, docs-builder setup). | ||
| module.exports = async ({ github, context, core }) => { | ||
| const labels = context.payload.pull_request.labels.map(l => l.name); | ||
| if (labels.includes('changelog:skip')) { |
There was a problem hiding this comment.
not universal, we need to flow this through docs-builder who can read the config
changelog/commit/scripts/evaluate.js
Outdated
|
|
||
| const labels = pr.labels.map(l => l.name); | ||
| if (labels.includes('changelog:skip')) { | ||
| core.info('changelog:skip label found on PR, aborting.'); |
There was a problem hiding this comment.
Note that the rules.create might be "only create changelog if xxx labels are present" (include option) or else "only create changelog if XXX labels are NOT present (exclude option). Likewise there are rules that apply only for specific product values. I think this action needs to handle those situations too.
changelog/README.md
Outdated
|
|
||
| ### 3. Create the labels | ||
|
|
||
| Make sure the GitHub labels referenced in your `docs/changelog.yml` exist in your repository. You also need a `changelog:skip` label for PRs that should not generate a changelog entry. |
There was a problem hiding this comment.
| Make sure the GitHub labels referenced in your `docs/changelog.yml` exist in your repository. You also need a `changelog:skip` label for PRs that should not generate a changelog entry. | |
| Make sure the GitHub labels referenced in your `docs/changelog.yml` exist in your repository. | |
| You also need a labelling strategy for situations where pull requests should not generate a changelog entry. |
At the moment, we can refer them to https://elastic.github.io/docs-builder/contribute/changelog/#rules-for-creation-and-publishing for more info, though I'm updating that path in one of my outstanding PRs.
changelog/README.md
Outdated
| v | ||
| generate workflow (read-only) | ||
| | | ||
| +-- skip if changelog:skip label is present |
There was a problem hiding this comment.
Per my earlier comment, this should ideally support both include/exclude rules:
| +-- skip if changelog:skip label is present | |
| +-- skip if "exclude" labels are present (or "include" labels are absent, depending on label strategy) |
changelog/README.md
Outdated
|
|
||
| ## Skipping changelog generation | ||
|
|
||
| Add the `changelog:skip` label to a PR to skip changelog generation entirely. The generate action will exit early and no artifact or commit is produced. |
There was a problem hiding this comment.
| Add the `changelog:skip` label to a PR to skip changelog generation entirely. The generate action will exit early and no artifact or commit is produced. | |
| Optionally add labels to a PR to skip changelog generation entirely. The generate action will exit early and no artifact or commit is produced. |
Per my other comments, this needs to handle all the options we provide in https://elastic.github.io/docs-builder/contribute/changelog/#rules-reference
|
|
||
| ## Output | ||
|
|
||
| Each PR produces a file at `docs/changelog/{PR_NUMBER}.yaml` on the PR branch. These files are consumed by `docs-builder` during documentation builds to produce a rendered changelog page. |
There was a problem hiding this comment.
Each PR produces a file at
docs/changelog/{PR_NUMBER}.yamlon the PR branch. These files are consumed bydocs-builderduring documentation builds to produce a rendered changelog page.
Per Martijn's comments elsewhere, I think this needs to accommodate the different file output names (https://elastic.github.io/docs-builder/contribute/changelog/#filenames) and file output directories (per config file). IMO we should expect them to have those choices defined in the config file rather than trying to support via command options.
|
I added a few comments, but one thing I couldn't tell from perusing the PR was where/if the Questions:
Per comments in our stand-up today, this might be a reason to quickly add support for "label -> product" mappings in the changelog configuration file so that this can optionally be derived similar to how we're deriving type, area, etc.
|
| CONFIG_FILE: ${{ inputs.config }} | ||
| run: | | ||
| mkdir -p /tmp/changelog-staging | ||
| docs-builder changelog add \ |
There was a problem hiding this comment.
If you want this command to generate PR-number filenames, it'll also need the --use-pr-number option per https://docs-v3-preview.elastic.dev/elastic/docs-builder/tree/main/cli/release/changelog-add. By default the command creates the kind of filenames Elastic Agent currently uses (timestamp plus title) but I suspect most teams will choose to use PR numbers like Elasticsearch does.
We don't currently have a way to set this in the changelog config, so want to leave it configurable we can add that.
There was a problem hiding this comment.
Pull request overview
Adds fork-safe changelog automation for PRs by introducing reusable workflows and composite actions that generate a changelog YAML entry via docs-builder, then either commit it to the PR branch or post it as an idempotent PR comment.
Changes:
- Added composite actions for generating a changelog artifact and submitting it (commit/comment) based on validated PR state.
- Added three GitHub Script helpers to post/update PR comments for success, comment-only mode, and “no matching label” failures.
- Added reusable workflows and documentation to support adoption by downstream repositories.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
changelog/generate/action.yml |
Composite action to evaluate PR metadata, generate YAML, and upload artifact. |
changelog/submit/action.yml |
Composite action to download artifact, re-validate, commit to PR branch or comment, and post status comments. |
changelog/submit/scripts/post-success-comment.js |
Posts/updates PR comment linking to committed changelog file. |
changelog/submit/scripts/post-comment-only.js |
Posts/updates PR comment containing the YAML content inline. |
changelog/submit/scripts/post-failure-comment.js |
Posts/updates PR comment guiding label selection when no type matches. |
.github/workflows/changelog-generate.yml |
Reusable workflow wrapper for the generate composite action. |
.github/workflows/changelog-submit.yml |
Reusable workflow wrapper for the submit composite action. |
changelog/README.md |
Adoption/setup docs explaining the two-workflow model and configuration. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const { data: comments } = await github.rest.issues.listComments({ | ||
| owner, repo, issue_number, per_page: 100, | ||
| }); | ||
| const existing = comments.find(c => | ||
| c.user?.login === 'github-actions[bot]' && | ||
| c.body?.startsWith(title) | ||
| ); |
There was a problem hiding this comment.
The script only fetches the first 100 PR comments. If a PR has more than 100 comments and the bot comment is older, existing may not be found and the action will create a duplicate comment instead of updating. Use Octokit pagination (e.g., github.paginate) or loop through pages until the matching comment is found.
| const { data: comments } = await github.rest.issues.listComments({ | ||
| owner, repo, issue_number, per_page: 100, | ||
| }); | ||
| const existing = comments.find(c => | ||
| c.user?.login === 'github-actions[bot]' && | ||
| c.body?.startsWith(title) | ||
| ); |
There was a problem hiding this comment.
The script only fetches the first 100 PR comments. On PRs with >100 comments, the existing bot comment may not be returned and the action can create duplicates. Consider using Octokit pagination (github.paginate) or iterating pages until the existing comment is found.
| const { data: comments } = await github.rest.issues.listComments({ | ||
| owner, repo, issue_number, per_page: 100, | ||
| }); | ||
| const existing = comments.find(c => | ||
| c.user?.login === 'github-actions[bot]' && | ||
| c.body?.startsWith(title) | ||
| ); |
There was a problem hiding this comment.
The script only fetches the first 100 PR comments. If the bot comment is not in the first page, this will post a new comment rather than updating, breaking the “idempotent” behavior. Use Octokit pagination (github.paginate) or page through results until the matching comment is found.
| - name: Download artifact | ||
| id: download | ||
| continue-on-error: true | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| name: changelog-result | ||
| path: /tmp/changelog-result | ||
| run-id: ${{ github.event.workflow_run.id }} | ||
| github-token: ${{ inputs.github-token }} | ||
|
|
||
| - name: Setup docs-builder | ||
| if: steps.download.outcome == 'success' | ||
| uses: elastic/docs-actions/docs-builder/setup@v1 | ||
| with: | ||
| version: latest | ||
| github-token: ${{ inputs.github-token }} | ||
|
|
There was a problem hiding this comment.
actions/download-artifact is marked continue-on-error: true, but if the artifact download fails the rest of the action is skipped and the workflow still succeeds without leaving any signal (no failure, no PR comment). This will make misconfigurations or transient artifact issues hard to detect; consider failing the action when download fails, or adding an explicit step that reports the failure (and optionally comments) when steps.download.outcome != 'success'.
| github-token: | ||
| description: 'GitHub token with contents:write and pull-requests:write' | ||
| default: '${{ github.token }}' | ||
| comment-only: | ||
| description: 'Post changelog as a PR comment instead of committing to the branch' | ||
| default: 'false' |
There was a problem hiding this comment.
The github-token input description mentions contents:write and pull-requests:write, but this action also needs actions:read to download artifacts from the generating workflow run. Updating the description (or documenting required permissions) would prevent confusing “artifact not found/unauthorized” failures for adopters.
| jobs: | ||
| generate: | ||
| if: github.event.pull_request.state == 'open' | ||
| runs-on: ubuntu-latest |
There was a problem hiding this comment.
This reusable workflow doesn’t set explicit permissions. If an adopting repo relies on the default GITHUB_TOKEN permissions, the generate job could run with broader rights than intended in PR context. Consider declaring minimal permissions here (e.g., contents: read plus any required read scopes) so the called workflow enforces least-privilege even when callers forget to set permissions.
| runs-on: ubuntu-latest | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: read |
| name: Changelog submit | ||
|
|
||
| on: | ||
| workflow_call: | ||
| inputs: | ||
| comment-only: | ||
| description: 'Post changelog as a PR comment instead of committing to the branch' | ||
| type: boolean | ||
| default: false | ||
|
|
||
| concurrency: | ||
| group: changelog-submit-${{ github.event.workflow_run.head_branch || github.run_id }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| submit: | ||
| if: > | ||
| github.event.workflow_run.event == 'pull_request' | ||
| && github.event.workflow_run.conclusion == 'success' | ||
| runs-on: ubuntu-latest |
There was a problem hiding this comment.
This reusable workflow doesn’t declare permissions, even though it needs at least actions: read to download artifacts and typically contents: write / pull-requests: write to commit and comment. Adding an explicit permissions block here enforces least privilege and makes adoption less error-prone (callers can still further restrict but not expand).
Summary
Add changelog automation for pull requests, powered by
docs-builderCLI commands.When a PR is opened, labeled, or has its title edited, this automation generates a changelog YAML file based on the PR metadata and label-to-type mappings defined in
docs/changelog.yml. The generated file is committed to the PR branch (or posted as a comment, depending on configuration).What's included
Two composite actions:
changelog/generate— Runs in read-only PR context. Evaluates PR metadata against the changelog config (docs-builder changelog evaluate-pr), generates a changelog entry (docs-builder changelog add), and uploads the result as an artifact (docs-builder changelog prepare-artifact).changelog/submit— Runs with write permissions viaworkflow_run. Downloads the artifact, re-validates PR state (docs-builder changelog evaluate-artifact), and either commits the file to the PR branch or posts it as a PR comment.Two reusable workflows:
.github/workflows/changelog-generate.yml.github/workflows/changelog-submit.ymlAdopting repositories call these reusable workflows — they don't need to reference the composite actions directly.
Three PR comment scripts:
post-success-comment.js— Links to the committed changelog file with view/edit URLs.post-comment-only.js— Renders the changelog content inline as a code block (for forks or opt-in comment-only mode).post-failure-comment.js— Lists available type labels when no matching label is found.Design decisions
contents: readfrom the PR context. The submit workflow runs fromworkflow_runwith write permissions on the base branch. This follows the standard pattern for preventing privilege escalation from fork PRs. Fork PRs automatically fall back to comment-only mode.docs-builder. PR evaluation, artifact preparation, and artifact validation are handled by three newdocs-builderCLI commands (evaluate-pr,prepare-artifact,evaluate-artifact). The action YAML is a thin orchestration layer — it passes GitHub context to the CLI and routes outputs to the appropriate steps.rules.createindocs/changelog.yml. Nothing is hardcoded in the actions. See Rules for creation and publishing.HEADmatches the expected SHA from the artifact metadata. This prevents writing to the wrong branch if the ref has drifted.github-actions[bot]), the automation skips regeneration to preserve manual changes.github-actions[bot]login filtering andper_page: 100pagination.New files
changelog/generate/action.ymlchangelog/submit/action.ymlchangelog/submit/scripts/post-success-comment.jschangelog/submit/scripts/post-comment-only.jschangelog/submit/scripts/post-failure-comment.js.github/workflows/changelog-generate.yml.github/workflows/changelog-submit.ymlchangelog/README.mdDependencies
This PR depends on three new
docs-builderCLI commands:docs-builder changelog evaluate-prdocs-builder changelog prepare-artifactdocs-builder changelog evaluate-artifactThese are being added in a separate
docs-builderPR.How to adopt
docs-builder changelog initin your repo to createdocs/changelog.yml.See
changelog/README.mdfor full setup instructions.