Skip to content

feat(availability): use WidgetAvailability for version-based widget validation#140

Merged
polaz merged 23 commits intomainfrom
feat/#137-featavailability-use-widgetavailability-for-versio
Jan 23, 2026
Merged

feat(availability): use WidgetAvailability for version-based widget validation#140
polaz merged 23 commits intomainfrom
feat/#137-featavailability-use-widgetavailability-for-versio

Conversation

@polaz
Copy link
Copy Markdown
Member

@polaz polaz commented Jan 23, 2026

Summary

  • Adds runtime validation of widget parameters in manage_work_item handler against the detected GitLab instance version and tier before making API calls
  • Introduces VERSION_RESTRICTED structured error type with required/detected version info and upgrade hints
  • Adds PARAMETER_WIDGET_MAP in WidgetAvailability as the source of truth for parameter-to-widget mapping
  • Integrates validateWidgetParams() check in both create and update actions

How it works

User requests manage_work_item with widget parameter (e.g. assigneeIds)
  → Map parameter to widget type (assigneeIds → ASSIGNEES)
  → Check WidgetAvailability.validateWidgetParams()
    → Check minVersion against detected instance version
    → Check tier against detected instance tier
  → If unavailable: throw StructuredToolError with VERSION_RESTRICTED error
  → If available: proceed with API call

Error Response Example

{
  "error_code": "VERSION_RESTRICTED",
  "widget": "CUSTOM_FIELDS",
  "parameter": "customFields",
  "required_version": "17.0",
  "detected_version": "16.5.0",
  "required_tier": "Ultimate",
  "current_tier": "Premium",
  "message": "Widget 'CUSTOM_FIELDS' (parameter 'customFields') requires GitLab >= 17.0 and GitLab Ultimate tier (detected: 16.5.0)",
  "suggested_fix": "Upgrade GitLab to version 17.0 or higher to use the 'customFields' parameter",
  "docs_url": "https://docs.gitlab.com/ee/user/project/work_items/"
}

Test plan

  • All 3494 unit tests pass
  • Lint clean
  • Build successful
  • New tests for validateWidgetParams() (version check, tier check, undefined params, unknown params, connection failure)
  • New tests for createVersionRestrictedError helper
  • New tests for getParameterWidgetMap

Closes #137

…alidation

Add runtime validation of widget parameters in manage_work_item handler
against the detected GitLab instance version and tier before making API calls.

- Add VERSION_RESTRICTED structured error type to error-handler
- Add parameter-to-widget mapping (PARAMETER_WIDGET_MAP) in WidgetAvailability
- Add validateWidgetParams() method that checks version/tier compatibility
- Integrate validation in manage_work_item create/update actions
- Return structured error with required version, detected version, and upgrade hint

Closes #137
Copilot AI review requested due to automatic review settings January 23, 2026 13:49
@github-actions
Copy link
Copy Markdown

github-actions bot commented Jan 23, 2026

📊 Test Coverage Report

Overall Coverage: 91.56%

Coverage Details

Metric Percentage
Statements 91.56%
Branches 83.52%
Functions 81.17%
Lines 91.98%

Coverage Report: View detailed coverage report

This report was generated automatically from your PR changes.

@codecov
Copy link
Copy Markdown

codecov bot commented Jan 23, 2026

Codecov Report

❌ Patch coverage is 96.33028% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/services/WidgetAvailability.ts 88.57% 2 Missing and 2 partials ⚠️

📢 Thoughts on this report? Let us know!

- Expand PARAMETER_WIDGET_MAP with premium/ultimate tier entries (weight,
  iterationId, linkedItemIds, healthStatus, startDate, dueDate, color)
- Add tier-restricted validation tests for validateWidgetParams
- Add VERSION_RESTRICTED error throw tests in registry create/update handlers
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds runtime validation for manage_work_item widget parameters using WidgetAvailability, returning a structured VERSION_RESTRICTED error when the target GitLab instance version/tier doesn’t support the requested widget inputs.

Changes:

  • Introduce VersionRestrictedError / createVersionRestrictedError() to return structured, actionable version/tier restriction errors.
  • Add PARAMETER_WIDGET_MAP, validateWidgetParams(), and helper accessors in WidgetAvailability to validate params against detected instance capabilities.
  • Integrate the runtime validation into manage_work_item create/update flows before GraphQL calls, plus new unit tests for the helpers.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tests/unit/utils/error-handler.test.ts Adds unit tests for createVersionRestrictedError() fields/message behavior.
