Jenkins - z/OS連携: (5) Pipeline+Git+DBBの利用

# はじめに
Jenkinsを活用してメインフレーム・アプリケーションの管理をどのように行えるのかを探っていく連載記事です。
今までのシナリオに加えて、DBB(Dependency Based Build)、zAppBuildを利用して実際のアプリケーションのビルドを実施してみます。

## 関連記事
[Jenkins - z/OS連携: (1) 概要](https://qiita.com/tomotagwork/items/d2c90c1f29e07d3b7c19)
[Jenkins - z/OS連携: (2) Pipelineの利用](https://qiita.com/tomotagwork/items/6d0481d58cdd10e44def)
[Jenkins - z/OS連携: (3) Pipeline+Gitの利用](https://qiita.com/tomotagwork/items/16b38599be3f8a134580)
[Jenkins - z/OS連携: (4) Pipeline+Git+Webhookの利用](https://qiita.com/tomotagwork/items/25eb40e56f1a5125e4fc)
[Jenkins - z/OS連携: (5) Pipeline+Git+DBBの利用](https://qiita.com/tomotagwork/items/0b25bbb9a72e37f4d98c)
[Jenkins - z/OS連携: (6) Jenkins Pipeline利用シナリオ](https://qiita.com/tomotagwork/items/9d2b3f697f31f23fd682)

# 全体像

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/6b3435b9-b9bc-76fc-3a63-b69c59d2072d.png)

# 環境情報
[以前の記事](https://qiita.com/tomotagwork/items/16b38599be3f8a134580#%E7%92%B0%E5%A2%83%E6%83%85%E5%A0%B1)の環境に加えてDBBが必要になります。これもz/OSの外のサーバーに対してアウトバウンドのリクエストを発行する必要があるので、SSHポートフォワード(トンネリング)の設定をしておく必要があります。

## DBB
DBB関連のコンポーネントとしては、z/OS上に構成するDBB toolkitおよび、Linuxサーバー上に構成するDBB Serverの2つがあります。ここでは両方使用するのでそれぞれセットアップしておきます。ここでは詳細は割愛します。

参考: 
[Installing and configuring the DBB toolkit on z/OS](https://www.ibm.com/docs/en/dbb/1.1.0?topic=dbb-installing-configuring-toolkit-zos)
[Installing and configuring the DBB server](https://www.ibm.com/docs/en/dbb/1.1.0?topic=dbb-installing-configuring-server)

## zAppBuild
参考: [GitHub - dbb-zappbuild](https://github.com/IBM/dbb-zappbuild)
DBBはビルド(コンパイル/リンク)のスクリプトをgroovyで記述するためのAPIや、依存関係の情報を保持、参照する仕組みを提供してくれていますが、これらを利用するにはそれなりにスクリプトを自分で記述する必要があります。一からそのようなスクリプトを書くのは大変なので、zAppBuildという汎用的に使えるビルドのスクリプトやプロパティーファイルの雛形を提供してくれています。これはGitHubで公開されておりダウンロードして自由に利用可能です( Apache-2.0 License)。

セットアップ方法などは以下の記事をご参照ください。
参考: [zAppBuild](https://qiita.com/tomotagwork/items/4bdd0b5a7284b5102d10#zappbuild-1)

## Proxy
Git Serverへの接続と同じように、中間のLinuxサーバーからSSHポートフォワードの構成を行っておき、DBB Serverへの経路を作っておきます。

```
ssh -f -N -R 9998:ibmdbb.wazi-dbb01:9443 -o 'StrictHostKeyChecking no' -o 'ServerAliveInterval=60' -o 'ServerAliveCountMax=3' -i /tmp/id_rsa JENKINS@wazi-ssh.wazi-test01
```

z/OS上のlocalhost:9998ポートにリクエストを投げると、DBB Server(ここではibmdbb.wazi-dbb01:9443)にフォワードされることになります。

# ビルドの実行例
DBBやzAppBuildの位置づけを理解するために、全部を一気に試すのではなく1つずつシンプルなケースで試していきます。

## シナリオ1: DBB toolkitの利用
参考:[Tutorial: Writing your first build script](https://www.ibm.com/docs/en/dbb/1.0.9?topic=scripts-tutorial-writing-your-first-build-script)
まず、JenkinsやGitは使わずにDBB toolkitを使ってビルドを実施するためにはどのような操作を行えばよいのかを試してみます。

当シナリオのスコープ:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/31af2ba5-d8e5-7fed-6710-694ead641444.png)


以下、基本USS上で操作します。

### COBOLソースの作成
USS上のファイルとして単純なCOBOLのソースを作成します。

```cbl:/u/TEST01/test/Hello/helloworld.cbl
       IDENTIFICATION DIVISION.
       PROGRAM-ID.     HELLO.

       PROCEDURE DIVISION.
           DISPLAY "Hello world!".
           STOP RUN.
```

### コンパイル用のスクリプト作成
DBBのAPIを使ってGroovyでコンパイル用のスクリプトを作成します。JCLの代わりにGroovyで

```groovy:/u/TEST01/test/Hello/helloworld.groovy
import com.ibm.dbb.build.*

println("Copying source from zFS to PDS . . .")
def copy = new CopyToPDS().file(new File("helloworld.cbl")).dataset("TAGUCHI.COBOL").member("HELLO")
copy.execute()

println("Compiling . . .")
def compile = new MVSExec().pgm("IGYCRCTL").parm("LIB")
compile.dd(new DDStatement().name("SYSIN").dsn("TAGUCHI.COBOL(HELLO)").options("shr"))
compile.dd(new DDStatement().name("SYSLIN").dsn("TAGUCHI.OBJ(HELLO)").options("shr"))
compile.dd(new DDStatement().name("SYSUT1").options("cyl space(5,5) unit(vio) new"))
compile.dd(new DDStatement().name("SYSUT2").options("cyl space(5,5) unit(vio) new"))
compile.dd(new DDStatement().name("SYSUT3").options("cyl space(5,5) unit(vio) new"))
compile.dd(new DDStatement().name("SYSUT4").options("cyl space(5,5) unit(vio) new"))
compile.dd(new DDStatement().name("SYSUT5").options("cyl space(5,5) unit(vio) new"))
compile.dd(new DDStatement().name("SYSUT6").options("cyl space(5,5) unit(vio) new"))
compile.dd(new DDStatement().name("SYSUT7").options("cyl space(5,5) unit(vio) new"))
compile.dd(new DDStatement().name("SYSUT8").options("cyl space(5,5) unit(vio) new"))
compile.dd(new DDStatement().name("SYSUT9").options("cyl space(5,5) unit(vio) new"))
compile.dd(new DDStatement().name("SYSUT10").options("cyl space(5,5) unit(vio) new"))
compile.dd(new DDStatement().name("SYSUT11").options("cyl space(5,5) unit(vio) new"))
compile.dd(new DDStatement().name("SYSUT12").options("cyl space(5,5) unit(vio) new"))
compile.dd(new DDStatement().name("SYSUT13").options("cyl space(5,5) unit(vio) new"))
compile.dd(new DDStatement().name("SYSUT14").options("cyl space(5,5) unit(vio) new"))
compile.dd(new DDStatement().name("SYSUT15").options("cyl space(5,5) unit(vio) new"))
compile.dd(new DDStatement().name("SYSUT16").options("cyl space(5,5) unit(vio) new"))
compile.dd(new DDStatement().name("SYSUT17").options("cyl space(5,5) unit(vio) new"))
compile.dd(new DDStatement().name("SYSMDECK").options("cyl space(5,5) unit(vio) new"))
compile.dd(new DDStatement().name("TASKLIB").dsn("IGY630.SIGYCOMP").options("shr"))
compile.dd(new DDStatement().name("SYSPRINT").options("cyl space(5,5) unit(vio)  new"))
compile.copy(new CopyToHFS().ddName("SYSPRINT").file(new File("/u/TEST01/test/Hello/helloworld.log")))
def rc = compile.execute()

if (rc > 4)
    println("Compile failed!  RC=$rc")
else
    println("Compile successful!  RC=$rc")
```

最初のステップ(CopyToPDS)では、USS上のソースをPDSメンバーにコピーしています。その後、MVSExecでコンパイル用の情報をセットしたオブジェクトを作成してexecute()メソッドで実行しています。
ここでは、`TAGUCHI.COBOL(HELLO)`にソースをコピーして、コンパイルした結果は`TAGUCHI.OBJ(HELLO)`に格納されるように指定しています。
また、コンパイル結果としてSYSPRINTをUSS上のファイル`/u/TEST01/test/Hello/helloworld.log`にコピーするようにしています。
基本的には、与える情報(実行するプログラム、DDなど)はJCLを作成する場合と同じでお作法が異なるだけです。
DBBが提供するAPIについては以下が参考になります。

参考: 
[What DBB APIs issue z/OS commands](https://www.ibm.com/docs/en/dbb/1.0.9?topic=scripts-what-dbb-apis-issue-zos-commands)
[DBB Toolkit API Java Doc](https://www.ibm.com/docs/en/dbb/1.1.0?topic=SS6T76_1.1.0/javadoc/index.html)

### コンパイル実行
一般的なGroovyの作法に従って上のスクリプトを実行してもよいですが、必要な環境変数などを含んだ"groovyz"という起動用のシェルスクリプトをDBBが提供してくれています。これを使って実行してみます。

<details><summary><font color="blue">参考: groovyz</font></summary><div>

```sh:/usr/lpp/IBM/dbb/bin/groovyz
#! /bin/sh
#
# Licensed materials - Property of IBM
# 5655-AC5 Copyright IBM Corp. 2018, 2019
# All rights reserved
# US Government users restricted rights  -  Use, duplication or
# disclosure restricted by GSA ADP schedule contract with IBM Corp.
#
#######################################################################
##
##  DBB Groovy invocation script which automatically sets appropriate
##  environment variables for DBB.
##
#######################################################################

PRGPATH="`dirname "$0"`"
DBB_HOME="$(dirname "$PRGPATH")"

# build arg list trapping/removing classpath
unset ARGS CP LP DBB_DAEMON_PORT DBB_DAEMON_HOST DBB_PERSONAL_DAEMON
while test $# -gt 0
do
  #echo arg $1                                                   #debug
  case "$1" in
    -cp|-classpath)        CP="$2"; shift;;
    -DBB_DAEMON_PORT)        export DBB_DAEMON_PORT="$2"; shift;;
    -DBB_DAEMON_HOST)        export DBB_DAEMON_HOST="$2"; shift;;
    -DBB_PERSONAL_DAEMON)    export DBB_PERSONAL_DAEMON="p";;
    -Djava.library.path=*) LP=$1;;
    *)                     ARGS="$ARGS $1";;
  esac
  shift
done

LP=$(echo $LP | awk -F '=' '{print $2}')      # strip key from key=value

# daemon
if test "$DBB_PERSONAL_DAEMON" ; then
        eval "$DBB_HOME/lib/pclient groovyz $ARGS"
        rc=$?
        echo "** Build finished"
        exit $rc
else
        if test "$DBB_DAEMON_PORT" ; then
                if test "$DBB_DAEMON_HOST" ;
                then
                        eval "$DBB_HOME/lib/sclient $DBB_DAEMON_HOST $DBB_DAEMON_PORT groovyz $ARGS"
                        rc=$?
                        echo "** Build finished"
                        exit $rc
                else
                        eval "$DBB_HOME/lib/sclient 127.0.0.1 $DBB_DAEMON_PORT groovyz $ARGS"
                        rc=$?
                        echo "** Build finished"
                        exit $rc
                fi
        fi
fi

# create and export the appropriate LIBPATH & CLASSPATH
if test "$LP" ; then
    #echo add LP $LP                                              #debug
    LIBPATH="$LP:$DBB_HOME/lib:/usr/lib/java_runtime64:$LIBPATH"
else
    LIBPATH="$DBB_HOME/lib:/usr/lib/java_runtime64:$LIBPATH"
fi
export LIBPATH
#echo LIBPATH $LIBPATH                                            #debug

if test "$CP" ; then
    #echo add CP $CP                                              #debug
    CLASSPATH="$CP:$DBB_HOME/lib/*:/usr/include/java_classes/isfjcall.jar:$CLASSPATH"
else
    CLASSPATH="$DBB_HOME/lib/*:/usr/include/java_classes/isfjcall.jar:$CLASSPATH"
fi
export CLASSPATH
#echo CLASSPATH $CLASSPATH                                        #debug

#Required to turn off this setting for multi-thread MVSJob
export _BPX_SHAREAS=NO

CMD="$DBB_HOME/groovy-2.4.12/bin/groovy "
$CMD $ARGS
rc=$?
echo "** Build finished"
exit $rc
```

</div></details>

```
TEST01:/u/TEST01/test/Hello: >/usr/lpp/IBM/dbb/bin/groovyz helloworld.groovy
Copying source from zFS to PDS . . .
ERROR StatusLogger No Log4j 2 configuration file found. Using default configuration (logging only errors to the console), or user programmatically provided configurations. Set system property 'log4j2.debug' to show Log4j 2 internal initialization logging. See https://logging.apache.org/log4j/2.x/manual/configuration.html for instructions on how to configure Log4j 2
Compiling . . .
Compile successful!  RC=0
** Build finished
```

<details><summary><font color="blue">結果(SYSPRINT)</font></summary><div>

```xxx:/u/TEST01/test/Hello/helloworld.log
PP 5655-EC6 IBM Enterprise COBOL for z/OS  6.3.0 P200319                 Date 03/18/2021  Time 13:26:47   Page     1

Invocation parameters:
 LIB

        IGYOS4090-I   The "LIB" option specification is no longer required.  COBOL library processing is always in effect.


Options in effect:
 NOADATA
   ADV
   AFP(NOVOLATILE)
   QUOTE
   ARCH(8)
   ARITH(COMPAT)
 NOAWO
 NOBLOCK0
   BUFSIZE(4096)
 NOCICS
   CODEPAGE(1140)
 NOCOMPILE(S)
 NOCOPYLOC
 NOCOPYRIGHT
 NOCURRENCY
   DATA(31)
   DBCS
 NODECK
 NODEFINE
 NODIAGTRUNC
   DISPSIGN(COMPAT)
 NODLL
 NODUMP
 NODYNAM
 NOEXIT
 NOEXPORTALL
 NOFASTSRT
   FLAG(I,I)
 NOFLAGSTD
   HGPR(PRESERVE)
 NOINITCHECK
 NOINITIAL
   INLINE
   INTDATE(ANSI)
 NOJTC
   LANGUAGE(EN)
   LINECOUNT(60)
 NOLIST
   LP(32)
 NOMAP
   MAXPCF(100000)
 NOMDECK
 NONAME
   NSYMBOL(NATIONAL)
 NONUMBER
 NONUMCHECK
   NUMPROC(NOPFD)
   OBJECT
 NOOFFSET
   OPTIMIZE(0)
   OUTDD(SYSOUT)
                PP 5655-EC6 IBM Enterprise COBOL for z/OS  6.3.0 P200319                 Date 03/18/2021  Time 13:26:47   Page     2

 NOPARMCHECK
   PGMNAME(COMPAT)
   QUALIFY(COMPAT)
   RENT
   RMODE(AUTO)
 NORULES
 NOSERVICE
   SEQUENCE
   SOURCE
   SPACE(1)
 NOSQL
   SQLCCSID
 NOSQLIMS
 NOSSRANGE
 NOSTGOPT
   SUPPRESS
 NOTERM
 NOTEST(NODWARF,NOSOURCE,NOSEPARATE)
 NOTHREAD
   TRUNC(STD)
 NOVBREF
   VLR(STANDARD)
   VSAMOPENFS(COMPAT)
 NOWORD
   XMLPARSE(XMLSS)
   XREF(FULL)
   ZONEDATA(PFD)
   ZWB
      PP 5655-EC6 IBM Enterprise COBOL for z/OS  6.3.0 P200319       HELLO     Date 03/18/2021  Time 13:26:47   Page     3
  LineID  PL SL  ----+-*A-1-B--+----2----+----3----+----4----+----5----+----6----+----7-|--+----8 Map and Cross Reference

  000001                IDENTIFICATION DIVISION.
  000002                PROGRAM-ID.     HELLO.
  000003
  000004                PROCEDURE DIVISION.
  000005                    DISPLAY "Hello world!".
  000006                    STOP RUN.
  000007
        PP 5655-EC6 IBM Enterprise COBOL for z/OS  6.3.0 P200319       HELLO     Date 03/18/2021  Time 13:26:47   Page     4

An "M" preceding a data-name reference indicates that the data-name is modified by this reference.

 Defined   Cross-reference of data names   References

PP 5655-EC6 IBM Enterprise COBOL for z/OS  6.3.0 P200319       HELLO     Date 03/18/2021  Time 13:26:47   Page     5

 Defined   Cross-reference of programs     References

       2   HELLO


Messages    Total    Informational    Warning    Error    Severe    Terminating

Printed:       1           1


* Statistics for COBOL program HELLO:
*    Source records = 7
*    Data Division statements = 0
*    Procedure Division statements = 2
*    Generated COBOL statements = 0
*    Program complexity factor = 2

End of compilation 1,  program HELLO,  highest severity 0.

Return code 0
```

</div></details>

DBB提供のAPIを使って、Groovyスクリプトを作成してCOBOLのコンパイルを実施する流れが確認できました。

## シナリオ2: Git+DBB+zAppBuild
イメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/e196fe26-53c1-ad8d-e593-c6ecf2ae560d.png)

複数のソースがまとまったプロジェクトをまるごとビルドすることを想定します。ソースやビルド用のスクリプトはGitServer上に管理することにします。
Jenkinsで自動化する前に、手動で実行する場合にはどのような手順を踏む必要があるかを確認していきます。

### ソースの準備(GitHub)
zAppBuildに付属のMortgageApplicationというサンプルがあるので、それをそのまま使います。
参考: [GitHub - IBM/dbb-zappbuild/samples/MortgageApplication](https://github.com/IBM/dbb-zappbuild/tree/development/samples/MortgageApplication)

これはCICS-COBOLアプリケーションで、BMSマップのソースも含んでいるようです。

GitHub上に新たなリポジトリ`TOMOTAG/wazi-sandbox01-mortgage`を作成しMortgageApplications以下をコピーします。

### .gitattributesファイルの作成(GitHub)
GitHubリポジトリの直下に.gitattributesファイルを作成し、ソース類をEBCDICに変換するよう以下のように記述します。

```.gitattributes
# line endings
* text eol=lf

# file encodings
*.cpy zos-working-tree-encoding=ibm-1399 git-encoding=utf-8
*.cbl zos-working-tree-encoding=ibm-1399 git-encoding=utf-8
*.bms zos-working-tree-encoding=ibm-1399 git-encoding=utf-8
*.pli zos-working-tree-encoding=ibm-1399 git-encoding=utf-8
*.mfs zos-working-tree-encoding=ibm-1399 git-encoding=utf-8
*.bnd zos-working-tree-encoding=ibm-1399 git-encoding=utf-8
*.lnk zos-working-tree-encoding=ibm-1399 git-encoding=utf-8
*.txt zos-working-tree-encoding=ibm-1399 git-encoding=utf-8
*.groovy zos-working-tree-encoding=ibm-1399 git-encoding=utf-8
*.sh zos-working-tree-encoding=ibm-1399 git-encoding=utf-8
*.properties zos-working-tree-encoding=ibm-1399 git-encoding=utf-8
*.asm zos-working-tree-encoding=ibm-1399 git-encoding=utf-8
*.jcl zos-working-tree-encoding=ibm-1399 git-encoding=utf-8
*.mac zos-working-tree-encoding=ibm-1399 git-encoding=utf-8
```

※z/OSからgit cloneした時に、上に指定された拡張子のファイルは定義に従ってコード変換されます。それ以外は基本的にISO8859-1でタグ付けされます。

GitServer上のRepositoryはこんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/eef5e7f3-4367-2a9b-d644-17da3260817a.png)

### zAppBuildの設定

zAppBuildは、汎用的に利用できるビルドスクリプトを提供しており、可変のパラメーターはプロパティファイルとして外出しされています。従って、そのプロパティファイルを整備すればよいことになります。
設定を行う箇所は大きく2つ、環境依存のものとアプリ依存のものがあります。環境依存(アプリ非依存)のものは、ビルドのターゲットとなるUSS上に設定しておきます。これは、主にzAppBuildを配置した先のbuild-conf/以下のプロパティファイルです。

#### build-conf
ここでは、別の記事でセットアップしたzAppBuildの環境(/u/dbb_common/dbb-zappbuild/)をそのまま利用します。
参考: [zAppBuild](https://qiita.com/tomotagwork/items/4bdd0b5a7284b5102d10#zappbuild-1)

datasets.propertiesは前と変わらずそのまま
<details><summary><font color="blue">datasets.properties</font></summary><div>

```/u/dbb_common/dbb-zappbuild/build-conf/datasets.properties
# Dataset references
# Build properties for Partition Data Sets (PDS) used by zAppBuild build scripts.
# Please provide a fully qualified DSN for each build property below.
# Ex:
# MACLIB=SYS1.MACLIB

# z/OS macro library. Example: SYS1.MACLIB
MACLIB=SYS1.MACLIB

# Assembler macro library. Example: CEE.SCEEMAC
SCEEMAC=CEE.SCEEMAC

# LE (Language Environment) load library. Example: CEE.SCEELKED
SCEELKED=CEE.SCEELKED

# High Level Assembler (HLASM) load library. Example: ASM.SASMMOD1
SASMMOD1=HLA.SASMMOD1

# Cobol Compiler Data Sets. Example: COBOL.V4R1M0.SIGYCOMP
SIGYCOMP_V4=
SIGYCOMP_V6=IGY630.SIGYCOMP

# PL/I Compiler Data Sets.  Example: PLI.V5R2M0.SIBMZCMP
IBMZPLI_V52=IEL530.SIBMZCMP
IBMZPLI_V51=

# CICS Macro Library. Example: CICSTS.V3R2M0.CICS.SDFHMAC
SDFHMAC=DFH550.CICS.SDFHMAC

# CICS Load Library. Example: CICSTS.V3R2M0.CICS.SDFHLOAD
SDFHLOAD=DFH550.CICS.SDFHLOAD

# CICS COBOL Library. Example: CICSTS.V3R2M0.CICS.SDFHCOB
SDFHCOB=DFH550.CICS.SDFHCOB

# MQ COBOL Library. Example: CSQ.V9R1M0.SCSQCOBC
SCSQCOBC=CSQ911.SCSQCOBC

# MQ Load Library. Example: CSQ.V9R1M0.SCSQLOAD
SCSQLOAD=CSQ911.SCSQLOAD

# DB2 Load Library. Example: DB2.V9R1M0.SDSNLOAD
SDSNLOAD=DSNC10.SDSNLOAD

# IMS Macro Library. Example: DFS.V11R1M0.SDFSMAC
SDFSMAC=DFSF10.SDFSMAC

# IMS RESLIB. Example: DFS.V11R1M0.SDFSRESL
SDFSRESL=DFSF10.USER.SDFSRESL

# User generated library for DB/DC and DC installations. Example: DFS.V11R1M0.REFERAL
REFERAL=DFSF10.REFERAL

# IBM Debug Library containing Exits
SEQAMOD=EQAF00.SEQAMOD

# Optional IDz Load Library. Example: FEL.V14R0M0.SFELLOAD
SFELLOAD=FELE20.SFELLOAD

# Optional IDZ zUnit / WAZI VTP library containing necessary copybooks. Example : FEL.V14R2.SBZUSAMP
SBZUSAMP=
```

</div></details>

今回実行しようとしているビルドのシナリオでは、ビルド結果や依存関係の情報をDBB Serverに登録することになるため、DBB Serverへのアクセス情報を指定する必要がありますが、それらはbuild.propertiesで指定可能です。その際、DBB Serverアクセス時の認証情報も指定しますが、パスワードをそのままベタで書くのを避けるため暗号化したファイルでパスワードを保持する仕組みが提供されています。まずそのパスワードファイルを作成します。
参考: [How to store and retrieve build result metadata](https://www.ibm.com/docs/en/dbb/1.1.0?topic=scripts-how-store-retrieve-build-result-metadata)

```
TAGUCHI:/u/dbb_common: >/usr/lpp/IBM/dbb/bin/pwf.sh pass.txt
Enter Password
xxxx
/usr/lpp/java/J8.0_64/bin/java -classpath /usr/lpp/IBM/dbb/lib/*: com.ibm.dbb.repository.CreatePasswordFile pass.txt xxxx
```

パスワードの入力が求められるのでパスワードを入力すると、指定されたファイルに暗号化された状態で保持されます。これを元に以下のようにbuild.propertiesをカスタマイズします。

<details><summary><font color="blue">build.properties</font></summary><div>

```/u/dbb_common/dbb-zappbuild/build-conf/build.properties
# Build properties used by build.groovy

#
# Comma separated list of additional build property files to load
# Supports both relative path (to zAppBuild/build-conf/) and absolute path
buildPropFiles=datasets.properties,Assembler.properties,BMS.properties,MFS.properties,PSBgen.properties,DBDgen.properties,ACBgen.properties,Cobol.properties,LinkEdit.properties,PLI.properties,ZunitConfig.properties

#
# file extension that indicates the build file is really a build list or build list filter
buildListFileExt=txt

#
# Alternate root directory for application-conf locations.  Allows for the deployment of
# the application-conf directories to an alternate location rather in the application repository.
# The expectation is that the root directory will have subfolders for all of the applications built
# by zAppBuild in which the actual application-conf directory is located:
#
# Example: Static location on USS
# applicationConfRootDir=/u/build/config/applications
# |- /u/build/config/applications
# |                       |- App1
# |                       |    |- application-conf
# |                       |    |        |- application.properties
# |                       |- App2
# |                       |    |- application-conf
#
# Example: Application cofig files stored in zAppBuild
# applicationConfRootDir=${zAppBuildDir}/applications
# |- /u/build/zAppBuild/applications
# |                          |- App1
# |                          |    |- application-conf
# |                          |    |        |- application.properties
# |                          |- App2
# |                          |    |- application-conf
#
# Defaults to ${workspace}
applicationConfRootDir=

#
# Comma separated list of required build properties for zAppBuild/build.groovy
requiredBuildProperties=buildOrder,buildListFileExt

# dbb.file.tagging controls compile log and build report file tagging. If true, files
# written as UTF-8 or ASCII are tagged. The default value is false. If the environment
# variable _BPXK_AUTOCVT is set ALL, file tagging may have an adverse effect if viewing
# log files and build report via Jenkins. In this case, set dbb.file.tagging to false or
# comment out the line. Default: true
dbb.file.tagging=true

# Set filter used to exclude certain information from the link edit scanning.
# The value contains a comma separated list of patterns.
# example: A filter of *.SUB1, *.SUB2 will exclude modules SUB1 and SUB2
#          from any dataset. To exclude member HELLO in PDS TEST.ASM will
#          be matched by the pattern TEST.ASM.HELLO. The pattern TEST.ASM.*
#          will match any member in the data set TEST.COBOL.
# The following filter excludes CICS and LE Library references.
dbb.LinkEditScanner.excludeFilter = ${SDFHLOAD}.*, ${SCEELKED}.*

#
# Determine the behavior when facing a scanner failure
# 'true' proceeds with the build and report the a warning (default)
# 'false' will terminate the build process
continueOnScanFailure=true

#
# default DBB Repository Web Application authentication properties
# can be overridden by build.groovy script options

# build.groovy option -url, --url
dbb.RepositoryClient.url=https://127.0.0.1:9998/dbb

# build.groovy option -id, --id
dbb.RepositoryClient.userId=ADMIN

# build.groovy option -pw, --pw
#dbb.RepositoryClient.password=

# build.groovy option -pf, --pf
#dbb.RepositoryClient.passwordFile=${zAppBuildDir}/utilities/ADMIN.pw
dbb.RepositoryClient.passwordFile=/u/dbb_common/pass.txt

# Use dbb.RepositoryClient.sslProtocols to specify one or more SSL protocols used
# to communication between DBB toolkit and server. Use a comma as separator for more
# than one protocol. Requires toolkit PTF UI72423 or version 1.1.0 or higher
# examples
# dbb.RepositoryClient.sslProtocols=TLSv1.2
# dbb.RepositoryClient.sslProtocols=TLS,TLSv1.2

# The dbb.gateway.type property determines which gateway type is used for the entire build process
# Possible values are 'legacy' and 'interactive.  Default if not indicated is 'legacy'
dbb.gateway.type=legacy

# Procedure Name - specified with the procname parameter
dbb.gateway.procedureName=

# Account number - specified with the acctnum parameter
dbb.gateway.accountNumber=

# Group name - specified with a groupid parameter
dbb.gateway.groupId=

# Region size - specified with the regionsz parameter
dbb.gateway.regionSize=

# Gateway logging level.  Add values for multiple types:
# 1 - Log error information
# 2 - Log debug information
# 4 - Log communication information
# 8 - Log time information
# 16 - Log information to the system console
dbb.gateway.logLevel=2
```

</div></details>

ここでは以下のプロパティをカスタマイズしています。

- **dbb.RepositoryClient.url**: DBB ServerのURLを指定します。ポートフォワード経由なのでローカルのポートを指定しています(`https://127.0.0.1:9998/dbb`)。 
- **dbb.RepositoryClient.password**: コメントアウトします(パスワードファイルを使用するため)
- **dbb.RepositoryClient.passwordFile**: 上で作成したパスワードファイルを指定します(/u/dbb_common/pass.txt)

※dbb.RepositoryClient.passwordをコメントアウトしないとパスワードが使われてしまうようで、Unauthorized(401)のエラーになります。

#### application-conf
もう一つは、アプリケーション依存のプロパティーです。アプリケーション依存なので各アプリケーション側、つまりGitServer上にソースと一緒に管理します。リポジトリの直下に`application-conf`というディレクトリを作成して、その配下に各プロパティ・ファイルを設定します。今回はサンプルを使っているのでプロパティ・ファイルも提供してくれています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/c0c6bcf1-4159-97f5-2adb-40b1666e37f7.png)

プロパティ・ファイルもサンプル提供のものをそのまま使います。

これらプロパティ・ファイルの設定については、以下のREADMEをご参照ください。
参考:
[環境依存プロパティ(build-conf)](https://github.com/IBM/dbb-zappbuild/tree/development/build-conf)
[アプリケーション依存プロパティ(application-conf)](https://github.com/IBM/dbb-zappbuild/tree/development/samples/application-conf)

### リポジトリをClone (z/OS USS)
USS上に適当なディレクトリを作成し、上のRepositoryを手動でクローンします。

```
TEST01:/u/TEST01/test: >mkdir workspace
TEST01:/u/TEST01/test: >mkdir logs
TEST01:/u/TEST01/test: >chmod 777 logs

TEST01:/u/TEST01/test: >cd workspace
TEST01:/u/TEST01/test/workspace: >git clone https://github.ibm.com/TOMOTAG/wazi-sandbox01-mortgage.git
Cloning into 'wazi-sandbox01-mortgage'...
Username for 'https://github.ibm.com':
Password for 'https://git@github.ibm.com':
remote: Enumerating objects: 32, done.
remote: Counting objects: 100% (32/32), done.
remote: Compressing objects: 100% (27/27), done.
remote: Total 32 (delta 4), reused 32 (delta 4), pack-reused 0
Unpacking objects: 100% (32/32), done.
```

### ビルド実行

環境依存の情報(各種ライブラリのHLQなど)、アプリ依存の情報(拡張子と言語のマッピングや順序性など)はプロパティファイルで与えているので、あとはビルド時に必要なパラメータを追加で与えてビルド実行すればよいです。
DBB提供のスクリプト起動用のシェル・スクリプト`groovyz`から、zAppBuild提供の汎用スクリプト`build.groovy`を実行することになります。
zAppBuildのビルド実行の仕方は以下をご参照ください。
参考: [Building Applications with zAppBuild](https://github.com/IBM/dbb-zappbuild/blob/development/BUILD.md)

zAppBuildはいくつかのビルド・オプションを提供していますが、今回はリポジトリ配下のプログラムをまとめて全部ビルドするため、fullbuildというオプションを使用します。コマンド1回叩けばよいだけですが、引数がいくつかあって分かりにくいのでシェル・スクリプトとしてコマンド記述します。

```sh:/u/TEST01/test/workspace/build_mortgage.sh
#!/bin/sh

DBB_HOME=/usr/lpp/IBM/dbb

${DBB_HOME}/bin/groovyz /u/dbb_common/dbb-zappbuild/build.groovy \
-DBB_DAEMON_HOST 127.0.0.1  \
-DBB_DAEMON_PORT 7380 \
--logEncoding UTF-8 \
--workspace /u/TEST01/test/workspace \
--application wazi-sandbox01-mortgage \
--hlq TEST01.DBB \
--outDir /u/TEST01/test/logs \
--fullBuild
```

オプション補足:

- **DBB_DAEMON_HOST, DBB_DAEMON_PORT**: groovyスクリプトはJVM上で稼働し、実行の度にJVM起動していると遅いので、事前にDaemonを立ち上げておいてそれを利用することができます。このオプションでShared Daemonを立ち上げておいてそれを使うためにShared Daemonのアドレスとポートを指定しています。
- **workspace**: 対象のアプリケーションを配置しているディレクトリ。この配下にリポジトリをクローンしています。
- **application**: 今回のビルド対象のアプリケーションが配置されているディレクトリ(workspaceからの相対パス)です。
- **hlq**: ソースやビルド後のロードモジュールなどはPDSのメンバーとして保持されますが、そのデータセットのHLQです。無ければ動的に作成されます。
- **outDir**: ログの出力先です。Shared Daemonを使う場合、Shared Daemon実行ユーザーの書き込み権限が必要になります。

上のコマンドを実行すると、以下のような結果が出力されます。

```
** Build start at 20210319.062456.024
** Repository client created for https://127.0.0.1:9998/dbb
** Build output located at /u/TEST01/test/logs/build.20210319.062456.024
** Build result created for BuildGroup:wazi-sandbox01-mortgage-master BuildLabel:build.20210319.062456.024 at https://127.0.0.1:9998/dbb/rest/buildResult/326
** --fullBuild option selected. Building all programs for application wazi-sandbox01-mortgage
** Writing build list file to /u/TEST01/test/logs/build.20210319.062456.024/buildList.txt
** Invoking build scripts according to build order: BMS.groovy,Cobol.groovy,LinkEdit.groovy
** Building files mapped to BMS.groovy script
*** Building file wazi-sandbox01-mortgage/bms/epsmlis.bms
*** Building file wazi-sandbox01-mortgage/bms/epsmort.bms
** Building files mapped to Cobol.groovy script
*** Building file wazi-sandbox01-mortgage/cobol/epsnbrvl.cbl
*** Building file wazi-sandbox01-mortgage/cobol/epscmort.cbl
*** Building file wazi-sandbox01-mortgage/cobol/epscsmrt.cbl
*** Building file wazi-sandbox01-mortgage/cobol/epsmpmt.cbl
*** Building file wazi-sandbox01-mortgage/cobol/epscsmrd.cbl
*** Building file wazi-sandbox01-mortgage/cobol/epsmlist.cbl
** Building files mapped to LinkEdit.groovy script
*** Building file wazi-sandbox01-mortgage/link/epsmlist.lnk
** Writing build report data to /u/TEST01/test/logs/build.20210319.062456.024/BuildReport.json
** Writing build report to /u/TEST01/test/logs/build.20210319.062456.024/BuildReport.html
** Build ended at Fri Mar 19 06:28:57 GMT 2021
** Build State : CLEAN
** Total files processed : 9
** Total build time  : 4 minutes, 0.794 seconds

__RC=0__
** Build finished
```

ビルド結果のロードモジュールはTEST01.DBB.LOAD配下に生成されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/92279094-45d5-6301-c509-9871d62d421e.png)

DBB Serverにブラウザからアクセスすると、ビルド結果(Build Report)や依存関係の情報(Collection)が登録されているのが確認できます。

<details><summary><font color="blue">Build Report例</font></summary><div>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/9a2d3d05-c691-4f60-6b28-e6f2d32460e7.png)
</div></details>

<details><summary><font color="blue">Collection例</font></summary><div>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/9f151374-1ff7-135f-422f-5b94d8466a2f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/2e531ff4-a810-332b-677e-20f8a8338419.png)

</div></details>

GitのRepositoryをUSS上にクローンし、そ子に含まれるソースをDBB, zAppBuildを利用してビルドする、という手順が確認できました。処理イメージは以下の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/c5f8d1ad-e172-2fdc-bb12-f448c1e4114b.png)

### 後始末
次のシナリオは、今回のシナリオを改修して使うので、一旦、ここで生成されたDBB Server上のBuild Result, Collectionを削除しておきます。

zAppBuildの --reset オプションを使用すると削除できます。以下のコマンドを実行すると消えました。

```sh:/u/TEST01/test/workspace/reset_mortgage.sh
#!/bin/sh

DBB_HOME=/usr/lpp/IBM/dbb

${DBB_HOME}/bin/groovyz /u/dbb_common/dbb-zappbuild/build.groovy \
-DBB_DAEMON_HOST 127.0.0.1  \
-DBB_DAEMON_PORT 7380 \
--logEncoding UTF-8 \
--workspace /u/TEST01/test/workspace \
--application wazi-sandbox01-mortgage \
--hlq TEST01.DBB \
--outDir /u/TEST01/test/logs \
--reset
```

## シナリオ3: Jenkins+Git+DBB+zAppBuild
いよいよ一気通貫で試してみます。シナリオ2で実施した手動の操作をJenkinsで自動化するイメージです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/03980083-9c53-fcaf-7e81-86132078ffa9.png)

シナリオ2で作成したものをカスタマイズしてJenkinsから実行できるようにします。

### Jenkinsfile(Pipeline Script)作成

Git Repolistryに以下Jenkinsfile(Pipeline Script)を追加します。

```groovy:Jenkinsfile
pipeline {
   agent {label 'wazi-test01'}

   stages {
      stage('Hello') {
         steps {
            echo 'Hello World'
         }
      }
      stage('Build'){
         steps {
            script {
               // get environment variables ---- test01
               def dbbHome = env.DBB_HOME
               def zAppBuildHome = env.ZAPPBUILD_HOME
               def dbbBuildExtraOpts = env.DBB_BUILD_EXTRA_OPTS
               def workspaceDir = env.WORKSPACE.tokenize('/').last()

               sh """
                  $dbbHome/bin/groovyz $zAppBuildHome/build.groovy \
                     $dbbBuildExtraOpts  \
                     --logEncoding UTF-8 \
                     --workspace ${WORKSPACE}/.. \
                     --application ${workspaceDir} \
                     --hlq TEST01.DBB \
                     --outDir /u/TEST01/test/logs \
                     --fullBuild
               """
            }
         }
      }
   }
}
```

zAppBuild(build.groovy)の起動コマンドには環境依存の情報も多く含まれているので、その手の情報はなるべく環境変数として取り込むようにします。環境変数は`env.xxx`で取得するようにしていますが、これはJenkinsのノード定義の所で指定することができます(後述)。
また、JenkinsのPipelineで元々持っている環境変数は`${xxx}`の形式で利用することができます。Jenkins Pipelineで利用できる環境変数は以下を参照のこと。
参考: [Jenkins User Handbook - Using environment variables](https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#using-environment-variables)

※Git Repositoryがクローンされる際、USS上に落とされるときにRepository名がそのまま保持されるのではなく、ディレクトリ名としてはJenkinsとしてのワークスペース名に置き換わるようなイメージになります。`${WORKSPACE}`で取得されるのはJenkinsワークスペースのフルパスなので、zAppBuildの`--workspace`としては`${WORKSPACE}`の一つ上のディレクトリ、`--application`としては　`${WORKSPACE}`のディレクトリ名のみを抽出して指定するようにしています。
(今回の例の場合`${WORKSPACE}`には`/u/TEST01/agent/wazi-test01/workspace/git_pipeline_zAppBuild01`が返されることになります。)

### Jenkins:ノード定義変更
Jenkinsfile(Pipeline Script)で環境変数から取得するようにした情報は、Jenkinsノード定義で指定できます。
管理対象のノードのプロパティ以下の環境変数にチェックを入れて、環境変数として与えたいキーと値を追加していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/2fd6177d-e694-5beb-3a31-732631f1ca0c.png)

Jenkinsfileで設定した環境変数に合わせて、以下設定します。

- **DBB_HOME**: DBBがインストールされているディレクトリ (/usr/lpp/IBM/dbb)
- **ZAPPBUILD_HOME**: zAppBuildをセットアップしたディレクトリ (/u/dbb_common/dbb-zappbuild)
- **DBB_BUILD_EXTRA_OPTS**: zAppBuild実行時の追加オプション (-DBB_DAEMON_HOST 127.0.0.1 -DBB_DAEMON_PORT 7380)

### Jenkins:Pipeline定義
Pipeline定義を作成します。今回はWebhookは使用しないので、普通にパイプラインの定義を追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/10b24ff8-cdab-23fc-a616-816f14205aa5.png)

### Jenkins:Pipeline実行
Jenkins DashboardからPipeline実行します。



<details><summary><font color="blue">ビルドのログ</font></summary><div>

```
Started by user jenkins user
Obtained Jenkinsfile from git https://github.ibm.com/TOMOTAG/wazi-sandbox01-mortgage.git
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] Start of Pipeline
[Pipeline] node
Running on wazi-test01 in /u/TEST01/agent/wazi-test01/workspace/git_pipeline_zAppBuild01
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Declarative: Checkout SCM)
[Pipeline] checkout
Selected Git installation does not exist. Using Default
The recommended git tool is: NONE
using credential TOMOTAG
Fetching changes from the remote Git repository
 > git rev-parse --is-inside-work-tree # timeout=10
 > git config remote.origin.url https://github.ibm.com/TOMOTAG/wazi-sandbox01-mortgage.git # timeout=10
Fetching upstream changes from https://github.ibm.com/TOMOTAG/wazi-sandbox01-mortgage.git
 > git --version # timeout=10
Checking out Revision db3d3ffcafa200af5899646cfb8b3f9d6cbde6f4 (refs/remotes/origin/master)
 > git --version # 'git version 2.14.4_zos_b09'
using GIT_ASKPASS to set credentials 
Using name charset 'IBM1047'
Using password charset 'IBM1047'
 > git fetch --tags --progress -- https://github.ibm.com/TOMOTAG/wazi-sandbox01-mortgage.git +refs/heads/*:refs/remotes/origin/* # timeout=10
 > git rev-parse refs/remotes/origin/master^{commit} # timeout=10
 > git config core.sparsecheckout # timeout=10
 > git checkout -f db3d3ffcafa200af5899646cfb8b3f9d6cbde6f4 # timeout=10
Commit message: "remove DBB server info"
 > git rev-list --no-walk db3d3ffcafa200af5899646cfb8b3f9d6cbde6f4 # timeout=10
[Pipeline] }
[Pipeline] // stage
[Pipeline] withEnv
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Hello)
[Pipeline] echo
Hello World
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Build)
[Pipeline] script
[Pipeline] {
[Pipeline] sh
+ /usr/lpp/IBM/dbb/bin/groovyz /u/dbb_common/dbb-zappbuild/build.groovy -DBB_DAEMON_HOST 127.0.0.1 -DBB_DAEMON_PORT 7380 --logEncoding UTF-8 --workspace /u/TEST01/agent/wazi-test01/workspace/git_pipeline_zAppBuild01/.. --application git_pipeline_zAppBuild01 --hlq TEST01.DBB --outDir /u/TEST01/test/logs --fullBuild 

** Build start at 20210323.045530.055
** Repository client created for https://127.0.0.1:9998/dbb
** Build output located at /u/TEST01/test/logs/build.20210323.045530.055
** Build result created for BuildGroup:git_pipeline_zAppBuild01-master BuildLabel:build.20210323.045530.055 at https://127.0.0.1:9998/dbb/rest/buildResult/496
** --fullBuild option selected. Building all programs for application git_pipeline_zAppBuild01
** Writing build list file to /u/TEST01/test/logs/build.20210323.045530.055/buildList.txt
** Scanning source code.
** Invoking build scripts according to build order: BMS.groovy,Cobol.groovy,LinkEdit.groovy
** Building files mapped to BMS.groovy script
*** Building file git_pipeline_zAppBuild01/bms/epsmort.bms
*** Building file git_pipeline_zAppBuild01/bms/epsmlis.bms
** Building files mapped to Cobol.groovy script
*** Building file git_pipeline_zAppBuild01/cobol/epsnbrvl.cbl
*** Building file git_pipeline_zAppBuild01/cobol/epscmort.cbl
*** Building file git_pipeline_zAppBuild01/cobol/epsmlist.cbl
*** Building file git_pipeline_zAppBuild01/cobol/epscsmrd.cbl
*** Building file git_pipeline_zAppBuild01/cobol/epsmpmt.cbl
*** Building file git_pipeline_zAppBuild01/cobol/epscsmrt.cbl
** Building files mapped to LinkEdit.groovy script
*** Building file git_pipeline_zAppBuild01/link/epsmlist.lnk
** Writing build report data to /u/TEST01/test/logs/build.20210323.045530.055/BuildReport.json
** Writing build report to /u/TEST01/test/logs/build.20210323.045530.055/BuildReport.html
** Build ended at Tue Mar 23 04:58:58 GMT 2021
** Build State : CLEAN
** Total files processed : 9
** Total build time  : 3 minutes, 27.652 seconds

__RC=0__
** Build finished
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
```

</div></details>

Jenkins Pipelineからビルド実行ができるようになりました！

# まとめ
今回の試した内容は以下のイメージです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/c7b3c1c6-ae7d-d746-e7ea-ee91cacecc0e.png)

Webhookを使えばGit Repositoryの更新をトリガーにビルドを動かすこともできますし、今回はビルド部分しかPipelineに記載していませんがテスト自動実行やデプロイなどの仕組みを組み込んでいけば自動化の範囲を広げることができると思います。