"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; function _xdl() { const data = require("@expo/xdl"); _xdl = function () { return data; }; return data; } function _chalk() { const data = _interopRequireDefault(require("chalk")); _chalk = function () { return data; }; return data; } function _delayAsync() { const data = _interopRequireDefault(require("delay-async")); _delayAsync = function () { return data; }; return data; } function _fp() { const data = _interopRequireDefault(require("lodash/fp")); _fp = function () { return data; }; return data; } function _get() { const data = _interopRequireDefault(require("lodash/get")); _get = function () { return data; }; return data; } function _ora() { const data = _interopRequireDefault(require("ora")); _ora = function () { return data; }; return data; } function _semver() { const data = _interopRequireDefault(require("semver")); _semver = function () { return data; }; return data; } function UrlUtils() { const data = _interopRequireWildcard(require("../utils/url")); UrlUtils = function () { return data; }; return data; } function _log() { const data = _interopRequireDefault(require("../../log")); _log = function () { return data; }; return data; } function _publish() { const data = require("../publish"); _publish = function () { return data; }; return data; } function _BuildError() { const data = _interopRequireDefault(require("./BuildError")); _BuildError = function () { return data; }; return data; } function _prompt() { const data = _interopRequireDefault(require("../../prompt")); _prompt = function () { return data; }; return data; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } const secondsToMilliseconds = seconds => seconds * 1000; class BaseBuilder { constructor(projectDir, options = {}) { _defineProperty(this, "projectDir", ''); _defineProperty(this, "options", { wait: true, clearCredentials: false, releaseChannel: 'default', publish: false }); _defineProperty(this, "manifest", {}); this.projectDir = projectDir; this.options = options; } async command() { try { await this.prepareProjectInfo(); await this.run(); } catch (e) { if (!(e instanceof _BuildError().default)) { throw e; } else { _log().default.error(e.message); process.exit(1); } } } async commandCheckStatus() { try { await this.prepareProjectInfo(); await this.checkStatus(); } catch (e) { if (!(e instanceof _BuildError().default)) { throw e; } else { _log().default.error(e.message); process.exit(1); } } } async prepareProjectInfo() { // always use local json to unify behaviour between regular apps and self hosted ones const { exp } = await _xdl().ProjectUtils.readConfigJsonAsync(this.projectDir); this.manifest = exp; this.user = await _xdl().UserManager.ensureLoggedInAsync(); await this.checkProjectConfig(); } async checkProjectConfig() { if (this.manifest.isDetached) { _log().default.error(`'expo build:${this.platform()}' is not supported for detached projects.`); process.exit(1); } // Warn user if building a project using the next deprecated SDK version let oldestSupportedMajorVersion = await _xdl().Versions.oldestSupportedMajorVersionAsync(); if (_semver().default.major(this.manifest.sdkVersion) === oldestSupportedMajorVersion) { let { version } = await _xdl().Versions.newestSdkVersionAsync(); _log().default.warn(`\nSDK${oldestSupportedMajorVersion} will be ${_chalk().default.bold('deprecated')} next! We recommend upgrading versions, ideally to the latest (SDK${_semver().default.major(version)}), so you can continue to build new binaries of your app and develop in the Expo Client.\n`); } } async checkForBuildInProgress() { (0, _log().default)('Checking if there is a build in progress...\n'); const buildStatus = await _xdl().Project.buildAsync(this.projectDir, { mode: 'status', platform: this.platform(), current: true, releaseChannel: this.options.releaseChannel, publicUrl: this.options.publicUrl, sdkVersion: this.manifest.sdkVersion }); if (buildStatus.jobs && buildStatus.jobs.length) { throw new (_BuildError().default)('Cannot start a new build, as there is already an in-progress build.'); } } async checkStatus(platform = 'all') { (0, _log().default)('Fetching build history...\n'); const buildStatus = await _xdl().Project.buildAsync(this.projectDir, { mode: 'status', platform, current: false, releaseChannel: this.options.releaseChannel }); if (buildStatus.err) { throw new Error('Error getting current build status for this project.'); } if (!(buildStatus.jobs && buildStatus.jobs.length)) { (0, _log().default)('No currently active or previous builds for this project.'); return; } this.logBuildStatuses(buildStatus); } async checkStatusBeforeBuild() { (0, _log().default)('Checking if this build already exists...\n'); const reuseStatus = await _xdl().Project.findReusableBuildAsync(this.options.releaseChannel, this.platform(), this.manifest.sdkVersion, this.manifest.slug); if (reuseStatus.canReuse) { _log().default.warn(`Did you know that Expo provides over-the-air updates? Please see the docs (${_chalk().default.underline('https://docs.expo.io/versions/latest/guides/configuring-ota-updates/')}) and check if you can use them instead of building your app binaries again.`); _log().default.warn(`There were no new changes from the last build, you can download that build from here: ${_chalk().default.underline(reuseStatus.downloadUrl)}`); let questions = [{ type: 'confirm', name: 'confirm', message: 'Do you want to build app anyway?' }]; const answers = await (0, _prompt().default)(questions); if (!answers.confirm) { (0, _log().default)('Stopping the build process'); process.exit(0); } } } logBuildStatuses(buildStatus) { _log().default.raw(); (0, _log().default)('================='); (0, _log().default)(' Builds Statuses '); (0, _log().default)('=================\n'); buildStatus.jobs.forEach((job, i) => { let platform, packageExtension; if (job.platform === 'ios') { platform = 'iOS'; packageExtension = 'IPA'; } else { platform = 'Android'; packageExtension = 'APK'; } (0, _log().default)(`### ${i} | ${platform} | ${UrlUtils().constructBuildLogsUrl(job.id)} ###`); const hasPriorityBuilds = buildStatus.numberOfRemainingPriorityBuilds > 0 || buildStatus.hasUnlimitedPriorityBuilds; const shouldShowUpgradeInfo = !hasPriorityBuilds && i === 0 && job.priority === 'normal' && buildStatus.canPurchasePriorityBuilds; let status; switch (job.status) { case 'pending': case 'sent-to-queue': status = `Build waiting in queue...\nQueue length: ${_chalk().default.underline(UrlUtils().constructTurtleStatusUrl())}`; if (shouldShowUpgradeInfo) { status += `\nWant to wait less? Get priority builds at ${_chalk().default.underline('https://expo.io/settings/billing')}.`; } break; case 'started': status = 'Build started...'; break; case 'in-progress': status = 'Build in progress...'; if (shouldShowUpgradeInfo) { status += `\nWant to wait less? Get priority builds at ${_chalk().default.underline('https://expo.io/settings/billing')}.`; } break; case 'finished': status = 'Build finished.'; if (shouldShowUpgradeInfo) { status += `\nLooks like this build could have been faster.\nRead more about priority builds at ${_chalk().default.underline('https://expo.io/settings/billing')}.`; } break; case 'errored': status = 'There was an error with this build.'; if (job.id) { status += ` When requesting support, please provide this build ID: ${job.id} `; } break; default: status = ''; break; } (0, _log().default)(status); if (job.status === 'finished') { if (job.artifacts) { (0, _log().default)(`${packageExtension}: ${job.artifacts.url}`); } else { (0, _log().default)(`Problem getting ${packageExtension} URL. Please try to build again.`); } } (0, _log().default)(); }); } async ensureReleaseExists() { if (this.options.publish) { const { ids, url, err } = await (0, _publish().action)(this.projectDir, { ...this.options, platform: this.platform(), duringBuild: true }); if (err) { throw new (_BuildError().default)(`No url was returned from publish. Please try again.\n${err}`); } else if (!url || url === '') { throw new (_BuildError().default)('No url was returned from publish. Please try again.'); } return ids; } else { (0, _log().default)('Looking for releases...'); const release = await _xdl().Project.getLatestReleaseAsync(this.projectDir, { releaseChannel: this.options.releaseChannel, platform: this.platform() }); if (!release) { throw new (_BuildError().default)('No releases found. Please create one using `expo publish` first.'); } (0, _log().default)(`Using existing release on channel "${release.channel}":\n` + `publicationId: ${release.publicationId}\n publishedTime: ${release.publishedTime}`); return [release.publicationId]; } } async wait(buildId, { timeout = 1200, interval = 30, publicUrl } = {}) { (0, _log().default)(`Waiting for build to complete. You can press Ctrl+C to exit.`); let spinner = (0, _ora().default)().start(); let time = new Date().getTime(); const endTime = time + secondsToMilliseconds(timeout); while (time <= endTime) { const res = await _xdl().Project.buildAsync(this.projectDir, { current: false, mode: 'status', ...(publicUrl ? { publicUrl } : {}) }); const job = _fp().default.compose(_fp().default.head, _fp().default.filter(job => buildId && job.id === buildId), _fp().default.getOr([], 'jobs'))(res); switch (job.status) { case 'finished': spinner.succeed('Build finished.'); return job; case 'pending': case 'sent-to-queue': spinner.text = 'Build queued...'; break; case 'started': case 'in-progress': spinner.text = 'Build in progress...'; break; case 'errored': spinner.fail('Build failed.'); throw new (_BuildError().default)(`Standalone build failed!`); default: spinner.warn('Unknown status.'); throw new (_BuildError().default)(`Unknown status: ${job.status} - aborting!`); } time = new Date().getTime(); await (0, _delayAsync().default)(secondsToMilliseconds(interval)); } spinner.warn('Timed out.'); throw new (_BuildError().default)('Timeout reached! Project is taking longer than expected to finish building, aborting wait...'); } async build(expIds) { const { publicUrl } = this.options; const platform = this.platform(); const bundleIdentifier = (0, _get().default)(this.manifest, 'ios.bundleIdentifier'); let opts = { mode: 'create', expIds, platform, releaseChannel: this.options.releaseChannel, ...(publicUrl ? { publicUrl } : {}) }; if (platform === 'ios') { opts = { ...opts, type: this.options.type, bundleIdentifier }; } else if (platform === 'android') { opts = { ...opts, type: this.options.type }; } // call out to build api here with url const { id: buildId, priority, canPurchasePriorityBuilds } = await _xdl().Project.buildAsync(this.projectDir, opts); (0, _log().default)('Build started, it may take a few minutes to complete.'); (0, _log().default)(`You can check the queue length at ${_chalk().default.underline(UrlUtils().constructTurtleStatusUrl())}\n`); if (priority === 'normal' && canPurchasePriorityBuilds) { (0, _log().default)('You can make this faster. 🐢\nGet priority builds at: https://expo.io/settings/billing\n'); } if (buildId) { (0, _log().default)(`You can monitor the build at\n\n ${_chalk().default.underline(UrlUtils().constructBuildLogsUrl(buildId))}\n`); } if (this.options.wait) { const waitOpts = publicUrl ? { publicUrl } : {}; const completedJob = await this.wait(buildId, waitOpts); const artifactUrl = completedJob.artifactId ? UrlUtils().constructArtifactUrl(completedJob.artifactId) : completedJob.artifacts.url; (0, _log().default)(`${_chalk().default.green('Successfully built standalone app:')} ${_chalk().default.underline(artifactUrl)}`); } else { (0, _log().default)('Alternatively, run `expo build:status` to monitor it from the command line.'); } } platform() { return 'all'; } } exports.default = BaseBuilder; //# sourceMappingURL=../../__sourcemaps__/commands/build/BaseBuilder.js.map