Air-Quality-Web/build

412 lines
13 KiB
Text
Raw Normal View History

2019-01-12 23:23:55 +00:00
#!/usr/bin/env bash
# Make sure the current directory is the location of this script to simplify matters
2019-07-18 22:38:56 +00:00
cd "$(dirname "$(readlink -f "$0")")" || exit 1;
2019-03-10 00:30:34 +00:00
if [ ! -d "${PWD}/.git" ]; then
2019-07-18 22:38:56 +00:00
# shellcheck disable=SC1117
2019-03-10 00:30:34 +00:00
echo -e "\033[1m\033[31mError: The .git folder does not appear to exist. Please ensure you clone this repository with git, like this:\n\n\tgit clone https://github.com/ConnectedHumber/Air-Quality-Web.git\n\033[0m";
exit 1;
fi
2019-01-12 23:23:55 +00:00
################
### Settings ###
################
# The name of this project
project_name="Air Quality Mapper";
# The path to the lantern build engine git submodule
lantern_path="./lantern-build-engine";
###
# Custom Settings
###
# Put any custom settings here.
# Client-side build output
cache_dir="./.cache";
2019-01-13 13:22:13 +00:00
build_output_folder="./app";
2019-01-12 23:23:55 +00:00
# Database settings for ssh port forwarding task
2019-01-14 20:50:12 +00:00
database_host="db.connectedhumber.org";
database_name="aq_db";
2019-09-18 21:41:42 +00:00
database_user="www-data";
2019-01-14 20:50:12 +00:00
# Minimum major version of npm
min_npm_version_major="6";
# Deployment settings
deploy_ssh_user="ci";
2019-09-19 17:30:50 +00:00
deploy_ssh_host="aq.connectedhumber.org";
deploy_ssh_port="22";
deploy_root_dir="Air-Quality-Web";
2019-07-18 22:27:15 +00:00
deploy_root_dir_beta="Air-Quality-Web-Beta";
2019-01-12 23:23:55 +00:00
###############################################################################
# Check out the lantern git submodule if needed
2019-01-13 12:50:47 +00:00
if [ ! -f "${lantern_path}/lantern.sh" ]; then git submodule update --init "${lantern_path}"; fi
2019-01-12 23:23:55 +00:00
2019-07-18 22:38:56 +00:00
# shellcheck disable=SC1090
2019-01-12 23:23:55 +00:00
source "${lantern_path}/lantern.sh";
if [[ "$#" -lt 1 ]]; then
echo -e "${FBLE}${project_name}${RS} build script";
echo -e " by Starbeamrainbowlabs";
2019-07-18 22:38:56 +00:00
# shellcheck disable=SC2154
2019-01-12 23:23:55 +00:00
echo -e "${LC}Powered by the lantern build engine, v${version}${RS}";
echo -e "";
echo -e "${CSECTION}Usage${RS}";
echo -e " ./build ${CTOKEN}{action}${RS} ${CTOKEN}{action}${RS} ${CTOKEN}{action}${RS} ...";
echo -e "";
echo -e "${CSECTION}Available actions${RS}";
echo -e " ${CACTION}setup${RS} - Perform initial setup";
2019-01-12 23:38:05 +00:00
echo -e " ${CACTION}setup-dev${RS} - Perform additional setup for development environments. Run after ${CACTION}setup${RS}.";
2019-01-12 23:23:55 +00:00
echo -e " ${CACTION}database${RS} - Connect to the database via SSH & open MariaDB CLI connection, prompting for a password";
echo -e " ${CACTION}dev-server${RS} - Start a development server";
echo -e " ${CACTION}dev-server-stop${RS} - Stop the currently running development server";
2019-01-13 13:15:11 +00:00
echo -e " ${CACTION}client${RS} - Build the client web app";
2019-03-17 13:29:20 +00:00
echo -e " ${CACTION}client-watch${RS} - Watch for changes to the client code & rebuild automatically";
echo -e " ${CACTION}docs${RS} - Render the documentation";
echo -e " ${CACTION}ci${RS} - Perform CI tasks";
2019-03-30 12:48:58 +00:00
echo -e " ${LC}${CACTION}archive${RS} - CI: Create release archive";
2019-01-12 23:23:55 +00:00
echo -e "";
exit 1;
fi
###############################################################################
2019-03-17 13:29:20 +00:00
# ███████ ███████ ████████ ██ ██ ██████
# ██ ██ ██ ██ ██ ██ ██
# ███████ █████ ██ ██ ██ ██████
# ██ ██ ██ ██ ██ ██
# ███████ ███████ ██ ██████ ██
task_download-composer() {
if [ -f "${cache_dir}/composer" ]; then
return 0;
fi
2019-03-30 12:03:25 +00:00
[ ! -d "${cache_dir}" ] && mkdir "${cache_dir}";
task_begin "Downloading composer";
2019-07-18 22:53:18 +00:00
execute curl -sS "https://getcomposer.org/composer.phar" -o "${cache_dir}/composer"; exit_code=$?;
chmod +x "${cache_dir}/composer";
task_end ${exit_code};
}
2019-04-04 22:01:57 +00:00
check_php_module() {
module_name="$1";
subtask_begin "Checking for ${module_name} PHP module";
2019-07-18 22:38:56 +00:00
if [[ "$(php -m | grep -ic pdo_mysql)" -eq "0" ]]; then
2019-04-04 22:01:57 +00:00
subtask_end 1 "Error: The php_mysql PHP module is not installed.";
fi
subtask_end 0;
}
2019-03-17 13:29:20 +00:00
task_setup() {
2019-01-12 23:23:55 +00:00
stage_begin "Setting up";
task_begin "Checking environment";
check_command git true;
check_command php true;
check_command node true;
check_command npm true;
check_command curl true;
2019-04-04 22:01:57 +00:00
check_php_module pdo_mysql;
check_php_module mbstring;
2019-04-04 22:01:57 +00:00
2019-03-10 00:30:34 +00:00
if [ ! -w "${PWD}" ]; then
task_end 1 "${HC}${FRED}Error: Can't write to the repository directory! This usually you have a permission error of some kind. Try using sudo to run this build command as the user that owns this cloned repository.";
fi
npm_version_major="$(npm --version | head -c 1)";
if [[ "${npm_version_major}" -lt "${min_npm_version_major}" ]]; then
echo "${FRED}${HC}Error: Your version of npm is too far out of date. You're running version $(npm --version), but version 6+ is required.";
fi
2019-01-12 23:23:55 +00:00
task_end $?;
task_begin "Initialising submodules";
execute git submodule update --init;
2019-01-12 23:23:55 +00:00
task_end $?;
task_begin "Installing client dependencies";
2019-04-06 22:47:04 +00:00
echo -e "${HC}Not including development dependencies. To complete setup for development, execute the ${CACTION}setup-dev${RS} ${HC}build task.${RS}";
execute npm install --production;
2019-01-12 23:23:55 +00:00
task_end $?;
tasks_run download-composer;
2019-01-12 23:23:55 +00:00
task_begin "Installing server dependencies";
execute "${cache_dir}/composer" install --no-dev;
2019-01-12 23:23:55 +00:00
task_end $?;
if [ ! -d "./data" ]; then
task_begin "Setting up initial data folder";
mkdir "./data"; chmod 0700 "./data";
echo -e "# -------[ Custom Settings File - Last updated $(date) ]-------" >"./data/settings.toml";
2019-04-23 12:48:53 +00:00
echo -e '[database]\nusername = "INSERT_DATABASE_USERNAME_HERE"\npassword = "INSERT_DATABASE_PASSWORD_HERE"' >>"./data/settings.toml";
chmod 0600 "./data/settings.toml";
echo -e "${HC}Don't forget to edit './data/settings.toml' to specify the database username and password${RS}";
2019-03-07 18:40:30 +00:00
echo -e "";
task_end $?;
fi
2019-01-12 23:23:55 +00:00
stage_end $?;
}
2019-03-17 13:29:20 +00:00
task_setup-dev() {
2019-01-12 23:23:55 +00:00
task_begin "Checking environment";
check_command mysql true optional;
task_end $?;
task_begin "Installing client development dependencies";
execute npm install;
2019-01-12 23:23:55 +00:00
task_end $?;
task_begin "Installing server development dependencies";
execute "${cache_dir}/composer" install;
2019-01-13 12:50:47 +00:00
task_end $?;
}
2019-03-17 13:29:20 +00:00
# ██████ ███████ ██ ██
# ██ ██ ██ ██ ██
# ██ ██ █████ ██ ██
# ██ ██ ██ ██ ██
# ██████ ███████ ████
task_database() {
2019-01-13 12:50:47 +00:00
task_begin "Connecting to the database";
2019-04-16 14:17:37 +00:00
set_title "Database";
2019-01-14 20:50:12 +00:00
ssh -TN "${database_host}" -L 3306:localhost:3306 &
2019-01-13 12:50:47 +00:00
ssh_pid=$!;
2019-01-14 20:50:12 +00:00
sleep 1;
2019-09-18 21:41:42 +00:00
mysql --host 127.0.0.1 --port 3306 --database "${database_name}" --user "${database_user}" --password;
2019-01-13 12:50:47 +00:00
kill "${ssh_pid}"; wait; sleep 0.5;
2019-01-12 23:23:55 +00:00
task_end $?;
}
2019-03-17 13:29:20 +00:00
task_dev-server() {
2019-01-12 23:23:55 +00:00
task_begin "Starting development server";
2019-07-18 22:38:56 +00:00
php -S "[::1]:40482" &
2019-01-12 23:23:55 +00:00
exit_code=$?;
[[ "${exit_code}" -eq "0" ]] && echo $! >/tmp/micro-lantern-dev-server.pid;
2019-01-12 23:23:55 +00:00
task_end $?; # Should be 0 unless php died for some reason
sleep 1;
}
2019-03-17 13:29:20 +00:00
task_dev-server-stop() {
2019-01-12 23:23:55 +00:00
task_begin "Stopping development server";
kill "$(cat /tmp/micro-lantern-dev-server.pid)";
rm /tmp/micro-lantern-dev-server.pid;
task_end $?;
}
2019-01-13 13:15:11 +00:00
2019-03-17 13:29:20 +00:00
# ██████ ██ ██ ███████ ███ ██ ████████
# ██ ██ ██ ██ ████ ██ ██
# ██ ██ ██ █████ ██ ██ ██ ██
# ██ ██ ██ ██ ██ ██ ██ ██
# ██████ ███████ ██ ███████ ██ ████ ██
task_client() {
2019-01-13 13:15:11 +00:00
task_begin "Packaging Javascript";
2019-09-18 21:41:42 +00:00
execute node_modules/.bin/rollup --sourcemap --config rollup.config.js;
task_end $? "Error: rollup packing failed!";
2019-01-12 23:23:55 +00:00
task_begin "Copying html";
execute cp client_src/index.html "${build_output_folder}";
2019-01-12 23:23:55 +00:00
task_end $?;
2019-01-17 12:48:09 +00:00
# task_begin "Copying css";
# # FUTURE: Package this up too?
# cp -r client_src/css/ "${build_output_folder}";
# task_end $?;
2019-01-12 23:23:55 +00:00
}
2019-03-17 13:29:20 +00:00
task_client-watch() {
2019-04-16 14:17:37 +00:00
set_title "Client Watcher";
2019-01-13 13:15:11 +00:00
echo -e "Watching for changes.";
while :; do # : = infinite loop
# Wait for an update
# inotifywait's non-0 exit code forces an exit for some reason :-/
inotifywait -qr --event modify --format '%:e %f' client_src;
# Rebuild the client code - spawn a sub-process to avoid the hard exit
# This still doesn't work though, which is *really* annoying
2019-01-13 13:15:11 +00:00
stage_begin "Rebuilding client code";
./build client;
2019-01-13 13:15:11 +00:00
stage_end $?;
done
}
2019-03-17 13:29:20 +00:00
# ██████ ██████ ██████ ███████
# ██ ██ ██ ██ ██ ██
# ██ ██ ██ ██ ██ ███████
# ██ ██ ██ ██ ██ ██
# ██████ ██████ ██████ ███████
task_docs() {
task_begin "Rendering docs";
execute node_modules/.bin/nightdocs --config nightdocs.toml;
2019-03-17 13:29:20 +00:00
task_end $?;
task_begin "Copying images";
cp -r docs/images/ __nightdocs/;
task_end $?;
2019-03-17 13:29:20 +00:00
}
# ██████ ██
# ██ ██
# ██ ██
# ██ ██
# ██████ ██
task_ci() {
2019-03-30 12:36:22 +00:00
tasks_run setup setup-dev
2019-03-30 12:48:58 +00:00
NODE_ENV="production" tasks_run client docs archive;
2019-04-14 20:41:04 +00:00
latest_commit="$(git log -n 1 --pretty=format:"%H")";
current_commit="$(git rev-parse HEAD)";
2019-07-18 22:27:15 +00:00
if [ "${latest_commit}" != "${current_commit}" ]; then
echo "Not deploying, as this isn't the latest commit on the branch.";
2019-07-18 22:51:55 +00:00
echo "It's likely that this commit is actually one of several in a queue to be processed by the CI server at once.";
2019-07-18 22:27:15 +00:00
return 0;
fi
if [ "${GIT_REF_NAME}" == "refs/heads/master" ]; then
tasks_run deploy;
2019-07-18 22:38:56 +00:00
elif [ "${GIT_REF_NAME}" == "refs/heads/dev" ]; then
2019-07-18 22:27:15 +00:00
echo "Deploying as beta release, as we're on the dev branch";
deploy_root_dir="${deploy_root_dir_beta}";
tasks_run deploy;
else
2019-07-18 22:27:15 +00:00
echo "Not deploying, as we're not on either the master or dev branches.";
fi
2019-03-30 12:48:58 +00:00
}
task_archive() {
task_begin "Preparing to archive";
2019-04-12 21:53:06 +00:00
execute mv vendor vendor.bak;
execute "${cache_dir}/composer" install --no-dev;
task_end $?;
task_begin "Packing archive";
2019-03-30 12:48:58 +00:00
# We include the data directory here because we assume that this task is ONLY run in a CI environment, so it should only contain the default setup generated by an earlier task.
2019-07-18 22:38:56 +00:00
execute tar cafv "${ARCHIVE}/Air-Quality-Web.tar.gz" app/ __nightdocs/ lib/ logic/ vendor/ data/ ./*.php ./*.md LICENSE version settings.default.toml;
task_end $?;
task_begin "Cleaning up";
execute rm -rf vendor;
execute mv vendor.bak vendor;
task_end $?;
2019-03-17 13:29:20 +00:00
}
task_deploy() {
stage_begin "Deploying to ${deploy_ssh_host}....";
if [ "${SSH_KEY_PATH}" == "" ]; then
2019-04-11 18:23:21 +00:00
echo "${FRED}${HC}Error: Can't find the SSH key as the environment variable SSH_KEY_PATH isn't set.${RS}" >&2;
stage_end 1;
fi
task_begin "Preparing upload";
subtask_begin "Creating temporary directory";
2019-04-07 16:07:21 +00:00
temp_dir="$(mktemp -d --suffix "-air-quality-upload")";
subtask_end $? "Error: Failed to create temporary directory";
subtask_begin "Unpacking release files";
2019-04-12 23:02:35 +00:00
execute tar -xf "${ARCHIVE}/Air-Quality-Web.tar.gz" -C "${temp_dir}";
subtask_end $? "Failed to unpack release files";
2019-04-12 22:50:36 +00:00
subtask_begin "Removing data directory";
2019-04-07 16:07:21 +00:00
rm -r "${temp_dir}/data"; # Delete the default data directory - there's one on the server already
2019-04-12 22:50:36 +00:00
subtask_end $?;
subtask_begin "Unwinding symlinks";
2019-04-12 23:02:35 +00:00
find "${temp_dir}" -type l -exec bash -c 'ln -f "$(readlink -m "$0")" "$0"' {} \;
2019-04-12 22:50:36 +00:00
subtask_end $?;
2019-04-12 22:51:34 +00:00
task_end $?;
# Define the directory whose contents we want to upload
2019-04-07 16:07:21 +00:00
source_upload_dir="${temp_dir}/";
task_begin "Acquiring upload lock";
# Acquire an exclusive project-wide lock so that we only upload stuff one-at-a-time
exec 9<"${WORKSPACE}";
flock --exclusive 9;
task_end $? "Failed to acquire lock!";
task_begin "Uploading release";
sftp -i "${SSH_KEY_PATH}" -P "${deploy_ssh_port}" -o PasswordAuthentication=no "${deploy_ssh_user}@${deploy_ssh_host}" << SFTPCOMMANDS
mkdir ${deploy_root_dir}/www-new
put -r ${source_upload_dir}/* ${deploy_root_dir}/www-new
bye
SFTPCOMMANDS
task_end $?;
task_begin "Making release live";
# Actions:
# 1. Connect to remote server
# 2. Upload new files
# 3. Create data dir symlink
# 4. Swap in new directory
# 5. Delete old directory
2019-04-07 22:43:17 +00:00
lftp_commands_filename="$(mktemp --suffix "-commands.lftp")";
(
2019-04-11 18:43:53 +00:00
echo "set sftp:connect-program 'ssh -x -i ${SSH_KEY_PATH}'";
2019-04-07 17:06:16 +00:00
# We have an extra : before the @ here to avoid the password prompt
2019-04-11 18:19:55 +00:00
echo "connect sftp://${deploy_ssh_user}:@${deploy_ssh_host}:${deploy_ssh_port}";
2019-04-07 16:53:55 +00:00
echo "ln -s \"../data\" \"${deploy_root_dir}/www-new/data\"";
2019-04-07 16:53:55 +00:00
echo "mv \"${deploy_root_dir}/www\" \"${deploy_root_dir}/www-old\"";
echo "mv \"${deploy_root_dir}/www-new\" \"${deploy_root_dir}/www\"";
2019-06-22 09:57:11 +00:00
echo "rm -r \"${deploy_root_dir}/data/cache\"";
echo "rm -r \"${deploy_root_dir}/www-old\"";
echo "bye";
2019-04-07 22:43:17 +00:00
) >"${lftp_commands_filename}";
2019-04-07 22:43:17 +00:00
execute lftp --version;
2019-04-11 21:15:53 +00:00
execute cat "${lftp_commands_filename}";
2019-04-07 22:43:17 +00:00
execute lftp -f "${lftp_commands_filename}";
exit_code=$?
task_end "${exit_code}" "Failed to make release live";
task_begin "Releasing lock";
exec 9>&- # Close file descriptor 9 and release the lock
task_end $?;
2019-04-07 14:34:06 +00:00
task_begin "Cleaning up";
execute rm -r "${temp_dir}";
task_end $?;
stage_end $? "Failed to deploy to ${deploy_ssh_host}.";
}
2019-01-12 23:23:55 +00:00
#########################################################################
2019-07-18 22:38:56 +00:00
tasks_run "$@";