I have a C# project property called Version defined as
<Version Condition="$(Version)==''">1.2.3.4<Version>
1.2.3.4 is the default value.
I have a Team City system property, also called Version, set up to override. So in the custom run dialog in Team City, I can specify a value for Version and that value gets used. This works fine.
If I leave the parameter blank in Team City, however, the default value is still overwritten with blank (null?). If I delete the Team City parameter, the default value is used.
Is the condition incorrect? How can I set up the Team City property to be blank, and only override if I enter some value?
Updated answer after OP's comment:
From docs:
MSBuild allows you to set properties
from the command line using the
/property or /p command line switch.
Property values received from the
command line override property values
set in the project file and property
values inherited from environment
variables.
So you can just set a property $(VersionTC) in TeamCity configuration and check if that property is empty or not and set version
<Version>$(VersionTC)<Version>
<Version Condition="'$(VersionTC)'==''">1.2.3.4<Version>
( so you set Version to VersionTC first. Then see if it empty and set the default )
Have a look at this blog post explaining all this.
Try something like below:
<Version Condition=" '$(Version)'=='' ">1.2.3.4<Version>
Note the ' ' (single quotes) around $(Version)
Team City is probably still passing the parameter on the command line, just with a blank value, as in,
/p:Version=""
or something similar. The symptom you are seeing is due to how MSBuild deals with overridden properties. When specified on a command line, a property will take that value whether or not it is also declared in a static (global in the file, not inside a target) PropertyGroup declaration. So your declaration of Version, with the Condition being checked for teh empty string, is being skipped entirely.
One way around this is to move your PropertyGroup containing the declaration of $(Version), with its Condition, inside the target where it is first used. MSBuild will allow overwriting the value of a command line property from a "dynamic" property created at runtime from within a target.
If you run this command line...
> msbuild My.proj /t:Ver /p:Version=""
...and have this target...
<Target Name="Ver">
<PropertyGroup>
<Version Condition="'$(Version)' == ''">1.2.3.4<Version>
</PropertyGroup>
<Message Text="Version: '$(Version)'" />
</Target>
... you will get Version showing 1.2.3.4, whereas with the PropertyGroup outside the target, it will retain the empty value.
Related
As explained in JBoss EAP 7 documentation, one can pass in a properties file to the CLI instance with the --properties flag.
I'm trying to create a generic script for logging profiles.
This is my properties file:
profilename=myProfileName
filepath=/some/dir/somefile.log
And this is my script:
set profilename=${profilename}
set filepath=${filepath}
/profile=full-ha/subsystem=logging/logging-profile=$profilename:add
/profile=full-ha/subsystem=logging/logging-profile=$profilename/periodic-size-rotating-file-handler=myHandler:add(file={"relative-to" => "some.dir","path" => $filepath},suffix=.yyyy-MM-dd,max-backup-index=50,rotate-on-boot=true,rotate-size=20m)
The script doesn't generate any error and completes successfully, and the $profilename variable is correctly replaced by its value.
But the $filepath variable seems to be a problem:
<logging-profile name="myProfileName">
<periodic-size-rotating-file-handler name="myHandler" rotate-on-boot="true">
<file relative-to="some.dir" path="$filepath}"/>
<rotate-size value="20m"/>
<max-backup-index value="50"/>
<suffix value=".yyyy-MM-dd"/>
</periodic-size-rotating-file-handler>
</logging-profile>
What is the specific format to use so that a variable can be used for the path attribute?
Edit: tested with JBoss EAP 7.2, and now it works as expected, so I guess it was indeed a bug.
I know this is very late answer, but is the filepath variable last one in your list ?
Because this seems like a line ending issue if add new line at the end this would get picked up correctly.
I created a Log File class that uses NLog with the hopes of writing to multiple log files at the same time. This seems to work fine until I add variables to the mix.
Problem
Changing the variable seems to change that variable setting for all instances of the log file instead of the particular instance I am working with.
My Code
Here is how I have the programming structured:
LogClass - Basically a wrapper to give me some additional functionality. The 'SetVariable' is what I am using to set the particular variable (called dqwAlertName)
With this log class, I am passing in the specific logger that I want to use like this:
Public iLogger as new Logger(NLog.LogManager.GetLogger("dataQualityWatcher"),True)
That statement instantiates the logging class with the "dataQualityWatcher" logger and sets Debug=True (which I simply use to allow a more verbose logging that can be turned on and off).
With that said... The statement above is ALSO within another class object:
dataQualityWatcher Class - This is a 'watcher' that is called many times over and runs continuously. If you familiar with FileSystemWatcher, it works similarly to that. It basically watches data for a specific value and raises an event.
Inside THIS class is where I instantiate the logger as mentioned above with the following code:
Public iLogger as new Logger(NLog.LogManager.GetLogger("dataQualityWatcher"), True)
iLogger.SetVariable("dqwAlertName", _AlertName)
The first line instantiates, the second line will set the variable. The Logging Class SetVariable method is pretty basic:
Public Sub SetVariable(variableName as string, value as String)
'Set variable context for the logger
NLog.LogManager.Configuration.Variables(variableName) = value
End Sub
I am using that variable within the NLog.config file in the following manner:
<variable name="LogLayout" value="[${date:format=MM/dd/yyyy h\:mm\:ss.fff tt}] [${gdc:item=location}] | ${level} | ${message}" />
<variable name="InfoLayout" value="[${date:format=MM/dd/yyyy h\:mm\:ss.fff tt}] ${gdc:item=SoftwareName} Version ${gdc:item=SoftwareVersion} - ${message}" />
<variable name="DebugInfoLayout" value="[${date:format=MM/dd/yyyy h\:mm\:ss.fff tt}] ${message}" />
<variable name="logDir" value="C:/Log/PWTester/" />
<variable name="dqwAlertName" value="" />
<targets>
<target name="dataQualityWatcher" xsi:type="File" fileName="${logDir}/LogFiles/${var:dqwAlertName}-DataQualityWatcher.log" layout="${LogLayout}" />
</targets>
<rules>
<logger name="dataQualityWatcher" minlevel="Trace" writeTo="dataQualityWatcher" />
</rules>
THE PROBLEM:
I run multiple 'watchers' (as I call them) with the following code to create that object and assign properties:
dataWatch.Add(New dataQualityWatcher(True) With {.Tags = lstTags, .AlertTimerInterval = Convert.ToInt64(intTimerMilliseconds), .AlertGroupID = Convert.ToInt64(CARow(0)), .EmailGroupID = Convert.ToInt64(CARow(1)), .CustomSubject = CARow(3), .CustomMessage = CARow(4), .AlertName = DataAlertGroupName, .Debug = blnVerboseLogging, .HistorianServer = SH})
Multiple Version Example
I run the code above where: .AlertName = {"Test1", "Test2", "Test3"}. Other parameters would also change and a new object is instantiated each time. In this example there are 3 dataQualityWatcher objects instantiated, which also instantiates 3 Logger objects.
Each time a new dataQualityWatcher object is instanciated, it instanciates a Logger, which would then write to the file. The AlertName variable is passed on through the SetVariable method above.
I would expect 3 log files to be written:
Test1-DataQualityWatcher.log
Test2-DataQualityWatcher.log
Test3-DataQualityWatcher.log
This DOES happen. However, the last dataQualityWatch object that is created will run the SetVariable method = "Test3" (in this example). Now that variable is set and all 3 Loggers will begin logging to that file (i.e., Test3-DataQualityWatcher.log).
I can only assume that there is a better way to do this with variables such that they are for the life of that particular log instance, but I can't seem to figure it out!
Thanks in advance and sorry for the VERY, VERY long post.
As far as I understand your are trying to log to multiple files, with one target.
This won't work well with the use of variables as they are static (Shared in VB.net) - so this isn't threadsafe.
Other options to do this are:
Create multiple file targets in your nlog.config and setup the right <rules>, or
Pass extra properties for every message, and use event-properties: fileName="${logDir}/LogFiles/${event-properties:dqwAlertName}-DataQualityWatcher.log", VB.NET call:
Dim theEvent As New LogEventInfo(LogLevel.Debug, "", "Pass my custom value")
theEvent.Properties("MyValue") = "My custom string".
You could write a sub class for Logger to make it less verbose. Or
Create the targets & rules programmatically (in VB.NET). See tutorial (in C#)
If performance is very important, choose for 1 or 3.
I have the following within the Product Tag:
<Property Id="LICENSEKEY" Admin="yes" Hidden="no">
<RegistrySearch Id="RememberLicenseKey" Root="HKLM" Key="SOFTWARE\MyApp\key1\Settings" Name="LICENSEKEY" Type="raw"></RegistrySearch>
</Property>
<Condition Message="License key is required to proceed">LICENSEKEY AND NOT Installed</Condition>
What I want to do is pass the License key as a command line argument to msiexec, and then set it in the registry. If the key is not passed I want to cancel the installation. Therefore, this check only needs to be run at install time. However, the condition that I have added causes a popup both at install and uninstall time. Can't seem to figure out what I am doing wrong.
EDIT:
I tested with the following condition and it seems to show the message both on install and uninstall:
<Condition Message="License key is required to proceed">NOT Installed</Condition>
The Message for a Condition element will be displayed when the condition evaluates to false, meaning the condition was not met.
This is noted in the Message attribute description in the WiX Condition documentation:
Set the value to the text to display when the condition fails and the installation must be terminated.
To resolve this issue, the logical operators in the Condition just need to be changed to LICENSEKEY OR Installed
This is a late answer, but, hopefully, this will help any future visitors that find this question.
You may need to clarify your requirement. That WiX source does a search for the key, so does it need to be passed on command line or you'll cancel the install (as your post says), or can it be used if it's found in the registry by that registry search? Currently it appears that your registry search is overwriting anything you pass on the command line, including setting it to null, so check that with a verbose log.
Also, all the launch condition examples I've seen or used have a CDATA around the text of the actual condition - that may be part of the problem.
I'll assume you allow the key on the command line or in the registry. So your registry search should be for another property name, let's call it REGKEY, so it doesn't set your passed LICENSEKEY to null. Then you have a set property (type 51) custom action immediately after the search that sets LICENSEKEY to REGKEY with a condition of -Not LICENSEKEY- so it will set LICENSEKEY to REGKEY only if LICENSEKEY was not passed on the command line. So if you pass it on the command line it will be used, otherwise the registry one will be used. At that point, a condition of LICENSEKEY should work ok as a launch condition. Internally, the AppSearch that finds the registry item is typically immediately followed by the launch condition check in a WiX MSI, so you need to set LICENSEKEY before the launch condition check.
When I build my project, I can get ${BuildNumber} variable.
BuildNumber can be customized by "UpdateBuildNumber" activity. In this activity we can use ${BuildId} to formate ${BuildNumber}.
But how to get separately ${BuildId} variable?
If you're looking for the BuildNumber:
Use the BuildDetail's BuildNumber property when setting the BuildNumberFormat property of the UpdateBuildNumber build step.
In the example build XAML below, the BuildNumberFormat property is set to:
newBuildString + BuildDetail.BuildNumber
newBuildString is a variable, but could also be a string:
"v1.2.0." + BuildDetail.BuildNumber
If you're looking for the BuildID:
The TFS internal BuildID can be extracted from the URI for the build, as accessed from the IBuildDetail object (see above).
This can be accessed using the following code:
LinkingUtilities.DecodeUri(BuildDetail.Uri.ToString()).ToolSpecificId;
See: https://social.msdn.microsoft.com/Forums/vstudio/en-US/ab8140a2-a236-40d0-b146-dd8f6f4eb4ce/getting-buildid-value-in-a-tfs-2010-build-workflow-activity?forum=tfsbuild
I've defined an MSBuild activity in a TFS Workflow template, but currently I have to hard code the 'property' command line arguments directly into the template.
I'd like to be able to specify the arguments in the build definition, via the advanced setting, 'MSBuild Arguments'
I can see that I may have to build up the command line with string replace/concat, as mentioned here, but I can't see what I need to put, maybe something like this:
This is what the default MsBuild task uses:
String.Format("/p:SkipInvalidConfigurations=true {0}", MSBuildArguments)
You can change the MSBuildArguments variable in the build process template in multiple steps. For example, I added a Run Architecture Validation property to the process template and then edited the workflow to simply append /ValidateArchitecture=true to the MSBuildArguments before they're being passed to the MsBuild activity.
<If Condition="[PerformArchitectureValidation]" DisplayName="Configure Architecture Validation MSBuild Arguments">
<If.Then>
<Assign>
<Assign.To>
<OutArgument x:TypeArguments="x:String">[MSBuildArguments]</OutArgument>
</Assign.To>
<Assign.Value>
<InArgument x:TypeArguments="x:String">[MSBuildArguments + " /p:ValidateArchitecture=true"]</InArgument>
</Assign.Value>
</Assign>
</If.Then>
</If>
The PerformArchitectureValidation variable is defined as a Property on the Build Process Template level of type Boolean.
Update: Wrote a blogpost that explains this with steps and screenshots