Skip to content

feat(mcp): manage dashboards and reports (#454) #771

feat(mcp): manage dashboards and reports (#454)

feat(mcp): manage dashboards and reports (#454) #771

Workflow file for this run

name: Docker Build and Push
on:
workflow_dispatch:
push:
paths-ignore:
# README and docs
- "**/README*"
- "**/readme*"
- "**/*.md"
- "**/docs/**"
- "**/CHANGELOG*"
- "**/LICENSE*"
# Test files
- "**/*.test.*"
- "**/*.spec.*"
- "**/__tests__/**"
- "**/tests/**"
# SDKs (published separately)
- "packages/sdks/**"
# Public app (docs/marketing, not part of Docker deploy)
- "apps/public/**"
# Dev / tooling
- "**/.vscode/**"
- "**/.cursor/**"
- "**/.env.example"
- "**/.env.*.example"
- "**/.gitignore"
- "**/.eslintignore"
- "**/.prettierignore"
env:
repo_owner: "openpanel-dev"
jobs:
lint-and-test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16-alpine
ports:
- 5432:5432
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
options: >-
--health-cmd "pg_isready -U postgres"
--health-interval 5s
--health-timeout 3s
--health-retries 20
redis:
image: redis:7-alpine
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping || exit 1"
--health-interval 5s
--health-timeout 3s
--health-retries 20
clickhouse:
image: clickhouse/clickhouse-server:26.1.3.52
ports:
- 8123:8123
env:
CLICKHOUSE_DB: openpanel
CLICKHOUSE_USER: default
CLICKHOUSE_PASSWORD: ""
CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: 1
options: >-
--health-cmd "wget -qO- http://localhost:8123/ping || exit 1"
--health-interval 5s
--health-timeout 3s
--health-retries 20
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
# .nvmrc is the source of truth; keep ARG NODE_VERSION in
# apps/*/Dockerfile in sync with it. Must stay >=22.19.0:
# undici@8 fails at import on older Node with
# "webidl.util.markAsUncloneable is not a function".
node-version-file: ".nvmrc"
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- name: Setup pnpm cache
uses: actions/cache@v3
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install
- name: Codegen
run: pnpm codegen
- name: Migrate database
run: pnpm migrate:deploy
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/postgres?schema=public
DATABASE_URL_DIRECT: postgresql://postgres:postgres@localhost:5432/postgres?schema=public
CLICKHOUSE_URL: http://localhost:8123/openpanel
SELF_HOSTED: "true"
- name: Run tests
run: pnpm test
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/postgres?schema=public
CLICKHOUSE_URL: http://localhost:8123/openpanel
REDIS_URL: redis://localhost:6379
# - name: Run Biome
# run: pnpm lint
# - name: Run TypeScript checks
# run: pnpm typecheck
build-api:
permissions:
packages: write
contents: read
needs: lint-and-test
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
runs-on: ${{ matrix.runner }}
steps:
- name: Prepare platform pair
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push by digest
id: build
uses: docker/build-push-action@v6
with:
context: .
file: apps/api/Dockerfile
platforms: ${{ matrix.platform }}
cache-from: type=gha,scope=api-${{ env.PLATFORM_PAIR }}
cache-to: type=gha,mode=max,scope=api-${{ env.PLATFORM_PAIR }}
outputs: type=image,name=ghcr.io/${{ env.repo_owner }}/api,push-by-digest=true,name-canonical=true,push=true
build-args: |
DATABASE_URL=postgresql://dummy:dummy@localhost:5432/dummy
- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-api-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
# Boots the images this run produced and asserts they actually serve traffic.
# Gates every merge-* job below, so a broken image never gets a pullable tag.
smoke:
permissions:
packages: read
contents: read
needs: [build-api, build-worker, build-dashboard]
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# build-* pushed by digest but has not tagged anything yet, so pull the
# exact amd64 digests this run produced.
- name: Download amd64 digests
uses: actions/download-artifact@v4
with:
path: /tmp/smoke-digests
pattern: digests-*-linux-amd64
- name: Resolve images
run: |
set -euo pipefail
for app in api worker dashboard; do
dir="/tmp/smoke-digests/digests-${app}-linux-amd64"
digest="$(ls "$dir" | head -1)"
if [ -z "$digest" ]; then
echo "::error::no digest artifact for $app"
exit 1
fi
image="ghcr.io/${{ env.repo_owner }}/${app}@sha256:${digest}"
echo "$app -> $image"
echo "OP_$(echo "$app" | tr '[:lower:]' '[:upper:]')_IMAGE=$image" >> "$GITHUB_ENV"
done
- name: Smoke test the stack
run: .github/smoke/smoke.sh
- name: Tear down
if: always()
run: docker compose -f .github/smoke/docker-compose.yml down -v || true
merge-api:
permissions:
packages: write
contents: write
needs: [build-api, smoke]
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download digests
uses: actions/download-artifact@v4
with:
path: /tmp/digests
pattern: digests-api-*
merge-multiple: true
- name: Generate tags
id: tags
run: |
BRANCH_NAME=$(echo "${{ github.ref_name }}" | sed 's/\//-/g')
SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-4)
echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT
echo "short_sha=$SHORT_SHA" >> $GITHUB_OUTPUT
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create manifest list and push
working-directory: /tmp/digests
run: |
docker buildx imagetools create \
-t ghcr.io/${{ env.repo_owner }}/api:${{ steps.tags.outputs.branch_name }}-${{ steps.tags.outputs.short_sha }} \
$(printf 'ghcr.io/${{ env.repo_owner }}/api@sha256:%s ' *)
- name: Create/Update API tag
if: github.ref == 'refs/heads/main'
run: |
# Delete existing tag if it exists
if git tag -l "api" | grep -q "api"; then
git tag -d "api"
echo "Deleted local tag: api"
fi
# Create new tag
git tag "api" "${{ github.sha }}"
echo "Created tag: api"
# Push tag to remote
git push origin "api" --force
echo "Pushed tag: api"
build-worker:
permissions:
packages: write
contents: read
needs: lint-and-test
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
runs-on: ${{ matrix.runner }}
steps:
- name: Prepare platform pair
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push by digest
id: build
uses: docker/build-push-action@v6
with:
context: .
file: apps/worker/Dockerfile
platforms: ${{ matrix.platform }}
cache-from: type=gha,scope=worker-${{ env.PLATFORM_PAIR }}
cache-to: type=gha,mode=max,scope=worker-${{ env.PLATFORM_PAIR }}
outputs: type=image,name=ghcr.io/${{ env.repo_owner }}/worker,push-by-digest=true,name-canonical=true,push=true
build-args: |
DATABASE_URL=postgresql://dummy:dummy@localhost:5432/dummy
- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-worker-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
merge-worker:
permissions:
packages: write
contents: write
needs: [build-worker, smoke]
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download digests
uses: actions/download-artifact@v4
with:
path: /tmp/digests
pattern: digests-worker-*
merge-multiple: true
- name: Generate tags
id: tags
run: |
BRANCH_NAME=$(echo "${{ github.ref_name }}" | sed 's/\//-/g')
SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-4)
echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT
echo "short_sha=$SHORT_SHA" >> $GITHUB_OUTPUT
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create manifest list and push
working-directory: /tmp/digests
run: |
docker buildx imagetools create \
-t ghcr.io/${{ env.repo_owner }}/worker:${{ steps.tags.outputs.branch_name }}-${{ steps.tags.outputs.short_sha }} \
$(printf 'ghcr.io/${{ env.repo_owner }}/worker@sha256:%s ' *)
- name: Create/Update Worker tag
if: github.ref == 'refs/heads/main'
run: |
# Delete existing tag if it exists
if git tag -l "worker" | grep -q "worker"; then
git tag -d "worker"
echo "Deleted local tag: worker"
fi
# Create new tag
git tag "worker" "${{ github.sha }}"
echo "Created tag: worker"
# Push tag to remote
git push origin "worker" --force
echo "Pushed tag: worker"
build-dashboard:
permissions:
packages: write
contents: read
needs: lint-and-test
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
runs-on: ${{ matrix.runner }}
steps:
- name: Prepare platform pair
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push by digest
id: build
uses: docker/build-push-action@v6
with:
context: .
file: apps/start/Dockerfile
platforms: ${{ matrix.platform }}
cache-from: type=gha,scope=dashboard-${{ env.PLATFORM_PAIR }}
cache-to: type=gha,mode=max,scope=dashboard-${{ env.PLATFORM_PAIR }}
outputs: type=image,name=ghcr.io/${{ env.repo_owner }}/dashboard,push-by-digest=true,name-canonical=true,push=true
build-args: |
NO_CLOUDFLARE=1
- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-dashboard-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
merge-dashboard:
permissions:
packages: write
contents: write
needs: [build-dashboard, smoke]
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download digests
uses: actions/download-artifact@v4
with:
path: /tmp/digests
pattern: digests-dashboard-*
merge-multiple: true
- name: Generate tags
id: tags
run: |
BRANCH_NAME=$(echo "${{ github.ref_name }}" | sed 's/\//-/g')
SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-4)
echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT
echo "short_sha=$SHORT_SHA" >> $GITHUB_OUTPUT
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create manifest list and push
working-directory: /tmp/digests
run: |
docker buildx imagetools create \
-t ghcr.io/${{ env.repo_owner }}/dashboard:${{ steps.tags.outputs.branch_name }}-${{ steps.tags.outputs.short_sha }} \
$(printf 'ghcr.io/${{ env.repo_owner }}/dashboard@sha256:%s ' *)
- name: Create/Update Dashboard tag
if: github.ref == 'refs/heads/main'
run: |
# Delete existing tag if it exists
if git tag -l "dashboard" | grep -q "dashboard"; then
git tag -d "dashboard"
echo "Deleted local tag: dashboard"
fi
# Create new tag
git tag "dashboard" "${{ github.sha }}"
echo "Created tag: dashboard"
# Push tag to remote
git push origin "dashboard" --force
echo "Pushed tag: dashboard"