diff --git a/.dockerignore b/.dockerignore index cf49945886..857edbc107 100644 --- a/.dockerignore +++ b/.dockerignore @@ -107,6 +107,7 @@ build/Release # Dependency directories node_modules +**/node_modules jspm_packages # Typescript v1 declaration files @@ -145,4 +146,4 @@ Dockerfile .dockerignore # git -.gitignore \ No newline at end of file +.gitignore diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ebdd425e6e..97265b574b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -286,19 +286,3 @@ jobs: - name: Build run: pnpm build - - validate_helm: - name: Validate Helm - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@main - - - name: Install Helm - uses: azure/setup-helm@v4 - - - name: Helm lint - run: helm lint ./nginx-serve/helm --values ./nginx-serve/helm/values-test.yaml - - - name: Helm template - run: helm template ./nginx-serve/helm --values ./nginx-serve/helm/values-test.yaml diff --git a/.github/workflows/publish-nginx-serve.yml b/.github/workflows/publish-nginx-serve.yml deleted file mode 100644 index 28c91fbc56..0000000000 --- a/.github/workflows/publish-nginx-serve.yml +++ /dev/null @@ -1,147 +0,0 @@ -name: Publish Helm - -on: - workflow_dispatch: - push: - branches: - - develop - - project/* - -permissions: - packages: write - - -jobs: - publish_image: - name: Publish Docker Image - runs-on: ubuntu-latest - - outputs: - docker_image_name: ${{ steps.prep.outputs.tagged_image_name }} - docker_image_tag: ${{ steps.prep.outputs.tag }} - docker_image: ${{ steps.prep.outputs.tagged_image }} - - steps: - - uses: actions/checkout@main - - - name: Login to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: 🐳 Prepare Docker - id: prep - env: - IMAGE_NAME: ghcr.io/${{ github.repository }} - run: | - BRANCH_NAME=$(echo $GITHUB_REF_NAME | sed 's|[/:]|-|' | tr '[:upper:]' '[:lower:]' | sed 's/_/-/g' | cut -c1-100 | sed 's/-*$//') - - # XXX: Check if there is a slash in the BRANCH_NAME eg: project/add-docker - if [[ "$BRANCH_NAME" == *"/"* ]]; then - # XXX: Change the docker image package to -alpha - IMAGE_NAME="$IMAGE_NAME-alpha" - TAG="$(echo "$BRANCH_NAME" | sed 's|/|-|g').$(echo $GITHUB_SHA | head -c7)" - else - TAG="$BRANCH_NAME.$(echo $GITHUB_SHA | head -c7)" - fi - - IMAGE_NAME=$(echo $IMAGE_NAME | tr '[:upper:]' '[:lower:]') - echo "tagged_image_name=${IMAGE_NAME}" >> $GITHUB_OUTPUT - echo "tag=${TAG}" >> $GITHUB_OUTPUT - echo "tagged_image=${IMAGE_NAME}:${TAG}" >> $GITHUB_OUTPUT - echo "::notice::Tagged docker image: ${IMAGE_NAME}:${TAG}" - - - name: 🐳 Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@v3 - - - name: 🐳 Cache Docker layers - uses: actions/cache@v4 - with: - path: /tmp/.buildx-cache - key: ${{ runner.os }}-buildx-${{ github.ref }} - restore-keys: | - ${{ runner.os }}-buildx-refs/develop - ${{ runner.os }}-buildx- - - - name: 🐳 Docker build - uses: docker/build-push-action@v6 - with: - context: . - builder: ${{ steps.buildx.outputs.name }} - file: nginx-serve/Dockerfile - target: nginx-serve - load: true - push: true - tags: ${{ steps.prep.outputs.tagged_image }} - cache-from: type=local,src=/tmp/.buildx-cache - cache-to: type=local,dest=/tmp/.buildx-cache-new - build-args: | - "APP_SENTRY_TRACES_SAMPLE_RATE=0.8" - "APP_SENTRY_REPLAYS_SESSION_SAMPLE_RATE=0.8" - "APP_SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE=0.8" - - - name: 🐳 Move docker cache - run: | - rm -rf /tmp/.buildx-cache - mv /tmp/.buildx-cache-new /tmp/.buildx-cache - - publish_helm: - name: Publish Helm - needs: publish_image - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Login to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Install Helm - uses: azure/setup-helm@v3 - - - name: Tag docker image in Helm Chart values.yaml - env: - IMAGE_NAME: ${{ needs.publish_image.outputs.docker_image_name }} - IMAGE_TAG: ${{ needs.publish_image.outputs.docker_image_tag }} - run: | - # Update values.yaml with latest docker image - sed -i "s|SET-BY-CICD-IMAGE|$IMAGE_NAME|" nginx-serve/helm/values.yaml - sed -i "s/SET-BY-CICD-TAG/$IMAGE_TAG/" nginx-serve/helm/values.yaml - - - name: Package Helm Chart - id: set-variables - run: | - # XXX: Check if there is a slash in the BRANCH_NAME eg: project/add-docker - if [[ "$GITHUB_REF_NAME" == *"/"* ]]; then - # XXX: Change the helm chart to -alpha - sed -i 's/^name: \(.*\)/name: \1-alpha/' nginx-serve/helm/Chart.yaml - fi - - SHA_SHORT=$(git rev-parse --short HEAD) - sed -i "s/SET-BY-CICD/$SHA_SHORT/g" nginx-serve/helm/Chart.yaml - helm package ./nginx-serve/helm -d .helm-charts - - - name: Push Helm Chart - env: - IMAGE: ${{ needs.publish_image.outputs.docker_image }} - OCI_REPO: oci://ghcr.io/${{ github.repository }} - run: | - OCI_REPO=$(echo $OCI_REPO | tr '[:upper:]' '[:lower:]') - PACKAGE_FILE=$(ls .helm-charts/*.tgz | head -n 1) - echo "# Helm Chart" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "Tagged Image: **$IMAGE**" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "Helm push output" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo '```bash' >> $GITHUB_STEP_SUMMARY - helm push "$PACKAGE_FILE" $OCI_REPO >> $GITHUB_STEP_SUMMARY - echo '```' >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/publish-web-app-serve.yml b/.github/workflows/publish-web-app-serve.yml new file mode 100644 index 0000000000..40c0961f99 --- /dev/null +++ b/.github/workflows/publish-web-app-serve.yml @@ -0,0 +1,23 @@ +name: Publish web app serve + +on: + workflow_dispatch: + push: + branches: + - develop + - project/* + +permissions: + packages: write + +jobs: + publish_image: + name: Publish Docker Image + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Publish web-app-serve + uses: toggle-corp/web-app-serve/.github/actions/publish-web-app-serve@v0.1.1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..905ba4ca1d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,55 @@ +# syntax=docker/dockerfile:1-labs + +# -------------------------- Dev --------------------------------------- +FROM node:20-bookworm AS dev + +ENV PNPM_HOME="/pnpm" +ENV PATH="$PNPM_HOME:$PATH" +RUN corepack enable + +WORKDIR /code + +# -------------------------- Nginx - Builder -------------------------------- +FROM dev AS web-app-build + +# NOTE: --parents is not yet available in stable syntax, using docker/dockerfile:1-labs +COPY --parents package.json pnpm-lock.yaml pnpm-workspace.yaml ./**/package.json patches/ /code/ + +RUN corepack prepare --activate + +RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile + +COPY . /code/ + +# Configuration Example +# These environment variables can be dynamicallly updated in containers. +# NOTE: These variables are not included in the build but they should still be valid +# See the schema field in ./app/env.ts +ENV APP_TITLE=GO +ENV APP_ENVIRONMENT=staging +ENV APP_API_ENDPOINT=https://goadmin-example.ifrc.org/api/ +ENV APP_ADMIN_URL=https://goadmin-example.ifrc.org/admin/ +ENV APP_MAPBOX_ACCESS_TOKEN=example-mapbox-access-token +ENV APP_TINY_API_KEY=example-tiny-api-key +ENV APP_RISK_API_ENDPOINT=https://go-risk-example.northeurope.cloudapp.azure.com/api/ +ENV APP_SDT_URL=https://surveydesigner-example-api.ifrc.org +ENV APP_SENTRY_DSN=https://xyz@example.com/123 +ENV APP_SENTRY_TRACES_SAMPLE_RATE=0.2 +ENV APP_SENTRY_REPLAYS_SESSION_SAMPLE_RATE=0.2 +ENV APP_SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE=0.2 +ENV APP_GOOGLE_ANALYTICS_ID=example-google-analytics-id + +# NOTE: WEB_APP_SERVE_ENABLED will skip defining the above env variables +# See overrideDefine field in ./app/env.ts +RUN WEB_APP_SERVE_ENABLED=true pnpm build + +# --------------------------------------------------------------------------- +FROM ghcr.io/toggle-corp/web-app-serve:v0.1.1 AS web-app-serve + +LABEL maintainer="IFRC" +LABEL org.opencontainers.image.source="https://github.com/IFRCGo/go-web-app" + +# NOTE: Used by apply-config.sh +ENV APPLY_CONFIG__SOURCE_DIRECTORY=/code/build/ + +COPY --from=web-app-build /code/build "$APPLY_CONFIG__SOURCE_DIRECTORY" diff --git a/app/env.ts b/app/env.ts index 15b21e39f8..fcde62562d 100644 --- a/app/env.ts +++ b/app/env.ts @@ -1,29 +1,40 @@ -import { defineConfig, Schema } from '@julr/vite-plugin-validate-env'; +import { + Schema, + defineConfig, + overrideDefineForWebAppServe, +} from '@julr/vite-plugin-validate-env'; + +const webAppServeEnabled = process.env.WEB_APP_SERVE_ENABLED?.toLowerCase() === 'true'; +if (webAppServeEnabled) { + console.warn('Building application for web-app-serve') +} +const overrideDefine = webAppServeEnabled + ? overrideDefineForWebAppServe + : undefined; export default defineConfig({ - APP_TITLE: Schema.string(), - APP_ENVIRONMENT: (key, value) => { - // NOTE: APP_ENVIRONMENT_PLACEHOLDER is meant to be used with image builds - // The value will be later replaced with the actual value - const regex = /^production|staging|testing|alpha-\d+|development|APP_ENVIRONMENT_PLACEHOLDER$/; - const valid = !!value && (value.match(regex) !== null); - if (!valid) { - throw new Error(`Value for environment variable "${key}" must match regex "${regex}", instead received "${value}"`); - } - if (value === 'APP_ENVIRONMENT_PLACEHOLDER') { - console.warn(`Using ${value} for app environment. Make sure to not use this for builds without helm chart`) - } - return value as ('production' | 'staging' | 'testing' | `alpha-${number}` | 'development' | 'APP_ENVIRONMENT_PLACEHOLDER'); + validator: "builtin", + schema: { + APP_TITLE: Schema.string(), + APP_ENVIRONMENT: (key, value) => { + const regex = /^production|staging|testing|alpha-\d+|development$/; + const valid = !!value && (value.match(regex) !== null); + if (!valid) { + throw new Error(`Value for environment variable "${key}" must match regex "${regex}", instead received "${value}"`); + } + return value as ('production' | 'staging' | 'testing' | `alpha-${number}` | 'development'); + }, + APP_API_ENDPOINT: Schema.string({ format: 'url', protocol: true, tld: false }), + APP_ADMIN_URL: Schema.string.optional({ format: 'url', protocol: true, tld: false }), + APP_MAPBOX_ACCESS_TOKEN: Schema.string(), + APP_TINY_API_KEY: Schema.string(), + APP_RISK_API_ENDPOINT: Schema.string({ format: 'url', protocol: true }), + APP_SDT_URL: Schema.string.optional({ format: 'url', protocol: true, tld: false }), + APP_SENTRY_DSN: Schema.string.optional(), + APP_SENTRY_TRACES_SAMPLE_RATE: Schema.number.optional(), + APP_SENTRY_REPLAYS_SESSION_SAMPLE_RATE: Schema.number.optional(), + APP_SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE: Schema.number.optional(), + APP_GOOGLE_ANALYTICS_ID: Schema.string.optional(), }, - APP_API_ENDPOINT: Schema.string({ format: 'url', protocol: true, tld: false }), - APP_ADMIN_URL: Schema.string.optional({ format: 'url', protocol: true, tld: false }), - APP_MAPBOX_ACCESS_TOKEN: Schema.string(), - APP_TINY_API_KEY: Schema.string(), - APP_RISK_API_ENDPOINT: Schema.string({ format: 'url', protocol: true }), - APP_SDT_URL: Schema.string.optional({ format: 'url', protocol: true, tld: false }), - APP_SENTRY_DSN: Schema.string.optional(), - APP_SENTRY_TRACES_SAMPLE_RATE: Schema.number.optional(), - APP_SENTRY_REPLAYS_SESSION_SAMPLE_RATE: Schema.number.optional(), - APP_SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE: Schema.number.optional(), - APP_GOOGLE_ANALYTICS_ID: Schema.string.optional(), + overrideDefine, }); diff --git a/app/package.json b/app/package.json index dd7cc7a6e5..d4e29a9fb2 100644 --- a/app/package.json +++ b/app/package.json @@ -62,7 +62,7 @@ "@eslint/eslintrc": "^3.1.0", "@eslint/js": "^9.20.0", "@eslint/json": "^0.5.0", - "@julr/vite-plugin-validate-env": "^1.0.1", + "@julr/vite-plugin-validate-env": "git+https://github.com/toggle-corp/vite-plugin-validate-env#v2.2.0-tc.1", "@types/file-saver": "^2.0.5", "@types/mapbox-gl": "^1.13.0", "@types/node": "^20.11.6", diff --git a/app/vite.config.ts b/app/vite.config.ts index d719f9fb50..93f3a80f8a 100644 --- a/app/vite.config.ts +++ b/app/vite.config.ts @@ -11,8 +11,6 @@ import { VitePluginRadar } from 'vite-plugin-radar'; import svgr from 'vite-plugin-svgr'; import pkg from './package.json'; -import envConfig from './env'; - /* Get commit hash */ const commitHash = execSync('git rev-parse --short HEAD').toString(); @@ -45,7 +43,9 @@ export default defineConfig(({ mode }) => { reactSwc(), tsconfigPaths(), webfontDownload(), - validateEnv(envConfig), + validateEnv({ + configFile: 'env', + }), isProd ? compression() : undefined, isProd ? visualizer({ sourcemap: true }) : undefined, VitePluginRadar({ diff --git a/nginx-serve/Dockerfile b/nginx-serve/Dockerfile deleted file mode 100644 index f7df63c741..0000000000 --- a/nginx-serve/Dockerfile +++ /dev/null @@ -1,57 +0,0 @@ -# syntax=docker/dockerfile:1-labs - -# -------------------------- Dev --------------------------------------- -FROM node:20-bookworm AS dev - -ENV PNPM_HOME="/pnpm" -ENV PATH="$PNPM_HOME:$PATH" -RUN corepack enable - -WORKDIR /code - -# -------------------------- Nginx - Builder -------------------------------- -FROM dev AS nginx-build - -# NOTE: --parents is not yet available in stable syntax, using docker/dockerfile:1-labs -COPY --parents package.json pnpm-lock.yaml pnpm-workspace.yaml ./**/package.json patches/ /code/ - -RUN corepack prepare --activate - -RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile - -COPY . /code/ - -# Dynamic configs. Can be changed with containers. (Placeholder values) -ENV APP_TITLE=APP_TITLE_PLACEHOLDER -ENV APP_ENVIRONMENT=APP_ENVIRONMENT_PLACEHOLDER -ENV APP_MAPBOX_ACCESS_TOKEN=APP_MAPBOX_ACCESS_TOKEN_PLACEHOLDER -ENV APP_TINY_API_KEY=APP_TINY_API_KEY_PLACEHOLDER -ENV APP_API_ENDPOINT=https://APP-API-ENDPOINT-PLACEHOLDER.COM/ -ENV APP_RISK_API_ENDPOINT=https://APP-RISK-API-ENDPOINT-PLACEHOLDER.COM/ -ENV APP_SDT_URL=https://APP-SDT-URL-PLACEHOLDER.COM/ -ENV APP_SENTRY_DSN=https://APP-SENTRY-DSN-PLACEHOLDER.COM - -# Static configs (Configured when building docker image) -ARG APP_SENTRY_TRACES_SAMPLE_RATE= -ENV APP_SENTRY_TRACES_SAMPLE_RATE=${APP_SENTRY_TRACES_SAMPLE_RATE} -ARG APP_SENTRY_REPLAYS_SESSION_SAMPLE_RATE= -ENV APP_SENTRY_REPLAYS_SESSION_SAMPLE_RATE=${APP_SENTRY_REPLAYS_SESSION_SAMPLE_RATE} -ARG APP_SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE= -ENV APP_SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE=${APP_SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE} - -RUN pnpm build - -# --------------------------------------------------------------------------- -FROM nginx:bookworm AS nginx-serve - -LABEL maintainer="IFRC" -LABEL org.opencontainers.image.source="https://github.com/IFRCGo/go-web-app" - -COPY ./nginx-serve/apply-config.sh /docker-entrypoint.d/ -COPY ./nginx-serve/nginx.conf.template /etc/nginx/templates/default.conf.template -COPY --from=nginx-build /code/build /code/build - -# NOTE: Used by apply-config.sh -ENV APPLY_CONFIG__SOURCE_DIRECTORY=/code/build/ -ENV APPLY_CONFIG__DESTINATION_DIRECTORY=/usr/share/nginx/html/ -ENV APPLY_CONFIG__OVERWRITE_DESTINATION=true diff --git a/nginx-serve/apply-config.sh b/nginx-serve/apply-config.sh deleted file mode 100755 index 1361d3390e..0000000000 --- a/nginx-serve/apply-config.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/bash -xe - -SOURCE_DIRECTORY=${APPLY_CONFIG__SOURCE_DIRECTORY?Required} -DESTINATION_DIRECTORY=${APPLY_CONFIG__DESTINATION_DIRECTORY?Required} - -# Parse arguments for --overwrite option -OVERWRITE_DESTINATION=${APPLY_CONFIG__OVERWRITE_DESTINATION:-false} -for arg in "$@"; do - if [[ "$arg" == "--overwrite" ]]; then - OVERWRITE_DESTINATION=true - fi -done - -if [ -d "$DESTINATION_DIRECTORY" ]; then - if [ "$OVERWRITE_DESTINATION" == "true" ]; then - echo "Destination directory <$DESTINATION_DIRECTORY> already exists. Force deleting..." - rm -rf "$DESTINATION_DIRECTORY" - else - echo "Destination directory <$DESTINATION_DIRECTORY> already exists. Please delete and try again, or use --overwrite to force delete." - exit 1 - fi -fi - -mkdir -p $(dirname "$DESTINATION_DIRECTORY") -cp -r --no-target-directory "$SOURCE_DIRECTORY" "$DESTINATION_DIRECTORY" - -find "$DESTINATION_DIRECTORY" -type f -exec sed -i "s|\|$APP_TITLE|g" {} + -find "$DESTINATION_DIRECTORY" -type f -exec sed -i "s|\|$APP_ENVIRONMENT|g" {} + -find "$DESTINATION_DIRECTORY" -type f -exec sed -i "s|\|$APP_MAPBOX_ACCESS_TOKEN|g" {} + -find "$DESTINATION_DIRECTORY" -type f -exec sed -i "s|\|$APP_TINY_API_KEY|g" {} + -# NOTE: We don't need a word boundary at end as we already have a trailing slash -find "$DESTINATION_DIRECTORY" -type f -exec sed -i "s|\|$APP_SENTRY_DSN|g" {} + - -# Show diffs (Useful to debug issues) -set +xe -find "$SOURCE_DIRECTORY" -type f -printf '%P\n' | while IFS= read -r file; do - diff -W 100 <(fold -w 100 "$SOURCE_DIRECTORY/$file") <(fold -w 100 "$DESTINATION_DIRECTORY/$file") --suppress-common-lines -done diff --git a/nginx-serve/helm/Chart.yaml b/nginx-serve/helm/Chart.yaml deleted file mode 100644 index 91615a52af..0000000000 --- a/nginx-serve/helm/Chart.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: v2 -name: ifrcgo-web-app-nginx-serve -description: "Helm Chart to deploy the IFRC Web App" -type: application -version: 0.0.1-SET-BY-CICD -sources: - - https://github.com/IFRCGo/go-web-app diff --git a/nginx-serve/helm/templates/_helpers.tpl b/nginx-serve/helm/templates/_helpers.tpl deleted file mode 100644 index 7fbb177a2f..0000000000 --- a/nginx-serve/helm/templates/_helpers.tpl +++ /dev/null @@ -1,32 +0,0 @@ -{{/* - Expand the name of the chart. -*/}} -{{- define "ifrcgo-web-app.name" -}} - {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* - Create a default fully qualified app name. - We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). - If release name contains chart name it will be used as a full name. - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-label-names -*/}} -{{- define "ifrcgo-web-app.fullname" -}} - {{- if .Values.fullnameOverride -}} - {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} - {{- else -}} - {{- $name := default .Chart.Name .Values.nameOverride -}} - {{- if contains $name .Release.Name -}} - {{- .Release.Name | trunc 63 | trimSuffix "-" -}} - {{- else -}} - {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} - {{- end -}} - {{- end -}} -{{- end -}} - -{{/* - Create chart name and version as used by the chart label. -*/}} -{{- define "ifrcgo-web-app.chart" -}} - {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} -{{- end -}} diff --git a/nginx-serve/helm/templates/configmap.yaml b/nginx-serve/helm/templates/configmap.yaml deleted file mode 100644 index 6162483039..0000000000 --- a/nginx-serve/helm/templates/configmap.yaml +++ /dev/null @@ -1,17 +0,0 @@ -kind: ConfigMap -apiVersion: v1 -metadata: - name: {{ template "ifrcgo-web-app.fullname" . }}-configmap - labels: - component: web-app-deployment - environment: {{ .Values.environment }} - release: {{ .Release.Name }} -data: - APP_TITLE: {{ required "env.APP_TITLE" .Values.env.APP_TITLE | quote }} - APP_ENVIRONMENT: {{ required "env.APP_ENVIRONMENT" .Values.env.APP_ENVIRONMENT | quote }} - APP_API_ENDPOINT: {{ required "env.APP_API_ENDPOINT" .Values.env.APP_API_ENDPOINT | quote }} - APP_MAPBOX_ACCESS_TOKEN: {{ required "env.APP_MAPBOX_ACCESS_TOKEN" .Values.env.APP_MAPBOX_ACCESS_TOKEN | quote }} - APP_TINY_API_KEY: {{ required "env.APP_TINY_API_KEY" .Values.env.APP_TINY_API_KEY | quote }} - APP_RISK_API_ENDPOINT: {{ required "env.APP_RISK_API_ENDPOINT" .Values.env.APP_RISK_API_ENDPOINT | quote }} - APP_SDT_URL: {{ required "env.APP_SDT_URL" .Values.env.APP_SDT_URL | quote }} - APP_SENTRY_DSN: {{ required "env.APP_SENTRY_DSN" .Values.env.APP_SENTRY_DSN | quote }} diff --git a/nginx-serve/helm/templates/deployment.yaml b/nginx-serve/helm/templates/deployment.yaml deleted file mode 100644 index 335cc7086b..0000000000 --- a/nginx-serve/helm/templates/deployment.yaml +++ /dev/null @@ -1,38 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ template "ifrcgo-web-app.fullname" . }} - labels: - environment: {{ .Values.environment }} - release: {{ .Release.Name }} -spec: - replicas: 1 - selector: - matchLabels: - app: {{ template "ifrcgo-web-app.name" . }} - release: {{ .Release.Name }} - run: {{ .Release.Name }} - template: - metadata: - labels: - app: {{ template "ifrcgo-web-app.name" . }} - release: {{ .Release.Name }} - run: {{ .Release.Name }} - spec: - containers: - - name: {{ .Chart.Name }} - image: "{{ .Values.image.name }}:{{ .Values.image.tag }}" - ports: - - name: http - containerPort: 80 - protocol: TCP - resources: - requests: - cpu: {{ .Values.resources.requests.cpu }} - memory: {{ .Values.resources.requests.memory }} - limits: - cpu: {{ .Values.resources.limits.cpu }} - memory: {{ .Values.resources.limits.memory }} - envFrom: - - configMapRef: - name: {{ template "ifrcgo-web-app.fullname" . }}-configmap diff --git a/nginx-serve/helm/templates/ingress.yaml b/nginx-serve/helm/templates/ingress.yaml deleted file mode 100644 index eb55551fe6..0000000000 --- a/nginx-serve/helm/templates/ingress.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: {{ template "ifrcgo-web-app.fullname" . }}-ingress - labels: - app: {{ template "ifrcgo-web-app.name" . }} - environment: {{ .Values.environment }} - release: {{ .Release.Name }} -spec: - ingressClassName: nginx - rules: - - host: {{ required "ingress.host" .Values.ingress.host | quote }} - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: {{ template "ifrcgo-web-app.fullname" . }}-svc - port: - number: 80 diff --git a/nginx-serve/helm/templates/service.yaml b/nginx-serve/helm/templates/service.yaml deleted file mode 100644 index 1cf04941f9..0000000000 --- a/nginx-serve/helm/templates/service.yaml +++ /dev/null @@ -1,18 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ template "ifrcgo-web-app.fullname" . }}-svc - labels: - app: {{ template "ifrcgo-web-app.name" . }} - environment: {{ .Values.environment }} - release: {{ .Release.Name }} -spec: - type: ClusterIP - selector: - app: {{ template "ifrcgo-web-app.name" . }} - release: {{ .Release.Name }} - run: {{ .Release.Name }} - ports: - - protocol: TCP - port: 80 - targetPort: 80 diff --git a/nginx-serve/helm/values-test.yaml b/nginx-serve/helm/values-test.yaml deleted file mode 100644 index 5c5ac98ef0..0000000000 --- a/nginx-serve/helm/values-test.yaml +++ /dev/null @@ -1,17 +0,0 @@ -environment: prod - -image: - name: test-image - tag: test-tag - -ingress: - host: web-app.test.com - -env: - APP_ENVIRONMENT: alpha-1 - APP_API_ENDPOINT: https://alpha-1-api.test.com - APP_MAPBOX_ACCESS_TOKEN: RANDOM_DUMMY_TOKEN - APP_TINY_API_KEY: RANDOM_DUMMY_TOKEN - APP_RISK_API_ENDPOINT: https://risk-1-api.test.com - APP_SENTRY_DSN: https://random-token@random-user@sentry-test.io/10000 - APP_SDT_URL: https://alpha-1-sdt.test.com diff --git a/nginx-serve/helm/values.yaml b/nginx-serve/helm/values.yaml deleted file mode 100644 index 48712cb0be..0000000000 --- a/nginx-serve/helm/values.yaml +++ /dev/null @@ -1,26 +0,0 @@ -environment: prod - -image: - name: SET-BY-CICD-IMAGE - tag: SET-BY-CICD-TAG - -resources: - requests: - cpu: "0.5" - memory: "100Mi" - limits: - cpu: "1" - memory: "100Mi" - -ingress: - host: - -env: - APP_TITLE: IFRC GO - APP_ENVIRONMENT: - APP_API_ENDPOINT: - APP_MAPBOX_ACCESS_TOKEN: - APP_TINY_API_KEY: - APP_RISK_API_ENDPOINT: - APP_SENTRY_DSN: - APP_SDT_URL: diff --git a/nginx-serve/nginx.conf.template b/nginx-serve/nginx.conf.template deleted file mode 100644 index c3ab6a55a7..0000000000 --- a/nginx-serve/nginx.conf.template +++ /dev/null @@ -1,18 +0,0 @@ -# vim: filetype=nginx - -server { - listen 80; - server_name _; - - gzip on; - gzip_comp_level 4; - - gzip_types text/plain text/css application/json - application/x-javascript text/xml application/xml - application/xml+rss text/javascript; - - location / { - alias $APPLY_CONFIG__DESTINATION_DIRECTORY; - try_files $uri /index.html; - } -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 15c912005d..d8ba3d38b7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -102,8 +102,8 @@ importers: specifier: ^0.5.0 version: 0.5.0 '@julr/vite-plugin-validate-env': - specifier: ^1.0.1 - version: 1.3.0(vite@5.4.14(@types/node@20.17.19))(zod@3.24.2) + specifier: git+https://github.com/toggle-corp/vite-plugin-validate-env#v2.2.0-tc.1 + version: https://codeload.github.com/toggle-corp/vite-plugin-validate-env/tar.gz/3225c8405bdadf1168f1fa6f8a6de76c6777b620(vite@5.4.14(@types/node@20.17.19)) '@types/file-saver': specifier: ^2.0.5 version: 2.0.7 @@ -533,9 +533,6 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} - '@antfu/utils@8.1.1': - resolution: {integrity: sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ==} - '@babel/code-frame@7.26.2': resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} engines: {node: '>=6.9.0'} @@ -1347,15 +1344,12 @@ packages: '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} - '@julr/vite-plugin-validate-env@1.3.0': - resolution: {integrity: sha512-J4SYsWh80cNspaUcVtAwqHNKlH37qOkNM0uAtI4MFKSVjU1j6TLcB9CjL8GFUIqUh2YG0PBn+GwrkRX3ywQVow==} - engines: {node: '>=16'} + '@julr/vite-plugin-validate-env@https://codeload.github.com/toggle-corp/vite-plugin-validate-env/tar.gz/3225c8405bdadf1168f1fa6f8a6de76c6777b620': + resolution: {tarball: https://codeload.github.com/toggle-corp/vite-plugin-validate-env/tar.gz/3225c8405bdadf1168f1fa6f8a6de76c6777b620} + version: 2.2.0 + engines: {node: '>=22'} peerDependencies: - vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0 || ^6.0.0 - zod: ^3.0.0 - peerDependenciesMeta: - zod: - optional: true + vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 '@keyv/serialize@1.0.3': resolution: {integrity: sha512-qnEovoOp5Np2JDGonIDL6Ayihw0RhnRh6vxPuHo4RDn1UOzwEo4AeIfpL6UGIrsceWrCMiVPgwRjbHu4vYFc3g==} @@ -1458,16 +1452,18 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@poppinss/cliui@6.4.2': - resolution: {integrity: sha512-+zx32scWjFUReNAzi75/QBwTiQrQ70a3khF5TNnyJVA8V2I9wTRPBLPdLWt83E5m1nTufoilF2MI7UBALkFH1Q==} - engines: {node: '>=18.16.0'} + '@poppinss/cliui@6.4.4': + resolution: {integrity: sha512-yJfm+3yglxdeH85C+YebxZ1zsTB4pBh+QwCuxJcxV/pVbxagn63uYyxqnQif2sKWi+nkNZxuyemON3WrtGMBCQ==} - '@poppinss/colors@4.1.4': - resolution: {integrity: sha512-FA+nTU8p6OcSH4tLDY5JilGYr1bVWHpNmcLr7xmMEdbWmKHa+3QZ+DqefrXKmdjO/brHTnQZo20lLSjaO7ydog==} - engines: {node: '>=18.16.0'} + '@poppinss/colors@4.1.5': + resolution: {integrity: sha512-FvdDqtcRCtz6hThExcFOgW0cWX+xwSMWcRuQe5ZEb2m7cVQOAVZOIMt+/v9RxGiD9/OY16qJBXK4CVKWAPalBw==} - '@poppinss/validator-lite@1.0.3': - resolution: {integrity: sha512-u4dmT7PDHwNtxY3q1jHVp/u+hMEEcBlkzd37QwwM4tVt/0mLlEDttSfPQ+TT7sqPG4VEtWKwVSlMInwPUYyJpA==} + '@poppinss/validator-lite@2.1.1': + resolution: {integrity: sha512-wD64/vpViB0qV40iR/nXYJJb0pOyXW4dvXGs2mR7lNiIUTZr1ceWlhxHu9XU8kQhTjaIDQphgMa9pPBa3scxPg==} + + '@quansync/fs@0.1.3': + resolution: {integrity: sha512-G0OnZbMWEs5LhDyqy2UL17vGhSVHkQIfVojMtEWVenvj0V5S84VBgy86kJIuNsGDp2p7sTKlpSIpBUWdC35OKg==} + engines: {node: '>=20.0.0'} '@remix-run/router@1.22.0': resolution: {integrity: sha512-MBOl8MeOzpK0HQQQshKB7pABXbmyHizdTpqnrIseTbsv0nAepwC2ENZa1aaBExNQcpLoXmWthhak8SABLzvGPw==} @@ -1652,6 +1648,9 @@ packages: engines: {node: '>=8.10'} hasBin: true + '@standard-schema/spec@1.0.0': + resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} + '@storybook/addon-a11y@8.5.8': resolution: {integrity: sha512-RaaelnxoJ8cHzLmyaIjDhLMkBVvKCcrULbJBHYTteJD0iEBdWQMaCTqvO9ekXYuMZt0dfTrDc9WMjZGysM2bDA==} peerDependencies: @@ -2855,12 +2854,6 @@ packages: resolution: {integrity: sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==} engines: {node: '>=0.2.0'} - bundle-require@5.1.0: - resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - peerDependencies: - esbuild: '>=0.18' - cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} @@ -4026,9 +4019,6 @@ packages: resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} engines: {node: '>=8'} - importx@0.5.2: - resolution: {integrity: sha512-YEwlK86Ml5WiTxN/ECUYC5U7jd1CisAVw7ya4i9ZppBoHfFkT2+hChhr3PE2fYxUKLkNyivxEQpa5Ruil1LJBQ==} - imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -4436,10 +4426,6 @@ packages: lit@2.8.0: resolution: {integrity: sha512-4Sc3OFX9QHOJaHbmTMk28SYgVxLN3ePDjg7hofEft2zWlehFL3LiAuapWc4U/kYwMYJSh2hTCPZ6/LIC7ii0MA==} - load-tsconfig@0.2.5: - resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - local-pkg@0.5.1: resolution: {integrity: sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==} engines: {node: '>=14'} @@ -5220,6 +5206,9 @@ packages: resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==} engines: {node: '>=0.6'} + quansync@0.2.10: + resolution: {integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -6080,8 +6069,8 @@ packages: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} - unconfig@0.6.1: - resolution: {integrity: sha512-cVU+/sPloZqOyJEAfNwnQSFCzFrZm85vcVkryH7lnlB/PiTycUkAjt5Ds79cfIshGOZ+M5v3PBDnKgpmlE5DtA==} + unconfig@7.3.2: + resolution: {integrity: sha512-nqG5NNL2wFVGZ0NA/aCFw0oJ2pxSf1lwg4Z5ill8wd7K4KX/rQbHlwbh+bjctXL5Ly1xtzHenHGOK0b+lG6JVg==} undici-types@6.19.8: resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} @@ -6515,8 +6504,6 @@ snapshots: '@jridgewell/gen-mapping': 0.3.8 '@jridgewell/trace-mapping': 0.3.25 - '@antfu/utils@8.1.1': {} - '@babel/code-frame@7.26.2': dependencies: '@babel/helper-validator-identifier': 7.25.9 @@ -7323,16 +7310,13 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 - '@julr/vite-plugin-validate-env@1.3.0(vite@5.4.14(@types/node@20.17.19))(zod@3.24.2)': + '@julr/vite-plugin-validate-env@https://codeload.github.com/toggle-corp/vite-plugin-validate-env/tar.gz/3225c8405bdadf1168f1fa6f8a6de76c6777b620(vite@5.4.14(@types/node@20.17.19))': dependencies: - '@poppinss/cliui': 6.4.2 - '@poppinss/validator-lite': 1.0.3 - unconfig: 0.6.1 + '@poppinss/cliui': 6.4.4 + '@poppinss/validator-lite': 2.1.1 + '@standard-schema/spec': 1.0.0 + unconfig: 7.3.2 vite: 5.4.14(@types/node@20.17.19) - optionalDependencies: - zod: 3.24.2 - transitivePeerDependencies: - - supports-color '@keyv/serialize@1.0.3': dependencies: @@ -7457,9 +7441,9 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@poppinss/cliui@6.4.2': + '@poppinss/cliui@6.4.4': dependencies: - '@poppinss/colors': 4.1.4 + '@poppinss/colors': 4.1.5 cli-boxes: 4.0.1 cli-table3: 0.6.5 cli-truncate: 4.0.0 @@ -7470,13 +7454,15 @@ snapshots: terminal-size: 4.0.0 wordwrap: 1.0.0 - '@poppinss/colors@4.1.4': + '@poppinss/colors@4.1.5': dependencies: kleur: 4.1.5 - '@poppinss/validator-lite@1.0.3': + '@poppinss/validator-lite@2.1.1': {} + + '@quansync/fs@0.1.3': dependencies: - validator: 13.12.0 + quansync: 0.2.10 '@remix-run/router@1.22.0': {} @@ -7651,6 +7637,8 @@ snapshots: ignore: 5.3.2 p-map: 4.0.0 + '@standard-schema/spec@1.0.0': {} + '@storybook/addon-a11y@8.5.8(storybook@8.5.8(prettier@2.8.8))': dependencies: '@storybook/addon-highlight': 8.5.8(storybook@8.5.8(prettier@2.8.8)) @@ -9348,11 +9336,6 @@ snapshots: buffers@0.1.1: {} - bundle-require@5.1.0(esbuild@0.25.0): - dependencies: - esbuild: 0.25.0 - load-tsconfig: 0.2.5 - cac@6.7.14: {} cacheable@1.8.8: @@ -10734,17 +10717,6 @@ snapshots: import-lazy@4.0.0: {} - importx@0.5.2: - dependencies: - bundle-require: 5.1.0(esbuild@0.25.0) - debug: 4.4.0 - esbuild: 0.25.0 - jiti: 2.4.2 - pathe: 2.0.3 - tsx: 4.19.3 - transitivePeerDependencies: - - supports-color - imurmurhash@0.1.4: {} indent-string@4.0.0: {} @@ -11190,8 +11162,6 @@ snapshots: lit-element: 3.3.3 lit-html: 2.8.0 - load-tsconfig@0.2.5: {} - local-pkg@0.5.1: dependencies: mlly: 1.7.4 @@ -11986,6 +11956,8 @@ snapshots: qs@6.5.3: {} + quansync@0.2.10: {} + queue-microtask@1.2.3: {} quickselect@2.0.0: {} @@ -12998,13 +12970,12 @@ snapshots: has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 - unconfig@0.6.1: + unconfig@7.3.2: dependencies: - '@antfu/utils': 8.1.1 + '@quansync/fs': 0.1.3 defu: 6.1.4 - importx: 0.5.2 - transitivePeerDependencies: - - supports-color + jiti: 2.4.2 + quansync: 0.2.10 undici-types@6.19.8: {} diff --git a/web-app-serve/.gitignore b/web-app-serve/.gitignore new file mode 100644 index 0000000000..4c49bd78f1 --- /dev/null +++ b/web-app-serve/.gitignore @@ -0,0 +1 @@ +.env diff --git a/web-app-serve/docker-compose.yml b/web-app-serve/docker-compose.yml new file mode 100644 index 0000000000..bb9e674e23 --- /dev/null +++ b/web-app-serve/docker-compose.yml @@ -0,0 +1,13 @@ +name: go-api-web-app-serve + +services: + web-app-serve: + build: + context: ../ + target: web-app-serve + environment: + APPLY_CONFIG__ENABLE_DEBUG: true + # NOTE: See ../Dockerfile for example values and env variables + env_file: .env + ports: + - '8050:80'