• Что бы вступить в ряды "Принятый кодер" Вам нужно:
    Написать 10 полезных сообщений или тем и Получить 10 симпатий.
    Для того кто не хочет терять время,может пожертвовать средства для поддержки сервеса, и вступить в ряды VIP на месяц, дополнительная информация в лс.

  • Пользаватели которые будут спамить, уходят в бан без предупреждения. Спам сообщения определяется администрацией и модератором.

  • Гость, Что бы Вы хотели увидеть на нашем Форуме? Изложить свои идеи и пожелания по улучшению форума Вы можете поделиться с нами здесь. ----> Перейдите сюда
  • Все пользователи не прошедшие проверку электронной почты будут заблокированы. Все вопросы с разблокировкой обращайтесь по адресу электронной почте : info@guardianelinks.com . Не пришло сообщение о проверке или о сбросе также сообщите нам.

Auto update version

Lomanu4 Оффлайн

Lomanu4

Команда форума
Администратор
Регистрация
1 Мар 2015
Сообщения
1,481
Баллы
155
As developers, we do not want to waste time on releases, and one of the challenges with an automatic release is updating the version number.

Conventional Commits


At multiple companies I have introduced the

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

website. This allows us to easily add the type of change in our commit title.

If every developer uses these conventions, you can automate versioning in the pipeline, and that is what I did about two years ago. I will show you how.

First of all, I have to admit that I am not a PowerShell guru, so feel free to improve the scripts if this post helped you.

Now lets start with all the steps we need to take and what better way then using an example pipeline.

Patch number logic


We set the default name of the pipeline to $(date:yyyyMMdd)$(rev:rr), so we can use this as the patch number. This gives us a couple of advantages:

  • No need for +1 or reset to 0 logic
  • We always know when a version is released

Now there are some restrictions to this, at least if you create a NuGet package:

  • Version parts in NuGet are integers, so the max version is 2147483647
  • Limit is 99 releases a day
  • This logic will fail from the year 2148; this will be the new Y2K bug!

# 2147483647
# yyyyMMddrr
name: $(date:yyyyMMdd)$(rev:rr)

variables:
system_accesstoken: $(System.AccessToken)
projectName: 'name'
isMaster: $[eq(variables['Build.SourceBranch'], 'refs/heads/master')]

trigger:
- master
Reuse scripts


After writing and testing the scripts (details later in the blog) we put the scripts in another repository, so they are reusable


resources:
repositories:
- repository: repoName
type: git
name: TeamProjectName/repoName
Nobody is perfect


Sometimes a (new) developer forgets to add the convention. So we added two extra parameters to set the type of release when we run a pipeline manually.


parameters:
- name: buildConfiguration
type: string
default: 'Release'
version
- name: releaseNewVersion
type: boolean
default: false
- name: newVersionType
type: string
default: 'patch'
values:
- patch
- minor
- major

This is how it looks when manually starting a run

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



verion tag in git


Our scripts will write the new version as a tag to Git. This means the pipeline needs permission to push to the repository.


steps:
- checkout: self
displayName: "Git checkout with allow scripts to access the system token for pushing"
persistCredentials: true
clean: true
fetchDepth: 0
flow of scripts


Here you can see all the scripts we built and how we call them in the pipeline.


- template: scriptsFolderName/set-latest-version-in-variables.yml@repoName
- template: scriptsFolderName/update-version-variables.yml@repoName
parameters:
overruleNewVersion: ${{ parameters.ReleaseNewVersion }}
newVersionType: ${{ parameters.newVersionType }}
- template: scriptsFolderName/create-git-tag.yml@repoName
- template: scriptsFolderName/update-version-in-project-file.yml@repoName
parameters:
buildConfiguration: ${{ parameters.buildConfiguration }}
- template: scriptsFolderName/default-build.yml@repoName
parameters:
buildConfiguration: ${{ parameters.buildConfiguration }}

- template: scriptsFolderName/push-new-version.yml@repoName
parameters:
buildConfiguration: ${{ parameters.buildConfiguration }}

- powershell: |
$newVersion = "$($(Major)).$($(Minor)).$($(Patch))"
Write-Host "##vso[build.updatebuildnumber]$newVersion"
displayName: 'Rename pipeline to new version'
condition: and(succeeded(), eq(variables.isRelease, 'true'))
Setting the Latest Version


To set the latest version, we get the latest tag. When no tag is available, we use version 0.0.0.

When you implement this script but want to start with a higher version, just create that tag if it is not already available.

After setting the full version, we split it up into major, minor, and patch variables that we can update later in the pipeline.


#set-latest-version-in-variables.yml
steps:
- powershell: |
$latestVersion = git describe --tags --abbrev=0 2>$null
if ($latestVersion) {
echo "Current version: $($latestVersion)"
} else {
$latestVersion = "0.0.0"
echo "No tag was found. Using version 0.0.0 as a base."
}

$versionArray = $latestVersion -split "\."

$major = [int]$versionArray[0]
$minor = [int]$versionArray[1]
$patch = [int]$versionArray[2]

