Passing Itemgroup between msbuild project - visual-studio-2010

How can i pass an itemgroup between msbuild project using MSbuild task. I have an Msbuild task as given below
<Target Name ="test">
<MSBuild Projects="New.proj" Targets="mytarget"
Properties="Itemproperty=#(Item->'%(FullPath)')">
</MSBuild>
</Target>
Where 'Item' is the itemgroup.But iam getting an error as below.
error MSB4012: The expression "Itemproperty=#(Item->'%(FullPath)')" cannot be used in this context. Item lists cannot beconcatenated with other strings where an item list is expected. Use a semicolonto separate multiple item lists.
Thanks

Can you "flatten" it into a big long (single) string?
example:
<PropertyGroup>
<MySuperLongString>#(MyIncludeFiles->'"%(fullpath)"')</MySuperLongString>
</PropertyGroup>
Here are some more "options"
<Message Text="The below items are good when you need to feed command line tools, like the console NUnit exe. Quotes around the filenames help with paths that have spaces in them. "/>
<Message Text="I found this method initially from : http://pscross.com/Blog/post/2009/02/22/MSBuild-reminders.aspx Thanks Pscross! "/>
<Message Text=" "/>
<Message Text=" "/>
<Message Text="Flat list, each file surrounded by quotes, with semi colon delimiter: "/>
<Message Text=" #(MyIncludeFiles->'"%(fullpath)"')"/>
<Message Text=" "/>
<Message Text=" "/>
<Message Text="Flat list, each file surrounded by quotes, no comma (space delimiter): "/>
<Message Text=" #(MyIncludeFiles->'"%(fullpath)"' , ' ')"/>
<Message Text=" "/>
<Message Text=" "/>
<Message Text="Flat list, each file surrounded by quotes, with comma delimiter: "/>
<Message Text=" #(MyIncludeFiles->'"%(fullpath)"' , ',')"/>
<Message Text=" "/>
<Message Text=" "/>
<Message Text="List of files using special characters (carriage return)"/>
<Message Text="#(MyIncludeFiles->'"%(fullpath)"' , '%0D%0A')"/>
<Message Text=" "/>
<Message Text=" "/>
Full example below:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="AllTargetsWrapper" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="AllTargetsWrapper">
<CallTarget Targets="FunWithFilesTask" />
</Target>
<PropertyGroup>
<WorkingCheckout>.</WorkingCheckout>
</PropertyGroup>
<!-- ===================================================== -->
<!--
See:
http://msdn.microsoft.com/en-us/library/ms164313.aspx
*Identity Value for the item specified in the Include attribute.
*Filename Filename for this item, not including the extension.
*Extension File extension for this item.
*FullPath Full path of this item including the filename.
*RelativeDir Path to this item relative to the current working directory.
*RootDir Root directory to which this item belongs.
RecursiveDir Used for items that were created using wildcards. This would be the directory that replaces the wildcard(s) statements that determine the directory.
*Directory The directory of this item.
AccessedTime Last time this item was accessed.
CreatedTime Time the item was created.
ModifiedTime Time this item was modified.
-->
<Target Name="FunWithFilesTask">
<ItemGroup>
<MyExcludeFiles Include="$(WorkingCheckout)\**\*.doesnotexist" />
</ItemGroup>
<ItemGroup>
<MyIncludeFiles Include="$(WorkingCheckout)\**\*.*" Exclude="#(MyExcludeFiles)" />
</ItemGroup>
<PropertyGroup>
<MySuperLongString>#(MyIncludeFiles->'"%(fullpath)"')</MySuperLongString>
</PropertyGroup>
<Message Text="MySuperLongString=$(MySuperLongString)"/>
<Message Text=" "/>
<Message Text=" "/>
<Message Text="The below items are good when you need to feed command line tools, like the console NUnit exe. Quotes around the filenames help with paths that have spaces in them. "/>
<Message Text="I found this method initially from : http://pscross.com/Blog/post/2009/02/22/MSBuild-reminders.aspx Thanks Pscross! "/>
<Message Text=" "/>
<Message Text=" "/>
<Message Text="Flat list, each file surrounded by quotes, with semi colon delimiter: "/>
<Message Text=" #(MyIncludeFiles->'"%(fullpath)"')"/>
<Message Text=" "/>
<Message Text=" "/>
<Message Text="Flat list, each file surrounded by quotes, no comma (space delimiter): "/>
<Message Text=" #(MyIncludeFiles->'"%(fullpath)"' , ' ')"/>
<Message Text=" "/>
<Message Text=" "/>
<Message Text="Flat list, each file surrounded by quotes, with comma delimiter: "/>
<Message Text=" #(MyIncludeFiles->'"%(fullpath)"' , ',')"/>
<Message Text=" "/>
<Message Text=" "/>
<Message Text="List of files using special characters (carriage return)"/>
<Message Text="#(MyIncludeFiles->'"%(fullpath)"' , '%0D%0A')"/>
<Message Text=" "/>
<Message Text=" "/>
</Target>
</Project>