tests/unit/services/WidgetAvailability.test.ts Adds unit tests for validateWidgetParams(), getParameterWidgetMap(), and formatVersion().
src/utils/error-handler.ts Adds VERSION_RESTRICTED structured error type and helper factory.
src/services/WidgetAvailability.ts Adds param→widget mapping + runtime param validation logic.
src/entities/workitems/registry.ts Calls validateWidgetParams() in manage_work_item create/update and throws structured errors early.

polaz added 2 commits January 23, 2026 16:03
Empty assigneeIds/labelIds arrays should not trigger widget version
validation on create, since the handler does not send widget input
for empty arrays. Update path keeps validation for empty arrays
because they semantically clear the widget.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

polaz added 4 commits January 23, 2026 16:14
Fix version comparison to use integer encoding (major*100+minor) instead
of float math that breaks for minor versions >= 10 (e.g., 16.11 was
incorrectly parsed as 17.1). Make VERSION_RESTRICTED error messages
contextual: show tier info only when tier is insufficient, and tailor
suggested_fix to the specific constraint violated. Remove duplicate
normalizeTierForDisplay from registry in favor of exported normalizeTier
from error-handler.
Replace string comparison of version strings with numeric parsing
(major*100+minor) to prevent incorrect results for single-digit major
versions (e.g., "9.0" > "15.0" in string comparison). Add tests for
contextual suggested_fix messaging.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Jan 23, 2026

Test Coverage Report

Overall Coverage: 93.2%

Metric Percentage
Statements 92.72%
Branches 84.33%
Functions 82.57%
Lines 93.2%

View detailed coverage report