Write-Host "##vso[task.setvariable variable=Major]$major"
Write-Host "##vso[task.setvariable variable=Minor]$minor"
Write-Host "##vso[task.setvariable variable=Patch]$patch"
displayName: 'Get latest version and set variables'
condition: and(succeeded(), eq(variables.isMaster, 'true'))
Incrementing the Version Number


The normal flow will be that the run was triggered automatically and the convention was used, which means that the commit title starts with:

  • fix = patch
  • feat = minor
  • anyType! = major

We do this with regex and also get other parts of the commit message. Who knows, maybe we can use them in the future. Some examples of how the regex will return the results.


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



After this, we just check the type of change and update the corresponding version type, where the patch will always be updated.

We added some extra checks for the manual run part that overrules the default logic.


#update-version-variables.yml
parameters:
overruleNewVersion: false
newVersionType: ''

steps:
- powershell: |
$latestCommitTitle = git log -n 1 --pretty=format:"%s"

#Normalize title
$pattern = "^merged pr \d+:\s*(.*)"
$normalizedTitle = $latestCommitTitle.ToLower()
if($latestCommitTitle.ToLower() -match $pattern) {
$normalizedTitle = $matches[1]
}

$pattern = "(?<type>\w+)(?<scope>(?:\([^()\r\n]*\)|\()?(?<breaking>!)?)(?<subject>:.*)?"
$normalizedTitle -match $pattern
echo "type: $($matches["type"])"
echo "scope: $($matches["scope"])"
echo "breaking: $($matches["breaking"])"
echo "subject: $($matches["subject"])"

$major = [int]$(Major)
$minor = [int]$(Minor)
$patch = $(Patch)

$changed = $false
if('${{ parameters.overruleNewVersion }}' -eq "true") {
echo '${{ parameters.newVersionType }}'
$changed = $true

if('${{ parameters.newVersionType }}' -eq "major") {
echo "breaking change"
$major += 1
$minor = 0
}
elseif('${{ parameters.newVersionType }}' -eq "minor"){
echo "minor change"
$minor += 1
}
else{
echo "patch change"
}
}
else {
if($matches["breaking"] -ne $null) {
echo "breaking change"
$major += 1
$minor = 0
$changed = $true
}
elseif($matches["type"] -eq "feat"){
echo "minor change"
$minor += 1
$changed = $true
}
elseif($matches["type"] -eq "fix"){
echo "patch change"
$changed = $true
}
}

echo "Changed: $($changed)"
if($changed) {
Write-Host "##vso[task.setvariable variable=Major]$major"
Write-Host "##vso[task.setvariable variable=Minor]$minor"
Write-Host "##vso[task.setvariable variable=Patch]$(Build.BuildNumber)"
Write-Host "##vso[task.setvariable variable=IsRelease]true"
}
displayName: 'Check change type and update version'
condition: and(succeeded(), eq(variables.isMaster, 'true'))
Creating the Git Tag


When there was a change that needed a release, the isRelease variable will be set to true in the last script, and when it is, we just create a new Git tag.

This will only work if you set the Git permission in the pipeline with persistCredentials: true


#create-git-tag.yml
steps:
- powershell: |
git tag "$($(Major)).$($(Minor)).$($(Patch))"
displayName: 'Create git tag'
condition: and(succeeded(), eq(variables.IsRelease, 'true'))
Optional: Updating project file


We develop libraries/NuGet packages in .NET, so the last step for us will be an update to the .csproj file. This will ensure that when we build, the version of the NuGet package will be correct.

As I have written earlier, NuGet uses an integer per version type. But if we look deeper, we find something interesting. The type is different per tag:

  • Packageversion: int32
  • version: int16 = 32.767

#update-version-in-project-file.yml
parameters:
projectName: ''

steps:
- powershell: |
$newVersionTag = git describe --tags --abbrev=0
echo "New version tag: $($newVersionTag)"

$projectName = '$(projectName)'
$pattern = '^(.*?(<PackageVersion>|<Version>).*?)([0-9].[0-9]{1,2}.)(([0-9]{1,2})(-rc([0-9]{2}))?)(.*?)$'
$path = if (Test-Path -Path $projectName) {'{0}\*' -f $projectName } else { '*' }
$ProjectFileName = '{0}.csproj' -f $projectName
$ProjectFiles = Get-ChildItem -Path $path -Include $ProjectFileName -Recurse

foreach ($file in $ProjectFiles)
{
echo "file: $($file)"
echo "file path $($file.PSPath)"
(Get-Content $file.PSPath) | ForEach-Object{
if($_ -match $pattern){
'{0}{1}{2}' -f $matches[1],$newVersionTag,$matches[8]
} else {
# Output line as is
$_
}
} | Set-Content $file.PSPath
}
displayName: 'Update version in project file'
condition: and(succeeded(), eq(variables.IsRelease, 'true'))

I hope this helps you guys with automating your versioning process and streamlining your releases. Feel free to reach out if you have any questions or need further assistance. Happy coding! ?


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

 
Вверх Снизу