Pass multiple parameters/arguments to target - cakebuild

I've got a target Release-Prepare taking the version as an argument:
var version = Argument("version", "1.0.0.0");
Task ("Release-Prepare")
.Does (() => {
// Compute the package version
var gitCommitHash = GitLogTip(projectDir).Sha;
var gitVersion = gitCommitHash?.Substring(0, 8) ?? "Unknown";
var currentDateTime = DateTime.UtcNow.ToString("yyyyMMddHHmmss");
var packageVersion = $"{version}-{gitVersion}-{currentDateTime}";
Information(packageVersion);
// Versions having to be modified in *.csproj
var versionXPath = "/Project/PropertyGroup/Version";
var assemblyVersionXPath = "/Project/PropertyGroup/AssemblyVersion";
var fileVersionXPath = "/Project/PropertyGroup/FileVersion";
// Set versions for all projects (excpet testing)
var projectFilePaths = GetFiles("./**/*.csproj");
foreach(var projectFilePath in projectFilePaths) {
if(projectFilePath.FullPath.Contains("Tests")){
// Do not version test projects
continue;
}
XmlPoke(projectFilePath, versionXPath, packageVersion);
XmlPoke(projectFilePath, assemblyVersionXPath, version);
XmlPoke(projectFilePath, fileVersionXPath, version);
}
});
Executing the target without parameters works fine:
PS E:\dev\Sppd.TeamTuner> powershell -ExecutionPolicy ByPass -File build.ps1 -script "e:\dev\Sppd.TeamTuner\build.cake" -target "Release-Prepare" -verbosity normal
Preparing to run build script...
Running build script...
========================================
Release-Prepare
========================================
1.0.0.0-af9d218d-20191125093743
Task Duration
--------------------------------------------------
Release-Prepare 00:00:02.3258569
--------------------------------------------------
Total: 00:00:02.3258569
But I can't figure out how to pass the target AND the version using a PowerShell command. I've tried:
powershell -ExecutionPolicy ByPass -File build.ps1 -script "e:\dev\Sppd.TeamTuner\build.cake" -target "Release-Prepare" -version="1.2.3.4" -verbosity normal -> Error: Argument value is not a valid boolean value.
powershell -ExecutionPolicy ByPass -File build.ps1 -script "e:\dev\Sppd.TeamTuner\build.cake" -ScriptArgs '--target=Release-Prepare','--version=1.3.1.2' -verbosity normal -> Error: The target 'Release-Prepare,--version=1.3.1.2' was not found.
I've tried all permutations of -ScriptArgs '--target=Release-Prepare','--version=1.3.1.2' I could think of (single dash, space/comma, single/double quotes. But everything I've tried resulted in cake intzerpreting as a single command.
How do ScriptArgs have to be specified to work for multiple parameters?

I am going to assume that you are using the latest bootstrapper file, which is available from here:
https://cakebuild.net/download/bootstrapper/windows
NOTE: If this is not the case, then the way that the arguments are parsed and sent to Cake might be different than what I am showing here.
You can download this using:
Invoke-WebRequest https://cakebuild.net/download/bootstrapper/windows -OutFile build.ps1
As mentioned here.
With that in place, let's use the following build.cake file:
///////////////////////////////////////////////////////////////////////////////
// ARGUMENTS
///////////////////////////////////////////////////////////////////////////////
var target = Argument("target", "Default");
var configuration = Argument("configuration", "Release");
var version = Argument("applicationVersion", "1.0.0.0");
///////////////////////////////////////////////////////////////////////////////
// SETUP / TEARDOWN
///////////////////////////////////////////////////////////////////////////////
Setup(ctx =>
{
// Executed BEFORE the first task.
Information("Running tasks...");
});
Teardown(ctx =>
{
// Executed AFTER the last task.
Information("Finished running tasks.");
});
///////////////////////////////////////////////////////////////////////////////
// TASKS
///////////////////////////////////////////////////////////////////////////////
Task("Default")
.Does(() => {
Information("Configuration: {0}", configuration);
Information("Target: {0}", target);
Information("Version: {0}", version);
});
Task("Release-Prepare")
.Does(() =>
{
Information("Configuration: {0}", configuration);
Information("Target: {0}", target);
Information("Version: {0}", version);
});
RunTarget(target);
If we run this with no arguments, we will get this as the output:
========================================
Default
========================================
Configuration: Release
Target: Default
Version: 1.0.0.0
However, if we run the following:
.\build.ps1 --target=Release-Prepare --configuration=Debug --applicationVersion=2.2.2.2
We will get:
========================================
Release-Prepare
========================================
Configuration: Debug
Target: Release-Prepare
Version: 2.2.2.2
One thing to mention compared to what you have...
The version argument is already one that is reserved by the Cake.exe directly, i.e. running:
cake.exe --version
Will output the version number of Cake itself. That is why I switched to using applicationVersion as the argument name, rather than version.

