diff --git a/Dockerfile b/Dockerfile index 4e7c0b8..90eaab5 100755 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM node:16.16.0-alpine3.16 LABEL org.opencontainers.image.source = "https://github.com/josedev-union/caprover-compose-action" -RUN apk add --no-cache git bash \ +RUN apk add --no-cache curl git bash jq \ && npm i -g caprover \ && npm cache clean --force diff --git a/README.md b/README.md index 47597d3..79cf48a 100755 --- a/README.md +++ b/README.md @@ -6,6 +6,17 @@ As Caprover doesn't support docker-compose stil([link](https://caprover.com/docs - First, in the compose context dir(configurable by `context` parameter), create one directory per one application. Directory name is used as the application name. - In each application folder, create a `captain_definition` file. This will be used for application deployment. - Also in the same folder, you can create `json` or `yml` files to configure the application. The file format should follow Caprover configuration file for consuming Caprover API([link](https://github.com/caprover/caprover-cli/tree/master#api)). These files are applied to the application in the order of their names using `caprover api` command. +Note: If Caprover configuration file includes application name, please use `$APP` as application name because a unique application name is generated per a pull request. +For example, this is a Caprover configuration file to enable SSL. +```json +{ + "path": "/user/apps/appDefinitions/enablebasedomainssl", + "method": "POST", + "data": { + "appName": "$APP" + } +} +``` ## Example compose context Here is the example directory structure of a system consisting of multiple microservices. @@ -54,11 +65,6 @@ This Github Action requires the following parameters; - context The path of definition and configuration files of applications. Optional. Default: `.caprover/` -- prefix - - The name prefix for all applications in the compose. - Note: Some Caprover APIs require app name as a request parameter so when you prepare app configuration files, keep in mind that you have to set the app name correctly. `${prefix}-${app_directory_name}` - For example, you set `prefix` as `ci`, then the applications' names in the above example directory structure are `ci-frontend`, `ci-auth_api`, etc. Example usage; ```yaml @@ -79,5 +85,4 @@ jobs: uses: josedev-union/caprover-compose-action@main with: server: https://captain.your-domain.com - prefix: ci ``` diff --git a/entrypoint.sh b/entrypoint.sh index 5af559b..d0d2223 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,18 +1,57 @@ -#!/bin/bash -set -e +#!/bin/bash -e # TODO(joseb): # 1. Convert to python. ref: https://github.com/ak4zh/Caprover-API # 2. Exception handling. This will be much easier with python sdk. # 3. Set output, like app url etc. This will be much easier with python sdk. +# 4. App name validation +# 5. Generate prefix based on the git ref automatically if not presented. -compose_ctx_path=${INPUT_CONTEXT:-.caprover} +########################### Global var def +COMPOSE_CTX_PATH=${INPUT_CONTEXT:-.caprover} +APP_NAME_PREFIX=${INPUT_PREFIX:-pr} +EVENT_ID=$(echo "$GITHUB_REF" | awk -F / '{print $3}') +## caprover cli config vars export CAPROVER_URL=$INPUT_SERVER export CAPROVER_PASSWORD=${INPUT_PASSWORD:-captain42} export CAPROVER_NAME=default -# caprover login +## caprover api request vars +NS="x-namespace: captain" +CTYPE="Content-Type: application/json" +# getToken gets the token from Caprover API. +getToken() { + res=$(curl -sSf "$CAPROVER_URL/api/v2/login" -X POST -d '{"password":"'$CAPROVER_PASSWORD'"}' -H "$CTYPE" -H "$NS") + token=$(echo "$res"|awk -F'"token":"' '{print $2}'|awk -F'"' '{print $1}'|grep .) + echo $token +} +AUTH="x-captain-auth: $(getToken)" + +########################### Function def + +# waitApp waits until the app is ready. +# +# Arguments: +# $1: app name. +# +waitApp() { + app_name=$1 + for i in $(seq 10); do + res=$(curl -sSf "$CAPROVER_URL/api/v2/user/apps/appData/$app_name" -H "$CTYPE" -H "$NS" -H "$AUTH") + echo $res|jq '.description' -r && echo "$res"|grep '"status":100,' >/dev/null + is_building=$(echo $res|jq '.data.isAppBuilding') + echo "App building: $is_building" + if [ "$is_building" == "false" ]; then + echo "App is ready now!" + break + else + echo "Waiting until ready (try: $i)" + sleep 10 + fi + done +} +# setOutput does action output setOutput() { echo "${1}=${2}" >> "${GITHUB_OUTPUT}" } @@ -38,33 +77,57 @@ createApp() { # ensureSingleApp() { app_ctx_path=${1} - app_name=${2} - echo "[app:$app_name] deployment step!"; + app_alias=${2} + app_name=$(generateAppName ${2}) + echo "[app:$app_alias] app name: $app_name"; + + # Deploy app + echo "[app:$app_alias] deployment step!"; set +e res=$(caprover deploy --appName $app_name -c $app_ctx_path/captain-definition) if [ $? -eq 0 ]; then set -e - echo "[app:$app_name] successfully deployed! $res"; + echo "$res"; + echo "[app:$app_alias] successfully deployed!"; else set -e if [[ "$res" == *"not exist"* ]]; then - echo "[app:$app_name] create a new app!"; + echo "[app:$app_alias] create a new app as it doesn't exist!"; createApp $app_name; - echo "[app:$app_name] deployment step!"; + waitApp $app_name; + echo "[app:$app_alias] deployment step!"; caprover deploy --appName $app_name -c $app_ctx_path/captain-definition; else - echo "::error::[app:$app_name]Caprover deploy failed." + echo "::error::[app:$app_alias]Caprover deploy failed." exit 1; fi fi - echo "[app:$app_name] configuration step!"; + + # Configure app + echo "[app:$app_alias] configuration step!"; for f in $(find $app_ctx_path/ -type f | egrep -i 'yml|yaml|json' | sort); do - echo "[app:$app_name] - processing $f config file..."; + echo "[app:$app_alias] - processing $f config file..."; + sed -i "s/\$APP/$app_name/g" $f caprover api -c $f done } -for app in $compose_ctx_path/*/; do +preValidate() { + # Allow only pull requests + if [ "${GITHUB_EVENT_NAME}" != "pull_request" ] + then + echo "This action only works in pull requests." + exit 0 + fi +} + +generateAppName() { + echo "${APP_NAME_PREFIX}-${GITHUB_REPOSITORY_ID}-${EVENT_ID}-${1}" +} + +########################### Main +preValidate +for app in $COMPOSE_CTX_PATH/*/; do echo "Deploying $(basename "$app") app..."; - ensureSingleApp "${app}" "${INPUT_PREFIX}-$(basename $app)" + ensureSingleApp "${app}" "$(basename $app)" done