diff --git a/examples/gitlab-ci/push-solution.yaml b/examples/gitlab-ci/push-solution.yaml index 30d1831..ff6e88d 100644 --- a/examples/gitlab-ci/push-solution.yaml +++ b/examples/gitlab-ci/push-solution.yaml @@ -5,103 +5,81 @@ stages: variables: GIT_STRATEGY: clone GIT_DEPTH: 0 # Full clone for accurate branch history + # Required: Set your Upsun project ID + # UPSUN_PROJECT_ID: your-project-id + # Required: Set your Upsun CLI token as a protected variable + # UPSUN_CLI_TOKEN: your-api-token -.setup_ssh: &setup_ssh - - echo "Setup SSH" - - mkdir -p ~/.ssh - - echo "$UPSUN_SSH_PRIVATE_KEY" | tr -d '\r' > ~/.ssh/id_rsa - - chmod 600 ~/.ssh/id_rsa - - ssh-keyscan -H git.$UPSUN_REGION.platform.sh >> ~/.ssh/known_hosts - -.access_token: &access_token - - | - export UPSUN_ACCESS_TOKEN=$(curl -u platform-api-user: \ - -d "grant_type=api_token&api_token=$UPSUN_API_TOKEN" \ - https://auth.upsun.com/oauth2/token | jq -r .access_token) +.upsun-cli: + image: pjcdawkins/platformsh-cli + before_script: + - curl -fsSL https://raw.githubusercontent.com/platformsh/cli/refs/heads/main/internal/config/upsun-cli.yaml > cli-config.yaml + - echo > upsun 'CLI_CONFIG_FILE=cli-config.yaml platform "$@"' + - chmod +x upsun + variables: + UPSUN_CLI_COMMAND: ./upsun -# Deploy on push to branches and new merge requests -deploy_to_upsun: +# Push to production on default branch +push-production: + extends: .upsun-cli stage: deploy - image: alpine:latest - before_script: - - apk add --no-cache curl jq git openssh - - *setup_ssh - - *access_token + variables: + UPSUN_PARENT_ENV: $CI_DEFAULT_BRANCH + UPSUN_TARGET_BRANCH: $CI_DEFAULT_BRANCH + rules: + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH script: - - | - echo "Configure Git" - git config --global user.email "gitlab-ci@example.com" - git config --global user.name "GitLab CI" - - echo "Add Upsun remote" - git remote add upsun $UPSUN_GIT_REMOTE - - echo "Checkout branch and push to Upsun" - git checkout -B $CI_COMMIT_REF_NAME - git push upsun $CI_COMMIT_REF_NAME + - bash examples/gitlab-ci/scripts/push.sh + environment: + name: production + url: $PRIMARY_URL + artifacts: + reports: + dotenv: environment.env - echo "Activate environment" - echo "UPSUN_ACCESS_TOKEN: $UPSUN_ACCESS_TOKEN" - curl -s -X POST \ - -H "Authorization: Bearer $UPSUN_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - "https://api.upsun.com/projects/$UPSUN_PROJECT_ID/environments/main/activate" - - only: - - merge_requests - except: - - main # Adjust based on your default branch - -# Deploy to production -deploy_production: +# Push to review environment for merge requests +push-review-env: + extends: .upsun-cli stage: deploy - image: alpine:latest - before_script: - - apk add --no-cache curl jq git openssh - - *setup_ssh + when: manual + variables: + UPSUN_PARENT_ENV: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME + UPSUN_TARGET_BRANCH: $CI_COMMIT_REF_SLUG + UPSUN_NO_CLONE_PARENT: "true" + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" script: - - | - git config --global user.email "gitlab-ci@example.com" - git config --global user.name "GitLab CI" - git remote add upsun $UPSUN_GIT_REMOTE || git remote set-url upsun $UPSUN_GIT_REMOTE - git push upsun main --force - only: - - main # Adjust based on your default branch + - bash examples/gitlab-ci/scripts/push.sh + environment: + name: review/$CI_COMMIT_REF_SLUG + url: $PRIMARY_URL + auto_stop_in: 7 day + on_stop: delete-review-env + artifacts: + reports: + dotenv: environment.env -# Cleanup environments when branches are deleted or MRs are merged -cleanup_environment: +# Cleanup merged environments +cleanup-review-envs: + extends: .upsun-cli stage: cleanup - image: alpine:latest - before_script: - - apk add --no-cache curl jq git openssh - - *setup_ssh - - *access_token - script: - - | - # Get the source branch name from the merge request - BRANCH_NAME="${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" - - if [ -z "$BRANCH_NAME" ]; then - echo "No branch name found, skipping cleanup" - exit 0 - fi - - echo "Cleaning up Upsun environment: $BRANCH_NAME" - - # Delete the branch from Upsun remote - git push upsun --delete "$BRANCH_NAME" || echo "Branch already deleted from remote" - - # Deactivate the environment via API - curl -s -X POST \ - -H "Authorization: Bearer $UPSUN_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - "https://api.upsun.com/projects/$UPSUN_PROJECT_ID/environments/$BRANCH_NAME/deactivate" || echo "Environment deactivation failed" - - # Optionally delete the environment completely - curl -s -X DELETE \ - -H "Authorization: Bearer $UPSUN_ACCESS_TOKEN" \ - "https://api.upsun.com/projects/$UPSUN_PROJECT_ID/environments/$BRANCH_NAME" || echo "Environment deletion failed" rules: - - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' - when: manual + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + script: + - bash examples/gitlab-ci/scripts/cleanup.sh allow_failure: true + +# Delete specific review environment when stopped +delete-review-env: + extends: .upsun-cli + stage: cleanup + when: manual + variables: + UPSUN_TARGET_BRANCH: $CI_COMMIT_REF_SLUG + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + script: + - bash examples/gitlab-ci/scripts/delete.sh + environment: + name: review/$CI_COMMIT_REF_SLUG + action: stop diff --git a/examples/gitlab-ci/scripts/cleanup.sh b/examples/gitlab-ci/scripts/cleanup.sh new file mode 100755 index 0000000..00df897 --- /dev/null +++ b/examples/gitlab-ci/scripts/cleanup.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +# This script cleans up Upsun environments that have been merged with their parent. + +set -e -o pipefail + +# Config. +if [ -z "$UPSUN_PROJECT_ID" ]; then + echo >&2 '$UPSUN_PROJECT_ID is required' + exit 1 +fi +if [ -z "$UPSUN_PARENT_ENV" ]; then + UPSUN_PARENT_ENV=${CI_MERGE_REQUEST_TARGET_BRANCH_NAME:-${CI_DEFAULT_BRANCH:-main}} +fi + +CLI_COMMAND=${UPSUN_CLI_COMMAND:-upsun} + +# Clean up environments if they are merged with their parent. +$CLI_COMMAND environment:delete --no-interaction --project="$UPSUN_PROJECT_ID" --merged --no-wait --exclude-type production,staging --exclude "$UPSUN_PARENT_ENV" diff --git a/examples/gitlab-ci/scripts/delete.sh b/examples/gitlab-ci/scripts/delete.sh new file mode 100755 index 0000000..c894214 --- /dev/null +++ b/examples/gitlab-ci/scripts/delete.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +# This script deletes a specific Upsun environment. + +set -e -o pipefail + +# Config. +if [ -z "$UPSUN_PROJECT_ID" ]; then + echo >&2 '$UPSUN_PROJECT_ID is required' + exit 1 +fi +BRANCH=${UPSUN_TARGET_BRANCH:-$CI_COMMIT_REF_SLUG} +if [ -z "$BRANCH" ]; then + echo >&2 'Branch name ($UPSUN_TARGET_BRANCH or $CI_COMMIT_REF_SLUG) not defined' + exit 1 +fi + +CLI_COMMAND=${UPSUN_CLI_COMMAND:-upsun} + +$CLI_COMMAND environment:delete --no-interaction --no-wait --project="$UPSUN_PROJECT_ID" --environment="$BRANCH" diff --git a/examples/gitlab-ci/scripts/push.sh b/examples/gitlab-ci/scripts/push.sh new file mode 100755 index 0000000..7fcb9f7 --- /dev/null +++ b/examples/gitlab-ci/scripts/push.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +# This script can be used from GitLab CI to push code to an Upsun environment. +# It always force-pushes and activates the environment. + +set -e -o pipefail + +# Config. +if [ -z "$UPSUN_PROJECT_ID" ]; then + echo >&2 '$UPSUN_PROJECT_ID is required' + exit 1 +fi +BRANCH=${UPSUN_TARGET_BRANCH:-$CI_COMMIT_REF_SLUG} +if [ -z "$BRANCH" ]; then + echo >&2 'Target branch ($UPSUN_TARGET_BRANCH or $CI_COMMIT_REF_SLUG) not defined' + exit 1 +fi +UPSUN_PARENT_ENV=${UPSUN_PARENT_ENV:-$CI_MERGE_REQUEST_TARGET_BRANCH_NAME} +if [ -z "$UPSUN_PARENT_ENV" ]; then + UPSUN_PARENT_ENV=${CI_DEFAULT_BRANCH:-main} +fi + +CLI_COMMAND=${UPSUN_CLI_COMMAND:-upsun} + +$CLI_COMMAND project:set-remote --no-interaction "$UPSUN_PROJECT_ID" + +# Build and run the push command. +push_command="$CLI_COMMAND push --no-interaction --force --target=${BRANCH}" +if [ "$UPSUN_PARENT_ENV" != "$BRANCH" ]; then + push_command="$push_command --activate --parent=${UPSUN_PARENT_ENV}" + if [ "$BRANCH" != main ]; then + push_command="$push_command --resources-init=default" + fi +fi +if [ -n "$UPSUN_NO_CLONE_PARENT" ]; then + push_command="$push_command --no-clone-parent" +fi + +$push_command + +# Write the environment's primary URL to a dotenv file. +# This can be used by a GitLab job via the "dotenv" artifact type. +echo "PRIMARY_URL=$($CLI_COMMAND url --primary --pipe --no-interaction --environment="$BRANCH")" > environment.env