diff --git a/docs/diagrams/version-calculation.mmd b/docs/diagrams/version-calculation.mmd index 0197259feb..d0175a6e6c 100644 --- a/docs/diagrams/version-calculation.mmd +++ b/docs/diagrams/version-calculation.mmd @@ -6,7 +6,8 @@ sequenceDiagram Next->>Base: GetBaseVersion Note right of Base: Determine the base version - Base-->>Next: 2.0.0 at 25e4ba + Base-->>Next: Semantic baseline 2.0.0 and its provenance + Next->>Next: Select counting anchor independently alt Base version allows increment Config->>Next: Branch increment strategy (patch) @@ -23,7 +24,7 @@ sequenceDiagram Note right of Next: 2.0.1-alpha.1 end - Next->>Metadata: Context - Metadata-->>Next: Commit count and branch/SHA metadata + Next->>Metadata: Semantic provenance and counting anchor + Metadata-->>Next: Count from anchor, both sources, and current branch/SHA metadata Next->>Next: Apply commit count and metadata Note right of Next: 2.0.1-alpha.1+10 diff --git a/docs/input/docs/migration/v6-to-v7.md b/docs/input/docs/migration/v6-to-v7.md index 7c6f22da12..215cd1457b 100644 --- a/docs/input/docs/migration/v6-to-v7.md +++ b/docs/input/docs/migration/v6-to-v7.md @@ -44,6 +44,16 @@ macOS. Use `VersionSourceDistance` instead; it has the same value. +## Separate semantic and counting sources + +Five additive output variables distinguish semantic provenance from counting: `SemVerSourceSemVer`, `SemVerSourceSha`, `SemVerSourceIncrement`, `CommitCountSourceSha`, and `CommitCountSourceDistance`. They are available in JSON, custom formats, generated version-information files, build-server output, and MSBuild. + +Existing `VersionSource*` fields keep their values. `VersionSourceSha` identifies the counting anchor, which may not be the artifact supplying `VersionSourceSemVer`. The legacy `VersionSourceIncrement` can be `None` after candidate resolution even when an increment was applied; new integrations should use `SemVerSourceIncrement`. + +For the removed v6 `CommitsSinceVersionSource`, `VersionSourceDistance` remains a compatible replacement; `CommitCountSourceDistance` is the explicit name for the same count. Do not replace that count with a distance from `SemVerSourceSha`: configuration and branch-name sources have no intrinsic SHA. New nullable source fields use JSON null; textual outputs use an empty string. + +Update strict JSON property-set consumers for the five added fields. Public source interfaces and existing constructors remain available. This change does not alter candidate ordering, version numbers, or commit counts. See [version variables](/docs/reference/variables) for a concrete example. + ## CLI Arguments - POSIX-style syntax GitVersion now uses POSIX-style command-line arguments powered by System.CommandLine. diff --git a/docs/input/docs/reference/custom-formatting.md b/docs/input/docs/reference/custom-formatting.md index a26c7e1be4..6c46971a73 100644 --- a/docs/input/docs/reference/custom-formatting.md +++ b/docs/input/docs/reference/custom-formatting.md @@ -51,6 +51,18 @@ output: custom-version-format: '{env:ANDROID_VERSION_CODE}' ``` +## Source variables + +Use `CommitCountSourceDistance` when formatting the count, and `SemVerSourceSemVer` or `SemVerSourceIncrement` when describing the selected semantic baseline: + +```yaml +output: + assembly-informational-format: '{SemVerSourceSemVer}-{SemVerSourceIncrement}+{CommitCountSourceDistance:000}' + # Example: 5.0.0-None+002 for an external 5.0.0 baseline and two counted commits. +``` + +`SemVerSourceSha` can be absent for configuration or branch-name sources; it is not a substitute for `Sha` (HEAD) or `CommitCountSourceSha` (the counting anchor). Existing `VersionSource*` format names remain available for compatibility. + ## Overview The custom formatter functionality introduces several new formatters that can be used in GitVersion configuration files and templates: diff --git a/docs/input/docs/reference/variables.md b/docs/input/docs/reference/variables.md index 910c640a99..575a707644 100644 --- a/docs/input/docs/reference/variables.md +++ b/docs/input/docs/reference/variables.md @@ -16,6 +16,8 @@ the repository history and effective configuration: "AssemblySemVer": "3.22.11.0", "BranchName": "release/3.022.011", "BuildMetaData": 88, + "CommitCountSourceDistance": 7, + "CommitCountSourceSha": "previous-source-commit-sha", "CommitDate": "2021-12-31", "CustomVersion": "3.22.11-beta.99", "EscapedBranchName": "release-3.022.011", @@ -32,13 +34,16 @@ the repository history and effective configuration: "PreReleaseLabel": "beta.99", "PreReleaseLabelWithDash": "-beta.99", "SemVer": "3.22.11-beta.99", + "SemVerSourceIncrement": "None", + "SemVerSourceSemVer": "3.22.11", + "SemVerSourceSha": null, "Sha": "28c853159a46b5a87e6cc9c4f6e940c59d6bc68a", "ShortSha": "28c8531", "UncommittedChanges": 0, "VersionSourceDistance": 7, "VersionSourceIncrement": "Minor", "VersionSourceSemVer": "3.22.11", - "VersionSourceSha": "28c853159a46b5a87e6cc9c4f6e940c59d6bc68a", + "VersionSourceSha": "previous-source-commit-sha", "WeightedPreReleaseNumber": 1099 } ``` @@ -50,7 +55,9 @@ Each property of the above JSON document is described in the below table. | `AssemblySemFileVer` | Suitable for .NET `AssemblyFileVersion`. Defaults to `Major.Minor.Patch.0`. | | `AssemblySemVer` | Suitable for .NET `AssemblyVersion`. Defaults to `Major.Minor.0.0` to allow the assembly to be hotfixed without breaking existing applications that may be referencing it. | | `BranchName` | The name of the checked out Git branch. | -| `BuildMetaData` | The build metadata, usually representing number of commits since the `VersionSourceSha`. Despite its name, will not increment for every build. | +| `BuildMetaData` | The build metadata, usually representing number of commits since the `CommitCountSourceSha`. Despite its name, will not increment for every build. | +| `CommitCountSourceDistance` | Number of non-ignored commits reachable from HEAD but not from the counting anchor. A null anchor counts all reachable history. | +| `CommitCountSourceSha` | SHA of the counting anchor, or JSON null when counting all reachable history. | | `CommitDate` | The ISO-8601 formatted date of the commit identified by `Sha`. | | `CustomVersion` | A custom version configured with `custom-version-format`. Empty when no format is configured. | | `EscapedBranchName` | Equal to `BranchName`, but with `/` replaced with `-`. | @@ -67,13 +74,16 @@ Each property of the above JSON document is described in the below table. | `PreReleaseLabel` | The full pre-release label, including the `PreReleaseNumber` when present. | | `PreReleaseLabelWithDash` | The pre-release label prefixed with a dash. | | `SemVer` | The semantic version number, including `PreReleaseLabelWithDash` for pre-release version numbers. | +| `SemVerSourceIncrement` | Final increment relative to the semantic baseline: `None`, `Patch`, `Minor`, or `Major`. | +| `SemVerSourceSemVer` | Baseline version supplied by the selected artifact or derivation. Mainline may use a folded baseline rather than a literal tag value. | +| `SemVerSourceSha` | SHA associated with the semantic source; JSON null for external sources such as configuration or a branch name. | | `Sha` | The SHA of the Git commit. | | `ShortSha` | The `Sha` limited to 7 characters. | | `UncommittedChanges` | The number of uncommitted changes present in the repository. | -| `VersionSourceDistance` | The number of commits since the version source. | -| `VersionSourceIncrement` | The increment strategy used for the version calculation. Possible values: `None`, `Patch`, `Minor`, `Major`. | -| `VersionSourceSemVer` | The semantic version of the commit used as version source. | -| `VersionSourceSha` | The SHA of the commit used as version source. | +| `VersionSourceDistance` | Compatibility alias for `CommitCountSourceDistance`. | +| `VersionSourceIncrement` | Legacy increment metadata, preserved for compatibility. Prefer `SemVerSourceIncrement`; the legacy field can be `None` even when an increment was applied. | +| `VersionSourceSemVer` | Legacy semantic baseline. It need not correspond to `VersionSourceSha`; prefer `SemVerSourceSemVer`. | +| `VersionSourceSha` | Legacy counting-anchor SHA. Prefer `CommitCountSourceSha`, which represents an absent anchor as null. | | `WeightedPreReleaseNumber` | A summation of branch specific `pre-release-weight` and the `PreReleaseNumber`. Can be used to obtain a monotonically increasing version number across the branches. | Depending on how and in which context GitVersion is executed (for instance @@ -81,6 +91,14 @@ within a [supported build server][build-servers]), the above version variables may be exposed automatically as **environment variables** in the format `GitVersion_FullSemVer`. +## Semantic and counting sources + +The semantic source and counting anchor can differ. With a `1.0.0` tag followed by one commit and `calculation.next-version: 5.0.0`, the semantic baseline is `5.0.0` and `SemVerSourceSha` is null, while `CommitCountSourceSha` points to the `1.0.0` tag and `CommitCountSourceDistance` is 1. A `release/5.0.0` branch name can supply the same external baseline. + +The distance remains available when a deployment mode incorporates the count into the pre-release number and clears `BuildMetaData`. On a selected tag at HEAD, both source SHAs are HEAD and distance is zero. `Sha` and `ShortSha` always identify the current commit. + +See [calculation strategies](/docs/reference/version-sources) for selection and counting rules. Missing source values are JSON null in the new fields; textual outputs such as environment variables and MSBuild properties use empty strings. + ## Formatting Variables GitVersion variables can be formatted using C# format strings. See [Format Strings](/docs/reference/custom-formatting) for details. diff --git a/docs/input/docs/reference/version-sources.md b/docs/input/docs/reference/version-sources.md index 8dbee4e684..a1219928c0 100644 --- a/docs/input/docs/reference/version-sources.md +++ b/docs/input/docs/reference/version-sources.md @@ -20,12 +20,24 @@ Strategies are selected with the [`strategies` configuration setting](/docs/refe ## Selection and increments -The order of entries in `strategies` is not a priority list. GitVersion evaluates candidates and selects a next version with a corresponding version source. Fallback is deferred until other strategies have been considered. +The order of entries in `strategies` is not a priority list. GitVersion evaluates candidates and selects a next version, preserving its semantic source separately from the commit-count anchor. Fallback is deferred until other strategies have been considered. Do not interpret a source as “always increments” or “never increments” without the relevant branch configuration. Tagged commits, merge handling, increment inheritance, and deployment mode affect the outcome. For the sequence of operations, see [how versions are calculated](/docs/learn/how-it-works). +## Semantic source and commit-count source + +The **semantic source** supplies the baseline version and its final increment. Tags and merge messages have associated commits. Configuration values and branch names are external sources: they do not intrinsically belong to a commit. Mainline can fold several operations into a derived baseline while retaining its source provenance. The source is not a detector for every commit that contains a version-bump message. + +The **commit-count source** anchors the count of commits reachable from the current commit, excluding commits reachable from the anchor and applying the configured ignore filters. This is a graph count, not first-parent distance or a count of builds. A null anchor counts all reachable, non-ignored history. + +GitVersion compares candidates by their incremented semantic version. For multiple equal candidates with source commits, it selects the latest source timestamp. Otherwise the counting search prefers a commit-backed candidate by descending incremented version and then source timestamp. When the winning version is stable, pre-release base candidates are excluded from this counting search. Only when no commit-backed candidate remains does it use a null anchor. The order in `strategies` does not establish precedence. + +For example, a `1.0.0` tag can remain the counting anchor while configuration or the branch name `release/5.0.0` supplies a `5.0.0` baseline. Replacing that anchor with the external semantic source would reset the meaning of the count. A later tag that raises the numeric version is reflected in semantic provenance without changing the selected counting anchor. + +See the `SemVerSource*` and `CommitCountSource*` [output variables](/docs/reference/variables). The legacy `VersionSource*` fields retain their existing values for compatibility; they mix the two concepts. + ## Existing source topics The following anchors are retained for older links. diff --git a/schemas/7.0/GitVersion.json b/schemas/7.0/GitVersion.json index 3354797c9a..a2691b95c5 100644 --- a/schemas/7.0/GitVersion.json +++ b/schemas/7.0/GitVersion.json @@ -27,12 +27,26 @@ ] }, "BuildMetaData": { - "description": "The build metadata, usually representing number of commits since the VersionSourceSha.", + "description": "The build metadata, usually representing number of commits since the CommitCountSourceSha.", "type": [ "null", "integer" ] }, + "CommitCountSourceDistance": { + "description": "The number of non-ignored commits reachable from HEAD but not from the counting anchor.", + "type": [ + "null", + "integer" + ] + }, + "CommitCountSourceSha": { + "description": "The commit used as the counting anchor, or null when counting all reachable history.", + "type": [ + "null", + "string" + ] + }, "CommitDate": { "description": "The ISO-8601 formatted date of the commit identified by Sha.", "type": [ @@ -145,6 +159,27 @@ "string" ] }, + "SemVerSourceIncrement": { + "description": "The final increment relative to the semantic baseline: None, Patch, Minor or Major.", + "type": [ + "null", + "string" + ] + }, + "SemVerSourceSemVer": { + "description": "The semantic baseline supplied by the selected artifact or derivation.", + "type": [ + "null", + "string" + ] + }, + "SemVerSourceSha": { + "description": "The semantic source commit SHA, or null for external sources such as configuration or a branch name.", + "type": [ + "null", + "string" + ] + }, "Sha": { "description": "The SHA of the Git commit.", "type": [ @@ -167,7 +202,7 @@ ] }, "VersionSourceDistance": { - "description": "The number of commits since the version source.", + "description": "Compatibility alias for CommitCountSourceDistance.", "type": [ "null", "integer" @@ -181,14 +216,14 @@ ] }, "VersionSourceSemVer": { - "description": "The semantic version of the commit used as version source.", + "description": "Legacy semantic baseline; it need not come from VersionSourceSha. Prefer SemVerSourceSemVer.", "type": [ "null", "string" ] }, "VersionSourceSha": { - "description": "The SHA of the commit used as version source.", + "description": "Compatibility alias for CommitCountSourceSha.", "type": [ "null", "string" diff --git a/src/GitVersion.Core.Tests/VersionCalculation/Approved/JsonVersionBuilderTests.Json.approved.txt b/src/GitVersion.Core.Tests/VersionCalculation/Approved/JsonVersionBuilderTests.Json.approved.txt index 5630e120f4..d9f9f77f8b 100644 --- a/src/GitVersion.Core.Tests/VersionCalculation/Approved/JsonVersionBuilderTests.Json.approved.txt +++ b/src/GitVersion.Core.Tests/VersionCalculation/Approved/JsonVersionBuilderTests.Json.approved.txt @@ -3,6 +3,8 @@ "AssemblySemVer": "1.2.0.0", "BranchName": "feature1", "BuildMetaData": 5, + "CommitCountSourceDistance": 5, + "CommitCountSourceSha": "versionSourceSha", "CommitDate": "2014-03-06", "CustomVersion": "", "EscapedBranchName": "feature1", @@ -19,6 +21,9 @@ "PreReleaseLabel": "unstable.4", "PreReleaseLabelWithDash": "-unstable.4", "SemVer": "1.2.0-unstable.4", + "SemVerSourceIncrement": "None", + "SemVerSourceSemVer": null, + "SemVerSourceSha": null, "Sha": "commitSha", "ShortSha": "commitShortSha", "UncommittedChanges": 0, diff --git a/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeliveryModeForFeatureBranch.approved.txt b/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeliveryModeForFeatureBranch.approved.txt index 713e3c2f47..528470c8bc 100644 --- a/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeliveryModeForFeatureBranch.approved.txt +++ b/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeliveryModeForFeatureBranch.approved.txt @@ -3,6 +3,8 @@ "AssemblySemVer": "1.2.3.0", "BranchName": "feature/123", "BuildMetaData": 5, + "CommitCountSourceDistance": 5, + "CommitCountSourceSha": "versionSourceSha", "CommitDate": "2014-03-06", "CustomVersion": "", "EscapedBranchName": "feature-123", @@ -19,6 +21,9 @@ "PreReleaseLabel": "", "PreReleaseLabelWithDash": "", "SemVer": "1.2.3", + "SemVerSourceIncrement": "None", + "SemVerSourceSemVer": null, + "SemVerSourceSha": null, "Sha": "commitSha", "ShortSha": "commitShortSha", "UncommittedChanges": 0, diff --git a/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeliveryModeForFeatureBranchWithCustomAssemblyInfoFormat.approved.txt b/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeliveryModeForFeatureBranchWithCustomAssemblyInfoFormat.approved.txt index 523467a4e2..ef5e204447 100644 --- a/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeliveryModeForFeatureBranchWithCustomAssemblyInfoFormat.approved.txt +++ b/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeliveryModeForFeatureBranchWithCustomAssemblyInfoFormat.approved.txt @@ -3,6 +3,8 @@ "AssemblySemVer": "1.2.3.0", "BranchName": "feature/123", "BuildMetaData": 5, + "CommitCountSourceDistance": 5, + "CommitCountSourceSha": "versionSourceSha", "CommitDate": "2014-03-06", "CustomVersion": "", "EscapedBranchName": "feature-123", @@ -19,6 +21,9 @@ "PreReleaseLabel": "", "PreReleaseLabelWithDash": "", "SemVer": "1.2.3", + "SemVerSourceIncrement": "None", + "SemVerSourceSemVer": null, + "SemVerSourceSha": null, "Sha": "commitSha", "ShortSha": "commitShortSha", "UncommittedChanges": 0, diff --git a/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeliveryModeForPreRelease.approved.txt b/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeliveryModeForPreRelease.approved.txt index 71e7812f73..be4dde22c3 100644 --- a/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeliveryModeForPreRelease.approved.txt +++ b/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeliveryModeForPreRelease.approved.txt @@ -3,6 +3,8 @@ "AssemblySemVer": "1.2.3.0", "BranchName": "develop", "BuildMetaData": 5, + "CommitCountSourceDistance": 5, + "CommitCountSourceSha": "versionSourceSha", "CommitDate": "2014-03-06", "CustomVersion": "", "EscapedBranchName": "develop", @@ -19,6 +21,9 @@ "PreReleaseLabel": "unstable.4", "PreReleaseLabelWithDash": "-unstable.4", "SemVer": "1.2.3-unstable.4", + "SemVerSourceIncrement": "None", + "SemVerSourceSemVer": null, + "SemVerSourceSha": null, "Sha": "commitSha", "ShortSha": "commitShortSha", "UncommittedChanges": 0, diff --git a/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeliveryModeForStable.approved.txt b/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeliveryModeForStable.approved.txt index 4d006e462e..897bcf1a9a 100644 --- a/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeliveryModeForStable.approved.txt +++ b/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeliveryModeForStable.approved.txt @@ -3,6 +3,8 @@ "AssemblySemVer": "1.2.3.0", "BranchName": "develop", "BuildMetaData": 5, + "CommitCountSourceDistance": 5, + "CommitCountSourceSha": "versionSourceSha", "CommitDate": "2014-03-06", "CustomVersion": "", "EscapedBranchName": "develop", @@ -19,6 +21,9 @@ "PreReleaseLabel": "", "PreReleaseLabelWithDash": "", "SemVer": "1.2.3", + "SemVerSourceIncrement": "None", + "SemVerSourceSemVer": null, + "SemVerSourceSha": null, "Sha": "commitSha", "ShortSha": "commitShortSha", "UncommittedChanges": 0, diff --git a/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeploymentModeForMainBranchWithEmptyLabel.approved.txt b/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeploymentModeForMainBranchWithEmptyLabel.approved.txt index de7b7f5f5f..f588268804 100644 --- a/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeploymentModeForMainBranchWithEmptyLabel.approved.txt +++ b/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeploymentModeForMainBranchWithEmptyLabel.approved.txt @@ -3,6 +3,8 @@ "AssemblySemVer": "1.2.3.0", "BranchName": "main", "BuildMetaData": null, + "CommitCountSourceDistance": 5, + "CommitCountSourceSha": "versionSourceSha", "CommitDate": "2014-03-06", "CustomVersion": "", "EscapedBranchName": "main", @@ -19,6 +21,9 @@ "PreReleaseLabel": "9", "PreReleaseLabelWithDash": "-9", "SemVer": "1.2.3-9", + "SemVerSourceIncrement": "None", + "SemVerSourceSemVer": null, + "SemVerSourceSha": null, "Sha": "commitSha", "ShortSha": "commitShortSha", "UncommittedChanges": 0, diff --git a/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeploymentModeForPreRelease.approved.txt b/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeploymentModeForPreRelease.approved.txt index 931b02b40e..0173eda741 100644 --- a/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeploymentModeForPreRelease.approved.txt +++ b/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeploymentModeForPreRelease.approved.txt @@ -3,6 +3,8 @@ "AssemblySemVer": "1.2.3.0", "BranchName": "develop", "BuildMetaData": null, + "CommitCountSourceDistance": 5, + "CommitCountSourceSha": "versionSourceSha", "CommitDate": "2014-03-06", "CustomVersion": "", "EscapedBranchName": "develop", @@ -19,6 +21,9 @@ "PreReleaseLabel": "unstable.8", "PreReleaseLabelWithDash": "-unstable.8", "SemVer": "1.2.3-unstable.8", + "SemVerSourceIncrement": "None", + "SemVerSourceSemVer": null, + "SemVerSourceSha": null, "Sha": "commitSha", "ShortSha": "commitShortSha", "UncommittedChanges": 0, diff --git a/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeploymentModeForStable.approved.txt b/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeploymentModeForStable.approved.txt index f08438fa27..7493c44bb2 100644 --- a/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeploymentModeForStable.approved.txt +++ b/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeploymentModeForStable.approved.txt @@ -3,6 +3,8 @@ "AssemblySemVer": "1.2.3.0", "BranchName": "develop", "BuildMetaData": null, + "CommitCountSourceDistance": 5, + "CommitCountSourceSha": "versionSourceSha", "CommitDate": "2014-03-06", "CustomVersion": "", "EscapedBranchName": "develop", @@ -19,6 +21,9 @@ "PreReleaseLabel": "ci.5", "PreReleaseLabelWithDash": "-ci.5", "SemVer": "1.2.3-ci.5", + "SemVerSourceIncrement": "None", + "SemVerSourceSemVer": null, + "SemVerSourceSha": null, "Sha": "commitSha", "ShortSha": "commitShortSha", "UncommittedChanges": 0, diff --git a/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeploymentModeForStableWhenCurrentCommitIsTagged.approved.txt b/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeploymentModeForStableWhenCurrentCommitIsTagged.approved.txt index 6a373e9406..2cbe83b562 100644 --- a/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeploymentModeForStableWhenCurrentCommitIsTagged.approved.txt +++ b/src/GitVersion.Core.Tests/VersionCalculation/Approved/VariableProviderTests.ProvidesVariablesInContinuousDeploymentModeForStableWhenCurrentCommitIsTagged.approved.txt @@ -3,6 +3,8 @@ "AssemblySemVer": "1.2.3.0", "BranchName": "", "BuildMetaData": 5, + "CommitCountSourceDistance": 5, + "CommitCountSourceSha": "versionSourceSha", "CommitDate": "2014-03-06", "CustomVersion": "", "EscapedBranchName": "", @@ -19,6 +21,9 @@ "PreReleaseLabel": "", "PreReleaseLabelWithDash": "", "SemVer": "1.2.3", + "SemVerSourceIncrement": "None", + "SemVerSourceSemVer": null, + "SemVerSourceSha": null, "Sha": "commitSha", "ShortSha": "commitShortSha", "UncommittedChanges": 0, diff --git a/src/GitVersion.Core.Tests/VersionCalculation/VariableProviderTests.cs b/src/GitVersion.Core.Tests/VersionCalculation/VariableProviderTests.cs index 08bcbc8ce0..9c901ef616 100644 --- a/src/GitVersion.Core.Tests/VersionCalculation/VariableProviderTests.cs +++ b/src/GitVersion.Core.Tests/VersionCalculation/VariableProviderTests.cs @@ -444,4 +444,62 @@ public void Format_Allows_CSharp_FormatStrings() variables.InformationalVersion.ShouldBe("1.2.3-0042"); } + + [TestCase(null)] + [TestCase("semantic-source-sha")] + public void SeparateSourcesSurviveFormattingEnumerationAndJson(string? semanticSourceSha) + { + var semanticVersion = new SemanticVersion(5, 0, 0) + { + BuildMetaData = new() + { + SemVerSourceSemVer = new(5, 0, 0), + SemVerSourceSha = semanticSourceSha, + SemVerSourceIncrement = VersionField.Minor, + VersionSourceSemVer = new(1, 0, 0), + VersionSourceSha = "count-source-sha", + VersionSourceDistance = 2, + VersionSourceIncrement = VersionField.None, + Sha = "head-sha" + } + }; + var configuration = GitFlowConfigurationBuilder.New + .WithAssemblyInformationalFormat("{SemVerSourceSemVer}-{SemVerSourceIncrement}+{CommitCountSourceDistance:000}") + .Build(); + + var variables = this.variableProvider.GetVariablesFor(semanticVersion, configuration, configuration.GetEffectiveConfiguration()); + variables.InformationalVersion.ShouldBe("5.0.0-Minor+002"); + variables.TryGetValue("SemVerSourceSha", out var enumeratedSource).ShouldBeTrue(); + enumeratedSource.ShouldBe(semanticSourceSha); + variables.Single(pair => pair.Key == "CommitCountSourceSha").Value.ShouldBe("count-source-sha"); + + var json = variables.ToJson(); + using var document = System.Text.Json.JsonDocument.Parse(json); + document.RootElement.GetProperty("CommitCountSourceDistance").GetInt64().ShouldBe(2); + document.RootElement.GetProperty("SemVerSourceSha").GetString().ShouldBe(semanticSourceSha); + var roundTrip = json.ToGitVersionVariables(); + roundTrip.SemVerSourceSemVer.ShouldBe("5.0.0"); + roundTrip.SemVerSourceSha.ShouldBe(semanticSourceSha); + roundTrip.SemVerSourceIncrement.ShouldBe("Minor"); + roundTrip.CommitCountSourceSha.ShouldBe("count-source-sha"); + roundTrip.CommitCountSourceDistance.ShouldBe("2"); + roundTrip.VersionSourceSemVer.ShouldBe("1.0.0"); + roundTrip.VersionSourceIncrement.ShouldBe("None"); + roundTrip.Sha.ShouldBe("head-sha"); + } + + [Test] + public void CopyingEnumeratedVariablesDoesNotReuseOldSourceValues() + { + var configuration = GitFlowConfigurationBuilder.New.Build(); + var original = this.variableProvider.GetVariablesFor(new SemanticVersion(1, 0, 0), configuration, configuration.GetEffectiveConfiguration()); + original.TryGetValue("SemVerSourceSha", out _).ShouldBeTrue(); + + var copy = original with { SemVerSourceSha = "updated-source", VersionSourceDistance = "3" }; + + copy.TryGetValue("SemVerSourceSha", out var source).ShouldBeTrue(); + source.ShouldBe("updated-source"); + copy.Single(pair => pair.Key == "CommitCountSourceDistance").Value.ShouldBe("3"); + original.SemVerSourceSha.ShouldBeNull(); + } } diff --git a/src/GitVersion.Core.Tests/VersionCalculation/VersionSourceTests.cs b/src/GitVersion.Core.Tests/VersionCalculation/VersionSourceTests.cs index 2203371313..9440ce3408 100644 --- a/src/GitVersion.Core.Tests/VersionCalculation/VersionSourceTests.cs +++ b/src/GitVersion.Core.Tests/VersionCalculation/VersionSourceTests.cs @@ -1,11 +1,400 @@ +using GitVersion.Configuration; using GitVersion.Git; using GitVersion.VersionCalculation; +using Microsoft.Extensions.DependencyInjection.Extensions; namespace GitVersion.Tests; [TestFixture] public class VersionSourceTests : TestBase { + [TestCase(1)] + [TestCase(2)] + public void ConfiguredVersionKeepsExternalSemanticSource(int commitsAfterTag) + { + using var fixture = new EmptyRepositoryFixture(); + var tagSha = fixture.MakeATaggedCommit("1.0.0"); + for (var index = 0; index < commitsAfterTag; index++) + { + fixture.MakeACommit(); + } + var configuration = GitHubFlowConfigurationBuilder.New.WithNextVersion("5.0.0").Build(); + + var version = FindVersion(fixture, configuration); + + version.ToString("f").ShouldBe($"5.0.0-{commitsAfterTag}"); + version.BuildMetaData.SemVerSourceSemVer?.ToString().ShouldBe("5.0.0"); + version.BuildMetaData.SemVerSourceSha.ShouldBeNull(); + version.BuildMetaData.SemVerSourceIncrement.ShouldBe(VersionField.None); + version.BuildMetaData.CommitCountSourceSha.ShouldBe(tagSha); + version.BuildMetaData.CommitCountSourceDistance.ShouldBe(commitsAfterTag); + version.BuildMetaData.VersionSourceSha.ShouldBe(tagSha); + version.BuildMetaData.VersionSourceDistance.ShouldBe(commitsAfterTag); + } + + [Test] + public void BranchNameKeepsExternalSemanticSource() + { + using var fixture = new EmptyRepositoryFixture(); + var tagSha = fixture.MakeATaggedCommit("1.0.0"); + fixture.BranchTo("release/5.0.0"); + fixture.MakeACommit(); + + var version = FindVersion(fixture, GitFlowConfigurationBuilder.New.Build()); + + version.ToString("f").ShouldBe("5.0.0-beta.1+1"); + version.BuildMetaData.SemVerSourceSemVer?.ToString().ShouldBe("5.0.0"); + version.BuildMetaData.SemVerSourceSha.ShouldBeNull(); + version.BuildMetaData.SemVerSourceIncrement.ShouldBe(VersionField.None); + version.BuildMetaData.CommitCountSourceSha.ShouldBe(tagSha); + version.BuildMetaData.CommitCountSourceDistance.ShouldBe(1); + } + + [TestCase("release/some_release", true)] + [TestCase("release/1.3.0", false)] + public void TrackedReleaseKeepsSemanticOriginSeparateFromMergeBase(string releaseBranch, bool usesTag) + { + using var fixture = new EmptyRepositoryFixture(); + fixture.MakeATaggedCommit("1.2.1"); + fixture.BranchTo("develop"); + var mergeBaseSha = fixture.MakeACommit(); + fixture.BranchTo(releaseBranch); + var tagSha = fixture.MakeATaggedCommit("1.3.0-beta.1"); + fixture.Checkout("develop"); + fixture.MakeACommit(); + + var version = FindVersion(fixture, GitFlowConfigurationBuilder.New.Build()); + + version.ToString("f").ShouldBe("1.4.0-alpha.1"); + version.BuildMetaData.SemVerSourceSemVer?.ToString().ShouldBe("1.3.0"); + version.BuildMetaData.SemVerSourceSha.ShouldBe(usesTag ? tagSha : null); + version.BuildMetaData.SemVerSourceIncrement.ShouldBe(VersionField.Minor); + version.BuildMetaData.CommitCountSourceSha.ShouldBe(mergeBaseSha); + version.BuildMetaData.CommitCountSourceDistance.ShouldBe(1); + version.BuildMetaData.VersionSourceSha.ShouldBe(mergeBaseSha); + } + + [Test] + public void ExternalOnlySourceCountsReachableHistory() + { + using var fixture = new EmptyRepositoryFixture(); + fixture.MakeACommit(); + fixture.MakeACommit(); + var configuration = GitHubFlowConfigurationBuilder.New.WithNextVersion("5.0.0").Build(); + + var version = FindVersion(fixture, configuration); + + version.ToString("f").ShouldBe("5.0.0-2"); + version.BuildMetaData.SemVerSourceSemVer?.ToString().ShouldBe("5.0.0"); + version.BuildMetaData.SemVerSourceSha.ShouldBeNull(); + version.BuildMetaData.CommitCountSourceSha.ShouldBeNull(); + version.BuildMetaData.CommitCountSourceDistance.ShouldBe(2); + } + + [Test] + public void OrdinaryTagRetainsSelectedIncrement() + { + using var fixture = new EmptyRepositoryFixture(); + var tagSha = fixture.MakeATaggedCommit("1.0.0"); + fixture.MakeACommit(); + + var version = FindVersion(fixture, GitHubFlowConfigurationBuilder.New.Build()); + + version.ToString("f").ShouldBe("1.0.1-1"); + version.BuildMetaData.SemVerSourceSemVer?.ToString().ShouldBe("1.0.0"); + version.BuildMetaData.SemVerSourceSha.ShouldBe(tagSha); + version.BuildMetaData.SemVerSourceIncrement.ShouldBe(VersionField.Patch); + version.BuildMetaData.VersionSourceIncrement.ShouldBe(VersionField.None); + version.BuildMetaData.CommitCountSourceSha.ShouldBe(tagSha); + version.BuildMetaData.CommitCountSourceDistance.ShouldBe(1); + } + + [TestCase(false)] + [TestCase(true)] + public void TaggedHeadUsesTagForBothSources(bool inheritedIncrement) + { + using var fixture = new EmptyRepositoryFixture(); + fixture.MakeACommit(); + if (inheritedIncrement) + { + fixture.BranchTo("feature/inherited"); + } + var tagSha = fixture.MakeATaggedCommit("2.3.4"); + + var configuration = GitHubFlowConfigurationBuilder.New + .WithBranch("feature", builder => builder.WithIncrement(IncrementStrategy.Inherit) + .WithPreventIncrementWhenCurrentCommitTagged(true)).Build(); + var version = FindVersion(fixture, configuration); + + version.ToString("f").ShouldBe("2.3.4"); + version.BuildMetaData.SemVerSourceSemVer?.ToString().ShouldBe("2.3.4"); + version.BuildMetaData.SemVerSourceSha.ShouldBe(tagSha); + version.BuildMetaData.SemVerSourceIncrement.ShouldBe(VersionField.None); + version.BuildMetaData.CommitCountSourceSha.ShouldBe(tagSha); + version.BuildMetaData.CommitCountSourceDistance.ShouldBe(0); + } + + [TestCase(DeploymentMode.ManualDeployment, "1.0.1-beta.1+2")] + [TestCase(DeploymentMode.ContinuousDelivery, "1.0.1-beta.2")] + [TestCase(DeploymentMode.ContinuousDeployment, "1.0.1")] + public void DeploymentModesPreserveSourceMetadata(DeploymentMode mode, string fullSemVer) + { + using var fixture = new EmptyRepositoryFixture(); + var tagSha = fixture.MakeATaggedCommit("1.0.0"); + fixture.MakeACommit(); + fixture.MakeACommit(); + var configuration = GitHubFlowConfigurationBuilder.New + .WithBranch("main", builder => builder.WithLabel("beta").WithDeploymentMode(mode)).Build(); + + var version = FindVersion(fixture, configuration); + + version.ToString("f").ShouldBe(fullSemVer); + version.BuildMetaData.SemVerSourceSha.ShouldBe(tagSha); + version.BuildMetaData.SemVerSourceSemVer?.ToString().ShouldBe("1.0.0"); + version.BuildMetaData.SemVerSourceIncrement.ShouldBe(VersionField.Patch); + version.BuildMetaData.CommitCountSourceSha.ShouldBe(tagSha); + version.BuildMetaData.CommitCountSourceDistance.ShouldBe(2); + } + + [Test] + public void IgnoredCommitInMergeGraphIsExcludedFromDistance() + { + using var fixture = new EmptyRepositoryFixture(); + var tagSha = fixture.MakeATaggedCommit("1.0.0"); + fixture.BranchTo("feature/counting"); + var ignoredSha = fixture.MakeACommit(); + fixture.MakeACommit(); + fixture.Checkout(MainBranch); + fixture.MakeACommit(); + fixture.MergeNoFF("feature/counting"); + var configuration = GitHubFlowConfigurationBuilder.New + .WithNextVersion("5.0.0") + .WithIgnoreConfiguration(new IgnoreConfiguration { Shas = [ignoredSha] }).Build(); + + var version = FindVersion(fixture, configuration); + + // The retained side-branch commit, main commit and merge all count. + version.ToString("f").ShouldBe("5.0.0-3"); + version.BuildMetaData.SemVerSourceSha.ShouldBeNull(); + version.BuildMetaData.SemVerSourceSemVer?.ToString().ShouldBe("5.0.0"); + version.BuildMetaData.CommitCountSourceSha.ShouldBe(tagSha); + version.BuildMetaData.CommitCountSourceDistance.ShouldBe(3); + } + + [TestCase(false)] + [TestCase(true)] + public void ReleaseBranchPresenceDoesNotChangeLatestSource(bool deleteReleaseBranch) + { + using var fixture = new EmptyRepositoryFixture(); + fixture.MakeATaggedCommit("0.1.0"); + fixture.BranchTo("develop"); + fixture.MakeACommit(); + fixture.BranchTo("release/0.2.0"); + fixture.MakeACommit(); + fixture.Checkout(MainBranch); + fixture.MergeNoFF("release/0.2.0"); + fixture.ApplyTag("0.2.0"); + var releaseTagSha = fixture.Repository.Head.Tip.Sha; + if (deleteReleaseBranch) + { + fixture.Repository.Branches.Remove("release/0.2.0"); + } + fixture.Checkout("develop"); + fixture.MergeNoFF(MainBranch); + var configuration = GitFlowConfigurationBuilder.New + .WithBranch("develop", builder => builder.WithDeploymentMode(DeploymentMode.ManualDeployment) + .WithTrackMergeMessage(false)).Build(); + + var version = FindVersion(fixture, configuration); + + version.ToString("f").ShouldBe("0.3.0-alpha.1+1"); + version.BuildMetaData.SemVerSourceSemVer?.ToString().ShouldBe("0.2.0"); + version.BuildMetaData.SemVerSourceSha.ShouldBe(releaseTagSha); + version.BuildMetaData.SemVerSourceIncrement.ShouldBe(VersionField.Minor); + version.BuildMetaData.CommitCountSourceSha.ShouldBe(releaseTagSha); + version.BuildMetaData.CommitCountSourceDistance.ShouldBe(1); + } + + [Test] + public void AlternativeTagFloorReplacesSemanticSourceWithoutResettingCount() + { + using var fixture = new EmptyRepositoryFixture(); + var countSha = fixture.MakeATaggedCommit("1.0.0"); + fixture.BranchTo("feature/work"); + var floorSha = fixture.MakeATaggedCommit("5.0.0-other.1"); + + var version = FindVersion(fixture, GitHubFlowConfigurationBuilder.New.Build()); + + version.ToString("f").ShouldBe("5.0.0-work.1+1"); + version.BuildMetaData.SemVerSourceSemVer?.ToString().ShouldBe("5.0.0-other.1"); + version.BuildMetaData.SemVerSourceSha.ShouldBe(floorSha); + version.BuildMetaData.SemVerSourceIncrement.ShouldBe(VersionField.None); + version.BuildMetaData.CommitCountSourceSha.ShouldBe(countSha); + version.BuildMetaData.CommitCountSourceDistance.ShouldBe(1); + version.BuildMetaData.VersionSourceSemVer?.ToString().ShouldBe("1.0.0"); + } + + [Test] + public void MainlineFoldKeepsExternalOriginWhenOperatorChangesCountAnchor() + { + var countCommit = GitRepositoryTestingExtensions.CreateMockCommit(); + var nextCountCommit = GitRepositoryTestingExtensions.CreateMockCommit(); + var version = new BaseVersion("Configured version", new SemanticVersion(5, 0, 0)) + { + Operator = new BaseVersionOperator { Increment = VersionField.Patch, BaseVersionSource = countCommit } + }; + + var folded = version.Apply(new BaseVersionOperator { Increment = VersionField.Minor, ForceIncrement = true, BaseVersionSource = nextCountCommit }); + + folded.GetIncrementedVersion().ToString().ShouldBe("5.1.0-1"); + folded.BaseVersionSource.ShouldBe(nextCountCommit); + var source = folded.GetSemVerSource(); + source.Commit.ShouldBeNull(); + source.Version.ToString().ShouldBe("5.0.1-1"); + source.Increment.ShouldBe(VersionField.Minor); + } + + [TestCase(5, "5.0.0", VersionField.None)] + [TestCase(0, "1.0.0", VersionField.Patch)] + public void OperatorAlternativeFloorUsesSupplyingSourceOnlyWhenItWins(int alternativeMajor, string sourceVersion, VersionField increment) + { + var originalCommit = GitRepositoryTestingExtensions.CreateMockCommit(); + var alternativeCommit = GitRepositoryTestingExtensions.CreateMockCommit(); + var alternative = new SemanticVersion(alternativeMajor, 0, 0); + var version = new BaseVersion("Original tag", new SemanticVersion(1, 0, 0), originalCommit) + { + Operator = new BaseVersionOperator + { + Increment = VersionField.Patch, + AlternativeSemanticVersion = alternative, + AlternativeSemVerSource = new SemanticVersionSource("Alternative tag", alternative, alternativeCommit, VersionField.None) + } + }; + + var source = version.GetSemVerSource(); + + source.Version.ToString().ShouldBe(sourceVersion); + source.Commit.ShouldBe(alternativeMajor == 5 ? alternativeCommit : originalCommit); + source.Increment.ShouldBe(increment); + version.GetIncrementedVersion().ToString().ShouldBe(alternativeMajor == 5 ? "5.0.0-1" : "1.0.1-1"); + version.BaseVersionSource.ShouldBe(originalCommit); + } + + [Test] + public void MainlineRepeatedIncrementsKeepTagOrigin() + { + using var fixture = new EmptyRepositoryFixture(); + var tagSha = fixture.MakeATaggedCommit("1.0.0"); + var previousSha = fixture.MakeACommit(); + fixture.MakeACommit(); + + var version = FindVersion(fixture, TrunkBasedConfigurationBuilder.New.Build()); + + version.ToString("f").ShouldBe("1.0.2"); + version.BuildMetaData.SemVerSourceSemVer?.ToString().ShouldBe("1.0.1-1"); + version.BuildMetaData.SemVerSourceSha.ShouldBe(tagSha); + version.BuildMetaData.SemVerSourceIncrement.ShouldBe(VersionField.Patch); + version.BuildMetaData.CommitCountSourceSha.ShouldBe(previousSha); + version.BuildMetaData.CommitCountSourceDistance.ShouldBe(1); + } + + [Test] + public void MainlineMergeKeepsChildSemanticOrigin() + { + using var fixture = new EmptyRepositoryFixture(); + var tagSha = fixture.MakeATaggedCommit("1.0.0"); + fixture.BranchTo("feature/work"); + fixture.MakeACommit(); + fixture.MakeACommit(); + fixture.Checkout(MainBranch); + fixture.MergeNoFF("feature/work"); + + var version = FindVersion(fixture, TrunkBasedConfigurationBuilder.New.Build()); + + version.ToString("f").ShouldBe("1.1.0"); + version.BuildMetaData.SemVerSourceSha.ShouldBe(tagSha); + version.BuildMetaData.SemVerSourceSemVer?.ToString().ShouldBe("1.0.0"); + version.BuildMetaData.SemVerSourceIncrement.ShouldBe(VersionField.Minor); + version.BuildMetaData.CommitCountSourceSha.ShouldBe(tagSha); + version.BuildMetaData.CommitCountSourceDistance.ShouldBe(3); + } + + [TestCase("2.0.0", "2.0.0-3")] + [TestCase("1.0.1", "1.0.1-3")] + public void MergeMessageKeepsSupplyingCommitSeparateFromOlderTag(string releaseVersion, string fullSemVer) + { + using var fixture = new EmptyRepositoryFixture(); + var tagSha = fixture.MakeATaggedCommit("1.0.0"); + var releaseBranch = $"release/{releaseVersion}"; + fixture.BranchTo(releaseBranch); + fixture.MakeACommit(); + fixture.Checkout(MainBranch); + fixture.MergeNoFF(releaseBranch); + var mergeSha = fixture.Repository.Head.Tip.Sha; + fixture.MakeACommit(); + + var version = FindVersion(fixture, GitFlowConfigurationBuilder.New.Build()); + + version.ToString("f").ShouldBe(fullSemVer); + version.BuildMetaData.SemVerSourceSemVer?.ToString().ShouldBe(releaseVersion); + version.BuildMetaData.SemVerSourceSha.ShouldBe(mergeSha); + version.BuildMetaData.SemVerSourceIncrement.ShouldBe(VersionField.None); + version.BuildMetaData.CommitCountSourceSha.ShouldBe(tagSha); + version.BuildMetaData.CommitCountSourceDistance.ShouldBe(3); + } + + [Test] + public void StableWinnerExcludesPreReleaseCandidateFromCountingSelection() + { + using var fixture = new EmptyRepositoryFixture(); + var stableSha = fixture.MakeATaggedCommit("1.0.0"); + var preReleaseSha = fixture.MakeATaggedCommit("4.0.0-alpha.1"); + fixture.MakeACommit(); + using var repository = fixture.Repository.ToGitRepository(); + var stableCommit = repository.Commits.Single(commit => commit.Sha == stableSha); + var preReleaseCommit = repository.Commits.Single(commit => commit.Sha == preReleaseSha); + var strategy = Substitute.For(); + strategy.GetBaseVersions(Arg.Any()).Returns([ + new BaseVersion("External stable version", new SemanticVersion(5, 0, 0)), + new BaseVersion("Pre-release tag", SemanticVersion.Parse("4.0.0-alpha.1", null), preReleaseCommit), + new BaseVersion("Stable tag", new SemanticVersion(1, 0, 0), stableCommit) + ]); + + var configuration = GitHubFlowConfigurationBuilder.New + .WithBranch("main", builder => builder.WithDeploymentMode(DeploymentMode.ContinuousDeployment)).Build(); + var version = FindVersion(fixture, configuration, strategy, repository); + + version.ToString("f").ShouldBe("5.0.0"); + version.BuildMetaData.SemVerSourceSemVer?.ToString().ShouldBe("5.0.0"); + version.BuildMetaData.SemVerSourceSha.ShouldBeNull(); + version.BuildMetaData.CommitCountSourceSha.ShouldBe(stableSha); + version.BuildMetaData.CommitCountSourceDistance.ShouldBe(2); + } + + private static SemanticVersion FindVersion(EmptyRepositoryFixture fixture, IGitVersionConfiguration configuration, + IVersionStrategy? strategy = null, IGitRepository? repository = null) + { + var provider = Substitute.For(); + provider.Provide(Arg.Any?>()).Returns(configuration); + var options = Options.Create(new GitVersionOptions { WorkingDirectory = fixture.Repository.Info.WorkingDirectory }); + using var services = (ServiceProvider)fixture.ConfigureServices((collection, _) => + { + collection.AddSingleton(provider); + collection.AddSingleton(options); + if (repository is not null) + { + collection.AddSingleton(repository); + } + if (strategy is not null) + { + collection.RemoveAll(); + collection.AddSingleton(strategy); + } + }); + services.DiscoverRepository(); + return services.GetRequiredService().FindVersion(); + } + [Test] public void VersionSourceSha() { @@ -23,6 +412,9 @@ public void VersionSourceSha() semanticVersion.BuildMetaData.VersionSourceSha.ShouldBeNull(); semanticVersion.BuildMetaData.VersionSourceDistance.ShouldBe(3); + semanticVersion.BuildMetaData.SemVerSourceSha.ShouldBeNull(); + semanticVersion.BuildMetaData.CommitCountSourceSha.ShouldBeNull(); + semanticVersion.BuildMetaData.CommitCountSourceDistance.ShouldBe(3); } [Test] diff --git a/src/GitVersion.Core/OutputVariables/GitVersionVariables.cs b/src/GitVersion.Core/OutputVariables/GitVersionVariables.cs index cc17949983..4d3d177763 100644 --- a/src/GitVersion.Core/OutputVariables/GitVersionVariables.cs +++ b/src/GitVersion.Core/OutputVariables/GitVersionVariables.cs @@ -32,6 +32,21 @@ public record GitVersionVariables( string WeightedPreReleaseNumber ) : IEnumerable> { + /// Gets or initializes the semantic baseline supplied by the selected artifact or derivation. + public string? SemVerSourceSemVer { get; init; } + + /// Gets or initializes the semantic source SHA, or null for configuration and branch-name sources. + public string? SemVerSourceSha { get; init; } + + /// Gets or initializes the final increment relative to the semantic baseline. + public string? SemVerSourceIncrement { get; init; } + + /// Gets the commit used as the counting anchor, or null when counting all reachable history. + public string? CommitCountSourceSha => string.IsNullOrEmpty(VersionSourceSha) ? null : VersionSourceSha; + + /// Gets the count of non-ignored commits beyond the counting anchor. + public string? CommitCountSourceDistance => VersionSourceDistance; + internal static readonly List AvailableVariables = [ nameof(AssemblySemFileVer), @@ -39,6 +54,8 @@ string WeightedPreReleaseNumber nameof(BranchName), nameof(BuildMetaData), nameof(CommitDate), + nameof(CommitCountSourceDistance), + nameof(CommitCountSourceSha), nameof(CustomVersion), nameof(EscapedBranchName), nameof(FullBuildMetaData), @@ -54,6 +71,9 @@ string WeightedPreReleaseNumber nameof(PreReleaseLabel), nameof(PreReleaseLabelWithDash), nameof(SemVer), + nameof(SemVerSourceIncrement), + nameof(SemVerSourceSemVer), + nameof(SemVerSourceSha), nameof(Sha), nameof(ShortSha), nameof(UncommittedChanges), @@ -64,13 +84,15 @@ string WeightedPreReleaseNumber nameof(WeightedPreReleaseNumber) ]; - private Dictionary Instance => field ??= new() + private Dictionary Instance => new() { { nameof(AssemblySemFileVer), AssemblySemFileVer }, { nameof(AssemblySemVer), AssemblySemVer }, { nameof(BranchName), BranchName }, { nameof(BuildMetaData), BuildMetaData }, { nameof(CommitDate), CommitDate }, + { nameof(CommitCountSourceDistance), CommitCountSourceDistance }, + { nameof(CommitCountSourceSha), CommitCountSourceSha }, { nameof(CustomVersion), CustomVersion }, { nameof(EscapedBranchName), EscapedBranchName }, { nameof(FullBuildMetaData), FullBuildMetaData }, @@ -86,6 +108,9 @@ string WeightedPreReleaseNumber { nameof(PreReleaseLabel), PreReleaseLabel }, { nameof(PreReleaseLabelWithDash), PreReleaseLabelWithDash }, { nameof(SemVer), SemVer }, + { nameof(SemVerSourceIncrement), SemVerSourceIncrement }, + { nameof(SemVerSourceSemVer), SemVerSourceSemVer }, + { nameof(SemVerSourceSha), SemVerSourceSha }, { nameof(Sha), Sha }, { nameof(ShortSha), ShortSha }, { nameof(UncommittedChanges), UncommittedChanges }, diff --git a/src/GitVersion.Core/PublicAPI.Unshipped.txt b/src/GitVersion.Core/PublicAPI.Unshipped.txt index d2bf01e297..b79738e4e7 100644 --- a/src/GitVersion.Core/PublicAPI.Unshipped.txt +++ b/src/GitVersion.Core/PublicAPI.Unshipped.txt @@ -1,4 +1,25 @@ #nullable enable +GitVersion.OutputVariables.GitVersionVariables.CommitCountSourceDistance.get -> string? +GitVersion.OutputVariables.GitVersionVariables.CommitCountSourceSha.get -> string? +GitVersion.OutputVariables.GitVersionVariables.SemVerSourceIncrement.get -> string? +GitVersion.OutputVariables.GitVersionVariables.SemVerSourceIncrement.init -> void +GitVersion.OutputVariables.GitVersionVariables.SemVerSourceSemVer.get -> string? +GitVersion.OutputVariables.GitVersionVariables.SemVerSourceSemVer.init -> void +GitVersion.OutputVariables.GitVersionVariables.SemVerSourceSha.get -> string? +GitVersion.OutputVariables.GitVersionVariables.SemVerSourceSha.init -> void +GitVersion.SemanticVersionBuildMetaData.CommitCountSourceDistance.get -> long +GitVersion.SemanticVersionBuildMetaData.CommitCountSourceSha.get -> string? +GitVersion.SemanticVersionBuildMetaData.SemVerSourceIncrement.get -> GitVersion.VersionField +GitVersion.SemanticVersionBuildMetaData.SemVerSourceIncrement.init -> void +GitVersion.SemanticVersionBuildMetaData.SemVerSourceSemVer.get -> GitVersion.SemanticVersion? +GitVersion.SemanticVersionBuildMetaData.SemVerSourceSemVer.init -> void +GitVersion.SemanticVersionBuildMetaData.SemVerSourceSha.get -> string? +GitVersion.SemanticVersionBuildMetaData.SemVerSourceSha.init -> void +GitVersion.SemanticVersionFormatValues.CommitCountSourceDistance.get -> string! +GitVersion.SemanticVersionFormatValues.CommitCountSourceSha.get -> string? +GitVersion.SemanticVersionFormatValues.SemVerSourceIncrement.get -> string! +GitVersion.SemanticVersionFormatValues.SemVerSourceSemVer.get -> string? +GitVersion.SemanticVersionFormatValues.SemVerSourceSha.get -> string? GitVersion.ConfigurationMigrationInfo GitVersion.ConfigurationMigrationInfo.ConfigurationMigrationInfo() -> void GitVersion.ConfigurationMigrationInfo.Force.get -> bool diff --git a/src/GitVersion.Core/SemVer/SemanticVersionBuildMetaData.cs b/src/GitVersion.Core/SemVer/SemanticVersionBuildMetaData.cs index 3f3e94380b..ef2d7eadca 100644 --- a/src/GitVersion.Core/SemVer/SemanticVersionBuildMetaData.cs +++ b/src/GitVersion.Core/SemVer/SemanticVersionBuildMetaData.cs @@ -31,21 +31,36 @@ public sealed class SemanticVersionBuildMetaData : IFormattable, IEquatableGets or initializes the date of the current commit. public DateTimeOffset? CommitDate { get; init; } - /// Gets or initializes the semantic version of the source tag from which the version was calculated. + /// Gets or initializes the legacy semantic baseline, which need not correspond to VersionSourceSha. public SemanticVersion? VersionSourceSemVer { get; init; } - /// Gets or initializes the SHA of the source tag commit. + /// Gets or initializes the legacy counting-anchor SHA. public string? VersionSourceSha { get; init; } - /// Gets or initializes the number of commits between the version source tag and the current commit. + /// Gets or initializes the count of non-ignored commits beyond the counting anchor. public long VersionSourceDistance { get; init; } /// Gets or initializes the number of uncommitted changes in the working tree. public long UncommittedChanges { get; init; } - /// Gets or initializes the version field that was incremented relative to the version source. + /// Gets or initializes legacy increment metadata; prefer SemVerSourceIncrement for the selected final increment. public VersionField VersionSourceIncrement { get; init; } + /// Gets or initializes the semantic baseline supplied by the selected artifact or derivation. + public SemanticVersion? SemVerSourceSemVer { get; init; } + + /// Gets or initializes the semantic source commit SHA, or null for an external source such as configuration or a branch name. + public string? SemVerSourceSha { get; init; } + + /// Gets or initializes the final increment relative to the semantic baseline. + public VersionField SemVerSourceIncrement { get; init; } + + /// Gets the commit used as the anchor for counting, or null when counting all reachable history. + public string? CommitCountSourceSha => VersionSourceSha; + + /// Gets the number of non-ignored commits reachable from HEAD but not from the counting anchor. + public long CommitCountSourceDistance => VersionSourceDistance; + /// Initializes a new empty build metadata instance. public SemanticVersionBuildMetaData() { @@ -93,6 +108,9 @@ public SemanticVersionBuildMetaData(SemanticVersionBuildMetaData buildMetaData) VersionSourceDistance = buildMetaData.VersionSourceDistance; UncommittedChanges = buildMetaData.UncommittedChanges; VersionSourceIncrement = buildMetaData.VersionSourceIncrement; + SemVerSourceSemVer = buildMetaData.SemVerSourceSemVer; + SemVerSourceSha = buildMetaData.SemVerSourceSha; + SemVerSourceIncrement = buildMetaData.SemVerSourceIncrement; } /// Returns when is a equal to this instance. diff --git a/src/GitVersion.Core/VersionCalculation/Caching/GitVersionCacheKeyFactory.cs b/src/GitVersion.Core/VersionCalculation/Caching/GitVersionCacheKeyFactory.cs index 14986d849c..66c109d180 100644 --- a/src/GitVersion.Core/VersionCalculation/Caching/GitVersionCacheKeyFactory.cs +++ b/src/GitVersion.Core/VersionCalculation/Caching/GitVersionCacheKeyFactory.cs @@ -34,7 +34,7 @@ public GitVersionCacheKey Create(IReadOnlyDictionary? overrideC var overrideConfigHash = GetOverrideConfigHash(overrideConfiguration); var configurationVersionHash = GetHash(ConfigurationVersionSelector.ResolveName()); - var compositeHash = GetHash(gitSystemHash, configFileHash, repositorySnapshotHash, repositoryTargetHash, overrideConfigHash, configurationVersionHash); + var compositeHash = GetHash(gitSystemHash, configFileHash, repositorySnapshotHash, repositoryTargetHash, overrideConfigHash, configurationVersionHash, "separate-semver-and-count-sources-v1"); return new(compositeHash); } diff --git a/src/GitVersion.Core/VersionCalculation/Mainline/EnrichSemanticVersion.cs b/src/GitVersion.Core/VersionCalculation/Mainline/EnrichSemanticVersion.cs index 3c7bec3ba6..67921eea90 100644 --- a/src/GitVersion.Core/VersionCalculation/Mainline/EnrichSemanticVersion.cs +++ b/src/GitVersion.Core/VersionCalculation/Mainline/EnrichSemanticVersion.cs @@ -16,7 +16,14 @@ public void Enrich(MainlineIteration iteration, MainlineCommit commit, MainlineC var semanticVersions = commit.SemanticVersions.Where( element => element.IsMatchForBranchSpecificLabel(branchSpecificLabel) ).ToList(); - context.AlternativeSemanticVersions.AddRange(commit.SemanticVersions.Except(semanticVersions)); + foreach (var version in commit.SemanticVersions.Except(semanticVersions)) + { + context.AddAlternativeSemanticVersion(version, + new SemanticVersionSource("Git tag", version, commit.Value, VersionField.None)); + } context.SemanticVersion = semanticVersions.Max(); + context.SemVerSource = context.SemanticVersion is { } selected + ? new SemanticVersionSource("Git tag", selected, commit.Value, VersionField.None) + : null; } } diff --git a/src/GitVersion.Core/VersionCalculation/Mainline/MainlineContext.cs b/src/GitVersion.Core/VersionCalculation/Mainline/MainlineContext.cs index 75aed87b77..81f3674550 100644 --- a/src/GitVersion.Core/VersionCalculation/Mainline/MainlineContext.cs +++ b/src/GitVersion.Core/VersionCalculation/Mainline/MainlineContext.cs @@ -19,6 +19,8 @@ internal record MainlineContext(IIncrementStrategyFinder IncrementStrategyFinder public SemanticVersion? SemanticVersion { get; set; } + public SemanticVersionSource? SemVerSource { get; set; } + public string? Label { get; set; } public VersionField Increment { get; set; } @@ -29,5 +31,25 @@ internal record MainlineContext(IIncrementStrategyFinder IncrementStrategyFinder public HashSet AlternativeSemanticVersions { get; } = []; + private readonly Dictionary alternativeSources = []; + + public void AddAlternativeSemanticVersion(SemanticVersion version, SemanticVersionSource source) + { + AlternativeSemanticVersions.Add(version); + this.alternativeSources.TryAdd(version, source); + } + + public SemanticVersionSource? GetAlternativeSemVerSource() + { + var version = AlternativeSemanticVersions.Max(); + return version is not null && this.alternativeSources.TryGetValue(version, out var source) ? source : null; + } + + public void ClearAlternativeSemanticVersions() + { + AlternativeSemanticVersions.Clear(); + this.alternativeSources.Clear(); + } + public bool ForceIncrement { get; set; } } diff --git a/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/CommitOnNonTrunk.cs b/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/CommitOnNonTrunk.cs index 93e210b67f..e13957b16b 100644 --- a/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/CommitOnNonTrunk.cs +++ b/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/CommitOnNonTrunk.cs @@ -38,7 +38,8 @@ public IEnumerable GetIncrements( Increment = context.Increment, ForceIncrement = context.ForceIncrement, Label = context.Label, - AlternativeSemanticVersion = context.AlternativeSemanticVersions.Max() + AlternativeSemanticVersion = context.AlternativeSemanticVersions.Max(), + AlternativeSemVerSource = context.GetAlternativeSemVerSource() }; context.BaseVersionSource = commit.Value; diff --git a/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/CommitOnNonTrunkBranchedBase.cs b/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/CommitOnNonTrunkBranchedBase.cs index d1ff759356..2bfe952de3 100644 --- a/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/CommitOnNonTrunkBranchedBase.cs +++ b/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/CommitOnNonTrunkBranchedBase.cs @@ -31,7 +31,8 @@ public virtual IEnumerable GetIncrements( Increment = VersionField.None, ForceIncrement = false, Label = context.Label, - AlternativeSemanticVersion = context.AlternativeSemanticVersions.Max() + AlternativeSemanticVersion = context.AlternativeSemanticVersions.Max(), + AlternativeSemVerSource = context.GetAlternativeSemVerSource() }; } } diff --git a/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/CommitOnNonTrunkWithPreReleaseTagBase.cs b/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/CommitOnNonTrunkWithPreReleaseTagBase.cs index a1fb230b8c..2e3cc00286 100644 --- a/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/CommitOnNonTrunkWithPreReleaseTagBase.cs +++ b/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/CommitOnNonTrunkWithPreReleaseTagBase.cs @@ -19,7 +19,8 @@ public virtual IEnumerable GetIncrements( { Source = GetType().Name, BaseVersionSource = context.BaseVersionSource, - SemanticVersion = context.SemanticVersion.NotNull() + SemanticVersion = context.SemanticVersion.NotNull(), + SemVerSource = context.SemVerSource }; context.Increment = commit.GetIncrementForcedByBranch(context.Configuration); diff --git a/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/CommitOnNonTrunkWithStableTagBase.cs b/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/CommitOnNonTrunkWithStableTagBase.cs index 16dce34061..018a8c4a55 100644 --- a/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/CommitOnNonTrunkWithStableTagBase.cs +++ b/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/CommitOnNonTrunkWithStableTagBase.cs @@ -19,7 +19,8 @@ public virtual IEnumerable GetIncrements( { Source = GetType().Name, BaseVersionSource = context.BaseVersionSource, - SemanticVersion = context.SemanticVersion.NotNull() + SemanticVersion = context.SemanticVersion.NotNull(), + SemVerSource = context.SemVerSource }; context.Increment = commit.GetIncrementForcedByBranch(context.Configuration); diff --git a/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/FirstCommitOnRelease.cs b/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/FirstCommitOnRelease.cs index 3fc2589719..cee6c4255b 100644 --- a/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/FirstCommitOnRelease.cs +++ b/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/FirstCommitOnRelease.cs @@ -35,6 +35,7 @@ public IEnumerable GetIncrements( yield break; } - context.AlternativeSemanticVersions.Add(element.Value); + context.AddAlternativeSemanticVersion(element.Value, + new SemanticVersionSource("Version in branch name", element.Value, null, VersionField.None)); } } diff --git a/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/LastCommitOnNonTrunkWithPreReleaseTag.cs b/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/LastCommitOnNonTrunkWithPreReleaseTag.cs index 5555fa3d93..b3a4c0756d 100644 --- a/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/LastCommitOnNonTrunkWithPreReleaseTag.cs +++ b/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/LastCommitOnNonTrunkWithPreReleaseTag.cs @@ -23,7 +23,8 @@ public override IEnumerable GetIncrements( Increment = context.Increment, ForceIncrement = false, Label = context.Label, - AlternativeSemanticVersion = context.AlternativeSemanticVersions.Max() + AlternativeSemanticVersion = context.AlternativeSemanticVersions.Max(), + AlternativeSemVerSource = context.GetAlternativeSemVerSource() }; } } diff --git a/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/LastCommitOnNonTrunkWithStableTag.cs b/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/LastCommitOnNonTrunkWithStableTag.cs index a9eeff4b76..0c85d4f0af 100644 --- a/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/LastCommitOnNonTrunkWithStableTag.cs +++ b/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/LastCommitOnNonTrunkWithStableTag.cs @@ -23,7 +23,8 @@ public override IEnumerable GetIncrements( Increment = context.Increment, ForceIncrement = true, Label = context.Label, - AlternativeSemanticVersion = context.AlternativeSemanticVersions.Max() + AlternativeSemanticVersion = context.AlternativeSemanticVersions.Max(), + AlternativeSemVerSource = context.GetAlternativeSemVerSource() }; } } diff --git a/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/LastMergeCommitOnNonTrunk.cs b/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/LastMergeCommitOnNonTrunk.cs index 4069f79444..d83db5c0b3 100644 --- a/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/LastMergeCommitOnNonTrunk.cs +++ b/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/LastMergeCommitOnNonTrunk.cs @@ -24,7 +24,8 @@ public override IEnumerable GetIncrements( Increment = context.Increment, ForceIncrement = context.ForceIncrement, Label = context.TargetLabel ?? context.Label, - AlternativeSemanticVersion = context.AlternativeSemanticVersions.Max() + AlternativeSemanticVersion = context.AlternativeSemanticVersions.Max(), + AlternativeSemVerSource = context.GetAlternativeSemVerSource() }; } } diff --git a/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/MergeCommitOnNonTrunkBase.cs b/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/MergeCommitOnNonTrunkBase.cs index b8a197b606..9302c5b661 100644 --- a/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/MergeCommitOnNonTrunkBase.cs +++ b/src/GitVersion.Core/VersionCalculation/Mainline/NonTrunk/MergeCommitOnNonTrunkBase.cs @@ -67,17 +67,20 @@ private static void ApplyBaseVersion(MainlineContext context, BaseVersion baseVe { context.BaseVersionSource = baseVersion.BaseVersionSource; context.SemanticVersion = baseVersion.SemanticVersion; + context.SemVerSource = baseVersion.GetBaselineSemVerSource(); return; } if (baseVersion.SemanticVersion != SemanticVersion.Empty) { - context.AlternativeSemanticVersions.Add(baseVersion.SemanticVersion); + context.AddAlternativeSemanticVersion(baseVersion.SemanticVersion, baseVersion.GetBaselineSemVerSource() with { Increment = VersionField.None }); } if (baseVersion.Operator?.AlternativeSemanticVersion is not null) { - context.AlternativeSemanticVersions.Add(baseVersion.Operator.AlternativeSemanticVersion); + context.AddAlternativeSemanticVersion(baseVersion.Operator.AlternativeSemanticVersion, + baseVersion.Operator.AlternativeSemVerSource ?? new SemanticVersionSource( + "Alternative semantic version", baseVersion.Operator.AlternativeSemanticVersion, null, VersionField.None)); } } } diff --git a/src/GitVersion.Core/VersionCalculation/Mainline/RemoveIncrement.cs b/src/GitVersion.Core/VersionCalculation/Mainline/RemoveIncrement.cs index 7b3327899e..062250bb65 100644 --- a/src/GitVersion.Core/VersionCalculation/Mainline/RemoveIncrement.cs +++ b/src/GitVersion.Core/VersionCalculation/Mainline/RemoveIncrement.cs @@ -12,6 +12,6 @@ public void Enrich(MainlineCommit commit, MainlineContext context) context.SuppressBranchIncrement = false; context.Increment = VersionField.None; context.Label = null; - context.AlternativeSemanticVersions.Clear(); + context.ClearAlternativeSemanticVersions(); } } diff --git a/src/GitVersion.Core/VersionCalculation/Mainline/RemoveSemanticVersion.cs b/src/GitVersion.Core/VersionCalculation/Mainline/RemoveSemanticVersion.cs index f0825a4498..63b379a3c0 100644 --- a/src/GitVersion.Core/VersionCalculation/Mainline/RemoveSemanticVersion.cs +++ b/src/GitVersion.Core/VersionCalculation/Mainline/RemoveSemanticVersion.cs @@ -2,5 +2,9 @@ namespace GitVersion.VersionCalculation.Mainline; internal sealed class RemoveSemanticVersion : IContextPostEnricher { - public void Enrich(MainlineCommit commit, MainlineContext context) => context.SemanticVersion = null; + public void Enrich(MainlineCommit commit, MainlineContext context) + { + context.SemanticVersion = null; + context.SemVerSource = null; + } } diff --git a/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/CommitOnTrunk.cs b/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/CommitOnTrunk.cs index 2c1db8d99c..d75e13b636 100644 --- a/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/CommitOnTrunk.cs +++ b/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/CommitOnTrunk.cs @@ -33,7 +33,8 @@ public IEnumerable GetIncrements( Increment = context.Increment, ForceIncrement = context.ForceIncrement, Label = context.Label, - AlternativeSemanticVersion = context.AlternativeSemanticVersions.Max() + AlternativeSemanticVersion = context.AlternativeSemanticVersions.Max(), + AlternativeSemVerSource = context.GetAlternativeSemVerSource() }; context.BaseVersionSource = commit.Value; diff --git a/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/CommitOnTrunkBranchedBase.cs b/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/CommitOnTrunkBranchedBase.cs index b3f7569c90..3829018b4b 100644 --- a/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/CommitOnTrunkBranchedBase.cs +++ b/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/CommitOnTrunkBranchedBase.cs @@ -19,7 +19,8 @@ public virtual IEnumerable GetIncrements( if (iteration.GetEffectiveConfiguration(context.Configuration).IsReleaseBranch && iteration.BranchName.TryGetSemanticVersion(effectiveConfiguration, out var element)) { - context.AlternativeSemanticVersions.Add(element.Value); + context.AddAlternativeSemanticVersion(element.Value, + new SemanticVersionSource("Version in branch name", element.Value, null, VersionField.None)); } var incrementForcedByBranch = iteration.Configuration.Increment == IncrementStrategy.Inherit @@ -38,7 +39,8 @@ public virtual IEnumerable GetIncrements( Increment = context.Increment, ForceIncrement = context.ForceIncrement, Label = context.Label, - AlternativeSemanticVersion = context.AlternativeSemanticVersions.Max() + AlternativeSemanticVersion = context.AlternativeSemanticVersions.Max(), + AlternativeSemVerSource = context.GetAlternativeSemVerSource() }; } } diff --git a/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/CommitOnTrunkWithPreReleaseTagBase.cs b/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/CommitOnTrunkWithPreReleaseTagBase.cs index b47e21886d..f5be13ae70 100644 --- a/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/CommitOnTrunkWithPreReleaseTagBase.cs +++ b/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/CommitOnTrunkWithPreReleaseTagBase.cs @@ -17,7 +17,8 @@ public virtual IEnumerable GetIncrements( { Source = GetType().Name, BaseVersionSource = context.BaseVersionSource, - SemanticVersion = context.SemanticVersion.NotNull() + SemanticVersion = context.SemanticVersion.NotNull(), + SemVerSource = context.SemVerSource }; } } diff --git a/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/CommitOnTrunkWithStableTagBase.cs b/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/CommitOnTrunkWithStableTagBase.cs index 256faec1eb..47acce4615 100644 --- a/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/CommitOnTrunkWithStableTagBase.cs +++ b/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/CommitOnTrunkWithStableTagBase.cs @@ -18,6 +18,7 @@ public virtual IEnumerable GetIncrements( { Source = GetType().Name, SemanticVersion = context.SemanticVersion.NotNull(), + SemVerSource = context.SemVerSource, BaseVersionSource = context.BaseVersionSource }; diff --git a/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/LastCommitOnTrunkWithPreReleaseTag.cs b/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/LastCommitOnTrunkWithPreReleaseTag.cs index bf3c1d4eb8..0e0a7bd3cc 100644 --- a/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/LastCommitOnTrunkWithPreReleaseTag.cs +++ b/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/LastCommitOnTrunkWithPreReleaseTag.cs @@ -36,7 +36,8 @@ public override IEnumerable GetIncrements( Increment = context.Increment, ForceIncrement = context.ForceIncrement, Label = context.Label, - AlternativeSemanticVersion = context.AlternativeSemanticVersions.Max() + AlternativeSemanticVersion = context.AlternativeSemanticVersions.Max(), + AlternativeSemVerSource = context.GetAlternativeSemVerSource() }; } } diff --git a/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/LastCommitOnTrunkWithStableTag.cs b/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/LastCommitOnTrunkWithStableTag.cs index 84be0c8466..bed6a33c93 100644 --- a/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/LastCommitOnTrunkWithStableTag.cs +++ b/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/LastCommitOnTrunkWithStableTag.cs @@ -30,7 +30,8 @@ public override IEnumerable GetIncrements( Increment = context.Increment, ForceIncrement = context.ForceIncrement, Label = context.Label, - AlternativeSemanticVersion = context.AlternativeSemanticVersions.Max() + AlternativeSemanticVersion = context.AlternativeSemanticVersions.Max(), + AlternativeSemVerSource = context.GetAlternativeSemVerSource() }; } } diff --git a/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/MergeCommitOnTrunkBase.cs b/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/MergeCommitOnTrunkBase.cs index b67abf05ef..b282bdb877 100644 --- a/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/MergeCommitOnTrunkBase.cs +++ b/src/GitVersion.Core/VersionCalculation/Mainline/Trunk/MergeCommitOnTrunkBase.cs @@ -52,11 +52,14 @@ IEnumerable GetIncrementsInternal() { context.BaseVersionSource = baseVersion.BaseVersionSource; context.SemanticVersion = baseVersion.SemanticVersion; + context.SemVerSource = baseVersion.GetBaselineSemVerSource(); context.ForceIncrement = baseVersion.Operator?.ForceIncrement ?? false; } else if (baseVersion.Operator?.AlternativeSemanticVersion is not null) { - context.AlternativeSemanticVersions.Add(baseVersion.Operator.AlternativeSemanticVersion); + context.AddAlternativeSemanticVersion(baseVersion.Operator.AlternativeSemanticVersion, + baseVersion.Operator.AlternativeSemVerSource ?? new SemanticVersionSource( + "Alternative semantic version", baseVersion.Operator.AlternativeSemanticVersion, null, VersionField.None)); } if (context.SemanticVersion is not null) @@ -65,7 +68,8 @@ IEnumerable GetIncrementsInternal() { Source = GetType().Name, BaseVersionSource = context.BaseVersionSource, - SemanticVersion = context.SemanticVersion.NotNull() + SemanticVersion = context.SemanticVersion.NotNull(), + SemVerSource = context.SemVerSource }; } @@ -76,7 +80,8 @@ IEnumerable GetIncrementsInternal() Increment = context.Increment, ForceIncrement = context.ForceIncrement, Label = context.Label, - AlternativeSemanticVersion = context.AlternativeSemanticVersions.Max() + AlternativeSemanticVersion = context.AlternativeSemanticVersions.Max(), + AlternativeSemVerSource = context.GetAlternativeSemVerSource() }; context.BaseVersionSource = commit.Value; diff --git a/src/GitVersion.Core/VersionCalculation/SemanticVersionSource.cs b/src/GitVersion.Core/VersionCalculation/SemanticVersionSource.cs new file mode 100644 index 0000000000..bf0b481719 --- /dev/null +++ b/src/GitVersion.Core/VersionCalculation/SemanticVersionSource.cs @@ -0,0 +1,16 @@ +using GitVersion.Git; + +namespace GitVersion.VersionCalculation; + +// An external source is represented by a source object with a null commit, not by a missing source object. +internal sealed record SemanticVersionSource(string Description, SemanticVersion Version, ICommit? Commit, VersionField Increment); + +// Keep the public IBaseVersion contract as the legacy calculation/counting view. +// The selected semantic source survives independently of the counting anchor. +internal sealed record ResolvedBaseVersion(IBaseVersion Candidate, SemanticVersionSource SemVerSource, ICommit? CommitCountSource) : IBaseVersion +{ + public string Source => Candidate.Source; + public SemanticVersion SemanticVersion => Candidate.SemanticVersion; + public VersionField Increment => VersionField.None; + public ICommit? BaseVersionSource => CommitCountSource; +} diff --git a/src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersionFormatValues.cs b/src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersionFormatValues.cs index 5835d2be2d..7f9d214210 100644 --- a/src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersionFormatValues.cs +++ b/src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersionFormatValues.cs @@ -74,7 +74,22 @@ public class SemanticVersionFormatValues(SemanticVersion semver, IGitVersionConf /// Gets the informational version string (SemVer + full build metadata). public string InformationalVersion => semver.ToString("i"); - /// Gets the semantic version of the source tag from which the version was calculated. + /// Gets the semantic baseline supplied by the selected artifact or derivation. + public string? SemVerSourceSemVer => semver.BuildMetaData.SemVerSourceSemVer?.ToString(); + + /// Gets the semantic source SHA, or null for external sources. + public string? SemVerSourceSha => semver.BuildMetaData.SemVerSourceSha; + + /// Gets the final increment relative to the semantic baseline. + public string SemVerSourceIncrement => semver.BuildMetaData.SemVerSourceIncrement.ToString(); + + /// Gets the nullable counting anchor SHA. + public string? CommitCountSourceSha => semver.BuildMetaData.CommitCountSourceSha; + + /// Gets the count of non-ignored commits beyond the counting anchor. + public string CommitCountSourceDistance => semver.BuildMetaData.CommitCountSourceDistance.ToString(CultureInfo.InvariantCulture); + + /// Gets the legacy semantic baseline, which may not correspond to VersionSourceSha. public string? VersionSourceSemVer => semver.BuildMetaData.VersionSourceSemVer?.ToString(); /// Gets the SHA of the source tag commit. diff --git a/src/GitVersion.Core/VersionCalculation/VariableProvider.cs b/src/GitVersion.Core/VersionCalculation/VariableProvider.cs index 9c5cdac4c6..6d5e5c9671 100644 --- a/src/GitVersion.Core/VersionCalculation/VariableProvider.cs +++ b/src/GitVersion.Core/VersionCalculation/VariableProvider.cs @@ -77,7 +77,12 @@ public GitVersionVariables GetVariablesFor( VersionSourceIncrement: semverFormatValues.VersionSourceIncrement, VersionSourceSemVer: semverFormatValues.VersionSourceSemVer, VersionSourceSha: semverFormatValues.VersionSourceSha, - WeightedPreReleaseNumber: semverFormatValues.WeightedPreReleaseNumber); + WeightedPreReleaseNumber: semverFormatValues.WeightedPreReleaseNumber) + { + SemVerSourceSemVer = semverFormatValues.SemVerSourceSemVer, + SemVerSourceSha = semverFormatValues.SemVerSourceSha, + SemVerSourceIncrement = semverFormatValues.SemVerSourceIncrement + }; } private string? CheckAndFormatString(string? formatString, T source, string? defaultValue, string formatVarName) where T : notnull diff --git a/src/GitVersion.Core/VersionCalculation/VersionCalculators/NextVersionCalculator.cs b/src/GitVersion.Core/VersionCalculation/VersionCalculators/NextVersionCalculator.cs index 91b7a6272b..af86e01cb0 100644 --- a/src/GitVersion.Core/VersionCalculation/VersionCalculators/NextVersionCalculator.cs +++ b/src/GitVersion.Core/VersionCalculation/VersionCalculators/NextVersionCalculator.cs @@ -86,16 +86,22 @@ public virtual SemanticVersion FindVersion() notOlderThan: Context.CurrentCommit.When ).Where(element => element.Key.When <= Context.CurrentCommit.When && !(element.Key.When <= ignore.Before) && !ignore.Shas.Contains(element.Key.Sha) - ).SelectMany(element => element).Max()?.Value; + ).SelectMany(element => element).Max(); if (alternativeSemanticVersion is not null - && semanticVersion.IsLessThan(alternativeSemanticVersion, includePreRelease: false)) + && semanticVersion.IsLessThan(alternativeSemanticVersion.Value, includePreRelease: false)) { semanticVersion = new SemanticVersion(semanticVersion) { - Major = alternativeSemanticVersion.Major, - Minor = alternativeSemanticVersion.Minor, - Patch = alternativeSemanticVersion.Patch + Major = alternativeSemanticVersion.Value.Major, + Minor = alternativeSemanticVersion.Value.Minor, + Patch = alternativeSemanticVersion.Value.Patch, + BuildMetaData = new SemanticVersionBuildMetaData(semanticVersion.BuildMetaData) + { + SemVerSourceSemVer = alternativeSemanticVersion.Value, + SemVerSourceSha = alternativeSemanticVersion.Tag.Commit.Sha, + SemVerSourceIncrement = VersionField.None + } }; } @@ -127,7 +133,12 @@ private bool TryGetSemanticVersion( commitShortSha: Context.CurrentCommit.Id.ToString(7), commitDate: Context.CurrentCommit.When, numberOfUnCommittedChanges: Context.NumberOfUncommittedChanges, - versionSourceIncrement: VersionField.None); + versionSourceIncrement: VersionField.None) + { + SemVerSourceSemVer = currentCommitTaggedVersion.Value, + SemVerSourceSha = Context.CurrentCommit.Sha, + SemVerSourceIncrement = VersionField.None + }; var preReleaseTag = currentCommitTaggedVersion.Value.PreReleaseTag; if (effectiveConfiguration.DeploymentMode == DeploymentMode.ContinuousDeployment) @@ -165,7 +176,7 @@ private NextVersion CalculateNextVersion(IBranch branch, IGitVersionConfiguratio var maxVersion = nextVersions.Max() ?? throw new GitVersionException("No base versions determined on the current branch."); - ICommit? latestBaseVersionSource; + ICommit? commitCountSource; var matchingVersionsOnceIncremented = nextVersions .Where( @@ -175,7 +186,7 @@ private NextVersion CalculateNextVersion(IBranch branch, IGitVersionConfiguratio if (matchingVersionsOnceIncremented.Length > 1) { var latestVersion = matchingVersionsOnceIncremented.Aggregate(CompareVersions); - latestBaseVersionSource = latestVersion.BaseVersion.BaseVersionSource; + commitCountSource = latestVersion.BaseVersion.BaseVersionSource; maxVersion = latestVersion; this.logger.LogInformation( "Found multiple base versions which will produce the same SemVer ({IncrementedVersion}), " + @@ -202,20 +213,18 @@ private NextVersion CalculateNextVersion(IBranch branch, IGitVersionConfiguratio version ??= versions.Where(v => v.BaseVersion.BaseVersionSource == null) .OrderByDescending(v => v.IncrementedVersion) .First(); - latestBaseVersionSource = version.BaseVersion.BaseVersionSource; + commitCountSource = version.BaseVersion.BaseVersionSource; } - BaseVersion calculatedBase = new() - { - Operand = new BaseVersionOperand - { - Source = maxVersion.BaseVersion.Source, - BaseVersionSource = latestBaseVersionSource, - SemanticVersion = maxVersion.BaseVersion.SemanticVersion - } - }; + var semVerSource = maxVersion.BaseVersion is BaseVersion candidate + ? candidate.GetSemVerSource() + : new SemanticVersionSource(maxVersion.BaseVersion.Source, maxVersion.BaseVersion.SemanticVersion, + maxVersion.BaseVersion.BaseVersionSource, maxVersion.BaseVersion.Increment); + ResolvedBaseVersion calculatedBase = new(maxVersion.BaseVersion, semVerSource, commitCountSource); - this.logger.LogInformation("Base version used: {BaseVersion}", calculatedBase); + this.logger.LogInformation("Semantic version source: {Source}, version {Version}, commit {Commit}", + semVerSource.Description, semVerSource.Version, semVerSource.Commit?.Sha ?? "External"); + this.logger.LogInformation("Commit count source: {Commit}", commitCountSource?.Sha ?? "All reachable history"); this.logger.LogSeparator(); return new(maxVersion.IncrementedVersion, calculatedBase, maxVersion.BranchConfiguration); diff --git a/src/GitVersion.Core/VersionCalculation/VersionCalculators/VersionCalculatorBase.cs b/src/GitVersion.Core/VersionCalculation/VersionCalculators/VersionCalculatorBase.cs index ce2e5a0950..b509b699d7 100644 --- a/src/GitVersion.Core/VersionCalculation/VersionCalculators/VersionCalculatorBase.cs +++ b/src/GitVersion.Core/VersionCalculation/VersionCalculators/VersionCalculatorBase.cs @@ -13,26 +13,37 @@ internal abstract class VersionCalculatorBase( protected SemanticVersionBuildMetaData CreateVersionBuildMetaData(IBaseVersion baseVersion) { + var semVerSource = baseVersion switch + { + ResolvedBaseVersion resolved => resolved.SemVerSource, + BaseVersion candidate => candidate.GetSemVerSource(), + _ => new SemanticVersionSource(baseVersion.Source, baseVersion.SemanticVersion, baseVersion.BaseVersionSource, baseVersion.Increment) + }; var commitLogs = this.repositoryStore.GetCommitLog( baseVersionSource: baseVersion.BaseVersionSource, currentCommit: Context.CurrentCommit, ignore: Context.Configuration.Ignore ); - var commitsSinceTag = commitLogs.Count; - this.logger.LogInformation("{CommitsSinceTag} commits found between {BaseVersionSource} and {CurrentCommit}", commitsSinceTag, baseVersion.BaseVersionSource, Context.CurrentCommit); + var commitCount = commitLogs.Count; + this.logger.LogInformation("{CommitCount} commits found between {CommitCountSource} and {CurrentCommit}", commitCount, baseVersion.BaseVersionSource, Context.CurrentCommit); var shortSha = Context.CurrentCommit.Id.ToString(7); return new SemanticVersionBuildMetaData( versionSourceSemVer: baseVersion.SemanticVersion, versionSourceSha: baseVersion.BaseVersionSource?.Sha, - commitsSinceTag: commitsSinceTag, + commitsSinceTag: commitCount, branch: Context.CurrentBranch.Name.Friendly, commitSha: Context.CurrentCommit.Sha, commitShortSha: shortSha, commitDate: Context.CurrentCommit.When, numberOfUnCommittedChanges: Context.NumberOfUncommittedChanges, versionSourceIncrement: baseVersion.Increment - ); + ) + { + SemVerSourceSemVer = semVerSource.Version, + SemVerSourceSha = semVerSource.Commit?.Sha, + SemVerSourceIncrement = semVerSource.Increment + }; } } diff --git a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/BaseVersion.cs b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/BaseVersion.cs index 66df93ec69..66ce885db2 100644 --- a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/BaseVersion.cs +++ b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/BaseVersion.cs @@ -40,6 +40,26 @@ public BaseVersion(string source, SemanticVersion semanticVersion, ICommit? base /// Gets or initializes the optional operator that describes the increment to apply. public BaseVersionOperator? Operator { get; init; } + internal SemanticVersionSource? SemVerSource { get; init; } + + internal SemanticVersionSource GetBaselineSemVerSource() + => (SemVerSource ?? Operand.SemVerSource) is { } origin + ? origin with { Version = SemanticVersion, Increment = Increment } + : new SemanticVersionSource(Operand.Source, SemanticVersion, Operand.BaseVersionSource, Increment); + + internal SemanticVersionSource GetSemVerSource() + { + if (Operator?.AlternativeSemanticVersion is { } alternative + && SemanticVersion.Increment(Operator.Increment, Operator.Label, Operator.ForceIncrement) + .IsLessThan(alternative, includePreRelease: false)) + { + return Operator.AlternativeSemVerSource + ?? new SemanticVersionSource("Alternative semantic version", alternative, null, VersionField.None); + } + + return GetBaselineSemVerSource(); + } + /// Returns the semantic version after applying the operator increment, or the base version when no increment is needed. public SemanticVersion GetIncrementedVersion() { @@ -100,6 +120,7 @@ internal BaseVersion Apply(BaseVersionOperator baseVersionOperator) return new BaseVersion(Source, GetIncrementedVersion(), BaseVersionSource) { + SemVerSource = GetSemVerSource(), Operator = baseVersionOperator }; } diff --git a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/BaseVersionOperand.cs b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/BaseVersionOperand.cs index 877594d4c4..a3ad0f2df0 100644 --- a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/BaseVersionOperand.cs +++ b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/BaseVersionOperand.cs @@ -18,6 +18,8 @@ public BaseVersionOperand() : this(string.Empty, SemanticVersion.Empty) /// Gets or initializes the discovered semantic version. public SemanticVersion SemanticVersion { get; init; } = SemanticVersion.NotNull(); + internal SemanticVersionSource? SemVerSource { get; init; } + /// Returns a human-readable description of this operand including its source and version. public override string ToString() { diff --git a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/BaseVersionOperator.cs b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/BaseVersionOperator.cs index 084d525ec4..91e0a99b1a 100644 --- a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/BaseVersionOperator.cs +++ b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/BaseVersionOperator.cs @@ -23,6 +23,8 @@ public sealed record BaseVersionOperator : IBaseVersionIncrement /// Gets or initializes an alternative semantic version that may be used instead when it is greater than the incremented version. public SemanticVersion? AlternativeSemanticVersion { get; init; } + internal SemanticVersionSource? AlternativeSemVerSource { get; init; } + /// Returns a human-readable description of this operator including source, increment field, label, and commit anchor. public override string ToString() { diff --git a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/MergeMessageVersionStrategy.cs b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/MergeMessageVersionStrategy.cs index e352242caa..5ecda56eb8 100644 --- a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/MergeMessageVersionStrategy.cs +++ b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/MergeMessageVersionStrategy.cs @@ -5,7 +5,7 @@ namespace GitVersion.VersionCalculation; /// /// Version is extracted from older commits' merge messages. -/// BaseVersionSource is the commit where the message was found. +/// Semantic provenance is the commit containing the message; counting and increment scans are selected independently. /// Increments if PreventIncrementOfMergedBranchVersion (from the branch configuration) is false. /// internal sealed class MergeMessageVersionStrategy(ILogger logger, Lazy contextLazy, @@ -62,6 +62,7 @@ private IEnumerable GetBaseVersionsInternal(EffectiveBranchConfigur yield return new BaseVersion($"Merge message '{commit.Message.Trim()}'", mergeMessage.Version) { + SemVerSource = new SemanticVersionSource($"Merge message '{commit.Message.Trim()}'", mergeMessage.Version, commit, increment), Operator = new() { Increment = increment, diff --git a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/TaggedCommitVersionStrategy.cs b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/TaggedCommitVersionStrategy.cs index 0668e999ce..0f8da4af8e 100644 --- a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/TaggedCommitVersionStrategy.cs +++ b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/TaggedCommitVersionStrategy.cs @@ -56,7 +56,8 @@ private IEnumerable GetBaseVersionsInternal(EffectiveBranchConfigur continue; } - var alternativeSemanticVersionMax = alternativeSemanticVersionsWithTag.Max()?.Value; + var alternativeTag = alternativeSemanticVersionsWithTag.Max(); + var alternativeSemanticVersionMax = alternativeTag?.Value; var highestPossibleSemanticVersion = semanticVersion.Value.Increment( VersionField.Major, null, forceIncrement: true, alternativeSemanticVersionMax ); @@ -88,7 +89,9 @@ private IEnumerable GetBaseVersionsInternal(EffectiveBranchConfigur Increment = increment, ForceIncrement = false, Label = label, - AlternativeSemanticVersion = alternativeSemanticVersionMax + AlternativeSemanticVersion = alternativeSemanticVersionMax, + AlternativeSemVerSource = alternativeTag is null ? null : new SemanticVersionSource( + $"Git tag '{alternativeTag.Tag.Name.Friendly}'", alternativeTag.Value, alternativeTag.Tag.Commit, VersionField.None) } }; alternativeSemanticVersionsWithTag.Clear(); diff --git a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/TrackReleaseBranchesVersionStrategy.cs b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/TrackReleaseBranchesVersionStrategy.cs index 2cf4eeac8a..bba233ff60 100644 --- a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/TrackReleaseBranchesVersionStrategy.cs +++ b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/TrackReleaseBranchesVersionStrategy.cs @@ -79,6 +79,7 @@ private bool TryGetBaseVersion( result = new BaseVersion( "Release branch exists -> " + baseVersion.Source, baseVersion.SemanticVersion, baseVersionSource) { + SemVerSource = baseVersion.GetBaselineSemVerSource(), Operator = new BaseVersionOperator { Increment = increment, @@ -133,7 +134,11 @@ private bool TryGetTaggedBaseVersion( // advances the minor instead of only changing the prerelease label or number. var version = tag.Value; result = new BaseVersion($"Version in release branch tag '{tag.Tag.Name.Friendly}'", - new SemanticVersion(version.Major, version.Minor, version.Patch)); + new SemanticVersion(version.Major, version.Minor, version.Patch)) + { + SemVerSource = new SemanticVersionSource($"Git tag '{tag.Tag.Name.Friendly}'", + version, tag.Tag.Commit, VersionField.None) + }; return true; } diff --git a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/VersionInBranchNameVersionStrategy.cs b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/VersionInBranchNameVersionStrategy.cs index ef2cb644eb..cd08844fb7 100644 --- a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/VersionInBranchNameVersionStrategy.cs +++ b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/VersionInBranchNameVersionStrategy.cs @@ -6,7 +6,7 @@ namespace GitVersion.VersionCalculation; /// /// Version is extracted from the name of the branch. -/// BaseVersionSource is the commit where the branch was branched from its parent. +/// The semantic source is the branch name and has no intrinsic source commit. /// Does not increment. /// internal sealed class VersionInBranchNameVersionStrategy(Lazy contextLazy, IEnvironment environment) : IVersionStrategy diff --git a/src/GitVersion.MsBuild.Tests/Tasks/GetVersionTaskTests.cs b/src/GitVersion.MsBuild.Tests/Tasks/GetVersionTaskTests.cs index 3ad602348f..5f52a021cf 100644 --- a/src/GitVersion.MsBuild.Tests/Tasks/GetVersionTaskTests.cs +++ b/src/GitVersion.MsBuild.Tests/Tasks/GetVersionTaskTests.cs @@ -41,6 +41,11 @@ public void GetVersionTaskShouldReturnVersionOutputVariables() result.Task.PreReleaseLabel.ShouldBe("1"); result.Task.PreReleaseLabelWithDash.ShouldBe("-1"); result.Task.FullSemVer.ShouldBe("1.2.4-1"); + result.Task.SemVerSourceSemVer.ShouldBe("1.2.3"); + result.Task.SemVerSourceIncrement.ShouldBe("Patch"); + result.Task.SemVerSourceSha.ShouldBe(result.Task.VersionSourceSha); + result.Task.CommitCountSourceSha.ShouldBe(result.Task.VersionSourceSha); + result.Task.CommitCountSourceDistance.ShouldBe("1"); } [Test] @@ -69,6 +74,9 @@ public void GetVersionTaskShouldReturnVersionOutputVariablesForBuildServer() [TestCase(nameof(GitVersionVariables.Patch), "4")] [TestCase(nameof(GitVersionVariables.MajorMinorPatch), "1.2.4")] [TestCase(nameof(GitVersionVariables.FullSemVer), "1.2.4-1")] + [TestCase(nameof(GitVersionVariables.SemVerSourceSemVer), "1.2.3")] + [TestCase(nameof(GitVersionVariables.SemVerSourceIncrement), "Patch")] + [TestCase(nameof(GitVersionVariables.CommitCountSourceDistance), "1")] public void GetVersionTaskShouldReturnVersionOutputVariablesWhenRunWithMsBuild(string outputProperty, string version) { const string taskName = nameof(GetVersion); diff --git a/src/GitVersion.MsBuild/PublicAPI.Unshipped.txt b/src/GitVersion.MsBuild/PublicAPI.Unshipped.txt index 7d8ec75e7f..d80c05e5f0 100644 --- a/src/GitVersion.MsBuild/PublicAPI.Unshipped.txt +++ b/src/GitVersion.MsBuild/PublicAPI.Unshipped.txt @@ -1,3 +1,13 @@ #nullable enable +GitVersion.MsBuild.Tasks.GetVersion.CommitCountSourceDistance.get -> string! +GitVersion.MsBuild.Tasks.GetVersion.CommitCountSourceDistance.set -> void +GitVersion.MsBuild.Tasks.GetVersion.CommitCountSourceSha.get -> string! +GitVersion.MsBuild.Tasks.GetVersion.CommitCountSourceSha.set -> void +GitVersion.MsBuild.Tasks.GetVersion.SemVerSourceIncrement.get -> string! +GitVersion.MsBuild.Tasks.GetVersion.SemVerSourceIncrement.set -> void +GitVersion.MsBuild.Tasks.GetVersion.SemVerSourceSemVer.get -> string! +GitVersion.MsBuild.Tasks.GetVersion.SemVerSourceSemVer.set -> void +GitVersion.MsBuild.Tasks.GetVersion.SemVerSourceSha.get -> string! +GitVersion.MsBuild.Tasks.GetVersion.SemVerSourceSha.set -> void GitVersion.MsBuild.Tasks.GetVersion.CustomVersion.get -> string! GitVersion.MsBuild.Tasks.GetVersion.CustomVersion.set -> void diff --git a/src/GitVersion.MsBuild/Tasks/GetVersion.cs b/src/GitVersion.MsBuild/Tasks/GetVersion.cs index 4582055bdc..e4049573f7 100644 --- a/src/GitVersion.MsBuild/Tasks/GetVersion.cs +++ b/src/GitVersion.MsBuild/Tasks/GetVersion.cs @@ -16,6 +16,21 @@ public class GetVersion : GitVersionTaskBase [Output] public string BuildMetaData { get; set; } = null!; + [Output] + public string CommitCountSourceDistance { get; set; } = null!; + + [Output] + public string CommitCountSourceSha { get; set; } = null!; + + [Output] + public string SemVerSourceIncrement { get; set; } = null!; + + [Output] + public string SemVerSourceSemVer { get; set; } = null!; + + [Output] + public string SemVerSourceSha { get; set; } = null!; + [Output] public string CommitDate { get; set; } = null!; diff --git a/src/GitVersion.MsBuild/msbuild/tools/GitVersion.MsBuild.targets b/src/GitVersion.MsBuild/msbuild/tools/GitVersion.MsBuild.targets index c7351733a1..3a21e79b36 100644 --- a/src/GitVersion.MsBuild/msbuild/tools/GitVersion.MsBuild.targets +++ b/src/GitVersion.MsBuild/msbuild/tools/GitVersion.MsBuild.targets @@ -59,6 +59,11 @@ + + + + + @@ -101,6 +106,11 @@ GitVersion_Sha=$(GitVersion_Sha);$(DefineConstants) GitVersion_ShortSha=$(GitVersion_ShortSha);$(DefineConstants) GitVersion_UncommittedChanges=$(GitVersion_UncommittedChanges);$(DefineConstants) + GitVersion_CommitCountSourceDistance=$(GitVersion_CommitCountSourceDistance);$(DefineConstants) + GitVersion_CommitCountSourceSha=$(GitVersion_CommitCountSourceSha);$(DefineConstants) + GitVersion_SemVerSourceIncrement=$(GitVersion_SemVerSourceIncrement);$(DefineConstants) + GitVersion_SemVerSourceSemVer=$(GitVersion_SemVerSourceSemVer);$(DefineConstants) + GitVersion_SemVerSourceSha=$(GitVersion_SemVerSourceSha);$(DefineConstants) GitVersion_VersionSourceDistance=$(GitVersion_VersionSourceDistance);$(DefineConstants) GitVersion_VersionSourceIncrement=$(GitVersion_VersionSourceIncrement);$(DefineConstants) GitVersion_VersionSourceSemVer=$(GitVersion_VersionSourceSemVer);$(DefineConstants) diff --git a/src/GitVersion.Output.Tests/Output/Approved/WixFileTests.UpdateWixVersionFile.approved.txt b/src/GitVersion.Output.Tests/Output/Approved/WixFileTests.UpdateWixVersionFile.approved.txt index 959a63a98c..1f65b55cb1 100644 --- a/src/GitVersion.Output.Tests/Output/Approved/WixFileTests.UpdateWixVersionFile.approved.txt +++ b/src/GitVersion.Output.Tests/Output/Approved/WixFileTests.UpdateWixVersionFile.approved.txt @@ -4,6 +4,8 @@ + + @@ -20,6 +22,9 @@ + + + diff --git a/src/GitVersion.Output.Tests/Output/Approved/WixFileTests.UpdateWixVersionFileWhenFileAlreadyExists.approved.txt b/src/GitVersion.Output.Tests/Output/Approved/WixFileTests.UpdateWixVersionFileWhenFileAlreadyExists.approved.txt index 959a63a98c..1f65b55cb1 100644 --- a/src/GitVersion.Output.Tests/Output/Approved/WixFileTests.UpdateWixVersionFileWhenFileAlreadyExists.approved.txt +++ b/src/GitVersion.Output.Tests/Output/Approved/WixFileTests.UpdateWixVersionFileWhenFileAlreadyExists.approved.txt @@ -4,6 +4,8 @@ + + @@ -20,6 +22,9 @@ + + + diff --git a/src/GitVersion.Output.Tests/Output/Approved/cs/GitVersionInfoGeneratorTests.ShouldCreateFile.approved.txt b/src/GitVersion.Output.Tests/Output/Approved/cs/GitVersionInfoGeneratorTests.ShouldCreateFile.approved.txt index 415275856c..d1350e0a47 100644 --- a/src/GitVersion.Output.Tests/Output/Approved/cs/GitVersionInfoGeneratorTests.ShouldCreateFile.approved.txt +++ b/src/GitVersion.Output.Tests/Output/Approved/cs/GitVersionInfoGeneratorTests.ShouldCreateFile.approved.txt @@ -16,6 +16,8 @@ static class GitVersionInformation public const string AssemblySemVer = "1.2.3.0"; public const string BranchName = "feature1"; public const string BuildMetaData = "5"; + public const string CommitCountSourceDistance = "5"; + public const string CommitCountSourceSha = "versionSourceSha"; public const string CommitDate = "2014-03-06"; public const string CustomVersion = ""; public const string EscapedBranchName = "feature1"; @@ -32,6 +34,9 @@ static class GitVersionInformation public const string PreReleaseLabelWithDash = "-unstable.4"; public const string PreReleaseNumber = "4"; public const string SemVer = "1.2.3-unstable.4"; + public const string SemVerSourceIncrement = "None"; + public const string SemVerSourceSemVer = ""; + public const string SemVerSourceSha = ""; public const string Sha = "commitSha"; public const string ShortSha = "commitShortSha"; public const string UncommittedChanges = "0"; diff --git a/src/GitVersion.Output.Tests/Output/Approved/cs/GitVersionInfoGeneratorTests.ShouldProperlyOutputNamespaceDeclaration.approved.txt b/src/GitVersion.Output.Tests/Output/Approved/cs/GitVersionInfoGeneratorTests.ShouldProperlyOutputNamespaceDeclaration.approved.txt index 1ca3823c1c..0fb547c54b 100644 --- a/src/GitVersion.Output.Tests/Output/Approved/cs/GitVersionInfoGeneratorTests.ShouldProperlyOutputNamespaceDeclaration.approved.txt +++ b/src/GitVersion.Output.Tests/Output/Approved/cs/GitVersionInfoGeneratorTests.ShouldProperlyOutputNamespaceDeclaration.approved.txt @@ -18,6 +18,8 @@ namespace My.Custom.Namespace public const string AssemblySemVer = "1.2.3.0"; public const string BranchName = "feature1"; public const string BuildMetaData = "5"; + public const string CommitCountSourceDistance = "5"; + public const string CommitCountSourceSha = "versionSourceSha"; public const string CommitDate = "2014-03-06"; public const string CustomVersion = ""; public const string EscapedBranchName = "feature1"; @@ -34,6 +36,9 @@ namespace My.Custom.Namespace public const string PreReleaseLabelWithDash = "-unstable.4"; public const string PreReleaseNumber = "4"; public const string SemVer = "1.2.3-unstable.4"; + public const string SemVerSourceIncrement = "None"; + public const string SemVerSourceSemVer = ""; + public const string SemVerSourceSha = ""; public const string Sha = "commitSha"; public const string ShortSha = "commitShortSha"; public const string UncommittedChanges = "0"; diff --git a/src/GitVersion.Output.Tests/Output/Approved/fs/GitVersionInfoGeneratorTests.ShouldCreateFile.approved.txt b/src/GitVersion.Output.Tests/Output/Approved/fs/GitVersionInfoGeneratorTests.ShouldCreateFile.approved.txt index 7f0c46a603..804d2166e3 100644 --- a/src/GitVersion.Output.Tests/Output/Approved/fs/GitVersionInfoGeneratorTests.ShouldCreateFile.approved.txt +++ b/src/GitVersion.Output.Tests/Output/Approved/fs/GitVersionInfoGeneratorTests.ShouldCreateFile.approved.txt @@ -18,6 +18,8 @@ type GitVersionInformation = static member AssemblySemVer = "1.2.3.0" static member BranchName = "feature1" static member BuildMetaData = "5" + static member CommitCountSourceDistance = "5" + static member CommitCountSourceSha = "versionSourceSha" static member CommitDate = "2014-03-06" static member CustomVersion = "" static member EscapedBranchName = "feature1" @@ -34,6 +36,9 @@ type GitVersionInformation = static member PreReleaseLabelWithDash = "-unstable.4" static member PreReleaseNumber = "4" static member SemVer = "1.2.3-unstable.4" + static member SemVerSourceIncrement = "None" + static member SemVerSourceSemVer = "" + static member SemVerSourceSha = "" static member Sha = "commitSha" static member ShortSha = "commitShortSha" static member UncommittedChanges = "0" diff --git a/src/GitVersion.Output.Tests/Output/Approved/fs/GitVersionInfoGeneratorTests.ShouldProperlyOutputNamespaceDeclaration.approved.txt b/src/GitVersion.Output.Tests/Output/Approved/fs/GitVersionInfoGeneratorTests.ShouldProperlyOutputNamespaceDeclaration.approved.txt index 3d71f6644e..b44b8078a9 100644 --- a/src/GitVersion.Output.Tests/Output/Approved/fs/GitVersionInfoGeneratorTests.ShouldProperlyOutputNamespaceDeclaration.approved.txt +++ b/src/GitVersion.Output.Tests/Output/Approved/fs/GitVersionInfoGeneratorTests.ShouldProperlyOutputNamespaceDeclaration.approved.txt @@ -18,6 +18,8 @@ type GitVersionInformation = static member AssemblySemVer = "1.2.3.0" static member BranchName = "feature1" static member BuildMetaData = "5" + static member CommitCountSourceDistance = "5" + static member CommitCountSourceSha = "versionSourceSha" static member CommitDate = "2014-03-06" static member CustomVersion = "" static member EscapedBranchName = "feature1" @@ -34,6 +36,9 @@ type GitVersionInformation = static member PreReleaseLabelWithDash = "-unstable.4" static member PreReleaseNumber = "4" static member SemVer = "1.2.3-unstable.4" + static member SemVerSourceIncrement = "None" + static member SemVerSourceSemVer = "" + static member SemVerSourceSha = "" static member Sha = "commitSha" static member ShortSha = "commitShortSha" static member UncommittedChanges = "0" diff --git a/src/GitVersion.Output.Tests/Output/Approved/vb/GitVersionInfoGeneratorTests.ShouldCreateFile.approved.txt b/src/GitVersion.Output.Tests/Output/Approved/vb/GitVersionInfoGeneratorTests.ShouldCreateFile.approved.txt index 0c58687225..3768e2b4c4 100644 --- a/src/GitVersion.Output.Tests/Output/Approved/vb/GitVersionInfoGeneratorTests.ShouldCreateFile.approved.txt +++ b/src/GitVersion.Output.Tests/Output/Approved/vb/GitVersionInfoGeneratorTests.ShouldCreateFile.approved.txt @@ -19,6 +19,8 @@ Namespace Global Public Shared AssemblySemVer As String = "1.2.3.0" Public Shared BranchName As String = "feature1" Public Shared BuildMetaData As String = "5" + Public Shared CommitCountSourceDistance As String = "5" + Public Shared CommitCountSourceSha As String = "versionSourceSha" Public Shared CommitDate As String = "2014-03-06" Public Shared CustomVersion As String = "" Public Shared EscapedBranchName As String = "feature1" @@ -35,6 +37,9 @@ Namespace Global Public Shared PreReleaseLabelWithDash As String = "-unstable.4" Public Shared PreReleaseNumber As String = "4" Public Shared SemVer As String = "1.2.3-unstable.4" + Public Shared SemVerSourceIncrement As String = "None" + Public Shared SemVerSourceSemVer As String = "" + Public Shared SemVerSourceSha As String = "" Public Shared Sha As String = "commitSha" Public Shared ShortSha As String = "commitShortSha" Public Shared UncommittedChanges As String = "0" diff --git a/src/GitVersion.Output.Tests/Output/Approved/vb/GitVersionInfoGeneratorTests.ShouldProperlyOutputNamespaceDeclaration.approved.txt b/src/GitVersion.Output.Tests/Output/Approved/vb/GitVersionInfoGeneratorTests.ShouldProperlyOutputNamespaceDeclaration.approved.txt index df357f7686..e7106b916f 100644 --- a/src/GitVersion.Output.Tests/Output/Approved/vb/GitVersionInfoGeneratorTests.ShouldProperlyOutputNamespaceDeclaration.approved.txt +++ b/src/GitVersion.Output.Tests/Output/Approved/vb/GitVersionInfoGeneratorTests.ShouldProperlyOutputNamespaceDeclaration.approved.txt @@ -19,6 +19,8 @@ Namespace My.Custom.Namespace Public Shared AssemblySemVer As String = "1.2.3.0" Public Shared BranchName As String = "feature1" Public Shared BuildMetaData As String = "5" + Public Shared CommitCountSourceDistance As String = "5" + Public Shared CommitCountSourceSha As String = "versionSourceSha" Public Shared CommitDate As String = "2014-03-06" Public Shared CustomVersion As String = "" Public Shared EscapedBranchName As String = "feature1" @@ -35,6 +37,9 @@ Namespace My.Custom.Namespace Public Shared PreReleaseLabelWithDash As String = "-unstable.4" Public Shared PreReleaseNumber As String = "4" Public Shared SemVer As String = "1.2.3-unstable.4" + Public Shared SemVerSourceIncrement As String = "None" + Public Shared SemVerSourceSemVer As String = "" + Public Shared SemVerSourceSha As String = "" Public Shared Sha As String = "commitSha" Public Shared ShortSha As String = "commitShortSha" Public Shared UncommittedChanges As String = "0" diff --git a/src/GitVersion.Output/Serializer/SourceVariableJsonConverter.cs b/src/GitVersion.Output/Serializer/SourceVariableJsonConverter.cs new file mode 100644 index 0000000000..6101c01bac --- /dev/null +++ b/src/GitVersion.Output/Serializer/SourceVariableJsonConverter.cs @@ -0,0 +1,11 @@ +namespace GitVersion.OutputVariables; + +// Legacy string variables serialize null as "". Source variables explicitly represent an external source as JSON null. +internal sealed class SourceVariableJsonConverter : JsonConverter +{ + public override string? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + => reader.GetString(); + + public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) + => writer.WriteStringValue(value); +} diff --git a/src/GitVersion.Output/Serializer/VersionVariableSerializer.cs b/src/GitVersion.Output/Serializer/VersionVariableSerializer.cs index 7d2249e9ce..cfea5a6405 100644 --- a/src/GitVersion.Output/Serializer/VersionVariableSerializer.cs +++ b/src/GitVersion.Output/Serializer/VersionVariableSerializer.cs @@ -66,18 +66,26 @@ public void ToFile(GitVersionVariables gitVersionVariables, string filePath) private static GitVersionVariables FromDictionary(IEnumerable>? properties) { + var values = properties?.ToDictionary(pair => pair.Key, pair => pair.Value, StringComparer.InvariantCultureIgnoreCase); var type = typeof(GitVersionVariables); var constructors = type.GetConstructors(); var ctor = constructors.Single(); var ctorArgs = ctor.GetParameters() - .Select(p => properties?.Single(v => string.Equals(v.Key, p.Name, StringComparison.InvariantCultureIgnoreCase)).Value) + .Select(p => values?[p.Name!]) .Cast() .ToArray(); var instance = Activator.CreateInstance(type, ctorArgs).NotNull(); - return (GitVersionVariables)instance; + return (GitVersionVariables)instance with + { + SemVerSourceSemVer = NullIfEmpty(values?.GetValueOrDefault(nameof(GitVersionVariables.SemVerSourceSemVer))), + SemVerSourceSha = NullIfEmpty(values?.GetValueOrDefault(nameof(GitVersionVariables.SemVerSourceSha))), + SemVerSourceIncrement = NullIfEmpty(values?.GetValueOrDefault(nameof(GitVersionVariables.SemVerSourceIncrement))) + }; } + private static string? NullIfEmpty(string? value) => string.IsNullOrEmpty(value) ? null : value; + private GitVersionVariables FromFileInternal(string filePath) { var json = fileSystem.File.ReadAllText(filePath); diff --git a/src/GitVersion.Output/Serializer/VersionVariablesJsonModel.cs b/src/GitVersion.Output/Serializer/VersionVariablesJsonModel.cs index fce35e8ca1..c8063b8475 100644 --- a/src/GitVersion.Output/Serializer/VersionVariablesJsonModel.cs +++ b/src/GitVersion.Output/Serializer/VersionVariablesJsonModel.cs @@ -13,9 +13,16 @@ internal class VersionVariablesJsonModel [JsonPropertyDescription("The name of the checked out Git branch.")] public string? BranchName { get; set; } - [JsonPropertyDescription("The build metadata, usually representing number of commits since the VersionSourceSha.")] + [JsonPropertyDescription("The build metadata, usually representing number of commits since the CommitCountSourceSha.")] public int? BuildMetaData { get; set; } + [JsonPropertyDescription("The number of non-ignored commits reachable from HEAD but not from the counting anchor.")] + public long? CommitCountSourceDistance { get; set; } + + [JsonPropertyDescription("The commit used as the counting anchor, or null when counting all reachable history.")] + [JsonConverter(typeof(SourceVariableJsonConverter))] + public string? CommitCountSourceSha { get; set; } + [JsonPropertyDescription("The ISO-8601 formatted date of the commit identified by Sha.")] public string? CommitDate { get; set; } @@ -64,6 +71,18 @@ internal class VersionVariablesJsonModel [JsonPropertyDescription("The semantic version number, including PreReleaseLabelWithDash for pre-release version numbers.")] public string? SemVer { get; set; } + [JsonPropertyDescription("The final increment relative to the semantic baseline: None, Patch, Minor or Major.")] + [JsonConverter(typeof(SourceVariableJsonConverter))] + public string? SemVerSourceIncrement { get; set; } + + [JsonPropertyDescription("The semantic baseline supplied by the selected artifact or derivation.")] + [JsonConverter(typeof(SourceVariableJsonConverter))] + public string? SemVerSourceSemVer { get; set; } + + [JsonPropertyDescription("The semantic source commit SHA, or null for external sources such as configuration or a branch name.")] + [JsonConverter(typeof(SourceVariableJsonConverter))] + public string? SemVerSourceSha { get; set; } + [JsonPropertyDescription("The SHA of the Git commit.")] public string? Sha { get; set; } @@ -73,16 +92,16 @@ internal class VersionVariablesJsonModel [JsonPropertyDescription("The number of uncommitted changes present in the repository.")] public int? UncommittedChanges { get; set; } - [JsonPropertyDescription("The number of commits since the version source.")] + [JsonPropertyDescription("Compatibility alias for CommitCountSourceDistance.")] public int? VersionSourceDistance { get; set; } [JsonPropertyDescription("The increment strategy used for the version calculation. Possible values: None, Patch, Minor, Major.")] public string? VersionSourceIncrement { get; set; } - [JsonPropertyDescription("The semantic version of the commit used as version source.")] + [JsonPropertyDescription("Legacy semantic baseline; it need not come from VersionSourceSha. Prefer SemVerSourceSemVer.")] public string? VersionSourceSemVer { get; set; } - [JsonPropertyDescription("The SHA of the commit used as version source.")] + [JsonPropertyDescription("Compatibility alias for CommitCountSourceSha.")] public string? VersionSourceSha { get; set; } [JsonPropertyDescription("A summation of branch specific pre-release-weight and the PreReleaseNumber. Can be used to obtain a monotonically increasing version number across the branches.")]