DevOps para um pipeline de ingestão de dadosDevOps for a data ingestion pipeline

Na maioria dos cenários, uma solução de ingestão de dados é uma composição de scripts, invocações de serviço e um pipeline que orquestra todas as atividades.In most scenarios, a data ingestion solution is a composition of scripts, service invocations, and a pipeline orchestrating all the activities. Neste artigo, você aprende a aplicar as práticas de DevOps ao ciclo de vida de desenvolvimento de um pipeline de ingestão de dados comum que prepara dados para treinamento de modelo de aprendizado de máquina.In this article, you learn how to apply DevOps practices to the development lifecycle of a common data ingestion pipeline that prepares data for machine learning model training. O pipeline é criado usando os seguintes serviços do Azure:The pipeline is built using the following Azure services:

  • Azure data Factory : lê os dados brutos e orquestra a preparação de dados.Azure Data Factory : Reads the raw data and orchestrates data preparation.
  • Azure Databricks : executa um bloco de anotações do Python que transforma os dados.Azure Databricks : Runs a Python notebook that transforms the data.
  • Azure pipelines : automatiza um processo contínuo de integração e desenvolvimento.Azure Pipelines : Automates a continuous integration and development process.

Fluxo de trabalho do pipeline de ingestão de dadosData ingestion pipeline workflow

O pipeline de ingestão de dados implementa o seguinte fluxo de trabalho:The data ingestion pipeline implements the following workflow:

  1. Os dados brutos são lidos em um pipeline de Azure Data Factory (ADF).Raw data is read into an Azure Data Factory (ADF) pipeline.
  2. O pipeline do ADF envia os dados para um cluster Azure Databricks, que executa um notebook Python para transformar os dados.The ADF pipeline sends the data to an Azure Databricks cluster, which runs a Python notebook to transform the data.
  3. Os dados são armazenados em um contêiner de BLOB, onde podem ser usados pelo Azure Machine Learning para treinar um modelo.The data is stored to a blob container, where it can be used by Azure Machine Learning to train a model.

fluxo de trabalho do pipeline de ingestão de dados

Visão geral de integração e entrega contínuaContinuous integration and delivery overview

Assim como ocorre com muitas soluções de software, há uma equipe (por exemplo, engenheiros de dados) trabalhando nela.As with many software solutions, there is a team (for example, Data Engineers) working on it. Eles colaboram e compartilham os mesmos recursos do Azure, como Azure Data Factory, Azure Databricks e contas de armazenamento do Azure.They collaborate and share the same Azure resources such as Azure Data Factory, Azure Databricks, and Azure Storage accounts. A coleção desses recursos é um ambiente de desenvolvimento.The collection of these resources is a Development environment. Os engenheiros de dados contribuem para a mesma base de código-fonte.The data engineers contribute to the same source code base.

Um sistema de integração e entrega contínua automatiza o processo de criação, teste e fornecimento (implantação) da solução.A continuous integration and delivery system automates the process of building, testing, and delivering (deploying) the solution. O processo de CI (integração contínua) executa as seguintes tarefas:The Continuous Integration (CI) process performs the following tasks:

  • Monta o códigoAssembles the code
  • Verifica com os testes de qualidade de códigoChecks it with the code quality tests
  • Executa testes de unidadeRuns unit tests
  • Produz artefatos como código testado e modelos de Azure Resource ManagerProduces artifacts such as tested code and Azure Resource Manager templates

O processo de entrega contínua (CD) implanta os artefatos nos ambientes downstream.The Continuous Delivery (CD) process deploys the artifacts to the downstream environments.

diagrama de ingestão de dados do cICD

Este artigo demonstra como automatizar os processos de CI e CD com o Azure pipelines.This article demonstrates how to automate the CI and CD processes with Azure Pipelines.

Gerenciamento de controle do código-fonteSource control management

O gerenciamento de controle do código-fonte é necessário para controlar as alterações e habilitar a colaboração entre os membros da equipe.Source control management is needed to track changes and enable collaboration between team members. Por exemplo, o código seria armazenado em um repositório DevOps, GitHub ou GitLab do Azure.For example, the code would be stored in an Azure DevOps, GitHub, or GitLab repository. O fluxo de trabalho de colaboração é baseado em um modelo de ramificação.The collaboration workflow is based on a branching model. Por exemplo, GitFlow.For example, GitFlow.

Código-fonte do notebook PythonPython Notebook Source Code

Os engenheiros de dados trabalham com o código-fonte do notebook Python localmente em um IDE (por exemplo, Visual Studio Code) ou diretamente no espaço de trabalho do databricks.The data engineers work with the Python notebook source code either locally in an IDE (for example, Visual Studio Code) or directly in the Databricks workspace. Depois que as alterações de código forem concluídas, elas serão mescladas ao repositório após uma política de ramificação.Once the code changes are complete, they are merged to the repository following a branching policy.

Dica

Recomendamos armazenar o código em .py arquivos em vez de no .ipynb formato Jupyter notebook.We recommended storing the code in .py files rather than in .ipynb Jupyter Notebook format. Ele melhora a legibilidade do código e permite verificações automáticas de qualidade de código no processo de CI.It improves the code readability and enables automatic code quality checks in the CI process.

Azure Data Factory código-fonteAzure Data Factory Source Code

O código-fonte de pipelines de Azure Data Factory é uma coleção de arquivos JSON gerados por um espaço de trabalho Azure Data Factory.The source code of Azure Data Factory pipelines is a collection of JSON files generated by an Azure Data Factory workspace. Normalmente, os engenheiros de dados trabalham com um designer visual no espaço de trabalho Azure Data Factory, e não com os arquivos de código-fonte diretamente.Normally the data engineers work with a visual designer in the Azure Data Factory workspace rather than with the source code files directly.

Para configurar o espaço de trabalho para usar um repositório de controle do código-fonte, confira autor com Azure Repos integração com o Git.To configure the workspace to use a source control repository, see Author with Azure Repos Git integration.

CI (Integração contínua)Continuous integration (CI)

O objetivo final do processo de integração contínua é reunir o trabalho de equipe conjunta do código-fonte e prepará-lo para a implantação nos ambientes downstream.The ultimate goal of the Continuous Integration process is to gather the joint team work from the source code and prepare it for the deployment to the downstream environments. Assim como no gerenciamento de código-fonte, esse processo é diferente para os notebooks Python e Azure Data Factory pipelines.As with the source code management this process is different for the Python notebooks and Azure Data Factory pipelines.

CI do notebook PythonPython Notebook CI

O processo de CI para os notebooks do Python Obtém o código da ramificação de colaboração (por exemplo, * Master _ ou develop ) e executa as seguintes atividades: _ fiapoing de códigoThe CI process for the Python Notebooks gets the code from the collaboration branch (for example, * master _ or develop ) and performs the following activities: _ Code linting

  • Teste de unidadeUnit testing
  • Salvando o código como um artefatoSaving the code as an artifact

O trecho de código a seguir demonstra a implementação dessas etapas em um pipeline do Azure DevOps * YAML _:The following code snippet demonstrates the implementation of these steps in an Azure DevOps * yaml _ pipeline:

steps:
- script: |
   flake8 --output-file=$(Build.BinariesDirectory)/lint-testresults.xml --format junit-xml  
  workingDirectory: '$(Build.SourcesDirectory)'
  displayName: 'Run flake8 (code style analysis)'  
  
- script: |
   python -m pytest --junitxml=$(Build.BinariesDirectory)/unit-testresults.xml $(Build.SourcesDirectory)
  displayName: 'Run unit tests'

- task: PublishTestResults@2
  condition: succeededOrFailed()
  inputs:
    testResultsFiles: '$(Build.BinariesDirectory)/_-testresults.xml'
    testRunTitle: 'Linting & Unit tests'
    failTaskOnFailedTests: true
  displayName: 'Publish linting and unit test results'

- publish: $(Build.SourcesDirectory)
    artifact: di-notebooks

O pipeline usa flake8 para fazer o refiapoção do código Python.The pipeline uses flake8 to do the Python code linting. Ele executa os testes de unidade definidos no código-fonte e publica os resultados de fiapos e de teste para que fiquem disponíveis na tela de execução do pipeline do Azure:It runs the unit tests defined in the source code and publishes the linting and test results so they're available in the Azure Pipeline execution screen:

refiapondo testes de unidade

Se os testes de unidade e de fiapoção forem bem-sucedidos, o pipeline copiará o código-fonte para o repositório de artefatos a ser usado pelas etapas de implantação subsequentes.If the linting and unit testing is successful, the pipeline will copy the source code to the artifact repository to be used by the subsequent deployment steps.

CI Azure Data FactoryAzure Data Factory CI

O processo de CI para um pipeline de Azure Data Factory é um afunilamento para um pipeline de ingestão de dados.CI process for an Azure Data Factory pipeline is a bottleneck for a data ingestion pipeline. Não há integração contínua.There's no continuous integration. Um artefato implantável para Azure Data Factory é uma coleção de modelos de Azure Resource Manager.A deployable artifact for Azure Data Factory is a collection of Azure Resource Manager templates. A única maneira de produzir esses modelos é clicar no botão * publicar _ no espaço de trabalho Azure data Factory.The only way to produce those templates is to click the * publish _ button in the Azure Data Factory workspace.

  1. Os engenheiros de dados mesclam o código-fonte de suas ramificações de recursos no Branch de colaboração, por exemplo, mestre ou desenvolvimento.The data engineers merge the source code from their feature branches into the collaboration branch, for example, master or develop.
  2. Alguém com as permissões concedidas clica no botão publicar para gerar modelos de Azure Resource Manager do código-fonte no Branch de colaboração.Someone with the granted permissions clicks the publish button to generate Azure Resource Manager templates from the source code in the collaboration branch.
  3. O espaço de trabalho valida os pipelines (Imagine-os a partir de refiapoing e teste de unidade), gera modelos de Azure Resource Manager (imagine a partir do prédio) e salva os modelos gerados em uma ramificação técnica adf_publish no mesmo repositório de código (Imagine-os a partir de artefatos de publicação).The workspace validates the pipelines (think of it as of linting and unit testing), generates Azure Resource Manager templates (think of it as of building) and saves the generated templates to a technical branch adf_publish in the same code repository (think of it as of publishing artifacts). Essa ramificação é criada automaticamente pelo espaço de trabalho Azure Data Factory.This branch is created automatically by the Azure Data Factory workspace.

Para obter mais informações sobre esse processo, consulte integração e entrega contínuas em Azure data Factory.For more information on this process, see Continuous integration and delivery in Azure Data Factory.

É importante garantir que os modelos de Azure Resource Manager gerados sejam independentes de ambiente.It's important to make sure that the generated Azure Resource Manager templates are environment agnostic. Isso significa que todos os valores que podem ser diferentes entre os ambientes são parametrizadas.This means that all values that may differ between environments are parametrized. Azure Data Factory é inteligente o suficiente para expor a maioria desses valores como parâmetros.Azure Data Factory is smart enough to expose the majority of such values as parameters. Por exemplo, no modelo a seguir, as propriedades de conexão para um Azure Machine Learning espaço de trabalho são expostas como parâmetros:For example, in the following template the connection properties to an Azure Machine Learning workspace are exposed as parameters:

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "factoryName": {
            "value": "devops-ds-adf"
        },
        "AzureMLService_servicePrincipalKey": {
            "value": ""
        },
        "AzureMLService_properties_typeProperties_subscriptionId": {
            "value": "0fe1c235-5cfa-4152-17d7-5dff45a8d4ba"
        },
        "AzureMLService_properties_typeProperties_resourceGroupName": {
            "value": "devops-ds-rg"
        },
        "AzureMLService_properties_typeProperties_servicePrincipalId": {
            "value": "6e35e589-3b22-4edb-89d0-2ab7fc08d488"
        },
        "AzureMLService_properties_typeProperties_tenant": {
            "value": "72f988bf-86f1-41af-912b-2d7cd611db47"
        }
    }
}

No entanto, talvez você queira expor suas propriedades personalizadas que não são tratadas pelo espaço de trabalho Azure Data Factory por padrão.However, you may want to expose your custom properties that are not handled by the Azure Data Factory workspace by default. No cenário deste artigo, um pipeline Azure Data Factory invoca um bloco de anotações Python que processa os dados.In the scenario of this article an Azure Data Factory pipeline invokes a Python notebook processing the data. O notebook aceita um parâmetro com o nome de um arquivo de dados de entrada.The notebook accepts a parameter with the name of an input data file.

import pandas as pd
import numpy as np

data_file_name = getArgument("data_file_name")
data = pd.read_csv(data_file_name)

labels = np.array(data['target'])
...

Esse nome é diferente para os ambientes dev , QA , UAT e prod .This name is different for Dev , QA , UAT , and PROD environments. Em um pipeline complexo com várias atividades, pode haver várias propriedades personalizadas.In a complex pipeline with multiple activities, there can be several custom properties. É uma boa prática coletar todos esses valores em um único local e defini-los como variáveis de pipeline:It's good practice to collect all those values in one place and define them as pipeline variables :

Captura de tela mostra um bloco de anotações chamado PrepareData e M L executar pipeline chamado M L executar pipeline na parte superior, com a guia variáveis selecionada abaixo com a opção de adicionar novas variáveis, cada uma com um nome, tipo e valor padrão.

As atividades de pipeline podem se referir às variáveis de pipeline ao mesmo tempo em que as utilizam:The pipeline activities may refer to the pipeline variables while actually using them:

A captura de tela mostra um bloco de anotações chamado PrepareData e M L executar pipeline chamado M L executar pipeline na parte superior, com a guia Configurações selecionada abaixo.

O espaço de trabalho Azure Data Factory não expõe variáveis de pipeline como parâmetros de modelos de Azure Resource Manager por padrão.The Azure Data Factory workspace doesn't expose pipeline variables as Azure Resource Manager templates parameters by default. O espaço de trabalho usa o modelo de parametrização padrão que determina quais propriedades de pipeline devem ser expostas como Azure Resource Manager parâmetros de modelo.The workspace uses the Default Parameterization Template dictating what pipeline properties should be exposed as Azure Resource Manager template parameters. Para adicionar variáveis de pipeline à lista, atualize a "Microsoft.DataFactory/factories/pipelines" seção do modelo de parametrização padrão com o trecho a seguir e coloque o arquivo JSON de resultado na raiz da pasta de origem:To add pipeline variables to the list, update the "Microsoft.DataFactory/factories/pipelines" section of the Default Parameterization Template with the following snippet and place the result json file in the root of the source folder:

"Microsoft.DataFactory/factories/pipelines": {
        "properties": {
            "variables": {
                "_": {
                    "defaultValue": "="
                }
            }
        }
    }

Isso forçará o espaço de trabalho Azure Data Factory a adicionar as variáveis à lista de parâmetros quando o botão * publicar _ for clicado:Doing so will force the Azure Data Factory workspace to add the variables to the parameters list when the * publish _ button is clicked:

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "factoryName": {
            "value": "devops-ds-adf"
        },
        ...
        "data-ingestion-pipeline_properties_variables_data_file_name_defaultValue": {
            "value": "driver_prediction_train.csv"
        }        
    }
}

Os valores no arquivo JSON são valores padrão configurados na definição do pipeline.The values in the JSON file are default values configured in the pipeline definition. Eles devem ser substituídos pelos valores de ambiente de destino quando o modelo de Azure Resource Manager é implantado.They're expected to be overridden with the target environment values when the Azure Resource Manager template is deployed.

CD (Entrega contínua)Continuous delivery (CD)

O processo de entrega contínua usa os artefatos e os implanta no primeiro ambiente de destino.The Continuous Delivery process takes the artifacts and deploys them to the first target environment. Ele verifica se a solução funciona executando testes.It makes sure that the solution works by running tests. Se for bem-sucedido, ele continuará no próximo ambiente.If successful, it continues to the next environment.

O pipeline do Azure do CD consiste em vários estágios que representam os ambientes.The CD Azure Pipeline consists of multiple stages representing the environments. Cada estágio contém implantações e trabalhos que executam as seguintes etapas:Each stage contains deployments and jobs that perform the following steps:

_ Implantar um bloco de anotações do Python no espaço de trabalho Azure Databricks_ Deploy a Python Notebook to Azure Databricks workspace

  • Implantar um pipeline de Azure Data FactoryDeploy an Azure Data Factory pipeline
  • Executar o pipelineRun the pipeline
  • Verificar o resultado da ingestão de dadosCheck the data ingestion result

Os estágios de pipeline podem ser configurados com aprovações e Gates que fornecem controle adicional sobre como o processo de implantação evolui pela cadeia de ambientes.The pipeline stages can be configured with approvals and gates that provide additional control on how the deployment process evolves through the chain of environments.

Implantar um bloco de anotações do PythonDeploy a Python Notebook

O trecho de código a seguir define uma implantação de pipeline do Azure que copia um bloco de anotações do Python para um cluster do databricks:The following code snippet defines an Azure Pipeline deployment that copies a Python notebook to a Databricks cluster:

- stage: 'Deploy_to_QA'
  displayName: 'Deploy to QA'
  variables:
  - group: devops-ds-qa-vg
  jobs:
  - deployment: "Deploy_to_Databricks"
    displayName: 'Deploy to Databricks'
    timeoutInMinutes: 0
    environment: qa
    strategy:
      runOnce:
        deploy:
          steps:
            - task: UsePythonVersion@0
              inputs:
                versionSpec: '3.x'
                addToPath: true
                architecture: 'x64'
              displayName: 'Use Python3'

            - task: configuredatabricks@0
              inputs:
                url: '$(DATABRICKS_URL)'
                token: '$(DATABRICKS_TOKEN)'
              displayName: 'Configure Databricks CLI'    

            - task: deploynotebooks@0
              inputs:
                notebooksFolderPath: '$(Pipeline.Workspace)/di-notebooks'
                workspaceFolder: '/Shared/devops-ds'
              displayName: 'Deploy (copy) data processing notebook to the Databricks cluster'       

Os artefatos produzidos pelo CI são copiados automaticamente para o agente de implantação e estão disponíveis na $(Pipeline.Workspace) pasta.The artifacts produced by the CI are automatically copied to the deployment agent and are available in the $(Pipeline.Workspace) folder. Nesse caso, a tarefa de implantação refere-se ao di-notebooks artefato que contém o bloco de notas do Python.In this case, the deployment task refers to the di-notebooks artifact containing the Python notebook. Essa implantação usa a extensão DevOps do databricks do Azure para copiar os arquivos do bloco de anotações para o espaço de trabalho do databricks.This deployment uses the Databricks Azure DevOps extension to copy the notebook files to the Databricks workspace.

O Deploy_to_QA estágio contém uma referência ao devops-ds-qa-vg grupo de variáveis definido no projeto DevOps do Azure.The Deploy_to_QA stage contains a reference to the devops-ds-qa-vg variable group defined in the Azure DevOps project. As etapas neste estágio referem-se às variáveis desse grupo de variáveis (por exemplo, $(DATABRICKS_URL) e $(DATABRICKS_TOKEN) ).The steps in this stage refer to the variables from this variable group (for example, $(DATABRICKS_URL) and $(DATABRICKS_TOKEN)). A ideia é que o próximo estágio (por exemplo, Deploy_to_UAT ) funcionará com os mesmos nomes de variáveis definidos em seu próprio grupo de variáveis no escopo de UAT.The idea is that the next stage (for example, Deploy_to_UAT) will operate with the same variable names defined in its own UAT-scoped variable group.

Implantar um pipeline de Azure Data FactoryDeploy an Azure Data Factory pipeline

Um artefato implantável para Azure Data Factory é um modelo de Azure Resource Manager.A deployable artifact for Azure Data Factory is an Azure Resource Manager template. Ela será implantada com a tarefa * implantação do grupo de recursos do Azure , pois ela é demonstrada no seguinte trecho de código:It's going to be deployed with the * Azure Resource Group Deployment _ task as it is demonstrated in the following snippet:

  - deployment: "Deploy_to_ADF"
    displayName: 'Deploy to ADF'
    timeoutInMinutes: 0
    environment: qa
    strategy:
      runOnce:
        deploy:
          steps:
            - task: AzureResourceGroupDeployment@2
              displayName: 'Deploy ADF resources'
              inputs:
                azureSubscription: $(AZURE_RM_CONNECTION)
                resourceGroupName: $(RESOURCE_GROUP)
                location: $(LOCATION)
                csmFile: '$(Pipeline.Workspace)/adf-pipelines/ARMTemplateForFactory.json'
                csmParametersFile: '$(Pipeline.Workspace)/adf-pipelines/ARMTemplateParametersForFactory.json'
                overrideParameters: -data-ingestion-pipeline_properties_variables_data_file_name_defaultValue "$(DATA_FILE_NAME)"

O valor do parâmetro data filename vem da $(DATA_FILE_NAME) variável definida em um grupo de variáveis de estágio de QA.The value of the data filename parameter comes from the $(DATA_FILE_NAME) variable defined in a QA stage variable group. Da mesma forma, todos os parâmetros definidos no ARMTemplateForFactory.jsem podem ser substituídos.Similarly, all parameters defined in ARMTemplateForFactory.json can be overridden. Se não forem, os valores padrão serão usados.If they are not, then the default values are used.

Executar o pipeline e verificar o resultado da ingestão de dadosRun the pipeline and check the data ingestion result

A próxima etapa é verificar se a solução implantada está funcionando.The next step is to make sure that the deployed solution is working. A definição de trabalho a seguir executa um pipeline Azure Data Factory com um script do PowerShell e executa um notebook Python em um cluster Azure Databricks.The following job definition runs an Azure Data Factory pipeline with a PowerShell script and executes a Python notebook on an Azure Databricks cluster. O notebook verifica se os dados foram ingeridos corretamente e valida o arquivo de dados de resultado com o $(bin_FILE_NAME) nome.The notebook checks if the data has been ingested correctly and validates the result data file with $(bin_FILE_NAME) name.

  - job: "Integration_test_job"
    displayName: "Integration test job"
    dependsOn: [Deploy_to_Databricks, Deploy_to_ADF]
    pool:
      vmImage: 'ubuntu-latest'
    timeoutInMinutes: 0
    steps:
    - task: AzurePowerShell@4
      displayName: 'Execute ADF Pipeline'
      inputs:
        azureSubscription: $(AZURE_RM_CONNECTION)
        ScriptPath: '$(Build.SourcesDirectory)/adf/utils/Invoke-ADFPipeline.ps1'
        ScriptArguments: '-ResourceGroupName $(RESOURCE_GROUP) -DataFactoryName $(DATA_FACTORY_NAME) -PipelineName $(PIPELINE_NAME)'
        azurePowerShellVersion: LatestVersion
    - task: UsePythonVersion@0
      inputs:
        versionSpec: '3.x'
        addToPath: true
        architecture: 'x64'
      displayName: 'Use Python3'

    - task: configuredatabricks@0
      inputs:
        url: '$(DATABRICKS_URL)'
        token: '$(DATABRICKS_TOKEN)'
      displayName: 'Configure Databricks CLI'    

    - task: executenotebook@0
      inputs:
        notebookPath: '/Shared/devops-ds/test-data-ingestion'
        existingClusterId: '$(DATABRICKS_CLUSTER_ID)'
        executionParams: '{"bin_file_name":"$(bin_FILE_NAME)"}'
      displayName: 'Test data ingestion'

    - task: waitexecution@0
      displayName: 'Wait until the testing is done'

A tarefa final no trabalho verifica o resultado da execução do bloco de anotações.The final task in the job checks the result of the notebook execution. Se ele retornar um erro, ele definirá o status da execução do pipeline como com falha.If it returns an error, it sets the status of pipeline execution to failed.

Juntando partesPutting pieces together

O pipeline completo de CI/CD do Azure consiste nos seguintes estágios: _ CIThe complete CI/CD Azure Pipeline consists of the following stages: _ CI

  • Implantar em p e rDeploy To QA
    • Implantar no databricks + implantar no ADFDeploy to Databricks + Deploy to ADF
    • Teste de integraçãoIntegration Test

Ele contém um número de * implantação _ estágios igual ao número de ambientes de destino que você tem.It contains a number of * Deploy _ stages equal to the number of target environments you have. Cada estágio de implantação contém duas implantações executadas em paralelo e um trabalho executado após as implantações para testar a solução no ambiente.Each Deploy stage contains two deployments that run in parallel and a job that runs after deployments to test the solution on the environment.

Uma implementação de exemplo do pipeline é montada no seguinte trecho de YAML :A sample implementation of the pipeline is assembled in the following yaml snippet:

variables:
- group: devops-ds-vg

stages:
- stage: 'CI'
  displayName: 'CI'
  jobs:
  - job: "CI_Job"
    displayName: "CI Job"
    pool:
      vmImage: 'ubuntu-latest'
    timeoutInMinutes: 0
    steps:
    - task: UsePythonVersion@0
      inputs:
        versionSpec: '3.x'
        addToPath: true
        architecture: 'x64'
      displayName: 'Use Python3'
    - script: pip install --upgrade flake8 flake8_formatter_junit_xml
      displayName: 'Install flake8'
    - checkout: self
    - script: |
       flake8 --output-file=$(Build.BinariesDirectory)/lint-testresults.xml --format junit-xml  
    workingDirectory: '$(Build.SourcesDirectory)'
    displayName: 'Run flake8 (code style analysis)'  
    - script: |
       python -m pytest --junitxml=$(Build.BinariesDirectory)/unit-testresults.xml $(Build.SourcesDirectory)
    displayName: 'Run unit tests'
    - task: PublishTestResults@2
    condition: succeededOrFailed()
    inputs:
        testResultsFiles: '$(Build.BinariesDirectory)/_-testresults.xml'
        testRunTitle: 'Linting & Unit tests'
        failTaskOnFailedTests: true
    displayName: 'Publish linting and unit test results'    

    # The CI stage produces two artifacts (notebooks and ADF pipelines).
    # The pipelines Azure Resource Manager templates are stored in a technical branch "adf_publish"
    - publish: $(Build.SourcesDirectory)/$(Build.Repository.Name)/code/dataingestion
      artifact: di-notebooks
    - checkout: git://${{variables['System.TeamProject']}}@adf_publish    
    - publish: $(Build.SourcesDirectory)/$(Build.Repository.Name)/devops-ds-adf
      artifact: adf-pipelines

- stage: 'Deploy_to_QA'
  displayName: 'Deploy to QA'
  variables:
  - group: devops-ds-qa-vg
  jobs:
  - deployment: "Deploy_to_Databricks"
    displayName: 'Deploy to Databricks'
    timeoutInMinutes: 0
    environment: qa
    strategy:
      runOnce:
        deploy:
          steps:
            - task: UsePythonVersion@0
              inputs:
                versionSpec: '3.x'
                addToPath: true
                architecture: 'x64'
              displayName: 'Use Python3'

            - task: configuredatabricks@0
              inputs:
                url: '$(DATABRICKS_URL)'
                token: '$(DATABRICKS_TOKEN)'
              displayName: 'Configure Databricks CLI'    

            - task: deploynotebooks@0
              inputs:
                notebooksFolderPath: '$(Pipeline.Workspace)/di-notebooks'
                workspaceFolder: '/Shared/devops-ds'
              displayName: 'Deploy (copy) data processing notebook to the Databricks cluster'             
  - deployment: "Deploy_to_ADF"
    displayName: 'Deploy to ADF'
    timeoutInMinutes: 0
    environment: qa
    strategy:
      runOnce:
        deploy:
          steps:
            - task: AzureResourceGroupDeployment@2
              displayName: 'Deploy ADF resources'
              inputs:
                azureSubscription: $(AZURE_RM_CONNECTION)
                resourceGroupName: $(RESOURCE_GROUP)
                location: $(LOCATION)
                csmFile: '$(Pipeline.Workspace)/adf-pipelines/ARMTemplateForFactory.json'
                csmParametersFile: '$(Pipeline.Workspace)/adf-pipelines/ARMTemplateParametersForFactory.json'
                overrideParameters: -data-ingestion-pipeline_properties_variables_data_file_name_defaultValue "$(DATA_FILE_NAME)"
  - job: "Integration_test_job"
    displayName: "Integration test job"
    dependsOn: [Deploy_to_Databricks, Deploy_to_ADF]
    pool:
      vmImage: 'ubuntu-latest'
    timeoutInMinutes: 0
    steps:
    - task: AzurePowerShell@4
      displayName: 'Execute ADF Pipeline'
      inputs:
        azureSubscription: $(AZURE_RM_CONNECTION)
        ScriptPath: '$(Build.SourcesDirectory)/adf/utils/Invoke-ADFPipeline.ps1'
        ScriptArguments: '-ResourceGroupName $(RESOURCE_GROUP) -DataFactoryName $(DATA_FACTORY_NAME) -PipelineName $(PIPELINE_NAME)'
        azurePowerShellVersion: LatestVersion
    - task: UsePythonVersion@0
      inputs:
        versionSpec: '3.x'
        addToPath: true
        architecture: 'x64'
      displayName: 'Use Python3'

    - task: configuredatabricks@0
      inputs:
        url: '$(DATABRICKS_URL)'
        token: '$(DATABRICKS_TOKEN)'
      displayName: 'Configure Databricks CLI'    

    - task: executenotebook@0
      inputs:
        notebookPath: '/Shared/devops-ds/test-data-ingestion'
        existingClusterId: '$(DATABRICKS_CLUSTER_ID)'
        executionParams: '{"bin_file_name":"$(bin_FILE_NAME)"}'
      displayName: 'Test data ingestion'

    - task: waitexecution@0
      displayName: 'Wait until the testing is done'                

Próximas etapasNext steps