├── .config
└── dotnet-tools.json
├── .github
└── workflows
│ ├── continuous.yml
│ └── deploy.yml
├── .gitignore
├── .nuke
├── build.schema.json
└── parameters.json
├── Readme.md
├── Try.Dotnet.Affected.Dependency
├── Dependency.cs
└── Try.Dotnet.Affected.Dependency.csproj
├── Try.Dotnet.Affected.ProxyStoryApi
├── Program.cs
├── Properties
│ └── launchSettings.json
├── Try.Dotnet.Affected.ProxyStoryApi.csproj
├── Try.Dotnet.Affected.ProxyStoryApi.csproj.user
├── appsettings.Development.json
└── appsettings.json
├── Try.Dotnet.Affected.Sidestory
├── Program.cs
└── Try.Dotnet.Affected.Sidestory.csproj
├── Try.Dotnet.Affected.StoryApi
├── Program.cs
├── Properties
│ └── launchSettings.json
├── Try.Dotnet.Affected.StoryApi.csproj
├── Try.Dotnet.Affected.StoryApi.csproj.user
├── appsettings.Development.json
└── appsettings.json
├── Try.Dotnet.Affected.Tests
├── GlobalUsings.cs
├── Try.Dotnet.Affected.Tests.csproj
└── UnitTest1.cs
├── Try.Dotnet.Affected.sln
├── Try.Dotnet.Affected
├── Program.cs
└── Try.Dotnet.Affected.csproj
├── build.cmd
├── build.ps1
├── build.sh
├── build
├── .editorconfig
├── Build.cs
├── Components
│ ├── Azure.Targets.cs
│ ├── Dotnet.Affected.Targets.cs
│ ├── Pulumi.Targets.cs
│ ├── Try.Dotnet.Affected.Build.cs
│ ├── Try.Dotnet.Affected.Dependency.Build.cs
│ ├── Try.Dotnet.Affected.DeployBase.cs
│ ├── Try.Dotnet.Affected.ProxyStoryApi.Build.cs
│ ├── Try.Dotnet.Affected.Sidestory.Build.cs
│ ├── Try.Dotnet.Affected.StoryApi.Build.cs
│ └── Try.Dotnet.Affected.Tests.Build.cs
├── Configuration.cs
├── Directory.Build.props
├── Directory.Build.targets
├── Properties
│ └── launchSettings.json
├── _build.csproj
└── _build.csproj.DotSettings
└── screenshots
└── BuildTargets.png
/.config/dotnet-tools.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 1,
3 | "isRoot": true,
4 | "tools": {
5 | "dotnet-affected": {
6 | "version": "3.2.0",
7 | "commands": [
8 | "dotnet-affected"
9 | ]
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/.github/workflows/continuous.yml:
--------------------------------------------------------------------------------
1 | # ------------------------------------------------------------------------------
2 | #
3 | #
4 | # This code was generated.
5 | #
6 | # - To turn off auto-generation set:
7 | #
8 | # [GitHubActions (AutoGenerate = false)]
9 | #
10 | # - To trigger manual generation invoke:
11 | #
12 | # nuke --generate-configuration GitHubActions_continuous --host GitHubActions
13 | #
14 | #
15 | # ------------------------------------------------------------------------------
16 |
17 | name: continuous
18 |
19 | on: [push]
20 |
21 | jobs:
22 | windows-latest:
23 | name: windows-latest
24 | runs-on: windows-latest
25 | steps:
26 | - uses: actions/checkout@v3
27 | with:
28 | fetch-depth: 0
29 | - name: 'Cache: .nuke/temp, ~/.nuget/packages'
30 | uses: actions/cache@v3
31 | with:
32 | path: |
33 | .nuke/temp
34 | ~/.nuget/packages
35 | key: ${{ runner.os }}-${{ hashFiles('**/global.json', '**/*.csproj', '**/Directory.Packages.props') }}
36 | - name: 'Run: CompileSolution'
37 | run: ./build.cmd CompileSolution
38 |
--------------------------------------------------------------------------------
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | name: deploy
2 |
3 | on: [push]
4 |
5 | jobs:
6 | windows-latest:
7 | name: windows-latest
8 | runs-on: windows-latest
9 | environment: 'Dev'
10 | steps:
11 | - uses: actions/checkout@v3
12 | with:
13 | fetch-depth: 0
14 | - name: 'Cache: .nuke/temp, ~/.nuget/packages'
15 | uses: actions/cache@v3
16 | with:
17 | path: |
18 | .nuke/temp
19 | ~/.nuget/packages
20 | key: ${{ runner.os }}-${{ hashFiles('**/global.json', '**/*.csproj', '**/Directory.Packages.props') }}
21 | - name: 'Run: DeploySolution'
22 | run: ./build.cmd DeploySolution
23 | env:
24 | ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }}
25 | ARM_CLIENT_SECRET: ${{ secrets.ARM_CLIENT_SECRET }}
26 | ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }}
27 | ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }}
28 | PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .vs
2 | bin/
3 | obj/
4 | affected.proj
5 | output/
6 | Try.Dotnet.Affected.Tests/TestResults
7 | Try.Dotnet.Affected.sln.DotSettings.user
8 | affected.txt
9 | .nuke/temp
10 | artifacts/
--------------------------------------------------------------------------------
/.nuke/build.schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json-schema.org/draft-04/schema#",
3 | "$ref": "#/definitions/build",
4 | "title": "Build Schema",
5 | "definitions": {
6 | "build": {
7 | "type": "object",
8 | "properties": {
9 | "ARM_CLIENT_ID": {
10 | "type": "string",
11 | "default": "Secrets must be entered via 'nuke :secrets [profile]'"
12 | },
13 | "ARM_CLIENT_SECRET": {
14 | "type": "string",
15 | "default": "Secrets must be entered via 'nuke :secrets [profile]'"
16 | },
17 | "ARM_TENANT_ID": {
18 | "type": "string",
19 | "default": "Secrets must be entered via 'nuke :secrets [profile]'"
20 | },
21 | "Configuration": {
22 | "type": "string",
23 | "description": "Configuration to build - Default is 'Debug' (local) or 'Release' (server)",
24 | "enum": [
25 | "Debug",
26 | "Release"
27 | ]
28 | },
29 | "Continue": {
30 | "type": "boolean",
31 | "description": "Indicates to continue a previously failed build attempt"
32 | },
33 | "Help": {
34 | "type": "boolean",
35 | "description": "Shows the help text for this build assembly"
36 | },
37 | "Host": {
38 | "type": "string",
39 | "description": "Host for execution. Default is 'automatic'",
40 | "enum": [
41 | "AppVeyor",
42 | "AzurePipelines",
43 | "Bamboo",
44 | "Bitbucket",
45 | "Bitrise",
46 | "GitHubActions",
47 | "GitLab",
48 | "Jenkins",
49 | "Rider",
50 | "SpaceAutomation",
51 | "TeamCity",
52 | "Terminal",
53 | "TravisCI",
54 | "VisualStudio",
55 | "VSCode"
56 | ]
57 | },
58 | "NoLogo": {
59 | "type": "boolean",
60 | "description": "Disables displaying the NUKE logo"
61 | },
62 | "Partition": {
63 | "type": "string",
64 | "description": "Partition to use on CI"
65 | },
66 | "Plan": {
67 | "type": "boolean",
68 | "description": "Shows the execution plan (HTML)"
69 | },
70 | "Profile": {
71 | "type": "array",
72 | "description": "Defines the profiles to load",
73 | "items": {
74 | "type": "string"
75 | }
76 | },
77 | "Root": {
78 | "type": "string",
79 | "description": "Root directory during build execution"
80 | },
81 | "Skip": {
82 | "type": "array",
83 | "description": "List of targets to be skipped. Empty list skips all dependencies",
84 | "items": {
85 | "type": "string",
86 | "enum": [
87 | "AzLogin",
88 | "Clean",
89 | "CleanTryDotnetAffectedProxyStoryApi",
90 | "CleanTryDotnetAffectedStoryApi",
91 | "CompileSolution",
92 | "CompileTryDotnetAffected",
93 | "CompileTryDotnetAffectedDependency",
94 | "CompileTryDotnetAffectedProxyStoryApi",
95 | "CompileTryDotnetAffectedSidestory",
96 | "CompileTryDotnetAffectedStoryApi",
97 | "CompileTryDotnetAffectedTests",
98 | "DeploySolution",
99 | "DeployStackTryDotnetAffectedDeployBase",
100 | "DeployStackTryDotnetAffectedProxyStoryApi",
101 | "DeployStackTryDotnetAffectedStoryApi",
102 | "DotnetAffected",
103 | "InstallAzureCli",
104 | "InstallPulumi",
105 | "ProvisionPulumi",
106 | "PublishSolution",
107 | "PublishStackTryDotnetAffectedProxyStoryApi",
108 | "PublishStackTryDotnetAffectedStoryApi",
109 | "PublishTryDotnetAffected",
110 | "PublishTryDotnetAffectedProxyStoryApi",
111 | "PublishTryDotnetAffectedSidestory",
112 | "PublishTryDotnetAffectedStoryApi",
113 | "Restore",
114 | "RunTestsSolution",
115 | "RunTestsTryDotnetAffectedTests"
116 | ]
117 | }
118 | },
119 | "Target": {
120 | "type": "array",
121 | "description": "List of targets to be invoked. Default is '{default_target}'",
122 | "items": {
123 | "type": "string",
124 | "enum": [
125 | "AzLogin",
126 | "Clean",
127 | "CleanTryDotnetAffectedProxyStoryApi",
128 | "CleanTryDotnetAffectedStoryApi",
129 | "CompileSolution",
130 | "CompileTryDotnetAffected",
131 | "CompileTryDotnetAffectedDependency",
132 | "CompileTryDotnetAffectedProxyStoryApi",
133 | "CompileTryDotnetAffectedSidestory",
134 | "CompileTryDotnetAffectedStoryApi",
135 | "CompileTryDotnetAffectedTests",
136 | "DeploySolution",
137 | "DeployStackTryDotnetAffectedDeployBase",
138 | "DeployStackTryDotnetAffectedProxyStoryApi",
139 | "DeployStackTryDotnetAffectedStoryApi",
140 | "DotnetAffected",
141 | "InstallAzureCli",
142 | "InstallPulumi",
143 | "ProvisionPulumi",
144 | "PublishSolution",
145 | "PublishStackTryDotnetAffectedProxyStoryApi",
146 | "PublishStackTryDotnetAffectedStoryApi",
147 | "PublishTryDotnetAffected",
148 | "PublishTryDotnetAffectedProxyStoryApi",
149 | "PublishTryDotnetAffectedSidestory",
150 | "PublishTryDotnetAffectedStoryApi",
151 | "Restore",
152 | "RunTestsSolution",
153 | "RunTestsTryDotnetAffectedTests"
154 | ]
155 | }
156 | },
157 | "Verbosity": {
158 | "type": "string",
159 | "description": "Logging verbosity during build execution. Default is 'Normal'",
160 | "enum": [
161 | "Minimal",
162 | "Normal",
163 | "Quiet",
164 | "Verbose"
165 | ]
166 | }
167 | }
168 | }
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/.nuke/parameters.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./build.schema.json",
3 | "Solution": "Try.Dotnet.Affected.sln"
4 | }
5 |
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | # Dotnet Affected 🔍 & Nuke ☢️
2 |
3 |
4 | This project shows an example on how to integrate [Dotnet Affected](https://github.com/leonardochaia/dotnet-affected) with [Nuke Build](https://nuke.build/).
5 |
6 |
7 |
8 | 🪟Project Screenshots:
9 | --
10 |
11 |
12 | 💡Features
13 | --
14 |
15 | * Use dotnet-affected to trigger specific build tasks
16 | * Seperate build files for different projects
17 | * Pulumi deployment to Azure using Pulumi Automation
18 |
19 | 🛠️ Installation Steps:
20 | --
21 | 1. Clone repository
22 | ```bash
23 | git clone https://github.com/jwdb/Try.Dotnet.Affected/
24 | ```
25 | 2. Install Nuke
26 | ```bash
27 | dotnet tool install Nuke.GlobalTool --global
28 | ```
29 | 3. Nuke ☢️ it from orbit 🚀
30 |
31 | ```bash
32 | nuke
33 | ```
34 |
35 | Project Structure
36 | --
37 | The project consists of multiple example projects and a build project.
38 | Example projects:
39 |
40 | * `/Try.Dotnet.Affected/` This is a plain console app with a dependency to `/Try.Dotnet.Affected.Dependency/`
41 | * `/Try.Dotnet.Affected.Sidestory/` Another plain console app with no dependencies.
42 | * `/Try.Dotnet.Affected.Tests/` This has a reference to `/Try.Dotnet.Affected/` and serves as a test-project for it.
43 | * `/Try.Dotnet.Affected.StoryApi/` A simple WebApi with no external dependencies
44 | * `/Try.Dotnet.Affected.ProxyStoryApi/` This project has a implicit dependenc on the StoryApi through a app setting.
45 |
46 | All these projects have their own Companion `*.build.cs` under `/build/Components/`. These files describe how the project should be *Compiled*, *Tested*, *Published* and *Deployed*.
47 |
48 | The description on how this is done is contained into individual targets.
49 |
50 | ---
51 | ### Compile
52 | Every `*.Build.cs` file has a **Compile** target that defines on how the project is built. This target has a dependency on The **DotnetAffected** Target.
53 |
54 | This target is *TriggeredBy the **CompileSolution** Target* but only ran if *the project is included in the **ProjectsToBuild** array* .
55 |
56 | ---
57 | ### Test
58 | When a project has Tests, a **Test** target can be added. Yet again this has a dependency on the **DotnetAffected** Target but also on the **Compile** Target.
59 |
60 | This target is *TriggeredBy the **RunTestsSolution** Target* but only ran if *the project is included in the **ProjectsToBuild** array*.
61 |
62 | ---
63 | ### Publish
64 | If a project can be Published. a **Publish** target can be added. In the same way as the previous targt, this has a dependency on **DotnetAffected** and the **Compile** Target.
65 |
66 | This target is *TriggeredBy the **RunTestsSolution** Target* but only ran if *the project is included in the **ProjectsToBuild** array*.
67 |
68 | ---
69 |
70 | ### Deploy
71 | The most complicated step. The step is divided into two parts: **DeployStack** and **PublishStack**.
72 |
73 | #### **DeployStack**
74 | This target is to setup the infrastructure using *Pulumi*.
75 | This function makes it possible to add extra items to the Pulumi stack:
76 | ```csharp
77 | IPulumiTargets.Stack.With(() => { })
78 | ```
79 | This function either has a `Action` as parameter or a `Func<{[name] = Output}>` where each property of the anonymous type of the type `Output` can be used in other Deploy targets using: `IPulumiTargets.Stack.GetOutput("ResourceGroupName")`.
80 |
81 | This Target has a *DependentFor* constraint on **IPulumiTargets.ProvisionPulumi**. Using this constraint this Target will be ran before Provisioning has happened.
82 |
83 | Using a combination of *After* and *Before* this Target can be placed on a certain place in the pulumi stack.
84 |
85 | ---
86 | ⚠️ Warning: This target has no dependency on **DotnetAffected** because otherwise the resource would be removed by Pulumi when it has not changed.
87 |
88 | ---
89 | #### **PublishStack**
90 | With this target the *published* project is *deployed* to the provisioned *stack*.
91 | This target yet again dependent on **DotnetAffected** but also on **IPulumiTargets.ProvisionPulumi**.
92 |
93 | This target is *TriggeredBy the **PublishSoltuin** Target* but only ran if *the project is included in the **ProjectsToBuild** array*.
--------------------------------------------------------------------------------
/Try.Dotnet.Affected.Dependency/Dependency.cs:
--------------------------------------------------------------------------------
1 | namespace Try.Dotnet.Affected.Dependency
2 | {
3 | public class Dependency
4 | {
5 | public Dependency()
6 | {
7 | Console.WriteLine("It depends.");
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/Try.Dotnet.Affected.Dependency/Try.Dotnet.Affected.Dependency.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Try.Dotnet.Affected.ProxyStoryApi/Program.cs:
--------------------------------------------------------------------------------
1 | var builder = WebApplication.CreateBuilder(args);
2 |
3 | // Add services to the container.
4 |
5 | var app = builder.Build();
6 |
7 | // Configure the HTTP request pipeline.
8 |
9 | app.UseHttpsRedirection();
10 |
11 | var apiUrl = app.Configuration.GetValue("StoryApiUrl");
12 | Console.WriteLine(apiUrl);
13 |
14 | var client = new HttpClient()
15 | {
16 | BaseAddress = new Uri(apiUrl),
17 | };
18 |
19 | app.MapGet("/story", async () => $"Proxy: {await client.GetStringAsync("/story")}");
20 |
21 | app.Run();
22 |
--------------------------------------------------------------------------------
/Try.Dotnet.Affected.ProxyStoryApi/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "http": {
4 | "commandName": "Project",
5 | "launchBrowser": true,
6 | "launchUrl": "story",
7 | "environmentVariables": {
8 | "ASPNETCORE_ENVIRONMENT": "Development"
9 | },
10 | "dotnetRunMessages": true,
11 | "applicationUrl": "http://localhost:5282"
12 | },
13 | "https": {
14 | "commandName": "Project",
15 | "launchBrowser": true,
16 | "launchUrl": "story",
17 | "environmentVariables": {
18 | "ASPNETCORE_ENVIRONMENT": "Development",
19 | "ASPNETCORE_URLS": "http://localhost:5001/"
20 | },
21 | "dotnetRunMessages": true,
22 | "applicationUrl": "https://localhost:7033;http://localhost:5282"
23 | },
24 | "IIS Express": {
25 | "commandName": "IISExpress",
26 | "launchBrowser": true,
27 | "launchUrl": "story",
28 | "environmentVariables": {
29 | "ASPNETCORE_ENVIRONMENT": "Development"
30 | }
31 | }
32 | },
33 | "$schema": "https://json.schemastore.org/launchsettings.json",
34 | "iisSettings": {
35 | "windowsAuthentication": false,
36 | "anonymousAuthentication": true,
37 | "iisExpress": {
38 | "applicationUrl": "http://localhost:37690",
39 | "sslPort": 44346
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/Try.Dotnet.Affected.ProxyStoryApi/Try.Dotnet.Affected.ProxyStoryApi.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Try.Dotnet.Affected.ProxyStoryApi/Try.Dotnet.Affected.ProxyStoryApi.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | https
5 |
6 |
--------------------------------------------------------------------------------
/Try.Dotnet.Affected.ProxyStoryApi/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Try.Dotnet.Affected.ProxyStoryApi/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "AllowedHosts": "*",
9 | "StoryApiUrl": "https://localhost:7187/"
10 | }
11 |
--------------------------------------------------------------------------------
/Try.Dotnet.Affected.Sidestory/Program.cs:
--------------------------------------------------------------------------------
1 | Console.WriteLine("Once upon a time");
2 | Console.WriteLine("We were free");
3 | Console.WriteLine("But everything changed");
4 | Console.WriteLine("When the fire nation attacked");
--------------------------------------------------------------------------------
/Try.Dotnet.Affected.Sidestory/Try.Dotnet.Affected.Sidestory.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net7.0
6 | enable
7 | enable
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Try.Dotnet.Affected.StoryApi/Program.cs:
--------------------------------------------------------------------------------
1 | var builder = WebApplication.CreateBuilder(args);
2 |
3 | // Add services to the container.
4 |
5 | var app = builder.Build();
6 |
7 | // Configure the HTTP request pipeline.
8 |
9 | app.UseHttpsRedirection();
10 |
11 | var summaries = new[]
12 | {
13 | "a cat", "a dog", "a wild ferret", "the moon", "martians", "kudos", "electrons", "an android", "a gray sky", "rain"
14 | };
15 |
16 | app.MapGet("/story", () => $"Once upon a time there was a story about {summaries[Random.Shared.Next(0, summaries.Length)]}");
17 |
18 | app.Run();
19 |
--------------------------------------------------------------------------------
/Try.Dotnet.Affected.StoryApi/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:8116",
8 | "sslPort": 44352
9 | }
10 | },
11 | "profiles": {
12 | "http": {
13 | "commandName": "Project",
14 | "dotnetRunMessages": true,
15 | "launchBrowser": true,
16 | "launchUrl": "story",
17 | "applicationUrl": "http://localhost:5137",
18 | "environmentVariables": {
19 | "ASPNETCORE_ENVIRONMENT": "Development"
20 | }
21 | },
22 | "https": {
23 | "commandName": "Project",
24 | "dotnetRunMessages": true,
25 | "launchBrowser": true,
26 | "launchUrl": "story",
27 | "applicationUrl": "https://localhost:7187;http://localhost:5137",
28 | "environmentVariables": {
29 | "ASPNETCORE_ENVIRONMENT": "Development"
30 | }
31 | },
32 | "IIS Express": {
33 | "commandName": "IISExpress",
34 | "launchBrowser": true,
35 | "launchUrl": "story",
36 | "environmentVariables": {
37 | "ASPNETCORE_ENVIRONMENT": "Development"
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Try.Dotnet.Affected.StoryApi/Try.Dotnet.Affected.StoryApi.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Try.Dotnet.Affected.StoryApi/Try.Dotnet.Affected.StoryApi.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | https
5 |
6 |
--------------------------------------------------------------------------------
/Try.Dotnet.Affected.StoryApi/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Try.Dotnet.Affected.StoryApi/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "AllowedHosts": "*"
9 | }
10 |
--------------------------------------------------------------------------------
/Try.Dotnet.Affected.Tests/GlobalUsings.cs:
--------------------------------------------------------------------------------
1 | global using Xunit;
--------------------------------------------------------------------------------
/Try.Dotnet.Affected.Tests/Try.Dotnet.Affected.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 | enable
6 | enable
7 |
8 | false
9 | true
10 |
11 |
12 |
13 |
14 |
15 |
16 | runtime; build; native; contentfiles; analyzers; buildtransitive
17 | all
18 |
19 |
20 | runtime; build; native; contentfiles; analyzers; buildtransitive
21 | all
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/Try.Dotnet.Affected.Tests/UnitTest1.cs:
--------------------------------------------------------------------------------
1 | namespace Try.Dotnet.Affected.Tests;
2 |
3 | public class UnitTest1
4 | {
5 | [Fact]
6 | public void Test1()
7 | {
8 | _ = new Dependency.Dependency();
9 |
10 | }
11 | }
--------------------------------------------------------------------------------
/Try.Dotnet.Affected.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.7.34003.232
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Try.Dotnet.Affected", "Try.Dotnet.Affected\Try.Dotnet.Affected.csproj", "{4540F94A-F4EF-43D6-9741-C1CBCE2DABAD}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Try.Dotnet.Affected.Dependency", "Try.Dotnet.Affected.Dependency\Try.Dotnet.Affected.Dependency.csproj", "{88E3DAA9-E14A-4142-A389-CBB3F8F08D28}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Try.Dotnet.Affected.Sidestory", "Try.Dotnet.Affected.Sidestory\Try.Dotnet.Affected.Sidestory.csproj", "{1B944318-BB51-4142-BA16-23B34D2CC8FD}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_build", "build\_build.csproj", "{A17BF7C7-E450-4FE7-B68C-76A9169422AF}"
13 | EndProject
14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Try.Dotnet.Affected.Tests", "Try.Dotnet.Affected.Tests\Try.Dotnet.Affected.Tests.csproj", "{80314E3D-C575-4895-9E0F-F0DD7F64BEC7}"
15 | EndProject
16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Try.Dotnet.Affected.StoryApi", "Try.Dotnet.Affected.StoryApi\Try.Dotnet.Affected.StoryApi.csproj", "{BE3DBDBD-38EE-47CA-AB12-EFE6D9CD04B9}"
17 | EndProject
18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Try.Dotnet.Affected.ProxyStoryApi", "Try.Dotnet.Affected.ProxyStoryApi\Try.Dotnet.Affected.ProxyStoryApi.csproj", "{3581007E-84AD-4745-BE95-BEBD7A619B5A}"
19 | EndProject
20 | Global
21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
22 | Debug|Any CPU = Debug|Any CPU
23 | Release|Any CPU = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
26 | {4540F94A-F4EF-43D6-9741-C1CBCE2DABAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {4540F94A-F4EF-43D6-9741-C1CBCE2DABAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {4540F94A-F4EF-43D6-9741-C1CBCE2DABAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {4540F94A-F4EF-43D6-9741-C1CBCE2DABAD}.Release|Any CPU.Build.0 = Release|Any CPU
30 | {88E3DAA9-E14A-4142-A389-CBB3F8F08D28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {88E3DAA9-E14A-4142-A389-CBB3F8F08D28}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {88E3DAA9-E14A-4142-A389-CBB3F8F08D28}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {88E3DAA9-E14A-4142-A389-CBB3F8F08D28}.Release|Any CPU.Build.0 = Release|Any CPU
34 | {1B944318-BB51-4142-BA16-23B34D2CC8FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {1B944318-BB51-4142-BA16-23B34D2CC8FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {1B944318-BB51-4142-BA16-23B34D2CC8FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
37 | {1B944318-BB51-4142-BA16-23B34D2CC8FD}.Release|Any CPU.Build.0 = Release|Any CPU
38 | {A17BF7C7-E450-4FE7-B68C-76A9169422AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 | {A17BF7C7-E450-4FE7-B68C-76A9169422AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
40 | {80314E3D-C575-4895-9E0F-F0DD7F64BEC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
41 | {80314E3D-C575-4895-9E0F-F0DD7F64BEC7}.Debug|Any CPU.Build.0 = Debug|Any CPU
42 | {80314E3D-C575-4895-9E0F-F0DD7F64BEC7}.Release|Any CPU.ActiveCfg = Release|Any CPU
43 | {80314E3D-C575-4895-9E0F-F0DD7F64BEC7}.Release|Any CPU.Build.0 = Release|Any CPU
44 | {BE3DBDBD-38EE-47CA-AB12-EFE6D9CD04B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
45 | {BE3DBDBD-38EE-47CA-AB12-EFE6D9CD04B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
46 | {BE3DBDBD-38EE-47CA-AB12-EFE6D9CD04B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
47 | {BE3DBDBD-38EE-47CA-AB12-EFE6D9CD04B9}.Release|Any CPU.Build.0 = Release|Any CPU
48 | {3581007E-84AD-4745-BE95-BEBD7A619B5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
49 | {3581007E-84AD-4745-BE95-BEBD7A619B5A}.Debug|Any CPU.Build.0 = Debug|Any CPU
50 | {3581007E-84AD-4745-BE95-BEBD7A619B5A}.Release|Any CPU.ActiveCfg = Release|Any CPU
51 | {3581007E-84AD-4745-BE95-BEBD7A619B5A}.Release|Any CPU.Build.0 = Release|Any CPU
52 | EndGlobalSection
53 | GlobalSection(SolutionProperties) = preSolution
54 | HideSolutionNode = FALSE
55 | EndGlobalSection
56 | GlobalSection(ExtensibilityGlobals) = postSolution
57 | SolutionGuid = {B84A7895-873E-4B6F-AA52-3C74762C822A}
58 | EndGlobalSection
59 | EndGlobal
60 |
--------------------------------------------------------------------------------
/Try.Dotnet.Affected/Program.cs:
--------------------------------------------------------------------------------
1 | using Try.Dotnet.Affected.Dependency;
2 |
3 | Console.WriteLine("What's the story Kenneth?");
4 | _ = new Dependency();
5 |
--------------------------------------------------------------------------------
/Try.Dotnet.Affected/Try.Dotnet.Affected.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net7.0
6 | enable
7 | enable
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/build.cmd:
--------------------------------------------------------------------------------
1 | :; set -eo pipefail
2 | :; SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
3 | :; ${SCRIPT_DIR}/build.sh "$@"
4 | :; exit $?
5 |
6 | @ECHO OFF
7 | powershell -ExecutionPolicy ByPass -NoProfile -File "%~dp0build.ps1" %*
8 |
--------------------------------------------------------------------------------
/build.ps1:
--------------------------------------------------------------------------------
1 | [CmdletBinding()]
2 | Param(
3 | [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
4 | [string[]]$BuildArguments
5 | )
6 |
7 | Write-Output "PowerShell $($PSVersionTable.PSEdition) version $($PSVersionTable.PSVersion)"
8 |
9 | Set-StrictMode -Version 2.0; $ErrorActionPreference = "Stop"; $ConfirmPreference = "None"; trap { Write-Error $_ -ErrorAction Continue; exit 1 }
10 | $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
11 |
12 | ###########################################################################
13 | # CONFIGURATION
14 | ###########################################################################
15 |
16 | $BuildProjectFile = "$PSScriptRoot\build\_build.csproj"
17 | $TempDirectory = "$PSScriptRoot\\.nuke\temp"
18 |
19 | $DotNetGlobalFile = "$PSScriptRoot\\global.json"
20 | $DotNetInstallUrl = "https://dot.net/v1/dotnet-install.ps1"
21 | $DotNetChannel = "STS"
22 |
23 | $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = 1
24 | $env:DOTNET_CLI_TELEMETRY_OPTOUT = 1
25 | $env:DOTNET_MULTILEVEL_LOOKUP = 0
26 |
27 | ###########################################################################
28 | # EXECUTION
29 | ###########################################################################
30 |
31 | function ExecSafe([scriptblock] $cmd) {
32 | & $cmd
33 | if ($LASTEXITCODE) { exit $LASTEXITCODE }
34 | }
35 |
36 | # If dotnet CLI is installed globally and it matches requested version, use for execution
37 | if ($null -ne (Get-Command "dotnet" -ErrorAction SilentlyContinue) -and `
38 | $(dotnet --version) -and $LASTEXITCODE -eq 0) {
39 | $env:DOTNET_EXE = (Get-Command "dotnet").Path
40 | }
41 | else {
42 | # Download install script
43 | $DotNetInstallFile = "$TempDirectory\dotnet-install.ps1"
44 | New-Item -ItemType Directory -Path $TempDirectory -Force | Out-Null
45 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
46 | (New-Object System.Net.WebClient).DownloadFile($DotNetInstallUrl, $DotNetInstallFile)
47 |
48 | # If global.json exists, load expected version
49 | if (Test-Path $DotNetGlobalFile) {
50 | $DotNetGlobal = $(Get-Content $DotNetGlobalFile | Out-String | ConvertFrom-Json)
51 | if ($DotNetGlobal.PSObject.Properties["sdk"] -and $DotNetGlobal.sdk.PSObject.Properties["version"]) {
52 | $DotNetVersion = $DotNetGlobal.sdk.version
53 | }
54 | }
55 |
56 | # Install by channel or version
57 | $DotNetDirectory = "$TempDirectory\dotnet-win"
58 | if (!(Test-Path variable:DotNetVersion)) {
59 | ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath }
60 | } else {
61 | ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath }
62 | }
63 | $env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe"
64 | }
65 |
66 | Write-Output "Microsoft (R) .NET SDK version $(& $env:DOTNET_EXE --version)"
67 |
68 | if (Test-Path env:NUKE_ENTERPRISE_TOKEN) {
69 | & $env:DOTNET_EXE nuget remove source "nuke-enterprise" > $null
70 | & $env:DOTNET_EXE nuget add source "https://f.feedz.io/nuke/enterprise/nuget" --name "nuke-enterprise" --username "PAT" --password $env:NUKE_ENTERPRISE_TOKEN > $null
71 | }
72 |
73 | ExecSafe { & $env:DOTNET_EXE build $BuildProjectFile /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet }
74 | ExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile --no-build -- $BuildArguments }
75 |
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | bash --version 2>&1 | head -n 1
4 |
5 | set -eo pipefail
6 | SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
7 |
8 | ###########################################################################
9 | # CONFIGURATION
10 | ###########################################################################
11 |
12 | BUILD_PROJECT_FILE="$SCRIPT_DIR/build/_build.csproj"
13 | TEMP_DIRECTORY="$SCRIPT_DIR//.nuke/temp"
14 |
15 | DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json"
16 | DOTNET_INSTALL_URL="https://dot.net/v1/dotnet-install.sh"
17 | DOTNET_CHANNEL="STS"
18 |
19 | export DOTNET_CLI_TELEMETRY_OPTOUT=1
20 | export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
21 | export DOTNET_MULTILEVEL_LOOKUP=0
22 |
23 | ###########################################################################
24 | # EXECUTION
25 | ###########################################################################
26 |
27 | function FirstJsonValue {
28 | perl -nle 'print $1 if m{"'"$1"'": "([^"]+)",?}' <<< "${@:2}"
29 | }
30 |
31 | # If dotnet CLI is installed globally and it matches requested version, use for execution
32 | if [ -x "$(command -v dotnet)" ] && dotnet --version &>/dev/null; then
33 | export DOTNET_EXE="$(command -v dotnet)"
34 | else
35 | # Download install script
36 | DOTNET_INSTALL_FILE="$TEMP_DIRECTORY/dotnet-install.sh"
37 | mkdir -p "$TEMP_DIRECTORY"
38 | curl -Lsfo "$DOTNET_INSTALL_FILE" "$DOTNET_INSTALL_URL"
39 | chmod +x "$DOTNET_INSTALL_FILE"
40 |
41 | # If global.json exists, load expected version
42 | if [[ -f "$DOTNET_GLOBAL_FILE" ]]; then
43 | DOTNET_VERSION=$(FirstJsonValue "version" "$(cat "$DOTNET_GLOBAL_FILE")")
44 | if [[ "$DOTNET_VERSION" == "" ]]; then
45 | unset DOTNET_VERSION
46 | fi
47 | fi
48 |
49 | # Install by channel or version
50 | DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix"
51 | if [[ -z ${DOTNET_VERSION+x} ]]; then
52 | "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --channel "$DOTNET_CHANNEL" --no-path
53 | else
54 | "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --version "$DOTNET_VERSION" --no-path
55 | fi
56 | export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet"
57 | fi
58 |
59 | echo "Microsoft (R) .NET SDK version $("$DOTNET_EXE" --version)"
60 |
61 | if [[ ! -z ${NUKE_ENTERPRISE_TOKEN+x} && "$NUKE_ENTERPRISE_TOKEN" != "" ]]; then
62 | "$DOTNET_EXE" nuget remove source "nuke-enterprise" &>/dev/null || true
63 | "$DOTNET_EXE" nuget add source "https://f.feedz.io/nuke/enterprise/nuget" --name "nuke-enterprise" --username "PAT" --password "$NUKE_ENTERPRISE_TOKEN" --store-password-in-clear-text &>/dev/null || true
64 | fi
65 |
66 | "$DOTNET_EXE" build "$BUILD_PROJECT_FILE" /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet
67 | "$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" --no-build -- "$@"
68 |
--------------------------------------------------------------------------------
/build/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.cs]
2 | dotnet_style_qualification_for_field = false:warning
3 | dotnet_style_qualification_for_property = false:warning
4 | dotnet_style_qualification_for_method = false:warning
5 | dotnet_style_qualification_for_event = false:warning
6 | dotnet_style_require_accessibility_modifiers = never:warning
7 |
8 | csharp_style_expression_bodied_methods = true:silent
9 | csharp_style_expression_bodied_properties = true:warning
10 | csharp_style_expression_bodied_indexers = true:warning
11 | csharp_style_expression_bodied_accessors = true:warning
12 |
--------------------------------------------------------------------------------
/build/Build.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using Components;
5 | using Nuke.Common;
6 | using Nuke.Common.CI.GitHubActions;
7 |
8 | [GitHubActions(
9 | "continuous",
10 | GitHubActionsImage.WindowsLatest,
11 | On = new[] { GitHubActionsTrigger.Push },
12 | FetchDepth = 0,
13 | InvokedTargets = new[] { nameof(CompileSolution) })]
14 | class Build : NukeBuild,
15 | IDotnetAffectedTargets,
16 | IPulumiTargets,
17 | IAzureTargets,
18 | ITryDotnetAffectedDeployBase,
19 | ITryDotnetAffectedBuild,
20 | ITryDotnetAffectedDependencyBuild,
21 | ITryDotnetAffectedSidestoryBuild,
22 | ITryDotnetAffectedTestsBuild,
23 | ITryDotnetAffectedStoryApiBuild,
24 | ITryDotnetAffectedProxyStoryApiBuild
25 | {
26 | [Parameter("Configuration to build - Default is 'Debug' (local) or 'Release' (server)")]
27 | public static readonly Configuration Configuration = IsLocalBuild ? Configuration.Debug : Configuration.Release;
28 |
29 | public static Dictionary ProjectsToBuild = new();
30 |
31 | public static int Main() => Execute(x => x.CompileSolution);
32 |
33 | public Target Clean => definition => definition
34 | .Executes(() =>
35 | {
36 | File.Delete("affected.json");
37 | });
38 |
39 | public Target Restore => definition => definition
40 | .DependsOn(Clean)
41 | .Executes(() => { });
42 |
43 | public Target CompileSolution => definition => definition
44 | .DependsOn(Restore)
45 | .DependsOn(c => c.DotnetAffected)
46 | .Executes(() => { });
47 |
48 | public Target PublishSolution => definition => definition
49 | .DependsOn(CompileSolution)
50 | .Executes(() => { });
51 |
52 | public Target RunTestsSolution => definition => definition
53 | .DependsOn(CompileSolution)
54 | .Executes(() => { });
55 |
56 | public Target DeploySolution => definition => definition
57 | .DependsOn(PublishSolution)
58 | .Executes(() => { });
59 |
60 | public static Func BaseTarget => projectName =>
61 | definition => definition
62 | .DependsOn(c => c.DotnetAffected)
63 | .OnlyWhenDynamic(() => ProjectsToBuild.ContainsKey(projectName), $"{projectName} is affected");
64 | }
--------------------------------------------------------------------------------
/build/Components/Azure.Targets.cs:
--------------------------------------------------------------------------------
1 | using Nuke.Common;
2 | using Nuke.Common.Tooling;
3 | using Nuke.Common.Tools.Chocolatey;
4 |
5 | // ReSharper disable InconsistentNaming
6 | namespace Components;
7 |
8 | interface IAzureTargets : INukeBuild
9 | {
10 | [PathVariable("az")] static Tool Az;
11 |
12 | [Parameter][Secret] string ARM_CLIENT_ID => TryGetValue(() => ARM_CLIENT_ID);
13 | [Parameter][Secret] string ARM_CLIENT_SECRET => TryGetValue(() => ARM_CLIENT_SECRET);
14 | [Parameter][Secret] string ARM_TENANT_ID => TryGetValue(() => ARM_TENANT_ID);
15 |
16 | Target InstallAzureCli => definition => definition
17 | .Executes(() => ChocolateyTasks.Chocolatey("upgrade azure-cli -y"));
18 |
19 | Target AzLogin => definition => definition
20 | .DependsOn(InstallAzureCli)
21 | .Executes(() =>
22 | {
23 | Az(new Arguments()
24 | .Add("login")
25 | .Add("--service-principal")
26 | .Add("-u {value}", ARM_CLIENT_ID, secret: true)
27 | .Add("-p {value}", ARM_CLIENT_SECRET, secret: true)
28 | .Add("--tenant {value}", ARM_TENANT_ID, secret: true)
29 | .RenderForExecution());
30 | });
31 | }
--------------------------------------------------------------------------------
/build/Components/Dotnet.Affected.Targets.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Text.Json;
4 | using Nuke.Common;
5 | using Nuke.Common.CI.AzurePipelines;
6 | using Nuke.Common.CI.GitHubActions;
7 | using Nuke.Common.Tooling;
8 | using Nuke.Common.Tools.DotNet;
9 |
10 | namespace Components;
11 | interface IDotnetAffectedTargets : INukeBuild
12 | {
13 | AzurePipelines AzurePipelines => AzurePipelines.Instance;
14 | GitHubActions GitHubActions => GitHubActions.Instance;
15 |
16 | // ReSharper disable once ClassNeverInstantiated.Local
17 | record AffectedJson(string Name, string FilePath);
18 |
19 | public Target DotnetAffected => definition => definition
20 | .Executes(() =>
21 | {
22 | var args = new Arguments()
23 | .Add("tool")
24 | .Add("run")
25 | .Add("dotnet-affected")
26 | .Add("--format json")
27 | .Add("--verbose", condition: Verbosity >= Verbosity.Normal);
28 |
29 | if (AzurePipelines != null)
30 | {
31 | args.Add("--from {value}", AzurePipelines.PullRequestSourceBranch)
32 | .Add("--to {value}", AzurePipelines.PullRequestTargetBranch);
33 | }
34 |
35 | if (GitHubActions != null)
36 | {
37 | if (GitHubActions.IsPullRequest)
38 | {
39 | args.Add("--from {value}", GitHubActions.HeadRef)
40 | .Add("--to {value}", GitHubActions.BaseRef);
41 | }
42 | else
43 | {
44 | args.Add("--from {value}", GitHubActions.GitHubEvent["before"]?.ToString());
45 | }
46 | }
47 |
48 | DotNetTasks.DotNetToolRestore();
49 | DotNetTasks.DotNet(args.ToString(), exitHandler: DotnetToolExitHandler);
50 |
51 | if (!File.Exists("affected.json"))
52 | {
53 | return;
54 | }
55 |
56 | var toBuildJson = File.ReadAllText("affected.json");
57 | var affectedProjects = JsonSerializer.Deserialize(toBuildJson);
58 | foreach (var project in affectedProjects)
59 | {
60 | Build.ProjectsToBuild.Add(project.Name, project.FilePath);
61 | }
62 | });
63 |
64 |
65 | void DotnetToolExitHandler(IProcess obj)
66 | {
67 | switch (obj.ExitCode)
68 | {
69 | case 0: // Success
70 | case 166: // No changed projects
71 | return;
72 | default:
73 | throw new Exception();
74 | }
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/build/Components/Pulumi.Targets.cs:
--------------------------------------------------------------------------------
1 | using Nuke.Common;
2 | using Pulumi.Automation;
3 | using System.Collections.Generic;
4 | using System;
5 | using System.Linq;
6 | using Nuke.Common.Tools.Chocolatey;
7 | using Pulumi;
8 | using Log = Serilog.Log;
9 |
10 | namespace Components;
11 |
12 | [ParameterPrefix("Pulumi")]
13 | interface IPulumiTargets : INukeBuild
14 | {
15 | public static PulumiStack Stack = new();
16 |
17 | Target InstallPulumi => definition => definition.Executes(() => ChocolateyTasks.Chocolatey("upgrade pulumi -y"));
18 |
19 | Target ProvisionPulumi => definition => definition
20 | .DependsOn(InstallPulumi)
21 | .Executes(async () =>
22 | {
23 | var program = Stack.Build();
24 |
25 | using var workspace = await LocalWorkspace.CreateOrSelectStackAsync(
26 | new InlineProgramArgs("Try.Dotnet.Affected", "WebApp", program));
27 |
28 | await workspace.UpAsync(new()
29 | {
30 | OnStandardOutput = Log.Information,
31 | OnStandardError = Log.Information
32 | });
33 | });
34 | }
35 |
36 | public class PulumiStack
37 | {
38 | readonly List Actions = new();
39 | readonly Dictionary Outputs = new ();
40 |
41 |
42 | public PulumiStack With(Action action)
43 | {
44 | Actions.Add(action);
45 | return this;
46 | }
47 |
48 | public PulumiStack With(Func action)
49 | {
50 | Actions.Add(() =>
51 | {
52 | var result = action();
53 | var outputs = typeof(T).GetProperties().Where(c => c.PropertyType.IsGenericType && c.PropertyType.GetGenericTypeDefinition() == typeof(Output<>));
54 | foreach (var item in outputs)
55 | {
56 | Outputs.Add(item.Name, item.GetValue(result));
57 | }
58 | });
59 | return this;
60 | }
61 |
62 | public Output GetOutput(string name)
63 | {
64 | return Outputs[name] as Output;
65 | }
66 |
67 | public PulumiFn Build() =>
68 | PulumiFn.Create(() => {
69 | Actions.ForEach(action => action());
70 | });
71 | }
--------------------------------------------------------------------------------
/build/Components/Try.Dotnet.Affected.Build.cs:
--------------------------------------------------------------------------------
1 | using Nuke.Common;
2 | using Nuke.Common.IO;
3 | using Nuke.Common.Tools.DotNet;
4 | using Nuke.Common.Tools.MSBuild;
5 |
6 | namespace Components;
7 |
8 | interface ITryDotnetAffectedBuild : INukeBuild
9 | {
10 | const string ProjectName = "Try.Dotnet.Affected";
11 | public AbsolutePath OutputDirectory => RootDirectory / "output" / ProjectName;
12 |
13 | Target CompileTryDotnetAffected => definition => definition
14 | .Inherit(Build.BaseTarget(ProjectName))
15 | .TriggeredBy(c => c.CompileSolution)
16 | .Executes(() =>
17 | {
18 | var project = Build.ProjectsToBuild[ProjectName];
19 |
20 | MSBuildTasks.MSBuild(settings => settings
21 | .SetTargetPath(project)
22 | .SetTargets("Build")
23 | .SetConfiguration(Build.Configuration)
24 | .EnableRestore()
25 | .EnableNodeReuse());
26 | });
27 |
28 | Target PublishTryDotnetAffected => definition => definition
29 | .Inherit(Build.BaseTarget(ProjectName))
30 | .DependsOn(CompileTryDotnetAffected)
31 | .TriggeredBy(c => c.PublishSolution)
32 | .Executes(() =>
33 | {
34 | var project = Build.ProjectsToBuild[ProjectName];
35 |
36 | DotNetTasks.DotNetPublish(s => s
37 | .SetOutput(OutputDirectory)
38 | .SetProject(project)
39 | .SetConfiguration(Build.Configuration)
40 | .EnableNoRestore());
41 | });
42 | }
--------------------------------------------------------------------------------
/build/Components/Try.Dotnet.Affected.Dependency.Build.cs:
--------------------------------------------------------------------------------
1 | using Nuke.Common;
2 | using Nuke.Common.Tools.MSBuild;
3 |
4 | namespace Components;
5 |
6 | interface ITryDotnetAffectedDependencyBuild : INukeBuild
7 | {
8 | const string ProjectName = "Try.Dotnet.Affected.Dependency";
9 |
10 | Target CompileTryDotnetAffectedDependency => definition => definition
11 | .Inherit(Build.BaseTarget(ProjectName))
12 | .TriggeredBy(c => c.CompileSolution)
13 | .Executes(() =>
14 | {
15 | var project = Build.ProjectsToBuild[ProjectName];
16 |
17 | MSBuildTasks.MSBuild(settings => settings
18 | .SetTargetPath(project)
19 | .SetTargets("Build")
20 | .SetConfiguration(Build.Configuration)
21 | .EnableRestore()
22 | .EnableNodeReuse());
23 | });
24 | }
--------------------------------------------------------------------------------
/build/Components/Try.Dotnet.Affected.DeployBase.cs:
--------------------------------------------------------------------------------
1 | using Nuke.Common;
2 | using Pulumi.AzureNative.Resources;
3 |
4 | namespace Components;
5 |
6 | interface ITryDotnetAffectedDeployBase : INukeBuild
7 | {
8 | public const string AzureRegion = "westeurope";
9 |
10 | Target DeployStackTryDotnetAffectedDeployBase => definition => definition
11 | .DependsOn(c => c.AzLogin)
12 | .DependentFor(c => c.ProvisionPulumi)
13 | .Triggers(c => c.ProvisionPulumi)
14 | .Executes(() =>
15 | IPulumiTargets.Stack.With(() =>
16 | {
17 | var resourceGroup = new ResourceGroup("poc-nuke-pulumi", new()
18 | {
19 | Location = AzureRegion,
20 | });
21 |
22 | return new { ResourceGroupName = resourceGroup.Name };
23 | })
24 | );
25 | }
--------------------------------------------------------------------------------
/build/Components/Try.Dotnet.Affected.ProxyStoryApi.Build.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.IO.Compression;
4 | using System.Net.Http.Headers;
5 | using System.Net.Http;
6 | using System.Text;
7 | using Nuke.Common;
8 | using Nuke.Common.IO;
9 | using Nuke.Common.Tools.DotNet;
10 | using Nuke.Common.Tools.MSBuild;
11 | using Pulumi.AzureNative.Web;
12 | using Pulumi.AzureNative.Web.Inputs;
13 |
14 | namespace Components;
15 |
16 | interface ITryDotnetAffectedProxyStoryApiBuild : INukeBuild
17 | {
18 | const string ProjectName = "Try.Dotnet.Affected.ProxyStoryApi";
19 | AbsolutePath OutputDirectory => RootDirectory / "output" / ProjectName;
20 | AbsolutePath PublishArtifact => RootDirectory / "artifacts" / ProjectName / "api.zip";
21 |
22 | static string PublishingUsername;
23 | static string PublishingPassword;
24 | static string PublishingAppServiceName;
25 |
26 | Target CleanTryDotnetAffectedProxyStoryApi => definition => definition
27 | .Inherit(Build.BaseTarget(ProjectName))
28 | .TriggeredBy(c => c.Clean)
29 | .Executes(() =>
30 | {
31 | Directory.CreateDirectory(Path.GetDirectoryName(PublishArtifact)!);
32 | File.Delete(PublishArtifact);
33 | });
34 |
35 | Target CompileTryDotnetAffectedProxyStoryApi => definition => definition
36 | .Inherit(Build.BaseTarget(ProjectName))
37 | .TriggeredBy(c => c.CompileSolution)
38 | .Executes(() =>
39 | {
40 | var project = Build.ProjectsToBuild[ProjectName];
41 |
42 | MSBuildTasks.MSBuild(settings => settings
43 | .SetTargetPath(project)
44 | .SetTargets("Build")
45 | .SetConfiguration(Build.Configuration)
46 | .EnableRestore()
47 | .EnableNodeReuse());
48 | });
49 |
50 | Target PublishTryDotnetAffectedProxyStoryApi => definition => definition
51 | .Inherit(Build.BaseTarget(ProjectName))
52 | .DependsOn(CompileTryDotnetAffectedProxyStoryApi, CleanTryDotnetAffectedProxyStoryApi)
53 | .TriggeredBy(c => c.PublishSolution)
54 | .Executes(() =>
55 | {
56 | var project = Build.ProjectsToBuild[ProjectName];
57 |
58 | DotNetTasks.DotNetPublish(s => s
59 | .SetOutput(OutputDirectory)
60 | .SetProject(project)
61 | .SetConfiguration(Build.Configuration)
62 | .EnableNoRestore());
63 |
64 | Directory.CreateDirectory(Path.GetDirectoryName(PublishArtifact)!);
65 | ZipFile.CreateFromDirectory(OutputDirectory, PublishArtifact);
66 | });
67 |
68 | Target DeployStackTryDotnetAffectedProxyStoryApi => definition => definition
69 | .After(c => c.DeployStackTryDotnetAffectedDeployBase)
70 | .After(c => c.DeployStackTryDotnetAffectedStoryApi)
71 | .Before(c => c.ProvisionPulumi)
72 | .DependentFor(c => c.ProvisionPulumi)
73 | .Executes(() =>
74 | IPulumiTargets.Stack.With(() =>
75 | {
76 | var resourceGroupName = IPulumiTargets.Stack.GetOutput("ResourceGroupName");
77 | var storyApiName = IPulumiTargets.Stack.GetOutput("StoryApiName").Apply(c => $"https://{c}.azurewebsites.net");
78 | var appService = new WebApp("app-proxy", new WebAppArgs
79 | {
80 | ResourceGroupName = resourceGroupName,
81 | Location = ITryDotnetAffectedDeployBase.AzureRegion,
82 | SiteConfig = new SiteConfigArgs
83 | {
84 | AppSettings =
85 | {
86 | new NameValuePairArgs
87 | {
88 | Name = "StoryApiUrl",
89 | Value = storyApiName,
90 | }
91 | }
92 | }
93 | });
94 |
95 | var publishingCredentials = ListWebAppPublishingCredentials.Invoke(new()
96 | {
97 | ResourceGroupName = resourceGroupName,
98 | Name = appService.Name
99 | });
100 |
101 | publishingCredentials.Apply(c => PublishingUsername = c.PublishingUserName);
102 | publishingCredentials.Apply(c => PublishingPassword = c.PublishingPassword);
103 | appService.Name.Apply(c => PublishingAppServiceName = c);
104 | })
105 | );
106 |
107 | Target PublishStackTryDotnetAffectedProxyStoryApi => definition => definition
108 | .Inherit(Build.BaseTarget(ProjectName))
109 | .DependsOn(DeployStackTryDotnetAffectedProxyStoryApi, PublishTryDotnetAffectedProxyStoryApi)
110 | .DependsOn(c => c.ProvisionPulumi)
111 | .TriggeredBy(c => c.PublishSolution)
112 | .Executes(async () =>
113 | {
114 | var base64Auth = Convert.ToBase64String(Encoding.Default.GetBytes($"{PublishingUsername}:{PublishingPassword}"));
115 |
116 | await using var package = File.OpenRead(PublishArtifact);
117 | using var httpClient = new HttpClient();
118 | httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", base64Auth);
119 | await httpClient.PostAsync($"https://{PublishingAppServiceName}.scm.azurewebsites.net/api/zipdeploy",
120 | new StreamContent(package));
121 | });
122 | }
--------------------------------------------------------------------------------
/build/Components/Try.Dotnet.Affected.Sidestory.Build.cs:
--------------------------------------------------------------------------------
1 | using Nuke.Common;
2 | using Nuke.Common.IO;
3 | using Nuke.Common.Tools.DotNet;
4 | using Nuke.Common.Tools.MSBuild;
5 |
6 | namespace Components;
7 |
8 | interface ITryDotnetAffectedSidestoryBuild : INukeBuild
9 | {
10 | const string ProjectName = "Try.Dotnet.Affected.Sidestory";
11 | public AbsolutePath OutputDirectory => RootDirectory / "output" / ProjectName;
12 |
13 | Target CompileTryDotnetAffectedSidestory => definition => definition
14 | .Inherit(Build.BaseTarget(ProjectName))
15 | .TriggeredBy(c => c.CompileSolution)
16 | .Executes(() =>
17 | {
18 | var project = Build.ProjectsToBuild[ProjectName];
19 |
20 | MSBuildTasks.MSBuild(settings => settings
21 | .SetTargetPath(project)
22 | .SetTargets("Build")
23 | .SetConfiguration(Build.Configuration)
24 | .EnableRestore()
25 | .EnableNodeReuse());
26 | });
27 |
28 | Target PublishTryDotnetAffectedSidestory => definition => definition
29 | .DependsOn(CompileTryDotnetAffectedSidestory)
30 | .Inherit(Build.BaseTarget(ProjectName))
31 | .TriggeredBy(c => c.PublishSolution)
32 | .Executes(() =>
33 | {
34 | var project = Build.ProjectsToBuild[ProjectName];
35 | DotNetTasks.DotNetPublish(s => s
36 | .SetOutput(OutputDirectory)
37 | .SetProject(project)
38 | .SetConfiguration(Build.Configuration)
39 | .EnableNoRestore());
40 | });
41 | }
--------------------------------------------------------------------------------
/build/Components/Try.Dotnet.Affected.StoryApi.Build.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.IO.Compression;
4 | using System.Net.Http.Headers;
5 | using System.Net.Http;
6 | using System.Text;
7 | using Nuke.Common;
8 | using Nuke.Common.IO;
9 | using Nuke.Common.Tools.DotNet;
10 | using Nuke.Common.Tools.MSBuild;
11 | using Pulumi.AzureNative.Web;
12 |
13 | namespace Components;
14 |
15 | interface ITryDotnetAffectedStoryApiBuild : INukeBuild
16 | {
17 | const string ProjectName = "Try.Dotnet.Affected.StoryApi";
18 | AbsolutePath OutputDirectory => RootDirectory / "output" / ProjectName;
19 | AbsolutePath PublishArtifact => RootDirectory / "artifacts" / ProjectName / "api.zip";
20 |
21 | static string PublishingUsername;
22 | static string PublishingPassword;
23 | static string PublishingAppServiceName;
24 |
25 | Target CleanTryDotnetAffectedStoryApi => definition => definition
26 | .Inherit(Build.BaseTarget(ProjectName))
27 | .TriggeredBy(c => c.Clean)
28 | .Executes(() =>
29 | {
30 | Directory.CreateDirectory(Path.GetDirectoryName(PublishArtifact)!);
31 | File.Delete(PublishArtifact);
32 | });
33 |
34 |
35 | Target CompileTryDotnetAffectedStoryApi => definition => definition
36 | .Inherit(Build.BaseTarget(ProjectName))
37 | .TriggeredBy(c => c.CompileSolution)
38 | .Executes(() =>
39 | {
40 | var project = Build.ProjectsToBuild[ProjectName];
41 |
42 | MSBuildTasks.MSBuild(settings => settings
43 | .SetTargetPath(project)
44 | .SetTargets("Build")
45 | .SetConfiguration(Build.Configuration)
46 | .EnableRestore()
47 | .EnableNodeReuse());
48 | });
49 |
50 | Target PublishTryDotnetAffectedStoryApi => definition => definition
51 | .Inherit(Build.BaseTarget(ProjectName))
52 | .DependsOn(CompileTryDotnetAffectedStoryApi, CleanTryDotnetAffectedStoryApi)
53 | .TriggeredBy(c => c.PublishSolution)
54 | .Executes(() =>
55 | {
56 | var project = Build.ProjectsToBuild[ProjectName];
57 |
58 | DotNetTasks.DotNetPublish(s => s
59 | .SetOutput(OutputDirectory)
60 | .SetProject(project)
61 | .SetConfiguration(Build.Configuration)
62 | .EnableNoRestore());
63 |
64 | Directory.CreateDirectory(Path.GetDirectoryName(PublishArtifact)!);
65 | ZipFile.CreateFromDirectory(OutputDirectory, PublishArtifact);
66 | });
67 |
68 | Target DeployStackTryDotnetAffectedStoryApi => definition => definition
69 | .After(c => c.DeployStackTryDotnetAffectedDeployBase)
70 | .Before(c => c.ProvisionPulumi)
71 | .DependentFor(c => c.ProvisionPulumi)
72 | .Executes(() =>
73 | IPulumiTargets.Stack.With(() =>
74 | {
75 | var resourceGroupName = IPulumiTargets.Stack.GetOutput("ResourceGroupName");
76 | var appService = new WebApp("app", new WebAppArgs
77 | {
78 | ResourceGroupName = resourceGroupName,
79 | Location = ITryDotnetAffectedDeployBase.AzureRegion,
80 | });
81 |
82 | var publishingCredentials = ListWebAppPublishingCredentials.Invoke(new()
83 | {
84 | ResourceGroupName = resourceGroupName,
85 | Name = appService.Name,
86 | });
87 |
88 | publishingCredentials.Apply(c => PublishingUsername = c.PublishingUserName);
89 | publishingCredentials.Apply(c => PublishingPassword = c.PublishingPassword);
90 | appService.Name.Apply(c => PublishingAppServiceName = c);
91 |
92 | return new { StoryApiName = appService.Name };
93 | })
94 | );
95 |
96 | Target PublishStackTryDotnetAffectedStoryApi => definition => definition
97 | .Inherit(Build.BaseTarget(ProjectName))
98 | .DependsOn(DeployStackTryDotnetAffectedStoryApi, PublishTryDotnetAffectedStoryApi)
99 | .DependsOn(c => c.ProvisionPulumi)
100 | .TriggeredBy(c => c.PublishSolution)
101 | .Executes(async () =>
102 | {
103 | var base64Auth = Convert.ToBase64String(Encoding.Default.GetBytes($"{PublishingUsername}:{PublishingPassword}"));
104 |
105 | await using var package = File.OpenRead(PublishArtifact);
106 | using var httpClient = new HttpClient();
107 | httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", base64Auth);
108 | await httpClient.PostAsync($"https://{PublishingAppServiceName}.scm.azurewebsites.net/api/zipdeploy",
109 | new StreamContent(package));
110 | });
111 | }
--------------------------------------------------------------------------------
/build/Components/Try.Dotnet.Affected.Tests.Build.cs:
--------------------------------------------------------------------------------
1 | using Nuke.Common;
2 | using Nuke.Common.Tools.DotNet;
3 | using Nuke.Common.Tools.MSBuild;
4 |
5 | namespace Components;
6 |
7 | interface ITryDotnetAffectedTestsBuild : INukeBuild
8 | {
9 | const string ProjectName = "Try.Dotnet.Affected.Tests";
10 |
11 | Target CompileTryDotnetAffectedTests => definition => definition
12 | .Inherit(Build.BaseTarget(ProjectName))
13 | .DependsOn(c => c.CompileTryDotnetAffected)
14 | .TriggeredBy(c => c.CompileSolution)
15 | .Executes(() =>
16 | {
17 | var project = Build.ProjectsToBuild[ProjectName];
18 |
19 | MSBuildTasks.MSBuild(settings => settings
20 | .SetTargetPath(project)
21 | .SetTargets("Build")
22 | .SetConfiguration(Build.Configuration)
23 | .EnableRestore()
24 | .EnableNodeReuse());
25 | });
26 |
27 | Target RunTestsTryDotnetAffectedTests => definition => definition
28 | .Inherit(Build.BaseTarget(ProjectName))
29 | .DependsOn(CompileTryDotnetAffectedTests)
30 | .TriggeredBy(c => c.RunTestsSolution)
31 | .Executes(() =>
32 | {
33 | var project = Build.ProjectsToBuild[ProjectName];
34 | DotNetTasks.DotNetTest(c => c
35 | .SetConfiguration(Build.Configuration)
36 | .SetProjectFile(project)
37 | .AddLoggers("trx"));
38 | });
39 | }
--------------------------------------------------------------------------------
/build/Configuration.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using Nuke.Common.Tooling;
3 |
4 | [TypeConverter(typeof(TypeConverter))]
5 | public class Configuration : Enumeration
6 | {
7 | public static Configuration Debug = new() { Value = nameof(Debug) };
8 | public static Configuration Release = new() { Value = nameof(Release) };
9 |
10 | public static implicit operator string(Configuration configuration)
11 | {
12 | return configuration.Value;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/build/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/build/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/build/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "_build": {
4 | "commandName": "Project",
5 | "workingDirectory": "D:\\source\\repos\\Try.Dotnet.Affected"
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/build/_build.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net7.0
6 |
7 | CS0649;CS0169;CA1050;CA1822;CA2211;IDE1006
8 | ..
9 | ..
10 | 1
11 | false
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/build/_build.csproj.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | DO_NOT_SHOW
3 | DO_NOT_SHOW
4 | DO_NOT_SHOW
5 | DO_NOT_SHOW
6 | DO_NOT_SHOW
7 | Implicit
8 | Implicit
9 | ExpressionBody
10 | 0
11 | NEXT_LINE
12 | True
13 | False
14 | 120
15 | IF_OWNER_IS_SINGLE_LINE
16 | WRAP_IF_LONG
17 | False
18 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
19 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
20 | True
21 | True
22 | True
23 | True
24 | True
25 | True
26 | True
27 | True
28 | True
29 |
--------------------------------------------------------------------------------
/screenshots/BuildTargets.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwdb/Try.Dotnet.Affected/1c6999290bc37948081a747026d40f7329ac330a/screenshots/BuildTargets.png
--------------------------------------------------------------------------------