Pipeline Automation for Forked Repository Environment Management
Introduction If your team chose the forked repo model for maximum isolation—or due to regulatory/access concerns—your CI/CD strategy has special requirements.
If your team chose the forked repo model for maximum isolation—or due to regulatory/access concerns—your CI/CD strategy has special requirements. This article shows how to set up and automate deployment pipelines when each environment is a special-purpose repo fork.
dev
, staging
, prod
) is a forked repository.main
.myapp-dev
→ myapp-staging
→ myapp-prod
.In each repo (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
could be set in repo secrets or CI environment variables.1stages:
2 - deploy
3
4deploy:
5 stage: deploy
6 script:
7 - ./deploy $ENV_NAME
You can have a “downstream pipeline” in myapp-dev
creating a pull/merge-request in myapp-staging
:
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 of 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}"
Forked repos with separated environments are powerful for security but require thoughtful, often custom pipeline automation. If your needs shift toward speed and simplification, consider moving toward a trunk-based model within the next article in this series.
You are interested in our courses or you simply have a question that needs answering? You can contact us at anytime! We will do our best to answer all your questions.
Contact us