Skip to content

Use shared localization submission and pull-only release imports - #1971

Merged
Bill Schnurr (bschnurr) merged 15 commits into
mainfrom
users/bschnurr/shared-localization
Nov 10, 2026
Merged

Bill Schnurr (bschnurr) merged 15 commits into
mainfrom
users/bschnurr/shared-localization

Conversation

@bschnurr

@bschnurr Bill Schnurr (bschnurr) commented Oct 30, 2026 •

Copy link
Copy Markdown
Member

Summary

  • Use the shared Python localization core and composite action rather than copying helper scripts into this extension.

  • Keep GitHub English submission separate from pull-only DevDiv stable/pre-release imports.

  • Use drop branch dev and canonical extension ID ms-python.vscode-python-envs; remove tracked generated locale snapshots where present and keep generated files in VSIX selection.

  • Preserve existing runtime metadata, extraction sources, feeds, platform matrices, and version/validation behavior.

  • Require complete, nonempty manifest/runtime tables for all 14 supported locales. Allow untranslated strings and wholly untranslated tables with English fallback. Reject missing, empty, malformed, or incomplete handbacks before packaging.

Shared dependencies

The GitHub action and Azure tooling checkout are pinned to 6b4a3573e7e7a9fe1e468e129544432278aec2d6, which implements the approved English-fallback policy in microsoft/vscode-common-python-lsp#127. Both release pipelines use the GitHub-hosted microsoft/pylance-eng templates at refs/heads/main through Github-Pylance.

Verification

Executable guards read the actual YAML and preserve existing triggers, build steps, publication defaults, validation contacts, version flags, and matrices. Both release YAMLs expanded with publishing explicitly disabled (environments used the enabled validation definition because its native definitions are disabled). Actual English export used the pinned CLI through the internal feed. Changed YAML/JSON formatting and whitespace checks passed.

Setup and release prerequisites

The localization drop must contain complete, nonempty manifest/runtime handbacks for all 14 supported locales; translated content is not a readiness requirement. Both native DevDiv release definitions remain disabled; the exact YAML was expanded through the enabled isort validation definition without enabling them.

Configure the PYTHON_LOCALIZATION_APP_ID Actions variable and PYTHON_LOCALIZATION_PRIVATE_KEY secret, or grant access to organization-level credentials. Credential access was not rechecked for this feedback update. Configure access through the owners; do not copy credentials between repositories. Authorize Github-Pylance for template, translation, and shared-tooling repository resources in both release pipelines.

Merge and publication remain owner-controlled. No merge or publication is requested.

GitHub pipeline templates

  • Use microsoft/pylance-eng on GitHub instead of DevDiv/Pylance-Eng in both stable and pre-release template resources, through the existing Github-Pylance service connection.

  • Preserve refs/heads/main, template paths, build steps, localization pins, release settings, and publication defaults. Document service-connection access for template, translation, and shared-tooling resources.

  • Follow the verified isort change: Use GitHub Pylance engineering pipeline templates vscode-isort#793 (test run 15971864 succeeded with publishing disabled and Publish skipped).

Verification

  • Existing executable actual-YAML localization/release guards passed.

  • Exact parsed-YAML comparisons against the pre-change commit confirmed that the template resource is the only release configuration change.

  • All fourteen changed sibling release YAMLs passed formatting; CRLF-aware whitespace checks passed.

  • Both native release definitions remain disabled. The exact stable and pre-release YAMLs expanded successfully through enabled isort definition 27670, covering all 10 configured build platforms. No pipeline was enabled.

  • Expanded pipeline checks preserved localization import ordering, source scanning, and disabled publishing/validation-stage conditions.

These are preview expansions, not full sibling build runs. No new release builds were queued, no extension was published, and no PR was merged.

Review feedback follow-up

  • Runtime environment routing is unchanged from main. Removed the PR-added routing change, explanatory comments, and added global-refresh test to keep this PR focused on localization/pipeline work.

  • Reconciled the acceptance contract with the README and exact pinned importer: wholly untranslated tables are allowed with English fallback; complete/nonempty locale coverage and structural validation remain required.

  • TypeScript compilation, targeted ESLint, whitespace checks, and all 76 focused environment-routing/global-selection tests passed. Verified that the GitHub action and both release imports use the approved English-fallback revision.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@bschnurr Bill Schnurr (bschnurr) added the debt Code quality issues label Oct 30, 2026