Related

How to display Text on MSBuild only when ItemGroup Count > 0?

I have following Target:
<Target Name="RemoveUnusedCopiedfiles" AfterTargets="CopyFilesToOutputDirectory" Condition="'$(Configuration)' == 'Release'">
<ItemGroup>
<FileToDelete Include="#(_SourceItemsToCopyToOutputDirectory -> '$(TargetDir)\%(FileName)%(Extension)')" Condition="%(Extension) == '.pdb' OR %(Extension) == '.xml'"/>
</ItemGroup>
<Delete Files="#(FileToDelete)"/>
<Message Text="Deleted Files #(FileToDelete -> '%(FullPath)', ', ')"
Importance="high"/> // Problem Here I need only show Deleted Files if FileToDelete.Count > 0
<!-- Remove other unused files -->
<Delete Files="$(MSBuildProjectDirectory)\$(MSBuildProjectName).nuspec"/>
</Target>
I don't know exactly how to make above <Message> only appeard if FileToDelete variable Count > 0? How to do that in MSBuild?
I always get this line: Image are here
Is there something in MSBuild collection value: i.e: Condition = "#(FileToDelete.Count > 0)"
You can check it like this:
<Message Text="Deleted Files #(FileToDelete -> '%(FullPath)', ', ')"
Importance="high" Condition="'#(FileToDelete)' != ''"/>
The #(...), in a "string context", will expand to the items, delimited by a semicolon. Or an empty string, if the ItemGroup is empty.

How can I get next Git commit by date?

