I would like to perform the following steps in the TFS build process:
do post build event that will copy some files from my compiled projects to another predefined directory, I'd like that directory path to include the branch name.
I'd like to be able to refer to the branch name inside my xaml workflow template as well.
The first one is rather simple. When you're using the new TFS 2013 build server and process template, you can simply add a post-build powershell script in the Build Definition Configuration, check in the script and run it during the build.
The second one is dependent on whether you're using TFVC or Git, in the first case, use the VersionControlServer class to query the BranchObjects, then check which one is the root for your working folder. Be aware though, that in TFVC multiple branches can be referenced in one workspace, so there may be multiple answers to this query, depending on which file you use the find the branchroot. A custom CodeActivity would do the trick, similar to this check in a custom checkin policy.
The code will be similar to:
IBuildDetail buildDetail = context.GetExtension<IBuildDetail>();
var workspace = buildDetail.BuildDefinition.Workspace;
var versionControlServer = buildDetail.BuildServer.TeamProjectCollection.GetService<VersionControlServer>();
var branches = versionControlServer.QueryRootBranchObjects(RecursionType.Full);
var referencedBranches = listOfFilePaths.GroupBy(
file =>
branches.SingleOrDefault(
branch => file.ServerItem.StartsWith(branch.Properties.RootItem.Item)
)
).Where(group => group.Key != null);
To get a list of all items in yo workspace, you can use Workspace.GetItems.
In case you're using Git, you have a few options as well. The simplest is to invoke the command line:
git symbolic-ref --short HEAD
or dive into LibGit2Sharp and use it to find the branch name based on the current working folder from a custom activity.
If you want to include this in an MsBuild task, this may well be possible as well. It goes a bit far for this answer to completely outline the steps required, but it's not that hard once you know what to do.
Create a custom MsBuild task that invokes the same snippet of code above, though instead of getting access to the workspace through BuildDetail.BuildDefinition.Workspace, but through the WorkStation class:
Workstation workstation = Workstation.Current;
WorkspaceInfo info = workstation.GetLocalWorkspaceInfo(path);
TfsTeamProjectCollection collection = new TfsTeamProjectCollection(info.ServerUri);
Workspace workspace = info.GetWorkspace(collection);
VersionControlServer versionControlServer = collection.GetService<VersionControlServer>();
Once the task has been created, you can create a custom .targets file that hooks into the MsBuild process by overriding certain variables or copying data when the build is finished. You can hook into multiple Targets and define whether you need to do something before or after them.
You can either <import> these into each of your projects, or you can place it in the ImportAfter or ImportBefore folder of your MsBuild version to make it load globally. You can find the folder here:
C:\Program Files (x86)\MSBuild\{MsBuild Version}\Microsoft.Common.Targets\ImportAfter
Related
I have a Jenkins job that is a declarative pipeline. It's URL is $JENKINS_URL/job/dnscheck/.
I started using Bitbucket projects on Jenkins, and now that Jenkinsfile is also discovered and the same job lives at $JENKINS_URL/job/website/job/dnscheck/job/master/
I want to copy the entire history (log files etc) from $JENKINS_URL/job/dnscheck/ to $JENKINS_URL/job/website/job/dnscheck/job/master/, and then delete $JENKINS_URL/job/dnscheck/.
Can I do that?
If yes, how do I do that?
I don't want to overwrite existing files
On the master, the logs are all stored in ${JENKINS_HOME}/jobs/<path/to/job>/builds/, unless overridden by a system property jenkins.model.Jenkins.buildsDir. They consist of a series of numbered directories with a log file (the build log) inside and possibly some additional data files (eg: build.xml, changelog.xml, injectedEnvVars.txt).
There are also some sym-links for last builds (good/bad, etc.), both inside the jobs directory and inside the builds directory. You could copy all the directories over (renumber if you have conflicts) AND update the sym-links accordingly. You may also need to reset the last build ( Number of builds since the start of the project ) to n+1 so that the next build number increments w/o overlapping. It's in a file inside /nextBuildNumber.
Finally, you must get Jenkins to recognize the new content since Jenkins caches everything. You can do that by either restarting the system, reloading the configuration from disk or less drastically, reload the data on the one job, something like:
def configXMLFile = job.getConfigFile();
def file = configXMLFile.getFile();
InputStream is = new FileInputStream(file);
job.updateByXml(new StreamSource(is));
job.save();
I am automating the configuration of Jenkins masters to get to a one-click instantiation. We have 6 standard jobs we create for each instance and I'd like to be able to create them via groovy.init.d scripts but haven't found examples for this type of job.
We use the cloudbees Bitbucket Team/Project plugin that ends up creating jobs of type WorkflowMultibranchProject with additional configuration to connect to our on-prem Bitbucket instance.
Does anyone have samples of creating such a job via groovy? Am I better off trying to use JobDSL to create the job (am doing that already for a Mother Seed job)
[UPDATE] : with the help of the answer below came up with a full sample creating an entire Bitbucket Team/Project Job: https://github.com/redfive/jenkins-init/blob/master/init.groovy.d/core-jobs.groovy
Having used Job DSL, I'm 50/50 undecided if it is easier compared to using Groovy (as Job DSL lacks support for some of the config options).
An example for the similar OrganizationFolder can be found in #coderanger's article on https://coderanger.net/jenkins/:
// Create the top-level item if it doesn't exist already.
def folder = jenkins.items.isEmpty() ? jenkins.createProject(OrganizationFolder, 'MyName') : jenkins.items[0]
// Set up GitHub source.
def navigator = new GitHubSCMNavigator(githubOrg)
navigator.credentialsId = cred.id // Loaded above in the GitHub section.
navigator.traits = [
// Too many repos to scan everything. This trims to a svelte 265 repos at the time of writing.
new jenkins.scm.impl.trait.WildcardSCMSourceFilterTrait('*-cookbook', ''),
// We have a ton of old branches so try to limit to just master and PRs for now.
new jenkins.scm.impl.trait.RegexSCMHeadFilterTrait('^(master|PR-.*)'),
new BranchDiscoveryTrait(1), // Exclude branches that are also filed as PRs.
new OriginPullRequestDiscoveryTrait(1), // Merging the pull request with the current target branch revision.
]
folder.navigators.replace(navigator)
The next time when I set up an instance, I'd likely give that a try.
I have a folder into tfs,and I want to take branch of this folder with creating new folder and put branch under this new folder programmatically.Normally when we do it in tfs it automatically change folder to branch.
When I use createbranch command ,it works ,create folder and under these new folder it create new branch,but branch seen like folder in tfs but I can merge it vs so it is working.If I want to change visualization I have to use second command CreateBranchObject.Is it possible to that in one command
Folder A-->take new branch
Folder A'(New Folder) --> Branch
Code Sample
int changesetId = VersionControlServer.CreateBranch(#"myfolder ", "mynewfolder\newbranch",
VersionSpec.Latest);
Changeset changeset = vcs.GetChangeset(changesetId);
changeset.Update();
This is not like in a single command and you will need to call both in sequence.
I'm redesigning a control that lists the contents (files and folders) under a given TFS path. The tricky part is that I don't want to create a workspace for achieving this, as my intention is just to list the contents and display the history of a selected item. The current implementation creates a local workspace mapping in the background to achieve this, is this needed? Can I attain this without a local workspace mapping?
Thanks
Joe.
Use GetItems, which does not require a workspace. For example:
TeamFoundationServer tfs = new TeamFoundationServer("http://tfs:8080/tfs/DefaultCollection");
VersionControlServer versionControl = tfs.GetService<VersionControlServer>();
ItemSet items = versionControl.GetItems(tfsPath, RecursionType.Full);
Is it possible to nest TFS build template arguments in one another?
Example (Set via build definition ui):
$(ToolsRoot) = E:\BuildTools
$(MSPECTools) = $(ToolsRoot)\MSpec\
Alternatively, is it possible to use environmental variables.
I have tried both, and neither seemed to work.
I need to find a way of setting the build root dynamically, as it differs on our various build servers.
I suppose you have implemented a topology like the this:
So, you need to control the root for each Agent.If you open the TFS Admin Console > Build configuration in Build Machine #1 you 'll see the Build Controller & Agents A.1 & A.2.If you open TFS Admin Console > Build configuration in Build Machine #2 you 'll see Agents A.3, A.4, A.5 & A.6.
For any given build Agent, if you click on "Properties" you 'll see the "Working Directory" entry, which typically is set to something like $(SystemDrive)\Builds\$(BuildAgentId)\. On runtime this is transformed into something like C:\Builds\55.
For any given build, in the build definition area "Workspaces" this "Working Directory" equals the entry $(SourceDir).
Suppose you have set in Agent A.1 a working directory "C:\A.1\Build" & in Agent A.2 "C:\A.2\Build". In order to get what you need, you have to set in the build definition a mapping to $(SourceDir)\Template