├── LICENSE
├── PiplineTemplate
├── ReadMe.md
└── SharpCollection.PipelineTemplate.json
├── README.md
├── ReleasePipeline
├── GitCommit.ps1
└── ReadMe.md
└── images
├── AccountInfo.png
└── OrgAndProject.png
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Red Siege
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/PiplineTemplate/ReadMe.md:
--------------------------------------------------------------------------------
1 | This template (SharpCollection.PipelineTemplate.json) can be used to create a new pipeline to build a .NET project. To use this template, you must have already signed up for a free or paid Azure DevOps account.
2 |
3 | # Overview
4 | This template will create a a new template to build a .NET executable from a GitHub project. The template will configure the pipeline to clone the repository, download any dependencies via NuGet, build executables for the `Any`, `x86`, and `x64` CPU targets, and build each of these executables for .NET 4.0, 4.5, and 4.7.
5 |
6 | # Creating an Organization and Project
7 | After creating and activating your account, you will need to create a new DevOps organization using the "New organization" link found in your DevOps homepage. In the example below, the organization name is **SiegeFactory**. After creating an organzation, you will create a new project using the "+ New Project" button in your DevOps homepage. In the example below, the project name is **SharpCollection**. You will also enter in a description for that project. In this example, the description is "Red Siege C# Tools Collection."
8 |
9 |
10 |
11 | # Connect your GitHub account
12 | If you have not already done so, the easiest way to connect your Azure DevOps account to your GitHub account is to create a new pipeline by clicking on the "New pipeline" button. Click the GitHub button. You will be prompted to log into your GitHub account. Save the connection to your Azure DevOps account and note the name used.
13 |
14 | # Modifying the template
15 | In order to use the new pipeline template, you will need to replace several placeholders in the template with with information about your Azure DevOps account, organization, project, and the GitHub project you wish to build:
16 |
17 | - GitHub Information
18 | - **###GHOrg###**
19 | - This placeholder is the GitHub organization name. For example, in https://github.com/RedSiege, RedSiege is the GitHub organization name. Replace ###GHOrg### with RedSiege.
20 |
21 | - **###GHProject###**
22 | - This is the placeholder for the GitHub project/repository name. For example, for this project, the replace ###GHProject### with SharpCollection.
23 |
24 | - **###GHProjectBranch###**
25 | - This is the default branch of the GitHub project you wish to build. This is typically set to `main` or `master.`
26 |
27 | - **###BuildName###**
28 | - In some cases, you may wish to use a different name to refer to the tool than the project name. For example, if a project contains multiple tools but you are only building one tool, replace ###BuildName### with the specific tool name. The ###BuildName### placeholder is used to populate the `$BuildName` pipeline variable.
29 |
30 | All Azure DevOps organization, project, and account information can be gathered using data you provided when creating your organization and project, or by viewing the page source of the Azure DevOps organization homepage.
31 |
32 | - Azure DevOps Information
33 | - **###AzOrg###**
34 | - This is the Azure DevOps organization name you created earlier. In the example above, the organization name was **SiegeFactory**.
35 |
36 | - **###AzProjectName###**
37 | - This is the name you gave the project you created. In the example above, the project name was **SharpCollection**.
38 |
39 | - **###AzProjectDescription###**
40 | - This is the description you gave the project you created. In the example above, the description was "Red Siege C# Tools Collection.
41 |
42 | - **###AzProjectUUID###**
43 | - Project information can be found by searching for `{"projects"` in the page source. Locate the `projectId` UUID and replace the **###AzProjectUUID##** placeholder with this value.
44 |
45 | - Azure DevOps Account Information
46 | - **###AzAccountID###**
47 | - This is the ID for your account, shown as #4 in the example below.
48 |
49 | - **###AzAccountURL###**
50 | - This is the URL for your Azure DevOps account. In the example below, the **##AzAccountUrl##** is shown as #2.
51 |
52 | - **###AzAccountDisplayName###**
53 | - This is the display name for your Azure DevOps account. In the example below (#1), the `displayName` is "Mike Saunders."
54 |
55 | - **###AzAvatarDescriptor###**
56 | - This is the unique ID for your avatar. In the example below, the descriptor is shown as #5.
57 |
58 | - **###AzAvatarURL###**
59 | - This is the URL for your Azure DevOps account avatar. It is shown as #3 in the example below.
60 |
61 |
62 |
63 | # Importing the pipeline template
64 | To import your modified pipeline template and create a new pipeline, open your Azure DevOps project by clicking on the project name in the Azure DevOps organization homepage. Click on the Pipelines icon on the left-hand side of the page. In the upper right-hand side of the page, next to the "New pipeline" button, click on the three vertical dots and select "Import a pipeline." Follow the dialog box to open your modified template and click the "Import" button to start the import process.
65 |
66 | The initial pipeline name will be `SharpCollection.###BuildName###-import`. For example, if you set **###BuildName###** to `Certify`, the initial pipeline name will be `SharpCollection.Certify-import.` Delete the "-import" from the pipeline name field. Select "Azure Pipelines" from the "Agent pool" dropdown. In some cases, it may be necessary to use the "windows-2022" or "windows-latest" agents, however you will typically want to select "windows-2019" from the "Agent Specification" dropdown.
67 |
68 | Select "Save & queue" from the top menu to save the pipeline and queue a build.
69 |
70 | # Adding artifacts to Organization
71 | Artifacts can be manually added to an Azure DevOps organization for use in pipelines. To upload artifacts to your organization, create a folder and place the items to upload in the folder. Then, using the Azure CLI, `cd` to the folder you created and use the command shown below. In this example, the Organization and feed names have been set to "ExampleFactory." The artifact name has been set to "example-executble." **Note:** Artifact names must be lowercase alphanumeric strings separated by a period, a dash, or a \\.
72 |
73 | ```
74 | az artifacts universal publish \
75 | --organization https://dev.azure.com/ExampleFactory/ \
76 | --feed ExampleFactory \
77 | --name example-executable \
78 | --version 0.0.1 \
79 | --description "Example executable" \
80 | --path .
81 | ```
82 |
83 |
--------------------------------------------------------------------------------
/PiplineTemplate/SharpCollection.PipelineTemplate.json:
--------------------------------------------------------------------------------
1 | {"options":[{"enabled":true,"definition":{"id":"5d58cc01-7c75-450c-be18-a388ddb129ec"},"inputs":{"branchFilters":"[\"+refs/heads/*\"]","additionalFields":"{}"}},{"enabled":false,"definition":{"id":"a9db38f9-9fdc-478c-b0f9-464221e58316"},"inputs":{"workItemType":"Issue","assignToRequestor":"true","additionalFields":"{}"}}],"triggers":[{"schedules":[{"branchFilters":["+main"],"timeZoneId":"UTC","startHours":3,"startMinutes":0,"daysToBuild":127,"scheduleJobId":"f37e49a8-19d6-411c-a0ac-c4a3d400278b","scheduleOnlyWithChanges":true}],"triggerType":8}],"variables":{"BuildConfiguration":{"value":"release","allowOverride":true},"BuildName":{"value":"SharpUp"},"BuildPath":{"value":"D:\\a\\1\\s"},"BuildPlatform":{"value":"any cpu","allowOverride":true},"system.debug":{"value":"false","allowOverride":true}},"properties":{},"tags":[],"_links":{"self":{"href":"https://dev.azure.com/###AzOrg###/###AzProjectUUID###/_apis/build/Definitions/43?revision=1"},"web":{"href":"https://dev.azure.com/###AzOrg###/###AzProjectUUID###/_build/definition?definitionId=43"},"editor":{"href":"https://dev.azure.com/###AzOrg###/###AzProjectUUID###/_build/designer?id=43&_a=edit-build-definition"},"badge":{"href":"https://dev.azure.com/###AzOrg###/###AzProjectUUID###/_apis/build/status/43"}},"buildNumberFormat":"$(date:yyyyMMdd)$(rev:.r)","comment":"test template","jobAuthorizationScope":1,"jobTimeoutInMinutes":60,"jobCancelTimeoutInMinutes":5,"badgeEnabled":true,"process":{"phases":[{"steps":[{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"Use NuGet 4.4.1","timeoutInMinutes":0,"retryCountOnTaskFailure":0,"condition":"succeeded()","task":{"id":"2c65196a-54fd-4a02-9be8-d9d1837b7c5d","versionSpec":"0.*","definitionType":"task"},"inputs":{"versionSpec":"4.4.1","checkLatest":"false"}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"NuGet restore","timeoutInMinutes":0,"retryCountOnTaskFailure":0,"condition":"succeeded()","task":{"id":"333b11bd-d341-40d9-afcf-b32d5ce6f23b","versionSpec":"2.*","definitionType":"task"},"inputs":{"command":"restore","solution":"$(Parameters.solution)","selectOrConfig":"select","feedRestore":"","includeNuGetOrg":"true","nugetConfigPath":"","externalEndpoints":"","noCache":"false","disableParallelProcessing":"false","packagesDirectory":"","verbosityRestore":"Detailed","searchPatternPush":"$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg","nuGetFeedType":"internal","feedPublish":"","publishPackageMetadata":"true","allowPackageConflicts":"false","externalEndpoint":"","verbosityPush":"Detailed","searchPatternPack":"**/*.csproj","configurationToPack":"$(BuildConfiguration)","outputDir":"$(Build.ArtifactStagingDirectory)","versioningScheme":"off","includeReferencedProjects":"false","versionEnvVar":"","requestedMajorVersion":"1","requestedMinorVersion":"0","requestedPatchVersion":"0","packTimezone":"utc","includeSymbols":"false","toolPackage":"false","buildProperties":"","basePath":"","verbosityPack":"Detailed","arguments":""}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"Build Target 4.5 Any","timeoutInMinutes":0,"retryCountOnTaskFailure":0,"condition":"succeeded()","task":{"id":"71a9a2d3-a98a-4caa-96ab-affca411ecda","versionSpec":"1.*","definitionType":"task"},"inputs":{"solution":"$(Parameters.solution)","vsVersion":"latest","msbuildArgs":"/p:TargetFrameworkVersion=v4.5","platform":"Any CPU","configuration":"$(BuildConfiguration)","clean":"false","maximumCpuCount":"false","restoreNugetPackages":"false","msbuildArchitecture":"x64","logProjectEvents":"true","createLogFile":"false","logFileVerbosity":"normal","enableDefaultLogger":"true","customVersion":""}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":true,"displayName":"Publish Artifact 4.5 Any","timeoutInMinutes":0,"retryCountOnTaskFailure":0,"condition":"succeededOrFailed()","task":{"id":"2ff763a7-ce83-4e1f-bc89-0ae63477cebe","versionSpec":"1.*","definitionType":"task"},"inputs":{"PathtoPublish":"$(BuildPath)\\$(BuildName)\\bin\\Release\\$(BuildName).exe","ArtifactName":"net_4.5_Any","ArtifactType":"Container","MaxArtifactSize":"0","TargetPath":"\\\\my\\share\\$(Build.DefinitionName)\\$(Build.BuildNumber)","Parallel":"false","ParallelCount":"8","StoreAsTar":"false"}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"Build Target 4.7 Any ","timeoutInMinutes":0,"retryCountOnTaskFailure":0,"condition":"succeeded()","task":{"id":"71a9a2d3-a98a-4caa-96ab-affca411ecda","versionSpec":"1.*","definitionType":"task"},"inputs":{"solution":"$(Parameters.solution)","vsVersion":"latest","msbuildArgs":"/p:TargetFrameworkVersion=v4.7","platform":"Any CPU","configuration":"$(BuildConfiguration)","clean":"false","maximumCpuCount":"false","restoreNugetPackages":"false","msbuildArchitecture":"x64","logProjectEvents":"true","createLogFile":"false","logFileVerbosity":"normal","enableDefaultLogger":"true","customVersion":""}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":true,"displayName":"Publish Artifact 4.7 Any","timeoutInMinutes":0,"retryCountOnTaskFailure":0,"condition":"succeededOrFailed()","task":{"id":"2ff763a7-ce83-4e1f-bc89-0ae63477cebe","versionSpec":"1.*","definitionType":"task"},"inputs":{"PathtoPublish":"$(BuildPath)\\$(BuildName)\\bin\\Release\\$(BuildName).exe","ArtifactName":"net_4.7_Any","ArtifactType":"Container","MaxArtifactSize":"0","TargetPath":"\\\\my\\share\\$(Build.DefinitionName)\\$(Build.BuildNumber)","Parallel":"false","ParallelCount":"8","StoreAsTar":"false"}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"Build Target 4.0 Any","timeoutInMinutes":0,"retryCountOnTaskFailure":0,"condition":"succeeded()","task":{"id":"71a9a2d3-a98a-4caa-96ab-affca411ecda","versionSpec":"1.*","definitionType":"task"},"inputs":{"solution":"$(Parameters.solution)","vsVersion":"latest","msbuildArgs":"/p:TargetFrameworkVersion=v4.0","platform":"Any CPU","configuration":"$(BuildConfiguration)","clean":"false","maximumCpuCount":"false","restoreNugetPackages":"false","msbuildArchitecture":"x64","logProjectEvents":"true","createLogFile":"false","logFileVerbosity":"normal","enableDefaultLogger":"true","customVersion":""}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":true,"displayName":"Publish Artifact 4.0 Any","timeoutInMinutes":0,"retryCountOnTaskFailure":0,"condition":"succeededOrFailed()","task":{"id":"2ff763a7-ce83-4e1f-bc89-0ae63477cebe","versionSpec":"1.*","definitionType":"task"},"inputs":{"PathtoPublish":"$(BuildPath)\\$(BuildName)\\bin\\Release\\$(BuildName).exe","ArtifactName":"net_4.0_Any","ArtifactType":"Container","MaxArtifactSize":"0","TargetPath":"\\\\my\\share\\$(Build.DefinitionName)\\$(Build.BuildNumber)","Parallel":"false","ParallelCount":"8","StoreAsTar":"false"}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"PowerShell Script","timeoutInMinutes":0,"retryCountOnTaskFailure":0,"condition":"succeeded()","task":{"id":"e213ff0f-5d5c-4791-802d-52ea3e7be1f1","versionSpec":"2.*","definitionType":"task"},"inputs":{"targetType":"inline","filePath":"","arguments":"","script":"\n$mainPath = \"$(BuildPath)\\$(BuildName).sln\"\n$XMLfile = \"$(BuildPath)\\$(BuildName)\\$(BuildName).csproj\"\n\n\n\nfunction InsertBuildConfigCsProjc{\n\n\n[XML]$empDetails = Get-Content $XMLfile\n\nforeach($propertyGroup in $empDetails.Project.PropertyGroup){\n\nif($propertyGroup.OutputPath){\n$reffObject = $propertyGroup\n}\n\nif($propertyGroup.ItemGroup.Reference){\n$referenceObject = $propertyGroup.ItemGroup.Reference\n}\n\n\n}\n\nif($reffObject.PlatformTarget){\n$reffObject.PlatformTarget = \"x64\"\n}\n\n$reffObject.OutputPath = \"bin\\x64\\Debug\\\"\n$reffObject.Condition = \"'`$(Configuration)|`$(Platform)' == 'Debug|x64'\"\n\n$debug64 = $empDetails.ImportNode($reffObject, $true)\n$empDetails.Project.PrependChild($debug64)\n\nif($reffObject.PlatformTarget){\n$reffObject.PlatformTarget = \"x64\"\n}\n$reffObject.OutputPath = \"bin\\x64\\Release\\\"\n$reffObject.Condition = \"'`$(Configuration)|`$(Platform)' == 'Release|x64'\"\n\n$rel64 = $empDetails.ImportNode($reffObject, $true)\n$empDetails.Project.PrependChild($rel64)\n\nif($reffObject.PlatformTarget){\n$reffObject.PlatformTarget = \"x86\"\n}\n$reffObject.OutputPath = \"bin\\x86\\Debug\\\"\n$reffObject.Condition = \"'`$(Configuration)|`$(Platform)' == 'Debug|x86'\"\n\n$debug32 = $empDetails.ImportNode($reffObject, $true)\n$empDetails.Project.PrependChild($debug32)\n\n\nif($reffObject.PlatformTarget){\n$reffObject.PlatformTarget = \"x86\"\n}\n$reffObject.OutputPath = \"bin\\x86\\Release\\\"\n$reffObject.Condition = \"'`$(Configuration)|`$(Platform)' == 'Release|x86'\"\n\n$rel32 = $empDetails.ImportNode($reffObject, $true)\n$empDetails.Project.PrependChild($rel32)\n\n\nif($reffObject.PlatformTarget){\n$reffObject.PlatformTarget = \"Any CPU\"\n}\n$reffObject.OutputPath = \"bin\\Release\\\"\n$reffObject.Condition = \"'`$(Configuration)|`$(Platform)' == 'Release|Any CPU'\"\n\n$relAny = $empDetails.ImportNode($reffObject, $true)\n$empDetails.Project.PrependChild($relAny)\n\nWrite-Host $empDetails.OuterXml\n\n$empDetails.Save($XMLfile) \n\n}\n\nfunction GetStringBetweenTwoStrings($firstString, $secondString){\n#Get content from file\n$file = Get-Content $mainPath\n#Regex pattern to compare two strings\n$pattern = \",..{(.*?)..EndProject\"\n#Perform the opperation\n$result = [regex]::Match($file,$pattern).Groups[1].Value\n#Return result\nreturn $result\n}\n\nfunction InsertBuildConfigSlnProjc{\n\n\n$stringHolder = \"\"\n$trigger = $false\n#Get-Content \nGet-Content $mainPath | ForEach-Object {\nif($_ -match \"EndProject\" -And !$trigger ){\n$projectGuid = GetStringBetweenTwoStrings(\"{\", \"}\" )\n# Work here\n$stringHolder += @\"\nEndProject\nGlobal\n GlobalSection(SolutionConfigurationPlatforms) = preSolution\n Debug|Any CPU = Debug|Any CPU\n Debug|x64 = Debug|x64\n Debug|x86 = Debug|x86\n Release|Any CPU = Release|Any CPU\n Release|x64 = Release|x64\n Release|x86 = Release|x86\n EndGlobalSection\n GlobalSection(ProjectConfigurationPlatforms) = postSolution\n {REPLACEGUID.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n {REPLACEGUID.Debug|Any CPU.Build.0 = Debug|Any CPU\n {REPLACEGUID.Debug|x64.ActiveCfg = Debug|x64\n {REPLACEGUID.Debug|x64.Build.0 = Debug|x64\n {REPLACEGUID.Debug|x86.ActiveCfg = Debug|x86\n {REPLACEGUID.Debug|x86.Build.0 = Debug|x86\n {REPLACEGUID.Release|Any CPU.ActiveCfg = Release|Any CPU\n {REPLACEGUID.Release|Any CPU.Build.0 = Release|Any CPU\n {REPLACEGUID.Release|x64.ActiveCfg = Release|x64\n {REPLACEGUID.Release|x64.Build.0 = Release|x64\n {REPLACEGUID.Release|x86.ActiveCfg = Release|x86\n {REPLACEGUID.Release|x86.Build.0 = Release|x86\n EndGlobalSection\n \n\"@\n$stringHolder = $stringHolder.Replace(\"REPLACEGUID\",$projectGuid)\n$trigger = $true\n}\nif($trigger){\n if($_ -match \"SolutionProperties\"){\n$trigger = $false\n }\n}\nif(!$trigger){\n $stringHolder += $_ + \"`n\"\n }\n}\n#Write-Host $stringHolder\nSet-Content -Path $mainPath -Value $stringHolder\n\n\n}\n\nInsertBuildConfigCsProjc\nInsertBuildConfigSlnProjc","errorActionPreference":"stop","warningPreference":"default","informationPreference":"default","verbosePreference":"default","debugPreference":"default","progressPreference":"silentlyContinue","failOnStderr":"false","showWarnings":"false","ignoreLASTEXITCODE":"false","pwsh":"false","workingDirectory":"","runScriptInSeparateScope":"false"}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"Build Target 4.5 x64","timeoutInMinutes":0,"retryCountOnTaskFailure":0,"condition":"succeeded()","task":{"id":"71a9a2d3-a98a-4caa-96ab-affca411ecda","versionSpec":"1.*","definitionType":"task"},"inputs":{"solution":"$(Parameters.solution)","vsVersion":"latest","msbuildArgs":"/p:TargetFrameworkVersion=v4.5","platform":"x64","configuration":"$(BuildConfiguration)","clean":"false","maximumCpuCount":"false","restoreNugetPackages":"false","msbuildArchitecture":"x64","logProjectEvents":"true","createLogFile":"false","logFileVerbosity":"normal","enableDefaultLogger":"true","customVersion":""}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":true,"displayName":"Publish Artifact 4.5 x64","timeoutInMinutes":0,"retryCountOnTaskFailure":0,"condition":"succeededOrFailed()","task":{"id":"2ff763a7-ce83-4e1f-bc89-0ae63477cebe","versionSpec":"1.*","definitionType":"task"},"inputs":{"PathtoPublish":"$(BuildPath)\\$(BuildName)\\bin\\x64\\Release\\$(BuildName).exe","ArtifactName":"net_4.5_64","ArtifactType":"Container","MaxArtifactSize":"0","TargetPath":"\\\\my\\share\\$(Build.DefinitionName)\\$(Build.BuildNumber)","Parallel":"false","ParallelCount":"8","StoreAsTar":"false"}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"Build Target 4.5 x86","timeoutInMinutes":0,"retryCountOnTaskFailure":0,"condition":"succeeded()","task":{"id":"71a9a2d3-a98a-4caa-96ab-affca411ecda","versionSpec":"1.*","definitionType":"task"},"inputs":{"solution":"$(Parameters.solution)","vsVersion":"latest","msbuildArgs":"/p:TargetFrameworkVersion=v4.5","platform":"x86","configuration":"$(BuildConfiguration)","clean":"false","maximumCpuCount":"false","restoreNugetPackages":"false","msbuildArchitecture":"x86","logProjectEvents":"true","createLogFile":"false","logFileVerbosity":"normal","enableDefaultLogger":"true","customVersion":""}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":true,"displayName":"Publish Artifact: 4.5 x86","timeoutInMinutes":0,"retryCountOnTaskFailure":0,"condition":"succeededOrFailed()","task":{"id":"2ff763a7-ce83-4e1f-bc89-0ae63477cebe","versionSpec":"1.*","definitionType":"task"},"inputs":{"PathtoPublish":"$(BuildPath)\\$(BuildName)\\bin\\x86\\Release\\$(BuildName).exe","ArtifactName":"net_4.5_32","ArtifactType":"Container","MaxArtifactSize":"0","TargetPath":"\\\\my\\share\\$(Build.DefinitionName)\\$(Build.BuildNumber)","Parallel":"false","ParallelCount":"8","StoreAsTar":"false"}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"Build Target 4.0 x86","timeoutInMinutes":0,"retryCountOnTaskFailure":0,"condition":"succeeded()","task":{"id":"71a9a2d3-a98a-4caa-96ab-affca411ecda","versionSpec":"1.*","definitionType":"task"},"inputs":{"solution":"$(Parameters.solution)","vsVersion":"latest","msbuildArgs":"/p:TargetFrameworkVersion=v4.0","platform":"x86","configuration":"$(BuildConfiguration)","clean":"false","maximumCpuCount":"false","restoreNugetPackages":"false","msbuildArchitecture":"x86","logProjectEvents":"true","createLogFile":"false","logFileVerbosity":"normal","enableDefaultLogger":"true","customVersion":""}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":true,"displayName":"Publish Artifact: 4.0 x86","timeoutInMinutes":0,"retryCountOnTaskFailure":0,"condition":"succeededOrFailed()","task":{"id":"2ff763a7-ce83-4e1f-bc89-0ae63477cebe","versionSpec":"1.*","definitionType":"task"},"inputs":{"PathtoPublish":"$(BuildPath)\\$(BuildName)\\bin\\x86\\Release\\$(BuildName).exe","ArtifactName":"net_4.0_32","ArtifactType":"Container","MaxArtifactSize":"0","TargetPath":"\\\\my\\share\\$(Build.DefinitionName)\\$(Build.BuildNumber)","Parallel":"false","ParallelCount":"8","StoreAsTar":"false"}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"Build Target 4.0 x64","timeoutInMinutes":0,"retryCountOnTaskFailure":0,"condition":"succeeded()","task":{"id":"71a9a2d3-a98a-4caa-96ab-affca411ecda","versionSpec":"1.*","definitionType":"task"},"inputs":{"solution":"$(Parameters.solution)","vsVersion":"latest","msbuildArgs":"/p:TargetFrameworkVersion=v4.0","platform":"x64","configuration":"$(BuildConfiguration)","clean":"false","maximumCpuCount":"false","restoreNugetPackages":"false","msbuildArchitecture":"x64","logProjectEvents":"true","createLogFile":"false","logFileVerbosity":"normal","enableDefaultLogger":"true","customVersion":""}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":true,"displayName":"Publish Artifact: 4.0 x64","timeoutInMinutes":0,"retryCountOnTaskFailure":0,"condition":"succeededOrFailed()","task":{"id":"2ff763a7-ce83-4e1f-bc89-0ae63477cebe","versionSpec":"1.*","definitionType":"task"},"inputs":{"PathtoPublish":"$(BuildPath)\\$(BuildName)\\bin\\x64\\Release\\$(BuildName).exe","ArtifactName":"net_4.0_64","ArtifactType":"Container","MaxArtifactSize":"0","TargetPath":"\\\\my\\share\\$(Build.DefinitionName)\\$(Build.BuildNumber)","Parallel":"false","ParallelCount":"8","StoreAsTar":"false"}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"Build Target 4.7 x86","timeoutInMinutes":0,"retryCountOnTaskFailure":0,"condition":"succeeded()","task":{"id":"71a9a2d3-a98a-4caa-96ab-affca411ecda","versionSpec":"1.*","definitionType":"task"},"inputs":{"solution":"$(Parameters.solution)","vsVersion":"latest","msbuildArgs":"/p:TargetFrameworkVersion=v4.7","platform":"x86","configuration":"$(BuildConfiguration)","clean":"false","maximumCpuCount":"false","restoreNugetPackages":"false","msbuildArchitecture":"x86","logProjectEvents":"true","createLogFile":"false","logFileVerbosity":"normal","enableDefaultLogger":"true","customVersion":""}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":true,"displayName":"Publish Artifact: 4.7 x86","timeoutInMinutes":0,"retryCountOnTaskFailure":0,"condition":"succeededOrFailed()","task":{"id":"2ff763a7-ce83-4e1f-bc89-0ae63477cebe","versionSpec":"1.*","definitionType":"task"},"inputs":{"PathtoPublish":"$(BuildPath)\\$(BuildName)\\bin\\x86\\Release\\$(BuildName).exe","ArtifactName":"net_4.7_32","ArtifactType":"Container","MaxArtifactSize":"0","TargetPath":"\\\\my\\share\\$(Build.DefinitionName)\\$(Build.BuildNumber)","Parallel":"false","ParallelCount":"8","StoreAsTar":"false"}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":false,"displayName":"Build Target 4.7 x64 ","timeoutInMinutes":0,"retryCountOnTaskFailure":0,"condition":"succeeded()","task":{"id":"71a9a2d3-a98a-4caa-96ab-affca411ecda","versionSpec":"1.*","definitionType":"task"},"inputs":{"solution":"$(Parameters.solution)","vsVersion":"latest","msbuildArgs":"/p:TargetFrameworkVersion=v4.7","platform":"x64","configuration":"$(BuildConfiguration)","clean":"false","maximumCpuCount":"false","restoreNugetPackages":"false","msbuildArchitecture":"x64","logProjectEvents":"true","createLogFile":"false","logFileVerbosity":"normal","enableDefaultLogger":"true","customVersion":""}},{"environment":{},"enabled":true,"continueOnError":false,"alwaysRun":true,"displayName":"Publish Artifact: 4.7 x64 ","timeoutInMinutes":0,"retryCountOnTaskFailure":0,"condition":"succeededOrFailed()","task":{"id":"2ff763a7-ce83-4e1f-bc89-0ae63477cebe","versionSpec":"1.*","definitionType":"task"},"inputs":{"PathtoPublish":"$(BuildPath)\\$(BuildName)\\bin\\x64\\Release\\$(BuildName).exe","ArtifactName":"net_4.7_64","ArtifactType":"Container","MaxArtifactSize":"0","TargetPath":"\\\\my\\share\\$(Build.DefinitionName)\\$(Build.BuildNumber)","Parallel":"false","ParallelCount":"8","StoreAsTar":"false"}}],"name":"Build SharpTool","refName":"Job_1","condition":"succeeded()","target":{"executionOptions":{"type":0},"allowScriptsAuthAccessOption":false,"type":1},"jobAuthorizationScope":1}],"target":{"agentSpecification":{"identifier":"windows-2019"}},"type":1},"repository":{"properties":{"apiUrl":"https://api.github.com/repos/###GHOrg###/###GHProject###","branchesUrl":"https://api.github.com/repos/###GHOrg###/###GHProject###/branches","cloneUrl":"https://api.github.com/repos/###GHOrg###/###GHProject###.git","connectedServiceId":"6d18758c-4615-401c-9f8f-5be3ac418b6c","defaultBranch":"master","fullName":"GhostPack/SharpUp","hasAdminPermissions":"False","isFork":"False","isPrivate":"False","lastUpdated":"01/16/2023 00:54:43","manageUrl":"https://github.com/GhostPack/SharpUp","nodeId":"MDEwOlJlcG9zaXRvcnkxNDIxOTI1MjA=","ownerId":"41304335","orgName":"GhostPack","refsUrl":"https://api.github.com/repos/###GHOrg###/###GHProject###/git/refs","safeRepository":"GhostPack/SharpUp","shortName":"SharpUp","ownerAvatarUrl":"https://avatars.githubusercontent.com/u/41304335?v=4","archived":"False","externalId":"142192520","ownerIsAUser":"False","checkoutNestedSubmodules":"false","cleanOptions":"0","fetchDepth":"0","gitLfsSupport":"false","reportBuildStatus":"false","skipSyncSource":"false","fetchTags":"true","labelSourcesFormat":"$(build.buildNumber)","labelSources":"0"},"id":"GhostPack/SharpUp","type":"GitHub","name":"GhostPack/SharpUp","url":"https://api.github.com/repos/###GHOrg###/###GHProject###.git","defaultBranch":"refs/heads/master","clean":"true","checkoutSubmodules":false},"processParameters":{"inputs":[{"aliases":[],"options":{},"properties":{},"name":"solution","label":"Solution","defaultValue":"**\\*.sln","required":true,"type":"filePath","helpMarkDown":"The path to the Visual Studio solution file or NuGet packages.config. Wildcards can be used. For example, `**\\\\*.sln` for all sln files in all sub folders."}]},"quality":1,"authoredBy":{"displayName":"authoredBy":{"displayName":"###AzAccountDisplayName###","url":"###AzAccountURL###","_links":{"avatar":{"href":"###AzAvatarURL###"}},"id":"###AzAccountID###","uniqueName":"###AzAccountEmail###","imageUrl":"###AzAvatarURL###","descriptor":"###AzAvatarDescriptor###"},"drafts":[],"queue":{"_links":{"self":{"href":"https://dev.azure.com/###AzOrg###/_apis/build/Queues/18"}},"id":18,"name":"Azure Pipelines","url":"https://dev.azure.com/###AzOrg###/_apis/build/Queues/18","pool":{"id":9,"name":"Azure Pipelines","isHosted":true}},"id":3,"name":"SharpCollection.###BuildName###","url":"https://dev.azure.com/###AzOrg###/###AzProjectUUID###/_apis/build/Definitions/3?revision=3","uri":"vstfs:///Build/Definition/3","path":"\\","type":2,"queueStatus":0,"revision":3,"createdDate":"2023-01-16T23:31:21.350Z","project":{"id":"###AzProjectUUID###","name":"###AzProjectName###","description":"###AzProjectDescription###","url":"https://dev.azure.com/###AzOrg###/_apis/projects/###AzProjectUUID###","state":1,"revision":19,"visibility":0,"lastUpdateTime":"2023-01-16T19:45:53.320Z"}}
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SharpCollectionTemplate
2 | A template for quickly building .NET tooling in Azure DevOps Pipelines
3 | ---
4 | This project was adapted from [@Flangvik](https://twitter.com/Flangvik) [SharpCollection](https://github.com/Flangvik/SharpCollection). All credit goes to Flangvik. I've just cleaned up the templates a bit and put in placeholders for you to substitute your own information.
5 |
6 | References
7 | * [Video overview and demonstration](https://www.youtube.com/watch?v=BbXRfMNjwg0)
8 | * [SharpCollection JSON Template](https://gist.githubusercontent.com/Flangvik/9b6ec18a1624025fcd15cf00bca62040/raw/79a4cf52f31c11c9af077240bd038b6c459f3674/SharepCollectioJson)
9 | * [PowerShell .NET Version Parser](https://gist.githubusercontent.com/Flangvik/c14e0387f72d111f4cbcbe27c30ca05c/raw/b229636a838fafc4a5970117e328f8840a635b11/gistfile1.txt)
10 |
11 | ## Refer to the ReadMe.md in the PiplineTemplate and ReleasePipeline directories for additional guidance on how to use this repository.
12 |
--------------------------------------------------------------------------------
/ReleasePipeline/GitCommit.ps1:
--------------------------------------------------------------------------------
1 | #Get all binary artifacts
2 | #Make sure you go to Agent Job -> Scroll down and check "Allow scripts to access the OAuth token"
3 | $binaryPaths = Get-ChildItem -Path "D:\a\r1\a\_SharpCollection.*" -Filter *.exe -r
4 |
5 | #Move into git repo
6 | cd "D:/a/r1/a/_YourAzureDevOpsOrg_SharpCollection\"
7 |
8 | #Prep config
9 | git config --global user.email "youremail@domain.tld"
10 | git config --global user.name "Azure Dev Ops Pipeline"
11 | git checkout main
12 |
13 | foreach ($binary in $binaryPaths ) {
14 |
15 | if ($binary -like '*net_4.0_32*') {
16 | $artifactName = (Split-Path -Path $binary -Leaf).Replace("net_4.0_32","").Split(".")[0]+ ".exe"
17 | Copy-Item $binary -Destination "D:\a\r1\a\_YourAzureDevOpsOrg_SharpCollection\NetFramework_4.0_x86\$artifactName"
18 | Write-Host "Moving $binary to D:\a\r1\a\_YourAzureDevOpsOrg_SharpCollection\NetFramework_4.0_x86\$artifactName"
19 | }
20 |
21 | if ($binary -like '*net_4.0_64*') {
22 | $artifactName = (Split-Path -Path $binary -Leaf).Replace("net_4.0_64","").Split(".")[0]+ ".exe"
23 | Copy-Item $binary -Destination "D:\a\r1\a\_YourAzureDevOpsOrg_SharpCollection\NetFramework_4.0_x64\$artifactName"
24 | Write-Host "Moving $binary to D:\a\r1\a\_YourAzureDevOpsOrg_SharpCollection\NetFramework_4.0_x64\$artifactName"
25 | }
26 |
27 | if ($binary -like '*net_4.0_Any*') {
28 | $artifactName = (Split-Path -Path $binary -Leaf).Replace("net_4.0_Any","").Split(".")[0]+ ".exe"
29 | Copy-Item $binary -Destination "D:\a\r1\a\_YourAzureDevOpsOrg_SharpCollection\NetFramework_4.0_Any\$artifactName"
30 | Write-Host "Moving $binary to D:\a\r1\a\_YourAzureDevOpsOrg_SharpCollection\NetFramework_4.0_Any\$artifactName"
31 | }
32 |
33 | if ($binary -like '*net_4.5_32*') {
34 | $artifactName = (Split-Path -Path $binary -Leaf).Replace("net_4.5_32","").Split(".")[0]+ ".exe"
35 | Copy-Item $binary -Destination "D:\a\r1\a\_YourAzureDevOpsOrg_SharpCollection\NetFramework_4.5_x86\$artifactName"
36 | Write-Host "Moving $binary to D:\a\r1\a\_YourAzureDevOpsOrg_SharpCollection\NetFramework_4.5_x86\$artifactName"
37 | }
38 |
39 | if ($binary -like '*net_4.5_64*') {
40 | $artifactName = (Split-Path -Path $binary -Leaf).Replace("net_4.5_64","").Split(".")[0]+ ".exe"
41 | Copy-Item $binary -Destination "D:\a\r1\a\_YourAzureDevOpsOrg_SharpCollection\NetFramework_4.5_x64\$artifactName"
42 | Write-Host "Moving $binary to D:\a\r1\a\_YourAzureDevOpsOrg_SharpCollection\NetFramework_4.5_x64\$artifactName"
43 | }
44 |
45 | if ($binary -like '*net_4.5_Any*') {
46 | $artifactName = (Split-Path -Path $binary -Leaf).Replace("net_4.5_Any","").Split(".")[0]+ ".exe"
47 | Copy-Item $binary -Destination "D:\a\r1\a\_YourAzureDevOpsOrg_SharpCollection\NetFramework_4.5_Any\$artifactName"
48 | Write-Host "Moving $binary to D:\a\r1\a\_YourAzureDevOpsOrg_SharpCollection\NetFramework_4.5_Any\$artifactName"
49 | }
50 |
51 | if ($binary -like '*net_4.7_64*') {
52 | $artifactName = (Split-Path -Path $binary -Leaf).Replace("net_4.7_64","").Split(".")[0]+ ".exe"
53 | Copy-Item $binary -Destination "D:\a\r1\a\_YourAzureDevOpsOrg_SharpCollection\NetFramework_4.7_x64\$artifactName"
54 | Write-Host "Moving $binary to D:\a\r1\a\_YourAzureDevOpsOrg_SharpCollection\NetFramework_4.7_x64\$artifactName"
55 | }
56 |
57 | if ($binary -like '*net_4.7_32*') {
58 | $artifactName = (Split-Path -Path $binary -Leaf).Replace("net_4.7_32","").Split(".")[0]+ ".exe"
59 | Copy-Item $binary -Destination "D:\a\r1\a\_YourAzureDevOpsOrg_SharpCollection\NetFramework_4.7_x86\$artifactName"
60 | Write-Host "Moving $binary to D:\a\r1\a\_YourAzureDevOpsOrg_SharpCollection\NetFramework_4.7_x86\$artifactName"
61 | }
62 |
63 | if ($binary -like '*net_4.7_Any*') {
64 | $artifactName = (Split-Path -Path $binary -Leaf).Replace("net_4.7_Any","").Split(".")[0]+ ".exe"
65 | Copy-Item $binary -Destination "D:\a\r1\a\_YourAzureDevOpsOrg_SharpCollection\NetFramework_4.7_Any\$artifactName"
66 | Write-Host "Moving $binary to D:\a\r1\a\_YourAzureDevOpsOrg_SharpCollection\NetFramework_4.7_Any\$artifactName"
67 | }
68 |
69 | cd "D:\a\r1\a\_YourAzureDevOpsOrg_SharpCollection\"
70 | git add .
71 | git commit -m "Added latest release of $artifactName"
72 | git push origin main
73 | }
74 |
75 | $gitPaths = Get-ChildItem -Path "D:\a\r1\a\" -Recurse
76 | foreach ($gitBinary in $gitPaths ) {
77 | Write-Host $gitBinary.FullName
78 | }
79 |
--------------------------------------------------------------------------------
/ReleasePipeline/ReadMe.md:
--------------------------------------------------------------------------------
1 | # Overview
2 | Release pipelines can be used to package completed builds into a release. For the purposes of the build pipeline, this means collecting the build artifacts (executables) for successful builds and publishing them to a GitHub repository.
3 |
4 | # Dependencies
5 | For pushing to GitHub, you will need a GitHub repository you control, and you will need to configure an OAuth token in Azure DevOps to allow access to your GitHub repositories. This should already be completed if you have created a build pipeline.
6 |
7 | ## Modifying GitCommit.ps1
8 | You will need to make several changes to this script. If your Azure DevOps project is not named "SharpCollection," you will need to modify the `$binaryPaths` variable on line 3 and change "SharpCollection" to your project name.
9 |
10 | The GitCommit.ps1 script is configured to publish to the YourAzureDevOpsOrg SharpCollection repository. This is referred to in the script as `\_YourAzureDevOpsOrg\_SharpCollection`. If your GitHub username is `LittleBobbyTables` and your repository is named `MySharpTools`, you would replace all instances of `\_LittleBobbyTables\_MySharpTools` with
11 |
12 | Change the `user.email` and `user.name` values on lines 9 and 10 to match your GitHub account.
13 |
14 | # Building a Release Pipeline
15 | - From the left-hand menu, select the Pipelines icon, then select Releases from the Pipelines menu. Click the "+ New" menu and select "+ New Release Pipeline" from the dropdown. In the template selection window, select "Empty job." When prompted, enter "Publish to GitHub" for the stage name."
16 | - From the Artifacts section, click "+ Add" to add an artifact. Select the GitHub icon. From the Service menu, select the GitHub connection you associated with Azure DevOps. If you have not previously configured an OAuth connection, you can create a new connection using the "+ New" menu and following the prompts. In the "Source (repository)" menu, enter the organization name and repository information. For example, to use the YourAzureDevOpsOrg SharpCollection repository, enter `YourAzureDevOpsOrg/SharpCollection`. **Note:** Do not enter the full URL. Enter only the organization name and repository name.
17 | - Select the default branch to use from the "Default branch" menu.
18 | - Select "Lates from the default branch" from the "Default version" menu.
19 | - Define a "Source alias" that will be referred to by your publisher script. The default name will be "\_OrgName\_RepositoryName."
20 | - Click "Add"
21 |
22 | You will now need to add the artifact collection for each pipeline you have configured.
23 | - From the Artifacts section, click "+ Add" to add an artifact. Select the "Build" source type. Select the appropriate Project from the dropdown. For the YourAzureDevOpsOrg SharpCollection pipeline, the Project would be SharpCollection. Select the desired source from the "Source (build pipeline)" dropdown. Repeat this process for each pipeline you wish to publish.
24 | - Leave the "Default version" dropdown at the default of "Latest."
25 | - Leave the "Source alias" entry as the default.
26 | - Click "Add"
27 | - Click the lightning bolt icon on the newly-created artifact and set the configuration slider for the "Continuous deployment trigger" to Enabled. This will cause the release pipeline to fire each time a new build is available.
28 |
29 | To configure the publication stage:
30 | - Click on the "Tasks" menu near the top of the page.
31 | - Click the "+" icon on the "Agent job" task.
32 | - From the Utility task menu, scroll and select "PowerShell" and click the Add button.
33 | - Click on the new PowerShell task to configure it.
34 | - If desired, change the "Display name" to something more descriptive, such as "Publish artifacts to GitHub."
35 | - Select the "Inline" radio button
36 | - Paste the contets of GitCommit.ps1 into the script pane.
37 | - Click "Save" near the top right.
38 |
39 | # Creating and publish a release
40 | - To create a release, select the "Create release" button near the top right-hand side of the page.
41 | - Click on the stage name. Alternatively, select the Stage name from the "Stages for a trigger change from automated to manual" dropbox.
42 | - Click Create.
43 | - Near the top of the page, you will see a message saying "Release \"Release-\#\#\" has been created". Click on the "Release-\#\#" to access the next phase.
44 | - From the Stages section, hover over your stage name and select the Deploy icon that appears below.
45 | - If necessary, scroll to the bottom of the page and select the Deploy button.
46 |
47 |
--------------------------------------------------------------------------------
/images/AccountInfo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RedSiege/SharpCollectionTemplate/13627e52e0b28a75adf839742d3b9a766dcd5173/images/AccountInfo.png
--------------------------------------------------------------------------------
/images/OrgAndProject.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RedSiege/SharpCollectionTemplate/13627e52e0b28a75adf839742d3b9a766dcd5173/images/OrgAndProject.png
--------------------------------------------------------------------------------