From 573cd4e211494ce460eb253101c7fc3bbc934cb7 Mon Sep 17 00:00:00 2001 From: Campion Fellin Date: Wed, 30 May 2018 13:23:08 -0700 Subject: [PATCH 1/2] LOG needs pluralize library (#199) Signed-off-by: campionfellin --- src/utils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils.ts b/src/utils.ts index 9da465b5..68ec6a6b 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -7,6 +7,7 @@ const splitLines = require('split-lines'); const dotf = require('dotf'); const read = require('read-file'); const isOnline = require('is-online'); +import * as pluralize from 'pluralize'; // Names / Paths export const PROJECT_NAME = 'clasp'; From 2d8ba8ee71edb2e84bfbfa10c601844d09d7212b Mon Sep 17 00:00:00 2001 From: Campion Fellin Date: Wed, 30 May 2018 23:56:01 -0700 Subject: [PATCH 2/2] Load credentials is now async (#202) Though it looks like a lot of changes, note that most of it is un-indenting the callbacks that were originally given to `getAPICredentials()`. It is now an `async` function, and any command that uses it has been changed to use `await getAPICredentials()` instead. Signed-off-by: campionfellin Fixes #201 - [x] `npm run test` succeeds. Results: ``` 19 passing (55s) 4 pending --------------|----------|----------|----------|----------|-------------------| File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s | --------------|----------|----------|----------|----------|-------------------| All files | 56.37 | 43.12 | 60.95 | 62.89 | | clasp | 96.55 | 50 | 100 | 96.55 | | index.js | 96.55 | 50 | 100 | 96.55 | 187 | clasp/src | 53.9 | 47.11 | 59.53 | 59.03 | | auth.js | 28.07 | 31.91 | 27.27 | 31.82 |... 39,240,241,245 | commands.js | 56.74 | 49.11 | 60.22 | 59.08 |... 05,706,707,733 | files.js | 67.11 | 55.14 | 93.1 | 78.57 |... 82,192,194,197 | utils.js | 60.61 | 48.21 | 67.35 | 70.16 |... 43,268,269,294 | clasp/tests | 61.25 | 9.38 | 66.1 | 72.64 | | test.js | 61.25 | 9.38 | 66.1 | 72.64 |... 55,256,257,258 | --------------|----------|----------|----------|----------|-------------------| ``` - [x] `npm run lint` succeeds. - [ ] Appropriate changes to README are included in PR. --- src/auth.ts | 22 +-- src/commands.ts | 498 +++++++++++++++++++++++------------------------- src/files.ts | 63 +++--- 3 files changed, 283 insertions(+), 300 deletions(-) diff --git a/src/auth.ts b/src/auth.ts index ce641c0c..f9c0d1c3 100644 --- a/src/auth.ts +++ b/src/auth.ts @@ -66,23 +66,19 @@ async function authorize(useLocalhost: boolean, writeToOwnKey: boolean) { /** * Loads the Apps Script API credentials for the CLI. * Required before every API call. - * @param {Function} cb The callback - * @param {boolean} isLocal If we should load local API credentials for this clasp project. */ -export function getAPICredentials(cb: (rc: ClaspSettings | void) => void) { - DOTFILE.RC_LOCAL.read().then((rc: ClaspSettings) => { +export async function loadAPICredentials() { + return DOTFILE.RC_LOCAL.read().then((rc: ClaspSettings) => { + oauth2Client.setCredentials(rc); + }).catch((err: any) => { + return DOTFILE.RC.read().then((rc: ClaspSettings) => { oauth2Client.setCredentials(rc); - cb(rc); }).catch((err: any) => { - DOTFILE.RC.read().then((rc: ClaspSettings) => { - oauth2Client.setCredentials(rc); - cb(rc); - }).catch((err: any) => { - console.error('Could not read API credentials. Error:'); - console.error(err); - process.exit(-1); - }); + console.error('Could not read API credentials. Error:'); + console.error(err); + process.exit(1); }); + }); } /** diff --git a/src/commands.ts b/src/commands.ts index 85ca7ae5..6374d61f 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -3,7 +3,7 @@ */ import * as del from 'del'; import * as pluralize from 'pluralize'; -import { drive, getAPICredentials, logger, script } from './auth'; +import { drive, loadAPICredentials, logger, script } from './auth'; import { fetchProject, getProjectFiles, hasProject } from './files'; import { DOT, @@ -41,40 +41,39 @@ export const pull = async () => { */ export const push = async () => { await checkIfOnline(); + await loadAPICredentials(); spinner.setSpinnerTitle(LOG.PUSHING).start(); - getAPICredentials(async () => { - const { scriptId, rootDir } = await getProjectSettings(); - if (!scriptId) return; - getProjectFiles(rootDir, (err, projectFiles, files) => { - if(err) { - console.log(err); + const { scriptId, rootDir } = await getProjectSettings(); + if (!scriptId) return; + getProjectFiles(rootDir, (err, projectFiles, files) => { + if(err) { + console.log(err); + spinner.stop(true); + } else if (projectFiles) { + const [nonIgnoredFilePaths] = projectFiles; + script.projects.updateContent({ + scriptId, + resource: { files }, + }, {}, (error: any) => { spinner.stop(true); - } else if (projectFiles) { - const [nonIgnoredFilePaths] = projectFiles; - script.projects.updateContent({ - scriptId, - resource: { files }, - }, {}, (error: any) => { - spinner.stop(true); - if (error) { - console.error(LOG.PUSH_FAILURE); - error.errors.map((err: any) => { - console.error(err.message); - }); - console.error(LOG.FILES_TO_PUSH); - nonIgnoredFilePaths.map((filePath: string) => { - console.error(`└─ ${filePath}`); - }); - process.exit(1); - } else { - nonIgnoredFilePaths.map((filePath: string) => { - console.log(`└─ ${filePath}`); - }); - console.log(LOG.PUSH_SUCCESS(nonIgnoredFilePaths.length)); - } - }); - } - }); + if (error) { + console.error(LOG.PUSH_FAILURE); + error.errors.map((err: any) => { + console.error(err.message); + }); + console.error(LOG.FILES_TO_PUSH); + nonIgnoredFilePaths.map((filePath: string) => { + console.error(`└─ ${filePath}`); + }); + process.exit(1); + } else { + nonIgnoredFilePaths.map((filePath: string) => { + console.log(`└─ ${filePath}`); + }); + console.log(LOG.PUSH_SUCCESS(nonIgnoredFilePaths.length)); + } + }); + } }); }; @@ -103,6 +102,7 @@ export const create = async (title: string, parentId: string) => { if (hasProject()) { logError(null, ERROR.FOLDER_EXISTS); } else { + await loadAPICredentials(); if (!title) { await prompt([{ type : 'input', @@ -115,29 +115,27 @@ export const create = async (title: string, parentId: string) => { console.log(err); }); } - getAPICredentials(async () => { - spinner.setSpinnerTitle(LOG.CREATE_PROJECT_START(title)).start(); - try { - const { scriptId } = await getProjectSettings(true); - if (scriptId) { - console.error(ERROR.NO_NESTED_PROJECTS); - process.exit(1); - } - } catch (err) { // no scriptId (because project doesn't exist) - //console.log(err); + spinner.setSpinnerTitle(LOG.CREATE_PROJECT_START(title)).start(); + try { + const { scriptId } = await getProjectSettings(true); + if (scriptId) { + console.error(ERROR.NO_NESTED_PROJECTS); + process.exit(1); } - script.projects.create({ title, parentId }, {}).then(res => { - spinner.stop(true); - const createdScriptId = res.data.scriptId; - console.log(LOG.CREATE_PROJECT_FINISH(createdScriptId)); - saveProjectId(createdScriptId); - if (!manifestExists()) { - fetchProject(createdScriptId); // fetches appsscript.json, o.w. `push` breaks - } - }).catch((error: object) => { - spinner.stop(true); - logError(error, ERROR.CREATE); - }); + } catch (err) { // no scriptId (because project doesn't exist) + //console.log(err); + } + script.projects.create({ title, parentId }, {}).then(res => { + spinner.stop(true); + const createdScriptId = res.data.scriptId; + console.log(LOG.CREATE_PROJECT_FINISH(createdScriptId)); + saveProjectId(createdScriptId); + if (!manifestExists()) { + fetchProject(createdScriptId); // fetches appsscript.json, o.w. `push` breaks + } + }).catch((error: object) => { + spinner.stop(true); + logError(error, ERROR.CREATE); }); } }; @@ -154,37 +152,36 @@ export const clone = async (scriptId: string, versionNumber?: number) => { logError(null, ERROR.FOLDER_EXISTS); } else { if (!scriptId) { - getAPICredentials(async () => { - const { data } = await drive.files.list({ - pageSize: 10, - fields: 'files(id, name)', - q: 'mimeType="application/vnd.google-apps.script"', - }); - const files = data.files; - if (files.length) { - const fileIds = files.map((file: any) => { - return { - name: `${file.name}`.padEnd(20) + ` - (${file.id})`, - value: file.id, - }; - }); - await prompt([{ - type : 'list', - name : 'scriptId', - message : 'Clone which script? ', - choices : fileIds, - }]).then((answers: any) => { - checkIfOnline(); - spinner.setSpinnerTitle(LOG.CLONING); - saveProjectId(answers.scriptId); - fetchProject(answers.scriptId, '', versionNumber); - }).catch((err: any) => { - console.log(err); - }); - } else { - console.log(LOG.FINDING_SCRIPTS_DNE); - } + await loadAPICredentials(); + const { data } = await drive.files.list({ + pageSize: 10, + fields: 'files(id, name)', + q: 'mimeType="application/vnd.google-apps.script"', }); + const files = data.files; + if (files.length) { + const fileIds = files.map((file: any) => { + return { + name: `${file.name}`.padEnd(20) + ` - (${file.id})`, + value: file.id, + }; + }); + await prompt([{ + type : 'list', + name : 'scriptId', + message : 'Clone which script? ', + choices : fileIds, + }]).then((answers: any) => { + checkIfOnline(); + spinner.setSpinnerTitle(LOG.CLONING); + saveProjectId(answers.scriptId); + fetchProject(answers.scriptId, '', versionNumber); + }).catch((err: any) => { + console.log(err); + }); + } else { + console.log(LOG.FINDING_SCRIPTS_DNE); + } } else { spinner.setSpinnerTitle(LOG.CLONING); saveProjectId(scriptId); @@ -244,7 +241,7 @@ export const logs = async (cmd: { const { projectId } = await getProjectSettings(); if (!projectId) { console.error(ERROR.NO_GCLOUD_PROJECT); - process.exit(-1); + process.exit(1); } if (cmd.open) { const url = 'https://console.cloud.google.com/logs/viewer?project=' + @@ -253,14 +250,13 @@ export const logs = async (cmd: { open(url); process.exit(0); } - getAPICredentials(async () => { - const { data } = await logger.entries.list({ - resourceNames: [ - `projects/${projectId}`, - ], - }); - printLogs(data.entries); + await loadAPICredentials(); + const { data } = await logger.entries.list({ + resourceNames: [ + `projects/${projectId}`, + ], }); + printLogs(data.entries); }; /** @@ -268,20 +264,19 @@ export const logs = async (cmd: { * @param functionName {string} The function name within the Apps Script project. * @see https://developers.google.com/apps-script/api/how-tos/execute */ -export const run = (functionName:string) => { - getAPICredentials(async () => { - await checkIfOnline(); - getProjectSettings().then(({ scriptId }: ProjectSettings) => { - const params = { - scriptId, - function: functionName, - devMode: false, - }; - script.scripts.run(params).then(response => { - console.log(response.data); - }).catch(e => { - console.log(e); - }); +export const run = async (functionName:string) => { + await checkIfOnline(); + await loadAPICredentials(); + getProjectSettings().then(({ scriptId }: ProjectSettings) => { + const params = { + scriptId, + function: functionName, + devMode: false, + }; + script.scripts.run(params).then(response => { + console.log(response.data); + }).catch(e => { + console.log(e); }); }); }; @@ -293,51 +288,50 @@ export const run = (functionName:string) => { */ export const deploy = async (version: string, description: string) => { await checkIfOnline(); + await loadAPICredentials(); description = description || ''; - getAPICredentials(async () => { - const { scriptId } = await getProjectSettings(); - if (!scriptId) return; - spinner.setSpinnerTitle(LOG.DEPLOYMENT_START(scriptId)).start(); - function createDeployment(versionNumber: string) { - spinner.setSpinnerTitle(LOG.DEPLOYMENT_CREATE); - script.projects.deployments.create({ - scriptId, - resource: { - versionNumber, - manifestFileName: PROJECT_MANIFEST_BASENAME, - description, - }, - }, {}, (err: any, response: any) => { - spinner.stop(true); - if (err) { - console.error(ERROR.DEPLOYMENT_COUNT); - } else if (response) { - console.log(`- ${response.data.deploymentId} @${versionNumber}.`); - } - }); - } + const { scriptId } = await getProjectSettings(); + if (!scriptId) return; + spinner.setSpinnerTitle(LOG.DEPLOYMENT_START(scriptId)).start(); + function createDeployment(versionNumber: string) { + spinner.setSpinnerTitle(LOG.DEPLOYMENT_CREATE); + script.projects.deployments.create({ + scriptId, + resource: { + versionNumber, + manifestFileName: PROJECT_MANIFEST_BASENAME, + description, + }, + }, {}, (err: any, response: any) => { + spinner.stop(true); + if (err) { + console.error(ERROR.DEPLOYMENT_COUNT); + } else if (response) { + console.log(`- ${response.data.deploymentId} @${versionNumber}.`); + } + }); + } - // If the version is specified, update that deployment - const versionRequestBody = { - description, - }; - if (version) { - createDeployment(version); - } else { // if no version, create a new version and deploy that - script.projects.versions.create({ - scriptId, - resource: versionRequestBody, - }, {}, (err: any, { data }: any) => { - spinner.stop(true); - if (err) { - logError(null, ERROR.ONE_DEPLOYMENT_CREATE); - } else { - console.log(LOG.VERSION_CREATED(data.versionNumber)); - createDeployment(data.versionNumber); - } - }); - } - }); + // If the version is specified, update that deployment + const versionRequestBody = { + description, + }; + if (version) { + createDeployment(version); + } else { // if no version, create a new version and deploy that + script.projects.versions.create({ + scriptId, + resource: versionRequestBody, + }, {}, (err: any, { data }: any) => { + spinner.stop(true); + if (err) { + logError(null, ERROR.ONE_DEPLOYMENT_CREATE); + } else { + console.log(LOG.VERSION_CREATED(data.versionNumber)); + createDeployment(data.versionNumber); + } + }); + } }; /** @@ -346,21 +340,20 @@ export const deploy = async (version: string, description: string) => { */ export const undeploy = async (deploymentId: string) => { await checkIfOnline(); - getAPICredentials(() => { - getProjectSettings().then(({ scriptId }: ProjectSettings) => { - if (!scriptId) return; - spinner.setSpinnerTitle(LOG.UNDEPLOYMENT_START(deploymentId)).start(); - script.projects.deployments.delete({ - scriptId, - deploymentId, - }, {}, (err: any, res: any) => { - spinner.stop(true); - if (err) { - logError(null, ERROR.READ_ONLY_DELETE); - } else { - console.log(LOG.UNDEPLOYMENT_FINISH(deploymentId)); - } - }); + await loadAPICredentials(); + getProjectSettings().then(({ scriptId }: ProjectSettings) => { + if (!scriptId) return; + spinner.setSpinnerTitle(LOG.UNDEPLOYMENT_START(deploymentId)).start(); + script.projects.deployments.delete({ + scriptId, + deploymentId, + }, {}, (err: any, res: any) => { + spinner.stop(true); + if (err) { + logError(null, ERROR.READ_ONLY_DELETE); + } else { + console.log(LOG.UNDEPLOYMENT_FINISH(deploymentId)); + } }); }); }; @@ -370,23 +363,22 @@ export const undeploy = async (deploymentId: string) => { */ export const list = async () => { await checkIfOnline(); + await loadAPICredentials(); spinner.setSpinnerTitle(LOG.FINDING_SCRIPTS).start(); - getAPICredentials(async () => { - const res = await drive.files.list({ - pageSize: 50, - fields: 'nextPageToken, files(id, name)', - q: 'mimeType="application/vnd.google-apps.script"', - }); - spinner.stop(true); - const files = res.data.files; - if (files.length) { - files.map((file: any) => { - console.log(`${file.name.padEnd(20)} – ${getScriptURL(file.id)}`); - }); - } else { - console.log('No script files found.'); - } + const res = await drive.files.list({ + pageSize: 50, + fields: 'nextPageToken, files(id, name)', + q: 'mimeType="application/vnd.google-apps.script"', }); + spinner.stop(true); + const files = res.data.files; + if (files.length) { + files.map((file: any) => { + console.log(`${file.name.padEnd(20)} – ${getScriptURL(file.id)}`); + }); + } else { + console.log('No script files found.'); + } }; /** @@ -397,26 +389,25 @@ export const list = async () => { */ export const redeploy = async (deploymentId: string, version: string, description: string) => { await checkIfOnline(); - getAPICredentials(() => { - getProjectSettings().then(({ scriptId }: ProjectSettings) => { - script.projects.deployments.update({ - scriptId, - deploymentId, - resource: { - deploymentConfig: { - versionNumber: version, - manifestFileName: PROJECT_MANIFEST_BASENAME, - description, - }, + await loadAPICredentials(); + getProjectSettings().then(({ scriptId }: ProjectSettings) => { + script.projects.deployments.update({ + scriptId, + deploymentId, + resource: { + deploymentConfig: { + versionNumber: version, + manifestFileName: PROJECT_MANIFEST_BASENAME, + description, }, - }, {}, (error: any, res: any) => { - spinner.stop(true); - if (error) { - logError(null, error); // TODO prettier error - } else { - console.log(LOG.REDEPLOY_END); - } - }); + }, + }, {}, (error: any, res: any) => { + spinner.stop(true); + if (error) { + logError(null, error); // TODO prettier error + } else { + console.log(LOG.REDEPLOY_END); + } }); }); }; @@ -426,31 +417,30 @@ export const redeploy = async (deploymentId: string, version: string, descriptio */ export const deployments = async () => { await checkIfOnline(); - getAPICredentials(async () => { - const { scriptId } = await getProjectSettings(); - if (!scriptId) return; - spinner.setSpinnerTitle(LOG.DEPLOYMENT_LIST(scriptId)).start(); - script.projects.deployments.list({ - scriptId, - }, {}, (error: any, { data }: any) => { - spinner.stop(true); - if (error) { - logError(error); - } else { - const deployments = data.deployments; - const numDeployments = deployments.length; - const deploymentWord = pluralize('Deployment', numDeployments); - console.log(`${numDeployments} ${deploymentWord}.`); - deployments.map(({ deploymentId, deploymentConfig }: any) => { - const versionString = !!deploymentConfig.versionNumber ? - `@${deploymentConfig.versionNumber}` : '@HEAD'; - const description = deploymentConfig.description ? - '- ' + deploymentConfig.description : ''; - console.log(`- ${deploymentId} ${versionString} ${description}`); - }); - } - }); - }); + await loadAPICredentials(); + const { scriptId } = await getProjectSettings(); + if (!scriptId) return; + spinner.setSpinnerTitle(LOG.DEPLOYMENT_LIST(scriptId)).start(); + script.projects.deployments.list({ + scriptId, + }, {}, (error: any, { data }: any) => { + spinner.stop(true); + if (error) { + logError(error); + } else { + const deployments = data.deployments; + const numDeployments = deployments.length; + const deploymentWord = pluralize('Deployment', numDeployments); + console.log(`${numDeployments} ${deploymentWord}.`); + deployments.map(({ deploymentId, deploymentConfig }: any) => { + const versionString = !!deploymentConfig.versionNumber ? + `@${deploymentConfig.versionNumber}` : '@HEAD'; + const description = deploymentConfig.description ? + '- ' + deploymentConfig.description : ''; + console.log(`- ${deploymentId} ${versionString} ${description}`); + }); + } + }); }; /** @@ -458,27 +448,26 @@ export const deployments = async () => { */ export const versions = async () => { await checkIfOnline(); + await loadAPICredentials(); spinner.setSpinnerTitle('Grabbing versions...').start(); - getAPICredentials(async () => { - const { scriptId } = await getProjectSettings(); - script.projects.versions.list({ - scriptId, - }, {}, (error: any, { data }: any) => { - spinner.stop(true); - if (error) { - logError(error); + const { scriptId } = await getProjectSettings(); + script.projects.versions.list({ + scriptId, + }, {}, (error: any, { data }: any) => { + spinner.stop(true); + if (error) { + logError(error); + } else { + if (data && data.versions && data.versions.length) { + const numVersions = data.versions.length; + console.log(LOG.VERSION_NUM(numVersions)); + data.versions.map((version: string) => { + console.log(LOG.VERSION_DESCRIPTION(version)); + }); } else { - if (data && data.versions && data.versions.length) { - const numVersions = data.versions.length; - console.log(LOG.VERSION_NUM(numVersions)); - data.versions.map((version: string) => { - console.log(LOG.VERSION_DESCRIPTION(version)); - }); - } else { - console.error(LOG.DEPLOYMENT_DNE); - } + console.error(LOG.DEPLOYMENT_DNE); } - }); + } }); }; @@ -487,20 +476,19 @@ export const versions = async () => { */ export const version = async (description: string) => { await checkIfOnline(); + await loadAPICredentials(); spinner.setSpinnerTitle(LOG.VERSION_CREATE).start(); - getAPICredentials(async () => { - const { scriptId } = await getProjectSettings(); - script.projects.versions.create({ - scriptId, - description, - }, {}, (error: any, { data }: any) => { - spinner.stop(true); - if (error) { - logError(error); - } else { - console.log(LOG.VERSION_CREATED(data.versionNumber)); - } - }); + const { scriptId } = await getProjectSettings(); + script.projects.versions.create({ + scriptId, + description, + }, {}, (error: any, { data }: any) => { + spinner.stop(true); + if (error) { + logError(error); + } else { + console.log(LOG.VERSION_CREATED(data.versionNumber)); + } }); }; diff --git a/src/files.ts b/src/files.ts index 6da82cea..d1a848ce 100644 --- a/src/files.ts +++ b/src/files.ts @@ -2,7 +2,7 @@ import * as fs from 'fs'; import * as anymatch from 'anymatch'; import * as mkdirp from 'mkdirp'; import * as recursive from 'recursive-readdir'; -import { getAPICredentials, script } from './auth'; +import { loadAPICredentials, script } from './auth'; import { DOT, DOTFILE, ERROR, LOG, checkIfOnline, getAPIFileType, logError, spinner } from './utils'; const path = require('path'); const readMultipleFiles = require('read-multiple-files'); @@ -134,39 +134,38 @@ export function getProjectFiles(rootDir: string, callback: FilesCallback): void * @param {string?} rootDir The directory to save the project files to. Defaults to `pwd` * @param {number?} versionNumber The version of files to fetch. */ -export function fetchProject(scriptId: string, rootDir = '', versionNumber?: number) { +export async function fetchProject(scriptId: string, rootDir = '', versionNumber?: number) { + await checkIfOnline(); + await loadAPICredentials(); spinner.start(); - getAPICredentials(async () => { - await checkIfOnline(); - script.projects.getContent({ - scriptId, - versionNumber, - }, {}, (error: any, { data }: any) => { - spinner.stop(true); - if (error) { - if (error.statusCode === 404) return logError(null, ERROR.SCRIPT_ID_INCORRECT(scriptId)); - return logError(error, ERROR.SCRIPT_ID); - } else { - if (!data.files) { - return logError(null, ERROR.SCRIPT_ID_INCORRECT(scriptId)); - } - // Create the files in the cwd - console.log(LOG.CLONE_SUCCESS(data.files.length)); - const sortedFiles = data.files.sort((file: AppsScriptFile) => file.name); - sortedFiles.map((file: AppsScriptFile) => { - const filePath = `${file.name}.${getFileType(file.type)}`; - const truePath = `${rootDir || '.'}/${filePath}`; - mkdirp(path.dirname(truePath), (err) => { - if (err) return logError(err, ERROR.FS_DIR_WRITE); - if (!file.source) return; // disallow empty files - fs.writeFile(truePath, file.source, (err) => { - if (err) return logError(err, ERROR.FS_FILE_WRITE); - }); - // Log only filename if pulling to root (Code.gs vs ./Code.gs) - console.log(`└─ ${rootDir ? truePath : filePath}`); + script.projects.getContent({ + scriptId, + versionNumber, + }, {}, (error: any, { data }: any) => { + spinner.stop(true); + if (error) { + if (error.statusCode === 404) return logError(null, ERROR.SCRIPT_ID_INCORRECT(scriptId)); + return logError(error, ERROR.SCRIPT_ID); + } else { + if (!data.files) { + return logError(null, ERROR.SCRIPT_ID_INCORRECT(scriptId)); + } + // Create the files in the cwd + console.log(LOG.CLONE_SUCCESS(data.files.length)); + const sortedFiles = data.files.sort((file: AppsScriptFile) => file.name); + sortedFiles.map((file: AppsScriptFile) => { + const filePath = `${file.name}.${getFileType(file.type)}`; + const truePath = `${rootDir || '.'}/${filePath}`; + mkdirp(path.dirname(truePath), (err) => { + if (err) return logError(err, ERROR.FS_DIR_WRITE); + if (!file.source) return; // disallow empty files + fs.writeFile(truePath, file.source, (err) => { + if (err) return logError(err, ERROR.FS_FILE_WRITE); }); + // Log only filename if pulling to root (Code.gs vs ./Code.gs) + console.log(`└─ ${rootDir ? truePath : filePath}`); }); - } - }); + }); + } }); } \ No newline at end of file