gCTS (Git-enabled Change and Transport System) revolutioniert das Transport-Management in SAP ABAP, indem es Git als zentrales Versionskontrollsystem nutzt. Damit werden moderne DevOps-Praktiken wie Branching, Pull Requests und CI/CD auch für ABAP-Entwicklung möglich.
Was ist gCTS?
gCTS verbindet das klassische SAP Transport-System mit Git-Repositories. Statt Transportaufträge zwischen Systemen zu verschieben, werden ABAP-Objekte als Dateien in Git gespeichert und über Git-Operationen synchronisiert.
| Aspekt | Klassisches CTS | gCTS |
|---|---|---|
| Versionierung | Transportaufträge | Git-Commits |
| Branching | Nicht möglich | Vollständiges Branching |
| Vergleich | Eingeschränkt | Diff zwischen Commits/Branches |
| 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 |
Architektur-Übersicht
┌─────────────────────────────────────────────────────────────────────┐│ Entwicklungslandschaft ││ ││ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ││ │ DEV │ │ QAS │ │ PRD │ ││ │ System │ │ System │ │ System │ ││ │ │ │ │ │ │ ││ │ ┌───────┐ │ │ ┌───────┐ │ │ ┌───────┐ │ ││ │ │ gCTS │ │ │ │ gCTS │ │ │ │ gCTS │ │ ││ │ │Client │ │ │ │Client │ │ │ │Client │ │ ││ │ └───┬───┘ │ │ └───┬───┘ │ │ └───┬───┘ │ ││ └──────│──────┘ └──────│──────┘ └──────│──────┘ ││ │ │ │ ││ └─────────┬────────┴────────┬─────────┘ ││ │ │ ││ Push │ │ Pull ││ ▼ ▼ ││ ┌───────────────────────────────┐ ││ │ Git Repository │ ││ │ (GitHub / GitLab / etc.) │ ││ │ │ ││ │ main ─────┬──────────────── │ ││ │ │ │ ││ │ feature/* ┴── branch ── │ ││ │ │ ││ └───────────────────────────────┘ │└─────────────────────────────────────────────────────────────────────┘Vorteile von gCTS
Entwickler-Perspektive
- Feature Branches: Isolierte Entwicklung neuer Features
- Pull Requests: Code Review vor der Integration
- Git-Historie: Vollständige Nachvollziehbarkeit aller Änderungen
- Vergleiche: Einfache Diffs zwischen Versionen
- Lokale Tools: Nutzung von VS Code, Git-Clients, etc.
Operations-Perspektive
- Automatisierung: CI/CD-Pipelines für Tests und Deployments
- Rollback: Einfaches Zurücksetzen auf frühere Versionen
- Branching-Strategien: GitFlow, Trunk-based Development
- Compliance: Audit-Trail durch Git-Historie
- Multi-System: Konsistente Deployments über Systemlandschaften
Setup und Konfiguration
Voraussetzungen
- SAP S/4HANA oder SAP BTP ABAP Environment
- Git-Repository (GitHub, GitLab, Azure DevOps, Bitbucket)
- SSL-Zertifikate für Git-Server
- Berechtigungen: S_CTS_ADMI, S_CTS_SADM
1. SSL-Zertifikate importieren
Zuerst müssen die SSL-Zertifikate des Git-Servers importiert werden:
Transaktion: STRUST
1. SSL Client (Standard) öffnen2. Zertifikat importieren: - GitHub: github.com - GitLab: gitlab.com (oder eigene Domain)3. Zertifikatsliste aktualisieren4. Speichern2. gCTS-Repository anlegen
In der Transaktion SE80 oder GCTS_MAINT (Fiori App):
┌──────────────────────────────────────────────────────────────┐│ Repository Configuration │├──────────────────────────────────────────────────────────────┤│ ││ Repository Name: Z_MY_PROJECT ││ Remote URL: https://github.com/company/my-project.git││ Branch: main ││ ││ Authentication: ││ ○ Basic Authentication ││ ● Token-based (recommended) ││ ││ Username: github-service-user ││ Token: ghp_xxxxxxxxxxxx ││ ││ vSID (Virtual System ID): DEV ││ │└──────────────────────────────────────────────────────────────┘3. Repository API-Aufruf
gCTS kann auch über die REST-API konfiguriert werden:
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 ).
" Request Body erstellen 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. " Error handling DATA(lv_error) = lo_response->get_text( ). RAISE EXCEPTION TYPE cx_web_http_client_error. ENDIF.
lo_client->close( ). ENDMETHOD.ENDCLASS.4. ABAP-Paket mit Repository verknüpfen
" Paket Z_MY_PACKAGE mit gCTS-Repository verbinden" Dies erfolgt in SE80 oder über die API
DATA: BEGIN OF ls_link, package TYPE devclass VALUE 'Z_MY_PACKAGE', repository TYPE string VALUE 'Z_MY_PROJECT', END OF ls_link.Git-Workflow mit gCTS
Commit erstellen
Nach Änderungen an ABAP-Objekten können diese committed werden:
┌──────────────────────────────────────────────────────────────┐│ Commit Dialog │├──────────────────────────────────────────────────────────────┤│ ││ Changed Objects: ││ ☑ ZCL_CUSTOMER_SERVICE (Class) ││ ☑ ZI_CUSTOMER (CDS View) ││ ☑ ZC_CUSTOMER (CDS Projection) ││ ☐ ZCL_TEST_HELPER (Class) ││ ││ Commit Message: ││ ┌────────────────────────────────────────────────────────┐ ││ │ feat: Customer API erweitert │ ││ │ │ ││ │ - Neue Methode get_customer_orders hinzugefügt │ ││ │ - CDS View um Orderhistory-Assoziation erweitert │ ││ │ - Unit Tests ergänzt │ ││ └────────────────────────────────────────────────────────┘ ││ ││ [ Commit ] [ Commit & Push ] [ Cancel ] ││ │└──────────────────────────────────────────────────────────────┘Push, Pull und Checkout
Push - Lokale Commits zum Remote-Repository übertragen:
METHOD push_changes. " gCTS REST-API aufrufen DATA(lo_client) = create_gcts_client( ).
DATA(lo_request) = lo_client->get_http_request( ). lo_request->set_uri_path( |/sap/bc/cts_abapvcs/repository/{ mv_repository }/push| ).
DATA(lo_response) = lo_client->execute( if_web_http_client=>post ).
IF lo_response->get_status( )-code = 200. " Push erfolgreich DATA(lv_result) = lo_response->get_text( ). ENDIF.
lo_client->close( ).ENDMETHOD.Pull - Änderungen vom Remote-Repository holen:
METHOD pull_changes. DATA(lo_client) = create_gcts_client( ).
DATA(lo_request) = lo_client->get_http_request( ). lo_request->set_uri_path( |/sap/bc/cts_abapvcs/repository/{ mv_repository }/pull| ).
DATA(lo_response) = lo_client->execute( if_web_http_client=>post ).
IF lo_response->get_status( )-code = 200. " Pull erfolgreich - ABAP-Objekte werden aktualisiert ENDIF.
lo_client->close( ).ENDMETHOD.Branch wechseln (Checkout):
METHOD checkout_branch. DATA(lo_client) = create_gcts_client( ).
DATA: BEGIN OF ls_request, branch TYPE string, END OF ls_request. ls_request-branch = iv_branch_name.
DATA(lv_json) = /ui2/cl_json=>serialize( data = ls_request compress = abap_true ).
DATA(lo_request) = lo_client->get_http_request( ). lo_request->set_uri_path( |/sap/bc/cts_abapvcs/repository/{ mv_repository }/checkout| ). 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 ). lo_client->close( ).ENDMETHOD.Branching-Strategien
GitFlow für ABAP
main (Production)│├── release/1.0 ────────────────────────────► PRD│ │├── develop ─────────────────────────────────► QAS│ ││ ├── feature/customer-api ────────────────► DEV│ │ ││ │ └── Merge via Pull Request│ ││ └── feature/order-workflow ──────────────► DEV│└── hotfix/fix-calculation ──────────────────► Merge to main & developTrunk-based Development
main│├── commit A ────► Auto-Deploy DEV├── commit B ────► Auto-Deploy DEV├── commit C ────► Auto-Deploy DEV│└── Release Tag v1.0 ────► Deploy QAS ────► Deploy PRDFeature-Branch-Workflow
Typischer Workflow für ein Feature:
# 1. Feature-Branch erstellen (in gCTS UI oder API)Branch: feature/new-customer-api
# 2. Entwicklung im DEV-System# - Code ändern# - Tests schreiben# - Commits erstellen
# 3. Push zum Remotegit push origin feature/new-customer-api
# 4. Pull Request erstellen (GitHub/GitLab)# - Code Review# - CI/CD Tests# - Approval
# 5. Merge in develop/main# - Automatisch oder manuell
# 6. Pull in QAS/PRD-System# - gCTS Pull-Operation# - Objekte werden aktualisiertIntegration mit GitHub/GitLab
GitHub Actions für ABAP
Erstelle eine Pipeline für automatisierte Tests:
name: ABAP CI/CD
on: push: branches: [ main, develop ] pull_request: branches: [ main, develop ]
jobs: abap-unit-tests: runs-on: ubuntu-latest
steps: - uses: actions/checkout@v4
- name: Run ABAP Unit Tests uses: sap/abap-ci-action@v1 with: abap-endpoint: ${{ secrets.ABAP_ENDPOINT }} username: ${{ secrets.ABAP_USER }} password: ${{ secrets.ABAP_PASSWORD }} packages: 'Z_MY_PACKAGE'
- name: Run ATC Checks uses: sap/abap-atc-action@v1 with: abap-endpoint: ${{ secrets.ABAP_ENDPOINT }} username: ${{ secrets.ABAP_USER }} password: ${{ secrets.ABAP_PASSWORD }} packages: 'Z_MY_PACKAGE' variant: 'Z_CI_CHECKS'
- name: Deploy to QAS if: github.ref == 'refs/heads/main' run: | curl -X POST \ "${{ secrets.QAS_ENDPOINT }}/sap/bc/cts_abapvcs/repository/Z_MY_PROJECT/pull" \ -u "${{ secrets.ABAP_USER }}:${{ secrets.ABAP_PASSWORD }}"GitLab CI/CD für ABAP
stages: - test - deploy
variables: ABAP_PACKAGE: "Z_MY_PACKAGE"
abap-unit-tests: stage: test image: node:18 script: - npm install @sap/abap-ci - npx abap-unit-test --endpoint $ABAP_ENDPOINT --package $ABAP_PACKAGE only: - merge_requests - main
atc-checks: stage: test image: node:18 script: - npm install @sap/abap-ci - npx abap-atc --endpoint $ABAP_ENDPOINT --package $ABAP_PACKAGE --variant Z_CI_CHECKS only: - merge_requests - main
deploy-qas: stage: deploy script: - | curl -X POST \ "$QAS_ENDPOINT/sap/bc/cts_abapvcs/repository/Z_MY_PROJECT/pull" \ -u "$DEPLOY_USER:$DEPLOY_PASSWORD" only: - main when: manual
deploy-prd: stage: deploy script: - | curl -X POST \ "$PRD_ENDPOINT/sap/bc/cts_abapvcs/repository/Z_MY_PROJECT/pull" \ -u "$DEPLOY_USER:$DEPLOY_PASSWORD" \ -H "Content-Type: application/json" \ -d '{"branch": "main", "tag": "'"$CI_COMMIT_TAG"'"}' only: - tags when: manualWebhook-Integration
Automatische Synchronisation bei Push-Events:
CLASS zcl_gcts_webhook_handler DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. INTERFACES if_http_service_extension.ENDCLASS.
CLASS zcl_gcts_webhook_handler IMPLEMENTATION. METHOD if_http_service_extension~handle_request. " GitHub Webhook Payload verarbeiten DATA(lv_payload) = request->get_text( ). DATA(lv_event) = request->get_header_field( 'X-GitHub-Event' ).
CASE lv_event. WHEN 'push'. " Push-Event verarbeiten DATA: BEGIN OF ls_push, ref TYPE string, repository TYPE string, END OF ls_push.
/ui2/cl_json=>deserialize( EXPORTING json = lv_payload CHANGING data = ls_push ).
" Bei Push auf main: Pull ausführen IF ls_push-ref = 'refs/heads/main'. DATA(lo_gcts) = NEW zcl_gcts_client( ). lo_gcts->pull_repository( 'Z_MY_PROJECT' ). ENDIF.
WHEN 'pull_request'. " Pull Request Event (z.B. für Notifications)
ENDCASE.
response->set_status( 200 ). response->set_text( '{"status": "processed"}' ). ENDMETHOD.ENDCLASS.Vergleich: gCTS vs. abapGit
| Feature | gCTS | abapGit |
|---|---|---|
| SAP-Support | Offiziell von SAP | Community-Projekt |
| Integration | Native ins CTS | Standalone Tool |
| Transport-Objekte | Vollständig unterstützt | Einige Einschränkungen |
| Systemlandschaft | Integriert | Separates Management |
| Open Source | Nein | Ja |
| Flexibilität | Standard-Workflows | Hochgradig anpassbar |
| Setup | Komplex | Einfacher |
| Lernkurve | Steiler | Flacher |
Empfehlung:
- gCTS: Für produktive Systemlandschaften mit Enterprise-Support-Anforderungen
- abapGit: Für Open-Source-Projekte, Prototypen oder wenn maximale Flexibilität benötigt wird
Troubleshooting
Häufige Probleme
SSL-Zertifikat-Fehler:
Fehler: SSL certificate verification failedLösung: Zertifikat in STRUST importieren (siehe Setup)Authentifizierungsfehler:
Fehler: 401 UnauthorizedLösung:- Token-Berechtigungen prüfen (repo, write:packages)- Username/Token in gCTS-Konfiguration aktualisierenMerge-Konflikte:
Fehler: Cannot pull - conflicts detectedLösung:1. Konflikte im Git-Repository auflösen2. Erneut Pull ausführen3. Ggf. lokale Änderungen verwerfen und neu pullenObjekt-Sperren:
Fehler: Object is locked by another userLösung:1. Sperre in SM12 prüfen/freigeben2. Pull erneut ausführenLogs und Diagnose
" gCTS Logs abrufenMETHOD 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
| Thema | Empfehlung |
|---|---|
| Commit-Messages | Konventionelle Commits nutzen (feat:, fix:, docs:, etc.) |
| Branching | Feature-Branches für isolierte Entwicklung |
| Code Review | Pull Requests mit mindestens einem Reviewer |
| CI/CD | Automatisierte Tests vor jedem Merge |
| Tagging | Releases mit semantischer Versionierung taggen |
| Dokumentation | README.md und CHANGELOG.md pflegen |
| Secrets | Tokens und Passwörter in Secrets verwalten |
| Backup | Git-Repository ist das Backup - regelmäßig pullen |
| Schulung | Team in Git-Grundlagen schulen |
| Migration | Schrittweise von CTS zu gCTS migrieren |
Weiterführende Themen
- CI/CD mit ABAP Cloud - Automatisierte Pipelines
- ABAP Cleaner - Code-Qualität automatisieren
- ADT Tipps & Tricks - Effiziente Entwicklung