¡Compártelo!

Creación de un proyecto DevOps con Azure PowerShell

En este post veremos cómo crear un proyecto en Azure DevOps, asignar a los usuarios a un grupo y vincular ese grupo al proyecto, además de la creación de un repositorio y librerías, todo ello utilizando un script de PowerShell. La finalidad es poder crear un script de automatización y para ahorrar tiempo al generar la estructura base de nuestros proyectos.

Lo primero que debemos tener en cuenta es que deberemos tener instalado Visual Studio u otra herramienta con la que podamos crear y ejecutar nuestro script. Una vez llegados a este punto, lo primero que definiremos en nuestro script será una serie de variables y funciones que nos servirán a lo largo de todo el desarrollo.

Variables y métodos que debemos definir en primer lugar

En primer lugar, debemos definir las siguientes variables.

$Organization="Profile"
$ProjectName="Proyecto"
$ProjectDescription="Proyecto creado desde prowershell"
$ProcessTemplateName = "Scrum"
$repositoryName= "mirepositorio"

También crearemos dos métodos para nuestras peticiones Get y Post, para no tener que repetir código.

function Headers-Get(){

$encodedBytes = [System.Text.Encoding]::UTF8.GetBytes("profile:$env:AZURE_DEVOPS_EXT_PAT")
$base64PAT = [convert]::ToBase64String($encodedBytes)
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Authorization", "Basic $base64PAT")

$headers
}
function Headers-Post(){

$encodedBytes = [System.Text.Encoding]::UTF8.GetBytes("profile:$env:AZURE_DEVOPS_EXT_PAT")
$base64PAT = [convert]::ToBase64String($encodedBytes)
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Authorization", "Basic $base64PAT")
$headers.Add("Content-Type", "application/json")

$headers

}

Pasos a seguir para crear un proyecto en Azure DevOps

Lo primero que tenemos que realizar es la recuperación del ID de la plantilla Scrum (template que usaremos para nuestro proyecto) según nuestra organización, para ello ejecutaremos el siguiente código. Obteniendo como resultado el objeto de la plantilla.

$headers= Headers-Get

$response = Invoke-RestMethod "https://dev.azure.com/$($Organization)/_apis/process/processes?api-version=7.1-preview.1" -Method 'GET' -Headers $headers

$template = $response.value | Where-Object { $_.name -eq $ProcessTemplateName }

Para crear el proyecto debemos tener en cuenta la petición que debemos realizar.

POST https://dev.azure.com/{organization}/_apis/projects?api-version=7.0

Una vez que tenemos dicha información, pasaremos a crear el cuerpo de la petición y realizaremos la llamada a la API, para que cree el proyecto.

$headers= Headers-Post
    
$body = "{
      `n  `"name`": `"$($ProjectName)`",
      `n  `"description`": `"$($ProjectDescription)`",
      `n  `"capabilities`": {
      `n    `"versioncontrol`": {
      `n      `"sourceControlType`": `"Git`"
      `n    },
      `n    `"processTemplate`": {
      `n      `"templateTypeId`": `"$($template.id)`"
      `n    }
      `n  }
      `n}"
      
Invoke-RestMethod "https://dev.azure.com/$($Organization)/_apis/projects?api-version=7.1-preview.4" -Method 'POST' -Headers $headers -Body $body
  

Con esto ya tendremos creado nuestro proyecto.

Creación de grupos, asignación de usuarios y roles

Ahora vamos a crear un grupo donde estarán, por ejemplo, los developers del proyecto. Podemos crear diferentes grupos, según nuestras necesidades, para gestionar nuestro proyecto.

$GroupName="Developers"

En primer lugar, recuperaremos el ID del proyecto que hemos generado.

$headers= Headers-Get

$response = Invoke-RestMethod "https://dev.azure.com/$($Organization)/_apis/projects/$($ProjectName)?api-version=7.0" -Method 'GET' -Headers $headers

$ProjectId =$response.id

Una vez que hayamos obtenido el identificador de proyecto, buscaremos el ScopeDescriptor del mismo. Para ello, realizaremos la siguiente petición.

$headers= Headers-Get

$response = Invoke-RestMethod "https://vssps.dev.azure.com/$($Organization)/_apis/graph/descriptors/$($ ProjectId)?api-version=6.0-preview.1" -Method 'GET' -Headers $headers

$projectDescriptor = $response.value

Ahora ya tenemos todos los datos necesarios para crear el grupo.

$headers= Headers-Post
    
$body = "{
      `n  `"displayName`": `"$($GroupName)`",
      `n  `"description`": `"$($GroupName)`"
      `n}"
  
  
