Skip to content

Support ItemDefinitionGroup in Choose/When#7979

Merged
Forgind merged 4 commits intomainfrom
v-jennybai/FixIssue#5436
Oct 7, 2022
Merged

Support ItemDefinitionGroup in Choose/When#7979
Forgind merged 4 commits intomainfrom
v-jennybai/FixIssue#5436

Conversation

@JaynieBai
Copy link
Member

@JaynieBai JaynieBai commented Sep 16, 2022

Fixes #5436

Context

Changes Made

There is a significant error in the original Constuctor ProjectItemDefinitionGroupElement(XmlElement xmlElement, ProjectRootElement parent, ProjectRootElement containingProject). The second parameter and third parameter types are the same. Fix the constructor bug and parse ItemDefinationGroup in when and otherwise.

Testing

Add one test SupportItemDefinationGroupInWhenOtherwise()

Notes

@dnfadmin
Copy link

dnfadmin commented Sep 16, 2022

CLA assistant check
All CLA requirements met.

@danmoseley
Copy link
Member

Hello, assuming the repo owners would like to take this change, they will ask for unit test coverage too.

MockLogger ml = ObjectModelHelpers.BuildProjectExpectSuccess(@"
<Project ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
<Choose>
<When Condition=` '$(OutputType)'=='Library' `>
Copy link
Member

Choose a reason for hiding this comment

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

I would expect tests that
-verify that the IDG works, and isn't ignored
-verify that multiple IDG are supported and they are processed top to bottom
-this for multiple When, as well as Otherwise

Copy link
Contributor

Choose a reason for hiding this comment

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

I think testing the same way as ItemGroup might cover all the scenarios. That could be a start.

Copy link
Member

Choose a reason for hiding this comment

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

Also put in some PropertyGroup and ItemGroup in there. Everything is evaluated in passes -- normally, all properties, then all IDG, then all items. each pass can "see" the previous, even if the elements were "lower" in the project file. So if there are PG and IG in here, whatever the ordering, the IG should see the IDG.

This comment is now wrong:

/// We enter here in both the property and item passes, since Chooses can contain both.

it's certainly important to verify that the IDG are "working" inside Choose.

Copy link
Member Author

Choose a reason for hiding this comment

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

@danmoseley Should we add PropertyGroup and ItemGroup in the project definition, and verify the itemdefinitiongroup works there in the test?

Copy link
Member Author

Choose a reason for hiding this comment

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

/// We enter here in both the property and item passes, since Chooses can contain both.

Will remove this line or update to "We enter here in the property, itemDefinition, and item passes, since Chooses can contain all of them" ?

Copy link
Member

Choose a reason for hiding this comment

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

@danmoseley Should we add PropertyGroup and ItemGroup in the project definition, and verify the itemdefinitiongroup works there in the test?

Sorry I'm not sure what you mean. Yes, I would expect tests that verify the IDG work, including consuming property expressions

Copy link
Contributor

@Forgind Forgind Sep 20, 2022

Choose a reason for hiding this comment

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

There's some confusion here, so I'll just lay out roughly what I'd want the test to look like:
Project
Choose
When
ItemGroup
ItemDefinitionGroup
PropertyGroup
Otherwise
ItemDefinitionGroup
PropertyGroup
ItemGroup

For each ItemDefinitionGroup, PropertyGroup, and ItemGroup, there should be things actually defined in it, so like for a PropertyGroup:

<PropertyGroup>
<Foo>bar</Foo>
</PropertyGroup

That's important because you can have something that parses without throwing an error but doesn't actually work, and you want to verify that it works.

So then you also want to make sure each of the Property/Item/ItemDefinitionGroups that you'd expected to execute actually did execute. It would be good to do that for both the When and the Otherwise case, so a Theory with one case for each would be appropriate here.

Is that clearer? (And I'm guessing that hits what you wanted, right danmoseley?)

Copy link
Member Author

Choose a reason for hiding this comment

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

@danmoseley I have updated the test case, please have a look. Any suggestions, please let me know. Thank you.

Copy link
Contributor

Choose a reason for hiding this comment

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

This looks much closer to what I'd expect, but the When and Otherwise conditions are currently identical. That means we don't know if it's following the When, Otherwise, or both. It would be good to disentangle those.

Copy link
Member Author

Choose a reason for hiding this comment

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

Add one condition to distinguish when it is following when or otherwise

/// Initialize a parented ProjectItemDefinitionGroupElement
/// </summary>
internal ProjectItemDefinitionGroupElement(XmlElement xmlElement, ProjectRootElement parent, ProjectRootElement containingProject)
internal ProjectItemDefinitionGroupElement(XmlElement xmlElement, ProjectElementContainer parent, ProjectRootElement containingProject)
Copy link
Contributor

Choose a reason for hiding this comment

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

We should probably add a check to make sure the parent isn't a Target, since we still reject ItemDefinitionGroups under targets.

Copy link
Member Author

Choose a reason for hiding this comment

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

In the function ParseProjectTargetElement,there is

case XMakeElements.itemDefinitionGroup:
ProjectErrorUtilities.ThrowInvalidProject(childElement.Location, "ItemDefinitionGroupNotLegalInsideTarget", childElement.Name);
break;
, before to call the Itemdefinationgroup constructor, the error "MSB4163: is not allowed inside a target" has been thrown when parse the child item under the target element.

{
var projectContent = $@"
<Project ToolsVersion= `msbuilddefaulttoolsversion` xmlns= `msbuildnamespace`>
<Choose>
Copy link
Contributor

@Nirmal4G Nirmal4G Sep 27, 2022

Choose a reason for hiding this comment

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

This might be out of topic but the only child element that doesn't support Condition attribute is Choose. Is it on purpose? I find myself, on some occasions, needing to add a conditional attribute to the Choose element itself.

If I don't have that option, the code kinda becomes error prone and cumbersome.

For Example

<Choose Condition="'$(RootCheck)' == 'true'">
  <When Condition="'$(ActualCheck)' == 'value1'">
  </When>
  <When Condition="'$(ActualCheck)' == 'value2'">
  </When>
  <Otherwise>
  </Otherwise>
</Choose>

is better, less repetitive and less error prone than the following...

<Choose>
  <When Condition="'$(RootCheck)' == 'true' AND '$(ActualCheck)' == 'value1'">
  </When>
  <When Condition="'$(RootCheck)' == 'true' AND '$(ActualCheck)' == 'value2'">
  </When>
  <Otherwise Condition="'$(RootCheck)' == 'true'">
  </Otherwise>
</Choose>

Copy link
Member Author

Choose a reason for hiding this comment

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

This test is for the ItemDefinitionGroup supported under choose/when and choose/otherwise, and not for the choose when or otherwise condition expression testing. So, didn't add condition expression for the Choose.

Copy link
Member

Choose a reason for hiding this comment

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

only child element that doesn't support Condition attribute is Choose. Is it on purpose?

Reaching back over 15 years .. no particular reason, it just didn't occur to anyone. I don't see why it couldn't be added if they want it.

Copy link
Member Author

Choose a reason for hiding this comment

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

only child element that doesn't support Condition attribute is Choose. Is it on purpose?

This should be on purpose from this test case

/// <summary>
/// Read choose with unexpected Condition attribute.
/// Condition is not currently allowed on Choose.
/// </summary>
[Fact]
public void ReadInvalidConditionAttribute()
{
Assert.Throws<InvalidProjectFileException>(() =>
{
string content = @"
<Project>
<Choose Condition='true'/>
</Project>
";
ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));
}
);
}

Copy link
Contributor

Choose a reason for hiding this comment

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

@JaynieBai Nice Find... Thanks for looking it up.

Seems on purpose but WHY? Instead of supporting it, they made sure it didn't. Still, WHY? I'm puzzled.

I need this badly. Any chance that this can be allowed?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure either. @Forgind @rainersigwald Do you know anything about this?

Copy link
Member

Choose a reason for hiding this comment

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

I said why 🙂 I implemented it. It just didn't occur to me at the time that it would be useful. Today I see no reason why it can't be added.

Copy link
Contributor

@Nirmal4G Nirmal4G Sep 29, 2022

Choose a reason for hiding this comment

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

It just didn't occur to me at the time that it would be useful.

So, were you one of devs who worked on MSBuild? 😲 I thought you were just speaking for the team. Sorry If I misunderstood you. 😥

Today I see no reason why it can't be added.

Thank you!

Copy link
Member

Choose a reason for hiding this comment

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

Ha.. no problem. Yes, but I don't speak for the current team. I work on ASPNET now. My knowledge is historical.

Copy link
Contributor

Choose a reason for hiding this comment

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

@Nirmal4G, as far as I'm concerned, you're free to file a bug to add conditions as an option. My first impulse is that we'd treat it the same as ItemDefinitionGroups: if you want to implement it, and you do it properly, we can take it, but we aren't likely to prioritize it. But file the bug first so we can have an official team opinion.

Copy link
Contributor

@Forgind Forgind left a comment

Choose a reason for hiding this comment

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

Thanks for taking care of this!

var project = ObjectModelHelpers.CreateInMemoryProject(projectContent);

var projectItem = project.GetItems("A").FirstOrDefault();
Assert.Equal("bar", projectItem.EvaluatedInclude);
Copy link
Contributor

Choose a reason for hiding this comment

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

nit:
We're trying to use Shouldly for new tests, but I'm not blocking on that.

@Forgind Forgind added the merge-when-branch-open PRs that are approved, except that there is a problem that means we are not merging stuff right now. label Oct 3, 2022
@Forgind Forgind merged commit 06db703 into main Oct 7, 2022
@Forgind Forgind deleted the v-jennybai/FixIssue#5436 branch October 7, 2022 14:59
@Forgind
Copy link
Contributor

Forgind commented Oct 7, 2022

Thanks @JaynieBai!

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

Labels

merge-when-branch-open PRs that are approved, except that there is a problem that means we are not merging stuff right now.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support ItemDefinitionGroup in Choose/When

6 participants