CI/CD s Jenkinsem v Azure Databricks

Poznámka:

Tento článek se zabývá Jenkinsem, který vyvíjí třetí strana. Pokud chcete kontaktovat poskytovatele, přečtěte si nápovědu Jenkinse.

Tento článek popisuje, jak pomocí automatizačního serveru Jenkinse s Azure Databricks implementovat pracovní postup vývoje CI/CD.

Přehled CI/CD s Azure Databricks najdete v tématu CI/CD v Azure Databricks. Osvědčené postupy najdete v pracovních postupech CI/CD v databricks a osvědčených postupech pro vývojáře v Databricks.

Nastavení místního vývojového počítače

V příkladu tohoto článku se pomocí Jenkinse dává pokyn Databricks CLI a balíčkům deklarativní automatizace provést následující:

  1. Vytvořte soubor kola Pythonu na místním vývojovém počítači.
  2. Nasaďte vytvořený soubor kola Pythonu spolu s dalšími soubory Pythonu a poznámkovými bloky Pythonu z místního vývojového počítače do pracovního prostoru Azure Databricks.
  3. Otestujte a spusťte nahraný soubor kol Pythonu a poznámkové bloky v daném pracovním prostoru.

Pokud chcete nastavit místní vývojový počítač, aby dal pracovnímu prostoru Azure Databricks pokyn k provedení fází sestavení a nahrání v tomto příkladu, udělejte na místním vývojovém počítači následující:

Krok 1: Instalace požadovaných nástrojů

V tomto kroku nainstalujete Databricks CLI, Jenkins, jq a nástroje pro sestavení Python wheel na vašem místním vývojovém počítači. Tyto nástroje jsou potřeba ke spuštění tohoto příkladu.

  1. Pokud jste to ještě neudělali, nainstalujte Databricks CLI verze 0.205 nebo vyšší. Jenkins používá rozhraní příkazového řádku Databricks k předání testovacích a provozních pokynů tohoto příkladu do vašeho pracovního prostoru. Viz Instalaci nebo aktualizaci rozhraní příkazového řádku Databricks.

  2. Pokud jste to ještě neudělali, nainstalujte a spusťte Jenkinse. Viz Instalace Jenkinse pro Linux, macOS nebo Windows.

  3. Nainstalujte jq. Tento příklad používá jq k analýze výstupu příkazu ve formátu JSON.

  4. Použijte pip k instalaci nástrojů pro sestavení kol Pythonu pomocí následujícího příkazu (některé systémy můžou vyžadovat, abyste místo pip3pip):

    pip install --upgrade wheel
    

Krok 2: Vytvoření kanálu Jenkinse

V tomto kroku pomocí Jenkinse vytvoříte kanál Jenkinse pro příklad tohoto článku. Jenkins nabízí několik různých typů projektů pro vytváření kanálů CI/CD. Jenkins Pipelines poskytuje rozhraní pro definování fází v kanálu Jenkinse pomocí kódu Groovy pro volání a konfiguraci modulů plug-in Jenkins.

Typy projektů Jenkinse

Vytvoření kanálu Jenkinse v Jenkinsi:

  1. Po spuštění Jenkinse klikněte na řídicím panelu Jenkinse na Nová položka.
  2. Jako název položky zadejte název kanálu Jenkinse, například jenkins-demo.
  3. Klikněte na ikonu typu projektu kanálu .
  4. Klikněte na OK. Zobrazí se stránka Konfigurace kanálu Jenkinse.
  5. V oblasti Kanálu v rozevíracím seznamu Definition vyberte skript kanálu z SCM.
  6. V rozevíracím seznamu SCM vyberte Git.
  7. Jako URL úložiště zadejte URL úložiště, které je hostované vaším poskytovatelem Git třetí stranou.
  8. Jako specifikátor větve zadejte */<branch-name>, kde <branch-name> je název větve ve vašem úložišti, který chcete použít, například */main.
  9. Pro cestu ke skriptu, zadejte Jenkinsfile, pokud ještě není nastavena. Později v tomto článku vytvoříte Jenkinsfile .
  10. Zrušte zaškrtnutí políčka s názvem Lightweight checkout(pokud už je zaškrtnuté).
  11. Klikněte na Uložit.

Krok 3: Přidání globálních proměnných prostředí do Jenkinse