Related

Powershell script not working when included in Jenkins Pipeline Script

What I am trying to achieve with Powershell is as follows:
Increment the Build Number in the AssemblyInfo.cs file on the Build Server. My Script looks like below right now after over a 100 iterations of different variations I am still unable to get it to work. The script works well in the Powershell console but when included into the Jenkins Pipeline Script I get various errors that are proving hard to fix...
def getVersion (file) {
def result = powershell(script:"""Get-Content '${file}' |
Select-String '[0-9]+\\.[0-9]+\\.[0-9]+\\.' |
foreach-object{$_.Matches.Value}.${BUILD_NUMBER}""", returnStdout: true)
echo result
return result
}
...
powershell "(Get-Content ${files[0].path}).replace('[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+',
${getVersion(files[0].path)})) } | Set-Content ${files[0].path}"
...
How about a groovy approach (with Jenkins keywords) instead of PowerShell:
def updtaeAssemblyVersion() {
def files = findFiles(glob: '**/AssemblyInfo.cs')
files.each {
def content = readFile file: it.path
def modifedContent = content.repalceAll(/([0-9]+\\.[0-9]+\\.[0-9]+\\.)([0-9]+)/,"\$1${BUILD_NUMBER}")
writeFile file: it.path, text: modifedContent
}
}
It will read all relevant files and replace only the build section of the version for every occurrence that matches the version regex.

Error occurs when debugging rust program with vscode (windows only)

I am trying to debug the code below with vscode, but an error occurs.
Development environment
Microsoft Windows 10 Home 10.0.19042 Build 19042
rustc 1.49.0 (e1884a8e3 2020-12-29)
Vscode 1.54.3
CodeLLDB v1.6.1
// Cargo.toml
//[dependencies]
//datafusion = "3.0.0"
//arrow = "3.0.0"
//tokio = { version = "0.2", features = ["macros", "blocking", "rt-core", "rt-threaded", "sync"] }
use std::time::{Duration, Instant};
use arrow::util::pretty;
use datafusion::error::Result;
use datafusion::prelude::*;
/// This example demonstrates executing a simple query against an Arrow data source (CSV) and
/// fetching results
#[tokio::main]
async fn main() -> Result<()> {
println!("======== Start Program ========");
let start = Instant::now();
// let res_path = r"/root/workspace/project/hello_arrow/res/sample_01.csv";
// http://insideairbnb.com/get-the-data.html
// listing_id,id,date,reviewer_id,reviewer_name,comments
// Boston, Massachusetts, United States
let res_path = r"D:\workspace\vscode\arrow_rust\res\review.01.csv";
// create local execution context
let mut ctx = ExecutionContext::new();
// register csv file with the execution context
ctx.register_csv("datatable_01", res_path, CsvReadOptions::new())?;
// execute the query
let sql = "SELECT count(id) from datatable_01";
let df = ctx.sql(sql)?;
let results = df.collect().await?;
// print the results
pretty::print_batches(&results)?;
let duration = start.elapsed();
println!("Time elapsed in expensive_function() is: {:?}", duration);
println!("======== End Program ========");
Ok(())
}
Error Code
configuration: {
type: 'lldb',
request: 'launch',
name: 'Debug Window',
program: '${workspaceRoot}/target/debug/arrow_rust.exe',
args: [],
cwd: '${workspaceRoot}',
sourceLanguages: [ 'rust' ],
__configurationTarget: 5,
relativePathBase: 'd:\\workspace\\vscode\\arrow_rust'
}
Listening on port 8541
error: arrow_rust.exe :: Class 'arrow::datatypes::DataType' has a member '__0' of type 'alloc::vec::Vec<arrow::datatypes::Field>' which does not have a complete definition.
Debug adapter exit code=3221225620, signal=null.
The program runs normally. Debugging fine on Linux for the same code.
Is there any other way to debug on Windows?
I have the same problem.
Inspired by the link below, I have solved it.
https://github.com/vadimcn/vscode-lldb/issues/410#issuecomment-786791796
The reason is that I have installed NVIDIA Nsight.
As shown below, the msdia140.dll for Nsight has been loaded by codelldb.
Run PowerShell as administrator. Execute the command below to register the component. Then codelldb works.
regsvr32.exe C:\Users\【user name】\.vscode\extensions\vadimcn.vscode-lldb-1.6.8\lldb\bin\msdia140.dll
Update
For newer versions, the DLL has moved to another folder:
regsvr32.exe C:\Users\[user name]\.vscode\extensions\vadimcn.vscode-lldb-1.8.1\adapter\msdia140.dll

