@google/clasp 2.5.0 → 3.0.0-alpha1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/README.md +251 -196
  2. package/build/src/auth/auth.js +176 -0
  3. package/build/src/auth/auth_code_flow.js +36 -0
  4. package/build/src/auth/credential_store.js +1 -0
  5. package/build/src/auth/file_credential_store.js +82 -0
  6. package/build/src/auth/localhost_auth_code_flow.js +62 -0
  7. package/build/src/auth/serverless_auth_code_flow.js +32 -0
  8. package/build/src/commands/clone-script.js +71 -0
  9. package/build/src/commands/create-deployment.js +33 -0
  10. package/build/src/commands/create-script.js +75 -0
  11. package/build/src/commands/create-version.js +31 -0
  12. package/build/src/commands/delete-deployment.js +71 -0
  13. package/build/src/commands/disable-api.js +19 -0
  14. package/build/src/commands/enable-api.js +31 -0
  15. package/build/src/commands/list-apis.js +23 -0
  16. package/build/src/commands/list-deployments.js +30 -0
  17. package/build/src/commands/list-scripts.js +28 -0
  18. package/build/src/commands/list-versions.js +29 -0
  19. package/build/src/commands/login.js +53 -54
  20. package/build/src/commands/logout.js +15 -15
  21. package/build/src/commands/open-apis.js +11 -0
  22. package/build/src/commands/open-container.js +15 -0
  23. package/build/src/commands/open-credentials.js +11 -0
  24. package/build/src/commands/open-logs.js +11 -0
  25. package/build/src/commands/open-script.js +18 -0
  26. package/build/src/commands/open-webapp.js +56 -0
  27. package/build/src/commands/program.js +108 -0
  28. package/build/src/commands/pull.js +19 -18
  29. package/build/src/commands/push.js +64 -74
  30. package/build/src/commands/run-function.js +61 -0
  31. package/build/src/commands/setup-logs.js +12 -0
  32. package/build/src/commands/show-authorized-user.js +18 -0
  33. package/build/src/commands/show-file-status.js +34 -0
  34. package/build/src/commands/tail-logs.js +92 -0
  35. package/build/src/commands/utils.js +82 -0
  36. package/build/src/constants.js +0 -3
  37. package/build/src/{apis.js → core/apis.js} +90 -92
  38. package/build/src/core/clasp.js +171 -0
  39. package/build/src/core/files.js +359 -0
  40. package/build/src/core/functions.js +51 -0
  41. package/build/src/core/logs.js +41 -0
  42. package/build/src/core/manifest.js +1 -0
  43. package/build/src/core/project.js +313 -0
  44. package/build/src/core/services.js +179 -0
  45. package/build/src/core/utils.js +121 -0
  46. package/build/src/index.js +16 -355
  47. package/build/src/intl.js +34 -0
  48. package/docs/README.md +0 -5
  49. package/docs/config-files.md +0 -1
  50. package/docs/run.md +2 -2
  51. package/package.json +86 -51
  52. package/CHANGELOG.md +0 -79
  53. package/build/src/apis.d.ts +0 -34
  54. package/build/src/apis.js.map +0 -1
  55. package/build/src/apiutils.d.ts +0 -16
  56. package/build/src/apiutils.js +0 -81
  57. package/build/src/apiutils.js.map +0 -1
  58. package/build/src/auth.d.ts +0 -37
  59. package/build/src/auth.js +0 -310
  60. package/build/src/auth.js.map +0 -1
  61. package/build/src/clasp-error.d.ts +0 -3
  62. package/build/src/clasp-error.js +0 -10
  63. package/build/src/clasp-error.js.map +0 -1
  64. package/build/src/commands/apis.d.ts +0 -10
  65. package/build/src/commands/apis.js +0 -90
  66. package/build/src/commands/apis.js.map +0 -1
  67. package/build/src/commands/clone.d.ts +0 -13
  68. package/build/src/commands/clone.js +0 -60
  69. package/build/src/commands/clone.js.map +0 -1
  70. package/build/src/commands/create.d.ts +0 -16
  71. package/build/src/commands/create.js +0 -81
  72. package/build/src/commands/create.js.map +0 -1
  73. package/build/src/commands/default.d.ts +0 -8
  74. package/build/src/commands/default.js +0 -10
  75. package/build/src/commands/default.js.map +0 -1
  76. package/build/src/commands/deploy.d.ts +0 -13
  77. package/build/src/commands/deploy.js +0 -51
  78. package/build/src/commands/deploy.js.map +0 -1
  79. package/build/src/commands/deployments.d.ts +0 -5
  80. package/build/src/commands/deployments.js +0 -29
  81. package/build/src/commands/deployments.js.map +0 -1
  82. package/build/src/commands/list.d.ts +0 -9
  83. package/build/src/commands/list.js +0 -34
  84. package/build/src/commands/list.js.map +0 -1
  85. package/build/src/commands/login.d.ts +0 -15
  86. package/build/src/commands/login.js.map +0 -1
  87. package/build/src/commands/logout.d.ts +0 -5
  88. package/build/src/commands/logout.js.map +0 -1
  89. package/build/src/commands/logs.d.ts +0 -17
  90. package/build/src/commands/logs.js +0 -181
  91. package/build/src/commands/logs.js.map +0 -1
  92. package/build/src/commands/open.d.ts +0 -15
  93. package/build/src/commands/open.js +0 -89
  94. package/build/src/commands/open.js.map +0 -1
  95. package/build/src/commands/pull.d.ts +0 -10
  96. package/build/src/commands/pull.js.map +0 -1
  97. package/build/src/commands/push.d.ts +0 -11
  98. package/build/src/commands/push.js.map +0 -1
  99. package/build/src/commands/run.d.ts +0 -14
  100. package/build/src/commands/run.js +0 -130
  101. package/build/src/commands/run.js.map +0 -1
  102. package/build/src/commands/setting.d.ts +0 -8
  103. package/build/src/commands/setting.js +0 -53
  104. package/build/src/commands/setting.js.map +0 -1
  105. package/build/src/commands/status.d.ts +0 -9
  106. package/build/src/commands/status.js +0 -25
  107. package/build/src/commands/status.js.map +0 -1
  108. package/build/src/commands/undeploy.d.ts +0 -9
  109. package/build/src/commands/undeploy.js +0 -55
  110. package/build/src/commands/undeploy.js.map +0 -1
  111. package/build/src/commands/version.d.ts +0 -5
  112. package/build/src/commands/version.js +0 -22
  113. package/build/src/commands/version.js.map +0 -1
  114. package/build/src/commands/versions.d.ts +0 -5
  115. package/build/src/commands/versions.js +0 -41
  116. package/build/src/commands/versions.js.map +0 -1
  117. package/build/src/conf.d.ts +0 -40
  118. package/build/src/conf.js +0 -100
  119. package/build/src/conf.js.map +0 -1
  120. package/build/src/constants.d.ts +0 -6
  121. package/build/src/constants.js.map +0 -1
  122. package/build/src/dotfile.d.ts +0 -50
  123. package/build/src/dotfile.js +0 -71
  124. package/build/src/dotfile.js.map +0 -1
  125. package/build/src/files.d.ts +0 -70
  126. package/build/src/files.js +0 -364
  127. package/build/src/files.js.map +0 -1
  128. package/build/src/index.d.ts +0 -18
  129. package/build/src/index.js.map +0 -1
  130. package/build/src/inquirer.d.ts +0 -82
  131. package/build/src/inquirer.js +0 -111
  132. package/build/src/inquirer.js.map +0 -1
  133. package/build/src/manifest.d.ts +0 -123
  134. package/build/src/manifest.js +0 -142
  135. package/build/src/manifest.js.map +0 -1
  136. package/build/src/messages.d.ts +0 -110
  137. package/build/src/messages.js +0 -161
  138. package/build/src/messages.js.map +0 -1
  139. package/build/src/urls.d.ts +0 -21
  140. package/build/src/urls.js +0 -33
  141. package/build/src/urls.js.map +0 -1
  142. package/build/src/utils.d.ts +0 -102
  143. package/build/src/utils.js +0 -232
  144. package/build/src/utils.js.map +0 -1
  145. package/docs/develop.md +0 -94
  146. package/docs/esmodules.md +0 -81
  147. package/docs/running-locally.md +0 -31
  148. package/docs/settings.md +0 -56
  149. package/docs/typescript.md +0 -354
@@ -1,18 +1,19 @@
1
- import { fetchProject, writeProjectFiles } from '../files.js';
2
- import { LOG } from '../messages.js';
3
- import { getProjectSettings, spinner, stopSpinner } from '../utils.js';
4
- /**
5
- * Force downloads all Apps Script project files into the local filesystem.
6
- * @param options.versionNumber {number} The version number of the project to retrieve.
7
- * If not provided, the project's HEAD version is returned.
8
- */
9
- export default async (options) => {
10
- const { scriptId, rootDir } = await getProjectSettings();
11
- if (scriptId) {
12
- spinner.start(LOG.PULLING);
13
- const files = await fetchProject(scriptId, options.versionNumber);
14
- await writeProjectFiles(files, rootDir);
15
- stopSpinner();
16
- }
17
- };
18
- //# sourceMappingURL=pull.js.map
1
+ import { Command } from 'commander';
2
+ import { intl } from '../intl.js';
3
+ import { withSpinner } from './utils.js';
4
+ export const command = new Command('pull')
5
+ .description('Fetch a remote project')
6
+ .option('--versionNumber <version>', 'The version number of the project to retrieve.')
7
+ .action(async function (options) {
8
+ const clasp = this.opts().clasp;
9
+ const versionNumber = options.versionNumber;
10
+ const spinnerMsg = intl.formatMessage({ id: "jilcJH", defaultMessage: [{ type: 0, value: "Pulling files..." }] });
11
+ const files = await withSpinner(spinnerMsg, async () => {
12
+ return await clasp.files.pull(versionNumber);
13
+ });
14
+ files.forEach(f => console.log(`└─ ${f.localPath}`));
15
+ const successMessage = intl.formatMessage({ id: "4mRAfN", defaultMessage: [{ type: 0, value: "Pulled " }, { type: 6, value: "count", options: { "=0": { value: [{ type: 0, value: "no files." }] }, one: { value: [{ type: 0, value: "one file." }] }, other: { value: [{ type: 7 }, { type: 0, value: " files" }] } }, offset: 0, pluralType: "cardinal" }, { type: 0, value: "." }] }, {
16
+ count: files.length,
17
+ });
18
+ console.log(successMessage);
19
+ });
@@ -1,84 +1,74 @@
1
- import fs from 'fs-extra';
2
- import multimatch from 'multimatch';
3
- import normalizeNewline from 'normalize-newline';
4
1
  import path from 'path';
5
- import chokidar from 'chokidar';
6
- import debouncePkg from 'debounce';
7
- import { loadAPICredentials } from '../auth.js';
8
- import { ClaspError } from '../clasp-error.js';
9
- import { Conf } from '../conf.js';
10
- import { FS_OPTIONS, PROJECT_MANIFEST_BASENAME, PROJECT_MANIFEST_FILENAME } from '../constants.js';
11
- import { DOTFILE } from '../dotfile.js';
12
- import { fetchProject, pushFiles } from '../files.js';
13
- import { overwritePrompt } from '../inquirer.js';
14
- import { isValidManifest } from '../manifest.js';
15
- import { LOG } from '../messages.js';
16
- import { getProjectSettings, spinner } from '../utils.js';
17
- const { debounce } = debouncePkg;
18
- const { readFileSync } = fs;
19
- const WATCH_DEBOUNCE_MS = 1000;
20
- const config = Conf.get();
21
- /**
22
- * Uploads all files into the script.google.com filesystem.
23
- * TODO: Only push the specific files that changed (rather than all files).
24
- * @param options.watch {boolean} If true, runs `clasp push` when any local file changes. Exit with ^C.
25
- */
26
- export default async (options) => {
27
- await loadAPICredentials();
28
- await isValidManifest();
29
- const projectSettings = await getProjectSettings();
30
- const { rootDir = '.' } = projectSettings;
31
- if (options.watch) {
32
- console.log(LOG.PUSH_WATCH);
33
- // Debounce calls to push to coalesce 'save all' actions from editors
34
- const debouncedPushFiles = debounce(async () => {
35
- if (!options.force && (await manifestHasChanges(projectSettings)) && !(await confirmManifestUpdate())) {
36
- console.log('Stopping push…');
37
- return;
2
+ import { Command } from 'commander';
3
+ import inquirer from 'inquirer';
4
+ import { intl } from '../intl.js';
5
+ import { isInteractive, withSpinner } from './utils.js';
6
+ export const command = new Command('push')
7
+ .description('Update the remote project')
8
+ .option('-f, --force', 'Forcibly overwrites the remote manifest.')
9
+ .option('-w, --watch', 'Watches for local file changes. Pushes when a non-ignored file changes.')
10
+ .action(async function (options) {
11
+ const clasp = this.opts().clasp;
12
+ const watch = options.watch;
13
+ let force = options.force;
14
+ const onChange = async (paths) => {
15
+ const isManifestUpdated = paths.findIndex(p => path.basename(p) === 'appsscript.json') !== -1;
16
+ if (isManifestUpdated && !force) {
17
+ force = await confirmManifestUpdate();
18
+ if (!force) {
19
+ const msg = intl.formatMessage({ id: "TItFfu", defaultMessage: [{ type: 0, value: "Skipping push." }] });
20
+ console.log(msg);
38
21
  }
39
- console.log(LOG.PUSHING);
40
- return pushFiles();
41
- }, WATCH_DEBOUNCE_MS);
42
- const patterns = await DOTFILE.IGNORE();
43
- const watchCallback = async (filePath) => {
44
- if (multimatch([filePath], patterns, { dot: true }).length > 0) {
45
- // The file matches the ignored files patterns so we do nothing
46
- return;
47
- }
48
- console.log(`\n${LOG.PUSH_WATCH_UPDATED(filePath)}\n`);
49
- return debouncedPushFiles();
50
- };
51
- const watcher = chokidar.watch(rootDir, { persistent: true, ignoreInitial: true });
52
- watcher.on('ready', pushFiles); // Push on start
53
- watcher.on('add', watchCallback);
54
- watcher.on('change', watchCallback);
55
- watcher.on('unlink', watchCallback);
56
- return;
22
+ }
23
+ const spinnerMsg = intl.formatMessage({ id: "qUq++d", defaultMessage: [{ type: 0, value: "Pushing files..." }] });
24
+ const files = await withSpinner(spinnerMsg, async () => {
25
+ return await clasp.files.push();
26
+ });
27
+ const successMessage = intl.formatMessage({ id: "aD3XSt", defaultMessage: [{ type: 0, value: "Pushed " }, { type: 6, value: "count", options: { "=0": { value: [{ type: 0, value: "no files." }] }, one: { value: [{ type: 0, value: "one file." }] }, other: { value: [{ type: 7 }, { type: 0, value: " files" }] } }, offset: 0, pluralType: "cardinal" }, { type: 0, value: "." }] }, {
28
+ count: files.length,
29
+ });
30
+ console.log(successMessage);
31
+ files.forEach(f => console.log(`└─ ${f.localPath}`));
32
+ return true;
33
+ };
34
+ const pendingChanges = await clasp.files.getChangedFiles();
35
+ if (pendingChanges.length) {
36
+ const paths = pendingChanges.map(f => f.localPath);
37
+ await onChange(paths);
57
38
  }
58
- if (!options.force && (await manifestHasChanges(projectSettings)) && !(await confirmManifestUpdate())) {
59
- console.log('Stopping push…');
39
+ else {
40
+ const msg = intl.formatMessage({ id: "X/QgBZ", defaultMessage: [{ type: 0, value: "Script is already up to date." }] });
41
+ console.log(msg);
42
+ }
43
+ if (!watch) {
60
44
  return;
61
45
  }
62
- spinner.start(LOG.PUSHING);
63
- await pushFiles();
64
- };
46
+ const onReady = async () => {
47
+ const msg = intl.formatMessage({ id: "m/C0lF", defaultMessage: [{ type: 0, value: "Waiting for changes..." }] });
48
+ console.log(msg);
49
+ };
50
+ const stopWatching = clasp.files.watchLocalFiles(onReady, async (paths) => {
51
+ if (!(await onChange(paths))) {
52
+ stopWatching();
53
+ }
54
+ });
55
+ });
65
56
  /**
66
57
  * Confirms that the manifest file has been updated.
67
58
  * @returns {Promise<boolean>}
68
59
  */
69
- const confirmManifestUpdate = async () => (await overwritePrompt()).overwrite;
70
- /**
71
- * Checks if the manifest has changes.
72
- * @returns {Promise<boolean>}
73
- */
74
- const manifestHasChanges = async (projectSettings) => {
75
- const { scriptId, rootDir = config.projectRootDirectory } = projectSettings;
76
- const localManifest = readFileSync(path.join(rootDir, PROJECT_MANIFEST_FILENAME), FS_OPTIONS);
77
- const remoteFiles = await fetchProject(scriptId, undefined, true);
78
- const remoteManifest = remoteFiles.find(file => file.name === PROJECT_MANIFEST_BASENAME);
79
- if (remoteManifest) {
80
- return normalizeNewline(localManifest) !== normalizeNewline(remoteManifest.source);
60
+ async function confirmManifestUpdate() {
61
+ if (!isInteractive()) {
62
+ return false;
81
63
  }
82
- throw new ClaspError('remote manifest no found');
83
- };
84
- //# sourceMappingURL=push.js.map
64
+ const prompt = intl.formatMessage({ id: "Dh7naZ", defaultMessage: [{ type: 0, value: "Manifest file has been updated. Do you want to push and overwrite?" }] });
65
+ const answer = await inquirer.prompt([
66
+ {
67
+ default: false,
68
+ message: prompt,
69
+ name: 'overwrite',
70
+ type: 'confirm',
71
+ },
72
+ ]);
73
+ return answer.overwrite;
74
+ }
@@ -0,0 +1,61 @@
1
+ import chalk from 'chalk';
2
+ import { Command } from 'commander';
3
+ import fuzzy from 'fuzzy';
4
+ import autocomplete from 'inquirer-autocomplete-standalone';
5
+ import { intl } from '../intl.js';
6
+ import { isInteractive, withSpinner } from './utils.js';
7
+ export const command = new Command('run-function')
8
+ .alias('run')
9
+ .description('Run a function in your Apps Scripts project')
10
+ .argument('[functionName]', 'The name of the function to run')
11
+ .option('--nondev', 'Run script function in non-devMode')
12
+ .option('-p, --params <value>', 'Parameters to pass to the function, as a JSON-encoded array')
13
+ .action(async function (functionName, options) {
14
+ var _a, _b;
15
+ const clasp = this.opts().clasp;
16
+ const devMode = !options.nondev; // Defaults to true
17
+ let params = [];
18
+ if (options.params) {
19
+ params = JSON.parse(options.params);
20
+ }
21
+ if (!functionName && isInteractive()) {
22
+ const allFunctions = await clasp.functions.getFunctionNames();
23
+ const source = async (input = '') => fuzzy.filter(input, allFunctions).map(element => ({
24
+ value: element.original,
25
+ }));
26
+ const prompt = intl.formatMessage({ id: "Y8u3Vb", defaultMessage: [{ type: 0, value: "Selection a function name" }] });
27
+ functionName = await autocomplete({
28
+ message: prompt,
29
+ source,
30
+ });
31
+ }
32
+ try {
33
+ const { error, response } = await withSpinner(`Running function: ${functionName}`, async () => {
34
+ return await clasp.functions.runFunction(functionName, params, devMode);
35
+ });
36
+ if (error && error.details) {
37
+ const { errorMessage, scriptStackTraceElements } = error.details[0];
38
+ const msg = intl.formatMessage({ id: "1l462L", defaultMessage: [{ type: 0, value: "Exception:" }] });
39
+ console.error(`${chalk.red(msg)}`, errorMessage, scriptStackTraceElements || []);
40
+ return;
41
+ }
42
+ if (response && response.result) {
43
+ console.log(response.result);
44
+ }
45
+ else {
46
+ const msg = intl.formatMessage({ id: "S/0IKk", defaultMessage: [{ type: 0, value: "No response." }] });
47
+ console.log(chalk.red(msg));
48
+ }
49
+ }
50
+ catch (error) {
51
+ if (((_a = error.cause) === null || _a === void 0 ? void 0 : _a.code) === 'NOT_AUTHORIZED') {
52
+ const msg = intl.formatMessage({ id: "HZmND2", defaultMessage: [{ type: 0, value: "Unable to run script function. Please make sure you have permission to run the script function." }] });
53
+ this.error(msg);
54
+ }
55
+ if (((_b = error.cause) === null || _b === void 0 ? void 0 : _b.code) === 'NOT_FOUND') {
56
+ const msg = intl.formatMessage({ id: "4wxpit", defaultMessage: [{ type: 0, value: "Script function not found. Please make sure script is deployed as API executable." }] });
57
+ this.error(msg);
58
+ }
59
+ throw error;
60
+ }
61
+ });
@@ -0,0 +1,12 @@
1
+ import { Command } from 'commander';
2
+ import { intl } from '../intl.js';
3
+ import { assertGcpProjectConfigured, isInteractive, maybePromptForProjectId } from './utils.js';
4
+ export const command = new Command('setup-logs').description('Setup Cloud Logging').action(async function () {
5
+ const clasp = this.opts().clasp;
6
+ if (!clasp.project.projectId && isInteractive()) {
7
+ await maybePromptForProjectId(clasp);
8
+ }
9
+ assertGcpProjectConfigured(clasp);
10
+ const successMessage = intl.formatMessage({ id: "mrsf6I", defaultMessage: [{ type: 0, value: "Script logs are now available in Cloud Logging." }] });
11
+ console.log(successMessage);
12
+ });
@@ -0,0 +1,18 @@
1
+ import { Command } from 'commander';
2
+ import { getUserInfo } from '../auth/auth.js';
3
+ import { intl } from '../intl.js';
4
+ export const command = new Command('show-authorized-user')
5
+ .description('Show information about the current authorizations state.')
6
+ .action(async function () {
7
+ const auth = this.opts().auth;
8
+ if (!auth.credentials) {
9
+ const msg = intl.formatMessage({ id: "ZqMsgV", defaultMessage: [{ type: 0, value: "Not logged in." }] });
10
+ console.log(msg);
11
+ return;
12
+ }
13
+ const user = await getUserInfo(auth.credentials);
14
+ const msg = intl.formatMessage({ id: "sZ9k34", defaultMessage: [{ type: 5, value: "email", options: { undefined: { value: [{ type: 0, value: "You are logged in as an unknown user." }] }, other: { value: [{ type: 0, value: "You are logged in as " }, { type: 1, value: "email" }, { type: 0, value: "." }] } } }] }, {
15
+ email: user === null || user === void 0 ? void 0 : user.email,
16
+ });
17
+ console.log(msg);
18
+ });
@@ -0,0 +1,34 @@
1
+ import { Command } from 'commander';
2
+ import { intl } from '../intl.js';
3
+ import { withSpinner } from './utils.js';
4
+ export const command = new Command('show-file-status')
5
+ .alias('status')
6
+ .description('Lists files that will be pushed by clasp')
7
+ .option('--json', 'Show status in JSON form')
8
+ .action(async function (options) {
9
+ var _a;
10
+ const clasp = this.opts().clasp;
11
+ const outputAsJson = (_a = options === null || options === void 0 ? void 0 : options.json) !== null && _a !== void 0 ? _a : false;
12
+ const spinnerMsg = intl.formatMessage({ id: "3pOneN", defaultMessage: [{ type: 0, value: "Analyzing project files..." }] });
13
+ const [filesToPush, untrackedFiles] = await withSpinner(spinnerMsg, async () => {
14
+ return await Promise.all([clasp.files.collectLocalFiles(), clasp.files.getUntrackedFiles()]);
15
+ });
16
+ if (outputAsJson) {
17
+ const json = JSON.stringify({
18
+ filesToPush: filesToPush.map(f => f.localPath),
19
+ untrackedFiles,
20
+ });
21
+ console.log(json);
22
+ return;
23
+ }
24
+ const trackedMsg = intl.formatMessage({ id: "eSUzih", defaultMessage: [{ type: 0, value: "Tracked files:" }] });
25
+ console.log(trackedMsg);
26
+ for (const file of filesToPush) {
27
+ console.log(`└─ ${file.localPath}`);
28
+ }
29
+ const untrackedMsg = intl.formatMessage({ id: "G6KFcG", defaultMessage: [{ type: 0, value: "Untracked files:" }] });
30
+ console.log(untrackedMsg);
31
+ for (const file of untrackedFiles) {
32
+ console.log(`└─ ${file}`);
33
+ }
34
+ });
@@ -0,0 +1,92 @@
1
+ import chalk from 'chalk';
2
+ import { Command } from 'commander';
3
+ import { intl } from '../intl.js';
4
+ import { assertGcpProjectConfigured, isInteractive, maybePromptForProjectId, withSpinner } from './utils.js';
5
+ export const command = new Command('tail-logs')
6
+ .alias('logs')
7
+ .description('Print the most recent log entries')
8
+ .option('--json', 'Show logs in JSON form')
9
+ .option('--watch', 'Watch and print new logs')
10
+ .option('--simplified', 'Hide timestamps with logs')
11
+ .action(async function (options) {
12
+ const clasp = this.opts().clasp;
13
+ const { json, simplified, watch } = options;
14
+ const seenEntries = new Set();
15
+ let since;
16
+ const fetchAndPrintLogs = async () => {
17
+ const spinnerMsg = intl.formatMessage({ id: "VtwoAE", defaultMessage: [{ type: 0, value: "Fetching logs..." }] });
18
+ const entries = await withSpinner(spinnerMsg, async () => await clasp.logs.getLogEntries(since));
19
+ entries.results.reverse().forEach(entry => {
20
+ if (entry.timestamp) {
21
+ since = new Date(entry.timestamp);
22
+ }
23
+ const id = entry.insertId;
24
+ if (!id) {
25
+ return;
26
+ }
27
+ if (seenEntries.has(id)) {
28
+ return;
29
+ }
30
+ seenEntries.add(id);
31
+ const msg = formatEntry(entry, {
32
+ json,
33
+ simplified,
34
+ });
35
+ if (msg) {
36
+ console.log(msg);
37
+ }
38
+ });
39
+ };
40
+ if (!clasp.project.projectId && isInteractive()) {
41
+ await maybePromptForProjectId(clasp);
42
+ }
43
+ assertGcpProjectConfigured(clasp);
44
+ await fetchAndPrintLogs();
45
+ if (watch) {
46
+ const POLL_INTERVAL = 6000; // 6s
47
+ setInterval(async () => {
48
+ await fetchAndPrintLogs();
49
+ }, POLL_INTERVAL);
50
+ }
51
+ });
52
+ const severityColor = {
53
+ ERROR: chalk.red,
54
+ INFO: chalk.cyan,
55
+ DEBUG: chalk.green, // Includes timeEnd
56
+ NOTICE: chalk.magenta,
57
+ WARNING: chalk.yellow,
58
+ };
59
+ function formatEntry(entry, options) {
60
+ var _a, _b;
61
+ const { severity = '', timestamp = '', resource } = entry;
62
+ if (!resource) {
63
+ return undefined;
64
+ }
65
+ let functionName = (_b = (_a = resource.labels) === null || _a === void 0 ? void 0 : _a['function_name']) !== null && _b !== void 0 ? _b : 'N/A';
66
+ let payloadData = '';
67
+ if (options.json) {
68
+ payloadData = JSON.stringify(entry, null, 2);
69
+ }
70
+ else {
71
+ const { jsonPayload, textPayload } = entry;
72
+ if (textPayload) {
73
+ payloadData = textPayload;
74
+ }
75
+ else if (jsonPayload && jsonPayload.message) {
76
+ payloadData = jsonPayload.message;
77
+ }
78
+ else if (jsonPayload) {
79
+ payloadData = JSON.stringify(jsonPayload);
80
+ }
81
+ else {
82
+ return undefined;
83
+ }
84
+ }
85
+ const coloredSeverity = `${severityColor[severity](severity) || severity}`.padEnd(20);
86
+ functionName = functionName.padEnd(15);
87
+ payloadData = payloadData.padEnd(20);
88
+ if (options.simplified) {
89
+ return `${coloredSeverity} ${functionName} ${payloadData}`;
90
+ }
91
+ return `${coloredSeverity} ${timestamp} ${functionName} ${payloadData}`;
92
+ }
@@ -0,0 +1,82 @@
1
+ import cliTruncate from 'cli-truncate';
2
+ import inquirer from 'inquirer';
3
+ import open from 'open';
4
+ import ora from 'ora';
5
+ import { intl } from '../intl.js';
6
+ export async function assertScriptConfigured(clasp) {
7
+ if (clasp.project.scriptId) {
8
+ return;
9
+ }
10
+ const msg = intl.formatMessage({ id: "2IuvqO", defaultMessage: [{ type: 0, value: "Script ID is not set, unable to continue." }] });
11
+ throw new Error(msg);
12
+ }
13
+ export async function assertGcpProjectConfigured(clasp) {
14
+ if (clasp.project.projectId) {
15
+ return;
16
+ }
17
+ const msg = intl.formatMessage({ id: "aD3+By", defaultMessage: [{ type: 0, value: "GCP project ID is not set, unable to continue." }] });
18
+ throw new Error(msg);
19
+ }
20
+ export async function maybePromptForProjectId(clasp) {
21
+ let projectId = clasp.project.getProjectId();
22
+ if (!projectId && isInteractive()) {
23
+ assertScriptConfigured(clasp);
24
+ const url = `https://script.google.com/home/projects/${clasp.project.scriptId}/settings`;
25
+ const instructions = intl.formatMessage({ id: "9gtRgW", defaultMessage: [{ type: 0, value: "The script is not bound to a GCP project. To view or configure the GCP project for this script, open " }, { type: 1, value: "url" }, { type: 0, value: " in your browser and follow instructions for setting up a GCP project. If a project is already configured, open the GCP project to get the project ID value." }] }, {
26
+ url,
27
+ });
28
+ console.log(instructions);
29
+ await openUrl(url);
30
+ const prompt = intl.formatMessage({ id: "Zde2DB", defaultMessage: [{ type: 0, value: "What is your GCP projectId?" }] });
31
+ const answer = await inquirer.prompt([
32
+ {
33
+ message: prompt,
34
+ name: 'projectId',
35
+ type: 'input',
36
+ },
37
+ ]);
38
+ projectId = answer.projectId;
39
+ await clasp.project.setProjectId(projectId);
40
+ }
41
+ return projectId;
42
+ }
43
+ const spinner = ora();
44
+ export async function withSpinner(message, fn) {
45
+ // If not interactive terminal, skip spinner
46
+ if (!isInteractive()) {
47
+ return await fn();
48
+ }
49
+ spinner.start(message);
50
+ try {
51
+ return await fn();
52
+ }
53
+ finally {
54
+ if (spinner.isSpinning) {
55
+ spinner.stop();
56
+ }
57
+ }
58
+ }
59
+ export function ellipsize(value, length) {
60
+ return cliTruncate(value, length, { preferTruncationOnSpace: true }).padEnd(length);
61
+ }
62
+ // Exporting and wrapping to allow it to be toggled in tests
63
+ export const claspEnv = {
64
+ isInteractive: process.stdout.isTTY
65
+ };
66
+ export function isInteractive() {
67
+ return claspEnv.isInteractive;
68
+ }
69
+ export async function openUrl(url) {
70
+ if (!isInteractive()) {
71
+ const msg = intl.formatMessage({ id: "kvR0OI", defaultMessage: [{ type: 0, value: "Open " }, { type: 1, value: "url" }, { type: 0, value: " in your browser to continue." }] }, {
72
+ url,
73
+ });
74
+ console.log(msg);
75
+ return;
76
+ }
77
+ const msg = intl.formatMessage({ id: "IVffJ2", defaultMessage: [{ type: 0, value: "Opening " }, { type: 1, value: "url" }, { type: 0, value: " in your browser." }] }, {
78
+ url,
79
+ });
80
+ console.log(msg);
81
+ return await open(url, { wait: false });
82
+ }
@@ -1,7 +1,4 @@
1
- // @see https://nodejs.org/api/fs.html#fs_fs_readfilesync_path_options
2
- export const FS_OPTIONS = { encoding: 'utf8' };
3
1
  // Names / Paths
4
2
  export const PROJECT_NAME = 'clasp';
5
3
  export const PROJECT_MANIFEST_BASENAME = 'appsscript';
6
4
  export const PROJECT_MANIFEST_FILENAME = `${PROJECT_MANIFEST_BASENAME}.json`;
7
- //# sourceMappingURL=constants.js.map