Skip to content

Commit

Permalink
Merge pull request #10 from uglow/feature/support-lambda
Browse files Browse the repository at this point in the history
feat: support AWS Lambda by allowing filePath to be specified
  • Loading branch information
uglow committed Nov 4, 2020
2 parents 637fc0b + 3d8e579 commit 86bc429
Show file tree
Hide file tree
Showing 16 changed files with 5,902 additions and 7,124 deletions.
9 changes: 0 additions & 9 deletions .eslintignore

This file was deleted.

47 changes: 28 additions & 19 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,40 @@
module.exports = {
root: true,
parserOptions: {
ecmaVersion: 2019,
},

env: {
es6: true,
node: true,
jest: true,
'jest/globals': true,
},

extends: [
'eslint:recommended',
'plugin:import/errors',
'plugin:import/warnings',
'plugin:node/recommended',
'plugin:prettier/recommended',
'plugin:unicorn/recommended',
'plugin:node/recommended-script',
'plugin:jest/recommended',
],

// required to lint *.vue files
plugins: ['node'],
// add your custom rules here
plugins: ['jest'],
rules: {
'prefer-const': 'error',
'no-var': 'error',
// Allow some flexibility here
'unicorn/prevent-abbreviations': 'off',

// Use camelCase for files (and directories - not enforced)
'unicorn/filename-case': ['error', { case: 'camelCase' }],

// Turn off explicit length checks
'unicorn/explicit-length-check': 'off',

// Turn off this rule as it is needed for web-component-lib integration (Nuxt.js doesn't like ESM files, yet)
'import/no-webpack-loader-syntax': 'off',
'import/no-unresolved': 'off',
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
// Turning off because it leads to many uses of the word 'error' in the same block, which is confusing
// E.g.
// } catch(error) {
// logger.error(error);
// return error(error);
// }
'unicorn/catch-error-name': 'off',

// Turn off node/no-unsupported-features because it complains about import & export
'node/no-unsupported-features': 'off',
// This rule is no good for test specs. Need to find a way to disable this for test specs
'unicorn/consistent-function-scoping': 'off',
},
};
7 changes: 7 additions & 0 deletions .prettierrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
semi: true,
trailingComma: 'all',
singleQuote: true,
printWidth: 120,
tabWidth: 2,
};
18 changes: 6 additions & 12 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
sudo: false
language: node_js
node_js:
- "8"
- "lts/*"

before_install:
- npm i -g npm@6.1
node_js:
- '10'

install:
- npm ci

before_script:
- npm install

script:
- npm run pre-release
- npm run verify
- npm run test:report

after_success:
- npm run upload-coverage
- npm run travis-deploy-once "npm run semantic-release"
- npm run semantic-release

branches:
except:
Expand All @@ -27,4 +22,3 @@ notifications:
email:
recipients:
- u_glow@hotmail.com

145 changes: 89 additions & 56 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ const smetrics = require('smetrics');

function addUnitTestMetrics() {
const stats = require('./test-reports/unit.json');
const tabName = 'My Stats';

smetrics.addMetric('Total tests', stats.numTotalTests);
smetrics.addMetric('Passed tests', stats.numPassedTests);
smetrics.addMetric(tabName, 'Total tests', stats.numTotalTests);
smetrics.addMetric(tabName, 'Passed tests', stats.numPassedTests);
}

// Gather all the metrics then commit them to Google Sheets
Expand All @@ -42,9 +43,10 @@ addUnitTestMetrics();
const creds = require('./google-generated-creds.json');
// OR, if you cannot save the file locally (like on heroku)
const options = {
client_email: process.env.SMETRICS_GOOGLE_SERVICE_ACCOUNT_CLIENT_EMAIL,
private_key: process.env.SMETRICS_GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY,
dateTimeFormat: 'googleDate', // defaults to 'milliseconds'
clientEmail: process.env.SMETRICS_GOOGLE_SERVICE_ACCOUNT_CLIENT_EMAIL,
privateKey: process.env.SMETRICS_GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY,
dateTimeFormat: 'googleDate', // defaults to 'milliseconds',
filePath: '/tmp/yourfile.json' // defaults to CWD + 'smetrics.json'
}
smetrics.commit('<spreadsheet key>', options); // Async - returns a promise

Expand All @@ -54,20 +56,60 @@ smetrics.commit('<spreadsheet key>', options); // Async - returns a promise
**The order that metrics are added is significant.** If you decide to change the order that you add metrics, you
should open the corresponding Google Sheet and change the column-order to match your new metric-capturing order.

