Skip to content

Commit

Permalink
👷 Implement 'Build Once' strategy in CI pipeline (#11)
Browse files Browse the repository at this point in the history
* Run CI with very branch push.
* Build only once, generating package in CI (with version `0.0.0-ci-$(Build.BuildNumber)` for now).
This requires applying a workaround for Coverlet, to able to collect code coverage when the solution is built with `ContinuousIntegrationBuild=true` (see [this](dotnet/sourcelink#572) and [this](https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/DeterministicBuild.md).
* Fix custom task conditions: `succeeded()` behavior only applies by default when `condition` is not overriden.
* Add publish package guard (`Push != ''`) and options to avoid commiting new version and tag (`NoCommit`) and pushing packages to GitHub (`NoGitHubPush`) and NuGet (`NoNuGetPush`).
* Bump `SourceLink` and `Coverlet` and `dotnet-version-cli` versions.
  • Loading branch information
eduherminio committed Jun 2, 2020
1 parent b2805b1 commit fa04c97
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 94 deletions.
21 changes: 21 additions & 0 deletions DeterministicBuild.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!-- Workaround for deterministic build and coverlet (https://github.com/dotnet/sourcelink/issues/572), see https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/DeterministicBuild.md -->
<Project>
<PropertyGroup>
<TargetFrameworkMonikerAssemblyAttributesPath>$([System.IO.Path]::Combine('$(IntermediateOutputPath)','$(TargetFrameworkMoniker).AssemblyAttributes$(DefaultLanguageSourceExtension)'))</TargetFrameworkMonikerAssemblyAttributesPath>
</PropertyGroup>
<ItemGroup>
<EmbeddedFiles Include="$(GeneratedAssemblyInfoFile)"/>
</ItemGroup>
<ItemGroup>
<SourceRoot Include="$(NuGetPackageRoot)" />
</ItemGroup>

<Target Name="CoverletGetPathMap"
DependsOnTargets="InitializeSourceRootMappedPaths"
Returns="@(_LocalTopLevelSourceRoot)"
Condition="'$(DeterministicSourcePaths)' == 'true'">
<ItemGroup>
<_LocalTopLevelSourceRoot Include="@(SourceRoot)" Condition="'%(SourceRoot.NestedRoot)' == ''"/>
</ItemGroup>
</Target>
</Project>
4 changes: 4 additions & 0 deletions Directory.Build.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<Project>
<!-- Workaround for deterministic build and coverlet (https://github.com/dotnet/sourcelink/issues/572), see https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/DeterministicBuild.md -->
<Import Project="$(MSBuildThisFileDirectory)DeterministicBuild.targets" />
</Project>
2 changes: 2 additions & 0 deletions SheepToolsSolution.sln
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
ProjectSection(SolutionItems) = preProject
azure-pipelines.yml = azure-pipelines.yml
.github\workflows\buid-github.yml = .github\workflows\buid-github.yml
DeterministicBuild.targets = DeterministicBuild.targets
Directory.Build.props = Directory.Build.props
Directory.Build.targets = Directory.Build.targets
README.md = README.md
EndProjectSection
EndProject
Expand Down
149 changes: 64 additions & 85 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
name: $(BuildID)

trigger:
branches:
include:
- master

schedules:
- cron: "1 0 * * 1"
displayName: 'Weekly build'
Expand All @@ -15,6 +10,7 @@ schedules:

variables:
SdkVersion: '3.1.x'
DotnetVersionCliVersion: '2.0.0-next.7'

stages:
- stage: CI
Expand All @@ -34,6 +30,8 @@ stages:
pool:
vmImage: $(imageName)
variables:
DefaultPackageVersion: '0.0.0-ci-$(Build.BuildNumber)'
PackageVersion: '$(DefaultPackageVersion)'
disable.coverage.autogenerate: 'true'
EscapedComma: '%2c'
TestResults: '$(Agent.TempDirectory)'
Expand All @@ -45,11 +43,22 @@ stages:
inputs:
packageType: sdk
version: '$(SdkVersion)'
installationPath: $(Agent.ToolsDirectory)/dotnet

- task: CmdLine@2
displayName: 'Modify SheepTools version'
condition: and(succeeded(), eq(variables['imageName'], 'ubuntu-latest'))
inputs:
failOnStderr: true
script: |
dotnet new tool-manifest
dotnet tool install dotnet-version-cli --version $(DotnetVersionCliVersion)
dotnet version -f src/SheepTools/SheepTools.csproj --skip-vcs $(PackageVersion)
dotnet version -f src/SheepTools.Moq/SheepTools.Moq.csproj --skip-vcs $(PackageVersion)
dotnet version -f src/SheepTools.XUnit/SheepTools.XUnit.csproj --skip-vcs $(PackageVersion)
- task: SonarCloudPrepare@1
displayName: 'Prepare SonarCloud analysis'
condition: eq(variables['imageName'], 'windows-latest')
condition: and(succeeded(), eq(variables['imageName'], 'windows-latest'))
inputs:
SonarCloud: 'SheepTools_SonarCloud'
organization: 'eduherminio-github'
Expand All @@ -71,7 +80,7 @@ stages:
displayName: 'Build'
inputs:
command: build
arguments: '--configuration Release --no-restore /p:ContinuousIntegrationBuild=false'
arguments: '--configuration Release --no-restore /p:ContinuousIntegrationBuild=true'
projects: 'SheepToolsSolution.sln'

- task: DotNetCoreCLI@2
Expand All @@ -88,7 +97,7 @@ stages:

- task: Palmmedia.reportgenerator.reportgenerator-build-release-task.reportgenerator@4
displayName: 'Generate tests report'
condition: eq(variables['imageName'], 'ubuntu-latest')
condition: and(succeeded(), eq(variables['imageName'], 'ubuntu-latest'))
inputs:
reports: '$(Build.SourcesDirectory)/**/coverage.cobertura.xml'
targetdir: '$(CoverageResults)'
Expand All @@ -97,31 +106,48 @@ stages:

- task: PublishCodeCoverageResults@1
displayName: 'Publish code coverage'
condition: eq(variables['imageName'], 'ubuntu-latest')
condition: and(succeeded(), eq(variables['imageName'], 'ubuntu-latest'))
inputs:
codeCoverageTool: Cobertura
summaryFileLocation: '$(CoverageResults)/Cobertura.xml'
reportDirectory: '$(CoverageResults)'
pathToSources: '$(Build.SourcesDirectory)'

- task: DotNetCoreCLI@2
displayName: 'Generate SheepTools NuGet package'
condition: and(succeeded(), eq(variables['imageName'], 'ubuntu-latest'))
inputs:
command: 'pack'
arguments: '--configuration Release'
configuration: 'Release'
packagesToPack: 'src/**/*.csproj'
nobuild: true
packDirectory: '$(Build.SourcesDirectory)/SheepTools/Artifacts'

- task: PublishBuildArtifacts@1
displayName: 'Publish artifact with NuGet package and its symbols'
condition: and(succeeded(), eq(variables['imageName'], 'ubuntu-latest'))
inputs:
pathtoPublish: '$(Build.SourcesDirectory)/SheepTools/Artifacts/'
artifactName: 'SheepTools'

- task: SonarCloudAnalyze@1
displayName: 'Perform SonarCloud analysis'
condition: eq(variables['imageName'], 'windows-latest')
condition: and(succeeded(), eq(variables['imageName'], 'windows-latest'))

- task: SonarCloudPublish@1
displayName: 'Publish SonarCloud analysis'
condition: eq(variables['imageName'], 'windows-latest')
condition: and(succeeded(), eq(variables['imageName'], 'windows-latest'))
inputs:
pollingTimeoutSec: '300'

- stage: CD
displayName: 'Pack & push'
- stage: Publish
displayName: 'Publish packages'
dependsOn: 'CI'
condition: and(succeeded('CI'), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
# It makes sense to allow other branches only of version replacement works with pre-release labels (-alpha-1, etc.)
condition: and(succeeded('CI'), ne(variables['PackageVersion'], variables['DefaultPackageVersion']), ne(variables['Push'], ''))
jobs:
- job: cd
displayName: 'Pack & push linux'
displayName: 'Publish package linux'
pool:
vmImage: ubuntu-latest
steps:
Expand All @@ -130,78 +156,20 @@ stages:
persistCredentials: true
clean: true

- task: UseDotNet@2
displayName: 'Use .NET Core sdk v$(SdkVersion)'
- task: DownloadPipelineArtifact@2
inputs:
packageType: sdk
version: '$(SdkVersion)'
installationPath: $(Agent.ToolsDirectory)/dotnet
artifact: SheepTools
path: $(Build.SourcesDirectory)/SheepTools/Artifacts/

- task: NuGetToolInstaller@1
displayName: 'Setup NuGet'
inputs:
versionSpec: '5.5.0'
checkLatest: true

- task: CmdLine@2
displayName: 'Setup Git'
inputs:
failOnStderr: true
script: |
git config --replace-all user.email "azure@devops.com"
git config --replace-all user.name "Azure DevOps"
- task: CmdLine@2
displayName: 'Setup dotnet-version-cli'
inputs:
failOnStderr: true
script: |
dotnet new tool-manifest
dotnet tool install dotnet-version-cli --version 1.1.2
- task: CmdLine@2
displayName: 'Modify SheepTools version'
condition: ne(variables['PackageVersion'], '')
inputs:
failOnStderr: true
script: |
dotnet version -f src/SheepTools/SheepTools.csproj --skip-vcs $(PackageVersion)
dotnet version -f src/SheepTools/SheepTools.csproj --skip-vcs $(PackageVersion)
dotnet version -f src/SheepTools/SheepTools.csproj --skip-vcs $(PackageVersion)
- task: DotNetCoreCLI@2
displayName: 'Restore'
inputs:
command: restore
arguments: '--configuration Release'
projects: 'SheepToolsSolution.sln'

- task: DotNetCoreCLI@2
displayName: 'Build'
inputs:
command: build
arguments: '--configuration Release --no-restore /p:ContinuousIntegrationBuild=true'
projects: 'SheepToolsSolution.sln'

- task: DotNetCoreCLI@2
displayName: 'Generate SheepTools NuGet package'
inputs:
command: 'pack'
arguments: '--configuration Release'
configuration: 'Release'
packagesToPack: 'src/**/*.csproj'
nobuild: true
packDirectory: '$(Build.SourcesDirectory)/SheepTools/Artifacts'

- task: PublishBuildArtifacts@1
displayName: 'Publish artifact with NuGet package and its symbols'
inputs:
pathtoPublish: '$(Build.SourcesDirectory)/SheepTools/Artifacts/'
artifactName: 'SheepTools'

- task: NuGetCommand@2
displayName: 'Push NuGet package'
condition: ne(variables['PackageVersion'], '')
condition: and(succeeded(), eq(variables['NoNuGetPush'], ''))
inputs:
command: 'push'
packagesToPush: '$(Build.SourcesDirectory)/SheepTools/Artifacts/*.nupkg'
Expand All @@ -211,7 +179,7 @@ stages:

- task: NuGetCommand@2
displayName: 'Push GitHub package'
condition: ne(variables['PackageVersion'], '')
condition: and(succeeded(), eq(variables['NoGitHubPush'], ''))
inputs:
command: 'push'
packagesToPush: '$(Build.SourcesDirectory)/SheepTools/Artifacts/*.nupkg'
Expand All @@ -220,16 +188,27 @@ stages:
verbosityPush: 'Detailed'

- task: CmdLine@2
displayName: 'Commit and push version increment'
condition: and(eq(variables['NoCommit'], ''), ne(variables['PackageVersion'], ''))
displayName: 'Modify SheepTools version'
inputs:
failOnStderr: true
script: |
dotnet new tool-manifest
dotnet tool install dotnet-version-cli --version $(DotnetVersionCliVersion)
dotnet version -f src/SheepTools/SheepTools.csproj --skip-vcs $(PackageVersion)
dotnet version -f src/SheepTools.Moq/SheepTools.Moq.csproj --skip-vcs $(PackageVersion)
dotnet version -f src/SheepTools.XUnit/SheepTools.XUnit.csproj --skip-vcs $(PackageVersion)
- task: CmdLine@2
displayName: 'Commit and push version increment'
condition: and(succeeded(), eq(variables['NoCommit'], ''))
inputs:
workingDirectory: $(Build.SourcesDirectory)/SheepTools
script: |
git checkout master
git config --replace-all user.email "azure@devops.com"
git config --replace-all user.name "Azure DevOps"
git switch $(Build.SourceBranchName)
git status
git add -A
git commit -m "Release v$(PackageVersion)"
git commit -am "Release v$(PackageVersion)"
git tag -a v$(PackageVersion) -m "v$(PackageVersion)"
git push
git push --tags
4 changes: 2 additions & 2 deletions src/SheepTools.XUnit/SheepTools.XUnit.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<LangVersion>8.0</LangVersion>
<IsPackable>true</IsPackable>
<IsTestProject>false</IsTestProject>
<SonarQubeTestProject>false</SonarQubeTestProject>
<SonarQubeTestProject>false</SonarQubeTestProject>
</PropertyGroup>

<PropertyGroup>
Expand All @@ -30,7 +30,7 @@
</PropertyGroup>

<ItemGroup>
<None Include="$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)\..\..\resources\icon.png'))" Pack="true" PackagePath=""/>
<None Include="$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)\..\..\resources\icon.png'))" Pack="true" PackagePath="" />
</ItemGroup>

<PropertyGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/SheepTools/SheepTools.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
</PropertyGroup>

<ItemGroup>
<None Include="$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)\..\..\resources\icon.png'))" Pack="true" PackagePath=""/>
<None Include="$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)\..\..\resources\icon.png'))" Pack="true" PackagePath="" />
</ItemGroup>

<PropertyGroup>
Expand Down
4 changes: 2 additions & 2 deletions tests/SheepTools.Moq.Test/SheepTools.Moq.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="1.2.1">
<PackageReference Include="coverlet.collector" Version="1.3.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.msbuild" Version="2.8.1">
<PackageReference Include="coverlet.msbuild" Version="2.9.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
4 changes: 2 additions & 2 deletions tests/SheepTools.Test/SheepTools.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="1.2.1">
<PackageReference Include="coverlet.collector" Version="1.3.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.msbuild" Version="2.8.1">
<PackageReference Include="coverlet.msbuild" Version="2.9.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
4 changes: 2 additions & 2 deletions tests/SheepTools.XUnit.Test/SheepTools.XUnit.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="1.2.1">
<PackageReference Include="coverlet.collector" Version="1.3.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.msbuild" Version="2.8.1">
<PackageReference Include="coverlet.msbuild" Version="2.9.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down

0 comments on commit fa04c97

Please sign in to comment.