Skip to content

Add temporary changelog migrate-from-web command - #3794

Open
cotti wants to merge 3 commits into
changelog-retire-client-registry-refreshfrom
changelog-migrate-from-web
Open

Add temporary changelog migrate-from-web command#3794
cotti wants to merge 3 commits into
changelog-retire-client-registry-refreshfrom
changelog-migrate-from-web

Conversation

@cotti

@cotti cotti commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds docs-builder changelog migrate-from-web, the deliberately temporary one-off migration command tracked by elastic/docs-eng-team#736 (epic: elastic/docs-eng-team#656). It migrates release notes that were published before the changelog pipeline existed into the S3 bundle store, and will be deleted once the rollout (elastic/docs-eng-team#683) completes.

Design follows the direction set in the review on #3681: plain code, minimal surface, no new schemas/envelopes/frameworks, delete-after-use. The whole feature is one folder (src/services/Elastic.Changelog/Migration/, 3 files), one small checked-in config, and one CLI method — all marked TEMPORARY.

Note

Restacked 2026-08-06 onto the registry-ownership chain (#3738#3760 ← this): with the scrubber Lambda owning the public manifests and the client-side refresh retired, the command now writes YAML bundle objects only — the earlier best-effort RegistryBuilder refresh was removed, and tests assert no registry.json is ever PUT.

How it works

  1. Explicit scope — the product must have an entry in the checked-in config/migrate-from-web.yml (product id → owner/repo/path/ref/cutoff). Nothing runs implicitly for all products. --versions narrows a run further; versions above the cutoff are always skipped (they belong to the live pipeline).
  2. Fetch — downloads the release-notes Markdown from raw.githubusercontent.com at the pinned commit SHA in the config.
  3. Map — parses ## {version} sections (typed ### … subsections → BundledEntry with PR references extracted; prose → bundle description, preserved verbatim) into the existing Bundle shape that changelog upload publishes. No new fields or schemas.
  4. Create-only upload — writes bundle/{product}/{version}.yaml with If-None-Match: *. Existing keys are skipped (identical vs. different content is distinguished via ETag), 412 races are reported as skips, nothing is ever overwritten. No registry writes: the scrubber Lambda materializes bundle/{product}/registry.json and the shallow per-tree maps from the S3 events these creates emit (Move public changelog registry ownership to the scrubber Lambda #3738; client-side refresh retired in Retire the client-side changelog registry refresh #3760).
  5. Run report — one line per key (created / would-create / skipped / failed + reason + ETag), printed as a Markdown table ready to paste into the tracking issue.

Content source: Markdown at a pinned ref, not live HTML

Per the issue's preference, the command fetches the raw Markdown that backed the published pages instead of scraping elastic.co HTML: it is the authoritative source (the site is rendered from it), structured (headings/bullets/PR links survive intact), and a pinned SHA makes runs reproducible. For the EDOT Java pilot the config pins 9a61ce4f, the last hand-authored state of docs/release-notes/index.md before elastic/elastic-otel-java#1023 switched that repo to native bundle YAMLs.

Create-only mechanism

HEAD (GetObjectMetadata) first — so skips can report the existing object's ETag and whether content is identical — then a conditional PutObject with If-None-Match: * as the actual race guard (a concurrent create surfaces as HTTP 412 and is reported as a skip). This mirrors the machinery from the closed #3715 but implemented locally in the temporary service to keep shared surface area at zero.

Running the EDOT Java pilot

# credential-free dry run (parses, maps, reports; no S3 access at all)
docs-builder changelog migrate-from-web edot-java --dry-run

# dry run against the real bucket (distinguishes would-create from skipped)
docs-builder changelog migrate-from-web edot-java --dry-run --s3-bucket-name <bucket>

# the real thing
docs-builder changelog migrate-from-web edot-java --s3-bucket-name <bucket>

Actual dry-run output (abridged — 13 releases parsed, 1.0.0 through 1.10.0):

### Run report: changelog migrate-from-web

- product: `edot-java`
- source: `elastic/elastic-otel-java@9a61ce4faaf08e272c433a083bcc6f0e96d80e0a` `docs/release-notes/index.md`
- cutoff: `1.10.0`
- mode: dry-run (no S3 writes)

| key | outcome | etag | detail |
|---|---|---|---|
| `bundle/edot-java/1.0.0.yaml` | would-create | `0d143b466fb7539fb572655fd6405581` | no bucket specified; existence not checked |
| ... | | | |
| `bundle/edot-java/1.9.0.yaml` | would-create | `fe5fc47886d346de106d7b0057eaea49` | no bucket specified; existence not checked |

totals: would-create 13

Temporary

The command, its service folder, config file, and docs page are all explicitly marked TEMPORARY (help text, XML docs, docs page warning) and will be removed after elastic/docs-eng-team#683.

Test plan

  • Parser: realistic EDOT Java-style Markdown fixture → bundle mapping (versions, release dates, entry types, PR-link variants incl. bare #123 refs, prose preservation, unrecognized-subsection warnings, serialized YAML round-trips through ReleaseNotesSerialization)
  • Create-only: first run creates every in-scope key with If-None-Match: *; second run over the same scope is a no-op (all skips, zero PUTs)
  • Existing key with different content is skipped, never overwritten; concurrent-create 412 reported as skip
  • Failure reporting: per-key failed with reason, non-zero exit
  • Cutoff and --versions scope filtering
  • Dry-run with and without bucket; no writes either way; no S3 access at all without a bucket
  • All fixtures in-memory (fake S3 client, stub HTTP handler, mock filesystem) — no network in tests
  • Never writes a registry.json (asserted after the restack onto Retire the client-side changelog registry refresh #3760)
  • dotnet format clean · ./build.sh build --skip-dirty-check ✓ · AOT publish zero warnings ✓ · Elastic.Changelog.Tests 877/877 on the restacked chain ✓ · cli-schema.json regenerated and verified ✓

Refs: elastic/docs-eng-team#736, elastic/docs-eng-team#656, elastic/docs-eng-team#683

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

Label error. Requires exactly 1 of: automation, breaking, bug, changelog:skip, chore, ci, dependencies, documentation, enhancement, feature, fix, redesign. Found:

cotti added 3 commits August 6, 2026 12:36
Restacked on the scrubber-ownership chain: the scrubber Lambda owns the
public bundle/{product}/registry.json manifests and the shallow per-tree
maps (#3738), and the client-side refresh machinery is retired (#3760).
The migration command now writes YAML bundle objects only; the S3 events
those creates emit trigger the reconciliation that materializes the
manifests. Tests assert no registry.json is ever PUT.
@cotti
cotti force-pushed the changelog-migrate-from-web branch from 45a28a0 to e9c26c7 Compare August 6, 2026 15:44
@cotti
cotti changed the base branch from main to changelog-retire-client-registry-refresh August 6, 2026 15:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant