How do you data drive task dependencies via properties in psake? - psake

In MSBuild you can data drive target dependencies by passing a item group into a target, like so:
<ItemGroup>
<FullBuildDependsOn Include="Package;CoreFinalize"
Condition="#(FullBuildDependsOn) == ''" />
</ItemGroup>
<Target Name="FullBuild"
DependsOnTargets="#(FullBuildDependsOn)" />
If you don't override the FullBuildDependsOn item group, the FullBuild target defaults to depending on the Package and CoreFinalize targets. However, you can override this by defining your own FullBuildDependsOn item group.
I'd like to do the same in psake - for example:
properties {
$FullBuildDependsOn = "Package", "CoreFinalize"
}
task default -depends FullBuild
# this won't work because $FullBuildDependsOn hasn't been defined yet - the "Task" function will see this as a null depends array
task FullBuild -depends $FullBuildDependsOn
What do I need to do to data drive the task dependencies in psake?

OK. I understand what you're trying to accomplish now. You can do this through regular PowerShell-fu.
$FullBuildDependsOn = "Package"
Invoke-psake buildScript.ps1
In buildScript.ps1:
if($FullBuildDependsOn -eq $Null) {
$FullBuildDependsOn = "Package", "CoreFinalize"
}
properties {
# Usual build properties here
}
task default -depends FullBuild
task FullBuild -depends $FullBuildDependsOn {}
task Package {}
task CoreFinalize {}
The key here is to use a normal PowerShell variable rather than using a psake property. HTH.

That's not a use-case that we ever considered when implementing psake. Changing FullBuild's list of dependencies seems a bit odd and unmaintainable to me. You can accomplish the same thing by passing in a list of tasks to run from the command line.
./invoke-psake buildScript.ps1 Package, CoreFinalize
Or am I missing something?

Related

How to update AssemblyVersion using Update Assembly Info plugin in VSTS?

