diff --git a/.claude/commands/docs-review/references/blog.md b/.claude/commands/docs-review/references/blog.md index 38e82e83af77..4787f8f9a7db 100644 --- a/.claude/commands/docs-review/references/blog.md +++ b/.claude/commands/docs-review/references/blog.md @@ -114,7 +114,7 @@ Vale catches Pulumi product-name capitalization, the Pulumi Policies singular-ve When a blog post announces a new feature, provider, or significant capability: -- **Check that `/content/docs/` covers it.** Search for the feature name across `content/docs/`, `content/tutorials/`. If the only mention of the feature is the blog post itself, that's a finding. +- **Check that `/content/docs/` covers it.** Search for the feature name across `content/docs/`. If the only mention of the feature is the blog post itself, that's a finding. - **Note specific gaps.** Don't just say "docs are missing" — name the page that should exist (e.g., "no `content/docs/esc/integrations//` page found"). - **Suggest a doc type.** Reference / tutorial / concept guide / how-to — pick the one that matches the feature's nature. diff --git a/.claude/commands/docs-review/references/docs.md b/.claude/commands/docs-review/references/docs.md index 50e8eac8ef85..08da5e5f4b81 100644 --- a/.claude/commands/docs-review/references/docs.md +++ b/.claude/commands/docs-review/references/docs.md @@ -1,6 +1,6 @@ --- user-invocable: false -description: Review criteria for technical documentation under content/docs, content/tutorials, content/what-is. +description: Review criteria for technical documentation under content/docs and content/what-is. --- # Review — Docs diff --git a/.claude/commands/docs-review/references/domain-routing.md b/.claude/commands/docs-review/references/domain-routing.md index 2f2cd2bd4138..fcddac4d26f1 100644 --- a/.claude/commands/docs-review/references/domain-routing.md +++ b/.claude/commands/docs-review/references/domain-routing.md @@ -11,7 +11,7 @@ Each changed file routes to **exactly one** domain by path. Apply the rules in o |---|---|---| | 1 | `docs-review:references:programs` | `static/programs/**` (includes every nested file in a program directory: `Pulumi.yaml`, `package.json`, `requirements.txt`, source files) | | 2 | `docs-review:references:blog` | `content/blog/**`, `content/case-studies/**` | -| 3 | `docs-review:references:docs` | `content/docs/**`, `content/tutorials/**`, `content/what-is/**` | +| 3 | `docs-review:references:docs` | `content/docs/**`, `content/what-is/**` | | 4 | `docs-review:references:website` | Any other `content/**.md` (pricing, legal, `vs/`, `why-pulumi/`, `about/`, `careers/`, etc.) | | 5 | `docs-review:references:infra` | `.github/workflows/**`, `scripts/**` except `scripts/programs/**`, `infrastructure/**`, `Makefile` (repo root), `package.json` (repo root only), `webpack.config.js`, `webpack.*.js` | | 6 | `docs-review:references:shared-criteria` only | Anything else (`layouts/`, `assets/`, `data/`, etc.) | diff --git a/.claude/commands/docs-review/scripts/triage-classify.py b/.claude/commands/docs-review/scripts/triage-classify.py index 68d4b15f1488..bff2e9411859 100755 --- a/.claude/commands/docs-review/scripts/triage-classify.py +++ b/.claude/commands/docs-review/scripts/triage-classify.py @@ -47,7 +47,7 @@ def classify_path(path: str) -> str | None: return "domain:programs" if path.startswith("content/blog/") or path.startswith("content/case-studies/"): return "domain:blog" - for prefix in ("content/docs/", "content/tutorials/", "content/what-is/"): + for prefix in ("content/docs/", "content/what-is/"): if path.startswith(prefix): return "domain:docs" if path.startswith(".github/workflows/"): diff --git a/.claude/commands/fix-broken-links/SKILL.md b/.claude/commands/fix-broken-links/SKILL.md index 4e4d833b90ab..267838ca3b90 100644 --- a/.claude/commands/fix-broken-links/SKILL.md +++ b/.claude/commands/fix-broken-links/SKILL.md @@ -111,7 +111,7 @@ Apply the first row that matches. |---|---|---| | Internal link points at a moved/renamed path, but the destination page still exists at a new path | **Hugo alias** | Add the old path to `aliases:` on the destination page's frontmatter | | Internal link to a page that was deleted/restructured, or a non-Hugo path (registry, generated docs) | **S3 redirect** | Add a redirect line to the topic-appropriate file in `scripts/redirects/` | -| Broken link living in **editable** content (`content/docs`, `content/product`, `content/tutorials`) | **Edit at source** | Fix the link in place; use the full root-relative path (`/docs/...`), never `../` | +| Broken link living in **editable** content (`content/docs`, `content/product`) | **Edit at source** | Fix the link in place; use the full root-relative path (`/docs/...`), never `../` | | Broken link in a **blog** post **and** an equivalent replacement exists (same content, or close enough that the post's meaning is unchanged) | **Edit at source + stamp `lastmod`** | Swap the link; add/update `lastmod:` in that post's frontmatter (leave `date:` alone) | | Broken link in a **blog** post with **no** equivalent replacement | **Route around the prose** | Add an alias/redirect so it resolves; if it's a dead external link, add it to the exclusion list. **Do not reword blog prose** | | Dead / transient / bot-protected **external** link | **Exclusion list** | Add the URL to `getDefaultExcludedKeywords()` in `check-links.js` with an inline `//` comment naming the reason + blog post/issue. If the page mattered, prefer swapping to a Wayback snapshot | diff --git a/.claude/commands/move-doc/references/link-updates.md b/.claude/commands/move-doc/references/link-updates.md index a2cdfe88050d..3d0b22f9a4d0 100644 --- a/.claude/commands/move-doc/references/link-updates.md +++ b/.claude/commands/move-doc/references/link-updates.md @@ -22,9 +22,8 @@ From `AGENTS.md` (lines 83-98): **DO NOT update links in**: - `content/blog/` - Historical blog posts -- `content/tutorials/` - Historical tutorials -**Why**: Blog posts and tutorials represent a point in time. Aliases handle redirects automatically, preserving historical accuracy. +**Why**: Blog posts represent a point in time. Aliases handle redirects automatically, preserving historical accuracy. ## Search Strategy diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 605cda96a1bd..587cf0ede053 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -5,9 +5,6 @@ # content/docs/esc/cli/commands/ # content/docs/iac/download-install/versions.md # -# content/tutorials/ @pulumi/docs -# content/templates/ @pulumi/docs -# # Require approval from docs team for edits to robots.txt (see issue #9885) # layouts/robots.txt @pulumi/docs # diff --git a/.github/labels-pr-review.md b/.github/labels-pr-review.md index 3191577ad59d..c6723e4734a8 100644 --- a/.github/labels-pr-review.md +++ b/.github/labels-pr-review.md @@ -10,7 +10,7 @@ Informational signal labels — surfaced for human filterability. Routing in CI | Label | Color | Description | |---|---|---| -| `domain:docs` | `0e8a16` | PR touches technical docs (`content/docs/`, `content/tutorials/`, `content/what-is/`). | +| `domain:docs` | `0e8a16` | PR touches technical docs (`content/docs/`, `content/what-is/`). | | `domain:blog` | `a2eeef` | PR touches blog posts or customer stories (`content/blog/`, `content/case-studies/`). | | `domain:infra` | `d4c5f9` | PR touches workflows, scripts, infrastructure code, Makefile, or build/bundling config. | | `domain:programs` | `fbca04` | PR touches example programs under `static/programs/`. | diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index e50614616824..870b410960b0 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -606,7 +606,7 @@ jobs: PR: ${{ steps.pr-context.outputs.pr_number }} run: | CHANGED=$(gh pr diff "$PR" --name-only \ - | grep -E '^content/(docs|blog|what-is|tutorials)/.*\.md$' || true) + | grep -E '^content/(docs|blog|what-is)/.*\.md$' || true) if [ -z "$CHANGED" ]; then echo '{}' > .vale-raw.json echo '[]' > .vale-findings.json @@ -653,7 +653,7 @@ jobs: PR: ${{ steps.pr-context.outputs.pr_number }} run: | CHANGED=$(gh pr diff "$PR" --name-only \ - | grep -E '^content/(docs|blog|what-is|tutorials)/.*\.md$' || true) + | grep -E '^content/(docs|blog|what-is)/.*\.md$' || true) if [ -z "$CHANGED" ]; then echo '[]' > .fetched-urls.json echo "extract-urls: no in-scope prose files changed; skipping" diff --git a/.github/workflows/claude-triage.yml b/.github/workflows/claude-triage.yml index 1393df4c1563..1e4927c99de1 100644 --- a/.github/workflows/claude-triage.yml +++ b/.github/workflows/claude-triage.yml @@ -242,7 +242,7 @@ jobs: VALE_BLOCKERS="" if [[ "$PROSE_CHECK_NEEDED" == "true" ]]; then VALE_FILES=$(gh pr diff "$PR" --repo "$REPO" --name-only \ - | grep -E '^content/(docs|blog|what-is|tutorials)/.*\.md$' || true) + | grep -E '^content/(docs|blog|what-is)/.*\.md$' || true) if [[ -n "$VALE_FILES" ]]; then vale --no-exit --output=JSON $VALE_FILES > .vale-raw.json 2>/dev/null \ || echo '{}' > .vale-raw.json diff --git a/.github/workflows/claude-update.yml b/.github/workflows/claude-update.yml index 1631bfc2980e..6c64afb7b270 100644 --- a/.github/workflows/claude-update.yml +++ b/.github/workflows/claude-update.yml @@ -340,8 +340,8 @@ jobs: printf '%s' "$BODY" > .claude-mention-body.txt # Run Vale on PR-changed prose files (content/docs, content/blog, - # content/what-is, content/tutorials) so the - # refreshed review reflects style nits in the current commit. + # content/what-is) so the refreshed review reflects style nits in + # the current commit. # Skipped on issue mentions and when no in-scope prose files were # touched. The `||` fallbacks ensure both files exist even when # vale is missing or the filter crashes (mirrors claude-triage.yml). @@ -356,7 +356,7 @@ jobs: PR: ${{ steps.pr-context.outputs.pr_number }} run: | CHANGED=$(gh pr diff "$PR" --name-only \ - | grep -E '^content/(docs|blog|what-is|tutorials)/.*\.md$' || true) + | grep -E '^content/(docs|blog|what-is)/.*\.md$' || true) if [ -z "$CHANGED" ]; then echo '{}' > .vale-raw.json echo '[]' > .vale-findings.json diff --git a/AGENTS.md b/AGENTS.md index 65c3bf9786d3..46bc7135f5b6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -35,7 +35,7 @@ For all content files, follow `STYLE-GUIDE.md`. If a rule is not covered there, Meta files like this one, `BUILD-AND-DEPLOY.md`, and agent instruction/skill files (e.g., `.claude/commands/*.md`) are exempt from formatting rules (heading case, trailing newlines, etc.). -For all content files (docs, blogs, tutorials, etc.): +For all content files (docs, blogs, changelog entries, etc.): - **Markdown**: Must always end with a newline. - **Headings**: @@ -62,7 +62,7 @@ For all content files (docs, blogs, tutorials, etc.): - **Ordered Lists**: Every item begins with `1.` to minimize diff noise. - **Diagrams**: Prefer Mermaid diagrams over ASCII art. The site renders Mermaid natively via a Hugo code block hook (`layouts/_default/_markup/render-codeblock-mermaid.html`). Use ` ```mermaid ` fenced code blocks. See [Mermaid docs](https://mermaid.js.org/) for syntax. - **Images on template-driven pages**: Place new images for template-driven pages (homepage, product pages, event pages, case studies — anything rendered through `layouts/partials/template-partials/*`) under `assets/fingerprinted/`, mirroring the path you'd use under `static/`. The template partials route every `` through `layouts/partials/fingerprinted-img.html`, which content-hashes filenames, converts rasters to WebP, and generates responsive `srcset`s. Frontmatter paths still look like `/images/foo.svg`; the partial resolves them. Missing assets cause a build panic, so there is no silent fallback. `meta_image` and assets used by non-template layouts can stay in `static/`. -- **Meta images**: `meta_image` is optional for `docs`, `tutorials`, `case-studies`, `what-is`, `migrate`, `partner`, `topics`, `events`, and `blog` pages. Leave it blank and `scripts/generate-meta-images.mjs` produces an on-brand social card at build time (resolved by `layouts/partials/meta-image-url.html`). A page-level `meta_image` always wins, but custom overrides are discouraged — the generated card covers virtually every case and stays on-brand automatically. For blog posts the card is built from the post title + `feature_image` (generate the feature image with `/blog-feature-image`, or label the PR `needs-design` for a designer-made one); a post's off-brand legacy meta image, if any, was renamed to `meta-legacy.png` and shows in a collapsed "Archived feature image" panel. +- **Meta images**: `meta_image` is optional for `docs`, `case-studies`, `what-is`, `migrate`, `partner`, `topics`, `events`, and `blog` pages. Leave it blank and `scripts/generate-meta-images.mjs` produces an on-brand social card at build time (resolved by `layouts/partials/meta-image-url.html`). A page-level `meta_image` always wins, but custom overrides are discouraged — the generated card covers virtually every case and stays on-brand automatically. For blog posts the card is built from the post title + `feature_image` (generate the feature image with `/blog-feature-image`, or label the PR `needs-design` for a designer-made one); a post's off-brand legacy meta image, if any, was renamed to `meta-legacy.png` and shows in a collapsed "Archived feature image" panel. - **Spelling/Grammar**: Always correct errors. Use American English spelling. --- @@ -79,7 +79,7 @@ Use the `/move-doc` skill for Hugo content files — it handles `git mv`, alias When moving documentation, aliases handle redirects automatically. Update internal links strategically: -- **DO update** links in `/content/docs/`, `/content/product/`, and `/content/tutorials/`. +- **DO update** links in `/content/docs/` and `/content/product/`. - **`/content/blog/`** is historical — swap a broken link only for an equivalent replacement, and when the change is worth surfacing to readers stamp `updated: YYYY-MM-DD` (not `lastmod`); otherwise route around it with an alias/redirect. See "Dates: `updated` vs `lastmod`" below. - **Link style**: links within `/docs/` must use the full canonical path (e.g. `/docs/iac/concepts/stacks/`). Never use parent-directory references (`../stacks/`) — they break when files move. @@ -93,11 +93,24 @@ The left nav is data-driven from `data/docs_menu_sections.yml`, which is consume --- +## Learn lives in another repo + +`/learn` — tutorials, official templates, community examples, and the glossary — is **not** in this repo. It ships from [pulumi/marketing-web](https://github.com/pulumi/marketing-web) (`apps/www`, an Astro build with its own S3 + CloudFront), and `infrastructure/index.ts` proxies `/learn*` to that distribution the same way it proxies `/registry` and `/guides`. Hugo's `content/tutorials/` and `content/templates/` trees were deleted when it launched; `scripts/redirects/learn-redirects.txt` 301s their URLs into `/learn`. + +What that means when you work here: + +- **Don't add tutorial or template content to this repo.** A new tutorial, a new official-template page, or a glossary term goes to pulumi/marketing-web. (The `glossary` shortcode and `data/glossary.toml` are a *different*, docs-only glossary rendered at `/docs/glossary/` — that one stays.) +- **Link to `/learn/tutorials//`, `/learn/official-templates//[/]`, and `/learn/glossary//`.** Never `/tutorials/` or `/templates/`; those only redirect. +- **`data/footer.yml` and `data/header_nav.yaml` are synced downstream.** marketing-web's `scripts/sync-content.mjs` reads both, so a nav or footer edit here also changes Learn's chrome. +- **Search does not cover Learn.** Docs search indexes this repo and the Registry only; `/learn` has its own search at `/learn/browse`. `scripts/search/update-search-index.js` deliberately doesn't fetch `/learn/search-index.json`, and there is no Learn facet in the docs search UI. + +--- + ## AI and agent positioning Pulumi supports the full spectrum of AI agents, and content must never present Neo as the only way to use AI with Pulumi or frame Neo as an either-or choice against other coding agents. -- **Docs** (`content/docs/`, `content/what-is/`, `content/tutorials/`): community-centric and balanced. Third-party coding agents (Claude Code, Codex, Cursor, GitHub Copilot, etc.) working with Pulumi — through IaC, [Agent Skills](/docs/ai/skills/), and the [Pulumi MCP server](/docs/ai/mcp-server/) — are first-class. Neo is Pulumi's purpose-built infrastructure agent: the deepest integration and the fastest path to a great infrastructure agent out of the box, but one option on a spectrum, and most teams benefit from using both. +- **Docs** (`content/docs/`, `content/what-is/`): community-centric and balanced. Third-party coding agents (Claude Code, Codex, Cursor, GitHub Copilot, etc.) working with Pulumi — through IaC, [Agent Skills](/docs/ai/skills/), and the [Pulumi MCP server](/docs/ai/mcp-server/) — are first-class. Neo is Pulumi's purpose-built infrastructure agent: the deepest integration and the fastest path to a great infrastructure agent out of the box, but one option on a spectrum, and most teams benefit from using both. - **Product/marketing pages** (`content/product/`, homepage): may lead with Neo and sell it hard, but should still acknowledge that Pulumi's code-first approach works with the agent a reader already uses. Avoid copy that disparages other agents (e.g. "unlike generic AI tools"). - **When listing agent options** (e.g. in migration guides), follow the pattern in `content/docs/iac/guides/migration/migrating-to-pulumi/from-terraform.md`: list Neo alongside Claude Code, Cursor, and Codex as equally legitimate choices, with at most a light note on Neo's built-in advantage. @@ -113,7 +126,7 @@ The reference pages under `content/docs/iac/concepts/resources/options/` show a Docs pages state which Pulumi Cloud edition a feature needs through a generated violet callout, not hand-written prose. A marker names a **feature**, never an edition — the edition the callout states is derived from that feature's availability in `data/pulumi_pricing.yaml` (see "Pricing data" below), so a feature that moves editions is a one-line edit that updates `/pricing/` and every marked page at once. -- **Whole page**: add `pulumi_cloud_feature: ` to the front matter (for example `pulumi_cloud_feature: rbac`). `layouts/docs/{single,list}.{html,md}` renders the callout above the content. We only mark what a reader has to buy, so an unknown id, an *edition* id, `true`, `false`, and a feature that's available on the Individual edition are all hard lint failures (`checkPulumiCloudFeature` in `scripts/lint/lint-markdown.js`). An ungated page carries no key. The key names the feature because the value does; it isn't `cloud_feature` because `content/templates/` already uses `cloud:` for the cloud *provider* a template targets. +- **Whole page**: add `pulumi_cloud_feature: ` to the front matter (for example `pulumi_cloud_feature: rbac`). `layouts/docs/{single,list}.{html,md}` renders the callout above the content. We only mark what a reader has to buy, so an unknown id, an *edition* id, `true`, `false`, and a feature that's available on the Individual edition are all hard lint failures (`checkPulumiCloudFeature` in `scripts/lint/lint-markdown.js`). An ungated page carries no key. The key names the feature because the value does, and to leave `cloud_feature` free for the cloud *provider* sense the word carries elsewhere. - **One section**: put `{{< pulumi-cloud "" />}}` on the line **directly after** the heading it applies to. `scripts/search/page.js` relies on that adjacency to skip the callout when it builds a heading's search snippet. The no-argument form `{{< pulumi-cloud />}}` means "Pulumi Cloud, all editions" and is only for mixed pages where the reader can't otherwise tell a section needs Cloud at all; a block form with inner content renders orientation prose in the same box. `checkPulumiCloudShortcode` validates the argument against the same vocabulary as the front matter key. - **If the feature isn't in the data file yet, add it there first.** Give it `hidden: true` when it isn't a marketed line item on `/pricing/` (gated deployments, ESC change requests, organization templates): hidden features stay out of the comparison table but remain resolvable by id. - **Don't say it twice.** When you add a marker, delete the hand-written "only available in the Enterprise and Business Critical editions" sentence or note it replaces. The callout already links to `/pricing/`. Keep only prose that says something the callout doesn't (for example, a per-edition limit like "Enterprise allows up to 25 custom roles"). diff --git a/BUILD-AND-DEPLOY.md b/BUILD-AND-DEPLOY.md index 72e2463bd74c..22e92d780872 100644 --- a/BUILD-AND-DEPLOY.md +++ b/BUILD-AND-DEPLOY.md @@ -835,10 +835,10 @@ Hugo processes 46+ content directories: - `/content/docs/` → Documentation - `/content/blog/` → Blog posts -- `/content/templates/` → Templates - `/content/product/` → Product pages +- `/content/case-studies/` → Customer stories -> **Note:** content/registry.md is a single landing page file, not a content directory. The full registry application is served from the separate pulumi/registry repository via CloudFront origin routing. +> **Note:** content/registry.md is a single landing page file, not a content directory. The full registry application is served from the separate pulumi/registry repository via CloudFront origin routing. `/learn` (tutorials, official templates, community examples, glossary) is served the same way, from pulumi/marketing-web. Templates are in `/layouts/` with various shortcodes for: @@ -1637,6 +1637,7 @@ Delivery: CloudWatch Logs infrastructure v2 | /js/*.js | S3 Main | 1 year | Versioned assets | | /registry/* | Registry | 30 minutes | Dynamic content, origin-proxied | | /guides/* | Guides | 30 minutes | Dynamic content, origin-proxied | +| /learn* | Learn (pulumi/marketing-web) | 30 minutes | Origin-proxied; cache key includes Accept for the origin's markdown negotiation | | /docs/* | S3 Main | 10 min | Content negotiation for Accept: text/markdown | | /docs/reference/pkg/dotnet/* | S3 Main | 10 min | CloudFront Function lowercases URI (viewer-request); Lambda@Edge handles redirects (origin-request) | | /ai | S3 Main | 1 week | 301 redirect to /product/neo/ (Lambda@Edge) | diff --git a/Makefile b/Makefile index 37a4541df88f..55ab33ab5698 100644 --- a/Makefile +++ b/Makefile @@ -165,22 +165,6 @@ test-review-pipeline: upgrade-programs: ./scripts/programs/upgrade.sh -.PHONY: new-tutorial-module -new-tutorial-module: - ./scripts/content/new-tutorial-module.sh - -.PHONY: new-tutorial-topic -new-tutorial-topic: - ./scripts/content/new-tutorial-topic.sh - -.PHONY: new-tutorial -new-tutorial: - ./scripts/content/new-tutorial.sh - -.PHONY: new-template -new-template: - ./scripts/content/new-template.sh - .PHONY: new-example-program new-example-program: ./scripts/content/new-example-program.sh diff --git a/SCHEMA.md b/SCHEMA.md index 6c7e5a0cb67e..4f85cddd8de3 100644 --- a/SCHEMA.md +++ b/SCHEMA.md @@ -21,7 +21,7 @@ The site automatically generates appropriate schema.org markup based on content | `blog` | BlogPosting | Blog posts | `/blog/my-post/` | | `article` | TechArticle | Documentation, educational content | `/docs/`, `/what-is/` | | `faq` | FAQPage | FAQ pages with Q&A pairs | `/docs/iac/faq/` | -| `howto` | HowTo | Step-by-step tutorials | `/tutorials/` | +| `howto` | HowTo | Step-by-step walkthroughs | `/docs/iac/get-started/` | | `product` | SoftwareApplication | Product pages | `/product/` | | `event` | Event | Webinars, conferences, meetups | `/events/` | | `auto` | (various) | Intelligent auto-detection | Default behavior | @@ -35,7 +35,6 @@ By default (or when `schema_type: auto`), the system automatically determines th ``` - type: blog → BlogPosting -- type: tutorials → HowTo - type: webinars → Event - type: docs → TechArticle, plus a supplemental FAQPage entity in the same @graph if the page has a "Frequently asked questions" section (H3s ending in `?`) @@ -218,20 +217,21 @@ main: ### HowTo Schema **Best for:** -- Step-by-step tutorials +- Step-by-step walkthroughs - Procedural guides - How-to content **Auto-extracts:** - Steps from numbered lists (`1.`, `2.`, ...) in the page body -- On `layout: template` pages with no numbered list, steps derived from H2 sections instead (see below) - Duration if specified - Prerequisites -Template pages (the product template gallery under `/templates/`) share a uniform, verified section structure ("Using this template", "Deploying the project", "Customizing the project", "Cleaning up", and similar) but rarely use numbered lists. For these pages only, each `##` heading becomes one `HowToStep`, using the heading as the step name and an excerpt of the section's prose as the step text. This heuristic is scoped to `layout: template` on purpose: the same approach applied to blog posts or tutorials would invent steps out of narrative headings ("Why this matters", "Conclusion") that describe no action. Purely navigational sections ("Learn more", "Related", "See also", "Further reading") are excluded from both extraction passes. +Purely navigational sections ("Learn more", "Related", "See also", "Further reading") are excluded from step extraction. -If neither extraction pass finds any steps, the page falls back to Article/TechArticle schema rather than emitting a HowTo with no `step` array (see "Smart Fallbacks" above). +If the extraction finds no steps, the page falls back to Article/TechArticle schema rather than emitting a HowTo with no `step` array (see "Smart Fallbacks" above). + +Opt a blog post in additively with `howto_schema: true` — it keeps its BlogPosting entity and gains a HowTo built from its own numbered walkthrough. [Learn more about HowTo schema](https://schema.org/HowTo) diff --git a/TAXONOMY.md b/TAXONOMY.md index 0f622927c1a3..ea48361fbcf2 100644 --- a/TAXONOMY.md +++ b/TAXONOMY.md @@ -8,7 +8,7 @@ The word **"guides"** currently refers to five different things: 1. Docs uses **"Guides"** as a second-level nav heading inside several product sections (`content/docs/esc/guides/`, `content/docs/deployments/guides/`, `content/docs/idp/guides/` all carry `title: Guides`; `content/docs/iac/guides/` holds the same kind of content but has no landing page of its own). 2. Marketing publishes **pulumi.com/guides** — "End-to-end blueprints for real cloud patterns" plus a library of Neo prompts. That page is **not** served from this repository. -3. Marketing also publishes **pulumi.com/tutorials**, which are occasionally referred to as guides. +3. Marketing also publishes the tutorials at **pulumi.com/learn**, which are occasionally referred to as guides. 4. The Registry currently republishes Pulumi examples and labels them "how-to guides". 5. Historic docs URLs like `/docs/guides/...` still circulate and are handled by redirects (`scripts/redirects/`). @@ -56,7 +56,7 @@ Teams: **Definition:** Task-oriented, sequenced, hands-on lessons. The reader follows along end to end and comes out having *built something* and *learned Pulumi*. Tutorials sometimes have time estimates and are occasionally grouped into collections and multi-part modules. -- **Lives at:** `content/tutorials/` → [pulumi.com/tutorials](https://www.pulumi.com/tutorials/) (also aliased at `/learn`) and `content/docs/*/get-started` +- **Lives at:** [pulumi.com/learn/tutorials](https://www.pulumi.com/learn/tutorials/) — **not in this repository**; published from pulumi/marketing-web (`apps/www/src/content/tutorials/`) — and `content/docs/*/get-started` - **Examples:** IaC Get Started, Deployments Get Started, ESC Get Started, Pulumi Fundamentals (3-part module), "Importing AWS Infrastructure" - **Owns:** Marketing - **Contributes:** Docs, Eng/Product @@ -142,14 +142,14 @@ Teams: **Definition:** Starter kits for generating new Pulumi projects with `pulumi new`. -- **Lives at:** `content/templates/` (sourced from https://github.com/pulumi/templates); includes both starter and architecture templates. +- **Lives at:** [pulumi.com/learn/official-templates](https://www.pulumi.com/learn/official-templates/) — **not in this repository**; published from pulumi/marketing-web, which syncs the starters from https://github.com/pulumi/templates and authors the architecture-template pages alongside them. - **Owns:** Marketing - **Contributes:** Eng/Product, Community Eng - **Consumes:** Practitioners bootstrapping new projects ### Example programs -**Definition:** Testable programs designed for embedding into docs and tutorials. +**Definition:** Testable programs designed for embedding into docs pages. - **Lives at:** `static/programs/`, tested via `scripts/programs/test.sh` - **Owns:** Docs @@ -162,7 +162,7 @@ Teams: |---|---|---|---|---|---| | Conceptual docs | Explains how Pulumi works and why | `content/docs/*/concepts/` | Docs | Eng/Product, Community Eng | Practitioners | | Guides | Walkthroughs designed for understanding and using Pulumi | `content/docs/*/guides/` | Docs | Eng/Product, Community Eng, community | Practitioners | -| Tutorials | Sequenced hands-on learning | `content/tutorials/` | Marketing | Docs, Eng/Product | Newcomers, learners | +| Tutorials | Sequenced hands-on learning | pulumi/marketing-web → `/learn/tutorials/` | Marketing | Docs, Eng/Product | Newcomers, learners | | Reference | Exhaustive lookup material | `content/docs/reference/`, generated CLI docs | Docs + Eng/Product | Eng/Product | Practitioners | | Topics | Adjacent, industry-relevant educational content ("what is X") | `content/what-is/` | Marketing | Docs, Community Eng | Learners, evaluators | | Blog posts | Point-in-time posts; historical | `content/blog/` | Marketing | Everyone | Community | @@ -170,7 +170,7 @@ Teams: | Product/campaign pages | Pages that sell | `content/product/`, `solutions/`, `gads/`, … | Marketing | Eng/Product, Docs | Evaluators, buyers | | Events & workshops | Registration/recap pages | `content/events/` | Marketing + Community Eng | — | Community, prospects | | Releases & changelog | Dated record of what shipped | `content/releases/` | Marketing | Eng/Product, Docs | Existing and prospective users | -| Templates | Runnable starting points | `content/templates/` | Marketing | Eng/Product, Community Eng | Practitioners | +| Templates | Runnable starting points | pulumi/marketing-web → `/learn/official-templates/` | Marketing | Eng/Product, Community Eng | Practitioners | | Example programs | Tested, embeddable code | `static/programs/` | Docs | Eng/Product, Community Eng | Practitioners | ## Naming decisions and open items @@ -180,18 +180,17 @@ The "guides" collision described at the top of this document has been resolved a 1. **"Guides" refers *only* to the docs guides** — the ones that live in the docs, generally underneath a given product or feature. These are owned by the Docs team, and each one, in the [Diátaxis](https://diataxis.fr/) sense, can take the form of either a "how-to guide" or an "explanation." These are the *only* things we'll refer to as Guides going forward. 1. **"Tutorials" refers to either:** - The things we currently call "the Getting Started guides" (`content/docs/*/get-started/`). We'll try to call these the Getting Started *tutorials* going forward — that's what they are in the Diátaxis sense. - - The things that live at [pulumi.com/tutorials](https://www.pulumi.com/tutorials/). The content at pulumi.com/guides is being folded selectively into these. -1. **Tutorials are Marketing-owned** (specifically Technical Content Marketing), with contribution from everyone welcome. The commented-out CODEOWNERS mapping of `content/tutorials/` to `@pulumi/docs` doesn't reflect this and should be corrected if CODEOWNERS is ever re-enabled. -1. **A new hub at `/learn` is in the works** that pulls in all tutorials, templates, and examples — as well as blog posts categorized [as tutorials](https://www.pulumi.com/blog/category/tutorials/). Like the Registry and pulumi.com/guides today, it will most likely be served by a separate web app rather than this repo. + - The things that live at [pulumi.com/learn/tutorials](https://www.pulumi.com/learn/tutorials/). The content at pulumi.com/guides is being folded selectively into these. +1. **Tutorials are Marketing-owned** (specifically Technical Content Marketing), with contribution from everyone welcome. +1. **The hub at `/learn` has shipped.** It pulls together tutorials, official templates, community examples, and a glossary, alongside blog posts categorized [as tutorials](https://www.pulumi.com/blog/category/tutorials/), series, workshops, and Academy programs. Like the Registry and pulumi.com/guides, it is served by a separate web app (pulumi/marketing-web) rather than this repo; `infrastructure/index.ts` proxies `/learn*` to it. Open items: 1. **Give `content/docs/iac/guides/` a landing page.** IaC holds the same guide content as the other product sections but has no `_index.md`, so the type is invisible in the IaC nav. Add an introduction page, titled "Guides," to match its siblings. -1. **Reserve "tutorials" for the two things above.** Don't introduce other "tutorial" sections inside `/docs/`. Note that `/learn` is currently an alias of `/tutorials`, and `content/learn` does not exist as a directory. +1. **Reserve "tutorials" for the two things above.** Don't introduce other "tutorial" sections inside `/docs/`, and don't recreate `content/tutorials/` here — new tutorials go to pulumi/marketing-web. 1. **Bring team metadata current.** The team-management repo may need tweaks (at least on the Marketing side) to reflect the ownership described here. ## Known gaps -- **CODEOWNERS is entirely commented out** (`.github/CODEOWNERS`), so no ownership is enforced — and the commented-out mapping doesn't fully match reality anyway (it assigns `content/tutorials/` to `@pulumi/docs`, while actual ownership sits with Marketing). -- **Stale `content/learn` reference:** the docs-review criteria (`.claude/commands/docs-review/references/docs.md`) scope includes `content/learn`, which doesn't exist. The `/learn` path itself is slated to be taken over by the new learning-hub web app described above. +- **CODEOWNERS is entirely commented out** (`.github/CODEOWNERS`), so no ownership is enforced. - **Untyped campaign directories:** ~20 one-off landing directories under `content/` (`gads/`, `cjs26/`, `kubecon/`, `reinvent/`, …) carry no declared type in repo metadata beyond falling into the "website" review domain. They are all Marketing-owned and treated here as product/campaign pages. diff --git a/archetypes/templates/template/architecture.png b/archetypes/templates/template/architecture.png deleted file mode 100644 index 44a346913c34..000000000000 Binary files a/archetypes/templates/template/architecture.png and /dev/null differ diff --git a/archetypes/templates/template/index.md b/archetypes/templates/template/index.md deleted file mode 100644 index 0dd4c525c7c1..000000000000 --- a/archetypes/templates/template/index.md +++ /dev/null @@ -1,215 +0,0 @@ ---- -title: "{{ replace .Name "-" " " | title }} Template" -layout: template - -# Make sure this is description accurate for this template. -meta_desc: The {{ replace .Name "-" " " | title }} template makes it easy to deploy a static website on $CLOUD with Pulumi, some service, and some other cloud service. - -# Be sure to replace this image. -# Figma source file: -# https://www.figma.com/file/lGrSpwbGGmbixEuewMbtkh/Template-Architecture-Diagrams?node-id=15%3A196 -meta_image: meta.png - -# Appears on the cards on template-overview pages. -card_desc: Deploy a $THING on $CLOUD with Pulumi, some cloud service, and some other cloud service. - -# Used for generating language-specific CLI commands -# and links to the templates repo on GitHub. -template: - prefix: architecture-cloud - dirname: my-project - languages: - - typescript - - python - - go - - csharp - - yaml - -# Used for generating links to sibling templates in the right-hand nav. -# Slug is this template's parent directory. -cloud: - name: Amazon Web Services - slug: aws - -# The content below is meant help you get started -# and to serve as a guide to work by. -# Feel free to adjust it needed for your template. ---- - -The $CLOUD $ARCHITECTURE template creates an infrastructure as code project -in your favorite language that deploys a $THING to $CLOUD with Pulumi. -It uses this resource, this other resource, and probably some other awesome resource -to accomplish some particular desirable outcome. -The template generates a complete Pulumi program, including $INCLUDED_STUFF, -to give you a working project out of the box that you can customize easily -and extend to suit your needs. - -![An architecture diagram of the Pulumi $CLOUD $ARCHITECTURE template](./architecture.png) - -## Using this template - -To use this template to deploy your own $THING, -make sure you've [installed Pulumi](/docs/install/) -and [configured your $CLOUD credentials](/registry/packages/$CLOUD/installation-configuration/#credentials), -then create a new [project](/docs/concepts/projects/) using the template in your language of choice: - -{{< templates/pulumi-new >}} - -Follow the prompts to complete the new-project wizard. -When it's done, you'll have a complete Pulumi project -that's ready to deploy and configured with the most common settings. -Feel free to inspect the code in {{< langfile >}} for a closer look. - -## Deploying the project - -The template requires no additional configuration. -Once the new project is created, -you can deploy it immediately with [`pulumi up`](/docs/cli/commands/pulumi_up/): - -```bash -$ pulumi up -``` - -When the deployment completes, -Pulumi exports the following [stack output](/docs/concepts/stack/#outputs) values: - -someOutput -: The provider-assigned property of the widget resource. - -someOtherOutput -: The fully-qualified HTTP URL of the widget resource. - -Output values like these are useful in many ways, -most commonly as inputs for other stacks or related cloud resources. -The computed `someOutput`, for example, can be used from the command line -to open the newly deployed website in your favorite web browser: - -```bash -$ open $(pulumi stack output cdnURL) -``` - -## Customizing the project - -Projects created with the $ARCHITECTURE template expose -the following [configuration](/docs/concepts/config/) settings: - -someProp -: The description of the property. Defaults to `someValue`. - -otherProp -: The file to use for top-level pages. Defaults to `otherValue`. - -All of these settings are optional and may be adjusted -either by editing the stack configuration file directly (by default, `Pulumi.dev.yaml`) -or by changing their values with [`pulumi config set`](/docs/cli/commands/pulumi_config_set/) as shown below. - -### Changing a config value - -If you already have a $THING you'd like to deploy on $CLOUD with Pulumi, -you can do so either by replacing placeholder content in the `foo` folder -or by configuring the stack to point to another folder on your computer with the `someProp` setting: - -```bash -$ pulumi config set someProp ../some/value -$ pulumi up -``` - -### Adjusting the code somehow - -By default, the generated program configures some resource in a particular way, -which may or may not be the best fit for your project. -You can adjust these settings by changing the code in {{< langfile >}}: - -{{% chooser language "typescript,python,go,csharp,yaml" / %}} - -{{% choosable %}} - -```diff -const cdn = new aws.cloudfront.Distribution("cdn", { - defaultCacheBehavior: { -- minTtl: 600, -+ minTtl: 3600, -``` - -{{% /choosable %}} - -{{% choosable language python %}} - -```diff -cdn = aws.cloudfront.Distribution( - default_cache_behavior=aws.cloudfront.DistributionDefaultCacheBehaviorArgs( -- min_ttl=600, -+ min_ttl=3600, -``` - -{{% /choosable %}} - -{{% choosable language go %}} - -```diff -cdn, err := cloudfront.NewDistribution(ctx, "cdn", &cloudfront.DistributionArgs{ - DefaultCacheBehavior: &cloudfront.DistributionDefaultCacheBehaviorArgs{ -- MinTtl: pulumi.Int(600), -+ MinTtl: pulumi.Int(3600), -``` - -{{% /choosable %}} - -{{% choosable language csharp %}} - -```diff -var cdn = new Aws.CloudFront.Distribution("cdn", new() -{ - DefaultCacheBehavior = new Aws.CloudFront.Inputs.DistributionDefaultCacheBehaviorArgs - { -- MinTtl = 600, -+ MinTtl = 3600, -``` - -{{% /choosable %}} - -{{% choosable language yaml %}} - -```diff -cdn: - type: aws:cloudfront:Distribution - properties: - defaultCacheBehavior: -- minTtl: 600 -+ minTtl: 600 -``` - -{{% /choosable %}} - -Alternatively, you could make these settings configurable as well, -which would allow them to vary between other stacks in your project. - -## Next steps - -This section is optional, but strongly encouraged. - -### Some next step - -A description of the next step. - -### Some other next step - -A description of the other next step. - -## Tidying up - -You can cleanly destroy the stack and all of its infrastructure with [`pulumi destroy`](/docs/cli/commands/pulumi_destroy/): - -```bash -$ pulumi destroy -``` - -## Learn more - -Congratulations! -You're now well on your way to managing a production-grade $THING on $CLOUD with Pulumi --- and there's lots more you can do from here: - -* Discover more architecture templates in [Templates →](/templates/) -* Dive into the $CLOUD package by exploring the [API docs in the Registry →](/registry/packages/$CLOUD/) -* Expand your understanding of how Pulumi works in [Learn Pulumi →](/tutorials/) -* Read up on the latest new features [in the Pulumi Blog →](/blog/) diff --git a/archetypes/templates/template/meta.png b/archetypes/templates/template/meta.png deleted file mode 100644 index 44a346913c34..000000000000 Binary files a/archetypes/templates/template/meta.png and /dev/null differ diff --git a/archetypes/templates/type/_index.md b/archetypes/templates/type/_index.md deleted file mode 100644 index 1be45b5c1f7d..000000000000 --- a/archetypes/templates/type/_index.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: "{{ replace .Name "-" " " | title }} Templates" -layout: overview -meta_desc: Pulumi program templates that make it easy to deploy {{ replace .Name "-" " " }}s on AWS, Azure, or Google Cloud Platform. - -# Be sure to replace this image. -# Figma source file: -# https://www.figma.com/file/lGrSpwbGGmbixEuewMbtkh/Template-Architecture-Diagrams?node-id=15%3A196 -meta_image: meta.png - -# Adjust this value to ensure the new template sorts as you'd like it to sort in the list. -weight: 99 ---- - -Pulumi program templates that make it easy to deploy {{ replace .Name "-" " " }}s on AWS, Azure, or Google Cloud Platform. diff --git a/archetypes/templates/type/meta.png b/archetypes/templates/type/meta.png deleted file mode 100644 index 44a346913c34..000000000000 Binary files a/archetypes/templates/type/meta.png and /dev/null differ diff --git a/archetypes/tutorials/module/_index.md b/archetypes/tutorials/module/_index.md deleted file mode 100644 index 360af5d8dcf2..000000000000 --- a/archetypes/tutorials/module/_index.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -title: "{{ replace .Name "-" " " | title }}" -title_tag: "{{ replace .Name "-" " " | title }}" -layout: module - -# A succinct description of the tutorial. It appears on the Tutorials home and collection pages. -description: Here is a brief description of what this module's all about. - -# A similar description used for search results and social-media previews. -meta_desc: Here is a brief description of what this module's all about. - -# An on-brand social-media preview card is generated automatically at build time, -# so leave this blank. Only set meta_image to override that card with a custom -# social-media image (it is no longer shown inline on the page). -# meta_image: meta.png - -# The order in which the module appears in most lists. Order is ascending, so higher numbers -# mean the module will appear further down the list. Positive integers only. -weight: 999 - -# A brief summary of the module. It appears at the top of the module-index page. Markdown is fine. -summary: | - This is the module summary. It should describe the overall goal of the module and briefly cover what - the reader will know how to do by the end of it. - -# A list of three to five things the reader will have learned by the end of the tutorial. -youll_learn: - - How to do X - - When to do Y - - Why X is more preferable than Y - -# A list of tutorial prerequisites. Markdown is fine. Keep it simple; no need to be exhaustive here. -prereqs: - - The [Pulumi CLI](/docs/install/) - - A [Pulumi Cloud account](https://app.pulumi.com/signup) and [access token](/docs/pulumi-cloud/accounts/#access-tokens) - - Familiarity with JavaScript, TypeScript, or Python - -# An optional list of collections this tutorial should be belong to. Collections are defined in data/tutorials/collections.yaml. -collections: - - some-non-existent-collection ---- diff --git a/archetypes/tutorials/module/meta.png b/archetypes/tutorials/module/meta.png deleted file mode 100644 index 44a346913c34..000000000000 Binary files a/archetypes/tutorials/module/meta.png and /dev/null differ diff --git a/archetypes/tutorials/single/index.md b/archetypes/tutorials/single/index.md deleted file mode 100644 index bec380815936..000000000000 --- a/archetypes/tutorials/single/index.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -title: "{{ replace .Name "-" " " | title }}" -title_tag: "{{ replace .Name "-" " " | title }}" -layout: single - -# A succinct description of the tutorial. It appears on the Tutorials home and collection pages. -description: Here is a brief description of what this tutorial's all about. - -# A similar description used for search results and social-media previews. -meta_desc: Here is a brief description of what this tutorial's all about. - -# An on-brand social-media preview card is generated automatically at build time, -# so leave this blank. Only set meta_image to override that card with a custom -# social-media image (it is no longer shown inline on the page). -# meta_image: meta.png - -# An optional video for the tutorial. When present, it appears at the top of the page. -# YouTube and HTML5 video sources are supported. -# video: -# url: /blog/drift-detection/drift.mp4 -# youtube: Q8tw6YTD3ac - -# The order in which the tutorial appears in most lists. Order is ascending, so higher numbers -# mean the tutorial will appear further down the list. Positive integers only. -weight: 999 - -# A brief summary of the tutorial. It appears at the top of the tutorial page. Markdown is fine. -summary: | - This is the tutorial summary. It should describe the overall goal of the tutorial and briefly cover what - the reader will know how to do by the end of it. - -# A list of three to five things the reader will have learned by the end of the tutorial. -youll_learn: - - How to do X - - When to do Y - - Why X is more preferable than Y - -# A list of tutorial prerequisites. Markdown is fine. Keep it simple; no need to be exhaustive here. -prereqs: - - The [Pulumi CLI](/docs/install/) - - A [Pulumi Cloud account](https://app.pulumi.com/signup) and [access token](/docs/pulumi-cloud/accounts/#access-tokens) - - Familiarity with JavaScript, TypeScript, or Python - -# The estimated time, in minutes, for new users to complete the topic. -estimated_time: 10 - -# An optional list of collections this tutorial should be belong to. Collections are defined in data/tutorials/collections.yaml. -collections: - - some-non-existent-collection ---- - -This is the actual content of the tutorial. diff --git a/archetypes/tutorials/single/meta.png b/archetypes/tutorials/single/meta.png deleted file mode 100644 index 44a346913c34..000000000000 Binary files a/archetypes/tutorials/single/meta.png and /dev/null differ diff --git a/archetypes/tutorials/topic/index.md b/archetypes/tutorials/topic/index.md deleted file mode 100644 index 3fc6d88aadef..000000000000 --- a/archetypes/tutorials/topic/index.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: "{{ replace .Name "-" " " | title }}" -title_tag: "{{ replace .Name "-" " " | title }}" -layout: topic - -# A succinct description of the tutorial. It appears on the Tutorials home and collection pages. -description: Here is a brief description of this topic. - -# A similar description used for search results and social-media previews. -meta_desc: Here is a brief description of this topic. - -# An on-brand social-media preview card is generated automatically at build time, -# so leave this blank. Only set meta_image to override that card with a custom -# social-media image (it is no longer shown inline on the page). -# meta_image: meta.png - -# The order in which the topic appears in most lists. Order is ascending, so higher numbers -# mean the topic will appear further down the list. Positive integers only. -weight: 999 - -# The estimated time, in minutes, for new users to complete the topic. -estimated_time: 10 ---- - -This is the actual content of the topic. diff --git a/archetypes/tutorials/topic/meta.png b/archetypes/tutorials/topic/meta.png deleted file mode 100644 index 44a346913c34..000000000000 Binary files a/archetypes/tutorials/topic/meta.png and /dev/null differ diff --git a/config/_default/config.yml b/config/_default/config.yml index ab7a9eec9769..f8e23e02e2fc 100644 --- a/config/_default/config.yml +++ b/config/_default/config.yml @@ -97,25 +97,7 @@ outputs: - rows - RSS -# Collection terms (/tutorials//) are the one non-blog taxonomy: no blog -# post carries `collections`, so the term outputs above would give every -# tutorials collection an empty "Pulumi Blog: " RSS feed (which head.html -# would then advertise for autodiscovery) plus an unused rows fragment. Scope -# them back to HTML only. cascade: - - _target: - kind: term - path: /collections/** - outputs: - - HTML - # The `industry` taxonomy (case-study verticals) is non-blog, like collections - # above: the default `term` outputs would give every industry an empty "Pulumi - # Blog: " RSS feed (term.rss.xml filters to Section=blog → no items) - # that head.html would then advertise, plus an unused `rows` fragment. Hugo - # also defaults the taxonomy LIST page to HTML+RSS. Scope BOTH kinds back to - # HTML only so nothing leaks into our feeds. NOTE: cascade `path` matches the - # page's LOGICAL path (taxonomy plural `/industry/...`), NOT the permalink URL - # (/case-studies/industry/...) — same as the /collections/** target above. - _target: kind: term path: /industry/** @@ -135,7 +117,6 @@ cascade: taxonomies: tag: tags author: authors - collection: collections # Plural is intentionally "category" (not "categories") so Hugo reads the # existing scalar `category:` front matter on blog posts. Hugo casts the # scalar value to a one-term list. See layouts/taxonomy/category.html and @@ -157,7 +138,6 @@ permalinks: term: authors: /blog/author/:slug/ tags: /blog/tag/:slug/ - collections: /tutorials/:slug/ category: /blog/category/:slug/ series: /blog/series/:slug/ industry: /case-studies/industry/:slug/ diff --git a/content/templates/container-service/aws/architecture.png b/content/blog/walkthrough-of-adopting-infrastructure-as-code/container-service-aws-architecture.png similarity index 100% rename from content/templates/container-service/aws/architecture.png rename to content/blog/walkthrough-of-adopting-infrastructure-as-code/container-service-aws-architecture.png diff --git a/content/templates/container-service/gcp/architecture.png b/content/blog/walkthrough-of-adopting-infrastructure-as-code/container-service-gcp-architecture.png similarity index 100% rename from content/templates/container-service/gcp/architecture.png rename to content/blog/walkthrough-of-adopting-infrastructure-as-code/container-service-gcp-architecture.png diff --git a/content/blog/walkthrough-of-adopting-infrastructure-as-code/index.md b/content/blog/walkthrough-of-adopting-infrastructure-as-code/index.md index 1fae660a6173..100be90012d2 100644 --- a/content/blog/walkthrough-of-adopting-infrastructure-as-code/index.md +++ b/content/blog/walkthrough-of-adopting-infrastructure-as-code/index.md @@ -45,13 +45,13 @@ In this example, we build and publish a Docker image running an NGINX web server If our chosen cloud is AWS, we will need an Elastic Container Service (ECS) cluster and registry, with a Fargate service and application load balancer in front of it. This enables our service to be accessed over the internet: -![AWS Containers Template](/templates/container-service/aws/architecture.png) +![AWS Containers Template](/blog/walkthrough-of-adopting-infrastructure-as-code/container-service-aws-architecture.png) *See the template for AWS [here](/templates/container-service/aws/)*. If we choose Google Cloud, on the other hand, we can either use Google Kubernetes Engine (GKE) or Google Cloud Run. In this example, we use Cloud Run and the built-in artifact repository, since these services are generally easier to use when just getting started: -![Google Cloud Containers Template](/templates/container-service/gcp/architecture.png) +![Google Cloud Containers Template](/blog/walkthrough-of-adopting-infrastructure-as-code/container-service-gcp-architecture.png) In both cases, after deploying the infrastructure, we will have a fully functioning microservice environment with one load-balanced service running the NGINX web server. The Infrastructure as Code tool will give us a URL for the internet-accessible load balancer so we can browse to it. @@ -63,7 +63,7 @@ In this example, we will create a serverless application. Unlike containers, whi For Azure, we’ll need to create an Azure Blob Storage container to host our code, upload the serverless function bundle, and then configure an Azure Function app that will make our function available over HTTPS: -![Azure Serverless Template](/templates/serverless-application/azure/architecture.png) +![Azure Serverless Template](/blog/walkthrough-of-adopting-infrastructure-as-code/serverless-application-azure-architecture.png) *See the template for Azure [here](/templates/serverless-application/azure/)*. @@ -71,7 +71,7 @@ For AWS, although the architecture is in spirit very similar, the details differ In both cases, after deploying the infrastructure, we get back a web URL to access it. This example is a good reminder that each of the clouds is very different in its details. Infrastructure as Code doesn’t necessarily shield you from those details, although it is possible to build abstractions that do, which is both a strength but also something you’ll need to navigate. -![AWS Serverless Template](/templates/serverless-application/aws/architecture.png) +![AWS Serverless Template](/blog/walkthrough-of-adopting-infrastructure-as-code/serverless-application-aws-architecture.png) *See the template for AWS [here](/templates/serverless-application/aws/)*. @@ -81,13 +81,13 @@ For the final example, let’s switch gears and focus on more “foundational” In the case of Azure’s Kubernetes Service (AKS), the design of the service is fairly chunky. So we can simply spin up a managed cluster with the associated networking infrastructure: -![Azure Kubernetes Template](/templates/kubernetes/azure/architecture.png) +![Azure Kubernetes Template](/blog/walkthrough-of-adopting-infrastructure-as-code/kubernetes-azure-architecture.png) *See the template for Azure [here](/templates/kubernetes/azure/)*. In the case of AWS’s Elastic Kubernetes Service (EKS), on the other hand, the service itself is rather complex to set up, involving many moving parts. That includes the control plane itself, the worker node groups, an autoscaling group, the AWS container network interface plugin to manage pod networking and more: -![AWS Kubernetes Template](/templates/kubernetes/aws/architecture.png) +![AWS Kubernetes Template](/blog/walkthrough-of-adopting-infrastructure-as-code/kubernetes-aws-architecture.png) *See the template for AWS [here](/templates/kubernetes/aws/)*. diff --git a/content/templates/kubernetes/aws/architecture.png b/content/blog/walkthrough-of-adopting-infrastructure-as-code/kubernetes-aws-architecture.png similarity index 100% rename from content/templates/kubernetes/aws/architecture.png rename to content/blog/walkthrough-of-adopting-infrastructure-as-code/kubernetes-aws-architecture.png diff --git a/content/templates/kubernetes/azure/architecture.png b/content/blog/walkthrough-of-adopting-infrastructure-as-code/kubernetes-azure-architecture.png similarity index 100% rename from content/templates/kubernetes/azure/architecture.png rename to content/blog/walkthrough-of-adopting-infrastructure-as-code/kubernetes-azure-architecture.png diff --git a/content/templates/serverless-application/aws/architecture.png b/content/blog/walkthrough-of-adopting-infrastructure-as-code/serverless-application-aws-architecture.png similarity index 100% rename from content/templates/serverless-application/aws/architecture.png rename to content/blog/walkthrough-of-adopting-infrastructure-as-code/serverless-application-aws-architecture.png diff --git a/content/templates/serverless-application/azure/architecture.png b/content/blog/walkthrough-of-adopting-infrastructure-as-code/serverless-application-azure-architecture.png similarity index 100% rename from content/templates/serverless-application/azure/architecture.png rename to content/blog/walkthrough-of-adopting-infrastructure-as-code/serverless-application-azure-architecture.png diff --git a/content/docs/_index.md b/content/docs/_index.md index 3cb0ee355327..c563e959f050 100644 --- a/content/docs/_index.md +++ b/content/docs/_index.md @@ -61,7 +61,7 @@ sections: - icon: graduation-cap heading: Tutorials ↗ description: Step-by-step guides for building real-world infrastructure with Pulumi. - link: /tutorials/ + link: /learn/tutorials/ - type: button-cards heading: More Documentation cards: diff --git a/content/docs/administration/get-started/setting-up-for-success.md b/content/docs/administration/get-started/setting-up-for-success.md index 1222c5a1ee27..922af8264571 100644 --- a/content/docs/administration/get-started/setting-up-for-success.md +++ b/content/docs/administration/get-started/setting-up-for-success.md @@ -66,7 +66,7 @@ Pulumi projects, stacks, and environments help reduce "sprawl"—the copy-and-pa Components provide all the benefits of native language packages: storage in package managers, versioning, secure dependencies, and more. -**[Templates](/docs/idp/concepts/organization-templates/)** are blueprints that scaffold entirely new projects. While components encapsulate cloud resource usage patterns, templates provide standard starting points for complete projects with many resources. [Pulumi offers templates](/templates/) for common architectures and patterns, but you can create your own. You can also register your organization's templates in the Pulumi Cloud New Project Wizard for convenient access. +**[Templates](/docs/idp/concepts/organization-templates/)** are blueprints that scaffold entirely new projects. While components encapsulate cloud resource usage patterns, templates provide standard starting points for complete projects with many resources. [Pulumi offers templates](/learn/official-templates/) for common architectures and patterns, but you can create your own. You can also register your organization's templates in the Pulumi Cloud New Project Wizard for convenient access. ### Make the decision diff --git a/content/docs/iac/get-started/aws/next-steps.md b/content/docs/iac/get-started/aws/next-steps.md index ae6971758013..08d6d689a1bd 100644 --- a/content/docs/iac/get-started/aws/next-steps.md +++ b/content/docs/iac/get-started/aws/next-steps.md @@ -44,13 +44,13 @@ With Pulumi ESC you can: Let our AWS tutorials guide you through key Pulumi concepts. -{{< get-started-next-step path="/tutorials/" label="Browse tutorials" ref="gs-aws-tutorials" >}} +{{< get-started-next-step path="/learn/tutorials/" label="Browse tutorials" ref="gs-aws-tutorials" >}} ## Launch a new project with a template -Easily deploy the most common cloud architectures, from [static websites](/templates/static-website/aws/) to [serverless applications](/templates/serverless-application/aws/), [virtual machines](/templates/virtual-machine/aws/), [container services](/templates/container-service/aws/), and [Kubernetes clusters](/templates/kubernetes/aws/). +Easily deploy the most common cloud architectures, from [static websites](/learn/official-templates/static-website/aws/) to [serverless applications](/learn/official-templates/serverless-application/aws/), [virtual machines](/learn/official-templates/virtual-machine/aws/), [container services](/learn/official-templates/container-service/aws/), and [Kubernetes clusters](/learn/official-templates/kubernetes/aws/). -{{< get-started-next-step path="/templates/" label="Browse templates" ref="gs-aws-guides" >}} +{{< get-started-next-step path="/learn/official-templates/" label="Browse templates" ref="gs-aws-guides" >}} ## Dive into the docs diff --git a/content/docs/iac/get-started/azure/next-steps.md b/content/docs/iac/get-started/azure/next-steps.md index 53770dd7dcb2..ed8b4e95a29e 100644 --- a/content/docs/iac/get-started/azure/next-steps.md +++ b/content/docs/iac/get-started/azure/next-steps.md @@ -43,13 +43,13 @@ With Pulumi ESC you can: Dive into Learn Pulumi for a comprehensive walkthrough of key Pulumi concepts in the context of a real-life application. -{{< get-started-next-step path="/learn/pulumi-fundamentals" label="Learn Pulumi Fundamentals" ref="gs-azure-learn" >}} +{{< get-started-next-step path="/learn/tutorials/pulumi-fundamentals/" label="Learn Pulumi Fundamentals" ref="gs-azure-learn" >}} ## Launch a new project with a template -Deploy the most common cloud architectures, from [static websites](/templates/static-website/azure/) to [serverless applications](/templates/serverless-application/azure/), [virtual machines](/templates/virtual-machine/azure/), [container services](/templates/container-service/azure/), and [Kubernetes clusters](/templates/kubernetes/azure/). +Deploy the most common cloud architectures, from [static websites](/learn/official-templates/static-website/azure/) to [serverless applications](/learn/official-templates/serverless-application/azure/), [virtual machines](/learn/official-templates/virtual-machine/azure/), [container services](/learn/official-templates/container-service/azure/), and [Kubernetes clusters](/learn/official-templates/kubernetes/azure/). -{{< get-started-next-step path="/templates/" label="Browse templates" ref="gs-azure-guides" >}} +{{< get-started-next-step path="/learn/official-templates/" label="Browse templates" ref="gs-azure-guides" >}} ## Dive into the docs diff --git a/content/docs/iac/get-started/gcp/next-steps.md b/content/docs/iac/get-started/gcp/next-steps.md index 0ca5ada67b80..36b8ddbc9610 100644 --- a/content/docs/iac/get-started/gcp/next-steps.md +++ b/content/docs/iac/get-started/gcp/next-steps.md @@ -44,13 +44,13 @@ With Pulumi ESC you can: Let our Google Cloud tutorials guide you through key Pulumi concepts. -{{< get-started-next-step path="/tutorials/" label="Browse tutorials" ref="gs-gcp-tutorials" >}} +{{< get-started-next-step path="/learn/tutorials/" label="Browse tutorials" ref="gs-gcp-tutorials" >}} ## Launch a new project with a template -Easily deploy the most common cloud architectures, from [static websites](/templates/static-website/gcp/) to [serverless applications](/templates/serverless-application/gcp/), [virtual machines](/templates/virtual-machine/gcp/), [container services](/templates/container-service/gcp/), and [Kubernetes clusters](/templates/kubernetes/gcp/). +Easily deploy the most common cloud architectures, from [static websites](/learn/official-templates/static-website/gcp/) to [serverless applications](/learn/official-templates/serverless-application/gcp/), [virtual machines](/learn/official-templates/virtual-machine/gcp/), [container services](/learn/official-templates/container-service/gcp/), and [Kubernetes clusters](/learn/official-templates/kubernetes/gcp/). -{{< get-started-next-step path="/templates/" label="Browse templates" ref="gs-gcp-guides" >}} +{{< get-started-next-step path="/learn/official-templates/" label="Browse templates" ref="gs-gcp-guides" >}} ## Dive into the docs diff --git a/content/docs/iac/get-started/kubernetes/next-steps.md b/content/docs/iac/get-started/kubernetes/next-steps.md index 594d4135eff0..161bca446d1d 100644 --- a/content/docs/iac/get-started/kubernetes/next-steps.md +++ b/content/docs/iac/get-started/kubernetes/next-steps.md @@ -40,13 +40,13 @@ With Pulumi ESC you can: Dive into Learn Pulumi for a comprehensive walkthrough of key Pulumi concepts in the context of a real-life application. -{{< get-started-next-step path="/learn/pulumi-fundamentals" label="Learn Pulumi Fundamentals" ref="gs-k8s-learn" >}} +{{< get-started-next-step path="/learn/tutorials/pulumi-fundamentals/" label="Learn Pulumi Fundamentals" ref="gs-k8s-learn" >}} ## Launch a new project with a template -Deploy the most common cloud architectures, from [static websites](/templates/static-website/) to [serverless applications](/templates/serverless-application/), [virtual machines](/templates/virtual-machine/), [container services](/templates/container-service/), and [Kubernetes clusters](/templates/kubernetes/). +Deploy the most common cloud architectures, from [static websites](/learn/official-templates/static-website/) to [serverless applications](/learn/official-templates/serverless-application/), [virtual machines](/learn/official-templates/virtual-machine/), [container services](/learn/official-templates/container-service/), and [Kubernetes clusters](/learn/official-templates/kubernetes/). -{{< get-started-next-step path="/templates/" label="Browse templates" ref="gs-k8s-templates" >}} +{{< get-started-next-step path="/learn/official-templates/" label="Browse templates" ref="gs-k8s-templates" >}} ## Dive into the docs diff --git a/content/docs/iac/operations/stack-management/moving-resources-between-stacks.md b/content/docs/iac/operations/stack-management/moving-resources-between-stacks.md index 174c38c30143..5dd0ed8b76c2 100644 --- a/content/docs/iac/operations/stack-management/moving-resources-between-stacks.md +++ b/content/docs/iac/operations/stack-management/moving-resources-between-stacks.md @@ -16,7 +16,7 @@ As a project grows, you may decide to split a monolithic stack into smaller ones `pulumi state move` only modifies the state files of the source and destination stacks. It does not change your program code. After moving resources you still need to add the corresponding resource declarations to the destination stack's program, as described in [Update the destination program](#update-the-destination-program) below. {{% /notes %}} -For a complete worked example that provisions resources, moves them between two stacks in different projects, and updates the program code on both sides, see the [Move Resources Between Stacks](/tutorials/move-resources-between-stacks/) tutorial. For the motivation behind splitting a monolithic stack in the first place, see [Organizing projects & stacks](/docs/iac/guides/basics/organizing-projects-stacks/). +For a complete worked example that provisions resources, moves them between two stacks in different projects, and updates the program code on both sides, see the [Move Resources Between Stacks](/learn/tutorials/move-resources-between-stacks/) tutorial. For the motivation behind splitting a monolithic stack in the first place, see [Organizing projects & stacks](/docs/iac/guides/basics/organizing-projects-stacks/). ## Identify the resources to move @@ -77,7 +77,7 @@ Once the program changes are in place, run `pulumi preview` on both stacks. A cl ## Learn more -* [Move Resources Between Stacks](/tutorials/move-resources-between-stacks/) — a full tutorial covering this workflow end to end, including cross-project moves and resolving dependencies with stack references. +* [Move Resources Between Stacks](/learn/tutorials/move-resources-between-stacks/) — a full tutorial covering this workflow end to end, including cross-project moves and resolving dependencies with stack references. * [Refactoring with aliases](/docs/iac/operations/stack-management/refactoring-with-aliases/) — use the `aliases` resource option when a moved resource's identity changes in the destination program. * [Organizing projects & stacks](/docs/iac/guides/basics/organizing-projects-stacks/) — the tradeoffs behind splitting a monolithic stack into layered or micro-stacks in the first place. * [`pulumi state move` CLI reference](/docs/iac/cli/commands/pulumi_state_move/) — the full command reference, including flags. diff --git a/content/docs/insights/policy/_index.md b/content/docs/insights/policy/_index.md index db792edee852..9ddb7d5270b0 100644 --- a/content/docs/insights/policy/_index.md +++ b/content/docs/insights/policy/_index.md @@ -122,7 +122,7 @@ Choose your path based on your needs: - **Using the CLI?** See the [CLI reference](/docs/insights/policy/cli/) for `pulumi policy` commands to create, publish, and manage policy packs from the command line. - **Enforcing policies in CI/CD?** Learn how to [integrate policy enforcement](/docs/insights/policy/ci-cd/) into GitHub Actions, Google Cloud Build, and other CI/CD pipelines. - **Building custom tooling?** Explore the [API & SDK reference](/docs/insights/policy/api-reference/) for the Policy SDK and Pulumi Cloud REST API endpoints. -- **Looking for tutorials?** Follow the [custom policy pack tutorial](/tutorials/custom-policy-pack/) to create, validate, and publish a policy pack step by step. Or learn how to [evaluate Terraform compliance with Pulumi](/tutorials/eval-compliance-terraform/). +- **Looking for tutorials?** Follow the [custom policy pack tutorial](/learn/tutorials/custom-policy-pack/) to create, validate, and publish a policy pack step by step. Or learn how to [evaluate Terraform compliance with Pulumi](/learn/tutorials/eval-compliance-terraform/). - **Building an internal developer platform?** Explore advanced patterns including [policies as tests](/docs/idp/guides/best-practices/patterns/policies-as-tests/), [validating component inputs using policy functions](/docs/idp/guides/best-practices/patterns/validating-component-inputs-using-policy-functions/), and [cost control using components, policies, and constrained inputs](/docs/idp/guides/best-practices/patterns/cost-control-using-components-policies-constrained-inputs/). For common questions and troubleshooting, see the [FAQ](/docs/support/faq/policies/). diff --git a/content/docs/integrations/clouds/aws/_index.md b/content/docs/integrations/clouds/aws/_index.md index a55750a28fd0..50846aa44359 100644 --- a/content/docs/integrations/clouds/aws/_index.md +++ b/content/docs/integrations/clouds/aws/_index.md @@ -35,15 +35,15 @@ Pulumi provides several packages for working with AWS. Most projects combine mor ## Architecture templates -[Pulumi templates](/templates/) are ready-to-deploy starting points for common architectures. Run `pulumi new