Cake Task output log to file

I have a set of Tasks inside a build.cake file and I would like to capture the log output from the console into a log file. I know it's possible to use the OnError() function to output errors to file but I would like to output everything to a log file, not just errors.
Below is an example of the build.cake file.
#load "SomeTask.cake"
#load "SomeOtherTask.cake"
var target = Argument("target", "Default");
var someTask = Task("SomeTask")
.Does(() =>
{
SomeMethodInsideSomeTask();
});
var someOtherTask = Task("SomeOtherTask")
.Does(() =>
{
SomeOtherMethodInsideSomeOtherTask();
});
Task("Default")
.IsDependentOn(someTask)
.IsDependentOn(someOtherTask);
RunTarget(target);
N.B. The Tasks are not running any sort of MSBuild commands so it's not possible to use MSBuildFileLogger.
How about pipe the stdout to a file i.e.
./build.ps1 > log.txt
Have you heard about tee ?
It reads standard input and writes it to both standard output and one or more files

How to get list of TFS builds running at the moment from command line?

I'm trying to automate the deployment process, and as part of it, I need to run my release build from command line. I can do it, using command like
.\TFSBuild start http://server-name:8080/tfs/project-collection project-name build-name priority:High /queue
It even returns some code for the queued build — Build queued. Queue position: 2, Queue ID: 11057.
What I don't know, is how to get info about currently running builds, or about the state of my running build from powershell command line? The final aim is to start publishing after that build completes.
I've already got all necessary powershell scripts to create the deployment package from the build results, zip it, copy to production and install there. All I need now — to know when my build succeedes.
This function will wait for a build with the Queue ID given by TFSBuild.exe:
function Wait-QueuedBuild {
param(
$QueueID
)
[void][Reflection.Assembly]::LoadWithPartialName('Microsoft.TeamFoundation.Build.Client')
[void][Reflection.Assembly]::LoadWithPartialName('Microsoft.TeamFoundation.Client')
$uri = [URI]"http://server-name:8080/tfs/project-collection"
$projectCollection = [Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory]::GetTeamProjectCollection($uri)
$buildServer = $projectCollection.GetService([Microsoft.TeamFoundation.Build.Client.IBuildServer])
$spec = $buildServer.CreateBuildQueueSpec('*','*')
do {
$build = $buildServer.QueryQueuedBuilds($spec).QueuedBuilds| where {$_.Id -eq $QueueID}
sleep 1
} while ($build)
}
You can get the id returned by TFSBuild.exe, then call the function.
$tfsBuild = .\TFSBuild start http://server-name:8080/tfs/project-collection project-name build-name priority:High /queue
Wait-QueuedBuild [regex]::Match($tfsBuild[-1],'Queue ID: (?<id>\d+)').Groups['id'].Value
Using the work by E.Hofman available here it is possible to write a C# console app that uses TFS SDK and reveals if any build agent is currently running as follows:
using System;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Client;
namespace ListAgentStatus
{
class Program
{
static void Main()
{
TfsTeamProjectCollection teamProjectCollection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri("http://TFSServer:8080"));
var buildServer = teamProjectCollection.GetService<IBuildServer>();
foreach (IBuildController controller in buildServer.QueryBuildControllers(true))
{
foreach (IBuildAgent agent in controller.Agents)
{
Console.WriteLine(agent.Name+" is "+agent.IsReserved);
}
}
}
}
}
The parameter .IsReserved is what toggles to 'True' during execution of a build.
I 'm sorry my powershell skills are not good enough for providing with a PS variant of the above. Please take a look here, where the work by bwerks might help you do that.
# load classes for execution
[Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Build.Client") | Out-Null
[Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Client") | Out-Null
# declare working variables
$Uri = New-Object System.Uri "http://example:8080/tfs"
# get reference to projection collection
$ProjectCollection = [Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory]::GetTeamProjectCollection($Uri)
# get reference to build server
$BuildServer = $ProjectCollection.GetService([Microsoft.TeamFoundation.Build.Client.IBuildServer])
# loop through the build servers
foreach($Controller in $BuildServer.QueryBuildControllers($true))
{
# loop through agents
foreach($BuildAgent in $Controller.Agents)
{
Write-Host "$($BuildAgent.Name) is $($BuildAgent.IsReserved)"
}
}

Get Tfs Shelveset file contents at the command prompt?

I'm interested in getting the contents of a shelveset at the command prompt. Now, you would think that a cmdlet such as Get-TfsShelveset, available in the TFS Power Tools, would do this. You might also think that "tf.exe shelvesets" would do this.
However, unless I've missed something, I'm appalled to report that neither of these is the case. Instead, each command requires you to give it a shelveset name, and then simply regurgitates a single line item for that shelveset, along with some metadata about the shelveset such as creationdate, displayname, etc. But as far as I can tell, no way to tell what's actually in the shelf.
This is especially heinous for Get-TfsShelveset, which has the ability to include an array of file descriptors along with the Shelveset object it returns. I even tried to get clever, thinking that I could harvest the file names from using -WhatIf with Restore-TfsShelveset, but sadly Restore-TfsShelveset doesn't implement -WhatIf.
Please, someone tell me I'm wrong about this!
tf status /shelveset:name
will list out the content of the named shelveset (you can also supplier an owner: see tf help status).
With the TFS PowerToy's PowerShell snapin:
Get-TfsPendingChange -Shelveset name
for the same information.
It is possible to construct a small command-line application that uses the TFS SDK, which returns the list of files contained in a given shelveset.
The sample below assumes knowledge of the Shelveset name & it's owner:
using System;
using System.IO;
using System.Collections.ObjectModel;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Framework.Common;
using Microsoft.TeamFoundation.Framework.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
namespace ShelvesetDetails
{
class Program
{
static void Main(string[] args)
{
Uri tfsUri = (args.Length < 1) ? new Uri("TFS_URI") : new Uri(args[0]);
TfsConfigurationServer configurationServer = TfsConfigurationServerFactory.GetConfigurationServer(tfsUri);
ReadOnlyCollection<CatalogNode> collectionNodes = configurationServer.CatalogNode.QueryChildren(
new[] { CatalogResourceTypes.ProjectCollection },
false, CatalogQueryOptions.None);
CatalogNode collectionNode = collectionNodes[0];
Guid collectionId = new Guid(collectionNode.Resource.Properties["InstanceId"]);
TfsTeamProjectCollection teamProjectCollection = configurationServer.GetTeamProjectCollection(collectionId);
var vcServer = teamProjectCollection.GetService<VersionControlServer>();
Shelveset[] shelves = vcServer.QueryShelvesets(
"SHELVESET_NAME", "SHELVESET_OWNER");
Shelveset shelveset = shelves[0];
PendingSet[] sets = vcServer.QueryShelvedChanges(shelveset);
foreach (PendingSet set in sets)
{
PendingChange[] changes = set.PendingChanges;
foreach (PendingChange change in changes)
{
Console.WriteLine(change.FileName);
}
}
}
}
}
Invoking this console app & catching the outcome during execution of the powershell should be possible.
Try:
tfpt review
/shelveset:shelvesetName;userName
You may also need to add on the server option so something like:
tfpt review /shelveset:Code Review;jim
/sever:company-source
I think this is what you are looking for.
This is what I ended up with, based on pentelif's code and the technique in the article at http://akutz.wordpress.com/2010/11/03/get-msi/ linked in my comment.
function Get-TfsShelvesetItems
{
[CmdletBinding()]
param
(
[string] $ShelvesetName = $(throw "-ShelvesetName must be specified."),
[string] $ShelvesetOwner = "$env:USERDOMAIN\$env:USERNAME",
[string] $ServerUri = $(throw "-ServerUri must be specified."),
[string] $Collection = $(throw "-Collection must be specified.")
)
$getShelvesetItemsClassDefinition = #'
public IEnumerable<PendingChange> GetShelvesetItems(string shelvesetName, string shelvesetOwner, string tfsUriString, string tfsCollectionName)
{
Uri tfsUri = new Uri(tfsUriString);
TfsConfigurationServer configurationServer = TfsConfigurationServerFactory.GetConfigurationServer(tfsUri);
ReadOnlyCollection<CatalogNode> collectionNodes = configurationServer.CatalogNode.QueryChildren( new[] { CatalogResourceTypes.ProjectCollection }, false, CatalogQueryOptions.None);
CatalogNode collectionNode = collectionNodes.Where(node => node.Resource.DisplayName == tfsCollectionName).SingleOrDefault();
Guid collectionId = new Guid(collectionNode.Resource.Properties["InstanceId"]);
TfsTeamProjectCollection teamProjectCollection = configurationServer.GetTeamProjectCollection(collectionId);
var vcServer = teamProjectCollection.GetService<VersionControlServer>();
var changes = new List<PendingChange>();
foreach (Shelveset shelveset in vcServer.QueryShelvesets(shelvesetName, shelvesetOwner))
{
foreach (PendingSet set in vcServer.QueryShelvedChanges(shelveset))
{
foreach ( PendingChange change in set.PendingChanges )
{
changes.Add(change);
}
}
}
return changes.Count == 0 ? null : changes;
}
'#;
$getShelvesetItemsType = Add-Type `
-MemberDefinition $getShelvesetItemsClassDefinition `
-Name "ShelvesetItemsAPI" `
-Namespace "PowerShellTfs" `
-Language CSharpVersion3 `
-UsingNamespace System.IO, `
System.Linq, `
System.Collections.ObjectModel, `
System.Collections.Generic, `
Microsoft.TeamFoundation.Client, `
Microsoft.TeamFoundation.Framework.Client, `
Microsoft.TeamFoundation.Framework.Common, `
Microsoft.TeamFoundation.VersionControl.Client `
-ReferencedAssemblies "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0\Microsoft.TeamFoundation.Client.dll", `
"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0\Microsoft.TeamFoundation.Common.dll", `
"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0\Microsoft.TeamFoundation.VersionControl.Client.dll" `
-PassThru;
# Initialize an instance of the class.
$getShelvesetItems = New-Object -TypeName "PowerShellTfs.ShelvesetItemsAPI";
# Emit the pending changes to the pipeline.
$getShelvesetItems.GetShelvesetItems($ShelvesetName, $ShelvesetOwner, $ServerUri, $Collection);
}
Spent a few days trying to do this as well, this always popped up on google so here is what I found to help future generations:
To get the contents of the shelveset (at least with Team Explorer Everywhere),
use the command: tf difference /shelveset:<Shelveset name>
That will print out the contents of the shelveset and give filenames in the form :
<Changetype>: <server file path>; C<base change number>
Shelved Change: <server file path again>;<shelveset name>
So if your file is contents/test.txt
in the shelveset shelve1 (with base revision 1), you will see :
edit: $/contents/file.txt;C1
Shelved Change: $/contents/file.txt;shelve1
After that, using the tf print command
(or view if not using TEE) on $/contents/file.txt;shelve1 should get you the contents :
tf print $/contents/file.txt;shelve1
Shows you what is in the file.txt in shelveset shelve1
If you want get shelveset changes from server by using tfs command
Using power shell:
Get-TfsPendingChange -Server http://example.com/org -Shelveset shelvsetName
Using vs commands:
c:\projects>tf shelvesets BuddyTest_23
more info about this please see here
https://learn.microsoft.com/en-us/azure/devops/repos/tfvc/shelvesets-command?view=azure-devops