polaz added 3 commits January 23, 2026 17:31
… flows (#132)

* feat(cli): add unified setup wizard consolidating init/install/docker flows (#129)

Create `gitlab-mcp setup` command that unifies the three separate wizards
(init, install, docker init) into a single entry point with discovery,
mode selection, tool configuration, and multiple execution flows.

- Add src/cli/setup/ module with types, presets, discovery, wizard, and flows
- Add local-setup, server-setup, configure-existing, and tool-selection flows
- Define 18 tool categories and 6 preset definitions (developer, senior-dev,
  devops, code-reviewer, full-access, readonly)
- Add missing preset YAML files: code-reviewer.yaml, full-access.yaml
- Route `init` as alias to `setup --mode=local`
- Route `docker init` as alias to `setup --mode=server`
- Update cli-utils.ts with setup command and --mode flag parsing
- Add 43 unit tests for presets, discovery, and wizard modules

* refactor(setup): align env vars with config and add category application

- Rename USE_ISSUES/USE_WIKI/etc to USE_WORKITEMS/USE_GITLAB_WIKI/etc
- Rename GITLAB_SCOPE_* to GITLAB_PROJECT_ID/GITLAB_ALLOWED_PROJECT_IDS
- Rename GITLAB_MCP_PRESET to GITLAB_PROFILE
- Rename GITLAB_URL to GITLAB_API_URL in local-setup
- Apply toolConfig env to Docker config in server-setup
- Add applyManualCategories() for manual mode category disabling
- Add failure reporting in configure-existing updateClients
- Replace process.exit(0) with null return in wizard cancel path
- Remove unused skipGitlab option from wizard
- Use manage_repository:fork in code-reviewer profile
- Add unit tests for setup flow modules

* refactor(setup): remove commits mapping, rename scope option, persist env to Docker

- Remove "commits" from CATEGORY_ENV_MAP (browse_commits is always-on core)
- Rename "namespace" scope option to "allowlist" with clearer prompt
- Add environment field to DockerConfig type
- Persist tool config env vars into docker-compose via generateDockerCompose
- Make SetupResult.mode optional for cancel-before-selection path
- Add generateDockerCompose environment tests

* fix(discovery): add docker-compose v1 fallback for compose detection

detectDocker now checks both `docker compose version` (v2) and
`docker-compose --version` (v1) for consistency with docker-utils.

* feat(docker): add native Podman support with container runtime detection

Add container-runtime module that detects Docker or Podman automatically.
When Docker is unavailable, falls back to podman/podman-compose for all
container operations. Centralizes runtime detection with process-level
caching, eliminating duplicated logic in discovery.ts.

* fix(setup): use runtime-aware messages and propagate deployment type

- Pass DEPLOYMENT_TYPE to Docker environment config
- Replace hardcoded "Docker" error messages with runtime label
- Add error field to configure-existing container operation failure

* fix(docker): propagate OAuth secrets to compose and throw on missing compose

- Use config.oauthSessionSecret and config.databaseUrl in compose env
- Throw controlled error in tailLogs when no compose tool detected

* fix(setup): implement deployment types, secure secrets, filter ungated categories

- Exit non-zero from main when setup wizard fails
- Add compose-bundle deployment with bundled postgres service
- Store OAuth secret in .env file (0600) instead of plaintext in compose
- Filter always-on categories from manual tool selection UI
- Add deploymentType field to DockerConfig interface

* fix(docker): require OAuth for postgres, use random password, fix exit code

- docker init now exits non-zero on wizard failure (like init/setup)
- compose-bundle only adds postgres service when oauthEnabled is true
- POSTGRES_PASSWORD uses randomBytes(24) instead of weak fixed default
- Add unit tests for setup subcommand parsing in cli-utils
- Add tests for docker init exit codes in main.entry

* fix(presets): correct tool names for webhooks/integrations, add return guard

- Rename list_webhooks → browse_webhooks in webhooks category
- Rename list_integrations → browse_integrations in integrations category
- Add return after process.exit in docker init to prevent fall-through
…pport

Change WidgetRequirement.minVersion from float to string to correctly
represent GitLab minor versions >= 10 (e.g., "16.11") without lossy
float-to-int conversion. Remove now-unnecessary minVersionToComparable
and formatVersion helpers — parseVersion handles both instance and
requirement versions uniformly. Clarify update validation semantics
and use toHaveBeenLastCalledWith in tests to prevent false positives.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Centralize version parsing (major*100+minor) into src/utils/version.ts
and use it in WidgetAvailability, GitLabVersionDetector, and
error-handler. This fixes GitLabVersionDetector incorrectly handling
minor versions >= 10 (e.g., 8.14 was compared as 9.4). Make
VERSION_RESTRICTED error message contextual — only mention the
violated constraint (version, tier, or both). Update PARAMETER_WIDGET_MAP
docstring to clarify planned #135 entries.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

…hy constant

- Remove redundant `GitLabTier | "free"` union (GitLabTier already includes "free")
- Hoist tierHierarchy to module-level TIER_HIERARCHY constant (avoid recreation per iteration)
- Fix tierHierarchy type in error-handler from Record<string, number> to Record<GitLabTier, number>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

polaz added 3 commits January 23, 2026 20:10
…licate tier hierarchy

- Return null from validateWidgetParams when version is undetectable (parsedVersion === 0)
  instead of incorrectly blocking all parameters
- Use shared TIER_HIERARCHY constant in isWidgetAvailable (was recreated per call)
- Clear mockValidateWidgetParams in beforeEach to prevent test state leakage
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

…on utility

- Replace private float-based parseVersion (major + minor/100) with shared
  integer-based utility (major * 100 + minor) from src/utils/version.ts
- Change minVersion type from number to string in ToolRequirement and
  ActionRequirement interfaces for consistency with WidgetAvailability
- Remove duplicate parseVersion method from ToolAvailability class
- Update all test assertions for string-based minVersion values
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated no new comments.

@polaz polaz merged commit 66e0215 into main Jan 23, 2026
19 checks passed
@polaz polaz deleted the feat/#137-featavailability-use-widgetavailability-for-versio branch January 23, 2026 19:36
sw-release-bot bot pushed a commit that referenced this pull request Jan 23, 2026
## [6.32.0](v6.31.2...v6.32.0) (2026-01-23)

### Features

* **availability:** use WidgetAvailability for version-based widget validation ([#140](#140)) ([66e0215](66e0215)), closes [#137](#137) [#132](#132) [#129](#129) [#135](#135)
@sw-release-bot
Copy link
Copy Markdown

🎉 This PR is included in version 6.32.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(availability): use WidgetAvailability for version-based widget validation

2 participants