How can I programmatically checkin code in TFS with policy override? - c#

I'm trying to checkin code from a c# program in a part of TFS repository which will trigger a gated checkin build and also a continuous integration build.
This is my code so far:
public static void Checkin(string path, string comment)
{
var wsInfo = Workstation.Current.GetLocalWorkspaceInfo(path);
var tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(wsInfo.ServerUri);
tfs.Connect(ConnectOptions.None);
var vcs = tfs.GetService<VersionControlServer>();
var ws = vcs.GetWorkspace(path);
var fullPath = Path.GetFullPath(path);
var change = ws.GetPendingChangesEnumerable().Where(p => p.LocalItem == fullPath).ToArray();
ws.CheckIn(change.ToArray(), comment);
tfs.Dispose();
}
what is basically happening is that I get a GatedCheckinException say that there is an affected build defintion.
I would like to do the checkin with the commonly known bypass to avoid triggering the gated checkin. I've been struggling with the altenate Checkin functions without success.
Any idea?
UPDATE:
Thanks Aghilas Yakoub for the link.
For completeness, here is the code to do the checkin with override that worked for me:
var wip = new WorkspaceCheckInParameters(change, comment)
{
OverrideGatedCheckIn = ((CheckInOptions2)vcs.SupportedFeatures & CheckInOptions2.OverrideGatedCheckIn) == CheckInOptions2.OverrideGatedCheckIn,
PolicyOverride = new PolicyOverrideInfo("Check-in from the build.", null)
};
ws.CheckIn(wip);

I suggest you this sample of code http://blogs.infosupport.com/override-gated-check-in-using-the-tfs-api/

Related

ReSharper dotcover showing 0% coverage despite tests running through code

I'm assuming this is an error on my part but I can't figure out why ReSharper dotcover is showing my test coverage of certain queries (and commands too) as 0%.
So I have a .NET Core CQRS API that is made up of a lot of EF Core LINQ. Below is a simple example of one of my queries's main execute method (I left out the DI constructor but I'm sure you git the idea):
public bool Execute(SelectIsReportRequested query)
{
var context = _clientDatabase.GetContext(query.DatabaseId);
var result = (from a in context.Assessments
join r in context.Registrations on a.AssessmentId equals r.AssessmentId
where a.PublicId == query.ResponseId
select r.ReportRequested).SingleOrDefault();
return result == 1;
}
Then I have the following test that mocks the various bits and runs the query:
[TestMethod]
public void It_should_return_true_if_a_report_has_been_requested_for_the_givenassessment()
{
const int assessmentId = 1;
var responseId = Guid.NewGuid();
var mockRepository = new Mock<ICViewClientContext>();
var assessments = new List<Assessments>
{
new Assessments { AssessmentId = assessmentId, PublicId = responseId },
};
var registrations = new List<Registrations>
{
new Registrations { AssessmentId = assessmentId, ReportRequested = 1 },
};
mockRepository.Setup(x => x.Registrations).Returns(registrations.AsDbSetMock().Object);
mockRepository.Setup(x => x.Assessments).Returns(assessments.AsDbSetMock().Object);
var mockClientDatabase = new Mock<IClientDatabase>();
mockClientDatabase.Setup(x => x.GetContext(1)).Returns(mockRepository.Object);
var query = new Queries.Assessments.SelectIsReportRequested(2, responseId);
var handler = new Queries.Assessments.SelectIsReportRequestedHandler(mockClientDatabase.Object);
var result = handler.Execute(query);
Assert.AreEqual(true, result);
}
The tests passes (and will also fail if I break the logic in the LINQ) or any other logic in the code.
However, running dotcover runs the test, passes it but says that none of it is covered.
I would love to know why because it's really driving me insane and worries me that I've done something completely wrong!
So I think through blind luck I have been able to solve my issue and wanted to post what I did just in case it helps anyone else.
Whilst trying to get the logs to submit to JetBrains I did the following:
In ReSharper | Options… | dotCover | General, disabled 'Use preloaded Unit Test runners'
Saved settings
Went back and enabled 'Use preloaded Unit Test runners'
Saved settings
Then I re-ran dotcover and suddenly all my test coverage was shown and all my test cover code highlighting was shown correctly.
I've sent a message back to JetBrains and if they give me any info as to why that solved it I'll post that too.
I had a similar issue when dotCover didn't recognize some of the unit tests.
I was able to resolve it by removing Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll from Test Project references and installing MSTest.TestFramework and MSTest.TestAdapter nuget packages.

