Create a local branch to track a remote branch with libgit2sharp - libgit2sharp

How can I create a local branch that tracks a remote branch with libgit2sharp? The git equivalent would be:
git branch --track development origin/development

The following code should just do that, assuming the local development branch doesn't exist yet.
const string testBranchName = "development";
const string trackedBranchName = "origin/development";
using (var repo = new Repository(path))
{
// Retrieve remote tracking branch
Branch trackedBranch = repo.Branches[trackedBranchName];
Debug.Assert(trackedBranch.IsRemote == true);
// Create local branch pointing at the same Commit
Branch branch = repo.CreateBranch(testBranchName, trackedBranch.Tip);
repo.Branches.Update(branch,
b => b.TrackedBranch = trackedBranch.CanonicalName);
}
Note: The BranchFixture.cs suite contains a CanSetTrackedBranch test which should provide you with further usage details.

Related

conditional branch in groovy code based on state

I have a webhook in gitlab, that triggers a Jenkins job which run a groovy script.
Now I want that the branch to checkout will be conditional:
If the state is merged to take the target_branch and if not that the source_branch
I couldn't find exactly how to do it in the groovy code. The triggers are different for one is note and for the other is merge request
There are gitlab variables that are passed: https://github.com/jenkinsci/gitlab-plugin#defined-variables
so the following solved my issue:
// Distniguish between 2 types of webhook triggers
if(env.gitlabMergeRequestState != null) {
merge_status = "merged"
if (merge_status.equalsIgnoreCase(env.gitlabMergeRequestState)) {
echo "Merged Trigger, using: ${env.gitlabTargetBranch} branch"
branch = env.gitlabTargetBranch
} else {
echo "Note Trigger, using: ${env.gitlabSourceBranch} branch"
branch = env.gitlabSourceBranch
}
}

Jenkinsfile - get all changes between builds

With reference to this question is there a way to get the equivalent information from when using the mult-branch pipeline? Specifically - the list of commits since the last successful build.
Currently we use the following
def scmAction = build?.actions.find { action ->
action instanceof jenkins.scm.api.SCMRevisionAction
}
return scmAction?.revision?.hash
but this only returns the last commit that triggered the build if multiple commits were pushed. I accept that the very first build of a new branch might be ambiguious but getting a list of commits that triggered the build when possible would be very useful.
I have found a solution that seems to work for us. It revolves around getting the currentBuild commit hash and then the lastSuccessfulBuild commit hash. First we wrote a utility method for getting a commit hash of a given Jenkins build object:
def commitHashForBuild(build) {
def scmAction = build?.actions.find { action -> action instanceof jenkins.scm.api.SCMRevisionAction }
return scmAction?.revision?.hash
}
then use that to get the lastSuccessfulBuild's hash:
def getLastSuccessfulCommit() {
def lastSuccessfulHash = null
def lastSuccessfulBuild = currentBuild.rawBuild.getPreviousSuccessfulBuild()
if ( lastSuccessfulBuild ) {
lastSuccessfulHash = commitHashForBuild(lastSuccessfulBuild)
}
return lastSuccessfulHash
}
finally combine those two in a sh function to get the list of commits
def lastSuccessfulCommit = getLastSuccessfulCommit()
def currentCommit = commitHashForBuild(currentBuild.rawBuild)
if (lastSuccessfulCommit) {
commits = sh(
script: "git rev-list $currentCommit \"^$lastSuccessfulCommit\"",
returnStdout: true
).split('\n')
println "Commits are: $commits"
}
you can then use the commits array to query various things in Git as your build requires. E.g. you can use this data to get a list of all changed files since the last successful build.
I have put this into a complete example Jenkinsfile Gist to show how it fits together in context.
A possible improvement would be to use a Java/Groovy native Git library instead of shelling out to a sh step.
I think Jenkins Last changes plugin can provide the information you need, take a look here:
https://plugins.jenkins.io/last-changes, following is an example:
node {
stage("checkout") {
git url: 'https://github.com/jenkinsci/last-changes-plugin.git'
}
stage("last-changes") {
def publisher = LastChanges.getLastChangesPublisher "LAST_SUCCESSFUL_BUILD", "SIDE", "LINE", true, true, "", "", "", "", ""
publisher.publishLastChanges()
def changes = publisher.getLastChanges()
println(changes.getEscapedDiff())
for (commit in changes.getCommits()) {
println(commit)
def commitInfo = commit.getCommitInfo()
println(commitInfo)
println(commitInfo.getCommitMessage())
println(commit.getChanges())
}
}
}
Note that by default (without the need for groovy scripting) the plugin makes the list of commits available for browsing on the jenkins UI, see here.
I hope it helps.
I was looking for how to get the git hash of the last successful build to do some git diff-tree change detection. I was following Friedrich's answer to programmatically get the SCM actions and revision hash out of the build returned from currentBuild.rawBuild.getPreviousSuccessfulBuild().
I was struggling to get this working with the current Jenkins API, and then realized that the git Jenkins plugin now exports the env var GIT_PREVIOUS_SUCCESSFUL_COMMIT. I now just refer to ${env.GIT_COMMIT} and ${env.GIT_PREVIOUS_SUCCESSFUL_COMMIT} to do a git diff-tree in my pipelines.

Programmatically delete a TFS branch

