Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Signed-off-by: campionfellin <campionfellin@gmail.com>
  • Loading branch information
campionfellin committed Feb 9, 2019
2 parents 4ffb8c0 + da038b4 commit b0ee106
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 57 deletions.
2 changes: 2 additions & 0 deletions src/apis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,5 @@ export const PUBLIC_ADVANCED_SERVICES: AdvancedService[] = [
version: 'v3',
},
];

export const SCRIPT_ID_LENGTH = 57;
3 changes: 2 additions & 1 deletion src/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import { discovery_v1, drive_v3, google, logging_v2, script_v1, serviceusage_v1
import { prompt } from 'inquirer';
import { ClaspToken, DOTFILE } from './dotfile';
import { enableExecutionAPI, readManifest } from './manifest';
import { ClaspCredentials, ERROR, LOG, URL, checkIfOnline, getOAuthSettings, logError } from './utils';
import { URL } from './urls';
import { ClaspCredentials, ERROR, LOG,checkIfOnline, getOAuthSettings, logError } from './utils';
import open = require('opn');
import readline = require('readline');

Expand Down
81 changes: 39 additions & 42 deletions src/commands/clone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import {
loadAPICredentials,
} from './../auth';

import {
extractScriptId,
} from './../urls';

import {
checkIfOnline,
ERROR,
Expand All @@ -24,55 +28,15 @@ const prompt = require('inquirer').prompt;
/**
* Fetches an Apps Script project.
* Prompts the user if no script ID is provided.
* @param scriptId {string} The Apps Script project ID to fetch.
* @param scriptId {string} The Apps Script project ID or project URL to fetch.
* @param versionNumber {string} An optional version to pull the script from.
* @param cmd.rootDir {string} Specifies the local directory in which clasp will store your project files.
* If not specified, clasp will default to the current directory.
*/
export default async (scriptId: string, versionNumber: number, cmd: { rootDir: string }) => {
await checkIfOnline();
if (hasProject()) return logError(null, ERROR.FOLDER_EXISTS);
if (!scriptId) {
await loadAPICredentials();
const list = await drive.files.list({
// pageSize: 10,
// fields: 'files(id, name)',
orderBy: 'modifiedByMeTime desc',
q: 'mimeType="application/vnd.google-apps.script"',
});
const data = list.data;
if (!data) return logError(list.statusText, 'Unable to use the Drive API.');
const files = data.files;
if (!files || !files.length) return console.log(LOG.FINDING_SCRIPTS_DNE);
const fileIds = files.map((file: any) => {
return {
name: `${padEnd(file.name, 20)}${LOG.SCRIPT_LINK(file.id)}`,
value: file.id,
};
});
const answers = await prompt([
{
type: 'list',
name: 'scriptId',
message: LOG.CLONE_SCRIPT_QUESTION,
choices: fileIds,
pageSize: 30,
},
]);
scriptId = answers.scriptId;
}
// We have a scriptId or URL
// If we passed a URL, extract the scriptId from that. For example:
// https://script.google.com/a/DOMAIN/d/1Ng7bNZ1K95wNi2H7IUwZzM68FL6ffxQhyc_ByV42zpS6qAFX8pFsWu2I/edit
if (scriptId.length !== 57) {
// 57 is the magic number
const ids = scriptId.split('/').filter(s => {
return s.length === 57;
});
if (ids.length) {
scriptId = ids[0];
}
}
scriptId = scriptId ? extractScriptId(scriptId) : await getScriptId();
spinner.setSpinnerTitle(LOG.CLONING);
const rootDir = cmd.rootDir;
saveProject({
Expand All @@ -81,4 +45,37 @@ export default async (scriptId: string, versionNumber: number, cmd: { rootDir: s
}, false);
const files = await fetchProject(scriptId, versionNumber);
await writeProjectFiles(files, rootDir);
};

/**
* Lists a user's AppsScripts and prompts them to choose one to clone.
*/
const getScriptId = async () => {
await loadAPICredentials();
const list = await drive.files.list({
// pageSize: 10,
// fields: 'files(id, name)',
orderBy: 'modifiedByMeTime desc',
q: 'mimeType="application/vnd.google-apps.script"',
});
const data = list.data;
if (!data) return logError(list.statusText, 'Unable to use the Drive API.');
const files = data.files;
if (!files || !files.length) return console.log(LOG.FINDING_SCRIPTS_DNE);
const fileIds = files.map((file: any) => {
return {
name: `${padEnd(file.name, 20)}${LOG.SCRIPT_LINK(file.id)}`,
value: file.id,
};
});
const answers = await prompt([
{
type: 'list',
name: 'scriptId',
message: LOG.CLONE_SCRIPT_QUESTION,
choices: fileIds,
pageSize: 30,
},
]);
return answers.scriptId;
};
39 changes: 39 additions & 0 deletions src/urls.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import {
SCRIPT_ID_LENGTH,
} from './apis';

/**
* Extracts scriptId from URL if given in URL form.
* @param scriptId {string} either a scriptId or URL containing the scriptId
* @example
* extractScriptId(
* 'https://script.google.com/a/DOMAIN/d/1Ng7bNZ1K95wNi2H7IUwZzM68FL6ffxQhyc_ByV42zpS6qAFX8pFsWu2I/edit'
* )
* returns '1Ng7bNZ1K95wNi2H7IUwZzM68FL6ffxQhyc_ByV42zpS6qAFX8pFsWu2I'
* @example
* extractScriptId('1Ng7bNZ1K95wNi2H7IUwZzM68FL6ffxQhyc_ByV42zpS6qAFX8pFsWu2I')
* returns '1Ng7bNZ1K95wNi2H7IUwZzM68FL6ffxQhyc_ByV42zpS6qAFX8pFsWu2I'
*/
export const extractScriptId = (scriptId: string) => {
if (scriptId.length !== SCRIPT_ID_LENGTH) {
const ids = scriptId.split('/').filter(s => {
return s.length === SCRIPT_ID_LENGTH;
});
if (ids.length) {
scriptId = ids[0];
}
}
return scriptId;
};

// Helpers to get Apps Script project URLs
export const URL = {
APIS: (projectId: string) => `https://console.developers.google.com/apis/dashboard?project=${projectId}`,
CREDS: (projectId: string) => `https://console.developers.google.com/apis/credentials?project=${projectId}`,
LOGS: (projectId: string) =>
`https://console.cloud.google.com/logs/viewer?project=${projectId}&resource=app_script_function`,
SCRIPT_API_USER: 'https://script.google.com/home/usersettings',
// It is too expensive to get the script URL from the Drive API. (Async/not offline)
SCRIPT: (scriptId: string) => `https://script.google.com/d/${scriptId}/edit`,
DRIVE: (driveId: string) => `https://drive.google.com/open?id=${driveId}`,
};
13 changes: 1 addition & 12 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { prompt } from 'inquirer';
import * as pluralize from 'pluralize';
import { ClaspToken, DOT, DOTFILE, ProjectSettings } from './dotfile';
import {Manifest} from './manifest';
import { URL } from './urls';

const ucfirst = require('ucfirst');
const isOnline = require('is-online');
Expand Down Expand Up @@ -57,18 +58,6 @@ export function getOAuthSettings(local: boolean): Promise<ClaspToken> {
});
}

// Helpers to get Apps Script project URLs
export const URL = {
APIS: (projectId: string) => `https://console.developers.google.com/apis/dashboard?project=${projectId}`,
CREDS: (projectId: string) => `https://console.developers.google.com/apis/credentials?project=${projectId}`,
LOGS: (projectId: string) =>
`https://console.cloud.google.com/logs/viewer?project=${projectId}&resource=app_script_function`,
SCRIPT_API_USER: 'https://script.google.com/home/usersettings',
// It is too expensive to get the script URL from the Drive API. (Async/not offline)
SCRIPT: (scriptId: string) => `https://script.google.com/d/${scriptId}/edit`,
DRIVE: (driveId: string) => `https://drive.google.com/open?id=${driveId}`,
};

// Error messages (some errors take required params)
export const ERROR = {
ACCESS_TOKEN: `Error retrieving access token: `,
Expand Down
15 changes: 13 additions & 2 deletions tests/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@ import { getAppsScriptFileName, getFileType } from './../src/files';
import {
ERROR,
LOG,
URL,
getAPIFileType,
getDefaultProjectName,
getWebApplicationURL,
hasOauthClientSettings,
saveProject,
} from './../src/utils.js';
} from './../src/utils';

import {
backupSettings,
Expand All @@ -36,6 +35,11 @@ import {
TEST_CODE_JS,
} from './constants';

import {
extractScriptId,
URL,
} from './../src/urls';

const { spawnSync } = require('child_process');

describe('Test --help for each function', () => {
Expand Down Expand Up @@ -158,6 +162,13 @@ describe('Test clasp clone <scriptId> function', () => {
after(cleanup);
});

describe('Test extractScriptId function', () => {
it('should return scriptId correctly', () => {
expect(extractScriptId(SCRIPT_ID)).to.equal(SCRIPT_ID);
expect(extractScriptId(URL.SCRIPT(SCRIPT_ID))).to.equal(SCRIPT_ID);
});
});

describe('Test clasp pull function', () => {
before(function () {
if (IS_PR) {
Expand Down

0 comments on commit b0ee106

Please sign in to comment.