Skip to content

Phase 1: restore the build and run tasks on 2026 agents#17

Merged
jochen-testingbot merged 3 commits into
masterfrom
phase1-restore-build
Jul 17, 2026
Merged

Phase 1: restore the build and run tasks on 2026 agents#17
jochen-testingbot merged 3 commits into
masterfrom
phase1-restore-build

Conversation

@jochen-testingbot

@jochen-testingbot jochen-testingbot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Why

From a clean checkout the repo cannot build a .vsix: Dependabot bumped gulp to ^4 and webpack-stream to ^7 (webpack 5) without migrating the gulp 3 / webpack 1 / babel 6 code, so gulp, npm run package, and every CI path fail. On top of that, both pipeline tasks declare the removed Node 6 "Node" execution handler (removed from new agents Nov 2026) and run against a vendored 2016-era vsts-task-lib committed into the repo.

This is Phase 1 of the roadmap in MODERNIZATION.md: make it build again and get the tasks onto a supported runtime. Credential hygiene, the tunnel-launcher swap, TypeScript, and the web-tab/SDK rewrite are Phases 2–4 and intentionally out of scope here.

What changed

Build system (1.1–1.2, 1.6)

  • Delete Gulpfile.js + .travis.yml; replace with npm scripts + webpack 5 (webpack.config.js) — AMD bundle of the results-tab scripts + copy-webpack-plugin for static files.
  • scripts/install-task-deps.js installs each task's production node_modules into dist/; scripts/stamp-version.js stamps package.json's version into the built manifest + task.jsons (resolves the 0.2.7 / 0.1.0 / 0.2.0 drift — package.json is now the single source of truth).
  • tfx-cli ^0.12^0.23.4; drop the babel-6 / gulp / webpack-stream toolchain.

Tasks (1.3–1.4)

  • Both task.json handlers NodeNode20_1, minimumAgentVersion3.232.1.
  • Add tb-main/package.json (azure-pipelines-task-lib@^5.277.0); delete the 210 committed vendored node_modules files; require('azure-pipelines-task-lib/task').

Correctness fixes (1.5)

  • tb-stop-tunnel: guard TB_TUNNEL_PID before use + validate the pid — an unstarted tunnel no longer crashes with a TypeError.
  • tb-main: null-check endpoint auth; fix the copy-pasted "SonarQube" error message; tl.getBoolInput for tbTunnel; fix the tunnel_bin variable shadowing (jar path vs ChildProcess); RELEASE_* fallback for TB_BUILD_NAME.
  • task.json: connectedServiceName required: true; remove the $(message) ghost input from instanceNameFormat.

Verification

  • npm run packagePackages/testingbot.testingbot-tasks-0.2.7.vsix (VSIX contains AMD-bundled info.js/dialog.js, azure-pipelines-task-lib under dist/tb-main/node_modules, and versions stamped to 0.2.7 across the manifest + both tasks).
  • Both tasks exercised under Node 22: tb-main no-tunnel happy path (writes the attachment, exits 0), tb-stop-tunnel no-pid and garbage-pid guards (graceful exit 0), and the RELEASE_* fallback (TB_BUILD_NAME=My_Release_99).

Not in scope (later phases)

Plaintext-credential attachment + browser-side secret use, the bundled 2019 tunnel jar, the unpkg.com CDN script, the vss-web-extension-sdkazure-devops-extension-sdk port, CI/publishing automation, lint/tests. See MODERNIZATION.md.

Summary by CodeRabbit

  • New Features
    • Updated tasks to run on modern Node.js 20-based Azure DevOps agents.
    • Improved packaging automation with npm run package, including consistent version stamping.
  • Bug Fixes
    • Hardened authentication and agent version checks.
    • Safer tunnel startup/shutdown, with improved PID and option handling.
  • Documentation
    • Refreshed build/setup instructions for the new packaging workflow.
    • Added a modernization roadmap and project guidance for future work.

The repo could not produce a .vsix from a clean checkout: Dependabot had
bumped gulp to ^4 and webpack-stream to ^7 without migrating the gulp 3 /
webpack 1 / babel 6 code, so `gulp` and every CI path failed. Both tasks also
declared the removed Node 6 execution handler. This restores a working,
versioned build and gets the tasks onto Node20_1.

