Skip to content

changelog: Add prs-artifact input for PR-list bundle filtering#235

Open
cotti wants to merge 3 commits into
mainfrom
feat/changelog-bundle-prs-profile-mode
Open

changelog: Add prs-artifact input for PR-list bundle filtering#235
cotti wants to merge 3 commits into
mainfrom
feat/changelog-bundle-prs-profile-mode

Conversation

@cotti

@cotti cotti commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Repos like elastic/cloud generate their shipped-PR list at release time (from a start/end commit range) and need to feed it into automated bundling. Today that isn't possible cleanly:

  • The prs input is option-mode only (mutually exclusive with profile), so it can't use a profile's output / output_products patterns, and PR-only option-mode bundles can't be fetched by changelog-bundle-pr.yml.
  • Passing a file requires it to be committed to the repo: bundle-create starts with its own actions/checkout, which resets the workspace, so a file produced by an earlier job or step never survives into the action.

This PR adds a prs-artifact input to bundle-create and the changelog-bundle.yml reusable workflow, following the artifact-handoff pattern already used across this pipeline (bundle-createbundle-upload, bundle-fetchbundle-pr, changelog-staging). The caller uploads a newline-delimited file of fully-qualified GitHub PR/issue URLs as a workflow artifact in the same run; bundle-create downloads it after its checkout and passes it to docs-builder:

  • Profile mode: as the positional filter-source argument (changelog bundle <profile> <version> <file>), the CLI's supported URL-list form — so {version}/{lifecycle} substitution, output_products, and the CDN entry sourcing all keep working, and changelog-bundle-pr.yml can still locate the bundle (it only needs profile + version; verified PlanBundleAsync never resolves the filter source).
  • Option mode: via --prs <file>.

Guardrails: prs-artifact is validated as an identifier and is mutually exclusive with prs, report, and release-version; the downloaded artifact must contain exactly one file and no symlinks; content validation (full GitHub URLs only, no PR/issue mixing) is enforced by docs-builder when the file is consumed.

Docs: updated the selection table (which previously referenced a prs mode without any example — spotted by @lcawl), added a copy-pasteable discover-prsbundle recipe, an inline option-mode prs example, and refreshed the bundle-create README.

Test plan

  • pre-commit run (check-yaml, actionlint, action-readme) passes — done locally
  • Dry-run from a sandbox repo: upload a prs.txt artifact in a discover job, call changelog-bundle.yml with profile + version + prs-artifact, confirm the bundle resolves the profile output pattern and uploads to S3
  • Confirm mutual-exclusivity errors fire when combining prs-artifact with prs/report/release-version

The bundle workflows could not consume a PR list generated at release
time: the prs input is option-mode only, and file paths must already be
committed because bundle-create's internal checkout resets the
workspace. Callers can now upload a newline-delimited URL list as a
workflow artifact and pass its name via prs-artifact; bundle-create
downloads it after checkout and feeds it to docs-builder as the
positional filter source in profile mode or via --prs in option mode.
@cotti
cotti requested a review from a team as a code owner July 14, 2026 17:52
@cotti
cotti requested a review from reakaleek July 14, 2026 17:52
- Detect the URL kind in the artifact and route option mode to --issues
  for issue lists; --prs put issue URLs into PrsToMatch where they
  silently matched nothing. Mixing kinds now fails fast in the action.
- Require version with profile + prs-artifact: without it the --plan
  step substitutes the file path into {version} while the real run uses
  "unknown", so the planned output path diverges and the upload fails.
- Make the README discover-prs example actually write prs.txt; the echo
  placeholder tripped if-no-files-found: error on the upload step.
@cotti

cotti commented Jul 14, 2026

Copy link
Copy Markdown
Contributor Author

Pushed fixes for the review feedback in 7127fea:

  • Issue lists in option mode: the resolve step now detects the URL kind (/pull/ vs /issues/) and passes --issues for issue lists; mixed files fail fast with a clear error. Confirmed against docs-builder source that --prs loads any URL into PrsToMatch (FilterLoaderUtilities.ReadUrlsFromFileAsync only checks IsUrl), so issue URLs previously produced silent empty bundles. Profile mode was already correct (ResolveUrlListFileAsync classifies and routes).
  • version required with profile + prs-artifact: validated explicitly. Worth noting the failure mode is worse than a {version} mismatch — PlanBundleAsync substitutes input.ProfileArgument (the file path) into the output pattern, while the real run resolves the file and uses unknown, so the planned path and the generated path always diverge.
  • README example: the discover job now genuinely writes prs.txt.

One pre-existing observation, out of scope here: profile + report without version has the same plan/run divergence (the report path becomes ProfileArgument in the plan step). If we want, a follow-up can extend the same validation to report, though that combination has existed since #42.

- Classify the URL list exhaustively with anchored patterns: every
  non-empty line must be a canonical GitHub PR or issue URL. The
  option-mode docs-builder loaders accept any http(s) line, so a
  partially valid file previously produced a silently partial bundle,
  and unanchored greps also matched URLs merely containing a
  github.com PR path.
- Fail explicitly on profile + prs and profile + release-version; the
  documented mutual exclusivity was unenforced and both inputs were
  silently dropped in profile mode.
- Correct the README claim that date-based versions work like stack
  versions: {lifecycle} inference treats 2026-07-07 as a prerelease
  ("preview"), so date-based profiles should omit {lifecycle}.
@cotti

cotti commented Jul 14, 2026

Copy link
Copy Markdown
Contributor Author

