Skip to content

Commit 2cd1002

Browse files
committed
Add ThisAssembly.Git, leveraging Microsoft.SourceLink and ThisAssembly.Constants
This new package is just targets that leverage git-based SourceLink packages (which must be installed separately since there is a variety) to populate source control information, turn it into constants that then the ThisAssembly.Constants package surfaces in a standard manner. We do not force run of source control queries in design-time builds, unless the user forces it. This keeps the performance characteristics of SourceLink, at the expense of a slightly confusing user experience where intellisense might show the properties as empty all the time while in fact it's just during design-time. Closes #69
1 parent 3633673 commit 2cd1002

File tree

11 files changed

+312
-58
lines changed

11 files changed

+312
-58
lines changed

ThisAssembly.sln

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThisAssembly.Metadata", "sr
77
EndProject
88
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4CA0A26B-C9E5-4F5A-93EC-A1E1FE8CA389}"
99
ProjectSection(SolutionItems) = preProject
10+
.editorconfig = .editorconfig
1011
src\Directory.props = src\Directory.props
1112
src\Directory.targets = src\Directory.targets
1213
readme.md = readme.md
@@ -35,7 +36,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThisAssembly.Constants", "s
3536
EndProject
3637
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThisAssembly.Tests", "src\ThisAssembly.Tests\ThisAssembly.Tests.csproj", "{AD25424F-7DE0-4515-AE9F-B95414218292}"
3738
EndProject
38-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThisAssembly.Resources", "src\ThisAssembly.Resources\ThisAssembly.Resources.csproj", "{14D0C5BA-8410-4454-87A2-7BF5993E1EA2}"
39+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThisAssembly.Resources", "src\ThisAssembly.Resources\ThisAssembly.Resources.csproj", "{14D0C5BA-8410-4454-87A2-7BF5993E1EA2}"
40+
EndProject
41+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThisAssembly.Git", "src\ThisAssembly.Git\ThisAssembly.Git.csproj", "{F34F8470-7C60-4BB8-ACB5-569D6D0F6A46}"
3942
EndProject
4043
Global
4144
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -79,6 +82,10 @@ Global
7982
{14D0C5BA-8410-4454-87A2-7BF5993E1EA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
8083
{14D0C5BA-8410-4454-87A2-7BF5993E1EA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
8184
{14D0C5BA-8410-4454-87A2-7BF5993E1EA2}.Release|Any CPU.Build.0 = Release|Any CPU
85+
{F34F8470-7C60-4BB8-ACB5-569D6D0F6A46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
86+
{F34F8470-7C60-4BB8-ACB5-569D6D0F6A46}.Debug|Any CPU.Build.0 = Debug|Any CPU
87+
{F34F8470-7C60-4BB8-ACB5-569D6D0F6A46}.Release|Any CPU.ActiveCfg = Release|Any CPU
88+
{F34F8470-7C60-4BB8-ACB5-569D6D0F6A46}.Release|Any CPU.Build.0 = Release|Any CPU
8289
EndGlobalSection
8390
GlobalSection(SolutionProperties) = preSolution
8491
HideSolutionNode = FALSE

src/Directory.Build.props

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@
6767
<DefaultItemExcludes>$(DefaultItemExcludes);*.binlog;*.zip;*.rsp;*.items;**/TestResults/**/*.*</DefaultItemExcludes>
6868

6969
<EnableSourceLink>true</EnableSourceLink>
70-
<EnableSourceControlManagerQueries>true</EnableSourceControlManagerQueries>
70+
<!-- This should only be enabled on non-DTB builds, so don't turn on indiscriminately -->
71+
<!--<EnableSourceControlManagerQueries>true</EnableSourceControlManagerQueries>-->
7172
<EmbedUntrackedSources>true</EmbedUntrackedSources>
7273
<UseSourceLink>true</UseSourceLink>
7374

src/Directory.Build.targets

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@
9292
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(BUDDY_EXECUTION_PULL_REQUEST_NO)' != ''">pr$(BUDDY_EXECUTION_PULL_REQUEST_NO)</RepositoryBranch>
9393
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(BUDDY_EXECUTION_TAG)' != ''">$(BUDDY_EXECUTION_TAG)</RepositoryBranch>
9494
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(BUDDY_EXECUTION_BRANCH)' != ''">$(BUDDY_EXECUTION_BRANCH)</RepositoryBranch>
95+
<!-- Jenkins: https://plugins.jenkins.io/git/#plugin-content-environment-variables -->
96+
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(GIT_LOCAL_BRANCH)' != ''">$(GIT_LOCAL_BRANCH)</RepositoryBranch>
9597
</PropertyGroup>
9698

9799
<ItemGroup>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"profiles": {
3+
"ThisAssembly.Git": {
4+
"commandName": "DebugRoslynComponent",
5+
"targetProject": "..\\ThisAssembly.Tests\\ThisAssembly.Tests.csproj"
6+
}
7+
}
8+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using Devlooped;
2+
using Microsoft.CodeAnalysis;
3+
4+
namespace ThisAssembly;
5+
6+
[Generator]
7+
class Generator : IIncrementalGenerator
8+
{
9+
readonly SponsorLink link;
10+
11+
public Generator() => link = new SponsorLink("devlooped", "ThisAssembly.Git");
12+
13+
public void Initialize(IncrementalGeneratorInitializationContext context) => link.Initialize(context);
14+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netstandard2.0</TargetFramework>
5+
<LangVersion>latest</LangVersion>
6+
<IsRoslynComponent>true</IsRoslynComponent>
7+
<DevelopmentDependency>true</DevelopmentDependency>
8+
</PropertyGroup>
9+
10+
<PropertyGroup>
11+
<PackageId>ThisAssembly.Git</PackageId>
12+
<Description>
13+
This package generates a static `ThisAssembly.Git` class with public
14+
constants for the following properties provided by Microsoft.SourceLink (git-based) packages:
15+
16+
* Commit
17+
* Sha (first 9 chars from Commit)
18+
* Root (normalized to forward slashes)
19+
* Url (if PublishRepositoryUrl=true)
20+
21+
It also provides the Branch property, calculated from supported CI
22+
environment variables (GitHub Actions, Azure DevOps, AppVeyor, TeamCity,
23+
Travis CI, Circle CI, GitLab CI, Buddy, and Jenkins).
24+
</Description>
25+
</PropertyGroup>
26+
27+
<ItemGroup>
28+
<ProjectReference Include="..\ThisAssembly.Constants\ThisAssembly.Constants.csproj" />
29+
</ItemGroup>
30+
31+
<ItemGroup>
32+
<PackageReference Include="Devlooped.SponsorLink" Version="0.3.0" />
33+
<PackageReference Include="NuGetizer" Version="0.9.1" />
34+
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="all" />
35+
<PackageReference Include="Microsoft.SourceLink.Common" Version="1.1.1" Pack="true" ExcludeAssets="all" />
36+
</ItemGroup>
37+
38+
</Project>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<Project>
2+
3+
<!-- Implemented by each SCM package in .targets, guaranteeing it's overwritten -->
4+
<Target Name="InitializeSourceControlInformationFromSourceControlManager" />
5+
6+
</Project>
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<Project>
2+
3+
<PropertyGroup Condition="'$(RepositoryBranch)' == ''">
4+
<!-- GitHub Actions: https://docs.github.com/en/actions/reference/environment-variables#default-environment-variables -->
5+
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(GITHUB_REF)' != '' and $(GITHUB_REF.Contains('refs/pull/'))">pr$(GITHUB_REF.Replace('refs/pull/', '').Replace('/merge', ''))</RepositoryBranch>
6+
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(GITHUB_REF)' != ''">$(GITHUB_REF.Replace('refs/heads/', '').Replace('refs/tags/', ''))</RepositoryBranch>
7+
<!-- Azure DevOps: https://docs.microsoft.com/en-us/azure/devops/pipelines/build/variables -->
8+
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(BUILD_SOURCEBRANCH)' != ''">$(BUILD_SOURCEBRANCH.Replace('refs/heads/', '').Replace('refs/tags/', ''))</RepositoryBranch>
9+
<!-- AppVeyor: https://www.appveyor.com/docs/environment-variables/ -->
10+
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(APPVEYOR_PULL_REQUEST_NUMBER)' != ''">pr$(APPVEYOR_PULL_REQUEST_NUMBER)</RepositoryBranch>
11+
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(APPVEYOR_REPO_TAG_NAME)' != ''">$(APPVEYOR_REPO_TAG_NAME)</RepositoryBranch>
12+
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(APPVEYOR_REPO_BRANCH)' != ''">$(APPVEYOR_REPO_BRANCH)</RepositoryBranch>
13+
<!-- TeamCity: https://www.jetbrains.com/help/teamcity/predefined-build-parameters.html#Branch-Related+Parameters -->
14+
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(TEAMCITY_BUILD_BRANCH)' != ''">$(TEAMCITY_BUILD_BRANCH)</RepositoryBranch>
15+
<!--TravisCI: https://docs.travis-ci.com/user/environment-variables/ -->
16+
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(TRAVIS_PULL_REQUEST)' != '' and '$(TRAVIS_PULL_REQUEST)' != 'false'">pr$(TRAVIS_PULL_REQUEST)</RepositoryBranch>
17+
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(TRAVIS_BRANCH)' != ''">$(TRAVIS_BRANCH)</RepositoryBranch>
18+
<!-- CircleCI: https://circleci.com/docs/2.0/env-vars/ -->
19+
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CIRCLE_PR_NUMBER)' != ''">pr$(CIRCLE_PR_NUMBER)</RepositoryBranch>
20+
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CIRCLE_TAG)' != ''">$(CIRCLE_TAG)</RepositoryBranch>
21+
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CIRCLE_BRANCH)' != ''">$(CIRCLE_BRANCH)</RepositoryBranch>
22+
<!-- GitLab: https://docs.gitlab.com/ee/ci/variables/predefined_variables.html -->
23+
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CI_COMMIT_TAG)' != ''">$(CI_COMMIT_TAG)</RepositoryBranch>
24+
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CI_MERGE_REQUEST_IID)' != ''">pr$(CI_MERGE_REQUEST_IID)</RepositoryBranch>
25+
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CI_EXTERNAL_PULL_REQUEST_IID)' != ''">pr$(CI_EXTERNAL_PULL_REQUEST_IID)</RepositoryBranch>
26+
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CI_COMMIT_BRANCH)' != ''">$(CI_COMMIT_BRANCH)</RepositoryBranch>
27+
<!-- Buddy: https://buddy.works/docs/pipelines/environment-variables#default-environment-variables -->
28+
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(BUDDY_EXECUTION_PULL_REQUEST_NO)' != ''">pr$(BUDDY_EXECUTION_PULL_REQUEST_NO)</RepositoryBranch>
29+
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(BUDDY_EXECUTION_TAG)' != ''">$(BUDDY_EXECUTION_TAG)</RepositoryBranch>
30+
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(BUDDY_EXECUTION_BRANCH)' != ''">$(BUDDY_EXECUTION_BRANCH)</RepositoryBranch>
31+
<!-- Jenkins: https://plugins.jenkins.io/git/#plugin-content-environment-variables -->
32+
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(GIT_LOCAL_BRANCH)' != ''">$(GIT_LOCAL_BRANCH)</RepositoryBranch>
33+
</PropertyGroup>
34+
35+
<!-- Make sure git info is available before calling source generators -->
36+
<Target Name="InitializeGitInformation"
37+
BeforeTargets="GenerateMSBuildEditorConfigFileShouldRun"
38+
DependsOnTargets="InitializeSourceControlInformation">
39+
40+
<PropertyGroup Condition="'$(SourceControlInformationFeatureSupported)' == 'true'">
41+
<!-- The project must specify PublishRepositoryUrl=true in order to publish the URL, in order to prevent inadvertent leak of internal URL. -->
42+
<RepositoryUrl Condition="'$(RepositoryUrl)' == '' and '$(PublishRepositoryUrl)' == 'true'">$(PrivateRepositoryUrl)</RepositoryUrl>
43+
</PropertyGroup>
44+
45+
<PropertyGroup Condition="'$(SourceRevisionId)' != ''">
46+
<RepositoryCommit Condition="'$(RepositoryCommit)' == ''">$(SourceRevisionId)</RepositoryCommit>
47+
<RepositorySha Condition="'$(RepositorySha)' == ''">$(SourceRevisionId.Substring(0, 9))</RepositorySha>
48+
</PropertyGroup>
49+
50+
<!-- Add SourceRoot as a project property too -->
51+
<ItemGroup>
52+
<_ThisAssemblyGitSourceRoot Include="@(SourceRoot -> WithMetadataValue('SourceControl', 'git'))" />
53+
</ItemGroup>
54+
55+
<PropertyGroup>
56+
<RepositoryRoot>@(_ThisAssemblyGitSourceRoot)</RepositoryRoot>
57+
</PropertyGroup>
58+
59+
</Target>
60+
61+
<Target Name="PrepareGitConstants"
62+
BeforeTargets="PrepareConstants"
63+
DependsOnTargets="InitializeGitInformation">
64+
<ItemGroup>
65+
<Constant Include="Branch" Value="$(RepositoryBranch)" Root="Git" />
66+
<Constant Include="Commit" Value="$(RepositoryCommit)" Root="Git" />
67+
<Constant Include="Sha" Value="$(RepositorySha)" Root="Git" />
68+
<Constant Include="Root" Value="$(RepositoryRoot.Replace('\', '/'))" Root="Git" />
69+
<Constant Include="Url" Value="$(RepositoryUrl)" Root="Git" />
70+
</ItemGroup>
71+
</Target>
72+
73+
</Project>