Build system (1.1-1.2, 1.6)
- Replace the Gulpfile with npm scripts + webpack 5 (webpack.config.js):
  AMD bundle of the results-tab scripts + copy-webpack-plugin for static files.
- Add scripts/install-task-deps.js (installs each task's prod node_modules into
  dist) and scripts/stamp-version.js (package.json version -> dist manifest +
  task.json, resolving the 0.2.7/0.1.0/0.2.0 drift).
- Upgrade tfx-cli ^0.12 -> ^0.23.4; drop the dead gulp/babel-6/webpack-stream
  toolchain and .travis.yml (it only ran `gulp`).

Tasks (1.3-1.4)
- Switch both task.json execution handlers Node -> Node20_1; bump
  minimumAgentVersion to 3.232.1.
- Add tb-main/package.json (azure-pipelines-task-lib ^5.277.0); delete the 210
  committed vendored node_modules files; require azure-pipelines-task-lib/task.

Correctness fixes (1.5)
- tb-stop-tunnel: guard TB_TUNNEL_PID before use and validate the pid, so an
  unstarted tunnel no longer crashes with a TypeError.
- tb-main: null-check endpoint auth and fix the copy-pasted "SonarQube" error
  message; use tl.getBoolInput for tbTunnel; fix the tunnel_bin variable
  shadowing (jar path vs ChildProcess); fall back to RELEASE_* vars for
  TB_BUILD_NAME so release runs get a real name.
- task.json: connectedServiceName required:true; drop the $(message) ghost input
  from instanceNameFormat.

Docs
- Add MODERNIZATION.md (full roadmap; this is Phase 1). Update README build
  steps and CLAUDE.md to the new build. Ignore nested node_modules and .serena.

Verified: `npm run package` produces testingbot.testingbot-tasks-0.2.7.vsix;
both tasks run under Node 22 (no-tunnel path, stop-tunnel guards, RELEASE_*
fallback all exercised).
@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The pull request replaces the legacy Gulp packaging setup with npm scripts and webpack, adds task dependency installation and version stamping, migrates tasks to Node20_1 and the Azure Pipelines task library, improves tunnel handling, and adds repository guidance and modernization documentation.

Changes

Build and task modernization

