UNPKG

@amplitude/ampli

Version:

Amplitude CLI

347 lines (346 loc) 17.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const chalk_1 = require("chalk"); const inquirer = require("inquirer"); const base_1 = require("./base"); const errors_1 = require("../errors"); const sentry_1 = require("../sentry"); const codegen_1 = require("../codegen"); const semver_1 = require("../util/semver"); const components_1 = require("../components"); const TrackingPlanDiff_1 = require("../components/TrackingPlanDiff"); const types_1 = require("../types"); const compareByName_1 = require("../util/sort/compareByName"); const icons_1 = require("../ui/icons"); const info_strings_1 = require("../info-strings"); const string_1 = require("../util/string"); const constants_1 = require("../constants"); const runtime_1 = require("../util/runtime"); const configure_1 = require("./configure"); const { bold } = chalk_1.default; class PullAction extends base_1.default { constructor(flags, args, config, setBranchMappedToMain) { super(flags, args, config); this.setBranchMappedToMain = setBranchMappedToMain; } async run(forceUserBranchPrompt = false) { var _a, _b; const settings = this.getSettings(); const zone = settings.getZone() || types_1.DEFAULT_ZONE; const currentSourceId = settings.getSourceId(); const inputBranchName = this.flags.branch; let currentBranchName = settings.getBranch(); const isFirstPull = !currentBranchName; const inputSemVer = this.flags.version; let currentSemVer = settings.getVersion() || '0.0.0'; const graphql = await this.getAmpliGraphQLClient(); const orgId = settings.getOrgId(); const workspaceId = settings.getWorkspaceId(); const { org, workspace, branches, defaultBranch } = await this.getOrgWorkspaceBranches(orgId, workspaceId); const inputBranch = inputBranchName ? branches.find(b => b.name === inputBranchName) : undefined; if (!inputBranch && inputBranchName) { this.error(new errors_1.UserFixableError(errors_1.USER_ERROR_MESSAGES.branchDoesNotExist(inputBranchName)), 1); return; } const currentBranch = currentBranchName ? branches.find(b => b.name === currentBranchName) : defaultBranch; const currentVersionId = await this.getVersionIdFromSettings(settings, currentBranch); const runtimes = await this.getRuntimes(); const source = await this.getSource(zone, orgId, workspaceId, defaultBranch, currentBranch, currentVersionId, currentSourceId); if (!source) { return; } const sourceChanged = (settings.getSourceId() !== source.id); settings.setSourceId(source.id); this.println(`Source: ${source.name}`); const runtime = runtimes.find(r => r.id === source.runtime.id); let settingRuntime = settings.getRuntime(runtimes); if (!sourceChanged && settingRuntime && runtime.id !== settingRuntime.id) { this.println(`${icons_1.ICON_WARNING_W_TEXT} Runtime configuration was updated externally from platform ${bold(settingRuntime.platform.name)} to platform ${bold(runtime.platform.name)}.`); } if (runtime_1.isSupportedRuntime(runtime.id)) { settings.setRuntime(runtime); } else if (!runtime_1.isPlatformOnlyRuntime(runtime.id) && !this.checkRuntimeIsSupported(runtime)) { return; } const wasSourceChanged = source.id !== currentSourceId; let branchToPull; let versionIdToPull; let mergedVersion; if (inputBranch) { branchToPull = inputBranch; this.println(`Branch: ${branchToPull.name}`); } else if (currentBranch && currentBranchName && !forceUserBranchPrompt) { branchToPull = currentBranch; this.println(`Branch: ${branchToPull.name}`); } else { if (!currentBranch) { if (currentVersionId) { mergedVersion = await this.getMergedVersionByVersionId(orgId, workspaceId, currentVersionId); } else { mergedVersion = await this.getMergedVersionByVersionSemVer(orgId, workspaceId, currentBranchName, currentSemVer); } if (mergedVersion != null) { this.println(`\ ${icons_1.ICON_WARNING_W_TEXT} Branch ${bold(currentBranchName)} version ${bold(settings.getVersion())} has already been merged into ${bold(defaultBranch.name)} version ${bold(mergedVersion.mainSemVer)}.`); branchToPull = defaultBranch; currentBranchName = defaultBranch.name; currentSemVer = mergedVersion.mainSemVer; versionIdToPull = mergedVersion.mainVersionId; this.setBranchMappedToMain(true); } } if (!branchToPull && (forceUserBranchPrompt || !currentBranchName)) { branchToPull = await this.selectBranchToPull(branches, defaultBranch, currentBranchName); } } if (!branchToPull) { this.error(new Error(errors_1.USER_ERROR_MESSAGES.branchDoesNotExist(currentBranchName)), 1); } if (inputBranchName && inputBranchName === defaultBranch.name && currentBranchName !== defaultBranch.name) { this.setBranchMappedToMain(false); } settings.setBranch(branchToPull.name); versionIdToPull = versionIdToPull !== null && versionIdToPull !== void 0 ? versionIdToPull : branchToPull.currentVersionId; const branchToPullVersions = await this.getBranchVersions(orgId, workspaceId, branchToPull.id); let branchFromSettingsVersions = branchToPullVersions; if (currentBranch != null) { if (currentBranch.id !== branchToPull.id) { branchFromSettingsVersions = await this.getBranchVersions(orgId, workspaceId, currentBranch.id); } } else { branchFromSettingsVersions = []; } const latestVersion = branchToPullVersions.find(v => v.id === (branchToPull === null || branchToPull === void 0 ? void 0 : branchToPull.currentVersionId)); const latestSemVer = latestVersion ? semver_1.default.fromAmpliVersion(latestVersion).toStringShort() : 'unknown'; if (inputSemVer) { const versionToPull = branchToPullVersions.find(v => semver_1.default.fromAmpliVersion(v).equalTo(inputSemVer)); if (versionToPull) { versionIdToPull = versionToPull.id; } else { this.error(new errors_1.UserFixableError(errors_1.USER_ERROR_MESSAGES.versionDoesNotExistOnBranch(inputSemVer, branchToPull.name, latestSemVer)), 1); } } const versionResponse = await graphql.versions({ orgId, workspaceId, branchId: branchToPull.id, versionId: versionIdToPull, }); if (versionResponse.orgs.length === 0) { this.error(new errors_1.UserFixableError(errors_1.USER_ERROR_MESSAGES.userDoesntHaveAccessToWorkspace), 1); } const [versionToPull] = versionResponse.orgs[0].workspaces[0].branches[0].versions; const semVerToPull = semver_1.default.fromAmpliVersion(versionToPull); settings.setVersion(semVerToPull.toString()); settings.setVersionId(versionIdToPull); const omitApiKeys = (_a = this.flags.omitApiKeys) !== null && _a !== void 0 ? _a : settings.getOmitApiKeys(); if (this.flags.omitApiKeys != null) { settings.setOmitApiKeys(this.flags.omitApiKeys); } if (runtime_1.isPlatformOnlyRuntime(runtime.id)) { await new configure_1.default(this.flags, {}, this.config).run(runtime.platform); } else { this.println(`Platform: ${runtime.platform.name}`); this.println(`Language: ${runtime.language.name}`); this.println(`SDK: ${runtime.sdk}`); } settingRuntime = settings.getRuntime(runtimes); if (settingRuntime && !info_strings_1.PULL_INFO[settingRuntime.id]) { throw new errors_1.UserFixableError(errors_1.USER_ERROR_MESSAGES.unsupportedRuntime(settingRuntime.id)); } sentry_1.default.captureSource(source); this.debug(`runtime: ${runtime.id}\n`); const shortSemVerToPull = semVerToPull.toStringShort(); this.startSpinner(`Pulling version ${shortSemVerToPull}${shortSemVerToPull === latestSemVer ? ' (latest)' : ''}`); try { const runtimeId = settingRuntime.id; const codegenDir = codegen_1.default.setPath(runtimeId, this.flags.path, this.flags.projectDir); const packageName = codegen_1.getPackageName(runtimeId, codegenDir); await this.generateSdk(orgId, workspaceId, source, branchToPull, versionIdToPull, omitApiKeys, packageName); this.stopSpinner(true); if (!runtime_1.isAmpliRuntime(runtimeId) && (isFirstPull || wasSourceChanged)) { this.println(); components_1.DestinationsInfo(source); this.println(); } const versionToDiffAgainst = wasSourceChanged ? '0.0.0' : currentSemVer; const versionIdToDiffAgainst = (_b = branchFromSettingsVersions.find(v => semver_1.default.fromAmpliVersion(v).equalTo(versionToDiffAgainst))) === null || _b === void 0 ? void 0 : _b.id; await this.showDiff(orgId, workspaceId, source, branchToPull, versionToPull, currentSemVer, versionIdToDiffAgainst); this.println(`\ ${icons_1.ICON_SUCCESS} Tracking library generated successfully. ${icons_1.ICON_RETURN_ARROW} Path: ${bold(codegenDir)}`); const events = versionToPull.events.filter(e => e.sources.some(s => s.id === source.id)); if (!events || events.length === 0) { this.println(`${icons_1.ICON_WARNING_W_TEXT}: ${errors_1.USER_ERROR_MESSAGES.sourceHasNoEvents(source.name)}`); } if (isFirstPull || wasSourceChanged) { this.println(); await components_1.SdkSetupAndUsageInfo(zone, org, workspace, source, codegenDir, settingRuntime, this.flags.projectDir); } if (mergedVersion && mergedVersion.mainVersionId !== branchToPull.currentVersionId) { this.println(`${icons_1.ICON_WARNING_W_TEXT} \ You are now on branch ${bold(currentBranchName)} version ${bold(currentSemVer)}. A newer version exists. Run ${bold(`ampli pull`)} again to update to version ${bold(latestSemVer)}`); } await this.checkBranchNeedsRefresh(orgId, workspaceId, branchToPull, defaultBranch); } finally { this.stopSpinner(false); } } async getSource(zone, orgId, workspaceId, defaultBranch, currentBranch, currentVersionId, currentSourceId) { const inputSourceName = this.args.source; let sources = await this.getSources(orgId, workspaceId, defaultBranch, currentBranch, currentVersionId, undefined); sources = inputSourceName ? sources.filter(s => s.name === inputSourceName) : sources; if (sources.length === 0) { if (!inputSourceName) { this.println(`${icons_1.ICON_WARNING_W_TEXT} You have yet to create a source in your account. Log into ${constants_1.APP_SETTINGS.ampli(zone).webUrl} to create one.`); } else { this.error(new errors_1.UserFixableError(errors_1.USER_ERROR_MESSAGES.sourceDoesNotExist(inputSourceName)), 1); } return undefined; } let sourceId = currentSourceId; if (!inputSourceName && !currentSourceId) { if (sources.length === 1) { sourceId = sources[0].id; } else { const promptSources = sources.map(source => ({ name: source.name + (!(runtime_1.isSupportedRuntime(source.runtime.id) || runtime_1.isPlatformOnlyRuntime(source.runtime.id)) ? ` (${bold('not supported')})` : ''), value: source.id, })); const { sourceId: selectedSourceId } = await inquirer.prompt([ { name: 'sourceId', message: `Select a source`, type: 'autocomplete', source: (_, input) => promptSources.filter(source => string_1.matchPattern(source.name, input)), }, ]); if (selectedSourceId) { sourceId = selectedSourceId; } } } const source = inputSourceName ? sources.find(s => s.name === inputSourceName) : sources.find(s => s.id === sourceId); if (!source) { this.error(new errors_1.UserFixableError(errors_1.USER_ERROR_MESSAGES.sourceDoesNotExist(inputSourceName || sourceId)), 1); return undefined; } return source; } async generateSdk(orgId, workspaceId, source, branch, versionId, omitApiKeys, packageName) { const graphql = await this.getAmpliGraphQLClient(); const sdkResponse = await graphql.sdk({ orgId, workspaceId, sourceId: source.id, branchId: branch.id, versionId, omitApiKeys, packageName, }); if (sdkResponse.orgs.length === 0) { this.error(new errors_1.UserFixableError(errors_1.USER_ERROR_MESSAGES.userDoesntHaveAccessToWorkspace), 1); } const { sdk } = sdkResponse.orgs[0].workspaces[0].branches[0].versions[0]; await codegen_1.default.saveCode(sdk); } async showDiff(orgId, workspaceId, source, branch, version, currentSemVer, versionIdToDiffAgainst) { const graphql = await this.getAmpliGraphQLClient(); if (branch.stagingVersionId) { const response = await graphql.versionChangeCount({ orgId, workspaceId, branchId: branch.id, versionId: branch.stagingVersionId, }); if (response.orgs.length === 0) { this.error(new errors_1.UserFixableError(errors_1.USER_ERROR_MESSAGES.userDoesntHaveAccessToWorkspace), 1); } components_1.StagedVersionInfo(response.orgs[0].workspaces[0].branches[0].versions[0].changes.forward .changeCount); } const versionChangesResponse = await graphql.versionChanges({ orgId, workspaceId, branchId: branch.id, versionId: version.id, versionIdToDiffAgainst, sourceId: source.id, }); if (versionChangesResponse.orgs.length === 0) { this.error(new errors_1.UserFixableError(errors_1.USER_ERROR_MESSAGES.userDoesntHaveAccessToWorkspace), 1); } const changes = versionChangesResponse.orgs[0].workspaces[0].branches[0].versions[0] .changes.forward; TrackingPlanDiff_1.default({ changes, source, previousVersion: currentSemVer ? semver_1.default.fromString(currentSemVer).toStringShort() : undefined, newVersion: semver_1.default.fromAmpliVersion(version).toStringShort(), }); } async selectBranchToPull(branches, defaultBranch, currentBranchName) { var _a; if (branches.length === 1) { this.println(`Branch: ${branches[0].name}`); return branches[0]; } const sortedBranches = [...branches].sort((b1, b2) => { if (b1.default !== b2.default) { return b1.default ? -1 : 1; } return compareByName_1.default(b1, b2); }); const promptBranches = sortedBranches.map(branch => ({ name: branch.name + (branch.name === currentBranchName ? ' (current)' : ''), value: branch.id, })); const { branchId: selectedBranchId } = await inquirer.prompt([ { name: 'branchId', message: `Select a branch`, type: 'autocomplete', source: (_, input) => promptBranches.filter(branch => string_1.matchPattern(branch.name, input)), default: defaultBranch, }, ]); return (_a = branches.find(b => b.id === selectedBranchId)) !== null && _a !== void 0 ? _a : defaultBranch; } async checkBranchNeedsRefresh(orgId, workspaceId, branch, defaultBranch) { if (branch.default) { return; } const pullRequest = await this.getPullRequest(orgId, workspaceId, branch.id, defaultBranch.id); if (pullRequest && pullRequest.changes.backward.changeCount) { this.println(`\ ${icons_1.ICON_WARNING_W_TEXT} Your branch is out of date with ${bold(defaultBranch.name)}. ${icons_1.ICON_RETURN_ARROW} ${bold('ampli refresh')} to update current branch with latest changes from ${bold(defaultBranch.name)}.`); } } } exports.default = PullAction;