Jenkins パイプラインアクション

  • リリースバージョン: Xanadu
  • 更新日 2024年08月01日
  • 所要時間:30分
  • Jenkinsパイプラインでこれらのアクションを使用して、DevOps コンフィグデータモデルを操作します。

    重要:
    Washington DC リリース以降、DevOps コンフィグ は将来の廃止に備えて準備されます。これは非表示になり、新しいインスタンスにはインストールされなくなりますが、引き続きサポートされます。詳細については、Now Support ナレッジベースの「Deprecation Process (廃止プロセス) [KB0867184]」の記事を参照してください。

    Jenkins スクリプト化されたピップラインと宣言型のパイプラインがサポートされています。

    これらのアクションは、目標を達成するための特定のパイプライン定義を作成するために提供されています。これらのアクションを実行するコマンドを Jenkins ファイルに追加します。
    • snDevOps コンフィグ

      構成データをアップロード、検証、および公開する複合アクション。

    • snDevOps ConfigUpload

      エージェントジョブを介して構成データを DevOps コンフィグ にアップロードします。

    • snDevOpsConfigGetSnapshots

      特定の展開可能項目、または影響を受けるすべての展開可能項目のスナップショットを取得します。

    • snDevOps コンフィグの公開

      指定されたアプリケーションおよび展開可能項目のスナップショットを公開します。

    • snDevOps ConfigExport

      特定のアプリケーションおよび展開可能項目のスナップショットをエクスポートします。

    • snDevOps ConfigRegisterPipeline

      変更セットやスナップショットをパイプライン実行に結び付けます。

    • snDevOps コンフィグ検証

      組織のポリシーに照らして構成データを検証します。

    • snDevOps の変更

      関連付けられたスナップショットを添付して変更要求を作成します。

    snDevOps コンフィグ

    構成データの変更をワンステップでアップロード、検証、公開します。

    このアクションは、各アクションを個別に実行するのではなく、snDevOpsConfigUpload、snDevOpsConfigGetSnapshots、および snDevOpsConfigRegisterPipeline の各アクションを 1 つのアクションに結合します。

    入力変数
    configFile データモデルのコンポーネントまたは展開可能パスにアップロードする構成データファイルを指定します。
    applicationName 構成データのアップロード先のアプリケーションを指定します。
    target 構成データのアップロード先のデータモデルターゲットを指定します ( コンポーネントコレクション展開可能項目など)。
    collectionName (オプション)アップロード先のコレクションの名前 (ターゲットがコレクションの場合は必須)。
    deployableName (オプション)アップロード先の展開可能項目の名前 (ターゲットが展開可能な場合は必須)。
    namePath

    構成データのアップロード先のデータモデルの名前パスを指定します。

    注:
    vars フォルダーにアップロードする場合は、名前パスの先頭に「vars/」を付けて、変数フォルダーのパスを指定する必要があります。
    dataFormat 構成ファイルのデータ形式 (JSON、YAMLXML など) を指定します。
    autoCommit アップロード後に構成データをコミットするかどうかを指定します (true/false)。デフォルトは true です。
    autoValidate コミット中に構成データを検証するかどうかを指定します (true/false)。デフォルトは true です。
    自動公開 検証後に構成データを公開するかどうか (true/false) を指定します。デフォルトは true です。
    changesetNumber

    (オプション)このアップロードアクティビティが関連付けられている (オープンな) 変更セットを指定します。指定しない場合、新しい変更セットが作成されます。

    注:
    複数のアップロードシナリオでのみ使用されます。
    マーク失敗 (オプション)検証の試行が (バックエンドの問題により) 失敗した場合は、パイプラインを失敗させます。
    結果を表示 (オプション) Jenkins ジョブコンソールログに検証結果を表示します。
    最新の continueWithLatest (オプション)スナップショットが生成されない場合に、applicatioName-deployableName-changesetNumber の組み合わせごとに最新のスナップショットを返すかどうかを指定します (true/false)。デフォルトは false です。
    出力
    • 成功した場合は、スナップショットまたはスナップショットのセット。
    • 失敗した場合は、API/バックエンドのエラーメッセージが表示されます。
    • 入力:
      
      snapshotObj = snDevOpsConfig(
           applicationName: "PaymentDemo",
           configFile: "config/application/Collection/Collection2/*.json",
           target: "collection",
           collectionName: "release-1.0",
           namePath: "settings/infrastructure/database",
           dataFormat: "json",
           autoCommit: 'true',
           autoValidate: 'true',
           autoPublish: 'true',
           continueWithLatest: 'true',
           markFailed: 'true',
           showResults: 'false'
      )
      
      echo"*************************\n ${snapshotObj}"
    • Jenkins snDevOpsConfig 応答出力を出力
    例:コレクション
    注:
    コレクションにアップロードする場合は、 collectionName 引数が必要です。
    
    snDevOpsConfig(
         applicationName: 'PaymentDemo',
         target: 'collection',
         collectionName: 'release-1.0',
         namePath: 'web-api-v1.0',
         configFile: 'k8s/helm/*.yml',
         dataFormat: 'yaml',
         autoCommit: 'true',
         autoValidate: 'true',
         autoPublish: 'true'
    )
    例:展開可能
    注:
    展開可能項目にアップロードする場合、 deployableName 引数が必要です。
    
    snDevOpsConfig(
         applicationName: 'PaymentDemo',
         target: 'deployable',
         deployableName: 'Production',
         namePath: 'web-api-v1.0',
         configFile: 'k8s/helm/*.yml',
         dataFormat: 'yaml',
         autoCommit: 'true',
         autoValidate: 'true',
         autoPublish: 'true'
    )
    1 回のコミットでの複数のアップロード

    さまざまな場所から構成データをアップロードしたり、データモデルへの単一のコミットとして追跡される複数のターゲット (たとえば、1 つのコンポーネント、1 つの展開可能項目など) に一連のデータをアップロードするには、最初の一連のアップロードで必要な回数だけ snDevOpsConfigUpload アクションを呼び出してから、最終アップロードで snDevOpsConfig アクションを呼び出します。

    次に例を示します。

    • 最初のアップロードで、変数 ($changeset など) を作成し、ステップの戻り値を代入して、後続のアップロードで再利用できるようにします。

      1 - XML ファイルをコンポーネントにアップロード:
      
      $changeset = snDevOpsConfigUpload(
           applicationName: 'PaymentDemo',
           target: 'component',
           namePath: 'paymentService-v1.0',
           configFile: 'infra/v1/config.xml',
           dataFormat: 'xml',
           autoCommit: 'false',
           autoValidate: 'false',
           autoPublish: 'false'
      )
    • 後続のアップロード (および最終アップロード) では、変数を入力として使用します。

      2:JSON ファイルを展開可能項目の vars フォルダーにアップロードします:
      
      snDevOpsConfig(
           applicationName: 'PaymentDemo',
           target: 'deployable',
           deployableName: 'Production',
           namePath: 'vars/dbSettings',
           configFile: 'infra/prod/dbConfig.json',
           dataFormat: 'json',
           changesetNumber: ”${changeset}”,
           autoCommit: 'false',
           autoValidate: 'false',
           autoPublish: 'false',
           continueWithLatest: 'true'
      )
    複数のデータ形式のアップロード
    さまざまなファイル形式で構成データをアップロードするには、これらの仕様で snDevOpsConfig アクションを呼び出すことができます。
    • configFile 引数がパスでワイルドカードを使用していることを確認します。
    • dataFormat 引数は指定しないでください。

    次に例を示します。

    • これらの構成ファイルがあるとします。

      DevOps コンフィグ Jenkins アップロードファイル

    • これは、 snDevOpsConfig を使用して構成ファイルをアップロードする方法です。
      
      snDevOpsConfig(
           applicationName: 'PaymentDemo',
           target: 'component',
           namePath: 'paymentService-v1.0',
           configFile: 'infra/v1/*',
           autoCommit: 'true',
           autoValidate: 'true',
           autoPublish: 'true'
      )

    snDevOps ConfigUpload

    このアクションは、アプリケーションデータモデル内の特定の場所に構成ファイルをアップロードします。

    これは、パイプラインの実行中にすべての構成ファイルをアプリケーション データ モデルにアップロードするために反復的に使用されることを意図しています。

    楨:
    • アップロード先:
      • コンポーネント、コレクション、または展開可能項目。
      • コンポーネント、コレクション、または展開可能項目の変数 (vars) フォルダー。
    • 構成ファイル入力の正規表現パターン。
    • 同じパイプラインで複数回呼び出される機能。
    入力変数
    configFile データモデルのコンポーネントまたは展開可能パスにアップロードする構成データファイルを指定します。
    applicationName 構成データのアップロード先のアプリケーションを指定します。
    target 構成データのアップロード先のデータモデルターゲットを指定します ( コンポーネントコレクション展開可能項目など)。
    collectionName (オプション)アップロード先のコレクションの名前 (ターゲットがコレクションの場合は必須)。
    deployableName アップロード先の展開可能項目の名前 (ターゲットが展開可能な場合は必須)。
    namePath

    構成データのアップロード先のデータモデルの名前パスを指定します。

    注:
    vars フォルダーにアップロードする場合は、名前パスの先頭に「vars/」を付けて、変数フォルダーのパスを指定する必要があります。
    dataFormat 構成ファイルのデータ形式 (JSON、YAMLXML など) を指定します。
    変換パス (オプション)構成ファイルのディレクトリ構造を (ワークスペースを基準にして) 保持し、ディレクトリをデータモデル内のパスに変換するかどうかを指定します。
    changesetNumber

    (オプション)このアップロードアクティビティが関連付けられている (オープンな) 変更セットを指定します。指定しない場合、新しい変更セットが作成されます。

    注:
    複数のアップロードシナリオでのみ使用されます。
    autoCommit アップロード後に構成データをコミットするかどうかを指定します (true/false)。デフォルトは false です。
    autoValidate コミット中に構成データを検証するかどうかを指定します (true/false)。デフォルトは false です。
    出力変数
    changesetNumber

    (オプション)このアップロードアクティビティが関連付けられている (オープンな) 変更セットを指定します。

    変更セット番号が指定されていない場合は、新しい変更セットが作成されます。

    • 入力:

      snDevOpsConfigUpload アクションの例を次に示します。説明のために、応答を変数 changeSetId に割り当て、シナリオのデバッグ用にコンソール ログにエコーアウトできるようにします。

      
      changeSetId = snDevOpsConfigUpload(
           applicationName: "PaymentDemo",
           target: 'component',
           namePath: "web-api-v1.0",
           configFile: "k8s/helm/values.yml",
           dataFormat: "json",
           autoCommit: 'true',
           autoValidate: 'true'
      )
      
      echo "Changeset: $changeSetId created"
    • 出力:

      データが DevOps コンフィグ のデータモデルにアップロードされるのに加えて、出力は次のようになります (Blue Ocean プラグインを使用してコンソール出力を視覚化します)。

      DevOps コンフィグ構成のアップロード出力

    例 - 複数のアップロード (コンポーネント)
    アップロード アクションを複数回呼び出して、アップロード部分を 1 つの変更セットに保持しながら、さまざまな場所からさまざまなファイル形式で構成データをアップロードできます。
    • 最初のアップロードでは、changesetNumber 出力変数を後続のアップロードで再利用できるように、アクションに名前を付けます。
      YAML ファイルのアップロード:
      
      $changeset = snDevOpsConfigUpload(
           applicationName: 'PaymentDemo',
           target: 'component',
           namePath: 'wep-api-v1.0',
           configFile: 'k8s/helm/values.yml',
           dataFormat: 'yaml',
           autoCommit: 'false',
           autoValidate: 'false'
      )
    • 後続のアップロードでは、最初のアップロードの changesetNumber 出力変数を入力変数として参照します。
      3 つの JSON ファイルのアップロード:
      
      snDevOpsConfigUpload(
           applicationName: 'PaymentDemo',
           target: 'component',
           namePath: 'wep-api-v1.0',
           configFile: 'infra/*.json',
           dataFormat: 'json',
           autoCommit: 'false',
           autoValidate: 'false',
           changesetNumber: ”${changeset}”
      )
    • 最後の呼び出しでは、最初のアップロードの changesetNumber 出力変数を入力変数として参照することに加えて、autoCommit と autoValidate を true に設定します。
      INI ファイルのアップロード:
      
      snDevOpsConfigUpload(
           applicationName: 'PaymentDemo',
           target: 'component',
           namePath: 'wep-api-v1.0',
           configFile: 'featureToggles/set1.ini',
           dataFormat: 'ini',
           autoCommit: 'true',
           autoValidate: 'true',
           changesetNumber: ”${changeset}”
      )
    例:複数のアップロード (コレクションと変数)
    アップロード アクションを複数回呼び出して、アップロード部分を 1 つの変更セットに保持しながら、さまざまな場所からさまざまなファイル形式で構成データをアップロードできます。
    • 最初のアップロードで、変数 ($changeset など) を作成し、ステップの戻り値を代入して、後続のアップロードで再利用できるようにします。
      XML ファイルのアップロード:
      
      $changeset = snDevOpsConfigUpload(
           applicationName: 'PaymentDemo',
           target: 'collection',
           collectionName: 'release-v1.0',
           namePath: 'v1-common-configs',
           configFile: 'infra/v1/config.xml',
           dataFormat: 'xml',
           autoCommit: 'false',
           autoValidate: 'false'
      )
    • 後続のアップロードでは、変数を入力として使用します。
      JSON ファイルのアップロード:
      
      snDevOpsConfigUpload(
           applicationName: 'PaymentDemo',
           target: 'deployable',
           deployableName: 'Production',
           namePath: 'vars/dbSettings',
           configFile: 'infra/prod/dbConfig.json',
           dataFormat: 'json',
           autoCommit: 'true',
           autoValidate: 'true',
           changesetNumber: ”${changeset}”
      )
    注:
    変数フォルダーにアップロードするには、uploadTarget を deployable に設定し、deployableName と changesetNumber に正しい値を設定する必要があります。

    snDevOpsConfigGetSnapshots

    このアクションは、さまざまなシナリオで使用することを目的としています。

    • 影響を受ける展開可能項目のすべてのスナップショットを取得します。

      構成ファイルがアプリケーションデータモデルにアップロードされると、システムはアップロードの影響を受けると判断された展開可能項目のスナップショットを作成します。CI フローに従って、最後のアップロード呼び出しで検証が有効になっていると仮定して、次のステップはスナップショットのリストを反復処理し、それらがすべて検証に合格したことを確認することです。

    • 特定のスナップショットを取得します。

      CD フローに従って、特定のスナップショットが取得され、公開してからエクスポートしてダウンストリームで使用できます (たとえば、インフラストラクチャやアプリケーションをプロビジョニングするため)。

    • アップロードでスナップショットが生成されない場合は、アプリケーションの展開可能項目の最新のスナップショットを取得します。

      構成変更が行われない場合、一連の構成データをアプリケーション展開可能変更セットの組み合わせの環境に展開できます。

    • パイプライン実行でポリシー検証結果を表示します。

      スナップショットを取得するときに、Jenkins ビルドテスト結果ページでポリシー検証結果をテスト結果として表示します (例外への準拠を含む)。

    入力定義
    applicationName 構成データのアップロード先またはデータのエクスポート元のアプリケーションを指定します。
    deployableName (オプション)最新のスナップショットデータを取得するアプリケーションの展開可能項目を指定します。
    changesetNumber (オプション)ユーザーが関心を持つ一連の構成変更の変更セット ID を指定します。
    isValidated (オプション)渡されたスナップショットのみを返すか、例外 (true/false) で渡されたスナップショットのみを返すかを指定します。デフォルトは true です。
    最新の continueWithLatest (オプション)スナップショットが生成されない場合に、applicatioName-deployableName-changesetNumber の組み合わせごとに最新のスナップショットを返すかどうかを指定します (true/false)。デフォルトは false です。
    出力
    • 成功した場合は、スナップショットまたはスナップショットのセット。
    • 失敗した場合は、API/バックエンドのエラーメッセージが表示されます。
    • 特定のスナップショット (指定):
      
      $snapshots = snDevOpsConfigGetSnapshots(
           applicationName: 'PaymentDemo',
           deployableName: 'Production',
           changesetNumber: 'Chset-16',
           isValidated: 'true',
           continueWithLatest: 'true'
      )
    • 最新の検証済みスナップショット (アプリケーションと展開可能項目の組み合わせの最新のスナップショットを返します):
      
      $snapshots = snDevOpsConfigGetSnapshots(
           applicationName: 'PaymentDemo',
           deployableName: 'Production',
           isValidated: 'true'
      )
    • すべての変更セットスナップショット (アプリケーションと展開可能項目の組み合わせのすべてのスナップショットを返します):
      
      $snapshots = snDevOpsConfigGetSnapshots(
           applicationName: 'PaymentDemo',
           changesetNumber: 'Chset-16'
      )
    • パイプライン実行でポリシー検証結果を表示します。
      1. snDevOpsConfigGetSnapshots アクション中に生成されたスナップショット検証結果を含むファイルのパスに変数をアサインします。
      2. JUnit アクションを呼び出して、スナップショット検証結果をパイプライン実行テストセクションにロードします。
      
      stage('Validate') {
          steps {
      	script {
                 changeSetResults = snDevOpsConfigGetSnapshots( … )
                 if (!changeSetResults) {
                    echo "No snapshots were created"
                 } else {
      	       def changeSetResultsObject = readJSON text: changeSetResults
      
      	       changeSetResultsObject.each {
                        snapshotName = it.name
                        snapshotObject = it
      	       }
      	       // STEP 1
      		validationResultsPath = "${snapshotName}_${currentBuild.projectName}_${currentBuild.number}.xml"
      	    }
      	}
          }
      }
      
      post {
          always {
              // STEP 2
              junit testResults: "${validationResultsPath}", skipPublishingChecks: true
          }
      }
      

    snDevOps コンフィグの公開

    このアクションは、指定されたアプリケーションおよび展開可能項目のスナップショットを公開します。ここから、スナップショットはエクスポートプロセスを通じて使用できます。

    入力定義
    applicationName 構成データの公開元のアプリケーションを指定します。
    deployableName 構成データの公開元のアプリケーションの展開可能項目を指定します。
    snapshotName 公開するスナップショットの名前を指定します。
    出力
    • 成功した場合は true です。
    • それ以外の場合は false。
    
    snDevOpsConfigPublish(
         applicationName: 'PaymentDemo',
         deployableName: 'Production',
         snapshotName: 'Production-v23.dpl',
    )

    snDevOps ConfigExport

    このアクションは、指定されたアプリケーションおよび展開可能項目のスナップショットをエクスポートします。

    ユーザーは、エクスポーター、関連するエクスポーター引数、エクスポート形式 (YAML、JSON など)、およびエクスポートされた構成データの出力場所を指定する必要があります。

    ここから、構成データをパイプラインのダウンストリームにある展開ツールまたはプロビジョニングツールの入力として直接使用できます。

    入力引数
    applicationName データのエクスポート元のアプリケーションを指定します。
    deployableName データのエクスポート元のアプリケーションに対して展開可能な構成を指定します。
    snapshotName

    (オプション)データのエクスポート元のスナップショットを指定します。

    スナップショットが指定されていない場合は、展開可能項目の最新のスナップショットが使用されます。

    exporterName スナップショットに適用するエクスポーター ( UniqueCDI など) を指定します。
    エクスポーター引数 (オプション)エクスポーターとともに使用する引数を指定します。
    エクスポート形式 スナップショットデータをエクスポートする形式 ( INIYAMLPROPS など) を指定します。
    fileName

    データのエクスポート先のファイルを指定します (ワークスペースにあると想定されます)。

    ファイル名が指定されていない場合は、アプリケーション名と展開可能名 (およびファイル拡張子) の連結がデフォルトで使用されます。

    出力
    • 成功した場合は true です。
    • それ以外の場合は false。
    
    snDevOpsConfigExport(
         applicationName: 'PaymentDemo',
         deployableName: 'Production',
         snapshotName: 'Production-v23.dpl',
         exporterFormat: 'yaml',
         exporterName: 'returnAllData-now',
         exporterArgs: '',
         fileName: 'exported_file-Production-20220302.yml'
    )

    snDevOps ConfigRegisterPipeline

    このアクションにより、変更セットやスナップショットがパイプラインに関連付けられ、パイプラインの実行中に追跡できるようになります。DevOps チェンジベロシティでは、これはパイプライン UI に表示されます。

    DevOps 変更の促進機能の詳細については、「DevOps変更プロセスの加速」を参照してください。

    入力引数
    applicationName アプリケーションの名前を指定します。
    changesetNumber

    (オプション)パイプライン実行に関連付ける変更セットを指定します。

    注:
    changesetNumber または snapshotName のいずれかを指定しますが、両方を指定することはできません。
    snapshotName

    (オプション)パイプライン実行に関連付けるスナップショットの名前を指定します。

    注:
    changesetNumber または snapshotName のいずれかを指定しますが、両方を指定することはできません。
    出力
    • 成功した場合は true です。
    • それ以外の場合は false。
    • 入力:

      snDevOpsConfigRegisterPipeline アクションの例を次に示します。説明のために、応答を変数 changeSetRegResult に割り当て、シナリオをデバッグするためにコンソール ログにエコーアウトできるようにします。

      
      changeSetRegResult = snDevOpsConfigRegisterPipeline(
           applicationName: "PaymentDemo",
           changesetNumber: "Chset-122"
      )
      
      echo "Pipeline registration result: ${changeSetRegResult}"
    • 出力:

      データが DevOps コンフィグ のデータモデルにアップロードされるのに加えて、出力は次のようになります (Blue Ocean プラグインを使用してコンソール出力を視覚化します)。

      DevOps 構成登録パイプライン出力

    snDevOps コンフィグ検証

    組織のポリシーに照らして構成データを検証します。

    入力引数
    applicationName 検証するアプリケーション。
    deployableName 検証するアプリケーション用に展開可能です。
    snapshotName (オプション)検証するスナップショットの名前。
    マーク失敗 (オプション)検証の試行が (バックエンドの問題により) 失敗した場合は、パイプラインを失敗させます。
    結果を表示 (オプション) Jenkins ジョブコンソールログに検証結果を表示します。
    出力
    • 成功した場合、出力はありません。
    • 失敗した場合は、API/バックエンドのエラーメッセージが表示されます。
    • 特定のスナップショット (指定):
      
      snDevOpsConfigValidate(
           applicationName: 'PaymentDemo',
           deployableName: 'Production',
           snapshotName: 'Production-v23.dpl',
      )
    • 最新のスナップショット (アプリケーションと展開可能項目の組み合わせの最新のスナップショットを取得して検証します):
      
      $changeset = snDevOpsConfigValidate(
           applicationName: 'PaymentDemo',
           deployableName: 'Production'
      )

    snDevOps の変更

    変更要求を作成し、参照用にスナップショットを添付します。

    DevOps 変更の促進機能の詳細については、「DevOps変更プロセスの加速」を参照してください。

    入力引数
    applicationName アプリケーションの名前を指定します。
    snapshotName 変更要求に関連付けるスナップショットの名前を指定します。
    
    snDevOpsChange(
         applicationName: 'PaymentDemo',
         snapshotName: 'Production-v23.dpl'
    )

    Jenkins パイプラインの例

    
    pipeline {
        environment {
            buildArtifactsPath = "build_artifacts/${currentBuild.number}"
            validationResultsPath = ""
        }
    
        agent any
    
        stages {
            // Initialize pipeline
            stage('Initialize') {
                steps {
                    script {
                        // DevOps Config application related information
                        appName = 'PaymentDemo'
                        deployableName = 'Production'
                        componentName = "web-api-v1.0"
                        collectionName = "release-1.0"
                        // Configuration file information
                        exportFormat = 'yaml'
                        configFilePath = "k8s/helm/values.yml"
                        // Exporter related information
                        exporterName = 'returnAllData-nowPreview' 
                        exporterArgs = ''
                        // Jenkins variables declared to be used in pipeline
                        exportFileName = "${buildArtifactsPath}/export_file-${appName}-${deployableName}-${currentBuild.number}.${exportFormat}"
                        changeSetId = ""
                        snapshotName = ""
                        snapshotObject = ""
                        isSnapshotValidateionRequired = false
                        isSnapshotPublisingRequired = false
                    }
                }
            }
                
            // Validate configuration data changes
            stage('Validate') {
                parallel {
                    stage('Config') {
                        stages('Config Steps') {
                            // Upload configuration data to DevOps Config
                            stage('Upload, Validate, & Publish') {
                                steps {
                                    sh "echo uploading and auto-validating configuration file: ${configFilePath}"
                                    script {
                                        changeSetResults = snDevOpsConfig(
                                            applicationName: "${appName}",
                                            target: 'component',
                                            namePath: "${componentName}",
                                            configFile: "${configFilePath}",
                                            dataFormat: "${configFileFormat}",
                                            autoCommit: 'true',
                                            autoValidate: 'true',
                                            autoPublish: 'true',
                                            isValidated: 'true',
                                            continueWithLatest: 'true',
                                            markFailed: 'true'
                                        )
    
                                        echo "Snapshots generated, validated, and published: ${changeSetResults}"
    
                                        def changeSetResultsObject = readJSON text: changeSetResults
    
                                        changeSetResultsObject.each {
                                            snapshotName = it.name
                                            snapshotObject = it
                                        }
    
                                        validationResultsPath = "${snapshotName}_${currentBuild.projectName}_${currentBuild.number}*.xml"
                                    }
                                }
                            }
                            // Export published snapshot to be used by downstream deployment tools
                            stage('Export') {
                                steps {
                                    script {
                                        // create build artifacts dir to store export file
                                        sh "mkdir -p ${buildArtifactsPath}"
                                        
                                        exportResponse = snDevOpsConfigExport(
                                            applicationName: "${appName}",
                                            snapshotName: "${snapshotObject.name}",
                                            deployableName: "${deployableName}",
                                            exporterFormat: "${exportFormat}",
                                            fileName: "${exportFileName}",
                                            exporterName: "${exporterName}",
                                            exporterArgs: "${exporterArgs}"
                                        )
                                    }
                                }
                            }
                        }
                    }
                }
            }
            
            // Create change request and attach snapshot for reference
            stage('Change Management') {
                steps {
                    script {
                        // Trigger change request
                        snDevOpsChange(
                            applicationName: "${appName}",
                            snapshotName: "${snapshotName}"
                        )
                    }     
                }
            }
        }
        // NOTE: attach snapshot validation results to run (if the snapshot fails validation)
        post {
            always {
                // attach policy validation results
                junit testResults: "${validationResultsPath}", skipPublishingChecks: true
            }
        }
    }