Skip to content

Commit

Permalink
improve output for release proposal script (#4897)
Browse files Browse the repository at this point in the history
  • Loading branch information
rochdev authored Nov 18, 2024
1 parent 9de411a commit 2072a1f
Show file tree
Hide file tree
Showing 3 changed files with 254 additions and 93 deletions.
8 changes: 4 additions & 4 deletions scripts/release/helpers/requirements.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

/* eslint-disable max-len */

const { capture, fatal } = require('./terminal')
const { capture, fatal, run } = require('./terminal')

const requiredScopes = ['public_repo', 'read:org']

// Check that the `git` CLI is installed.
function checkGit () {
try {
capture('git --version')
run('git --version')
} catch (e) {
fatal(
'The "git" CLI could not be found.',
Expand All @@ -21,7 +21,7 @@ function checkGit () {
// Check that the `branch-diff` CLI is installed.
function checkBranchDiff () {
try {
capture('branch-diff --version')
run('branch-diff --version')
} catch (e) {
const link = [
'https://datadoghq.atlassian.net/wiki/spaces/DL/pages/3125511269/Node.js+Tracer+Release+Process',
Expand All @@ -47,7 +47,7 @@ function checkGitHub () {
}

try {
capture('gh --version')
run('gh --version')
} catch (e) {
fatal(
'The "gh" CLI could not be found.',
Expand Down
135 changes: 117 additions & 18 deletions scripts/release/helpers/terminal.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,35 @@
'use strict'

/* eslint-disable no-console */

const { execSync, spawnSync } = require('child_process')

// Helpers for colored output.
const log = (...msgs) => msgs.forEach(msg => console.log(msg))
const success = (...msgs) => msgs.forEach(msg => console.log(`\x1b[32m${msg}\x1b[0m`))
const error = (...msgs) => msgs.forEach(msg => console.log(`\x1b[31m${msg}\x1b[0m`))
const whisper = (...msgs) => msgs.forEach(msg => console.log(`\x1b[90m${msg}\x1b[0m`))
const { params, flags } = parse()

// Helpers for exiting with a message.
const exit = (...msgs) => log(...msgs) || process.exit(0)
const fatal = (...msgs) => error(...msgs) || process.exit(1)
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']

// Output a command to the terminal and execute it.
function run (cmd) {
whisper(`> ${cmd}`)
const BOLD = '\x1b[1m'
const CYAN = '\x1b[36m'
const ERASE = '\x1b[0K'
const GRAY = '\x1b[90m'
const GREEN = '\x1b[32m'
const PREVIOUS = '\x1b[1A'
const RED = '\x1b[31m'
const RESET = '\x1b[0m'

const output = execSync(cmd, {}).toString()
const print = (...msgs) => msgs.forEach(msg => process.stdout.write(msg))
const log = (...msgs) => msgs.forEach(msg => print(`${msg}\n`))
const fatal = (...msgs) => log(...msgs) || process.exit(1)

log(output)
let timer
let current

// Output a command to the terminal and execute it.
function run (cmd) {
capture(cmd)
}

// Ask a question in terminal and return the response.
function prompt (question) {
process.stdout.write(`${question} `)
print(`${BOLD}${CYAN}?${RESET} ${BOLD}${question}${RESET} `)

const child = spawnSync('bash', ['-c', 'read answer && echo $answer'], {
stdio: ['inherit']
Expand All @@ -37,15 +41,110 @@ function prompt (question) {
// Ask whether to continue and otherwise exit the process.
function checkpoint (question) {
const answer = prompt(`${question} [Y/n]`).trim()
const prefix = `\r${PREVIOUS}${BOLD}${CYAN}?${RESET}`

question = `${BOLD}${question}${RESET}`

if (answer && answer.toLowerCase() !== 'y') {
print(`\r${prefix} ${question} ${BOLD}${CYAN}No${RESET}${ERASE}\n`)
process.exit(0)
} else {
print(`\r${prefix} ${question} ${BOLD}${CYAN}Yes${RESET}${ERASE}\n`)
}
}

// Run a command and capture its output to return it to the caller.
function capture (cmd) {
return execSync(cmd, {}).toString()
if (flags.debug) {
log(`${GRAY}> ${cmd}${RESET}`)
}

const output = execSync(cmd, { encoding: 'utf8', stdio: 'pipe' }).toString().trim()

if (flags.debug) {
log(output)
}

return output
}

// Start an operation and show a spinner until it reports as passing or failing.
function start (title) {
current = title

spin(0)
}

// Show a spinner for the current operation.
function spin (index) {
if (flags.debug) return

print(`\r${CYAN}${frames[index]}${RESET} ${BOLD}${current}${RESET}`)

timer = setTimeout(spin, 80, index === frames.length - 1 ? 0 : index + 1)
}

// Finish the current operation as passing.
function pass (result) {
if (!current) return

clearTimeout(timer)

if (!flags.debug) {
print(`\r${GREEN}${RESET} ${BOLD}${current}${RESET}`)

if (result) {
print(`: ${BOLD}${CYAN}${result}${RESET}`)
}

print('\n')
}

current = undefined
}

// Finish the current operation as failing.
function fail (err) {
if (!current) return

clearTimeout(timer)

if (!flags.debug) {
print(`\r${RED}${RESET} ${BOLD}${current}${RESET}\n`)
}

current = undefined

throw err
}

// Parse CLI arguments into parameters and flags.
function parse () {
const args = process.argv.slice(2)
const params = []
const flags = {}

for (const arg of args) {
if (arg.startsWith('-')) {
const name = arg.replace(/^-+/, '')
flags[name] = true
} else {
params.push(arg)
}
}

return { params, flags }
}

module.exports = { capture, checkpoint, error, exit, fatal, log, success, run, whisper }
module.exports = {
capture,
checkpoint,
fail,
fatal,
flags,
log,
params,
pass,
run,
start
}
Loading

0 comments on commit 2072a1f

Please sign in to comment.