diff --git a/.github/workflows/sync-openapi-docs.yml b/.github/workflows/sync-openapi-docs.yml new file mode 100644 index 000000000..24619619c --- /dev/null +++ b/.github/workflows/sync-openapi-docs.yml @@ -0,0 +1,93 @@ +name: Generate and Sync OpenAPI + +on: + # Se ejecuta cuando hay cambios en los routers de la API + push: + branches: + - canary + paths: + - 'apps/dokploy/server/api/routers/**' + - 'packages/server/src/services/**' + - 'packages/server/src/db/schema/**' + + # Permite ejecuciรณn manual + workflow_dispatch: + +jobs: + generate-and-commit: + name: Generate OpenAPI and commit to Dokploy repo + runs-on: ubuntu-latest + steps: + - name: Checkout Dokploy repository + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Setup pnpm + uses: pnpm/action-setup@v2 + with: + version: 8 + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Generate OpenAPI specification + run: pnpm generate:openapi + + - name: Commit OpenAPI spec + run: | + git config user.name "Dokploy Bot" + git config user.email "bot@dokploy.com" + + # Verifica si el archivo existe + if [ ! -f openapi.json ]; then + echo "โŒ openapi.json not found" + exit 1 + fi + + # Usa -f para forzar el add de archivos en .gitignore + git add -f openapi.json + + # Verifica si hay cambios para commitear + if git diff --cached --quiet; then + echo "๐Ÿ“ No changes detected in OpenAPI spec" + echo "HAS_CHANGES=false" >> $GITHUB_ENV + exit 0 + fi + + echo "HAS_CHANGES=true" >> $GITHUB_ENV + + # Commit los cambios + git commit -m "chore: update OpenAPI specification [skip ci] + +Generated from commit: ${{ github.sha }} +Triggered by: ${{ github.event_name }}" + + git push + + echo "โœ… OpenAPI spec committed successfully" + + - name: Trigger website sync + if: env.HAS_CHANGES == 'true' + uses: peter-evans/repository-dispatch@v2 + with: + token: ${{ secrets.DOCS_SYNC_TOKEN }} + repository: dokploy/website # Cambia por tu repo de docs + event-type: openapi-updated + client-payload: '{"commit": "${{ github.sha }}", "timestamp": "${{ github.event.head_commit.timestamp }}"}' + + - name: Create summary + run: | + echo "## ๐Ÿ“Š OpenAPI Generation Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "- **Repository:** \`${{ github.repository }}\`" >> $GITHUB_STEP_SUMMARY + echo "- **Commit:** \`${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY + echo "- **Trigger:** \`${{ github.event_name }}\`" >> $GITHUB_STEP_SUMMARY + echo "- **Changes:** \`${{ env.HAS_CHANGES }}\`" >> $GITHUB_STEP_SUMMARY + echo "- **Status:** โœ… Success" >> $GITHUB_STEP_SUMMARY + diff --git a/.gitignore b/.gitignore index 5e6e4eb3c..d531bab01 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,8 @@ node_modules .env.test.local .env.production.local +openapi.json + # Testing coverage diff --git a/apps/dokploy/package.json b/apps/dokploy/package.json index 1301fe91b..800e59b35 100644 --- a/apps/dokploy/package.json +++ b/apps/dokploy/package.json @@ -34,7 +34,8 @@ "docker:build:canary": "./docker/build.sh canary", "docker:push:canary": "./docker/push.sh canary", "version": "echo $(node -p \"require('./package.json').version\")", - "test": "vitest --config __test__/vitest.config.ts" + "test": "vitest --config __test__/vitest.config.ts", + "generate:openapi": "tsx -r dotenv/config scripts/generate-openapi.ts" }, "dependencies": { "@ai-sdk/anthropic": "^2.0.5", diff --git a/apps/dokploy/scripts/generate-openapi.ts b/apps/dokploy/scripts/generate-openapi.ts new file mode 100644 index 000000000..16f826474 --- /dev/null +++ b/apps/dokploy/scripts/generate-openapi.ts @@ -0,0 +1,132 @@ +#!/usr/bin/env tsx + +/** + * Script to generate OpenAPI specification locally + * This runs in CI/CD to generate the openapi.json file + * which can then be consumed by the documentation website + */ + +import { writeFileSync } from "node:fs"; +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +import { generateOpenApiDocument } from "@dokploy/trpc-openapi"; +import { appRouter } from "../server/api/root"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +async function generateOpenAPI() { + try { + console.log("๐Ÿ”„ Generating OpenAPI specification..."); + + const openApiDocument = generateOpenApiDocument(appRouter, { + title: "Dokploy API", + version: "1.0.0", + baseUrl: "https://your-dokploy-instance.com/api", + docsUrl: "https://docs.dokploy.com/api", + tags: [ + "admin", + "docker", + "compose", + "registry", + "cluster", + "user", + "domain", + "destination", + "backup", + "deployment", + "mounts", + "certificates", + "settings", + "security", + "redirects", + "port", + "project", + "application", + "mysql", + "postgres", + "redis", + "mongo", + "mariadb", + "sshRouter", + "gitProvider", + "bitbucket", + "github", + "gitlab", + "gitea", + "server", + "swarm", + "ai", + "organization", + "schedule", + "rollback", + "volumeBackups", + "environment", + ], + }); + + // Enhance metadata + openApiDocument.info = { + title: "Dokploy API", + description: + "Complete API documentation for Dokploy - Deploy applications, manage databases, and orchestrate your infrastructure. This API allows you to programmatically manage all aspects of your Dokploy instance.", + version: "1.0.0", + contact: { + name: "Dokploy Team", + url: "https://dokploy.com", + }, + license: { + name: "Apache 2.0", + url: "https://github.com/dokploy/dokploy/blob/canary/LICENSE", + }, + }; + + // Add security schemes + openApiDocument.components = { + ...openApiDocument.components, + securitySchemes: { + apiKey: { + type: "apiKey", + in: "header", + name: "x-api-key", + description: + "API key authentication. Generate an API key from your Dokploy dashboard under Settings > API Keys.", + }, + }, + }; + + // Apply global security + openApiDocument.security = [ + { + apiKey: [], + }, + ]; + + // Add external docs + openApiDocument.externalDocs = { + description: "Full documentation", + url: "https://docs.dokploy.com", + }; + + // Write to root of repo + const outputPath = resolve(__dirname, "../../../openapi.json"); + writeFileSync( + outputPath, + JSON.stringify(openApiDocument, null, 2), + "utf-8", + ); + + console.log("โœ… OpenAPI specification generated successfully!"); + console.log(`๐Ÿ“„ Output: ${outputPath}`); + console.log( + `๐Ÿ“Š Endpoints: ${Object.keys(openApiDocument.paths || {}).length}`, + ); + } catch (error) { + console.error("โŒ Error generating OpenAPI specification:", error); + process.exit(1); + } finally { + process.exit(0); + } +} + +generateOpenAPI(); diff --git a/package.json b/package.json index 684e40405..4ce1089eb 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "build": "pnpm -r run build", "format-and-lint": "biome check .", "check": "biome check --write --no-errors-on-unmatched --files-ignore-unknown=true", - "format-and-lint:fix": "biome check . --write" + "format-and-lint:fix": "biome check . --write", + "generate:openapi": "pnpm --filter=dokploy run generate:openapi" }, "devDependencies": { "@biomejs/biome": "2.1.1",