Some checks failed
CI/CD / lint (push) Successful in 41s
CI/CD / typecheck (push) Successful in 42s
CI/CD / test (push) Successful in 53s
CI/CD / build (push) Successful in 1m8s
CI/CD / docker (push) Failing after 33s
CI/CD / publish-rpm (push) Successful in 38s
CI/CD / deploy (push) Has been skipped
Docker CLI can't connect to the podman socket in the runner container (permission denied even as root). Switch to podman for building images locally and skopeo with containers-storage transport for pushing. Podman builds don't need a daemon socket. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
275 lines
8.7 KiB
YAML
275 lines
8.7 KiB
YAML
name: CI/CD
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
pull_request:
|
|
branches: [main]
|
|
|
|
env:
|
|
GITEA_REGISTRY: 10.0.0.194:3012
|
|
GITEA_OWNER: michal
|
|
|
|
# ============================================================
|
|
# Required Gitea secrets:
|
|
# PACKAGES_TOKEN — Gitea API token (packages + registry)
|
|
# PORTAINER_PASSWORD — Portainer login for stack deploy
|
|
# POSTGRES_PASSWORD — Database password for production stack
|
|
# ============================================================
|
|
|
|
jobs:
|
|
# ── CI checks (run in parallel on every push/PR) ──────────
|
|
|
|
lint:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: pnpm/action-setup@v4
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 20
|
|
cache: pnpm
|
|
|
|
- run: pnpm install --frozen-lockfile
|
|
|
|
- name: Lint
|
|
run: pnpm lint || echo "::warning::Lint has errors — not blocking CI yet"
|
|
|
|
typecheck:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: pnpm/action-setup@v4
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 20
|
|
cache: pnpm
|
|
|
|
- run: pnpm install --frozen-lockfile
|
|
|
|
- name: Generate Prisma client
|
|
run: pnpm --filter @mcpctl/db exec prisma generate
|
|
|
|
- name: Typecheck
|
|
run: pnpm typecheck
|
|
|
|
test:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: pnpm/action-setup@v4
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 20
|
|
cache: pnpm
|
|
|
|
- run: pnpm install --frozen-lockfile
|
|
|
|
- name: Generate Prisma client
|
|
run: pnpm --filter @mcpctl/db exec prisma generate
|
|
|
|
- name: Build (needed by completions test)
|
|
run: pnpm build
|
|
|
|
- name: Run tests
|
|
run: pnpm test:run
|
|
|
|
# ── Build & package RPM ───────────────────────────────────
|
|
|
|
build:
|
|
runs-on: ubuntu-latest
|
|
needs: [lint, typecheck, test]
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: pnpm/action-setup@v4
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 20
|
|
cache: pnpm
|
|
|
|
- name: Install dependencies (hoisted for bun compile compatibility)
|
|
run: |
|
|
echo "node-linker=hoisted" >> .npmrc
|
|
pnpm install --frozen-lockfile
|
|
|
|
- name: Generate Prisma client
|
|
run: pnpm --filter @mcpctl/db exec prisma generate
|
|
|
|
- name: Build all packages
|
|
run: pnpm build
|
|
|
|
- name: Generate shell completions
|
|
run: pnpm completions:generate
|
|
|
|
- uses: oven-sh/setup-bun@v2
|
|
|
|
- name: Install nfpm
|
|
run: |
|
|
curl -sL -o /tmp/nfpm.tar.gz "https://github.com/goreleaser/nfpm/releases/download/v2.45.0/nfpm_2.45.0_Linux_x86_64.tar.gz"
|
|
tar xzf /tmp/nfpm.tar.gz -C /usr/local/bin nfpm
|
|
|
|
- name: Bundle standalone binaries
|
|
run: |
|
|
mkdir -p dist
|
|
# Stub for optional dep that Ink tries to import (only used when DEV=true)
|
|
# Copy instead of symlink — bun can't read directory symlinks
|
|
if [ ! -e node_modules/react-devtools-core/package.json ]; then
|
|
rm -rf node_modules/react-devtools-core
|
|
cp -r src/cli/stubs/react-devtools-core node_modules/react-devtools-core
|
|
fi
|
|
bun build src/cli/src/index.ts --compile --outfile dist/mcpctl
|
|
bun build src/mcplocal/src/main.ts --compile --outfile dist/mcpctl-local
|
|
|
|
- name: Package RPM
|
|
run: nfpm pkg --packager rpm --target dist/
|
|
|
|
- name: Upload RPM artifact
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: rpm-package
|
|
path: dist/mcpctl-*.rpm
|
|
retention-days: 7
|
|
|
|
# ── Release pipeline (main branch push only) ──────────────
|
|
|
|
docker:
|
|
runs-on: ubuntu-latest
|
|
needs: [build]
|
|
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
|
env:
|
|
REGISTRY: ${{ env.GITEA_REGISTRY }}
|
|
OWNER: ${{ env.GITEA_OWNER }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Install podman and skopeo
|
|
run: sudo apt-get update && sudo apt-get install -y podman skopeo
|
|
|
|
- name: Build & push mcpd
|
|
run: |
|
|
sudo -E podman build -t mcpd:latest -f deploy/Dockerfile.mcpd .
|
|
sudo -E skopeo copy --dest-tls-verify=false \
|
|
--dest-creds "${{ env.OWNER }}:${{ secrets.PACKAGES_TOKEN }}" \
|
|
containers-storage:mcpd:latest \
|
|
docker://${{ env.REGISTRY }}/${{ env.OWNER }}/mcpd:latest
|
|
|
|
- name: Build & push node-runner
|
|
run: |
|
|
sudo -E podman build -t node-runner:latest -f deploy/Dockerfile.node-runner .
|
|
sudo -E skopeo copy --dest-tls-verify=false \
|
|
--dest-creds "${{ env.OWNER }}:${{ secrets.PACKAGES_TOKEN }}" \
|
|
containers-storage:node-runner:latest \
|
|
docker://${{ env.REGISTRY }}/${{ env.OWNER }}/mcpctl-node-runner:latest
|
|
|
|
- name: Build & push python-runner
|
|
run: |
|
|
sudo -E podman build -t python-runner:latest -f deploy/Dockerfile.python-runner .
|
|
sudo -E skopeo copy --dest-tls-verify=false \
|
|
--dest-creds "${{ env.OWNER }}:${{ secrets.PACKAGES_TOKEN }}" \
|
|
containers-storage:python-runner:latest \
|
|
docker://${{ env.REGISTRY }}/${{ env.OWNER }}/mcpctl-python-runner:latest
|
|
|
|
- name: Build & push docmost-mcp
|
|
run: |
|
|
sudo -E podman build -t docmost-mcp:latest -f deploy/Dockerfile.docmost-mcp .
|
|
sudo -E skopeo copy --dest-tls-verify=false \
|
|
--dest-creds "${{ env.OWNER }}:${{ secrets.PACKAGES_TOKEN }}" \
|
|
containers-storage:docmost-mcp:latest \
|
|
docker://${{ env.REGISTRY }}/${{ env.OWNER }}/docmost-mcp:latest
|
|
|
|
- name: Link packages to repository
|
|
env:
|
|
GITEA_TOKEN: ${{ secrets.PACKAGES_TOKEN }}
|
|
GITEA_URL: http://${{ env.GITEA_REGISTRY }}
|
|
GITEA_OWNER: ${{ env.GITEA_OWNER }}
|
|
GITEA_REPO: mcpctl
|
|
run: |
|
|
source scripts/link-package.sh
|
|
link_package "container" "mcpd"
|
|
link_package "container" "mcpctl-node-runner"
|
|
link_package "container" "mcpctl-python-runner"
|
|
link_package "container" "docmost-mcp"
|
|
|
|
publish-rpm:
|
|
runs-on: ubuntu-latest
|
|
needs: [build]
|
|
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Download RPM artifact
|
|
uses: actions/download-artifact@v3
|
|
with:
|
|
name: rpm-package
|
|
path: dist/
|
|
|
|
- name: Install rpm tools
|
|
run: sudo apt-get update && sudo apt-get install -y rpm
|
|
|
|
- name: Publish RPM to Gitea
|
|
env:
|
|
GITEA_TOKEN: ${{ secrets.PACKAGES_TOKEN }}
|
|
GITEA_URL: http://${{ env.GITEA_REGISTRY }}
|
|
GITEA_OWNER: ${{ env.GITEA_OWNER }}
|
|
GITEA_REPO: mcpctl
|
|
run: |
|
|
RPM_FILE=$(ls dist/mcpctl-*.rpm | head -1)
|
|
RPM_VERSION=$(rpm -qp --queryformat '%{VERSION}-%{RELEASE}' "$RPM_FILE")
|
|
echo "Publishing $RPM_FILE (version $RPM_VERSION)..."
|
|
|
|
# Delete existing version if present
|
|
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
|
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
"${GITEA_URL}/api/v1/packages/${GITEA_OWNER}/rpm/mcpctl/${RPM_VERSION}")
|
|
|
|
if [ "$HTTP_CODE" = "200" ]; then
|
|
echo "Version exists, replacing..."
|
|
curl -s -o /dev/null -X DELETE \
|
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
"${GITEA_URL}/api/v1/packages/${GITEA_OWNER}/rpm/mcpctl/${RPM_VERSION}"
|
|
fi
|
|
|
|
# Upload
|
|
curl --fail -X PUT \
|
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
--upload-file "$RPM_FILE" \
|
|
"${GITEA_URL}/api/packages/${GITEA_OWNER}/rpm/upload"
|
|
|
|
echo "Published successfully!"
|
|
|
|
# Link package to repo
|
|
source scripts/link-package.sh
|
|
link_package "rpm" "mcpctl"
|
|
|
|
deploy:
|
|
runs-on: ubuntu-latest
|
|
needs: [docker, publish-rpm]
|
|
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Create stack env file
|
|
env:
|
|
POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
|
|
run: |
|
|
printf '%s\n' \
|
|
"POSTGRES_USER=mcpctl" \
|
|
"POSTGRES_PASSWORD=${POSTGRES_PASSWORD}" \
|
|
"POSTGRES_DB=mcpctl" \
|
|
"MCPD_PORT=3100" \
|
|
"MCPD_LOG_LEVEL=info" \
|
|
> stack/.env
|
|
|
|
- name: Deploy to Portainer
|
|
env:
|
|
PORTAINER_PASSWORD: ${{ secrets.PORTAINER_PASSWORD }}
|
|
run: bash deploy.sh
|