Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- [Inputs](#inputs)
- [Usage](#usage)
- [Developer Guide](#developer-guide)

- [Contribution Guidelines](#contribution-guidelines)
- [License Information](#license-information)
- [Contact or Support Information](#contact-or-support-information)
Expand Down Expand Up @@ -106,6 +107,9 @@ See the default action step definition:

See this [Developer Guide](DEVELOPER.md) for more technical, development-related information.

## Documentation

- [Version qualifier validation specification](docs/qualifier-spec.md) – defines the supported version tag format, allowed qualifiers, precedence rules, and validation behavior used by this action.
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

The link path 'docs/qualifier-spec.md' is incorrect. The actual file is located at '.github/docs/qualifier-spec.md' based on the diff. Update the path to match the actual location.

Suggested change
- [Version qualifier validation specification](docs/qualifier-spec.md) – defines the supported version tag format, allowed qualifiers, precedence rules, and validation behavior used by this action.
- [Version qualifier validation specification](.github/docs/qualifier-spec.md) – defines the supported version tag format, allowed qualifiers, precedence rules, and validation behavior used by this action.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@copilot: The files has been moved to correct path.

Comment on lines +110 to +112
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix broken link to qualifier specification.

The link path docs/qualifier-spec.md does not match the actual file location at .github/docs/qualifier-spec.md. This breaks discoverability and violates the PR's acceptance criteria that the spec be "discoverable from main documentation."

Apply this diff to correct the path:

 ## Documentation

- - [Version qualifier validation specification](docs/qualifier-spec.md) – defines the supported version tag format, allowed qualifiers, precedence rules, and validation behavior used by this action.
+ - [Version qualifier validation specification](.github/docs/qualifier-spec.md) – defines the supported version tag format, allowed qualifiers, precedence rules, and validation behavior used by this action.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## Documentation
- [Version qualifier validation specification](docs/qualifier-spec.md) – defines the supported version tag format, allowed qualifiers, precedence rules, and validation behavior used by this action.
## Documentation
- [Version qualifier validation specification](.github/docs/qualifier-spec.md) – defines the supported version tag format, allowed qualifiers, precedence rules, and validation behavior used by this action.
🤖 Prompt for AI Agents
In README.md around lines 110 to 112, the link to the version qualifier spec
points to docs/qualifier-spec.md but the actual file lives at
.github/docs/qualifier-spec.md; update the Markdown link target to
.github/docs/qualifier-spec.md so the documentation is discoverable from the
main README.


## Contribution Guidelines

Expand Down
335 changes: 335 additions & 0 deletions docs/qualifier-spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,335 @@
# Version Qualifier Validation Specification

## 1. Objective

This document defines how version tags with **qualifiers** are to be interpreted, validated, and compared by the `version-tag-check` GitHub Action.

The goals are:

- To support version tags that extend semantic versioning with qualifiers.
- To restrict qualifiers to a small, well-defined set with clear patterns.
- To define precedence (ordering) rules between versions with and without qualifiers.
- To clarify how sequences of tags are validated for monotonic increase.

This specification is **business/functional** and does not prescribe implementation details.

Related issues:

- [#5 – Add support for qualifiers and their validation](https://github.com/AbsaOSS/version-tag-check/issues/5)
- [#38 – Spike: Integrate new version qualifier validation spec into repo documentation and workflow](https://github.com/AbsaOSS/version-tag-check/issues/38)

---

## 2. Supported Version Format

### 2.1 Base version

The base version follows the standard semantic pattern:

- `Major.Minor.Patch`

Where each of `Major`, `Minor`, and `Patch` is a non-negative integer.

Examples:

- `1.0.0`
- `2.3.5`
- `10.0.12`

### 2.2 Optional qualifier

Versions may include a single, optional **qualifier** appended with a hyphen:

- `Major.Minor.Patch[-qualifier]`

Rules:

- The hyphen `-` introduces the qualifier.
- At most **one** qualifier is allowed.
- No additional segments after the qualifier are allowed.

Examples of **valid shapes** (ignoring whether the qualifier itself is allowed):

- `1.0.0-ALPHA`
- `1.0.0-RC1`
- `1.0.1-HF2`

Examples of **invalid shapes**:

- `1.0.0-ALPHA-RC1`
- `1.0.0-ALPHA.1`
- `1.0.0-` (no qualifier after hyphen)

---

## 3. Allowed Qualifiers and Patterns

Only the following qualifiers are allowed. Qualifiers are case-sensitive and must appear in **uppercase** exactly as described here.

### 3.1 SNAPSHOT

- Literal: `SNAPSHOT`
- Pattern: exactly `SNAPSHOT`

Examples:

- Valid: `1.0.0-SNAPSHOT`
- Invalid: `1.0.0-snapshot`, `1.0.0-SNAPSHOT1`

### 3.2 ALPHA

- Literal: `ALPHA`
- Pattern: exactly `ALPHA`

Examples:

- Valid: `1.0.0-ALPHA`
- Invalid: `1.0.0-alpha`, `1.0.0-ALPHA1`

### 3.3 BETA

- Literal: `BETA`
- Pattern: exactly `BETA`

Examples:

- Valid: `1.0.0-BETA`
- Invalid: `1.0.0-beta`, `1.0.0-BETA2`

### 3.4 Release Candidate (RC)

- Prefix: `RC`
- Numeric suffix: 1–2 digits (`1`–`99`)
- Overall pattern: `RC[0-9]{1,2}`

Examples:

- Valid: `1.0.0-RC1`, `1.0.0-RC2`, `1.0.0-RC10`
- Invalid: `1.0.0-RC`, `1.0.0-RC001`, `1.0.0-Rc1`, `1.0.0-rc1`

### 3.5 RELEASE

- Literal: `RELEASE`
- Pattern: exactly `RELEASE`

Examples:

- Valid: `1.0.0-RELEASE`
- Invalid: `1.0.0-release`, `1.0.0-RELEASE1`

> Note: `1.0.0-RELEASE` is distinct from `1.0.0` (no qualifier). Both are “final-like” states but have different precedence.

### 3.6 HOTFIX (HF)

- Prefix: `HF`
- Numeric suffix: 1–2 digits (`1`–`99`)
- Overall pattern: `HF[0-9]{1,2}`

Examples:

- Valid: `1.0.1-HF1`, `1.0.1-HF2`, `1.0.1-HF10`
- Invalid: `1.0.1-HF`, `1.0.1-HF001`, `1.0.1-hf1`

Comment on lines +99 to +132
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Clarify leading-zero handling in RC and HF numeric patterns.

Lines 103 and 126 use the regex pattern [0-9]{1,2} to describe RC and HF suffixes, but the spec states the allowed range as "1–2 digits (199)" (lines 102, 125). The regex notation technically matches strings like RC00, RC01, HF00, etc., which fall outside the intended 1–99 range.

For clarity during implementation, explicitly state whether leading zeros (e.g., RC01, HF02) are accepted or rejected. Consider updating the pattern notation or adding a clarifying sentence.

For example: "Numeric suffix: 1–2 digits, in the range 1–99, without leading zeros (e.g., RC1, RC99, but not RC01 or RC001)."

🤖 Prompt for AI Agents
In docs/qualifier-spec.md around lines 99 to 132, the RC and HF numeric regex
"[0-9]{1,2}" currently allows values like "00" or "01" which contradicts the
intended range 1–99; update the spec to explicitly forbid leading zeros and show
the intended valid examples and pattern (e.g., state "Numeric suffix: 1–2 digits
in the range 1–99, without leading zeros — valid: RC1, RC99; invalid: RC01,
RC00, RC001") and either replace the regex with one that enforces no leading
zeros (or add a clarifying sentence) so implementers know to reject values with
leading zeros.

---

## 4. Version Precedence Rules

### 4.1 Numeric precedence

Versions are compared first by their numeric components:

1. `Major`
2. `Minor`
3. `Patch`

Qualifiers are only considered if the numeric components are equal.

Examples:

- `2.0.0-SNAPSHOT` > `1.9.9-RELEASE`
- `1.1.0-ALPHA` > `1.0.5-HF2`

### 4.2 Qualifier precedence for the same numeric version

For the same `Major.Minor.Patch`, qualifier precedence is:

1. `SNAPSHOT` (lowest)
2. `ALPHA`
3. `BETA`
4. `RCx` (ordered by `x`)
5. `RELEASE`
6. No qualifier (highest for that numeric base)

Formally, for version `v = Major.Minor.Patch`:

- `v-SNAPSHOT` < `v-ALPHA` < `v-BETA`
- `v-BETA` < `v-RC1` < `v-RC2` < … < `v-RC99`
- Any `v-RC*` < `v-RELEASE`
- `v-RELEASE` < `v`

Example ordering:

- `1.0.0-SNAPSHOT`
- `1.0.0-ALPHA`
- `1.0.0-BETA`
- `1.0.0-RC1`
- `1.0.0-RC2`
- `1.0.0-RELEASE`
- `1.0.0`

### 4.3 Hotfix precedence (HF)

For the same `Major.Minor.Patch`, hotfix qualifiers are ordered by their numeric suffix:

- `v-HF1` < `v-HF2` < `v-HF10`

For comparisons with the bare version:

- A hotfix is considered a more advanced state than the same numeric version without `HF`:

- `1.0.1` < `1.0.1-HF1` < `1.0.1-HF2`

---
Comment on lines +135 to +192
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Clarify HF (hotfix) precedence in the overall qualifier hierarchy.

Section 4.2 defines the main precedence order (lines 154–161) as: SNAPSHOT < ALPHA < BETA < RCx < RELEASE < no qualifier. However, section 4.3 states that hotfixes are "more advanced" than the base version (1.0.1 < 1.0.1-HF1), which would place HF above the base version.

This creates an ambiguity: where exactly does HF fit in the precedence hierarchy? Is it RELEASE < HF < no qualifier, or does HF have different semantics that bypasses the main precedence order? The spec must explicitly place HF relative to RELEASE and the unqualified base version to avoid confusion during implementation.

Proposed fix: Update section 4.2 to include HF in the overall precedence order, or clarify in section 4.3 whether HF qualifiers follow the same precedence rules as other qualifiers or whether they have special semantics. For example:

### 4.2 Qualifier precedence for the same numeric version

For the same `Major.Minor.Patch`, qualifier precedence is:

1. `SNAPSHOT` (lowest)
2. `ALPHA`
3. `BETA`
4. `RCx` (ordered by `x`)
5. `RELEASE`
6. `HFx` (ordered by `x`)
7. No qualifier (highest for that numeric base)

Or, if HF qualifiers are meant to represent patches/fixes after the base release and should not follow the standard precedence, clarify that special case explicitly.

🤖 Prompt for AI Agents
In docs/qualifier-spec.md around lines 135 to 192, the spec is ambiguous about
where HF (hotfix) qualifiers belong relative to RELEASE and the unqualified base
version; clarify by explicitly inserting HF into the qualifier precedence or by
stating HF is a special case. Update section 4.2 to show HFx ordered by numeric
suffix (e.g., ... RELEASE, HFx, No qualifier) or add a short sentence in 4.3
saying HF qualifiers are ranked after RELEASE but before the bare version (and
ordered by HF number), ensuring examples and formal statements reflect that
placement.


## 5. Validation Rules

### 5.1 Validating a single tag

A tag is **valid** if:

1. It matches the `Major.Minor.Patch` or `Major.Minor.Patch-QUALIFIER` structure, and
2. If a qualifier is present, it matches one of the allowed patterns defined in this spec.

### 5.2 Invalid qualifiers

A tag is **invalid** if:

- The qualifier is not in the allowed set (`SNAPSHOT`, `ALPHA`, `BETA`, `RC[0-9]{1,2}`, `RELEASE`, `HF[0-9]{1,2}`).
- The qualifier uses incorrect casing (e.g. `alpha`, `Rc1`).
- The qualifier pattern is malformed (e.g. `RC`, `RC001`, `HF001`).
- Multiple qualifiers or additional segments are present (e.g. `1.0.0-RC1-SNAPSHOT`).

Invalid tags should be rejected with clear error messages indicating:

- Which tag is invalid.
- Whether the problem is in the structure or the qualifier.

---

## 6. Sequence Validation (Monotonicity)

The action may validate **sequences** of tags (for example, tags over time).

A sequence is considered **monotonically increasing** if, for each consecutive pair:

- `current` is greater than (or, depending on configuration, equal to) `previous`,
- using the numeric + qualifier precedence rules defined in this document.

### 6.1 Examples of valid sequences

Examples assuming strictly increasing order:

- Pre-release progression:

- `1.0.0-SNAPSHOT`
- `1.0.0-ALPHA`
- `1.0.0-BETA`
- `1.0.0-RC1`
- `1.0.0-RC2`
- `1.0.0-RELEASE`
- `1.0.0`

- Across minor versions:

- `1.0.0-ALPHA`
- `1.0.0-BETA`
- `1.0.0`
- `1.1.0-SNAPSHOT`
- `1.1.0-RC1`
- `1.1.0-RELEASE`
- `1.1.0`

- With hotfixes:

- `1.0.0-RELEASE`
- `1.0.0`
- `1.0.1`
- `1.0.1-HF1`
- `1.0.1-HF2`

### 6.2 Examples of invalid sequences

- Backwards in qualifier precedence:

- `1.0.0-RC2`
- `1.0.0-RC1` (invalid: RC1 < RC2)

- Backwards in numeric version:

- `1.1.0-SNAPSHOT`
- `1.0.1-RELEASE` (invalid: 1.0.1 < 1.1.0)

- Invalid qualifier in the middle:

- `1.0.0-ALPHA`
- `1.0.0-BETA1` (invalid: `BETA1` qualifier not allowed)

- Regressing from final to pre-release for same numeric version:

- `1.0.0`
- `1.0.0-RELEASE` (invalid: `1.0.0-RELEASE` < `1.0.0`)

---

## 7. Non-Goals / Exclusions

The following are explicitly **out of scope**:

- Combined qualifiers (e.g. `1.0.0-RC1-SNAPSHOT`, `1.0.0-BETA-HF1`).
- Arbitrary/custom qualifiers beyond the allowed set.
- Pre-release or build metadata segments (e.g. `1.0.0-RC1+build.123`, `1.0.0-ALPHA.1`).
- Multi-part numeric qualifiers (e.g. `RC1.1`, `HF1.2`).
- Changing semantics for versions **without** qualifiers (`Major.Minor.Patch`).

---

## 8. Future Configuration Considerations

Potential future options (not required for initial implementation):

1. **Configurable allowed qualifiers**

- Enable or disable specific qualifiers (e.g. disallow `SNAPSHOT` on main branch).

2. **Case-sensitivity settings**

- Make qualifier matching case-insensitive and normalize to uppercase.

3. **Strict vs lenient sequence rules**

- Strict: sequences must strictly increase.
- Lenient: allow equal versions (e.g. re-tagging).

4. **Hotfix semantics**

- Ability to configure how hotfix tags relate to non-hotfix versions.

5. **Custom precedence**

- Override default order `SNAPSHOT < ALPHA < BETA < RC < RELEASE < no qualifier`.

---

## 9. Acceptance Criteria (Spec)

The specification is considered adopted when:

- It is present in the repository (e.g. `docs/qualifier-spec.md`).
- It is discoverable from main documentation (e.g. linked from `README.md`).
- It clearly documents:
- Allowed formats and qualifiers.
- Precedence rules.
- Validation and sequence rules.
- Non-goals and future configuration considerations.

Implementation and testing of these rules in code can be tracked in separate issues.