Skip to content

Commit

Permalink
Add ThisAssembly.Git, leveraging Microsoft.SourceLink and ThisAssembl…
Browse files Browse the repository at this point in the history
…y.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
  • Loading branch information
kzu committed Jan 25, 2023
1 parent 68e531e commit f495697
Show file tree
Hide file tree
Showing 11 changed files with 251 additions and 3 deletions.
9 changes: 8 additions & 1 deletion ThisAssembly.sln
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThisAssembly.Metadata", "sr
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4CA0A26B-C9E5-4F5A-93EC-A1E1FE8CA389}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
src\Directory.props = src\Directory.props
src\Directory.targets = src\Directory.targets
readme.md = readme.md
Expand Down Expand Up @@ -35,7 +36,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThisAssembly.Constants", "s
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThisAssembly.Tests", "src\ThisAssembly.Tests\ThisAssembly.Tests.csproj", "{AD25424F-7DE0-4515-AE9F-B95414218292}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThisAssembly.Resources", "src\ThisAssembly.Resources\ThisAssembly.Resources.csproj", "{14D0C5BA-8410-4454-87A2-7BF5993E1EA2}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThisAssembly.Resources", "src\ThisAssembly.Resources\ThisAssembly.Resources.csproj", "{14D0C5BA-8410-4454-87A2-7BF5993E1EA2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThisAssembly.Git", "src\ThisAssembly.Git\ThisAssembly.Git.csproj", "{F34F8470-7C60-4BB8-ACB5-569D6D0F6A46}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -79,6 +82,10 @@ Global
{14D0C5BA-8410-4454-87A2-7BF5993E1EA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{14D0C5BA-8410-4454-87A2-7BF5993E1EA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{14D0C5BA-8410-4454-87A2-7BF5993E1EA2}.Release|Any CPU.Build.0 = Release|Any CPU
{F34F8470-7C60-4BB8-ACB5-569D6D0F6A46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F34F8470-7C60-4BB8-ACB5-569D6D0F6A46}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F34F8470-7C60-4BB8-ACB5-569D6D0F6A46}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F34F8470-7C60-4BB8-ACB5-569D6D0F6A46}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
3 changes: 2 additions & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@
<DefaultItemExcludes>$(DefaultItemExcludes);*.binlog;*.zip;*.rsp;*.items;**/TestResults/**/*.*</DefaultItemExcludes>

<EnableSourceLink>true</EnableSourceLink>
<EnableSourceControlManagerQueries>true</EnableSourceControlManagerQueries>
<!-- This should only be enabled on non-DTB builds, so don't turn on indiscriminately -->
<!--<EnableSourceControlManagerQueries>true</EnableSourceControlManagerQueries>-->
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<UseSourceLink>true</UseSourceLink>

Expand Down
2 changes: 2 additions & 0 deletions src/Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(BUDDY_EXECUTION_PULL_REQUEST_NO)' != ''">pr$(BUDDY_EXECUTION_PULL_REQUEST_NO)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(BUDDY_EXECUTION_TAG)' != ''">$(BUDDY_EXECUTION_TAG)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(BUDDY_EXECUTION_BRANCH)' != ''">$(BUDDY_EXECUTION_BRANCH)</RepositoryBranch>
<!-- Jenkins: https://plugins.jenkins.io/git/#plugin-content-environment-variables -->
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(GIT_LOCAL_BRANCH)' != ''">$(GIT_LOCAL_BRANCH)</RepositoryBranch>
</PropertyGroup>

<ItemGroup>
Expand Down
8 changes: 8 additions & 0 deletions src/ThisAssembly.Git/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"profiles": {
"ThisAssembly.Git": {
"commandName": "DebugRoslynComponent",
"targetProject": "..\\ThisAssembly.Tests\\ThisAssembly.Tests.csproj"
}
}
}
14 changes: 14 additions & 0 deletions src/ThisAssembly.Git/SponsorLink.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Devlooped;
using Microsoft.CodeAnalysis;

namespace ThisAssembly;