V tomto kroku přidáte do Jenkinse tři globální proměnné prostředí. Jenkins tyto proměnné prostředí předává do rozhraní příkazového řádku Databricks. Rozhraní příkazového řádku Databricks potřebuje hodnoty těchto proměnných prostředí k ověření v pracovním prostoru Azure Databricks. V tomto příkladu se používá ověřování OAuth machine-to-machine (M2M) pro služební účet, ačkoli jsou k dispozici i jiné typy ověřování. Pokud chcete nastavit ověřování OAuth M2M pro váš pracovní prostor Azure Databricks, přečtěte si téma Autorizace přístupu instančního objektu k Azure Databricks pomocí OAuth.

V tomto příkladu jsou tři globální proměnné prostředí:

  • DATABRICKS_HOST, nastavte na adresu URL svého pracovního prostoru Azure Databricks, která začíná https://. Viz názvy instancí pracovního prostoru, adresy URL a ID.
  • DATABRICKS_CLIENT_ID, nastavte na ID klienta instančního objektu, které se označuje také jako ID aplikace.
  • DATABRICKS_CLIENT_SECRET, nastavte tajný klíč Azure Databricks OAuth instančního objektu.

Pokud chcete nastavit globální proměnné prostředí v Jenkinse, na řídicím panelu Jenkinse:

  1. Na bočním panelu klikněte na Spravovat Jenkinse.
  2. V části Konfigurace systému klepněte na tlačítko Systém.
  3. V části Globální vlastnosti zaškrtněte políčko s názvem Proměnné prostředí.
  4. Klikněte na Přidat a zadejte název a hodnotu proměnné prostředí. Tento postup opakujte pro každou další proměnnou prostředí.
  5. Po dokončení přidávání proměnných prostředí klikněte na Uložit a vraťte se na Jenkinsův řídicí panel.

Návrh kanálu Jenkinse

Jenkins nabízí několik různých typů projektů pro vytváření kanálů CI/CD. Tento příklad implementuje pipeline Jenkins. Jenkins Pipelines poskytuje rozhraní pro definování fází v kanálu Jenkinse pomocí kódu Groovy pro volání a konfiguraci modulů plug-in Jenkins.

Definici kanálu Jenkinse zapíšete do textového souboru s názvem Jenkinsfile, který je zase vrácen do úložiště správy zdrojového kódu projektu. Další informace najdete v tématu Jenkins Pipeline. Tady je kanál Jenkinse pro příklad tohoto článku. V tomto příkladu Jenkinsfilenahraďte následující zástupné symboly:

  • Nahraďte <user-name> uživatelským jménem a <repo-name> názvem úložiště, jak je hostováno vaším poskytovatelem Git služeb třetí strany. Tento článek používá jako příklad adresu URL GitHubu.
  • Nahraďte <release-branch-name> názvem větve pro vydání ve vašem úložišti. Může to být mainnapříklad .
  • Nahraďte <databricks-cli-installation-path> cestu na místním vývojovém počítači, kde je nainstalované rozhraní příkazového řádku Databricks. Například v macOS to může být /usr/local/bin.
  • Nahraďte <jq-installation-path> cestu na místním vývojovém počítači, na kterém jq je nainstalovaný. Například v macOS to může být /usr/local/bin.
  • Nahraďte <job-prefix-name> řetězcem, který vám pomůže jednoznačně identifikovat úlohy vytvořené v pracovním prostoru v tomto příkladu. Může to být jenkins-demonapříklad .
  • Všimněte si, že BUNDLETARGET je nastavena na dev, což je název cíle sady deklarativní automatizace, který je definován dále v tomto článku. Při reálných implementacích změňte tento název na název vlastního cíle sady. Další podrobnosti o cílech sady najdete dále v tomto článku.

Tady je soubor Jenkinsfile, který se musí přidat do kořenového adresáře úložiště:

// Filename: Jenkinsfile
node {
  def GITREPOREMOTE = "https://github.com/<user-name>/<repo-name>.git"
  def GITBRANCH     = "<release-branch-name>"
  def DBCLIPATH     = "<databricks-cli-installation-path>"
  def JQPATH        = "<jq-installation-path>"
  def JOBPREFIX     = "<job-prefix-name>"
  def BUNDLETARGET  = "dev"

  stage('Checkout') {
    git branch: GITBRANCH, url: GITREPOREMOTE
  }
  stage('Validate Bundle') {
    sh """#!/bin/bash
          ${DBCLIPATH}/databricks bundle validate -t ${BUNDLETARGET}
       """
  }
  stage('Deploy Bundle') {
    sh """#!/bin/bash
          ${DBCLIPATH}/databricks bundle deploy -t ${BUNDLETARGET}
       """
  }
  stage('Run Unit Tests') {
    sh """#!/bin/bash
          ${DBCLIPATH}/databricks bundle run -t ${BUNDLETARGET} run-unit-tests
       """
  }
  stage('Run Notebook') {
    sh """#!/bin/bash
          ${DBCLIPATH}/databricks bundle run -t ${BUNDLETARGET} run-dabdemo-notebook
       """
  }
  stage('Evaluate Notebook Runs') {
    sh """#!/bin/bash
          ${DBCLIPATH}/databricks bundle run -t ${BUNDLETARGET} evaluate-notebook-runs
       """
  }
  stage('Import Test Results') {
    def DATABRICKS_BUNDLE_WORKSPACE_ROOT_PATH
    def getPath = "${DBCLIPATH}/databricks bundle validate -t ${BUNDLETARGET} | ${JQPATH}/jq -r .workspace.file_path"
    def output = sh(script: getPath, returnStdout: true).trim()

    if (output) {
      DATABRICKS_BUNDLE_WORKSPACE_ROOT_PATH = "${output}"
    } else {
      error "Failed to capture output or command execution failed: ${getPath}"
    }

    sh """#!/bin/bash
          ${DBCLIPATH}/databricks workspace export-dir \
          ${DATABRICKS_BUNDLE_WORKSPACE_ROOT_PATH}/Validation/Output/test-results \
          ${WORKSPACE}/Validation/Output/test-results \
          -t ${BUNDLETARGET} \
          --overwrite
       """
  }
  stage('Publish Test Results') {
    junit allowEmptyResults: true, testResults: '**/test-results/*.xml', skipPublishingChecks: true
  }
}

Zbývající část tohoto článku popisuje jednotlivé fáze tohoto kanálu Jenkinse a jak nastavit artefakty a příkazy pro Jenkinse ke spuštění v této fázi.

Stažení nejnovějších artefaktů z úložiště třetí strany

První fáze v tomto kanálu Jenkinse, fáze Checkout , je definována takto:

stage('Checkout') {
  git branch: GITBRANCH, url: GITREPOREMOTE
}

Tato fáze zajišťuje, že pracovní adresář, který Jenkins používá na místním vývojovém počítači, má nejnovější artefakty z vašeho úložiště Git třetí strany. Jenkins obvykle nastaví tento pracovní adresář na <your-user-home-directory>/.jenkins/workspace/<pipeline-name>. To vám umožní na stejném místním vývojovém počítači zachovat vlastní kopii artefaktů ve vývoji odděleně od artefaktů, které Jenkins používá z vašeho úložiště Git třetí strany.

Ověření sady prostředků Databricks

Druhá fáze v tomto kanálu Jenkinse, Validate Bundle fáze, je definována takto:

stage('Validate Bundle') {
  sh """#!/bin/bash
        ${DBCLIPATH}/databricks bundle validate -t ${BUNDLETARGET}
     """
}

Tato fáze zajišťuje, že sada, která definuje pracovní postupy pro testování a spouštění artefaktů, je syntakticky správná. Deklarativní balíčky automatizace umožňují vyjádřit kompletní data, analýzy a projekty ML jako kolekci zdrojových souborů. Viz Co jsou balíčky deklarativní automatizace?

Pokud chcete definovat sadu pro tento článek, vytvořte soubor s názvem databricks.yml v kořenovém adresáři klonovaného úložiště na místním počítači. V tomto ukázkovém databricks.yml souboru nahraďte následující zástupné symboly:

  • Nahraďte <bundle-name> jedinečným programovým názvem sady. Může to být jenkins-demonapříklad .
  • Nahraďte <job-prefix-name> řetězcem, který vám pomůže jednoznačně identifikovat úlohy vytvořené v pracovním prostoru v tomto příkladu. Může to být jenkins-demonapříklad . Měla by odpovídat hodnotě JOBPREFIX v souboru Jenkinsfile.
  • Nahraďte <spark-version-id> ID verze databricks Runtime pro clustery úloh, například 13.3.x-scala2.12.
  • Nahraďte <cluster-node-type-id> ID typu uzlu pro clustery úloh, například Standard_DS3_v2.
  • Všimněte si, že dev v targets mapování je stejné jako BUNDLETARGET v souboru Jenkinsfile. Cíl sady určuje hostitele a související chování nasazení.

