gCTS (Git-enabled Change and Transport System) und CI/CD-Pipelines bringen moderne DevOps-Praktiken in die ABAP-Welt. In diesem Artikel lernst du, wie du eine vollständige DevOps-Pipeline für ABAP Cloud einrichtest - von der Git-Integration bis zur automatisierten Deployment-Pipeline.
Was ist gCTS?
gCTS verbindet das klassische SAP-Transportwesen mit Git-Repositories. Statt Transportaufträge manuell zwischen Systemen zu verschieben, werden ABAP-Objekte als Dateien in Git gespeichert und über Git-Operationen synchronisiert.
Kernkonzept
┌─────────────────────────────────────────────────────────────────────┐│ Entwicklungslandschaft mit gCTS ││ ││ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ││ │ DEV │ │ QAS │ │ PRD │ ││ │ System │ │ System │ │ System │ ││ │ ┌───────┐ │ │ ┌───────┐ │ │ ┌───────┐ │ ││ │ │ gCTS │ │ │ │ gCTS │ │ │ │ gCTS │ │ ││ │ │Client │ │ │ │Client │ │ │ │Client │ │ ││ │ └───┬───┘ │ │ └───┬───┘ │ │ └───┬───┘ │ ││ └──────│──────┘ └──────│──────┘ └──────│──────┘ ││ │ │ │ ││ └─────────┬────────┴────────┬─────────┘ ││ Push │ │ Pull ││ ▼ ▼ ││ ┌───────────────────────────────┐ ││ │ Git Repository │ ││ │ (GitHub / GitLab / Azure) │ ││ └───────────────────────────────┘ │└─────────────────────────────────────────────────────────────────────┘Klassisches CTS vs. gCTS
| Aspekt | Klassisches CTS | gCTS |
|---|---|---|
| Versionierung | Transportaufträge | Git-Commits |
| Branching | Nicht möglich | Vollständiges Branching |
| Vergleich | Eingeschränkt | Diff zwischen Commits |
| Collaboration | Limitiert | Pull Requests, Code Review |
| History | Transportlogs | Vollständige Git-Historie |
| Rollback | Manuell | Git Revert/Reset |
| CI/CD | Schwierig | Native Integration |
| Tooling | SAP-spezifisch | Standard Git-Tools |
gCTS vs. abapGit: Wann nutze ich was?
Eine häufige Frage in der ABAP-Community: Was ist der Unterschied zwischen gCTS und abapGit?
| Kriterium | gCTS | abapGit |
|---|---|---|
| Herkunft | SAP-Produkt (offiziell) | Open-Source (Community) |
| Zielgruppe | IT Operations & Enterprise | Entwickler & Teams |
| Fokus | Transport-Automatisierung | Code-Versionierung |
| Git-Integration | Push & Pull | Vollständig (bidirektional) |
| Kosten | SAP-Lizenz erforderlich | Kostenlos |
| Setup-Komplexität | Höher (Enterprise-Setup) | Geringer (Quick Start) |
| CI/CD Pipeline | Native SAP Integration | Manuell einrichtbar |
| Transport-Integration | Vollständig integriert | Keine |
| SAP-Support | Ja, offizieller Support | Community-Support |
Empfehlung
- gCTS wählen: Enterprise-Umgebungen mit produktiven Systemlandschaften, wenn offizieller SAP-Support benötigt wird
- abapGit wählen: Open-Source-Projekte, Entwicklerteams, schneller Einstieg, maximale Flexibilität
- Kombination: Beide Tools können kombiniert werden - abapGit für Entwicklung, gCTS für Enterprise-Deployments
Für einen detaillierten Einstieg in abapGit, siehe den abapGit Tutorial-Artikel.
CI/CD-Konzepte für ABAP
Continuous Integration (CI) und Continuous Delivery (CD) bringen bewährte DevOps-Praktiken in die ABAP-Entwicklung:
| Phase | Ohne CI/CD | Mit CI/CD |
|---|---|---|
| Tests | Manuell, oft vergessen | Automatisch bei jedem Commit |
| Code-Qualität | Sporadische ATC-Checks | Kontinuierliche Prüfung |
| Deployment | Manueller Transport | Automatisiert & reproduzierbar |
| Feedback | Verzögert, nach Tagen | Sofort, in Minuten |
| Risiko | Große Releases, hohes Risiko | Kleine Änderungen, geringes Risiko |
| Rollback | Komplex, manuell | Einfach, automatisiert |
Die CI/CD-Pipeline für ABAP
┌─────────────────────────────────────────────────────────────────────────┐│ CI/CD Pipeline für ABAP Cloud ││ ││ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ││ │ Code │ │ Build │ │ Test │ │ Quality │ │ Deploy │ ││ │ Push │──▶│ Check │──▶│ Stage │──▶│ Gate │──▶│ Stage │ ││ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ ││ │ │ │ │ │ ││ ▼ ▼ ▼ ▼ ▼ ││ Git Push Syntax & ABAP Unit ATC Checks gCTS Pull ││ Trigger Activation Tests Code Review Transport ││ Integration Coverage ││ Tests Security │└─────────────────────────────────────────────────────────────────────────┘gCTS einrichten: Setup-Anleitung
Voraussetzungen
- SAP S/4HANA oder SAP BTP ABAP Environment
- Git-Repository (GitHub, GitLab, Azure DevOps)
- SSL-Zertifikate für Git-Server
- Berechtigungen: S_CTS_ADMI, S_CTS_SADM
Schritt 1: SSL-Zertifikate importieren
Transaktion: STRUST
1. SSL Client (Standard) öffnen2. Zertifikat importieren: - GitHub: github.com - GitLab: gitlab.com (oder eigene Domain)3. Zertifikatsliste aktualisieren4. SpeichernSchritt 2: gCTS-Repository anlegen
In der Transaktion GCTS_MAINT oder über die Fiori App:
┌──────────────────────────────────────────────────────────────┐│ Repository Configuration │├──────────────────────────────────────────────────────────────┤│ Repository Name: Z_MY_PROJECT ││ Remote URL: https://github.com/company/project.git ││ Branch: main ││ ││ Authentication: ││ ● Token-based (recommended) ││ ││ Username: github-service-user ││ Token: ghp_xxxxxxxxxxxx ││ ││ vSID (Virtual System ID): DEV │└──────────────────────────────────────────────────────────────┘Schritt 3: Repository über API anlegen (optional)
CLASS zcl_gcts_setup DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. METHODS create_repository IMPORTING iv_repository_name TYPE string iv_remote_url TYPE string iv_branch TYPE string DEFAULT 'main' RAISING cx_web_http_client_error.ENDCLASS.
CLASS zcl_gcts_setup IMPLEMENTATION. METHOD create_repository. DATA(lo_destination) = cl_http_destination_provider=>create_by_url( i_url = |http://localhost:50000/sap/bc/cts_abapvcs/repository| ).
DATA(lo_client) = cl_web_http_client_manager=>create_by_http_destination( i_destination = lo_destination ).
DATA: BEGIN OF ls_request, repository TYPE string, url TYPE string, branch TYPE string, role TYPE string VALUE 'SOURCE', END OF ls_request.
ls_request-repository = iv_repository_name. ls_request-url = iv_remote_url. ls_request-branch = iv_branch.
DATA(lv_json) = /ui2/cl_json=>serialize( data = ls_request compress = abap_true pretty_name = /ui2/cl_json=>pretty_mode-camel_case ).
DATA(lo_request) = lo_client->get_http_request( ). lo_request->set_header_field( i_name = 'Content-Type' i_value = 'application/json' ). lo_request->set_text( lv_json ).
DATA(lo_response) = lo_client->execute( if_web_http_client=>post ).
IF lo_response->get_status( )-code <> 201. RAISE EXCEPTION TYPE cx_web_http_client_error. ENDIF.
lo_client->close( ). ENDMETHOD.ENDCLASS.Schritt 4: ABAP-Paket mit Repository verknüpfen
Nach dem Anlegen des Repositories muss das ABAP-Paket verknüpft werden:
" In SE80 oder über ADT:" Paket Z_MY_PACKAGE → Properties → gCTS Repository zuweisenGitHub Actions Pipeline für ABAP
GitHub Actions bietet maximale Flexibilität für ABAP CI/CD. Hier eine vollständige, produktionsreife Pipeline:
Vollständige Pipeline-Konfiguration
name: ABAP CI/CD Pipeline
on: push: branches: [ main, develop, 'release/**' ] pull_request: branches: [ main, develop ] workflow_dispatch: inputs: deploy_target: description: 'Deploy to environment' required: true default: 'dev' type: choice options: - dev - qas - prd
env: ABAP_PACKAGE: ${{ vars.ABAP_PACKAGE }} ATC_VARIANT: ${{ vars.ATC_VARIANT || 'DEFAULT' }}
jobs: # Job 1: Syntax Check und Aktivierung build: name: Build & Syntax Check runs-on: ubuntu-latest
steps: - name: Checkout Repository uses: actions/checkout@v4
- name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20'
- name: Verify ABAP Syntax run: | curl -X POST \ "${{ secrets.ABAP_ENDPOINT }}/sap/bc/adt/programs/checks" \ -u "${{ secrets.ABAP_USER }}:${{ secrets.ABAP_PASSWORD }}" \ -H "Content-Type: application/json" \ --fail
# Job 2: ABAP Unit Tests unit-tests: name: ABAP Unit Tests needs: build runs-on: ubuntu-latest
steps: - name: Run ABAP Unit Tests id: aunit run: | curl -X POST \ "${{ secrets.ABAP_ENDPOINT }}/sap/bc/adt/abapunit/testruns" \ -u "${{ secrets.ABAP_USER }}:${{ secrets.ABAP_PASSWORD }}" \ -H "Content-Type: application/vnd.sap.adt.abapunit.testruns.config.v4+xml" \ -H "Accept: application/vnd.sap.adt.abapunit.testruns.result.v1+xml" \ -d @- << 'EOF' > aunit_results.xml <?xml version="1.0" encoding="UTF-8"?> <aunit:runConfiguration xmlns:aunit="http://www.sap.com/adt/aunit"> <external> <coverage active="true" branchCoverage="true"/> </external> <options> <uriType value="semantic"/> <testDeterminationStrategy sameProgram="true"/> <testRiskCoverage> <harmless active="true"/> <dangerous active="true"/> <critical active="true"/> </testRiskCoverage> <durationCoverage short="true" medium="true" long="true"/> </options> <adtcore:objectSets xmlns:adtcore="http://www.sap.com/adt/core"> <objectSet kind="inclusive"> <adtcore:objectReferences> <adtcore:objectReference adtcore:uri="/sap/bc/adt/vit/wb/object_type/devck/object_name/${{ env.ABAP_PACKAGE }}"/> </adtcore:objectReferences> </objectSet> </adtcore:objectSets> </aunit:runConfiguration> EOF
- name: Parse Test Results run: | if grep -q 'alerts severity="error"' aunit_results.xml; then echo "::error::ABAP Unit Tests failed!" exit 1 fi echo "✅ All ABAP Unit Tests passed"
- name: Upload Test Results uses: actions/upload-artifact@v4 with: name: aunit-results path: aunit_results.xml
# Job 3: ATC Code Quality Checks atc-checks: name: ATC Quality Checks needs: build runs-on: ubuntu-latest
steps: - name: Run ATC Checks id: atc run: | # ATC Run starten RUN_ID=$(curl -X POST \ "${{ secrets.ABAP_ENDPOINT }}/sap/bc/adt/atc/runs" \ -u "${{ secrets.ABAP_USER }}:${{ secrets.ABAP_PASSWORD }}" \ -H "Content-Type: application/vnd.sap.atc.run.parameters.v1+xml" \ -d @- << EOF | grep -oP 'id="\K[^"]+' | head -1 <?xml version="1.0" encoding="UTF-8"?> <atc:run xmlns:atc="http://www.sap.com/adt/atc"> <checkVariant>${{ env.ATC_VARIANT }}</checkVariant> <objectSets> <objectSet name="run"> <softwareComponent name="${{ env.ABAP_PACKAGE }}"/> </objectSet> </objectSets> </atc:run> EOF )
echo "ATC Run ID: $RUN_ID" sleep 30
# Ergebnisse abrufen curl -X GET \ "${{ secrets.ABAP_ENDPOINT }}/sap/bc/adt/atc/runs/$RUN_ID/results" \ -u "${{ secrets.ABAP_USER }}:${{ secrets.ABAP_PASSWORD }}" \ -H "Accept: application/vnd.sap.atc.checkresult.v1+xml" \ > atc_results.xml
- name: Evaluate ATC Results run: | ERRORS=$(grep -c 'priority="1"' atc_results.xml || true) WARNINGS=$(grep -c 'priority="2"' atc_results.xml || true)
echo "ATC Results: $ERRORS errors, $WARNINGS warnings"
if [ "$ERRORS" -gt 0 ]; then echo "::error::ATC found $ERRORS critical issues!" exit 1 fi echo "✅ ATC checks passed"
- name: Upload ATC Results uses: actions/upload-artifact@v4 with: name: atc-results path: atc_results.xml
# Job 4: Deploy to DEV deploy-dev: name: Deploy to DEV needs: [unit-tests, atc-checks] runs-on: ubuntu-latest if: github.ref == 'refs/heads/develop' environment: development
steps: - name: Pull to DEV System via gCTS run: | curl -X POST \ "${{ secrets.DEV_ENDPOINT }}/sap/bc/cts_abapvcs/repository/${{ vars.GCTS_REPO }}/pull" \ -u "${{ secrets.DEPLOY_USER }}:${{ secrets.DEPLOY_PASSWORD }}" \ -H "Content-Type: application/json" \ -d '{"branch": "develop"}' echo "✅ Deployed to DEV"
# Job 5: Deploy to QAS deploy-qas: name: Deploy to QAS needs: [unit-tests, atc-checks] runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' environment: quality-assurance
steps: - name: Pull to QAS System via gCTS run: | curl -X POST \ "${{ secrets.QAS_ENDPOINT }}/sap/bc/cts_abapvcs/repository/${{ vars.GCTS_REPO }}/pull" \ -u "${{ secrets.DEPLOY_USER }}:${{ secrets.DEPLOY_PASSWORD }}" \ -H "Content-Type: application/json" \ -d '{"branch": "main"}' echo "✅ Deployed to QAS"
# Job 6: Deploy to PRD (Manual Approval) deploy-prd: name: Deploy to PRD needs: deploy-qas runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' && github.event_name == 'workflow_dispatch' environment: production
steps: - name: Pull to PRD System via gCTS run: | curl -X POST \ "${{ secrets.PRD_ENDPOINT }}/sap/bc/cts_abapvcs/repository/${{ vars.GCTS_REPO }}/pull" \ -u "${{ secrets.DEPLOY_USER }}:${{ secrets.DEPLOY_PASSWORD }}" \ -H "Content-Type: application/json" \ -d '{"branch": "main", "tag": "${{ github.sha }}"}' echo "✅ Deployed to PRD"Azure DevOps Pipeline Alternative
Für Microsoft-Umgebungen bietet Azure DevOps eine hervorragende Alternative:
trigger: branches: include: - main - develop
pool: vmImage: 'ubuntu-latest'
variables: ABAP_PACKAGE: 'Z_MY_PACKAGE' ATC_VARIANT: 'Z_CI_CHECKS'
stages: - stage: Test displayName: 'Test Stage' jobs: - job: ABAPUnitTests displayName: 'ABAP Unit Tests' steps: - script: | curl -X POST \ "$(ABAP_ENDPOINT)/sap/bc/adt/abapunit/testruns" \ -u "$(ABAP_USER):$(ABAP_PASSWORD)" \ -H "Content-Type: application/vnd.sap.adt.abapunit.testruns.config.v4+xml" \ -d '<aunit:runConfiguration xmlns:aunit="http://www.sap.com/adt/aunit"> <options><uriType value="semantic"/></options> </aunit:runConfiguration>' \ --fail displayName: 'Run ABAP Unit Tests'
- job: ATCChecks displayName: 'ATC Quality Checks' steps: - script: | curl -X POST \ "$(ABAP_ENDPOINT)/sap/bc/adt/atc/runs" \ -u "$(ABAP_USER):$(ABAP_PASSWORD)" \ -H "Content-Type: application/vnd.sap.atc.run.parameters.v1+xml" \ --fail displayName: 'Run ATC Checks'
- stage: DeployDev displayName: 'Deploy to DEV' dependsOn: Test condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/develop')) jobs: - deployment: DeployDEV environment: 'development' strategy: runOnce: deploy: steps: - script: | curl -X POST \ "$(DEV_ENDPOINT)/sap/bc/cts_abapvcs/repository/$(GCTS_REPO)/pull" \ -u "$(DEPLOY_USER):$(DEPLOY_PASSWORD)" \ -d '{"branch": "develop"}' displayName: 'gCTS Pull to DEV'
- stage: DeployQAS displayName: 'Deploy to QAS' dependsOn: Test condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main')) jobs: - deployment: DeployQAS environment: 'quality-assurance' strategy: runOnce: deploy: steps: - script: | curl -X POST \ "$(QAS_ENDPOINT)/sap/bc/cts_abapvcs/repository/$(GCTS_REPO)/pull" \ -u "$(DEPLOY_USER):$(DEPLOY_PASSWORD)" \ -d '{"branch": "main"}' displayName: 'gCTS Pull to QAS'Automatisierte Tests einbinden
ABAP Unit Test Klasse für CI/CD
CLASS zcl_customer_test DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT.
PRIVATE SECTION. CLASS-DATA: mo_environment TYPE REF TO if_cds_test_environment.
CLASS-METHODS: class_setup, class_teardown.
METHODS: setup, teardown, test_create_customer_success FOR TESTING, test_create_customer_invalid_email FOR TESTING, test_update_customer_status FOR TESTING.ENDCLASS.
CLASS zcl_customer_test IMPLEMENTATION. METHOD class_setup. " CDS Test Double Framework für isolierte Tests mo_environment = cl_cds_test_environment=>create_for_multiple_cds( VALUE #( ( i_for_entity = 'ZI_CUSTOMER' ) ( i_for_entity = 'ZI_ORDER' ) ) ). ENDMETHOD.
METHOD class_teardown. mo_environment->destroy( ). ENDMETHOD.
METHOD setup. mo_environment->clear_doubles( ). " Mock-Daten einfügen DATA(lt_customers) = VALUE zt_customer_t( ). mo_environment->insert_test_data( lt_customers ). ENDMETHOD.
METHOD teardown. ROLLBACK WORK. ENDMETHOD.
METHOD test_create_customer_success. " Given DATA(lo_cut) = NEW zcl_customer_service( ). DATA(ls_input) = VALUE zs_customer_create( name = 'New Customer' ).
" When DATA(ls_result) = lo_cut->create_customer( ls_input ).
" Then cl_abap_unit_assert=>assert_not_initial( act = ls_result-customer_id msg = 'Customer ID should be generated' ). ENDMETHOD.
METHOD test_create_customer_invalid_email. " Given DATA(lo_cut) = NEW zcl_customer_service( ). DATA(ls_input) = VALUE zs_customer_create( name = 'Invalid Customer' email = 'not-an-email' ).
" When / Then TRY. lo_cut->create_customer( ls_input ). cl_abap_unit_assert=>fail( 'Exception expected' ). CATCH zcx_customer_error INTO DATA(lx_error). cl_abap_unit_assert=>assert_equals( act = lx_error->error_code exp = 'INVALID_EMAIL' ). ENDTRY. ENDMETHOD.
METHOD test_update_customer_status. " Given DATA(lo_cut) = NEW zcl_customer_service( ).
" When lo_cut->set_customer_status( iv_customer_id = '1' iv_status = 'I' ).
" Then DATA(ls_customer) = lo_cut->get_customer( '1' ). cl_abap_unit_assert=>assert_equals( act = ls_customer-status exp = 'I' msg = 'Status should be updated' ). ENDMETHOD.ENDCLASS.Test-Annotations für CI/CD-Reporting
"! <p class="shorttext">Customer Service Test Coverage</p>"! @testing ZCL_CUSTOMER_SERVICECLASS zcl_customer_test DEFINITION FOR TESTING RISK LEVEL HARMLESS " Wichtig: HARMLESS für CI/CD DURATION SHORT. " Wichtig: SHORT für schnelle PipelinesCode Quality Checks: ATC-Variante für CI/CD
Custom ATC-Variante erstellen
Erstelle eine eigene ATC-Variante für CI/CD-Prüfungen:
┌────────────────────────────────────────────────────────────────┐│ ATC Check Variant: Z_CICD_CHECKS │├────────────────────────────────────────────────────────────────┤│ ││ Priority 1 (Blocker - Pipeline fails): ││ ☑ Syntax Errors ││ ☑ Security Vulnerabilities (SQL Injection, XSS) ││ ☑ Performance Critical (SELECT without WHERE) ││ ☑ Obsolete Statements (not cloud-ready) ││ ││ Priority 2 (Warning - Report only): ││ ☑ Naming Conventions ││ ☑ Code Style ││ ☑ Missing Documentation ││ ☑ Unused Variables ││ ││ Priority 3 (Info - Ignored in CI/CD): ││ ☐ Spelling Suggestions ││ ☐ Refactoring Opportunities ││ ││ Exemptions: ││ - Test Classes (RISK LEVEL, DURATION checks) ││ - Generated Code (SICF handlers) │└────────────────────────────────────────────────────────────────┘ATC-Exemption im Code
METHOD call_legacy_function. " ATC Exemption für bewusst genutzten Legacy-Code "#EC CI_NOCHECK - Legacy-Integration, Migration geplant Q3 CALL FUNCTION 'Z_LEGACY_FUNCTION' EXPORTING iv_input = mv_input.ENDMETHOD.Branching-Strategie für ABAP
Empfohlenes GitFlow-Modell
main (Production)│├── release/1.0 ────────────────────────────► PRD│ │├── develop ─────────────────────────────────► QAS│ ││ ├── feature/US-001-kunde-anlegen ────────► DEV│ │ ││ │ └── Merge via Pull Request│ ││ └── feature/US-002-material-suche ───────► DEV│└── hotfix/fix-calculation ──────────────────► Merge to main & developBranch-Regeln
| Branch | Zweck | Deployment |
|---|---|---|
main | Stabile, getestete Releases | PRD |
develop | Integration aller Features | QAS |
feature/* | Ein Branch pro User Story | DEV |
bugfix/* | Schnelle Fehlerbehebungen | DEV |
release/* | Release-Kandidaten | QAS → PRD |
hotfix/* | Kritische Produktionsfixes | PRD (direkt) |
Notifications und Reporting
Slack-Integration in GitHub Actions
# Am Ende der Pipeline hinzufügen- name: Notify Slack on Failure if: failure() uses: slackapi/slack-github-action@v1 with: channel-id: 'C01234567' slack-message: | :x: *ABAP Pipeline Failed* Repository: ${{ github.repository }} Branch: ${{ github.ref_name }} Commit: ${{ github.sha }} <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Details> env: SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
- name: Notify Slack on Success if: success() uses: slackapi/slack-github-action@v1 with: channel-id: 'C01234567' slack-message: | :white_check_mark: *ABAP Pipeline Successful* Repository: ${{ github.repository }} Deployed to: ${{ matrix.environment }} env: SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}Troubleshooting
Häufige Probleme und Lösungen
| Problem | Ursache | Lösung |
|---|---|---|
| SSL-Zertifikat-Fehler | Zertifikat fehlt in STRUST | Zertifikat importieren |
| 401 Unauthorized | Token-Berechtigungen | Token mit repo Scope erstellen |
| Merge-Konflikte | Gleichzeitige Änderungen | Im Git-Repository auflösen, dann Pull |
| Objekt-Sperren | Benutzer hat Sperre | SM12: Sperre freigeben |
| ATC Timeout | Zu viele Objekte | Paket aufteilen oder Timeout erhöhen |
Logs abrufen
METHOD get_repository_logs. DATA(lo_client) = create_gcts_client( ).
DATA(lo_request) = lo_client->get_http_request( ). lo_request->set_uri_path( |/sap/bc/cts_abapvcs/repository/{ iv_repository }/log| ).
DATA(lo_response) = lo_client->execute( if_web_http_client=>get ).
IF lo_response->get_status( )-code = 200. rv_logs = lo_response->get_text( ). ENDIF.
lo_client->close( ).ENDMETHOD.Best Practices Zusammenfassung
| Thema | Empfehlung |
|---|---|
| Test-Isolation | CDS Test Environment für Unit Tests |
| Test-Daten | Mock-Daten in Setup-Methoden |
| ATC-Variante | Eigene CI/CD-Variante mit sinnvollen Checks |
| Secrets | GitHub Secrets / Azure Key Vault nutzen |
| Parallelisierung | Unabhängige Jobs parallel ausführen |
| Environments | GitHub Environments für Approval-Workflows |
| Commit-Messages | Konventionelle Commits (feat:, fix:, etc.) |
| Code Review | Pull Requests vor jedem Merge |
| Tagging | Releases mit semantischer Versionierung |
| Monitoring | Slack/Teams-Integration für Benachrichtigungen |
Fazit
gCTS und CI/CD transformieren die ABAP-Entwicklung von manuellen Transportprozessen zu automatisierten DevOps-Workflows:
- gCTS ermöglicht Git-basiertes Transport-Management mit vollständiger Historie und Branching
- CI/CD-Pipelines automatisieren Tests, Qualitätsprüfungen und Deployments
- ABAP Unit Tests in der Pipeline sichern die Code-Qualität bei jedem Commit
- ATC Checks verhindern, dass Sicherheitslücken oder Performance-Probleme in Produktion gelangen
Nächste Schritte:
- ✅ gCTS-Repository für dein ABAP-Projekt einrichten
- ✅ GitHub Actions oder Azure DevOps Pipeline konfigurieren
- ✅ ABAP Unit Tests für kritische Businesslogik schreiben
- ✅ Custom ATC-Variante für CI/CD erstellen
- ✅ Team in Git-Workflows schulen
Weiterführende Artikel
- abapGit Tutorial - Versionskontrolle für Entwickler
- gCTS: Git-enabled CTS - Detaillierte gCTS-Referenz
- CI/CD mit ABAP Cloud - Erweiterte Pipeline-Konfigurationen
- ABAP Unit Testing - Testgetriebene Entwicklung
- Clean ABAP: Regeln und Best Practices - Code-Qualität