Skip to content
This repository was archived by the owner on Dec 12, 2020. It is now read-only.

Commit 06982c0

Browse files
authored
Merge pull request #198 from AArnott/feature/tool-custom-package
[WIP] Refactor: Tool now self-contained, BuildTime merged into it
2 parents 38fb4ed + 2a9fbab commit 06982c0

46 files changed

Lines changed: 1098 additions & 203 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.config/dotnet-tools.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"version": 1,
3+
"isRoot": true,
4+
"tools": {
5+
"nbgv": {
6+
"version": "3.1.71",
7+
"commands": [
8+
"nbgv"
9+
]
10+
}
11+
}
12+
}

.github/workflows/ci.yml

Lines changed: 25 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -12,87 +12,49 @@ on:
1212

1313
env:
1414
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
15-
build_configuration: Release
15+
Configuration: Release
1616

1717
jobs:
18-
build-windows:
19-
runs-on: windows-latest
18+
build:
19+
strategy:
20+
matrix:
21+
os: [ windows-latest, ubuntu-latest, macos-latest ]
22+
runs-on: ${{ matrix.os }}
2023
steps:
2124
- uses: actions/checkout@v1
22-
- name: Install .NET Core
23-
shell: pwsh
24-
run: |
25-
$info = dotnet --info
26-
$isRuntime = $info -contains 'Microsoft.NETCore.App 2.1'
27-
Push-Location src; dotnet --version > $null; Pop-Location; $isSdk = $LASTEXITCODE -eq 0; $LASTEXITCODE = 0
28-
if ($isSdk -and $isRuntime) { return }
29-
[string]$dotnetroot = "~/.dotnet" | %{ if (-not (Test-Path $_)) { mkdir $_ > $null }; Resolve-Path $_ }
30-
Invoke-WebRequest "https://dotnetwebsite.azurewebsites.net/download/dotnet-core/scripts/v1/dotnet-install.ps1" -OutFile ~/dotnet-install.ps1
31-
~/dotnet-install.ps1 -JsonFile src/global.json -InstallDir $dotnetroot
32-
~/dotnet-install.ps1 -Channel 2.1 -Runtime dotnet -InstallDir $dotnetroot
33-
Write-Output "::add-path::$dotnetroot"
34-
Write-Output "::set-env name=DOTNET_ROOT::$dotnetroot"
25+
3526
- name: Setup .NET Core
3627
uses: actions/setup-dotnet@v1
28+
3729
- run: dotnet --info
38-
- name: Install and run nbgv
39-
run: |
40-
dotnet tool install --tool-path . nbgv
41-
./nbgv get-version -p src
30+
31+
- run: dotnet tool restore
32+
33+
- name: Run nbgv
34+
run: dotnet nbgv get-version -p src
35+
4236
- name: Restore
4337
run: dotnet restore src -v normal
38+
4439
- name: Build
45-
run: dotnet build src -t:build,pack --no-restore -m -c ${{ env.build_configuration }} -bl:obj/logs/build-windows.binlog
40+
run: dotnet build src -t:build,pack --no-restore -m -bl:obj/logs/build-${{ matrix.os }}.binlog
41+
4642
- name: Test
47-
run: dotnet test src --no-build -c ${{ env.build_configuration }}
43+
run: dotnet test src --no-build
44+
4845
- name: Upload nugets
49-
if: github.event_name == 'push'
46+
if: github.event_name == 'push' && matrix.os == 'windows-latest'
5047
uses: actions/upload-artifact@v1
5148
with:
5249
name: nugets
53-
path: bin/Packages/${{ env.build_configuration }}
54-
- name: Upload logs
55-
uses: actions/upload-artifact@v1
56-
with:
57-
name: logs-windows
58-
path: obj/logs/
50+
path: bin/Packages/${{ env.Configuration }}
5951

