So, I have a list of versions that looks like this:
v1.1.0
v1.2.0
v1.3.0
v1.4.0
v1.5.0
v1.7.0
v1.8.0
v1.9.0
v2.0.0
v2.1.0
v2.10.0
v2.11.0
v2.12.0
v2.2.0
v2.3.0
v2.4.0
v2.5.0
v2.6.0
v2.7.0
v2.8.0
v2.9.0
The problem is, they are ordered incorrectly. I am new to Powershell, so I am having some issues trying to sort them. I tried to do this:
$tags = git tag
$versions = $tags | %{ new-object System.Version ($_) } | sort
But I get this error:
new-object : Exception calling ".ctor" with "1" argument(s): "Version string portion was too short or too long." At line:1 char:24 + $versions = $tags | %{ new-object System.Version ($_) } | sort + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [New-Object], MethodInvocationException + FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
Can anyone help?
Update
I have used one of the solutions which looks like this:
$location = Get-Location
$path = $location.tostring() + "\CHANGELOG.md"
$tags = git tag
$i = 0
Clear-Content $path
Add-Content $path "Change Log"
Add-Content $path "=========="
Add-Content $path " "
$ToNatural = { [regex]::Replace($_, '\d+', { $args[0].Value.PadLeft(20) }) }
$tags | Sort-Object $ToNatural
foreach($tag in $tags)
{
if (-NOT ($tag -match "v(\d+\.)(\d+\.)(\*|\d+)")) { continue }
$i = $i + 1
if ($i -eq 0) { continue }
$tag
If ($i -gt 0) {
$previous = $tags[$i - 1]
Add-Content $path " "
}
}
This sort of works, but all tags seem to be console logged and it shows this:
1.6.0
changeDeliveryFieldAccess
orders/autoComplete
returns/autoComplete
save-lines-dates
services/serviceDetails
tile-colours
users/confirmation
v0.1
v1.1.0
v1.2.0
v1.3.0
v1.4.0
v1.5.0
v1.7.0
v1.8.0
v1.9.0
v2.0.0
v2.1.0
v2.2.0
v2.3.0
v2.4.0
v2.5.0
v2.6.0
v2.7.0
v2.8.0
v2.9.0
v2.10.0
v2.11.0
v2.12.0
v.2.7.1
As you can see, there are a few in there that I don't want. Specifically:
1.6.0
changeDeliveryFieldAccess
orders/autoComplete
returns/autoComplete
save-lines-dates
services/serviceDetails
tile-colours
users/confirmation
v.2.7.1
Once those have been purged from my list, then the order will be right :)
Update 2
So I have tried another solution that is hopefully better:
$location = Get-Location $path = $location.tostring() + "\CHANGELOG.md" $tags = git tag $i = 0
Clear-Content $path
Add-Content $path "#Change Log"
Add-Content $path "=========="
Add-Content $path " "
$tags |
Where-Object { $_.Substring(1) -as [version] } |
Sort-Object { [version] $_.Substring(1) }
foreach($tag in $tags) {
write-host "$($tag) is ok"
}
I am not sure if I am doing this right, but this is the output from the above code:
1.6.0 is ok
changeDeliveryFieldAccess is ok
orders/autoComplete is ok
returns/autoComplete is ok
save-lines-dates is ok
services/serviceDetails is ok
tile-colours is ok
users/confirmation is ok
v.2.7.1 is ok
v0.1 is ok
v1.1.0 is ok
v1.2.0 is ok
v1.3.0 is ok
v1.4.0 is ok
v1.5.0 is ok
v1.7.0 is ok
v1.8.0 is ok
v1.9.0 is ok
v2.0.0 is ok
v2.1.0 is ok
v2.10.0 is ok
v2.11.0 is ok
v2.12.0 is ok
v2.2.0 is ok
v2.3.0 is ok
v2.4.0 is ok
v2.5.0 is ok
v2.6.0 is ok
v2.7.0 is ok
v2.8.0 is ok
v2.9.0 is ok
tl;dr:
You've later indicated that your
$tagsarray also contains other, non-version strings, so these must be filtered out:Where-Object { $_.Substring(1) -as [version] }only passes those strings through that can be converted to[version](System.Version) objects --as [version]- after removing thevat the beginning (.Substring(1); neglecting to remove thevwas your initial problem); the-asoperator either returns a successfully converted value or$null.Sort-Objectthen sorts the filtered tags as version numbers, which yields the correct order - see the next section for an explanation.$sortedVersionTagsthen receives version tags only, in their original form (asv-prefixed strings), properly sorted.The
vprefix in your version numbers prevents their conversion to[System.Version]instances; simply remove it first (not from the input itself; only temporarily, for the purpose of creating a version-info object e.g.,v1.1.0->1.1.0).Additionally, your command can be simplified:
[version]is a type accelerator (shorter name) built into PowerShell that refers to[System.Version].[1]You can simply cast a string to
[version], which is both more concise and faster than usingNew-Object.Sort-Objectaccepts an expression, via a script block ({ ... }), in lieu of a fixed property to sort by; inside the script block,$_refers to a given input object;$_.Substring(1)simply removes the first character (thev).Sort-Objectstill outputs the original strings - sorted.With your sample input the above yields (note how
v2.10.0correctly sorts afterv2.9.0, which wouldn't be the case with lexical sorting):If you'd rather output
System.Versioninstances instead of the input strings, the command becomes even simpler (PSv3+ syntax):If there's a possibility that not all strings contained in
$tagscan be converted this way (due to not havingv<version>format), use the following (PSv4+ syntax):This approach ensures that encountering strings that cannot be converted do not break the overall command:
Those that can be converted are, and are output.
Those that cannot be converted will cause an error that prints to the console and will also be reflected in the automatic
$Errorcollection afterwards. You can suppress console output with2>$null.[1] Generally, PowerShell allows you to omit the
System.prefix in type names.