I want to programmatically delete a branch in TFS that was create automatically.
There is an existing method "ICommonStructureService.DeleteBranches" that should do the work.
My problem is that the method requires a parameter "string[] nodeUris" that specifies the branch to delete using a "vstfs://... " URI and I just don't know how to get that for my branch.
What I need is something like:
var projectCollection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri <myCollectionUrl>));
var cssService = projectCollection.GetService<ICommonStructureService3>();
var project = cssService.GetProjectFromName(<myProjectName>);
But how can I get the Branch Uri from there?
Meanwhile I found a solution. For deleting the branches I am using
versionControl.Destroy(new ItemSpec(myBranchPath, RecursionType.Full), VersionSpec.Latest, null, DestroyFlags.KeepHistory);
This does exactly what I needed.
versionControl is of type VersionControlServer and must be initialized using the Team Collection
Deleting a branch in version control is like deleting any other version control item. You will need to pend a delete with Workspace.PendDelete on the Item.
The method you reference is wholly unrelated to version control, it's part of the TFS common structure service, which controls the "areas and iterations" that TFS work items can be assigned to.
In short, there's no way to perform any sort of version control operations against the common structure service. You delete a branch by creating a Workspace against a VersionControlServer, pending a delete and then checking in your pending changes.
I agree to Edward Thomson about using Destroy command. So I followed on advice from him and came up with following,
public void DeleteBranch(string path)
{
var vcs = GetVersionControlServer();
var itemSpec = new ItemSpec(path, RecursionType.Full);
var itemSpecs = new[] {itemSpec};
var workSpace = GetOrCreateWorkSpace(vcs);
try
{
workSpace.Map(path, #"c:\Temp\tfs");
var request = new GetRequest(itemSpec, VersionSpec.Latest);
workSpace.Get(request, GetOptions.GetAll | GetOptions.Overwrite);
workSpace.PendDelete(path, RecursionType.Full);
var pendingchanges = workSpace.GetPendingChanges(itemSpecs);
workSpace.CheckIn(pendingchanges, "Deleting The Branch");
}
finally
{
if (workSpace != null)
{
workSpace.Delete();
}
}
}
If there is a neat way to do the same than I am looking forward to it. This is bit slow as it does too many things,
Creates Temp Workspace
Gets All changes to that
Performs Delete to whole change set
checks it in
Cleans up the workspace

TFS 2010 - merge changesets

In TFS 2010, the scenario is to merge the selected changesets via tf command line.
Suppose there were 20 changesets which is to be merged from branch to main folder. I am using the tf command line to merge all the 20 changesets.
If there is a conflict in any of the changeset, email should be triggered to the person who checked-in the changesets.
Is there is anyway to send an email to the person who checkin the changeset?
I think your only resort is to write an application that will take as input the sourceBranch and the targetBranch & will try to programmatically merge the latest of the one to the other. Then it 'll query for conflicts, find the Changeset they belong to and finally send the email to the Changeset owner.
The following bases heavily on the work by Eugene Zakhareyev found here:
using System;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
namespace DetectConflicts
{
class Program
{
static void Main()
{
TfsTeamProjectCollection teamProjectCollection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri("http://TFS:8080/tfs/{Collection}"));
var versionControl = teamProjectCollection.GetService<VersionControlServer>();
const string sourceBranch = "$/PathToFROMBranch";
const string targetBranch = "$/PathToTOBranch";
Workspace myWorkspace = versionControl.GetWorkspace("WorkspaceName", "{DOMAIN}\\YourName");
GetStatus getStatus = myWorkspace.Merge(sourceBranch,
targetBranch,
null,
null,
LockLevel.None,
RecursionType.Full,
MergeOptions.None);
Conflict[] conflicts = myWorkspace.QueryConflicts(new[] {targetBranch}, true);
foreach (var conflict in conflicts)
{
string owner = versionControl.GetChangeset(conflict.TheirVersion).Owner;
//
//send an email to "owner"
//
...
}
}
}
}

TFS2010 Custom Build Activity : to Merge branches

I'm working on customizing our build activity. I'd like to have your help for an issue.
Following is our version control hierarchy.
Main
|- Dev
|- QA
we are working on Dev branch and while taking the build we need to merge Dev branch to Main then to QA.
Main is the root branch as you might know.
In our build template, I've added two custom activities to merge one from Dev to Main and another one to merge from Main to QA. Following is the code for the custom activity.
protected override string Execute(CodeActivityContext context)
{
string lstrStatus = string.Empty;
string lstrSourceBranchPath = context.GetValue(this.SourceBranchPath);
string lstrTargetBranchPath = context.GetValue(this.TargetBranchPath);
// Obtain the runtime value of the input arguments
Workspace workspace = context.GetValue(this.Workspace);
GetStatus status = workspace.Merge(lstrSourceBranchPath,
lstrTargetBranchPath,
null,
null,
LockLevel.None,
RecursionType.Full,
MergeOptions.None);
// resolve the conflicts, if any
if (status.NumConflicts > 0)
{
Conflict[] conflicts = workspace.QueryConflicts(new string[]
{ lstrTargetBranchPath }, true);
foreach (Conflict conflict in conflicts)
{
conflict.Resolution = Resolution.AcceptTheirs;
workspace.ResolveConflict(conflict);
}
}
// checkin the changes
PendingChange[] pendingChanges = workspace.GetPendingChanges();
if (pendingChanges != null && pendingChanges.Length > 0)
{
workspace.CheckIn(pendingChanges, "Merged by MERGE BRANCHES activity");
}
return lstrStatus;
}
Problem is, merging happens perfectly in the server. But, it's not getting reflected in the local folder. I tried to add SyncWorkspace activity after each Merge custom activity. Still not working.
My guess was that a SyncWorkspace should be the only thing to do.
You could try doing a RevertWorkspace before that.
EDIT
After you now stated that even this wouldn't work, I would generate a bug against MS at least to get an official answer.
In the meanwhile you can try with the following method, which I absolutely see as an overkill: Once you have checked in, redo all the steps within sequence Initialize Workspace.
If even that doesn't work I'd consider two different builds, one that does your merge & one that does the actual build. You can then organize a scheme where your first build, once it's done, triggers the second one. Here is a good resource for that.

Resources