Using p4 api .NET to add files to a Changelist - c#

My overall goal is to be able to sync, check out, and check in files within a workspace. This is the main part I am confused about:
IList<FileSpec> files = new List<FileSpec>();
FileSpec file = new FileSpec(testpath, null, locpath, VersionSpec.Head);
files.Add(file);
IList<FileSpec> foundFiles = rep.GetDepotFiles(files, null);
con.Client.SyncFiles(foundFiles, null);
Changelist cl = new Changelist();
cl.Description = "newest change";
cl.ClientId = ws_client;
Changelist changelist = rep.CreateChangelist(cl);
//Added the line below
con.Client.EditFiles(new Options(EditFilesCmdFlags.None, changelist.Id, null), file);
I first create the list of depot files (foundFiles) that I get from the repository, which works fine. I then try to sync these files to the client. I then create a Changelist, but I do not know how to go about editing files and submitting the changes. I am aware of the Client.EditFiles and Changelist.Submit methods, but I am not sure how to utilize them in this situation since I do not fully understand the linkage between a client/workspace and a changelist. In short, I would like to be able to access, edit, and submit files. One main problem is that my Changelist has no files in it and I am predicting that knowing how to add files is the first step. Any help or sample code is greatly appreciated!

I know the question is 2 years old, but the p4api.net documentation is still poor, so any answer might help future users.
I believe your remaining problem is that you use versioned file spec. Your problem should be solved by following last line:
//Added the line below
con.Client.EditFiles(new P4.Options(P4.EditFilesCmdFlags.None, changelist.Id, null), P4.FileSpec.UnversionedSpecList(foundFiles).ToArray());

I don't have a lot of experience with P4API.NET, but I think what you need to do is call Client.EditFiles, and use the options parameter to specify the changelist. Not sure if you'd use a reference to the changelist object, or just the changelist number.

Related

Libgit2sharp Get remote branches

Maybe asked before, but I cannot find the clear answer. When I need to list the branches of a repo with gitlib2sharp, do I really first need to clone to a local repo? What is the sense in that? I just want to clone a specific branch, like you do with git clone https://bla/repo.git -b branch1
Now I first need to do a local checkout, then get the branches and from there do a second round.
Am I missing something here (hope I do).
TIA for your answer!
Grtz,
Ronald
Update (to long for comment):
OK, so here's the use case. A company delivers ssrs reports, which we need to deploy through TAP. So my thoughts were to do this via Git. For each change let them create a branche, upload/alter/etc in this branche. And iterate changes in this branch till all is fine. In the iterations they should be able to (re)deploy themselves on at least T. At the final stage we merge the brnanch to master and (re)deploy master in P. In Github you can completely 'click' this flow, but of course I want to automate this and have preferably someelse push the buttons, so they don't need me for this. So what's the best programmatic choice here? When they make a branch and start deploying in T, should I create (clone) the repo, point my local repo to the specific branch, get the files (.sql and .rdl files) and execute/upload these? I was not aware that when you clone a repo, you clone all the branches with it. Thanks so far already!
If you want to do something like git clone https://bla/repo.git -b branch1 with libgtk2sharp try this one:
var exampleRepositoryUrl = "https://github.com/npgsql/npgsql.git";
var exampleDestinationFolder = "branch-hotfix-3.0.8";
var exampleBranchName = "hotfix/3.0.8";
var repositoryClonedPath = Repository.Clone(exampleRepositoryUrl,
exampleDestinationFolder,
new CloneOptions()
{
BranchName = exampleBranchName
});
using (var clonedRepo = new Repository(repositoryClonedPath))
{
// ...
}
To list names of remote branches without cloning a repo you can use something like this:
var branches = Repository.ListRemoteReferences(exampleRepositoryUrl)
.Where(elem => elem.IsLocalBranch)
.Select(elem => elem.CanonicalName
.Replace("refs/heads/", ""));
PiKos answer worked for me, but I had to set a credentials handler, e.g.:
var branches = Repository.ListRemoteReferences(exampleRepositoryUrl, MyCredentialsHandler)
.Where(elem => elem.IsLocalBranch)
.Select(elem => elem.CanonicalName
.Replace("refs/heads/", ""));
For more details on how to set a custom credentials handler, see this answer:
https://stackoverflow.com/a/55371988/5507590

How to get all changes to a file in Git, with Lib2GitSharp

I want to be able to Get a list of all changes done to a file. I've seen this post
How to get file's contents on Git using LibGit2Sharp?, but this requires to start off with a commit. I want to start digging with the filename.
Also is this possible without getting the whole repo locally?
After a bit of research I think I found an answer.
/*Small test*/
using (Repository repo = new Repository(strLocalDeliveryPath))
{
var fileHistory = repo.Commits.QueryBy(#"Path/To/file.ini").ToList();
int i = fileHistory.Count();
}
This is in order newest to oldest, and that suits me fine. I would normally only need the latest version of the file content, but nor i have the option of digging through the history of the file.
You can see this answer for a bit more info, but yes, the functionality was added in libgit2sharp 0.22.0. Here's an example:
var fileHistory = repository.Commits.QueryBy(filePathRelativeToRepository);
foreach (var version in fileHistory)
{
// Get further details by inspecting version.Commit
}

Find out the source control state of a ProjectItem from a Visual Studio extension

I'm currently developing a Visual Studio extension. For a new feature I need to find out whether a given ProjectItem (file) was modified (has "Pending Changes" since the last commit). For this I would like to query the source control provider.
I already tried searching all the properties of the ProjectItem but there is nothing hidden in there.
I also tried getting a service associated with source control from the Package.cs. I tried getting IVsSccManager2, IVsSccManager3 and IVsSccGlyphs. All return null (the test project is under source control). edit: I try to get these services by calling GetService(typeof(IVsSccManager2)) inside my Package.cs. The source control plugin of my debugging session correctly shows the changed files at the time this is called.
I can't seem to find anything online about this topic. How can I find out the modified state? Is it even possible?
After letting this topic sit for some time I recently came back to it and found the solution thanks to the help of my collegue. The problem was that I had no experience in bitwise comparison so I didn't know how to handle the response properly. Luckily my collegue gave me the right tip.
To interpret the result of status (thanks to #simon-mourier for the help on this code):
uint[] sccStatus = new uint[] { 0 };
if (VSConstants.S_OK == manager.GetSccGlyph(1, new[] { filePath }, new[] { VsStateIcon.STATEICON_NOSTATEICON }, sccStatus))
{
__SccStatus status = (__SccStatus)sccStatus[0];
}
One has to do bitwise comparison with the state of __SccStatus you are looking for, for example:
if ((sccStatus[0] & (uint)__SccStatus.SCC_STATUS_RESERVED_2) != 0)
return true;
The comparison returns true in case the state is set. If you need help on what specific state combinations can mean, just comment here and I can help on that.

Using c# how can I programmatically check if a folder exists on my reporting server

I Have spent hours looking but without any success.
I am programmatically creating snap shots of reports in SSRS using c# which creates report folders. The reports are created in these folders but to prevent errors occurring I am deleting the whole folder structure and then re-creating the reports to prevent SSRS throwing an exception.
I am using ReportingService2010.
ReportingService2010.DeleteItem(deleteFolderPath);
…
ReportingService2010.CreateFolder(folder, parentFolder, null);
-- This is the line where I need to check if the folder and report exist
var ret = CheckExist(linkedReportName, newParent);
var param = GetReportParameters(existingReportPath);
ReportingService2010.SetItemParameters(existingReportPath, param);
-- If I do not delete the folder structure the error will be thrown after this in a try/Catch
ReportingService2010.CreateLinkedItem(linkedReportName, newParent, existingReportPath, props);
I need to add a method to see if the report and report folder has already been created
I think the nicest way is ReportService2010.GetItemType() method. This returns a string (ReportingService2010.ListItemTypes() method), including possible values "Unknown" for non-existent (rather than throwing an exception) or "Folder" for a folder.
Another possible alternative is to directly work with the path, type, and parentid fields of the Catalog table in your report server database. If you open SQL Server and look at the table, it should be pretty clear what you need to do.
You can use C# to run a SQL command such as
SELECT COUNT(*) FROM CATALOG WHERE PATH LIKE '%TheFolderNameImLookingFor%'
If the count is greater than zero, then the folder exists.
You can vary this for your needs. Folder items have a type of 1; Report items have a type of 2, so you can use this to distinguish between reports and folders.
How to delete folders if they exist using ListChildren;
var items = ReportingService2010.ListChildren(parentFolder, false);
if (items.Where(x => x.TypeName == "Folder").Any(x => x.Name == folder))
{
ReportingService2010.DeleteItem(folder, parentFolder, null);
}
Directory.Exists() might work for you.
if (Directory.Exists(folderString))
{
// Do something
}
Don't forget the System.IO namespace:
using System.IO;
UPDATE: In the future, if you're looking for a file, you can do the same thing with File.Exists(), which is also in the System.IO namespace.
if (!Directory.Exists(folder))
{
ReportingService2010.CreateFolder(folder, parentFolder, null);
}

Saving WorkItem#IterationPath on newly created Iteration

I can successfully create an iteration path via:
var commonservice = collection.GetService<ICommonStructureService>();
// create new area path and iteration path
var iterationRoot = commonservice.GetNodeFromPath("\\MyTeamProject\\Iteration");
var newIterationPath = commonservice.CreateNode("my new sprint", iterationRoot.Uri);
However, when I try and assign this path to a work item and save it the field doesn't validate.
If I run the tests again (with the iteration already created) the same code succeeds.
Does anybody know how to make this work?
This fixed it for me:
WorkItemStore wis = (WorkItemStore)tfsTeamProjColl.GetService(typeof(WorkItemStore));
wis.RefreshCache();
wis.SyncToCache();
Maybe it will help someone.
I experienced exactly the same behavior, and unfortunately #JWC answer didn't help. The solution which works for me can be found by this link.
So, this is a quick summary in case the original answer gets lost.
The key point is to use WorkItemServer class. It lives in the Microsoft.TeamFoundation.WorkItemTracking.Proxy.dll assembly.
First of all, you create a WorkItemStore instance:
var store = collection.GetService<WorkItemStore>();
Then, create necessary iteration paths:
var commonservice = collection.GetService<ICommonStructureService>();
var iterationRoot = commonservice.GetNodeFromPath("\\MyTeamProject\\Iteration");
var newIterationPath = commonservice.CreateNode("my sprint", iterationRoot.Uri);
Next, refresh the cache in TFS (I suspect this is similar to pressing F5 in web interface):
var wiServer = collection.GetService<WorkItemServer>();
wiServer.SyncExternalStructures(WorkItemServer.NewRequestId(), commonservice.GetProjectFromName("MyTeamProject").Uri);
store.RefreshCache();
And finally, assign newly created work item to the newly created iteration:
var wi = new WorkItem(store.Projects["MyTeamProject"].WorkItemTypes["Product Backlog Item"]);
wi.Title = "Hello from API";
wi.Description = "This work item was created from API";
wi.Fields["Assigned To"].Value = "Yan Sklyarenko";
wi.IterationPath = FormatPath(commonservice.GetNode(newIterationPath).Path, "Iteration", "MyTeamProject");
wi.Save();
That's it! The method FormatPath translates the iteration path to the form required by the work item IterationPath field, that is from \MyTeamProject\Iteration\my sprint to MyTeamProject\my sprint.
Hope this can save some time.
NOTE: I run this towards TFS 2013.
You are likely running into a caching issue. Try clearing the cache after you create the iteration. A couple things you could try:
Get a new copy of the WorkItemStore.
Disconnect and reconnect to TFS
Check to see if there's a "refresh" method on either the WIS or on the TFS server objects. I've shut down my dev instance of TFS for the night, and I don't recall if there's anything like it.
If that's not quite it, post your code and I'll see if I can reproduce it.
I had the similar issue. I created Areapath and then created a query where the AreaPath was used. I did call store.RefreshCashe() but it did not work. Only in Debugger when I run store.RefreshCashe() two times manually.
Thanks "Yan Sklyarenko". I tried your Suggestion and it works fine (TFS Server 2012).

Categories