Partilhar via


Adicionar uma extensão de tarefa personalizada para pipelines

Serviços de DevOps do Azure | Azure DevOps Server 2022 | Azure DevOps Server 2020

Este guia orienta você pela criação, teste e publicação de tarefas personalizadas de compilação ou lançamento como extensões do Azure DevOps. As tarefas de pipeline personalizadas permitem estender o Azure DevOps com funcionalidades especializadas adaptadas aos fluxos de trabalho da sua equipe, desde utilitários simples até integrações complexas com sistemas externos.

Saiba como realizar as seguintes tarefas:

  • Configurar o ambiente de desenvolvimento e a estrutura do projeto
  • Criar lógica de tarefa usando o TypeScript e a Biblioteca de Tarefas de Pipelines do Azure
  • Implemente testes de unidade abrangentes com estruturas simuladas
  • Empacote sua extensão para distribuição
  • Publicar no Visual Studio Marketplace
  • Configurar pipelines de CI/CD automatizados para manutenção de extensões

Para obter mais informações sobre o Azure Pipelines, consulte O que é o Azure Pipelines?

Nota

Este artigo aborda as tarefas de agentes em extensões baseadas em agentes. Para obter informações sobre tarefas de servidor e extensões baseadas em servidor, consulte Criação de tarefas de servidor.

Pré-requisitos

Antes de começar, certifique-se de que tem os seguintes requisitos em vigor:

Componente Requisito Descrição
Organização do Azure DevOps Obrigatório Crie uma organização se não tiver uma
Editor de texto Recomendado Visual Studio Code para IntelliSense e suporte a depuração
Node.js Obrigatório Instale a versão mais recente (Node.js 20 ou posterior recomendado)
Compilador TypeScript Obrigatório Instale a versão mais recente (versão 4.6.3 ou posterior)
CLI do Azure DevOps (tfx-cli) Obrigatório Instalar usando npm i -g tfx-cli extensões de pacote para
SDK da Extensão Azure DevOps Obrigatório Instalar o pacote azure-devops-extension-sdk
Estrutura de teste Obrigatório Mocha para teste de unidade (instalado durante a configuração)

Estrutura do projeto

Crie um home diretório para o seu projeto. Depois de concluir este tutorial, sua extensão deve ter a seguinte estrutura:

|--- README.md    
|--- images                        
    |--- extension-icon.png  
|--- buildandreleasetask            // Task scripts ___location
    |--- task.json                  // Task definition
    |--- index.ts                   // Main task logic
    |--- package.json               // Node.js dependencies
    |--- tests/                     // Unit tests
        |--- _suite.ts
        |--- success.ts
        |--- failure.ts
|--- vss-extension.json             // Extension manifest

Importante

Sua máquina de desenvolvimento deve executar a versão mais recente do Node.js para garantir a compatibilidade com o ambiente de produção. Atualize seu arquivo para usar o task.json Node 20:

"execution": {
    "Node20_1": {
      "target": "index.js"
    }
}

1. Crie uma tarefa personalizada

Esta seção o orienta na criação da estrutura básica e na implementação de sua tarefa personalizada. Todos os arquivos nesta etapa devem ser criados dentro da buildandreleasetask pasta dentro do diretório do home seu projeto.

Nota

Este passo a passo usa o Windows com PowerShell. As etapas funcionam em todas as plataformas, mas a sintaxe da variável de ambiente é diferente. No Mac ou Linux, substitua $env:<var>=<val> por export <var>=<val>.

Configurar o andaime de tarefas

Crie a estrutura básica do projeto e instale as dependências necessárias:

  1. Para inicializar o projeto Node.js, abra o PowerShell, vá para sua buildandreleasetask pasta e execute:

    npm init --yes
    

    O package.json arquivo é criado com as configurações padrão. O --yes sinalizador aceita todas as opções padrão automaticamente.

    Gorjeta

    Os agentes do Azure Pipelines esperam que as pastas de tarefas incluam módulos de nó. Copie node_modules para a sua buildandreleasetask pasta. Para gerenciar o tamanho do arquivo VSIX (limite de 50 MB), considere executar npm install --production ou npm prune --production antes do empacotamento.

  2. Instale a Biblioteca de Tarefas do Azure Pipelines:

    npm install azure-pipelines-task-lib --save
    
  3. Instale as definições de tipo do TypeScript:

    npm install @types/node --save-dev
    npm install @types/q --save-dev
    
  4. Configurar exclusões de controle de versão

    echo node_modules > .gitignore
    

    Seu processo de compilação deve ser executado npm install para reconstruir node_modules cada vez.

  5. Instale dependências de teste:

    npm install mocha --save-dev -g
    npm install sync-request --save-dev
    npm install @types/mocha --save-dev
    
  6. Instale o compilador TypeScript:

    npm install typescript@4.6.3 -g --save-dev
    

    Nota

    Instale o TypeScript globalmente para garantir que o tsc comando esteja disponível. Sem ele, o TypeScript 2.3.4 é usado por padrão.

  7. Configure a compilação do TypeScript:

    tsc --init --target es2022
    

    O tsconfig.json arquivo é criado com as configurações de destino do ES2022.

Implementar a lógica da tarefa

Com o andaime concluído, crie os arquivos de tarefas principais que definem a funcionalidade e os metadados:

  1. Criar o arquivo de definição de tarefa: Criar task.json na buildandreleasetask pasta. Este arquivo descreve sua tarefa para o sistema Azure Pipelines, definindo entradas, configurações de execução e apresentação da interface do usuário.

    {
     "$schema": "https://raw.githubusercontent.com/Microsoft/azure-pipelines-task-lib/master/tasks.schema.json",
     "id": "{{taskguid}}",
     "name": "{{taskname}}",
     "friendlyName": "{{taskfriendlyname}}",
     "description": "{{taskdescription}}",
     "helpMarkDown": "",
     "category": "Utility",
     "author": "{{taskauthor}}",
     "version": {
         "Major": 0,
         "Minor": 1,
         "Patch": 0
     },
     "instanceNameFormat": "Echo $(samplestring)",
     "inputs": [
         {
             "name": "samplestring",
             "type": "string",
             "label": "Sample String",
             "defaultValue": "",
             "required": true,
             "helpMarkDown": "A sample string"
         }
     ],
     "execution": {
         "Node20_1": {
             "target": "index.js"
         }
     }
     }
    

    Nota

    Substitua {{placeholders}} pelas informações reais da sua tarefa. O taskguid deve ser único. Gere um usando o PowerShell: (New-Guid).Guid

  2. Para implementar a lógica da tarefa, crie index.ts com a funcionalidade principal da tarefa:

    import tl = require('azure-pipelines-task-lib/task');
    
     async function run() {
         try {
             const inputString: string | undefined = tl.getInput('samplestring', true);
             if (inputString == 'bad') {
                 tl.setResult(tl.TaskResult.Failed, 'Bad input was given');
                 return;
             }
             console.log('Hello', inputString);
         }
         catch (err: any) {
             tl.setResult(tl.TaskResult.Failed, err.message);
         }
     }
    
     run();
    
  3. Compile TypeScript para JavaScript:

    tsc
    

    O index.js arquivo é criado a partir de sua fonte TypeScript.

Noções básicas sobre task.json componentes

O task.json arquivo é o coração da definição da tarefa. Aqui estão as principais propriedades:

Propriedade Descrição Exemplo
id Identificador GUID exclusivo para sua tarefa Gerado usando (New-Guid).Guid
name Nome da tarefa sem espaços (usado internamente) MyCustomTask
friendlyName Nome para exibição mostrado na interface do usuário My Custom Task
description Descrição detalhada da funcionalidade da tarefa Performs custom operations on files
author Nome do editor ou autor My Company
instanceNameFormat Como a tarefa aparece nas etapas do pipeline Process $(inputFile)
inputs Matriz de parâmetros de entrada Veja os seguintes tipos de entrada
execution Especificação do ambiente de execução Node20_1, PowerShell3, etc.
restrictions Restrições de segurança para comandos e variáveis Recomendado para novas tarefas

Restrições de segurança

Para tarefas de produção, adicione restrições de segurança para limitar o uso de comandos e o acesso variável:

"restrictions": {
  "commands": {
    "mode": "restricted"
  },
  "settableVariables": {
    "allowed": ["variable1", "test*"]
  }
}

O modo restrito permite apenas estes comandos:

  • logdetail, logissue, complete, setprogress
  • setsecret, setvariable, debug, settaskvariable
  • prependpath, publish

Variable allowlist controla quais variáveis podem ser definidas via setvariable ou prependpath. Suporta padrões regex básicos.

Nota

Esse recurso requer a versão 2.182.1 ou posterior do agente.

Tipos de entrada e exemplos

Tipos de entrada comuns para parâmetros de tarefa:

"inputs": [
    {
        "name": "stringInput",
        "type": "string",
        "label": "Text Input",
        "defaultValue": "",
        "required": true,
        "helpMarkDown": "Enter a text value"
    },
    {
        "name": "boolInput",
        "type": "boolean",
        "label": "Enable Feature",
        "defaultValue": "false",
        "required": false
    },
    {
        "name": "picklistInput",
        "type": "pickList",
        "label": "Select Option",
        "options": {
            "option1": "First Option",
            "option2": "Second Option"
        },
        "defaultValue": "option1"
    },
    {
        "name": "fileInput",
        "type": "filePath",
        "label": "Input File",
        "required": true,
        "helpMarkDown": "Path to the input file"
    }
]

Teste a sua tarefa localmente

Antes de empacotar, teste sua tarefa para garantir que ela funcione corretamente:

  1. Teste com entrada ausente (deve falhar):

    node index.js
    

    Resultados esperados:

    ##vso[task.debug]agent.workFolder=undefined
    ##vso[task.debug]loading inputs and endpoints
    ##vso[task.debug]loaded 0
    ##vso[task.debug]task result: Failed
    ##vso[task.issue type=error;]Input required: samplestring
    ##vso[task.complete result=Failed;]Input required: samplestring
    
  2. Teste com entrada válida (deve ser bem-sucedido):

    $env:INPUT_SAMPLESTRING="World"
    node index.js
    

    Resultados esperados:

    ##vso[task.debug]agent.workFolder=undefined
    ##vso[task.debug]loading inputs and endpoints
    ##vso[task.debug]loading INPUT_SAMPLESTRING
    ##vso[task.debug]loaded 1
    ##vso[task.debug]samplestring=World
    Hello World
    
  3. Tratamento de erros de teste:

    $env:INPUT_SAMPLESTRING="bad"
    node index.js
    

    Essa ação deve acionar o caminho de tratamento de erros em seu código.

    Gorjeta

    Para obter informações sobre executores de tarefas e versões Node.js, consulte Diretrizes de atualização do executor de nó.

Para obter mais informações, consulte a referência da tarefa Compilar/liberar.

2. Implementar testes de unidade abrangentes

Testar completamente sua tarefa garante a confiabilidade e ajuda a detetar problemas antes da implantação em pipelines de produção.

Instalar dependências de teste

Instale as ferramentas de teste necessárias:

npm install mocha --save-dev -g
npm install sync-request --save-dev
npm install @types/mocha --save-dev

Criar teste

  1. Crie uma tests pasta no diretório de tarefas contendo um _suite.ts arquivo:

     import * as path from 'path';
     import * as assert from 'assert';
     import * as ttm from 'azure-pipelines-task-lib/mock-test';
    
     describe('Sample task tests', function () {
    
         before( function() {
             // Setup before tests
         });
    
         after(() => {
             // Cleanup after tests
         });
    
         it('should succeed with simple inputs', function(done: Mocha.Done) {
             // Success test implementation
         });
    
         it('should fail if tool returns 1', function(done: Mocha.Done) {
             // Failure test implementation
         });    
       });
    

    Gorjeta

    Sua pasta de teste deve estar localizada na pasta de tarefas (por exemplo, buildandreleasetask). Se você encontrar um erro de solicitação de sincronização, instale-o na pasta de tarefas: npm i --save-dev sync-request.

  2. Crie success.ts em seu diretório de teste para simular a execução bem-sucedida da tarefa:

     import ma = require('azure-pipelines-task-lib/mock-answer');
     import tmrm = require('azure-pipelines-task-lib/mock-run');
     import path = require('path');
    
     let taskPath = path.join(__dirname, '..', 'index.js');
     let tmr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath);
    
     // Set valid input for success scenario
     tmr.setInput('samplestring', 'human');
    
     tmr.run();
    
  3. Adicione o teste de sucesso ao seu _suite.ts ficheiro:

     it('should succeed with simple inputs', function(done: Mocha.Done) {
         this.timeout(1000);
    
         let tp: string = path.join(__dirname, 'success.js');
         let tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp);
    
         tr.runAsync().then(() => {
             console.log(tr.succeeded);
             assert.equal(tr.succeeded, true, 'should have succeeded');
             assert.equal(tr.warningIssues.length, 0, "should have no warnings");
             assert.equal(tr.errorIssues.length, 0, "should have no errors");
             console.log(tr.stdout);
             assert.equal(tr.stdout.indexOf('Hello human') >= 0, true, "should display Hello human");
             done();
         }).catch((error) => {
             done(error); // Ensure the test case fails if there's an error
         });
     });
    
  4. Crie failure.ts em seu diretório de teste para testar o tratamento de erros:

    import ma = require('azure-pipelines-task-lib/mock-answer');
    import tmrm = require('azure-pipelines-task-lib/mock-run');
    import path = require('path');
    
    let taskPath = path.join(__dirname, '..', 'index.js');
    let tmr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath);
    
    // Set invalid input to trigger failure
    tmr.setInput('samplestring', 'bad');
    
    tmr.run();
    
  5. Adicione o teste de falha ao seu _suite.ts arquivo:

     it('should fail if tool returns 1', function(done: Mocha.Done) {
         this.timeout(1000);
    
         const tp = path.join(__dirname, 'failure.js');
         const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp);
    
         tr.runAsync().then(() => {
             console.log(tr.succeeded);
             assert.equal(tr.succeeded, false, 'should have failed');
             assert.equal(tr.warningIssues.length, 0, 'should have no warnings');
             assert.equal(tr.errorIssues.length, 1, 'should have 1 error issue');
             assert.equal(tr.errorIssues[0], 'Bad input was given', 'error issue output');
             assert.equal(tr.stdout.indexOf('Hello bad'), -1, 'Should not display Hello bad');
             done();
         });
     });
    

Execute os testes

Execute o conjunto de testes:

# Compile TypeScript
tsc

# Run tests
mocha tests/_suite.js

Ambos os testes devem ser aprovados. Para saída detalhada (semelhante à saída do console de compilação), defina a variável de ambiente de rastreamento:

$env:TASK_TEST_TRACE=1
mocha tests/_suite.js

Práticas recomendadas de cobertura de teste

  • Teste todas as combinações de entrada: entradas válidas, entradas inválidas, entradas necessárias ausentes
  • Cenários de erro de teste: falhas de rede, erros do sistema de arquivos, problemas de permissão
  • Simular dependências externas: não confie em serviços externos em testes de unidade
  • Validar saídas: verifique a saída do console, os resultados das tarefas e os artefatos gerados
  • Teste de desempenho: considere adicionar testes para tarefas que processam arquivos grandes

Práticas recomendadas de segurança

  • Validação de entradas: sempre valide e higienize as entradas
  • Tratamento de segredos: uso setSecret para dados confidenciais
  • Restrições de comando: implementar restrições de comando para tarefas de produção
  • Permissões mínimas: solicite apenas as permissões necessárias
  • Atualizações regulares: Mantenha as dependências e Node.js versões atualizadas

Depois de testar sua tarefa localmente e implementar testes de unidade abrangentes, empacote-a em uma extensão para o Azure DevOps.

Instalar ferramentas de empacotamento

Instale a interface de linha de comando multiplataforma (tfx-cli):

npm install -g tfx-cli

Criar o manifesto da extensão

O manifesto da extensão (vss-extension.json) contém todas as informações sobre sua extensão, incluindo referências às pastas de tarefas e imagens.

  1. Criar uma pasta de imagens com um extension-icon.png arquivo

  2. Crie vss-extension.json no diretório raiz da sua extensão (não na pasta de tarefas):

    {
     "manifestVersion": 1,
     "id": "my-custom-tasks",
     "name": "My Custom Tasks",
     "version": "1.0.0",
     "publisher": "your-publisher-id",
     "targets": [
         {
             "id": "Microsoft.VisualStudio.Services"
         }
     ],
     "description": "Custom build and release tasks for Azure DevOps",
     "categories": [
         "Azure Pipelines"
     ],
     "icons": {
         "default": "images/extension-icon.png"
     },
     "files": [
         {
             "path": "MyCustomTask"
         }
     ],
     "contributions": [
         {
             "id": "my-custom-task",
             "type": "ms.vss-distributed-task.task",
             "targets": [
                 "ms.vss-distributed-task.tasks"
             ],
             "properties": {
                 "name": "MyCustomTask"
             }
         }
     ]
    }
    

Principais propriedades do manifesto

Propriedade Descrição
publisher O seu identificador de editor do marketplace
contributions.id Identificador exclusivo dentro da extensão
contributions.properties.name Deve corresponder ao nome da pasta da tarefa
files.path Caminho para a pasta de tarefas relativo ao manifesto

Nota

Altere o valor do editor para o nome do editor. Para obter informações sobre como criar um editor, consulte Criar seu editor.

Empacote sua extensão

Empacote sua extensão em um arquivo .vsix:

tfx extension create --manifest-globs vss-extension.json

Gerenciamento de versões

  • Versão da extensão: incremente a versão para vss-extension.json cada atualização
  • Versão da tarefa: incremente a versão para cada atualização da task.json tarefa
  • Incremento automático: use --rev-version para incrementar automaticamente a versão do patch
tfx extension create --manifest-globs vss-extension.json --rev-version

Importante

A versão da tarefa e a versão da extensão devem ser atualizadas para que as alterações entrem em vigor no Azure DevOps.

Estratégia de controle de versão

Siga os princípios de controle de versão semântico para suas atualizações de tarefas:

  • Versão principal: Alterações significativas nas entradas/saídas
  • Versão secundária: Novos recursos, compatível com versões anteriores
  • Versão do patch: Apenas correções de bugs

Processo de atualização:

  1. Versão de atualização task.json
  2. Versão de atualização vss-extension.json
  3. Teste completamente em uma organização de teste
  4. Publicar e monitorar problemas

Publicar no Visual Studio Marketplace

1. Crie o seu editor

  1. Entre no Portal de Publicação do Visual Studio Marketplace
  2. Crie um novo editor, se solicitado:
    • Identificador do editor: usado no manifesto da extensão (por exemplo, mycompany-myteam)
    • Nome para exibição: nome público mostrado no mercado (por exemplo, My Team)
  3. Rever e aceitar o Contrato de Editor do Marketplace

2. Carregue a sua extensão

Método de interface Web:

  1. Selecione Carregar nova extensão
  2. Escolha o seu ficheiro empacotado .vsix
  3. Selecione Carregar

Método de linha de comando:

tfx extension publish --manifest-globs vss-extension.json --share-with yourOrganization

3. Partilhe a sua extensão

  1. Clique com o botão direito do rato na sua extensão no mercado
  2. Selecione Partilhar
  3. Introduza o nome da sua organização
  4. Adicione mais organizações conforme necessário

Importante

Os publicadores devem ser verificados para partilhar extensões publicamente. Para obter mais informações, consulte Package/Publish/Install.

4. Instale na sua organização

Depois de compartilhar, instale a extensão em sua organização do Azure DevOps:

  1. Navegue atéExtensões>
  2. Procure a sua extensão
  3. Selecione Obter grátis e instalar

3. Empacote e publique sua extensão

Verifique a sua extensão

Após a instalação, verifique se a tarefa funciona corretamente:

  1. Crie ou edite um pipeline.
  2. Adicione sua tarefa personalizada:
    • Selecione Adicionar tarefa no editor de pipeline
    • Procure a sua tarefa personalizada pelo nome
    • Adicione-o ao seu pipeline
  3. Configure os parâmetros da tarefa:
    • Definir entradas necessárias
    • Configurar definições opcionais
  4. Execute o pipeline para testar a funcionalidade
  5. Monitore a execução:
    • Verifique os logs de tarefas para a execução adequada
    • Verificar as saídas esperadas
    • Certifique-se de que não há erros ou avisos

4. Automatize a publicação de extensões com CI/CD

Para manter sua tarefa personalizada de forma eficaz, crie pipelines automatizados de compilação e liberação que lidam com testes, empacotamento e publicação.

Pré-requisitos para automação

  • Tarefas de extensão do Azure DevOps: instale a extensão gratuitamente
  • Grupo de variáveis: crie um grupo de variáveis da biblioteca de pipeline com estas variáveis:
    • publisherId: O ID do editor do marketplace
    • extensionId: ID da extensão de vss-extension.json
    • extensionName: Nome da extensão de vss-extension.json
    • artifactName: Nome do artefato VSIX
  • Conexão de serviço: crie uma conexão de serviço do Marketplace com permissões de acesso ao pipeline

Pipeline completo de CI/CD

Crie um pipeline YAML com estágios abrangentes para teste, empacotamento e publicação:

trigger: 
- main

pool:
  vmImage: "ubuntu-latest"

variables:
  - group: extension-variables # Your variable group name

stages:
  - stage: Test_and_validate
    displayName: 'Run Tests and Validate Code'
    jobs:
      - job: RunTests
        displayName: 'Execute unit tests'
        steps:
          - task: TfxInstaller@4
            displayName: 'Install TFX CLI'
            inputs:
              version: "v0.x"
          
          - task: Npm@1
            displayName: 'Install task dependencies'
            inputs:
              command: 'install'
              workingDir: '/MyCustomTask' # Update to your task directory
          
          - task: Bash@3
            displayName: 'Compile TypeScript'
            inputs:
              targetType: "inline"
              script: |
                cd MyCustomTask # Update to your task directory
                tsc
          
          - task: Npm@1
            displayName: 'Run unit tests'
            inputs:
              command: 'custom'
              workingDir: '/MyCustomTask' # Update to your task directory
              customCommand: 'test' # Ensure this script exists in package.json
          
          - task: PublishTestResults@2
            displayName: 'Publish test results'
            inputs:
              testResultsFormat: 'JUnit'
              testResultsFiles: '**/test-results.xml'
              searchFolder: '$(System.DefaultWorkingDirectory)'

  - stage: Package_extension
    displayName: 'Package Extension'
    dependsOn: Test_and_validate
    condition: succeeded()
    jobs:
      - job: PackageExtension
        displayName: 'Create VSIX package'
        steps:
          - task: TfxInstaller@4
            displayName: 'Install TFX CLI'
            inputs:
              version: "v0.x"
          
          - task: Npm@1
            displayName: 'Install dependencies'
            inputs:
              command: 'install'
              workingDir: '/MyCustomTask'
          
          - task: Bash@3
            displayName: 'Compile TypeScript'
            inputs:
              targetType: "inline"
              script: |
                cd MyCustomTask
                tsc
          
          - task: QueryAzureDevOpsExtensionVersion@4
            name: QueryVersion
            displayName: 'Query current extension version'
            inputs:
              connectTo: 'VsTeam'
              connectedServiceName: 'marketplace-connection'
              publisherId: '$(publisherId)'
              extensionId: '$(extensionId)'
              versionAction: 'Patch'
          
          - task: PackageAzureDevOpsExtension@4
            displayName: 'Package extension'
            inputs:
              rootFolder: '$(System.DefaultWorkingDirectory)'
              publisherId: '$(publisherId)'
              extensionId: '$(extensionId)'
              extensionName: '$(extensionName)'
              extensionVersion: '$(QueryVersion.Extension.Version)'
              updateTasksVersion: true
              updateTasksVersionType: 'patch'
              extensionVisibility: 'private'
              extensionPricing: 'free'
          
          - task: PublishBuildArtifacts@1
            displayName: 'Publish VSIX artifact'
            inputs:
              PathtoPublish: '$(System.DefaultWorkingDirectory)/*.vsix'
              ArtifactName: '$(artifactName)'
              publishLocation: 'Container'

  - stage: Publish_to_marketplace
    displayName: 'Publish to Marketplace'
    dependsOn: Package_extension
    condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
    jobs:
      - deployment: PublishExtension
        displayName: 'Deploy to marketplace'
        environment: 'marketplace-production'
        strategy:
          runOnce:
            deploy:
              steps:
                - task: TfxInstaller@4
                  displayName: 'Install TFX CLI'
                  inputs:
                    version: "v0.x"
                
                - task: PublishAzureDevOpsExtension@4
                  displayName: 'Publish to marketplace'
                  inputs:
                    connectTo: 'VsTeam'
                    connectedServiceName: 'marketplace-connection'
                    fileType: 'vsix'
                    vsixFile: '$(Pipeline.Workspace)/$(artifactName)/*.vsix'
                    publisherId: '$(publisherId)'
                    extensionId: '$(extensionId)'
                    extensionName: '$(extensionName)'
                    updateTasksVersion: false
                    extensionVisibility: 'private'
                    extensionPricing: 'free'

Configurar package.json para teste

Adicione scripts de teste ao seu package.json:

{
  "scripts": {
    "test": "mocha tests/_suite.js --reporter xunit --reporter-option output=test-results.xml",
    "test-verbose": "cross-env TASK_TEST_TRACE=1 npm test"
  }
}

Detalhamento do estágio do pipeline

Etapa 1: Testar e validar

  • Objetivo: Garantir a qualidade e a funcionalidade do código
  • Ações: Instalar dependências, compilar TypeScript, executar testes de unidade, publicar resultados
  • Validação: Todos os testes devem passar para prosseguir

Etapa 2: Extensão do pacote

  • Finalidade: Criar pacote VSIX implantável
  • Ações: Consultar a versão atual, incrementar a versão, a extensão do pacote, publicar artefatos
  • Controle de versão: lida automaticamente com incrementos de versão

Etapa 3: Publicar no mercado

  • Finalidade: implantar no Visual Studio Marketplace
  • Condições: Só funciona na ramificação principal após o empacotamento bem-sucedido
  • Ambiente: usa o ambiente de implantação para portas de aprovação

Melhores práticas para CI/CD

  • Proteção de ramificação: publique somente a partir de ramificações principais/de lançamento
  • Portas de ambiente: use ambientes de implantação para versões de produção
  • Gerenciamento de versões: automatize incrementos de versão para evitar conflitos
  • Cobertura do teste: Garanta uma cobertura abrangente do teste antes da embalagem
  • Segurança: use conexões de serviço em vez de credenciais codificadas
  • Monitoramento: configurar alertas para implantações com falha

Para pipelines de construção clássicos, siga estas etapas para configurar o empacotamento e a publicação de extensão:

  1. Adicione a tarefa Bash para a compilação do TypeScript para JavaScript.

  2. Para consultar a versão existente, adicione a tarefa Versão de Extensão de Consulta usando as seguintes entradas:

    • Conectar-se a: Visual Studio Marketplace
    • Visual Studio Marketplace (conexão de serviço): Conexão de serviço
    • ID do editor: ID do seu editor do Visual Studio Marketplace
    • ID da extensão: ID da sua extensão no vss-extension.json arquivo
    • Atualizar versão: Patch
    • Variável de saída: Task.Extension.Version
  3. Para empacotar as extensões com base no manifesto Json, adicione a tarefa Extensão de pacote usando as seguintes entradas:

    • Pasta de manifestos raiz: aponta para o diretório raiz que contém o arquivo de manifesto. Por exemplo, $(System.DefaultWorkingDirectory) é o diretório raiz
    • Arquivo de manifesto: vss-extension.json
    • ID do editor: ID do seu editor do Visual Studio Marketplace
    • ID da extensão: ID da sua extensão no vss-extension.json arquivo
    • Nome da extensão: Nome da sua extensão no vss-extension.json arquivo
    • Versão da extensão: $(Task.Extension.Version)
    • Substituir versão de tarefas: verificada (true)
    • Tipo de substituição: Substituir apenas patch (1.0.r)
    • Visibilidade da extensão: Se a extensão ainda estiver em desenvolvimento, defina o valor como privado. Para liberar a extensão para o público, defina o valor como público.
  4. Para copiar para arquivos publicados, adicione a tarefa Copiar arquivos usando as seguintes entradas:

    • Conteúdo: Todos os arquivos a serem copiados para publicá-los como um artefato
    • Pasta de destino: a pasta para a qual os arquivos são copiados
      • Por exemplo: $(Build.ArtifactStagingDirectory)
  5. Adicione Publicar artefatos de compilação para disponibilizar os artefatos para uso em outras tarefas ou pipelines. Use as seguintes entradas:

    • Caminho para publicação: o caminho para a pasta que contém os arquivos que estão sendo publicados
      • Por exemplo: $(Build.ArtifactStagingDirectory)
    • Nome do artefato: O nome dado ao artefato
    • Local de publicação de artefatos: escolha o Azure Pipelines para usar o artefato em trabalhos futuros

Etapa 3: Baixar artefatos de compilação e publicar a extensão

  1. Para instalar o tfx-cli no seu agente de compilação, adicione Use Node CLI for Azure DevOps (tfx-cli).

  2. Para baixar os artefatos em um novo trabalho, adicione a tarefa Baixar artefatos de compilação usando as seguintes entradas:

    • Baixar artefatos produzidos por: Se estiveres a baixar o artefato num novo trabalho da mesma linha de montagem, seleciona Compilação atual. Se estiver a baixar num novo pipeline, selecione Compilação específica
    • Tipo de download: escolha Artefato específico para baixar todos os arquivos que foram publicados.
    • Nome do artefato: o nome do artefato publicado
    • Diretório de destino: A pasta onde os arquivos devem ser baixados
  3. Para obter a tarefa Publicar extensão, use as seguintes informações:

    • Conectar-se a: Visual Studio Marketplace
    • Conexão do Visual Studio Marketplace: ServiceConnection
    • Tipo de arquivo de entrada: arquivo VSIX
    • Arquivo VSIX: /Publisher.*.vsix
    • ID do editor: ID do seu editor do Visual Studio Marketplace
    • ID da extensão: ID da sua extensão no vss-extension.json arquivo
    • Nome da extensão: Nome da sua extensão no vss-extension.json arquivo
    • Visibilidade da extensão: privada ou pública

