Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for NBGV_ThisAssemblyNamespace property. #911

Merged
merged 1 commit into from
Mar 28, 2023
Merged

Add support for NBGV_ThisAssemblyNamespace property. #911

merged 1 commit into from
Mar 28, 2023

Conversation

alexrp
Copy link
Contributor

@alexrp alexrp commented Mar 20, 2023

Closes #555

@alexrp
Copy link
Contributor Author

alexrp commented Mar 20, 2023

@AArnott How do you feel about the approach here?

Also, how would you suggest I test this? I'm not really familiar with NBGV's test harness.

@KalleOlaviNiemitalo
Copy link

I wonder about ThisAssemblyNamespace being null vs. an empty string. If the AssemblyVersionInfo task is called from Nerdbank.GitVersioning.targets, then what do users set in MSBuild properties to distinguish between those cases?

@KalleOlaviNiemitalo
Copy link

Here it distinguishes null from "", but if ThisAssemblyNamespace is "", then I don't think the generated F# code will compile anyway:

this.generator.EmitNamespaceIfRequired(this.ThisAssemblyNamespace ?? this.RootNamespace ?? "AssemblyInfo");

Likewise C# here:

if (ns is not null)
{
this.CodeBuilder.AppendLine($"namespace {ns} {{");
}

I think those null checks should all be !IsNullOrEmpty(ns), or alternatively map "" to null before any CodeGenerator is called.

@AArnott
Copy link
Collaborator

AArnott commented Mar 20, 2023

@KalleOlaviNiemitalo MSBuild does not distinguish between null or an empty string as property values, nor an unset value vs. a value set to an empty string. An MSBuild task property that is set to an msbuild property will never be null, although I believe it will be null if the .targets file doesn't set the task property at all.

@KalleOlaviNiemitalo
Copy link

Well then the ?? operator in the F# case makes no sense at all.

@AArnott
Copy link
Collaborator

AArnott commented Mar 20, 2023

The PR looks ineffective for the other languages as well, since only F# emits a namespace. The other languages just no-op for the emit namespace instruction.

Copy link
Collaborator

@AArnott AArnott left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexrp you can add the tests to this file. Please test all the languages. There is already a test for each language, so leave those alone I suppose but duplicate them with your optional property set.
Please make sure the task works properly given task inputs that are set to the empty string (indicating the msbuild property is not set).

@alexrp
Copy link
Contributor Author

alexrp commented Mar 20, 2023

The PR looks ineffective for the other languages as well, since only F# emits a namespace. The other languages just no-op for the emit namespace instruction.

Not sure I follow here. There's code to emit namespaces for all of them. It's just that the F# case is handled specially in EmitNamespaceIfRequired().

@@ -119,7 +121,8 @@ public string BuildCode()
this.generator.AddBlankLine();
this.generator.AddAnalysisSuppressions();
this.generator.AddBlankLine();
this.generator.EmitNamespaceIfRequired(this.RootNamespace ?? "AssemblyInfo");
this.generator.EmitNamespaceIfRequired(this.ThisAssemblyNamespace ?? this.RootNamespace ?? "AssemblyInfo");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So is the conclusion that this should be changed to use string.IsNullOrEmpty() for both of these properties?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ya, that would probably be appropriate.

@AArnott
Copy link
Collaborator

AArnott commented Mar 20, 2023

There's code to emit namespaces for all of them.

No, I don't think so. The tests themselves prove that no namespace is emitted for C# or VB, but there is for F#. Issue #555 was originally filed because this class is always in the same global namespace for all projects.

@alexrp
Copy link
Contributor Author

alexrp commented Mar 20, 2023

The tests themselves prove that no namespace is emitted for C# or VB

But that's expected, right? The PR makes it so that, for C#/VB, a namespace is only emitted if the project explicitly sets NBGV_ThisAssemblyNamespace to some non-empty value. For F#, a namespace is indeed always emitted as was the case prior to the PR.

I could make it always emit a namespace, but I figured that might be a bad idea for compatibility reasons.

@AArnott
Copy link
Collaborator

AArnott commented Mar 20, 2023

Agreed, we don't want a namespace by default. But I'm pointing out that because we never wanted a namespace before, we never implemented emitting code for the namespace, except for F# which required it. If you look at EmitNamespaceIfRequired, it is only implemented for F#, and nowhere else is the namespace produced.
If I'm wrong, can you point me to the code that emits the namespace?

@alexrp
Copy link
Contributor Author

alexrp commented Mar 20, 2023

If I'm wrong, can you point me to the code that emits the namespace?

Here (and similarly for VB):

https://github.com/dotnet/Nerdbank.GitVersioning/pull/911/files#diff-784868d214d0f8f1823e743bdc0b7b56b4e899e08201e712ccb2bc9e35594977L756-R766

I put the code in those methods out of convenience since for C#/VB it requires opening and closing a namespace, unlike F#. (Also, I figured we shouldn't rely on file-scoped namespaces since people might be using older C# versions?) I could add a new pair of StartThisAssemblyNamespace/EndThisAssemblyNamespace methods if you think that'd be clearer.

@KalleOlaviNiemitalo
Copy link

people might be using older C# versions

Certainly are.

@AArnott
Copy link
Collaborator

AArnott commented Mar 20, 2023

I put the code in those methods out of convenience since for C#/VB

Ah, I missed that. I don't think we should have two separate methods for emitting namespaces.
Whether the class emitting method wraps with a namespace itself or we add before- and after- namespace methods, I don't have strong feelings. But let's just have one or the other. It's too confusing otherwise.
The One Way should probably include a parameter indicating whether the project wants the namespace emitted, so that F# can always do it and C#/VB can only do it if the caller wants it.

@KalleOlaviNiemitalo
Copy link

C# allows assembly attributes before namespace NS {}, but not within or after it.

For F# however, BuildCode calls EmitNamespaceIfRequired before GenerateAssemblyAttributes, i.e. the attributes come after the namespace declaration. Does F# allow attributes before the namespace? If not, that gets tricky to unify. It might be best to give the language-specific classes full control on the order of calls.

@AArnott
Copy link
Collaborator

AArnott commented Mar 20, 2023

Bummer. Ya to give the language-specific generator more freedom, let's just set a namespace property on the class, and the generator can pick it up when it wants to.

@alexrp
Copy link
Contributor Author

alexrp commented Mar 21, 2023

OK, here's take 2, now with tests.

@alexrp alexrp marked this pull request as ready for review March 21, 2023 04:58
Copy link
Collaborator

@AArnott AArnott left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks much better. Thank you. Just one small change please.

@AArnott AArnott added this to the v3.6 milestone Mar 28, 2023
@AArnott AArnott merged commit 6d30af4 into dotnet:main Mar 28, 2023
@AArnott
Copy link
Collaborator

AArnott commented Mar 28, 2023

Thanks again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow changing the name or namespace of ThisAssembly class
3 participants