### Usage within AWS Lambda functions

### The `options` parameter
Because this library persists state to a file, you need to specify the `filePath` when calling `addMetric` and `commit`
with a path underneath the `/tmp` directory:

#### `client_email` (string)
``` js
const fs = require('fs');
const smetrics = require('smetrics');

// NOTE: filePath is specified explicitly, under the '/tmp' folder
smetrics.addMetric(tabName, 'Total tests', stats.numTotalTests, { filePath: '/tmp/smetrics.json' });

// See Authentication section for how to generate this information
const creds = require('./google-generated-creds.json');
// OR, if you cannot save the file locally (like on heroku)
const options = {
clientEmail: process.env.SMETRICS_GOOGLE_SERVICE_ACCOUNT_CLIENT_EMAIL,
privateKey: process.env.SMETRICS_GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY,
dateTimeFormat: 'googleDate',

// NOTE: filePath is specified explicitly:
filePath: '/tmp/smetrics.json'
}
smetrics.commit('<spreadsheet key>', options); // Async - returns a promise

```

This value is available in the JSON file that you can download when setting up Authentication with a service account.
## API

#### `private_key` (string)
### `addMetric(sheetName, column, value, options) : object`

This value is available in the JSON file that you can download when setting up Authentication with a service account.
Adds a metric to the temporary metric-file

#### `dateTimeFormat` (string, default = 'milliseconds')
- `sheetName` <string> The name of the sheet within the spreadsheet
- `column` <string> The name of the column within the sheet
- `value` <any> The value to store
- `options` <object> (optional):
- `timestamp` <timeMillis> The timestamp to associate with the metric. Defaults to the current time.
- `filePath` <string> The file path to write the metric data to. Defaults to current working directory 'smetrics.json'

The default format for the DateTime column is `milliseconds`, which is the number of milliseconds since the epoch (e.g. 1537165777561,
### `commit(spreadsheetKey, options) : void`

- `spreadsheetId` <string> The SpreadsheetId

Reads the metrics in the metric-data file ('smetrics.json') and persists it to the
designated Google Sheet.

- `sheetName` <string> The name of the sheet within the spreadsheet
- `options` <object>:
- `clientEmail` <string> This value is available in the JSON file that you can download when setting up Authentication with a service account.
- `privateKey` <string> This value is available in the JSON file that you can download when setting up Authentication with a service account.
- `dateFormat` <string> Default value 'milliseconds'.

The default format for DateTime columns is `milliseconds`, which is the number of milliseconds since the epoch (e.g. 1537165777561,
which is equivalent to Mon Sep 17 2018 16:29:37 GMT+1000 (Australian Eastern Standard Time)).

Alternately, you can specify the format as `googleDate`, which formats the date as `dd-mon-yyyy hh:mm:ss`.
Expand All @@ -76,9 +118,8 @@ may need to manually format the DateTime column as a 'Date Time' in the Google S

## How it works

Every time a metric is added using this module, a temporary file (`smetrics.json`, [example](fixtures/smetrics.json)) is created/updated in your
application's root directory (using the [app-root-path](https://www.npmjs.com/package/app-root-path) module),
with the metric name and a value:
Every time a metric is added, a temporary file (`smetrics.json`, [example](fixtures/smetrics.json)) is created/updated in your
current working directory with the metric name and a value:

```js
// smetrics.json:
Expand All @@ -105,29 +146,6 @@ may even add multiple rows of metrics in one go (Why would you want to? I'm not

## Authentication

IMPORTANT: Google recently deprecated their ClientLogin (username+password)
access, so things are slightly more complicated now. Older versions of this
module supported it, so just be aware that things changed.

### Unauthenticated access (read-only access on public docs)

By default, this module makes unauthenticated requests and can therefore
only access spreadsheets that are "public".

The Google Spreadsheets Data API reference and developers guide is a little
ambiguous about how you access a "published" public Spreadsheet.

If you wish to work with a Google Spreadsheet without authenticating, not only
must the Spreadsheet in question be visible to the web, but it must also have
been explicitly published using "File > Publish to the web" menu option in
the google spreadsheets GUI.

Many seemingly "public" sheets have not also been "published" so this may
cause some confusion.

*Unauthenticated requests allow reading, but not writing to sheets. To write on a sheet, you must authenticate.*


### Service Account (recommended method)

This is a 2-legged OAuth method and designed to be "an account that belongs to your application instead of to an individual end user".
Expand All @@ -137,29 +155,44 @@ Use this for an app that needs to access a set of documents that you have full a
__Setup Instructions__

1. Go to the [Google Developers Console](https://console.developers.google.com/project)
2. Select your project or create a new one (and then select it)
3. Enable the Drive API for your project
- In the sidebar on the left, expand __APIs & auth__ > __APIs__
- Search for "drive"
- Click on "Drive API" or "Google Sheets API"
- click the blue "Enable API" button
4. Create a service account for your project
- In the sidebar on the left, expand __APIs & auth__ > __Credentials__
- Click blue "Add credentials" button
- Select the "Service account" option
- Select "Furnish a new private key" checkbox
- Select the "JSON" key type option
- Click blue "Create" button
- your JSON key file is generated and downloaded to your machine (__it is the only copy!__)
- note your service account's email address (also available in the JSON key file)
5. **Share the doc (or docs) with your service account using the email noted above.**

1. Select your project or create a new one (and then select it)
1. Enable the Drive API for your project
1. In the sidebar on the left, expand APIs & auth > APIs
1. Search for "sheets"
1. Click on "Google Sheets API"
1. Click the blue "Enable API" button
1. Create a service account for your project:
1. In the sidebar on the left, expand IAM & Admin > Service Accounts
1. Click "Create Service Account" button
1. Enter the service account name & a description for step 1 and press Create.
1. Skip steps 2 & 3 by pressing Cancel
1. In the Service Accounts panel, select Actions > Create Key
1. Select the "JSON" key type option
1. Click blue "Create" button.

Your JSON key file is generated and downloaded to your machine (it is the only copy!)
note your service account's email address (also available in the JSON key file)
Share the doc (or docs) with your service account using the email noted above.

The `private_key` field in the JSON file that is the private key.

### Sharing the sheet with the service account

1. Open the Google Sheet
1. Press the Share button.
1. In the Share dialog, type the service accounts email: your-service-account-name@google-app.iam.gserviceaccount.com
1. Press Send.

## Spreadsheet ID

The Spreadsheet ID can be found in the URL of the spreadsheet.

E.g. docs.google.com/spreadsheets/d/spreadhseetID/edit#gid=0

## Graphing the results

Once you have the data in your spreadsheet, you can provide read-access to allow other tools


## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md).
Expand Down
64 changes: 64 additions & 0 deletions _package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"name": "smetrics",
"version": "0.0.0-development",
"description": "A simple tool to record metrics in a spreadsheet.",
"license": "MIT",
"files": [
"src",
"*.md"
],
"main": "src/index.js",
"repository": {
"type": "git",
"url": "https://github.com/uglow/smetrics.git"
},
"scripts": {
"commitmsg": "cz-customizable-ghooks",
"prepush": "npm-run-all verify test:report --silent",
"test": "npm run test:unit",
"test:int": "node ./test/integration-test.js",
"test:unit": "jest",
"test:report": "jest --coverage",
"test:snaps": "jest -u",
"test:watch": "jest --watchAll",
"upload-coverage": "coveralls < test-reports/coverage/lcov.info",
"lint": "eslint --fix src/",
"verify": "eslint --max-warnings=0 src/",
"travis-deploy-once": "travis-deploy-once",
"semantic-release": "semantic-release",
"x": "jest --init"
},
"config": {
"commitizen": {
"path": "node_modules/cz-customizable"
},
"cz-customizable": {
"config": "commitMessageConfig.js"
}
},
"dependencies": {
"google-auth-library": "6.1.3"
},
"devDependencies": {
"@getify/eslint-plugin-proper-arrows": "10.0.0",
"coveralls": "3.1.0",
"cross-env": "7.0.2",
"cz-customizable": "6.3.0",
"dotenv-safe": "6.0.0",
"eslint": "7.12.1",
"eslint-config-prettier": "6.10.1",
"eslint-plugin-jest": "24.1.0",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-prettier": "3.1.3",
"eslint-plugin-unicorn": "23.0.0",
"husky": "4.2.5",
"jest": "26.6.2",
"npm-run-all": "4.1.5",
"prettier": "2.1.2",
"semantic-release": "17.2.2"
},
"engines": {
"node": ">=10",
"npm": ">=6.1"
}
}
Loading

0 comments on commit 86bc429

Please sign in to comment.