name: Release Baron SSO to Production on: workflow_dispatch: inputs: rc_version_tag: description: "The version tag to release to production (e.g., v1.2601.1-RC1)" required: true type: string jobs: release: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Login to Harbor Registry uses: docker/login-action@v3 with: registry: ${{ vars.HARBOR_ENDPOINT }} username: ${{ vars.HARBOR_ROBOT_ACCOUNT }} password: ${{ secrets.HARBOR_ROBOT_KEY }} - name: Parse RC and re-tag to final id: retag env: HARBOR_HOSTNAME: ${{ vars.HARBOR_HOSTNAME }} HARBOR_USER: ${{ vars.HARBOR_ROBOT_ACCOUNT }} HARBOR_PASSWORD: ${{ secrets.HARBOR_ROBOT_KEY }} run: | BASE_TAG=$(echo "${{ github.event.inputs.rc_version_tag }}" | xargs) if [[ ! "$BASE_TAG" =~ ^v[0-9]+\.[0-9]{4}\.[0-9]+-RC[0-9]+$ ]]; then echo "::error::rc_version_tag must look like vX.YYMM.Z-RC## (got: $BASE_TAG)" exit 1 fi RE_TAG="${BASE_TAG%-RC*}" echo "Final tag will be: ${RE_TAG}" if ! command -v skopeo >/dev/null 2>&1; then sudo apt-get update -y && sudo apt-get install -y skopeo fi # Re-tag backend image echo "Re-tagging backend image..." skopeo copy --preserve-digests \ --src-creds "${HARBOR_USER}:${HARBOR_PASSWORD}" --dest-creds "${HARBOR_USER}:${HARBOR_PASSWORD}" \ --src-tls-verify=false --dest-tls-verify=false \ "docker://${HARBOR_HOSTNAME}/baron_sso/backend:${BASE_TAG}" "docker://${HARBOR_HOSTNAME}/baron_sso/backend:${RE_TAG}" # Re-tag userfront image echo "Re-tagging userfront image..." skopeo copy --preserve-digests \ --src-creds "${HARBOR_USER}:${HARBOR_PASSWORD}" --dest-creds "${HARBOR_USER}:${HARBOR_PASSWORD}" \ --src-tls-verify=false --dest-tls-verify=false \ "docker://${HARBOR_HOSTNAME}/baron_sso/userfront:${BASE_TAG}" "docker://${HARBOR_HOSTNAME}/baron_sso/userfront:${RE_TAG}" echo "final_image_tag=${RE_TAG}" >> "$GITHUB_OUTPUT" - name: Setup SSH uses: webfactory/ssh-agent@v0.9.0 with: ssh-private-key: ${{ secrets.PROD_SSH_PRIVATE_KEY }} - name: Deploy to Production env: IMAGE_TAG: ${{ steps.retag.outputs.final_image_tag }} BACKEND_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/backend USERFRONT_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/userfront DEPLOY_PATH: ${{ vars.PROD_DEPLOY_PATH }} PROD_HOST: ${{ vars.PROD_HOST }} PROD_USER: ${{ vars.PROD_USER }} HARBOR_ENDPOINT: ${{ vars.HARBOR_ENDPOINT }} HARBOR_ROBOT_ACCOUNT: ${{ vars.HARBOR_ROBOT_ACCOUNT }} HARBOR_ROBOT_KEY: ${{ secrets.HARBOR_ROBOT_KEY }} run: | set -euo pipefail echo "DEBUG: PROD_USER='${PROD_USER}'" echo "DEBUG: PROD_HOST='${PROD_HOST}'" echo "DEBUG: DEPLOY_PATH='${DEPLOY_PATH}'" # Sanity check (fail fast with a clear message) if [ -z "${PROD_USER}" ] || [ -z "${PROD_HOST}" ] || [ -z "${DEPLOY_PATH}" ]; then echo "::error::Missing required vars (PROD_USER/PROD_HOST/DEPLOY_PATH). Check Gitea repo variables." exit 1 fi ssh-keyscan -H "${PROD_HOST}" >> ~/.ssh/known_hosts ssh "${PROD_USER}@${PROD_HOST}" "mkdir -p '${DEPLOY_PATH}/adminfront'" # Create the main .env file for Baron SSO on the remote server # Note: All values are pulled from Gitea secrets and variables printf '%s\n' \ "APP_ENV=production" \ "TZ=Asia/Seoul" \ "DB_PORT=${{ vars.PROD_DB_PORT }}" \ "CLICKHOUSE_PORT_HTTP=${{ vars.PROD_CLICKHOUSE_PORT_HTTP }}" \ "CLICKHOUSE_PORT_NATIVE=${{ vars.PROD_CLICKHOUSE_PORT_NATIVE }}" \ "CLICKHOUSE_USER=${{ vars.PROD_CLICKHOUSE_USER }}" \ "CLICKHOUSE_PASSWORD=${{ secrets.PROD_CLICKHOUSE_PASSWORD }}" \ "BACKEND_PORT=${{ vars.PROD_BACKEND_PORT }}" \ "USERFRONT_PORT=${{ vars.PROD_USERFRONT_PORT }}" \ "DB_USER=${{ vars.PROD_DB_USER }}" \ "DB_PASSWORD=${{ secrets.PROD_DB_PASSWORD }}" \ "DB_NAME=${{ vars.PROD_DB_NAME }}" \ "COOKIE_SECRET=${{ secrets.PROD_COOKIE_SECRET }}" \ "JWT_SECRET=${{ secrets.PROD_JWT_SECRET }}" \ "REDIS_ADDR=${{ vars.PROD_REDIS_ADDR }}" \ "NAVER_CLOUD_ACCESS_KEY=${{ vars.NAVER_CLOUD_ACCESS_KEY }}" \ "NAVER_CLOUD_SECRET_KEY=${{ secrets.NAVER_CLOUD_SECRET_KEY }}" \ "NAVER_CLOUD_SERVICE_ID=${{ vars.NAVER_CLOUD_SERVICE_ID }}" \ "NAVER_SENDER_PHONE_NUMBER=${{ vars.NAVER_SENDER_PHONE_NUMBER }}" \ "AWS_REGION=${{ vars.AWS_REGION }}" \ "AWS_ACCESS_KEY_ID=${{ vars.AWS_ACCESS_KEY_ID }}" \ "AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}" \ "AWS_SES_SENDER=${{ vars.AWS_SES_SENDER }}" \ "USERFRONT_URL=${{ vars.PROD_USERFRONT_URL }}" \ "BACKEND_URL=${{ vars.PROD_BACKEND_URL }}" \ > .env # Copy compose template and .env file to the remote server scp adminfront/seed-tenant.csv "${PROD_USER}@${PROD_HOST}:${DEPLOY_PATH}/adminfront/" scp docker/docker-compose.template.yaml .env "${PROD_USER}@${PROD_HOST}:${DEPLOY_PATH}/" scp docker/compose.infra.prd.yaml "${PROD_USER}@${PROD_HOST}:${DEPLOY_PATH}/compose.infra.yml" # Deploy Baron SSO echo "${HARBOR_ROBOT_KEY}" | ssh "${PROD_USER}@${PROD_HOST}" \ "export DEPLOY_PATH='${DEPLOY_PATH}'; \ export BACKEND_IMAGE_NAME='${BACKEND_IMAGE_NAME}'; \ export USERFRONT_IMAGE_NAME='${USERFRONT_IMAGE_NAME}'; \ export IMAGE_TAG='${IMAGE_TAG}'; \ export HARBOR_ENDPOINT='${HARBOR_ENDPOINT}'; \ export HARBOR_ROBOT_ACCOUNT='${HARBOR_ROBOT_ACCOUNT}'; \ set -e; \ cd \"\${DEPLOY_PATH}\"; \ docker login \"\${HARBOR_ENDPOINT}\" -u \"\${HARBOR_ROBOT_ACCOUNT}\" --password-stdin; \ set -a; \ . ./.env; \ set +a; \ envsubst < docker-compose.template.yaml > docker-compose.yml; \ docker compose -f compose.infra.yml -f docker-compose.yml pull; \ docker compose -f compose.infra.yml -f docker-compose.yml up -d --remove-orphans"