Pushed fixes for the second review round in 0f60444:

  • Exhaustive, anchored URL classification: every non-empty line must now match ^https://github.com/{owner}/{repo}/pull/{n}$ (or the /issues/ equivalent, with optional surrounding whitespace/CRLF tolerated). Verified locally against the three adversarial cases from the review (valid PR + non-GitHub URL, valid PR + issue-with-query-string, and a github.com/.../pull/ path embedded in another host) — all now fail fast with a count breakdown instead of classifying as prs. This matters most in option mode, where the docs-builder --prs/--issues loaders accept any http(s) line and would have produced a silently partial bundle.
  • profile + prs and profile + release-version now fail explicitly: the documented mutual exclusivity was unenforced — both inputs were silently dropped by the profile-mode argument builder, so the bundle would build (and upload) from the profile's products alone. The errors point at prs-artifact and source: github_release respectively as the supported alternatives. Same latent gap exists in bundle-fetch (also drops prs/release-version in profile mode) — left for a follow-up since this PR doesn't touch that action and its failure mode is more benign (fetch-by-plan, no generation).
  • {lifecycle} and date-based versions: confirmed — VersionLifecycleInference treats everything after the first hyphen as a prerelease moniker, so 2026-07-07 infers preview. Removed the misleading "works for dates alike" claim and added a note to omit {lifecycle} from patterns for date-based releases (matching cloud's current profile shape).

@Mpdreamz

Copy link
Copy Markdown
Member

Can you provide some background into how and when cloud creates these files?

  • is it automated?
  • how do they decide what's included and what's not?
  • do they do this before, during after git tagging the release.
  • is it a single file of mixed issues / pull requests?
  • at what stage do they do they need the bundling?

My gut sits uneasy with staging 'arbitrary' files between workflows. I don't like it with in the rare cases we do it for own usages too. Cache poisoning and other concers.

The --prs and --issues flags are an artifact of when we needed to render without feature loss. How do those flags relate to this PR?

@cotti

cotti commented Jul 14, 2026

Copy link
Copy Markdown
Contributor Author

Can you provide some background into how and when cloud creates these files?

* is it automated?

* how do they decide what's included and what's not?

* do they do this before, during after git tagging the release.

* is it a single file of mixed issues / pull requests?

* at what stage do they do they need the bundling?

From how Dominik mentioned, they are being generated from a release promotion as a list ranging from the start-commit to the end-commit of the intended release. Being commits, I suppose they are linked to their PRs. I'll check the timing.

My gut sits uneasy with staging 'arbitrary' files between workflows. I don't like it with in the rare cases we do it for own usages too. Cache poisoning and other concers.

I suppose a possible alternative would be doing the assessment of PRs ourselves by getting the refs to the beginning and end commits? But I'm not sure if this is further processed by them (or would be by anyone using a similar mechanism).

The --prs and --issues flags are an artifact of when we needed to render without feature loss. How do those flags relate to this PR?

The objective was to expose the artifact as a possible input, but the flags weren't involved in this PR.

@gigerdo

gigerdo commented Jul 15, 2026

Copy link
Copy Markdown
Member

To explain a bit our side of the process:

  • We are using argocd (echkube) to release services.
  • These use gitops, so to release another service we would update commit x to y, and then y will be deployed
  • After updating our main service (adminconsole) in production, I would like to automatically publish all changelogs that are included in that newly deployed commit (and not re-publish anything that was already included in a previously deployed commit).

My guess was that I would use git/github to calculate the list of PRs between previous commit and current, then run the bundler with that information. However my knowledge on the bundler is very limited, so let me know if there is a better way.

I have also heard about the github bundler workflow, but I'm unsure how I would integrate that one into the argocd deployment (but we could probably for example add a tag or something like that)

@lcawl

lcawl commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

In case it's helpful, this action will also apply to the kibana repo, where they're currently giving us the list of PRs in this format: https://github.com/elastic/kibana/actions/runs/29327282670/job/87066539375

For example:

image

I'm currently copying and pasting that list of PR URLs into a temporary local prs.txt file and following the steps described in PRs like elastic/kibana#278313. I'd love if my human intervention was no longer required (i.e. the list would be fed directly to the bundling action).

@Mpdreamz

Mpdreamz commented Jul 16, 2026

Copy link
Copy Markdown
Member

I just want to zoom in on that generate step, and whether that is something we can take ownership of, or at the very least do the same: query the prs between commits.

Especially with gitops we need it to be repeatable, atomic on our end too. I rather the handoff be from and to commit hashes.

Again gut reaction but I rather not build the process on an external list of PR's/issues. Unless that list is an immutable build artifact as well which is what we initially thought the serverless promotion job reports were. Which would have included more metadata too.

On PTO, back Monday so apologies if this is a bit of a drive by comment.

@gigerdo

gigerdo commented Jul 17, 2026

Copy link
Copy Markdown
Member

If you can directly allow two commits as input that is fine too. However I think generating PRs from commits is itself also stable and immutable, as you can add/remove PRs between two already merged commits.

One thing I forgot to mention: We also have the use-case of manually adding changelogs after the release when someone forgot to add their change. (or sometimes edit existing changelogs when the dev worded their change poorly) But for that we would manually open a PR and manually generate a new bundle for that changelog (and in that case the changelog would also be checked in at the same time).

@Mpdreamz

Copy link
Copy Markdown
Member

However I think generating PRs from commits is itself also stable and immutable, as you can add/remove PRs between two already merged commits.

Not sure I follow these hashes would both be from an protected integration branch? You can not rewrite the history on those and therefor don't add/remove PR's?

One thing I forgot to mention: We also have the use-case of manually adding changelogs after the release when someone forgot to add their change.

Aye! You can create bundle amend files at any point in time:

https://docs-v3-preview.elastic.dev/elastic/docs-builder/tree/main/contribute/bundle-changelogs#changelog-bundle-amend

These will be also synced to S3 and amend any immutable published bundle. This can be used to add/edit/remove entries.

@cotti cotti added the enhancement New feature or request label Jul 21, 2026
@gigerdo

gigerdo commented Jul 22, 2026

Copy link
Copy Markdown
Member

Not sure I follow these hashes would both be from an protected integration branch? You can not rewrite the history on those and therefor don't add/remove PR's?

Yeah I think you can never rewrite history in git. But in any case handing off two commits would be great for us. Actually even better would be one commit and it automatically detects all the PRs that have not been published so far :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants