Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev > Main #3

Merged
merged 53 commits into from
Sep 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
766a689
The big rename. NuGet.Build.Packaging > NuGetizer
kzu Sep 23, 2020
83c07f2
Minor missing renaming
kzu Sep 23, 2020
c689512
Don't use ILRepack, it's unnecessary
kzu Sep 23, 2020
cf6e407
Rename properties for targets imports
kzu Sep 23, 2020
72e59ac
Rename IncludeProjectReferencesInPackage > PackProjectReference
kzu Sep 23, 2020
69084a4
Add multi-targeting pack support
kzu Sep 24, 2020
887e818
Rename IncludeSymbolsInPackage > PackSymbols
kzu Sep 24, 2020
ace11cb
Rename IncludeContentInPackage > PackContent
kzu Sep 24, 2020
0f4579d
Rename IncludeNoneInPackage > PackNone
kzu Sep 24, 2020
546c05f
Rename IncludeOutputsInPackage > PackBuildOutput
kzu Sep 24, 2020
c85f0fb
Add BuildOutputTargetFolder and IncludeContentInPack SDK compat
kzu Sep 24, 2020
43429b7
Rename IncludeFrameworkReferencesInPackage > PackFrameworkReferences
kzu Sep 24, 2020
e347400
Add tests for package metadata customization scenario
kzu Sep 24, 2020
3a6504d
Add support for PackageLicenseExpression
kzu Sep 24, 2020
de7eb84
Fix metadata by item definition test
kzu Sep 24, 2020
d44d5e4
Rename PrimaryOutput* to BuildOutput*, remove old workarounds
kzu Sep 24, 2020
d0112a4
Add package icon
kzu Sep 24, 2020
fe41b5e
Add support for icon in addition to iconurl
kzu Sep 24, 2020
34eba1d
Explicit PackagePath in Content/None equals Pack=true
kzu Sep 24, 2020
111d1c4
Add Pack step to CI
kzu Sep 24, 2020
47c20c4
Add support for source information when available
kzu Sep 24, 2020
c5fe4dc
Test cleanup, migration and improvements
kzu Sep 24, 2020
d50646c
Deduplicate inferred project output
kzu Sep 24, 2020
7b9fd10
Collect and publish build logs when System.Debug=true
kzu Sep 24, 2020
567b3b8
Make sure tests run with an SDK that knows how to parse Xamarin TFMs
kzu Sep 24, 2020
1984de3
Opt out of first run messages from .NET Core
kzu Sep 24, 2020
05364e8
Allow rollforward for .NET SDK used in tests
kzu Sep 24, 2020
8c48e87
Use actual commit count since initial commit
kzu Sep 24, 2020
850a0d7
Allow packing from the IDE, and cleanup package contents
kzu Sep 24, 2020
2dece24
When packing, return the actually built output item
kzu Sep 24, 2020
1ab2dcd
Added missing task assemblies in the package
kzu Sep 24, 2020
a4bf83c
Don't force pack during package cache cleaning
kzu Sep 24, 2020
732ae67
Use GH run ID for the number suffix
kzu Sep 24, 2020
4060c22
Push dev CI package to GH package feed
kzu Sep 25, 2020
1c6ed6b
Use version prefix/suffix combination for more flexibility
kzu Sep 25, 2020
ae25cb8
Fix push nuget credentials
kzu Sep 25, 2020
ebe0005
Make sure dynamic package metadata is updated
kzu Sep 25, 2020
0803de6
Push CI packages to sleet feed instead of GH packages
kzu Sep 25, 2020
bec5eac
Add ability to selectively emit nuspec and nupkg
kzu Sep 27, 2020
0ca8ddd
Make sure not to include metadata which doesn't have values
kzu Sep 28, 2020
73538e2
Add nugetize dotnet global tool that helps discover NuGetizer
kzu Sep 28, 2020
3118834
Make sure tasks aren't locked during build
kzu Sep 28, 2020
b4771cb
Don't build again during pack
kzu Sep 28, 2020
7f0c021
Move adding nupkg to a target
kzu Sep 28, 2020
211e9f4
Always unconditionally set the package output path
kzu Sep 28, 2020
f79ee54
Delete local MSBuild spike
kzu Sep 28, 2020
25c6f73
Include symbols by default unless excluded
kzu Sep 28, 2020
be06b9e
Improve package property docs
kzu Sep 28, 2020
0106acd
Allow excluding framework references with Pack=false
kzu Sep 28, 2020
f8371a7
Rename to make it more clear
kzu Sep 28, 2020
ff1c848
Add build-in support in NuGetizer for dotnet-nugetize
kzu Sep 29, 2020
d5f0a27
Add screenshots, readme
kzu Sep 29, 2020
db268db
Improve selection of startup project for nugetize and binlog gen
kzu Sep 29, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ indent_style = space
indent_size = 4

# Xml project files
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj,msbuildproj}]
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj,msbuildproj,nuproj}]
indent_size = 2

# Xml config files
Expand All @@ -23,6 +23,7 @@ indent_size = 2
# YAML files
[*.{yaml,yml}]
indent_size = 2
indent_style = space

# JSON files
[*.json]
Expand Down
24 changes: 22 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,38 @@
name: build
on: push

env:
DOTNET_NOLOGO: true
MSBUILDDISABLENODEREUSE: 1

jobs:
build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.100-rc.1.20452.10
- uses: actions/setup-dotnet@v1
with:
dotnet-version: 2.1.x
- uses: actions/setup-dotnet@v1
with:
dotnet-version: 3.1.x
- run: dotnet tool update -g dotnet-vs
- name: set version
run: echo "::set-env name=VERSION_SUFFIX::$(git name-rev --name-only --refs=refs/heads/* HEAD).$($env:GITHUB_RUN_NUMBER)"
- run: echo "::set-env name=MSB::$(vs where preview --prop=InstallationPath)"
- run: vs install preview --quiet +Microsoft.VisualStudio.Component.ManagedDesktop.Core +Microsoft.NetCore.Component.DevelopmentTools
if: env.MSB == ''
- run: echo "::add-path::$(vs where preview --prop=InstallationPath)\MSBuild\Current\Bin"
- run: msbuild -r
- run: msbuild -t:test
- name: build
run: msbuild -r -p:versionsuffix=$($env:VERSION_SUFFIX)
- name: test
run: msbuild -t:test
- name: pack
run: msbuild -t:pack -p:nobuild=true -p:versionsuffix=$($env:VERSION_SUFFIX)
- name: sleet
run: |
dotnet tool install -g --version 2.3.33 sleet
sleet push bin --config none -f --verbose -p "SLEET_FEED_CONTAINER=nuget" -p "SLEET_FEED_CONNECTIONSTRING=${{ secrets.SLEET_CONNECTION }}" -p "SLEET_FEED_TYPE=azure"
38 changes: 38 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: release
on:
release:
types: [created]

env:
DOTNET_NOLOGO: true
MSBUILDDISABLENODEREUSE: 1

jobs:
build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.100-rc.1.20452.10
- uses: actions/setup-dotnet@v1
with:
dotnet-version: 2.1.x
- uses: actions/setup-dotnet@v1
with:
dotnet-version: 3.1.x
- run: dotnet tool update -g dotnet-vs
- name: set version
run: echo "::set-env name=VERSION::${GITHUB_REF#refs/*/v}
- run: echo "::set-env name=MSB::$(vs where preview --prop=InstallationPath)"
- run: vs install preview --quiet +Microsoft.VisualStudio.Component.ManagedDesktop.Core +Microsoft.NetCore.Component.DevelopmentTools
if: env.MSB == ''
- run: echo "::add-path::$(vs where preview --prop=InstallationPath)\MSBuild\Current\Bin"
- name: build
run: msbuild -r -p:version=$($env:VERSION)
- name: test
run: msbuild -t:test
- name: pack
run: msbuild -t:pack -p:nobuild=true -p:version=$($env:VERSION)
- name: push
run: dotnet nuget push ./bin/**/*.nupkg -s https://api.nuget.org/v3/index.json -k ${{secrets.NUGET_API_KEY}} --skip-duplicate
12 changes: 10 additions & 2 deletions NuGetizer.sln
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,19 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
src\Directory.Build.props = src\Directory.Build.props
src\Directory.Build.targets = src\Directory.Build.targets
src\NuGet.Config = src\NuGet.Config
README.md = README.md
.github\workflows\release.yml = .github\workflows\release.yml
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.Build.Packaging.Tasks", "src\Build\NuGet.Build.Packaging.Tasks\NuGet.Build.Packaging.Tasks.csproj", "{57F59BF6-9272-4B66-98A1-334B3FDA5721}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGetizer.Tasks", "src\NuGetizer.Tasks\NuGetizer.Tasks.csproj", "{57F59BF6-9272-4B66-98A1-334B3FDA5721}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.Build.Packaging.Tests", "src\Build\NuGet.Build.Packaging.Tests\NuGet.Build.Packaging.Tests.csproj", "{50032C88-1B52-4DB1-BFC5-6BADE2CC58CC}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGetizer.Tests", "src\NuGetizer.Tests\NuGetizer.Tests.csproj", "{50032C88-1B52-4DB1-BFC5-6BADE2CC58CC}"
ProjectSection(ProjectDependencies) = postProject
{57F59BF6-9272-4B66-98A1-334B3FDA5721} = {57F59BF6-9272-4B66-98A1-334B3FDA5721}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-nugetize", "src\dotnet-nugetize\dotnet-nugetize.csproj", "{53B47B9E-212F-420D-9E9A-68EC3B44D39E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -34,6 +38,10 @@ Global
{50032C88-1B52-4DB1-BFC5-6BADE2CC58CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{50032C88-1B52-4DB1-BFC5-6BADE2CC58CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{50032C88-1B52-4DB1-BFC5-6BADE2CC58CC}.Release|Any CPU.Build.0 = Release|Any CPU
{53B47B9E-212F-420D-9E9A-68EC3B44D39E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{53B47B9E-212F-420D-9E9A-68EC3B44D39E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{53B47B9E-212F-420D-9E9A-68EC3B44D39E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{53B47B9E-212F-420D-9E9A-68EC3B44D39E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
140 changes: 134 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,140 @@
![Nugetizer-3000 Logo](https://raw.githubusercontent.com/NuGet/NuGet.Build.Packaging/master/Nugetizer-3000.png)
![icon](img/nugetizer-32.png) nugetizer
===

# NuGetizer 3000

For the original design and intended goals and features, check out the [spec](https://github.com/NuGet/Home/wiki/NuGetizer-3000).
Simple, flexible, intuitive and powerful NuGet packaging.

## Why

I got sick of trying to modify the gazillion properties, weird item, property and target names and more from the built-in SDK Pack targets, and still never quite achieving the simple goals I had in mind. Also, the original clean and clear design from [NuGet.Build.Packaging](https://github.com/NuGet/NuGet.Build.Packaging) never got traction or support from the NuGet team, so the weirdness kept evolving in ever more incomprehensible ways ¯\_(ツ)_/¯.
The .NET SDK has built-in support for packing. The design of its targets, property
and item names it not very consistent, however. When packing non-trivial solutions
with multiple projects, it's quite hard to actually get it to pack exactly the
way you want it to.

An [alternative clean and clear design](https://github.com/NuGet/Home/wiki/NuGetizer-3000)
was proposed and I got to implement the initial spec, but it never got traction
with the NuGet team.

## What

With the learnings from years of building and shipping packages of different
levels of complexity, as well as significant use of the SDK Pack functionality
and its various extension points, NuGetizer takes a fresh look and exposes a
clean set of primitives so that you never have to create `.nuspec` files again.

All the [built-in properties](https://docs.microsoft.com/en-us/nuget/reference/msbuild-targets#pack-target)
are supported.

A key difference is that adding arbitrary content to the package is supported
with the first-class `PackageFile` item for absolute control of the package
contents.

```xml
<ItemGroup>
<PackageFile Include=".." PackagePath="..." />
</ItemGroup>
```

Another key design choice is that any package content inference should be trivial
to turn off wholesale in case the heuristics don't do exactly what you need. Just set
`EnablePackInference=false` and you will only get explicit `PackageFile` items
in your package.

### Package Inference

Package inference provides some built-in heuristics for common scenarios so you
don't have to customize the packing much. It works by transforming various built-in
items into corresponding `PackageFile` items, much as if you had added them by
hand.

Inference can be turned off for specific items by just adding `Pack="false"`
item metadata.

The default transformations are:

| Source | Inferred | Notes |
| --------------------------------------------------------------- | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| Project build output | `<PackageFile Kind="$(BuildOutputKind)"/>` | Kind defaults to `Lib`. Includes .xml and .pdb if they are generated. (1) |
| `<PackageReference ... />` | `<PackageFile ... Kind="Dependency" />` | `PrivateAssets=all` is present, it's not added as dependency. (2) |
| `<Content .../>` | `<PackageFile ... Kind="content" />` | Regular content that's not part of the build output |
| `<Content ... CopyToOutputDirectory="PreserveNewest\|Always"/>` | `<PackageFile Include="%(TargetPath)" Kind="$(BuildOutputKind)" ` | Content that's copied to the build output is part of the primary output so it uses its kind. (3) |
| `<None ... Pack="true" />` | `<PackageFile ... Kind="none" />` | |
| `<Reference ... />` | `<PackageFile ... Kind="frameworkReference"` | Only those resolved from the target framework directory are included. (4) |
| | | |

1. Back in the day, PDBs were Windows-only and fat files. Nowadays, portable PDBs
(the new default) are lightweight and can even be embedded. Combined with [SourceLink](https://github.com/dotnet/sourcelink), including them in the package by default (either standalone or embeded) provides the best experience for your users, so it's the default.
2. `PrivateAssets=all` in a `PackageReference` causes all the contributed files to the compilation to be packed together with the built output, unless `Pack=false` is also specified. Build-only dependencies that don't contribute assemblies to the output (i.e. analyzers or things like [GitInfo](https://github.com/kzu/GitInfo) or [ThisAssembly](https://github.com/kzu/ThisAssembly) won't cause any extra items).
3. This is the most intuitive default: things that you typically copy to the output in order to "run" your project, is stuff that will typically also be needed at run-time when users reference your package. This can be MSBuild props/targets for a build tasks package, for example, or additional files used by an analyzer or a tool.
4. `Reference` items are resolved by the `ResolveAssemblyReference` standard targets as `ReferencePath` items. Only those that have a `ResolvedFrom` metadata of `{TargetFrameworkDirectory}` are considered.

Inference control properties and metadata:

| Property | Description |
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `PackContent=true\|false` | Turns on/off the default inference for `@(Content)`.  Items with `Pack=true` metadata are always included. Defaults to `true`. |
| `PackNone=true\|false` | Turns on/off the default inference for `@(None)`.  Items with `Pack=true` metadata are always included. Defaults to `false`. |
| `PackSymbols=true\|false` | Turns on/off inclusion of symbols (if generated). Defaults to `true`. |
| `PackFrameworkReferences=true\|false` | Turns on/off the default inference of `<Reference...` items |

All of these [inference rules are laid out in a single .targets](src/NuGetizer.Tasks/NuGetizer.Inference.targets] file that's easy to inspect to learn more.

### Project References

Unlike SDK Pack that [considers project references as package references by default](https://docs.microsoft.com/en-us/nuget/reference/msbuild-targets#project-to-project-references), NuGetizer has an explicit contract between projects: `GetPackageContents`. This target is invoked when packing project references, and it returns whatever the referenced project exposes as package contents (including the inference rules above). If the project is *packable* (that is, it produces a package, denoted by the presence of a `PackageId` property), it will be packed as a dependency/package reference instead.

This means that by default, things Just Work: if you reference a library with no `PackageId`, it becomes part of whatever output your main project produces (analyzer, tools, plain lib). The moment you decide you want to make it a package on its own, you add the required metadata properties to that project, and automatically it becomes a dependency instead.

This works flawlessly even when multi-targeting: if the main (packable) project multitargets `net472;netcoreapp3.1`, say, and it references a `netstandard2.0` (non-packable) library, the package contents will be:

```
/lib/
net472/
library.dll
library.pdb
sample.dll
sample.pdb
netcoreapp3.1/
library.dll
library.pdb
sample.dll
sample.pdb
```

If the packaging metadata is added to the library, it automatically turns to:

```
Package: Sample.1.0.0.nupkg
...\Sample.nuspec
Authors : sample
Description : Sample
Version : 1.0.0
Dependencies:
net472
Library, 1.0.0
netcoreapp3.1
Library, 1.0.0
Contents:
/lib/
net472/
sample.dll
sample.pdb
netcoreapp3.1/
sample.dll
sample.pdb
```

### dotnet-nugetize

Carefully tweaking your packages until they look exactly the way you want them should not be a tedious and slow process. Even requiring your project to be built between changes can be costly and reduce the speed at which you can iterate on the packaging aspects of the project. Also, generating the final `.nupkg`, opening it in a tool and inspecting its content, is also not ideal for rapid iteration.

For this reason, NuGetizer provides a dotnet global tool to make this process straightforward and quick. Installation is just like for any other dotnet tool:

```
> dotnet tool install -g dotnet-nugetize
```

After installation, you can just run `nugetize` from the project directory to quickly get a report of the package that would be generated. This is done in the fastest possible way without compromising your customizations to the build process. They way this is achieved is by a combination of a simulated [design-time build](https://github.com/dotnet/project-system/blob/master/docs/design-time-builds.md) that skips the compiler invocation and avoids the output file copying entirely, and built-in support in NuGetizer to emit the entire contents of the package as MSBuild items with full metadata, that the tool can use to render an accurate report that contains exactly the same information that would be used to actually emit the final `.nupkg` without actually emitting it.

So, on to forking and shipping for real the simplified, understandable way of packing your libraries.
Here's a sample output screenshot:

![nugetize screenshot](img/dotnet-nugetize.png)
20 changes: 18 additions & 2 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
pool:
vmImage: 'windows-2019'

variables:
- name: DOTNET_NOLOGO
value: 'true'

steps:
- checkout: self

- task: UseDotNet@2
inputs:
packageType: sdk
version: 5.0.100-rc.1.20452.10
performMultiLevelLookup: true

- task: UseDotNet@2
inputs:
packageType: sdk
Expand All @@ -17,7 +28,12 @@ steps:
condition: eq(variables['MSB'], '')
- pwsh: echo "##vso[task.prependpath]$(vs where preview --prop=InstallationPath)\MSBuild\Current\Bin"
displayName: prepend MSBuild to %PATH%
- script: msbuild -r
- script: msbuild -r -bl:$(System.DefaultWorkingDirectory)/logs/build.binlog
displayName: msbuild -r
- script: msbuild -t:test
displayName: msbuild -t:test
displayName: msbuild -t:test
- publish: $(System.DefaultWorkingDirectory)/logs
artifact: logs
condition: always()
- script: msbuild -t:Pack -p:PackOnBuild=true
displayName: msbuild -t:pack
Binary file added img/dotnet-nugetize-xplat.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/dotnet-nugetize.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/nugetizer-100.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/nugetizer-128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/nugetizer-256.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/nugetizer-32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/nugetizer-512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions img/nugetizer.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading