gCTS: Git-enabled Change and Transport System

kategorie
DevOps
Veröffentlicht
autor
Johannes

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.

AspektKlassisches CTSgCTS
VersionierungTransportaufträgeGit-Commits
BranchingNicht möglichVollständiges Branching
VergleichEingeschränktDiff zwischen Commits/Branches
CollaborationLimitiertPull Requests, Code Review
HistoryTransportlogsVollständige Git-Historie
RollbackManuellGit Revert/Reset
CI/CDSchwierigNative Integration
ToolingSAP-spezifischStandard 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) öffnen
2. Zertifikat importieren:
- GitHub: github.com
- GitLab: gitlab.com (oder eigene Domain)
3. Zertifikatsliste aktualisieren
4. Speichern

2. 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 & develop

Trunk-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 PRD

Feature-Branch-Workflow

Typischer Workflow für ein Feature:

Terminal window
# 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 Remote
git 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 aktualisiert

Integration mit GitHub/GitLab

GitHub Actions für ABAP

Erstelle eine Pipeline für automatisierte Tests:

.github/workflows/abap-ci.yml
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

.gitlab-ci.yml
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: manual

Webhook-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

FeaturegCTSabapGit
SAP-SupportOffiziell von SAPCommunity-Projekt
IntegrationNative ins CTSStandalone Tool
Transport-ObjekteVollständig unterstütztEinige Einschränkungen
SystemlandschaftIntegriertSeparates Management
Open SourceNeinJa
FlexibilitätStandard-WorkflowsHochgradig anpassbar
SetupKomplexEinfacher
LernkurveSteilerFlacher

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 failed
Lösung: Zertifikat in STRUST importieren (siehe Setup)

Authentifizierungsfehler:

Fehler: 401 Unauthorized
Lösung:
- Token-Berechtigungen prüfen (repo, write:packages)
- Username/Token in gCTS-Konfiguration aktualisieren

Merge-Konflikte:

Fehler: Cannot pull - conflicts detected
Lösung:
1. Konflikte im Git-Repository auflösen
2. Erneut Pull ausführen
3. Ggf. lokale Änderungen verwerfen und neu pullen

Objekt-Sperren:

Fehler: Object is locked by another user
Lösung:
1. Sperre in SM12 prüfen/freigeben
2. Pull erneut ausführen

Logs und Diagnose

" gCTS 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

ThemaEmpfehlung
Commit-MessagesKonventionelle Commits nutzen (feat:, fix:, docs:, etc.)
BranchingFeature-Branches für isolierte Entwicklung
Code ReviewPull Requests mit mindestens einem Reviewer
CI/CDAutomatisierte Tests vor jedem Merge
TaggingReleases mit semantischer Versionierung taggen
DokumentationREADME.md und CHANGELOG.md pflegen
SecretsTokens und Passwörter in Secrets verwalten
BackupGit-Repository ist das Backup - regelmäßig pullen
SchulungTeam in Git-Grundlagen schulen
MigrationSchrittweise von CTS zu gCTS migrieren

Weiterführende Themen