How to query VSTS Work Items with Wiql - tfs

I need to query VSTS work items using Wiql from vsp-node-api package, Please provide any examples if possible.

Refer to following code for details:
import * as vm from 'vso-node-api/WebApi';
import * as wa from 'vso-node-api/WorkItemTrackingApi';
import * as wi from 'vso-node-api/interfaces/WorkItemTrackingInterfaces';
import * as vss from 'vso-node-api/interfaces/Common/VSSInterfaces';
import * as core from 'vso-node-api/interfaces/CoreInterfaces';
var collectionUrl = "https://xxxxxx.visualstudio.com";
let token: string = "PersonalAccessToekn";
let creds = vm.getPersonalAccessTokenHandler(token);
var connection = new vm.WebApi(collectionUrl, creds);
let vstsWI: wa.IWorkItemTrackingApi = connection.getWorkItemTrackingApi();
async function WIQLquery() {
let teamC: core.TeamContext = {project: "", projectId: "", team: "", teamId: "" };
let wiqls: wi.Wiql = { query: "Select [System.Id] From WorkItems Where [System.WorkItemType] = 'Task' And [System.TeamProject] = 'Project'"};
let queryResult: wi.WorkItemQueryResult = await vstsWI.queryByWiql(wiqls, teamC);
queryResult.workItems.forEach(s=>console.log(s.url));
}
WIQLquery();

Here is how I did it, using Javascript instead of Typescript.
Shout out to Eddie Chen for leading me in the right direction.
// file - models/witModel.js
var azdev = require("azure-devops-node-api");
var Model = function(){};
Model.prototype.getWiqlQuery = function(wiqlQuery, teamName){
return new Promise(function(resolve, reject){
const orgUrl = process.env.ADOURI; // ex. https://dev.azure.com/<your org>
const token = process.env.ADOPAT; // Your personal access token
const teamProject = process.env.ADOPROJ;// Team Project
let authHandler = azdev.getPersonalAccessTokenHandler(token);
let connection = new azdev.WebApi(orgUrl, authHandler);
connection.getWorkItemTrackingApi().then(function(witAPI){
var teamContext = {project: teamProject, team: teamName };
witAPI.queryByWiql(wiqlQuery, teamContext).then(function(queryResult){
resolve(queryResult);
}).catch(function(err){reject(err)});
}).catch(function(err){
reject(err);
});
});
};
module.exports = new Model();
And this was how I used it.
// usage - the above code was saved in a module called witModel.js
// feel free to put the module where you need to.
var witModel = require("./models/witModel.js");
// form query and set the value of the teame to query
var query = {query: "your wiql query"};
var team = "team name in Azure DEvops";
// call the promise and handle resolve/reject - then/catch
witModel.getWiqlQueryResuults(query,team).then(function(data){
console.log(data);
}).catch(function(err){
console.log(err)
});

Related

Create team in GraphAPI returns always null

I am using GraphAPI SDK to create a new Team in Microsoft Teams:
var newTeam = new Team()
{
DisplayName = teamName,
Description = teamName,
AdditionalData = new Dictionary<string, object>()
{
{"template#odata.bind", "https://graph.microsoft.com/v1.0/teamsTemplates('standard')"}
},
Members = new TeamMembersCollectionPage()
{
new AadUserConversationMember
{
Roles = new List<String>()
{
"owner"
},
AdditionalData = new Dictionary<string, object>()
{
{"user#odata.bind", $"https://graph.microsoft.com/v1.0/users/{userId}"}
}
}
}
};
var team = await this.graphStableClient.Teams
.Request()
.AddAsync(newTeam);
The problem is that I get always null. According documentation this method returns a 202 response (teamsAsyncOperation), but the AddAsync method from SDK returns a Team object. Is there any way to get the tracking url to check if the team creation has been finished with the SDK?
Documentation and working SDK works different... As they wrote in microsoft-graph-docs/issues/10840, we can only get the teamsAsyncOperation header values if we use HttpRequestMessage as in contoso-airlines-teams-sample. They wrote to the people who asks this problem, look to the joined teams :)) :)
var newTeam = new Team()
{
DisplayName = model.DisplayName,
Description = model.Description,
AdditionalData = new Dictionary<string, object>
{
["template#odata.bind"] = $"{graph.BaseUrl}/teamsTemplates('standard')",
["members"] = owners.ToArray()
}
};
// we cannot use 'await client.Teams.Request().AddAsync(newTeam)'
// as we do NOT get the team ID back (object is always null) :(
BaseRequest request = (BaseRequest)graph.Teams.Request();
request.ContentType = "application/json";
request.Method = "POST";
string location;
using (HttpResponseMessage response = await request.SendRequestAsync(newTeam, CancellationToken.None))
location = response.Headers.Location.ToString();
// looks like: /teams('7070b1fd-1f14-4a06-8617-254724d63cde')/operations('c7c34e52-7ebf-4038-b306-f5af2d9891ac')
// but is documented as: /teams/7070b1fd-1f14-4a06-8617-254724d63cde/operations/c7c34e52-7ebf-4038-b306-f5af2d9891ac
// -> this split supports both of them
string[] locationParts = location.Split(new[] { '\'', '/', '(', ')' }, StringSplitOptions.RemoveEmptyEntries);
string teamId = locationParts[1];
string operationId = locationParts[3];
// before querying the first time we must wait some secs, else we get a 404
int delayInMilliseconds = 5_000;
while (true)
{
await Task.Delay(delayInMilliseconds);
// lets see how far the teams creation process is
TeamsAsyncOperation operation = await graph.Teams[teamId].Operations[operationId].Request().GetAsync();
if (operation.Status == TeamsAsyncOperationStatus.Succeeded)
break;
if (operation.Status == TeamsAsyncOperationStatus.Failed)
throw new Exception($"Failed to create team '{newTeam.DisplayName}': {operation.Error.Message} ({operation.Error.Code})");
// according to the docs, we should wait > 30 secs between calls
// https://learn.microsoft.com/en-us/graph/api/resources/teamsasyncoperation?view=graph-rest-1.0
delayInMilliseconds = 30_000;
}
// finally, do something with your team...
I found a solution from another question... Tried and saw that it's working...