In a script (msbuild) on a windows machine, I have the SHA1 of a commit.
What is the correct git command, to get the "next" (by date) commit SHA1 in the same branch?
Take a look at this example log from TortoiseGit:
In my script I currently have the 4b60a7e87762f421ddeee4ea0282a99c5db20e4a. Now I need a command to get c0fb4c86c354cfe32c6d0f1753958ab60db7e086.
I ended up writing a Custom MSBuild-Task which finds the predecessor. I post it in case it might come in handy for someone else.
Based on the comments of joanis I ended up looking in the git log for the next commit. So in my msbuild-script I now have a target which finds the next git commit and executes a specific target TargetToExecuteForNextGitCommit and sets the property CurrentCommitHash to the hash value of the next git commit. So this looks like:
<Target Name="DoTargetForNextGitCommit">
<!-- 6. Nachfolger vom aktuellen Commit finden -->
<!-- 6.a Tag des aktuellen Commits finden. Damit die Anzahl der zu durchsuchenden Commits einschränken.
Denn ich suche ja nur nach Commits, die danach kamen. -->
<Exec Command="git log --format=%25%25cd --date=iso-strict -n 1 $(CurrentCommitHash)"
WorkingDirectory="$(GitRepoDir)"
ConsoleToMSBuild="true">
<Output TaskParameter="ConsoleOutput" PropertyName="GitCommitTimestamp"/>
</Exec>
<Message Text="Commit-Zeitstempel: $(GitCommitTimestamp)"/>
<!-- 6.b Git-Log holen, in eine ItemGroup packen, den Index des Elements finden, das meinen Hash hat
und dann den Nachfolger holen und dessen hash finden -->
<!-- 6.b.i Git-Log holen -->
<Exec Command="git log --date-order --format=%25%25H --after=$(GitCommitTimestamp) origin/master"
WorkingDirectory="$(GitRepoDir)"
ConsoleToMSBuild="true">
<Output TaskParameter="ConsoleOutput" PropertyName="GitCommitHashesAfterCommitDay"/>
</Exec>
<ItemGroup>
<GitCommitHashesAfterCommitDayEntries Include="$(GitCommitHashesAfterCommitDay)"/>
</ItemGroup>
<!-- 6.b.ii Nachfolger holen-->
<GetNextCommit Items="#(GitCommitHashesAfterCommitDayEntries)" CurrentCommitHash="$(CurrentCommitHash)">
<Output TaskParameter="NextCommitHash" PropertyName="NextCommitHashProperty"/>
</GetNextCommit>
<Message Text="Nächster Commit: $(NextCommitHashProperty)" />
<!-- 7. Wenn es einen Nachfolger gibt, dann beginne mit diesem wieder bei 1. -->
<MSBuild Projects="$(MSBuildThisFile)"
Targets="$(TargetToExecuteForNextGitCommit)"
Properties="CurrentCommitHash=$(NextCommitHashProperty)"
Condition=" '$(NextCommitHashProperty)' != '0' "/>
</Target>
<UsingTask TaskName="GetNextCommit" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v12.0.dll">
<ParameterGroup>
<Items ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
<CurrentCommitHash ParameterType="System.String" Required="true" />
<NextCommitHash ParameterType="System.String" Output="true" Required="false" />
</ParameterGroup>
<Task>
<Using Namespace="System.Linq"/>
<Code Type="Fragment" Language="cs">
<![CDATA[
var hashes = Items.Select(i => i.ItemSpec).ToList();
var currentCommitIndex = hashes.IndexOf(CurrentCommitHash);
if (currentCommitIndex < 1)
{
NextCommitHash = "0";
}
else
{
var nextCommitIndex = currentCommitIndex - 1;
NextCommitHash = hashes[nextCommitIndex];
}]]>
</Code>
</Task>
</UsingTask>

Need to finding overlapping dates in XML code

