Skip to content

Move /learn to pulumi/marketing-web; retire /tutorials and /templates - #21095

Open
jeffmerrick wants to merge 9 commits into
masterfrom
jeffmerrick/learn-site-migration
Open

Move /learn to pulumi/marketing-web; retire /tutorials and /templates#21095
jeffmerrick wants to merge 9 commits into
masterfrom
jeffmerrick/learn-site-migration

Conversation

@jeffmerrick

@jeffmerrick jeffmerrick commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Warning

Don't merge until /learn is live from pulumi/marketing-web. content/tutorials/ and content/templates/ are deleted here and their URLs 301 into /learn, which 404s until that ships.

Proposed changes

Learn - tutorials, official templates, community examples, and a glossary - now ships from pulumi/marketing-web (apps/www) at /learn, with its own S3 + CloudFront. This is the pulumi/docs half of that cutover.

  • infrastructure/index.ts gains a /learn* behavior pointed at the Learn stack's cloudFrontDomain, the same shape as /registry and /guides. It uses the thirty-minute cache policy since that one keys on Accept, which the Learn origin needs - it rewrites a page URL to its .md twin when the viewer asks for markdown. learnStack is optional, so dev stacks and PR previews are unchanged.
  • content/tutorials/ (48 pages, 13 glossary terms) and content/templates/ (23 pages) are deleted, along with the collections taxonomy and the layouts, shortcodes, archetypes, scaffolding scripts, and SCSS that only served them.
  • scripts/redirects/learn-redirects.txt is 99 301s. Slugs are 1:1 on the other side, so only the section prefix changes. Every target was checked against a local build of apps/www.
  • Links outside content/blog/ now point at /learn; blog rides the 301s, per AGENTS.md. The exception is six architecture.png references in walkthrough-of-adopting-infrastructure-as-code - those are assets rather than pages and no redirect covers them, so the images moved into the post's bundle.
  • /learn is not in the Algolia index and has no facet in the docs search box, since it has its own search at /learn/browse.
  • robots.txt gets a second Sitemap: directive for /learn/sitemap-index.xml, since nesting one sitemap index inside another isn't defined by the spec.
  • data/footer.yml and data/header_nav.yaml are read by marketing-web's scripts/sync-content.mjs, so the nav change also lands on Learn's own chrome.
  • run-pulumi.sh adds /learn/* to the post-deploy CloudFront invalidation. /tutorials/* stays, since the pre-cutover HTML still needs flushing.

Still open

  • Redirects for the old /learn/... alias URLs (/learn/pulumi-fundamentals/ and friends) still need to land in pulumi/marketing-web. Hugo answers them today; once /learn* proxies away, this repo can't. They're recorded there as aliases frontmatter on the ported pages.
  • Three master changes edited tutorial and template pages that are deleted here, so they need applying to the ported copies in marketing-web. None of them break anything in the meantime. Administration IA phase 1: re-shelve the SaaS side into get-started / concepts / guides / reference #21056 moved /docs/administration/access-identity/access-tokens/ to /docs/administration/concepts/access-tokens/ and updated four links to it across three ESC tutorials - the old path is aliased on the new page, so those redirect rather than 404. fix(seo): normalize Pulumi language lists on gads landing pages, templates, and brand-consistency surfaces #20919 normalized the Pulumi language list in meta_desc on 16 template pages. Fix internal links to old /docs/concepts/ URLs (redirect-hop cleanup) #21072 pointed internal links at current /docs paths on 10 tutorial pages, removing a redirect hop. The full diffs are in .context/marketing-web-carryover.md in the workspace.
  • layouts/partials/schema/utils/related-content.html is deleted here and was edited by Fix latent @id mismatches in unwired product-entities.html / related-content.html #21071 (@id and @type corrections). Nothing in layouts/ or scripts/ references that partial on master either, so the fix was to a file that never rendered.
  • learnStack is set on www-production only, so /learn 404s on www.pulumi-test.io and the cutover can't be smoke-tested there. Pointing it somewhere needs a marketing-web testing stack - is there one?
  • A comment-stripping pass over the branch took out two notes that documented non-obvious constraints: why /learn* has no trailing slash, and that the cascade path in config.yml matches the logical taxonomy path (/industry/...) rather than the permalink (/case-studies/industry/...). Neither is in the branch now, open for discussion.

Related issues

pulumi/marketing-web#82

jeffmerrick and others added 3 commits August 24, 2026 09:51
Learn — tutorials, official templates, community examples, and a glossary —
now ships from pulumi/marketing-web (apps/www) at /learn, with its own S3 +
CloudFront (pulumi/marketing-web#82). www.pulumi.com is otherwise Hugo out of
this repo, so this is the pulumi/docs half of the cutover.

Routing. infrastructure/index.ts gains a /learn* behavior pointed at the Learn
stack's cloudFrontDomain, the same shape as /registry and /guides. It uses the
thirty-minute policy because that one keys on Accept: the Learn origin rewrites
a page URL to its .md twin when the viewer asks for markdown, and the two
representations must not collide in the apex cache. learnStack is optional, so
dev stacks and PR previews are unchanged.

Content. content/tutorials/ (48 pages + 13 glossary terms) and
content/templates/ (23 pages) are deleted along with their layouts, partials,
shortcodes, archetypes, scaffolding scripts, SCSS, data files, and the
`collections` taxonomy. Slugs are 1:1 on the other side, so
scripts/redirects/learn-redirects.txt is 99 301s: /tutorials/<path>/ →
/learn/tutorials/<path>/, /templates/<path>/ → /learn/official-templates/<path>/,
the glossary to /learn/glossary/, the six collection term pages to their browse
facet landings, and the frontmatter aliases those pages carried. Every target
was checked against a local build of apps/www.

Links. Everything outside content/blog/ now points at /learn (blog rides the
301s, per AGENTS.md). The one exception is six architecture.png references in
walkthrough-of-adopting-infrastructure-as-code: those are assets, not pages, and
no redirect covers them, so the images moved into the post's bundle.

Search still covers docs and the Registry only — /learn has its own search at
/learn/browse and is not merged into the Algolia index. What goes is the dead
scaffolding the deleted pages leave behind: the Tutorials and Templates section
mappings in page.js, the /templates ranking rule, the Tutorials facet in the
docs search box, and its icon.

robots.txt gets a second Sitemap: directive for /learn/sitemap-index.xml — a
separate directive rather than an entry in ours, since nesting one sitemap index
inside another isn't defined by the spec — plus a pointer to /learn/llms.txt.

Nav keeps its Templates slot (now /learn/official-templates/) and the Tutorials
entry becomes Learn. Both files are synced downstream by marketing-web, so
Learn's own chrome picks the change up.

Still to land in pulumi/marketing-web: redirects for the old /learn/... alias
URLs (/learn/pulumi-fundamentals/ and friends). Those are Hugo aliases today;
once /learn* proxies away, this repo can't answer them. The provenance is
already recorded there as `aliases` frontmatter on the ported pages.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The Azure and Kubernetes get-started pages linked /learn/pulumi-fundamentals,
which was a Hugo alias of the old /tutorials page rather than a real URL. Now
that /learn* proxies away, this repo can't answer it, so both point at the
canonical /learn/tutorials/pulumi-fundamentals/. That leaves content/docs/ with
no link that depends on an alias being ported downstream.

run-pulumi.sh invalidates /registry/* and /guides/* after a deploy but had no
/learn/*, which is now cached at the apex for thirty minutes like the other two.
/tutorials/* stays, since the pre-cutover HTML still needs flushing.

The Vale file filter in the three claude-* workflows still matched
content/tutorials/.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Comments that restate the code they sit on, in the files this branch touched:
the /learn origin and behavior block in infrastructure/index.ts (the same shape
as /registry and /guides directly above it), the section headers in
learn-redirects.txt, four in howto-entity.html, and the menu-tree list item.

Two carried something real and are gone anyway, worth a look before merge:
"/learn* has no trailing slash on purpose" and the cascade `path` note in
config.yml (it matches the logical taxonomy path /industry/..., not the
permalink /case-studies/industry/...).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@jeffmerrick
jeffmerrick marked this pull request as ready for review August 24, 2026 15:28
@github-actions github-actions Bot added review:triaging Claude Triage is currently classifying the PR domain:website PR touches marketing, pricing, legal, or competitive landing pages domain:docs PR touches technical docs domain:mixed PR touches more than one domain domain:infra PR touches workflows, scripts, infra, Makefile, or build config domain:blog PR touches blog posts or customer stories review:oversized Diff too large for automated review (generated corpora); skips Claude review labels Aug 24, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📦 Oversized PR — this diff (+295/−19935 across 100 files) exceeds the automated review budget, so the Claude review is skipped (review:oversized).

A diff this size is usually mostly generated output, which an automated line-review can't finish (and wouldn't add value to). What works better:

  • Split the hand-written source (scripts, workflows, layouts, templates) into its own PR — that PR gets a normal full review.
  • Have a human spot-check a sample of the generated output here.

@claude #new-review still force-runs a full review, but on a diff this size it will likely hit the job timeout.

@github-actions github-actions Bot removed the review:triaging Claude Triage is currently classifying the PR label Aug 24, 2026

@unblocked unblocked Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No issues found

About Unblocked

Unblocked has been set up to automatically review your team's pull requests to identify genuine bugs and issues.

📖 Documentation — Learn more in our docs.

💬 Ask questions — Mention @unblocked to request a review or summary, or ask follow-up questions.

👍 Give feedback — React to comments with 👍 or 👎 to help us improve.

⚙️ Customize — Adjust settings in your preferences.

…ite-migration

# Conflicts:
#	content/tutorials/esc-managed-chatapp/index.md
#	content/tutorials/esc-setup-psp-creds/index.md
#	content/tutorials/esc-version-tagging/index.md
…ite-migration

# Conflicts:
#	content/templates/container-service/aws/index.md
#	content/templates/container-service/azure/index.md
#	content/templates/container-service/gcp/index.md
#	content/templates/kubernetes-application/helm-chart/index.md
#	content/templates/kubernetes-application/web-application/index.md
#	content/templates/kubernetes/aws/index.md
#	content/templates/kubernetes/azure/index.md
#	content/templates/kubernetes/gcp/index.md
#	content/templates/serverless-application/aws/index.md
#	content/templates/serverless-application/azure/index.md
#	content/templates/serverless-application/gcp/index.md
#	content/templates/static-website/azure/index.md
#	content/templates/static-website/gcp/index.md
#	content/templates/virtual-machine/aws/index.md
#	content/templates/virtual-machine/azure/index.md
#	content/templates/virtual-machine/gcp/index.md
#	content/tutorials/building-with-pulumi/secrets/index.md
#	content/tutorials/creating-resources-aws/index.md
#	content/tutorials/creating-resources-azure/index.md
#	content/tutorials/creating-resources-gcp/index.md
#	content/tutorials/creating-resources-kubernetes/index.md
#	content/tutorials/inspecting-infrastructure/index.md
#	content/tutorials/pulumi-fundamentals/create-a-pulumi-project/index.md
#	content/tutorials/stack-outputs-refs-aws/index.md
#	content/tutorials/stack-outputs-refs-azure/index.md
#	content/tutorials/stack-outputs-refs-gcp/index.md
#	layouts/partials/schema/utils/related-content.html
#	layouts/partials/tutorials/right-nav-ad.html
…ite-migration

# Conflicts:
#	archetypes/templates/template/index.md
#	archetypes/templates/type/_index.md
#	archetypes/tutorials/module/_index.md
#	archetypes/tutorials/single/index.md
#	archetypes/tutorials/topic/index.md
workprentice Bot pushed a commit that referenced this pull request Aug 26, 2026
…nt/blog

Part of #20958. Lowercases 130 mid-sentence, generic-concept
occurrences of 'Infrastructure as Code' / 'Infrastructure-as-Code'
across 65 blog posts, flagged by the Pulumi.Overcapitalization Vale
rule shipped in PR #20983.

Deliberately left capitalized (2 occurrences, genuine proper-noun
exceptions):
- announcing-speaker-lineup-pulumiup-2023/index.md: a talk title
  ('Using Monorepos to Level-up your Infrastructure as Code...').
- platform-engineering-pillars-1/index.md: a quoted article title
  ('Platform Engineering: Recommended Practices for Infrastructure
  as Code').

Excluded from this sweep because an open PR is concurrently editing
the same file (left for the author of that PR / a follow-up):
- infrastructure-as-code-tools/index.md (PR #21065)
- walkthrough-of-adopting-infrastructure-as-code/index.md (PR #21095)
- aws-cdk-vs-pulumi-why-sst-switched/index.md (PR #21066)
jeffmerrick and others added 3 commits August 26, 2026 16:00
…ntry

Learn is one catalog over seven content types, so the header and footer carry
one entry for it rather than three that each land inside it.

- Header "For engineers" drops Templates (/learn/official-templates/) and
  Pulumi guides (/guides/); the remaining Learn entry points at /learn/.
- Footer Resources drops Templates and Guides on the same basis.
- The Learn icon moves from graduation-cap to compass. graduation-cap is
  reserved for Pulumi Academy; compass was freed by the Pulumi guides entry.
- The docs landing page's Learning Resources card points at /learn/ rather
  than /learn/tutorials/, and is relabeled to match.

/guides/ is still served — the guidesStack CloudFront behavior is untouched —
but is now unlinked from both nav surfaces. TAXONOMY.md records that alongside
its existing end-of-life note.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Header and footer: the Learn entry is now labeled "Learn Pulumi". The
  `header-engineers-learn` and `footer-learn` track values are unchanged, so
  the analytics series stays continuous.
- Header Get started: "Follow a step-by-step guide to quickly learn Pulumi"
  becomes "Install Pulumi and deploy your first project in minutes", taken from
  the target page's own meta_desc.

The docs sidebar and the docs landing card still read "Learn ↗" — out of scope
here, which was deliberate.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A dropdown description that wrapped left its final word alone on a line
("Browse 170+ cloud providers and / packages"). All 23 descriptions now join
their last two words with a literal non-breaking space (U+00A0).

The character rather than `&nbsp;`: partials/header/nav-dropdown-item.html
prints the value with `{{ . }}`, which escapes an entity into visible text.
It also survives the downstream sync — marketing-web's sync-content.mjs passes
`description` through JSON.stringify, which leaves U+00A0 as the character.

The characters are invisible in an editor, so the file header says they're
there and how to carry one into a new description.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
cnunciato added a commit that referenced this pull request Aug 27, 2026
…tent/blog (#21125)

* Fix mid-sentence 'Infrastructure as Code' overcapitalization in content/blog

Part of #20958. Lowercases 130 mid-sentence, generic-concept
occurrences of 'Infrastructure as Code' / 'Infrastructure-as-Code'
across 65 blog posts, flagged by the Pulumi.Overcapitalization Vale
rule shipped in PR #20983.

Deliberately left capitalized (2 occurrences, genuine proper-noun
exceptions):
- announcing-speaker-lineup-pulumiup-2023/index.md: a talk title
  ('Using Monorepos to Level-up your Infrastructure as Code...').
- platform-engineering-pillars-1/index.md: a quoted article title
  ('Platform Engineering: Recommended Practices for Infrastructure
  as Code').

Excluded from this sweep because an open PR is concurrently editing
the same file (left for the author of that PR / a follow-up):
- infrastructure-as-code-tools/index.md (PR #21065)
- walkthrough-of-adopting-infrastructure-as-code/index.md (PR #21095)
- aws-cdk-vs-pulumi-why-sst-switched/index.md (PR #21066)

* Address pre-merge review findings: casing mismatches and deprecated names

Fixes 7 issues flagged by the pre-merge review on PR #21125:
- 4 same-sentence casing mismatches left by the mechanical sweep
  (automation-api, going-beyond-with-advanced-infrastructure-as-code-use-cases
  x2, infrastructure-as-code-in-any-programming-language) where one
  occurrence of 'Infrastructure as Code' in a sentence was lowercased
  but a sibling occurrence in the same sentence/paragraph was missed.
- 2 deprecated product name references ('Pulumi Service' -> 'Pulumi
  Cloud', per STYLE-GUIDE.md SS Product Names) in
  esc-automation-api-pulumi-service-provider-launch and
  using-pulumi-securely.
- 1 nomenclature fix ('Pulumi Cloud Console' -> 'Pulumi Cloud console')
  in visual-import, per STYLE-GUIDE.md SS Product Names.

* Fix two more casing findings surfaced by update-review

Second round of pre-merge review findings on PR #21125:
- infrastructure-as-code-in-any-programming-language/index.md L24:
  a fifth same-line casing mismatch missed by the initial pass;
  lowercased the trailing mid-sentence occurrence.
- visual-import/index.md L48: the L90 fix left the identical phrase
  ('Pulumi Cloud Console') uncorrected 42 lines earlier; lowercased
  to match the canonical 'Pulumi Cloud console' spelling.

* Lowercase sentence-initial link anchor casing (L24)

Third round of pre-merge review findings on PR #21125:
infrastructure-as-code-in-any-programming-language/index.md L24 was
still carrying both casings after round 2 — the sentence-initial link
anchor [Infrastructure as Code] against the lowercase mid-sentence
occurrences later on the same line. Per the sentence-initial-anchor
convention already used elsewhere in content/blog (automation-api L13,
going-beyond... L18), only the second word needs lowercasing:
[Infrastructure as code].

* Fix conflict-resolution regression and new third-party-name findings

Corrects a mistake from the rebase conflict resolution: using-pulumi-securely/index.md
L45 had reverted master's identity-provider link modernization back to
stale /docs/administration/concepts/identity-providers/ URLs. Restored
master's current link paths while keeping this PR's casing fix, and
along the way fixed 'Github'/'Gitlab' to 'GitHub'/'GitLab' on the same
line and 'VMWare' to 'VMware' in pulumi-bloggers-oct-2019/index.md
(both heading and body) per styles/Pulumi/ThirdPartyNames.yml, which
the rebase pulled in from master and which now covers these lines.

* Fix VSphere to vSphere product-name casing (3 occurrences)

Vale's ThirdPartyNames.yml doesn't yet have a VSphere entry, but VMware
spells its own product 'vSphere' (lowercase v, capital S). All three
occurrences in pulumi-bloggers-oct-2019/index.md read 'VSphere'; fixed
to match VMware's own spelling and the rest of the site (vSphere
outnumbers VSphere 15:4 in content/).

* Apply suggestions from code review

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

---------

Co-authored-by: workprentice <257153108+workprentice@users.noreply.github.com>
Co-authored-by: Christian Nunciato <c@nunciato.org>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge domain:blog PR touches blog posts or customer stories domain:docs PR touches technical docs domain:infra PR touches workflows, scripts, infra, Makefile, or build config domain:mixed PR touches more than one domain domain:website PR touches marketing, pricing, legal, or competitive landing pages review:oversized Diff too large for automated review (generated corpora); skips Claude review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants