image: edbizarro/gitlab-ci-pipeline-php:7.4-alpine stages: - prepare - testing - build - deploy variables: APP_IMAGE_NAME: "$CI_REGISTRY_IMAGE/app" WEB_IMAGE_NAME: "$CI_REGISTRY_IMAGE/web" DB_IMAGE_NAME: "$CI_REGISTRY_IMAGE/db" ####################### # Shared script steps # ####################### # GitLab do not supports bash syntax in the "variables" definitions, # so we use custom step to define all necessary environment variables .defineVars: &defineVars |- export VERSION="${CI_COMMIT_TAG:-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}}" export APP_VERSIONED_IMAGE_NAME="$APP_IMAGE_NAME:$VERSION" export APP_LATEST_IMAGE_NAME="$APP_IMAGE_NAME:latest" export WEB_VERSIONED_IMAGE_NAME="$WEB_IMAGE_NAME:$VERSION" export WEB_LATEST_IMAGE_NAME="$WEB_IMAGE_NAME:latest" export DB_VERSIONED_IMAGE_NAME="$DB_IMAGE_NAME:$VERSION" export DB_LATEST_IMAGE_NAME="$DB_IMAGE_NAME:latest" .dockerLogin: &dockerLogin |- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY .installSentry: &installSentry |- apk add --update-cache --upgrade curl bash curl -sL https://sentry.io/get-cli/ | bash .setupSSH: &setupSSH |- mkdir ~/.ssh echo -e "Host *\n StrictHostKeyChecking no\n" > ~/.ssh/config eval $(ssh-agent -s) echo "$SSH_DEPLOY_KEY" | tr -d '\r' | ssh-add - ################### # Steps to extend # ################### .vendorCache: cache: key: backend-deps paths: - vendor policy: pull ################# # Prepare stage # ################# Composer: stage: prepare extends: - .vendorCache cache: policy: pull-push before_script: - sudo composer self-update --2 - composer config github-oauth.github.com "$GITHUB_TOKEN" - sudo apk add --update --no-cache patch # necessary to make cweagans/composer-patches work script: - composer install --ignore-platform-reqs ################# # Testing stage # ################# PHP-CS-Fixer: stage: testing extends: - .vendorCache script: - vendor/bin/php-cs-fixer fix -v --dry-run Codeception: stage: testing extends: - .vendorCache services: - name: redis:4.0.10-alpine alias: redis - name: bitnami/mariadb:10.3.20-debian-9-r4 alias: db variables: # App config DB_HOST: "db" DB_DATABASE: "ely_accounts_test" DB_USER: "ely_accounts_tester" DB_PASSWORD: "ely_accounts_tester_password" REDIS_HOST: "redis" REDIS_PORT: "6379" # MariaDB config ALLOW_EMPTY_PASSWORD: "yes" MARIADB_DATABASE: "ely_accounts_test" MARIADB_USER: "ely_accounts_tester" MARIADB_PASSWORD: "ely_accounts_tester_password" before_script: # We don't count code coverage yet, so xdebug can be removed - sudo rm /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini # Install wait-for-it script - sudo curl "https://raw.githubusercontent.com/vishnubob/wait-for-it/81b1373f17855/wait-for-it.sh" -o /usr/local/bin/wait-for-it - sudo chmod a+x /usr/local/bin/wait-for-it script: - php yii rbac/generate - wait-for-it "${DB_HOST}:3306" -s -t 0 -- php yii migrate/up --interactive=0 - vendor/bin/codecept run ############### # Build stage # ############### Docker: stage: build image: docker:19.03.9 services: - docker:19.03.9-dind variables: # Use TLS https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#tls-enabled DOCKER_HOST: tcp://docker:2376 DOCKER_TLS_CERTDIR: "/certs" before_script: - *defineVars - *dockerLogin - sed -i -e "s/{{PLACE_VERSION_HERE}}/$VERSION/g" common/config/config.php script: # Download previous images to use them as a cache - docker pull "$APP_LATEST_IMAGE_NAME" || true - docker pull "$WEB_LATEST_IMAGE_NAME" || true - docker pull "$DB_LATEST_IMAGE_NAME" || true # Build images - > docker build . --pull --target app --build-arg "build_env=prod" --cache-from "$APP_LATEST_IMAGE_NAME" -t "$APP_VERSIONED_IMAGE_NAME" -t "$APP_LATEST_IMAGE_NAME" - > docker build . --pull --target web --build-arg "build_env=prod" --cache-from "$APP_VERSIONED_IMAGE_NAME" --cache-from "$WEB_LATEST_IMAGE_NAME" -t "$WEB_VERSIONED_IMAGE_NAME" -t "$WEB_LATEST_IMAGE_NAME" - > docker build . --pull --target db --build-arg "build_env=prod" --cache-from "$APP_VERSIONED_IMAGE_NAME" --cache-from "$WEB_VERSIONED_IMAGE_NAME" --cache-from "$DB_LATEST_IMAGE_NAME" -t "$DB_VERSIONED_IMAGE_NAME" -t "$DB_LATEST_IMAGE_NAME" # Push images to the registry - docker push $APP_VERSIONED_IMAGE_NAME - docker push $APP_LATEST_IMAGE_NAME - docker push $WEB_VERSIONED_IMAGE_NAME - docker push $WEB_LATEST_IMAGE_NAME - docker push $DB_VERSIONED_IMAGE_NAME - docker push $DB_LATEST_IMAGE_NAME rules: - if: '$CI_COMMIT_TAG' when: on_success - if: '$CI_COMMIT_BRANCH == "master"' when: on_success - if: '$CI_COMMIT_MESSAGE =~ /\[deploy.*\]/' when: on_success # Default: - when: never ########## # Deploy # ########## .beforeSentryDeploy: &beforeSentryDeploy |- sentry-cli releases new $VERSION sentry-cli releases set-commits --commit "elyby/accounts@${CI_COMMIT_SHA}" $VERSION .afterSentryDeploy: &afterSentryDeploy |- sentry-cli releases deploys $VERSION new -e $CI_ENVIRONMENT_NAME sentry-cli releases finalize $VERSION .deployJob: stage: deploy image: docksal/ssh-agent:1.3 needs: - Docker variables: GIT_STRATEGY: none before_script: - *defineVars - *installSentry - *setupSSH script: - *beforeSentryDeploy # Escape $ with backslash to prevent value evaluation from CI container. # We're not using $APP_LATEST_IMAGE_NAME because on remote server might be # a different semantic of preferred image version tag - | ssh -J deploy@ely.by:4534 -p 722 "root@$VM_HOST_NAME" /bin/bash << EOF set -e cd "$VM_DEPLOY_PATH" docker pull "$APP_VERSIONED_IMAGE_NAME" docker pull "$WEB_VERSIONED_IMAGE_NAME" docker tag "$APP_VERSIONED_IMAGE_NAME" "$APP_IMAGE_NAME:latest" docker tag "$WEB_VERSIONED_IMAGE_NAME" "$WEB_IMAGE_NAME:latest" docker-compose stop app worker cron docker-compose rm -fv app worker cron docker-compose up -d --scale worker=3 app worker cron docker-compose stop web docker-compose rm -fv web docker-compose up -d web EOF - *afterSentryDeploy Dev: extends: - .deployJob environment: name: Development variables: VM_HOST_NAME: playground.ely.local VM_DEPLOY_PATH: /srv/dev.account.ely.by rules: - if: '$CI_COMMIT_TAG' when: on_success - if: '$CI_COMMIT_BRANCH == "master"' when: on_success - if: '$CI_COMMIT_MESSAGE =~ /\[deploy dev\]/' when: on_success # Default: - when: never Prod: extends: - .deployJob environment: name: Production variables: VM_HOST_NAME: accounts.ely.local VM_DEPLOY_PATH: /srv rules: - if: '$CI_COMMIT_BRANCH != "master"' when: never - if: '$CI_COMMIT_MESSAGE =~ /\[deploy\]/' when: on_success # Default: - when: manual