diff --git a/azure-pipelines.qodana.yml b/azure-pipelines.qodana.yml
new file mode 100644
index 000000000..5d2c9f18c
--- /dev/null
+++ b/azure-pipelines.qodana.yml
@@ -0,0 +1,15 @@
+pool:
+ vmImage: 'ubuntu-latest'
+
+jobs:
+ - job: QodanaScan
+ displayName: 'Qodana Scan'
+ steps:
+ - task: Cache@2 # Not required, but Qodana will open projects with cache faster.
+ inputs:
+ key: '"$(Build.Repository.Name)" | "$(Build.SourceBranchName)" | "$(Build.SourceVersion)"'
+ path: '$(Agent.TempDirectory)/qodana/cache'
+ restoreKeys: |
+ "$(Build.Repository.Name)" | "$(Build.SourceBranchName)"
+ "$(Build.Repository.Name)"
+ - task: QodanaScan@2023
diff --git a/docs/01-getting-started/01-installation.md b/docs/01-getting-started/01-installation.md
new file mode 100644
index 000000000..b63bcb8ad
--- /dev/null
+++ b/docs/01-getting-started/01-installation.md
@@ -0,0 +1,39 @@
+---
+title: Installation
+---
+
+Before you can set up a build project, you need to install NUKE's dedicated [.NET global tool](https://docs.microsoft.com/en-us/dotnet/core/tools/global-tools):
+
+```powershell
+# terminal-command
+dotnet tool install Nuke.GlobalTool --global
+```
+
+From now on, you can use the global tool to:
+
+- [Set up new builds](02-setup.md)
+- [Run existing builds](03-execution.md)
+- [Leverage shell completion](../06-global-tool/00-shell-completion.md)
+- [Add tool & library packages](../06-global-tool/01-packages.md)
+- [Navigate around root directories](../06-global-tool/03-navigation.md)
+- [Convert CAKE build scripts](../06-global-tool/04-cake.md)
+- [Manage secrets in parameter files](../06-global-tool/02-secrets.md)
+
+:::note
+If you're running on Linux-based systems, it's worth checking if the `nuke` global tool is available. This can be verified with `where nuke`. If the global tool is not found, you have to manually add `$HOME/.dotnet/tools` to your terminal configuration:
+
+
+
+
+```powershell
+# terminal-command
+echo 'export PATH=$HOME/.dotnet/tools:$PATH' >> ~/.zshrc
+```
+
+
+
+:::
+
+:::info
+While theoretically, you could use NUKE by only adding its main NuGet package, we highly recommend using the dedicated global tool to set up new builds. This ensures that your repository will run consistently in different environments and that your build implementation is always properly formatted.
+:::
diff --git a/docs/01-getting-started/02-setup.md b/docs/01-getting-started/02-setup.md
new file mode 100644
index 000000000..73641e1ac
--- /dev/null
+++ b/docs/01-getting-started/02-setup.md
@@ -0,0 +1,142 @@
+---
+title: Build Setup
+---
+
+import AsciinemaPlayer from '@site/src/components/AsciinemaPlayer';
+
+After [installing the NUKE global tool](01-installation.md), you can call it from anywhere on your machine to set up a new build:
+
+```powershell
+# terminal-command
+nuke :setup
+```
+
+:::tip
+Preferably, you should run the setup from inside an existing repository. NUKE will search for the next upwards `.git` or `.svn` directory to determine the _build root directory_. If neither is found, it will use the current directory. You can also pass the `--root` parameter to specify that the current directory should be used as a root directory.
+:::
+
+During the setup, you'll be asked several questions to configure your build to your preferences:
+
+
+
+
+
+**Congratulations!** π₯³ Your first build has now been set up, and you can [run the build](03-execution.md) with the default implementation!
+
+## Effective Changes
+
+The setup will create a number of files in your repository and β if you've chosen so β add the build project to your solution file. Below, you can examine the structure of added files and what they are used for:
+
+```bash
+
+βββ .nuke # Root directory marker
+β βββ build.schema.json # Build schema file
+β βββ parameters.json # Default parameters file
+β
+βββ build
+β βββ .editorconfig # Common formatting
+β βββ _build.csproj # Build project file
+β βββ _build.csproj.DotSettings # ReSharper/Rider formatting
+β βββ Build.cs # Default build implementation
+β βββ Directory.Build.props # MSBuild stop files
+β βββ Directory.Build.targets
+β
+βββ build.cmd # Cross-platform bootstrapping
+βββ build.ps1 # Windows/PowerShell bootstrapping
+βββ build.sh # Linux/Shell bootstrapping
+```
+
+:::note
+If you prefer, you _may_ choose to delete any of the bootstrapping scripts, MSBuild stop files, or formatting settings. For instance, when you're sure that no other MSBuild files will interfere with the build project, or you don't rely on either Roslyn or ReSharper/Rider for formatting. However, note that the **bootstrapping scripts play an essential role** in CI/CD environments, and are also used for the configuration generation feature.
+:::
+
+## Project Structure
+
+While you can enjoy writing most build-relevant logic inside your build console applications, there is still a large number of files involved in the general process of build automation. NUKE organizes these files in different folders as linked files in the build project for you:
+
+
+
+
+```powershell
+
+βββ .nuke
+β βββ parameters.json # Parameters files
+β βββ parameters.*.json
+β
+βββ GitVersion.yml # GitVersion configuration
+βββ global.json # SDK version
+βββ nuget.config # NuGet feeds configuration
+βββ version.json # Nerdbank GitVersioning configuration
+```
+
+
+
+
+```powershell
+
+βββ .github
+β βββ workflows # GitHub Actions
+β βββ *.yml
+β
+βββ .teamcity # TeamCity
+β βββ settings.kts
+β
+βββ .gitlab-ci.yml # GitLab CI
+βββ .space.kts # JetBrains Space
+βββ .travis.yml # Travis CI
+βββ appveyor.yml # AppVeyor
+βββ appveyor.*.yml
+βββ azure-pipelines.yml # Azure Pipelines
+βββ azure-pipelines.*.yml
+βββ bitrise.yml # Bitrise
+```
+
+
+
+
+```powershell
+
+βββ build.cmd # Cross-platform
+βββ build.ps1 # Windows/PowerShell
+βββ build.sh # Linux/Shell
+```
+
+
+
+
+```powershell
+
+βββ **
+ βββ Directory.Build.props
+ βββ Directory.Build.targets
+```
+
+
+
+
+:::info
+You can deactivate linking of the above files by removing the `NukeRootDirectory` and `NukeScriptDirectory` properties from the build project file.
+
+```xml title="_build.csproj"
+
+
+
+ // highlight-start
+
+
+ // highlight-end
+
+
+
+```
+
+:::
+
+[^1]: Interface default members behave like explicit interface implementations, which means that to access their members, the `this` reference must be cast explicitly to the interface type. For instance, `((IComponent)this).Target`.
diff --git a/docs/01-getting-started/03-execution.md b/docs/01-getting-started/03-execution.md
new file mode 100644
index 000000000..f656f0c61
--- /dev/null
+++ b/docs/01-getting-started/03-execution.md
@@ -0,0 +1,239 @@
+---
+title: Build Execution
+---
+
+import AsciinemaPlayer from '@site/src/components/AsciinemaPlayer';
+
+After you've [set up a build](02-setup.md) you can run it either through the global tool or one of the installed bootstrapping scripts:
+
+
+
+
+```powershell
+# terminal-command
+nuke [arguments]
+```
+
+
+
+
+```powershell
+# terminal-command
+.\build.cmd [arguments]
+```
+
+
+
+
+```powershell
+# terminal-command
+./build.sh [arguments]
+```
+
+
+
+
+:::info
+This document discusses the default build arguments (also referred to as parameters). You will learn how to [define custom parameters](../02-fundamentals/06-parameters.md) in a following chapter.
+:::
+
+:::tip
+The global tool makes running builds a lot easier. Once you've configured the [shell completion](../06-global-tool/00-shell-completion.md), you can enter arguments much faster and avoid any typos. It also allows you to run a build from anywhere below the root directory without having to go back to where the bootstrapping scripts are located.
+:::
+
+## Build Summary
+
+Once a build has finished running an execution plan, it will print a comprehensive summary with all involved targets, their outcome, duration, and additional metadata:
+
+
+βββββββββββββββββββββββββββββββββββββββ{'\n'}
+Target Status Duration{'\n'}
+βββββββββββββββββββββββββββββββββββββββ{'\n'}
+Restore Succeeded 0:16{'\n'}
+Compile Succeeded 0:59 // Version: 5.3.0-alpha.35{'\n'}
+Test Succeeded 0:41 // Passed: 327, Skipped: 6{'\n'}
+Pack Succeeded 0:10 // Packages: 4{'\n'}
+βββββββββββββββββββββββββββββββββββββββ{'\n'}
+Total 2:08{'\n'}
+βββββββββββββββββββββββββββββββββββββββ{'\n'}
+{'\n'}
+Build succeeded on {new Date().toLocaleString()}. οΌΌοΌοΌΎα΄οΌΎοΌοΌ
+
+
+[//]: # (## Default Parameters)
+[//]: # ()
+[//]: # (| Parameter | Comment |)
+[//]: # (|:--------------|:----------------------------------------------------------|)
+[//]: # (| `--target` | List of targets to be invoked |)
+[//]: # (| `--skip` | List of targets to be skipped (empty for all non-invoked) |)
+[//]: # (| `--help` | Shows the help text |)
+[//]: # (| `--host` | Forcefully sets the `Host` implementation |)
+[//]: # (| `--profile` | List of `parameters..json` files to load |)
+[//]: # (| `--plan` | Shows the HTML dependency graph |)
+[//]: # (| `--verbosity` | Sets the verbosity used for logging |)
+[//]: # (| `--continue` | Continues the build from last point of failure |)
+[//]: # (| `--root` | Forcefully sets the root directory |)
+
+## Invoking Targets
+
+You can invoke a single target or a set of targets either through positional or named arguments:
+
+
+
+
+```powershell
+# terminal-command
+nuke [other-targets...]
+```
+
+
+
+
+```powershell
+# terminal-command
+nuke [arguments...] --targets [other-targets...]
+```
+
+
+
+
+:::tip
+Passing targets as named arguments allows you to quickly overwrite the invoked targets without moving the caret to the front of a long invocation command.
+:::
+
+## Skipping Targets
+
+You can skip all or individual targets from the execution plan that are not specifically invoked:
+
+
+
+
+```powershell
+# terminal-command
+nuke [targets] --skip
+```
+
+
+
+
+```powershell
+# terminal-command
+nuke [targets] --skip
+```
+
+
+
+
+:::tip
+Skipping targets can greatly improve your troubleshooting experience. Irrelevant targets won't waste execution time, and there is no need to temporarily change dependencies between targets.
+:::
+
+## Aborting Builds
+
+At any moment during execution, you can hit `Ctrl-C` to abort the build with a [SIGINT signal](https://docs.microsoft.com/en-us/windows/console/ctrl-c-and-ctrl-break-signals). Targets that were running at the time will be marked with the `Aborted` status:
+
+```
+βββββββββββββββββββββββββββββββββββββββ
+Target Status Duration
+βββββββββββββββββββββββββββββββββββββββ
+Restore Succeeded 0:16
+Compile Aborted 0:01
+Pack NotRun
+βββββββββββββββββββββββββββββββββββββββ
+Total 0:17
+βββββββββββββββββββββββββββββββββββββββ
+```
+
+## Continuing Builds
+
+You can continue a failed or aborted build from the first point of failure:
+
+```powershell
+# terminal-command
+nuke [arguments...] --continue
+```
+
+All previously succeeded targets will be skipped automatically, which can save a lot of unnecessary execution time:
+
+```
+βββββββββββββββββββββββββββββββββββββββ
+Target Status Duration
+βββββββββββββββββββββββββββββββββββββββ
+Restore Skipped
+Compile Succeeded 0:15
+Pack Succeeded 0:05
+βββββββββββββββββββββββββββββββββββββββ
+Total 0:20
+βββββββββββββββββββββββββββββββββββββββ
+```
+
+:::tip
+When you combine the `--continue` argument with the [`dotnet watch`](https://docs.microsoft.com/dotnet/core/tools/dotnet-watch) command, you can establish a very tight feedback loop while working on your target implementation. Just go to the build project directory and call:
+
+```powershell
+# terminal-command
+dotnet watch run -- [arguments..] --continue
+```
+:::
+
+:::caution
+The state of the build instance is NOT serialized. I.e., if a succeeded target produced data for a failed target, that data won't be available during the continuation of the build.
+
+Moreover, a build can only reliably continue when the invocation is the same as in the previous attempt. That means that you can only add the `--continue` switch but not change any other arguments. If this rule is violated, the build will start from the very beginning.
+:::
+
+## Help Text
+
+When you're coming back to a repository or build you haven't worked on in a while, you can bring up the integrated help text by calling:
+
+```powershell
+# terminal-command
+nuke --help
+```
+
+This allows you to inspect all available targets with their direct dependencies as well as parameters with their descriptions:
+
+```text
+Targets (with their direct dependencies):
+
+ Clean
+ Restore
+ Compile (default) -> Restore
+
+Parameters:
+
+ --configuration Configuration to build - Default is 'Debug' (local) or
+ 'Release' (server).
+
+ --continue Indicates to continue a previously failed build attempt.
+ --help Shows the help text for this build assembly.
+ --host Host for execution. Default is 'automatic'.
+ --no-logo Disables displaying the NUKE logo.
+ --plan Shows the execution plan (HTML).
+ --profile Defines the profiles to load.
+ --root Root directory during build execution.
+ --skip List of targets to be skipped. Empty list skips all
+ dependencies.
+ --target List of targets to be invoked. Default is 'Compile'.
+ --verbosity Logging verbosity during build execution. Default is
+ 'Normal'.
+```
+
+## Execution Plans
+
+In order to get a better understanding of how your builds are structured, you can load a visual representation of the different execution plans by calling:
+
+```powershell
+# terminal-command
+nuke --plan
+```
+
+Hovering a target will show its individual execution plan, that means, all targets that are going to be executed when one specific target is invoked. The style of an edge (solid/dashed/yellow) between two targets indicates their [dependency relation](../02-fundamentals/05-targets.md#dependencies) (execution/ordering/trigger):
+
+![Visualizing Execution Plans](plan.gif)
+
+:::info
+
+When no targets are hovered, the execution plan for the [default targets](../02-fundamentals/04-builds.md) is highlighted.
+
+:::
diff --git a/docs/01-getting-started/07-telemetry.md b/docs/01-getting-started/07-telemetry.md
new file mode 100644
index 000000000..a04a9df4c
--- /dev/null
+++ b/docs/01-getting-started/07-telemetry.md
@@ -0,0 +1,81 @@
+---
+title: Telemetry
+---
+
+As an effort to improve NUKE and to provide you with a better, more tailored experience, we include a telemetry feature that collects anonymous usage data and enables us to make more informed decisions for the future.
+
+We want you to be fully aware about telemetry, which is why the global tool will show a disclosure notice on first start. In addition, every build project requires to define a `NukeTelemetryVersion` property:
+
+```xml title="_build.csproj"
+
+ 1
+
+```
+
+We will increase the telemetry version whenever we add or change significant data points. With every version change and after updating the `Nuke.Common` package, you will be prompted again for confirmation.
+
+## Disclosure
+
+NUKE will display a prompt similar to the following when executing a build project without the `NukeTelemetryVersion` property being set or when executing the global tool for the first time.
+
+```text
+Telemetry
+---------
+NUKE collects anonymous usage data in order to help us improve your experience.
+
+Read more about scope, data points, and opt-out: https://nuke.build/telemetry
+```
+
+Once you confirm the notice, NUKE will either:
+
+- Create an awareness cookie under `~/.nuke/telemetry-awareness/v1` for the respective global tool, or
+- Add the `NukeTelemetryVersion` property to the project file.
+
+## Scope
+
+As a global tool and library, NUKE has [multiple events](https://github.com/nuke-build/nuke/blob/master/source/Nuke.Common/Execution/Telemetry.Events.cs) where telemetry is collected:
+
+- `BuildStarted` β when a build was started
+- `TargetSucceeded` β when a target succeeded (only `Restore`, `Compile`, `Test`)
+- `BuildSetup` β when setting up a build via `nuke [:setup]`
+- `CakeConvert` β when converting Cake files via `nuke :cake-convert`
+
+:::info
+Data for `BuildStarted` and `TargetSucceeded` is only collected when `IsServerBuild` returns `true` (i.e., CI build), or the build is invoked via global tool. I.e., a contributor executing `build.ps1` or `build.sh` will not have telemetry enabled unknowingly. Likewise, when a build project targets a higher telemetry version than the installed global tool, the lower version will be used.
+:::
+
+## Data Points
+
+The [telemetry data points](https://github.com/nuke-build/nuke/blob/master/source/Nuke.Common/Execution/Telemetry.Properties.cs) do not collect personal data, such as usernames or email addresses. The data is sent securely to Microsoft servers using [Azure Monitor](https://azure.microsoft.com/services/monitor/) technology, held under restricted access, and published under strict security controls from secure [Azure Storage](https://azure.microsoft.com/services/storage/) systems.
+
+Protecting your privacy is important to us. If you suspect the telemetry is collecting sensitive data or the data is being insecurely or inappropriately handled, file an issue in the [nuke-build/nuke](https://github.com/nuke-build/nuke) repository or [email us](mailto:info@nuke.build?subject=Telemetry) for investigation.
+
+The telemetry feature collects the following data:
+
+| Version | Data |
+|:--------|:------------------------------------------------------------------------------------------|
+| All | Timestamp of invocation |
+| All | Operating system |
+| All | Version of .NET SDK |
+| All | Repository provider (GitHub, GitLab, Bitbucket, etc.) |
+| All | Repository Branch (`main`, `develop`, `feature`, `hotfix`, custom) |
+| All | Hashed Repository URL (SHA256; first 6 characters) |
+| All | Hashed Commit Sha (SHA256; first 6 characters) |
+| All | Compile time of build project in seconds |
+| All | Target framework |
+| All | Version of `Nuke.Common` and `Nuke.GlobalTool` |
+| All | Host implementation (only non-custom) |
+| All | Build type (project/global tool) |
+| All | Number of executable targets |
+| All | Number of custom extensions |
+| All | Number of custom components |
+| All | Used configuration generators and build components (only non-custom) |
+| All | Target execution time in seconds (only for targets named _Restore_, _Compile_, or _Test_) |
+
+:::note
+Whenever a type does not originate from the `Nuke` namespace, it is replaced with ``.
+:::
+
+## How to opt out
+
+The telemetry feature is enabled by default. To opt out, set the `NUKE_TELEMETRY_OPTOUT` environment variable to `1` or `true`.
diff --git a/docs/01-getting-started/_category_.json b/docs/01-getting-started/_category_.json
new file mode 100644
index 000000000..41f4c00e7
--- /dev/null
+++ b/docs/01-getting-started/_category_.json
@@ -0,0 +1,3 @@
+{
+ "label": "Getting Started"
+}
diff --git a/docs/01-getting-started/plan.gif b/docs/01-getting-started/plan.gif
new file mode 100644
index 000000000..7f7e52188
Binary files /dev/null and b/docs/01-getting-started/plan.gif differ
diff --git a/docs/02-fundamentals/04-builds.md b/docs/02-fundamentals/04-builds.md
new file mode 100644
index 000000000..a8d0c02d5
--- /dev/null
+++ b/docs/02-fundamentals/04-builds.md
@@ -0,0 +1,133 @@
+---
+title: Build Anatomy
+---
+
+A build project is a regular .NET console application. However, unlike regular console applications, NUKE chooses to name the main class `Build` instead of `Program`. This establishes a convention and allows easier navigation in your solution. The `Build` class must inherit from the `NukeBuild` base class and define a `Main` method to invoke the build execution and define any number of default targets:
+
+
+
+
+```csharp title="Build.cs"
+class Build : NukeBuild
+{
+ public static int Main() => Execute(x => x.Compile);
+
+ // Target definitions
+}
+```
+
+
+
+
+```csharp title="Build.cs"
+class Build : NukeBuild
+{
+ public static int Main() => Execute(x => x.Test, x => x.Pack);
+
+ // Target definitions
+}
+```
+
+
+
+
+```csharp title="Build.cs"
+class Build : NukeBuild
+{
+ public static int Main() => Execute();
+
+ // Target definitions
+}
+```
+
+
+
+
+:::info
+You will learn how to [write target definitions](05-targets.md) in the next chapter.
+:::
+
+## Base Properties
+
+The `NukeBuild` base class offers great insight into your build through various properties.
+
+### Build Environment
+
+Properties related to the build environment provide information about where the build is running and where various files are located:
+
+```csharp title="NukeBuild.cs"
+abstract class NukeBuild
+{
+ static Host Host { get; }
+ static bool IsLocalBuild { get; }
+ static bool IsServerBuild { get; }
+
+ static AbsolutePath RootDirectory { get; }
+ static AbsolutePath TemporaryDirectory { get; }
+
+ static AbsolutePath BuildAssemblyFile { get; }
+ static AbsolutePath BuildAssemblyDirectory { get; }
+ static AbsolutePath BuildProjectFile { get; }
+ static AbsolutePath BuildProjectDirectory { get; }
+}
+```
+
+:::tip
+With the `Host` property you can determine the running environment, for instance with `Host is TeamCity`. Make sure to explore other implementations of the `Host` base class through your IDE.
+
+---
+
+Since `Host`, `IsLocalBuild`, and `IsServerBuild` are static properties, you can conveniently use them in [static conditions](05-targets.md#conditional-execution) to skip targets (including their dependencies) in local or server builds.
+:::
+
+:::info
+Learn more about the `AbsolutePath` class and how it's used for [path construction](../03-common/03-paths.md).
+:::
+
+### Build Status
+
+Properties related to the build status allow you to examine the status of your targets and the overall build:
+
+```csharp title="NukeBuild.cs"
+abstract class NukeBuild
+{
+ IReadOnlyCollection InvokedTargets { get; }
+ IReadOnlyCollection SkippedTargets { get; }
+
+ bool IsSuccessful { get; }
+ bool IsFailing { get; }
+ bool IsFinished { get; }
+ int? ExitCode { get; set; }
+
+ IReadOnlyCollection ExecutionPlan { get; }
+
+ IReadOnlyCollection ScheduledTargets { get; }
+ IReadOnlyCollection RunningTargets { get; }
+ IReadOnlyCollection AbortedTargets { get; }
+ IReadOnlyCollection FailedTargets { get; }
+ IReadOnlyCollection SucceededTargets { get; }
+ IReadOnlyCollection FinishedTargets { get; }
+}
+```
+
+:::tip
+You can examine the status of targets by using any of the appropriate `ICollection`. For instance, to check if a target has failed, you can write `FailedTargets.Contains(MyTarget)`. This pattern is especially useful with [dynamic conditions](05-targets.md#conditional-execution).
+:::
+
+## Build Events
+
+For implementing cross-cutting concerns, like telemetry and similar, you can hook into various build events:
+
+```csharp title="NukeBuild.cs"
+abstract class NukeBuild
+{
+ virtual void OnBuildCreated();
+ virtual void OnBuildInitialized();
+ virtual void OnBuildFinished();
+
+ virtual void OnTargetRunning(string target);
+ virtual void OnTargetSkipped(string target);
+ virtual void OnTargetFailed(string target);
+ virtual void OnTargetSucceeded(string target);
+}
+```
diff --git a/docs/02-fundamentals/05-targets.md b/docs/02-fundamentals/05-targets.md
new file mode 100644
index 000000000..5f53a633d
--- /dev/null
+++ b/docs/02-fundamentals/05-targets.md
@@ -0,0 +1,332 @@
+---
+title: Target Definitions
+---
+
+Inside a `Build` class, you can define your build steps as `Target` properties. The implementation for a build step is provided as a lambda function through the `Executes` method:
+
+
+
+
+```csharp title="Build.cs"
+class Build : NukeBuild
+{
+ public static int Main() => Execute();
+
+ Target MyTarget => _ => _
+ .Executes(() =>
+ {
+ Console.WriteLine("Hello!");
+ });
+}
+```
+
+
+
+
+
+```csharp title="Build.cs"
+class Build : NukeBuild
+{
+ public static int Main() => Execute();
+
+ Target MyTarget => _ => _
+ .Executes(async () =>
+ {
+ await Console.Out.WriteLineAsync("Hello!");
+ });
+}
+```
+
+:::caution
+Async targets are just a convenience feature that allows you using async APIs in a straightforward way. Behind the scenes, they are still run synchronously.
+:::
+
+
+
+
+## Dependencies
+
+Specifying dependencies is essential to let targets run in a meaningful and predictable order. There are 3 different types of dependencies, each of them can be defined from both directions.
+
+
+
+
+
+
+Define that target `A` must run before target `B` unless `A` is skipped:
+
+```csharp title="Build.cs"
+class Build : NukeBuild
+{
+ Target A => _ => _
+ // highlight-start
+ .DependentFor(B) // Choose this...
+ // highlight-end
+ .Executes(() => { });
+
+ Target B => _ => _
+ // highlight-start
+ .DependsOn(A) // ...or this!
+ // highlight-end
+ .Executes(() => { });
+}
+```
+
+
+
+
+
+
+Define that target `A` runs before target `B` if both are scheduled:
+
+```csharp title="Build.cs"
+class Build : NukeBuild
+{
+ Target A => _ => _
+ // highlight-start
+ .Before(B) // Choose this...
+ // highlight-end
+ .Executes(() => { });
+
+ Target B => _ => _
+ // highlight-start
+ .After(A) // ...or this!
+ // highlight-end
+ .Executes(() => { });
+}
+```
+
+
+
+
+
+
+Define that target `A` invokes target `B` once it completes:
+
+
+```csharp title="Build.cs"
+class Build : NukeBuild
+{
+ Target A => _ => _
+ // highlight-start
+ .Triggers(B) // Choose this...
+ // highlight-end
+ .Executes(() => { });
+
+ Target B => _ => _
+ // highlight-start
+ .TriggeredBy(A) // ...or this!
+ // highlight-end
+ .Executes(() => { });
+}
+```
+
+
+
+
+:::tip
+When choosing a direction, you should ask yourself which target should know about the existence of the other. For instance, should a `Release` target _trigger_ a `Tweet` target? Or should a `Tweet` target _be triggered_ by a `Release` target?
+
+:::
+
+:::caution
+
+Dependencies between targets are solely defined between the individual targets and _not_ through the position they take in a dependency call. The following examples illustrate the difference between the **partial and total order** of targets:
+
+
+
+
+The execution is nondeterministic between `A->B->C` and `B->A->C`. This isn't necessarily problematic, but something to be aware of. In particular, it allows different targets to run in parallel (currently only in compatible CI/CD environments).
+
+```csharp title="Build.cs"
+class Build : NukeBuild
+{
+ Target A => _ => _
+ .Executes(() => { });
+
+ Target B => _ => _
+ .Executes(() => { });
+
+ Target C => _ => _
+ // highlight-start
+ .DependsOn(A, B)
+ // highlight-end
+ .Executes(() => { });
+}
+```
+
+
+
+
+The execution is always deterministic with `A->B->C`.
+
+```csharp title="Build.cs"
+class Build : NukeBuild
+{
+ Target A => _ => _
+ .Executes(() => { });
+
+ Target B => _ => _
+ // highlight-start
+ .DependsOn(A)
+ // highlight-end
+ .Executes(() => { });
+
+ Target C => _ => _
+ // highlight-start
+ .DependsOn(B)
+ // highlight-end
+ .Executes(() => { });
+}
+```
+
+
+
+
+:::
+
+## Conditional Execution
+
+Apart from [skipping targets manually](../01-getting-started/03-execution.md#skipping-targets), you can also programmatically decide whether a target should be skipped. Depending on the use-case, you can choose between dynamic and static conditions.
+
+
+
+
+Define a condition that is checked right before target `B` executes:
+
+```csharp
+class Build : NukeBuild
+{
+ readonly List Data = new();
+
+ Target A => _ => _
+ .Executes(() => { /* Populate Data */ });
+
+ Target B => _ => _
+ .DependsOn(A)
+ // highlight-start
+ .OnlyWhenDynamic(() => Data.Any())
+ // highlight-end
+ .Execute(() => { });
+}
+```
+
+
+
+
+Define a condition that is checked before target `A` and `B` execute:
+
+```csharp
+class Build : NukeBuild
+{
+ Target A => _ => _
+ .Executes(() => { });
+
+ Target B => _ => _
+ // highlight-start
+ .OnlyWhenStatic(() => IsLocalBuild)
+ // By default, dependencies are skipped
+ .WhenSkipped(DependencyBehavior.Execute)
+ // highlight-end
+ .DependsOn(A)
+ .Execute(() => { });
+}
+```
+
+
+
+
+:::tip
+When a condition is not met, the skip reason is created from the boolean expression. For more complex conditions, you can extract the logic into a separate method or property to make the message more readable.
+:::
+
+## Requirements
+
+You can define target requirements that are checked right at the beginning of the build execution before any other targets are executed:
+
+```csharp
+class Build : NukeBuild
+{
+ Target A => _ => _
+ // highlight-start
+ .Requires(() => IsServerBuild)
+ // highlight-end
+ .Executes(() => { });
+}
+```
+
+:::note
+Target requirements are an important aspect to achieve a [fail-fast behavior](https://en.wikipedia.org/wiki/Fail-fast). Preceding targets won't waste any execution time only to discover that a condition that was known right from the beginning was not met.
+:::
+
+:::tip
+When a requirement is not met, the exception message is created from the boolean expression. For more complex requirements, you can extract the logic into a separate method or property to make the message more readable.
+:::
+
+## Failure Handling
+
+Not every failing target should completely stop the build. Targets that are not essential can allow to continue the execution for other targets are important to run even if another target has failed. For these use-cases, you can configure the failure handling.
+
+
+
+
+Define that execution continues after target `A` throws:
+
+```csharp
+class Build : NukeBuild
+{
+ Target A => _ => _
+ // highlight-start
+ .ProceedAfterFailure()
+ // highlight-end
+ .Executes(() =>
+ {
+ Assert.Fail("error");
+ });
+
+ Target B => _ => _
+ .DependsOn(A)
+ .Execute(() => { });
+}
+```
+
+
+
+
+Define that target `B` executes even if another target fails:
+
+```csharp
+class Build : NukeBuild
+{
+ Target A => _ => _
+ .Executes(() =>
+ {
+ Assert.Fail("error");
+ });
+
+ Target B => _ => _
+ // highlight-start
+ .AssuredAfterFailure()
+ // highlight-end
+ .DependsOn(A)
+ .Execute(() => { });
+}
+```
+
+
+
+
+## Unlisting Targets
+
+It is good practice to follow the [single-responsibility principle](https://en.wikipedia.org/wiki/Single-responsibility_principle) when implementing targets. However, you may not want to expose every target through the [build help text](../01-getting-started/03-execution.md#help-text). For cases like this, you can un-list a target:
+
+```csharp
+class Build : NukeBuild
+{
+ Target A => _ => _
+ // highlight-start
+ .Unlisted()
+ // highlight-end
+ .Executes(() => { });
+}
+```
diff --git a/docs/02-fundamentals/06-parameters.md b/docs/02-fundamentals/06-parameters.md
new file mode 100644
index 000000000..318391bc1
--- /dev/null
+++ b/docs/02-fundamentals/06-parameters.md
@@ -0,0 +1,244 @@
+---
+title: Parameters
+---
+
+Another important aspect of build automation is the ability of passing input values to your build. These input values can be anything from generic texts, numeric and enum values, file and directory paths, arrays of aforementioned, boolean flags, or secrets. NUKE comes with a succinct way to declare parameters and lets you set their values in various ways.
+
+You can declare a parameter by adding the `Parameter` attribute to a field or property:
+
+```csharp
+[Parameter("Description")]
+readonly string MyParameter;
+```
+
+:::tip
+You can set default values for parameters as you would normally do through field and property initializers. You can also use static [build base properties](04-builds.md#base-properties) like `IsLocalBuild` or `IsServerBuild` for environmental adjustments:
+
+```csharp
+[Parameters]
+readonly Configuration Configuration = IsServerBuild
+ ? Configuration.Release
+ : Configuration.Debug;
+```
+
+Following best practices, you should mark all your parameters as `readonly`.
+:::
+
+## Passing Parameter Values
+
+Parameters are resolved through different mechanisms, each supporting a different automation use-case. These mechanisms are explained in the following sections by their resolution priority.
+
+### Passing Values through the Command-Line
+
+In the most straightforward way, you can pass parameter values from the command-line through their [kebab-case](https://www.theserverside.com/definition/Kebab-case) names prefixed with a double-dash:
+
+```powershell
+# terminal-command
+nuke --my-parameter
+```
+
+:::tip
+With the global tool installed and [shell completion](../06-global-tool/00-shell-completion.md) configured, you can pass parameters much faster and avoid any typos.
+:::
+
+### Passing Values through Parameter Files
+
+Instead of providing default values in your `Build` class or repeatedly specifying them through the command-line, you can also define them in so-called parameter files (JSON). These files are located under the `.nuke` directory:
+
+```json title=".nuke/parameters.json"
+{
+ "$schema": "./build.schema.json",
+ "MyParameter": "value"
+}
+```
+
+Besides the default `parameters.json` file, you can create additional profiles following the `parameters..json` naming pattern. These profiles can be loaded on-demand
+
+```powershell
+# terminal-command
+nuke --profile [other-profiles...]
+```
+
+:::info
+Profiles are applied in the order they are passed, whereas the default parameters file comes first.
+:::
+
+:::tip
+Based on the `build.schema.json` file, you can easily configure your parameters inside your IDE using schema-completion:
+
+
+
+![Completion in Parameter Files](parameter-file-completion-light.webp#gh-light-mode-only)
+![Completion in Parameter Files](parameter-file-completion-dark.webp#gh-dark-mode-only)
+
+
+
+Remember, that the `build.schema.json` file must be regenerated whenever you add or change a parameter. For instance by calling `nuke --help`.
+:::
+
+### Passing Values through Environment Variables
+
+You can set parameter values through environment variables, which can be really helpful when setting up global values in CI/CD pipelines. This is done in such a manner that casing and underscores are completely ignored. Also, you can use the `NUKE_` prefix to easily distinguish them from others:
+
+```powershell
+SET MY_PARAMETER =
+SET NUKE_MY_PARAMETER =
+```
+
+## Required Parameters
+
+You can specify a parameter as a [target requirement](../02-fundamentals/05-targets.md#requirements) using the following shorthand syntax:
+
+
+```cs
+Target Deploy => _ => _
+ .Requires(() => ApiKey)
+ .Executes(() =>
+ {
+ });
+```
+
+
+:::tip
+Using the shorthand syntax allows you to provide the value interactively when the build is executed locally.
+:::
+
+## Secret Parameters
+
+When parameters are meant to hold **secret values** like passwords or authentication tokens, you can add the `Secret` attribute:
+
+
+```cs
+[Parameter] [Secret] readonly string NuGetApiKey;
+```
+
+
+Marking a parameter as a secret allows you to use the [secret management](../06-global-tool/02-secrets.md) through the global tool.
+
+## Unlisting Parameters
+
+Just like targets, your parameters will automatically show up in the [build help text](../01-getting-started/03-execution.md#help-text) along with their description. You can opt out from this behavior by setting the `List` property:
+
+```csharp
+[Parameter(List = false)]
+readonly string MyParameter;
+```
+
+Unlisted parameters can be passed as normal and are still available through [shell completion](../06-global-tool/00-shell-completion.md).
+
+## Supported Types
+
+Parameters **support a wide range of primitive and complex types**, including their nullable and array counterparts:
+
+
+```cs
+[Parameter] readonly string StringValue;
+[Parameter] readonly bool BoolValue;
+[Parameter] readonly int? IntegerValue;
+[Parameter] readonly string[] StringArray;
+
+[Parameter] readonly MSBuildVersion MSBuildVersion;
+[Parameter] readonly Configuration Configuration;
+[Parameter] readonly AbsolutePath AbsolutePath;
+
+Target Print => _ => _
+ .Executes(() =>
+ {
+ Log.Information("StringValue = {Value}", StringValue);
+ Log.Information("BoolValue = {Value}", BoolValue);
+ Log.Information("IntegerValue = {Value}", IntegerValue?.ToString() ?? "");
+ Log.Information("StringArray = {Value}", StringArray?.JoinComma() ?? "");
+
+ Log.Information("MSBuildVersion = {Value}", MSBuildVersion);
+ Log.Information("Configuration = {Value}", Configuration);
+ Log.Information("AbsolutePath = {Value}", AbsolutePath);
+ });
+```
+
+
+:::note
+By default, the whitespace character is used to pass multiple values for an array parameter. You can quote your values to treat them as single elements for the parameters. Additionally, you can provide a custom separator through the attribute (whitespace will still work as a separator):
+
+```csharp
+[Parameter(Separator = '+')]
+readonly int[] Numbers;
+```
+:::
+
+### Custom Types
+
+All the supported types from above use the [type converter](https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.typeconverter) infrastructure to convert string values to their respective type instances. This works independently of the fact how the parameter is resolved. It's worth noting that also parameter files will be converter to strings internally.
+
+Depending on your use-case, you can choose one of the following approaches to define your custom type that can convert from string values:
+
+
+
+
+[Enumeration types](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/enum) define a set of named constants with underlying numeric value:
+
+```csharp
+enum CustomType
+{
+ One,
+ Two,
+ Three
+}
+```
+
+:::info
+Members of enumeration types automatically show up during [shell completion](../06-global-tool/00-shell-completion.md).
+:::
+
+
+
+
+[Enumeration classes](https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/enumeration-classes-over-enum-types) are open for external extension. The `Enumeration` base class defines equality operators and implicit string conversion:
+
+```csharp
+[TypeConverter(typeof(TypeConverter))]
+public class Configuration : Enumeration
+{
+ public static Configuration Debug = new () { Value = nameof(Debug) };
+ public static Configuration Release = new () { Value = nameof(Release) };
+}
+```
+
+:::info
+Members of enumeration classes automatically show up during [shell completion](../06-global-tool/00-shell-completion.md).
+:::
+
+
+
+
+```csharp
+[TypeConverter(typeof(TypeConverter))]
+public class CustomType
+{
+ public class TypeConverter : System.ComponentModel.TypeConverter
+ {
+ public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
+ {
+ return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
+ }
+
+ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
+ {
+ if (value is string data)
+ return new CustomType(data);
+
+ if (value is null)
+ return null;
+
+ return base.ConvertFrom(context, culture, value);
+ }
+ }
+
+ public CustomType(string data)
+ {
+ // ...
+ }
+}
+```
+
+
+
diff --git a/docs/02-fundamentals/10-logging.md b/docs/02-fundamentals/10-logging.md
new file mode 100644
index 000000000..2f88e8667
--- /dev/null
+++ b/docs/02-fundamentals/10-logging.md
@@ -0,0 +1,176 @@
+---
+title: Logging
+---
+
+As with any other application, good logging greatly reduces the time to detect the source of errors and fix them quickly. NUKE integrates with [Serilog](https://serilog.net/) and prepares a console and file logger for you. Most functions with side effects will automatically log their performed actions. This also includes [invocations of CLI tools](../03-common/08-cli-tools.md). Of course, you can also add your own log messages:
+
+```csharp
+// using Serilog;
+
+Log.Verbose("This is a verbose message");
+Log.Debug("This is a debug message");
+Log.Information("This is an information message");
+Log.Warning("This is a warning message");
+Log.Error("This is an error message");
+```
+
+:::tip
+For error messages, you most certainly want to use [assertions](14-assertions.md) instead to also fail the build.
+:::
+
+## Console Sink
+
+Based on your IDE and CI/CD service, the console sink is automatically configured with the [best-looking themes](https://github.com/serilog/serilog-sinks-console#themes). When your terminal supports [ANSI colors](https://en.wikipedia.org/wiki/ANSI_escape_code) (`TERM=xterm`), an ANSI theme is chosen. Otherwise, a simple [system-color](https://docs.microsoft.com/en-us/dotnet/api/system.consolecolor) theme is used.
+
+:::info
+Adaptive themes are particularly great for consistent colors in your CI/CD environment.
+:::
+
+Log messages are only written to console when the appropriate `LogLevel` is set. You can change it by passing the `--verbosity` parameter:
+
+
+
+
+```powershell
+# terminal-command
+nuke --verbosity verbose
+```
+
+
+
+
+```powershell
+# terminal-command
+nuke --verbosity normal
+```
+
+
+
+
+```powershell
+# terminal-command
+nuke --verbosity minimal
+```
+
+
+
+
+```powershell
+# terminal-command
+nuke --verbosity quiet
+```
+
+
+
+
+Or by setting it directly in the build implementation:
+
+
+
+
+
+```csharp
+Logging.Level = LogLevel.Trace;
+```
+
+
+
+
+
+```csharp
+Logging.Level = LogLevel.Normal;
+```
+
+
+
+
+```csharp
+Logging.Level = LogLevel.Warning;
+```
+
+
+
+
+```csharp
+Logging.Level = LogLevel.Error;
+```
+
+
+
+
+In the following image you can see that the verbose message is hidden because the current log level was set to `Normal`:
+
+
+
+![Logging Output in Console](logging-console-light.webp#gh-light-mode-only)
+![Logging Output in Console](logging-console-dark.webp#gh-dark-mode-only)
+
+
+
+:::tip
+Error and warning log messages are repeated right before the [build summary](../01-getting-started/03-execution.md#build-summary) to give you a quick-look at what went wrong.
+:::
+
+## File Sinks
+
+For each build, a new log file is written to the temporary directory. The Serilog message template is pre-configured as:
+
+```text title="Message Template"
+{Timestamp:HH:mm:ss.fff} | {Level:u1} | {Target} | {Message:l}{{NewLine}{{Exception}
+```
+
+With the sample logging from above, the file would like roughly like this:
+
+```log title=".nuke/temp/build.log"
+03:57:38.208 | V | Compile | This is a verbose message
+03:57:38.208 | D | Compile | This is a debug message
+03:57:38.208 | I | Compile | This is an information message
+03:57:38.208 | W | Compile | This is a warning message
+03:57:38.208 | E | Compile | This is an error message
+```
+
+:::tip
+With the [Ideolog plugin](https://plugins.jetbrains.com/plugin/9746-ideolog) for [JetBrains Rider](https://jetbrains.com/rider/) you can view and inspect log files more comfortably. It automatically highlights messages according to their log level, allows collapsing irrelevant messages based on search terms, and will enable navigation for exception stack traces.
+
+
+
+![Ideolog plugin in JetBrains Rider](logging-ideolog-light.webp#gh-light-mode-only)
+![Ideolog plugin in JetBrains Rider](logging-ideolog-dark.webp#gh-dark-mode-only)
+
+
+:::
+
+### Comparing Log Files
+
+For the purpose of log comparison, local builds will create another log file with the current timestamp in its name but without the timestamp in the message template:
+
+```text title="Message Template"
+{Level:u1} | {Target} | {Message:l}{NewLine}{Exception}
+```
+
+:::info
+Only the last 5 build logs are kept.
+:::
+
+With the same sample logging from above, the file now looks like this:
+
+
+{`
+V | Compile | This is a verbose message
+D | Compile | This is a debug message
+I | Compile | This is an information message
+W | Compile | This is a warning message
+E | Compile | This is an error message
+`.trim()}
+
+
+With the comparison tool of your choice, you can then select two files and compare them. For instance, when you remove the debug message and add another warning message, the comparison tool will show the following:
+
+```diff title="Diff Output"
+ V | Compile | This is a verbose message
+- D | Compile | This is a debug message
+ I | Compile | This is an information message
+ W | Compile | This is a warning message
++ W | Compile | This is another warning message
+ E | Compile | This is an error message
+```
diff --git a/docs/02-fundamentals/14-assertions.md b/docs/02-fundamentals/14-assertions.md
new file mode 100644
index 000000000..8b1b84300
--- /dev/null
+++ b/docs/02-fundamentals/14-assertions.md
@@ -0,0 +1,66 @@
+---
+title: Assertions
+---
+
+As in any other codebase, it is good practice to assert assumptions before continuing with more heavy procedures in your build automation. When an assertion is violated, it usually entails that the build should fail immediately.
+
+In the most simple form, you can fail a build by calling:
+
+```csharp
+Assert.Fail("This was unexpected!");
+```
+
+Furthermore, you can use one of the following more specific assertion methods:
+
+
+
+
+```csharp
+// Assert not-null fluently
+obj.NotNull().ToString();
+
+// Assert not-null explicitly
+Assert.NotNull(obj);
+```
+
+
+
+
+```csharp
+// Assert true condition
+Assert.True(response.IsSuccessStatusCode);
+
+// Assert false condition
+Assert.False(repository.IsOnMainBranch());
+```
+
+
+
+
+```csharp
+// Assert collection is not empty or empty
+Assert.NotEmpty(releaseNotes);
+Assert.Empty(errors);
+
+// Assert collection count
+Assert.Count(packages, length: 5);
+Assert.HasSingleItem(matchingEntries);
+```
+
+
+
+
+```csharp
+// Assert file exists
+Assert.FileExists(file);
+
+// Assert directory exists
+Assert.DirectoryExists(directory);
+```
+
+
+
+
+:::info
+Each of the above methods uses the [`CallerArgumentExpressionAttribute`](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-10.0/caller-argument-expression) to capture usage details from the call-site. If you want to provide a more comprehensive explanation, you can pass the `message` parameter instead.
+:::
diff --git a/docs/02-fundamentals/_category_.json b/docs/02-fundamentals/_category_.json
new file mode 100644
index 000000000..3d3a48f26
--- /dev/null
+++ b/docs/02-fundamentals/_category_.json
@@ -0,0 +1,3 @@
+{
+ "label": "Fundamentals"
+}
diff --git a/docs/02-fundamentals/logging-console-dark.png b/docs/02-fundamentals/logging-console-dark.png
new file mode 100644
index 000000000..4488ef4b0
Binary files /dev/null and b/docs/02-fundamentals/logging-console-dark.png differ
diff --git a/docs/02-fundamentals/logging-console-dark.webp b/docs/02-fundamentals/logging-console-dark.webp
new file mode 100644
index 000000000..0afdbac5e
Binary files /dev/null and b/docs/02-fundamentals/logging-console-dark.webp differ
diff --git a/docs/02-fundamentals/logging-console-light.png b/docs/02-fundamentals/logging-console-light.png
new file mode 100644
index 000000000..83b6c4dbd
Binary files /dev/null and b/docs/02-fundamentals/logging-console-light.png differ
diff --git a/docs/02-fundamentals/logging-console-light.webp b/docs/02-fundamentals/logging-console-light.webp
new file mode 100644
index 000000000..dbcc4fff5
Binary files /dev/null and b/docs/02-fundamentals/logging-console-light.webp differ
diff --git a/docs/02-fundamentals/logging-ideolog-dark.png b/docs/02-fundamentals/logging-ideolog-dark.png
new file mode 100644
index 000000000..45ec583ce
Binary files /dev/null and b/docs/02-fundamentals/logging-ideolog-dark.png differ
diff --git a/docs/02-fundamentals/logging-ideolog-dark.webp b/docs/02-fundamentals/logging-ideolog-dark.webp
new file mode 100644
index 000000000..ccdf3894e
Binary files /dev/null and b/docs/02-fundamentals/logging-ideolog-dark.webp differ
diff --git a/docs/02-fundamentals/logging-ideolog-light.png b/docs/02-fundamentals/logging-ideolog-light.png
new file mode 100644
index 000000000..b5a6218df
Binary files /dev/null and b/docs/02-fundamentals/logging-ideolog-light.png differ
diff --git a/docs/02-fundamentals/logging-ideolog-light.webp b/docs/02-fundamentals/logging-ideolog-light.webp
new file mode 100644
index 000000000..8f761677f
Binary files /dev/null and b/docs/02-fundamentals/logging-ideolog-light.webp differ
diff --git a/docs/02-fundamentals/parameter-file-completion-dark.png b/docs/02-fundamentals/parameter-file-completion-dark.png
new file mode 100644
index 000000000..5895593fa
Binary files /dev/null and b/docs/02-fundamentals/parameter-file-completion-dark.png differ
diff --git a/docs/02-fundamentals/parameter-file-completion-dark.webp b/docs/02-fundamentals/parameter-file-completion-dark.webp
new file mode 100644
index 000000000..e136140ab
Binary files /dev/null and b/docs/02-fundamentals/parameter-file-completion-dark.webp differ
diff --git a/docs/02-fundamentals/parameter-file-completion-light.png b/docs/02-fundamentals/parameter-file-completion-light.png
new file mode 100644
index 000000000..c3c495d5e
Binary files /dev/null and b/docs/02-fundamentals/parameter-file-completion-light.png differ
diff --git a/docs/02-fundamentals/parameter-file-completion-light.webp b/docs/02-fundamentals/parameter-file-completion-light.webp
new file mode 100644
index 000000000..56e17dbac
Binary files /dev/null and b/docs/02-fundamentals/parameter-file-completion-light.webp differ
diff --git a/docs/03-common/03-paths.md b/docs/03-common/03-paths.md
new file mode 100644
index 000000000..7d823b071
--- /dev/null
+++ b/docs/03-common/03-paths.md
@@ -0,0 +1,73 @@
+---
+title: Constructing Paths
+---
+
+Referencing files and directories seems like a trivial task. Nevertheless, developers often run into problems where relative paths no longer match the current working directory, or find themselves fixing path separator issues that stem from [historical design decisions](https://www.youtube.com/watch?v=5T3IJfBfBmI). NUKE follows the approach to use absolute paths whenever possible, which ensures explicitness and allows copying [tool invocations](08-cli-tools.md) from the log and executing them from anywhere you are.
+
+Central to the idea of absolute paths is the `AbsolutePath` type and the `NukeBuild.RootDirectory` property. From there on, you can easily construct paths through the [overloaded division operator](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/operator-overloading):
+
+
+```cs
+AbsolutePath SourceDirectory => RootDirectory / "src";
+AbsolutePath OutputDirectory => RootDirectory / "output";
+AbsolutePath IndexFile => RootDirectory / "docs" / "index.md";
+```
+
+
+## Common Methods
+
+While `AbsolutePath` is agnostic to whether it points to a file or directory, it provides several commonly used methods for interaction:
+
+
+```cs
+// Get names
+var nameWithExtension = IndexFile.Name;
+var nameWithoutExtension = IndexFile.NameWithoutExtension;
+var extensionWithDot = IndexFile.Extension;
+
+// Get the parent directory
+var parent1 = IndexFile.Parent;
+var parent2 = IndexFile / ".."; // gets normalized
+
+// Check if one path contains another
+var containsFile = SourceDirectory.Contains(IndexFile);
+
+// Check if a directory or file exists
+var directoryExists = SourceDirectory.DirectoryExists();
+var fileExists = IndexFile.FileExists();
+var pathExists = (RootDirectory / "dirOrFile").Exists(); // checks for both
+```
+
+
+## Relative Paths
+
+Occasionally, you may actually want relative paths, for instance to include them in manifest files that get shipped with your artifacts. In this case, you can make use of `RelativePath`, which uses the path separator dictated by the operating system, or one of types `WinRelativePath` or `UnixRelativePath`, which enforce using backslash or slash respectively:
+
+
+```cs
+// Get the relative path to the index file
+var indexRelativeFile = RootDirectory.GetRelativePathTo(IndexFile);
+
+// Get relative path for Unix
+var indexUnixRelativePath1 = RootDirectory.GetUnixRelativePathTo(IndexFile);
+var indexUnixRelativePath2 = (UnixRelativePath)indexRelativeFile;
+```
+
+
+All relative path types support using the division operator.
+
+## Globbing
+
+Through the integrated [Glob](https://github.com/kthompson/glob) NuGet package, you can use [globbing patterns](https://en.wikipedia.org/wiki/Glob_(programming)) to collect files or directories from a base directory:
+
+
+```cs
+// Collect all package files from the output directory
+var packageFiles = OutputDirectory.GlobFiles("*.nupkg");
+
+// Collect and delete all /obj and /bin directories in all sub-directories
+SourceDirectory
+ .GlobDirectories("**/{obj,bin}", otherPatterns)
+ .DeleteDirectories();
+```
+
diff --git a/docs/03-common/05-repository.md b/docs/03-common/05-repository.md
new file mode 100644
index 000000000..7b44f2920
--- /dev/null
+++ b/docs/03-common/05-repository.md
@@ -0,0 +1,114 @@
+---
+title: Repository Insights
+---
+
+Having knowledge about the current branch, applied tags, and the repository origin is eminently important in various scenarios. For instance, the deployment destination for an application is different whether executed from a release or personal branch. An announcement target may only be executed when running on the main branch. And in many cases it is advisable to include repository metadata, like origin and commit hash, into the artifacts for better traceability.
+
+You can use the `GitRepositoryAttribute` on a `GitRepository` field or property, to automatically load all relevant information for the current revision at the beginning of build execution:
+
+
+```cs
+[GitRepository] readonly GitRepository Repository;
+
+Target Print => _ => _
+ .Executes(() =>
+ {
+ Log.Information("Commit = {Value}", Repository.Commit);
+ Log.Information("Branch = {Value}", Repository.Branch);
+ Log.Information("Tags = {Value}", Repository.Tags);
+
+ Log.Information("main branch = {Value}", Repository.IsOnMainBranch());
+ Log.Information("main/master branch = {Value}", Repository.IsOnMainOrMasterBranch());
+ Log.Information("release/* branch = {Value}", Repository.IsOnReleaseBranch());
+ Log.Information("hotfix/* branch = {Value}", Repository.IsOnHotfixBranch());
+
+ Log.Information("Https URL = {Value}", Repository.HttpsUrl);
+ Log.Information("SSH URL = {Value}", Repository.SshUrl);
+ });
+```
+
+
+:::tip
+Repository insights allow you to design your targets in a flexible manner using [requirements](../02-fundamentals/05-targets.md#requirements), [conditional execution](../02-fundamentals/05-targets.md#conditional-execution), or hybrid implementations:
+
+
+```cs
+[GitRepository] readonly GitRepository Repository;
+string OriginalRepositoryUrl => "https://github.com/nuke-build/nuke";
+
+Target Deploy => _ => _
+ .Requires(() => Repository.IsOnMainOrMasterBranch());
+
+Target CheckMilestone => _ => _
+ .OnlyWhenStatic(() => Repository.HttpsUrl.EqualsOrdinalIgnoreCase(OriginalRepositoryUrl));
+
+Target Hotfix => _ => _
+ .Executes(() =>
+ {
+ if (Repository.IsOnHotfixBranch())
+ FinishHotfix();
+ else
+ CreateHotfix();
+ });
+```
+
+:::tip
+
+:::info
+You can also manually create a `GitRepository` instance:
+
+```c#
+var repository1 = GitRepository.FromLocalDirectory(directory);
+var repository2 = GitRepository.FromUrl(url);
+```
+
+The only difference between `FromUrl` and `FromLocalDirectory` is that the latter can initialize more properties, including `Commit`, `Tags`, and `RemoteBranch`.
+:::
+
+## GitHub Integration
+
+As one of the most popular Git hosting services, NUKE provides several methods to retrieve GitHub-specific **identifiers and links** from a repository:
+
+
+```cs
+// Get repository owner and name
+var (owner, name) = (Repository.GetGitHubOwner(), Repository.GetGitHubName());
+
+// Get commit details URL when Repository is fully-synced
+var commitUrl = Repository.GetGitHubCommitUrl(Repository.Commit);
+
+// Get comparison URL between tags
+var comparisonUrl = Repository.GetGitHubCompareTagsUrl("1.0.1", "1.0.2");
+
+// Get file download URL
+var downloadUrl = Repository.GetGitHubDownloadUrl(RootDirectory / "CHANGELOG.md", branch: "main");
+```
+
+
+You can also further interact with the repository using the [Octokit.NET](https://github.com/octokit/octokit.net) integration:
+
+
+```cs
+// Get the default branch
+var defaultBranch = Repository.GetDefaultBranch();
+
+// Get the latest release
+var latestRelease = Repository.GetLatestRelease(includePrerelease: false);
+```
+
+
+For certain operations, you may initialize an **authorized client**:
+
+
+```cs
+// Set credentials for authorized actions
+var credentials = new Credentials(GitHubActions.Instance.Token);
+GitHubTasks.GitHubClient = new GitHubClient(
+ new ProductHeaderValue(nameof(NukeBuild)),
+ new InMemoryCredentialStore(credentials));
+
+// Create and close a milestone
+Repository.CreateGitHubMilestone("5.1.0");
+Repository.CloseGitHubMilestone("5.1.0", enableIssueChecks: true);
+```
+
diff --git a/docs/03-common/06-serialization.md b/docs/03-common/06-serialization.md
new file mode 100644
index 000000000..9cb8eebbf
--- /dev/null
+++ b/docs/03-common/06-serialization.md
@@ -0,0 +1,134 @@
+---
+title: Data Serialization
+---
+
+Structured data plays an essential role in build automation. You may want to read a list of repositories to be checked out, write data that's consumed by another tool, or update version numbers of SDKs and tools you consume. The central entry point for data serialization is the `SerializationTasks` class, which comes with support for JSON, XML, and YAML.
+
+
+
+
+:::note
+Please read the [Newtonsoft.Json documentation](https://www.newtonsoft.com/json/help/html/Introduction.htm) before proceeding.
+:::
+
+
+
+
+:::note
+Please read the [XDocument documentation](https://docs.microsoft.com/en-us/dotnet/standard/linq/xdocument-class-overview) before proceeding.
+:::
+
+
+
+
+:::note
+Please read the [YamlDotNet documentation](https://github.com/aaubry/YamlDotNet/wiki) before proceeding.
+:::
+
+
+
+
+## String Serialization
+
+You can serialize data to strings and deserialize back from them as follows:
+
+
+
+
+```csharp title="Build.cs"
+// Strongly-typed
+var configuration = json.GetJson();
+var json = configuration.ToJson();
+
+// Dynamically-typed
+var jobject = json.GetJson();
+```
+
+
+
+
+```csharp title="Build.cs"
+// Strongly-typed
+var configuration = xml.GetXml();
+var xml = configuration.ToXml();
+```
+
+
+
+
+```csharp title="Build.cs"
+// Strongly-typed
+var configuration = yaml.GetYaml();
+var yaml = configuration.ToYaml();
+```
+
+
+
+
+## File Serialization
+
+You can serialize data to files and deserialize back from them as follows:
+
+
+
+
+```csharp title="Build.cs"
+// Strongly-typed
+var configuration = jsonFile.ReadJson();
+jsonFile.WriteJson(configuration);
+
+// Dynamically-typed
+var jobject = jsonFile.ReadJson();
+```
+
+
+
+
+```csharp title="Build.cs"
+// Strongly-typed
+var configuration = xmlFile.ReadXml();
+xmlFile.WriteXml(configuration);
+```
+
+
+
+
+```csharp title="Build.cs"
+// Strongly-typed
+var configuration = yamlFile.ReadYaml();
+yamlFile.WriteYaml(configuration);
+```
+
+
+
+
+### Updating Files
+
+Instead of reading, updating, and writing files in separated steps, you can also use the atomic functions below:
+
+
+
+
+```csharp title="Build.cs"
+jsonFile.UpdateJson(
+ update: x => x.Value = "new-value");
+```
+
+
+
+
+```csharp title="Build.cs"
+xmlFile.UpdateXml(
+ update: x => x.Value = "new-value");
+```
+
+
+
+
+```csharp title="Build.cs"
+yamlFile.UpdateYaml(
+ update: x => x.Value = "new-value");
+```
+
+
+
diff --git a/docs/03-common/06-versioning.md b/docs/03-common/06-versioning.md
new file mode 100644
index 000000000..042e233e0
--- /dev/null
+++ b/docs/03-common/06-versioning.md
@@ -0,0 +1,187 @@
+---
+title: Versioning Artifacts
+---
+
+Whenever a build produces artifacts, those should be identifiable with a unique version number. This avoids making wrong expectations about available features or fixed bugs, and allows for clear discussions between developers, QA team, and product users. The most common version approaches are are [semantic versioning](https://semver.org/) and [calendar versioning](https://calver.org/).
+
+## Repository-based Versioning
+
+NUKE supports 4 different tools that help generating version numbers from your repository and its commits. Each of these tools comes with its own attribute that populates the field with the information calculated:
+
+
+
+
+:::note
+Please refer to the [GitVersion documentation](https://gitversion.net/docs/reference/configuration) for any questions.
+:::
+
+```powershell title="Tool Installation"
+# terminal-command
+nuke :add-package GitVersion.Tool
+```
+
+```csharp title="Build.cs"
+[GitVersion]
+readonly GitVersion GitVersion;
+
+Target Print => _ => _
+ .Executes(() =>
+ {
+ Log.Information("GitVersion = {Value}", GitVersion.MajorMinorPatch);
+ });
+```
+
+
+
+
+:::note
+Please refer to the [Nerdbank.GitVersioning documentation](https://github.com/dotnet/Nerdbank.GitVersioning/blob/master/doc/versionJson.md) for any questions.
+:::
+
+```powershell title="Tool Installation"
+# terminal-command
+nuke :add-package Nerdbank.GitVersioning
+```
+
+```csharp title="Build.cs"
+[NerdbankGitVersioning]
+readonly NerdbankGitVersioning NerdbankVersioning;
+
+Target Print => _ => _
+ .Executes(() =>
+ {
+ Log.Information("NerdbankVersioning = {Value}", NerdbankVersioning.SimpleVersion);
+ });
+```
+
+
+
+
+:::note
+Please refer to the [OctoVersion documentation](https://github.com/OctopusDeploy/OctoVersion#configuration) for any questions.
+:::
+
+```powershell title="Tool Installation"
+# terminal-command
+nuke :add-package Octopus.OctoVersion.Tool
+```
+
+```csharp title="Build.cs"
+[OctoVersion]
+readonly OctoVersionInfo OctoVersionInfo;
+
+Target Print => _ => _
+ .Executes(() =>
+ {
+ Log.Information("OctoVersionInfo = {Value}", OctoVersionInfo.MajorMinorPatch);
+ });
+```
+
+
+
+
+:::note
+Please refer to the [MinVer documentation](https://github.com/adamralph/minver#usage) for any questions.
+:::
+
+```powershell title="Tool Installation"
+# terminal-command
+nuke :add-package MinVer
+```
+
+```csharp title="Build.cs"
+[MinVer]
+readonly MinVer MinVer;
+
+Target Print => _ => _
+ .Executes(() =>
+ {
+ Log.Information("MinVer = {Value}", MinVer.Version);
+ });
+```
+
+
+
+
+:::info
+Note that when the versioning tool fails to calculate version numbers, a warning will be logged and the attributed field remains uninitialized. In that case, you can try executing the issued command manually or `nuke --verbosity verbose` to reveal more detailed information. In most cases, the repository is either not initialized, has no commits, or is missing the tool-specific configuration file.
+:::
+
+## Dependency-based Versioning
+
+When your versioning is affected by external dependencies, NUKE provides another mechanism to load the latest version of those prior to build execution. Each attribute provides various properties to control which versions should be considered and how it should be transformed:
+
+
+
+
+```csharp title="Build.cs"
+[LatestNuGetVersion(
+ packageId: "JetBrains.ReSharper.SDK",
+ IncludePrerelease = true)]
+readonly NuGetVersion ReSharperVersion;
+
+Target Print => _ => _
+ .Executes(() =>
+ {
+ Log.Information("ReSharperVersion = {Value}", ReSharperVersion);
+ });
+```
+
+
+
+
+```csharp title="Build.cs"
+[LatestGitHubRelease(
+ identifier: "JetBrains/gradle-intellij-plugin",
+ TrimPrefix = true)]
+readonly string GradlePluginVersion;
+
+Target Print => _ => _
+ .Executes(() =>
+ {
+ Log.Information("GradlePluginVersion = {Value}", GradlePluginVersion);
+ });
+```
+
+
+
+
+```csharp title="Build.cs"
+[LatestMyGetVersion(
+ feed: "rd-snapshots",
+ package: "rd-gen")]
+readonly string RdGenVersion;
+
+Target Print => _ => _
+ .Executes(() =>
+ {
+ Log.Information("RdGenVersion = {Value}", RdGenVersion);
+ });
+```
+
+
+
+
+```csharp title="Build.cs"
+[LatestMavenVersion(
+ repository: "plugins.gradle.org/m2",
+ groupId: "org.jetbrains.kotlin.jvm",
+ artifactId: "org.jetbrains.kotlin.jvm.gradle.plugin")]
+readonly string KotlinJvmVersion;
+
+Target Print => _ => _
+ .Executes(() =>
+ {
+ Log.Information("KotlinJvmVersion = {Value}", KotlinJvmVersion);
+ });
+```
+
+
+
+
+## Related Resources
+
+You can learn more about different versioning aspects from the following resources:
+
+- [Why I don't start versions at 0.x any more](https://codeblog.jonskeet.uk/2019/10/20/why-i-dont-start-versions-at-0-x-any-more/) by Jon Skeet
+- [Versioning, and how it makes our heads hurt](https://www.youtube.com/watch?v=GLr72TnSnPw) by Jon Skeet
diff --git a/docs/03-common/07-solution-project-model.md b/docs/03-common/07-solution-project-model.md
new file mode 100644
index 000000000..5410610ed
--- /dev/null
+++ b/docs/03-common/07-solution-project-model.md
@@ -0,0 +1,107 @@
+---
+title: Solution & Project Model
+---
+
+Particularly when building .NET applications, your build may require information related to solution or project files. Such information is often duplicated with string literals and quickly becomes out-of-date. For instance, when publishing a project you want to build for every target framework that is defined in the project file. NUKE has best-in-class support to read and modify the .NET solution and project model.
+
+## Working with Solutions
+
+The easiest way to load your solution is to create a new `Solution` field, add the `SolutionAttribute`, and define the file path into the default [parameters file](../02-fundamentals/06-parameters.md#passing-values-through-parameter-files):
+
+```csharp
+[Solution]
+readonly Solution Solution;
+
+Target Print => _ => _
+ .Executes(() =>
+ {
+ Log.Information("Solution path = {Value}", Solution);
+ Log.Information("Solution directory = {Value}", Solution.Directory);
+ });
+```
+
+You can also manually load solutions with `AbsolutePath` extension method or the `ProjectModelTasks`:
+
+```csharp
+var solution1 = SolutionFile.ReadSolution();
+var solution2 = ProjectModelTasks.ParseSolution("/path/to/file");
+```
+
+### Read & Write
+
+With an instance of the `Solution` type you can **read and write the solution** in regard to projects, solution folders, items, and build configurations:
+
+```csharp
+// Gather projects
+var globalToolProject = Solution.GetProject("Nuke.GlobalTool");
+var testProjects = Solution.GetProjects("*.Tests");
+
+// Gather all solution items
+var allItems = Solution.AllSolutionFolders.SelectMany(x => x.Items);
+
+// Add a new project to solution
+var project = Solution.AddProject(
+ name: "DummyProject",
+ typeId: ProjectType.CSharpProject,
+ path: RootDirectory / "DummyProject.csproj");
+Solution.Save();
+```
+
+### Strong-Typed Project Access
+
+Using the `GenerateProjects` property you can enable a [source generator](https://devblogs.microsoft.com/dotnet/introducing-c-source-generators/) that provides **strong-typed access to the solution structure**. This greatly improves how you can reference individual projects:
+
+```csharp
+[Solution(GenerateProjects = true)]
+readonly Solution Solution;
+
+Project GlobalToolProject => Solution.Nuke_GlobalTool;
+```
+
+:::info
+For every `SolutionAttribute` with the `GenerateProjects` property enabled, the source generator will create a new type with the same name as the field. In the example above, the type `Nuke.Common.ProjectModel.Solution` is silently replaced by a new type `global::Solution` that is local to your project. Therefore, the field name and type must always be the same.
+:::
+
+### Creating Solutions
+
+Apart from reading and writing from existing solutions, you can also **create new solution files**. This can be very helpful to generate a global solution for many decoupled solutions in different repositories:
+
+```csharp
+var globalSolution = CreateSolution(
+ fileName: "global.generated.sln",
+ solutions: new[] { MainSolution }.Concat(ExternalSolutions),
+ folderNameProvider: x => x == Solution ? null : x.Name);
+
+globalSolution.Save();
+```
+
+## Working with Projects through MSBuild
+
+Apart from reading the path and directory of a project through a `Solution` object, you can also use the [Microsoft.Build](https://www.nuget.org/packages/Microsoft.Build) integration to access the MSBuild project model:
+
+```csharp
+var msbuildProject = project.GetMSBuildProject();
+```
+
+Again, you can also manually load the project using:
+
+```csharp
+var msbuildProject = ProjectModelTasks.ParseProject("/path/to/file");
+```
+
+Some of the most important information, like target frameworks, runtime identifiers, output type, properties, and item groups can also be retrieved with **predefined helper methods**:
+
+```csharp
+var targetFrameworks = project.GetTargetFrameworks();
+var runtimeIdentifiers = project.GetRuntimeIdentifiers();
+var outputType = project.GetOutputType();
+
+var isPackable = project.GetProperty("IsPackable");
+var compiledFiles = project.GetItems("Compile");
+```
+
+However, behind the scenes, these methods will still load the project through the `Microsoft.Build` package.
+
+:::caution
+It is **strongly discouraged** to use anything but MSBuild to examine project files. Other approaches, like reading and parsing the XML, are very fragile against the complex evaluation logic that is inherent for project files.
+:::
diff --git a/docs/03-common/08-cli-tools.md b/docs/03-common/08-cli-tools.md
new file mode 100644
index 000000000..e8842501e
--- /dev/null
+++ b/docs/03-common/08-cli-tools.md
@@ -0,0 +1,326 @@
+---
+title: Executing CLI Tools
+---
+
+import ToolConfirmation from '@site/src/components/ToolConfirmation';
+
+
+
+Interacting with third-party command-line interface tools (CLIs) is an essential task in build automation. This includes a wide range of aspects, such as resolution of the tool path, construction of arguments to be passed, evaluation of the exit code and capturing of standard and error output. NUKE hides these concerns in dedicated auto-generated CLI wrappers.
+
+
+Exhaustive list of supported tools
+
+| Tool | Supported Commands |
+|:----------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| [AzureSignTool](https://github.com/vcsjones/AzureSignTool) | `sign` |
+| [BenchmarkDotNet](https://benchmarkdotnet.org/) | _Single top-level command_ |
+| [Boots](https://github.com/jonathanpeppers/boots) | _Single top-level command_ |
+| [Chocolatey](https://chocolatey.org/) | `find`, `list`, `new`, `outdated`, `pack`, `push`, `search` |
+| [CloudFoundry](https://docs.cloudfoundry.org/cf-cli/cf-help.html) | `api`, `auth`, `bind-service`, `bind-service`, `create-route`, `create-service`, `create-space`, `cups`, `curl`, `delete`, `delete-service`, `delete-space`, `login`, `map-route`, `push`, `restage`, `restart`, `scale -f`, `service`, `set-env`, `set-env`, `start`, `stop`, `target`, `unmap-route` |
+| [Codecov](https://about.codecov.io/) | _Single top-level command_ |
+| [CodeMetrics](https://docs.microsoft.com/en-us/visualstudio/code-quality/code-metrics-values) | _Single top-level command_ |
+| [CorFlags](https://docs.microsoft.com/en-us/dotnet/framework/tools/corflags-exe-corflags-conversion-tool) | _Single top-level command_ |
+| [CoverallsNet](https://coverallsnet.readthedocs.io) | _Single top-level command_ |
+| [Coverlet](https://github.com/tonerdo/coverlet/) | _Single top-level command_ |
+| [DocFX](https://dotnet.github.io/docfx/) | `build`, `dependency`, `download`, `help`, `init`, `merge`, `metadata`, `pdf`, `serve`, `template` |
+| [Docker](https://www.docker.com/) | `attach`, `build`, `builder`, `builder build`, `builder prune`, `buildx build`, `checkpoint`, `checkpoint create`, `checkpoint ls`, `checkpoint rm`, `commit`, `config`, `config create`, `config inspect`, `config ls`, `config rm`, `container`, `container attach`, `container commit`, `container create`, `container diff`, `container exec`, `container export`, `container inspect`, `container kill`, `container logs`, `container ls`, `container pause`, `container port`, `container prune`, `container rename`, `container restart`, `container rm`, `container run`, `container start`, `container stats`, `container stop`, `container top [ps`, `container unpause`, `container update`, `container wait`, `context`, `context create`, `context export`, `context import`, `context inspect`, `context ls`, `context rm`, `context update`, `context use`, `create`, `deploy`, `diff`, `engine`, `engine activate`, `engine check`, `engine update`, `events`, `exec`, `export`, `history`, `image`, `image build`, `image history`, `image import`, `image inspect`, `image load`, `image ls`, `image prune`, `image pull`, `image push`, `image rm`, `image save`, `image tag`, `images`, `import`, `info`, `inspect`, `kill`, `load`, `login`, `logout`, `logs`, `manifest`, `manifest annotate`, `manifest create`, `manifest inspect`, `manifest push`, `network`, `network connect`, `network create`, `network disconnect`, `network inspect`, `network ls`, `network prune`, `network rm`, `node`, `node demote`, `node inspect`, `node ls`, `node promote`, `node ps`, `node rm`, `node update`, `pause`, `plugin`, `plugin create`, `plugin disable`, `plugin enable`, `plugin inspect`, `plugin install`, `plugin ls`, `plugin push`, `plugin rm`, `plugin set`, `plugin upgrade`, `port`, `ps`, `pull`, `push`, `rename`, `restart`, `rm`, `rmi`, `run`, `save`, `search`, `secret`, `secret create`, `secret inspect`, `secret ls`, `secret rm`, `service`, `service create`, `service inspect`, `service logs`, `service ls`, `service ps`, `service rm`, `service rollback`, `service scale`, `service update`, `stack`, `stack deploy`, `stack ls`, `stack ps`, `stack rm`, `stack services`, `start`, `stats`, `stop`, `swarm`, `swarm ca`, `swarm init`, `swarm join HOST:PORT`, `swarm join-token`, `swarm leave`, `swarm unlock`, `swarm unlock-key`, `swarm update`, `system`, `system df`, `system events`, `system info`, `system prune`, `tag`, `top [ps`, `trust`, `trust inspect`, `trust key`, `trust key generate`, `trust key load`, `trust revoke`, `trust sign IMAGE:TAG`, `trust signer`, `trust signer add`, `trust signer remove`, `unpause`, `update`, `version`, `volume`, `volume create`, `volume inspect`, `volume ls`, `volume prune`, `volume rm`, `wait` |
+| [DotCover](https://www.jetbrains.com/dotcover) | `analyse`, `cover`, `delete`, `dotnet`, `merge`, `report`, `zip` |
+| [DotNet](https://docs.microsoft.com/en-us/dotnet/core/tools/) | `build`, `clean`, `msbuild`, `nuget add source`, `nuget push`, `pack`, `publish`, `restore`, `run`, `test`, `tool install`, `tool restore`, `tool uninstall`, `tool update` |
+| [EntityFramework](https://docs.microsoft.com/en-us/ef/core/miscellaneous/cli/dotnet) | `ef database drop`, `ef database update`, `ef dbcontext info`, `ef dbcontext list`, `ef dbcontext scaffold`, `ef dbcontext script`, `ef migrations add`, `ef migrations list`, `ef migrations remove`, `ef migrations script` |
+| [Fixie](https://fixie.github.io/) | _Single top-level command_ |
+| [GitLink](https://github.com/GitTools/GitLink/) | _Single top-level command_ |
+| [GitReleaseManager](https://gitreleasemanager.readthedocs.io) | `addasset`, `close`, `create`, `export`, `publish` |
+| [GitVersion](http://gitversion.readthedocs.io/en/stable/) | _Single top-level command_ |
+| [Helm](https://helm.sh/) | `completion`, `create`, `delete`, `dependency build`, `dependency list`, `dependency update`, `fetch`, `get`, `get hooks`, `get manifest`, `get notes`, `get values`, `history`, `home`, `init`, `inspect`, `inspect chart`, `inspect readme`, `inspect values`, `install`, `lint`, `list`, `package`, `plugin install`, `plugin list`, `plugin remove`, `plugin update`, `repo add`, `repo index`, `repo list`, `repo remove`, `repo update`, `reset`, `rollback`, `search`, `serve`, `status`, `template`, `test`, `upgrade`, `verify`, `version` |
+| [ILRepack](https://github.com/gluck/il-repack#readme) | _Single top-level command_ |
+| [InnoSetup](http://www.jrsoftware.org/isinfo.php) | _Single top-level command_ |
+| [Kubernetes](https://kubernetes.io/) | `alpha`, `annotate`, `api-resources`, `api-versions`, `apply`, `apply -k`, `attach`, `auth`, `autoscale`, `certificate`, `cluster-info`, `completion`, `config`, `convert`, `cordon`, `cp`, `create`, `delete`, `describe`, `drain`, `edit`, `exec`, `explain`, `expose`, `get`, `kubectl`, `label`, `logs`, `options`, `patch`, `plugin`, `port-forward`, `proxy`, `replace`, `rolling-update`, `rollout`, `run`, `run-container`, `scale`, `set`, `taint`, `top`, `uncordon`, `version`, `wait` |
+| [MauiCheck](https://github.com/Redth/dotnet-maui-check) | `config` |
+| [MinVer](https://github.com/adamralph/minver) | _Single top-level command_ |
+| [MSBuild](https://msdn.microsoft.com/en-us/library/ms164311.aspx) | _Single top-level command_ |
+| [MSpec](https://github.com/machine/machine.specifications) | _Single top-level command_ |
+| [NerdbankGitVersioning](https://github.com/AArnott/Nerdbank.GitVersioning) | `cloud`, `get-commits`, `get-version`, `install`, `prepare-release`, `set-version`, `tag` |
+| [Netlify](https://docs.netlify.com/cli/get-started/) | `netlify deploy`, `netlify sites:create`, `netlify sites:delete` |
+| [Npm](https://www.npmjs.com/) | `ci`, `install`, `run` |
+| [NSwag](https://github.com/RSuter/NSwag) | `aspnetcore2openapi`, `aspnetcore2swagger`, `jsonschema2csclient`, `jsonschema2tsclient`, `list-controllers`, `list-types`, `new`, `openapi2csclient`, `openapi2cscontroller`, `openapi2tsclient`, `run`, `swagger2csclient`, `swagger2cscontroller`, `swagger2tsclient`, `types2openapi`, `types2swagger`, `version`, `webapi2openapi`, `webapi2swagger` |
+| [NuGet](https://docs.microsoft.com/en-us/nuget/tools/nuget-exe-cli-reference) | `install`, `pack`, `push`, `restore`, `sources add`, `sources disable`, `sources enable`, `sources list`, `sources remove`, `sources update` |
+| [NUnit](https://www.nunit.org/) | _Single top-level command_ |
+| [Octopus](https://octopus.com/) | `build-information`, `create-release`, `deploy-release`, `pack`, `push` |
+| [OctoVersion](https://github.com/OctopusDeploy/OctoVersion) | `octoversion`, `octoversion` |
+| [OpenCover](https://github.com/OpenCover/opencover) | _Single top-level command_ |
+| [Paket](https://fsprojects.github.io/paket) | `pack`, `push`, `restore`, `update` |
+| [PowerShell](https://docs.microsoft.com/en-us/powershell/) | _Single top-level command_ |
+| [Pulumi](https://www.pulumi.com/) | `config`, `config cp`, `config get`, `config refresh`, `config rm`, `config set`, `destroy`, `new`, `preview`, `stack`, `stack change-secrets-provider`, `stack export`, `stack graph`, `stack history`, `stack import`, `stack init`, `stack ls`, `stack output`, `stack rename`, `stack rm`, `stack select`, `stack tag get`, `stack tag ls`, `stack tag rm`, `stack tag set`, `up` |
+| [ReportGenerator](https://github.com/danielpalme/ReportGenerator) | _Single top-level command_ |
+| [ReSharper](https://www.jetbrains.com/help/resharper/ReSharper_Command_Line_Tools.html) | `cleanupcode`, `dupfinder`, `inspectcode` |
+| [SignClient](https://discoverdot.net/projects/sign-service) | `sign` |
+| [SignTool](https://docs.microsoft.com/en-us/dotnet/framework/tools/signtool-exe) | `sign` |
+| [SonarScanner](https://www.sonarqube.org/) | `begin`, `end` |
+| [SpecFlow](https://specflow.org/) | `buildserverrun`, `mstestexecutionreport`, `nunitexecutionreport`, `register`, `register`, `register`, `run`, `stepdefinitionreport` |
+| [Squirrel](https://github.com/Squirrel/Squirrel.Windows) | _Single top-level command_ |
+| [TestCloud](https://developer.xamarin.com/guides/testcloud/) | `submit` |
+| [Unity](https://unity3d.com/) | `-createManualActivationFile`, `-returnlicense` |
+| [VSTest](https://msdn.microsoft.com/en-us/library/jj155796.aspx) | _Single top-level command_ |
+| [VSWhere](https://github.com/Microsoft/vswhere) | _Single top-level command_ |
+| [WebConfigTransformRunner](https://github.com/erichexter/WebConfigTransformRunner) | _Single top-level command_ |
+| [Xunit](https://xunit.github.io) | _Single top-level command_ |
+
+
+
+You can execute MSBuild using the [lightweight API](#lightweight-api) as follows:
+
+```csharp
+MSBuildTasks.MSBuild($"{SolutionFile} /target:Rebuild /p:Configuration={Configuration} /nr:false");
+```
+
+The returned object is a collection of standard and error output.
+
+:::info
+Many CLI tasks require to add a package reference to the build project file. For instance, when using `NUnitTasks` there should be one of the following entries to ensure the tool is available:
+
+
+
+
+```xml title="_build.csproj"
+
+
+
+
+
+
+
+```
+
+
+
+
+```xml title="_build.csproj"
+
+
+
+
+
+
+
+```
+
+
+
+
+While it would be possible to magically download required packages, this explicit approach ensures that your builds are reproducible at any time. If a package is not referenced, the resulting error message will include a command to [install the package via the global tool](../06-global-tool/01-packages.md).
+:::
+
+## Fluent API
+
+While the example from above is quite easy to understand, it also illustrates certain weaknesses. What if `SolutionFile` contains a space and must be quoted? What is the separator to pass multiple targets? Is the configuration actually passed as a dedicated argument or as an MSBuild property? What does the `/nr` switch stand for? To solve these issues, you can use the individual fluent interfaces:
+
+```csharp
+MSBuildTasks.MSBuild(_ => _
+ .SetTargetPath(SolutionFile)
+ .SetTargets("Clean", "Build")
+ .SetConfiguration(Configuration)
+ .EnableNodeReuse());
+```
+
+You can also use the fluent interfaces to manipulate the process invocation, including tool path, arguments, working directory, timeout and environment variables.
+
+:::info
+All fluent interfaces implement a variation of the [builder pattern](https://en.wikipedia.org/wiki/Builder_pattern), in which every fluent call will create an immutable copy of the current `ToolSettings` instance with the intended changes applied. This enables great flexibility in composing similar process invocations.
+:::
+
+
+
+
+### Conditional Modifications
+
+In some cases, you may want to apply certain options only when a particular condition is met. This can be done fluently too, by using the `When` extension:
+
+```csharp
+DotNetTasks.DotNetTest(_ => _
+ .SetProjectFile(ProjectFile)
+ .SetConfiguration(Configuration)
+ .EnableNoBuild()
+ .When(PublishTestResults, _ => _
+ .SetLogger("trx")
+ .SetResultsDirectory(TestResultsDirectory)));
+```
+
+### Combinatorial Modifications
+
+A typical situation when using MSBuild for compilation, is to compile for different configurations, target frameworks or runtimes. You can use the `CombineWith` method to create different combinations for invocation:
+
+```csharp
+var publishCombinations =
+ from project in new[] { FirstProject, SecondProject }
+ from framework in project.GetTargetFrameworks()
+ from runtime in new[] { "win10-x86", "osx-x64", "linux-x64" }
+ select new { project, framework, runtime };
+
+DotNetTasks.DotNetPublish(_ => _
+ .EnableNoRestore()
+ .SetConfiguration(Configuration)
+ .CombineWith(publishCombinations, (_, v) => _
+ .SetProject(v.project)
+ .SetFramework(v.framework)
+ .SetRuntime(v.runtime)));
+```
+
+### Multiple Invocations
+
+Based on [combinatorial modifications](#combinatorial-modifications) it is possible to set a `degreeOfParallelism` (default `1`) and a flag to `continueOnFailure` (default `false`):
+
+```csharp
+DotNetTasks.DotNetNuGetPush(_ => _
+ .SetSource(Source)
+ .SetSymbolSource(SymbolSource)
+ .SetApiKey(ApiKey)
+ .CombineWith(
+ OutputDirectory.GlobFiles("*.nupkg").NotEmpty(), (_, v) => _
+ .SetTargetPath(v)),
+ degreeOfParallelism: 5,
+ continueOnFailure: true);
+```
+
+This example will always have 5 packages being pushed simultaneously. Possible exceptions, for instance when a package already exists, are accumulated to an `AggregateException` and thrown when all invocations have been processed. The console output is buffered until all invocations are completed.
+
+### Custom Arguments
+
+It may happen that certain arguments are not available from the fluent interface. In this case, the `SetProcessArgumentConfigurator` method can be used to add them manually:
+
+```csharp
+MSBuildTasks.MSBuild(_ => _
+ .SetTargetPath(SolutionFile)
+ .SetProcessArgumentConfigurator(_ => _
+ .Add("/r")));
+```
+
+
+
+### Exit Code Handling
+
+By default, every invocation is asserted to have a zero exit code. However, you can also overwrite this behavior using `SetProcessExitHandler` when required:
+
+
+
+
+
+```csharp
+NUnitTasks.NUnit3(_ => _
+ .SetInputFiles(Assemblies)
+ .SetProcessExitHandler(p => p.ExitCode switch
+ {
+ -1 => throw new Exception("Invalid args"),
+ >0 => throw new Exception($"{p.ExitCode} tests have failed"),
+ _ => null
+ }));
+```
+
+
+
+
+```csharp
+NUnitTasks.NUnit3(_ => _
+ .SetInputFiles(Assemblies)
+ .SetProcessExitHandler(p =>
+ {
+ switch (p.ExitCode)
+ {
+ case -1:
+ throw new Exception("Invalid args");
+ case >0:
+ throw new Exception($"{p.ExitCode} tests have failed");
+ }
+ }));
+```
+
+
+
+
+
+
+As a shorthand syntax, you can also disable the default assertion of a zero exit code, which essentially sets an empty delegate as the exit handler:
+
+```csharp
+NUnitTasks.NUnit3(_ => _
+ .SetInputFiles(Assemblies)
+ .DisableProcessAssertZeroExitCode());
+```
+
+
+
+
+
+
+### Verbosity Mapping
+
+Using the `VerbosityMappingAttribute`, it is possible to automatically map the verbosity passed via `--verbosity` to individual tools. The attribute must be applied on the build class level:
+
+```csharp
+[VerbosityMapping(typeof(MSBuildVerbosity),
+ Quiet = nameof(MSBuildVerbosity.Quiet),
+ Minimal = nameof(MSBuildVerbosity.Minimal),
+ Normal = nameof(MSBuildVerbosity.Normal),
+ Verbose = nameof(MSBuildVerbosity.Detailed))]
+class Build : NukeBuild
+{
+ // ...
+}
+```
+
+## Lightweight API
+
+Many of the most popular tools are already implemented. In case a certain tool is not yet supported with a proper CLI task class, NUKE allows you to use the following **injection attributes** to load them:
+
+
+```csharp
+[PathVariable]
+readonly Tool Git;
+
+[NuGetPackage(
+ packageId: "Redth.Net.Maui.Check",
+ packageExecutable: "MauiCheck.dll",
+ // Must be set for tools shipping multiple versions
+ Framework = "net6.0")]
+readonly Tool MauiCheck;
+
+// Relative to root directory or absolute path
+[LocalPath("./tools/corflags.exe")]
+readonly Tool CorFlags;
+
+// Different path on Windows and Unix
+[LocalPath(
+ windowsPath: "gradlew.bat",
+ unixPath: "gradlew")]
+readonly Tool Gradle;
+```
+
+
+The injected `Tool` delegate allows passing arguments, working directory, environment variables and many more process-specific options:
+
+
+```csharp
+// Pass arguments with string interpolation
+Git($"checkout -b {Branch}");
+
+// Change working directory and environment variables
+CorFlags(
+ arguments: $"...",
+ workingDirectory: SourceDirectory,
+ environmentVariables: EnvironmentInfo.Variables
+ .ToDictionary(x => x.Key, x => x.Value)
+ .SetKeyValue("key", "value").AsReadOnly());
+
+// Only execute when available
+// Requires:
+MauiCheck?.Invoke($"--fix --preview");
+```
+
diff --git a/docs/03-common/09-compression.md b/docs/03-common/09-compression.md
new file mode 100644
index 000000000..f102f8aaa
--- /dev/null
+++ b/docs/03-common/09-compression.md
@@ -0,0 +1,84 @@
+---
+title: Archive Compression
+---
+
+In many situations you have to deal with compressed archives. Good examples are when you want to provide additional assets for your GitHub releases, or when you depend on other project's release assets yourself, and need to extract them before they can be used.
+
+:::note
+Please refer to the [SharpZipLib documentation](https://github.com/icsharpcode/SharpZipLib) for any questions.
+:::
+
+## Compressing Archives
+
+You can create a compressed archive from a directory follows:
+
+
+
+
+```csharp title="Build.cs"
+PublishDirectory.ZipTo(
+ ArchiveFile,
+ filter: x => !x.HasExtension(ExcludedExtensions),
+ compressionLevel: CompressionLevel.SmallestSize,
+ fileMode: FileMode.CreateNew);
+```
+
+
+
+
+```csharp title="Build.cs"
+PublishDirectory.TarGZipTo(
+ ArchiveFile,
+ filter: x => !x.HasExtension(ExcludedExtensions),
+ fileMode: FileMode.CreateNew);
+```
+
+
+
+
+```csharp title="Build.cs"
+PublishDirectory.TarBZip2To(
+ ArchiveFile,
+ filter: x => !x.HasExtension(ExcludedExtensions),
+ fileMode: FileMode.CreateNew);
+```
+
+
+
+
+:::tip
+If you want to allow your consumers to verify the integrity of your archive files, you can calculate their MD5 checksums and publish them publicly:
+
+```
+var checksum = ArchiveFile.GetFileHash();
+```
+
+:::
+
+## Extracting Archives
+
+You can extract an existing archive file to a directory:
+
+
+
+
+```csharp title="Build.cs"
+ArchiveFile.UnZipTo(PublishDirectory);
+```
+
+
+
+
+```csharp title="Build.cs"
+ArchiveFile.UnTarGZip(PublishDirectory);
+```
+
+
+
+
+```csharp title="Build.cs"
+ArchiveFile.UnTarBZip2(PublishDirectory);
+```
+
+
+
diff --git a/docs/03-common/11-chats.md b/docs/03-common/11-chats.md
new file mode 100644
index 000000000..905754085
--- /dev/null
+++ b/docs/03-common/11-chats.md
@@ -0,0 +1,104 @@
+---
+title: Chats & Social Media
+---
+
+As a final step of your build automation process, you may want to report errors or announce a new version through different chats and social media channels. NUKE comes with basic support for the most common platforms.
+
+
+
+
+You can send a [Slack](https://slack.com/) messages as follows:
+
+```csharp
+// using static Nuke.Common.Tools.Slack.SlackTasks;
+
+[Parameter] [Secret] readonly string SlackWebhook;
+
+Target Send => _ => _
+ .Executes(async () =>
+ {
+ await SendSlackMessageAsync(_ => _
+ .SetText("Hello from NUKE!"),
+ SlackWebhook);
+ });
+```
+
+:::note
+For more advanced scenarios, check out the [SlackAPI](https://github.com/Inumedia/SlackAPI) or [SlackNet](https://github.com/soxtoby/SlackNet) project.
+:::
+
+
+
+
+You can send a [Microsoft Teams](https://www.microsoft.com/en/microsoft-teams/group-chat-software) messages as follows:
+
+```csharp
+// using static Nuke.Common.Tools.Teams.TeamsTasks;
+
+[Parameter] [Secret] readonly string TeamsWebhook;
+
+Target Send => _ => _
+ .Executes(async () =>
+ {
+ await SendTeamsMessageAsync(_ => _
+ .SetText("Hello from NUKE!"),
+ TeamsWebhook)
+ });
+```
+
+
+
+
+You can send a [Twitter](https://twitter.com/) messages as follows:
+
+```csharp
+// using static Nuke.Common.Tools.Twitter.TwitterTasks;
+
+[Parameter] [Secret] readonly string TwitterConsumerKey;
+[Parameter] [Secret] readonly string TwitterConsumerSecret;
+[Parameter] [Secret] readonly string TwitterAccessToken;
+[Parameter] [Secret] readonly string TwitterAccessTokenSecret;
+
+Target Send => _ => _
+ .Executes(async () =>
+ {
+ await SendTweetAsync(
+ message: "Hello from NUKE",
+ TwitterConsumerKey,
+ TwitterConsumerSecret,
+ TwitterAccessToken,
+ TwitterAccessTokenSecret);
+ });
+```
+
+:::note
+For more advanced scenarios, check out the [Tweetinvi](https://github.com/linvi/tweetinvi) project.
+:::
+
+
+
+
+You can send a [Gitter](https://gitter.im/) messages as follows:
+
+```csharp
+// using static Nuke.Common.Tools.Gitter.GitterTasks;
+
+[Parameter] readonly string GitterRoomId;
+[Parameter] [Secret] readonly string GitterAuthToken;
+
+Target Send => _ => _
+ .Executes(() =>
+ {
+ SendGitterMessage(
+ message: "Hello from NUKE",
+ GitterRoomId,
+ GitterAuthToken);
+ });
+```
+
+:::note
+For more advanced scenarios, check out the [gitter-api-pcl](https://github.com/uwp-squad/gitter-api-pcl) project.
+:::
+
+
+
diff --git a/docs/03-common/_category_.json b/docs/03-common/_category_.json
new file mode 100644
index 000000000..182e612cb
--- /dev/null
+++ b/docs/03-common/_category_.json
@@ -0,0 +1,3 @@
+{
+ "label": "Common Tasks"
+}
diff --git a/docs/04-sharing/01-global-builds.md b/docs/04-sharing/01-global-builds.md
new file mode 100644
index 000000000..332cdc5ca
--- /dev/null
+++ b/docs/04-sharing/01-global-builds.md
@@ -0,0 +1,89 @@
+---
+title: Global Builds
+---
+
+Instead of adding and maintaining build projects in all your repositories, you can also build them by convention using a global build. Global builds are based on the concept of [.NET global tools](https://docs.microsoft.com/en-us/dotnet/core/tools/global-tools) and additionally include all the necessary tools referenced through NuGet packages. That means that for building one of your repositories, you only need to install and execute your pre-packaged build.
+
+## Packaging
+
+As a first step, you need to extend the build project file with the [necessary information for global tool packaging](https://docs.microsoft.com/en-us/dotnet/core/tools/global-tools-how-to-create#setup-the-global-tool). Particularly, that includes the `PackAsTool` and `ToolCommandName` property:
+
+```xml title="MyBuild.csproj"
+
+
+
+ Exe
+ net6.0
+ // highlight-start
+ true
+ my-build
+ // highlight-end
+
+
+
+```
+
+Afterwards, the project can be packaged and deployed as usual:
+
+```powershell
+# terminal-command
+dotnet pack --version
+# terminal-command
+dotnet nuget push MyBuild..nupkg --source