60-
build-other:
61-
strategy:
62-
matrix:
63-
os: [ubuntu-latest, macos-latest]
64-
runs-on: ${{ matrix.os }}
65-
steps:
66-
- uses: actions/checkout@v1
67-
- name: Install .NET Core
68-
shell: pwsh
69-
run: |
70-
$info = dotnet --info
71-
$isRuntime = $info -contains 'Microsoft.NETCore.App 2.1'
72-
Push-Location src; dotnet --version > $null; Pop-Location; $isSdk = $LASTEXITCODE -eq 0; $LASTEXITCODE = 0
73-
if ($isSdk -and $isRuntime) { return }
74-
[string]$dotnetroot = "~/.dotnet" | %{ if (-not (Test-Path $_)) { mkdir $_ > $null }; Resolve-Path $_ }
75-
Invoke-WebRequest "https://dotnetwebsite.azurewebsites.net/download/dotnet-core/scripts/v1/dotnet-install.sh" -OutFile ~/dotnet-install.sh
76-
chmod +x ~/dotnet-install.sh
77-
~/dotnet-install.sh -JsonFile src/global.json -InstallDir $dotnetroot
78-
~/dotnet-install.sh -Channel 2.1 -Runtime dotnet -InstallDir $dotnetroot
79-
Write-Output "::add-path::$dotnetroot"
80-
Write-Output "::set-env name=DOTNET_ROOT::$dotnetroot"
81-
- name: Setup .NET Core
82-
uses: actions/setup-dotnet@v1
83-
- run: dotnet --info
84-
- name: Install and run nbgv
85-
run: |
86-
dotnet tool install --tool-path . nbgv --version 3.0.28
87-
./nbgv get-version -p src
88-
- name: Restore
89-
run: dotnet restore src -v normal
90-
- name: Build
91-
run: dotnet build src --no-restore -m -c ${{ env.build_configuration }} -bl:obj/logs/build-${{ matrix.os }}.binlog
92-
- name: Test
93-
run: dotnet test src --no-build -c ${{ env.build_configuration }} -f netcoreapp2.1
9452
- name: Upload logs
9553
uses: actions/upload-artifact@v1
9654
with:
9755
name: logs-${{ matrix.os }}
9856
path: obj/logs/
57+
58+
- name: Build samples
59+
shell: pwsh
60+
run: samples/build.ps1

CHANGELOG.md

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
> ⚠ There are major changes, please look at [v0.7 migration guide].
11+
1012
### Added
11-
* GeneratorInCustomerSolution sample in `samples` folder
13+
* Various samples in `samples` folder
1214
* GitHub Actions CI
1315
* Support for plugin dependencies! 🎉 ([#156]).
16+
* Plugins (generators) are now easier to build using `CodeGeneration.Roslyn.Plugin.Sdk` MSBuildSdk package ([#113]).
1417

1518
### Changed
1619
* .NET Core SDK version bumped to `3.1.100` ([#178]).
1720
* `Attributes` package now targets `net20;net40` in addition to `netstandard1.0` ([#178]).
18-
* `dotnet-codegen` now has `RollForward=Major` policy to allow it to run on newer runtimes than 2.x,
21+
* Tool now has `RollForward=Major` policy to allow it to run on newer runtimes than 2.x,
1922
e.g. .NET Core SDK v3.x *only* should suffice for most usage scenarios ([#178]).
2023
* MSBuild ItemGroup used for registration of plugin paths changed to `CodeGenerationRoslynPlugin`
2124
(was `GeneratorAssemblySearchPaths`). A warning for using old one is introduced (`CGR1002`). ([#156])
2225
* ItemGroup now should contain full path to generator dll (previously it was a containing folder path)
23-
* Old behavior has a compat-plug and the paths are searched for any dll, and those found are added to new ItemGroup.
26+
* Old behavior has a compat-plug for now and the paths are searched for any dll, and those found are added to new ItemGroup.
2427
* When using P2P generator (same solution), a consuming project needs to add an attribute `OutputItemType="CodeGenerationRoslynPlugin"` to the `ProjectReference` of the generator project. See [v0.7 migration guide].
28+
* `dotnet-codegen` package is now `CodeGeneration.Roslyn.Tool` and is build very differently;
29+
also it includes build assets from `BuildTime` package ([#198]).
30+
31+
### Removed
32+
* `CodeGeneration.Roslyn.BuildTime` package is now merged into `CodeGeneration.Roslyn.Tool`
33+
(which is now the only package required to be referenced by generator consumers, aside from generators themselves) ([#198]).
2534

35+
[#113]: https://github.com/AArnott/CodeGeneration.Roslyn/issues/113
2636
[#156]: https://github.com/AArnott/CodeGeneration.Roslyn/pull/156
2737
[#178]: https://github.com/AArnott/CodeGeneration.Roslyn/pull/178
38+
[#198]: https://github.com/AArnott/CodeGeneration.Roslyn/pull/198
2839
[v0.7 migration guide]: https://github.com/AArnott/CodeGeneration.Roslyn/wiki/Migrations#v07
2940

3041

README.md

Lines changed: 52 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ for it. That's because code generation runs *before* the consuming project is it
5252
Now we'll use an [MSBuild project SDK] `CodeGeneration.Roslyn.Plugin.Sdk` to speed up configuring our generator plugin. Edit your project file and add the `<Sdk>` element:
5353

5454
```xml
55+
<!-- Duplicator/Duplicator.csproj -->
5556
<Project Sdk="Microsoft.NET.Sdk">
5657
<!-- Add the following element above any others: -->
5758
<Sdk Name="CodeGeneration.Roslyn.Plugin.Sdk" Version="{replace with actual version used}"/>
@@ -141,6 +142,7 @@ with a dependency on your code generation assembly.
141142

142143
We'll consume our generator in a Reflector app:
143144
> `dotnet new console -f netcoreapp2.1 -o Reflector`
145+
>
144146
> `dotnet add Reflector reference Duplicator`
145147
146148
Let's write a simple program that prints all types in its assembly:
@@ -183,14 +185,15 @@ namespace Reflector
183185

184186
Right now `dotnet run -p Reflector` outputs:
185187
> `Reflector.Program`
188+
>
186189
> `Reflector.Test`
187190
188-
Now all that's left is to plumb the build pipeline with code generation tool. You'll need to add the following two references to your Reflector project file:
189-
* [`CodeGeneration.Roslyn.BuildTime`][BuildTimeNuPkg]
190-
* [`dotnet-codegen`][ToolNuPkg]
191+
Now all that's left is to plumb the build pipeline with code generation tool.
192+
You'll need to add a reference to [`CodeGeneration.Roslyn.Tool`][ToolNuPkg] package:
193+
> `dotnet add Reflector package CodeGeneration.Roslyn.Tool`
191194
192195
Also, you need to add the following metadata to your generator project reference:
193-
`OutputItemType="CodeGenerationRoslynPlugin"`. This will add the path to the `Duplicator.dll` to the list of plugins the tool uses.
196+
`OutputItemType="CodeGenerationRoslynPlugin"`. This will add the path to the `Duplicator.dll` to the list of plugins the tool runs.
194197

195198
This is how your project file can look like:
196199

@@ -200,31 +203,30 @@ This is how your project file can look like:
200203
<PropertyGroup>
201204
<OutputType>Exe</OutputType>
202205
<TargetFramework>netcoreapp2.1</TargetFramework>
203-
<CodeGenerationRoslynVersion>{replace with actual version used}</CodeGenerationRoslynVersion>
204206
</PropertyGroup>
205207
<ItemGroup>
206208
<!-- This ProjectReference to the generator need to have the OutputItemType metadata -->
207209
<ProjectReference Include="..\Duplicator\Duplicator.csproj"
208210
OutputItemType="CodeGenerationRoslynPlugin" />
209-
<!-- This reference imports targets that run the dotnet-codegen tool during build. It contains only MSBuild targets and so can be marked with PrivateAssets="all" -->
210-
<PackageReference Include="CodeGeneration.Roslyn.BuildTime"
211-
Version="$(CodeGenerationRoslynVersion)"
211+
<!--
212+
This contains the generation tool and MSBuild targets that invoke it,
213+
and so can be marked with PrivateAssets="all"
214+
-->
215+
<PackageReference Include="CodeGeneration.Roslyn.Tool"
216+
Version="{replace with actual version used}"
212217
PrivateAssets="all" />
213-
<!-- This allows the build to invoke dotnet-codegen console tool that actually
214-
performs code generation: compiles you source files, runs plugins and saves
215-
results adding them to the list of Compile sources for the CoreCompile step. -->
216-
<DotNetCliToolReference Include="dotnet-codegen"
217-
Version="$(CodeGenerationRoslynVersion)" />
218218
</ItemGroup>
219219
</Project>
220220
```
221221

222222
And if all steps were done correctly, `dotnet run -p Reflector` should print:
223223
> `Reflector.Program`
224+
>
224225
> `Reflector.Test`
226+
>
225227
> `Reflector.TestPassed`
226228
227-
> Notice that there is a `TestPassed` type in the assembly now.
229+
> 💡 Notice that there is a `TestPassed` type in the assembly now.
228230
229231
What's even better is that you should see that new type in IntelliSense as well!
230232
Try executing Go to Definition (<kbd>F12</kbd>) on it - your IDE (VS/VS Code) should open the generated file for you (it'll be located in `IntermediateOutputPath` - most commonly `obj/`).
@@ -264,18 +266,27 @@ So, the consuming project will have a simple ProjectReference to the
264266
`Duplicator.Attributes` project, and the generator project will not have
265267
any attribute defined. With that done, we can move to the next section.
266268

267-
> 📋 Side note: if you use generator only in a single TFM-incompatible project,
269+
> 📋 Side note: if there's only one consumer project for your generator,
268270
> you can define the triggering attribute in the consuming project as well.
271+
> In our case, this would bean moving the `DuplicateWithSuffixAttribute.cs`
272+
> from `Duplicator` to `Reflector`, and adding a reference to the
273+
> [`CodeGeneration.Roslyn.Attributes`][AttrNuPkg] in Reflector:
274+
> > `dotnet add Reflector package CodeGeneration.Roslyn.Attributes`
275+
> >
276+
> > `mv Duplicator/DuplicateWithSuffixAttribute.cs Reflector`
277+
>
278+
> For simplicity, we'll assume this is the case in the following sections.
269279
270280
### Customize generator reference
271281

272282
With the attribute available to consuming code, we don't need a reference to
273283
the generator project, right? Well, not quite. The magic OutputItemType metadata
274284
is important - it adds a path to the generator dll to the list of plugins known
275-
to the `dotnet-codegen` tool. Additionally, we want to specify that there's a build
276-
dependency of the consuming project on the generator. So we modify the reference:
285+
to the `CodeGeneration.Roslyn.Tool` tool. Additionally, we want to specify that there's a build dependency of the consuming project on the generator. So we modify
286+
the reference:
277287

278288
```xml
289+
<!-- Reflector/Reflector.csproj -->
279290
<ItemGroup>
280291
<ProjectReference Include="..\Duplicator\Duplicator.csproj"
281292
ReferenceOutputAssembly="false"
@@ -293,17 +304,28 @@ We add two new metadata attributes:
293304

294305
#### Multitargeting generator
295306

296-
The case gets more complicated when the generator project is multitargeting,
297-
e.g. it has
307+
It can happen that your generator project will become multi-targeting. You could
308+
need to do that to use C#8's Nullable Reference Types feature in the Duplicator;
309+
the generator has to target `netcoreapp2.1` as this is the framework it'll be run
310+
in by the `CG.R.Tool` - on the other hand, NRT feature is only supported in newer
311+
TFMs, starting with `netcoreapp3.1`. So you'll do:
298312
```xml
299-
<TargetFrameworks>netcoreapp2.1;netcoreapp3.0</TargetFrameworks>
313+
<!-- Duplicator/Duplicator.csproj -->
314+
<Project Sdk="Microsoft.NET.Sdk">
315+
<PropertyGroup>
316+
<TargetFrameworks>netcoreapp2.1;netcoreapp3.1</TargetFrameworks>
317+
</PropertyGroup>
318+
<!-- ... -->
319+
</Project>
300320
```
301321

302-
You could want to do that to use C#8's Nullable Reference Types feature.
303-
304-
This won't work now, because the generator's Build target output will contain two references. To fix that you can use `SetTargetFramework` metadata:
322+
There'll be a build error, because the consumer (Reflector) doesn't know which
323+
output to use (and assign to the CodeGenerationRoslynPlugin Item). To fix that
324+
we have to use `SetTargetFramework` metadata. Setting it implies
325+
`SkipGetTargetFrameworkProperties="true"` so we can replace it.
305326

306327
```xml
328+
<!-- Reflector/Reflector.csproj -->
307329
<ItemGroup>
308330
<ProjectReference Include="..\Duplicator\Duplicator.csproj"
309331
ReferenceOutputAssembly="false"
@@ -312,54 +334,36 @@ This won't work now, because the generator's Build target output will contain tw
312334
</ItemGroup>
313335
```
314336

315-
Non-empty `SetTargetFramework` automatically implies `SkipGetTargetFrameworkProperties="true"` so we can omit that.
316-
317-
We also need to add a condition on `TargetFrameworks` element so that we skip
318-
setting it at all when a singular property is set.
319-
320-
```xml
321-
<TargetFrameworks Condition="'$(TargetFramework)' == ''">
322-
netcoreapp2.1;
323-
netcoreapp3.0
324-
</TargetFrameworks>
325-
```
326-
327337
### Package your code generator
328338

329339
You can also package up your code generator as a NuGet package for others to install
330340
and use. A project using `CodeGeneration.Roslyn.Plugin.Sdk` is automatically
331341
configured to produce a correct Plugin nuget package.
332342

333343
Your consumers will have to depend on the following:
334-
- [`dotnet-codegen`][ToolNuPkg] tool
335-
- [`CodeGeneration.Roslyn.BuildTime`][BuildTimeNuPkg]
344+
- [`CodeGeneration.Roslyn.Tool`][ToolNuPkg] tool
336345
- `Duplicator.Attributes` (your attributes package)
337346
- `Duplicator` (your generator/plugin package)
338347

339348
An example consuming project file should contain:
340349
```xml
350+
<!-- Reflector/Reflector.csproj -->
341351
<ItemGroup>
342352
<PackageReference Include="Duplicator" Version="1.0.0" PrivateAssets="all" />
343353
<PackageReference Include="Duplicator.Attributes" Version="1.0.0" PrivateAssets="all" />
344-
<PackageReference Include="CodeGeneration.Roslyn.BuildTime"
345-
Version="$(CodeGenerationRoslynVersion)"
354+
<PackageReference Include="CodeGeneration.Roslyn.Tool"
355+
Version="{CodeGeneration.Roslyn.Tool version}"
346356
PrivateAssets="all" />
347-
<DotNetCliToolReference Include="dotnet-codegen"
348-
Version="$(CodeGenerationRoslynVersion)" />
349357
</ItemGroup>
350358
```
351359

352-
where `CodeGenerationRoslynVersion` is a correctly defined Property.
353-
354360
> 📋 You can also attempt to craft a self-contained package that will
355-
> flow all the needed dependencies and assets into the consuming project,
356-
> but the `DotNetCliToolReference` has to be in the consumer's project file
357-
> no matter what. Just a friendly reminder. Also, such a scenario is definitely
358-
> outside this project's scope.
361+
> flow all the needed dependencies and assets into the consuming project.
362+
> For a sample implementation, see [MetapackageSample](samples/MetapackageSample/).
359363
360364
[NuPkg]: https://nuget.org/packages/CodeGeneration.Roslyn
361365
[BuildTimeNuPkg]: https://nuget.org/packages/CodeGeneration.Roslyn.BuildTime
362366
[AttrNuPkg]: https://nuget.org/packages/CodeGeneration.Roslyn.Attributes
363-
[ToolNuPkg]: https://nuget.org/packages/dotnet-codegen
367+
[ToolNuPkg]: https://nuget.org/packages/CodeGeneration.Roslyn.Tool
364368
[netstandard-table]: https://docs.microsoft.com/dotnet/standard/net-standard#net-implementation-support
365369
[MSBuild project SDK]: https://docs.microsoft.com/visualstudio/msbuild/how-to-use-project-sdk

azure-pipeline.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ jobs:
3333
workingDirectory: src
3434

3535
- script: |
36-
dotnet tool install --tool-path . nbgv --version 3.0.28
37-
.\nbgv cloud -p src
36+
dotnet tool restore
37+
dotnet nbgv cloud -p src
3838
displayName: Set build number
3939
condition: ne(variables['system.pullrequest.isfork'], true)
4040

samples/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.nuget

0 commit comments

Comments
 (0)