@google/clasp
Version:
Develop Apps Script Projects locally
318 lines (317 loc) • 13 kB
JavaScript
import Debug from 'debug';
import fs from 'fs/promises';
import { google } from 'googleapis';
import { fetchWithPages } from './utils.js';
import { assertAuthenticated, assertScriptConfigured, handleApiError } from './utils.js';
import path from 'path';
const debug = Debug('clasp:core');
export class Project {
constructor(options) {
this.options = options;
}
get scriptId() {
var _a;
return (_a = this.options.project) === null || _a === void 0 ? void 0 : _a.scriptId;
}
get projectId() {
var _a;
return (_a = this.options.project) === null || _a === void 0 ? void 0 : _a.projectId;
}
get parentId() {
var _a;
return (_a = this.options.project) === null || _a === void 0 ? void 0 : _a.parentId;
}
// TODO - Do we need the assertion or can just use accessor?
getProjectId() {
assertScriptConfigured(this.options);
return this.options.project.projectId;
}
async createScript(name, parentId) {
var _a;
debug('Creating script %s', name);
assertAuthenticated(this.options);
if ((_a = this.options.project) === null || _a === void 0 ? void 0 : _a.scriptId) {
debug('Warning: Creating script while id already exists');
}
const credentials = this.options.credentials;
const script = google.script({ version: 'v1', auth: credentials });
try {
const requestOptions = {
requestBody: {
parentId,
title: name,
},
};
debug('Creating project with request %O', requestOptions);
const res = await script.projects.create(requestOptions);
if (!res.data.scriptId) {
throw new Error('Unexpected error, script ID missing from response.');
}
debug('Created script %s', res.data.scriptId);
const scriptId = res.data.scriptId;
this.options.project = { scriptId, parentId };
return scriptId;
}
catch (error) {
handleApiError(error);
}
}
async createWithContainer(name, mimeType) {
var _a;
debug('Creating container bound script %s (%s)', name, mimeType);
assertAuthenticated(this.options);
if ((_a = this.options.project) === null || _a === void 0 ? void 0 : _a.scriptId) {
debug('Warning: Creating script while id already exists');
}
let parentId;
const credentials = this.options.credentials;
const drive = google.drive({ version: 'v3', auth: credentials });
try {
const requestOptions = {
requestBody: {
mimeType,
name,
},
};
debug('Creating project with request %O', requestOptions);
const res = await drive.files.create(requestOptions);
parentId = res.data.id;
debug('Created container %s', parentId);
if (!parentId) {
throw new Error('Unexpected error, container ID missing from response.');
}
}
catch (error) {
handleApiError(error);
}
const scriptId = await this.createScript(name, parentId);
return {
parentId,
scriptId,
};
}
async listScripts() {
debug('Fetching scripts');
assertAuthenticated(this.options);
const credentials = this.options.credentials;
const drive = google.drive({ version: 'v3', auth: credentials });
try {
return fetchWithPages(async (pageSize, pageToken) => {
var _a, _b;
const requestOptions = {
pageSize,
pageToken,
fields: 'nextPageToken, files(id, name)',
q: 'mimeType="application/vnd.google-apps.script"',
};
debug('Fetching scripts from drive with request %O', requestOptions);
const res = await drive.files.list(requestOptions);
return {
results: ((_a = res.data.files) !== null && _a !== void 0 ? _a : []),
pageToken: (_b = res.data.nextPageToken) !== null && _b !== void 0 ? _b : undefined,
};
});
}
catch (error) {
handleApiError(error);
}
}
async version(description = '') {
var _a;
debug('Creating version: %s', description);
assertAuthenticated(this.options);
assertScriptConfigured(this.options);
const credentials = this.options.credentials;
const scriptId = this.options.project.scriptId;
const script = google.script({ version: 'v1', auth: credentials });
try {
const requestOptions = {
requestBody: {
description: description !== null && description !== void 0 ? description : '',
},
scriptId: scriptId,
};
debug('Creating version with request %O', requestOptions);
const res = await script.projects.versions.create(requestOptions);
const versionNumber = (_a = res.data.versionNumber) !== null && _a !== void 0 ? _a : 0;
debug('Created new version %d', versionNumber);
return versionNumber;
}
catch (error) {
handleApiError(error);
}
}
async listVersions() {
debug('Fetching versions');
assertAuthenticated(this.options);
assertScriptConfigured(this.options);
const scriptId = this.options.project.scriptId;
const credentials = this.options.credentials;
const script = google.script({ version: 'v1', auth: credentials });
try {
return fetchWithPages(async (pageSize, pageToken) => {
var _a, _b;
const requestOptions = {
scriptId,
pageSize,
pageToken,
};
debug('Fetching versions with request %O', requestOptions);
const res = await script.projects.versions.list(requestOptions);
return {
results: (_a = res.data.versions) !== null && _a !== void 0 ? _a : [],
pageToken: (_b = res.data.nextPageToken) !== null && _b !== void 0 ? _b : undefined,
};
});
}
catch (error) {
handleApiError(error);
}
}
async listDeployments() {
debug('Listing deployments');
assertAuthenticated(this.options);
assertScriptConfigured(this.options);
const scriptId = this.options.project.scriptId;
const credentials = this.options.credentials;
const script = google.script({ version: 'v1', auth: credentials });
try {
return fetchWithPages(async (pageSize, pageToken) => {
var _a, _b;
const requestOptions = {
scriptId,
pageSize,
pageToken,
};
debug('Fetching deployments with request %O', requestOptions);
const res = await script.projects.deployments.list(requestOptions);
return {
results: (_a = res.data.deployments) !== null && _a !== void 0 ? _a : [],
pageToken: (_b = res.data.nextPageToken) !== null && _b !== void 0 ? _b : undefined,
};
});
}
catch (error) {
handleApiError(error);
}
}
async deploy(description = '', deploymentId, versionNumber) {
debug('Deploying project: %s (%s)', description, versionNumber !== null && versionNumber !== void 0 ? versionNumber : 'HEAD');
assertAuthenticated(this.options);
assertScriptConfigured(this.options);
if (versionNumber === undefined) {
versionNumber = await this.version(description);
}
const scriptId = this.options.project.scriptId;
const credentials = this.options.credentials;
const script = google.script({ version: 'v1', auth: credentials });
try {
let deployment;
if (!deploymentId) {
const requestOptions = {
scriptId: scriptId,
requestBody: {
description: description !== null && description !== void 0 ? description : '',
versionNumber: versionNumber,
manifestFileName: 'appsscript',
},
};
debug('Creating deployment with request %O', requestOptions);
const res = await script.projects.deployments.create(requestOptions);
deployment = res.data;
}
else {
const requestOptions = {
scriptId: scriptId,
deploymentId: deploymentId,
requestBody: {
deploymentConfig: {
description: description !== null && description !== void 0 ? description : '',
versionNumber: versionNumber,
scriptId: scriptId,
manifestFileName: 'appsscript',
},
},
};
debug('Updating existing deployment with request %O', requestOptions);
const res = await script.projects.deployments.update(requestOptions);
deployment = res.data;
}
return deployment;
}
catch (error) {
handleApiError(error);
}
}
async entryPoints(deploymentId) {
var _a, _b;
assertAuthenticated(this.options);
assertScriptConfigured(this.options);
const scriptId = this.options.project.scriptId;
const credentials = this.options.credentials;
const script = google.script({ version: 'v1', auth: credentials });
try {
const res = await script.projects.deployments.get({ scriptId, deploymentId });
const entryPoints = (_b = (_a = res.data) === null || _a === void 0 ? void 0 : _a.entryPoints) !== null && _b !== void 0 ? _b : [];
return entryPoints;
}
catch (error) {
handleApiError(error);
}
}
async undeploy(deploymentId) {
debug('Deleting deployment %s', deploymentId);
assertAuthenticated(this.options);
assertScriptConfigured(this.options);
const scriptId = this.options.project.scriptId;
const credentials = this.options.credentials;
const script = google.script({ version: 'v1', auth: credentials });
try {
const requestOptions = {
scriptId: scriptId,
deploymentId,
};
debug('Deleting deployment with request %O', requestOptions);
await script.projects.deployments.delete(requestOptions);
}
catch (error) {
handleApiError(error);
}
}
async updateSettings() {
debug('Updating settings');
assertScriptConfigured(this.options);
const srcDir = path.relative(this.options.files.projectRootDir, this.options.files.contentDir);
const settings = {
scriptId: this.options.project.scriptId,
rootDir: srcDir,
parentId: this.options.project.parentId,
projectId: this.options.project.projectId,
scriptExtensions: this.options.files.fileExtensions['SERVER_JS'],
htmlExtensions: this.options.files.fileExtensions['HTML'],
jsonExtensions: this.options.files.fileExtensions['JSON'],
filePushOrder: [],
skipSubdirectories: this.options.files.skipSubdirectories,
};
await fs.writeFile(this.options.configFilePath, JSON.stringify(settings, null, 2));
}
async setProjectId(projectId) {
debug('Setting project ID %s in file %s', projectId, this.options.configFilePath);
assertScriptConfigured(this.options);
this.options.project.projectId = projectId;
this.updateSettings();
}
exists() {
var _a;
return ((_a = this.options.project) === null || _a === void 0 ? void 0 : _a.scriptId) !== undefined;
}
async readManifest() {
debug('Reading manifest');
assertScriptConfigured(this.options);
const manifestPath = path.join(this.options.files.contentDir, 'appsscript.json');
debug('Manifest path is %s', manifestPath);
const content = await fs.readFile(manifestPath);
const manifest = JSON.parse(content.toString());
return manifest;
}
}