UNPKG

@sap/cds-dk

Version:

Command line client and development toolkit for the SAP Cloud Application Programming Model

114 lines (97 loc) 4.03 kB
const { utils: { local }} = require ('../cds'); const { join } = require('path'); const { readFileSync, existsSync } = require('fs'); const axios = require('axios'); const { login } = require('./auth_manager'); const buildSystem = require('../build') require('../util/axios').pruneErrors(); const { getMessage } = require('./util/logging'); const { schemaRegex } = require('./util/urls'); const { handleHttpError } = require('./util/errors'); const JOB_STATUS = { QUEUED: 'QUEUED', RUNNING: 'RUNNING', FINISHED: 'FINISHED', FAILED: 'FAILED' }; module.exports = class Push { static async run(paramValues, pushOptions = {}) { const params = await login(paramValues); const projectFolder = params.get('projectFolder'); const extensionName = this.getExtensionName(projectFolder); if (!('extArchive' in pushOptions)) { await buildSystem.build(); } const { src, content } = await this.readSource(params, pushOptions); const url = params.get('appUrl'); const subdomain = params.get('subdomain'); const target = { url, ...subdomain && { subdomain } }; console.log(`\nPushing extension '${extensionName}' from`, { src }, 'to', target); const push = await this.pushTgz(params, content, extensionName); if (params.get('async')) { await this.pollUntilFinished(push.headers.location, params) } console.log ('Activation succeeded.\n') } static async readSource(params, pushOptions) { let src = pushOptions?.extArchive ?? join(params.get('projectFolder'), 'gen/extension.tgz'); let content; if (existsSync(src)) { content = readFileSync(src, { encoding: 'base64' }); src = local(src); } else { if (!schemaRegex.test(src)) { throw getMessage(`Non-existent path: ${src}`, { command: 'push' }); } try { content = (await axios.get(src, { responseEncoding: 'base64' })).data; } catch (error) { handleHttpError(error, params, { url: src }); } } return { src, content }; } static getExtensionName(projectFolder) { try { return require(join(projectFolder, 'package.json')).name; } catch (error) { throw getMessage(`Extension project at ${projectFolder} is missing package.json file`, { error, command: 'push' }); } } static async pushTgz(params, tgz, extensionName) { const pushUrl = `${params.get('appUrl')}/-/cds/extensibility/push`; const options = { ...params.get('reqAuth') }; const async = params.get('async'); if (async) { options.headers = { prefer: 'respond-async', ...options.headers } } return axios.post(pushUrl, { extension: tgz, tag: extensionName }, options) .catch(error => handleHttpError(error, params, { url: pushUrl })); } static async pollUntilFinished(jobUrl, params) { return new Promise((resolve, reject) => { const options = { ...params.get('reqAuth') }; const timeout = setTimeout(() => { clearInterval(interval); reject(new Error('cds push timed out after 5 minutes')); }, 5 * 60 * 1000); const interval = setInterval(async () => { const jobResult = await axios.get(jobUrl, options); const { status, tasks } = jobResult.data; const error = tasks[0]?.error ?? 'cds push failed' if (status === JOB_STATUS.FINISHED || status === JOB_STATUS.FAILED) { clearInterval(interval); clearTimeout(timeout); if (status === JOB_STATUS.FINISHED) { resolve(); } else if (status === JOB_STATUS.FAILED) { reject(new Error(error)); } } }, 1000); }); } }