Opcional: Instale e teste sua extensão

Depois de publicar sua extensão, ela precisa ser instalada nas organizações do Azure DevOps.

Instalar extensão na organização

Instale sua extensão compartilhada em algumas etapas:

  1. Vá para Configurações da organização e selecione Extensões.

  2. Localize sua extensão na seção Extensões compartilhadas comigo :

    • Selecione o link da extensão
    • Selecione Obter gratuitamente ou Instalar
  3. Verifique se a extensão aparece na lista de extensões instaladas :

    • Confirme se está disponível na sua biblioteca de tarefas de pipeline

Nota

Se não vir o separador Extensões , certifique-se de que está ao nível da administração da organização (https://dev.azure.com/{organization}/_admin) e não ao nível do projeto.

Testes de ponta a ponta

Após a instalação, execute testes abrangentes:

  1. Crie um pipeline de teste:

    • Adicionar sua tarefa personalizada a um novo pipeline
    • Configurar todos os parâmetros de entrada
    • Teste com várias combinações de entrada
  2. Validar funcionalidade:

    • Execute o pipeline e monitore a execução
    • Verificar saídas e logs de tarefas
    • Verificar o tratamento de erros com entradas inválidas
  3. Desempenho do teste:

    • Teste com arquivos de entrada grandes (se aplicável)
    • Monitorar o uso de recursos
    • Validar o comportamento de tempo limite

Perguntas frequentes

P: Como é tratado o cancelamento de tarefas?

R: O agente de pipeline envia SIGINT e SIGTERM sinaliza para processos de tarefas. Embora a biblioteca de tarefas não forneça tratamento explícito de cancelamento, sua tarefa pode implementar manipuladores de sinal. Para obter detalhes, consulte Cancelamento de trabalhos do agente.

P: Como posso remover uma tarefa da minha organização?

R: A exclusão automática não é suportada , pois quebraria os pipelines existentes. Em vez disso:

  1. Depreciar a tarefa: marque a tarefa como preterida
  2. Gerenciamento de versão: aumente a versão da tarefa
  3. Comunicação: Notificar os usuários sobre o cronograma de descontinuação

P: Como posso atualizar a minha tarefa para a versão Node.js mais recente?

R: Atualize para a versão mais recente do Node para melhor desempenho e segurança. Para obter orientações sobre migração, consulte Atualizando tarefas para o Nó 20.

Suporta várias versões de nó incluindo várias seções de execução em task.json:

"execution": {
  "Node20_1": {
    "target": "index.js"
  },
  "Node10": {
    "target": "index.js"
  }
}

Os agentes com o Nó 20 usam a versão preferida, enquanto os agentes mais antigos voltam para o Nó 10.

Para atualizar suas tarefas:

  • Para garantir que seu código se comporte conforme o esperado, teste suas tarefas nas várias versões do Node runner.

  • Na seção de execução da tarefa, atualize de Node ou Node10 para Node16 ou Node20.

  • Para suportar versões mais antigas do servidor, deve-se deixar o Node/Node10 alvo. As versões mais antigas do Azure DevOps Server podem não incluir a versão mais recente do executor de Node.

  • Você pode optar por compartilhar o ponto de entrada definido no alvo ou ter alvos otimizados para a versão do Node.js usada.

    "execution": {
       "Node10": {
         "target": "bash10.js",
         "argumentFormat": ""
       },
       "Node16": {
         "target": "bash16.js",
         "argumentFormat": ""
       },
       "Node20_1": {
         "target": "bash20.js",
         "argumentFormat": ""
       }
    }
    

Importante

Se não adicionar suporte para o executor do Node 20 às suas tarefas personalizadas, elas falharão nos agentes instalados a partir do feed release.