How do I get TFS wiki page attachment over API - tfs

I need to download TFS wiki page attachment via the TFS API.
From MS Docs, it looks like the API alows to create it but I can't seem to find a way to get it.
Calling GET on /_apis/wiki/wikis/{wikiIdentifier}/pages/{pageId}/attachments/{attachmentId} returns Method not allowed
Then I tried to use the WIT attachments API /_apis/wit/attachments/{id} but that one does not find the attachment and returns 404. (I suspect it can access only work items attachments.)

use GitHttpClient.GetItemContentAsync({project}, {repositoryId}, path:{path})
where
path is "/.attachments/my attached file-89553727-xxx-yyy-zzz-829fbe167411.docx" as found in the wiki page content (note the leading /)
Found this completely by accident once I moved to experimenting with GitHttpClient and listed all items in my repo. One of the items was an attachment and it had this path populated which I then plugged into the GetItemContentAsync method and voila.
My piece of code:
var uri = new Uri(_tfsBaseUri);
var credentials = GetCredentials();
using (var tpc = new TfsTeamProjectCollection(uri, credentials))
{
var wikiClient = tpc.GetClient<WikiHttpClient>();
var gitClient = tpc.GetClient<GitHttpClient>();
var mypage = wikiClient.GetPageAsync(_tfsProject, _tfsWiki, "My page name", includeContent: true).GetAwaiter().GetResult();
var pageContent = mypage.Page.Content;
if (pageContent.Contains("(.attachments"))
{
var path = "";// parse out the attachment path
var attachmentContent = gitClient.GetItemContentAsync(_tfsProject, new Guid("_tfsWiki repo ID"), path: path).GetAwaiter().GetResult();
}
}
private static VssCredentials GetCredentials()
{
return new VssCredentials(new Microsoft.VisualStudio.Services.Common.WindowsCredential(CredentialCache.DefaultCredentials));
}

Actually the TFS/Azure DevOps Server Wiki are just Git repos, so if you want you can clone them and get all the content by using
Git clone "https://{instance}/{collection}/{project}/_git/{projectName}"
If it's the default project wiki. If you want to get a wiki based on a git repo, then you just clone the repo in question and get the content.
Update:
Your attachments will be in the .attachments folder.

Related

Microsoft Graph API SDK for SharePoint to query a file

