Closed Ni2Be closed 2 years ago
Hi @Ni2Be
could you please clarify whether I understood it correctly: Ideally you would like to see on the triggered build which other build was triggerring it (and potentially vice versa)?
If that's the case, I'm not sure if it's possible. Maybe a custom extension could be written that appears as "tab" like the "Releases" tab in your second screenshot. However that is probably quite some work. Other than that I can not think of something - ideally would be some existing functionality that could be hooked in to, as it would limit the effort. But I am not aware of anything like that, sorry.
Hi @huserben
Almost, the Build is not triggered by another build but by a release-pipeline. So, for all builds I want to go into a build and see which release it belongs to and for a release I want to see which builds it did trigger.
I was thinking of adding the artifact the build created as an artifact of the release-pipeline with the api, but I think it is not possible to add them after the release was created. (these are the artifacts I’m talking about: https://docs.microsoft.com/en-us/azure/devops/pipelines/release/artifacts?view=azure-devops)
We want to give our release process a complete overhaul so maybe writing our own plugin would be an option, I’m just collection options at the moment. Is getting into “writing Azure DevOps extensions” something for a week + a sample project and then you are good to go or more like learning a new programming language + all frameworks? 😅
Almost, the Build is not triggered by another build but by a release-pipeline. So, for all builds I want to go into a build and see which release it belongs to and for a release I want to see which builds it did trigger.
Ok got it. I think what could be done is on the release side to just collect all builds and put it in some (text) file and upload it as artifact to that release. The task has the option to store all build ids of triggered builds, this could then be read and stored in a file (e.g. via some powershell script or so). On the side of the triggered build, I think it would be trickier. What could be done is to add a variable with the triggering build that you then pass - however that means you would need to adjust all the builds to have such a variable that you then can set while triggering. Otherwise there is no way to know what triggered it, as it's a simple REST call that is made in the back, like if you would queue it up manually...
We want to give our release process a complete overhaul so maybe writing our own plugin would be an option, I’m just collection options at the moment.
Maybe you can also think about ditching the "Releases" and instead look at yaml pipelines, they offer more functionality and also have support for triggering "upstream" builds (see docs on Pipeline Triggers). We moved to yaml builds for most of our pipelines and make use of pipeline triggers and also of multiple stages within one pipeline - that removed the need for this task in fact :-)
Is getting into “writing Azure DevOps extensions” something for a week + a sample project and then you are good to go or more like learning a new programming language + all frameworks?
As usual it depends. A pipeline task is easy to start if you have some basic knowledge of typescript/node.js. Of course if you want to do it more properly you should also think about how you (unit) test your task, and build & deploy it etc., that might take a bit more time. But you get started quickly if you want to try something out to even see if it's possible what you want to achieve. I can recommend having a look at the tutorial.
If we talk about an extension that adds some graphical things to Azure, you will need to know some things about frontend development (Reactjs is supported, not sure if other frameworks work too). This is what is called a web extension. I'm not that familiar with it, I just developed some extension for the Pipelines once, see:
Given that I was not really aware what I'm doing (due to the lack of frontend development know how) the code is probably not very optimally done. But maybe it can serve as inspiration what's possible.
So all in all it depends on what exactly you want to achieve and how good looking it should be :-)
I hope that helps you a bit.
Maybe a file wouldn’t be too bad, I could probably generate the urls so navigating to a build would be easy.
On the side of the triggered build, I think it would be trickier. What could be done is to add a variable with the triggering build that you then pass - however that means you would need to adjust all the builds to have such a variable that you then can set while triggering. Otherwise there is no way to know what triggered it, as it's a simple REST call that is made in the back, like if you would queue it up manually...
The other way around is even trickier. :D Before a build is triggered we check if the micro-service needs to be build – so if there are no changes there is no build. We just use the artifact that was created last time the build ran. But we would like to link those “old” builds too.
Maybe you can also think about ditching the "Releases" and instead look at yaml pipelines, they offer more functionality and also have support for triggering "upstream" builds (see docs on Pipeline Triggers). We moved to yaml builds for most of our pipelines and make use of pipeline triggers and also of multiple stages within one pipeline - that removed the need for this task in fact :-)
I already forgot why I moved to a release-pipeline in the first place and we are already using yaml builds, so it’s probably worth a try.
The web extension thing also doesn’t sound too bad. We have some capable React developers and maybe this would be a very cool new toolkit to have :D
Big thanks for you input!
No problem, happy that I could be of (some) help.
If you have any other questions, face some issues with the task or have a request for a missing feature please don't hesitate to open up another issue.
For future readers: We went with an approach to move back into a yaml-build-pipeline.
I wrote a template that does this:
Output:
Can be used like this:
- stage: BuildMyCoolService
displayName: CoolServiceName
pool:
name: 'PoolName'
demands: 'CanBuildCoolStuff'
jobs:
- template: BuildIfChanged.yaml
parameters:
AzureServerAndCollection: 'https://myBuildServer.com/CollectionName/'
AzureProject: 'AwesomeProjectName'
Branch_Name: 'dev/justSomeBranchNameNothingCoolGoingOnHere'
Build_Name: 'AzureBuildName'
Template (Maybe there is a simpler way to get the needed information using Azures Api but I didn’t find one ;D):
# BuildIfChanged.yaml
###############################################################################################################
#
# Builds the provided Build only if the provided branch contains changes (since last build of that branch).
# If the Branch has not changed it will show a link to the last Build of it.
#
###############################################################################################################
parameters:
- name: AzureServerAndCollection # like "https://myBuildServer.com/CollectionName/"
type: string
- name: AzureProject # project the repo and build are part of
type: string
- name: Branch_Name # branch to be build
type: string
- name: Build_Name # build to be used
type: string
jobs:
- job: 'BuildIfChanged'
displayName: 'Build if changed'
# Workspace settings
workspace:
clean: all
variables:
AzureServerAndCollection: ${{ parameters.AzureServerAndCollection }}
AzureProject: ${{ parameters.AzureProject }}
Build_Name: ${{ parameters.Build_Name }}
Branch_Name: ${{ parameters.Branch_Name }}
Is_UpToDate: false
steps:
- task: PowerShell@2
displayName: 'Check if up to date'
inputs:
targetType: 'inline'
script: |
# uncomment for local development
# $pat = "1234swy1234b1234fx54y1234xayuoz1234l7hdoeuz7mag1234"
# $token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($pat)"))
# $header = @{authorization = "Basic $token"}
#$definition=""
#$branchName="develop"
#$upToDateAzureVarName = "$env:UPTODATE"
$header = @{ Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" }
$azureServerAndCollection = "$(AzureServerAndCollection)"
$azureProject ="$(AzureProject)"
$definition="$(Build_Name)"
$branchName="$(Branch_Name)"
$upToDateAzureVarName = "$env:UPTODATE"
Write-Host get latest build of branch
$uri = $azureServerAndCollection+$azureProject+"/_apis/build/latest/"+$definition+"?branchName="+$branchName+"&api-version=6.0-preview.1"
try {
$result = Invoke-WebRequest -Uri $uri -Method GET -Headers $header -UseBasicParsing
} catch [System.Net.WebException] {
Write-Host (ConvertFrom-Json $_).message
Write-Host Needs to be build`n
Write-Host "##vso[task.setvariable variable=$upToDateAzureVarName;]False"
exit 1
}
$result = ConvertFrom-Json $([String]::new($result.Content))
$buildId = $result.id
$repositoryId = $result.repository.id
Write-Host Latest buildId for branch $brancdirhName : $buildId`n
Write-Host Latest repositoryId for branch $branchName : $repositoryId`n
Write-Host get latest commit id in branch
$uri = $azureServerAndCollection+$azureProject+"/_apis/git/repositories/"+$repositoryId+"/stats/branches?name="+$branchName+"&api-version=6.0"
$result = Invoke-WebRequest -Uri $uri -Method GET -Headers $header -UseBasicParsing
$result = ConvertFrom-Json $([String]::new($result.Content))
$commitId = $result.commit.commitId
Write-Host latest commit in branch $branchName : $commitId`n
Write-Host get latest build of that branch
$uri = $azureServerAndCollection+$azureProject+"/_apis/git/repositories/"+$repositoryId+"/commits/"+$commitId+"/statuses?api-version=5.1"
$result = Invoke-RestMethod -Uri $uri -Method GET -Headers $header -UseBasicParsing
$latestBuildOfBranch = $result.value[0].targetUrl.Split('/')[-1]
$state = $result.value[0].state
Write-Host lastest build was: $latestBuildOfBranch
Write-Host state: $state`n
if($state -eq "succeeded" -and $latestBuildOfBranch -eq $buildId){
Write-Host Is up to date, no need to build`n
Write-Host "##vso[task.setvariable variable=$upToDateAzureVarName;]True"
Write-Host related build:
$uri = $azureServerAndCollection+$azureProject+"/_apis/build/builds/"+$buildId+"?api-version=6.0"
$result = Invoke-RestMethod -Uri $uri -Method GET -Headers $header -UseBasicParsing
Write-Host $result._links.web.href
} else {
Write-Host Needs to be build`n
Write-Host "##vso[task.setvariable variable=$upToDateAzureVarName;]False"
exit 1
}
env:
UPTODATE: Is_UpToDate
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
continueOnError: true
- task: TriggerBuild@4
displayName: 'Trigger a new build'
inputs:
definitionIsInCurrentTeamProject: false
tfsServer: '$(AzureServerAndCollection)'
teamProject: '$(AzureProject)'
buildDefinition: '$(Build_Name)'
useSameBranch: false
branchToUse: '$(Branch_Name)'
waitForQueuedBuildsToFinish: true
waitForQueuedBuildsToFinishRefreshTime: 15
storeInEnvironmentVariable: true
authenticationMethod: 'OAuth Token'
condition: and(succeeded(), eq(variables['Is_UpToDate'], False))
Note:
To get visual feedback we set the build to "succeeded with issues" if the build is triggered. If this behavior in not wanted delete lines:
exit 1
and
continueOnError: true
Hi, we are using "Trigger Build" in our release pipeline to build multiple micro services in one stage, that get packed into a setup in a second stage.
When I create a release that builds the setup with Build Artifacts (instead of using "Trigger Build") I have a link between the two. In Release:
In Build:
This is very convenient if we want to go from a release to a specific commit of a build.
Is there some way to achieve this (or something similar) with builds triggered by "Build Task"?