src/ThisAssembly.Git/readme.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<!-- #content -->
2+
This package generates a static `ThisAssembly.Git` class with constants
3+
for the following Git properties from the current project:
4+
5+
* Commit
6+
* Sha (first 9 chars from Commit)
7+
* Root (normalized to forward slashes)
8+
* Url (if PublishRepositoryUrl=true)
9+
* Branch (from CI environment variables)
10+
11+
This package relies on your project's Microsoft.SourceLink.* package
12+
reference according to you specific Git-based source control server
13+
(such as GitHub, Azure DevOps, BitBucket, etc). Explore the
14+
[supported source control providers](https://www.nuget.org/packages?q=Microsoft.SourceLink).
15+
16+
The `Branch` property is populated from supported CI environment variables
17+
for the currently supported CI systems: GitHub Actions, Azure DevOps,
18+
AppVeyor, TeamCity, Travis CI, Circle CI, GitLab CI, Buddy, and Jenkins.
19+
20+
Whenever the CI system provides a pull request number, the branch name is
21+
`pr[NUMBER]`, such as `pr123`. This makes it easy to use it as a semver
22+
metadata label.
23+
24+
> NOTE: by default, the values of these constants are populated during
25+
"real" builds (that is, not IDE/design-time builds used to populate
26+
intellisense). This is to avoid negatively affecting the editor's
27+
performance. This means, however, that the properties will seem to
28+
always be empty when inspecting them in the IDE (although never at
29+
run-time). If you want to force population of these values for
30+
design-time builds, set the `EnableSourceControlManagerQueries` property to `true`.
31+
This property is defined and documented by
32+
[dotnet/sourcelink](https://github.com/dotnet/sourcelink/blob/main/src/SourceLink.Common/build/Microsoft.SourceLink.Common.props#L14).
33+
34+
At the MSBuild level, targets can take a dependency on the provided
35+
`InitializeGitInformation` target, which sets the equivalent properties
36+
named:
37+
38+
* RepositoryCommit
39+
* RepositorySha
40+
* RepositoryRoot
41+
* RepositoryUrl
42+
* RepositoryBranch
43+
44+
The names of these properties were chosen on purpose to match the
45+
properties used by [nuget pack](https://learn.microsoft.com/en-us/nuget/reference/msbuild-targets#pack-target)
46+
and [nugetizer](https://github.com/devlooped/nugetizer) to populate
47+
the relevant package metadata.
48+
49+
So if you have a GitHub repository, installing these three packages
50+
will ensure you have the proper metadata out of the box and the simplest
51+
packaging experience possible:
52+
53+
```xml
54+
<Project Sdk="Microsoft.NET.Sdk">
55+
<PropertyGroup>
56+
<TargetFramework>netstandard2.0</TargetFramework>
57+
</PropertyGroup>
58+
59+
<ItemGroup>
60+
<PackageReference Include="Microsoft.SourceLink.GitHub" />
61+
<PackageReference Include="ThisAssembly.Git" />
62+
<PackageReference Include="NuGetizer" />
63+
</ItemGroup>
64+
</Project>
65+
```
66+
67+
68+
<!-- #content -->
69+
70+
<!-- include https://github.com/devlooped/sponsors/raw/main/footer.md -->
71+
# Sponsors
72+
73+
<!-- sponsors.md -->
74+
[![Clarius Org](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/clarius.png "Clarius Org")](https://github.com/clarius)
75+
[![Christian Findlay](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/MelbourneDeveloper.png "Christian Findlay")](https://github.com/MelbourneDeveloper)
76+
[![C. Augusto Proiete](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/augustoproiete.png "C. Augusto Proiete")](https://github.com/augustoproiete)
77+
[![Kirill Osenkov](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/KirillOsenkov.png "Kirill Osenkov")](https://github.com/KirillOsenkov)
78+
[![MFB Technologies, Inc.](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/MFB-Technologies-Inc.png "MFB Technologies, Inc.")](https://github.com/MFB-Technologies-Inc)
79+
[![SandRock](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/sandrock.png "SandRock")](https://github.com/sandrock)
80+
[![Eric C](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/eeseewy.png "Eric C")](https://github.com/eeseewy)
81+
[![Andy Gocke](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/agocke.png "Andy Gocke")](https://github.com/agocke)
82+
83+
84+
<!-- sponsors.md -->
85+
86+
[![Sponsor this project](https://raw.githubusercontent.com/devlooped/sponsors/main/sponsor.png "Sponsor this project")](https://github.com/sponsors/devlooped)
87+
&nbsp;
88+
89+
[Learn more about GitHub Sponsors](https://github.com/sponsors)
90+
91+
<!-- https://github.com/devlooped/sponsors/raw/main/footer.md -->

src/ThisAssembly.Tests/Tests.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
using System.IO;
1+
using System.Diagnostics.CodeAnalysis;
2+
using System.IO;
23
using Xunit;
34

5+
[assembly: SuppressMessage("SponsorLink", "SL04")]
6+
47
namespace ThisAssemblyTests
58
{
69
public class Tests
@@ -56,5 +59,9 @@ public void CanUseByteResource()
5659
[Fact]
5760
public void CanUseSameNameDifferentExtensions()
5861
=> Assert.NotNull(ThisAssembly.Resources.Content.Swagger.swagger_ui.css.GetBytes());
62+
63+
[Fact]
64+
public void CanUseGitConstants()
65+
=> Assert.NotEmpty(ThisAssembly.Git.Commit);
5966
}
6067
}

0 commit comments

Comments
 (0)