Moved actions to remote repo
Some checks failed
Deploy / deploy-production (push) Failing after 9s
Deploy / deploy-preview (push) Has been skipped
Deploy / cleanup-preview (push) Has been skipped

This commit is contained in:
2026-04-11 21:03:34 -05:00
parent 3f632c98f3
commit 1ea827f568
5 changed files with 38 additions and 263 deletions

View File

@@ -1,40 +0,0 @@
#!/usr/bin/env bash
# Start or replace a Next.js Docker container
set -euo pipefail
APP_NAME=""
TAG=""
PORT=""
ENV=""
while [[ $# -gt 0 ]]; do
case $1 in
--name) APP_NAME="$2"; shift 2 ;;
--tag) TAG="$2"; shift 2 ;;
--port) PORT="$2"; shift 2 ;;
--env) ENV="$2"; shift 2 ;;
*) echo "Unknown arg: $1"; exit 1 ;;
esac
done
CONTAINER="${APP_NAME}-${TAG}"
echo "→ Deploying container: ${CONTAINER} on port ${PORT}"
docker stop "${CONTAINER}" 2>/dev/null && docker rm "${CONTAINER}" 2>/dev/null || true
ENV_FILE_ARG=""
if [[ -f "/opt/apps/${APP_NAME}/.env.${ENV}" ]]; then
ENV_FILE_ARG="--env-file /opt/apps/${APP_NAME}/.env.${ENV}"
fi
docker run -d \
--name "${CONTAINER}" \
--restart unless-stopped \
-p "0.0.0.0:${PORT}:3000" \
-e NODE_ENV=production \
-e PORT=3000 \
${ENV_FILE_ARG} \
"${APP_NAME}:${TAG}"
echo "✓ Container ${CONTAINER} running on 0.0.0.0:${PORT}"

View File

@@ -1,41 +0,0 @@
#!/usr/bin/env bash
# Remove a Pangolin resource by name
#
# Required env vars:
# PANGOLIN_API_URL, PANGOLIN_API_KEY, PANGOLIN_ORG_ID
set -euo pipefail
RESOURCE_NAME=""
while [[ $# -gt 0 ]]; do
case $1 in
--resource-name) RESOURCE_NAME="$2"; shift 2 ;;
*) echo "Unknown arg: $1"; exit 1 ;;
esac
done
API="${PANGOLIN_API_URL}/v1"
AUTH="Authorization: Bearer ${PANGOLIN_API_KEY}"
echo "→ Pangolin delete: ${RESOURCE_NAME}"
RESOURCE_ID=$(curl -sf \
-H "${AUTH}" \
"${API}/org/${PANGOLIN_ORG_ID}/resources?limit=1000" \
| jq -r --arg name "${RESOURCE_NAME}" \
'.data.resources[] | select(.name == $name) | .resourceId' \
|| echo "")
if [[ -z "${RESOURCE_ID}" ]]; then
echo " No resource found with name '${RESOURCE_NAME}', skipping."
exit 0
fi
echo " Found resource ${RESOURCE_ID}, deleting…"
curl -sf -X DELETE \
-H "${AUTH}" \
"${API}/resource/${RESOURCE_ID}" \
> /dev/null
echo "✓ Resource ${RESOURCE_ID} (${RESOURCE_NAME}) removed from Pangolin"

View File

@@ -1,93 +0,0 @@
#!/usr/bin/env bash
# Idempotently register an HTTP resource + target in Pangolin
#
# Required env vars:
# PANGOLIN_API_URL, PANGOLIN_API_KEY, PANGOLIN_ORG_ID,
# PANGOLIN_DOMAIN_ID, PANGOLIN_SITE_ID, PANGOLIN_TARGET_IP
set -euo pipefail
SUBDOMAIN=""
PORT=""
RESOURCE_NAME=""
TARGET_IP=""
while [[ $# -gt 0 ]]; do
case $1 in
--subdomain) SUBDOMAIN="$2"; shift 2 ;;
--port) PORT="$2"; shift 2 ;;
--resource-name) RESOURCE_NAME="$2"; shift 2 ;;
--target-ip) TARGET_IP="$2"; shift 2 ;;
*) echo "Unknown arg: $1"; exit 1 ;;
esac
done
API="${PANGOLIN_API_URL}/v1"
AUTH="Authorization: Bearer ${PANGOLIN_API_KEY}"
echo "→ Pangolin upsert: ${RESOURCE_NAME}${SUBDOMAIN} on port ${PORT}"
# Check if resource already exists
EXISTING=$(curl -sf \
-H "${AUTH}" \
"${API}/org/${PANGOLIN_ORG_ID}/resources?limit=1000" \
| jq -r --arg name "${RESOURCE_NAME}" \
'.data.resources[] | select(.name == $name) | .resourceId' \
|| echo "")
if [[ -n "${EXISTING}" ]]; then
echo " Resource already exists (id=${EXISTING}), updating…"
RESOURCE_ID="${EXISTING}"
curl -sf -X POST \
-H "${AUTH}" \
-H "Content-Type: application/json" \
-d "{\"subdomain\": \"${SUBDOMAIN}\"}" \
"${API}/resource/${RESOURCE_ID}" \
> /dev/null
# Remove existing targets so we can re-register with potentially new port
TARGETS=$(curl -sf \
-H "${AUTH}" \
"${API}/resource/${RESOURCE_ID}/targets" \
| jq -r '.data.targets[].targetId' || echo "")
for TID in ${TARGETS}; do
curl -sf -X DELETE \
-H "${AUTH}" \
"${API}/target/${TID}" > /dev/null
echo " Removed old target ${TID}"
done
else
echo " Creating new resource…"
CREATE_RESP=$(curl -sf -X PUT \
-H "${AUTH}" \
-H "Content-Type: application/json" \
-d "{
\"name\": \"${RESOURCE_NAME}\",
\"http\": true,
\"subdomain\": \"${SUBDOMAIN}\",
\"domainId\": \"${PANGOLIN_DOMAIN_ID}\",
\"protocol\": \"tcp\"
}" \
"${API}/org/${PANGOLIN_ORG_ID}/resource")
RESOURCE_ID=$(echo "${CREATE_RESP}" | jq -r '.data.resourceId')
FULL_DOMAIN=$(echo "${CREATE_RESP}" | jq -r '.data.fullDomain')
echo " Created resource ${RESOURCE_ID}${FULL_DOMAIN}"
fi
# Add target
echo " Adding target localhost:${PORT} on site ${PANGOLIN_SITE_ID}"
TARGET_RESP=$(curl -sf -X PUT \
-H "${AUTH}" \
-H "Content-Type: application/json" \
-d "{
\"ip\": \"${TARGET_IP}\",
\"port\": ${PORT},
\"method\": \"http\",
\"siteId\": ${PANGOLIN_SITE_ID}
}" \
"${API}/resource/${RESOURCE_ID}/target")
TARGET_ID=$(echo "${TARGET_RESP}" | jq -r '.data.targetId')
echo "✓ Target ${TARGET_ID} registered for resource ${RESOURCE_ID}"

View File

@@ -2,11 +2,17 @@ name: Deploy
on:
push:
branches:
- main
- '**'
branches: ["main", "**"]
delete:
env:
PANGOLIN_API_URL: ${{ secrets.PANGOLIN_API_URL }}
PANGOLIN_API_KEY: ${{ secrets.PANGOLIN_API_KEY }}
PANGOLIN_ORG_ID: ${{ secrets.PANGOLIN_ORG_ID }}
PANGOLIN_DOMAIN_ID: ${{ secrets.PANGOLIN_DOMAIN_ID }}
PANGOLIN_SITE_ID: ${{ secrets.PANGOLIN_SITE_ID }}
PANGOLIN_TARGET_IP: ${{ secrets.PANGOLIN_TARGET_IP }}
jobs:
deploy-production:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
@@ -14,34 +20,13 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Build Docker image
run: |
docker build \
--build-arg NEXT_PUBLIC_APP_ENV=production \
-t ${{ vars.APP_NAME }}:production \
-f dockerfile .
- name: Deploy production container
run: |
bash .gitea/scripts/deploy.sh \
--name "${{ vars.APP_NAME }}" \
--tag "production" \
--port "${{ vars.PROD_PORT }}" \
--env "production"
- name: Register Pangolin resource
run: |
bash .gitea/scripts/pangolin-upsert.sh \
--subdomain "${{ vars.PROD_SUBDOMAIN }}" \
--port "${{ vars.PROD_PORT }}" \
--resource-name "${{ vars.APP_NAME }}-production" \
--target-ip "${{ secrets.PANGOLIN_TARGET_IP }}"
env:
PANGOLIN_API_URL: ${{ secrets.PANGOLIN_API_URL }}
PANGOLIN_API_KEY: ${{ secrets.PANGOLIN_API_KEY }}
PANGOLIN_ORG_ID: ${{ secrets.PANGOLIN_ORG_ID }}
PANGOLIN_DOMAIN_ID: ${{ secrets.PANGOLIN_DOMAIN_ID }}
PANGOLIN_SITE_ID: ${{ secrets.PANGOLIN_SITE_ID }}
- uses: zyrrus/node-deploy-action/deploy@v1
with:
app-name: ${{ vars.APP_NAME }}
tag: production
port: ${{ vars.PROD_PORT }}
environment: production
subdomain: ${{ vars.PROD_SUBDOMAIN }}
deploy-preview:
if: github.event_name == 'push' && github.ref != 'refs/heads/main'
@@ -51,41 +36,17 @@ jobs:
- name: Compute preview slug
id: slug
run: |
BRANCH="${GITHUB_REF_NAME}"
SLUG=$(echo "$BRANCH" | tr '/' '-' | tr '_' '-' | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]//g' | cut -c1-40)
echo "slug=$SLUG" >> "$GITHUB_OUTPUT"
PORT=$(( 20000 + ( $(echo -n "$SLUG" | cksum | awk '{print $1}') % 10000 ) ))
echo "port=$PORT" >> "$GITHUB_OUTPUT"
uses: zyrrus/node-deploy-action/slug@v1
with:
branch: ${{ github.ref_name }}
- name: Build Docker image
run: |
docker build \
--build-arg NEXT_PUBLIC_APP_ENV=preview \
-t ${{ vars.APP_NAME }}:${{ steps.slug.outputs.slug }} \
-f dockerfile .
- name: Deploy preview container
run: |
bash .gitea/scripts/deploy.sh \
--name "${{ vars.APP_NAME }}" \
--tag "${{ steps.slug.outputs.slug }}" \
--port "${{ steps.slug.outputs.port }}" \
--env "preview"
- name: Register Pangolin preview resource
run: |
bash .gitea/scripts/pangolin-upsert.sh \
--subdomain "${{ steps.slug.outputs.slug }}.${{ vars.APP_NAME }}" \
--port "${{ steps.slug.outputs.port }}" \
--resource-name "${{ vars.APP_NAME }}-${{ steps.slug.outputs.slug }}" \
--target-ip "${{ secrets.PANGOLIN_TARGET_IP }}"
env:
PANGOLIN_API_URL: ${{ secrets.PANGOLIN_API_URL }}
PANGOLIN_API_KEY: ${{ secrets.PANGOLIN_API_KEY }}
PANGOLIN_ORG_ID: ${{ secrets.PANGOLIN_ORG_ID }}
PANGOLIN_DOMAIN_ID: ${{ secrets.PANGOLIN_DOMAIN_ID }}
PANGOLIN_SITE_ID: ${{ secrets.PANGOLIN_SITE_ID }}
- uses: zyrrus/node-deploy-action/deploy@v1
with:
app-name: ${{ vars.APP_NAME }}
tag: ${{ steps.slug.outputs.slug }}
port: ${{ steps.slug.outputs.port }}
environment: preview
subdomain: ${{ steps.slug.outputs.slug }}.${{ vars.APP_NAME }}
cleanup-preview:
if: github.event_name == 'delete' && github.event.ref_type == 'branch'
@@ -93,27 +54,15 @@ jobs:
steps:
- name: Compute preview slug
id: slug
run: |
BRANCH="${{ github.event.ref }}"
SLUG=$(echo "$BRANCH" | tr '/' '-' | tr '_' '-' | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]//g' | cut -c1-40)
echo "slug=$SLUG" >> "$GITHUB_OUTPUT"
uses: zyrrus/node-deploy-action/slug@v1
with:
branch: ${{ github.event.ref }}
- uses: actions/checkout@v4
with:
ref: main
- name: Remove Pangolin resource
run: |
bash .gitea/scripts/pangolin-delete.sh \
--resource-name "${{ vars.APP_NAME }}-${{ steps.slug.outputs.slug }}"
env:
PANGOLIN_API_URL: ${{ secrets.PANGOLIN_API_URL }}
PANGOLIN_API_KEY: ${{ secrets.PANGOLIN_API_KEY }}
PANGOLIN_ORG_ID: ${{ secrets.PANGOLIN_ORG_ID }}
- name: Stop preview container
run: |
CONTAINER="${{ vars.APP_NAME }}-${{ steps.slug.outputs.slug }}"
docker stop "$CONTAINER" 2>/dev/null || true
docker rm "$CONTAINER" 2>/dev/null || true
docker rmi "${{ vars.APP_NAME }}:${{ steps.slug.outputs.slug }}" 2>/dev/null || true
- uses: zyrrus/node-deploy-action/cleanup@v1
with:
app-name: ${{ vars.APP_NAME }}
slug: ${{ steps.slug.outputs.slug }}

View File

@@ -1,4 +1,4 @@
# ── Stage 1: deps
# === Stage 1: deps ===
FROM node:20-alpine AS deps
WORKDIR /app
@@ -9,19 +9,19 @@ RUN \
else npm ci; \
fi
# ── Stage 2: build
# === Stage 2: build ===
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ARG NEXT_PUBLIC_APP_ENV=production
ENV NEXT_PUBLIC_APP_ENV=$NEXT_PUBLIC_APP_ENV
ARG APP_ENV=production
ENV NEXT_PUBLIC_APP_ENV=$APP_ENV
RUN npm run build
# ── Stage 3: runner
# === Stage 3: runner ===
FROM node:20-alpine AS runner
WORKDIR /app