I try to use Graph API SDK to query a file in a SharePoint site
var site = await graphClient.Sites["myDomain"]
.SiteWithPath("relativePath").Request()
.GetAsync().ConfigureAwait(false);
var drive = await graphClient.Sites["myDomain]
.SiteWithPath("relativePath").Lists["mylib"].Drive
.Request().GetAsync().ConfigureAwait(false);
var file = await graphClient.Sites[site.Id]
.Drives[drive.Id].Root.ItemWithPath("/folder1").Children["myfile.txt"]
.Request().GetAsync().ConfigureAwait(false);
This is working and I get the file.
I try to combine the three steps into one,
var file = await graphClient.Sites["myDomain"]
.SiteWithPath("relativePath").Lists["mylib"].Drive
.Root.ItemWithPath("/folder1").Children["myfile.txt"]
.Request().GetAsync().ConfigureAwait(false);
But it gives Bad Request error. What's wrong? What is the best way to do this?
The navigation you are using is not accepted by Graph.
As per the get files docs, you need the site-id.
# Valid
GET /sites/mydomain.sharepoint.com:/relativePath/lists/mylib/drive
# Invalid addition to above url
GET /sites/mydomain.sharepoint.com:/relativePath/lists/mylib/drive/root:/myfile.txt:
If you don't have the site id, you can expand the list relationship in the get list drive call and use the site-id to request for the file. This will be two requests instead.
var drive = await graphServiceClient
.Sites["mydomain.sharepoint.com"]
.SiteWithPath(relativePath)
.Lists["mylib"]
.Drive
.Request()
.Expand("list")
.GetAsync()
.ConfigureAwait(false);
var file = await graphServiceClient
.Sites[drive.List.ParentReference.SiteId]
.Drives[drive.Id]
.Root.ItemWithPath("/Folder 1")
.Children["myfile.txt"]
.Request().GetAsync().ConfigureAwait(false);

How access message of git commits from Microsoft.TeamFoundation.WorkItemTracking.Client?

I'm using TFS 2017 update 1 on premises. I'm using #ID in log comments of commits in order to associate workitem ID (of User Story, Task etc.) with GIT commits of source code. It properly works (I can see links to commit from workitem interface).
I'd like to use TFS SDK API with tfs aggregator in order to better manage GIT commits (e.g. automatic transition to custom state of workitem when a specific custom git commit message is done by programmers).
How can access message/log of git commits from Microsoft.TeamFoundation.WorkItemTracking.Client in order be able to parser custom message in addition to those described here (e.g. "Fixes #123" or "Close #123")?
You can't get the commit comment only with WorkItemHttpClient, you can get it along with GitHttpClient. first of all get the work item links with WorkItemHttpClient, than get the commit id and get the comment with GitHttpClient.
A working example:
VssClientCredentials cred = new VssClientCredentials();
VssConnection tfs = new VssConnection(new Uri("http://tfs-server:8080/tfs/collection"), cred);
var workItemClient = tfs.GetClient<WorkItemTrackingHttpClient>();
var gitClient = tfs.GetClient<GitHttpClient>();
int workItemId = 1213;
var workItem = workItemClient.GetWorkItemAsync("Project-Name", workItemId, expand: WorkItemExpand.Relations).Result;
// We need to retrieve the commit id from the links, debug the following line to understand what I did
var commitId = wit.Relations.Where(r => r.Url.Contains("Git")).FirstOrDefault().Url.Split('%')[2].Remove(0,2);
var commit = gitClient.GetCommitAsync("Project-Name", commitId, "Repo-Name").Result;
string comment = commit.comment;
By the way, you can't use the Fixes #123 syntax because is not supported in TFS 2017.

TFS2018 path to api

I have a TFS2018 setup on a server and I am trying to figure out what is the path to the api. Should the path look look like this? Do I have to enable the API on the server?
https://myserver/tfs/DefaultCollection/MyProject/_apis
If I run this in code like this
var cred = new VssCredentials(
new WindowsCredential(new NetworkCredential("username", "Pass")));
var buildClient = new BuildHttpClient(new Uri("https://myserver/tfs/DefaultCollection/MyProject/_apis", UriKind.Absolute), cred);
await buildClient.CreateDefinitionAsync(buildDef);
I get the following error
Web method running:
[https://myserver/tfs/DefaultCollection/MyProject/_apis]
(OPTIONS)_apis[]
It depends on how the server was setup. If it's a fresh install, the /tfs/ is no longer used. If it's an upgrade the /tfs/ is retained to not break existing clients. And I suspect you can leave off the /_api/ part as well, as that should be automatically added.
The best way to get to the BuildCLient is to use the TFS Server or Collection object and request the server:
var collection = new TfsTeamProjectCollection(tfsCollectionUri, credential);
var buildClient = collection.GetClient<BuildHttpClient>();

Complete TFS Pull Request programmatically

Using the Microsoft.TeamFoundationServer.Client (15.112.1) to connect to a TFS 2017 Update 2 server we can get details about an existing PR like this:
var connection = new VssConnection(collectionUri, credentials);
var client = connection.GetClient<GitHttpClient>();
var pr = await client.GetPullRequestByIdAsync(pullRequestId);
Also, we can create new PR like this:
var pr = await client.CreatePullRequestAsync(
new GitPullRequest
{
SourceRefName = "master",
TargetRefName = "develop",
Title = "[Automatic Merge]"
},
projectName, repositoryName);
In addition, we can vote on the PR like this:
var pr = await client.CreatePullRequestReviewerAsync(
reviewer, projectName, repositoryName, pullRequestId, authorizedIdenity.Id.ToString());
Is there any way to complete the PR (overriding or not existing branch
policies) and proceed with the merge operation?
The GitHttpClient has an UpdatePullRequestAsync method.
To complete the pull request you need to update the Status property of your pull request. and use the UpdatePullRequestAsync method to complete your PR.
Please make sure that to set the the CompletionOptions property to specify whether you are merging the commit, delete the source branch etc.
So your code would look like following
pr.Status = PullRequestStatus.Completed
pr.CompletionOption = new GitPullRequestCompletionOption() { SquashMerge = true };
client.UpdatePullRequest(pr, repositoryId, pullRequestId);
EDIT:
The ByPassPolicy is not available for the released version of Microsoft.TeamFoundationServer.ExtendedClient yet.
However, if you install the pre-release NuGet Package v15.122.1-preview of library Microsoft.TeamFoundationServer.ExtendedClient, you will see the option ByPassPolicy as a property in the GitPullrequestCompletionOptions class. You can set it to true to by pass policy.

Get the URL of the WebAccess for a TFS Team Project programmatically

I want to get the URL of the web access Page for a specific TeamProject.
I found some samples using a TswaClientHyperlinkService object calling GetHomeUrl(new Uri("MyprojectName")), but I was not able to provide a correct Uri value for that. Maybe I did not understand how to format the parameter..
I know how to get the base url for the webaccess, but I want to get to the page for a specific Team Project within a specifc Team Project Collection.
It turns out that the GetHomeUrl method expects a vsts:// url, not the url to the project collection you'd normally use. The following code can be used to get the Uri:
var server = TfsConfigurationServerFactory.GetConfigurationServer(new Uri("http://localhost:8080/tfs" /* your tfs uri here */));
server.Authenticate();
var service = server.GetService<TswaClientHyperlinkService>();
var projectCollection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri("http://localhost:8080/tfs/DefaultCollection"));
var cssService = projectCollection.GetService<ICommonStructureService3>();
var project = cssService.GetProjectFromName(/*YourProjectNameHere*/);
var home = service.GetHomeUrl(new Uri(project.Uri));

Resources