-
Notifications
You must be signed in to change notification settings - Fork 22
/
Expand-Template.ps1
179 lines (159 loc) · 6.61 KB
/
Expand-Template.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
<#
.SYNOPSIS
Expands this template into an actual project, taking values for placeholders
.PARAMETER LibraryName
The name of the library. Should consist only of alphanumeric characters and periods.
.PARAMETER Author
The name to use in copyright and owner notices.
.PARAMETER CodeCovToken
A token obtained from codecov.io for your repo. If not specified, code coverage results will not be published to codecov.io,
but can be added later by editing the Azure Pipelines YAML file.
.PARAMETER CIFeed
The `/{guid}` path to the Azure Pipelines artifact feed to push your nuget package to as part of your CI.
.PARAMETER Squash
A switch that causes all of git history to be squashed to just one initial commit for the template, and one for its expansion.
#>
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[string]$LibraryName,
[Parameter(Mandatory=$true)]
[string]$Author,
[Parameter()]
[string]$CodeCovToken,
[Parameter()]
[string]$CIFeed,
[Parameter()]
[switch]$Squash
)
function Replace-Placeholders {
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]$Path,
[Parameter(Mandatory=$true)]
$Replacements
)
$Path = Resolve-Path $Path
Write-Host "Replacing tokens in `"$Path`""
$content = Get-Content -Path $Path | Out-String
$Replacements.GetEnumerator() |% {
$modifiedContent = $content -replace $_.Key,$_.Value
if ($modifiedContent -eq $content) {
Write-Error "No $($_.Key) token found to replace."
}
$content = $modifiedContent
}
$content = $content.TrimEnd(("`r","`n"))
[System.IO.File]::WriteAllLines($Path, $content) # Don't use Set-Content because that adds a UTF8 BOM
git add $Path
}
# Try to find sn.exe if it isn't on the PATH
$sn = Get-Command sn -ErrorAction SilentlyContinue
if (-not $sn) {
$snExes = Get-ChildItem -Recurse "${env:ProgramFiles(x86)}\Microsoft SDKs\Windows\sn.exe"
if ($snExes) {
$sn = Get-Command $snExes[0].FullName
} else {
Write-Error "sn command not found on PATH and SDK could not be found."
exit(1)
}
}
# Verify all commands we use are on the PATH
('git','dotnet') |% {
if (-not (Get-Command $_ -ErrorAction SilentlyContinue)) {
Write-Error "$_ command not found on PATH."
exit(1)
}
}
Push-Location $PSScriptRoot
try {
if ($Squash) {
$originalCommitId = git rev-parse HEAD
git reset --soft $(git rev-list --max-parents=0 HEAD)
git commit --amend -qm "Initial template from https://github.com/AArnott/Library.Template" -m "Original commit from template $originalCommitId"
}
# Rename project directories and solution
Set-Location src
git mv Library.sln "$LibraryName.sln"
git mv Library/Library.csproj "Library/$LibraryName.csproj"
git mv Library "$LibraryName"
git mv Library.Tests/Library.Tests.csproj "Library.Tests/$LibraryName.Tests.csproj"
git mv Library.Tests "$LibraryName.Tests"
# Refresh solution file both to update paths and give the projects unique GUIDs
dotnet sln remove Library/Library.csproj
dotnet sln remove Library.Tests/Library.Tests.csproj
dotnet sln add "$LibraryName"
dotnet sln add "$LibraryName.Tests"
git add "$LibraryName.sln"
# Update project reference in test project. Add before removal to keep the same ItemGroup in place.
dotnet add "$LibraryName.Tests" reference "$LibraryName"
dotnet remove "$LibraryName.Tests" reference Library/Library.csproj
git add "$LibraryName.Tests/$LibraryName.Tests.csproj"
# Establish a new strong-name key
& $sn.Path -k 2048 strongname.snk
git add strongname.snk
Set-Location ..
# Replace placeholders in source files
Replace-Placeholders -Path "src/$LibraryName/Calculator.cs" -Replacements @{
'Library'=$LibraryName
'COMPANY-PLACEHOLDER'=$Author
}
Replace-Placeholders -Path "src/$LibraryName.Tests/CalculatorTests.cs" -Replacements @{
'Library'=$LibraryName
'COMPANY-PLACEHOLDER'=$Author
}
Replace-Placeholders -Path "LICENSE" -Replacements @{
'COMPANY-PLACEHOLDER'=$Author
}
Replace-Placeholders -Path "src/stylecop.json" -Replacements @{
'COMPANY-PLACEHOLDER'=$Author
}
Replace-Placeholders -Path "src/Directory.Build.props" -Replacements @{
'COMPANY-PLACEHOLDER'=$Author
}
Replace-Placeholders -Path "README.md" -Replacements @{
"(?m)^.*\[NuGet package\][^`r`n]*"="[![NuGet package](https://img.shields.io/nuget/v/$LibraryName.svg)](https://nuget.org/packages/$LibraryName)"
"(?m)^.*\[Build Status\].*`r?`n"=""
"(?m)^.*\[codecov\].*`r?`n"=""
}
# Specially handle azure-pipelines .yml edits
Replace-Placeholders -Path "azure-pipelines/build.yml" -Replacements @{
"(?m).*expand-template\.yml(?:\r)?\n" = ""
}
$YmlReplacements = @{}
if ($CodeCovToken) {
$YmlReplacements['(codecov_token: ).*(#.*)'] = "`$1$CodeCovToken"
} else {
$YmlReplacements['(codecov_token: ).*(#.*)'] = "#`$1`$2"
}
if ($CIFeed) {
$YmlReplacements['(ci_feed: ).*(#.*)'] = "`$1$CIFeed"
} else {
$YmlReplacements['(ci_feed: ).*(#.*)'] = "#`$1`$2"
}
Replace-Placeholders -Path "azure-pipelines.yml" -Replacements $YmlReplacements
# Self destruct
$Invocation = (Get-Variable MyInvocation -Scope 1).Value
git rm Expand-Template.*
git rm :/azure-pipelines/expand-template.yml
# Self-integrity check
Get-ChildItem -Recurse -File -Exclude bin,obj,README.md,Expand-Template.* |? { -not $_.FullName.Contains("obj") } |% {
$PLACEHOLDERS = Get-Content -Path $_.FullName |? { $_.Contains('PLACEHOLDER') }
if ($PLACEHOLDERS) {
Write-Error "PLACEHOLDER discovered in $($_.FullName)"
}
}
# Commit the changes
git commit -qm "Expanded template for $LibraryName" -m "This expansion done by the (now removed) Expand-Template.ps1 script."
Write-Host -ForegroundColor Green "Template successfully expanded."
if ($env:PS1UnderCmd) {
# We're running under the Expand-Template.cmd script.
# Since we just deleted it from disk cmd.exe will complain. Just advise the user it's OK.
Write-Host -ForegroundColor Green 'Disregard an error you may see: "The batch file cannot be found." We just cleaned up after ourselves.'
}
} finally {
Pop-Location
}
# When testing this script, all the changes can be quickly reverted with this command:
# git reset HEAD :/README.md :/LICENSE :/azure-pipelines.yml :/src :/azure-pipelines; git co -- :/README.md :/LICENSE :/azure-pipelines.yml :/src :/azure-pipelines; git clean -fd :/src