问题描述
在Azure Pipeline(dev.azure.com)中尝试构建一个PowerShell模块。他已经设置了一个初始的Pipeline,并逐步进行小步骤的构建,因为在Azure上很容易遇到莫名其妙的错误。
他已经添加了一个’Prepare’阶段:
name: $(Build.DefinitionName)_$(Date:yyyyMMdd))
trigger:
- master
pool:
vmImage: 'ubuntu-latest'
variables:
major: 0
minor: 0
patch: $(Build.BuildID)
buildVersion: $(major).$(minor).$(patch)
stages:
- stage: Prepare
jobs:
- job: Prepare
steps:
- powershell: .\bootstrap.ps1
displayName: 'Install pre-requisites'
这是基于在启动新Pipeline时默认生成的yaml文件,所以调用bootstrap文件的部分是我免费获得的(这部分工作正常)。
bootstrap使用一个依赖文件,你可以在其中声明你的依赖关系,然后导入这些依赖关系。其中一个依赖关系是包含Invoke-Build命令的InvokeBuild。所以我期望在后续阶段能够使用Invoke-Build命令。
下一个yaml pipeline的部分如下:
- stage: Build
jobs:
- job: Build
steps:
- task: PowerShell@2
inputs:
targetType: 'inline'
script: 'invoke-build build'
在本身上,invoke-build build
是正确且有效的,并且在本地主机上工作。
Build作业失败,并显示以下错误:
/usr/bin/pwsh -NoLogo -NoProfile -NonInteractive -Command . '/home/vsts/work/_temp/edb3758b-8e16-448d-bea2-9ba18acb9693.ps1'
Invoke-Build: /home/vsts/work/1/s/do-build.ps1:3
Line | 3 | Invoke-Build build | ~~~~~~~~~~~~
| The term 'Invoke-Build' is not recognized as the name of a
| cmdlet, function, script file, or operable program. Check the
| spelling of the name, or if a path was included, verify that
| the path is correct and try again.
我发现还有另一种使用PowerShell@2任务调用构建的方法,使用filePath
输入:
- stage: Build
jobs:
- job: Build
steps:
- task: PowerShell@2
inputs:
filePath: '$(System.DefaultWorkingDirectory)/do-build.ps1'
do-build.ps1脚本定义如下:
Set-Location .\Elizium.FakeBuddy
Invoke-Build build
(Elizium.FakeBuddy是我正在构建的PowerShell测试模块的名称,该目录包含InvokeBuild构建脚本)
但是这个方法也失败,并显示完全相同的错误。
那么为什么在构建阶段的PowerShell会话中没有可用的invoke-build命令,即使Prepare阶段已经导入了该模块?
我唯一能想到的是不同的阶段不共享相同的PowerShell会话,但我不知道这是否正确,这似乎不太可能,不同的阶段不共享相同的会话。
编辑:我尝试了一个将Build作业声明在Prepare相同阶段的替代版本,但是没有任何区别,Invoke-Build命令仍然有问题。
解决方案
请注意以下操作注意版本差异及修改前做好备份。
方案1
根据回答1,你需要在使用Invoke-Build命令的脚本中安装InvokeBuild模块。你的YAML应该如下所示:
- stage: Build
jobs:
- job: Build
steps:
- task: PowerShell@2
inputs:
targetType: 'inline'
script: |
Install-Module InvokeBuild
Invoke-Build build
正如@Michael Erpenbeck所说,“托管代理程序从一个干净的状态开始”。也就是说,它对于你的Pipeline中的每个作业都是从一个干净的状态开始的。我不确定bootstrap.ps1应该做什么,所以无法评论你的Invoke-Build是否应该作为同一个作业的步骤运行。但是要记住的主要观点是,除了标准的Azure Pipelines代理程序提供的要求之外,任何其他要求都应在每个作业中处理。
方案2
根据评论1,你可以在bootstrap.ps1中添加Install-Module InvokeBuild
命令来安装InvokeBuild模块。这样,你就可以在后续的步骤中使用Invoke-Build命令,而无需在每个作业中安装模块。
# bootstrap.ps1
Install-Module InvokeBuild
然后,你的YAML可以保持不变:
- stage: Build
jobs:
- job: Build
steps:
- task: PowerShell@2
inputs:
targetType: 'inline'
script: 'invoke-build build'
这样,你就可以在Build阶段中使用Invoke-Build命令,而无需在每个作业中安装模块。