-
-
Notifications
You must be signed in to change notification settings - Fork 243
ci: Add a new option silentLogs for cleaner CI/build output
#2563
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -287,11 +287,17 @@ function getPath() { | |||||
| * - `'rejectOnError'` to inherit stdio and reject the promise if the command | ||||||
| * exits with a non-zero exit code. | ||||||
| * @param {boolean} silent Disable stdout for silents build (CI/Webpack Stats, ...) | ||||||
| * @param {boolean} silentLogs Show only errors and success messages, hide verbose logs | ||||||
| * @param {string} [configFile] Relative or absolute path to the configuration file. | ||||||
| * @param {Object} [config] More configuration to pass to the CLI | ||||||
| * @returns {Promise.<string>} A promise that resolves to the standard output. | ||||||
| */ | ||||||
| async function execute(args, live, silent, configFile, config = {}) { | ||||||
| async function execute(args, live, silent, silentLogs, configFile, config = {}) { | ||||||
| // Ensure silent takes precedence over silentLogs | ||||||
| if (silent) { | ||||||
| silentLogs = false; | ||||||
| } | ||||||
|
|
||||||
| const env = { ...process.env }; | ||||||
| if (configFile) { | ||||||
| env.SENTRY_PROPERTIES = configFile; | ||||||
|
|
@@ -329,19 +335,47 @@ async function execute(args, live, silent, configFile, config = {}) { | |||||
|
|
||||||
| return new Promise((resolve, reject) => { | ||||||
| if (live === true || live === 'rejectOnError') { | ||||||
| const output = silent ? 'ignore' : 'inherit'; | ||||||
| // Configure stdio options for child process based on settings | ||||||
| // TypeScript needs explicit typing for stdio options | ||||||
| /** @type {('ignore' | 'pipe' | 'inherit')[]} */ | ||||||
| let stdio; | ||||||
| if (silent) { | ||||||
| // Complete silence | ||||||
| stdio = ['ignore', 'ignore', 'ignore']; | ||||||
| } else if (silentLogs && live !== 'rejectOnError') { | ||||||
| // Capture stdout to filter it, but show stderr for errors | ||||||
| // Not applicable for rejectOnError mode which needs to capture output | ||||||
| stdio = ['ignore', 'pipe', 'inherit']; | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: Sentry CLI Hangs on Unread Piped OutputWhen |
||||||
| } else { | ||||||
| // Show everything (default behavior) | ||||||
| stdio = ['ignore', 'inherit', 'inherit']; | ||||||
| } | ||||||
|
|
||||||
| const pid = childProcess.spawn(getPath(), args, { | ||||||
| env, | ||||||
| // stdin, stdout, stderr | ||||||
| stdio: ['ignore', output, output], | ||||||
| stdio, | ||||||
| }); | ||||||
|
|
||||||
| pid.on('exit', (exitCode) => { | ||||||
| if (live === 'rejectOnError') { | ||||||
| if (exitCode === 0) { | ||||||
| resolve('success (live mode)'); | ||||||
| } else { | ||||||
| reject(new Error(`Command ${args.join(' ')} failed with exit code ${exitCode}`)); | ||||||
| } | ||||||
| reject(new Error(`Command ${args.join(' ')} failed with exit code ${exitCode}`)); | ||||||
| return; | ||||||
| } | ||||||
|
|
||||||
| if (silentLogs && exitCode === 0) { | ||||||
| const successMessage = determineSuccessMessage(args); | ||||||
| if (successMessage) { | ||||||
| console.info(successMessage); | ||||||
| } | ||||||
| resolve(''); | ||||||
| return; | ||||||
| } | ||||||
|
|
||||||
| // Default case | ||||||
| // According to the type definition, resolving with void is not allowed. | ||||||
| // However, for backwards compatibility, we resolve void here to | ||||||
| // avoid a behaviour-breaking change. | ||||||
|
|
@@ -354,7 +388,15 @@ async function execute(args, live, silent, configFile, config = {}) { | |||||
| if (err) { | ||||||
| reject(err); | ||||||
| } else { | ||||||
| resolve(stdout); | ||||||
| if (silentLogs) { | ||||||
| const successMessage = determineSuccessMessage(args); | ||||||
| if (successMessage) { | ||||||
| console.info(successMessage); | ||||||
| } | ||||||
| resolve(''); | ||||||
| } else { | ||||||
| resolve(silent ? '' : stdout); | ||||||
| } | ||||||
| } | ||||||
| }); | ||||||
| } | ||||||
|
|
@@ -365,6 +407,73 @@ function getProjectFlagsFromOptions({ projects = [] } = {}) { | |||||
| return projects.reduce((flags, project) => flags.concat('-p', project), []); | ||||||
| } | ||||||
|
|
||||||
| /** | ||||||
| * Determines an appropriate success message based on the command. | ||||||
| * | ||||||
| * @param {string[]} args Command line arguments passed to sentry-cli | ||||||
| * @returns {string|null} Success message to display or null if no message needed | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe it is preferable to type this just as string, using empty string instead of null? Not sure how we typically do it in JS, so I'll defer to you on this.
Suggested change
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Returning null expresses that "there is no success message to show" rather than "the success message is empty". |
||||||
| */ | ||||||
| function determineSuccessMessage(args) { | ||||||
| if (!args || args.length === 0) { | ||||||
| return null; | ||||||
| } | ||||||
|
|
||||||
| const command = args[0]; | ||||||
|
|
||||||
| // Only show success messages for high-impact operations customers care about | ||||||
| switch (command) { | ||||||
| case 'releases': | ||||||
| if (args[1] === 'new' && args[2]) { | ||||||
| return `✓ Release ${args[2]} created`; | ||||||
| } else if (args[1] === 'finalize' && args[2]) { | ||||||
| return `✓ Release ${args[2]} finalized`; | ||||||
| } else if (args[1] === 'files' && args[3] === 'upload-sourcemaps') { | ||||||
| return `✓ Source maps uploaded`; | ||||||
| } | ||||||
| break; | ||||||
|
|
||||||
| case 'sourcemaps': | ||||||
| if (args[1] === 'upload') { | ||||||
| return `✓ Source maps uploaded`; | ||||||
| } else if (args[1] === 'inject') { | ||||||
| return `✓ Source maps injected`; | ||||||
| } | ||||||
| break; | ||||||
|
|
||||||
| case 'debug-files': | ||||||
| if (args[1] === 'upload') { | ||||||
| return `✓ Debug files uploaded`; | ||||||
| } | ||||||
| break; | ||||||
|
|
||||||
| case 'upload-proguard': | ||||||
| return `✓ ProGuard mappings uploaded`; | ||||||
|
|
||||||
| case 'upload-dif': | ||||||
| case 'upload-dsym': | ||||||
| return `✓ Debug information files uploaded`; | ||||||
|
|
||||||
| case 'deploys': | ||||||
| if (args[1] === 'new') { | ||||||
| return `✓ Deploy created`; | ||||||
| } | ||||||
| break; | ||||||
|
|
||||||
| case 'send-event': | ||||||
| return `✓ Event sent`; | ||||||
|
|
||||||
| case 'send-envelope': | ||||||
| return `✓ Envelope sent`; | ||||||
|
|
||||||
| // Don't show success messages for info/list operations - they show their own output | ||||||
| // Don't show for --version, --help - the output is the success | ||||||
| default: | ||||||
| return null; | ||||||
| } | ||||||
|
|
||||||
| return null; | ||||||
| } | ||||||
|
|
||||||
| module.exports = { | ||||||
| execute, | ||||||
| getPath, | ||||||
|
|
@@ -375,4 +484,5 @@ module.exports = { | |||||
| getDistributionForThisPlatform, | ||||||
| throwUnsupportedPlatformError, | ||||||
| getFallbackBinaryPath, | ||||||
| determineSuccessMessage, | ||||||
| }; | ||||||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this part of public API?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think users should only use the execute method provided by the SentryCli class