From a7b12f5c6539046ebf52fce2de4557bf37dd1539 Mon Sep 17 00:00:00 2001 From: Robert Herber Date: Wed, 31 Jan 2024 12:02:45 +0000 Subject: [PATCH] Add docker-build, caprover-deploy and caprover-configure-app --- .github/workflows/caprover-configure-app.yml | 171 +++++++++++++++++++ .github/workflows/caprover-deploy.yml | 66 +++++++ .github/workflows/docker-build.yml | 59 +++++++ 3 files changed, 296 insertions(+) create mode 100644 .github/workflows/caprover-configure-app.yml create mode 100644 .github/workflows/caprover-deploy.yml create mode 100644 .github/workflows/docker-build.yml diff --git a/.github/workflows/caprover-configure-app.yml b/.github/workflows/caprover-configure-app.yml new file mode 100644 index 0000000..aa79ef7 --- /dev/null +++ b/.github/workflows/caprover-configure-app.yml @@ -0,0 +1,171 @@ +# This is a basic workflow to help you get started with Actions + +name: Create Caprover App + +on: + workflow_call: + secrets: + caproverPassword: + required: true + inputs: + discordWebhook: + required: false + type: string + envFile: + required: false + type: string + default: .env.github + caproverAppName: + required: true + type: string + caproverDomain: + required: true + type: string + deployTargetUrl: + required: false + type: string + deploymentEnvFile: + required: false + type: string + deploymentEnvVars: + required: false + type: string + description: Overrides deploymentEnvFile if specified + default: "[]" + hasPersistentData: + type: boolean + required: false + default: false + websocketSupport: + type: boolean + required: false + default: true + containerHttpPort: + type: number + default: 80 + instanceCount: + type: number + default: 1 + workflow_dispatch: + inputs: + instanceCount: + type: number + default: 1 + containerHttpPort: + type: number + default: 80 + discordWebhook: + required: false + type: string + envFile: + required: false + type: string + default: .env.github + deploymentEnvFile: + required: false + type: string + deploymentEnvVars: + required: false + type: string + description: Overrides deploymentEnvFile if specified + default: "[]" + caproverAppName: + required: true + type: string + caproverDomain: + required: true + type: string + deployTargetUrl: + required: false + type: string + hasPersistentData: + type: boolean + required: false + default: false + websocketSupport: + type: boolean + required: false + default: true + +jobs: + deploy: + runs-on: ubuntu-latest + timeout-minutes: 5 + concurrency: deploy-to-kingstinct-dev + env: + CAPROVER_URL: https://captain.${{ inputs.caproverDomain }} + defaultDeployTargetUrl: "https://${{ inputs.caproverAppName }}.${{ inputs.caproverDomain }}" + CAPROVER_PASSWORD: ${{ secrets.caproverPassword }} + envVars: ${{ inputs.deploymentEnvVars }} + CAPROVER_APP: ${{ inputs.caproverAppName }} + environment: + name: ${{ inputs.caproverAppName }} + url: ${{ inputs.deployTargetUrl || env.defaultDeployTargetUrl }} + steps: + - uses: actions/checkout@v3 + + - uses: cardinalby/export-env-action@2.2.0 + with: + envFile: ${{ inputs.envFile }} + + - uses: oven-sh/setup-bun@v1 + with: + bun-version: ${{ env.BUN_VERSION }} + + - name: Create Caprover App 👨‍✈️ + run: bunx caprover api --path=/user/apps/appDefinitions/register --method=POST --data='{"appName":"${{ inputs.caproverAppName }}","hasPersistentData":${{ inputs.hasPersistentData }}}' || true + + # # should optimally combine manual env vars (that could contain secrets) with .env file, problem with .ts here is the dependency on the code from the workflow.. + - name: Read env file + if: ${{ !inputs.deploymentEnvVars && inputs.deploymentEnvFile }} + run: | + | file_path="${ENV_PATH:-.env.github}" + | + | index=0 + | multiline_start_index=-1 + | + | json="[" + + | while IFS= read -r line || [[ -n "$line" ]]; do + | has_multiline_character=$(echo "$line" | grep -F "'") + + | if [[ -n "$has_multiline_character" && $multiline_start_index -eq -1 ]]; then + | # found a multiline value + | multiline_start_index=$index + | elif [[ -n "$has_multiline_character" && $multiline_start_index -ne -1 ]]; then + | # found end of a multiline value + | rows_with_value=$(sed -n "$((multiline_start_index+1)),$((index+1))p" "$file_path" | tr '\n' '\n') + | key=$(echo "$rows_with_value" | cut -d '=' -f 1) + | value=$(echo "$rows_with_value" | cut -d '=' -f 2- | sed "s/'//g") + | json+="{\"key\":\"$key\",\"value\":\"$value\"}," + | multiline_start_index=-1 + | elif [[ -z "$has_multiline_character" && $multiline_start_index -ne -1 ]]; then + | # keep looking for end of multiline value + | : + | else + | # Single-line value + | key=$(echo "$line" | cut -d '=' -f 1) + | value=$(echo "$line" | cut -d '=' -f 2-) + | json+="{\"key\":\"$key\",\"value\":\"$value\"}," + | fi + | + | ((index++)) + | done < "$file_path" + | + | # Remove trailing comma and close the JSON array + | json="${json%?}]" + | + | echo "$json" + | echo "envVars=$json" >> $GITHUB_ENV + + - name: Update App Settings ⚙️ + run: bunx caprover api --path=/user/apps/appDefinitions/update --method=POST --data='{ "appName":"${{ inputs.caproverAppName }}", "websocketSupport":${{ inputs.websocketSupport }}, "containerHttpPort":${{ inputs.containerHttpPort }}, "instanceCount":${{ inputs.instanceCount }}, "envVars":${{ env.envVars }} }' + + - name: Enable SSL 🔒 + run: bunx caprover api --path=/user/apps/appDefinitions/enablebasedomainssl --method=POST --data='{"appName":"${{ inputs.caproverAppName }}"}' + + - uses: sarisia/actions-status-discord@v1 + if: ${{ inputs.discordWebhook }} + with: + webhook: ${{ inputs.discordWebhook }} + url: ${{ inputs.deployTargetUrl || env.defaultDeployTargetUrl }} diff --git a/.github/workflows/caprover-deploy.yml b/.github/workflows/caprover-deploy.yml new file mode 100644 index 0000000..dfd92b0 --- /dev/null +++ b/.github/workflows/caprover-deploy.yml @@ -0,0 +1,66 @@ +# This is a basic workflow to help you get started with Actions + +name: Caprover Deploy + +on: + workflow_call: + secrets: + caproverPassword: + required: true + description: Caprover password + inputs: + discordWebhook: + required: false + description: Discord webhook + type: string + envFile: + required: false + type: string + default: .env.github + caproverAppName: + required: true + type: string + caproverDomain: + required: true + type: string + deployTargetUrl: + required: false + type: string + caproverImageName: + required: false + type: string + default: "ghcr.io/${{ github.repository }}:${{ github.sha }}" + +jobs: + deploy: + runs-on: ubuntu-latest + timeout-minutes: 5 + env: + defaultDeployTargetUrl: "https://${{ inputs.caproverAppName }}.${{ inputs.caproverDomain }}" + environment: + name: ${{ inputs.caproverAppName }} + url: ${{ inputs.deployTargetUrl || env.defaultDeployTargetUrl }} + steps: + - uses: actions/checkout@v3 + - uses: cardinalby/export-env-action@2.2.0 + with: + envFile: ${{ inputs.envFile }} + + - uses: oven-sh/setup-bun@v1 + with: + bun-version: ${{ env.BUN_VERSION }} + + - run: bun install --concurrent-scripts 1 --frozen-lockfile + + - run: bunx caprover deploy + env: + CAPROVER_URL: https://captain.${{ inputs.caproverDomain }} + CAPROVER_PASSWORD: ${{ secrets.caproverPassword }} + CAPROVER_IMAGE_NAME: ${{ inputs.caproverImageName }} + CAPROVER_APP: ${{ inputs.caproverAppName }} + + - uses: sarisia/actions-status-discord@v1 + if: ${{ inputs.discordWebhook }} + with: + webhook: ${{ inputs.discordWebhook }} + url: ${{ inputs.deployTargetUrl || env.defaultDeployTargetUrl }} diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml new file mode 100644 index 0000000..2249ccb --- /dev/null +++ b/.github/workflows/docker-build.yml @@ -0,0 +1,59 @@ +# This is a basic workflow to help you get started with Actions + +name: Docker Build + +on: + workflow_call: + secrets: + GITHUB_TOKEN: + required: true + inputs: + envFile: + required: false + type: string + default: .env.github + discordWebhook: + required: false + type: string + dockerBuildArgs: + required: false + type: string + dockerImageTags: + required: false + type: string + default: ghcr.io/${{ github.repository }}:latest,ghcr.io/${{ github.repository }}:${{ github.sha }} + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v3 + - uses: cardinalby/export-env-action@2.2.0 + with: + envFile: ${{ inputs.envFile }} + + - name: Log in to the Container registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - uses: docker/setup-buildx-action@v2 + + - uses: docker/build-push-action@v4 + env: + baseImage: BASE_IMAGE=oven/bun:${{ env.BUN_VERSION || 'latest' }}-slim + with: + push: true + context: . + build-args: ${{ inputs.dockerBuildArgs || env.baseImage }} + cache-from: type=gha + cache-to: type=gha,mode=max + tags: ${{ inputs.tags }} + + - uses: sarisia/actions-status-discord@v1 + if: ${{ failure() && inputs.discordWebhook }} + with: + webhook: ${{ inputs.discordWebhook }}