#!/usr/bin/env bash SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" BASE_DIR="$(pwd)" BASE_EXT=$(basename ${BASE_DIR}) CYAN="\033[96m" YELLOW="\033[93m" RESET="\033[0m" BOLD="\033[1m" NORMAL="\033[22m" CHECK="\xE2\x9C\x94" PUSH="" REGISTRY="" REGISTRY_ORG="" IMAGE_PREFIX="ui-extension-" FORCE="false" GITHUB_BUILD="true" GITHUB_SOURCE=$(git config --get remote.origin.url | sed -e 's/^git@.*:\([[:graph:]]*\).git/\1/') GITHUB_BRANCH="main" usage() { echo "Usage: $0 [] [plugins]" echo " options:" echo " -p Push container images on build" echo " -f Force building the chart even if it already exists" echo " -r Specify destination container registry for built images" echo " -o Specify destination container registry organization for built images" echo " -i Specify prefix for the built container image (default: 'ui-extension-')" echo " -c Build as a container image rather than publishing to Github" echo " -s Specify destination GitHub repository (org/name) - defaults to the git origin" echo " -b Specify destination GitHub branch" exit 1 } while getopts "hvr:o:pi:fcb:s:" opt; do case $opt in h) usage ;; p) PUSH="--push" ;; r) REGISTRY="${OPTARG%/}/" ;; o) REGISTRY_ORG="${OPTARG}" ;; i) IMAGE_PREFIX="${OPTARG}" ;; f) FORCE="true" ;; c) GITHUB_BUILD="false" ;; s) GITHUB_BUILD="true" GITHUB_SOURCE="${OPTARG}" ;; b) GITHUB_BUILD="true" GITHUB_BRANCH="${OPTARG}" ;; *) usage ;; esac done shift $((OPTIND-1)) PLUGINS=( "$@" ) BUILT="false" echo -e "${CYAN}${BOLD}Publishing UI Plugins${RESET}" pushd ${BASE_DIR} > /dev/null if [ "${GITHUB_BUILD}" == "true" ]; then # Determine if gh-pages build is possible if [[ "${GITHUB_BRANCH}" == "gh-pages" ]] && ! git show-ref -q gh-pages; then echo -e "${YELLOW}'gh-pages' branch not found, this branch must exist before running this script${RESET}" exit 1 fi echo -e "${CYAN}GitHub Repository: ${GITHUB_SOURCE}${RESET}" echo -e "${CYAN}GitHub Branch : ${GITHUB_BRANCH}${RESET}" else echo -e ${CYAN}"Image prefix: ${IMAGE_PREFIX}${RESET}" fi # -------------------------------------------------------------------------------- # Check that we have the required commands avaialble for this script # -------------------------------------------------------------------------------- if ! [[ -f ${BASE_DIR}/package.json ]]; then echo -e "${YELLOW}You must run from the top-level folder${RESET}" exit 1 fi # Check this is a Rancher extension IS_SHELL=$(grep "\"@rancher/shell" package.json -c) if [ "${IS_SHELL}" -ne 1 ]; then echo -e "${YELLOW}Current folder does not appear to contain Rancher Extensions${RESET}" exit 1 fi if ! [[ -d ${BASE_DIR}/node_modules ]]; then echo -e "${YELLOW}You must run ${BOLD}yarn install${NORMAL} before running this script${RESET}" exit 1 fi COMMANDS=("node" "jq" "yq" "git" "docker" "helm" "yarn") HAVE_COMMANDS="true" for CMD in "${COMMANDS[@]}" do if ! command -v ${CMD} >/dev/null; then echo -e "${YELLOW}This script requires ${BOLD}${CMD}${NORMAL} to be installed and on your PATH${RESET}" HAVE_COMMANDS="false" fi done if [ "${HAVE_COMMANDS}" == "false" ]; then exit 1 fi # -------------------------------------------------------------------------------- # Only do conatiner args checks if not GitHub publish if [ "${GITHUB_BUILD}" == "false" ]; then if [[ -z ${REGISTRY_ORG} ]]; then # Infer that the user has the same Docker registry org as their GitHub org GITHUB_REPO=$(git config --get remote.origin.url | sed -e 's/^git@.*:\([[:graph:]]*\).git/\1/') REGISTRY_ORG=$(dirname ${GITHUB_REPO}) echo -e "Inferring built images will reside in registry organization ${CYAN}${BOLD}${REGISTRY}${REGISTRY_ORG}${RESET} based on configured origin remote pointing to ${CYAN}${BOLD}${GITHUB_REPO}${RESET}" fi if [[ -z ${REGISTRY_ORG} ]]; then # Inferring from the git config still failed echo "Cannot build images without valid organization for Docker images. Unable to infer REGISTRY_ORG=" exit 1 fi docker images > /dev/null if [ $? -ne 0 ]; then echo "docker is not running - this is required to build container images for the UI Plugins" exit 1 fi fi ASSETS=${BASE_DIR}/assets CHARTS=${BASE_DIR}/charts mkdir -p ${ASSETS} mkdir -p ${CHARTS} TMP=${BASE_DIR}/tmp CHART_TMP=${BASE_DIR}/tmp/_charts rm -rf ${TMP} mkdir -p ${TMP} # -------------------------------------------------------------------------------- # Copy the plugin server template into the temporary folder # -------------------------------------------------------------------------------- pushd ${TMP} > /dev/null cp -r ${SCRIPT_DIR}/helm . popd > /dev/null CHART_TEMPLATE=${BASE_DIR}/tmp/helm ROOT_INDEX=${BASE_DIR}/index.yaml # -------------------------------------------------------------------------------- # Iterate through all packages - built them all or build only those specified on the command line # -------------------------------------------------------------------------------- for d in pkg/*/ ; do pkg=$(basename $d) if [ -z "$1" ] || [[ " ${PLUGINS[*]} " =~ " ${pkg} " ]]; then # Check we don't already have a published version by looking in the assets folder PKG_VERSION=$(jq -r .version ./pkg/${pkg}/package.json) PKG_NAME="${pkg}-${PKG_VERSION}" PKG_ASSET=${ASSETS}/${pkg}/${PKG_NAME}.tgz echo -e "${CYAN}${BOLD}Building plugin: ${pkg} (${PKG_VERSION}) ${RESET}" echo "Package version: ${PKG_VERSION}" echo "Package folder: ${PKG_NAME}" # -------------------------------------------------------------------------------- # Build the plugin from source # -------------------------------------------------------------------------------- echo -e "${CYAN}Building plugin from source code${RESET}" FORCE_COLOR=1 yarn build-pkg $pkg | cat echo -e "${CYAN}Adding plugin code ...${RESET}" EXT_FOLDER=${BASE_DIR}/extensions/${pkg}/${PKG_VERSION} PKG_DIST="${BASE_DIR}/dist-pkg/${PKG_NAME}" rm -rf ${EXT_FOLDER} mkdir -p ${EXT_FOLDER}/plugin # Copy the code into the folder cp -R ${PKG_DIST}/* ${EXT_FOLDER}/plugin pushd ${BASE_DIR}/extensions/${pkg}/${PKG_VERSION} > /dev/null rm -f plugin/report.html find plugin -type f | sort > files.txt popd > /dev/null # -------------------------------------------------------------------------------- # Create the Helm chart # -------------------------------------------------------------------------------- if [ -f ${PKG_ASSET} ] && [ "${FORCE}" == "false" ]; then echo -e "${YELLOW}Helm chart has already been created - skipping (run with -f to force build)${RESET}" continue; fi CHART_FOLDER=${CHARTS}/${pkg}/${PKG_VERSION} mkdir -p ${ASSETS}/${pkg} rm -rf ${CHART_FOLDER} mkdir -p ${CHART_FOLDER} cp -R ${CHART_TEMPLATE}/charts/ui-plugin-server/* ${CHART_FOLDER} # Update Chart.yaml and values.yaml from the package file metadata # Use the script from the template repository echo -e "${CYAN}Patching Helm chart template${RESET}" CHART=${CHART_FOLDER} REGISTRY="${REGISTRY}" ORG="${REGISTRY_ORG}" PACKAGE_JSON=${BASE_DIR}/pkg/${pkg}/package.json ${CHART_TEMPLATE}/scripts/patch # Copy README file from the plugin to the Helm chart, if there is one if [ -f "./pkg/${pkg}/README.md" ]; then cp ./pkg/${pkg}/README.md ${CHART_FOLDER}/README.md fi pushd ${CHART_FOLDER}/templates > /dev/null if [ "${GITHUB_BUILD}" == "true" ]; then echo "Patching for GitHub build" ENDPOINT=https://raw.githubusercontent.com/${GITHUB_SOURCE}/${GITHUB_BRANCH}/extensions/${pkg}/${PKG_VERSION} else echo "Patching for container build" ENDPOINT=http://${IMAGE_PREFIX}${BASE_EXT}-svc.cattle-ui-plugin-system:8080/plugin/${PKG_NAME} fi sed -i.bak -e 's@endpoint: .*@endpoint: '"${ENDPOINT}"'@g' cr.yaml rm *.bak popd > /dev/null # Additional patches ${SCRIPT_DIR}/helmpatch ${CHART_FOLDER} "${BASE_DIR}/pkg/${pkg}/package.json" # Package into a .tgz helm chart helm package ${CHART_FOLDER} -d ${ASSETS}/${pkg} # -------------------------------------------------------------------------------- # Update the helm index just for this chart # -------------------------------------------------------------------------------- HELM_INDEX=${BASE_DIR}/index.yaml if [ -f "${HELM_INDEX}" ]; then UPDATE="--merge ${HELM_INDEX}" elif [ "${GITHUB_BUILD}" == "true" ] && [[ -n ${GITHUB_SOURCE} ]]; then # Check if git branch contains index.yaml GITHUB_SOURCE=$(echo -e "${GITHUB_SOURCE}" | sed 's/https:\/\///g') wget -P ${BASE_DIR} https://raw.githubusercontent.com/${GITHUB_SOURCE}/${GITHUB_BRANCH}/index.yaml 2>/dev/null HELM_INDEX="${BASE_DIR}/index.yaml" if [ -f "${HELM_INDEX}" ]; then UPDATE="--merge ${HELM_INDEX}" fi fi # Base URL referencing assets directly from GitHub BASE_URL="assets/" # Relative URL references assets within the container deployment RELATIVE_URL="plugin/" rm -rf ${CHART_TMP} mkdir -p ${CHART_TMP} cp ${ASSETS}/${pkg}/*.tgz ${CHART_TMP} if [ "${GITHUB_BUILD}" == "true" ]; then helm repo index ${ASSETS} --url ${BASE_URL} ${UPDATE} elif ! [ -e "${HELM_INDEX}" ]; then helm repo index ${ASSETS} --url ${RELATIVE_URL} fi BUILT="true" fi done if [ -f ${ROOT_INDEX} ]; then UPDATE="--merge ${ROOT_INDEX}" helm repo index ${ASSETS} ${UPDATE} fi if [ -f ${ASSETS}/index.yaml ]; then cp ${ASSETS}/index.yaml ${BASE_DIR} fi if [ "${GITHUB_BUILD}" == "false" ]; then EXT_VERSION=$(jq -r .version ${BASE_DIR}/package.json) if [ -z ${EXT_VERSION} ]; then EXT_VERSION="0.0.0" fi echo -e "${CYAN}Base extension: ${BASE_EXT}${RESET}" echo -e "${CYAN}Extension version: ${EXT_VERSION}${RESET}" # Build the docker image ${SCRIPT_DIR}/bundle ${BASE_EXT} ${EXT_VERSION} ${REGISTRY} ${REGISTRY_ORG} ${IMAGE_PREFIX} ${PUSH} else rm -rf ${CHART_TEMPLATE} fi if [ "${GITHUB_BUILD}" == "true" ] && [ -f ${ROOT_INDEX} ]; then cp ${ROOT_INDEX} tmp fi if [ "${GITHUB_BUILD}" == "true" ] && [ "${BUILT}" == "true" ]; then echo -e "${BOLD}${CYAN}Packaging for Github Build${RESET}" # Make temp directory for workflow build artifact mkdir -p tmp/{assets,charts,extensions} cp -r ${ASSETS}/* tmp/assets cp -r ${CHARTS}/* tmp/charts cp -r ${BASE_DIR}/extensions/* tmp/extensions fi if [ "${BUILT}" == "true" ]; then echo -e "${CYAN}${BOLD}${CHECK} One or more packages built${RESET}" fi # Clean up rm -rf ${CHART_TMP} if [ "${GITHUB_BUILD}" == "false" ]; then rm -rf ${TMP} fi