From 89b3288ab55b0d07bdbe3f754f7beebf3c1189a7 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Wed, 21 Apr 2021 16:14:06 +0200 Subject: [PATCH 1/3] MOBILE-3738 docker: Use docker-layer cache Taken from https://github.com/moodlehq/moodleapp/pull/2631 Co-authored-by: LetsMelon --- Dockerfile | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 031dc280b..43cb968af 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ -# This image is based on the fat node 14 image. +# This image is based on the fat node 11 image. # We require fat images as neither alpine, or slim, include git binaries. -FROM node:14 +FROM node:11 # Port 8100 for ionic dev server. EXPOSE 8100 @@ -13,10 +13,13 @@ EXPOSE 53703 WORKDIR /app -COPY . /app - # Install npm libraries. -RUN npm install && rm -rf /root/.npm +COPY package*.json ./ +RUN npm ci +# Delete caches. +RUN rm -rf /root/.npm + +COPY . /app # Run gulp before starting. RUN npx gulp From 368bbfceb782afdf368b798f1b153d28b253f7f9 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Wed, 21 Apr 2021 16:16:56 +0200 Subject: [PATCH 2/3] MOBILE-3738 docker: Bundle assets in image --- Dockerfile | 32 +++++++++++--------------------- angular.json | 1 + hooks/build | 13 +++++++++++++ package.json | 3 ++- 4 files changed, 27 insertions(+), 22 deletions(-) create mode 100755 hooks/build diff --git a/Dockerfile b/Dockerfile index 43cb968af..fdb616c3b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,30 +1,20 @@ -# This image is based on the fat node 11 image. -# We require fat images as neither alpine, or slim, include git binaries. -FROM node:11 - -# Port 8100 for ionic dev server. -EXPOSE 8100 - -# Port 35729 is the live-reload server. -EXPOSE 35729 - -# Port 53703 is the Chrome dev logger port. -EXPOSE 53703 +## BUILD STAGE +FROM node:14 as build-stage WORKDIR /app -# Install npm libraries. +# Prepare node dependencies +RUN apt-get update && apt-get install libsecret-1-0 -y COPY package*.json ./ RUN npm ci -# Delete caches. -RUN rm -rf /root/.npm +# Build source +ARG build_command="npm run build:prod" COPY . /app +RUN ${build_command} -# Run gulp before starting. -RUN npx gulp +## SERVE STAGE +FROM nginx:alpine as serve-stage -# Provide a Healthcheck command for easier use in CI. -HEALTHCHECK --interval=10s --timeout=5s --start-period=60s CMD curl -f http://localhost:8100 || exit 1 - -CMD ["npm", "run", "ionic:serve"] +# Copy assets +COPY --from=build-stage /app/www /usr/share/nginx/html diff --git a/angular.json b/angular.json index 2b8ec418d..c1275f42d 100644 --- a/angular.json +++ b/angular.json @@ -69,6 +69,7 @@ "builder": "@angular-devkit/build-angular:dev-server", "options": { "browserTarget": "app:build", + "disableHostCheck": true, "port": 8100 }, "configurations": { diff --git a/hooks/build b/hooks/build new file mode 100755 index 000000000..2cfd00774 --- /dev/null +++ b/hooks/build @@ -0,0 +1,13 @@ +#!/bin/bash +# Override DockerHub build hook in order to create images of different flavors (production & testing). +# See: https://docs.docker.com/docker-hub/builds/advanced/ + +if [[ "$IMAGE_NAME" == *-test ]] +then + docker build --build-arg build_command="npm run build:test" -f $DOCKERFILE_PATH -t $IMAGE_NAME . +elif [[ "$IMAGE_NAME" == *-dev ]] +then + docker build --build-arg build_command="npm run build" -f $DOCKERFILE_PATH -t $IMAGE_NAME . +else + docker build -f $DOCKERFILE_PATH -t $IMAGE_NAME . +fi diff --git a/package.json b/package.json index a98696dbe..b825a765f 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,8 @@ "ng": "ng", "start": "ionic serve", "build": "ionic build", - "build:prod": "ionic build --prod", + "build:prod": "NODE_ENV=production ionic build --prod", + "build:test": "NODE_ENV=testing ionic build", "test": "NODE_ENV=testing gulp && jest --verbose", "test:ci": "NODE_ENV=testing gulp && jest -ci --runInBand --verbose", "test:watch": "NODE_ENV=testing gulp watch & jest --watch", From dc30331e1bf322057f615c0caa55e23a26645689 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Thu, 22 Apr 2021 12:52:58 +0200 Subject: [PATCH 3/3] MOBILE-3738 env: Add version and lowercase keys --- gulp/task-build-env.js | 43 +++++++++++++++++++++++++++++++---- scripts/env-utils.js | 51 ------------------------------------------ src/core/constants.ts | 5 +++-- 3 files changed, 42 insertions(+), 57 deletions(-) delete mode 100644 scripts/env-utils.js diff --git a/gulp/task-build-env.js b/gulp/task-build-env.js index b96005906..1ccb8dec0 100644 --- a/gulp/task-build-env.js +++ b/gulp/task-build-env.js @@ -12,9 +12,44 @@ // See the License for the specific language governing permissions and // limitations under the License. -const { getConfig, getBuild } = require('../scripts/env-utils'); +const { execSync } = require('child_process'); +const { existsSync, readFileSync, writeFile } = require('fs'); +const { parse: parseJsonc } = require('jsonc-parser'); const { resolve } = require('path'); -const { writeFile } = require('fs'); + +function getConfig(environment) { + const envSuffixesMap = { + testing: ['test', 'testing'], + development: ['dev', 'development'], + production: ['prod', 'production'], + }; + const config = parseJsonc(readFileSync(resolve(__dirname, '../moodle.config.json')).toString()); + const envSuffixes = (envSuffixesMap[environment] || []); + const envConfigPath = envSuffixes.map(suffix => resolve(__dirname, `../moodle.${suffix}.config.json`)).find(existsSync); + + if (envConfigPath) { + const envConfig = parseJsonc(readFileSync(envConfigPath).toString()); + + for (const [key, value] of Object.entries(envConfig)) { + config[key] = value; + } + } + + return config; +} + +function getBuild(environment) { + const { version } = JSON.parse(readFileSync(resolve(__dirname, '../package.json'))); + + return { + version, + isProduction: environment === 'production', + isTesting: environment === 'testing', + isDevelopment: environment === 'development', + lastCommitHash: execSync('git log -1 --pretty=format:"%H"').toString(), + compilationTime: Date.now(), + }; +} /** * Task to build an env file depending on the current environment. @@ -29,8 +64,8 @@ class BuildEnvTask { run(done) { const envFile = resolve(__dirname, '../src/assets/env.json'); const env = { - CONFIG: getConfig(process.env.NODE_ENV || 'development'), - BUILD: getBuild(process.env.NODE_ENV || 'development'), + config: getConfig(process.env.NODE_ENV || 'development'), + build: getBuild(process.env.NODE_ENV || 'development'), }; writeFile(envFile, JSON.stringify(env), done); diff --git a/scripts/env-utils.js b/scripts/env-utils.js deleted file mode 100644 index 39944ac00..000000000 --- a/scripts/env-utils.js +++ /dev/null @@ -1,51 +0,0 @@ -// (C) Copyright 2015 Moodle Pty Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -const { execSync } = require('child_process'); -const { resolve } = require('path'); - -function getConfig(environment) { - const { parse: parseJsonc } = require('jsonc-parser'); - const { readFileSync, existsSync } = require('fs'); - const envSuffixesMap = { - testing: ['test', 'testing'], - development: ['dev', 'development'], - production: ['prod', 'production'], - }; - const config = parseJsonc(readFileSync(resolve(__dirname, '../moodle.config.json')).toString()); - const envSuffixes = (envSuffixesMap[environment] || []); - const envConfigPath = envSuffixes.map(suffix => resolve(__dirname, `../moodle.${suffix}.config.json`)).find(existsSync); - - if (envConfigPath) { - const envConfig = parseJsonc(readFileSync(envConfigPath).toString()); - - for (const [key, value] of Object.entries(envConfig)) { - config[key] = value; - } - } - - return config; -} - -function getBuild(environment) { - return { - isProduction: environment === 'production', - isTesting: environment === 'testing', - isDevelopment: environment === 'development', - lastCommitHash: execSync('git log -1 --pretty=format:"%H"').toString(), - compilationTime: Date.now(), - }; -} - -module.exports = { getConfig, getBuild }; diff --git a/src/core/constants.ts b/src/core/constants.ts index 24da454ae..7e6f45e98 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -126,8 +126,8 @@ export class CoreConstants { static readonly MOD_ARCHETYPE_SYSTEM = 3; // System (not user-addable) module archetype. // Config & environment constants. - static readonly CONFIG = envJson.CONFIG as unknown as EnvironmentConfig; // Data parsed from config.json files. - static readonly BUILD = envJson.BUILD as unknown as EnvironmentBuild; // Build info. + static readonly CONFIG = envJson.config as unknown as EnvironmentConfig; // Data parsed from config.json files. + static readonly BUILD = envJson.build as unknown as EnvironmentBuild; // Build info. } @@ -168,6 +168,7 @@ type EnvironmentConfig = { }; type EnvironmentBuild = { + version: string; isProduction: boolean; isTesting: boolean; isDevelopment: boolean;