[Generator]
class Generator : IIncrementalGenerator
{
readonly SponsorLink link;

public Generator() => link = new SponsorLink("devlooped", "ThisAssembly.Git");

public void Initialize(IncrementalGeneratorInitializationContext context) => link.Initialize(context);
}
38 changes: 38 additions & 0 deletions src/ThisAssembly.Git/ThisAssembly.Git.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>latest</LangVersion>
<IsRoslynComponent>true</IsRoslynComponent>
<DevelopmentDependency>true</DevelopmentDependency>
</PropertyGroup>

<PropertyGroup>
<PackageId>ThisAssembly.Git</PackageId>
<Description>
This package generates a static `ThisAssembly.Git` class with public
constants for the following properties provided by Microsoft.SourceLink (git-based) packages:

* Commit
* Sha (first 9 chars from Commit)
* Root (normalized to forward slashes)
* Url (if PublishRepositoryUrl=true)

It also provides the Branch property, calculated from supported CI
environment variables (GitHub Actions, Azure DevOps, AppVeyor, TeamCity,
Travis CI, Circle CI, GitLab CI, Buddy, and Jenkins).
</Description>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\ThisAssembly.Constants\ThisAssembly.Constants.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Devlooped.SponsorLink" Version="0.3.0" />
<PackageReference Include="NuGetizer" Version="0.9.1" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="all" />
<PackageReference Include="Microsoft.SourceLink.Common" Version="1.1.1" Pack="true" ExcludeAssets="all" />
</ItemGroup>

</Project>
6 changes: 6 additions & 0 deletions src/ThisAssembly.Git/ThisAssembly.Git.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<Project>

<!-- Implemented by each SCM package in .targets, guaranteeing it's overwritten -->
<Target Name="InitializeSourceControlInformationFromSourceControlManager" />

</Project>
73 changes: 73 additions & 0 deletions src/ThisAssembly.Git/ThisAssembly.Git.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<Project>

<PropertyGroup Condition="'$(RepositoryBranch)' == ''">
<!-- GitHub Actions: https://docs.github.com/en/actions/reference/environment-variables#default-environment-variables -->
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(GITHUB_REF)' != '' and $(GITHUB_REF.Contains('refs/pull/'))">pr$(GITHUB_REF.Replace('refs/pull/', '').Replace('/merge', ''))</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(GITHUB_REF)' != ''">$(GITHUB_REF.Replace('refs/heads/', '').Replace('refs/tags/', ''))</RepositoryBranch>
<!-- Azure DevOps: https://docs.microsoft.com/en-us/azure/devops/pipelines/build/variables -->
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(BUILD_SOURCEBRANCH)' != ''">$(BUILD_SOURCEBRANCH.Replace('refs/heads/', '').Replace('refs/tags/', ''))</RepositoryBranch>
<!-- AppVeyor: https://www.appveyor.com/docs/environment-variables/ -->
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(APPVEYOR_PULL_REQUEST_NUMBER)' != ''">pr$(APPVEYOR_PULL_REQUEST_NUMBER)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(APPVEYOR_REPO_TAG_NAME)' != ''">$(APPVEYOR_REPO_TAG_NAME)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(APPVEYOR_REPO_BRANCH)' != ''">$(APPVEYOR_REPO_BRANCH)</RepositoryBranch>
<!-- TeamCity: https://www.jetbrains.com/help/teamcity/predefined-build-parameters.html#Branch-Related+Parameters -->
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(TEAMCITY_BUILD_BRANCH)' != ''">$(TEAMCITY_BUILD_BRANCH)</RepositoryBranch>
<!--TravisCI: https://docs.travis-ci.com/user/environment-variables/ -->
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(TRAVIS_PULL_REQUEST)' != '' and '$(TRAVIS_PULL_REQUEST)' != 'false'">pr$(TRAVIS_PULL_REQUEST)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(TRAVIS_BRANCH)' != ''">$(TRAVIS_BRANCH)</RepositoryBranch>
<!-- CircleCI: https://circleci.com/docs/2.0/env-vars/ -->
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CIRCLE_PR_NUMBER)' != ''">pr$(CIRCLE_PR_NUMBER)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CIRCLE_TAG)' != ''">$(CIRCLE_TAG)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CIRCLE_BRANCH)' != ''">$(CIRCLE_BRANCH)</RepositoryBranch>
<!-- GitLab: https://docs.gitlab.com/ee/ci/variables/predefined_variables.html -->
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CI_COMMIT_TAG)' != ''">$(CI_COMMIT_TAG)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CI_MERGE_REQUEST_IID)' != ''">pr$(CI_MERGE_REQUEST_IID)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CI_EXTERNAL_PULL_REQUEST_IID)' != ''">pr$(CI_EXTERNAL_PULL_REQUEST_IID)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CI_COMMIT_BRANCH)' != ''">$(CI_COMMIT_BRANCH)</RepositoryBranch>
<!-- Buddy: https://buddy.works/docs/pipelines/environment-variables#default-environment-variables -->
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(BUDDY_EXECUTION_PULL_REQUEST_NO)' != ''">pr$(BUDDY_EXECUTION_PULL_REQUEST_NO)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(BUDDY_EXECUTION_TAG)' != ''">$(BUDDY_EXECUTION_TAG)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(BUDDY_EXECUTION_BRANCH)' != ''">$(BUDDY_EXECUTION_BRANCH)</RepositoryBranch>
<!-- Jenkins: https://plugins.jenkins.io/git/#plugin-content-environment-variables -->
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(GIT_LOCAL_BRANCH)' != ''">$(GIT_LOCAL_BRANCH)</RepositoryBranch>
</PropertyGroup>