ask for version control server (client) from VssConnection

Dears
Please help me to work with VssConnection from Microsoft.VisualStudio.Services.Client.15.134.0-preview package
I need to get pending changes for workspace, query it for conflict and commit
This is how i do it with TfsTeamProjectCollection and
var vssCred = new VssClientCredentials();
using (TfsTeamProjectCollection collection = new TfsTeamProjectCollection(uri, vssCred))
{
collection.Authenticate();
var scs = collection.GetService<VersionControlServer>();
var scsProject = scs.GetTeamProject(teamProjectName);
var workspace = scsProject.VersionControlServer.GetWorkspace(localPath);
var pending = scs.QueryPendingSets(new string[] { "$/" }, RecursionType.Full, workspace.Name, loginName);
if (pending.Any())
{
var pendingChanges = new[] { pending.First().PendingChanges.First() };
var validation = workspace.EvaluateCheckin2(CheckinEvaluationOptions.Conflicts, pendingChanges, "", null, null);
var conflicts = validation.Conflicts;
if (conflicts != null && conflicts.Any())
{
var message = string.Join("\r\n", conflicts.Select(_ => string.Format("{0} {1}", _.Message, _.ServerItem)));
throw new ArgumentException(string.Format("conflict was found\r\n{0}", message));
}
var res = workspace.CheckIn(pendingChanges, "test checkin");
TestContext.WriteLine("checked in {0}", res);
}
}
However there are vsts integration samples that uses VssConnection object
How can I get the same VersionControlServer from VssConnection instance?
I've tried to find Microsoft.TeamFoundation.VersionControl.Client.WebAPi (like Microsoft.TeamFoundation.WorkItemTracking.WebApi) but failed.
var vssCred = new VssClientCredentials();
using (VssConnection connection = new VssConnection(uri, vssCred))
{
var prj = connection.GetClient<ProjectHttpClient>();
var p = prj.GetProject(teamProjectName).Result;
//i'd like to get prj.VersionControl here
//or something like var scs = connection.GetService<VersionControlServer>();
}
Is it possible to get versionControlServer from VssConnection? Should I continue to use TfsTeamProjectCollection to do this task?
You could use TfsTeamProjectCollection as before, as there is no workspace method in VssConnection:
TfvcHttpClient tfvcClient = connection.GetClient<TfvcHttpClient>();
List <TfvcItem> tfvcItems = tfvcClient.GetItemsAsync("$/", VersionControlRecursionType.OneLevel).Result;
More examples, you can refer to the link below:
https://learn.microsoft.com/en-us/vsts/integrate/get-started/client-libraries/samples?view=vsts

How to get certificate for Azure Automation Client