Layer / File(s) Summary
Repository guidance and modernization plan
CLAUDE.md, MODERNIZATION.md
Documents the extension architecture, build workflow, known modernization issues, phased roadmap, comparisons, and recommendations.
Task runtime and Node20 execution
tb-main/*, tb-stop-tunnel/*, tb-build-info/scripts/info.js
Updates task metadata and runtime dependencies for Node20_1, improves build-name and authentication handling, normalizes tunnel input and process references, and validates tunnel PIDs.
Webpack web bundle
webpack.config.js, tb-build-info/scripts/info.js
Adds AMD web entry points, VSS externals, Babel transpilation, Buffer support, and static asset copying into dist.
Npm packaging and artifact versioning
package.json, scripts/*, README.md, .gitignore
Replaces the legacy packaging workflow with npm/webpack commands, installs task production dependencies, stamps versions into manifests, updates build instructions, and ignores generated artifacts.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Developer
  participant npm as npm run package
  participant webpack as webpack
  participant tasks as install-task-deps.js
  participant manifests as stamp-version.js
  participant tfx as tfx extension create
  Developer->>npm: start packaging
  npm->>webpack: build web assets into dist
  webpack->>tasks: provide tb-* task directories
  tasks->>manifests: install production dependencies
  manifests->>tfx: stamp extension and task versions
  tfx-->>Developer: create packaged VSIX
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main goal: restoring build/run task compatibility on newer agents.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CLAUDE.md`:
- Around line 73-78: Update the task-code documentation paragraph to state that
azure-pipelines-task-lib/task is used only by tb-main/testingbot.js, while
tb-stop-tunnel/sample.js reads TB_TUNNEL_PID directly and remains
dependency-free. Keep the existing tb-main runtime-dependency and
build-installation details, and explicitly preserve the stop-tunnel task’s
dependency-free requirement.

In `@MODERNIZATION.md`:
- Around line 7-15: Update MODERNIZATION.md to mark the completed Phase 1
findings as resolved or historical, including clean-checkout packaging, Node 6
handler migration, dependency/version drift, and the Gulp/npm/webpack migration.
Remove these items from the pending action list while preserving only genuinely
outstanding work as future actions.

In `@README.md`:
- Around line 12-23: Update the README build instructions to use consistent 1.,
2., and 3. ordered-list markers, add blank lines before and after each fenced
code block, and specify bash as the fence language for the npm commands to
satisfy MD029, MD031, and MD040.

In `@scripts/stamp-version.js`:
- Around line 27-30: Update the task-manifest loop in the version-stamping logic
to fail immediately when either required manifest under tb-main or
tb-stop-tunnel is missing, instead of continuing. Preserve stamping from
package.json for every existing task.json and report the missing manifest as a
build error.
- Around line 9-10: Update the version parsing in scripts/stamp-version.js
around the version constant and major/minor/patch destructuring to require an
exact major.minor.patch format, reject prerelease or malformed values, and
convert each component to a number before stamping task.json. Ensure the
resulting Major, Minor, and Patch fields are numeric and fail clearly when the
package version is invalid.

In `@tb-main/package.json`:
- Around line 1-11: Add an engines.node constraint to the tb-main package
manifest requiring Node.js 20 or later, while preserving the existing package
metadata and dependencies.

In `@tb-main/task.json`:
- Line 19: Update the stale minimum-agent version message in testingbot.js to
require version 3.232.1, matching the minimumAgentVersion value in task
metadata, or derive the message directly from that metadata.

In `@tb-stop-tunnel/sample.js`:
- Around line 10-15: Validate the PID parsed in the sample’s shutdown flow
before any process.kill call: accept only a complete, decimal, strictly positive
PID matching the expected pid_ value format, rejecting pid_0, negative values,
suffixes, and other malformed input. Preserve the existing log and clean exit
for invalid PIDs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e64f41bc-cec1-4b27-bb60-d6bbb9306e14

📥 Commits

Reviewing files that changed from the base of the PR and between 81b9872 and 6ca324d.

⛔ Files ignored due to path filters (212)
  • package-lock.json is excluded by !**/package-lock.json
  • tb-main/node_modules/.bin/semver is excluded by !**/node_modules/**
  • tb-main/node_modules/.bin/shjs is excluded by !**/node_modules/**
  • tb-main/node_modules/.bin/uuid is excluded by !**/node_modules/**
  • tb-main/node_modules/balanced-match/.npmignore is excluded by !**/node_modules/**
  • tb-main/node_modules/balanced-match/LICENSE.md is excluded by !**/node_modules/**
  • tb-main/node_modules/balanced-match/README.md is excluded by !**/node_modules/**
  • tb-main/node_modules/balanced-match/index.js is excluded by !**/node_modules/**
  • tb-main/node_modules/balanced-match/package.json is excluded by !**/node_modules/**
  • tb-main/node_modules/brace-expansion/README.md is excluded by !**/node_modules/**
  • tb-main/node_modules/brace-expansion/index.js is excluded by !**/node_modules/**
  • tb-main/node_modules/brace-expansion/package.json is excluded by !**/node_modules/**
  • tb-main/node_modules/concat-map/.travis.yml is excluded by !**/node_modules/**
  • tb-main/node_modules/concat-map/LICENSE is excluded by !**/node_modules/**
  • tb-main/node_modules/concat-map/README.markdown is excluded by !**/node_modules/**
  • tb-main/node_modules/concat-map/example/map.js is excluded by !**/node_modules/**
  • tb-main/node_modules/concat-map/index.js is excluded by !**/node_modules/**
  • tb-main/node_modules/concat-map/package.json is excluded by !**/node_modules/**
  • tb-main/node_modules/concat-map/test/map.js is excluded by !**/node_modules/**
  • tb-main/node_modules/glob/LICENSE is excluded by !**/node_modules/**
  • tb-main/node_modules/glob/README.md is excluded by !**/node_modules/**
  • tb-main/node_modules/glob/common.js is excluded by !**/node_modules/**
  • tb-main/node_modules/glob/glob.js is excluded by !**/node_modules/**
  • tb-main/node_modules/glob/package.json is excluded by !**/node_modules/**
  • tb-main/node_modules/glob/sync.js is excluded by !**/node_modules/**
  • tb-main/node_modules/inflight/LICENSE is excluded by !**/node_modules/**
  • tb-main/node_modules/inflight/README.md is excluded by !**/node_modules/**
  • tb-main/node_modules/inflight/inflight.js is excluded by !**/node_modules/**
  • tb-main/node_modules/inflight/package.json is excluded by !**/node_modules/**
  • tb-main/node_modules/inherits/LICENSE is excluded by !**/node_modules/**
  • tb-main/node_modules/inherits/README.md is excluded by !**/node_modules/**
  • tb-main/node_modules/inherits/inherits.js is excluded by !**/node_modules/**
  • tb-main/node_modules/inherits/inherits_browser.js is excluded by !**/node_modules/**
  • tb-main/node_modules/inherits/package.json is excluded by !**/node_modules/**
  • tb-main/node_modules/minimatch/LICENSE is excluded by !**/node_modules/**
  • tb-main/node_modules/minimatch/README.md is excluded by !**/node_modules/**
  • tb-main/node_modules/minimatch/minimatch.js is excluded by !**/node_modules/**
  • tb-main/node_modules/minimatch/package.json is excluded by !**/node_modules/**
  • tb-main/node_modules/mockery/.npmignore is excluded by !**/node_modules/**
  • tb-main/node_modules/mockery/.travis.yml is excluded by !**/node_modules/**
  • tb-main/node_modules/mockery/LICENSE is excluded by !**/node_modules/**
  • tb-main/node_modules/mockery/README.md is excluded by !**/node_modules/**
  • tb-main/node_modules/mockery/examples/example1.js is excluded by !**/node_modules/**
  • tb-main/node_modules/mockery/mockery.js is excluded by !**/node_modules/**
  • tb-main/node_modules/mockery/package.json is excluded by !**/node_modules/**
  • tb-main/node_modules/mockery/test/1-general.js is excluded by !**/node_modules/**
  • tb-main/node_modules/mockery/test/allowable-unhook.js is excluded by !**/node_modules/**
  • tb-main/node_modules/mockery/test/fixtures/fake_module.js is excluded by !**/node_modules/**
  • tb-main/node_modules/mockery/test/fixtures/fake_module_2.js is excluded by !**/node_modules/**
  • tb-main/node_modules/mockery/test/fixtures/intermediary.js is excluded by !**/node_modules/**
  • tb-main/node_modules/mockery/test/fixtures/substitute_fake_module.js is excluded by !**/node_modules/**
  • tb-main/node_modules/mockery/test/intermediary.js is excluded by !**/node_modules/**
  • tb-main/node_modules/mockery/test/logging-allow-array.js is excluded by !**/node_modules/**
  • tb-main/node_modules/mockery/test/logging-allowable.js is excluded by !**/node_modules/**
  • tb-main/node_modules/mockery/test/logging.js is excluded by !**/node_modules/**
  • tb-main/node_modules/mockery/test/registered.js is excluded by !**/node_modules/**
  • tb-main/node_modules/mockery/test/self-register.js is excluded by !**/node_modules/**
  • tb-main/node_modules/mockery/test/substitute.js is excluded by !**/node_modules/**
  • tb-main/node_modules/mockery/test/warn-replace.js is excluded by !**/node_modules/**
  • tb-main/node_modules/node-uuid/.npmignore is excluded by !**/node_modules/**
  • tb-main/node_modules/node-uuid/LICENSE.md is excluded by !**/node_modules/**
  • tb-main/node_modules/node-uuid/README.md is excluded by !**/node_modules/**
  • tb-main/node_modules/node-uuid/benchmark/README.md is excluded by !**/node_modules/**
  • tb-main/node_modules/node-uuid/benchmark/bench.gnu is excluded by !**/node_modules/**
  • tb-main/node_modules/node-uuid/benchmark/bench.sh is excluded by !**/node_modules/**
  • tb-main/node_modules/node-uuid/benchmark/benchmark-native.c is excluded by !**/node_modules/**
  • tb-main/node_modules/node-uuid/benchmark/benchmark.js is excluded by !**/node_modules/**
  • tb-main/node_modules/node-uuid/bin/uuid is excluded by !**/node_modules/**
  • tb-main/node_modules/node-uuid/bower.json is excluded by !**/node_modules/**
  • tb-main/node_modules/node-uuid/component.json is excluded by !**/node_modules/**
  • tb-main/node_modules/node-uuid/package.json is excluded by !**/node_modules/**
  • tb-main/node_modules/node-uuid/test/compare_v1.js is excluded by !**/node_modules/**
  • tb-main/node_modules/node-uuid/test/test.html is excluded by !**/node_modules/**
  • tb-main/node_modules/node-uuid/test/test.js is excluded by !**/node_modules/**
  • tb-main/node_modules/node-uuid/uuid.js is excluded by !**/node_modules/**
  • tb-main/node_modules/once/LICENSE is excluded by !**/node_modules/**
  • tb-main/node_modules/once/README.md is excluded by !**/node_modules/**
  • tb-main/node_modules/once/once.js is excluded by !**/node_modules/**
  • tb-main/node_modules/once/package.json is excluded by !**/node_modules/**
  • tb-main/node_modules/path-is-absolute/index.js is excluded by !**/node_modules/**
  • tb-main/node_modules/path-is-absolute/license is excluded by !**/node_modules/**
  • tb-main/node_modules/path-is-absolute/package.json is excluded by !**/node_modules/**
  • tb-main/node_modules/path-is-absolute/readme.md is excluded by !**/node_modules/**
  • tb-main/node_modules/q/CHANGES.md is excluded by !**/node_modules/**
  • tb-main/node_modules/q/LICENSE is excluded by !**/node_modules/**
  • tb-main/node_modules/q/README.md is excluded by !**/node_modules/**
  • tb-main/node_modules/q/package.json is excluded by !**/node_modules/**
  • tb-main/node_modules/q/q.js is excluded by !**/node_modules/**
  • tb-main/node_modules/q/queue.js is excluded by !**/node_modules/**
  • tb-main/node_modules/semver/LICENSE is excluded by !**/node_modules/**
  • tb-main/node_modules/semver/README.md is excluded by !**/node_modules/**
  • tb-main/node_modules/semver/bin/semver is excluded by !**/node_modules/**
  • tb-main/node_modules/semver/package.json is excluded by !**/node_modules/**
  • tb-main/node_modules/semver/range.bnf is excluded by !**/node_modules/**
  • tb-main/node_modules/semver/semver.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/.documentup.json is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/.jshintrc is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/.npmignore is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/.travis.yml is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/LICENSE is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/README.md is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/bin/shjs is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/global.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/make.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/package.json is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/scripts/generate-docs.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/scripts/run-tests.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/shell.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/src/cat.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/src/cd.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/src/chmod.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/src/common.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/src/cp.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/src/dirs.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/src/echo.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/src/error.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/src/exec.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/src/find.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/src/grep.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/src/ln.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/src/ls.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/src/mkdir.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/src/mv.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/src/popd.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/src/pushd.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/src/pwd.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/src/rm.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/src/sed.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/src/tempdir.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/src/test.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/src/to.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/src/toEnd.js is excluded by !**/node_modules/**
  • tb-main/node_modules/shelljs/src/which.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/BuildApi.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/ClientApiBases.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/CoreApi.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/FileContainerApi.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/GalleryApi.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/GitApi.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/HttpClient.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/README.md is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/ReleaseManagementApi.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/RestClient.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/Serialization.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/TaskAgentApi.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/TaskAgentApiBase.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/TaskApi.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/TestApi.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/TfvcApi.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/VsoClient.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/WebApi.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/WorkItemTrackingApi.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/handlers/apiversion.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/handlers/basiccreds.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/handlers/bearertoken.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/interfaces/BuildInterfaces.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/interfaces/CoreInterfaces.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/interfaces/FileContainerInterfaces.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/interfaces/GalleryInterfaces.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/interfaces/GitInterfaces.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/interfaces/ReleaseManagementInterfaces.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/interfaces/TaskAgentInterfaces.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/interfaces/TestInterfaces.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/interfaces/TfvcInterfaces.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/interfaces/WorkItemTrackingInterfaces.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/interfaces/common/FormInputInterfaces.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/interfaces/common/OperationsInterfaces.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/interfaces/common/SystemDataInterfaces.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/interfaces/common/TfsInterfaces.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/interfaces/common/VSSInterfaces.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/interfaces/common/VsoBaseInterfaces.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vso-node-api/package.json is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/LICENSE is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/README.md is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/Strings/resources.resjson/de-de/resources.resjson is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/Strings/resources.resjson/en-US/resources.resjson is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/Strings/resources.resjson/es-es/resources.resjson is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/Strings/resources.resjson/fr-fr/resources.resjson is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/Strings/resources.resjson/it-IT/resources.resjson is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/Strings/resources.resjson/ja-jp/resources.resjson is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/Strings/resources.resjson/ko-KR/resources.resjson is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/Strings/resources.resjson/ru-RU/resources.resjson is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/Strings/resources.resjson/zh-CN/resources.resjson is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/Strings/resources.resjson/zh-TW/resources.resjson is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/extensions.d.ts is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/extensions.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/lib.json is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/mock-answer.d.ts is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/mock-answer.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/mock-run.d.ts is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/mock-run.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/mock-task.d.ts is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/mock-task.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/mock-test.d.ts is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/mock-test.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/mock-toolrunner.d.ts is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/mock-toolrunner.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/package.json is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/task.d.ts is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/task.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/taskcommand.d.ts is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/taskcommand.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/toolrunner.d.ts is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/toolrunner.js is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/typings.json is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/vault.d.ts is excluded by !**/node_modules/**
  • tb-main/node_modules/vsts-task-lib/vault.js is excluded by !**/node_modules/**
  • tb-main/node_modules/wrappy/LICENSE is excluded by !**/node_modules/**
  • tb-main/node_modules/wrappy/README.md is excluded by !**/node_modules/**
  • tb-main/node_modules/wrappy/package.json is excluded by !**/node_modules/**
  • tb-main/node_modules/wrappy/wrappy.js is excluded by !**/node_modules/**
  • tb-main/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (16)
  • .gitignore
  • .travis.yml
  • CLAUDE.md
  • Gulpfile.js
  • MODERNIZATION.md
  • README.md
  • package.json
  • scripts/install-task-deps.js
  • scripts/stamp-version.js
  • tb-build-info/scripts/info.js
  • tb-main/package.json
  • tb-main/task.json
  • tb-main/testingbot.js
  • tb-stop-tunnel/sample.js
  • tb-stop-tunnel/task.json
  • webpack.config.js
💤 Files with no reviewable changes (3)
  • .travis.yml
  • tb-build-info/scripts/info.js
  • Gulpfile.js

Comment thread CLAUDE.md Outdated
Comment thread MODERNIZATION.md Outdated
Comment thread README.md Outdated
Comment thread scripts/stamp-version.js Outdated
Comment thread scripts/stamp-version.js
Comment thread tb-main/package.json
Comment thread tb-main/task.json
Comment thread tb-stop-tunnel/sample.js Outdated
- stamp-version.js: validate package.json version is exact numeric
  major.minor.patch (reject prerelease/malformed) and stamp numeric task
  versions; fail the build if a task manifest is missing instead of skipping it.
- tb-stop-tunnel/sample.js: accept only "pid_<positive-int>" before
  process.kill (rejects pid_0, negatives that would signal a whole process
  group, and trailing garbage); handle ESRCH so an already-gone tunnel is a
  graceful no-op.
- tb-main/testingbot.js: update the stale "min version 0.3.0" endpoint error to
  match minimumAgentVersion 3.232.1.
- tb-main/package.json: declare engines.node >=20.
- README.md: fix markdown lint (ordered-list markers, fenced-block spacing,
  bash language) MD029/MD031/MD040.
- CLAUDE.md: document that only tb-main uses azure-pipelines-task-lib; the
  stop task reads TB_TUNNEL_PID directly and stays dependency-free.
- MODERNIZATION.md: add a phase status banner and annotate the top-5 actions so
  the roadmap reflects what Phase 1/2 already shipped.

Verified: npm run package produces the vsix; stop-tunnel guards exercised for
empty/pid_0/pid_-1/garbage/dead-pid; version regex rejects bad values.
git add -A on the phase1 branch picked up index.js/*.map and the tests output
left in the working tree after switching from the phase2 branch (phase1's
.gitignore did not cover them). Phase 1 ships testingbot.js/sample.js, not the
compiled TypeScript. Untrack them and add ignore rules to prevent recurrence.
jochen-testingbot added a commit that referenced this pull request Jul 17, 2026
Brings in the CodeRabbit fixes from PR #17 (stamp-version validation,
README/CLAUDE/MODERNIZATION docs, engines.node) and applies the review points
that also affect the Phase 2 TypeScript code:

- tb-stop-tunnel is now genuinely dependency-free (honors the "stop task must
  not pull azure-pipelines-task-lib" guideline consistently): index.ts reads
  TB_TUNNEL_PID from process.env, validates the exact "pid_<positive-int>" shape
  (rejects pid_0 / negatives that would signal a process group / trailing
  garbage), handles ESRCH, and emits the raw ##vso[task.complete] command
  itself. Its package.json declares no dependencies, so nothing is installed
  into dist/tb-stop-tunnel (VSIX no longer ships task-lib twice).
- install-task-deps.js / ensure-task-src-deps.js skip tasks with no deps.
- Tests rewritten to spawn the compiled task directly (no task-lib): no-pid,
  malformed pids, ESRCH, and a real process-kill case.
- engines.node >=20 on both task package.json files.

Verified: npm test -> 8 passing; npm run package -> vsix with compiled index.js
for both tasks, tunnel-launcher under tb-main only, tb-stop-tunnel with no
node_modules, and no source .ts shipped.

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tb-main/testingbot.js (1)

92-104: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Handle tunnel spawn failures and early close as fatal. spawn() can emit error when Java is missing, and the current close handler exits with the child’s code even if the tunnel never reached You may start your tests, so an early 0 can look like success. Add an error listener and only allow a clean exit after readiness.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tb-main/testingbot.js` around lines 92 - 104, Update the tunnel_process
lifecycle around spawn to listen for its error event and terminate with failure
when Java or the tunnel cannot be started. Track whether the tunnel has reached
the existing “You may start your tests” readiness signal, and make the close
handler exit successfully only after readiness; otherwise treat early closure as
fatal regardless of the child exit code.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@MODERNIZATION.md`:
- Around line 5-15: Update the Phase 2 status in MODERNIZATION.md to PENDING,
since testingbot.js remains JavaScript and still launches 2.30.jar. Revise the
Phase 2 summary and related roadmap references to show the TypeScript,
testingbot-tunnel-launcher, and test migrations are unfinished, while preserving
the stated scope boundaries for the PR.

In `@scripts/stamp-version.js`:
- Around line 11-17: Update the version validation in the stamp-version flow
around the match and destructuring logic to require canonical numeric components
without leading zeros, and reject any component that is not a safe integer.
Validate the string segments before converting them with Number(), preserving
acceptance of ordinary major.minor.patch versions and rejection of oversized or
non-canonical values.

---

Outside diff comments:
In `@tb-main/testingbot.js`:
- Around line 92-104: Update the tunnel_process lifecycle around spawn to listen
for its error event and terminate with failure when Java or the tunnel cannot be
started. Track whether the tunnel has reached the existing “You may start your
tests” readiness signal, and make the close handler exit successfully only after
readiness; otherwise treat early closure as fatal regardless of the child exit
code.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6882ca6b-fbef-470c-9b93-d2e22bece7be

📥 Commits

Reviewing files that changed from the base of the PR and between 6ca324d and db9d6a5.

📒 Files selected for processing (8)
  • .gitignore
  • CLAUDE.md
  • MODERNIZATION.md
  • README.md
  • scripts/stamp-version.js
  • tb-main/package.json
  • tb-main/testingbot.js
  • tb-stop-tunnel/sample.js

Comment thread MODERNIZATION.md
Comment on lines +5 to +15
> **Status (living document).** The findings below describe the pre-modernization
> state as originally analyzed; sections are being resolved phase by phase.
> - **Phase 1 — DONE (PR #17):** clean-checkout packaging restored (npm scripts +
> webpack 5, gulp/Travis removed), both tasks on the `Node20_1` handler,
> `azure-pipelines-task-lib` 5 with committed `node_modules` deleted, version
> drift resolved via `scripts/stamp-version.js`, immediate correctness bugs fixed.
> - **Phase 2 — DONE (PR #18):** tasks rewritten in TypeScript, runtime tunnel via
> `testingbot-tunnel-launcher` (jar deleted), secret pipeline variables, tests.
> - **Phase 3 — PENDING:** results-tab / SDK rewrite, including moving the `/mini`
> URL signing server-side so the secret leaves the browser (finding #1).
> - **Phase 4 — PENDING:** CI/CD, lint, publishing.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Keep Phase 2 marked pending.

The document claims TypeScript tasks, testingbot-tunnel-launcher, and tests are complete, but tb-main/testingbot.js is still JavaScript and still spawns 2.30.jar at Lines 84-98. The PR objectives also explicitly leave these migrations out of scope. Align the status and roadmap so unfinished work is not treated as shipped.

Also applies to: 25-29, 73-86

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@MODERNIZATION.md` around lines 5 - 15, Update the Phase 2 status in
MODERNIZATION.md to PENDING, since testingbot.js remains JavaScript and still
launches 2.30.jar. Revise the Phase 2 summary and related roadmap references to
show the TypeScript, testingbot-tunnel-launcher, and test migrations are
unfinished, while preserving the stated scope boundaries for the PR.

Comment thread scripts/stamp-version.js
Comment on lines +11 to +17
// Require an exact numeric major.minor.patch — task.json versions must be
// integers and a malformed/prerelease value would silently produce a broken vsix.
const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(version);
if (!match) {
throw new Error(`package.json version "${version}" is not a plain major.minor.patch version.`);
}
const [, major, minor, patch] = match.map(Number);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== files ==\n'
git ls-files | rg '^(scripts/stamp-version\.js|package\.json|README\.md|docs/|\.github/)' || true

printf '\n== script outline ==\n'
ast-grep outline scripts/stamp-version.js --view expanded || true

printf '\n== script lines ==\n'
wc -l scripts/stamp-version.js
cat -n scripts/stamp-version.js | sed -n '1,220p'

printf '\n== version guidance search ==\n'
rg -n "version.*source of truth|single source of truth|stamp-version|task\.json|major\.minor\.patch|safe integer|canonical" . -g '!**/node_modules/**' -g '!**/dist/**' -g '!**/build/**' || true

Repository: testingbot/vso-testingbot-plugin

Length of output: 7673


🏁 Script executed:

#!/bin/bash
set -euo pipefail
cat -n scripts/stamp-version.js | sed -n '1,120p'

Repository: testingbot/vso-testingbot-plugin

Length of output: 2301


🌐 Web query:

semver numeric identifier leading zeros invalid major.minor.patch safe integer javascript Number precision package.json version

💡 Result:

According to the official Semantic Versioning (SemVer) 2.0.0 specification, numeric identifiers for major, minor, patch, and pre-release versions must not include leading zeros [1][2]. An exception is the single digit "0", which is permitted [1][3]. For example, "1.0.0" is valid, whereas "1.0.01" is invalid [4][5]. In practice, the npm ecosystem enforces this strictly. When managing package versions in package.json, including leading zeros in these identifiers will cause errors, such as failures during npm version commands or invalidation of the version string [5][6]. While some coercion utilities (like those in the semver npm package) can automatically strip leading zeros to make a version string valid [7][8], these should not be relied upon for maintaining your package.json. Regarding JavaScript precision, the semver package for Node.js handles numeric components by attempting to parse them into JavaScript Numbers [9]. Because JavaScript uses IEEE-754 double-precision floats, it can only represent integers exactly up to Number.MAX_SAFE_INTEGER (2^53 - 1) [10][11]. To avoid precision loss when dealing with extremely large numeric identifiers (those exceeding this limit), the semver package has evolved to handle these values as strings or via BigInt comparisons, ensuring that version comparison logic remains accurate even when identifiers exceed safe integer limits [9]. However, as a best practice, version identifiers should remain within reasonable numerical bounds to ensure broad compatibility and adherence to the SemVer spec [1][12].

Citations:


Reject non-canonical or oversized version components. ^(\d+)\.(\d+)\.(\d+)$ still accepts invalid SemVer like 01.2.3, and Number() can round values above Number.MAX_SAFE_INTEGER before they’re written into task.json. Enforce canonical numeric segments and safe integers here.

🧰 Tools
🪛 OpenGrep (1.25.0)

[ERROR] 13-13: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.

(coderabbit.command-injection.exec-js)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/stamp-version.js` around lines 11 - 17, Update the version validation
in the stamp-version flow around the match and destructuring logic to require
canonical numeric components without leading zeros, and reject any component
that is not a safe integer. Validate the string segments before converting them
with Number(), preserving acceptance of ordinary major.minor.patch versions and
rejection of oversized or non-canonical values.

Source: Coding guidelines

@jochen-testingbot
jochen-testingbot merged commit cde4c6e into master Jul 17, 2026
1 check passed
@jochen-testingbot
jochen-testingbot deleted the phase1-restore-build branch July 17, 2026 19:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant