Skip to content

fix(go,mcp,php,java): declare config validation examples and fix the patterns they expose - #155

Open
2ynn wants to merge 12 commits into
fix/ruby/module-name-acronymsfrom
test/config-validation-examples
Open

2ynn wants to merge 12 commits into
fix/ruby/module-name-acronymsfrom
test/config-validation-examples

Conversation

@2ynn

@2ynn 2ynn commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #152, which adds ValidationExamples and TestValidationRegexes. Review after #152; this PR will be retargeted to main once #152 merges.

Why

#152 lets a config field in config.ts list accepted and rejected values next to its ValidationRegex, and checks them in TestValidationRegexes. Only the Ruby module field uses it so far. A default-value check cannot catch a pattern that rejects valid input, which is how the Ruby regression went unnoticed, and the same gap exists for every other target.

Writing examples for the remaining fields surfaced two patterns that reject every or many valid values:

  • Go retractions is a list of {version, comment} objects, but its ValidationRegex matches a single semantic version. The Speakeasy CLI checks a field's pattern against the value formatted with %v, so a configured list arrives as [map[comment:Published accidentally version:v1.0.0]] and always fails. The field cannot be used through the CLI, although the generator renders it into the retract block of go.mod.
  • MCP mcpName only allowed lowercase letters and digits per namespace segment, and lowercase letters, digits and hyphens in the server name. The MCP registry's server.json schema (the 2025-12-11 version the generated server.json declares) accepts ^[a-zA-Z0-9.-]+/[a-zA-Z0-9._-]+$, so registry names such as io.github.acme-labs/petstore (a GitHub owner with a hyphen) were rejected.

What changed

  • Examples (test-only, no pattern changes): ValidationExamples on 69 fields across common/common and every target with structured patterns (cli, csharp, go, javav2, mcp-typescript, php, postman, pythonv2, ruby, terraform, typescriptv2, unity): names, identifiers, package and module paths, versions, URLs, durations, and numbers. Fields whose pattern only lists fixed values, such as ^(true|false)$ or ^(net8\.0|net10\.0)$, have no examples; the pattern already is the list. Values are generic (acme, example.com). Fields that share a pattern use the same examples (for example every version, maxMethodParams, and defaultErrorName); config.ts files run as standalone scripts and cannot import shared constants.

  • Go retractions: the ValidationRegex and ValidationMessage are removed from the field. No generator-side check replaces them: Generator.validateConfig runs whenever the generator loads gen.yaml, and templateRetractions already accepts single versions, ranges such as [v1.0.0, v1.9.9], and items keyed Version, and skips items without a version. A stricter check there would stop generation for configurations that render a valid go.mod today. An invalid version still fails when the go command loads the generated go.mod. Changeset: core / go patch.

  • MCP mcpName: pattern replaced with the registry's, and the message and description now describe the accepted shape (a namespace and a server name separated by one slash, the namespace usually reverse-DNS), since names such as acme/petstore are valid. The registry's 3 to 200 character length limit is not enforced: Go's regexp has no lookahead to combine it with the pattern. The value is only written to package.json and server.json. Changeset: core / mcp-typescript patch.

  • PHP packageName: the pattern had no closing $, so any value starting with a valid Composer name passed, such as acme/petstoreSDK or acme/petstore sdk. The value is written unchanged to name in the generated composer.json, and composer install fails on such names. The pattern is now Composer's own name pattern from its JSON schema (^[a-z0-9]([_.-]?[a-z0-9]+)*/[a-z0-9](([_.]|-{1,2})?[a-z0-9]+)*$), which matches the same names as before and is anchored. Changeset: core / php patch.

  • Java githubURL links: publishing.gradle prepends https:// to the value and appends .git for the SCM connection. Values the unanchored pattern already accepts, such as https://github.com/acme/acme-java, www.github.com/acme/acme-java or github.com/acme/acme-java.git, rendered as https://https://github.com/... or scm:git:ssh://git@github.com/acme/acme-java.git.git. A leading http(s):// and www. and a trailing / and .git are now stripped, ignoring case, before the links are written; a non-string value is converted to a string first, so it renders as before instead of failing. The pattern is unchanged, and github.com/owner/repo renders exactly as before, so the review SDK does not change. Changeset: core / javav2 patch.

