Guest post: Integrare un’applicazione o un servizio con Visual Studio Online
Questo post è stato scritto da Davide Benvegnù di DotNetToscana .
Visual Studio Online, al pari della sua versione on-premise Team Foundation Server, fornisce moltissime funzionalità già incluse. Spesso, però, in scenari complessi la gestione del ciclo di vita del software richiede delle integrazioni con applicazioni o servizi esterni.
Ad esempio, potrebbe essere utile aggiungere un nuovo Work Item ad un nostro Team Project in modo automatico, magari in risposta ad un determinato evento. Oppure essere notificati dell’avverarsi di determinate condizioni (penso ad esempio ad una Build andata male). O ancora poter controllare il nostro account Visual Studio Online tramite device mobili.
Metodi di integrazione
Grazie alle nuove funzionalità introdotte, ora Visual Studio Online offre diverse possibilità di integrazione con altri strumenti e servizi.
È possibile, ad esempio:
· Integrare VSO con i più popolari servizi cloud come Trello, GitHub, Jenkins, HipChat e molti altri
· Sviluppare applicazioni e servizi custom che estendono la potenzialità di Visual Studio Online
· Interrogare e/o utilizzare VSO da qualsiasi piattaforma (anche mobile)
Ci sono principalmente due metodi per integrarsi con Visual Studio Online:
· REST API
· Service Hooks
Sebbene entrambi i metodi sono attualmente in preview (rilasciati con l’update del 12 Maggio), sono perfettamente funzionanti.
REST API: Panoramica
Le REST API, nella loro ultima versione 1.0 preview Update 2 (rilasciata il 4 settembre), permettono a chi le consuma di interagire con praticamente tutte le componenti di Visual Studio Online.
Come dice il nome, sono API che sfruttano il protocollo REST ed utilizzano Json sia come input nei request body (di solito utilizzati per operazioni di POST, PUT e PATCH) che come output delle response.
Tutte le richieste verso le API devono seguire questo pattern:
https:// {account} .VisualStudio.com/DefaultCollection/_apis[/ {area} ]/ {resource} ?api-version=1.0-preview.2
dove “account” sarà il nome dell’account che si vuole usare, “area” il servizio esposto dalle api su cui si vuole operare (l’elenco completo delle aree è disponibile a questa pagina) e “resource” il tipo di risorsa su cui andare ad insistere. Inoltre si noti che la versione delle API deve essere specificata.
Ad esempio, per creare un nuovo Task su un Team Project di nome “tpTest” di un VSO account chiamato “myvso”, l’url della richiesta sarà:
REST API: Autenticazione
È importante sottolineare che queste API richiedono l’autenticazione al servizio, che può essere di due tipi: Basic e OAuth 2.0.
Per poter utilizzare l’autenticazione di tipo “Basic” è necessario abilitare le “alternate credentials” per l’account VSO dall’apposito pannellino del portale.
Per poter usare le Alternate Credentials basta entrare sul portale di VSO con l’account a cui si vogliono abilitare, cliccare sul nome utente in alto a destra e scegliere “My Profile”. A questo punto è sufficiente posizionarsi sulla tab “Credentials”, cliccare “Enable alternate credentials” ed inserire la password ed, eventualmente, un username secondario (utile se l’applicazione che vogliamo integrare non supporta il login con un indirizzo email)
Dopo aver eseguito questi passaggi è possibile utilizzarle per l’interazione con la API. Se ad esempio stiamo implementando un’applicazione .Net possiamo utilizzare la classe HttpClient come nell’esempio seguente, dove è riportato anche come costruire correttamente la richiesta (in questo caso una richiesta per recuperare tutte le build di un determinato account):
using System.Net.Http;
using System.Net.Http.Headers;
public static async void GetBuilds()
{
try
{
var username = "username";
var password = "password";
var account = "account";
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(
new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(
System.Text.ASCIIEncoding.ASCII.GetBytes(
string.Format("{0}:{1}", username, password))));
using (HttpResponseMessage response = client.GetAsync("https://" + account +
".visualstudio.com/DefaultCollection/_apis/build/builds").Result)
{
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseBody);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
Con l’autenticazione Basic possono essere utilizzate tutte le aree delle API ad eccezione di “Accounts” e “Profiles”, che quindi possono essere consumate solo utilizzando l’autenticazione OAuth.
REST API: Autenticazione con OAuth 2.0
Sebbene sia possibile, come abbiamo visto, integrarsi con Visual Studio Online usando il metodo di autenticazione Basic, è preferibile utilizzare il protocollo OAuth 2.0 per autorizzare le applicazioni di terze parti e generare un token di accesso. Questo token va utilizzato al posto delle credenziali quando si chiamano le REST API dall’applicazione.
Per usare l’autenticazione con OAuth per prima cosa è necessario registrare l’applicazione su Visual Studio Online (attraverso il portale https://app.vssps.visualstudio.com/app/register) ed ottenere quindi un ID univoco. La prima volta che un nuovo utente userà l’applicazione, dovrà essere fatta una chiamata alle API con quell’ID; VSO si occuperà in autonomia di autenticare l’utente e di generare un token per lui visualizzando una finestra simile alla seguente:
A questo punto ogni volta che il nostro utente utilizzerà di nuovo l’applicazione non dovrà più effettuare il login ma basterà utilizzare il token salvato. (Attenzione che tale token ha una validità limitate nel tempo, quindi alla scadenza sarà necessario rigenerarlo).
Il flusso completo di autenticazione tramite OAuth è descritto dallo schema seguente:
REST API: Utilizzo
Precedentemente, abbiamo visto in un esempio come recuperare le build di un account. Vediamo ora come è possibile creare un Work Item utilizzando le API.
Per farlo, è necessario effettuare una richiesta HTTP PATCH e valorizzare il body della request in base a questo formato:
[
{
"op": "add",
"path": { string }
"value": { string or int, depending on the field }
},
{
"op": "add",
"path": "/relations/-",
"value":
{
"rel": { string },
"url": { string },
"attributes":
{
{ name/value pairs }
}
}
}
]
Un esempio reale di creazione di un task con titolo e descrizione, riprendendo l’url riportato precedentemente ed impostando il Content-type della request a “application/json-patch+json”, sarà:
[
{
"op": "add",
"path": "/fields/System.Title",
"value": "Change blog title height"
},
{
"op": "add",
"path": "/fields/System.Description",
"value": "This is the task description"
},
]
Questa richiesta produce una response come la seguente, in cui si possono trovare tutte le informazioni relative al work item appena creato:
{
"id": 88,
"rev": 1,
"fields": {
"System.AreaPath": "tpTest",
"System.TeamProject": "tpTest",
"System.IterationPath": "tpTest",
"System.WorkItemType": "Task",
"System.State": "To Do",
"System.Reason": "New task",
"System.CreatedDate": "2014-09-30T10:25:12.943Z",
"System.CreatedBy": "Davide Benvegnu",
"System.ChangedDate": "2014-09-30T10:25:12.943Z",
"System.ChangedBy": "Davide Benvegnu,
"System.Title": "Change blog title height",
"System.Description: "This is the task description"
},
"_links": {
"self": {
"href": "https://myvso.visualstudio.com/DefaultCollection/_apis/wit/workItems/88"
},
"workItemUpdates": {
"href": "https://myvso.visualstudio.com/DefaultCollection/_apis/wit/workItems/88/updates"
},
"workItemRevisions": {
"href": "https://myvso.visualstudio.com/DefaultCollection/_apis/wit/workItems/88/revisions"
},
"workItemHistory": {
"href": "https://myvso.visualstudio.com/DefaultCollection/_apis/wit/workItems/88/history"
},
"html": {
"href": "https://myvso.visualstudio.com/web/wi.aspx?pcguid=0fa87894-6f48-4458-957d-3438b6bb9343&id=88"
},
"workItemType": {
"href": "https://myvso.visualstudio.com/DefaultCollection/c4637008-2068-4b3f-828d-a214e2ba5210/_apis/wit/workItemTypes/Task"
},
"fields": {
"href": "https://myvso.visualstudio.com/DefaultCollection/_apis/wit/fields"
}
},
"url": "https://myvso.visualstudio.com/DefaultCollection/_apis/wit/workItems/88"
}
In modo similare è possibile, ad esempio, interrogare l’area relativa al source control e verificare quali modifiche sono state effettuate in un determinato changeset:
Verb e Url della richiesta:
Response:
{
"count": 1,
"value": {
"item": {
"version": 6,
"path": "$/tpTest/Models/IdentityDbInitializer.cs",
"url": "https://myvso.visualstudio.com/DefaultCollection/_apis/tfvc/items/%24/tpTest/Models/IdentityDbInitializer.cs?versionType=Changeset&version=6"
},
"changeType":"edit"
}
}
Service Hooks
Tramite i service hooks è possibile integrarsi a Visual Studio Online sottoscrivendo una serie di eventi che sono scatenati dal servizio.
Allo stato attuale questi sono gli eventi sottoscrivibili:
· Build completed
· Code pushed (Git team projects)
· Code checked in (TFVC team projects)
· Work item created
· Work item updated
· Comments added to work item
È possibile creare una sottoscrizione ad uno o più eventi; si riferirà ad uno specifico Team Project, sarà consumata da un “consumer” e scatenerà una specifica “action”.
È possibile creare una sottoscrizione ad un evento in modo “automatico” (utilizzando cioè il portale di Visual Studio Online) oppure in modo completamente manuale utilizzando le REST API, che sono quindi parte integrante anche di questa funzionalità.
Service Hooks: sottoscrizioni da pannello
Utilizzare il pannello di VSO per creare una sottoscrizione ad un Service Hooks è sicuramente il modo più veloce per utilizzare questa feature.
È sufficiente entrare nel portale del Team Project a cui ci si vuole sottoscrivere e cliccare sul pulsante delle impostazioni (quello con l’ingranaggio, in alto a destra). Le ultime due tab sono quelle relative ai Service Hooks: la prima, omonima, serve per creare le sottoscrizioni e la seconda, denominata semplicemente “Services”, serve per monitorare le sottoscrizioni esistenti.
Per creare una sottoscrizione è innanzitutto necessario scegliere a che tipo di servizio sarà destinata.
Ovviamente a seconda del tipo di consumer selezionato saranno disponibili o meno alcuni eventi ed azioni.
Scelto il servizio da integrare, è necessario configurare l’evento a cui la sottoscrizione si riferirà ed è possibile inserire dei filtri (che dipendono dal tipo di evento selezionato) in modo da limitare la sottoscrizione a ciò che realmente ci interessa.
In questo caso ho deciso di sottoscrivere l’evento generato dal completamento delle Build, solo in caso che le Build siano fallite.
Configurato l’evento, si passa alla configurazione dei parametri del consumer. Vanno indicati gli endpoint e tutti i parametri necessari per poter effettivamente inviare una notifica. Nel mio esempio, ho deciso di utilizzare uno Storage Account su Azure:
Inseriti tutti i valori è possibile effettuare un test di integrazione (con l’apposito pulsante “Test”) e, se tutto ok, completare la creazione della subscription.
Da questo momento ogni volta che sul progetto selezionato una Build fallirà, VSO salverà automaticamente le informazioni sul mio Storage Account.
Service Hooks: sottoscrizioni via API
È possibile creare delle sottoscrizioni anche utilizzando una chiamata alle API. In questo caso non è possibile utilizzare l’autenticazione Basic ma solo quella con OAuth 2.0.
L’url da chiamare per la request, utilizzando il Verb POST, è:
https://{account}.visualstudio.com/defaultcollection/_apis/hooks/subscriptions?api-version=1.0-preview.1
Il request body deve essere costruito con i valori specifici per il Team Project, l’evento, il consumer e l’action che vogliamo configurare.
Ad esempio, per una configurazione simile a quella vista precedentemente, il body sarà come il seguente:
{
"publisherId": "tfs",
"eventType": "build.complete",
"resourceVersion": "1.0-preview.1",
"consumerId": "azureStorageQueue",
"consumerActionId": "enqueue",
"publisherInputs": {
"buildStatus": "failed",
"definitionName": "Continuous Integration",
"projectId": "56479caf-1eeb-4bca-86ab-aaa6f29399d9",
},
"consumerInputs": {
"accountName": "MyStorage",
"accountKey": "abcdefghijklmnopqrstuvzabcdefghijklmnopqrstuvzabcdefghijklmnopqrstuvz",
"queueName": "tptestfailedbuilds",
"visiTimeout": "0",
"ttl": "604800",
},
}
Per la lista completa dei valori per “eventType”, “consumerId”, “consumerActionId” ed i parametri relativi all’evento ed al consumer è possibile consultare questa reference.
Conclusioni
Usando le REST API ed i Service Hooks è possibile estendere Visual Studio Online a tutti gli scenari possibili, anche grazie al formato REST e Json che rendono disponibili le funzionalità su qualsiasi piattaforma e in qualsiasi contesto.