$grupo = Invoke-RestMethod "https://vssps.dev.azure.com/$($Organization)/_apis/graph/groups?scopeDescriptor=$($projectDescriptor)&api-version=5.0-preview.1" -Method 'POST' -Headers $headers -Body $body

Para añadir un usuario a nuestro grupo realizaremos los siguientes pasos:

Lo primero, es recuperar el SubjectDescriptor del usuario y luego asignarlos al grupo.

$ListMembersDevelopment = @("mail1@mail.com","mail2@mail.com",…)

# recorremos todos los miembros 
foreach ($member in $ListMembersDevelopment){

#recuperamos el subjectdescriptor del miembro
      $headers= Headers-Get


$response = Invoke-RestMethod "https://vssps.dev.azure.com/$($Organization)/_apis/identities?api-version=6.0&searchFilter=General&filterValue=$($member)" -Method 'GET' -Headers $headers
    
$userDescriptors = $response.value[0].subjectDescriptor

#peticion para asignar al grupo
      foreach ($userDescriptor in $userDescriptors) {
             $headers= Headers-Get

Invoke-RestMethod "https://vssps.dev.azure.com/$($Organization)/_apis/graph/memberships/$($userDescriptor)/$($grupo.descriptor)?api-version=5.0-preview.1" -Method 'PUT' -Headers $headers
  }
  
}

Creación de un repositorio en Azure DevOps

Lo primero que haremos será recuperar el ID del proyecto al cual queremos añadir un nuevo repositorio. Para ello, realizaremos una llamada GET a nuestro Azure con la siguiente estructura de URL:

GET https://dev.azure.com/{organization}/_apis/projects/{projectId}?api-version=7.0

Por lo tanto, nuestro código resultante sería de la siguiente manera:

$headers= Headers-Get

$Project = Invoke-RestMethod "https://dev.azure.com/$($Organization)/_apis/projects/$($ProjectName)?api-version=7.1-preview.4" -Method 'GET' -Headers $headers

Para recuperar el ID de nuestro proyecto, utilizaremos la variable en la que se ha guardado la respuesta del Invoke.

$projectId = $Project.id

Ahora que ya tenemos el ID de nuestro proyecto, procederemos a la creación de un nuevo repositorio asignado al proyecto.

Lo primero que debemos tener en cuenta es la URL a la que se realizará la llamada, la cual es:

POST https://dev.azure.com/{organization}/{project}/_apis/git/repositories?api-version=7.0

Y debemos crear el cuerpo de la petición, en el cual indicaremos el ID del proyecto recuperado y el nombre de nuestro repositorio, siguiendo la siguiente estructura:

$body = "{
    `n  `"name`": `"$($repositoryName)`",
    `n  `"project`": {
    `n      `"id`": `"$($projectId)`"
    `n    }
    `n}"

Como consecuencia, nuestro código resultante sería el siguiente:

$headers= Headers-Post

$url = "https://dev.azure.com/$($Organization)/_apis/git/repositories?api-version=7.0"

$body = "{
    `n  `"name`": `"$($repositoryName)`",
    `n  `"project`": {
    `n      `"id`": `"$($projectId)`"
    `n    }
    `n}"

Invoke-WebRequest -Uri $url -Method POST -Headers $headers -Body $body -ContentType "application/json" 

Si todo ha ido correctamente, obtendremos una respuesta 200, que indica que se ha creado el repositorio.

Una vez que sabemos cómo recuperar el ID del proyecto y cómo crear un repositorio en ese proyecto, intentaremos unificar todo el código asignando valores a nuestras variables.

$headers= Headers-Get

$Project = Invoke-RestMethod "https://dev.azure.com/$($Organization)/_apis/projects/$($ProjectName)?api-version=7.1-preview.4" -Method 'GET' -Headers $headers

$projectId = $Project.id


$headers= Headers-Post
  
$url = "https://dev.azure.com/$($Organization)/_apis/git/repositories?api-version=7.0"

$body = "{
    `n  `"name`": `"$($repositoryName)`",
    `n  `"project`": {
    `n      `"id`": `"$($projectId)`"
    `n    }
    `n}"

Invoke-WebRequest -Uri $url -Method POST -Headers $headers -Body $body -ContentType "application/json" 

Si, por el contrario, deseas crear más de un repositorio para nuestro proyecto, solo habría que duplicar el body, modificando el nombre del repositorio, y duplicar la línea de Invoke. Aunque otra forma de realizar esta operación es realizar una pequeña modificación a la hora de llamar al invoke de creación.

@("repo001", "repo002") | ForEach-Object {
    $name = $_
    $body = @"
{
    "name": "$name",
    "project": {
        "id": "$projectId"
    }
}
"@
    Invoke-WebRequest -Uri $url -Method POST -Headers $headers -Body $body -ContentType "application/json" 
}

Creación de variables Vsts

Para crear variables de entorno en nuestro apartado Pipelines > Library, debemos tener en cuenta la petición que debemos realizar, la cual es la siguiente:

POST https://dev.azure.com/{organization}/_apis/serviceendpoint/endpoints?api-version=7.0

Lo primero que rellenaremos será, como siempre, nuestra cabecera que enviaremos en la solicitud, la URL con los parámetros necesarios y el projectId previamente recuperado. A continuación, configuraremos el cuerpo del mensaje con toda la información necesaria.

  • Por ejemplo, vamos a crear un grupo de variables llamado «GRUPO_VARIABLES» que incluirá las siguientes variables: ENTORNO: PRE y PERTENECE_SISTEMA: SI.
$body = "{
            `n `"name`":`"GRUPO_VARIABLES`",
            `n `"type`":`"Vsts`",
            `n `"variables`":{
                `n `"ENTORNO`":{ `"isSecret`":false, `"value`": `"PRE)`" },
                `n `" PERTENECE_SISTEMA `":{ `"isSecret`":false, `"value`": `"SI`" }
                `n },
                `n `"variableGroupProjectReferences`":[{
                `n    `"name`":`"GRUPO_VARIABLES`",
                `n    `"projectReference`":{
                `n         `"id`":`"$($ProjectId)`"  
                        }
                }]
        }"

Como resultado de todos los pasos, el fragmento de código debería quedar de la siguiente manera:

$headers= Headers-Post

$url = "https://dev.azure.com/$($Organization)/_apis/distributedtask/variablegroups?api-version=7.0"       
 $body = "{
            `n `"name`":`"$($GroupName)`",
            `n `"type`":`"Vsts`",
            `n `"variables`":{
                `n `"ENTORNO`":{ `"isSecret`":false, `"value`": `"$($Entorno)`" },
                `n `"GRUPOS`":{ `"isSecret`":false, `"value`": `"$($VarGrupos)`" }
                `n },
                `n `"variableGroupProjectReferences`":[{
                `n    `"name`":`"$($GroupName)`",
                `n    `"projectReference`":{
                `n         `"id`":`"$($ProjectId)`"  
                        }
                }]
        }"
    Invoke-WebRequest -Uri $url -Method POST -Headers $headers -Body $body -ContentType "application/json"

Conclusión

Aunque en este artículo solo se ha visto una pequeña pincelada de lo que podemos hacer con la API de Azure DevOps mediante llamadas desde PowerShell, hay que tener en cuenta que automatizar la creación de proyectos es algo complejo, pero que ahorrará una gran cantidad de tiempo. La creación manual es un proceso que puede llevar varias horas, mientras que generando un script que se encargue de ello, reduciríamos el tiempo a unos minutos. Espero que esta breve introducción a la automatización de proyectos en Azure DevOps mediante la ejecución de un script les haya resultado gratificante.

Para no perderte ningún artículo sobre desarrollo, ¡no te olvides de seguirnos en Twitter y de suscribirte a nuestro canal de YouTube!

Artículos relacionados

Bruno para simplificar el trabajo con APIs

Cómo utilizar Bruno para simplificar el trabajo con APIs

En el desarrollo de software, la gestión eficaz de las API es imprescindible para garantizar el éxito de los proyectos. Desde la fase de pruebas y documentación hasta la colaboración en equipo, contar con las herramientas adecuadas puede marcar una gran diferencia. Es aquí donde

Qué es una API

Qué es una API y para qué sirve: Funcionamiento y utilidad

El término «API» se ha convertido en parte del vocabulario cotidiano de desarrolladores/as, empresarios/as y usuarios/as de tecnología. Sin embargo, para algunas personas, este concepto sigue siendo un misterio. ¿Qué es realmente una API y por qué es tan importante en el mundo de la

Cómo subir imágenes y archivos usando Multer

Cómo subir imágenes y archivos usando Multer con Node.js y Express

En este post, aprenderemos cómo subir imágenes y archivos usando Multer con Node.js y Express. Desarrollaremos una aplicación básica que permita seleccionar archivos mediante un formulario y guardarlos en una carpeta del servidor. Es necesario instalar Node.js y algún IDE para Javascript, en este caso,