I need to create automaion client for Azure webhook.
Following code is written by me to get AutomationManagementClient Value.
var cert = new X509Certificate2(Convert.FromBase64String(ConfigurationManager.AppSettings["CertBase64String"]));
var creds[![enter image description here][1]][1] = new CertificateCloudCredentials(ConfigurationManager.AppSettings["SubscriptionId"], cert);
AutomationManagementClient automationManagementClient = new AutomationManagementClient(creds);
I need that certificate string i.e. CertBase64String value as I don't know from where I will get that value.
Help me...
This error I am getting after updating as per your answer.
If you want to create the automation client, I suggest you try to use the ARM way to operate the automation. The following is the demo code works correctly on my side.
Prepare: Registry an AD application and assign role to applcation, more details please refer to Azure official tutorials. After that we can get tenantId, appId, secretKey from the Azure Portal.
We could use the following code to get the token
var tenantId = "tenantId";
var context = new AuthenticationContext($"https://login.windows.net/{tenantId}");
var clientId = "application Id";
var clientSecret = "client secret";
var resourceGroup = "resource group";
var automationAccount = "automationAccount";
var subscriptionId = "susbscriptionId";
var token = context.AcquireTokenAsync(
"https://management.azure.com/",
new ClientCredential(clientId, clientSecret)).Result.AccessToken;
if you use the Microsoft.Azure.Management.Automation Version <= 2.0.4 please try the following code.
var automationClient = new AutomationManagementClient(new TokenCloudCredentials(subscriptionId,token));
var webhook = automationClient.Webhooks.CreateOrUpdate(resourceGroup, automationAccount,new WebhookCreateOrUpdateParameters
{
Properties = new WebhookCreateOrUpdateProperties
{
ExpiryTime = DateTimeOffset.Now.AddDays(1),
IsEnabled = false,
Parameters = parameters,
Runbook = new RunbookAssociationProperty
{
Name = "xxxx"
},
Name = "xxxx",
Uri = "https://xxxx.xx"
}
});
if use the Microsoft.Azure.Management.Automation Version 3.0.0-preview, please try to the following case.
var automationClient = new AutomationClient(new TokenCredentials(token)) {SubscriptionId = subscriptionId};
var webhook = automationClient.Webhook.CreateOrUpdate(resourceGroup, automationAccount, "webhookName",
new WebhookCreateOrUpdateParameters
{
ExpiryTime = DateTime.Now.AddDays(1),
IsEnabled = false,
Parameters = parameters,
Name = "xxxxx",
Runbook = new RunbookAssociationProperty
{
Name = "xxxxx"
},
Uri = "https://xxx.xxx"
});
Update:
You could set the Parameters = null or if you have parameter, you could define the parameters as dictionary. Please also add the Name = "xxxx" in the code.
var parameters = new Dictionary<string, string> {{"test", "test"}};
var webhook = automationClient.Webhooks.CreateOrUpdate(resourceGroup, automationAccount,new WebhookCreateOrUpdateParameters
{
Properties = new WebhookCreateOrUpdateProperties
{
ExpiryTime = DateTimeOffset.Now.AddDays(1),
IsEnabled = false,
Parameters = parameters,
Runbook = new RunbookAssociationProperty
{
Name = "xxxx"
},
Name = "xxxx",
Uri = "https://xxxx.xx"
}
});
I test it on my side, it works correctly
"CertBase64String" will get by passing thumb-print of that certificate to following fucntion.
internal static X509Certificate2 GetCertificateFromthumbPrint(String certThumbPrint) {
X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
certStore.Open(OpenFlags.ReadOnly);
//Find the certificate that matches the thumbprint.
X509Certificate2Collection certCollection = certStore.Certificates.Find(X509FindType.FindByThumbprint, certThumbPrint, false);
certStore.Close();
//Get the first cert with the thumbprint
X509Certificate2 cert = (certCollection.Count > 0) ? certCollection[0] : null;
return cert;
}

Fetch latest checked in information using TfvcHttpClient Class

Trying to fetch latest checked in information using TfvcHttpClient class from a specific folder in Team Foundation Server using its client API from a console application.
Please help how can I achieve it? I have personal access token and below mentioned is able to connect by using it:
Code:
string uri = _uri;
string personalAccessToken = _personalAccessToken;
string project = _project;
string credentials = Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", "", personalAccessToken)));
//create wiql object
var wiql = new
{
query = "Select [State], [Title] " +
"From WorkItems " +
"Where [Work Item Type] = 'Bug' " +
"And [System.TeamProject] = '" + project + "' " +
"And [System.State] <> 'Closed' " +
"Order By [State] Asc, [Changed Date] Desc"
};
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(uri);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", credentials);
//serialize the wiql object into a json string
var postValue = new StringContent(JsonConvert.SerializeObject(wiql), Encoding.UTF8, "application/json"); //mediaType needs to be application/json for a post call
//send query to REST endpoint to return list of id's from query
var method = new HttpMethod("POST");
var httpRequestMessage = new HttpRequestMessage(method, uri + "/_apis/wit/wiql?api-version=2.2") { Content = postValue };
var httpResponseMessage = client.SendAsync(httpRequestMessage).Result;
}
I have tried below mentioned code for achieving:
VssConnection connection = new VssConnection(serverUrl, new
VssBasicCredential(string.Empty, _personalAccessToken));
var buildServer = connection.GetClient<BuildHttpClient>(); // connect to the build server subpart
var sourceControlServer = connection.GetClient<Microsoft.TeamFoundation.SourceControl.WebApi.TfvcHttpClient>(); // connect to the TFS source control subpart
var changesets = buildServer.GetChangesBetweenBuildsAsync("client-rsa", 1, 5).Result;
foreach (var changeset in changesets)
{
var csDetail = sourceControlServer.GetChangesetAsync("client-rsa", Convert.ToInt32(changeset.Id.Replace("C", string.Empty).Trim()), includeDetails: true).Result;
var checkinNote = csDetail.CheckinNotes?.FirstOrDefault(_ => _.Name == "My check-in note");
if (checkinNote != null)
{
Console.WriteLine("{0}: {1}", changeset.Id, changeset.Message);
Console.WriteLine("Check-in note: {0}", checkinNote.Value);
}
else
Console.WriteLine("Warning: {0} has no check-in note", changeset.Id);
}
Here is the simple sample code which use TfvcHttpClient to get the latest changeset information:
string purl = "https://xxx.visualstudio.com";
string projectname = "projectname";
VssCredentials creds = new VssClientCredentials();
creds.Storage = new VssClientCredentialStorage();
VssConnection vc = new VssConnection(new Uri(purl),creds);
TfvcHttpClient thc = vc.GetClient<TfvcHttpClient>();
TfvcChangesetSearchCriteria tcsc = new TfvcChangesetSearchCriteria();
//Specify the server path of the folder
tcsc.ItemPath = "$/XXXX/XXXX";
//Get the entire history of the specified path
List<TfvcChangesetRef> changerefs = thc.GetChangesetsAsync(projectname,null,null,null,null,tcsc).Result;
//Get the latest changeset ref
TfvcChangesetRef changeref = changerefs.First();
//Get the changeset
TfvcChangeset changeset = thc.GetChangesetAsync(projectname,changeref.ChangesetId).Result;
//Get the detailed changes
List<TfvcChange> changes = thc.GetChangesetChangesAsync(changeref.ChangesetId).Result;
foreach (TfvcChange cg in changes)
{
//Code to read detail information
}

Run firebase cloud function when a key is a specific value

const functions = require('firebase-functions');
var IAPVerifier = require('iap_verifier');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.verifyReceipt = functions.database.ref('/Customers/{uid}/updateReceipt')
.onWrite(event => {
const uid = event.params.uid;
var receipt = event.data.val();
(strReceipt).toString('base64');
var client = new IAPVerifier('IAP_secretkey')
client.verifyAutoRenewReceipt(receipt, true,function(valid, msg, data){
console.log(' RECEIPT');
if(valid) {
console.log('VALID RECEIPT');
console.log('msg:' + msg);
var strData = JSON.stringify(data);
console.log('data"' + strData);
const newReceiptRef = admin.database().ref('/Customers/{uid}/');
newReceiptRef.update({'receiptData1': data});
const recVerRef = admin.database().ref('/Customers/{uid}/');
newReceiptRef.update({'updateReceipt': 0});
// update status of payment in your system
}else{
console.log('INVALID RECEIPT');
console.log('msg:' + msg);
var strData = JSON.stringify(data);
console.log('data"' + strData);
}
});
});
This is my node js cloud function. The possible values for 'updateReceipt' are 0 and 1. Is it possible to run the cloud function only when the value is 1?
Thanks.
There is no way to only trigger the function when a specific value is present.
I can think of two options:
Write the nodes to a different branch depending on the updateReceipt value.
Add an if to your code.
The second options is definitely the simplest:
exports.verifyReceipt =
functions.database.ref('/Customers/{uid}/updateReceipt')
.onWrite(event => {
const uid = event.params.uid;
var receipt = event.data.val();
if (receipt.updateReceipt === 0) {
var client = new IAPVerifier('IAP_secretkey')
...
Alternatively, you can keep the updated receipt in a separate branch from the new receipts. That way you can trigger a function separately for just the new receipts.

Resources