1. 개요 및 이 글에서 다룰 것
ABAP 개발도 이제 자바·자바스크립트 진영처럼 Git 기반 버전 관리와 CI(Continuous Integration) 파이프라인을 통해 빌드·테스트를 자동화할 수 있습니다. 핵심 도구는 세 가지입니다. abapGit은 ABAP 오브젝트를 Git 저장소와 동기화해 주고, Jenkins는 파이프라인 오케스트레이션을 담당하며, SAP Piper는 SAP 환경에 특화된 Jenkins 공유 라이브러리(공식 오픈소스 프로젝트)로서 ABAP/BTP/Fiori 전용 스텝을 제공합니다.
이 글에서 다룰 것:
- abapGit으로 ABAP 패키지를 GitHub/Azure Repos에 연결
- Jenkinsfile에
abapEnvironmentCloneGitRepo스텝으로 BTP ABAP 환경에 코드 풀 abapEnvironmentRunAUnitTest로 ABAP Unit을 자동 실행하고 JUnit 리포트 수집- 인증·범위·실패 처리 등 실무 트러블슈팅
대상 독자: ABAP 개발자 또는 BTP ABAP Environment 운영자 중 CI 파이프라인을 처음 구축하는 분.
2. 사전 가정
이 글은 다음을 알고 있다고 가정합니다.
- abapGit 기본 사용:
SE80/ADT에서 패키지를 abapGit 저장소에 연결하고 stage/commit을 수행해 본 경험 - Jenkins 설치/운영: Jenkins LTS를 도커 또는 VM에 띄우고 Multibranch Pipeline 잡을 만들어 본 경험
- ABAP Unit:
FOR TESTING클래스 작성과 로컬 실행(Ctrl+Shift+F10) 경험 - YAML/Groovy 문법에 대한 기본 이해
3. 환경 / 버전 / 준비물
일반적으로 권장되는 조합은 다음과 같습니다(2026년 6월 기준).
- SAP BTP ABAP Environment (Steampunk) 또는 SAP S/4HANA on-premise 2022/2023 +
gCTS활성화 - abapGit: 최신 standalone 버전 또는 ABAP 1909+ 내장 버전
- Jenkins LTS 2.426.x 이상 (Pipeline, Git, Credentials Binding 플러그인 필수)
- project "Piper" Jenkins library:
master또는v1.400이상 고정 권장 - Communication Arrangement: BTP ABAP 환경의
SAP_COM_0510(Software Component Test Integration) 또는SAP_COM_0948 - Service Key (JSON):
cf create-service-key로 발급, Jenkins Credentials에 secret file로 등록 - Git 호스팅: GitHub Enterprise, Azure Repos, 또는 자체 GitLab
Jenkins 컨트롤러에는 도커가 설치돼 있어야 합니다. Piper의 ABAP 스텝은 내부적으로 ppiper/cf-cli 도커 이미지를 사용해 Cloud Foundry CLI 호출을 격리합니다.
4. 핵심 개념
CI/CD와 ABAP
전통적인 ABAP 개발은 Transport Request(CTS)를 통해 DEV → QAS → PRD로 이동했습니다. CI/CD 관점에서 보면 운반 자체는 배포(CD)에 가깝지만, "커밋 시점에 자동으로 빌드·테스트가 돌아가는" CI 단계가 비어 있었습니다. abapGit과 Piper가 이 구멍을 메웁니다.
abapGit의 역할
abapGit은 ABAP 리포지토리 오브젝트(클래스, 인터페이스, DDIC, CDS 뷰 등)를 직렬화해 .abap/.xml 파일로 만들고 Git 저장소에 푸시합니다. 비유하자면 ABAP 시스템과 Git 사이의 번역기입니다. 반대로 pull하면 Git의 직렬화된 파일을 다시 SAP 시스템에 활성화합니다.
SAP Piper 구조
Piper는 두 부분으로 구성됩니다.
- Jenkins Library (Groovy):
library 'piper-lib-os'로 로드되며piperPipeline,abapEnvironmentPipeline같은 상위 오케스트레이터를 제공 - Piper Go binary: 실제 스텝 로직은 Go로 작성돼 컨테이너에서 실행. Jenkins-독립적이라 GitHub Actions에서도 동일 스텝 사용 가능
도식으로 표현하면 다음과 같습니다.
Developer Push (Git)
|
v
Jenkins Webhook ----> Jenkinsfile
|
v
piper-lib-os (Groovy)
|
v
Piper Go binary (Docker)
|
+--------------+--------------+
v v
abapEnvironmentCloneGitRepo abapEnvironmentRunAUnitTest
| |
v v
BTP ABAP Env JUnit XML
주요 스텝
abapEnvironmentCreateSystem: 일회성 테스트 시스템 프로비저닝abapEnvironmentCloneGitRepo: Software Component를 시스템에 pullabapEnvironmentRunAUnitTest: ABAP Unit 실행 후 JUnit 결과 다운로드abapEnvironmentRunATCCheck: ABAP Test Cockpit 정적 분석
5. 실전 코드 3단계
1단계: abapGit으로 ABAP 패키지를 Git에 연결
먼저 SAP 시스템 측에서 패키지 ZCI_DEMO를 만들고 abapGit Online Repository로 등록합니다. ADT에서 Ctrl+Shift+A > "abapGit Repositories" > + 버튼으로 신규 저장소를 추가하면 다음과 같이 .abapgit.xml 메타파일이 자동 생성됩니다.
<?xml version="1.0" encoding="utf-8"?>
<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
<asx:values>
<DATA>
<MASTER_LANGUAGE>E</MASTER_LANGUAGE>
<STARTING_FOLDER>/src/</STARTING_FOLDER>
<FOLDER_LOGIC>PREFIX</FOLDER_LOGIC>
<IGNORE>
<item>/.gitignore</item>
<item>/LICENSE</item>
<item>/README.md</item>
</IGNORE>
</DATA>
</asx:values>
</asx:abap>
다음으로 첫 번째 ABAP Unit 클래스를 작성합니다. 단순 계산 로직과 테스트입니다.
CLASS zcl_ci_calc DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
METHODS add IMPORTING iv_a TYPE i iv_b TYPE i
RETURNING VALUE(rv_sum) TYPE i.
ENDCLASS.
CLASS zcl_ci_calc IMPLEMENTATION.
METHOD add.
rv_sum = iv_a + iv_b.
ENDMETHOD.
ENDCLASS.
CLASS ltc_calc DEFINITION FOR TESTING
DURATION SHORT RISK LEVEL HARMLESS FINAL.
PRIVATE SECTION.
METHODS add_two_plus_three FOR TESTING.
ENDCLASS.
CLASS ltc_calc IMPLEMENTATION.
METHOD add_two_plus_three.
DATA(lo_calc) = NEW zcl_ci_calc( ).
cl_abap_unit_assert=>assert_equals(
act = lo_calc->add( iv_a = 2 iv_b = 3 )
exp = 5 ).
ENDMETHOD.
ENDCLASS.
abapGit에서 stage > commit > push 하면 Git 저장소에 src/zcl_ci_calc.clas.abap이 생성됩니다.
2단계: Jenkinsfile + SAP Piper 파이프라인
Jenkins Multibranch Pipeline에서 읽어 들일 Jenkinsfile을 리포지토리 루트에 둡니다. Piper 라이브러리는 @Library로 로드합니다.
# .pipeline/config.yml
general:
cfCredentialsId: 'cfDeployUser'
abapCredentialsId: 'abapCommUser'
stages:
Prepare System:
cfApiEndpoint: 'https://api.cf.eu10.hana.ondemand.com'
cfOrg: 'mycompany_prod'
cfSpace: 'CI'
cfServiceInstance: 'abap-ci-system'
cfServiceKeyName: 'ci-key'
Clone Repositories:
repositories:
- name: '/DMO/ZCI_DEMO'
branch: 'main'
ATC:
atcConfig: 'atcConfig.yml'
AUnit:
aUnitConfig: 'aUnitConfig.yml'
@Library('piper-lib-os') _
node('linux') {
stage('Init') {
checkout scm
setupCommonPipelineEnvironment script: this
}
stage('Prepare System') {
abapEnvironmentCreateSystem script: this,
includeAddon: false
}
stage('Clone Repositories') {
abapEnvironmentCloneGitRepo script: this
}
stage('ATC') {
abapEnvironmentRunATCCheck script: this
}
stage('AUnit') {
abapEnvironmentRunAUnitTest script: this
}
stage('Cleanup') {
cloudFoundryDeleteService script: this
}
}
여기서 setupCommonPipelineEnvironment는 .pipeline/config.yml을 읽어 모든 스텝에 공통 파라미터를 주입합니다. Jenkins Credentials에는 cfDeployUser(Cloud Foundry 사용자), abapCommUser(Communication User basic auth)를 미리 등록해 둡니다.
3단계: AUnit 자동 실행 + JUnit 결과 수집
실행 범위를 정의하는 aUnitConfig.yml을 작성합니다. 패키지 단위로 테스트 범위를 좁히는 것이 일반적입니다.
title: AUnit run for ZCI_DEMO
context: AUnit run
options:
measurements: none
scope:
ownTests: true
foreignTests: false
riskLevel:
harmless: true
dangerous: true
critical: false
duration:
short: true
medium: true
long: false
objectSet:
type: unionSet
set:
type: componentSet
component:
- name: /DMO/ZCI_DEMO
스텝 실행 결과는 AUnitResults.xml(JUnit 호환)로 작업공간에 떨어집니다. Jenkins의 표준 junit 스텝으로 수집하면 트렌드 그래프와 실패 알림이 자동으로 활성화됩니다.
stage('AUnit') {
try {
abapEnvironmentRunAUnitTest script: this,
aUnitResultsFileName: 'AUnitResults.xml'
} finally {
junit testResults: 'AUnitResults.xml',
allowEmptyResults: false
archiveArtifacts artifacts: 'AUnitResults.xml',
fingerprint: true
}
}
프로덕션에서는 다음을 추가로 권장합니다.
- Secret 분리: 서비스 키 JSON은
withCredentials([file(...)])로만 노출, 로그 마스킹 활성화 - 병렬 실행: ATC와 AUnit을
parallel { }블록으로 동시 실행해 파이프라인 시간 단축 - 실패 게이팅:
unstable임계값을aUnitConfig.yml에 정의해 PR 머지 차단 - 리트라이: BTP 시스템 프로비저닝은 가끔 타임아웃이 나므로
retry(2)로 감싸기
6. 흔한 실수 / 트러블슈팅
FAQ 1. 401 Unauthorized가 떨어진다
대부분 Communication Arrangement(SAP_COM_0510) 사용자의 비밀번호 만료 또는 Jenkins Credentials ID 오타입니다. cfServiceKeyName이 실제 서비스 키 이름과 정확히 일치하는지, 공백·줄바꿈이 섞이지 않았는지 확인하세요. curl -u user:pass https://<host>/sap/opu/odata/...로 직접 호출해 격리 테스트하는 것이 빠릅니다.
FAQ 2. AUnit이 0건만 실행된다
aUnitConfig.yml의 objectSet 범위가 잘못된 경우입니다. componentSet의 name은 Software Component(예: /DMO/ZCI_DEMO)지 일반 패키지가 아닙니다. 패키지로 좁히려면 packageSet 타입과 includeSubpackages: true를 함께 지정해야 합니다. 또한 ownTests: false로 두면 자체 테스트도 제외되니 주의하세요.
FAQ 3. 테스트는 통과했는데 빌드가 unstable이다
Piper는 riskLevel.critical: true로 설정된 테스트가 한 건이라도 있으면 위험 등급 정책에 따라 결과를 unstable로 마킹할 수 있습니다. CI 단계에서는 critical을 제외하고 별도 nightly 잡에서 돌리는 것이 일반적입니다. 또한 JUnit 플러그인의 healthScaleFactor가 너무 민감하게 설정돼 있을 수 있으니 함께 점검하세요.
기타 자주 만나는 문제
- 도커 권한 오류: Jenkins 에이전트가
docker.sock에 접근하지 못하면 Piper Go 바이너리 실행 실패.usermod -aG docker jenkins후 재시작 - Software Component 미등록: BTP ABAP 환경의 "Manage Software Components" Fiori 앱에서 먼저 컴포넌트를 등록해야
abapEnvironmentCloneGitRepo가 동작 - 네트워크 프록시: 사내망에서는
HTTP_PROXY/NO_PROXY를 Jenkins 글로벌 환경변수와 도커 이미지 양쪽에 모두 설정
7. 다음 단계 / 관련 주제
CI 파이프라인이 안정화되면 다음 영역으로 확장하세요.
- ABAP Test Cockpit(ATC): 정적 코드 품질 검사.
abapEnvironmentRunATCCheck스텝으로 동일 파이프라인에 추가 가능 - Code Inspector(SCI): 온프렘 시스템에서 변수명 규칙·성능 패턴 검사. 체크 변형을 미리 만들어 두면 ATC와 결과 공유
- gCTS(Git-enabled CTS): 온프렘 S/4HANA에서 transport와 Git을 양방향 동기화. abapGit 대안으로 검토
- SAP Cloud Transport Management(cTMS): CI 통과 후 QAS/PRD 자동 배포로 CD 단계 완성
- Trunk-based development: short-lived feature branch + PR 머지 시 자동 ATC/AUnit 게이팅
8. 참고 자료
- SAP Help - ABAP Environment (BTP)
- SAP Help - Manage Software Components
- SAP Help - Run AUnit Tests in ABAP Environment
- Project Piper - 공식 문서 (오픈소스)
- Piper Step Reference - abapEnvironmentRunAUnitTest
- Piper Step Reference - abapEnvironmentCloneGitRepo
- abapGit 공식 문서
- Jenkins Pipeline 공식 문서
- SAP Community Blogs - Continuous Integration ABAP
댓글 0
아직 댓글이 없습니다.