I want to update the version number of my .exe file using Update Assembly Info plugin.
I am using the following configuration:
But, I keep getting an error
'$(Date:yyyy.MM.dd)$(Rev:.r)' is not a valid parameter for attribute 'AssemblyVersion'
The $(Date:yyyy.MM.dd) and $(Rev:.r) can’t be used as the build-in variable, it can be used in Build number format (Options tab).
The workaround is that:
Include $(Rev:.r) in Build number format, such as $(date:yyyyMMdd)$(rev:.r)
Add PowerShell task to add a new variable (Arguments: -bn $(Build.BuildNumber)
Script:
param(
[string]$bn
)
$d=Get-Date -Format "yyyyMMdd"
$r=$bn.split("{.}")[-1]
Write-Host "##vso[task.setvariable variable=currentVersion]$d$r"
Then use currentVersion variable in subsequent tasks, such as Update Assembly task.

How to replace variables of JSON file in Team Services?

I'm stuck with a release variable substitution of an angular project. I have a settings.json file which I would like to replace some variables:
{
test : "variable to replace"
}
I tried to find some custom task on the marketplace but all of the tasks seems to work only with xml files for the web.config.
I use the "Replace tokens" from the Marketplace https://marketplace.visualstudio.com/items?itemName=qetza.replacetokens
You define the desired values as variables in the Release Definition and then you add the Replace Tokens task and configure a wildcard path for all target text files in your repository where you want to replace values (for example: **/*.json). The token that gets replaced has configurable prefix and postfix (default are '#{' and '}#'). So if you have a variable named constr you can put in your config.json
{
"connectionstring": "#{constr}#"
}
and it will deploy the file like
{
"connectionstring": "server=localhost,user id=admin,password=secret"
}
The IIS Web App Deploy Task in VSTS Releases has JSON variable substitution under *File Transforms & Variable Substitution Options.
Provide a list of json files and JSONPath expressions for the variables that need replacing
For example, to replace the value of ‘ConnectionString’ in the sample below, you need to define a variable as ‘Data.DefaultConnection.ConnectionString’ in the build/release definition (or release definition’s environment).
{
  "Data": {
    "DefaultConnection": {
      "ConnectionString": "Server=(localdb)\SQLEXPRESS;Database=MyDB;Trusted_Connection=True"
    }
  }
}
You can add a variable in release variables Tab, and then use PowerShell task to update the content of your settings.json.
Assume the original content is
{
test : "old
}
And you want to change it to
{
test : "new"
}
So you can replace the variable in json file with below steps:
1. Add variable
Define a variable in release variable tab with the value you want to replace with (variable test with value new):
2. Add PowerShell task
Settings for powershell task:
Type: Inline Script.
Inline Script:
# System.DefaultWorkingDirectory is the path like C:\_work\r1\a, so you need specify where your appsettings.json is.
$path="$(System.DefaultWorkingDirectory)\buildName\drop\WebApplication1\src\WebApplication1\appsettings.json"
(Get-Content $path) -replace "old",$(test) | out-file $path

Pass content from build back into Visual Studio Team Services Build

I am running build on Azure with a custom build agent (using Unity3d to be precise) I generate output of the build within a .txt file on the build machine and would like to include content within work items created during build.
Example:
Unity build fails and an error is logged to Build.log.
New bug is created with reference to build and the error message from the
logfile
Right now I am using a powershell script
$content = [IO.File]::ReadAllText("$(Build.Repository.LocalPath)\BuildProjectPC\Build.log")
Write-Host "##vso[task.setvariable variable=logContent;]$content"
To format the bug i use System.Description = $logContent but the content of the variable from PS does for some reason not end up in the bug item (it just contains "$logContent").
Any idea or direction how to fix this, respectively how to feed info back into vsts?
The variable value that used for creating work item is initialized before running build steps, so you can’t specify a dynamic variable or change the variable value during the build step that used for creating work item.
You can follow up these steps to verify it:
Open your build definition > Variable > Add a new variable (e.g. logContent, value: oldValue)
Select Options > Check Work Item on Failure > Additional Fields > System.Title $(logContent)
Add PowerShell build step: Write-Host "$(logContent)"
Add PowerShell build step: Write-Host "##vso[task.setvariable variable=logContent;]newValue"
Add PowerShell build step: Write-Host "$(logContent)"
Add PowerShell build step: [Environment]::Exit(1)
The log result:
Step 3 output oldValue
Step 5 output newValue
The created work item title oldValue.
The workaround for your requirement is that, you can create a work item and associated to build through PowerShell with Rest API (add PowerShell step at the end of other steps and Check Always run option).
Associate work item to build:
Request Type: Patch
Request URL: https://[your vsts account].visualstudio.com/DefaultCollection/_apis/wit/workitems/[work item id]?api-version=1.0
Content-Type:application/json-patch+json
Body:
[
{
"op": "add",
"path": "/relations/-",
"value": {
"rel": "ArtifactLink",
"url": "vstfs:///Build/Build/[build id]",
"attributes": {
"comment": "Making a new link for the dependency"
}
}
}
]
You can refer to this blog for PowerShell scripts to create and associate work item.
Build association with work Items in vNext
In the Additional Fields you need to reference the build/release definition variable with the following notation: $(logContent)
as shown here below:

Can I dynamically create psake tasks?

Is it possible to dynamically create psake tasks based on configuration (much as rake does)? For example, given a hashtable of environments:
environments {
$dev = 'server1',
$uat= 'server2'
}
I'd like tasks deploy.db.dev, deploy.db.uat, deploy.app.dev, deploy.app.uat etc. where the appropriate server name is provided to the task template?
Thanks

Setting a Property Value in 1 task and use the updated value in another

In my psake build script, I have a property called $build_mode that I set to "Release".
I have 2 tasks; "Compile_Debug", "Compile_Release". In Compile_Debug, I change $build_mode to "Debug" and it works fine while that task executes; however, if I have a have another task execute that uses $build_mode afterwards, $build_mode is back to "Release".
Is there a way to globally change or set a variable in a Psake build script so that an updated value can be used between tasks?
(I'm trying to have 1 "test" or 1 "package" task instead of a "Test_Debug", etc.)
Code:
properties {
$build_mode = "Release"
}
task default -depends Compile_Debug, Test
task Compile_Debug {
$build_mode = "Debug"
# Compilation tasks here that use the Debug value
}
task Test {
# Test related tasks that depend on $build_mode being updated.
}
I usually set the build mode as #manojlds suggested, passing in as a paramenter in the Invoke-Psake call. But, if you find yourself again in a situation that you want to modify the value of a object in Task A and have access to the modified value in Task B, here is how to do it:
The fact that the modified value of $build_mode is not accessible in Task B is due to powershell scoping. When you set a value for the $buildMode variable in a Task A, that change is made within Task A's scope, therefore outside it the variable value keeps unchanged.
One way to achieve what you want is to use a hashtable scoped to the whole script to store your objects:
Code:
properties {
#initializes your global hash
$script:hash = #{}
$script:hash.build_mode = "Release"
}
task default -depends Compile_Debug, Test
task Compile_Debug {
$script:hash.build_mode = "Debug"
# Compilation tasks here that use the Debug value
}
task Test {
# Test related tasks that depend on $script:hash.build_mode being updated.
}
The only caveat is that every time you want to refer to your build mode you have to use the long $script:hash.build_mode name instead of simply $build_mode
Why don't you pass the build mode as parameter to the tasks from the Invoke-Psake?
Invoke-Psake "$PSScriptRoot\Deploy\Deploy.Tasks.ps1" `
-framework $conventions.framework `
-taskList $tasks `
-parameters #{
"build_mode" = "Debug"
}
And in the tasks you can now use $build_mode