boilerplate-nestjs-api-crud/.gitlab-ci.yml
2023-04-17 10:20:39 +08:00

222 lines
8.6 KiB
YAML

# -----------------------------------------------------------------------------
# Original/Ref: https://git.price-hk.com/boilerplate-samples-projects/basic-docker-ci
# -----------------------------------------------------------------------------
# Generic Gitlab CI for docker project for building and uploading img to Nexus and QCloud
#
# This file requires the following variables:
# See Also: https://git.price-hk.com/admin/application_settings/ci_cd
# (Requried:)
# - NAMESPACE: [price|myprice] # It will be prepended to the DOCKER_IMAGE_NAME
# - PRICE_DOCKER_REPO_HOST # Nexus Repo Host
# - PRICE_DOCKER_REPO_USER # Nexus Repo User
# - PRICE_DOCKER_REPO_PWD # Nexus Repo Password
# - QCLOUD_TKE_TCR_HOST # QCloud TKE TCR (Registry) Host
# - QCLOUD_TKE_TCR_USER # QCloud TKE TCR (Registry) User
# - QCLOUD_TKE_TCR_PWD # QCloud TKE TCR (Registry) Password
#
# (Optional:)
# - DOCKER_IMAGE_NAME # It can be overrided if specified
#
# Triggering the Pipeline:
# The pipeline can be triggered by git tagging or running the pipeline manually with CI_COMMIT_TAG var.
#
# The pattern of Git tag or CI_COMMIT_TAG should be either:
# - Image for release purpose => release-{Docker Image Tag}
# - Docker Image Tag pattern: {semantic version style: x.y.z}[-{Optional text}]
# - Image for Non-release/Development purpose => dev-{Docker Image Tag}
# - Docker Image Tag pattern: any text follow docker tag requirements
#
stages:
- trigger
- docker-build-push-nexus
- push-qcloud
default:
interruptible: false
tags:
# Note: There may be a performance issue while using dind
# so that we switch to docker executor.
- docker-executor
artifacts:
reports:
dotenv: build.env
# after_script:
# # Only for debug propose, comment for production
# - env
variables:
NAMESPACE: price
DOCKER_IMAGE_NAME: "${NAMESPACE}/${CI_PROJECT_PATH_SLUG}"
DOCKERFILE_NAME: "Dockerfile"
.release_tag_rules:
rules:
# Force git-tag trigger only, run-pipeline not support (recommended)
- if: '$CI_COMMIT_TAG =~ /^release-\d+(\.\d+){0,2}\.\d+(-([a-zA-Z0-9\.\-\_]+)*[a-zA-Z0-9])?$/ && $CI_PIPELINE_SOURCE == "push"'
# Can use git-tag trigger and run-pipeline (for ci-development only)
# - if: '$CI_COMMIT_TAG =~ /^release-\d+(\.\d+){0,2}\.\d+(-([a-zA-Z0-9\.\-\_]+)*[a-zA-Z0-9])?$/'
when: on_success
.dev_tag_rules:
rules:
# Force git-tag trigger only, run-pipeline not support (recommended)
- if: '$CI_COMMIT_TAG =~ /^dev-[a-zA-Z0-9\.\-\_]+[a-zA-Z0-9]$/ && $CI_PIPELINE_SOURCE == "push"'
# Can use git-tag trigger and run-pipeline (for ci-development only)
# - if: '$CI_COMMIT_TAG =~ /^dev-[a-zA-Z0-9\.\-\_]+[a-zA-Z0-9]$/'
when: on_success
.tag_trigger_save_build_env:
script:
# Send to next stages
- |
echo "IS_RELEASE_IMAGE=${IS_RELEASE_IMAGE}" >> build.env
echo "DOCKERFILE_NAME=${DOCKERFILE_NAME}" >> build.env
echo "DOCKER_IMAGE_TAG=${DOCKER_IMAGE_TAG}" >> build.env
.check_get_docker_image_tag:
script:
- |
# Extract the docker image tag from commit tag
if [ -z $CI_COMMIT_TAG ]; then
echo "[!] ERROR, missing CI_COMMIT_TAG"
exit 1
else
DOCKER_IMAGE_TAG=$(echo "$CI_COMMIT_TAG" | sed -re 's/^[^-]+-(.*)$/\1/g')
fi
# ---------- JOB ---------
Tag Trigger for Release:
stage: trigger
rules:
- !reference [.release_tag_rules, rules]
script:
- IS_RELEASE_IMAGE=true
- !reference [.check_get_docker_image_tag, script]
- !reference [.tag_trigger_save_build_env, script]
# ---------- JOB ---------
Tag or Manual Trigger for Dev Build:
stage: trigger
rules:
- !reference [.dev_tag_rules, rules]
script:
- IS_RELEASE_IMAGE=false
- !reference [.check_get_docker_image_tag, script]
# Append 'dev-' to the docekr tag for the non-release image
- DOCKER_IMAGE_TAG="dev-${DOCKER_IMAGE_TAG}"
# Check if Dockerfile.dev exist, then use it for docker build
# TODO: consider to use filename suffix for other image tag like architecture suffix
- |
if [ -f "${DOCKERFILE_NAME}.dev" ]; then
DOCKERFILE_NAME=${DOCKERFILE_NAME}.dev
fi
- !reference [.tag_trigger_save_build_env, script]
# ---------- JOB ---------
Docker Build and Push to Nexus:
stage: docker-build-push-nexus
rules:
- !reference [.release_tag_rules, rules]
- !reference [.dev_tag_rules, rules]
# Not using 'needs' properly. The following settings cannot restrict only
# running from below jobs. It can be triggered if the rule passes anyway.
# Therefore, we still need to govern the trigger by rules.
# The use of 'needs' is for better flow declaration, for DAG.
needs:
- job: Tag or Manual Trigger for Dev Build
optional: true
- job: Tag Trigger for Release
optional: true
before_script:
# Login to Price Registry - Nexus
- echo "${PRICE_DOCKER_REPO_PWD}" | docker login -u "${PRICE_DOCKER_REPO_USER}" --password-stdin ${PRICE_DOCKER_REPO_HOST}
# pull latest image for cache-from, if any
- docker pull ${PRICE_DOCKER_REPO_HOST}/${DOCKER_IMAGE_NAME}:latest || true
script:
# ---------- PRE-BUILD ----------
# Modify the source code version string so that the VERSION_STRING will be added to the application
# - |
# sed -i -e "s/const BuildVersion string = .*$/const BuildVersion string = \"${VERSION_STRING}\"/g" cmd/priceuid2server/main.go
- DOCKER_IMAGE_NAME_WITH_TAG=${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG}
# ---------- BUILD DOCKER IMAGE ----------
- |
echo "Using Dockerfile: ${DOCKERFILE_NAME}"
- >
docker build
-f "${DOCKERFILE_NAME}"
--pull
--tag ${PRICE_DOCKER_REPO_HOST}/${DOCKER_IMAGE_NAME_WITH_TAG}
--cache-from ${PRICE_DOCKER_REPO_HOST}/${DOCKER_IMAGE_NAME}:latest
--build-arg org_label_schema_name="${DOCKER_IMAGE_NAME}"
--build-arg org_label_schema_version="${DOCKER_IMAGE_TAG}"
--build-arg org_label_schema_description="${CI_PROJECT_TITLE}"
--build-arg org_label_schema_build_date="${CI_PIPELINE_CREATED_AT}"
--build-arg org_label_schema_vcs_ref="${CI_COMMIT_SHA}"
--build-arg org_label_schema_vcs_url="${CI_PROJECT_URL}"
--build-arg maintainer="${GITLAB_USER_LOGIN}<${GITLAB_USER_EMAIL}>"
--build-arg APP_VERSION="${DOCKER_IMAGE_TAG}"
.
# ---------- PUBLISH DOCKER IMAGE TO NEXUS REGISTRY ----------
# Push local image to Price's registry
- docker push ${PRICE_DOCKER_REPO_HOST}/${DOCKER_IMAGE_NAME_WITH_TAG}
# Tag latest image if it is an image for release
- |
if [ "$IS_RELEASE_IMAGE" = true ]; then
docker tag \
${PRICE_DOCKER_REPO_HOST}/${DOCKER_IMAGE_NAME_WITH_TAG} \
${PRICE_DOCKER_REPO_HOST}/${DOCKER_IMAGE_NAME}:latest
docker push ${PRICE_DOCKER_REPO_HOST}/${DOCKER_IMAGE_NAME}:latest
fi
# Artifacts to next stage
- !reference [.tag_trigger_save_build_env, script]
# ---------- JOB ---------
Push Image to QCloud:
stage: push-qcloud
rules:
- !reference [.release_tag_rules, rules]
- !reference [.dev_tag_rules, rules]
needs:
- Docker Build and Push to Nexus
before_script:
# Login to Price Registry - Nexus
- echo "${PRICE_DOCKER_REPO_PWD}" | docker login -u "${PRICE_DOCKER_REPO_USER}" --password-stdin ${PRICE_DOCKER_REPO_HOST}
# Login to QCLOUD TCR (Registry)
- echo "${QCLOUD_TKE_TCR_PWD}" | docker login -u "${QCLOUD_TKE_TCR_USER}" --password-stdin ${QCLOUD_TKE_TCR_HOST}
# Because we have no guarantee that this job will be picked up by the same runner
# that built the image in the previous step, we pull it again locally
- docker pull ${PRICE_DOCKER_REPO_HOST}/${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG}
script:
# ---------- PRE-PUBLISH ----------
- DOCKER_IMAGE_NAME_WITH_TAG=${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG}
# ---------- PUBLISH DOCKER IMAGE TO QCLOUD REGISTRY ----------
- |
docker tag \
${PRICE_DOCKER_REPO_HOST}/${DOCKER_IMAGE_NAME_WITH_TAG} \
${QCLOUD_TKE_TCR_HOST}/${DOCKER_IMAGE_NAME_WITH_TAG}
docker push ${QCLOUD_TKE_TCR_HOST}/${DOCKER_IMAGE_NAME_WITH_TAG}
# Tag latest image if it is an image for release
- |
if [ "$IS_RELEASE_IMAGE" = true ]; then
docker tag \
${QCLOUD_TKE_TCR_HOST}/${DOCKER_IMAGE_NAME_WITH_TAG} \
${QCLOUD_TKE_TCR_HOST}/${DOCKER_IMAGE_NAME}:latest
docker push ${QCLOUD_TKE_TCR_HOST}/${DOCKER_IMAGE_NAME}:latest
docker rmi ${QCLOUD_TKE_TCR_HOST}/${DOCKER_IMAGE_NAME}:latest
fi
# Clean up
- docker rmi ${QCLOUD_TKE_TCR_HOST}/${DOCKER_IMAGE_NAME_WITH_TAG}
# Artifacts to next stage
- !reference [.tag_trigger_save_build_env, script]