【问题标题】:Powershell: how to split, do math and formatPowershell:如何拆分、做数学和格式化
【发布时间】:2020-02-15 17:51:11
【问题描述】:

我正在寻找一个看起来像这样的 1-liner:

(gitversion | ConvertFrom-Json).SemVer.split('.') | [string]::Format("{0}.{1}.{2}",$_[0],$_[1] + 1,$_[2]) | git tag $_

所以,现在我有 0.1.0 并且我想要一个 1 班轮将其映射到: 0.2.0

我相信 PS 方面的大师可以快速解决这个问题

【问题讨论】:

  • Powershell 实际上知道版本号是什么...'0.2.0' -as [VERSION]。这样您就可以正确计算版本号或正确比较它们...

标签: powershell


【解决方案1】:

您可以阅读整个 json,使用版本的主要、次要和补丁编号,然后更新您感兴趣的任何一个...补丁、次要或主要。

我正在使用foreach-object 访问 json 的所有属性,即使只有一个可用。 1-liner

gitversion | ConvertFrom-Json | % { "$($_.Major).$($_.Minor + 1).$($_.Patch)" } | % { git tag $_ }

% / ForEach-Object 如何与多个存储库一起工作

如果您运行 gitversion 的路径中只有一个存储库,它将始终为您提供一个对象。 (当您在没有 git 存储库的目录中运行时,gitversion 失败并出现错误。)

我想强调的是,这在您只有主要、次要和补丁版本的情况下非常有用。在 SemVersion 类似于"SemVer":"0.1.0" 的情况下,这很好。但是,如果您的兴趣是在下一个版本中保留 PreReleaseTag(而不是删除 alpha / beta 等标签),您也可以将 PreReleaseTagWithDash 包含到您的输出中。例如预发布标签:"SemVer":"0.1.0-alpha.915"

gitversion | ConvertFrom-Json | % { "$($_.Major).$($_.Minor + 1).$($_.Patch)$($_.PreReleaseTagWithDash)" } | % { git tag $_ }

gitversion 的 JSON 示例

  • 从 dev 或其他分支中,您可以预期 semVer 中包含预发布标签的变体。
{
  "Major":0,
  "Minor":1,
  "Patch":0,
  "PreReleaseTag":"alpha.915",
  "PreReleaseTagWithDash":"-alpha.915",
  "PreReleaseLabel":"alpha",
  "PreReleaseNumber":915,
  "WeightedPreReleaseNumber":915,
  "BuildMetaData":"",
  "BuildMetaDataPadded":"",
  "FullBuildMetaData":"Branch.dev.Sha.888xxx.xxx888",
  "MajorMinorPatch":"0.1.0",
  "SemVer":"0.1.0-alpha.915",
  "LegacySemVer":"0.1.0-alpha915",
  "LegacySemVerPadded":"0.1.0-alpha0915",
  "AssemblySemVer":"0.1.0.0",
  "AssemblySemFileVer":"0.1.0.0",
  "FullSemVer":"0.1.0-alpha.915",
  "InformationalVersion":"0.1.0-alpha.915+Branch.dev.Sha.888xx.xx888",
  "BranchName":"dev",
  "Sha":"888xx.xx888",
  "ShortSha":"7a1152f",
  "NuGetVersionV2":"0.1.0-alpha0915",
  "NuGetVersion":"0.1.0-alpha0915",
  "NuGetPreReleaseTagV2":"alpha0915",
  "NuGetPreReleaseTag":"alpha0915",
  "VersionSourceSha":"88xxx.xx88",
  "CommitsSinceVersionSource":915,
  "CommitsSinceVersionSourcePadded":"0915",
  "CommitDate":"2019-12-06"
}
  • 从 master 分支,您通常会期望 semver = major.minor.patch。
{
  "Major":0,
  "Minor":1,
  "Patch":0,
  "PreReleaseTag":"",
  "PreReleaseTagWithDash":"",
  "PreReleaseLabel":"",
  "PreReleaseNumber":"",
  "WeightedPreReleaseNumber":"",
  "BuildMetaData":0,
  "BuildMetaDataPadded":"0000",
  "FullBuildMetaData":"0.Branch.master.Sha.9999xxx....xxx999",
  "MajorMinorPatch":"0.1.0",
  "SemVer":"0.1.0",
  "LegacySemVer":"0.1.0",
  "LegacySemVerPadded":"0.1.0",
  "AssemblySemVer":"0.1.0.0",
  "AssemblySemFileVer":"0.1.0.0",
  "FullSemVer":"0.1.0+0",
  "InformationalVersion":"0.1.0+0.Branch.master.Sha.999xxx...xxx999",
  "BranchName":"master",
  "Sha":"86b0be929a84ba7e9b2a463e7dbdc9a3c9325dc1",
  "ShortSha":"86b0be9",
  "NuGetVersionV2":"0.1.0",
  "NuGetVersion":"0.1.0",
  "NuGetPreReleaseTagV2":"",
  "NuGetPreReleaseTag":"",
  "VersionSourceSha":"999xxx...xxx999",
  "CommitsSinceVersionSource":0,
  "CommitsSinceVersionSourcePadded":"0000",
  "CommitDate":"2018-02-18"
}

注意:我没有在一个位置使用多个 git 存储库对此进行测试。如果您正在运行的路径中只有存储库,则此解决方案将起作用。

【讨论】:

  • 这正是我想要的——通过拆分它,我实际上让问题变得更难了。我还是太习惯了bash
【解决方案2】:

注意:以下解决方案假定要解析一个字符串表示,例如0.1.0;事实证明,utility gitversion 输出的 JSON 具有单独的版本号组件,例如 MajorMinor、...,Jawad's answer 依赖于这些组件;但是,如果要保留 所有 semver 版本组件,即使利用单个属性来合成输出 string 也可能具有挑战性。


对于既强大又方便的解决方案,请使用 PowerShell [Core] 6+ 提供的 [semver] (System.Management.Automation.SemanticVersion) 类型(命令已传播跨多行以提高可读性):

你可以简单地cast一个版本字符串,比如0.1.0[semver],产生一个带有数字对象 /em> .Major.Minor.Patch 属性,以及其他属性;您可以从中构造一个 new [semver] 实例,并通过修改后的次要版本和所有其他属性传递:

(gitversion | ConvertFrom-Json).FullSemVer | foreach { 
   $v = [semver] $_;
   [semver]::new($v.Major, ($v.Minor+1), $v.Patch, $v.PreReleaseLabel, $v.BuildLabel) 
  } | foreach { 
        git tag $_ 
      }

foreachForEach-Object cmdlet 的内置别名。
第一个foreach 命令输出的是[semver] object,而不是字符串,而是隐式传递这样一个对象stringify它,从而产生所需的表示。支持>

以上确保semver-compliant 版本字符串的所有组件都保留在输出中,特别是包括 pre-release 和 build-metadata 字段,如果存在(例如,
1.0.0-alpha+001)。


如果您的版本号字符串始终由 2 - 4 个纯数字组件组成(例如,1.0、@987654348 @、1.0.2.10),您可以改用 [version] 类型 (System.Version),也可在 Windows PowerShell 中使用(PowerShell 5.1 及以下版本):

'0.1.0.34' | foreach { 
    $v = [version] $_; $newMinor = $v.Minor + 1
    if ($v.Build -ne -1 -and $v.Revision -ne -1) { [version]::new($v.Major, $newMinor, $v.Build, $v.Revision) }
    elseif ($v.Build -ne -1) { [version]::new($v.Major, $newMinor, $v.Build) }
    else {[version]::new($v.Major, $newMinor) }
   } | foreach { 
        git tag $_ 
      }

注意 - 不幸 - 需要选择性地使用 [version] 的各种构造函数重载,这是设计不对称的结果:非指定版本组件(用于可选的构建和修订字段)默认为占位符 -1 ,但将这些占位符传递给 4 组件构造函数是支持的。


注意:上述解决方案的优点是您可以获得正确的对象版本号表示,这通常使编程处理更容易

  • 然而,令人困惑的是[semver][version] 它们提供了方法来增加它们所代表的版本号。

如果你只需要修改版本号的字符串表示, 一个简洁的基于正则表达式的文本解析解决方案也是可能的,PowerShell [Core] 6.2+ 再次变得更容易,因为基于正则表达式的-replace operator 支持script-block-based substitutions(请参阅链接的答案以了解如何在 Windows PowerShell 中执行此操作):

(gitversion | ConvertFrom-Json).FullSemVer | foreach { 
   $_ -replace '(?<=^\d+\.)\d+(?=.*)', { 1 + [int] $_.Value }
  } | foreach { 
        git tag $_ 
      }

用于增加 3 个版本号组件的正则表达式的变体(将保留尾随的预发布和构建标签):

  • 主要号码(例如,2.0.9 -> 3.0.9):

    • '2.0.9' -replace '\d+(?=\..+)', { 1 + [int] $_.Value }
  • 次要号码(如上;2.0.9 -> 2.1.9)):

    • '2.0.9' -replace '(?&lt;=^\d+\.)\d+(?=.*)', { 1 + [int] $_.Value }
  • 补丁编号(第三部分;2.0.9 -> 2.0.10):

    • '2.0.9' -replace '(?&lt;=^\d+\.\d+\.)\d+(?=.*)', { 1 + [int] $_.Value }

Caveat:假设目标版本组件存在在输入字符串中;例如,尝试增加输入字符串 '2.0' 中的 patch 组件将 起作用;这种脆弱性是通过[semver] 更喜欢基于对象的方法的另一个原因。

【讨论】:

    【解决方案3】:

    如果我理解正确,您想在第二个数字上加 1。我希望我可以做 $a.minor += 1,但是 [version] 类型是只读的。

    $a = '0.1.0'
    $nums = $a.split('.')
    '{0}.{1}.{2}' -f $nums[0], ([int]$nums[1] + 1), $nums[2]
    
    0.2.0
    

    或者

    $a = '0.1.0'
    $nums = $a -split '\.'
    ([int]$nums[1])++
    $nums -join '.'
    
    0.2.0
    

    或者

    $a = '0.1.0'
    $nums = $a.split('.')
    ([int]$nums[1])++
    '{0}.{1}.{2}' -f $nums
    
    0.2.0
    

    我也在尝试使用脚本块的 ps 6 版本的 -replace,但它变得具有挑战性。

    另见Increment version in a text file

    这是另一个,但它需要 powershell 6 才能用脚本块替换 -replace。我正在使用正则表达式,正则前瞻和正后瞻,所以我只替换数字而不是每边的 2 个点。这仅适用于 3 个数字,除非您想将 2 个中间数字增加 1,哈哈。它当然有资格作为单线。

    '0.11.0' -replace '(?<=\.)\d+(?=\.)', { [int]"$_" + 1 }
    
    0.12.0
    
    
    '0.11.11.0' -replace '(?<=\.)\d+(?=\.)', { [int]"$_" + 1 }
    
    0.12.12.0
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-02-27
      • 2020-05-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多