The Go, MCP and Java fixes only widen what is accepted or correct the rendered output. The generator's own validateConfig is unchanged, so no configuration that passes CLI validation or generates today stops doing so. The PHP fix narrows it, but only by names that Composer already rejects.

Not changed here

Writing examples also showed patterns that accept values they should reject. Tightening a pattern makes existing gen.yaml files that rely on the looser behaviour fail validation, and when speakeasyVersion is latest the CLI then reruns with the last version that succeeded, so those SDKs stop receiving generator updates. Each of these needs its own decision, so the examples above avoid the affected values:

  • javav2 githubURL (github\.com\/[a-zA-z\d_-]+?\/.+) has no anchors, and A-z also matches [, \, ], ^, _ and a backtick, so values such as ssh://git@github.com/acme/acme-java or see github.com/acme/acme-java pass. The rendered POM links are now normalized (see above); tightening the pattern would reject values that generate today.
  • javav2 templateVersion (v2) has no anchors, so any value containing v2 passes. The gen.yaml value does not select the template (the field's default does) and the generator overwrites it with the template's version, so a value such as v2.0 generates normally today; tightening would only reject it.
  • The POM scm.url is written without a scheme (github.com/owner/repo) for every value. Fixing it changes the generated publishing.gradle of every published Java SDK, so it is left for a separate change.
  • cli packageName (^[\w\d.\-_/]+$) accepts a leading or trailing slash, such as /acme or acme/, which is not a valid Go module path.
  • typescriptv2 and mcp-typescript packageName (^[\w\d._@\/-]+$) accept values npm rejects, such as @acme (scope without a name) or acme@sdk.
  • baseErrorName ("Must start with a capital letter") and go sdkPackageName ("Must start with letter") accept a leading digit or underscore. The generator sanitizes both names (a leading digit is spelled out), so generated code is not affected.
  • javav2 groupID ("Must start with a letter") accepts a leading digit or underscore, and terraform packageName and providerTypeNameOverride ("Letters, numbers, or - only") accept _.
  • csharp and unity packageName reject - although NuGet package IDs allow it; the value is also used as the root namespace, where - is invalid, so the examples list Acme-Sdk as invalid.

Testing

  • go test ./pkg/templates -run TestValidationRegexes -count=1: passes; examples are read for all 70 fields (69 here plus Ruby module from fix(ruby): accept acronyms in module name validation #152).
  • With the previous PHP packageName pattern, the new invalid examples acme/petstoreSDK, acme/petstore sdk and acme/petstore---sdk match. A root composer.json named acme/petstoreSDK, acme/petstore sdk or acme/petstore! fails composer validate and composer install (Composer 2.10.3) with name : Does not match the regex pattern.
  • cmd/generate -l java -p with githubURL: github.com/owner/repo writes the same three POM links as before; with https://www.github.com/acme/acme-java.git/ or HTTPS://WWW.github.com/acme/acme-java.GIT it writes https://github.com/acme/acme-java, github.com/acme/acme-java and scm:git:ssh://git@github.com/acme/acme-java.git. githubURL: 123 renders https://123 as before.
  • With the previous mcpName pattern, the new valid examples io.github.acme-labs/petstore and io.github.Acme/petstore_mcp.v2 fail.
  • cmd/generate for go with retractions set to {version: v1.0.0, comment: Published accidentally}, {version: "[v1.1.0, v1.1.5]"}, and {Version: v1.2.0} generates a retract block with all three, which go mod edit -json parses. A go.mod retracting 1.0.0 or v2.0.0+build.5 fails go list -m.
  • pkg/generate/java_publishing_links_test.go generates a published Java SDK for canonical, scheme/www./.git/trailing-slash, uppercase and numeric githubURL values and asserts the three rendered links. With the normalization removed, made case-sensitive, or without the string conversion, the matching cases fail.
  • TestListFieldsHaveNoValidationRegex asserts that Go retractions has no ValidationRegex; restoring a version pattern on it fails. List fields with a default are already caught by the default value check.
  • Boundary examples: Composer acme/petstore--sdk (two hyphens) is valid, and MCP io.github.acme/2petstore (server name starting with a digit) is valid.
  • go test ./pkg/generate -count=1, go test ./pkg/templates -count=1, make lint (includes TypeScript checks for every template): pass.
  • Generated output does not change, so no review SDKs are regenerated.
  • Not run: end-to-end speakeasy run, which needs a CLI build bundling this generator.

Public-safety check

  • This change contains no credentials, customer documents, private repository URLs, private filesystem paths, or unredacted private logs.
  • Title, body, comments, and commit messages name no customers or customer-derived identifiers, private paths or trackers, or workflow provenance, and are understandable without private context (.claude/skills/public-repo-communication/SKILL.md).
  • Generated fixtures and review SDK changes are public-safe.
  • I reviewed git diff --check.

2ynn added 3 commits October 26, 2026 15:27
Add ValidationExamples to every config field whose ValidationRegex
describes a structured value (names, identifiers, paths, versions,
URLs, durations, numbers) across the common fields and all targets.
Fields whose pattern only lists fixed values, such as ^(true|false)$,
are left without examples.

TestValidationRegexes checks each example against its pattern, so a
future change that rejects a listed valid value or accepts a listed
invalid one fails the test. No pattern changes.
The retractions field is a list of {version, comment} objects, but its
ValidationRegex matched a single semantic version. The Speakeasy CLI
checks a field's pattern against the value formatted with %v, so any
configured list, such as [map[version:v1.0.0]], failed gen.yaml
validation and could not be used.

Drop the pattern from the field and check each retraction's version in
the Go target's validateConfig instead, which receives the list itself.
The cli config validation tests' helper becomes newLanguageTestConfig
so the Go tests can share it.
The mcpName pattern only allowed lowercase letters and digits in each
namespace segment and lowercase letters, digits and hyphens in the
server name. The MCP registry's server.json schema accepts
^[a-zA-Z0-9.-]+/[a-zA-Z0-9._-]+$, so valid registry names such as
io.github.acme-labs/petstore (a GitHub owner with a hyphen) or
io.github.Acme/petstore_mcp.v2 failed gen.yaml validation. Use the
registry's pattern. The value is only written to server.json and
package.json.
@github-actions github-actions Bot added csharp Trigger (24) snapshot tests for csharp go Trigger (90) snapshot tests for go java Trigger (40) snapshot tests for java mcp-typescript Trigger (16) snapshot tests for mcp-typescript php Trigger (22) snapshot tests for php postman Trigger (3) snapshot tests for postman python Trigger (106) snapshot tests for python ruby Trigger (19) snapshot tests for ruby terraform Trigger (12) snapshot tests for terraform typescript Trigger (168) snapshot tests for typescript unity labels Oct 26, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

All reported issues were addressed across 17 files

Shadow auto-approve: would not auto-approve because issues were found.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread pkg/generate/go_config_validation_test.go Outdated
2ynn added 2 commits October 26, 2026 15:58
The validateConfig check added for retractions runs whenever the
generator loads gen.yaml, not only in the CLI. It rejected inputs that
templateRetractions renders correctly: version ranges such as
[v1.0.0, v1.9.9], items keyed Version, and items without a version,
which the template skips. It also accepted build metadata such as
v2.0.0+build.5, which Go module versions do not allow.

Remove the check and its tests. With the field's ValidationRegex
already gone, retractions are no longer pattern-checked by the CLI, and
the generator accepts what it accepted before; an invalid version still
fails when the go command loads go.mod.
The mcpName message still said "reverse-DNS format" although the
pattern now follows the MCP registry and also accepts names such as
acme/petstore. State the accepted shape instead. Also replace a
non-generic httpClientPrefix example in the C# config.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

All reported issues were addressed across 5 files (changes from recent commits).

Shadow auto-approve: would not auto-approve because issues were found.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread templates/templates/mcp-typescript/config.ts
@speakeasy-generator-bot

speakeasy-generator-bot Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Generator Snapshot Testing

Selector(s) Result Summary
snapshot-csharp, snapshot-go, snapshot-java, snapshot-mcp-typescript, snapshot-php, snapshot-postman, snapshot-python, snapshot-ruby, snapshot-terraform, snapshot-typescript ❌ Snapshot run failed

Snapshot results: https://github.com/speakeasy-api/openapi-generation-snapshots/issues/138#issuecomment-6427754866

Snapshot results are summarized above. Additional run context is linked for maintainers with access.

The packageName pattern had no closing $, so any value that started
with a valid Composer name passed, such as acme/petstoreSDK or
acme/petstore sdk. The value is written unchanged to the name field of
the generated composer.json, and Composer rejects such names when the
SDK is installed. Use Composer's own name pattern from its JSON schema,
which matches the same names and is anchored.
@2ynn 2ynn changed the title fix(go,mcp): declare config validation examples and fix the patterns they expose fix(go,mcp,php): declare config validation examples and fix the patterns they expose Oct 26, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

0 issues found across 2 files (changes from recent commits).

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Shadow auto-approve: would not auto-approve. Auto-approval blocked by 1 unresolved issue from previous reviews.

View guided diff | Turn on auto-fix | Re-trigger cubic

2ynn added 2 commits October 26, 2026 16:22
The githubURL pattern is unanchored, so values such as
https://github.com/acme/acme-java, www.github.com/acme/acme-java or
github.com/acme/acme-java.git pass validation. publishing.gradle
prepends https:// and appends .git to the value, which turned them into
POM links such as https://https://github.com/... and
scm:git:ssh://git@github.com/acme/acme-java.git.git.

Strip a leading http(s):// and www. and a trailing slash and .git
before writing the links. The pattern is unchanged, so every value
that passes validation today still passes; the canonical
github.com/owner/repo form renders exactly as before.
The field description still said the name is in reverse-DNS format,
while the pattern follows the MCP registry and also accepts names such
as acme/petstore. Describe the namespace/server-name shape and keep
reverse-DNS as the usual namespace form.
@2ynn 2ynn changed the title fix(go,mcp,php): declare config validation examples and fix the patterns they expose fix(go,mcp,php,java): declare config validation examples and fix the patterns they expose Oct 26, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

All reported issues were addressed across 4 files (changes from recent commits).

Shadow auto-approve: would not auto-approve because issues were found.
Tip: Review your code locally with the cubic CLI to iterate faster.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread templates/templates/javav2/auxiliary/publishing.gradle.stmpl Outdated
Comment thread templates/templates/javav2/auxiliary/publishing.gradle.stmpl Outdated
The githubURL pattern is case-sensitive only for github.com, so values
such as HTTPS://WWW.github.com/acme/acme-java.GIT pass validation; strip
the scheme, www. and .git regardless of case.

A non-string githubURL, such as a YAML number, made the normalization
throw and abort generation, where the template previously rendered it
as is. Convert the value to a string before normalizing.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

0 issues found across 2 files (changes from recent commits).

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Shadow auto-approve: would not auto-approve. Auto-approval blocked by 1 unresolved issue from previous reviews.

View guided diff | Turn on auto-fix | Re-trigger cubic

@2ynn
2ynn marked this pull request as ready for review October 26, 2026 20:42
@2ynn
2ynn requested a review from a team as a code owner October 26, 2026 20:42
@2ynn
2ynn requested review from TristanSpeakEasy and removed request for a team October 26, 2026 20:42
2ynn added 3 commits October 26, 2026 16:56
Generate a published Java SDK for canonical, scheme/www/.git/trailing
slash, uppercase and non-string githubURL values and assert the three
links written to publishing.gradle. The githubURL examples only check
the unchanged pattern, so they do not cover the normalization.
…examples

The CLI matches a field's ValidationRegex against its value formatted
with %v, so a pattern on a list field rejects every list. List fields
with a default are already caught by the default value check; add a
test for those without one, starting with Go retractions.

Also add valid examples for the two-hyphen Composer package name
boundary and an MCP server name that starts with a digit.

@TristanSpeakEasy TristanSpeakEasy left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good, the examples cover the pattern fixes well and normalising githubURL before building the publishing links makes sense.

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

Labels

csharp Trigger (24) snapshot tests for csharp go Trigger (90) snapshot tests for go java Trigger (40) snapshot tests for java mcp-typescript Trigger (16) snapshot tests for mcp-typescript php Trigger (22) snapshot tests for php postman Trigger (3) snapshot tests for postman python Trigger (106) snapshot tests for python ruby Trigger (19) snapshot tests for ruby terraform Trigger (12) snapshot tests for terraform typescript Trigger (168) snapshot tests for typescript unity

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants