Pipeline-Automatisierung bei geforkten Repository-Umgebungen


Bicycle

Einführung

Wenn sich euer Team für das Forked-Repo-Modell entschieden hat – entweder zur maximalen Isolierung oder aus regulatorischen/zugriffsbedingten Gründen – hat eure CI/CD-Strategie besondere Anforderungen. In diesem Artikel zeigen wir, wie man Deployment-Pipelines einrichtet und automatisiert, wenn jede Umgebung ein eigens dafür vorgesehenes geforktes Repository ist.


Rückblick: Forked Repo

  • Modell: Jede Umgebung (dev, staging, prod) ist ein geforktes Repository.
  • Promotion: Code wandert per Pull-/Merge-Requests zwischen Repositories.
  • Jedes Repository hat eine isolierte Konfiguration, eigene Historie, Secrets und Berechtigungen.


Prinzipien für die Pipeline

  • Jedes Repository verwaltet seine eigene CI/CD-Pipeline, die nur auf main für seine jeweilige Umgebung deployt.
  • Promotionen können manuell oder automatisiert per PR-Erstellung über Repos hinweg (mit Bots oder Skripten) erfolgen.
  • Sync-/Promotions-Workflows sind die größte Herausforderung.

Promotion automatisieren

  • Entwickler erstellen PRs von myapp-devmyapp-stagingmyapp-prod.
  • Optional können Bots/Skripte die PR-Erstellung in den nachfolgenden Forks nach Genehmigungen automatisieren.

Beispiel: GitHub Actions in geforkten Repositories

In jedem Repository (myapp-dev, myapp-staging, myapp-prod):

 1# .github/workflows/deploy.yml
 2name: Deploy
 3
 4on:
 5  push:
 6    branches: [main]
 7
 8jobs:
 9  deploy:
10    runs-on: ubuntu-latest
11    steps:
12      - uses: actions/checkout@v3
13      - run: ./deploy.sh $ENV_NAME
  • $ENV_NAME kann in den Repository-Secrets oder CI-Umgebungsvariablen definiert werden.

Beispiel: GitLab CI/CD

1stages:
2    - deploy
3
4deploy:
5    stage: deploy
6    script:
7    - ./deploy $ENV_NAME

Beispiel: GitLab Multi-Project Pipeline Automation

Ein sogenanntes „Downstream-Pipeline“-Setup in myapp-dev kann einen Merge-Request in myapp-staging erstellen:

 1on:
 2  workflow_run:
 3    workflows: ["Deploy"]
 4    types:
 5      - completed
 6
 7jobs:
 8    promote:
 9        env:
10            DOWNSTREAM_REPOSITORY: myapp-staging
11            TARGET_BRANCH: main
12        steps:
13        - run: |
14
15            git config --global "user.name" "Machine"
16            git config --global "user.email" "machine@infralovers.com"
17
18            export GIT_COMMIT_DATE=$(git log -1 --format=%cd --date=format:%Y%m%dh%H%M%S)
19            export GIT_COMMIT_MSG=$(git log -1  --format=%s)
20            export BRANCH_NAME="${GITHUB_REPOSITORY}-update-${GIT_COMMIT_DATE}"
21
22            git fetch -v origin
23            git remote add downstream https://x-token-auth:${GH_TOKEN}@${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY_OWNER}/${DOWNSTREAM_REPOSITORY}
24            git fetch -v downstream
25            git checkout -b "${BRANCH_NAME}" "downstream/${TARGET_BRANCH}"
26            git config merge.ours.driver true
27            git merge origin/main --no-commit
28            git reset HEAD CHANGELOG.md .github
29            git checkout -- CHANGELOG.md .github
30            git status --short
31            export CI_COMMIT_PREFIX=$(echo $GIT_COMMIT_MSG | sed -E "s/(.*):.*/\1/")
32            git commit -m "${CI_COMMIT_PREFIX}:automatic update ${GITHUB_REPOSITORY}
33                        $GIT_COMMIT_MSG"
34            git push -u downstream "${BRANCH_NAME}"
35
36            gh pr create --repo "${GITHUB_REPOSITORY_OWNER}/${DOWNSTREAM_REPOSITORY}"
37                        --title "${CI_COMMIT_PREFIX}:automatic update from ${GITHUB_REPOSITORY}"
38                        --head "${BRANCH_NAME}"
39                        --base "${TARGET_BRANCH}"
 1# In .gitlab-ci.yml von myapp-dev
 2stages:
 3  - deploy
 4  - promote
 5
 6promote_staging:
 7  stage: promote
 8  image: python:3-alpine
 9  variables:
10    DOWNSTREAM_REPOSITORY: myapp-staging
11    TARGET_BRANCH: main
12  rules:
13    - if: '$CI_COMMIT_BRANCH == "main"'
14  before_script:
15    - apk add --no-cache git
16    - git config --global "user.name" "Machine"
17    - git config --global "user.email" "machine@infralovers.com"
18  script:
19    - export BRANCH_NAME="${CI_PROJECT_NAME}-update-${CI_COMMIT_TIMESTAMP}"
20    - git fetch -v origin
21    - git remote add downstream https://gitlab-ci-token:${GL_TOKEN}@${CI_SERVER_HOST}/$DOWNSTREAM_REPOSITORY
22    - git fetch -v downstream
23    - git checkout -b "${BRANCH_NAME}" "downstream/${TARGET_BRANCH}"
24    - git config merge.ours.driver true
25    - git merge origin/main --no-commit
26    - git reset HEAD CHANGELOG.md .gitlab-ci.yml
27    - git checkout -- CHANGELOG.md .gitlab-ci.yml
28    - git status --short
29    - export CI_COMMIT_PREFIX=$(echo $CI_COMMIT_TITLE | sed -E "s/(.*):.*/\1/")
30    - git commit -m "${CI_COMMIT_PREFIX}:automatic update ${CI_PROJECT_NAME}
31                      $CI_COMMIT_MESSAGE"
32    - git push -u downstream
33               -o merge_request.create
34               -o merge_request.target="${TARGET_BRANCH}"
35               -o merge_request.title="${CI_COMMIT_PREFIX}:automatic update from ${CI_PROJECT_NAME}"
36               -o merge_request.description="automatic update from ${CI_PROJECT_NAME}"
37               -o merge_request.remove_source_branch
38               "${BRANCH_NAME}"

Stolperfallen & Best Practices

  • Fragmentierte Historie: Promotions-PRs sorgfältig nachverfolgen.
  • Duplizierte Konfiguration: CI/CD-Dateien und Deployment-Logik konsistent in allen Repositories halten.
  • So viel wie möglich automatisieren: Manuelle Promotionen sind langsam und fehleranfällig.
  • Audits und Rollbacks: Cross-Repo-PRs sollten immer per Code-Review geprüft und für Compliance-Zwecke protokolliert werden.

Fazit

Geforkte Repositories mit separierten Umgebungen bieten starke Sicherheitsvorteile, erfordern aber durchdachte und oft individuelle Pipeline-Automatisierung. Wenn der Bedarf stärker in Richtung Geschwindigkeit und Vereinfachung geht, empfiehlt sich der Umstieg auf ein Trunk-Based-Modell – mehr dazu im nächsten Teil dieser Serie.


Zurück Unsere Trainings entdecken

Wir sind für Sie da

Sie interessieren sich für unsere Trainings oder haben einfach eine Frage, die beantwortet werden muss? Sie können uns jederzeit kontaktieren! Wir werden unser Bestes tun, um alle Ihre Fragen zu beantworten.

Hier kontaktieren