<!-- Make sure git info is available before calling source generators -->
<Target Name="InitializeGitInformation"
BeforeTargets="GenerateMSBuildEditorConfigFileShouldRun"
DependsOnTargets="InitializeSourceControlInformation">

<PropertyGroup Condition="'$(SourceControlInformationFeatureSupported)' == 'true'">
<!-- The project must specify PublishRepositoryUrl=true in order to publish the URL, in order to prevent inadvertent leak of internal URL. -->
<RepositoryUrl Condition="'$(RepositoryUrl)' == '' and '$(PublishRepositoryUrl)' == 'true'">$(PrivateRepositoryUrl)</RepositoryUrl>
</PropertyGroup>

<PropertyGroup Condition="'$(SourceRevisionId)' != ''">
<RepositoryCommit Condition="'$(RepositoryCommit)' == ''">$(SourceRevisionId)</RepositoryCommit>
<RepositorySha Condition="'$(RepositorySha)' == ''">$(SourceRevisionId.Substring(0, 9))</RepositorySha>
</PropertyGroup>

<!-- Add SourceRoot as a project property too -->
<ItemGroup>
<_ThisAssemblyGitSourceRoot Include="@(SourceRoot -> WithMetadataValue('SourceControl', 'git'))" />
</ItemGroup>

<PropertyGroup>
<RepositoryRoot>@(_ThisAssemblyGitSourceRoot)</RepositoryRoot>
</PropertyGroup>

</Target>

<Target Name="PrepareGitConstants"
BeforeTargets="PrepareConstants"
DependsOnTargets="InitializeGitInformation">
<ItemGroup>
<Constant Include="Branch" Value="$(RepositoryBranch)" Root="Git" />
<Constant Include="Commit" Value="$(RepositoryCommit)" Root="Git" />
<Constant Include="Sha" Value="$(RepositorySha)" Root="Git" />
<Constant Include="Root" Value="$(RepositoryRoot.Replace('\', '/'))" Root="Git" />
<Constant Include="Url" Value="$(RepositoryUrl)" Root="Git" />
</ItemGroup>
</Target>

</Project>
91 changes: 91 additions & 0 deletions src/ThisAssembly.Git/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<!-- #content -->
This package generates a static `ThisAssembly.Git` class with constants
for the following Git properties from the current project:

* Commit
* Sha (first 9 chars from Commit)
* Root (normalized to forward slashes)
* Url (if PublishRepositoryUrl=true)
* Branch (from CI environment variables)

