forked from cerc-io/stack-orchestrator
Add new build-webapp command and related scripts and containers. (#626)
* Add new build-webapp command and related scripts and containers.
This commit is contained in:
parent
4456e70c93
commit
660326f713
49
.gitea/workflows/test-webapp.yml
Normal file
49
.gitea/workflows/test-webapp.yml
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
name: Webapp Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches: '*'
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- ci-test
|
||||||
|
paths-ignore:
|
||||||
|
- '.gitea/workflows/triggers/*'
|
||||||
|
|
||||||
|
# Needed until we can incorporate docker startup into the executor container
|
||||||
|
env:
|
||||||
|
DOCKER_HOST: unix:///var/run/dind.sock
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
name: "Run webapp test suite"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: "Clone project repository"
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
# At present the stock setup-python action fails on Linux/aarch64
|
||||||
|
# Conditional steps below workaroud this by using deadsnakes for that case only
|
||||||
|
- name: "Install Python for ARM on Linux"
|
||||||
|
if: ${{ runner.arch == 'arm64' && runner.os == 'Linux' }}
|
||||||
|
uses: deadsnakes/action@v3.0.1
|
||||||
|
with:
|
||||||
|
python-version: '3.8'
|
||||||
|
- name: "Install Python cases other than ARM on Linux"
|
||||||
|
if: ${{ ! (runner.arch == 'arm64' && runner.os == 'Linux') }}
|
||||||
|
uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: '3.8'
|
||||||
|
- name: "Print Python version"
|
||||||
|
run: python3 --version
|
||||||
|
- name: "Install shiv"
|
||||||
|
run: pip install shiv
|
||||||
|
- name: "Generate build version file"
|
||||||
|
run: ./scripts/create_build_tag_file.sh
|
||||||
|
- name: "Build local shiv package"
|
||||||
|
run: ./scripts/build_shiv_package.sh
|
||||||
|
- name: Start dockerd # Also needed until we can incorporate into the executor
|
||||||
|
run: |
|
||||||
|
dockerd -H $DOCKER_HOST --userland-proxy=false &
|
||||||
|
sleep 5
|
||||||
|
- name: "Run webapp tests"
|
||||||
|
run: ./tests/webapp-test/run-webapp-test.sh
|
@ -33,6 +33,73 @@ from stack_orchestrator.base import get_npm_registry_url
|
|||||||
# TODO: find a place for this
|
# TODO: find a place for this
|
||||||
# epilog="Config provided either in .env or settings.ini or env vars: CERC_REPO_BASE_DIR (defaults to ~/cerc)"
|
# epilog="Config provided either in .env or settings.ini or env vars: CERC_REPO_BASE_DIR (defaults to ~/cerc)"
|
||||||
|
|
||||||
|
def make_container_build_env(dev_root_path: str,
|
||||||
|
container_build_dir: str,
|
||||||
|
debug: bool,
|
||||||
|
force_rebuild: bool,
|
||||||
|
extra_build_args: str):
|
||||||
|
container_build_env = {
|
||||||
|
"CERC_NPM_REGISTRY_URL": get_npm_registry_url(),
|
||||||
|
"CERC_GO_AUTH_TOKEN": config("CERC_GO_AUTH_TOKEN", default=""),
|
||||||
|
"CERC_NPM_AUTH_TOKEN": config("CERC_NPM_AUTH_TOKEN", default=""),
|
||||||
|
"CERC_REPO_BASE_DIR": dev_root_path,
|
||||||
|
"CERC_CONTAINER_BASE_DIR": container_build_dir,
|
||||||
|
"CERC_HOST_UID": f"{os.getuid()}",
|
||||||
|
"CERC_HOST_GID": f"{os.getgid()}",
|
||||||
|
"DOCKER_BUILDKIT": config("DOCKER_BUILDKIT", default="0")
|
||||||
|
}
|
||||||
|
container_build_env.update({"CERC_SCRIPT_DEBUG": "true"} if debug else {})
|
||||||
|
container_build_env.update({"CERC_FORCE_REBUILD": "true"} if force_rebuild else {})
|
||||||
|
container_build_env.update({"CERC_CONTAINER_EXTRA_BUILD_ARGS": extra_build_args} if extra_build_args else {})
|
||||||
|
docker_host_env = os.getenv("DOCKER_HOST")
|
||||||
|
if docker_host_env:
|
||||||
|
container_build_env.update({"DOCKER_HOST": docker_host_env})
|
||||||
|
|
||||||
|
return container_build_env
|
||||||
|
|
||||||
|
|
||||||
|
def process_container(container,
|
||||||
|
container_build_dir: str,
|
||||||
|
container_build_env: dict,
|
||||||
|
dev_root_path: str,
|
||||||
|
quiet: bool,
|
||||||
|
verbose: bool,
|
||||||
|
dry_run: bool,
|
||||||
|
continue_on_error: bool,
|
||||||
|
):
|
||||||
|
if not quiet:
|
||||||
|
print(f"Building: {container}")
|
||||||
|
build_dir = os.path.join(container_build_dir, container.replace("/", "-"))
|
||||||
|
build_script_filename = os.path.join(build_dir, "build.sh")
|
||||||
|
if verbose:
|
||||||
|
print(f"Build script filename: {build_script_filename}")
|
||||||
|
if os.path.exists(build_script_filename):
|
||||||
|
build_command = build_script_filename
|
||||||
|
else:
|
||||||
|
if verbose:
|
||||||
|
print(f"No script file found: {build_script_filename}, using default build script")
|
||||||
|
repo_dir = container.split('/')[1]
|
||||||
|
# TODO: make this less of a hack -- should be specified in some metadata somewhere
|
||||||
|
# Check if we have a repo for this container. If not, set the context dir to the container-build subdir
|
||||||
|
repo_full_path = os.path.join(dev_root_path, repo_dir)
|
||||||
|
repo_dir_or_build_dir = repo_full_path if os.path.exists(repo_full_path) else build_dir
|
||||||
|
build_command = os.path.join(container_build_dir,
|
||||||
|
"default-build.sh") + f" {container}:local {repo_dir_or_build_dir}"
|
||||||
|
if not dry_run:
|
||||||
|
if verbose:
|
||||||
|
print(f"Executing: {build_command} with environment: {container_build_env}")
|
||||||
|
build_result = subprocess.run(build_command, shell=True, env=container_build_env)
|
||||||
|
if verbose:
|
||||||
|
print(f"Return code is: {build_result.returncode}")
|
||||||
|
if build_result.returncode != 0:
|
||||||
|
print(f"Error running build for {container}")
|
||||||
|
if not continue_on_error:
|
||||||
|
print("FATAL Error: container build failed and --continue-on-error not set, exiting")
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
print("****** Container Build Error, continuing because --continue-on-error is set")
|
||||||
|
else:
|
||||||
|
print("Skipped")
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.option('--include', help="only build these containers")
|
@click.option('--include', help="only build these containers")
|
||||||
@ -83,61 +150,16 @@ def command(ctx, include, exclude, force_rebuild, extra_build_args):
|
|||||||
if stack:
|
if stack:
|
||||||
print(f"Stack: {stack}")
|
print(f"Stack: {stack}")
|
||||||
|
|
||||||
# TODO: make this configurable
|
container_build_env = make_container_build_env(dev_root_path,
|
||||||
container_build_env = {
|
container_build_dir,
|
||||||
"CERC_NPM_REGISTRY_URL": get_npm_registry_url(),
|
debug,
|
||||||
"CERC_GO_AUTH_TOKEN": config("CERC_GO_AUTH_TOKEN", default=""),
|
force_rebuild,
|
||||||
"CERC_NPM_AUTH_TOKEN": config("CERC_NPM_AUTH_TOKEN", default=""),
|
extra_build_args)
|
||||||
"CERC_REPO_BASE_DIR": dev_root_path,
|
|
||||||
"CERC_CONTAINER_BASE_DIR": container_build_dir,
|
|
||||||
"CERC_HOST_UID": f"{os.getuid()}",
|
|
||||||
"CERC_HOST_GID": f"{os.getgid()}",
|
|
||||||
"DOCKER_BUILDKIT": config("DOCKER_BUILDKIT", default="0")
|
|
||||||
}
|
|
||||||
container_build_env.update({"CERC_SCRIPT_DEBUG": "true"} if debug else {})
|
|
||||||
container_build_env.update({"CERC_FORCE_REBUILD": "true"} if force_rebuild else {})
|
|
||||||
container_build_env.update({"CERC_CONTAINER_EXTRA_BUILD_ARGS": extra_build_args} if extra_build_args else {})
|
|
||||||
docker_host_env = os.getenv("DOCKER_HOST")
|
|
||||||
if docker_host_env:
|
|
||||||
container_build_env.update({"DOCKER_HOST": docker_host_env})
|
|
||||||
|
|
||||||
def process_container(container):
|
|
||||||
if not quiet:
|
|
||||||
print(f"Building: {container}")
|
|
||||||
build_dir = os.path.join(container_build_dir, container.replace("/", "-"))
|
|
||||||
build_script_filename = os.path.join(build_dir, "build.sh")
|
|
||||||
if verbose:
|
|
||||||
print(f"Build script filename: {build_script_filename}")
|
|
||||||
if os.path.exists(build_script_filename):
|
|
||||||
build_command = build_script_filename
|
|
||||||
else:
|
|
||||||
if verbose:
|
|
||||||
print(f"No script file found: {build_script_filename}, using default build script")
|
|
||||||
repo_dir = container.split('/')[1]
|
|
||||||
# TODO: make this less of a hack -- should be specified in some metadata somewhere
|
|
||||||
# Check if we have a repo for this container. If not, set the context dir to the container-build subdir
|
|
||||||
repo_full_path = os.path.join(dev_root_path, repo_dir)
|
|
||||||
repo_dir_or_build_dir = repo_full_path if os.path.exists(repo_full_path) else build_dir
|
|
||||||
build_command = os.path.join(container_build_dir, "default-build.sh") + f" {container}:local {repo_dir_or_build_dir}"
|
|
||||||
if not dry_run:
|
|
||||||
if verbose:
|
|
||||||
print(f"Executing: {build_command} with environment: {container_build_env}")
|
|
||||||
build_result = subprocess.run(build_command, shell=True, env=container_build_env)
|
|
||||||
if verbose:
|
|
||||||
print(f"Return code is: {build_result.returncode}")
|
|
||||||
if build_result.returncode != 0:
|
|
||||||
print(f"Error running build for {container}")
|
|
||||||
if not continue_on_error:
|
|
||||||
print("FATAL Error: container build failed and --continue-on-error not set, exiting")
|
|
||||||
sys.exit(1)
|
|
||||||
else:
|
|
||||||
print("****** Container Build Error, continuing because --continue-on-error is set")
|
|
||||||
else:
|
|
||||||
print("Skipped")
|
|
||||||
|
|
||||||
for container in containers_in_scope:
|
for container in containers_in_scope:
|
||||||
if include_exclude_check(container, include, exclude):
|
if include_exclude_check(container, include, exclude):
|
||||||
process_container(container)
|
process_container(container, container_build_dir, container_build_env,
|
||||||
|
dev_root_path, quiet, verbose, dry_run, continue_on_error)
|
||||||
else:
|
else:
|
||||||
if verbose:
|
if verbose:
|
||||||
print(f"Excluding: {container}")
|
print(f"Excluding: {container}")
|
||||||
|
76
stack_orchestrator/build/build_webapp.py
Normal file
76
stack_orchestrator/build/build_webapp.py
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
# Copyright © 2022, 2023 Vulcanize
|
||||||
|
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http:#www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# Builds webapp containers
|
||||||
|
|
||||||
|
# env vars:
|
||||||
|
# CERC_REPO_BASE_DIR defaults to ~/cerc
|
||||||
|
|
||||||
|
# TODO: display the available list of containers; allow re-build of either all or specific containers
|
||||||
|
|
||||||
|
import os
|
||||||
|
from decouple import config
|
||||||
|
import click
|
||||||
|
from pathlib import Path
|
||||||
|
from stack_orchestrator.build import build_containers
|
||||||
|
|
||||||
|
|
||||||
|
@click.command()
|
||||||
|
@click.option('--base-container', default="cerc/nextjs-base")
|
||||||
|
@click.option('--source-repo', help="directory containing the webapp to build", required=True)
|
||||||
|
@click.option("--force-rebuild", is_flag=True, default=False, help="Override dependency checking -- always rebuild")
|
||||||
|
@click.option("--extra-build-args", help="Supply extra arguments to build")
|
||||||
|
@click.pass_context
|
||||||
|
def command(ctx, base_container, source_repo, force_rebuild, extra_build_args):
|
||||||
|
'''build the specified webapp container'''
|
||||||
|
|
||||||
|
quiet = ctx.obj.quiet
|
||||||
|
verbose = ctx.obj.verbose
|
||||||
|
dry_run = ctx.obj.dry_run
|
||||||
|
debug = ctx.obj.debug
|
||||||
|
local_stack = ctx.obj.local_stack
|
||||||
|
stack = ctx.obj.stack
|
||||||
|
continue_on_error = ctx.obj.continue_on_error
|
||||||
|
|
||||||
|
# See: https://stackoverflow.com/questions/25389095/python-get-path-of-root-project-structure
|
||||||
|
container_build_dir = Path(__file__).absolute().parent.parent.joinpath("data", "container-build")
|
||||||
|
|
||||||
|
if local_stack:
|
||||||
|
dev_root_path = os.getcwd()[0:os.getcwd().rindex("stack-orchestrator")]
|
||||||
|
print(f'Local stack dev_root_path (CERC_REPO_BASE_DIR) overridden to: {dev_root_path}')
|
||||||
|
else:
|
||||||
|
dev_root_path = os.path.expanduser(config("CERC_REPO_BASE_DIR", default="~/cerc"))
|
||||||
|
|
||||||
|
if not quiet:
|
||||||
|
print(f'Dev Root is: {dev_root_path}')
|
||||||
|
|
||||||
|
# First build the base container.
|
||||||
|
container_build_env = build_containers.make_container_build_env(dev_root_path, container_build_dir, debug,
|
||||||
|
force_rebuild, extra_build_args)
|
||||||
|
|
||||||
|
build_containers.process_container(base_container, container_build_dir, container_build_env, dev_root_path, quiet,
|
||||||
|
verbose, dry_run, continue_on_error)
|
||||||
|
|
||||||
|
|
||||||
|
# Now build the target webapp. We use the same build script, but with a different Dockerfile and work dir.
|
||||||
|
container_build_env["CERC_CONTAINER_BUILD_WORK_DIR"] = os.path.abspath(source_repo)
|
||||||
|
container_build_env["CERC_CONTAINER_BUILD_DOCKERFILE"] = os.path.join(container_build_dir,
|
||||||
|
base_container.replace("/", "-"),
|
||||||
|
"Dockerfile.webapp")
|
||||||
|
webapp_name = os.path.abspath(source_repo).split(os.path.sep)[-1]
|
||||||
|
container_build_env["CERC_CONTAINER_BUILD_TAG"] = f"cerc/{webapp_name}:local"
|
||||||
|
|
||||||
|
build_containers.process_container(base_container, container_build_dir, container_build_env, dev_root_path, quiet,
|
||||||
|
verbose, dry_run, continue_on_error)
|
@ -0,0 +1,55 @@
|
|||||||
|
# Originally from: https://github.com/devcontainers/images/blob/main/src/javascript-node/.devcontainer/Dockerfile
|
||||||
|
# [Choice] Node.js version (use -bullseye variants on local arm64/Apple Silicon): 18, 16, 14, 18-bullseye, 16-bullseye, 14-bullseye, 18-buster, 16-buster, 14-buster
|
||||||
|
ARG VARIANT=18-bullseye
|
||||||
|
FROM node:${VARIANT}
|
||||||
|
|
||||||
|
ARG USERNAME=node
|
||||||
|
ARG NPM_GLOBAL=/usr/local/share/npm-global
|
||||||
|
|
||||||
|
# Add NPM global to PATH.
|
||||||
|
ENV PATH=${NPM_GLOBAL}/bin:${PATH}
|
||||||
|
# Prevents npm from printing version warnings
|
||||||
|
ENV NPM_CONFIG_UPDATE_NOTIFIER=false
|
||||||
|
|
||||||
|
RUN \
|
||||||
|
# Configure global npm install location, use group to adapt to UID/GID changes
|
||||||
|
if ! cat /etc/group | grep -e "^npm:" > /dev/null 2>&1; then groupadd -r npm; fi \
|
||||||
|
&& usermod -a -G npm ${USERNAME} \
|
||||||
|
&& umask 0002 \
|
||||||
|
&& mkdir -p ${NPM_GLOBAL} \
|
||||||
|
&& touch /usr/local/etc/npmrc \
|
||||||
|
&& chown ${USERNAME}:npm ${NPM_GLOBAL} /usr/local/etc/npmrc \
|
||||||
|
&& chmod g+s ${NPM_GLOBAL} \
|
||||||
|
&& npm config -g set prefix ${NPM_GLOBAL} \
|
||||||
|
&& su ${USERNAME} -c "npm config -g set prefix ${NPM_GLOBAL}" \
|
||||||
|
# Install eslint
|
||||||
|
&& su ${USERNAME} -c "umask 0002 && npm install -g eslint" \
|
||||||
|
&& npm cache clean --force > /dev/null 2>&1
|
||||||
|
|
||||||
|
# [Optional] Uncomment this section to install additional OS packages.
|
||||||
|
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||||
|
&& apt-get -y install --no-install-recommends jq gettext-base
|
||||||
|
|
||||||
|
# [Optional] Uncomment if you want to install an additional version of node using nvm
|
||||||
|
# ARG EXTRA_NODE_VERSION=10
|
||||||
|
# RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}"
|
||||||
|
|
||||||
|
# We do this to get a yq binary from the published container, for the correct architecture we're building here
|
||||||
|
# COPY --from=docker.io/mikefarah/yq:latest /usr/bin/yq /usr/local/bin/yq
|
||||||
|
|
||||||
|
COPY /scripts /scripts
|
||||||
|
|
||||||
|
# [Optional] Uncomment if you want to install more global node modules
|
||||||
|
# RUN su node -c "npm install -g <your-package-list-here>"
|
||||||
|
|
||||||
|
# RUN mkdir -p /config
|
||||||
|
# COPY ./config.yml /config
|
||||||
|
|
||||||
|
# Install simple web server for now (use nginx perhaps later)
|
||||||
|
# RUN yarn global add http-server
|
||||||
|
|
||||||
|
# Expose port for http
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
# Default command sleeps forever so docker doesn't kill it
|
||||||
|
CMD ["/scripts/start-serving-app.sh"]
|
@ -0,0 +1,5 @@
|
|||||||
|
FROM cerc/nextjs-base:local
|
||||||
|
WORKDIR /app
|
||||||
|
COPY . .
|
||||||
|
RUN rm -rf node_modules build .next*
|
||||||
|
RUN /scripts/build-app.sh /app
|
13
stack_orchestrator/data/container-build/cerc-nextjs-base/build.sh
Executable file
13
stack_orchestrator/data/container-build/cerc-nextjs-base/build.sh
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build cerc/laconic-registry-cli
|
||||||
|
|
||||||
|
source ${CERC_CONTAINER_BASE_DIR}/build-base.sh
|
||||||
|
|
||||||
|
# See: https://stackoverflow.com/a/246128/1701505
|
||||||
|
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||||
|
|
||||||
|
CERC_CONTAINER_BUILD_WORK_DIR=${CERC_CONTAINER_BUILD_WORK_DIR:-$SCRIPT_DIR}
|
||||||
|
CERC_CONTAINER_BUILD_DOCKERFILE=${CERC_CONTAINER_BUILD_DOCKERFILE:-$SCRIPT_DIR/Dockerfile}
|
||||||
|
CERC_CONTAINER_BUILD_TAG=${CERC_CONTAINER_BUILD_TAG:-cerc/nextjs-base:local}
|
||||||
|
|
||||||
|
docker build -t $CERC_CONTAINER_BUILD_TAG ${build_command_args} -f $CERC_CONTAINER_BUILD_DOCKERFILE $CERC_CONTAINER_BUILD_WORK_DIR
|
@ -0,0 +1,36 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [ -n "$CERC_SCRIPT_DEBUG" ]; then
|
||||||
|
set -x
|
||||||
|
fi
|
||||||
|
|
||||||
|
WORK_DIR="${1:-./}"
|
||||||
|
SRC_DIR="${2:-.next}"
|
||||||
|
TRG_DIR="${3:-.next-r}"
|
||||||
|
|
||||||
|
cd "${WORK_DIR}" || exit 1
|
||||||
|
|
||||||
|
rm -rf "$TRG_DIR"
|
||||||
|
mkdir -p "$TRG_DIR"
|
||||||
|
cp -rp "$SRC_DIR" "$TRG_DIR/"
|
||||||
|
|
||||||
|
if [ -f ".env" ]; then
|
||||||
|
TMP_ENV=`mktemp`
|
||||||
|
declare -px > $TMP_ENV
|
||||||
|
set -a
|
||||||
|
source .env
|
||||||
|
source $TMP_ENV
|
||||||
|
set +a
|
||||||
|
rm -f $TMP_ENV
|
||||||
|
fi
|
||||||
|
|
||||||
|
for f in $(find "$TRG_DIR" -regex ".*.[tj]sx?$" -type f | grep -v 'node_modules'); do
|
||||||
|
for e in $(cat "${f}" | tr -s '[:blank:]' '\n' | tr -s '[{},()]' '\n' | egrep -o '^"CERC_RUNTIME_ENV[^\"]+"$'); do
|
||||||
|
orig_name=$(echo -n "${e}" | sed 's/"//g')
|
||||||
|
cur_name=$(echo -n "${orig_name}" | sed 's/CERC_RUNTIME_ENV_//g')
|
||||||
|
cur_val=$(echo -n "\$${cur_name}" | envsubst)
|
||||||
|
esc_val=$(sed 's/[&/\]/\\&/g' <<< "$cur_val")
|
||||||
|
echo "$cur_name=$cur_val"
|
||||||
|
sed -i "s/$orig_name/$esc_val/g" $f
|
||||||
|
done
|
||||||
|
done
|
@ -0,0 +1,63 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [ -n "$CERC_SCRIPT_DEBUG" ]; then
|
||||||
|
set -x
|
||||||
|
fi
|
||||||
|
|
||||||
|
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||||
|
|
||||||
|
WORK_DIR="${1:-/app}"
|
||||||
|
|
||||||
|
cd "${WORK_DIR}" || exit 1
|
||||||
|
|
||||||
|
cp next.config.js next.config.dist
|
||||||
|
|
||||||
|
npm i -g js-beautify
|
||||||
|
js-beautify next.config.dist > next.config.js
|
||||||
|
|
||||||
|
npm install
|
||||||
|
|
||||||
|
CONFIG_LINES=$(wc -l next.config.js | awk '{ print $1 }')
|
||||||
|
MOD_EXPORTS_LINE=$(grep -n 'module.exports' next.config.js | cut -d':' -f1)
|
||||||
|
|
||||||
|
head -$(( ${MOD_EXPORTS_LINE} - 1 )) next.config.js > next.config.js.1
|
||||||
|
|
||||||
|
cat > next.config.js.2 <<EOF
|
||||||
|
const webpack = require('webpack');
|
||||||
|
|
||||||
|
let envMap;
|
||||||
|
try {
|
||||||
|
// .env-list.json provides us a list of identifiers which should be replaced at runtime.
|
||||||
|
envMap = require('./.env-list.json').reduce((a, v) => {
|
||||||
|
a[v] = \`"CERC_RUNTIME_ENV_\${v.split(/\./).pop()}"\`;
|
||||||
|
return a;
|
||||||
|
}, {});
|
||||||
|
} catch {
|
||||||
|
// If .env-list.json cannot be loaded, we are probably running in dev mode, so use process.env instead.
|
||||||
|
envMap = Object.keys(process.env).reduce((a, v) => {
|
||||||
|
if (v.startsWith('CERC_')) {
|
||||||
|
a[\`process.env.\${v}\`] = JSON.stringify(process.env[v]);
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
grep 'module.exports' next.config.js > next.config.js.3
|
||||||
|
|
||||||
|
cat > next.config.js.4 <<EOF
|
||||||
|
webpack: (config) => {
|
||||||
|
config.plugins.push(new webpack.DefinePlugin(envMap));
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
EOF
|
||||||
|
|
||||||
|
tail -$(( ${CONFIG_LINES} - ${MOD_EXPORTS_LINE} + 1 )) next.config.js | grep -v 'process\.env\.' > next.config.js.5
|
||||||
|
|
||||||
|
cat next.config.js.* | js-beautify > next.config.js
|
||||||
|
rm next.config.js.*
|
||||||
|
|
||||||
|
"${SCRIPT_DIR}/find-env.sh" "$(pwd)" > .env-list.json
|
||||||
|
|
||||||
|
npm run build
|
||||||
|
rm .env-list.json
|
24
stack_orchestrator/data/container-build/cerc-nextjs-base/scripts/find-env.sh
Executable file
24
stack_orchestrator/data/container-build/cerc-nextjs-base/scripts/find-env.sh
Executable file
@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [ -n "$CERC_SCRIPT_DEBUG" ]; then
|
||||||
|
set -x
|
||||||
|
fi
|
||||||
|
|
||||||
|
WORK_DIR="${1:-./}"
|
||||||
|
TMPF=$(mktemp)
|
||||||
|
|
||||||
|
cd "$WORK_DIR" || exit 1
|
||||||
|
|
||||||
|
for d in $(find . -maxdepth 1 -type d | grep -v '\./\.' | grep '/' | cut -d'/' -f2); do
|
||||||
|
egrep "/$d[/$]?" .gitignore >/dev/null 2>/dev/null
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
for f in $(find "$d" -regex ".*.[tj]sx?$" -type f); do
|
||||||
|
cat "$f" | tr -s '[:blank:]' '\n' | tr -s '[{},()]' '\n' | egrep -o 'process.env.[A-Za-z0-9_]+' >> $TMPF
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
cat $TMPF | sort -u | jq --raw-input . | jq --slurp .
|
||||||
|
rm -f $TMPF
|
@ -0,0 +1,13 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
if [ -n "$CERC_SCRIPT_DEBUG" ]; then
|
||||||
|
set -x
|
||||||
|
fi
|
||||||
|
|
||||||
|
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||||
|
|
||||||
|
CERC_WEBAPP_FILES_DIR="${CERC_WEBAPP_FILES_DIR:-/app}"
|
||||||
|
cd "$CERC_WEBAPP_FILES_DIR"
|
||||||
|
|
||||||
|
rm -rf .next-r
|
||||||
|
"$SCRIPT_DIR/apply-runtime-env.sh" "`pwd`" .next .next-r
|
||||||
|
npm start .next-r -p ${CERC_LISTEN_PORT:-3000}
|
@ -19,6 +19,7 @@ from stack_orchestrator.command_types import CommandOptions
|
|||||||
from stack_orchestrator.repos import setup_repositories
|
from stack_orchestrator.repos import setup_repositories
|
||||||
from stack_orchestrator.build import build_containers
|
from stack_orchestrator.build import build_containers
|
||||||
from stack_orchestrator.build import build_npms
|
from stack_orchestrator.build import build_npms
|
||||||
|
from stack_orchestrator.build import build_webapp
|
||||||
from stack_orchestrator.deploy import deploy
|
from stack_orchestrator.deploy import deploy
|
||||||
from stack_orchestrator import version
|
from stack_orchestrator import version
|
||||||
from stack_orchestrator.deploy import deployment
|
from stack_orchestrator.deploy import deployment
|
||||||
@ -48,6 +49,7 @@ def cli(ctx, stack, quiet, verbose, dry_run, local_stack, debug, continue_on_err
|
|||||||
cli.add_command(setup_repositories.command, "setup-repositories")
|
cli.add_command(setup_repositories.command, "setup-repositories")
|
||||||
cli.add_command(build_containers.command, "build-containers")
|
cli.add_command(build_containers.command, "build-containers")
|
||||||
cli.add_command(build_npms.command, "build-npms")
|
cli.add_command(build_npms.command, "build-npms")
|
||||||
|
cli.add_command(build_webapp.command, "build-webapp")
|
||||||
cli.add_command(deploy.command, "deploy") # deploy is an alias for deploy-system
|
cli.add_command(deploy.command, "deploy") # deploy is an alias for deploy-system
|
||||||
cli.add_command(deploy.command, "deploy-system")
|
cli.add_command(deploy.command, "deploy-system")
|
||||||
cli.add_command(deployment.command, "deployment")
|
cli.add_command(deployment.command, "deployment")
|
||||||
|
62
tests/webapp-test/run-webapp-test.sh
Executable file
62
tests/webapp-test/run-webapp-test.sh
Executable file
@ -0,0 +1,62 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
if [ -n "$CERC_SCRIPT_DEBUG" ]; then
|
||||||
|
set -x
|
||||||
|
fi
|
||||||
|
# Dump environment variables for debugging
|
||||||
|
echo "Environment variables:"
|
||||||
|
env
|
||||||
|
# Test basic stack-orchestrator webapp
|
||||||
|
echo "Running stack-orchestrator webapp test"
|
||||||
|
# Bit of a hack, test the most recent package
|
||||||
|
TEST_TARGET_SO=$( ls -t1 ./package/laconic-so* | head -1 )
|
||||||
|
# Set a non-default repo dir
|
||||||
|
export CERC_REPO_BASE_DIR=~/stack-orchestrator-test/repo-base-dir
|
||||||
|
echo "Testing this package: $TEST_TARGET_SO"
|
||||||
|
echo "Test version command"
|
||||||
|
reported_version_string=$( $TEST_TARGET_SO version )
|
||||||
|
echo "Version reported is: ${reported_version_string}"
|
||||||
|
echo "Cloning repositories into: $CERC_REPO_BASE_DIR"
|
||||||
|
rm -rf $CERC_REPO_BASE_DIR
|
||||||
|
mkdir -p $CERC_REPO_BASE_DIR
|
||||||
|
git clone https://git.vdb.to/cerc-io/test-progressive-web-app.git $CERC_REPO_BASE_DIR/test-progressive-web-app
|
||||||
|
|
||||||
|
# Test webapp command execution
|
||||||
|
$TEST_TARGET_SO build-webapp --source-repo $CERC_REPO_BASE_DIR/test-progressive-web-app
|
||||||
|
|
||||||
|
UUID=`uuidgen`
|
||||||
|
|
||||||
|
set +e
|
||||||
|
|
||||||
|
CONTAINER_ID=$(docker run -p 3000:3000 -d cerc/test-progressive-web-app:local)
|
||||||
|
sleep 3
|
||||||
|
wget -O test.before -m http://localhost:3000
|
||||||
|
|
||||||
|
docker remove -f $CONTAINER_ID
|
||||||
|
|
||||||
|
CONTAINER_ID=$(docker run -p 3000:3000 -e CERC_WEBAPP_DEBUG=$UUID -d cerc/test-progressive-web-app:local)
|
||||||
|
sleep 3
|
||||||
|
wget -O test.after -m http://localhost:3000
|
||||||
|
|
||||||
|
docker remove -f $CONTAINER_ID
|
||||||
|
|
||||||
|
echo "###########################################################################"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
grep "$UUID" test.before > /dev/null
|
||||||
|
if [ $? -ne 1 ]; then
|
||||||
|
echo "BEFORE: FAILED"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "BEFORE: PASSED"
|
||||||
|
fi
|
||||||
|
|
||||||
|
grep "`uuidgen`" test.after > /dev/null
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "AFTER: FAILED"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "AFTER: PASSED"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
34
tests/webapp-test/test.before
Normal file
34
tests/webapp-test/test.before
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user