I need help finding the overlapping dates in this XML code. I need to make sure that the End date is not less than or equal to the proceeding Start Date.
<Inventory>
<StatusApplicationControl Start="2019-07-18" End="2019-07-18" InvTypeCode="STDX" />
<InvCounts>
<InvCount CountType="2" Count="9" />
</InvCounts>
</Inventory>
<Inventory>
<StatusApplicationControl Start="2019-07-18" End="2019-07-19" InvTypeCode="STDX" />
<InvCounts>
<InvCount CountType="2" Count="8" />
</InvCounts>
</Inventory>
I have tried the following code.
<rule context="Inventory">
<report test="translate(StatusApplicationControl/#Start, '-', '') <= translate(preceding::Inventory/preceding::StatusApplicationControl/#End, '-', '')">The #Start="<value-of select="#Start"/>" and #End="<value-of select="#End"/>" dates are overlaping</report>
</rule>
I expect this message to be printed -
The Start="2019-07-18" is less than or equal to the End="2019-07-18" date
Any help is greatly appreciated!
It looks like the comments are not helping you.
The rule should be:
<rule context="Inventory">
<report
test="translate(StatusApplicationControl/#Start, '-', '')
<=translate(preceding::Inventory[1]/StatusApplicationControl/#End,'-','')"
>The #Start="<value-of select="#Start"/>" and #End="<value-of
select="preceding::Inventory[1]/StatusApplicationControl/#End"
/>" dates are overlaping</report>
</rule>
EDIT
This Schematron
<schema xmlns="http://purl.oclc.org/dsdl/schematron">
<pattern>
<title>Test dates</title>
<rule context="Inventory">
<assert
test="translate(StatusApplicationControl/#Start, '-', '')
> translate(preceding::Inventory[1]/StatusApplicationControl/#End,'-','')"
>The #Start="<value-of
select="StatusApplicationControl/#Start"
/>" and #End="<value-of
select="preceding::Inventory[1]/StatusApplicationControl/#End"
/>" dates are overlaping</assert>
</rule>
</pattern>
</schema>
With this input:
<root>
<Inventory>
<StatusApplicationControl Start="2019-07-18" End="2019-07-18" InvTypeCode="STDX" />
<InvCounts>
<InvCount CountType="2" Count="9" />
</InvCounts>
</Inventory>
<Inventory>
<StatusApplicationControl Start="2019-07-18" End="2019-07-19" InvTypeCode="STDX" />
<InvCounts>
<InvCount CountType="2" Count="8" />
</InvCounts>
</Inventory>
</root>
Output:
Pattern 'Test dates' Failed : The #Start="2019-07-18" and #End="2019-07-18" dates are overlaping.
Check in https://www.liquid-technologies.com/online-schematron-validator
Here is the SchemaTron rule that worked for me. The issue was passing preceding:: to the translate() function. When doing that I got a SchemaTron Exception.
<rule context="Inventory/StatusApplicationControl">
<report test="translate(#Start, '-', '') <= preceding::StatusApplicationControl/translate(#End, '-', '') ">The #Start="<value-of select="#Start"/>" and #End="<value-of select="#End"/>" dates are overlaping</report>
</rule>

Is there a bug in the Advanced Find in MS CRM 2015 online, when in recursive queries? Example: Find Account Branches that belong to Account Branches

No matter what I have tried, I was unsuccessful in getting the Advanced Find feature of MS CRM 2015 online to show me Active Accounts that are of type Branch that have as their parent have an Account type again of Branch.
I have checked and re-checked the data but perhaps there is something wrong with my query in the Advanced Find feature.
Or there is a bug to it.
I have run this query in SQL as well, we have a BigData db that holds our CRM data and there it reveals the correct results (of course).
Here is my query so that you can see:
--BRANCH OF A BRANCH
select [dbo].[fn_getDescFromCRMguid](a.[Parentaccountid]) as [ParentAccountName],
--[fn_getDescFromCRMguid] udf is just a look-up for descriptions and names
( select left(a3.[etf_accountlevel],6)
from [Stg_CRMAccount] a3
where a3.[accountid] = left(a.[parentaccountid],36)
) as [ParentAccountLevel],
[dbo].[fn_getDescFromCRMguid](isnull(a.[owninguser], a.[owningteam])) as [OwningEntity],
a.*
from [Stg_CRMAccount] a
where a.[statuscode] = 'Active::1'
and a.[etf_accountlevel] like 'Branch%'
and a.[Parentaccountid] is not null
and exists (
select 0
from [Stg_CRMAccount] a2
where a2.[statuscode] = 'Active::1'
and a2.[etf_accountlevel] like 'Branch%'
and left(a.[Parentaccountid],36) = a2.[accountid]
)
order by a.[Parentaccountid],
a.[name],
a.[address1_city];
I am also attaching the screenshot of my Advanced Find query and please feel free to comment or let me know of any useful thoughts.
I hope some person has any idea about this because to me it is puzzling.
I have navigated into the resulting Accounts from this and then into their parent Account and it was not a Branch.
Despite the clear (at least to me) specification of the Where clause under the use of the related Entity - Account, using the relation Parent Account.
The plot thickens even more, if you remove the Account Type = Branch for the related Entity and say change the Status = Active to Inactive then it will very correctly find and show only those Branches where their Parent is Inactive.
That leads me to suspect some kind of a recursive error with the query builder they are using.
It finds Account Type = Branch twice and erroneously does not differentiate between the first occurrence which is for the outer selection and the second occurrence which would be for the nested (in the Where clause) selection.
But all that is mere speculation.
I don't really know why it can't handle it.
It begs the question in what other scenarios it can mess up recursive query builds.
Your thoughts?
and here is my fetch XML from the Advanced Find query
<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="true">
<entity name="account">
<attribute name="etf_rating" />
<attribute name="parentaccountid" />
<attribute name="etf_lastcontact" />
<attribute name="etf_city" />
<attribute name="address1_line1" />
<attribute name="etf_accountlevel" />
<attribute name="name" />
<attribute name="ownerid" />
<attribute name="etf_segment" />
<attribute name="accountid" />
<order attribute="name" descending="false" />
<filter type="and">
<condition attribute="statecode" operator="eq" value="0" />
<condition attribute="etf_accountlevel" operator="eq" value="964850002" />
</filter>
<link-entity name="account" from="parentaccountid" to="accountid" alias="ag">
<filter type="and">
<condition attribute="statecode" operator="eq" value="0" />
<condition attribute="etf_accountlevel" operator="eq" value="964850002" />
</filter>
</link-entity>
</entity>
</fetch>

XPath-1.0: mark node where opposite node is missing

I try to write custom rule in sonar (plsql) by copy xpath rule. The task of this rule is to mark 'rollback to savepoint' statement where savepoint statement is missing.
For 2 savepoint and 3 rollback statements the AST (Abstract Syntax Tree) looks like:
<PROCEDURE_DEFINITION>
...
<SAVEPOINT>
<IDENTIFIER tokenValue="SAVEPOINT" />
<IDENTIFIER tokenValue="spA" />
<SEMICOLON tokenValue=";" />
</SAVEPOINT>
...
<SAVEPOINT>
<IDENTIFIER tokenValue="SAVEPOINT" />
<IDENTIFIER tokenValue="spB" />
<SEMICOLON tokenValue=";" />
</SAVEPOINT>
...
<ROLLBACK>
<IDENTIFIER tokenValue="ROLLBACK" />
<TO />
<IDENTIFIER tokenValue="SAVEPOINT" />
<IDENTIFIER tokenValue="spB" />
<SEMICOLON tokenValue=";" />
</ROLLBACK>
...
<ROLLBACK>
<IDENTIFIER tokenValue="ROLLBACK" />
<TO />
<IDENTIFIER tokenValue="SAVEPOINT" />
<IDENTIFIER tokenValue="spA" />
<SEMICOLON tokenValue=";" />
</ROLLBACK>
...
<ROLLBACK>
<IDENTIFIER tokenValue="ROLLBACK" />
<TO />
<IDENTIFIER tokenValue="SAVEPOINT" />
<IDENTIFIER tokenValue="spX" />
<SEMICOLON tokenValue=";" />
</ROLLBACK>
...
</PROCEDURE_DEFINITION>
I search for XPath query that marks last rollback because savepoint spX is missing.
But this xpath marks last both rollbacks
//PROCEDURE_DEFINITION//ROLLBACK[
IDENTIFIER[
#tokenValue =
./ancestor::PROCEDURE_DEFINITION
//SAVEPOINT/IDENTIFIER[2]/#tokenValue
]
]
Any suggestions?
EDIT:
I found this suboptimal solution:
//PROCEDURE_DEFINITION//ROLLBACK
[
not(
./IDENTIFIER[3]/#tokenValue =
ancestor::PROCEDURE_DEFINITION//SAVEPOINT/IDENTIFIER[2]/#tokenValue
)
]
PLSQL is case insensitive. But when i add translate function, i get marked first and last ROLLBACK node. I think all rollback's names will agreed with first savepoint's name?
First of all, according to the AST you show, it seems to me that this is the PL/SQL code you want to run your XPath query on:
DECLARE
PROCEDURE foo AS
BEGIN
SAVEPOINT spA;
SAVEPOINT spB;
ROLLBACK spB; -- Compliant
ROLLBACK spA; -- Compliant
ROLLBACK spX; -- Non-Compliant
END;
BEGIN
NULL;
END;
/
When I run your first XPath query using the SSLR PL/SQL Toolkit, the rollbacks to 'spB' and 'spA' are selected, but not the one to 'spX'.
Your second XPath query selects all of them.
It seems to me that you only want to select the one to 'spX', as there is no corresponding savepoint.
A trivial change to your first query allows to reverse the selected nodes, by negating the condition using not():
//PROCEDURE_DEFINITION//ROLLBACK[
not(IDENTIFIER[
#tokenValue =
./ancestor::PROCEDURE_DEFINITION
//SAVEPOINT/IDENTIFIER[2]/#tokenValue
])
]
But I would actually recommend that you drop the PROCEDURE_DEFINITION part of the query, as SAVEPOINT and ROLLBACK statements are also valid within functions or anonymous blocks:
//ROLLBACK[not(IDENTIFIER[#tokenValue = //SAVEPOINT/IDENTIFIER[2]/#tokenValue])]

Resources