如何使用Azure DevOps管道增加npm包的版本。

17
管道会在 master 分支有新提交时被触发,并发布软件包。
当前版本需要手动设置,我希望自动设置版本。
一开始我的想法是将以下任务添加到管道中:
  1. 检出 $Build.SourceBranch
  2. 运行 version patch --force
  3. git push
这样可以工作,版本确实被正确地递增了。但问题是它又会触发管道的另一次运行,导致版本再次递增,如此循环往复,永无止境。 有更好的方法吗?

最理想的方式是使用构建管道和发布管道。不幸的是,DevOps使这变得困难,因为DevOps中的npm命令需要完整源路径。否则,在构建管道中使用npm pack可以生成一个很好的包,您可以使用npm publish进行发布(可能是可行的,但在尝试多次后我放弃了)。 - Jonas Stensved
3个回答

10

我已经按照问题中提到的做法添加了相同的任务,只是做了一些小修改。
显然有一种方法可以跳过管道触发,请参见这里

所以npm version任务看起来像这样:

version patch -m "Bump version to %s [skip ci]" --force

这会阻止下一次构建被触发。

TIP: 记得授予“作者”(Azure DevOps用户)在推送时绕过策略的权限,如果有的话。


除非你将那个变更从构建流程推回到源代码库,否则每次运行都会补丁到相同的编号,对吧? - Alan McBee
正确的,那必须被推送,但是那一步是publish步骤的依赖,所以如果没有提交,就不会有发布:)。我只能在几个小时后接受它作为答案。 - SagiLow
这只会进行补丁增量更新...你如何处理次要和主要更新? - Mike Loffland
@MikeLoffland手动更新,因为我们没有固定的规则来决定何时应该更新这些内容。 - SagiLow

3

这是我在PowerShell中的实现,完全基于接受答案的步骤。请注意,这也处理了一些git问题,例如与此类方法一起出现的分离头。

steps:
- checkout: self
  persistCredentials: true
.
.
.
    - task: PowerShell@2
      displayName: 'Bump the version'
      inputs:
        targetType: 'inline'
        script: |
          $BranchName = "$(Build.SourceBranch)" -replace "refs/heads/"
          git checkout $BranchName
          git config --global user.email "anymail@anycompany.com"
          git config --global user.name "Your name"
          npm version prerelease -m "Auto increment pre-release version to %s [skip ci]" --force
          git push

