From 5bf6472a58f96fc1428a2e2f21d2da573fc36777 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Thu, 15 Oct 2026 10:33:45 -0700 Subject: [PATCH 1/2] Make CLI help baselines independent of version length Release version bumps change the help header's padding even after its version text is normalized. This makes release creation fail solely because the new version has a different length. Keep normalized headers aligned so development and release versions can share the same baseline. --- tsc/internal/execute/tsctests/sys.go | 14 +++++- tsc/internal/execute/tsctests/tsc_test.go | 43 +++++++++++++++++++ ...tatus.DiagnosticsPresent_OutputsSkipped.js | 2 +- 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/tsc/internal/execute/tsctests/sys.go b/tsc/internal/execute/tsctests/sys.go index cfcd2b4196998..555377a2aed31 100644 --- a/tsc/internal/execute/tsctests/sys.go +++ b/tsc/internal/execute/tsctests/sys.go @@ -485,12 +485,22 @@ var ( func (o *outputSanitizer) addOutputLine(s string) { s = strings.ReplaceAll(s, fmt.Sprintf("'%s'", core.Version()), fmt.Sprintf("'%s'", harnessutil.FakeTSVersion)) - s = strings.ReplaceAll(s, englishVersion, fakeEnglishVersion) - s = strings.ReplaceAll(s, czechVersion, fakeCzechVersion) + s = sanitizeVersion(s, englishVersion, fakeEnglishVersion) + s = sanitizeVersion(s, czechVersion, fakeCzechVersion) s = fsbaselineutil.SanitizeInternalSymbolName(s) o.outputLines = append(o.outputLines, s) } +func sanitizeVersion(s string, version string, replacement string) string { + if before, after, ok := strings.Cut(s, version); ok && strings.HasPrefix(after, " ") { + // Preserve the padded field width when replacing the version in the help header. + suffix := strings.TrimLeft(after, " ") + width := len(version) + len(after) - len(suffix) + s = before + fmt.Sprintf("%-*s", width, replacement) + suffix + } + return strings.ReplaceAll(s, version, replacement) +} + func (o *outputSanitizer) sanitizeBuildStatusTimeStamp() string { statusLine := o.lines[o.index] hhSeparator := strings.IndexRune(statusLine, ':') diff --git a/tsc/internal/execute/tsctests/tsc_test.go b/tsc/internal/execute/tsctests/tsc_test.go index aff5f93620582..f1c8a890e877c 100644 --- a/tsc/internal/execute/tsctests/tsc_test.go +++ b/tsc/internal/execute/tsctests/tsc_test.go @@ -7,11 +7,54 @@ import ( "testing" "github.com/microsoft/TypeScript/tsc/internal/core" + "github.com/microsoft/TypeScript/tsc/internal/diagnostics" + "github.com/microsoft/TypeScript/tsc/internal/locale" "github.com/microsoft/TypeScript/tsc/internal/testutil/contentmappertest" + "github.com/microsoft/TypeScript/tsc/internal/testutil/harnessutil" "github.com/microsoft/TypeScript/tsc/internal/testutil/stringtestutil" "github.com/microsoft/TypeScript/tsc/internal/vfs/vfstest" + "gotest.tools/v3/assert" ) +func TestOutputSanitizerVersionPadding(t *testing.T) { + t.Parallel() + for name, language := range map[string]locale.Locale{"en": locale.Default, "cs": czech} { + t.Run(name, func(t *testing.T) { + t.Parallel() + version := diagnostics.Version_0.Localize(language, core.Version()) + fakeVersion := diagnostics.Version_0.Localize(language, harnessutil.FakeTSVersion) + header := diagnostics.X_tsc_Colon_The_TypeScript_Compiler.Localize(language) + " - " + for _, test := range []struct { + name string + input string + want string + }{ + {name: "version", input: version, want: fakeVersion}, + {name: "version in prose", input: version + " is installed", want: fakeVersion + " is installed"}, + {name: "repeated versions", input: version + ", " + version, want: fakeVersion + ", " + fakeVersion}, + {name: "header without logo", input: header + version, want: header + fakeVersion}, + { + name: "header with logo", + input: fmt.Sprintf("%-115s\x1b[44m \x1b[39;49m", header+version), + want: fmt.Sprintf("%-115s\x1b[44m \x1b[39;49m", header+fakeVersion), + }, + { + name: "narrow header with logo", + input: fmt.Sprintf("%-75s\x1b[44m \x1b[39;49m", header+version), + want: fmt.Sprintf("%-75s\x1b[44m \x1b[39;49m", header+fakeVersion), + }, + } { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + sanitizer := &outputSanitizer{} + sanitizer.addOutputLine(test.input) + assert.Equal(t, strings.Join(sanitizer.outputLines, "\n"), test.want) + }) + } + }) + } +} + func TestTscCommandline(t *testing.T) { t.Parallel() colorTest := func(subScenario string, env map[string]string, outputIsTTY bool) *tscInput { diff --git a/tsc/testdata/baselines/reference/tsc/commandLine/show-help-with-ExitStatus.DiagnosticsPresent_OutputsSkipped.js b/tsc/testdata/baselines/reference/tsc/commandLine/show-help-with-ExitStatus.DiagnosticsPresent_OutputsSkipped.js index a0ea9d62b910e..bc19a963b175d 100644 --- a/tsc/testdata/baselines/reference/tsc/commandLine/show-help-with-ExitStatus.DiagnosticsPresent_OutputsSkipped.js +++ b/tsc/testdata/baselines/reference/tsc/commandLine/show-help-with-ExitStatus.DiagnosticsPresent_OutputsSkipped.js @@ -6,7 +6,7 @@ tsgo ExitStatus:: DiagnosticsPresent_OutputsSkipped Output:: Version FakeTSVersion -tsc: The TypeScript Compiler - Version FakeTSVersion   +tsc: The TypeScript Compiler - Version FakeTSVersion    TS  COMMON COMMANDS From 8692719d076ee1fc78d0a78d98714c55fb0e78a1 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Thu, 15 Oct 2026 10:33:45 -0700 Subject: [PATCH 2/2] Keep bot workflow failure reporting authenticated Failures before token creation leave the result-reporting action without a token, preventing the bot from explaining what went wrong. Three of the workflows also omit the issue permission needed to post results. Allow reporting authentication after earlier failures without allowing branch pushes or PR creation to proceed on failure. --- .github/workflows/create-cherry-pick-pr.yml | 2 ++ .github/workflows/new-release-branch.yaml | 3 +++ .github/workflows/set-version.yaml | 3 +++ .github/workflows/sync-branch.yaml | 3 +++ 4 files changed, 11 insertions(+) diff --git a/.github/workflows/create-cherry-pick-pr.yml b/.github/workflows/create-cherry-pick-pr.yml index 90b999946080c..a0dd69e68bb5d 100644 --- a/.github/workflows/create-cherry-pick-pr.yml +++ b/.github/workflows/create-cherry-pick-pr.yml @@ -66,11 +66,13 @@ jobs: run: git switch --detach "origin/$TARGET_BRANCH" - run: npm ci - uses: azure/login@a641126d1b8aa4d1fa005f4f92df94a3a4c4c906 # v3.1.0 + if: ${{ !cancelled() }} with: client-id: ${{ vars.AZURE_CLIENT_ID }} tenant-id: ${{ vars.AZURE_TENANT_ID }} subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }} - name: Create GitHub App token + if: ${{ !cancelled() }} id: app-token uses: microsoft/create-github-app-token-via-key-vault@5ba0d436e9c3cac52feff4d1f2f66f9698ce4a2d # v1 with: diff --git a/.github/workflows/new-release-branch.yaml b/.github/workflows/new-release-branch.yaml index 9132dd867e69b..834655bf8998e 100644 --- a/.github/workflows/new-release-branch.yaml +++ b/.github/workflows/new-release-branch.yaml @@ -108,11 +108,13 @@ jobs: git config core.hooksPath /dev/null git commit -m "Bump version to $PACKAGE_VERSION" - uses: azure/login@a641126d1b8aa4d1fa005f4f92df94a3a4c4c906 # v3.1.0 + if: ${{ !cancelled() }} with: client-id: ${{ vars.AZURE_CLIENT_ID }} tenant-id: ${{ vars.AZURE_TENANT_ID }} subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }} - name: Create GitHub App token + if: ${{ !cancelled() }} id: app-token uses: microsoft/create-github-app-token-via-key-vault@5ba0d436e9c3cac52feff4d1f2f66f9698ce4a2d # v1 with: @@ -121,6 +123,7 @@ jobs: owner: microsoft repositories: TypeScript permission-contents: write + permission-issues: write - name: Configure git for GitHub App token env: GITHUB_APP_TOKEN: ${{ steps.app-token.outputs.token }} diff --git a/.github/workflows/set-version.yaml b/.github/workflows/set-version.yaml index edf2b5309b71b..b7328a178120c 100644 --- a/.github/workflows/set-version.yaml +++ b/.github/workflows/set-version.yaml @@ -125,11 +125,13 @@ jobs: git config core.hooksPath /dev/null git commit -m "Bump version to $PACKAGE_VERSION" - uses: azure/login@a641126d1b8aa4d1fa005f4f92df94a3a4c4c906 # v3.1.0 + if: ${{ !cancelled() }} with: client-id: ${{ vars.AZURE_CLIENT_ID }} tenant-id: ${{ vars.AZURE_TENANT_ID }} subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }} - name: Create GitHub App token + if: ${{ !cancelled() }} id: app-token uses: microsoft/create-github-app-token-via-key-vault@5ba0d436e9c3cac52feff4d1f2f66f9698ce4a2d # v1 with: @@ -138,6 +140,7 @@ jobs: owner: microsoft repositories: TypeScript permission-contents: write + permission-issues: write - name: Configure git for GitHub App token if: steps.configure.outputs.changed == 'true' env: diff --git a/.github/workflows/sync-branch.yaml b/.github/workflows/sync-branch.yaml index c6bebd8159a64..fd7e5583a1292 100644 --- a/.github/workflows/sync-branch.yaml +++ b/.github/workflows/sync-branch.yaml @@ -116,11 +116,13 @@ jobs: exit 1 fi - uses: azure/login@a641126d1b8aa4d1fa005f4f92df94a3a4c4c906 # v3.1.0 + if: ${{ !cancelled() }} with: client-id: ${{ vars.AZURE_CLIENT_ID }} tenant-id: ${{ vars.AZURE_TENANT_ID }} subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }} - name: Create GitHub App token + if: ${{ !cancelled() }} id: app-token uses: microsoft/create-github-app-token-via-key-vault@5ba0d436e9c3cac52feff4d1f2f66f9698ce4a2d # v1 with: @@ -129,6 +131,7 @@ jobs: owner: microsoft repositories: TypeScript permission-contents: write + permission-issues: write - name: Configure git for GitHub App token env: GITHUB_APP_TOKEN: ${{ steps.app-token.outputs.token }}