Skip to content

Commit 47bd693

Browse files
workprentice[bot]workprenticeCamSopergithub-actions[bot]
authored
Add Vale rule for overcapitalized "Stack" (issue #20653) (#20952)
* Add Vale rule for overcapitalized generic concepts (issue #20653) The brand writing-style guide says only proper nouns are capitalized: "stack" not "Stack", "environment" not "Environment", "infrastructure as code" not "Infrastructure as Code" mid-sentence. Product-name casing and retired names are already well covered by Pulumi.Nomenclature and Pulumi.DeprecatedProductNames, but nothing enforced this rule, so generic IaC concepts kept drifting into Title Case. Add Pulumi.Overcapitalization, an existence rule flagging a determiner followed by capitalized "Stack" and a lowercase word followed by "Infrastructure as Code". Both tokens use a negative lookahead (Vale's regexp2 fallback, same technique as Pulumi.NarrativeWe) to skip a following capitalized word, so compound proper nouns like "Stack Admin", "Stack Tags", and "Stack API" aren't mistaken for the generic concept. Tuned against the full content/ tree (2,241 files): the Pulumi Kubernetes Operator's `Stack` custom resource (a Kubernetes CRD Kind) and the Pulumi CDK bridge's `pulumicdk.Stack` class both legitimately capitalize "Stack", so the operator docs subtree, the operator's launch/update blog posts, the ArgoCD integration guide, and the CDK guide are opted out in .vale.ini. A handful of other posts had the same CRD/class bleed into otherwise-generic prose; those got backticks instead of a rule exception. One 2019 blog post (stack-readme) treats "Stack" as a UI feature name throughout and is opted out rather than rewritten wholesale. Every other true violation the rule found -- about a dozen, split between docs and blog -- is fixed in this same commit, following the precedent set by #19975 and #20689 of shipping a new rule against already-clean copy. The tree now has zero Overcapitalization findings. The rule ships at warning, alongside DeprecatedProductNames rather than Nomenclature/Substitutions: telling the generic concept from a genuine proper noun is a judgment call, not a fixed substitution, so it isn't added to the pinned-review blocker list. STYLE-GUIDE.md's Product Names section now states the rule explicitly. Issue #20653 is terse (a title plus a link to a closed, abandoned draft), so this is a scope judgment: interpreting it as closing the gap between the brand guide's naming rules and what Vale actually enforces, and picking the clearest unenforced gap in that guide as the concrete deliverable. Flagging this as a proposal on scope, not a foregone conclusion -- redirect me if a different reading of the issue was intended. * Address review follow-up: finish overcapitalization sweep, fix broken link, fix operator provider-count attribution - Repair a years-old broken markdown link in new-kubernetes-superpowers/index.md L46 (unclosed link swallowed "extends"), while updating the stale "Pulumi Service" name to "Pulumi Cloud". - Finish the overcapitalization sweep in pulumi-yaml/index.md (L12 x2, L16) and opt the file out of the rule with a stated reason for the two legitimate proper-noun uses (workshop title, "Universal Infrastructure as Code platform" branded phrase) that should stay capitalized. - Finish the overcapitalization sweep in why-every-cloud-engineer-needs-pulumi-esc-secrets-management/index.md L161 (L105 was already fixed). - Fix what-is-gitops.md L91/L97: stop attributing a registry-wide provider count to the Pulumi Kubernetes Operator specifically; use the framing-preserving "every provider Pulumi supports" instead, consistent with L115's existing prose. * Address round-2 review: finish sweep, fix branded-phrase false positive Three issues from the re-entrant review pass, which re-greps every occurrence of a phrase a prior finding quoted rather than only the locations named: - content/blog/new-kubernetes-superpowers/index.md L32 and content/docs/esc/guides/integrate-with/cloudflare.md L176 still had mid-sentence "Infrastructure as Code" the earlier sweep missed. Lowercased both. - The rule's lookahead only excludes a compound proper noun whose capitalized half comes *after* the phrase ("Infrastructure as Code (IaC)"), not one where it comes first. Pulumi's own branded "Universal Infrastructure as Code" phrase recurs in 12 content files, so the per-file .vale.ini opt-out added for pulumi-yaml patched one of twelve. Replaced it with a global TokenIgnores entry (alongside the existing shortcode ignores) that covers all 12 at once, and trimmed the pulumi-yaml opt-out comment down to its one remaining real reason (a workshop title). - Also lowercased two more "the Stack" console-breadcrumb instances the reviewer found in content/docs/deployments/concepts/{ttl,schedules}.md (list-item text, same generic concept). Re-verified against the full content/ tree: zero Pulumi.Overcapitalization findings. * Fix terminology on a line this PR already touches: Business Critical edition, not tier content/blog/pulumi-policy-mgmt-launch/index.md's lowercased-IaC sentence also said "Business Critical tier," but current product vocabulary (see content/pricing/_index.md, policy-packs/metadata.md) is "edition," not "tier." Fixed on the same line this PR is already editing. * Fix silent boundary bug, drop unvalidated IaC token While double-checking the round-3 review's residual-finding claim by hand rather than trusting either side, found the real cause: the 'Infrastructure as Code' token used a bare [a-z] to anchor the preceding context. Vale auto-wraps existence tokens in \b...\b, and \b only holds at a genuine word/non-word transition. A single-character class only sits at that boundary when it's preceded by punctuation (an apostrophe, as in "Pulumi's"), so the token silently missed the overwhelmingly common case of an ordinary word immediately before the phrase ("the Infrastructure as Code", "your Infrastructure as Code"). The tree-wide validation stayed at zero findings not because the copy was clean, but because a whole class of true positives never matched in the first place. Fixing the anchor to a full word ([a-z]+) rather than a single character surfaces the real violation surface: 161 hits across 78 files, almost entirely blog posts written over several years. That's a real, separate editorial sweep, not something to rush through under review pressure in the same PR as the Stack token (which has been validated clean, hand-audited, and review-approved across three rounds). Scoping this PR down to the Stack token only. Dropped the IaC token, the .vale.ini TokenIgnores entry that existed solely to support it, and the pulumi-yaml opt-out whose only remaining reason was IaC-specific. Re-verified zero Pulumi.Overcapitalization findings tree-wide with the Stack-only rule. Filing the IaC sweep as a follow-up issue rather than shipping it half-validated. * Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Document scope:paragraph as deliberate, confirm headings excluded Per CamSoper's review: record that scope: paragraph is a considered choice, not an oversight, and that widening it to text or bare heading would flag correct Title-Case H1s -- this repo already hit that wall with Google.Headings. Confirmed empirically with a minimal repro that paragraph scope does exclude headings, which means the argocd.md opt-out (whose only match on that page is an H2) currently covers nothing. Left the opt-out in place -- removing it on a premise this comment only now confirms would be a separate speculative edit -- but documented so the next reader doesn't mistake it for load-bearing. Tracked alongside the dropped IaC token's own scope question in issue #20958. --------- Co-authored-by: workprentice <257153108+workprentice@users.noreply.github.com> Co-authored-by: Cam Soper <csoper@pulumi.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent eb990cf commit 47bd693

20 files changed

Lines changed: 119 additions & 27 deletions

File tree

.vale.ini

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,32 @@ Pulumi.HeadingSentenceCase = NO # Generated from `pulumi gen-docs`; the cobra `
4848
Pulumi.CrossReferenceHeadings = NO # Same generated pages; the cobra `SEE ALSO` blocks are tooling output, not hand-authored cross-references.
4949
Pulumi.FutureTense = NO # Generated from `pulumi gen-docs`; tense fixes belong upstream in pulumi/pulumi.
5050
Pulumi.NarrativeWe = NO # Same generated pages; not hand-authored prose.
51+
52+
[content/docs/integrations/clouds/kubernetes/pulumi-kubernetes-operator/**/*.md]
53+
Pulumi.Overcapitalization = NO # This subtree's capitalized "Stack" is the operator's Kubernetes CRD Kind name (a genuine proper noun, like "Pod" or "Deployment"), not the generic IaC concept -- confirmed by _index.md's own description of the operator's custom resources.
54+
55+
[content/docs/iac/guides/clouds/aws/cdk.md]
56+
Pulumi.Overcapitalization = NO # This page's capitalized "Stack" is almost always the literal `pulumicdk.Stack` class identifier (see the surrounding `new pulumicdk.Stack(...)` code samples), not the generic concept.
57+
58+
[content/docs/iac/operations/continuous-delivery/argocd.md]
59+
Pulumi.Overcapitalization = NO # This page's capitalized "Stack" is the operator's `Stack` custom resource (a proper noun, consistently backticked elsewhere on the page), not the generic concept.
60+
61+
# Same Kubernetes-CRD-Kind false positive as the docs subtree above, but in the
62+
# blog posts that introduce and update the Pulumi Kubernetes Operator (each
63+
# confirmed by grep: `kind: Stack`, "the `Stack` Custom Resource", "PKO Stack
64+
# resource", etc.).
65+
[content/blog/pko-2-0-ga/index.md]
66+
Pulumi.Overcapitalization = NO
67+
[content/blog/pulumi-kubernetes-operator/index.md]
68+
Pulumi.Overcapitalization = NO
69+
[content/blog/pulumi-kubernetes-operator-2-3/index.md]
70+
Pulumi.Overcapitalization = NO
71+
[content/blog/pulumi-kubernetes-operator-and-kargo/index.md]
72+
Pulumi.Overcapitalization = NO
73+
[content/blog/pulumi-kubernetes-operator-2-0/index.md]
74+
Pulumi.Overcapitalization = NO
75+
76+
[content/blog/stack-readme/index.md]
77+
Pulumi.Overcapitalization = NO # This 2019 post treats "Stack" as a UI feature name throughout ("the Stack page", "Stack outputs", "Stack 'Production'") -- a self-consistent, if non-house-style, voice baked into the whole piece rather than a scattered slip. Rewriting it end to end is a larger editorial pass than this rule's scope.
78+
79+

STYLE-GUIDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ See [Hugo diagrams docs](https://gohugo.io/content-management/diagrams/) and [Me
328328
- Always refer to it in the singular form (e.g., "Pulumi Policies enforces compliance").
329329
- Never refer to it in the plural (e.g., avoid "Pulumi Policies enforce compliance").
330330
- Use **"public preview"** for pre-GA features, not "public beta." This aligns with Pulumi's release terminology.
331+
- Don't overcapitalize generic concepts, even Pulumi-specific ones. Only proper nouns are capitalized: "stack" (not "Stack"), "environment" (not "Environment"), "token" (not "Token"), "infrastructure as code" (not "Infrastructure as Code") when used as a common noun mid-sentence. This mirrors the Headings rule above and applies to body prose too. It doesn't apply where the capitalized word is itself a proper noun in context — for example, the Pulumi Kubernetes Operator's `Stack` custom resource (a Kubernetes CRD Kind) or a `pulumicdk.Stack` class identifier.
331332

332333
---
333334

content/blog/automation-api-dotnet/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Currently available in public preview, Pulumi's Automation API enables you to pr
2020

2121
## Using Automation API in .NET
2222

23-
The `Pulumi.Automation` [NuGet package](https://www.nuget.org/packages/Pulumi.Automation) exposes a `LocalWorkspace` for creating and managing Pulumi [Stacks](/docs/iac/concepts/stacks/), and a `WorkspaceStack` that is a programmatic representation of a Stack for updating, refreshing, previewing, and destroying cloud resources. The Automation API makes it trivial to run Pulumi programs inline:
23+
The `Pulumi.Automation` [NuGet package](https://www.nuget.org/packages/Pulumi.Automation) exposes a `LocalWorkspace` for creating and managing Pulumi [Stacks](/docs/iac/concepts/stacks/), and a `WorkspaceStack` that is a programmatic representation of a stack for updating, refreshing, previewing, and destroying cloud resources. The Automation API makes it trivial to run Pulumi programs inline:
2424

2525
```csharp
2626
var program = PulumiFn.Create(() =>

content/blog/aws-cdk-on-pulumi/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ To deploy existing AWS CDK Constructs using Pulumi, simply do the following:
3131
2. In the constructor, use any AWS CDK constructs from existing libraries such as [`aws-cdk-lib`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib-readme.html)
3232
3. Call `this.synth()` to finalize the stack and deploy its resources.
3333

34-
Constructing an instance of this `pulumicdk.Stack` from within your Pulumi program will then deploy all of the infrastructure defined by the CDK constructs in the Stack using Pulumi.
34+
Constructing an instance of this `pulumicdk.Stack` from within your Pulumi program will then deploy all the infrastructure defined by the CDK constructs in the `Stack` using Pulumi.
3535

3636
For example, the following program deploys two AWS CDK Constructs using Pulumi.
3737

content/blog/azure-native-defaultazurecredential-and-private-cloud/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ EOF
291291

292292
#### Run the Program using Workload Identity
293293

294-
Create a Stack object to run the Pulumi program using your service account and with `azure-native:useDefaultAzureCredential` enabled.
294+
Create a stack object to run the Pulumi program using your service account and with `azure-native:useDefaultAzureCredential` enabled.
295295

296296
```shell
297297
cat <<EOF | kubectl apply -f -

content/blog/data-science-in-the-cloud/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Pick any cloud provider, and you will find a cloud SDK in various languages, for
3131

3232
Pulumi reduces the burden of creating and maintaining repeatable and robust deployments by providing the latest language runtimes, concurrency management, support for diffing updates, and maintaining state with robust checkpoints. Your infrastructure will always be in a well-defined and recoverable state.
3333

34-
[Automation API](https://github.com/pulumi/automation-api-examples) takes this one step further by providing an API overlay to Pulumi's Infrastructure as Code engine. A data scientist can build infrastructure programmatically within Jupyter to automate building and creating infrastructure as functions and call them as needed. Let's take a look at an example using a Jupyter notebook.
34+
[Automation API](https://github.com/pulumi/automation-api-examples) takes this one step further by providing an API overlay to Pulumi's infrastructure as code engine. A data scientist can build infrastructure programmatically within Jupyter to automate building and creating infrastructure as functions and call them as needed. Let's take a look at an example using a Jupyter notebook.
3535

3636
## Infrastructure as a function
3737

content/blog/kubecon-na-2024-roundup/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ We've launched several new and improved capabilities recently to serve Kubernete
2727

2828
### Pulumi Kubernetes Operator 2.0
2929

30-
The **Pulumi Kubernetes Operator** automates the deployment and management of infrastructure by running Pulumi programs directly in Kubernetes clusters, enabling teams to manage cloud resources alongside Kubernetes-native resources. The **Pulumi Kubernetes Operator 2.0** is a significant upgrade that introduces dedicated "workspace" pods for each Stack resource, effectively isolating each stack’s compute and memory resources, improving the isolation of secrets, and opening up new customization options. The operator now scales horizontally, enhancing performance and enabling teams to manage complex Kubernetes setups with greater reliability.
30+
The **Pulumi Kubernetes Operator** automates the deployment and management of infrastructure by running Pulumi programs directly in Kubernetes clusters, enabling teams to manage cloud resources alongside Kubernetes-native resources. The **Pulumi Kubernetes Operator 2.0** is a significant upgrade that introduces dedicated "workspace" pods for each `Stack` resource, effectively isolating each stack’s compute and memory resources, improving the isolation of secrets, and opening up new customization options. The operator now scales horizontally, enhancing performance and enabling teams to manage complex Kubernetes setups with greater reliability.
3131

3232
[Read more about the Pulumi Kubernetes Operator 2.0](https://www.pulumi.com/blog/pulumi-kubernetes-operator-2-0/)
3333

content/blog/managing-github-with-pulumi/index.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ fmt.Println("encountered error creating new Pulumi GitHub team: ", team.Name)
228228
}
229229
```
230230
231-
Notice how the GitHub provider allows us to use team names to create teams. In contrast, team IDs are only needed for importing to the Stack, not for maintaining state.
231+
Notice how the GitHub provider allows us to use team names to create teams. In contrast, team IDs are only needed for importing to the stack, not for maintaining state.
232232
233233
## Relationships Are Hard
234234
@@ -343,7 +343,7 @@ teams:
343343
- username: "owlcat"
344344
```
345345
346-
A [`TeamMembership` in GitHub](/registry/packages/github/api-docs/teammembership) is a cross reference between a `Team` and a `User`. Fortunately these do not need to be explicitly imported, as they are merely establishing relationships between GitHub Users and Teams. We can add `TeamMemberships` to the Stack with a `Members` struct, a new `Members[]` field on the `Team` struct, and an extra function. Again, Pulumi lets us use the promised output of the team ID to set the `TeamId` field in the `TeamMembership`:
346+
A [`TeamMembership` in GitHub](/registry/packages/github/api-docs/teammembership) is a cross reference between a `Team` and a `User`. Fortunately these do not need to be explicitly imported, as they are merely establishing relationships between GitHub Users and Teams. We can add `TeamMemberships` to the stack with a `Members` struct, a new `Members[]` field on the `Team` struct, and an extra function. Again, Pulumi lets us use the promised output of the team ID to set the `TeamId` field in the `TeamMembership`:
347347
348348
```go
349349
type Team struct {
@@ -479,7 +479,7 @@ jobs:
479479
stack-name: pulumi/prod
480480
```
481481
482-
Note that we are calling `refresh: true` in both Workflows, which uses [Pulumi Refresh](/docs/iac/cli/commands/pulumi_refresh/) to make sure that the existing GitHub resources are aligned with the resource state in our Stack.
482+
Note that we are calling `refresh: true` in both Workflows, which uses [Pulumi Refresh](/docs/iac/cli/commands/pulumi_refresh/) to make sure that the existing GitHub resources are aligned with the resource state in our stack.
483483
484484
Now, anyone with access to the GitHub management repo can:
485485

content/blog/new-kubernetes-superpowers/index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Whether you are designing your cloud native delivery platform, looking to enforc
2929

3030
## Pulumi + Kubernetes
3131

32-
Pulumi is an Infrastructure as Code platform designed from the ground up for the modern cloud. That means deep support for containers, serverless, and Kubernetes, using your favorite programming languages to define, test, and manage your cloud infrastructure. Pulumi supports easy provisioning of Kubernetes clusters in many different managed platforms, including AWS, Azure, GCP, Digital Ocean, Rancher, Linode, and Civo. Additionally, Pulumi can manage resources inside a Kubernetes cluster using the same powerful tools, replacing the need for brittle and unscalable YAML configuration. Best of all, Pulumi combines these into a single cohesive programming model across your cloud infrastructure in managed cloud services *and* in Kubernetes.
32+
Pulumi is an infrastructure as code platform designed from the ground up for the modern cloud. That means deep support for containers, serverless, and Kubernetes, using your favorite programming languages to define, test, and manage your cloud infrastructure. Pulumi supports provisioning of Kubernetes clusters in many different managed platforms, including AWS, Azure, GCP, Digital Ocean, Rancher, Linode, and Civo. Additionally, Pulumi can manage resources inside a Kubernetes cluster using the same powerful tools, replacing the need for brittle and unscalable YAML configuration. Best of all, Pulumi combines these into a single cohesive programming model across your cloud infrastructure in managed cloud services *and* in Kubernetes.
3333

3434
Kubernetes has been at the center of many Pulumi-enabled cloud modernization projects, including provisioning managed Kubernetes clusters, connecting them to supporting cloud infrastructure, enabling platform teams to configure and manage platforms on top of Kubernetes, and allowing teams to replace unmaintainable piles of YAML with code and software-based deployment processes. Hundreds of modern cloud engineering teams have been able to accelerate the move to the cloud and Kubernetes thanks to Pulumi.
3535

@@ -43,7 +43,7 @@ We’re excited to announce the new [pulumi-kubernetes-operator](https://github.
4343

4444
![Pulumi Kubernetes Operator](pulumi-kubernetes-operator.png)
4545

46-
Creating a Stack is simple: provide the stack name, project repo, and a commit (support for branches coming soon!), and the operator starts driving toward the specified state. Stacks can be used directly, or as part of higher-level abstractions to manage your infrastructure and applications. The [Pulumi Service](/docs/pulumi-cloud/ents these capabilities by providing visibility into the updates, resources under management, and policy enforcement of your stacks.
46+
Creating a `Stack` is simple: provide the stack name, project repo, and a commit (support for branches coming soon!), and the operator starts driving toward the specified state. Stacks can be used directly, or as part of higher-level abstractions to manage your infrastructure and applications. [Pulumi Cloud](/docs/pulumi-cloud/) extends these capabilities by providing visibility into the updates, resources under management, and policy enforcement of your stacks.
4747

4848
```yaml
4949
apiVersion: pulumi.com/v1alpha1

content/blog/pulumi-policy-mgmt-launch/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ tags:
1818
category: product
1919
---
2020

21-
Pulumi’s Infrastructure as Code has included a powerful policy engine from day one. Over the past year, we’ve been enhancing it significantly to provide stronger governance for modern cloud platforms. Until now, these capabilities were limited to our Business Critical tier. Today, we’re excited to announce that [policy guardrails](/docs/insights/policy/) are now available to all Team and Enterprise customers. Alongside this, we’re launching a redesigned policy management experience and introducing out-of-the-box policy packs that make it easier than ever to secure, govern, and optimize your cloud environments—even when powered by AI agents like [Pulumi Neo](/blog/pulumi-neo/).
21+
Pulumi’s infrastructure as code has included a powerful policy engine from day one. Over the past year, we’ve been enhancing it significantly to provide stronger governance for modern cloud platforms. Until now, these capabilities were limited to our Business Critical edition. Today, we’re excited to announce that [policy guardrails](/docs/insights/policy/) are now available to all Team and Enterprise customers. Alongside this, we’re launching a redesigned policy management experience and introducing out-of-the-box policy packs that make it easier than ever to secure, govern, and optimize your cloud environments—even when powered by AI agents like [Pulumi Neo](/blog/pulumi-neo/).
2222

2323
<!--more-->
2424

0 commit comments

Comments
 (0)