diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml deleted file mode 100644 index b2cf177..0000000 --- a/.github/workflows/preview.yml +++ /dev/null @@ -1,148 +0,0 @@ -# .github/workflows/preview.yml -name: Preview deploy all Workers and CLIs - -on: - pull_request: - branches: - - main - types: - - opened - - reopened - - synchronize - -env: - # each folder under the repo root that contains one of your CLIs - WORKSPACES: create-db create-pg create-postgres - CREATE_DB_WORKER_URL: ${{ secrets.CREATE_DB_WORKER_URL }} - CLAIM_DB_WORKER_URL: ${{ secrets.CLAIM_DB_WORKER_URL }} - POSTHOG_API_HOST: ${{ secrets.POSTHOG_API_HOST }} - POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }} - -jobs: - preview: - name: ๐ง Preview release (PR #${{ github.event.number }}) - runs-on: ubuntu-latest - - steps: - - name: ๐๏ธ Checkout full history - uses: actions/checkout@v3 - with: - fetch-depth: 0 - persist-credentials: true - - - name: ๐ค Disable Husky - run: echo "HUSKY=0" >> $GITHUB_ENV - - - name: ๐ฆ Setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 8 - - - name: ๐ง Install dependencies - run: pnpm install - - - name: โ Disable pnpm git-checks - run: pnpm config set git-checks false - - - name: ๐ Copy README to child CLIs - run: | - for pkg in create-pg create-postgres; do - cp create-db/README.md "$pkg/README.md" - done - - - name: ๐ Create unique preview tag - run: | - SAFE_REF=$(echo "${{ github.event.pull_request.head.ref }}" | tr '/' '-') - echo "PRE_TAG=pr${{ github.event.number }}-${SAFE_REF}-${{ github.run_id }}" >> $GITHUB_ENV - - # โ CF Worker preview deploys commented out; we will use pre-built URLs - # - name: โ๏ธ Deploy create-db-worker (preview) - # uses: cloudflare/wrangler-action@v3 - # with: - # apiToken: ${{ secrets.CF_API_TOKEN }} - # accountId: ${{ secrets.CF_ACCOUNT_ID }} - # environment: ${{ env.PRE_TAG }} - # workingDirectory: create-db-worker - # - # - name: โ๏ธ Deploy claim-db-worker (preview) - # uses: cloudflare/wrangler-action@v3 - # with: - # apiToken: ${{ secrets.CF_API_TOKEN }} - # accountId: ${{ secrets.CF_ACCOUNT_ID }} - # environment: ${{ env.PRE_TAG }} - # workingDirectory: claim-db-worker - - - name: ๐ Configure npm auth - run: echo "//registry.npmjs.org/:_authToken=${{ secrets.CREATE_DB_TOKEN_NPM }}" > ~/.npmrc - - - name: ๐ Bump & publish CLI previews - env: - WORKSPACES: create-db create-pg create-postgres - POSTHOG_API_HOST: ${{ secrets.POSTHOG_API_HOST }} - POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }} - CREATE_DB_WORKER_URL: ${{ env.CREATE_DB_WORKER_URL }} - CLAIM_DB_WORKER_URL: ${{ env.CLAIM_DB_WORKER_URL }} - run: | - # Resolve URLs with fallback - CREATE_DB_WORKER_URL="${{ steps.deploy-db.outputs.deployment-url || secrets.CREATE_DB_WORKER_URL }}" - CLAIM_DB_WORKER_URL="${{ steps.deploy-claim.outputs.deployment-url || secrets.CLAIM_DB_WORKER_URL }}" - - # Persist for next steps - echo "CREATE_DB_WORKER_URL=$CREATE_DB_WORKER_URL" >> $GITHUB_ENV - echo "CLAIM_DB_WORKER_URL=$CLAIM_DB_WORKER_URL" >> $GITHUB_ENV - - - echo "Using CREATE_DB_WORKER_URL=$CREATE_DB_WORKER_URL" - echo "Using CLAIM_DB_WORKER_URL=$CLAIM_DB_WORKER_URL" - echo "Using POSTHOG_API_HOST=${POSTHOG_API_HOST}" - - for pkg in $WORKSPACES; do - cd "$pkg" - export CREATE_DB_WORKER_URL - export CLAIM_DB_WORKER_URL - export POSTHOG_API_HOST="${POSTHOG_API_HOST}" - export POSTHOG_API_KEY="${POSTHOG_API_KEY}" - - npm version prerelease \ - --preid "$PRE_TAG" \ - --no-git-tag-version - pnpm publish --access public --tag pr${{ github.event.number }} - cd - >/dev/null - done - - - name: ๐ฌ Post preview-testing instructions - uses: actions/github-script@v6 - env: - PRE_TAG: ${{ env.PRE_TAG }} - CREATE_DB_WORKER_URL: ${{ steps.deploy-db.outputs.deployment-url }} - CLAIM_DB_WORKER_URL: ${{ steps.deploy-claim.outputs.deployment-url }} - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const tag = process.env.PRE_TAG; - const dbUrl = process.env.CREATE_DB_WORKER_URL; - const clUrl = process.env.CLAIM_DB_WORKER_URL; - - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.payload.pull_request.number, - body: ` - โ **Preview CLIs & Workers are live!** - - Test the CLIs locally under tag \`${tag}\`: - - \`\`\`bash - npx create-db@pr${{ github.event.number }} - npx create-pg@pr${{ github.event.number }} - npx create-postgres@$pr${{ github.event.number }} - \`\`\` - - **Worker URLs** - โข Create-DB Worker: ${dbUrl} - โข Claim-DB Worker: ${clUrl} - - > These will live as long as this PR exists under tag \`${tag}\`.` - }); - - name: ๐งน Cleanup npm auth - run: rm -f ~/.npmrc diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3e533c5..ed3ce9d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,92 +1,224 @@ -name: Release CLIs +name: Publish CLIs on: - workflow_dispatch: - push: - branches: - - main + push: + branches: + - main + pull_request: + branches: + - main + types: + - opened + - reopened + - synchronize + workflow_dispatch: concurrency: ${{ github.workflow }}-${{ github.ref }} env: - WORKSPACES: create-db create-pg create-postgres - POSTHOG_API_HOST: ${{ secrets.POSTHOG_API_HOST }} - POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }} + WORKSPACES: create-db create-pg create-postgres + POSTHOG_API_HOST: ${{ secrets.POSTHOG_API_HOST }} + POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }} + CREATE_DB_WORKER_URL: ${{ secrets.CREATE_DB_WORKER_URL }} + CLAIM_DB_WORKER_URL: ${{ secrets.CLAIM_DB_WORKER_URL }} + +permissions: + contents: read jobs: - release: - name: ๐ Release CLIs - runs-on: ubuntu-latest - - steps: - - name: ๐๏ธ Checkout Repo - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: ๐ค Disable Husky - run: echo "HUSKY=0" >> $GITHUB_ENV - - - name: ๐ฆ Setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 8 - - - name: ๐ง Install dependencies - run: pnpm install - - - name: โ Disable pnpm git-checks - run: pnpm config set git-checks false - - - name: ๐ Configure npm auth - run: echo "//registry.npmjs.org/:_authToken=${{ secrets.CREATE_DB_TOKEN_NPM }}" > ~/.npmrc - - # Publish each CLI package using the version in package.json - - name: ๐ Publish Each CLI Package - run: | - echo "Using CREATE_DB_WORKER_URL=${CREATE_DB_WORKER_URL}" - echo "Using CLAIM_DB_WORKER_URL=${CLAIM_DB_WORKER_URL}" - echo "Using POSTHOG_API_HOST=${POSTHOG_API_HOST}" - - for pkg in $WORKSPACES; do - echo "Publishing $pkg to npm..." - cd "$pkg" - export POSTHOG_API_HOST="${{ secrets.POSTHOG_API_HOST }}" - export POSTHOG_API_KEY="${{ secrets.POSTHOG_API_KEY }}" - # pnpm publish --access public || echo "Publish failed for $pkg" - # First try to publish - if ! pnpm publish --access public; then - echo "Publish failed, trying to bump version and retry..." - npm version patch --no-git-tag-version - pnpm publish --access public || echo "Publish failed again for $pkg" - fi - cd - >/dev/null - done - env: - NODE_AUTH_TOKEN: ${{ secrets.CREATE_DB_TOKEN_NPM }} - CREATE_DB_WORKER_URL: ${{ secrets.CREATE_DB_WORKER_URL }} - CLAIM_DB_WORKER_URL: ${{ secrets.CLAIM_DB_WORKER_URL }} - POSTHOG_API_HOST: ${{ secrets.POSTHOG_API_HOST }} - POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }} - - - name: ๐งน Cleanup npm auth - run: rm -f ~/.npmrc - - # Create a default changeset if none exist - - name: ๐ Ensure Changeset Exists - run: | - if [ -z "$(ls -A .changeset 2>/dev/null)" ]; then - echo "No changeset found. Creating a default one..." - pnpm changeset add --empty --message "chore(release): auto-generated changeset" - fi - - # Finally, create a PR for version bump + changelogs - - name: ๐ Prepare Changesets PR - id: changesets - uses: changesets/action@v1 - with: - version: pnpm changeset version - commit: "chore(release): version packages" - title: "chore(release): version packages" - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + release: + name: ๐ Release CLIs + if: (github.event_name == 'push' && github.ref == 'refs/heads/main') || github.event_name == 'workflow_dispatch' + runs-on: ubuntu-latest + permissions: + contents: write # to create changeset PRs and version commits + pull-requests: write # to create changeset PRs + id-token: write # required for OIDC / Trusted Publishers + steps: + - name: ๐๏ธ Checkout Repo + uses: actions/checkout@v4 + with: + fetch-depth: 0 + persist-credentials: true + + - name: ๐ค Disable Husky + run: echo "HUSKY=0" >> $GITHUB_ENV + + - name: ๐ฆ Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 8 + + - name: ๐ง Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "lts/*" + registry-url: "https://registry.npmjs.org" + cache: "pnpm" + + - name: ๐ง Install dependencies + run: pnpm install + + - name: โ Disable pnpm git-checks + run: pnpm config set git-checks false + + - name: ๐ Publish Each CLI Package + env: + CREATE_DB_WORKER_URL: ${{ secrets.CREATE_DB_WORKER_URL }} + CLAIM_DB_WORKER_URL: ${{ secrets.CLAIM_DB_WORKER_URL }} + POSTHOG_API_HOST: ${{ secrets.POSTHOG_API_HOST }} + POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }} + run: | + echo "Using CREATE_DB_WORKER_URL=${CREATE_DB_WORKER_URL}" + echo "Using CLAIM_DB_WORKER_URL=${CLAIM_DB_WORKER_URL}" + echo "Using POSTHOG_API_HOST=${POSTHOG_API_HOST}" + + for pkg in ${{ env.WORKSPACES }}; do + echo "Publishing $pkg to npm..." + cd "$pkg" + export POSTHOG_API_HOST="${POSTHOG_API_HOST}" + export POSTHOG_API_KEY="${POSTHOG_API_KEY}" + export CREATE_DB_WORKER_URL="${CREATE_DB_WORKER_URL}" + export CLAIM_DB_WORKER_URL="${CLAIM_DB_WORKER_URL}" + + # First try to publish + if ! pnpm publish --access public --no-git-checks; then + echo "Publish failed, trying to bump version and retry..." + npm version patch --no-git-tag-version + pnpm publish --access public --no-git-checks || echo "Publish failed again for $pkg" + fi + cd - >/dev/null + done + + - name: ๐ Ensure Changeset Exists + run: | + if [ -z "$(ls -A .changeset 2>/dev/null)" ]; then + echo "No changeset found. Creating a default one..." + pnpm changeset add --empty --message "chore(release): auto-generated changeset" + fi + + - name: ๐ Prepare Changesets PR + id: changesets + uses: changesets/action@v1 + with: + version: pnpm changeset version + commit: "chore(release): version packages" + title: "chore(release): version packages" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + preview: + name: ๐ง Preview release (PR #${{ github.event.number }}) + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + permissions: + contents: write # For publishing to GitHub releases + pull-requests: write # To comment on PRs + id-token: write # required for OIDC / Trusted Publishers + steps: + - name: ๐๏ธ Checkout full history + uses: actions/checkout@v4 + with: + fetch-depth: 0 + persist-credentials: true + + - name: ๐ค Disable Husky + run: echo "HUSKY=0" >> $GITHUB_ENV + + - name: ๐ฆ Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 8 + + - name: ๐ง Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "lts/*" + registry-url: "https://registry.npmjs.org" + cache: "pnpm" + + - name: ๐ง Install dependencies + run: pnpm install + + - name: โ Disable pnpm git-checks + run: pnpm config set git-checks false + + - name: ๐ Copy README to child CLIs + run: | + for pkg in create-pg create-postgres; do + cp create-db/README.md "$pkg/README.md" + done + + - name: ๐ Create unique preview tag + run: | + SAFE_REF=$(echo "${{ github.event.pull_request.head.ref }}" | tr '/' '-') + echo "PRE_TAG=pr${{ github.event.number }}-${SAFE_REF}-${{ github.run_id }}" >> $GITHUB_ENV + + - name: ๐ Bump & publish CLI previews + env: + PRE_TAG: ${{ env.PRE_TAG }} + CREATE_DB_WORKER_URL: ${{ secrets.CREATE_DB_WORKER_URL }} + CLAIM_DB_WORKER_URL: ${{ secrets.CLAIM_DB_WORKER_URL }} + POSTHOG_API_HOST: ${{ secrets.POSTHOG_API_HOST }} + POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }} + run: | + # Resolve URLs with fallback + CREATE_DB_WORKER_URL="${{ secrets.CREATE_DB_WORKER_URL }}" + CLAIM_DB_WORKER_URL="${{ secrets.CLAIM_DB_WORKER_URL }}" + + # Persist for next steps + echo "CREATE_DB_WORKER_URL=$CREATE_DB_WORKER_URL" >> $GITHUB_ENV + echo "CLAIM_DB_WORKER_URL=$CLAIM_DB_WORKER_URL" >> $GITHUB_ENV + + echo "Using CREATE_DB_WORKER_URL=$CREATE_DB_WORKER_URL" + echo "Using CLAIM_DB_WORKER_URL=$CLAIM_DB_WORKER_URL" + echo "Using POSTHOG_API_HOST=${POSTHOG_API_HOST}" + + for pkg in ${{ env.WORKSPACES }}; do + cd "$pkg" + export CREATE_DB_WORKER_URL + export CLAIM_DB_WORKER_URL + export POSTHOG_API_HOST="${POSTHOG_API_HOST}" + export POSTHOG_API_KEY="${POSTHOG_API_KEY}" + + npm version prerelease \ + --preid "$PRE_TAG" \ + --no-git-tag-version + pnpm publish --access public --tag pr${{ github.event.number }} --no-git-checks + cd - >/dev/null + done + + - name: ๐ฌ Post preview-testing instructions + uses: actions/github-script@v6 + env: + PRE_TAG: ${{ env.PRE_TAG }} + CREATE_DB_WORKER_URL: ${{ secrets.CREATE_DB_WORKER_URL }} + CLAIM_DB_WORKER_URL: ${{ secrets.CLAIM_DB_WORKER_URL }} + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const tag = process.env.PRE_TAG; + const dbUrl = process.env.CREATE_DB_WORKER_URL; + const clUrl = process.env.CLAIM_DB_WORKER_URL; + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number, + body: ` + โ **Preview CLIs & Workers are live!** + + Test the CLIs locally under tag \`${tag}\`: + + \`\`\`bash + npx create-db@pr${{ github.event.number }} + npx create-pg@pr${{ github.event.number }} + npx create-postgres@pr${{ github.event.number }} + \`\`\` + + **Worker URLs** + โข Create-DB Worker: ${dbUrl} + โข Claim-DB Worker: ${clUrl} + + > These will live as long as this PR exists under tag \`${tag}\`.` + }); diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b3d334c..d53b221 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -41,8 +41,14 @@ jobs: run: pnpm install --frozen-lockfile working-directory: ./create-db + - name: Build create-db + run: pnpm build + working-directory: ./create-db + - name: Run create-db tests run: pnpm test working-directory: ./create-db env: NODE_ENV: test + CREATE_DB_WORKER_URL: ${{ secrets.CREATE_DB_WORKER_URL }} + CLAIM_DB_WORKER_URL: ${{ secrets.CLAIM_DB_WORKER_URL }} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 18399cb..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "folder-color.pathColors": [] -} diff --git a/claim-db-worker/__tests__/callback-api.test.ts b/claim-db-worker/__tests__/callback-api.test.ts index 46f5be4..b1b175b 100644 --- a/claim-db-worker/__tests__/callback-api.test.ts +++ b/claim-db-worker/__tests__/callback-api.test.ts @@ -55,6 +55,7 @@ describe("auth callback API", () => { vi.mocked(transferProject).mockResolvedValue({ success: true, status: 200, + transferResponse: {}, }); vi.mocked(redirectToSuccess).mockReturnValue( @@ -64,10 +65,23 @@ describe("auth callback API", () => { }) ); - mockFetch.mockResolvedValue({ - ok: true, - json: async () => ({}), - }); + mockFetch + .mockResolvedValueOnce({ + ok: true, + json: async () => ({ + data: { workspace: { id: "wksp_test-workspace-123" } }, + }), + }) + .mockResolvedValueOnce({ + ok: true, + json: async () => ({ + data: [{ id: "db_test-database-123" }], + }), + }) + .mockResolvedValue({ + ok: true, + json: async () => ({}), + }); const request = new NextRequest( "http://localhost:3000/api/auth/callback?code=test-code&state=test-state&projectID=test-project-123" @@ -86,7 +100,9 @@ describe("auth callback API", () => { ); expect(redirectToSuccess).toHaveBeenCalledWith( request, - "test-project-123" + "test-project-123", + "test-workspace-123", // workspaceId + "test-database-123" // databaseId ); expect(mockFetch).toHaveBeenCalledWith( @@ -170,6 +186,7 @@ describe("auth callback API", () => { success: false, status: 403, error: "Insufficient permissions", + transferResponse: {}, }); vi.mocked(redirectToError).mockReturnValue( diff --git a/claim-db-worker/app/api/auth/callback/route.ts b/claim-db-worker/app/api/auth/callback/route.ts index 2c2b544..b8ac49f 100644 --- a/claim-db-worker/app/api/auth/callback/route.ts +++ b/claim-db-worker/app/api/auth/callback/route.ts @@ -114,9 +114,10 @@ export async function GET(request: NextRequest) { ); } - // Validate project exists + // Validate project exists and get project data + let projectData; try { - await validateProject(projectID); + projectData = await validateProject(projectID); } catch (error) { const errorMessage = error instanceof Error ? error.message : "Unknown error"; @@ -141,16 +142,57 @@ export async function GET(request: NextRequest) { projectID, tokenData.access_token ); - if (transferResult.success) { + // Fetch project details with user's token to get workspace ID + const projectDetailsRes = await fetch( + `https://api.prisma.io/v1/projects/${projectID}`, + { + headers: { + Authorization: `Bearer ${tokenData.access_token}`, + "Content-Type": "application/json", + }, + } + ); + const projectDetails = (await projectDetailsRes.json()) as { + data?: { workspace?: { id?: string } }; + }; + const workspaceId = (projectDetails.data?.workspace?.id ?? "").replace( + /^wksp_/, + "" + ); + + // Fetch databases to get database ID + const databasesRes = await fetch( + `https://api.prisma.io/v1/projects/${projectID}/databases`, + { + headers: { + Authorization: `Bearer ${tokenData.access_token}`, + "Content-Type": "application/json", + }, + } + ); + const databases = (await databasesRes.json()) as { + data?: Array<{ id?: string }>; + }; + const databaseId = (databases.data?.[0]?.id ?? "").replace(/^db_/, ""); + await sendServerAnalyticsEvent( "create_db:claim_successful", { "project-id": projectID, + "workspace-id": workspaceId, + "database-id": databaseId, }, request ); - return redirectToSuccess(request, projectID); + + const cleanProjectId = projectID.replace(/^proj_/, ""); + return redirectToSuccess( + request, + cleanProjectId, + workspaceId, + databaseId + ); } else { await sendServerAnalyticsEvent( "create_db:claim_failed", diff --git a/claim-db-worker/app/success/page.tsx b/claim-db-worker/app/success/page.tsx index 092d096..57ce09c 100644 --- a/claim-db-worker/app/success/page.tsx +++ b/claim-db-worker/app/success/page.tsx @@ -8,6 +8,13 @@ import { Suspense } from "react"; function SuccessContent() { const searchParams = useSearchParams(); const projectID = searchParams.get("projectID"); + const workspaceId = searchParams.get("workspaceId"); + const databaseId = searchParams.get("databaseId"); + + const consoleUrl = + workspaceId && projectID && databaseId + ? `https://console.prisma.io/${workspaceId}/${projectID}/${databaseId}` + : "https://console.prisma.io/"; return (