diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1b7b786b..c2098eaf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ permissions: contents: read jobs: - main: + lint-test-build: name: Nx Cloud - Main Job uses: nrwl/ci/.github/workflows/nx-cloud-main.yml@v0.13.1 with: @@ -27,6 +27,34 @@ jobs: npx nx affected --target=test --parallel=3 --ci --code-coverage npx nx affected --target=build --parallel=3 + build-docker: + needs: lint-test-build + name: Build and upload docker image and archive + runs-on: ubuntu-latest + + steps: + - name: Build datahub and produce archives + if: github.event_name == 'release' + run: | + npx nx run-many --projects=datahub --target=build + + - uses: docker/login-action@v1 + name: Login to GitHub Container Registry + with: + registry: ghcr.io + username: c2c-bot-gis-ci + password: ${{ secrets.GOPASS_CI_GITHUB_TOKEN }} + + - name: Setting image tag + id: version + run: echo ::set-output name=VERSION::$(echo $GITHUB_REF | cut -d / -f 3) + + - name: "Pushing the image onto ghcr.io" + run: | + docker image ls --format '{{.Repository}}:{{.Tag}}' --filter=reference='ghcr.io/camptocamp/mel-dataplatform/*' | \ + xargs -r -L1 docker push $1 + + agents: name: Nx Cloud - Agents uses: nrwl/ci/.github/workflows/nx-cloud-agents.yml@v0.13.1 diff --git a/apps/datahub/project.json b/apps/datahub/project.json index b6012e6d..d511bbec 100644 --- a/apps/datahub/project.json +++ b/apps/datahub/project.json @@ -93,6 +93,16 @@ "buildTarget": "datahub:build", "staticFilePath": "dist/apps/datahub/browser" } + }, + "docker-build": { + "executor": "nx:run-commands", + "options": { + "commands": [ + "nx build datahub --base-href='/datahub/'", + "docker build --build-arg APP_NAME=datahub -f ./tools/docker/Dockerfile . -t $(tools/print-docker-tag.sh datahub) -t ghcr.io/camptocamp/mel-dataplatform/datahub:latest" + ], + "parallel": false + } } } } diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile new file mode 100644 index 00000000..57641d5a --- /dev/null +++ b/tools/docker/Dockerfile @@ -0,0 +1,23 @@ +# This dockerfile should work for all traditional apps, +# i.e. it only sets up a nginx server with the app dist folder + +FROM nginx:1.24-alpine + +ARG APP_NAME="search" +ENV APP_NAME=datahub +ENV GN4_API_URL "" +ENV PROXY_PATH "" +ENV CONFIG_DIRECTORY_OVERRIDE "" +ENV ASSETS_DIRECTORY_OVERRIDE "" +ENV CUSTOM_SCRIPTS_DIRECTORY "" + +COPY dist/apps/datahub /usr/share/nginx/html/datahub +COPY tools/docker/docker-entrypoint.sh / + +# copy default NGINX conf & put the app name in it +COPY tools/docker/nginx.conf /etc/nginx/conf.d/default.conf +RUN sed -i "s/APP_NAME/datahub/" /etc/nginx/conf.d/default.conf + +EXPOSE 80 + +ENTRYPOINT ["sh", "/docker-entrypoint.sh", "nginx", "-g", "daemon off;"] diff --git a/tools/docker/docker-entrypoint.sh b/tools/docker/docker-entrypoint.sh new file mode 100755 index 00000000..af211cb1 --- /dev/null +++ b/tools/docker/docker-entrypoint.sh @@ -0,0 +1,68 @@ +#!/bin/bash + +APP_FILES_PATH=/usr/share/nginx/html/${APP_NAME}/ + +CONFIG_FILE_PATH=assets/configuration/ +CONFIG_FILE_NAME=default.toml +CONFIG_OVERRIDE_FILE_PATH=${CONFIG_DIRECTORY_OVERRIDE:-/conf}/${CONFIG_FILE_NAME} + +ASSETS_PATH=assets/ +CUSTOM_ASSETS_PATH=${ASSETS_DIRECTORY_OVERRIDE:-/assets}/ + +## 1. COPY CONFIG FILE + +# check if conf file from $CONFIG_DIRECTORY_OVERRIDE (defaults to /conf) is present +if [ -f "${CONFIG_OVERRIDE_FILE_PATH}" ] +then + # copy file straight to the assets + echo "[INFO] Copying custom configuration file located at ${CONFIG_OVERRIDE_FILE_PATH}..." + cp ${CONFIG_OVERRIDE_FILE_PATH} ${APP_FILES_PATH}${CONFIG_FILE_PATH}${CONFIG_FILE_NAME} +else + # no conf file; use env variables to tweak app config + echo "[INFO] No custom configuration file found at ${CONFIG_OVERRIDE_FILE_PATH}" + # Modify the GN4 url and proxy path based on env variables (if defined) + if [ ! -z "${GN4_API_URL}" ] + then + echo "[INFO] Replacing GN4 url in conf with: ${GN4_API_URL}..." + sed -i "s%geonetwork4_api_url = \".*\"%geonetwork4_api_url = \"${GN4_API_URL}\"%" ${APP_FILES_PATH}${CONFIG_FILE_PATH}${CONFIG_FILE_NAME} + fi + if [ ! -z "${PROXY_PATH}" ] + then + echo "[INFO] Replacing proxy path in conf with: ${PROXY_PATH}..." + sed -i "s%proxy_path = \".*\"%proxy_path = \"${PROXY_PATH}\"%" ${APP_FILES_PATH}${CONFIG_FILE_PATH}${CONFIG_FILE_NAME} + fi +fi + +## 2. COPY ASSETS + +# check whether the $CUSTOM_ASSETS_PATH directory is present and not empty +if [ -d "${CUSTOM_ASSETS_PATH}" ] && [ "$(ls -A ${CUSTOM_ASSETS_PATH})" ]; then + files_count=$(find ${CUSTOM_ASSETS_PATH} -type f | wc -l) + # copy assets right away + echo "[INFO] Copying ${files_count} custom assets found in ${CUSTOM_ASSETS_PATH}..." + cp ${CUSTOM_ASSETS_PATH}. -r ${APP_FILES_PATH}${ASSETS_PATH} + # add a preload link for each asset that is an image + cd ${CUSTOM_ASSETS_PATH} + images=$(find . -type f -a \( -iname "*.png" -o -iname "*.svg" -o -iname "*.webp" -o -iname "*.jpg" -o -iname "*.jpeg" \)) + for image in ${images} + do + echo "[INFO] Adding preload link for ${image}..." + sed -i "s@@\n@" \ + ${APP_FILES_PATH}index.html + done +else + echo "[INFO] No custom assets found at ${CUSTOM_ASSETS_PATH}" +fi + +# Executing custom scripts located in CUSTOM_SCRIPTS_DIRECTORY if environment variable is set +if [[ -z "${CUSTOM_SCRIPTS_DIRECTORY}" ]]; then + echo "[INFO] No CUSTOM_SCRIPTS_DIRECTORY env variable set" +else + echo "[INFO] CUSTOM_SCRIPTS_DIRECTORY env variable set to ${CUSTOM_SCRIPTS_DIRECTORY}" + run-parts ${CUSTOM_SCRIPTS_DIRECTORY}/ + echo "[INFO] End executing custom scripts" +fi + +echo "[INFO] docker-entrypoint.sh ended successfully." + +exec "$@" diff --git a/tools/docker/nginx.conf b/tools/docker/nginx.conf new file mode 100644 index 00000000..3460467d --- /dev/null +++ b/tools/docker/nginx.conf @@ -0,0 +1,29 @@ +server { + listen 80; + listen [::]:80; + server_name localhost; + + root /usr/share/nginx/html; + + server_tokens off; + + location ~ /index.html|.*\.toml|.*\.json$ { + expires -1; + add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0'; + } + + location ~ .*\.css$|.*\.js$ { + add_header Cache-Control 'max-age=86400'; # 24h + } + + location / { + try_files $uri $uri/ /APP_NAME/index.html; + + add_header Cache-Control 'max-age=86400'; # 24h + } + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } +} diff --git a/tools/print-docker-tag.sh b/tools/print-docker-tag.sh new file mode 100755 index 00000000..264c8f5c --- /dev/null +++ b/tools/print-docker-tag.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +# Will print a docker tag with a version based on the current git branch and tag +# e.g.: geonetwork/geonetwork-ui-my-app:1.0.0-RC2 +# or: geonetwork/geonetwork-ui-my-app:feature-branch + +appName=$1 +gitTag=$(git describe --exact-match --tags 2>/dev/null | sed "s/^v//") # remove "v" in front of version if any +gitBranch=$(git symbolic-ref --short HEAD) +gitRef=$(git rev-parse --short HEAD) +dockerTag=${gitTag:-${gitBranch}} +if [ ${dockerTag} == "main" ]; then + dockerTag=${dockerTag}-${gitRef} +fi + +echo "ghcr.io/camptocamp/mel-dataplatform/${appName}:${dockerTag}"