@bschnurr

Copy link
Copy Markdown
Member Author

Current CI blocker: Smoke Tests (windows-latest, 3.15) fails in the before-all hook because environment discovery does not complete within 45000ms. This PR does not change the runtime discovery implementation or smoke-test workflow. The failure has not been reproduced on the base branch, so it is not being classified as confirmed pre-existing. Left unresolved and outside the localization change; keep this PR draft pending CI investigation as well as its documented localization onboarding and disabled release definitions.

Eduardo Villalpando Mello (edvilme) pushed a commit to microsoft/vscode-python-ci that referenced this pull request Oct 30, 2026
…lation checkout support

## Shared pull-only release localization
This PR replaces the unused unmerged Azure English extraction/submission machinery with an opt-in pullLocalization interface on both public release wrappers. It invokes the same Python core as the public GitHub composite action in microsoft/vscode-common-python-lsp#125 rather than maintaining a second importer.

- Consumers declare translations (private drop dev) and localizationTools (reviewed immutable common-LSP SHA), with literal Github-Pylance endpoints.
- Source stays at workspace/s; tools and translations are sibling checkouts outside extension source.
- Run the shared importer after caller build/pre-built overlays and before final VSIX packaging.
- Keep the default self SDL scan, explicitly include executable tooling, and exclude translation data. Additional caller exclusions remain supported; sourceAnalysisPool preserves original caller pools.
- Derive canonical IDs and optional runtime metadata. Require all locales and per-table real-language translation evidence before copying; allow individual untranslated strings.
- No release-side English extraction, app write-token acquisition, Git pushes, or translation-update PRs. Existing signing/setup PowerShell is intentionally unchanged.
- Preserve opt-out callers, platform/version parameters, stable manual validation, and publication gates. Azure expansion can persist checkout credentials; no claim is made otherwise.

## Verification and rollout
Actual YAML-reading guards and shared Python/Git fixtures passed. Both release entry points for seven enabled repositories expanded successfully with publishing explicitly disabled. Both environments definitions are disabled; their exact YAML also expanded through the enabled isort definition without enabling or modifying those definitions. All expanded platform jobs preserve import order, source paths, SDL scanning, and publication gates. Shared core CI and the actual isort GitHub submission action passed.

Shared dependency: microsoft/vscode-common-python-lsp#125
Pilot: microsoft/vscode-isort#777
Sibling draft PRs:
- debugger: microsoft/vscode-python-debugger#1134
- environments: microsoft/vscode-python-environments#1971
- pylint: microsoft/vscode-pylint#915
- flake8: microsoft/vscode-flake8#609
- autopep8 (including runtime l10n): microsoft/vscode-autopep8#415
- mypy: microsoft/vscode-mypy#651
- black-formatter: microsoft/vscode-black-formatter#833

Keep this PR and callers draft pending dependencies, credential setup, and real handbacks. Current drop blocks isort (English-only), environments (missing canonical output), and flake8/mypy/black (missing runtime tables). Debugger, pylint, and autopep8 passed actual manifest/runtime imports from current drop. Autopep8 runtime ...
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep the selecting manager separate from the fallback environment owner when clearing explicit global selections. Capture non-Linux E2E and integration host logs to diagnose remaining failures.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: d6166fde-f261-4e66-abe4-3ef5c1313713
@bschnurr

Bill Schnurr (bschnurr) commented Nov 3, 2026 •

Copy link
Copy Markdown
Member Author

