1
0
mirror of synced 2025-12-19 09:57:42 -05:00

docstat quiet option (#58812)

This commit is contained in:
Sarah Schneider
2025-12-10 16:33:36 -05:00
committed by GitHub
parent 53f5acfb26
commit e7b6146b90
5 changed files with 130 additions and 130 deletions

View File

@@ -11,9 +11,66 @@ CLI tools to fetch data from the Kusto API.
1. Enter your `<username>@githubazure.com` credentials.
* These will get cached for future logins.
1. At the prompt in Terminal asking which subscription you want to use, just press Enter to choose the default.
1. Open or create an `.env` file in the root directory of your checkout (this file is already in `.gitignore`).
1. Add the `KUSTO_CLUSTER` and `KUSTO_DATABASE` values to the `.env`.
1. Open or create an `.env` file in the root directory of your checkout (this file is already in `.gitignore` so it won't be tracked by Git).
1. Add the `KUSTO_CLUSTER` and `KUSTO_DATABASE` values to the `.env` (_these values are pinned in slack_):
```
KUSTO_CLUSTER='<value>'
KUSTO_DATABASE='<value>'
```
```
## docstat usage
Run `npm run docstat -- <URL>` on any GitHub Docs URL to gather a set of default metrics about it, including 30d views, users, view duration, bounces, helpfulness score, and exits to support.
Notes:
* If the URL doesn't include a version, `docstat` will return data that includes **all versions** (so FPT, Cloud, Server, etc.).
* If you want data for FPT only, pass the `--fptOnly` option.
* `docstat` only accepts URLs with an `en` language code or no language code, and it only fetches English data.
To see all the options:
```
npm run docstat -- --help
```
You can combine options like this:
```
npm run docstat -- https://docs.github.com/copilot/tutorials/modernize-legacy-code --compare --range 60
```
Use `--redirects` to include `redirect_from` frontmatter paths in the queries (this is helpful if the article may have moved recently):
```
npm run docstat -- https://docs.github.com/copilot/tutorials/modernize-legacy-code --redirects
```
Use the `--json` (or `-j`) option to output JSON:
```
npm run docstat -- https://docs.github.com/copilot/tutorials/modernize-legacy-code --json
```
If you want to pass the results of the JSON to `jq`, you need to use `silent` mode:
```
npm run --silent docstat -- https://docs.github.com/copilot/tutorials/modernize-legacy-code --json | jq .data.users
```
## docsaudit usage
Run `npm run docsaudit` on a top-level content directory to gather data about its files—including title, path, versions, 30d views, and 30d users—and output it to a CSV file.
To see all the options:
```
npm run docsaudit -- --help
```
Run the script on any top-level content directory:
```
npm run docsaudit -- <content directory name>
```
For example:
```
npm run docsaudit -- actions
```
## Future development
Applies to all scripts:
* The date range option only accepts a start date (via `-r <number>`, where the number means "`<number>` days ago"). The end date will always be the current date.
* In the future, we can add an option to set a custom end date.
* The only Kusto queries available are hardcoded in the `kusto/queries` directory.
* In the future, we can hardcode more queries, add the ability to send custom queries, or perhaps create pre-defined sets of queries.

View File

@@ -4,9 +4,7 @@ import {
KustoResultTable,
} from 'azure-kusto-data'
import dotenv from 'dotenv'
dotenv.config()
import 'dotenv/config'
if (!(process.env.KUSTO_CLUSTER || process.env.KUSTO_DATABASE)) {
console.error(`Add KUSTO_CLUSTER and KUSTO_DATABASE to your .env file`)

View File

@@ -1,102 +0,0 @@
## Scripts
See documentation below for:
* [docstat](#docstat)
Run this on any GitHub Docs URL to gather a set of metrics about it.
* [docsaudit](#docsaudit)
Run this on a top-level content directory to gather info about its files and output to a CSV.
Print usage info for any script in this directory:
```bash
tsx src/metrics/scripts/<SCRIPT_NAME>.ts --help
```
If you get `command not found: tsx`, run:
```
npm install -g tsx
```
## docstat
Run `docstat` on any GitHub Docs URL to gather a set of default metrics about it, including 30d views, users, view duration, bounces, helpfulness score, and exits to support.
`docstat` checks the URL against the Docs API pagelist at https://docs.github.com/api/pagelist to see if it's valid.
If the URL doesn't include a version, `docstat` will return data for **all versions**. Pass `--fptOnly` for free-pro-team data.
`docstat` only accepts URLs with an `en` language code or no language code, and it only fetches English data.
### Usage
The steps below show the [global alias](#set-a-global-alias). Use the full command path (`tsx src/metrics/scripts/docstat.ts`) if you don't set up an alias.
To see the available options:
```
docstat --help
```
Run the script on any GitHub Docs URL:
```
docstat https://docs.github.com/en/copilot/rolling-out-github-copilot-at-scale
```
Spell options out like this:
```
docstat https://docs.github.com/en/copilot/rolling-out-github-copilot-at-scale --compare --range 60
```
or use the shorthand versions:
```
docstat https://docs.github.com/en/copilot/rolling-out-github-copilot-at-scale -c -r 60
```
Use `--redirects` to include `redirect_from` frontmatter paths in the queries:
```
docstat https://docs.github.com/en/copilot/rolling-out-github-copilot-at-scale --redirects
```
Use the `--json` (or `-j`) option to output JSON:
```
docstat https://docs.github.com/en/copilot/rolling-out-github-copilot-at-scale --json
```
### Set a global alias
To use `docstat` from any location in Terminal, set up a global alias:
1. Open your shell configuration file (like `~/.bash_profile` or `~/.zshrc`) in a text editor.
2. Add the following line, replacing the path with the actual path to your local directory, for example:
```bash
alias docstat="tsx ~/gh-repos/docs-internal/src/metrics/scripts/docstat.ts"
```
3. Save the file and reload your configuration:
```bash
source ~/.bash_profile # or ~/.zshrc, etc.
```
Now you can run `docstat <url>` from any directory.
## docsaudit
Run `docsaudit` on a top-level content directory to gather data about its files—including title, path, versions, 30d views, and 30d users—and output it to a CSV file.
To see the available options:
```
tsx src/metrics/scripts/docsaudit.ts --help
```
Run the script on any top-level content directory:
```
tsx src/metrics/scripts/docsaudit.ts <content directory name>
```
For example:
```
tsx src/metrics/scripts/docsaudit.ts actions
```
## Future development
Applies to all scripts in this directory:
* The date range option only accepts a start date (via `-r <number>`, where the number means "`<number>` days ago"). The end date will always be the current date.
* In the future, we can add an option to set a custom end date.
* The only Kusto queries available are hardcoded in the `kusto/queries` directory.
* In the future, we can hardcode more queries, add the ability to send custom queries, or perhaps create pre-defined sets of queries.

View File

@@ -42,6 +42,7 @@ interface CliOptions {
defaultToAll?: boolean
showDocset?: boolean
allVersions?: boolean
quiet?: boolean
}
interface JsonOutput {
@@ -103,10 +104,16 @@ program
'Get data for free-pro-team@latest only (default: all versions if URL is versionless)',
)
.option('--verbose', 'Display Kusto queries being executed')
.option('-q, --quiet', 'Suppress all output except results (automatically enabled with --json)')
.parse(process.argv)
const options = program.opts<CliOptions>()
// Auto-enable quiet mode when JSON output is requested
if (options.json) {
options.quiet = true
}
// If specific options are not provided, default to all
options.defaultToAll = !(
options.views ||
@@ -141,26 +148,34 @@ const usingFptOnly = !!options.fptOnly
if (version === FREE_PRO_TEAM) {
if (usingFptOnly) {
// User explicitly wants only free-pro-team@latest
console.log(
'\nFetching data for free-pro-team@latest only. To get all versions, omit the --fptOnly flag.\n',
)
if (!options.quiet) {
console.log(
'\nFetching data for free-pro-team@latest only. To get all versions, omit the --fptOnly flag.\n',
)
}
} else {
// Default: all versions
version = null
console.log(
'\nFetching data for all versions (no version specified in URL). To get only free-pro-team@latest, pass "--fptOnly".\n',
)
if (!options.quiet) {
console.log(
'\nFetching data for all versions (no version specified in URL). To get only free-pro-team@latest, pass "--fptOnly".\n',
)
}
}
} else {
// Version is specified in the URL (e.g. enterprise-server@)
console.log(
`\nFetching data for version "${version}" as specified in the URL. To get data for all versions, remove the version segment from the URL.\n`,
)
if (usingFptOnly) {
if (!options.quiet) {
console.log(
`You specified a version in the URL (${version}), but also passed --fptOnly. Only the version in the URL will be used.\n`,
`\nFetching data for version "${version}" as specified in the URL. To get data for all versions, remove the version segment from the URL.\n`,
)
}
if (usingFptOnly) {
if (!options.quiet) {
console.log(
`You specified a version in the URL (${version}), but also passed --fptOnly. Only the version in the URL will be used.\n`,
)
}
}
// Always use the version from the URL
}
@@ -194,21 +209,22 @@ const queryPaths = [cleanPath].concat(redirects)
const dates: DateRange = getDates(options.range)
async function main(): Promise<void> {
const spinner = ora('Connecting to Kusto...').start()
const spinner = options.quiet ? null : ora('Connecting to Kusto...').start()
try {
const client = getKustoClient()
if (!client) {
spinner.fail('Failed to connect to Kusto')
if (spinner) spinner.fail('Failed to connect to Kusto')
else if (!options.quiet) console.error('Failed to connect to Kusto')
process.exit(1)
}
spinner.text = 'Connected! Querying Kusto...'
if (spinner) spinner.text = 'Connected! Querying Kusto...'
// Only show docset stats if option is passed AND if the given path is not already a docset.
options.showDocset = !(cleanPath === docsetPath) && options.compare
if (options.compare && cleanPath === docsetPath) {
if (options.compare && cleanPath === docsetPath && !options.quiet) {
console.log(`\n\nSkipping comparison, since '${cleanPath}' is already a docset.\n`)
}
@@ -272,7 +288,7 @@ async function main(): Promise<void> {
: undefined,
])
spinner.succeed('Data retrieved successfully!\n')
if (spinner) spinner.succeed('Data retrieved successfully!\n')
// Output JSON and exit
if (options.json) {
@@ -399,17 +415,48 @@ async function main(): Promise<void> {
console.log(green('-------------------------------------------'))
} catch (error) {
spinner.fail('Error getting data')
console.error(red('Error details:'))
console.error(error)
if (spinner) spinner.fail('Error getting data')
if (options.json) {
// Output error in JSON format for consistent parsing
console.log(
JSON.stringify(
{
error: true,
message: 'Error getting data',
details: error instanceof Error ? error.message : String(error),
},
null,
2,
),
)
} else {
console.error(red('Error details:'))
console.error(error)
}
}
}
try {
await main()
} catch (error) {
console.error(red('Unexpected error:'))
console.error(error)
if (options.json) {
// Output error in JSON format for consistent parsing
console.log(
JSON.stringify(
{
error: true,
message: 'Unexpected error',
details: error instanceof Error ? error.message : String(error),
},
null,
2,
),
)
} else {
console.error(red('Unexpected error:'))
console.error(error)
}
process.exit(1)
}