Skip to content

Commit

Permalink
Add new option "auth" to set credentials for Google Sheets API
Browse files Browse the repository at this point in the history
  • Loading branch information
Victor Rusakovich authored and theghostbel committed Dec 29, 2022
1 parent 98e2c1a commit 7e1ad61
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 12 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,16 +93,18 @@ export default {
}
```

## 🙊 What about secrets?
## 🙊 How to provide credentials to access Google Spreadsheets API?

Google Sheets API requires any kind of authentication since v4.
Google Sheets API requires authentication since v4.
`gdocs-table-downloader` is limited to the "service account" type.
You should create such account in Google Console and then you have two options:
You should create such account in Google Console, and then you have several options:

1. Put `private_key` and `client_email` directly to a file specified by `--customOptions` param. See `customOptions.default.js` for example.
2. Put `private_key` and `client_email` to ENV and read them from `process.env`
3. Provide `--auth ./path-to-auth.json` to enable authentication. This file can be obtained from Google Console. See `auth-example.json` for example.
Only `private_key` and `client_email` fields are required.

Frankly, you're not restricted to only these two methods. You can invent any
Frankly, you're not restricted to only these methods. You can invent any
type of "secrets storing", just ensure that `getGoogleAuthCredentials()` returns
an object with two properties: `private_key` and `client_email`.

Expand Down
28 changes: 23 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ const mkdirp = require('mkdirp')
const { getSheets } = require('./googleapis-client')
const path = require('path')

const { token, target, sheets, moduleType, muteEslintQuotes, customOptions } = require('./options')
const { token, target, sheets, moduleType, muteEslintQuotes, customOptions, auth } = require('./options')

;(async() => {
const allSheetsWithTranslations = await loadTranslations(customOptions)
const allSheetsWithTranslations = await loadTranslations(customOptions, auth)
saveTranslationsToFiles(allSheetsWithTranslations)

log([
Expand All @@ -18,17 +18,35 @@ const { token, target, sheets, moduleType, muteEslintQuotes, customOptions } = r
].join(''))
})()

async function loadTranslations({ getGoogleAuthCredentials, getValueMapper }) {
const googleAuthCredentials = getGoogleAuthCredentials()
async function loadTranslations({ getGoogleAuthCredentials, getValueMapper }, auth) {
console.log('auth', auth)
let googleAuthCredentials = getGoogleAuthCredentials()

if (!googleAuthCredentials || Object.values(googleAuthCredentials).join('').length === 0) {
// using auth from customOptions.getGoogleAuthCredentials()
if (!auth && (!googleAuthCredentials || Object.values(googleAuthCredentials).join('').length === 0)) {
throw Error(
'Google Auth Credentials are empty, function getGoogleAuthCredentials() from --customOptions file '
+ 'should return object with "private_key" and "client_email".'
+ `Instead, received: ${JSON.stringify(googleAuthCredentials, null, 2)}`
)
}

// using auth from auth.json
if (auth) {
if (!auth.private_key ||!auth.client_email) {
throw Error(
'Google Auth Credentials are empty, auth option '
+ 'should be an object with "private_key" and "client_email".'
+ `Instead, received: ${JSON.stringify(auth, null, 2)}`
)
}

googleAuthCredentials = {
client_email: auth.client_email,
private_key: auth.private_key
}
}

const sheetsAsJson = await getSheets({
credentials: googleAuthCredentials,
spreadsheetId: token,
Expand Down
23 changes: 20 additions & 3 deletions options.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const fs = require('fs')
const path = require('path')
const yargs = require('yargs')

const TRIGGER_DEFAULT_VALUE_FOR_CUSTOM_OPTIONS = 'non-existing-value-just-to-trigger-loading-of-default-custom-options'
const TRIGGER_DEFAULT_VALUE_FOR_PATH_OPTION = 'non-existing-value-to-know-that-path-was-not-given'

module.exports = yargs
.example('$0 --token XYZ --target src/l10n/{sheet}/{locale}.js --moduleType AMD --sheets my_sheet,other_sheet',
Expand Down Expand Up @@ -35,8 +35,25 @@ module.exports = yargs
choices: ['AMD', 'ESM', 'JSON'],
type: 'string'
})
.option('auth', {
default: TRIGGER_DEFAULT_VALUE_FOR_PATH_OPTION,
demandOption: false,
describe: 'Path to auth.json file that has "private_key" and "client_email" fields. This file can be downloaded from Google Console (see docs).',
type: 'string',
coerce: value => {
const authPath = path.join(process.cwd(), value)
try {
fs.accessSync(authPath, fs.constants.R_OK)
return require(authPath)
} catch (_) {
if (value !== TRIGGER_DEFAULT_VALUE_FOR_PATH_OPTION) {
console.log(`Error! File "${value}" is not readable.`)
}
}
}
})
.option('customOptions', {
default: TRIGGER_DEFAULT_VALUE_FOR_CUSTOM_OPTIONS,
default: TRIGGER_DEFAULT_VALUE_FOR_PATH_OPTION,
demandOption: false,
describe: 'Path to module with custom options',
type: 'string',
Expand All @@ -50,7 +67,7 @@ module.exports = yargs
...require(userCustomFnPath)
}
} catch (_) {
if (pathToCustomOptions !== TRIGGER_DEFAULT_VALUE_FOR_CUSTOM_OPTIONS) {
if (pathToCustomOptions !== TRIGGER_DEFAULT_VALUE_FOR_PATH_OPTION) {
console.log(`Error! Custom options file "${userCustomFnPath}" is not readable, using default options.`)
}
return defaultCustomOptions
Expand Down

0 comments on commit 7e1ad61

Please sign in to comment.