Fixed and pushed in 5e192fc and 385c9c6. Global interpreter routing now retains the selecting manager instead of inferring it from a fallback environment owner; regression coverage verifies that clearing an explicit selection follows the configured manager on subsequent refreshes. Added non-Linux E2E/integration failure diagnostics using the existing test-host hooks, without weakening assertions or adding automatic test retries. Validation: full local unit suite, 72 targeted manager tests including the new regression, TypeScript compilation, webpack, ESLint, actionlint, actual-YAML diagnostic checks and the existing Python-matrix guard. Real Windows discovery and controlled stdlib/UV venv removal probes passed. Final revision 385c9c6: all 53 jobs in the pull-request workflow passed (https://github.com/microsoft/vscode-python-environments/actions/runs/41703916165); the duplicate push workflow also passed (https://github.com/microsoft/vscode-python-environments/actions/runs/41703906838). Reran only jobs that failed before executing tests because of Marketplace HTTP 503 or VS Code download timeouts. The original Windows discovery/removal failures did not recur. The test-file policy check now passes. No failed checks remain; the separate external VS Code PR Check is still pending.

Verify that a later configured-manager refresh publishes and reads its new environment rather than routing through the stale fallback owner.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: d6166fde-f261-4e66-abe4-3ef5c1313713
@bschnurr
Bill Schnurr (bschnurr) marked this pull request as ready for review November 4, 2026 17:48
@rchiodo

Rich Chiodo (rchiodo) commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

🔒 Automated review in progress — Rich Chiodo (@rchiodo) is auto-reviewing this PR.

@rchiodo

Copy link
Copy Markdown
Contributor

Result: ⚠️ partially-verified

Verification details

Verification: Automated verification is best effort. The PR author remains responsible for testing.

Summary: Test compilation and all 30 targeted environment-manager tests passed, including the PR’s new regression test. Offline dependency preparation succeeded; local YAML contract checks and generated-localization file selection through VSCE also passed. Initial discovery encountered missing dependencies and absent container Git metadata, not a demonstrated PR defect. Shared localization execution, real handback readiness, Azure template expansion, and non-Linux diagnostic collection remain unverified. **Reviewer dependency follow-up (nonblocking):** Suggest a separate PR adding `mocha ^10.8.2`, `typescript ^5.1.3` to the official reviewer dependency declarations, using `package.json` as the dependency/version evidence. Do not automatically create that PR. This is reviewer environment maintenance, not a required change to the reviewed PR.

Test runs: 5 passed, 1 failed, 2 not run

  • ⚠️ Not run | Shared localization submission, release import and readiness validation
  • ⚠️ Not run | Non-Linux E2E and integration failure diagnostics
  • ❌ Failed | unrelated to this PR | Dependency and test discovery | git status --short; git log -3 --oneline; printf '\nEnvironment\n'; printenv AUTOMATION_SANDBOX_PROFILE; uname -s; node --version; npm --version; printf '\nDependency and test discovery\n'; node -e "const fs=require('fs'); const p=require('./package.json'); console.log(JSON.stringify({scripts:p.scripts,devDependencies:p.devDependencies,dependencies:p.dependencies},null,2)); for(const f of ['node_modules','node_modules/mocha/bin/mocha.js','node_modules/typescript/bin/tsc','out/test/features/envManagers.unit.test.js']) console.log(f,fs.existsSync(f));"; git diff --stat HEAD~1 HEAD; git ls-files 'localization' 'unit.test' 'test.py'
  • ✅ Passed | Compile TypeScript tests | npm run compile-tests
  • ✅ Passed | Environment manager unit tests | node ./node_modules/mocha/bin/mocha.js --no-config --require source-map-support/register --require ./out/test/unittests.js --ui tdd --timeout 180000 out/test/features/envManagers.unit.test.js
  • ✅ Passed | Offline dependency preparation | npm ci --offline
  • ✅ Passed | Local localization and diagnostics YAML contracts | node <<'JS'
    const assert = require('node:assert/strict');
    const fs = require('node:fs');
    const yaml = require('js-yaml');
    const read = p => yaml.load(fs.readFileSync(p, 'utf8'));
    const workflow = read('.github/workflows/localization.yml');
    assert.deepEqual(workflow.permissions, {contents:'read'});
    assert.deepEqual(workflow.on.push.branches, ['main']);
    assert.equal(workflow.concurrency['cancel-in-progress'], false);
    assert.equal(workflow.jobs.localization.if, "github.repository == 'microsoft/vscode-python-environments'");
    const action = workflow.jobs.localization.steps[0];
    const pin = 'd1877b84bb10ff7caa6bd12ab4e75498ba760790';
    assert.equal(action.uses, microsoft/vscode-common-python-lsp/.github/actions/localization@${pin});
    assert.equal(action.with['app-id'], '${{ vars.PYTHON_LOCALIZATION_APP_ID }}');
    assert.equal(action.with['private-key'], '${{ secrets.PYTHON_LOCALIZATION_PRIVATE_KEY }}');
    for (const quality of ['stable', 'pre-release']) {
    const pipeline = read(build/azure-devdiv-pipeline.${quality}.yml);
    const repos = Object.fromEntries(pipeline.resources.repositories.map(r => [r.repository, r]));
    assert.equal(repos.translations.name, 'microsoft/vscode-python-extensions-loc');
    assert.equal(repos.translations.ref, 'refs/heads/dev');
    assert.equal(repos.translations.endpoint, 'Github-Pylance');
    assert.equal(repos.localizationTools.name, 'microsoft/vscode-common-python-lsp');
    assert.equal(repos.localizationTools.ref, pin);
    assert.equal(repos.localizationTools.endpoint, 'Github-Pylance');
    assert.equal(pipeline.extends.template, azure-pipelines/extension/${quality}.yml@templates);
    assert.equal(pipeline.extends.parameters.pullLocalization, true);
    assert.equal(pipeline.extends.parameters.standardizedVersioning, true);
    assert.equal(pipeline.parameters.find(p => p.name === 'publishExtension').default, true);
    assert.deepEqual(pipeline.parameters.find(p => p.name === 'buildPlatforms').default.map(p => p.vsceTarget), ['web','linux-arm64','linux-armhf','linux-x64','alpine-arm64','alpine-x64','darwin-arm64','darwin-x64','win32-arm64','win32-x64']);
    assert.deepEqual(pipeline.parameters.find(p => p.name === 'buildSteps').default.map(s => s.script), ['npm ci','python ./build/update_package_json.py', quality === 'stable' ? 'python ./build/update_ext_version.py --release --for-publishing' : 'python ./build/update_ext_version.py --for-publishing','npm run package']);
    if (quality === 'stable') {
    assert.equal(pipeline.extends.parameters.validationNotifyUsers, 'plseng@microsoft.com');
    assert.deepEqual(pipeline.trigger.branches.include, ['release/*']);
    } else {
    assert.equal(pipeline.trigger, 'none');
    assert.equal(pipeline.schedules[0].cron, '0 10 * * 1-5');
    }
    console.log(PASS ${quality}: pinned pull-only caller wiring, version flags, build steps, publication default and 10 targets);
    }
    const pr = read('.github/workflows/pr-check.yml');
    for (const [job, id] of [['e2e-tests','e2e-non-linux'], ['integration-tests','integration-non-linux']]) {
    const steps = pr.jobs[job].steps;
    const run = steps.find(s => s.id === id);
    assert.equal(run.if, "runner.os != 'Linux'");
    assert.equal(run.env.VSCODE_TEST_DIAGNOSTICS_DIR, '${{ runner.temp }}/vscode-test-diagnostics');
    const upload = steps.find(s => s.if === '${{ failure() && steps.' + id + ".outcome == 'failure' }}");
    assert.ok(upload);
    assert.equal(upload.with.path, run.env.VSCODE_TEST_DIAGNOSTICS_DIR);
    assert.equal(upload.with['retention-days'], 7);
    assert.equal(upload.with['if-no-files-found'], 'error');
    console.log(PASS ${job}: non-Linux diagnostic capture and failure-only upload wiring);
    }
    console.log('PASS English submission workflow pin and read-only caller token');
    console.log('LIMITATION: parsed local YAML only; external actions/templates and live services were not executed.');
    JS
  • ✅ Passed | VSCE generated localization file selection | node <<'JS'
    const fs = require('node:fs');
    const assert = require('node:assert/strict');
    const {execFileSync} = require('node:child_process');
    const manifest = 'package.nls.de.json';
    const runtime = 'l10n/bundle.l10n.de.json';
    assert.ok(!fs.existsSync(manifest) && !fs.existsSync(runtime), 'fixture paths must not overwrite existing translations');
    const hadDir = fs.existsSync('l10n');
    try {
    fs.mkdirSync('l10n', {recursive:true});
    fs.writeFileSync(manifest, JSON.stringify({description:'Deutsche Testübersetzung'}));
    fs.writeFileSync(runtime, JSON.stringify({'Test string':'Testzeichenfolge'}));
    const files = execFileSync(process.execPath, ['./node_modules/@vscode/vsce/vsce', 'ls', '--no-dependencies'], {encoding:'utf8'}).split(/\r?\n/);
    assert.ok(files.includes(manifest), 'generated manifest must be selected by VSCE');
    assert.ok(files.includes(runtime), 'generated runtime table must be selected by VSCE');
    assert.ok(files.includes('package.nls.json'), 'English manifest must remain selected');
    console.log('PASS VSCE selects package.nls.json, generated package.nls.de.json and l10n/bundle.l10n.de.json despite localization ignore patterns');
    console.log('LIMITATION: fixture file selection only; no translated drop import or VSIX publication performed.');
    } finally {
    fs.rmSync(manifest, {force:true});
    fs.rmSync(runtime, {force:true});
    if (!hadDir) fs.rmdirSync('l10n');
    }
    JS
⚠️ Shared localization submission, release import and readiness validation diagnostic output
Only caller YAML was checked locally. The referenced shared action and Azure templates were not executed or expanded, and no real 14-locale handback was imported. External resources and services are unavailable in the network-isolated verification container.
⚠️ Non-Linux E2E and integration failure diagnostics diagnostic output
Discovery reported Linux. Both changed diagnostic-enabled test steps require runner.os != 'Linux'; Windows/macOS collection and artifact upload were not exercised. Their YAML wiring passed a separate static check.
❌ Dependency and test discovery diagnostic output
AUTOMATION_SANDBOX_PROFILE=typescript
Linux
Node v22.21.1; npm 10.9.4
package.json declares mocha ^10.8.2 and typescript ^5.1.3.
node_modules false
node_modules/mocha/bin/mocha.js false
node_modules/typescript/bin/tsc false
out/test/features/envManagers.unit.test.js false
fatal: not a git repository (or any parent up to mount point /)
[container exit=128]
Dependency gap subsequently resolved with npm ci --offline; compilation and targeted tests then passed. Git metadata remained unavailable.

@rchiodo Rich Chiodo (rchiodo) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approved via Review Center.

@rchiodo Rich Chiodo (rchiodo) added the review-auto:approved Automated review: no blocking findings (approval posted). label Nov 4, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approved via Review Center.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@bschnurr

Copy link
Copy Markdown
Member Author

Investigated the failing Windows/Python 3.15 E2E job:

  • Can trigger environment refresh fails with RpcTimeoutError: Request 'refresh' timed out after 30000ms.
  • Discovers at least one environment then exceeds its 90000ms test timeout.
  • Uploaded Python Environments diagnostics show PET server refreshes repeatedly hitting their 30-second limit and restarting. The JSON CLI fallback eventually succeeds after approximately 48 seconds; logs show slow Conda discovery under C:\Miniconda, including missing package metadata and fallback probing.
  • The remaining 11 E2E matrix jobs passed, including Windows/Python 3.10, 3.12, and 3.14.
  • Both src/managers/common/nativePythonFinder.ts and src/test/e2e/environmentDiscovery.e2e.test.ts match current main. This failure is in runtime discovery, not localization extraction/import. A baseline run on the same runner image has not been performed, so this is not being labeled conclusively pre-existing or a harmless flake.

No tests were skipped, timeouts increased, or production discovery behavior changed. The underlying reason for slow Conda discovery still needs investigation; this is separate from the PR's current merge conflicts.

@bschnurr

Copy link
Copy Markdown
Member Author

The isolated Windows/Python 3.15 E2E rerun passed: https://github.com/microsoft/vscode-python-environments/actions/runs/41893763980/job/126925681445 . Run attempt 2 completed successfully with no code changes, skipped tests, or timeout increases. The original PET/Conda discovery timeout did not reproduce on this attempt; this supports an intermittent failure but does not establish that the underlying slowdown is fixed. Merge conflicts/approval remain separate requirements.

@bschnurr
Bill Schnurr (bschnurr) enabled auto-merge (squash) November 5, 2026 00:12
@rchiodo

Rich Chiodo (rchiodo) commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Reviewed commit: f8e829ae0568f9de7dd84d65424442ad108c419e

Result: ⚠️ partially-verified

Verification details

Verification: Automated verification is best effort. The PR author remains responsible for testing.

Summary: Container verification passed actual-YAML configuration guards, generated-locale VSCE file selection, TypeScript compilation, and the production build. Offline Node dependency preparation succeeded; the existing version tests could not collect because freezegun was unavailable. The PR adds no tests. External action execution, Azure template expansion, and the 14-locale importer/fallback contract remain unverified; no PR-caused failure was demonstrated. **Reviewer dependency follow-up (nonblocking):** Suggest a separate PR adding `@vscode/vsce ^3.9.2`, `mocha ^10.8.2`, `typescript ^5.1.3` to the official reviewer dependency declarations, using `package.json` as the dependency/version evidence. Do not automatically create that PR. This is reviewer environment maintenance, not a required change to the reviewed PR.

Test runs: 4 passed, 3 not run

  • ⚠️ Not run | Extension version tests | python -m pytest -q build/test_update_ext_version.py
  • ⚠️ Not run | Dependency and test discovery | printf 'PROFILE=%s\n' "$AUTOMATION_SANDBOX_PROFILE"; uname -s; git status --short; git log -3 --oneline; git diff --stat HEAD^ HEAD; node --version; npm --version; python --version; node -e "const p=require('./package.json');console.log(JSON.stringify({scripts:p.scripts,devDependencies:p.devDependencies},null,2)); for(const x of ['yaml','js-yaml','mocha','typescript','@vscode/vsce']){try{console.log(x,require.resolve(x))}catch(e){console.log(x,'NOT INSTALLED')}}"; python -c "import importlib.util; print({x: bool(importlib.util.find_spec(x)) for x in ['pytest','yaml']})"; git ls-files 'test' 'spec' 'localiz' 'lock' | head -100
  • ⚠️ Not run | External localization action and release importer
  • ✅ Passed | Offline Node dependency preparation | npm ci --offline --frozen-lockfile
  • ✅ Passed | Actual-YAML localization and release configuration guards | python - <<'PY'
    import json
    from pathlib import Path
    import yaml

pin = '6b4a3573e7e7a9fe1e468e129544432278aec2d6'
workflow = yaml.load(Path('.github/workflows/localization.yml').read_text(), Loader=yaml.BaseLoader)
assert workflow['on'] == {'workflow_dispatch': '', 'push': {'branches': ['main'], 'paths': ['package.json', 'package.nls.json', 'src/**/.ts', '.nvmrc', '.github/workflows/localization.yml']}}
assert workflow['permissions'] == {'contents': 'read'}
assert workflow['concurrency'] == {'group': 'localization-${{ github.ref }}', 'cancel-in-progress': 'false'}
job = workflow['jobs']['localization']
assert job['if'] == "github.repository == 'microsoft/vscode-python-environments'"
assert job['runs-on'] == 'ubuntu-latest' and job['timeout-minutes'] == '20'
assert job['steps'] == [{'uses': 'microsoft/vscode-common-python-lsp/.github/actions/localization@' + pin, 'with': {'app-id': '${{ vars.PYTHON_LOCALIZATION_APP_ID }}', 'private-key': '${{ secrets.PYTHON_LOCALIZATION_PRIVATE_KEY }}', 'node-version': '22.21.1'}}]
print('PASS: GitHub workflow triggers, concurrency, read-only token, repository guard, credentials wiring and shared-action pin')
expected_targets = ['web', 'linux-arm64', 'linux-armhf', 'linux-x64', 'alpine-arm64', 'alpine-x64', 'darwin-arm64', 'darwin-x64', 'win32-arm64', 'win32-x64']
for quality in ['stable', 'pre-release']:
path = Path(f'build/azure-devdiv-pipeline.{quality}.yml')
doc = yaml.safe_load(path.read_text())
resources = doc['resources']['repositories']
assert resources == [
{'repository': 'templates', 'type': 'github', 'name': 'microsoft/pylance-eng', 'ref': 'refs/heads/main', 'endpoint': 'Github-Pylance'},
{'repository': 'translations', 'type': 'github', 'name': 'microsoft/vscode-python-extensions-loc', 'ref': 'refs/heads/dev', 'endpoint': 'Github-Pylance'},
{'repository': 'localizationTools', 'type': 'github', 'name': 'microsoft/vscode-common-python-lsp', 'ref': pin, 'endpoint': 'Github-Pylance'},
]
params = {p['name']: p for p in doc['parameters']}
assert params['publishExtension']['default'] is True
assert [p['vsceTarget'] for p in params['buildPlatforms']['default']] == expected_targets
assert [p['name'] for p in params['buildPlatforms']['default']] == ['Linux'] * 6 + ['MacOS'] * 2 + ['Windows'] * 2
version_args = '--release --for-publishing' if quality == 'stable' else '--for-publishing'
assert [s['script'] for s in params['buildSteps']['default']] == ['npm ci', 'python ./build/update_package_json.py', f'python ./build/update_ext_version.py {version_args}', 'npm run package']
expected = {'buildPlatforms': '${{ parameters.buildPlatforms }}', 'buildSteps': '${{ parameters.buildSteps }}', 'standardizedVersioning': True, 'customNPMRegistry': '$(AZURE_ARTIFACTS_FEED)', 'nodeVersion': '$(NodeVersion)', 'publishExtension': '${{ parameters.publishExtension }}', 'teamName': '$(TeamName)', 'ghCreateTag': True, 'ghCreateRelease': True, 'ghReleaseAddChangeLog': True, 'sourceAnalysisPool': 'VSEng-MicroBuildVSStable', 'pullLocalization': True}
if quality == 'stable':
expected['validationNotifyUsers'] = 'plseng@microsoft.com'
assert doc['trigger'] == {'branches': {'include': ['release/
']}}
else:
assert doc['trigger'] == 'none'
assert doc['schedules'] == [{'cron': '0 10 * * 1-5', 'displayName': 'Nightly Pre-Release Schedule', 'always': False, 'branches': {'include': ['main']}}]
assert doc['pr'] == 'none'
assert doc['extends'] == {'template': f'azure-pipelines/extension/{quality}.yml@templates', 'parameters': expected}
variables = {v['name']: v['value'] for v in doc['variables']}
assert variables == {'TeamName': 'VSCode-python-environments', 'VsixName': 'python-environments.vsix', 'NodeVersion': '22.21.1', 'AZURE_ARTIFACTS_FEED': 'https://devdiv.pkgs.visualstudio.com/DevDiv/_packaging/Pylance_PublicPackages/npm/registry/&#x27;}
print(f'PASS: {quality} actual YAML: pull-only flag, resource pins, 10-platform matrix, feeds, version flags, build steps, publication defaults and validation wiring')
manifest = json.loads(Path('package.json').read_text())
assert manifest['publisher'] + '.' + manifest['name'] == 'ms-python.vscode-python-envs'
assert manifest['l10n'] == './l10n'
assert isinstance(json.loads(Path('package.nls.json').read_text()), dict)
ignore = Path('.gitignore').read_text().splitlines()
assert '/package.nls..json' in ignore and '/l10n/' in ignore
assert not list(Path('.').glob('package.nls.
.json')) and not Path('l10n').exists()
print('PASS: canonical extension identity, runtime localization path, tracked English source and absent generated locale snapshots')
print('LIMIT: these guards do not expand external Azure templates or execute the external localization action/importer')
PY

  • ✅ Passed | Generated localization VSCE selection | python - <<'PY'
    import json
    from pathlib import Path
    import subprocess

fixtures = {
Path('package.nls.de.json'): {'fixture': 'Deutsch'},
Path('package.nls.zh-cn.json'): {'fixture': 'Chinese'},
Path('l10n/bundle.l10n.de.json'): {'fixture': 'Deutsch'},
Path('l10n/bundle.l10n.zh-cn.json'): {'fixture': 'Chinese'},
}
assert not Path('l10n').exists()
assert all(not p.exists() for p in fixtures)
created = []
try:
for path, content in fixtures.items():
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(content), encoding='utf-8')
created.append(path)
result = subprocess.run(['node', 'node_modules/@vscode/vsce/vsce', 'ls', '--no-dependencies'], capture_output=True, text=True, timeout=60)
if result.returncode:
print(result.stdout)
print(result.stderr)
assert result.returncode == 0, f'vsce ls exit={result.returncode}'
files = set(result.stdout.splitlines())
for path in fixtures:
assert path.as_posix() in files, f'Generated translation omitted: {path}'
assert 'package.nls.json' in files
assert 'package.json' in files
print('PASS: actual VSCE file selection includes English manifest and all four generated manifest/runtime locale fixtures despite .gitignore')
for path in fixtures:
print('INCLUDED:', path)
finally:
for path in reversed(created):
path.unlink()
if Path('l10n').exists():
Path('l10n').rmdir()
print('CLEANUP: generated fixtures removed')
PY

  • ✅ Passed | TypeScript compilation and production build | npm run compile-tests && npm run package
⚠️ Extension version tests diagnostic output
[container exit=2]
ERROR collecting build/test_update_ext_version.py
build/test_update_ext_version.py:6: import freezegun
ModuleNotFoundError: No module named 'freezegun'
1 error in 0.13s
Interpreter: /usr/local/lib/python3.13 (Python 3.13.18). HEAD^ contains the same import. No dependency manifest declaring freezegun or its version constraint was found, so no package/version was invented for installation. The single dependency bootstrap had already restored the declared Node environment.
⚠️ Dependency and test discovery diagnostic output
[container exit=0]
PROFILE=typescript
Linux
Node v22.21.1; npm 10.9.4; Python 3.13.18
mocha NOT INSTALLED
typescript NOT INSTALLED
@vscode/vsce NOT INSTALLED
{'pytest': True, 'yaml': True}
package.json declares mocha ^10.8.2, typescript ^5.1.3 and @vscode/vsce ^3.9.2. Node checks were initially blocked; the following offline bootstrap succeeded. Git inspection was unavailable because the container source copy lacked Git metadata.
⚠️ External localization action and release importer diagnostic output
The offline container provided the caller repository, not the external shared action, importer, translation handbacks, or Azure templates. No authenticated submission, Azure expansion, release pipeline, or 14-locale acceptance/rejection matrix was executed. Static caller guards do not establish importer behavior or external service authorization.

Combine selection-manager tracking with main explicit-selection guard so clearing a global selection restores configured-manager routing.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pin submission and release imports to the same reviewed shared revision. Untranslated handbacks no longer block packaging; required locale tables and structural checks remain.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@bschnurr

Copy link
Copy Markdown
Member Author

Dependency: microsoft/vscode-common-python-lsp#127

Pin the localization action and both release import resources to 6b4a3573e7e7a9fe1e468e129544432278aec2d6. This allows untranslated strings, including wholly untranslated tables, to retain English rather than fail packaging. Missing/empty/malformed/incomplete locale tables remain errors. Update the documented policy; preserve dev translation branch, Pylance-Eng main, publication defaults, and all build/release settings.

Validation: actual-YAML caller guards, formatting, and Azure preview expansion passed. Shared tests/lint passed; real isort dev import produces all 28 locale files with English fallback. Environments' native pipelines remain disabled; exact YAML expansion was verified through an enabled definition. No release builds queued or publication performed. Merge the shared dependency before this consumer pin update.

Comment thread src/features/envManagers.ts Resolved
Comment thread README.md Resolved
@rchiodo

Copy link
Copy Markdown
Contributor

Warning · Non-blocking recommendation

Please add focused test coverage for global refresh preserves the selecting manager when its fallback belongs to another manager.

Add persistent coverage for the new routing branch: select a global environment, have that manager return another manager's descriptor during refresh, and assert subsequent routing/readback stays with the selecting manager; the temporary verification probe passed this scenario.

Switch both release resources to microsoft/pylance-eng through Github-Pylance while preserving release settings.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove duplicate global manager state and read the selected manager directly from the existing explicit-selection record.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Explain the global-only override, selecting-manager identity, and configured/cached fallback behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Restore the runtime routing implementation and its tests to main, removing the added global-refresh regression test. Keep localization and pipeline template changes intact.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Restore pr-check.yml to main. The non-Linux diagnostic upload instrumentation was left over from earlier test debugging and is not required for localization.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@bschnurr

Copy link
Copy Markdown
Member Author

Removed the leftover non-Linux failure-diagnostics instrumentation from earlier test debugging. .github/workflows/pr-check.yml now exactly matches main, as do the runtime routing and test files. The PR now contains only localization workflow/ignore/documentation changes and the two release pipelines. YAML formatting, exact parsed-YAML/text baseline checks, whitespace checks, and existing executable localization/release guards passed.

@bschnurr
Bill Schnurr (bschnurr) merged commit 6454420 into main Nov 10, 2026
113 of 114 checks passed
@bschnurr
Bill Schnurr (bschnurr) deleted the users/bschnurr/shared-localization branch November 10, 2026 05:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

debt Code quality issues review-auto:approved Automated review: no blocking findings (approval posted).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants