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

Add automatic cleanups to improve the inner devloop #17

Merged
merged 2 commits into from
Oct 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ jobs:
run: msbuild -t:pack -p:nobuild=true -p:versionsuffix=$($env:VERSION_SUFFIX)
- name: sleet
run: |
dotnet tool install -g --version 2.3.33 sleet
dotnet tool install -g --version 3.2.0 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"
28 changes: 27 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ Package: Sample.1.0.0.nupkg

Finally, you can focedly turn a project reference build output into a private asset even if it defines a `PackageId` by adding `PrivateAssets=all`. This is very useful for build and analyzer packages, which typically reference the main library project too, but need its output as private, since neither can use dependencies at run-time.

### dotnet-nugetize
## 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.

Expand All @@ -198,3 +198,29 @@ After installation, you can just run `nugetize` from the project directory to qu
Here's a sample output screenshot:

![nugetize screenshot](img/dotnet-nugetize.png)

## Inner DevLoop

Authoring, testing and iterating with your nuget packages should be easy and straightforward. So NuGetizer has built-in support for this process that makes it even enjoyable. The following are some notes and advise on how to make the best of it.

1. Use single `PackageOutputPath`: if you create multiple packages, it's helpful to place them all in a single output directory. This can be achieved easily by adding the property to a `Directory.Build.props` file and place it at your repository root (or your `src` folder).:

```xml
<PackageOutputPath Condition="'$(PackageOutputPath)' == ''">$(MSBuildThisFileDirectory)..\bin</PackageOutputPath>
```

2. Use `<RestoreSources>` in your consuming projects: this allows you to point to that common folder and even do it selectively only if the folder exists (i.e. use local packages if you built them, use regular feed otherwise). You can place this too in a `Directory.Build.props` for all your consuming/sample/test projects to use:

```xml
<RestoreSources>https://api.nuget.org/v3/index.json;$(RestoreSources)</RestoreSources>
<RestoreSources Condition="Exists('$(MSBuildThisFileDirectory)..\..\bin\')">
$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\..\bin'));$(RestoreSources)
</RestoreSources>
```

3. NuGetizer will automatically perform the following cleanups whenever you build a new version of a package:
a. Clean previous versions of the same package in the package output path
b. Clean NuGet cache folder for the package id (i.e. *%userprofile%\.nuget\packages\mypackage*)
c. Clean the NuGet HTTP cache: this avoids a subsequent restore from a test/sample project from getting an older version from there, in case you build locally the same version of a previously restored one from an HTTP source.

These cleanups only apply in local builds, never in CI, and you can turn them all off by setting `EnablePackCleanup=false`.
54 changes: 54 additions & 0 deletions src/NuGetizer.Tasks/NuGetizer.Cleanup.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<!--
***********************************************************************************************
NuGetizer.Cleanup.targets
Cleans up previously built packages from the package output folder, as well
as the local caches so that restoring packages (even using wildcards) will
always pick the freshly built ones.
Copyright (c) .NET Foundation. All rights reserved.
***********************************************************************************************
-->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

<PropertyGroup Label="Hidden">
<HttpNuGetCache>$(LocalAppData)\NuGet\v3-cache</HttpNuGetCache>
<!-- We clean the HTTP cache by default. This does *not* clear the cached installed packages -->
<CleanHttpNuGetCacheOnPack Condition="'$(CleanHttpNuGetCacheOnPack)' == ''">true</CleanHttpNuGetCacheOnPack>
<!-- The actual NuGet cache is only cleared for the *current* PackageId, so no need to turn off its clearing on build/pack -->
<NuGetCache>$(UserProfile)\.nuget\packages</NuGetCache>
</PropertyGroup>

<Target Name="CleanPackageOutput" BeforeTargets="Build">
<ItemGroup>
<_ExistingPackage Include="$(PackageOutputPath)\$(PackageId)*.nupkg" />
<_PackageToDelete Include="@(_ExistingPackage)"
Condition="$([System.Text.RegularExpressions.Regex]::IsMatch('%(Filename)', '$(PackageId)\.\d\.\d\.\d.*'))" />
</ItemGroup>
<Delete Files="@(_PackageToDelete)" ContinueOnError="true">
<Output TaskParameter="DeletedFiles" ItemName="_CleanedPackages" />
</Delete>
<Message Text="Cleaned existing packages: @(_CleanedPackages -> '%(Filename)%(Extension)')"
Condition="'@(_CleanedPackages)' != ''" />
</Target>

<!-- Clears nuget cache for the current project package id -->
<Target Name="CleanCachedPackageId" AfterTargets="Build;Pack">
<PropertyGroup>
<PackageFolder>$(NuGetCache)\$(PackageId.ToLowerInvariant())</PackageFolder>
</PropertyGroup>

<Message Text="Cleaning $(PackageFolder)" Condition="Exists($(PackageFolder))" />
<Exec Command='rd "$(PackageFolder)" /q /s' Condition="Exists($(PackageFolder)) and '$(OS)' == 'Windows_NT'" />
<Exec Command='rm -rf "$(PackageFolder)"' Condition="Exists($(PackageFolder)) and '$(OS)' != 'Windows_NT'" />
</Target>

<Target Name="CleanHttpNuGetCache"
Condition="'$(CleanHttpNuGetCacheOnPack)' == 'true' and Exists('$(HttpNuGetCache)')"
AfterTargets="Build;Pack">
<Message Text="Cleaning $(HttpNuGetCache)" />
<Exec Command='rd "$(HttpNuGetCache)" /q /s' Condition="'$(OS)' == 'Windows_NT'" />
<Exec Command='rm -rf "$(HttpNuGetCache)"' Condition="'$(OS)' != 'Windows_NT'" />
</Target>

</Project>
5 changes: 5 additions & 0 deletions src/NuGetizer.Tasks/NuGetizer.Shared.targets
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ Copyright (c) .NET Foundation. All rights reserved.
<!-- Whether to infer package contents -->
<EnablePackInference Condition="'$(EnablePackInference)' == ''">true</EnablePackInference>

<!-- Whether to cleanup package output folder and nuget caches on pack -->
<EnablePackCleanup Condition="'$(EnablePackCleanup)' == ''">true</EnablePackCleanup>

<!-- Whether include referenced projects' contents in the package. -->
<PackProjectReference Condition="'$(PackProjectReference)' == ''">true</PackProjectReference>

Expand Down Expand Up @@ -271,5 +274,7 @@ Copyright (c) .NET Foundation. All rights reserved.
<Message Importance="high" Text="Created package at %(_PackageTargetPath.FullPath)." Condition="'$(EmitPackage)' == 'true'" />
</Target>

<!-- Cleanups improve the local development loop, by always ensure the fresly built packages can be restored from output -->
<Import Project="NuGetizer.Cleanup.targets" Condition="'$(CI)' != 'true' and '$(EnablePackCleanup)' != 'false' and '$(IsPackable)' == 'true' and '$(PackageId)' != ''" />
<Import Project="NuGetizer.PackageMetadata.targets" Condition="'$(UsingMicrosoftNETSdk)' != 'true'" />
</Project>
14 changes: 13 additions & 1 deletion src/NuGetizer.Tasks/NuGetizer.props
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,19 @@ Copyright (c) .NET Foundation. All rights reserved.
<NuGetBuildTasksPackTargets>$(MSBuildThisFileDirectory)NuGetizer.PackageMetadata.targets</NuGetBuildTasksPackTargets>
<ImportNuGetBuildTasksPackTargetsFromSdk>true</ImportNuGetBuildTasksPackTargetsFromSdk>
</PropertyGroup>


<PropertyGroup Label="Hidden" Condition="'$(CI)' == ''">
<CI>false</CI>
<!-- GH, CircleCI, GitLab and BitBucket already use CI -->
<CI Condition="'$(TF_BUILD)' == 'true' or
'$(TEAMCITY_VERSION)' != '' or
'$(APPVEYOR)' != '' or
'$(BuildRunner)' == 'MyGet' or
'$(JENKINS_URL)' != '' or
'$(TRAVIS)' == 'true' or
'$(BUDDY)' == 'true'">true</CI>
</PropertyGroup>

<ItemGroup>
<AvailableItemName Include="PackageFile" />
</ItemGroup>
Expand Down