UNPKG

@dataroadinc/setup-auth

Version:

CLI tool and programmatic API for automated OAuth setup across cloud platforms

159 lines (141 loc) 5.13 kB
import { SetupAuthError } from "../../../utils/error.js" import { ProjectsClient } from "@google-cloud/resource-manager" import { GcpProjectManager, gcpSetOauthProjectId } from "./index.js" /** * This is basically a private method of the GcpProjectManager class, do * not use this method directly, use GcpProjectManager.createProject() method instead. */ export async function gcpCreateProject( projectManager: GcpProjectManager, projectsClient: ProjectsClient, organizationId: string, projectId: string ): Promise<void> { try { await _gcpCreateProject( projectManager, projectsClient, organizationId, projectId ) } catch (error) { if (error instanceof SetupAuthError) { throw error // Re-throw SetupAuthError as is } // Handle any other errors from the outer try block throw new SetupAuthError(`Failed to create GCP project ${projectId}:`, { cause: error, }) } } async function _gcpCreateProject( projectManager: GcpProjectManager, projectsClient: ProjectsClient, organizationId: string, projectId: string ): Promise<void> { // Check if the project already exists const exists = await projectManager.projectExists(projectId) if (exists) { return await _gcpUpdateProject(projectManager, organizationId, projectId) } return await _gcpCreateNewProject(projectsClient, organizationId, projectId) } async function _gcpUpdateProject( projectManager: GcpProjectManager, organizationId: string, projectId: string ): Promise<void> { // Check if the project is attached to our organization const isAttached = await projectManager.isAttachedToOrganization(projectId) if (isAttached) { console.log( `✅ Project ${projectId} already exists in organization ${organizationId}` ) // Set environment variables after confirming project exists and is attached await gcpSetOauthProjectId({ gcpOauthProjectId: projectId }) return } // Project exists but is not attached to our organization console.log( `Project ${projectId} exists but is not attached to organization ${organizationId}` ) // Try to migrate the project to our organization const migrationSucceeded = await projectManager.migrateProjectToOrganization(projectId) if (migrationSucceeded) { console.log( `✅ Successfully migrated project ${projectId} to organization ${organizationId}` ) // Set environment variables after successful migration await gcpSetOauthProjectId({ gcpOauthProjectId: projectId }) return } // If migration fails, delete the project and recreate it console.log(`Migration failed. Deleting and recreating project ${projectId}`) await projectManager.deleteProject(projectId) // Wait a moment for deletion to be processed await new Promise(resolve => setTimeout(resolve, 3000)) } async function _gcpCreateNewProject( projectsClient: ProjectsClient, organizationId: string, projectId: string ): Promise<void> { // Create a new project console.log( `Creating new project ${projectId} in organization ${organizationId}` ) try { const [operation] = await projectsClient.createProject({ project: { projectId, parent: `organizations/${organizationId}`, }, }) // Wait for the operation to complete await operation.promise() console.log( `Created project ${projectId} in organization ${organizationId}` ) // Set environment variables only after successful project creation await gcpSetOauthProjectId({ gcpOauthProjectId: projectId }) // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (createError: any) { // Log detailed error information about project creation console.error("Project creation failed with error:", { projectId, organizationId, errorCode: createError?.code, errorStatus: createError?.status, errorName: createError?.name, errorDetails: createError?.details, errorMessage: createError?.message, metadata: createError?.metadata?.internalRepr ? Object.fromEntries(createError.metadata.internalRepr) : undefined, }) // Build a comprehensive error message const errorParts = [] if (createError?.code) errorParts.push(`Code: ${createError.code}`) if (createError?.status) errorParts.push(`Status: ${createError.status}`) if (createError?.name) errorParts.push(`Type: ${createError.name}`) const errorContext = errorParts.length > 0 ? ` (${errorParts.join(", ")})` : "" const errorDetails = [ createError?.details, createError?.message, createError?.metadata?.internalRepr ?.get("google.rpc.errorinfo-bin") ?.toString(), createError?.stack?.split("\n")[0], // First line of stack trace if available ] .filter(Boolean) .join(". ") throw new SetupAuthError( `Failed to create project ${projectId} in organization ${organizationId}${errorContext}. ` + `Details: ${errorDetails || "No additional error details available"}`, createError ) } }