Tady je databricks.yml soubor, který se musí přidat do kořenového adresáře úložiště, aby tento příklad fungoval správně:

# Filename: databricks.yml
bundle:
  name: <bundle-name>

variables:
  job_prefix:
    description: A unifying prefix for this bundle's job and task names.
    default: <job-prefix-name>
  spark_version:
    description: The cluster's Spark version ID.
    default: <spark-version-id>
  node_type_id:
    description: The cluster's node type ID.
    default: <cluster-node-type-id>

artifacts:
  dabdemo-wheel:
    type: whl
    path: ./Libraries/python/dabdemo

resources:
  jobs:
    run-unit-tests:
      name: ${var.job_prefix}-run-unit-tests
      tasks:
        - task_key: ${var.job_prefix}-run-unit-tests-task
          new_cluster:
            spark_version: ${var.spark_version}
            node_type_id: ${var.node_type_id}
            num_workers: 1
            spark_env_vars:
              WORKSPACEBUNDLEPATH: ${workspace.root_path}
          notebook_task:
            notebook_path: ./run_unit_tests.py
            source: WORKSPACE
          libraries:
            - pypi:
                package: pytest
    run-dabdemo-notebook:
      name: ${var.job_prefix}-run-dabdemo-notebook
      tasks:
        - task_key: ${var.job_prefix}-run-dabdemo-notebook-task
          new_cluster:
            spark_version: ${var.spark_version}
            node_type_id: ${var.node_type_id}
            num_workers: 1
            data_security_mode: SINGLE_USER
            spark_env_vars:
              WORKSPACEBUNDLEPATH: ${workspace.root_path}
          notebook_task:
            notebook_path: ./dabdemo_notebook.py
            source: WORKSPACE
          libraries:
            - whl: '/Workspace${workspace.root_path}/files/Libraries/python/dabdemo/dist/dabdemo-0.0.1-py3-none-any.whl'
    evaluate-notebook-runs:
      name: ${var.job_prefix}-evaluate-notebook-runs
      tasks:
        - task_key: ${var.job_prefix}-evaluate-notebook-runs-task
          new_cluster:
            spark_version: ${var.spark_version}
            node_type_id: ${var.node_type_id}
            num_workers: 1
            spark_env_vars:
              WORKSPACEBUNDLEPATH: ${workspace.root_path}
          spark_python_task:
            python_file: ./evaluate_notebook_runs.py
            source: WORKSPACE
          libraries:
            - pypi:
                package: unittest-xml-reporting

targets:
  dev:
    mode: development

Další informace o souboru naleznete v databricks.yml tématu Konfigurace deklarativních automatizačních balíčků.

Nasazení sady do pracovního prostoru

Třetí fáze pipeline Jenkinse s názvem Deploy Bundle je definována takto:

stage('Deploy Bundle') {
  sh """#!/bin/bash
        ${DBCLIPATH}/databricks bundle deploy -t ${BUNDLETARGET}
     """
}

Tato fáze dělá dvě věci:

  1. Vzhledem k tomu, že artifact mapování v databricks.yml souboru je nastavené whl, dává rozhraní příkazového řádku Databricks pokyn k sestavení souboru kola Pythonu pomocí setup.py souboru v zadaném umístění.
  2. Po vytvoření souboru kola Pythonu na místním vývojovém počítači nasadí rozhraní příkazového řádku Databricks vytvořený soubor kola Pythonu spolu se zadanými soubory a poznámkovými bloky Pythonu do pracovního prostoru Azure Databricks. Ve výchozím nastavení deklarativní automatizační balíčky nasadí Python Wheel soubor a další soubory do /Workspace/Users/<your-username>/.bundle/<bundle-name>/<target-name>.

Pokud chcete povolit, aby se soubor kola Pythonu vytvořil tak, jak je uvedeno v databricks.yml souboru, vytvořte následující složky a soubory v kořenovém adresáři naklonovaného úložiště na místním počítači.

Pokud chcete definovat logiku a testy jednotek pro soubor kola Pythonu, na který se poznámkový blok spustí, vytvořte dva pojmenované addcol.pytest_addcol.pysoubory a přidejte je do struktury složek pojmenované python/dabdemo/dabdemo ve složce úložiště Libraries :

├── ...
├── Libraries
│    └── python
│          └── dabdemo
│                └── dabdemo
│                      ├── addcol.py
│                      └── test_addcol.py
├── ...

Soubor addcol.py obsahuje funkci knihovny, která je později integrovaná do souboru kola Pythonu a pak je nainstalovaná v clusteru Azure Databricks. Tato funkce přidá do datového rámce Apache Spark nový sloupec naplněný literálem:

# Filename: addcol.py
import pyspark.sql.functions as F

def with_status(df):
  return df.withColumn("status", F.lit("checked"))

Soubor test_addcol.py obsahuje testy, které předávají simulovaný objekt DataFrame funkci with_status definované v addcol.py. Výsledek se pak porovná s objektem DataFrame obsahujícím očekávané hodnoty. Pokud se hodnoty shodují, což v tomto případě proběhne, test projde:

# Filename: test_addcol.py
import pytest
from pyspark.sql import SparkSession
from dabdemo.addcol import *

class TestAppendCol(object):

  def test_with_status(self):
    spark = SparkSession.builder.getOrCreate()

    source_data = [
      ("paula", "white", "paula.white@example.com"),
      ("john", "baer", "john.baer@example.com")
    ]

    source_df = spark.createDataFrame(
      source_data,
      ["first_name", "last_name", "email"]
    )

    actual_df = with_status(source_df)

    expected_data = [
      ("paula", "white", "paula.white@example.com", "checked"),
      ("john", "baer", "john.baer@example.com", "checked")
    ]
    expected_df = spark.createDataFrame(
      expected_data,
      ["first_name", "last_name", "email", "status"]
    )

    assert(expected_df.collect() == actual_df.collect())

Aby rozhraní příkazového řádku Databricks správně zabalilo kód knihovny do souboru pythonového balíku typu wheel, vytvořte dva soubory pojmenované __init__.py a __main__.py ve stejné složce jako předchozí dva soubory. Vytvořte také soubor s názvem setup.py ve python/dabdemo složce:

├── ...
├── Libraries
│    └── python
│          └── dabdemo
│                ├── dabdemo
│                │    ├── __init__.py
│                │    ├── __main__.py
│                │    ├── addcol.py
│                │    └── test_addcol.py
│                └── setup.py
├── ...

Soubor __init__.py obsahuje číslo verze a autora knihovny. Nahraďte <my-author-name> svým jménem:

# Filename: __init__.py
__version__ = '0.0.1'
__author__ = '<my-author-name>'

import sys, os

sys.path.append(os.path.join(os.path.dirname(__file__), "..", ".."))

Soubor __main__.py obsahuje vstupní bod knihovny:

# Filename: __main__.py
import sys, os

sys.path.append(os.path.join(os.path.dirname(__file__), "..", ".."))

from addcol import *

def main():
  pass

if __name__ == "__main__":
  main()

Soubor setup.py obsahuje další nastavení pro sestavení knihovny do souboru kola Pythonu. Nahraďte <my-url>, <my-author-name>@<my-organization>a <my-package-description> smysluplnými hodnotami:

# Filename: setup.py
from setuptools import setup, find_packages

import dabdemo

setup(
  name = "dabdemo",
  version = dabdemo.__version__,
  author = dabdemo.__author__,
  url = "https://<my-url>",
  author_email = "<my-author-name>@<my-organization>",
  description = "<my-package-description>",
  packages = find_packages(include = ["dabdemo"]),
  entry_points={"group_1": "run=dabdemo.__main__:main"},
  install_requires = ["setuptools"]
)

Testování logiky komponent kolečka Pythonu

Fáze Run Unit Tests, čtvrtá fáze tohoto pipeline Jenkinse, používá pytest k otestování logiky knihovny, aby se ujistila, že funguje podle očekávání. Tato fáze je definována takto:

stage('Run Unit Tests') {
  sh """#!/bin/bash
        ${DBCLIPATH}/databricks bundle run -t ${BUNDLETARGET} run-unit-tests
     """
}

Tato fáze používá rozhraní příkazového řádku Databricks ke spuštění úlohy poznámkového bloku. Tato úloha spustí poznámkový blok Pythonu s názvem souboru run-unit-test.py. Tento poznámkový blok běží pytest proti logice knihovny.

