Add SemVer constraint resolution #32

Open
opened 2026-01-03 23:40:26 +00:00 by KofTwentyTwo · 0 comments
KofTwentyTwo commented 2026-01-03 23:40:26 +00:00 (Migrated from github.com)

Part of #11

User Story

As a developer, I want version constraints to be resolved correctly so that compatible package versions are installed.

Design

Supported Constraint Syntax

Syntax Example Matches
Exact 2.0.0 Only 2.0.0
Caret ^2.0.0 >=2.0.0 <3.0.0 (compatible)
Tilde ~2.0.0 >=2.0.0 <2.1.0 (patch only)
Range >=2.0.0 <3.0.0 Explicit range
Latest (none) Highest available

SemVer Model

public record SemVer(int major, int minor, int patch, String prerelease) 
    implements Comparable<SemVer> {
    
    public static SemVer parse(String version);
    public boolean satisfies(VersionConstraint constraint);
}

public record VersionConstraint(ConstraintType type, SemVer base) {
    public boolean matches(SemVer version);
    public SemVer findBestMatch(List<SemVer> available);
}

Files to Create

File Description
qctl-qbit/src/main/java/io/qrun/qctl/qbit/semver/SemVer.java Version model with parsing and comparison
qctl-qbit/src/main/java/io/qrun/qctl/qbit/semver/VersionConstraint.java Constraint parsing and matching
qctl-qbit/src/main/java/io/qrun/qctl/qbit/semver/ConstraintType.java Enum for constraint types

Resolution Algorithm

  1. Parse constraint string into VersionConstraint
  2. Fetch available versions from registry
  3. Filter versions that satisfy constraint
  4. Sort by version (descending)
  5. Return highest matching version

Edge Cases

Scenario Behavior
No matching version Throw with clear message listing available versions
Prerelease versions Only match if explicitly requested (e.g., 2.0.0-beta.1)
Invalid constraint Throw with syntax help

Implementation Tasks

  • Create SemVer record with parsing logic
  • Implement Comparable<SemVer> for sorting
  • Handle prerelease versions (alpha, beta, rc)
  • Create ConstraintType enum (EXACT, CARET, TILDE, RANGE, LATEST)
  • Create VersionConstraint with parsing logic
  • Implement matches(SemVer) for each constraint type
  • Implement findBestMatch(List<SemVer>)
  • Add comprehensive unit tests for parsing
  • Add unit tests for constraint matching
  • Add unit tests for edge cases (prereleases, invalid input)

Acceptance Criteria

  • ^2.0.0 matches 2.0.0, 2.1.0, 2.9.9 but not 3.0.0
  • ~2.0.0 matches 2.0.0, 2.0.5 but not 2.1.0
  • 2.0.0 matches only 2.0.0
  • Prerelease versions only match explicit constraints
  • Clear error messages for invalid constraints
  • Versions sort correctly (2.10.0 > 2.9.0)
Part of #11 ## User Story As a developer, I want version constraints to be resolved correctly so that compatible package versions are installed. ## Design ### Supported Constraint Syntax | Syntax | Example | Matches | |--------|---------|---------| | Exact | `2.0.0` | Only 2.0.0 | | Caret | `^2.0.0` | >=2.0.0 <3.0.0 (compatible) | | Tilde | `~2.0.0` | >=2.0.0 <2.1.0 (patch only) | | Range | `>=2.0.0 <3.0.0` | Explicit range | | Latest | (none) | Highest available | ### SemVer Model ```java public record SemVer(int major, int minor, int patch, String prerelease) implements Comparable<SemVer> { public static SemVer parse(String version); public boolean satisfies(VersionConstraint constraint); } public record VersionConstraint(ConstraintType type, SemVer base) { public boolean matches(SemVer version); public SemVer findBestMatch(List<SemVer> available); } ``` ### Files to Create | File | Description | |------|-------------| | `qctl-qbit/src/main/java/io/qrun/qctl/qbit/semver/SemVer.java` | Version model with parsing and comparison | | `qctl-qbit/src/main/java/io/qrun/qctl/qbit/semver/VersionConstraint.java` | Constraint parsing and matching | | `qctl-qbit/src/main/java/io/qrun/qctl/qbit/semver/ConstraintType.java` | Enum for constraint types | ### Resolution Algorithm 1. Parse constraint string into `VersionConstraint` 2. Fetch available versions from registry 3. Filter versions that satisfy constraint 4. Sort by version (descending) 5. Return highest matching version ### Edge Cases | Scenario | Behavior | |----------|----------| | No matching version | Throw with clear message listing available versions | | Prerelease versions | Only match if explicitly requested (e.g., `2.0.0-beta.1`) | | Invalid constraint | Throw with syntax help | ## Implementation Tasks - [ ] Create `SemVer` record with parsing logic - [ ] Implement `Comparable<SemVer>` for sorting - [ ] Handle prerelease versions (alpha, beta, rc) - [ ] Create `ConstraintType` enum (EXACT, CARET, TILDE, RANGE, LATEST) - [ ] Create `VersionConstraint` with parsing logic - [ ] Implement `matches(SemVer)` for each constraint type - [ ] Implement `findBestMatch(List<SemVer>)` - [ ] Add comprehensive unit tests for parsing - [ ] Add unit tests for constraint matching - [ ] Add unit tests for edge cases (prereleases, invalid input) ## Acceptance Criteria - [ ] `^2.0.0` matches 2.0.0, 2.1.0, 2.9.9 but not 3.0.0 - [ ] `~2.0.0` matches 2.0.0, 2.0.5 but not 2.1.0 - [ ] `2.0.0` matches only 2.0.0 - [ ] Prerelease versions only match explicit constraints - [ ] Clear error messages for invalid constraints - [ ] Versions sort correctly (2.10.0 > 2.9.0)
Sign in to join this conversation.