forked from baron/baron-sso
fix(deploy): align staging frontend runtime with production images
This commit is contained in:
@@ -18,6 +18,30 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: sudo apt-get update && sudo apt-get install -y jq curl
|
run: sudo apt-get update && sudo apt-get install -y jq curl
|
||||||
|
|
||||||
|
- name: Validate RC build configuration
|
||||||
|
env:
|
||||||
|
HARBOR_ENDPOINT: ${{ vars.HARBOR_ENDPOINT }}
|
||||||
|
HARBOR_HOSTNAME: ${{ vars.HARBOR_HOSTNAME }}
|
||||||
|
HARBOR_ROBOT_ACCOUNT: ${{ vars.HARBOR_ROBOT_ACCOUNT }}
|
||||||
|
HARBOR_ROBOT_KEY: ${{ secrets.HARBOR_ROBOT_KEY }}
|
||||||
|
ADMINFRONT_URL: ${{ vars.ADMINFRONT_URL }}
|
||||||
|
DEVFRONT_URL: ${{ vars.DEVFRONT_URL }}
|
||||||
|
ORGFRONT_URL: ${{ vars.ORGFRONT_URL }}
|
||||||
|
VITE_OIDC_AUTHORITY: ${{ vars.VITE_OIDC_AUTHORITY }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
required_action_env="
|
||||||
|
HARBOR_ENDPOINT HARBOR_HOSTNAME HARBOR_ROBOT_ACCOUNT HARBOR_ROBOT_KEY
|
||||||
|
ADMINFRONT_URL DEVFRONT_URL ORGFRONT_URL VITE_OIDC_AUTHORITY
|
||||||
|
"
|
||||||
|
for key in ${required_action_env}; do
|
||||||
|
if [ -z "${!key:-}" ]; then
|
||||||
|
echo "::error::Missing required RC build value: ${key}. Check Gitea repo variables/secrets."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
- name: Login to Docker Registry
|
- name: Login to Docker Registry
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
@@ -93,6 +117,11 @@ jobs:
|
|||||||
file: ./adminfront/Dockerfile
|
file: ./adminfront/Dockerfile
|
||||||
push: true
|
push: true
|
||||||
tags: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/adminfront:${{ steps.rc_calculator.outputs.new_rc_tag }}
|
tags: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/adminfront:${{ steps.rc_calculator.outputs.new_rc_tag }}
|
||||||
|
build-args: |
|
||||||
|
VITE_ADMIN_PUBLIC_URL=${{ vars.ADMINFRONT_URL }}
|
||||||
|
VITE_OIDC_AUTHORITY=${{ vars.VITE_OIDC_AUTHORITY }}
|
||||||
|
VITE_OIDC_CLIENT_ID=adminfront
|
||||||
|
ORGFRONT_URL=${{ vars.ORGFRONT_URL }}
|
||||||
provenance: false
|
provenance: false
|
||||||
sbom: false
|
sbom: false
|
||||||
|
|
||||||
@@ -103,6 +132,10 @@ jobs:
|
|||||||
file: ./devfront/Dockerfile
|
file: ./devfront/Dockerfile
|
||||||
push: true
|
push: true
|
||||||
tags: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/devfront:${{ steps.rc_calculator.outputs.new_rc_tag }}
|
tags: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/devfront:${{ steps.rc_calculator.outputs.new_rc_tag }}
|
||||||
|
build-args: |
|
||||||
|
VITE_DEVFRONT_PUBLIC_URL=${{ vars.DEVFRONT_URL }}
|
||||||
|
VITE_OIDC_AUTHORITY=${{ vars.VITE_OIDC_AUTHORITY }}
|
||||||
|
VITE_OIDC_CLIENT_ID=devfront
|
||||||
provenance: false
|
provenance: false
|
||||||
sbom: false
|
sbom: false
|
||||||
|
|
||||||
@@ -113,6 +146,10 @@ jobs:
|
|||||||
file: ./orgfront/Dockerfile
|
file: ./orgfront/Dockerfile
|
||||||
push: true
|
push: true
|
||||||
tags: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/orgfront:${{ steps.rc_calculator.outputs.new_rc_tag }}
|
tags: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/orgfront:${{ steps.rc_calculator.outputs.new_rc_tag }}
|
||||||
|
build-args: |
|
||||||
|
VITE_ORGFRONT_PUBLIC_URL=${{ vars.ORGFRONT_URL }}
|
||||||
|
VITE_OIDC_AUTHORITY=${{ vars.VITE_OIDC_AUTHORITY }}
|
||||||
|
VITE_OIDC_CLIENT_ID=orgfront
|
||||||
provenance: false
|
provenance: false
|
||||||
sbom: false
|
sbom: false
|
||||||
|
|
||||||
|
|||||||
@@ -42,19 +42,13 @@ jobs:
|
|||||||
sudo apt-get update -y && sudo apt-get install -y skopeo
|
sudo apt-get update -y && sudo apt-get install -y skopeo
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Re-tag backend image
|
for image in backend userfront adminfront devfront orgfront; do
|
||||||
echo "Re-tagging backend image..."
|
echo "Re-tagging ${image} image..."
|
||||||
skopeo copy --preserve-digests \
|
skopeo copy --preserve-digests \
|
||||||
--src-creds "${HARBOR_USER}:${HARBOR_PASSWORD}" --dest-creds "${HARBOR_USER}:${HARBOR_PASSWORD}" \
|
--src-creds "${HARBOR_USER}:${HARBOR_PASSWORD}" --dest-creds "${HARBOR_USER}:${HARBOR_PASSWORD}" \
|
||||||
--src-tls-verify=false --dest-tls-verify=false \
|
--src-tls-verify=false --dest-tls-verify=false \
|
||||||
"docker://${HARBOR_HOSTNAME}/baron_sso/backend:${BASE_TAG}" "docker://${HARBOR_HOSTNAME}/baron_sso/backend:${RE_TAG}"
|
"docker://${HARBOR_HOSTNAME}/baron_sso/${image}:${BASE_TAG}" "docker://${HARBOR_HOSTNAME}/baron_sso/${image}:${RE_TAG}"
|
||||||
|
done
|
||||||
# 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"
|
echo "final_image_tag=${RE_TAG}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
@@ -68,6 +62,9 @@ jobs:
|
|||||||
IMAGE_TAG: ${{ steps.retag.outputs.final_image_tag }}
|
IMAGE_TAG: ${{ steps.retag.outputs.final_image_tag }}
|
||||||
BACKEND_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/backend
|
BACKEND_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/backend
|
||||||
USERFRONT_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/userfront
|
USERFRONT_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/userfront
|
||||||
|
ADMINFRONT_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/adminfront
|
||||||
|
DEVFRONT_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/devfront
|
||||||
|
ORGFRONT_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/orgfront
|
||||||
DEPLOY_PATH: ${{ vars.PROD_DEPLOY_PATH }}
|
DEPLOY_PATH: ${{ vars.PROD_DEPLOY_PATH }}
|
||||||
PROD_HOST: ${{ vars.PROD_HOST }}
|
PROD_HOST: ${{ vars.PROD_HOST }}
|
||||||
PROD_USER: ${{ vars.PROD_USER }}
|
PROD_USER: ${{ vars.PROD_USER }}
|
||||||
@@ -101,8 +98,12 @@ jobs:
|
|||||||
"CLICKHOUSE_PORT_NATIVE=${{ vars.PROD_CLICKHOUSE_PORT_NATIVE }}" \
|
"CLICKHOUSE_PORT_NATIVE=${{ vars.PROD_CLICKHOUSE_PORT_NATIVE }}" \
|
||||||
"CLICKHOUSE_USER=${{ vars.PROD_CLICKHOUSE_USER }}" \
|
"CLICKHOUSE_USER=${{ vars.PROD_CLICKHOUSE_USER }}" \
|
||||||
"CLICKHOUSE_PASSWORD=${{ secrets.PROD_CLICKHOUSE_PASSWORD }}" \
|
"CLICKHOUSE_PASSWORD=${{ secrets.PROD_CLICKHOUSE_PASSWORD }}" \
|
||||||
"BACKEND_PORT=${{ vars.PROD_BACKEND_PORT }}" \
|
"PROD_BACKEND_PORT=${{ vars.PROD_BACKEND_PORT }}" \
|
||||||
"USERFRONT_PORT=${{ vars.PROD_USERFRONT_PORT }}" \
|
"BACKEND_PORT=3000" \
|
||||||
|
"USERFRONT_PORT=${{ vars.PROD_FRONTEND_PORT }}" \
|
||||||
|
"ADMINFRONT_PORT=${{ vars.ADMINFRONT_PORT }}" \
|
||||||
|
"DEVFRONT_PORT=${{ vars.DEVFRONT_PORT }}" \
|
||||||
|
"ORGFRONT_PORT=${{ vars.ORGFRONT_PORT }}" \
|
||||||
"DB_USER=${{ vars.PROD_DB_USER }}" \
|
"DB_USER=${{ vars.PROD_DB_USER }}" \
|
||||||
"DB_PASSWORD=${{ secrets.PROD_DB_PASSWORD }}" \
|
"DB_PASSWORD=${{ secrets.PROD_DB_PASSWORD }}" \
|
||||||
"DB_NAME=${{ vars.PROD_DB_NAME }}" \
|
"DB_NAME=${{ vars.PROD_DB_NAME }}" \
|
||||||
@@ -117,10 +118,33 @@ jobs:
|
|||||||
"AWS_ACCESS_KEY_ID=${{ vars.AWS_ACCESS_KEY_ID }}" \
|
"AWS_ACCESS_KEY_ID=${{ vars.AWS_ACCESS_KEY_ID }}" \
|
||||||
"AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}" \
|
"AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}" \
|
||||||
"AWS_SES_SENDER=${{ vars.AWS_SES_SENDER }}" \
|
"AWS_SES_SENDER=${{ vars.AWS_SES_SENDER }}" \
|
||||||
"USERFRONT_URL=${{ vars.PROD_USERFRONT_URL }}" \
|
"USERFRONT_URL=${{ vars.PROD_FRONTEND_URL }}" \
|
||||||
|
"ADMINFRONT_URL=${{ vars.ADMINFRONT_URL }}" \
|
||||||
|
"DEVFRONT_URL=${{ vars.DEVFRONT_URL }}" \
|
||||||
|
"ORGFRONT_URL=${{ vars.ORGFRONT_URL }}" \
|
||||||
"BACKEND_URL=${{ vars.PROD_BACKEND_URL }}" \
|
"BACKEND_URL=${{ vars.PROD_BACKEND_URL }}" \
|
||||||
|
"VITE_OIDC_AUTHORITY=${{ vars.VITE_OIDC_AUTHORITY }}" \
|
||||||
|
"ADMINFRONT_CALLBACK_URLS=${{ vars.ADMINFRONT_CALLBACK_URLS }}" \
|
||||||
|
"DEVFRONT_CALLBACK_URLS=${{ vars.DEVFRONT_CALLBACK_URLS }}" \
|
||||||
|
"ORGFRONT_CALLBACK_URLS=${{ vars.ORGFRONT_CALLBACK_URLS }}" \
|
||||||
> .env
|
> .env
|
||||||
|
|
||||||
|
required_dotenv_keys="
|
||||||
|
APP_ENV TZ DB_PORT CLICKHOUSE_PORT_HTTP CLICKHOUSE_PORT_NATIVE CLICKHOUSE_USER CLICKHOUSE_PASSWORD
|
||||||
|
PROD_BACKEND_PORT BACKEND_PORT USERFRONT_PORT ADMINFRONT_PORT DEVFRONT_PORT ORGFRONT_PORT
|
||||||
|
DB_USER DB_PASSWORD DB_NAME COOKIE_SECRET JWT_SECRET REDIS_ADDR
|
||||||
|
NAVER_CLOUD_ACCESS_KEY NAVER_CLOUD_SECRET_KEY NAVER_CLOUD_SERVICE_ID NAVER_SENDER_PHONE_NUMBER
|
||||||
|
AWS_REGION AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SES_SENDER
|
||||||
|
USERFRONT_URL ADMINFRONT_URL DEVFRONT_URL ORGFRONT_URL BACKEND_URL VITE_OIDC_AUTHORITY
|
||||||
|
ADMINFRONT_CALLBACK_URLS DEVFRONT_CALLBACK_URLS ORGFRONT_CALLBACK_URLS
|
||||||
|
"
|
||||||
|
for key in ${required_dotenv_keys}; do
|
||||||
|
if ! grep -Eq "^${key}=.+" .env; then
|
||||||
|
echo "::error::Missing required production .env value: ${key}. Check Gitea repo variables/secrets."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
# Copy compose template and .env file to the remote server
|
# Copy compose template and .env file to the remote server
|
||||||
scp adminfront/seed-tenant.csv "${PROD_USER}@${PROD_HOST}:${DEPLOY_PATH}/adminfront/"
|
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/docker-compose.template.yaml .env "${PROD_USER}@${PROD_HOST}:${DEPLOY_PATH}/"
|
||||||
@@ -131,6 +155,9 @@ jobs:
|
|||||||
"export DEPLOY_PATH='${DEPLOY_PATH}'; \
|
"export DEPLOY_PATH='${DEPLOY_PATH}'; \
|
||||||
export BACKEND_IMAGE_NAME='${BACKEND_IMAGE_NAME}'; \
|
export BACKEND_IMAGE_NAME='${BACKEND_IMAGE_NAME}'; \
|
||||||
export USERFRONT_IMAGE_NAME='${USERFRONT_IMAGE_NAME}'; \
|
export USERFRONT_IMAGE_NAME='${USERFRONT_IMAGE_NAME}'; \
|
||||||
|
export ADMINFRONT_IMAGE_NAME='${ADMINFRONT_IMAGE_NAME}'; \
|
||||||
|
export DEVFRONT_IMAGE_NAME='${DEVFRONT_IMAGE_NAME}'; \
|
||||||
|
export ORGFRONT_IMAGE_NAME='${ORGFRONT_IMAGE_NAME}'; \
|
||||||
export IMAGE_TAG='${IMAGE_TAG}'; \
|
export IMAGE_TAG='${IMAGE_TAG}'; \
|
||||||
export HARBOR_ENDPOINT='${HARBOR_ENDPOINT}'; \
|
export HARBOR_ENDPOINT='${HARBOR_ENDPOINT}'; \
|
||||||
export HARBOR_ROBOT_ACCOUNT='${HARBOR_ROBOT_ACCOUNT}'; \
|
export HARBOR_ROBOT_ACCOUNT='${HARBOR_ROBOT_ACCOUNT}'; \
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ jobs:
|
|||||||
CLICKHOUSE_PORT_NATIVE=${{ vars.CLICKHOUSE_PORT_NATIVE }}
|
CLICKHOUSE_PORT_NATIVE=${{ vars.CLICKHOUSE_PORT_NATIVE }}
|
||||||
CLICKHOUSE_HOST=${{ vars.CLICKHOUSE_HOST }}
|
CLICKHOUSE_HOST=${{ vars.CLICKHOUSE_HOST }}
|
||||||
CLICKHOUSE_USER=${{ vars.CLICKHOUSE_USER }}
|
CLICKHOUSE_USER=${{ vars.CLICKHOUSE_USER }}
|
||||||
CLICKHOUSE_PASSWORD=${{ vars.CLICKHOUSE_PASSWORD }}
|
CLICKHOUSE_PASSWORD=${{ secrets.CLICKHOUSE_PASSWORD }}
|
||||||
|
|
||||||
|
|
||||||
BACKEND_PORT=${{ vars.BACKEND_PORT }}
|
BACKEND_PORT=${{ vars.BACKEND_PORT }}
|
||||||
@@ -142,9 +142,32 @@ jobs:
|
|||||||
# OATHKEEPER_INTROSPECT_CLIENT_SECRET=${{ secrets.STG_OATHKEEPER_INTROSPECT_CLIENT_SECRET }}
|
# OATHKEEPER_INTROSPECT_CLIENT_SECRET=${{ secrets.STG_OATHKEEPER_INTROSPECT_CLIENT_SECRET }}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
required_dotenv_keys="
|
||||||
|
APP_ENV BACKEND_LOG_LEVEL CLIENT_LOG_DEBUG WORKS_ADMIN_API_BASE_URL WORKS_ADMIN_OAUTH_TOKEN_URL TZ IDP_PROVIDER
|
||||||
|
DB_PORT CLICKHOUSE_PORT_HTTP CLICKHOUSE_PORT_NATIVE CLICKHOUSE_HOST CLICKHOUSE_USER CLICKHOUSE_PASSWORD
|
||||||
|
BACKEND_PORT ADMINFRONT_PORT DEVFRONT_PORT ORGFRONT_PORT USERFRONT_PORT OATHKEEPER_API_URL
|
||||||
|
DB_USER DB_PASSWORD DB_NAME COOKIE_SECRET JWT_SECRET REDIS_ADDR CORS_ALLOWED_ORIGINS PROFILE_CACHE_TTL
|
||||||
|
NAVER_CLOUD_ACCESS_KEY NAVER_CLOUD_SECRET_KEY NAVER_CLOUD_SERVICE_ID NAVER_SENDER_PHONE_NUMBER
|
||||||
|
AWS_REGION AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SES_SENDER ADMIN_EMAIL ADMIN_PASSWORD
|
||||||
|
USERFRONT_URL ORGFRONT_URL BACKEND_PUBLIC_URL BACKEND_URL OATHKEEPER_PUBLIC_URL
|
||||||
|
ORY_POSTGRES_TAG ORY_POSTGRES_USER ORY_POSTGRES_PASSWORD ORY_POSTGRES_DB KRATOS_DB HYDRA_DB KETO_DB
|
||||||
|
KRATOS_VERSION KRATOS_UI_NODE_VERSION HYDRA_VERSION KETO_VERSION ORY_SDK_URL KRATOS_PUBLIC_URL
|
||||||
|
KRATOS_ADMIN_URL KRATOS_BROWSER_URL KRATOS_UI_URL HYDRA_ADMIN_URL HYDRA_PUBLIC_URL JWKS_URL
|
||||||
|
OATHKEEPER_VERSION OATHKEEPER_UID OATHKEEPER_GID OATHKEEPER_HEALTH_URL OATHKEEPER_HEALTH_INTERVAL_SECONDS
|
||||||
|
OATHKEEPER_HEALTH_TIMEOUT_SECONDS OATHKEEPER_HEALTH_ENABLED CSRF_COOKIE_NAME CSRF_COOKIE_SECRET
|
||||||
|
VITE_OIDC_AUTHORITY ADMINFRONT_CALLBACK_URLS DEVFRONT_CALLBACK_URLS ORGFRONT_CALLBACK_URLS
|
||||||
|
"
|
||||||
|
for key in ${required_dotenv_keys}; do
|
||||||
|
if ! grep -Eq "^${key}=.+" .env; then
|
||||||
|
echo "::error::Missing required staging .env value: ${key}. Check Gitea repo variables/secrets."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
# 파일 복사
|
# 파일 복사
|
||||||
ssh "${STAGE_USER}@${STAGE_HOST}" "mkdir -p ${DEPLOY_PATH}/docker"
|
ssh "${STAGE_USER}@${STAGE_HOST}" "mkdir -p ${DEPLOY_PATH}/docker"
|
||||||
ssh "${STAGE_USER}@${STAGE_HOST}" "mkdir -p ${DEPLOY_PATH}/adminfront"
|
ssh "${STAGE_USER}@${STAGE_HOST}" "mkdir -p ${DEPLOY_PATH}/adminfront"
|
||||||
|
ssh "${STAGE_USER}@${STAGE_HOST}" "mkdir -p ${DEPLOY_PATH}/scripts"
|
||||||
|
|
||||||
# [중요] docker/ory 폴더 복사 (여기에 init-db/1-createdb.sql이 있어야 함)
|
# [중요] docker/ory 폴더 복사 (여기에 init-db/1-createdb.sql이 있어야 함)
|
||||||
scp -r docker/ory "${STAGE_USER}@${STAGE_HOST}:${DEPLOY_PATH}/docker/"
|
scp -r docker/ory "${STAGE_USER}@${STAGE_HOST}:${DEPLOY_PATH}/docker/"
|
||||||
@@ -158,9 +181,10 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
scp adminfront/seed-tenant.csv "${STAGE_USER}@${STAGE_HOST}:${DEPLOY_PATH}/adminfront/"
|
scp adminfront/seed-tenant.csv "${STAGE_USER}@${STAGE_HOST}:${DEPLOY_PATH}/adminfront/"
|
||||||
|
scp scripts/render_ory_config.sh "${STAGE_USER}@${STAGE_HOST}:${DEPLOY_PATH}/scripts/"
|
||||||
scp docker/docker-compose.staging.template.yaml .env "${STAGE_USER}@${STAGE_HOST}:${DEPLOY_PATH}/"
|
scp docker/docker-compose.staging.template.yaml .env "${STAGE_USER}@${STAGE_HOST}:${DEPLOY_PATH}/"
|
||||||
scp docker/compose.infra.yaml "${STAGE_USER}@${STAGE_HOST}:${DEPLOY_PATH}/compose.infra.yml"
|
scp docker/compose.infra.yaml "${STAGE_USER}@${STAGE_HOST}:${DEPLOY_PATH}/compose.infra.yml"
|
||||||
scp docker/compose.ory.yaml "${STAGE_USER}@${STAGE_HOST}:${DEPLOY_PATH}/compose.ory.yml"
|
scp compose.ory.yaml "${STAGE_USER}@${STAGE_HOST}:${DEPLOY_PATH}/compose.ory.yml"
|
||||||
|
|
||||||
# 배포 실행
|
# 배포 실행
|
||||||
echo "${HARBOR_ROBOT_KEY}" | ssh "${STAGE_USER}@${STAGE_HOST}" \
|
echo "${HARBOR_ROBOT_KEY}" | ssh "${STAGE_USER}@${STAGE_HOST}" \
|
||||||
@@ -181,6 +205,9 @@ jobs:
|
|||||||
for net in baron_net public_net ory-net hydranet kratosnet; do
|
for net in baron_net public_net ory-net hydranet kratosnet; do
|
||||||
docker network inspect \"\$net\" >/dev/null 2>&1 || docker network create \"\$net\"
|
docker network inspect \"\$net\" >/dev/null 2>&1 || docker network create \"\$net\"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
bash scripts/render_ory_config.sh; \
|
||||||
|
chmod -R 777 config/.generated/ory || true; \
|
||||||
|
|
||||||
envsubst < docker-compose.staging.template.yaml > docker-compose.yml; \
|
envsubst < docker-compose.staging.template.yaml > docker-compose.yml; \
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +1,40 @@
|
|||||||
FROM node:lts
|
FROM node:lts AS build
|
||||||
|
|
||||||
WORKDIR /workspace
|
WORKDIR /workspace
|
||||||
|
|
||||||
# Set CI environment variable to true to avoid TTY issues with pnpm
|
|
||||||
ENV CI=true
|
ENV CI=true
|
||||||
|
ENV ADMINFRONT_BUILD_OUT_DIR=/workspace/adminfront/dist
|
||||||
|
|
||||||
# Install pnpm
|
|
||||||
RUN corepack enable && corepack prepare pnpm@10.5.2 --activate
|
RUN corepack enable && corepack prepare pnpm@10.5.2 --activate
|
||||||
|
|
||||||
# Copy workspace configs and common package
|
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
|
||||||
COPY pnpm-workspace.yaml pnpm-lock.yaml ./
|
|
||||||
COPY common ./common
|
COPY common ./common
|
||||||
COPY adminfront ./adminfront
|
COPY adminfront ./adminfront
|
||||||
|
|
||||||
# Install dependencies for the workspace
|
ARG VITE_ADMIN_PUBLIC_URL
|
||||||
RUN pnpm install --filter adminfront... --filter baron-sso... --no-frozen-lockfile --ignore-scripts
|
ARG VITE_OIDC_AUTHORITY
|
||||||
|
ARG VITE_OIDC_CLIENT_ID
|
||||||
|
ARG ORGFRONT_URL
|
||||||
|
ENV VITE_ADMIN_PUBLIC_URL=$VITE_ADMIN_PUBLIC_URL
|
||||||
|
ENV VITE_OIDC_AUTHORITY=$VITE_OIDC_AUTHORITY
|
||||||
|
ENV VITE_OIDC_CLIENT_ID=$VITE_OIDC_CLIENT_ID
|
||||||
|
ENV ORGFRONT_URL=$ORGFRONT_URL
|
||||||
|
|
||||||
# 프로덕션 서빙을 위한 serve 패키지 글로벌 설치
|
RUN pnpm install --frozen-lockfile --ignore-scripts
|
||||||
RUN npm install -g serve
|
|
||||||
|
|
||||||
WORKDIR /workspace/adminfront
|
WORKDIR /workspace/adminfront
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
FROM node:24-alpine AS production
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
ENV FRONTEND_DIST_DIR=/app/dist
|
||||||
|
ENV PORT=5173
|
||||||
|
|
||||||
|
COPY scripts/serve_frontend_prod.mjs ./serve_frontend_prod.mjs
|
||||||
|
COPY --from=build /workspace/adminfront/dist ./dist
|
||||||
|
|
||||||
# Vite 기본 포트
|
|
||||||
EXPOSE 5173
|
EXPOSE 5173
|
||||||
|
|
||||||
# 실행 스크립트: APP_ENV에 따라 개발 서버 또는 빌드 후 서빙
|
CMD ["node", "./serve_frontend_prod.mjs"]
|
||||||
RUN chmod +x ./scripts/runtime-mode.sh
|
|
||||||
CMD ["sh", "./scripts/runtime-mode.sh"]
|
|
||||||
|
|||||||
@@ -314,48 +314,56 @@ services:
|
|||||||
networks: [app_net]
|
networks: [app_net]
|
||||||
|
|
||||||
adminfront:
|
adminfront:
|
||||||
image: node:20-alpine
|
build:
|
||||||
|
context: ../..
|
||||||
|
dockerfile: ./adminfront/Dockerfile
|
||||||
|
args:
|
||||||
|
VITE_ADMIN_PUBLIC_URL: ${ADMINFRONT_URL}
|
||||||
|
VITE_OIDC_AUTHORITY: ${VITE_OIDC_AUTHORITY}
|
||||||
|
VITE_OIDC_CLIENT_ID: adminfront
|
||||||
|
ORGFRONT_URL: ${ORGFRONT_URL}
|
||||||
container_name: ${COMPOSE_PROJECT_NAME}_adminfront
|
container_name: ${COMPOSE_PROJECT_NAME}_adminfront
|
||||||
working_dir: /app
|
|
||||||
env_file: .env
|
env_file: .env
|
||||||
|
environment:
|
||||||
|
- APP_ENV=${APP_ENV:-production}
|
||||||
|
- API_PROXY_TARGET=http://backend:${BACKEND_PORT}
|
||||||
ports:
|
ports:
|
||||||
- "${ADMINFRONT_PORT}:5173"
|
- "${ADMINFRONT_PORT}:5173"
|
||||||
volumes:
|
|
||||||
- ../../common:/common
|
|
||||||
- ../../adminfront:/app
|
|
||||||
- ./adminfront/vite.config.ts:/app/vite.config.ts:ro
|
|
||||||
- ./adminfront/auth.ts:/app/src/lib/auth.ts:ro
|
|
||||||
command: sh ./scripts/runtime-mode.sh
|
|
||||||
networks: [app_net]
|
networks: [app_net]
|
||||||
|
|
||||||
devfront:
|
devfront:
|
||||||
image: node:20-alpine
|
build:
|
||||||
|
context: ../..
|
||||||
|
dockerfile: ./devfront/Dockerfile
|
||||||
|
args:
|
||||||
|
VITE_DEVFRONT_PUBLIC_URL: ${DEVFRONT_URL}
|
||||||
|
VITE_OIDC_AUTHORITY: ${VITE_OIDC_AUTHORITY}
|
||||||
|
VITE_OIDC_CLIENT_ID: devfront
|
||||||
container_name: ${COMPOSE_PROJECT_NAME}_devfront
|
container_name: ${COMPOSE_PROJECT_NAME}_devfront
|
||||||
working_dir: /app
|
|
||||||
env_file: .env
|
env_file: .env
|
||||||
|
environment:
|
||||||
|
- APP_ENV=${APP_ENV:-production}
|
||||||
|
- API_PROXY_TARGET=http://backend:${BACKEND_PORT}
|
||||||
ports:
|
ports:
|
||||||
- "${DEVFRONT_PORT}:5173"
|
- "${DEVFRONT_PORT}:5173"
|
||||||
volumes:
|
|
||||||
- ../../common:/common
|
|
||||||
- ../../devfront:/app
|
|
||||||
- ./devfront/vite.config.ts:/app/vite.config.ts:ro
|
|
||||||
- ./devfront/auth.ts:/app/src/lib/auth.ts:ro
|
|
||||||
command: sh ./scripts/runtime-mode.sh
|
|
||||||
networks: [app_net]
|
networks: [app_net]
|
||||||
|
|
||||||
orgfront:
|
orgfront:
|
||||||
image: node:20-alpine
|
build:
|
||||||
|
context: ../..
|
||||||
|
dockerfile: ./orgfront/Dockerfile
|
||||||
|
args:
|
||||||
|
VITE_ORGFRONT_PUBLIC_URL: ${ORGFRONT_URL}
|
||||||
|
VITE_OIDC_AUTHORITY: ${VITE_OIDC_AUTHORITY}
|
||||||
|
VITE_OIDC_CLIENT_ID: orgfront
|
||||||
container_name: ${COMPOSE_PROJECT_NAME}_orgfront
|
container_name: ${COMPOSE_PROJECT_NAME}_orgfront
|
||||||
working_dir: /app
|
|
||||||
env_file: .env
|
env_file: .env
|
||||||
|
environment:
|
||||||
|
- APP_ENV=${APP_ENV:-production}
|
||||||
|
- API_PROXY_TARGET=http://backend:${BACKEND_PORT}
|
||||||
|
- USERFRONT_URL=${USERFRONT_URL}
|
||||||
ports:
|
ports:
|
||||||
- "${ORGFRONT_PORT}:5175"
|
- "${ORGFRONT_PORT}:5175"
|
||||||
volumes:
|
|
||||||
- ../../common:/common
|
|
||||||
- ../../orgfront:/app
|
|
||||||
- ./orgfront/vite.config.ts:/app/vite.config.ts:ro
|
|
||||||
- ./orgfront/auth.ts:/app/src/lib/auth.ts:ro
|
|
||||||
command: sh ./scripts/runtime-mode.sh
|
|
||||||
networks: [app_net]
|
networks: [app_net]
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
|
|||||||
@@ -1,29 +1,38 @@
|
|||||||
FROM node:lts
|
FROM node:lts AS build
|
||||||
|
|
||||||
WORKDIR /workspace
|
WORKDIR /workspace
|
||||||
|
|
||||||
# Set CI environment variable to true to avoid TTY issues with pnpm
|
|
||||||
ENV CI=true
|
ENV CI=true
|
||||||
|
ENV DEVFRONT_BUILD_OUT_DIR=/workspace/devfront/dist
|
||||||
|
|
||||||
# Install pnpm
|
|
||||||
RUN corepack enable && corepack prepare pnpm@10.5.2 --activate
|
RUN corepack enable && corepack prepare pnpm@10.5.2 --activate
|
||||||
|
|
||||||
# Copy workspace configs and common package
|
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
|
||||||
COPY pnpm-workspace.yaml pnpm-lock.yaml ./
|
|
||||||
COPY common ./common
|
COPY common ./common
|
||||||
COPY devfront ./devfront
|
COPY devfront ./devfront
|
||||||
|
|
||||||
# Install dependencies for the workspace
|
ARG VITE_DEVFRONT_PUBLIC_URL
|
||||||
RUN pnpm install --filter devfront... --filter baron-sso... --no-frozen-lockfile --ignore-scripts
|
ARG VITE_OIDC_AUTHORITY
|
||||||
|
ARG VITE_OIDC_CLIENT_ID
|
||||||
|
ENV VITE_DEVFRONT_PUBLIC_URL=$VITE_DEVFRONT_PUBLIC_URL
|
||||||
|
ENV VITE_OIDC_AUTHORITY=$VITE_OIDC_AUTHORITY
|
||||||
|
ENV VITE_OIDC_CLIENT_ID=$VITE_OIDC_CLIENT_ID
|
||||||
|
|
||||||
# 프로덕션 서빙을 위한 serve 패키지 글로벌 설치
|
RUN pnpm install --frozen-lockfile --ignore-scripts
|
||||||
RUN npm install -g serve
|
|
||||||
|
|
||||||
WORKDIR /workspace/devfront
|
WORKDIR /workspace/devfront
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
FROM node:24-alpine AS production
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
ENV FRONTEND_DIST_DIR=/app/dist
|
||||||
|
ENV PORT=5173
|
||||||
|
|
||||||
|
COPY scripts/serve_frontend_prod.mjs ./serve_frontend_prod.mjs
|
||||||
|
COPY --from=build /workspace/devfront/dist ./dist
|
||||||
|
|
||||||
# Vite 기본 포트
|
|
||||||
EXPOSE 5173
|
EXPOSE 5173
|
||||||
|
|
||||||
# 실행 스크립트: APP_ENV에 따라 개발 서버 또는 빌드 후 서빙
|
CMD ["node", "./serve_frontend_prod.mjs"]
|
||||||
RUN chmod +x ./scripts/runtime-mode.sh
|
|
||||||
CMD ["sh", "./scripts/runtime-mode.sh"]
|
|
||||||
|
|||||||
@@ -17,15 +17,16 @@ services:
|
|||||||
- CLICKHOUSE_USER=${CLICKHOUSE_USER:-baron}
|
- CLICKHOUSE_USER=${CLICKHOUSE_USER:-baron}
|
||||||
- CLICKHOUSE_PASSWORD=${CLICKHOUSE_PASSWORD:-password}
|
- CLICKHOUSE_PASSWORD=${CLICKHOUSE_PASSWORD:-password}
|
||||||
- USERFRONT_URL=${USERFRONT_URL:-https://sso.hmac.kr}
|
- USERFRONT_URL=${USERFRONT_URL:-https://sso.hmac.kr}
|
||||||
|
- BACKEND_PORT=3000
|
||||||
- SEED_TENANT_CSV_PATH=/app/seed-tenant.csv
|
- SEED_TENANT_CSV_PATH=/app/seed-tenant.csv
|
||||||
ports:
|
ports:
|
||||||
- "${BACKEND_PORT:-3010}:3010"
|
- "${PROD_BACKEND_PORT:-3010}:3000"
|
||||||
volumes:
|
volumes:
|
||||||
- ./adminfront/seed-tenant.csv:/app/seed-tenant.csv:ro
|
- ./adminfront/seed-tenant.csv:/app/seed-tenant.csv:ro
|
||||||
depends_on:
|
depends_on:
|
||||||
- infra_check
|
- infra_check
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3010/health"]
|
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/health"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 3
|
retries: 3
|
||||||
@@ -37,11 +38,71 @@ services:
|
|||||||
image: ${USERFRONT_IMAGE_NAME}:${IMAGE_TAG}
|
image: ${USERFRONT_IMAGE_NAME}:${IMAGE_TAG}
|
||||||
container_name: baron_userfront
|
container_name: baron_userfront
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
environment:
|
environment:
|
||||||
- USERFRONT_URL=${USERFRONT_URL:-https://sso.hmac.kr}
|
- USERFRONT_URL=${USERFRONT_URL:-https://sso.hmac.kr}
|
||||||
- BACKEND_URL=${USERFRONT_URL:-https://sso.hmac.kr}
|
- BACKEND_URL=${BACKEND_URL:-https://sso.hmac.kr}
|
||||||
ports:
|
ports:
|
||||||
- "${USERFRONT_PORT:-80}:80"
|
- "${USERFRONT_PORT:-80}:5000"
|
||||||
|
depends_on:
|
||||||
|
backend:
|
||||||
|
condition: service_healthy
|
||||||
|
networks:
|
||||||
|
- baron_net
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:5000/"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
start_period: 30s
|
||||||
|
|
||||||
|
adminfront:
|
||||||
|
image: ${ADMINFRONT_IMAGE_NAME}:${IMAGE_TAG}
|
||||||
|
container_name: baron_adminfront
|
||||||
|
restart: unless-stopped
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
environment:
|
||||||
|
- APP_ENV=production
|
||||||
|
- API_PROXY_TARGET=http://baron_backend:${BACKEND_PORT:-3000}
|
||||||
|
ports:
|
||||||
|
- "${ADMINFRONT_PORT:-5173}:5173"
|
||||||
|
depends_on:
|
||||||
|
backend:
|
||||||
|
condition: service_healthy
|
||||||
|
networks:
|
||||||
|
- baron_net
|
||||||
|
|
||||||
|
devfront:
|
||||||
|
image: ${DEVFRONT_IMAGE_NAME}:${IMAGE_TAG}
|
||||||
|
container_name: baron_devfront
|
||||||
|
restart: unless-stopped
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
environment:
|
||||||
|
- APP_ENV=production
|
||||||
|
- API_PROXY_TARGET=http://baron_backend:${BACKEND_PORT:-3000}
|
||||||
|
ports:
|
||||||
|
- "${DEVFRONT_PORT:-5174}:5173"
|
||||||
|
depends_on:
|
||||||
|
backend:
|
||||||
|
condition: service_healthy
|
||||||
|
networks:
|
||||||
|
- baron_net
|
||||||
|
|
||||||
|
orgfront:
|
||||||
|
image: ${ORGFRONT_IMAGE_NAME}:${IMAGE_TAG}
|
||||||
|
container_name: baron_orgfront
|
||||||
|
restart: unless-stopped
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
environment:
|
||||||
|
- APP_ENV=production
|
||||||
|
- API_PROXY_TARGET=http://baron_backend:${BACKEND_PORT:-3000}
|
||||||
|
- USERFRONT_URL=${USERFRONT_URL}
|
||||||
|
ports:
|
||||||
|
- "${ORGFRONT_PORT:-5175}:5175"
|
||||||
depends_on:
|
depends_on:
|
||||||
backend:
|
backend:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|||||||
@@ -427,6 +427,11 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: ./adminfront/Dockerfile
|
dockerfile: ./adminfront/Dockerfile
|
||||||
|
args:
|
||||||
|
VITE_ADMIN_PUBLIC_URL: ${ADMINFRONT_URL:-}
|
||||||
|
VITE_OIDC_AUTHORITY: ${VITE_OIDC_AUTHORITY:-}
|
||||||
|
VITE_OIDC_CLIENT_ID: adminfront
|
||||||
|
ORGFRONT_URL: ${ORGFRONT_URL:-}
|
||||||
container_name: baron_adminfront
|
container_name: baron_adminfront
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
@@ -435,11 +440,6 @@ services:
|
|||||||
- API_PROXY_TARGET=http://baron_backend:3000
|
- API_PROXY_TARGET=http://baron_backend:3000
|
||||||
ports:
|
ports:
|
||||||
- "${ADMINFRONT_PORT:-5173}:5173"
|
- "${ADMINFRONT_PORT:-5173}:5173"
|
||||||
volumes:
|
|
||||||
- ./adminfront:/app
|
|
||||||
- ./common:/common
|
|
||||||
- ./locales:/locales
|
|
||||||
- /app/node_modules
|
|
||||||
networks:
|
networks:
|
||||||
- baron_net
|
- baron_net
|
||||||
healthcheck:
|
healthcheck:
|
||||||
@@ -453,6 +453,10 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: ./devfront/Dockerfile
|
dockerfile: ./devfront/Dockerfile
|
||||||
|
args:
|
||||||
|
VITE_DEVFRONT_PUBLIC_URL: ${DEVFRONT_URL:-}
|
||||||
|
VITE_OIDC_AUTHORITY: ${VITE_OIDC_AUTHORITY:-}
|
||||||
|
VITE_OIDC_CLIENT_ID: devfront
|
||||||
container_name: baron_devfront
|
container_name: baron_devfront
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
@@ -461,11 +465,6 @@ services:
|
|||||||
- API_PROXY_TARGET=http://baron_backend:3000
|
- API_PROXY_TARGET=http://baron_backend:3000
|
||||||
ports:
|
ports:
|
||||||
- "${DEVFRONT_PORT:-5174}:5173"
|
- "${DEVFRONT_PORT:-5174}:5173"
|
||||||
volumes:
|
|
||||||
- ./devfront:/app
|
|
||||||
- ./common:/common
|
|
||||||
- ./locales:/locales
|
|
||||||
- /app/node_modules
|
|
||||||
networks:
|
networks:
|
||||||
- baron_net
|
- baron_net
|
||||||
healthcheck:
|
healthcheck:
|
||||||
@@ -479,6 +478,10 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: ./orgfront/Dockerfile
|
dockerfile: ./orgfront/Dockerfile
|
||||||
|
args:
|
||||||
|
VITE_ORGFRONT_PUBLIC_URL: ${ORGFRONT_URL:-}
|
||||||
|
VITE_OIDC_AUTHORITY: ${VITE_OIDC_AUTHORITY:-}
|
||||||
|
VITE_OIDC_CLIENT_ID: orgfront
|
||||||
container_name: baron_orgfront
|
container_name: baron_orgfront
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
@@ -488,11 +491,6 @@ services:
|
|||||||
- USERFRONT_URL=${USERFRONT_URL}
|
- USERFRONT_URL=${USERFRONT_URL}
|
||||||
ports:
|
ports:
|
||||||
- "${ORGFRONT_PORT:-5175}:5175"
|
- "${ORGFRONT_PORT:-5175}:5175"
|
||||||
volumes:
|
|
||||||
- ./orgfront:/app
|
|
||||||
- ./common:/common
|
|
||||||
- ./locales:/locales
|
|
||||||
- /app/node_modules
|
|
||||||
networks:
|
networks:
|
||||||
- baron_net
|
- baron_net
|
||||||
healthcheck:
|
healthcheck:
|
||||||
|
|||||||
@@ -1,29 +1,38 @@
|
|||||||
FROM node:lts
|
FROM node:lts AS build
|
||||||
|
|
||||||
WORKDIR /workspace
|
WORKDIR /workspace
|
||||||
|
|
||||||
# Set CI environment variable to true to avoid TTY issues with pnpm
|
|
||||||
ENV CI=true
|
ENV CI=true
|
||||||
|
ENV ORGFRONT_BUILD_OUT_DIR=/workspace/orgfront/dist
|
||||||
|
|
||||||
# Install pnpm
|
|
||||||
RUN corepack enable && corepack prepare pnpm@10.5.2 --activate
|
RUN corepack enable && corepack prepare pnpm@10.5.2 --activate
|
||||||
|
|
||||||
# Copy workspace configs and common package
|
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
|
||||||
COPY pnpm-workspace.yaml pnpm-lock.yaml ./
|
|
||||||
COPY common ./common
|
COPY common ./common
|
||||||
COPY orgfront ./orgfront
|
COPY orgfront ./orgfront
|
||||||
|
|
||||||
# Install dependencies for the workspace
|
ARG VITE_ORGFRONT_PUBLIC_URL
|
||||||
RUN pnpm install --filter orgfront... --filter baron-sso... --no-frozen-lockfile --ignore-scripts
|
ARG VITE_OIDC_AUTHORITY
|
||||||
|
ARG VITE_OIDC_CLIENT_ID
|
||||||
|
ENV VITE_ORGFRONT_PUBLIC_URL=$VITE_ORGFRONT_PUBLIC_URL
|
||||||
|
ENV VITE_OIDC_AUTHORITY=$VITE_OIDC_AUTHORITY
|
||||||
|
ENV VITE_OIDC_CLIENT_ID=$VITE_OIDC_CLIENT_ID
|
||||||
|
|
||||||
# 프로덕션 서빙을 위한 serve 패키지 글로벌 설치
|
RUN pnpm install --frozen-lockfile --ignore-scripts
|
||||||
RUN npm install -g serve
|
|
||||||
|
|
||||||
WORKDIR /workspace/orgfront
|
WORKDIR /workspace/orgfront
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
FROM node:24-alpine AS production
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
ENV FRONTEND_DIST_DIR=/app/dist
|
||||||
|
ENV PORT=5175
|
||||||
|
|
||||||
|
COPY scripts/serve_frontend_prod.mjs ./serve_frontend_prod.mjs
|
||||||
|
COPY --from=build /workspace/orgfront/dist ./dist
|
||||||
|
|
||||||
# Vite 기본 포트
|
|
||||||
EXPOSE 5175
|
EXPOSE 5175
|
||||||
|
|
||||||
# 실행 스크립트: APP_ENV에 따라 개발 서버 또는 빌드 후 서빙
|
CMD ["node", "./serve_frontend_prod.mjs"]
|
||||||
RUN chmod +x ./scripts/runtime-mode.sh
|
|
||||||
CMD ["sh", "./scripts/runtime-mode.sh"]
|
|
||||||
|
|||||||
155
scripts/serve_frontend_prod.mjs
Normal file
155
scripts/serve_frontend_prod.mjs
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
import { readFile, stat } from "node:fs/promises";
|
||||||
|
import { createServer } from "node:http";
|
||||||
|
import { extname, join, normalize, resolve } from "node:path";
|
||||||
|
|
||||||
|
const distDir = resolve(process.env.FRONTEND_DIST_DIR ?? "/app/dist");
|
||||||
|
const host = process.env.HOST ?? "0.0.0.0";
|
||||||
|
const port = Number(process.env.PORT ?? 5173);
|
||||||
|
const backendTarget = new URL(
|
||||||
|
process.env.API_PROXY_TARGET || "http://localhost:3000",
|
||||||
|
);
|
||||||
|
|
||||||
|
const contentTypes = {
|
||||||
|
".css": "text/css; charset=utf-8",
|
||||||
|
".html": "text/html; charset=utf-8",
|
||||||
|
".ico": "image/x-icon",
|
||||||
|
".js": "application/javascript; charset=utf-8",
|
||||||
|
".json": "application/json; charset=utf-8",
|
||||||
|
".map": "application/json; charset=utf-8",
|
||||||
|
".mjs": "application/javascript; charset=utf-8",
|
||||||
|
".png": "image/png",
|
||||||
|
".svg": "image/svg+xml",
|
||||||
|
".txt": "text/plain; charset=utf-8",
|
||||||
|
".webp": "image/webp",
|
||||||
|
".woff": "font/woff",
|
||||||
|
".woff2": "font/woff2",
|
||||||
|
};
|
||||||
|
|
||||||
|
function getContentType(filePath) {
|
||||||
|
return (
|
||||||
|
contentTypes[extname(filePath).toLowerCase()] ?? "application/octet-stream"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendJson(res, statusCode, body) {
|
||||||
|
res.writeHead(statusCode, {
|
||||||
|
"Content-Type": "application/json; charset=utf-8",
|
||||||
|
"Cache-Control": "no-store",
|
||||||
|
});
|
||||||
|
res.end(JSON.stringify(body));
|
||||||
|
}
|
||||||
|
|
||||||
|
function toSafePath(pathname) {
|
||||||
|
const decoded = decodeURIComponent(pathname);
|
||||||
|
const relative = decoded.replace(/^\/+/, "");
|
||||||
|
const safe = normalize(relative).replace(/^(\.\.(?:[\\/]|$))+/, "");
|
||||||
|
return join(distDir, safe);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function tryReadFile(filePath) {
|
||||||
|
try {
|
||||||
|
return await readFile(filePath);
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function proxyToBackend(req, res, pathname, search) {
|
||||||
|
const target = new URL(pathname + search, backendTarget);
|
||||||
|
const headers = new Headers();
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(req.headers)) {
|
||||||
|
if (!value) continue;
|
||||||
|
if (key === "host" || key === "content-length" || key === "connection") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
headers.set(key, Array.isArray(value) ? value.join(", ") : value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasBody = !["GET", "HEAD"].includes(req.method ?? "GET");
|
||||||
|
const response = await fetch(target, {
|
||||||
|
method: req.method,
|
||||||
|
headers,
|
||||||
|
body: hasBody ? req : undefined,
|
||||||
|
duplex: hasBody ? "half" : undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
const responseHeaders = new Headers(response.headers);
|
||||||
|
responseHeaders.delete("content-length");
|
||||||
|
responseHeaders.delete("transfer-encoding");
|
||||||
|
responseHeaders.delete("connection");
|
||||||
|
|
||||||
|
res.writeHead(response.status, Object.fromEntries(responseHeaders.entries()));
|
||||||
|
|
||||||
|
if (req.method === "HEAD") {
|
||||||
|
res.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const arrayBuffer = await response.arrayBuffer();
|
||||||
|
res.end(Buffer.from(arrayBuffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function serveStatic(req, res, pathname) {
|
||||||
|
const indexPath = join(distDir, "index.html");
|
||||||
|
const filePath = toSafePath(pathname);
|
||||||
|
|
||||||
|
let resolvedPath = filePath;
|
||||||
|
try {
|
||||||
|
const fileStat = await stat(resolvedPath);
|
||||||
|
if (fileStat.isDirectory()) {
|
||||||
|
resolvedPath = join(resolvedPath, "index.html");
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
resolvedPath = indexPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
let body = await tryReadFile(resolvedPath);
|
||||||
|
if (!body) {
|
||||||
|
body = await tryReadFile(indexPath);
|
||||||
|
resolvedPath = indexPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!body) {
|
||||||
|
sendJson(res, 500, { error: "dist_not_found" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.writeHead(200, {
|
||||||
|
"Content-Type": getContentType(resolvedPath),
|
||||||
|
"Cache-Control": resolvedPath.endsWith("index.html")
|
||||||
|
? "no-cache"
|
||||||
|
: "public, max-age=31536000, immutable",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (req.method === "HEAD") {
|
||||||
|
res.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.end(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
createServer(async (req, res) => {
|
||||||
|
try {
|
||||||
|
const url = new URL(
|
||||||
|
req.url ?? "/",
|
||||||
|
`http://${req.headers.host ?? "localhost"}`,
|
||||||
|
);
|
||||||
|
const { pathname, search } = url;
|
||||||
|
|
||||||
|
if (pathname === "/api" || pathname.startsWith("/api/")) {
|
||||||
|
await proxyToBackend(req, res, pathname, search);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await serveStatic(req, res, pathname === "/" ? "/index.html" : pathname);
|
||||||
|
} catch (error) {
|
||||||
|
sendJson(res, 500, {
|
||||||
|
error: "internal_server_error",
|
||||||
|
message: error instanceof Error ? error.message : String(error),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).listen(port, host, () => {
|
||||||
|
console.log(`Frontend server listening on http://${host}:${port}`);
|
||||||
|
});
|
||||||
@@ -64,13 +64,19 @@ for file in "$STAGING_COMPOSE" "$PULL_COMPOSE"; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
assert_contains "$STAGING_COMPOSE" 'image: ${ORGFRONT_IMAGE_NAME}:${IMAGE_TAG}'
|
assert_contains "$STAGING_COMPOSE" 'image: ${ORGFRONT_IMAGE_NAME}:${IMAGE_TAG}'
|
||||||
assert_contains "$PULL_COMPOSE" "context: ./orgfront"
|
assert_contains "$PULL_COMPOSE" "context: ."
|
||||||
assert_contains "$DEPLOY_TEMPLATE" "../../orgfront:/app"
|
assert_contains "$PULL_COMPOSE" "dockerfile: ./orgfront/Dockerfile"
|
||||||
assert_contains "$DEPLOY_TEMPLATE" "./orgfront/vite.config.ts:/app/vite.config.ts:ro"
|
assert_contains "$PULL_COMPOSE" "VITE_ORGFRONT_PUBLIC_URL: \${ORGFRONT_URL:-}"
|
||||||
assert_contains "$DEPLOY_TEMPLATE" "./orgfront/auth.ts:/app/src/lib/auth.ts:ro"
|
assert_not_contains "$PULL_COMPOSE" "./orgfront:/app"
|
||||||
|
assert_contains "$DEPLOY_TEMPLATE" "dockerfile: ./orgfront/Dockerfile"
|
||||||
|
assert_contains "$DEPLOY_TEMPLATE" "VITE_ORGFRONT_PUBLIC_URL: \${ORGFRONT_URL}"
|
||||||
|
assert_not_contains "$DEPLOY_TEMPLATE" "../../orgfront:/app"
|
||||||
|
assert_not_contains "$DEPLOY_TEMPLATE" "./orgfront/vite.config.ts:/app/vite.config.ts:ro"
|
||||||
|
assert_not_contains "$DEPLOY_TEMPLATE" "./orgfront/auth.ts:/app/src/lib/auth.ts:ro"
|
||||||
|
|
||||||
assert_contains "$BUILD_RC" "Build and push orgfront RC image"
|
assert_contains "$BUILD_RC" "Build and push orgfront RC image"
|
||||||
assert_contains "$BUILD_RC" "context: ./orgfront"
|
assert_contains "$BUILD_RC" "context: ."
|
||||||
|
assert_contains "$BUILD_RC" "file: ./orgfront/Dockerfile"
|
||||||
assert_contains "$BUILD_RC" "/baron_sso/orgfront:"
|
assert_contains "$BUILD_RC" "/baron_sso/orgfront:"
|
||||||
|
|
||||||
assert_contains "$CODE_CHECK" "run_orgfront_tests"
|
assert_contains "$CODE_CHECK" "run_orgfront_tests"
|
||||||
|
|||||||
102
test/production_image_release_policy_test.sh
Normal file
102
test/production_image_release_policy_test.sh
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
|
||||||
|
assert_contains() {
|
||||||
|
local file="$1"
|
||||||
|
local pattern="$2"
|
||||||
|
if ! grep -Fq -- "$pattern" "$file"; then
|
||||||
|
echo "ERROR: missing pattern in $file: $pattern" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_not_contains() {
|
||||||
|
local file="$1"
|
||||||
|
local pattern="$2"
|
||||||
|
if grep -Fq -- "$pattern" "$file"; then
|
||||||
|
echo "ERROR: forbidden pattern remains in $file: $pattern" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
build_rc="$ROOT_DIR/.gitea/workflows/build_RC.yml"
|
||||||
|
staging_release="$ROOT_DIR/.gitea/workflows/staging_release.yml"
|
||||||
|
production_release="$ROOT_DIR/.gitea/workflows/production_release.yml"
|
||||||
|
production_compose="$ROOT_DIR/docker/docker-compose.template.yaml"
|
||||||
|
|
||||||
|
for file in "$build_rc" "$staging_release" "$production_release" "$production_compose"; do
|
||||||
|
if [[ ! -f "$file" ]]; then
|
||||||
|
echo "ERROR: expected file not found: $file" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
for app in adminfront devfront orgfront; do
|
||||||
|
assert_contains "$build_rc" "Build and push $app RC image"
|
||||||
|
assert_contains "$build_rc" "file: ./$app/Dockerfile"
|
||||||
|
assert_contains "$build_rc" "build-args: |"
|
||||||
|
assert_contains "$build_rc" "VITE_OIDC_AUTHORITY=\${{ vars.VITE_OIDC_AUTHORITY }}"
|
||||||
|
done
|
||||||
|
assert_contains "$build_rc" "Validate RC build configuration"
|
||||||
|
assert_contains "$build_rc" "Missing required RC build value"
|
||||||
|
assert_contains "$build_rc" "Check Gitea repo variables/secrets"
|
||||||
|
assert_contains "$build_rc" "VITE_ADMIN_PUBLIC_URL=\${{ vars.ADMINFRONT_URL }}"
|
||||||
|
assert_contains "$build_rc" "VITE_DEVFRONT_PUBLIC_URL=\${{ vars.DEVFRONT_URL }}"
|
||||||
|
assert_contains "$build_rc" "VITE_ORGFRONT_PUBLIC_URL=\${{ vars.ORGFRONT_URL }}"
|
||||||
|
assert_contains "$build_rc" "ORGFRONT_URL=\${{ vars.ORGFRONT_URL }}"
|
||||||
|
|
||||||
|
assert_contains "$staging_release" "CLICKHOUSE_PASSWORD=\${{ secrets.CLICKHOUSE_PASSWORD }}"
|
||||||
|
assert_not_contains "$staging_release" "CLICKHOUSE_PASSWORD=\${{ vars.CLICKHOUSE_PASSWORD }}"
|
||||||
|
assert_contains "$staging_release" "PROFILE_CACHE_TTL=\${{ vars.PROFILE_CACHE_TTL }}"
|
||||||
|
assert_contains "$staging_release" "KRATOS_UI_NODE_VERSION=\${{ vars.KRATOS_UI_NODE_VERSION }}"
|
||||||
|
assert_contains "$staging_release" "Missing required staging .env value"
|
||||||
|
assert_contains "$staging_release" "Check Gitea repo variables/secrets"
|
||||||
|
assert_contains "$staging_release" "scp scripts/render_ory_config.sh"
|
||||||
|
assert_contains "$staging_release" "scp compose.ory.yaml"
|
||||||
|
assert_not_contains "$staging_release" "scp docker/compose.ory.yaml"
|
||||||
|
assert_contains "$staging_release" "bash scripts/render_ory_config.sh"
|
||||||
|
assert_contains "$staging_release" "chmod -R 777 config/.generated/ory"
|
||||||
|
|
||||||
|
assert_contains "$production_release" "for image in backend userfront adminfront devfront orgfront; do"
|
||||||
|
assert_contains "$production_release" 'docker://${HARBOR_HOSTNAME}/baron_sso/${image}:${BASE_TAG}'
|
||||||
|
assert_contains "$production_release" 'docker://${HARBOR_HOSTNAME}/baron_sso/${image}:${RE_TAG}'
|
||||||
|
assert_contains "$production_release" "ADMINFRONT_IMAGE_NAME: \${{ vars.HARBOR_HOSTNAME }}/baron_sso/adminfront"
|
||||||
|
assert_contains "$production_release" "DEVFRONT_IMAGE_NAME: \${{ vars.HARBOR_HOSTNAME }}/baron_sso/devfront"
|
||||||
|
assert_contains "$production_release" "ORGFRONT_IMAGE_NAME: \${{ vars.HARBOR_HOSTNAME }}/baron_sso/orgfront"
|
||||||
|
assert_contains "$production_release" "USERFRONT_URL=\${{ vars.PROD_FRONTEND_URL }}"
|
||||||
|
assert_contains "$production_release" "BACKEND_URL=\${{ vars.PROD_BACKEND_URL }}"
|
||||||
|
assert_contains "$production_release" "USERFRONT_PORT=\${{ vars.PROD_FRONTEND_PORT }}"
|
||||||
|
assert_contains "$production_release" "PROD_BACKEND_PORT=\${{ vars.PROD_BACKEND_PORT }}"
|
||||||
|
assert_contains "$production_release" "BACKEND_PORT=3000"
|
||||||
|
assert_contains "$production_release" "ADMINFRONT_URL=\${{ vars.ADMINFRONT_URL }}"
|
||||||
|
assert_contains "$production_release" "DEVFRONT_URL=\${{ vars.DEVFRONT_URL }}"
|
||||||
|
assert_contains "$production_release" "ORGFRONT_URL=\${{ vars.ORGFRONT_URL }}"
|
||||||
|
assert_contains "$production_release" "VITE_OIDC_AUTHORITY=\${{ vars.VITE_OIDC_AUTHORITY }}"
|
||||||
|
assert_contains "$production_release" "ADMINFRONT_CALLBACK_URLS=\${{ vars.ADMINFRONT_CALLBACK_URLS }}"
|
||||||
|
assert_contains "$production_release" "DEVFRONT_CALLBACK_URLS=\${{ vars.DEVFRONT_CALLBACK_URLS }}"
|
||||||
|
assert_contains "$production_release" "ORGFRONT_CALLBACK_URLS=\${{ vars.ORGFRONT_CALLBACK_URLS }}"
|
||||||
|
assert_contains "$production_release" "ADMINFRONT_PORT=\${{ vars.ADMINFRONT_PORT }}"
|
||||||
|
assert_contains "$production_release" "DEVFRONT_PORT=\${{ vars.DEVFRONT_PORT }}"
|
||||||
|
assert_contains "$production_release" "ORGFRONT_PORT=\${{ vars.ORGFRONT_PORT }}"
|
||||||
|
assert_contains "$production_release" "export ADMINFRONT_IMAGE_NAME='\${ADMINFRONT_IMAGE_NAME}'"
|
||||||
|
assert_contains "$production_release" "export DEVFRONT_IMAGE_NAME='\${DEVFRONT_IMAGE_NAME}'"
|
||||||
|
assert_contains "$production_release" "export ORGFRONT_IMAGE_NAME='\${ORGFRONT_IMAGE_NAME}'"
|
||||||
|
assert_contains "$production_release" "Missing required production .env value"
|
||||||
|
assert_not_contains "$production_release" "PROD_USERFRONT_URL"
|
||||||
|
assert_not_contains "$production_release" "PROD_USERFRONT_PORT"
|
||||||
|
|
||||||
|
for app in adminfront devfront orgfront; do
|
||||||
|
assert_contains "$production_compose" "$app:"
|
||||||
|
done
|
||||||
|
assert_contains "$production_compose" 'image: ${ADMINFRONT_IMAGE_NAME}:${IMAGE_TAG}'
|
||||||
|
assert_contains "$production_compose" 'image: ${DEVFRONT_IMAGE_NAME}:${IMAGE_TAG}'
|
||||||
|
assert_contains "$production_compose" 'image: ${ORGFRONT_IMAGE_NAME}:${IMAGE_TAG}'
|
||||||
|
assert_contains "$production_compose" 'API_PROXY_TARGET=http://baron_backend:${BACKEND_PORT:-3000}'
|
||||||
|
assert_contains "$production_compose" '${PROD_BACKEND_PORT:-3010}:3000'
|
||||||
|
assert_contains "$production_compose" '${USERFRONT_PORT:-80}:5000'
|
||||||
|
assert_contains "$production_compose" 'BACKEND_PORT=3000'
|
||||||
|
assert_contains "$production_compose" 'http://127.0.0.1:3000/health'
|
||||||
|
|
||||||
|
echo "production image release policy checks passed"
|
||||||
@@ -30,6 +30,9 @@ adminfront_vite="adminfront/vite.config.ts"
|
|||||||
adminfront_runtime="adminfront/scripts/runtime-mode.sh"
|
adminfront_runtime="adminfront/scripts/runtime-mode.sh"
|
||||||
devfront_runtime="devfront/scripts/runtime-mode.sh"
|
devfront_runtime="devfront/scripts/runtime-mode.sh"
|
||||||
orgfront_runtime="orgfront/scripts/runtime-mode.sh"
|
orgfront_runtime="orgfront/scripts/runtime-mode.sh"
|
||||||
|
adminfront_dockerfile="adminfront/Dockerfile"
|
||||||
|
devfront_dockerfile="devfront/Dockerfile"
|
||||||
|
orgfront_dockerfile="orgfront/Dockerfile"
|
||||||
|
|
||||||
for file in \
|
for file in \
|
||||||
"$staging_pull" \
|
"$staging_pull" \
|
||||||
@@ -42,7 +45,10 @@ for file in \
|
|||||||
"$orgfront_vite" \
|
"$orgfront_vite" \
|
||||||
"$adminfront_runtime" \
|
"$adminfront_runtime" \
|
||||||
"$devfront_runtime" \
|
"$devfront_runtime" \
|
||||||
"$orgfront_runtime"
|
"$orgfront_runtime" \
|
||||||
|
"$adminfront_dockerfile" \
|
||||||
|
"$devfront_dockerfile" \
|
||||||
|
"$orgfront_dockerfile"
|
||||||
do
|
do
|
||||||
if [ ! -f "$file" ]; then
|
if [ ! -f "$file" ]; then
|
||||||
echo "missing expected file: $file" >&2
|
echo "missing expected file: $file" >&2
|
||||||
@@ -72,8 +78,11 @@ for app in adminfront devfront orgfront; do
|
|||||||
assert_contains "$pull_compose" "$app:"
|
assert_contains "$pull_compose" "$app:"
|
||||||
assert_contains "$pull_compose" "context: ."
|
assert_contains "$pull_compose" "context: ."
|
||||||
assert_contains "$pull_compose" "dockerfile: ./$app/Dockerfile"
|
assert_contains "$pull_compose" "dockerfile: ./$app/Dockerfile"
|
||||||
|
assert_contains "$pull_compose" "VITE_OIDC_AUTHORITY: \${VITE_OIDC_AUTHORITY:-}"
|
||||||
assert_not_contains "$pull_compose" "context: ./$app"
|
assert_not_contains "$pull_compose" "context: ./$app"
|
||||||
|
assert_not_contains "$pull_compose" "./$app:/app"
|
||||||
done
|
done
|
||||||
|
assert_not_contains "$pull_compose" "/app/node_modules"
|
||||||
assert_contains "$pull_compose" "dockerfile: userfront/Dockerfile"
|
assert_contains "$pull_compose" "dockerfile: userfront/Dockerfile"
|
||||||
assert_not_contains "$pull_compose" 'target: ${USERFRONT_BUILD_TARGET:-dev}'
|
assert_not_contains "$pull_compose" 'target: ${USERFRONT_BUILD_TARGET:-dev}'
|
||||||
assert_not_contains "$pull_compose" "target: dev"
|
assert_not_contains "$pull_compose" "target: dev"
|
||||||
@@ -82,8 +91,12 @@ assert_contains "$pull_compose" "http://127.0.0.1:5173/"
|
|||||||
assert_contains "$pull_compose" "http://127.0.0.1:5175/"
|
assert_contains "$pull_compose" "http://127.0.0.1:5175/"
|
||||||
assert_contains "$pull_compose" 'APP_ENV=${APP_ENV:-stage}'
|
assert_contains "$pull_compose" 'APP_ENV=${APP_ENV:-stage}'
|
||||||
|
|
||||||
assert_contains "$deploy_compose" "sh ./scripts/runtime-mode.sh"
|
assert_contains "$deploy_compose" "dockerfile: ./adminfront/Dockerfile"
|
||||||
|
assert_contains "$deploy_compose" "dockerfile: ./devfront/Dockerfile"
|
||||||
|
assert_contains "$deploy_compose" "dockerfile: ./orgfront/Dockerfile"
|
||||||
|
assert_not_contains "$deploy_compose" "sh ./scripts/runtime-mode.sh"
|
||||||
assert_not_contains "$deploy_compose" "command: npm run dev"
|
assert_not_contains "$deploy_compose" "command: npm run dev"
|
||||||
|
assert_not_contains "$deploy_compose" "image: node:20-alpine"
|
||||||
assert_contains "$deploy_gateway" "root /usr/share/nginx/html;"
|
assert_contains "$deploy_gateway" "root /usr/share/nginx/html;"
|
||||||
assert_contains "$deploy_gateway" 'try_files $uri $uri/ /index.html;'
|
assert_contains "$deploy_gateway" 'try_files $uri $uri/ /index.html;'
|
||||||
assert_not_contains "$deploy_gateway" "baron_userfront"
|
assert_not_contains "$deploy_gateway" "baron_userfront"
|
||||||
@@ -96,6 +109,21 @@ for app in adminfront devfront orgfront; do
|
|||||||
assert_not_contains ".gitea/workflows/build_RC.yml" "context: ./$app"
|
assert_not_contains ".gitea/workflows/build_RC.yml" "context: ./$app"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
for app in adminfront devfront orgfront; do
|
||||||
|
dockerfile="$app/Dockerfile"
|
||||||
|
assert_contains "$dockerfile" "COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./"
|
||||||
|
assert_contains "$dockerfile" "RUN pnpm install --frozen-lockfile --ignore-scripts"
|
||||||
|
assert_contains "$dockerfile" "FROM node:24-alpine AS production"
|
||||||
|
assert_contains "$dockerfile" "COPY scripts/serve_frontend_prod.mjs ./serve_frontend_prod.mjs"
|
||||||
|
assert_contains "$dockerfile" "RUN npm run build"
|
||||||
|
assert_contains "$dockerfile" 'CMD ["node", "./serve_frontend_prod.mjs"]'
|
||||||
|
assert_not_contains "$dockerfile" "cd common && pnpm install"
|
||||||
|
assert_not_contains "$dockerfile" "npm install -g serve"
|
||||||
|
assert_not_contains "$dockerfile" "runtime-mode.sh"
|
||||||
|
done
|
||||||
|
assert_contains "scripts/serve_frontend_prod.mjs" "pathname === \"/api\" || pathname.startsWith(\"/api/\")"
|
||||||
|
assert_contains "scripts/serve_frontend_prod.mjs" "API_PROXY_TARGET"
|
||||||
|
|
||||||
assert_contains "$adminfront_vite" "/tmp/baron-sso-adminfront-dist"
|
assert_contains "$adminfront_vite" "/tmp/baron-sso-adminfront-dist"
|
||||||
assert_contains "$adminfront_vite" "/tmp/baron-sso-adminfront-vite-cache"
|
assert_contains "$adminfront_vite" "/tmp/baron-sso-adminfront-vite-cache"
|
||||||
assert_contains "adminfront/biome.json" '".vite"'
|
assert_contains "adminfront/biome.json" '".vite"'
|
||||||
|
|||||||
Reference in New Issue
Block a user