TFS API: Request Review on Changeset in C#

In Visual Studio I usually open the Changeset via Source Control Explorer, open the Changeset via Go to Changeset and then select Actions->Request Review in the Team Explorer window where the Changeset is shown.
In C# I have code that lets me query all my changesets:
VersionControlServer vcs = tpc.GetService<VersionControlServer>();
vcs.QueryHistory(...)
Now I have a List of Changeset instances.
How can I implement the "Request Review" functionality?
I tried to create a Code Review Request like so:
Project teamProject = _workItemStore.Projects["XYZ"];
WorkItemType workItemType = teamProject.WorkItemTypes["Code Review Request"];
var request = new WorkItem(workItemType) { Title = "Testreview" };
request.Fields["Associated Context Type"].Value = "Changeset";
request.Fields["Associated Context"].Value = "5169";
request.Fields["Assigned To"].Value = "Joe Doe";
request.AreaPath = #"XYZ\Test";
request.IterationPath = #"XYZ\Test\1.5";
request.Save();
This creates a code review request very similar to the one in Visual Studio but Code Review can not be performed. What am I missing?
From what I see you are using the package Microsoft.TeamFoundationServer.ExtendedClient. You are on the right track, but you need one more work item called Code Review Response. For the creation of these two work items refer to the blog post Tfs Extensibility - Automatically Create Code Reviews on Checkin. This post helped me a lot regarding the work item field values. Here is the essential code section from the post:
var type = project.WorkItemTypes["Code Review Response"];
var workItem = new WorkItem(type) { Title = checkinNotification.Comment };
workItem.Fields["System.AssignedTo"].Value = "Betty"; //todo pick someone better
workItem.Fields["System.State"].Value = "Requested";
workItem.Fields["System.Reason"].Value = "New";
var result = workItem.Validate();
foreach (Field item in result)
{
//insert some form of logging here
}
workItem.Save();
var responseId = workItem.Id;
type = project.WorkItemTypes["Code Review Request"];
workItem = new WorkItem(type) { Title = checkinNotification.Comment };
workItem.Fields["System.AssignedTo"].Value = checkinNotification.ChangesetOwner.DisplayName;
workItem.Fields["Microsoft.VSTS.CodeReview.ContextType"].Value = "Changeset";
workItem.Fields["Microsoft.VSTS.CodeReview.Context"].Value = checkinNotification.Changeset;
workItem.Fields["System.AreaPath"].Value = project.Name; //todo: may want a better location from source path
workItem.Fields["System.IterationPath"].Value = project.Name;
workItem.Fields["System.State"].Value = "Requested";
workItem.Fields["System.Reason"].Value = "New";
WorkItemLinkTypeEnd linkTypeEnd = workitemStore.WorkItemLinkTypes.LinkTypeEnds["Child"];
workItem.Links.Add(new RelatedLink(linkTypeEnd, responseId));
workItem.Save();
The actual comments on the code review use the discussion service (see Creating code review request through API). Microsoft documentation on the disscusion service: Microsoft.TeamFoundation.Discussion.Client.
In this namespace take a look at the class DiscussionThread
I hope this helps.

using libgit2sharp to pull latest from a branch

I am using libgit2sharp in a c# solution to switch to a branch and pull in the latest changes. Here is the code I am using:
public void FetchAll()
{
using (var repo = new Repository(_LocalGitPath))
{
foreach (Remote remote in repo.Network.Remotes)
{
FetchOptions options = new FetchOptions();
options.CredentialsProvider = new CredentialsHandler((url, usernameFromUrl, types) => new UsernamePasswordCredentials()
{
Username = _UserName,
Password = _Password
});
repo.Network.Fetch(remote, options);
}
}
}
public string CheckoutBranch(string branchName)
{
using (var repo = new Repository(_LocalGitPath))
{
var trackingBranch = repo.Branches[branchName];
if (trackingBranch.IsRemote)
{
branchName = branchName.Replace("origin/", string.Empty);
var branch = repo.CreateBranch(branchName, trackingBranch.Tip);
repo.Branches.Update(branch, b => b.TrackedBranch = trackingBranch.CanonicalName);
Commands.Checkout(repo, branch, new CheckoutOptions { CheckoutModifiers = CheckoutModifiers.Force });
}
else
{
Commands.Checkout(repo, trackingBranch, new CheckoutOptions { CheckoutModifiers = CheckoutModifiers.Force });
}
return branchName;
}
}
public void PullBranch(string branchName)
{
using (var repo = new Repository(_LocalGitPath))
{
PullOptions options = new PullOptions();
options.MergeOptions = new MergeOptions();
options.MergeOptions.FailOnConflict = true;
options.FetchOptions = new FetchOptions();
options.FetchOptions.CredentialsProvider = new CredentialsHandler((url, usernameFromUrl, types) => new UsernamePasswordCredentials()
{
Username = _UserName,
Password = _Password
});
repo.Network.Pull(new Signature(_UserName, _Password, new DateTimeOffset(DateTime.Now)), options);
}
}
I have no problem fetching, and checking out a branch. When I try to pull latest, I get an error saying, 'There is no tracking information for the current branch.' I believe that this means that the local branch doesn't know what the correct remote repository is to pull changes from, but I haven't been able to figure out how to tell libgit2sharp what the remote repo path is. Anyone have any suggestions?
While doing research on this problem I found this: https://github.com/libgit2/libgit2sharp/issues/1235. Essentially, a libgit2sharp dev describes the exact problem I am seeing, but doesn't provide any code for the fix.
One additional note: I will never be merging or pushing any changes back from this repository. I am pulling it for an automated build, so we can ignore or overwrite any local changes. I just need to get the latest code.
SOLUTION:
I have updated the code above with the solution that I got working. You need to be really careful to make sure that when you checkout a branch, you check the isRemote flag on the branch you are checking out is set to true. If you checkout a branch that isn't a remote it will set the remote to '.' in your git config file, and you need to manually fix it. If there isn't a valid remote you will not be able to pull the branch changes.
Do not use the code sample on the libgit2sharp wiki unless they add this check in.
You can setup the tracking brach information on the local branch by using the Refspec:
using (var repo = new Repository("/Users/sushi/code/redux/mono"))
{
var trackingBranch = repo.Branches["remotes/origin/work-btls"];
if (trackingBranch.IsRemote)
{
var branch = repo.CreateBranch("SomeLocalBranchName", trackingBranch.Tip);
repo.Branches.Update(branch, b => b.TrackedBranch = trackingBranch.CanonicalName);
repo.Checkout(branch, new CheckoutOptions { CheckoutModifiers = CheckoutModifiers.Force });
}
}
You can use git to verify that SomeLocalBranchName is now tracking remotes/origin/work-btls:
>>>git for-each-ref --format='%(refname:short) <- %(upstream:short)' refs/heads
SomeLocalBranchName <- remotes/origin/work-btls
master <- origin/master
>>>git status
On branch SomeLocalBranchName
Your branch is up-to-date with 'remotes/origin/work-btls'.

Detect current VSIX package's version from code

I am writing a VSIX project and I would like for the code to be able to determine whether an update is available.
I know Visual Studio would be able to check for the update, however, I would like for the extension to be able to prompt user (developer) more verbosely.
I wonder how could make the extension read its own version from the package manifest?
Thank you.
I found that I could read the version information directly from the manifest XML file.
var doc = new XmlDocument();
doc.Load(manifestPath);
var metaData = doc.DocumentElement.ChildNodes.Cast<XmlElement>().First(x => x.Name == "Metadata");
var identity = metaData.ChildNodes.Cast<XmlElement>().First(x => x.Name == "Identity");
var version = identity.GetAttribute("Version");
I also wrote a gist C# class code that encapsulate the code above. Besides, version, this technique could be used to get other information provided by the manifest file.
Nordin's solution seems good, but I just want to mention that there is one more way to get current version of the extension. I have no idea in what situation my solution might be better, maybe if you don't know the path to the manifest on the client that uses this extension.
// get ExtensionManager
IVsExtensionManager manager = GetService(typeof(SVsExtensionManager)) as IVsExtensionManager;
// get your extension by Product Id
IInstalledExtension myExtension = manager.GetInstalledExtension("ProductId-1234-1234-1234-123456789012");
// get current version
Version currentVersion = myExtension.Header.Version;
I call this inside Initialize() method of my package.
This code motivated by Wayne Koorts works for me, even if deploying the package on Visual Studio Gallery:
private string getVsixVersion()
{
var asm = Assembly.GetExecutingAssembly();
var asmDir = Path.GetDirectoryName(asm.Location);
var manifestPath = Path.Combine(asmDir, "extension.vsixmanifest");
var version = "?";
if (File.Exists(manifestPath))
{
var doc = new XmlDocument();
doc.Load(manifestPath);
var metaData = doc.DocumentElement.ChildNodes.Cast<XmlElement>().First(x => x.Name == "Metadata");
var identity = metaData.ChildNodes.Cast<XmlElement>().First(x => x.Name == "Identity");
version = identity.GetAttribute("Version");
}
return version;
}

How to get Workspace object in new TeamFoundation 2013 Templates

In new version of TeamFoundation 2013 default build templates, the Workspace variable is missing. It is needed as intput parameter for few key activities like ConvertWorkspaceItem. How do I get current workspace for TfvcTemplate.12.xaml templates? I've tried to use this msdn thread but it's not working for me (returns null workspace name). Any suggestions?
There's a new activity in 2013 called GetLocalPath that replaces ConvertWorkspaceItem.
The activity is under the Microsoft.TeamFoundation.Build.Activities.Core namespace in the Microsoft.TeamFoundation.Build.Activities assembly.
It uses the LocalPathProvider class that aggregates all workspaces used in the build and exposes path translation for all of them in one place. This basically removes the dependency of knowing the workspace in order to translate server paths to local paths and allows you to use as many workspaces as you want without worrying about breaking something down the line.
When MS takes something away, it's usually for a good reason. "hacking" is really not necessary.
I went with a hack using internal classes from Microsoft.TeamFoundation.Build.Activities.dll (used by microsoft to create workspace name). You need to create custom activity with following code:
public sealed class GetDefaultWorkspace : BaseActivity<Workspace>
{
public override Activity CreateBody()
{
var type = typeof(TfGetSources).Assembly.GetType("Microsoft.TeamFoundation.Build.Activities.TeamFoundation.TfGetSources+GetDefaultWorkspaceName");
var activity = (CodeActivity<string>)Activator.CreateInstance(type);
var sequence = new Sequence();
var workspaceName = new Variable<string>();
sequence.Variables.Add(workspaceName);
sequence.Activities.Add(activity);
activity.Result = (OutArgument<string>) workspaceName;
sequence.Activities.Add(new GetWorkspace
{
Name = workspaceName,
Result = new LambdaReference<Workspace>(ctx => Result.Get(ctx))
});
return sequence;
}
}
This answer might work better for some people. ghord's answer works well, and passes the Workspace back where it can be used in the XAML. However, for my purposes I only want the workspace in my custom TFS activities, so I ended up with this alternative...
public sealed class CustomActivity : CodeActivity
{
protected override void Execute(CodeActivityContext context)
{
// get workspace
var buildDetail = context.GetExtension<IBuildDetail>();
var buildAgent = context.GetExtension<IBuildAgent>();
var buildDirectory = buildAgent.GetExpandedBuildDirectory(buildDetail.BuildDefinition);
var workspacePath = Path.Combine(buildDirectory, "src");
var wsInfo = Workstation.Current.GetLocalWorkspaceInfo(workspacePath);
var tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(wsInfo.ServerUri);
tfs.Connect(ConnectOptions.None);
var vcs = tfs.GetService<VersionControlServer>();
// finally can get to the workspace here
var workspace = vcs.GetWorkspace(workspacePath);
}
}
Using this method, I don't have to have an activity that just returns the workspace, and then have to pass the workspace into other TFS activities. I just get the workspace from within my own activity while it runs.
I believe the method employed here will use the already downloaded workspace. Keep in mind, that this approach will only work within the scope of "Run on agent" sequence after "Initialize Environment" and before ResetEnvironment within the finally statement of Try Compile, Test, Publish. Else, the workflow will have no knowledge of a sources directory.
http://social.msdn.microsoft.com/Forums/vstudio/en-US/420ba073-bdf5-4ab4-88da-c84561d1a1ba/creating-dynamic-working-folder-in-tfs2013-defaulttemplate?forum=tfsbuild

Categories

Resources