2
不要使用源代码库中的文件来跟踪当前/下一个版本。如果这样做,我认为你很难打破循环。
你可以尝试运行“npm --no-git-tag-version version”命令,在构建代理内部递增package.json版本而不进行提交,这样你就不必推回到原始库中。它只会更改package.json并保持其处于未提交状态。
等待构建成功后再执行此操作。使用自定义脚本任务从package.json中提取版本号,然后执行“git reset --hard”(没有必要保留在构建服务器上发生变化的任何内容)。虽然这将撤销package.json中的更改,但现在您可以在包含该版本的head上创建一个标签,然后执行“git push origin {tag-name}”,这不应该在原始库中引入新的提交,从而重新触发您的管道。
实际上,我不认为只添加标签就会触发管道,但是我真的没有测试过。我非常确定不会触发。
管道中的任务顺序:给定一个源代码库,在其中确保已根据语义化版本控制规则设置了package.json中的主要和次要版本以反映代码的当前状态,并始终将补丁值设置为0,如果需要,使用pre-*值来描述主要/次要值的质量。
  1. (This is not really a task, but just describing the start of the execution:) The job starts. Automatically, the code is pulled from the source repo into the build agent.
  2. Using a utility command-line task and code or script that you write, run git describe --tags to find the most recent tag with a tagname matching the pattern you use (see below). (I prefer this sequence over calling npm version from-git because npm will just use the latest tag, which might not be a version number, depending on how much control you have over the branch.) Use string or regular expression operations to extract the major, minor, patch, and whatever pre-* value you might have. This is the previous version that we'll use to compare with what's in the package.json file. Note that you may have to follow these instructions to run a git command. Save it to a pipeline variable.
  3. Using a utility command-line task and code or script that you write, run npm version to get the current major/minor/pre version out of the package.json file and save it to a different pipeline variable. I'm using PowerShell Core, so my command would look something like this to create a "currentPackageVersion" pipeline variable:

    & npm.cmd version | ConvertFrom-Json | Select-Object -ExpandProperty {name-of-your-package} | Set-Variable -Name 'packageVersion' | Write-Output "#vso[task.setvariable variable=currentPackageVersion]$packageVersion"
    
  4. Using a utility command-line task and code or script that you write, compare the previous version's major, minor, and pre-* values to determine whether any of them have changed. Set a new pipeline variable to reflect whether it has changed or not. I'll use the name "restartVersionPatchNumber", which is true if the current major, minor, or pre-* values are different from the previous version's major, minor, or pre-* values.

  5. The npm Task conditionally runs a custom command: npm --no-git-tag-version version patch, which updates package.json in the build agent but does not commit the change, leaving your Working Area modified (dirty) (which might cause issues on subsequent builds if you are using your own build agents instead of hosted agents). The condition expression of the Task uses a custom condition that evaluates to the variable that I just set in the previous step ("restartVersionPatchNumber"). Note that if this task does not run, it should just use the value of the version that is in the package.json file (the current version that is now in the "currentPackageVersion" pipeline variable).
  6. Using a utility command-line task and code or script that you write, run npm version to extract the new version that the npm version command set. Save it to a new pipeline variable; I'll call it "newVersionNumber".
  7. The regular build tasks run, producing artifacts and possibly publishing them
  8. Using a utility command-line task, run git reset --hard. You'll need to do this even if you're using a hosted build agent, because of the next step.
  9. Using a utility command-line task, create a variable from the saved version number ("newVersionNumber") that contains the value of the tag's tagname that you want to use. Use a distinctive patter, like "AzPipelineBuild-PipelineName-PackageVersion-1.0.0" but using your version instead of 1.0.0.
  10. Using a utility command-line task, run git tag {*tagname*}. For PowerShell, the syntax would be & git.exe tag $env:newVersionNumber
  11. Using a utility command-line task, run git push origin {*tagname*}
  12. Profit
您可以(也许应该)合并命令行步骤。我非常喜欢使用运行PowerShellCore(pwsh)的PowerShell任务,正如您可能已经猜到的那样。
作业生成的软件包将具有更新的版本,因为它是在构建过程中创建的,并且它将与现在在原始源代码存储库中的标记匹配。
或者,使用外部来源(Azure Function等)或不同的(第二个)git存储库或甚至另一个分支,它与您的CI触发器无关,您只用于跟踪构建号码,然后在开始构建之前使用令牌替换任务设置版本。我不太喜欢这个想法,但它可以防止重新触发新的构建。
此外,您希望只使用该存储库构建一个软件包。下一步是将该软件包发布到Azure Artifacts feed、npmjs.org或其他位置。不要依赖于版本嵌入原始源代码;任何依赖于该软件包的内容都应该从您发布到的feed中提取它,而不是依赖于它在构建步骤中以新版本号构建。

谢谢,但是我不太确定我理解了,版本必须存在于 package.json 文件中,否则用户将无法更新。Git 标签很好,但只适用于自我监控。我能想到的最简单的方法(如果可能的话)是排除 DevOps 用户提交触发管道,但我不确定是否可能。 - SagiLow
@SagiLow 我已经大幅度修改了我的回答。如果有帮助,请告诉我。 - Alan McBee
谢谢,我们并没有使用标签,而且我认为这会使版本控制变得困难。此外,这意味着 package.json 的版本永远不正确,这很令人困惑。我认为我已经找到了一个更简单的解决方案来解决我的问题,请看下面的答案。非常感谢您的回答! - SagiLow

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接