Pokud chcete spustit testy jednotek pro tento příklad, přidejte do kořenového adresáře naklonovaného úložiště na místním počítači soubor run_unit_tests.py poznámkového bloku Pythonu s následujícím obsahem:

# Databricks notebook source

# COMMAND ----------

# MAGIC %sh
# MAGIC
# MAGIC mkdir -p "/Workspace${WORKSPACEBUNDLEPATH}/Validation/reports/junit/test-reports"

# COMMAND ----------

# Prepare to run pytest.
import sys, pytest, os

# Skip writing pyc files on a readonly filesystem.
sys.dont_write_bytecode = True

# Run pytest.
retcode = pytest.main(["--junit-xml", f"/Workspace{os.getenv('WORKSPACEBUNDLEPATH')}/Validation/reports/junit/test-reports/TEST-libout.xml",
                      f"/Workspace{os.getenv('WORKSPACEBUNDLEPATH')}/files/Libraries/python/dabdemo/dabdemo/"])

# Fail the cell execution if there are any test failures.
assert retcode == 0, "The pytest invocation failed. See the log for details."

Použití sestaveného kola Pythonu

Pátá fáze tohoto kanálu Jenkinse s názvem Run Notebook, spustí poznámkový blok Pythonu, který volá logiku v integrovaném souboru kola Pythonu následujícím způsobem:

stage('Run Notebook') {
  sh """#!/bin/bash
        ${DBCLIPATH}/databricks bundle run -t ${BUNDLETARGET} run-dabdemo-notebook
     """
  }

Tato fáze spustí rozhraní příkazového řádku Databricks, které zase dává vašemu pracovnímu prostoru pokyn ke spuštění úlohy v poznámkovém bloku. Tento poznámkový blok vytvoří objekt datového rámce, předá ho with_status funkci knihovny, vytiskne výsledek a nahlásí výsledky spuštění úlohy. Vytvořte poznámkový blok přidáním souboru poznámkového bloku Pythonu s následujícím dabdaddemo_notebook.py obsahem v kořenovém adresáři naklonovaného úložiště na místním vývojovém počítači:

# Databricks notebook source

# COMMAND ----------

# Restart Python after installing the wheel.
dbutils.library.restartPython()

# COMMAND ----------

from dabdemo.addcol import with_status

df = (spark.createDataFrame(
  schema = ["first_name", "last_name", "email"],
  data = [
    ("paula", "white", "paula.white@example.com"),
    ("john", "baer", "john.baer@example.com")
  ]
))

new_df = with_status(df)

display(new_df)

# Expected output:
#
# +------------+-----------+-------------------------+---------+
# │first_name │last_name │email                   │status  |
# +============+===========+=========================+=========+
# │paula      │white     │paula.white@example.com │checked |
# +------------+-----------+-------------------------+---------+
# │john       │baer      │john.baer@example.com   │checked |
# +------------+-----------+-------------------------+---------+

Vyhodnocení výsledků spuštění úlohy notebooku

Fáze Evaluate Notebook Runs, šestá fáze Jenkins Pipeline, vyhodnocuje výsledky předchozího spuštění notebookové úlohy. Tato fáze je definována takto:

stage('Evaluate Notebook Runs') {
  sh """#!/bin/bash
        ${DBCLIPATH}/databricks bundle run -t ${BUNDLETARGET} evaluate-notebook-runs
     """
  }

Tato fáze spustí rozhraní příkazového řádku Databricks, které pak dává vašemu pracovnímu prostoru pokyn ke spuštění úlohy souboru Pythonu. Tento soubor Pythonu určuje kritéria selhání a úspěchu pro spuštění úlohy poznámkového bloku a hlásí tento výsledek selhání nebo úspěchu. V kořenovém adresáři naklonovaného úložiště v místním vývojovém počítači vytvořte soubor evaluate_notebook_runs.py s následujícím obsahem:

import unittest
import xmlrunner
import json
import glob
import os

class TestJobOutput(unittest.TestCase):

  test_output_path = f"/Workspace${os.getenv('WORKSPACEBUNDLEPATH')}/Validation/Output"

  def test_performance(self):
    path = self.test_output_path
    statuses = []

    for filename in glob.glob(os.path.join(path, '*.json')):
      print('Evaluating: ' + filename)

      with open(filename) as f:
        data = json.load(f)

        duration = data['tasks'][0]['execution_duration']

        if duration > 100000:
            status = 'FAILED'
        else:
            status = 'SUCCESS'

        statuses.append(status)
        f.close()

    self.assertFalse('FAILED' in statuses)

  def test_job_run(self):
    path = self.test_output_path
    statuses = []

    for filename in glob.glob(os.path.join(path, '*.json')):
      print('Evaluating: ' + filename)

      with open(filename) as f:
        data = json.load(f)
        status = data['state']['result_state']
        statuses.append(status)
        f.close()

    self.assertFalse('FAILED' in statuses)

if __name__ == '__main__':
  unittest.main(
    testRunner = xmlrunner.XMLTestRunner(
      output = f"/Workspace${os.getenv('WORKSPACEBUNDLEPATH')}/Validation/Output/test-results",
    ),
    failfast   = False,
    buffer     = False,
    catchbreak = False,
    exit       = False
  )

Import a hlášení výsledků testů

Sedmá fáze tohoto kanálu Jenkinse s názvem Import Test Results, používá rozhraní příkazového řádku Databricks k odeslání výsledků testu z vašeho pracovního prostoru do místního vývojového počítače. Osmá a poslední fáze s názvem , publikuje Publish Test Resultsvýsledky testu jenkins pomocí modulu plug-in junit Jenkins. Díky tomu můžete vizualizovat sestavy a řídicí panely související se stavem výsledků testu. Tyto fáze jsou definovány takto:

stage('Import Test Results') {
  def DATABRICKS_BUNDLE_WORKSPACE_FILE_PATH
  def getPath = "${DBCLIPATH}/databricks bundle validate -t ${BUNDLETARGET} | ${JQPATH}/jq -r .workspace.file_path"
  def output = sh(script: getPath, returnStdout: true).trim()

  if (output) {
    DATABRICKS_BUNDLE_WORKSPACE_FILE_PATH = "${output}"
  } else {
    error "Failed to capture output or command execution failed: ${getPath}"
  }

  sh """#!/bin/bash
        ${DBCLIPATH}/databricks workspace export-dir \
        ${DATABRICKS_BUNDLE_WORKSPACE_FILE_PATH}/Validation/Output/test-results \
        ${WORKSPACE}/Validation/Output/test-results \
        --overwrite
     """
}
stage('Publish Test Results') {
  junit allowEmptyResults: true, testResults: '**/test-results/*.xml', skipPublishingChecks: true
}

Výsledky testu Jenkinse

Odeslat všechny změny kódu do úložiště třetí strany

Obsah naklonovaného úložiště byste teď měli odeslat do místního vývojového počítače do úložiště třetí strany. Než nasdílíte změny, měli byste nejprve do souboru .gitignore ve vašem klonovaném úložišti přidat následující položky; pravděpodobně byste neměli do úložiště třetích stran odesílat interní pracovní soubory balíčku, validační zprávy, sestavovací soubory Pythonu a mezipaměti Pythonu. Obvykle budete chtít znovu vygenerovat nové sestavy ověření a nejnovější buildy kol Pythonu v pracovním prostoru Azure Databricks, místo abyste mohli používat potenciálně zastaralé ověřovací sestavy a buildy kol Pythonu:

.databricks/
.vscode/
Libraries/python/dabdemo/build/
Libraries/python/dabdemo/__pycache__/
Libraries/python/dabdemo/dabdemo.egg-info/
Validation/

Spuštění kanálu Jenkinse

Teď jste připraveni spustit Jenkinsův pipeline ručně. Uděláte to tak, že na řídicím panelu Jenkinse:

  1. Klikněte na název kanálu Jenkinse.
  2. Na bočním panelu klikněte na Sestavit hned.
  3. Pokud chcete zobrazit výsledky, klikněte na nejnovější spuštění kanálu (například #1) a potom klikněte na výstup konzoly.

V tuto chvíli CI/CD pipeline dokončil integrační a nasazovací cyklus. Automatizací tohoto procesu můžete zajistit, aby byl váš kód testován a nasazen efektivním, konzistentním a opakovatelným procesem. Pokud chcete externímu poskytovateli Gitu dát pokyn ke spuštění Jenkinse při každé konkrétní události, jako je například žádost o přijetí změn úložiště, prohlédněte si dokumentaci poskytovatele Gitu třetí strany.