Servicios REST con .NET Core
  • Servicios REST con ASP.NET Core y Entity Framework Core
  • 1. Introducción
    • 1.1 Instalación Visual Studio Community
    • 1.2 Instalación de SQL Server en Mac
    • 1.3 Extensión Intellicode
    • 1.4 Aplicación de ejemplo
  • 2. Explicación de Conceptos
    • 2.1 Servicios REST
      • 2.1.1 OData
      • 2.1.2 GraphQL
    • 2.2 Entity Framework para versiones de tu base de datos
    • 2.3 Paquetes Nuget
    • 2.4 Archivo de recursos
    • 2.5 Estructura de los Proyectos .Net Core
    • 2.6 Código Limpio
    • 2.7 Programación asíncrona
    • 2.8 Git
    • 2.9 ¿Qué es Scrum?
      • 2.9.1 Personas
      • 2.9.2 Roles Scrum
      • 2.9.3 Backlog
      • 2.9.4 Reuniones del Scrum
  • 3. Control de código fuente y Scrum con Azure DevOps
    • 3.1 Introducción a Azure DevOps
      • 3.1.1 Crear un nuevo Proyecto en Azure DevOps
      • 3.1.2 Agregando personas al equipo de trabajo
      • 3.1.3 Agregando los sprints y la capacidad de trabajo
      • 3.1.4 Crear el Backlog y asignar User Stories al Sprint
      • 3.1.5 Crear Prototipos
      • 3.1.6 Conectar a Azure DevOps desde Visual Studio
        • 3.1.6.1 Crear tu proyecto con Visual Studio Community y sincronizarlo a Azure DevOps
      • 3.1.7 Consultar tus tareas pendientes
        • 3.1.7.1 Tareas y Dashboards con Azure DevOps
        • 3.1.7.2 Consultar tus tareas desde Visual Studio Community
      • 3.1.8 Trabajando con Ramas (Branches)
        • 3.1.8.1 Crear la rama desarrollo desde Azure DevOps
          • 3.1.8.1 Crear una rama(branch) desde tu tarea en Azure DevOps
        • 3.1.8.2 Como trabajar con ramas (branches) desde Visual Studio Community
        • 3.1.8.3 Crear el Pull Request con Azure DevOps
      • 3.1.9 Retrospectiva del Sprint
      • 3.1.10 Agregando una Wiki
    • 3.2 Integrando tu código fuente a GitHub
      • 3.2.1 Trabajando con ramas en GitHub
      • 3.2.2 Sincronizar los cambios del código con GitHub y Visual Studio
      • 3.3 Trabajando con Branches (Ramas) con Visual Studio
        • 3.3.1 Branches con Visual Studio
        • 3.3.2 Creando un template para tus PR (Pull Request)
        • 3.3.3 Protegiendo tu branch
  • 4. Creando tu primer servicio
    • 4.1 Crear las base de datos y los usuarios en MySQL
    • 4.2 Crear la tabla Categoría y sus validaciones
    • 4.3 Creando el servicio Categorias
    • 4.4 Probando tus servicios con POSTMAN
    • 4.5 Documentar y Probar tus servicios con Swagger
      • 4.5.1 Configurar Swagger
      • 4.5.2 Comentarios XML
      • 4.5.3 Generando la página de documentación
    • 4.6 Agregando índices
    • 4.7 Mejorando tu código
      • 4.7.1 Creando Objetos de Accesos a Datos
      • 4.7.2 Creando tus mensajes de error en diferentes idiomas
      • 4.7.3 Cambiando el formato del Json de los servicios
  • 5. Agregando el servicio para los productos
    • 5.1 Crear la tabla de Productos
    • 5.2 Formas de cargar información de tablas relacionadas
    • 5.3 Crear llaves fóraneas e índices
    • 5.4 Creando el servicio Productos
    • 5.5 Validar Reglas Mejorando tu código
      • 5.5.1 Agregando una excepción a todos nuestros servicios
      • 5.5.2 Agregando clases genéricas para validar y/o consultar información
      • 5.5.3 Alternativa para validar reglas con ef core
  • 6. Cambiar de base de datos a SQL Server
    • 6.1 Cambiar la base de datos a SQL Server
    • 6.2 Cambiar a SQL Server en Azure
  • 7. Crear servicios con OData
    • 7.1.1 Creando el modelo Clientes
    • 7.1.2 Creando el modelo ClienteCategoría
    • 7.1.3 Agregando paquete Nuget para OData
    • 7.1.4 Configurar el EDM Model
    • 7.1.5 Configurar el servicio OData y llaves foráneas
    • 7.1.6 Creando el Controller para clientes
    • 7.1.7 Configurar y probar los servicios con OData
    • 7.1.8 Práctica Crear el servicio para ClientesCategorias
    • 7.1.9 Recomendaciones de seguridad y rendimiento a tomar en cuenta con OData
  • 8. GraphQL
    • 8.1.1 Creando la tabla Caducidad
    • 8.1.2 Creando el query
    • 8.1.3 Configurando y probando graphQL
    • 8.1.4 Creando la Mutation
    • 8.1.5 Probando nuestros servicios con Postman
  • 9. Seguridad
    • 9.1 Json Web Tokens
    • 9.2 Seguridad basada en roles y usuarios
      • 9.2.1 Creando nuestra tabla roles e insertando los roles principales
      • 9.2.2 Consideraciones de seguridad para almacenar tus passwords
      • 9.2.3 Creando las tablas para manejar la seguridad
      • 9.2.4 Agregando usuarios y roles
    • 9.3 Agregando seguridad a nuestros servicios
    • 9.4 Creando nuestro servicio de login y generar el token
    • 9.5 ¿Cómo agregar seguridad basada en roles a los Servicios REST?
      • 9.5.1 Seguridad basada en claims
      • 9.5.2 Creando las tablas para validar permisos por cada tabla
      • 9.5.3 Seguridad basada en directivas
      • 9.5.4 Seguridad con Action Filters
    • 9.6 Guardando el historial de cambios
    • 9.7 Refrescando tu token
    • 9.8 Seguridad Mejorando tu código
      • 9.8.1 ¿Cómo limitar el número de intentos incorrectos en el login?
      • 9.8.2 ¿Cómo obtener la ciudad del usuario por medio de la IP?
      • 9.8.3 Habilitando CORS
  • 10. Pruebas Unitarias
    • 10.1 Agregando el proyecto de pruebas unitarias
    • 10.2 Crear una prueba unitaria
      • 10.2.1 Ejecutando las pruebas unitarias
    • 10.3 Agregando una base de datos en memoria para nuestras pruebas unitarias
    • 10.4 Agregando la referencia de nuestro proyecto CaducaRest
      • 10.4.1 Agregando paquetes nuget necesarios
    • 10.5 Configurando Clases para Objetos Sustitutos
      • 10.5.1 Configurando el Contexto para utilizar la base de datos en Memoria
      • 10.5.2 Configurando el objeto para sustituir mensajes de Error por idioma
    • 10.6 Agregando pruebas para las Categorías
  • 11. Integración continua
    • 11.1 ¿Qué es la integración continua?
    • 11.2 Subir tu código fuente a BitBucket
      • 11.2.1 Integración continua y pruebas automáticas con Bitbucket
    • 11.3 Integración continua y pruebas automáticas en Azure DevOps
  • 12. Pruebas de integración
    • 12.1 ¿Qué es SpecFlow?
    • 12.2 Agregando el proyecto de pruebas de integración
    • 12.3 Configurando Specflow
    • 12.4 Creando pruebas para el login
    • 12.5 Agregando las pruebas de Integración a Azure Devops
    • 12.6 Specflow Mejorando tu código
      • 12.6.1 Cambiando las pruebas a español
      • 12.6.2 Pasando tablas a nuestras pruebas
      • 12.6.3 Agregar los passwords como variables de ambiente
      • 12.6.4 Probando con SQLite
      • 12.6.5 Agregando diferentes parámetros con MSTest
      • 12.6.6 Generando el reporte living doc de specflow
  • 13. Integración continua con Postman
    • 13.1 Recomendaciones para probar tus servicios
    • 13.2 Instrucciones básicas para probar con Postman
    • 13.3 Crear colecciones en Postman
    • 13.4 Agregar pruebas a tus servicios
    • 13.5 Crear environments
    • 13.6 Agregando datos de prueba con archivos .csv
    • 13.7 Exportando tus colecciones y ejecutarlas con Newman.
    • 13.8 Agregando las colecciones de postman al pipeline
  • 14. Pruebas de usuario
    • 14.1 Page Object Model
    • 14.2 ¿Qué es Selenium?
      • 14.2.1 Selenium Instrucciones básicas
      • 14.2.2 Agregando el proyecto de pruebas de usuario
    • 14.3 ¿Qué es Cypress?
      • 14.3.1 Cypress Instrucciones básicas
    • 14.4 ¿Qué es Playwright?
      • 14.4.1 Playwright Instrucciones básicas
  • 15. Despliegue Continuo con Azure DevOps y Azure
    • 15.1 Crear un App Service en Azure
    • 15.2 Generando Artifacts en Azure Pipelines
    • 15.3 Generando el Release en Azure Pipelines al App Service de Azure
    • 15.4 Ejecutando las colecciones de Postman después del release
    • 15.5 Agregando las pruebas de usuario en Azure Pipelines
  • 16. Instalación en Windows Server e IIS
    • 16.1 Instalar IIS en Windows Server
    • 16.2 Instalación del ASP.NET Core Module/Hosting Bundle
    • 16.3 Crea el Sitio Web en IIS
  • 17. Instalación en Linux
    • 17.1 Creando una máquina virtual linux en Azure
    • 17.2 Habilitando el acceso remoto
    • 17.3 Configura linux para .Net Core
    • 17.4 Instalando mysql
    • 17.5 Instalando Nginx y configurando tu servicio
    • 17.6 Instalando un certificado SSL gratuito con CertBot
    • 17.7 Agregando diferentes subdominios
  • 18. Docker
Powered by GitBook
On this page

Was this helpful?

  1. 15. Despliegue Continuo con Azure DevOps y Azure

15.2 Generando Artifacts en Azure Pipelines

Previous15.1 Crear un App Service en AzureNext15.3 Generando el Release en Azure Pipelines al App Service de Azure

Last updated 1 year ago

Was this helpful?

Para explicar la flexibilida de .net y Azure Pipelines voy a publicar 2 artifacts con el mismo código, uno para instalarlo en un AppService en Linux con Azure con una base de datos MySQL y el otro para publicar en el AppService en Windows Con Azure.

Una parte interesante de Azure pipelines es que te permite crear variables de tipo Secret, las cuales estan ocultas y son independientes del código. Vamos a agregar una variable para guardar la cadena de conexión donde vamos a tener nuestra base de datos de MySQL puedes tener la bd de MySQL en un hosting, un servidor o en Azure. Esta cadena de conexión se va a reemplazar en el momento en que generamos el Pipeline para poder generar el script que actualizará la base de datos.

Modificando el Pipeline para generar el Artifact para publicar a Azure.

Agregando variables

  1. Entramos a Azure Devops en la opción Pipelines. Selecciona el último Pipeline y da clic en Edit.

2. Damos clic en el botón Variables para agregar una variable de tipo secret que tendra nuestra cadena de conexión, al tenerla en variable la cadena de conexión no esta disponible en el código fuente.

3. Da clic en el botón + para agregar una nueva variable. En la imagen ya tengo agregada la imagen, como es de tipo secreta solo se ve el nombre pero no el valor.

Como ejemplo voy a agregar otra variable para la base de datos de SQL de Azure. Con el nombre AzureSQLServer y en value agrego la cadena de conexión de Azure.

Server=tcp:armhe.database.windows.net,1433;
Initial Catalog=CaducaRest;Persist Security Info=False;
User ID=AdminCaduca;Password=tuPassword;
MultipleActiveResultSets=False;Encrypt=True;
TrustServerCertificate=False;Connection Timeout=30;

Puedes ver que se agrega la variable. Da clic en Save.

4. En la sección de variables puedes agregar las variables que deseas cambiar de tu archivo appsettings.json

appsettings.json
{
  "ConnectionStrings": {
    "DefaultConnection": "server=localhost;port=3306;database=caduca;user=AdminCaduca;Password=StKRV6MR6A;sslMode=none",
    "SQLServerConnection": "Server=localhost;Database=caduca;User Id=AdminCaduca;Password=StKRV6MR6A;",
    "AzureSQLConnection": "Server=tcp:armhe.database.windows.net,1433;Initial Catalog=CaducaRest;Persist Security Info=False;User ID=AdminCaduca;Password=StKRV6MR6A;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
  },
  "Tokens": {
    "Key": "4eQXP7GTCTRwC6x6",
    "Issuer": "http://localhost:5000",
    "Audience": "http://localhost:5000"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Debug"
    }
  },
  "AllowedHosts": "*"
}

Por ejemplo para cambiar la cadena de Conexión DefaultConnection debemos agregar una variable con el nombre ConnectionStrings.DefaultConnection, para cada nivel del json se sustituye con un punto (.). Para utilizar las variables que definimos agregamos la variable con $ y entre paréntesis. Ejemplo $(Mysql).

variables:
  solution: '**/*.sln'
  buildPlatform: 'Any CPU'
  buildConfiguration: 'Release'
  system.debug: false
  ConnectionStrings.DefaultConnection: $(Mysql)

Para practicar el remplazo de variables puedes agregar variables para cambiar el key, Issuer, Audience, el nivel de log, con variables secretas o directamente en el código yaml. Como el código yaml se incluye en el repositorio de Github, es mejor utilizar variables para los valores que no deseas que esten disponibles para cualquier programador en el código fuente.

El archivo yaml queda de la siguiente manera:

azure-pipelines.yml
variables:
  solution: '**/*.sln'
  buildPlatform: 'Any CPU'
  buildConfiguration: 'Release'
  system.debug: false
  ConnectionStrings.DefaultConnection: $(Mysql)
  Tokens.Key: $(key)
  Tokens.Issuer: $(issuer)
  Tokens.Audience: $(issuer)
  Logging.LogLevel.Default: "Error"

12.1.2 Transformando el appsettings con las variables .

Agrega un task llamado File Transform para remplazar los valores de archivos json o xml por las variables definidas en nuestro pipeline.

Agrega lo siguiente:

  • Package or folder: Agrega la dirección de la carpeta donde esta el archivo que deseas cambiar. En este caso es: $(build.SourcesDirectory)/CaducaRest/

  • XML Transformation rules: Aqui se agregan las reglas para transformar algún webconfig.xml en este caso no voy a realizar ningún cambio al webcofig o algún otro xml por lo que voy a borrar el contenido por default.

  • Json target files: Selecciona los archivos json que deseas cambiar. En este caso solo deseo cambiar el archivo appsettings, por lo tanto teclea el valor **/appsettings.json

  • Xml target files: Aquí se seleccionan los archivos xml que deseas cambiar, en este caso no necesito cambiar nada.

Da clic en el botón Add y borra la propiedad del xml. Queda de la siguiente manera. Siempre agrego la propiedad displayName para tener un nombre mas descriptivo en este caso es: Transformar appsettings.

- task: FileTransform@2
  displayName: "Transformar appsettings"
  inputs:
    folderPath: '$(build.SourcesDirectory)/CaducaRest/'
    jsonTargetFiles: '**/appsettings.json'

12.1.3 Instalado Entity Framework

Para poder generar el script de MySQL para las migraciones necesitamos instalar la herramienta para ef, la podemos instalar con el siguiente comando:

dotnet tool install --global dotnet-ef

Para esto agrega una tarea Command line y en el área de Script agrega el comando

El archivo yaml queda de la siguiente manera:

- task: CmdLine@2
  displayName: "Instalar .NET Global"
  inputs:
    script: 'dotnet tool install --global dotnet-ef'

12.1.4 Generando el script para actualizar la base de datos.

Después de generar el build del proyecto de Caduca Rest podemos agregar el siguiente comando para generar un script para actualizar la base de datos, con los siguientes parámetos:

  • -p: Indicas la ruta y el nombre del archivo de tu proyecto, el cual termina en .csproj, en este caso es $(build.SourcesDirectory)\CaducaRest\CaducaRest.csproj

  • -i: Genera un script que se puede utilizar en cualquier base de datos, se tenga un cambio o no en el commit.

  • -o: Indicas la ruta y nombre del archivo .sql con los cambios para la base de datos. En mi caso lo quiero en la ruta Scripts con el nombre update_to_latest.sql. $(Build.ArtifactStagingDirectory)\Scripts\update_to_latest.sql

El comando a ejecutar queda de la siguiente manera:

dotnet ef migrations script 
-p $(build.SourcesDirectory)\CaducaRest\CaducaRest.csproj 
-i -o $(Build.ArtifactStagingDirectory)
\Scripts\update_to_latest.sql

Para ejecutar este comando agrega el siguiente yaml.

- script: dotnet ef migrations script -p $(build.SourcesDirectory)\CaducaRest\CaducaRest.csproj -i -o $(Build.ArtifactStagingDirectory)\Scripts\update_to_latest.sql
  displayName: 'Generar Script'

12.1.5 Generando un Artifact para Linux.

Agrega una tarea de .Net Core para generar los archivos necesarios para publicar los archivos necesarios para linux.

  • Command: Seleciona publish para generar los archivos necesarios.

  • Arguments: Agrega los siguientes argumentos:

    • -r: Selecciona runtime, en este caso para linux es linux-x64 Este parámetro es opcional cuando el App Service no tiene la misma versión que tu código. Anteriormente se tardaban algunas semanas en tener listo app services con la mas reciente versión de .Net Core.

    • -configuration: Selecciona la configuración que esta al inicio del pipeline $(BuildConfiguration)

    • --output: Selecciona la ruta donde se van a publicar los archivos, en este caso es $(Build.ArtifactStagingDirectory)/linux

La tarea queda de la siguiente manera:

- task: DotNetCoreCLI@2
  displayName: "Publish Linux"
  inputs:
        command: 'publish'
        publishWebProjects: true
        arguments: '--configuration $(BuildConfiguration) --output $(Build.ArtifactStagingDirectory)'
        zipAfterPublish: true

12.1.6 Generando un Artifact para Windows.

Para windows solo voy a configurar el directorio de salida.

--output $(Build.ArtifactStagingDirectory)/win
- task: DotNetCoreCLI@2
  displayName: "Publish Win"
  inputs:
        command: 'publish'
        publishWebProjects: true
        arguments: '--configuration $(BuildConfiguration) --output $(Build.ArtifactStagingDirectory)/win'
        zipAfterPublish: true

12.1.7 Publicando los Artifacts.

Por último después de los scripts de pruebas, agrega una tarea Publish build artifacts para generar artifacts para windows, linux y el script de sql.

Configura la tarea de la siguiente manera:

  • Path to publish: selecciona la carpeta que deseas publicar, en el caso de linux será $(Build.ArtifactStagingDirectory)/linux

  • Artifact name: Teclea el nombre el artifacto en este caso sera restLinux

  • Artifact publish Location: Selecciona si deseas publicarlo en el pipeline o en una carpeta compartida.

La tarea queda de la siguiente manera:

- task: PublishBuildArtifacts@1
  displayName: "Upload Artifacts linux"
  inputs:
        pathtoPublish: '$(Build.ArtifactStagingDirectory)/linux' 
        artifactName: 'restLinux' 

Puedes agregar las demás tareas para publicar el artifact de windows y el script de sql.

El archivo queda de la sigueinte manera:

# ASP.NET Core (.NET Framework)
# Build and test ASP.NET Core projects targeting the full .NET Framework.
# Add steps that publish symbols, save build artifacts, and more:
# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core

trigger:
- master

pool:
  vmImage: 'windows-latest'

variables:
  solution: '**/*.sln'
  buildPlatform: 'Any CPU'
  buildConfiguration: 'Release'
  system.debug: false
  ConnectionStrings.DefaultConnection: $(SQL)
  Tokens.Key: $(key)
  Tokens.Issuer: $(issuer)
  Tokens.Audience: $(issuer)
  Logging.LogLevel.Default: "Error"

steps:

- task: UseDotNet@2 
  displayName: "Instalar .NET Core 7.0.x"
  inputs:
        version: '7.0.x'
        performMultiLevelLookup: true
        packageType: sdk

- task: CmdLine@2
  displayName: "Instalar .NET Global"
  inputs:
    script: 'dotnet tool install --global dotnet-ef'

- task: DotNetCoreCLI@2
  displayName: 'Build CaducaRest'
  inputs:
    command: build
    projects: |
      **/CaducaRest/CaducaRest.csproj

- task: DotNetCoreCLI@2
  displayName: Testing Unit Test
  inputs:
    command: 'test'
    projects: '**/CaducaRest.UnitTest/*.csproj'
    arguments: '--configuration $(buildConfiguration) /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura /p:CoverletOutput=$(Build.SourcesDirectory)/TestResults/Coverage/'
    publishTestResults: true
    testRunTitle: 'Unit Test'

- task: DotNetCoreCLI@2
  displayName: Testing Integration Test
  inputs:
    command: 'test'
    projects: '**/CaducaRest.IntegrationTest/*.csproj'
    arguments: '--configuration $(buildConfiguration) /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura /p:CoverletOutput=$(Build.SourcesDirectory)/TestResults/Coverage/'
    publishTestResults: true
    testRunTitle: 'Integration Test'
  env:
    CARLOS: $(CARLOS)
    JUAN: $(JUAN)
    MARIA: $(MARIA)
    
- task: SpecFlowPlus@0
  displayName: Specflow plus
  condition: always()
  inputs:
    generatorSource: 'TestAssembly'
    testAssemblyFilePath: '$(Build.SourcesDirectory)\CaducaRest.IntegrationTest\bin\Release\net7.0\CaducaRest.IntegrationTest.dll'
    projectName: 'Integration'
    testExecutionJson: '$(Build.SourcesDirectory)\CaducaRest.IntegrationTest\bin\Release\net7.0\TestExecution.json'
    projectLanguage: 'es'

- task: PublishCodeCoverageResults@1
  displayName: 'Publish code coverage report'
  inputs:
    codeCoverageTool: 'Cobertura'
    summaryFileLocation: '$(Build.SourcesDirectory)/**/coverage.cobertura.xml'

- task: DotNetCoreCLI@2
  displayName: 'Build playwright'
  inputs:
    command: build
    projects: |
      **/CaducaRest.PlayWright.UITest/*.csproj

- task: CopyFiles@2
  displayName: Copy postman scripts
  inputs:
    SourceFolder: 'CaducaRest.IntegrationTest/postman'
    Contents: '**'
    TargetFolder: '$(Build.ArtifactStagingDirectory)/postman'

- task: FileTransform@2
  displayName: "Transformar appsettings"
  inputs:
    folderPath: '$(build.SourcesDirectory)/CaducaRest/'
    jsonTargetFiles: '**/appsettings.json'

- script: dotnet ef migrations script -p $(build.SourcesDirectory)\CaducaRest\CaducaRest.csproj -i -o $(Build.ArtifactStagingDirectory)\Scripts\update_to_latest.sql
  displayName: 'Generar Script'

- script: dotnet ef migrations bundle -p $(build.SourcesDirectory)\CaducaRest\CaducaRest.csproj --verbose --configuration --force
  displayName: 'Generar Bundle'

- task: DotNetCoreCLI@2
  displayName: "Publish Linux"
  inputs:
        command: 'publish'
        publishWebProjects: true
        arguments: '--configuration $(BuildConfiguration) --output $(Build.ArtifactStagingDirectory)/linux'
        zipAfterPublish: true

- task: DotNetCoreCLI@2
  displayName: "Publish Win"
  inputs:
        command: 'publish'
        publishWebProjects: true
        arguments: '--configuration $(BuildConfiguration) --output $(Build.ArtifactStagingDirectory)/win'
        zipAfterPublish: true
- task: DotNetCoreCLI@2
  displayName: "Build Selenium testing"
  inputs:
    command: 'publish'
    publishWebProjects: false
    projects: '**/CaducaRest.UITest/*.csproj' 
    arguments: '--configuration $(BuildConfiguration) --output $(Build.ArtifactStagingDirectory)/selenium'
    zipAfterPublish: false

- task: CopyFiles@2
  displayName: Copy Playwright
  inputs:
    SourceFolder: '$(Pipeline.Workspace)/s/CaducaRest.PlayWright.UITest/bin/Debug/net7.0/'
    Contents: '**'
    TargetFolder: '$(Build.ArtifactStagingDirectory)/playwright'

- task: PublishBuildArtifacts@1
  displayName: "Upload Artifacts linux"
  inputs:
        pathtoPublish: '$(Build.ArtifactStagingDirectory)/linux' 
        artifactName: 'restLinux' 

- task: PublishBuildArtifacts@1
  displayName: "Upload Artifacts win"
  inputs:
        pathtoPublish: '$(Build.ArtifactStagingDirectory)/win' 
        artifactName: 'restWin' 

- task: PublishBuildArtifacts@1
  displayName: "Upload Artifacts postman"
  inputs:
        pathtoPublish: '$(Build.ArtifactStagingDirectory)/postman' 
        artifactName: 'postmanTesting' 

- task: PublishBuildArtifacts@1
  displayName: "Upload Artifacts selenium"
  inputs:
        pathtoPublish: '$(Build.ArtifactStagingDirectory)/selenium' 
        artifactName: 'seleniumTesting' 

- task: PublishBuildArtifacts@1
  displayName: "Upload Artifacts playwright"
  inputs:
        pathtoPublish: '$(Build.ArtifactStagingDirectory)/playwright' 
        artifactName: 'playwrightTesting' 

 - task: PublishBuildArtifacts@1
   displayName: "Upload Artifacts SQL"
   inputs:
         pathtoPublish: '$(Build.ArtifactStagingDirectory)/Scripts' 
         artifactName: 'Scripts' 

Listo, si todo fue correcto cada vez que le des commit a tu código se crearán los artifacts. Solo hay un error en el reemplazo de variables que después voy a revisar porque marca error.

En el ejemplo tengo 5 artifacts porque tengo ya configurado los artifacts para postman y selenium que explicaré mas adelante.

En el botón View 3 changes se tiene la lista de cambios, ya sea en el commit o la lista de tareas cambiadas en Azure Devops.

Un ejemplo de la lista de cambios es el siguiente

Si das clic en el link de los artifacts puedes ver la lista de artifacts y los puedes descargar.

Puedes ver la documentación oficial de este task .

Puedes ver la referencia completa del comando .

Puedes ver la documentación oficial del comando publish .

Puedes ver la documentación oficial de la tarea de publish .

aquí
aquí
aquí
aquí