diff --git a/CHANGELOG.md b/CHANGELOG.md index bf45cd3..d2e35ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ All notable changes to this project will be documented in this file. +## [5.3.0] + +- fix tenantId that was not setup on the .env file after installation +- add discovery api tenant ignition + ## [5.2.2] - fix bug introduced in the 5.2.1 for tenant create command diff --git a/Makefile b/Makefile index 7869be8..78b0035 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,8 @@ YELLOW=$(shell echo "\033[00;33m") RED=$(shell echo "\033[00;31m") RESTORE=$(shell echo "\033[0m") +BUN=bun +# BUN=/opt/homebrew/Cellar/bun@1.1.45/1.1.45/bin/bun .DEFAULT_GOAL := list @@ -16,23 +18,32 @@ list: .PHONY: codeclean codeclean: ## Code Clean - @bun prettier --write . + @$(BUN) prettier --write . + +.PHONY: run +run: ## Run ARGS="" + @LOG_LEVELS=info,debug $(BUN) src/index.ts $$ARGS + + +.PHONY: staging-run +staging-run: ## Run ARGS="" + @CRYSTALLIZE_ENVIRONMENT=staging LOG_LEVELS=info,debug $(BUN) src/index.ts $$ARGS .PHONY: build build: ## Build - @bun build --bundle src/index.ts --outfile crystallize.js --target=bun - @bun shim.ts - @bun build --compile --minify crystallize.js --outfile crystallize + @$(BUN) build --bundle src/index.ts --outfile crystallize.js --target=bun + @$(BUN) shim.ts + @$(BUN) build --compile --minify crystallize.js --outfile crystallize @rm crystallize.js @rm -f ./.*.bun-build .PHONY: build-all build-all: - @bun build --bundle src/index.ts --outfile crystallize.js --target=bun - @bun shim.ts + @$(BUN) build --bundle src/index.ts --outfile crystallize.js --target=bun + @$(BUN) shim.ts for target in bun-linux-x64 bun-linux-arm64 bun-windows-x64 bun-darwin-x64 bun-darwin-arm64; do \ - bun build --compile --minify crystallize.js --outfile crystallize-$$target --target=$$target; \ + $(BUN) build --compile --minify crystallize.js --outfile crystallize-$$target --target=$$target; \ done @rm crystallize.js @rm -f ./.*.bun-build diff --git a/package.json b/package.json index 68df889..be08f95 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@crystallize/cli", - "version": "5.2.2", + "version": "5.3.0", "description": "Crystallize CLI", "module": "src/index.ts", "repository": "https://github.com/CrystallizeAPI/crystallize-cli", diff --git a/src/domain/use-cases/create-clean-tenant.ts b/src/domain/use-cases/create-clean-tenant.ts index 1ad7832..c3e0294 100644 --- a/src/domain/use-cases/create-clean-tenant.ts +++ b/src/domain/use-cases/create-clean-tenant.ts @@ -9,11 +9,14 @@ import type { FlySystem } from '../contracts/fly-system'; import type { Operations } from '@crystallize/schema/mass-operation'; import type { Logger } from '../contracts/logger'; import { getMassOperationBulkTask } from '../../command/mass-operation/run'; +import type { InstallBoilerplateStore } from '../../ui/journeys/install-boilerplate/create-store'; type Deps = { createCrystallizeClient: typeof createClient; runMassOperation: ReturnType; credentialsRetriever: CredentialRetriever; + crystallizeEnvironment: 'staging' | 'production'; + installBoilerplateCommandStore: InstallBoilerplateStore; flySystem: FlySystem; logger: Logger; }; @@ -29,13 +32,27 @@ export type CreateCleanTenantHandlerDefinition = CommandHandlerDefinition< Awaited> >; +const sleep = (second: number) => new Promise((resolve) => setTimeout(resolve, second * 1000)); + const handler = async ( envelope: Envelope, - { createCrystallizeClient, credentialsRetriever, runMassOperation, flySystem, logger }: Deps, + { + createCrystallizeClient, + credentialsRetriever, + runMassOperation, + flySystem, + logger, + crystallizeEnvironment, + installBoilerplateCommandStore, + }: Deps, ): Promise<{ id: string; identifier: string; }> => { + const { storage, atoms } = installBoilerplateCommandStore; + const addTraceLog = (log: string) => storage.set(atoms.addTraceLogAtom, log); + const addTraceError = (log: string) => storage.set(atoms.addTraceErrorAtom, log); + const { tenant, credentials } = envelope.message; const finalCredentials = credentials || (await credentialsRetriever.getCredentials()); const client = createCrystallizeClient({ @@ -67,6 +84,7 @@ const handler = async ( }, ); const { id, identifier } = createResult.tenant.create; + addTraceLog(`Tenant created with id: ${id}.`); const shapeIdentifiers = ['default-product', 'default-folder', 'default-document']; const mutation = { shape: shapeIdentifiers.reduce((memo: Record, shapeIdentifier: string) => { @@ -85,6 +103,7 @@ const handler = async ( }; const query = jsonToGraphQLQuery({ mutation }); await client.pimApi(query); + addTraceLog(`Shape cleaned.`); // if we have a folder, we check that folder for .crystallize folder and convention const { folder } = envelope.message; @@ -115,18 +134,23 @@ const handler = async ( }, } as Envelope); logger.debug('Mass operation task created', startedTask); + addTraceLog(`Mass operation task created: ${startedTask?.id}`); + await sleep(10); // we have an easy 10 sec sleep here to let the task start while (startedTask?.status !== 'complete') { - await new Promise((resolve) => setTimeout(resolve, 1000)); const get = await cClient.nextPimApi(getMassOperationBulkTask, { id: startedTask?.id }); if (get.bulkTask.error) { throw new Error(get.data.bulkTask.error); } startedTask = get.bulkTask; + await sleep(3); // then we check every 3 seconds } } catch (e) { + addTraceError(`Failed to run mass operation.`); logger.error('Failed to run mass operation', e); } + addTraceLog(`Mass operation completed.`); + // now the extra mutations try { const results = await cClient.pimApi(`#graphql query { @@ -156,15 +180,32 @@ const handler = async ( }[]; for (const { mutation, sets } of Object.values(extraMutations)) { - await Promise.all([ + await Promise.all( sets.map(async (set) => { await cClient.pimApi(mutation, set); }), - ]); + ); } } catch (e) { + addTraceError(`Failed to run extra mutations.`); logger.error('Failed to run extra mutations', e); } + + // now the index + await cClient.nextPimApi(`mutation { igniteTenant }`); + // check the 404 + + const discoHost = crystallizeEnvironment === 'staging' ? 'api-dev.crystallize.digital' : 'api.crystallize.com'; + let discoApiPingResponseCode = 404; + + await sleep(15); // easy 15 sec sleep to let the index finish + do { + const discoApiPingResponse = await fetch(`https://${discoHost}/${identifier}/discovery`); + discoApiPingResponseCode = discoApiPingResponse.status; + sleep(5); // then every 5 seconds + } while (discoApiPingResponseCode === 404); + + addTraceLog(`Tenant ignited in Discovery API.`); return { id, identifier, diff --git a/src/domain/use-cases/setup-boilerplate-project.ts b/src/domain/use-cases/setup-boilerplate-project.ts index 456f62d..b3f9065 100644 --- a/src/domain/use-cases/setup-boilerplate-project.ts +++ b/src/domain/use-cases/setup-boilerplate-project.ts @@ -6,6 +6,7 @@ import type { Logger } from '../contracts/logger'; import type { Runner } from '../../core/create-runner'; import type { InstallBoilerplateStore } from '../../ui/journeys/install-boilerplate/create-store'; import type { CredentialRetriever } from '../contracts/credential-retriever'; +import type { createClient } from '@crystallize/js-api-client'; type Deps = { flySystem: FlySystem; @@ -13,6 +14,7 @@ type Deps = { runner: Runner; installBoilerplateCommandStore: InstallBoilerplateStore; credentialsRetriever: CredentialRetriever; + createCrystallizeClient: typeof createClient; }; type Command = { @@ -28,7 +30,7 @@ export type SetupBoilerplateProjectHandlerDefinition = CommandHandlerDefinition< >; const handler = async (envelope: Envelope, deps: Deps) => { - const { flySystem, logger, runner, installBoilerplateCommandStore } = deps; + const { flySystem, logger, runner, installBoilerplateCommandStore, createCrystallizeClient } = deps; const { folder, tenant, credentials } = envelope.message; const { storage, atoms } = installBoilerplateCommandStore; @@ -40,6 +42,17 @@ const handler = async (envelope: Envelope, deps: Deps) => { const finalCredentials = credentials || (await deps.credentialsRetriever.getCredentials()); logger.log(`Setting up boilerplate project in ${folder} for tenant ${tenant.identifier}`); + const apiClient = createCrystallizeClient({ + tenantIdentifier: tenant.identifier, + accessTokenId: finalCredentials?.ACCESS_TOKEN_ID, + accessTokenSecret: finalCredentials?.ACCESS_TOKEN_SECRET, + }); + + // let's get the Tenant Id + const tenantInfo = await apiClient.nextPimApi( + `query { tenant(identifier:"${tenant.identifier}") { ... on Tenant { id } } }`, + ); + const tenantId = tenantInfo.tenant.id; if (await flySystem.isFileExists(`${crytallizeHiddenFolder}/env`)) { try { @@ -50,7 +63,7 @@ const handler = async (envelope: Envelope, deps: Deps) => { }, { search: '##CRYSTALLIZE_TENANT_ID##', - replace: '', + replace: tenantId, }, { search: '##CRYSTALLIZE_TENANT_IDENTIFIER##', diff --git a/src/ui/journeys/install-boilerplate/actions/execute-recipes.tsx b/src/ui/journeys/install-boilerplate/actions/execute-recipes.tsx index 3953c8d..8daf953 100644 --- a/src/ui/journeys/install-boilerplate/actions/execute-recipes.tsx +++ b/src/ui/journeys/install-boilerplate/actions/execute-recipes.tsx @@ -14,7 +14,10 @@ const feedbacks = [ 'Preparing files for install...', 'Installing...', 'Still installing...', + 'Setting up tenant...', + 'Discovering the meaning of life...', 'Daydreaming...', + 'Indexing...', 'Growing that node_modules...', 'Looking for car keys...', 'Looking for the car...', @@ -87,7 +90,7 @@ export const ExecuteRecipes = ({ store, commandBus, logger }: ExecuteRecipesProp <> - Importing tenant data + Importing tenant data, it can take several minutes... )}