forked from google/clasp
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement metrics command, google#353
- Loading branch information
Showing
6 changed files
with
128 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { loadAPICredentials, script } from '../auth'; | ||
import { checkIfOnline, getProjectSettings, LOG, logError, spinner, ERROR } from '../utils'; | ||
import { script_v1 } from 'googleapis'; | ||
|
||
/** | ||
* Displays metrics for the current script | ||
* @param cmd.json {boolean} Displays the status in json format. | ||
*/ | ||
export default async (): Promise<void> => { | ||
await checkIfOnline(); | ||
await loadAPICredentials(); | ||
const { scriptId } = await getProjectSettings(); | ||
if (!scriptId) return; | ||
spinner.setSpinnerTitle(LOG.METRICS(scriptId)).start(); | ||
const metrics = await script.projects.getMetrics({ | ||
scriptId, | ||
metricsGranularity: 'DAILY', | ||
}); | ||
if (spinner.isSpinning()) spinner.stop(true); | ||
if (metrics.status !== 200) logError(metrics.statusText); | ||
const { data } = metrics; | ||
|
||
type Maybe<T> = T | undefined | null; | ||
// Function to format a time range into a user friendly format. | ||
// API appears to always returns whole UTC days. Bail out if this assumption doesn't hold. | ||
const formatTime = ({startTime, endTime}: {startTime: Maybe<string>, endTime: Maybe<string>}) => | ||
(startTime?.endsWith('T00:00:00Z') && endTime?.endsWith('T00:00:00Z')) ? | ||
startTime.slice(0, 10) : | ||
logError(ERROR.METRICS_UNEXPECTED_RANGE); | ||
|
||
// Function to create a Map from an array of MetricsValues (time range -> value) | ||
const array2map = (metricsValues: script_v1.Schema$MetricsValue[]) => | ||
new Map(metricsValues.map(({startTime, endTime, value}) => ([ | ||
formatTime({ startTime , endTime }), | ||
value || '0', | ||
])), | ||
); | ||
|
||
// Turn raw data array into range (string) -> value (string) Maps | ||
const activeUsers = array2map(data.activeUsers || []); | ||
const failedExecutions = array2map(data.failedExecutions || []); | ||
const totalExecutions = array2map(data.totalExecutions || []); | ||
|
||
// Create a sorted array of unique time ranges | ||
const timeRanges = Array.from(new Set([ | ||
...activeUsers.keys(), | ||
...failedExecutions.keys(), | ||
...totalExecutions.keys(), | ||
])).sort().reverse(); | ||
|
||
// Turn the dataset into a table | ||
const table = timeRanges.map(timeRange => { | ||
const get = (map: Map<string, string>) => (map.get(timeRange) || '0'); | ||
return [ | ||
timeRange, | ||
' ' + get(activeUsers), | ||
get(activeUsers) === '1' ? 'user' : 'users', | ||
' ' + get(totalExecutions), | ||
get(totalExecutions) === '1' ? 'execution' : 'executions', | ||
' ' + get(failedExecutions), | ||
'failed', | ||
]; | ||
}); | ||
|
||
const padders = [ | ||
String.prototype.padEnd, // for time range | ||
String.prototype.padStart, // for number of user(s) | ||
String.prototype.padEnd, // for 'user' / 'users' | ||
String.prototype.padStart, // for number of executions | ||
String.prototype.padEnd, // for 'execution' / 'executions' | ||
String.prototype.padStart, // for number of failed executions | ||
String.prototype.padEnd, // for 'failed' | ||
]; | ||
|
||
// Determine padding for each column | ||
const paddings = padders.map( | ||
(_, columnIndex) => Math.max(...table.map(row => row[columnIndex].length)), | ||
); | ||
|
||
// Metrics API only supports UTC, and users might expect local time, let them know it's UTC. | ||
console.error('UTC Date'); | ||
|
||
// Print results | ||
for (const row of table) { | ||
console.log(row.map((v, i) => padders[i].apply(v, [paddings[i]])).join(' ')); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { spawnSync } from 'child_process'; | ||
import { expect } from 'chai'; | ||
import { describe, it } from 'mocha'; | ||
import { | ||
CLASP, | ||
} from '../constants'; | ||
import { cleanup, setup } from '../functions'; | ||
|
||
describe('Test clasp metrics function', () => { | ||
before(setup); | ||
it('should display metrics', () => { | ||
const today = new Date(); | ||
const yesterday = new Date(); | ||
yesterday.setDate(today.getDate() - 1); | ||
|
||
const result = spawnSync( | ||
CLASP, ['metrics'], { encoding: 'utf8' }, | ||
); | ||
|
||
expect(result.stderr).to.contain('UTC Date'); | ||
expect(result.stdout).to.contain(yesterday.toISOString().slice(0, 10)); | ||
expect(result.status).to.equal(0); | ||
}); | ||
after(cleanup); | ||
}); |