This package relies on your project's Microsoft.SourceLink.* package
reference according to you specific Git-based source control server
(such as GitHub, Azure DevOps, BitBucket, etc). Explore the
[supported source control providers](https://www.nuget.org/packages?q=Microsoft.SourceLink).

The `Branch` property is populated from supported CI environment variables
for the currently supported CI systems: GitHub Actions, Azure DevOps,
AppVeyor, TeamCity, Travis CI, Circle CI, GitLab CI, Buddy, and Jenkins.

Whenever the CI system provides a pull request number, the branch name is
`pr[NUMBER]`, such as `pr123`. This makes it easy to use it as a semver
metadata label.

> NOTE: by default, the values of these constants are populated during
"real" builds (that is, not IDE/design-time builds used to populate
intellisense). This is to avoid negatively affecting the editor's
performance. This means, however, that the properties will seem to
always be empty when inspecting them in the IDE (although never at
run-time). If you want to force population of these values for
design-time builds, set the `EnableSourceControlManagerQueries` property to `true`.
This property is defined and documented by
[dotnet/sourcelink](https://github.com/dotnet/sourcelink/blob/main/src/SourceLink.Common/build/Microsoft.SourceLink.Common.props#L14).

At the MSBuild level, targets can take a dependency on the provided
`InitializeGitInformation` target, which sets the equivalent properties
named:

* RepositoryCommit
* RepositorySha
* RepositoryRoot
* RepositoryUrl
* RepositoryBranch

The names of these properties were chosen on purpose to match the
properties used by [nuget pack](https://learn.microsoft.com/en-us/nuget/reference/msbuild-targets#pack-target)
and [nugetizer](https://github.com/devlooped/nugetizer) to populate
the relevant package metadata.

So if you have a GitHub repository, installing these three packages
will ensure you have the proper metadata out of the box and the simplest
packaging experience possible:

```xml
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" />
<PackageReference Include="ThisAssembly.Git" />
<PackageReference Include="NuGetizer" />
</ItemGroup>
</Project>
```


<!-- #content -->

<!-- include https://github.com/devlooped/sponsors/raw/main/footer.md -->
# Sponsors

<!-- sponsors.md -->
[![Clarius Org](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/clarius.png "Clarius Org")](https://github.com/clarius)
[![Christian Findlay](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/MelbourneDeveloper.png "Christian Findlay")](https://github.com/MelbourneDeveloper)
[![C. Augusto Proiete](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/augustoproiete.png "C. Augusto Proiete")](https://github.com/augustoproiete)
[![Kirill Osenkov](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/KirillOsenkov.png "Kirill Osenkov")](https://github.com/KirillOsenkov)
[![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)
[![SandRock](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/sandrock.png "SandRock")](https://github.com/sandrock)
[![Eric C](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/eeseewy.png "Eric C")](https://github.com/eeseewy)
[![Andy Gocke](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/agocke.png "Andy Gocke")](https://github.com/agocke)


<!-- sponsors.md -->

[![Sponsor this project](https://raw.githubusercontent.com/devlooped/sponsors/main/sponsor.png "Sponsor this project")](https://github.com/sponsors/devlooped)
&nbsp;

[Learn more about GitHub Sponsors](https://github.com/sponsors)

<!-- https://github.com/devlooped/sponsors/raw/main/footer.md -->
9 changes: 8 additions & 1 deletion src/ThisAssembly.Tests/Tests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
using System.IO;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using Xunit;

[assembly: SuppressMessage("SponsorLink", "SL04")]

namespace ThisAssemblyTests
{
public class Tests
Expand Down Expand Up @@ -60,5 +63,9 @@ public void CanUseSameNameDifferentExtensions()
[Fact]
public void CanUseFileInvalidCharacters()
=> Assert.NotNull(ThisAssembly.Resources.webhook_data.Text);

[Fact]
public void CanUseGitConstants()
=> Assert.NotEmpty(ThisAssembly.Git.Commit);
}
}
1 change: 1 addition & 0 deletions src/ThisAssembly.Tests/ThisAssembly.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="all" />
<PackageReference Include="PolySharp" Version="1.12.1" PrivateAssets="All" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.3.1" Pack="false" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.1" />
Expand Down

0 comments on commit f495697

Please sign in to comment.