From 08a0b2decb4a066a44e8bc386268e704b77fa645 Mon Sep 17 00:00:00 2001 From: Stephen Sawchuk Date: Thu, 4 Jun 2015 16:02:57 -0400 Subject: [PATCH] require project ID --- lib/bigquery/dataset.js | 5 ++++- lib/bigquery/index.js | 4 ++++ lib/bigquery/job.js | 2 +- lib/bigquery/table.js | 6 ++++-- lib/common/util.js | 8 ++++++++ lib/datastore/dataset.js | 4 ++++ lib/datastore/index.js | 18 +++++++++++------- lib/datastore/query.js | 4 +++- lib/datastore/request.js | 4 ++-- lib/datastore/transaction.js | 2 +- lib/pubsub/index.js | 4 ++++ lib/pubsub/subscription.js | 4 +++- lib/pubsub/topic.js | 4 +++- lib/storage/acl.js | 8 ++++++-- lib/storage/bucket.js | 12 ++++-------- lib/storage/file.js | 8 ++++++-- lib/storage/index.js | 10 +++++++++- test/bigquery/index.js | 8 ++++++++ test/common/util.js | 14 ++++++++++++++ test/datastore/dataset.js | 8 +++++++- test/pubsub/index.js | 10 +++++++++- test/storage/index.js | 8 +++++++- 22 files changed, 122 insertions(+), 33 deletions(-) diff --git a/lib/bigquery/dataset.js b/lib/bigquery/dataset.js index f6ce3918700..7997e26f7af 100644 --- a/lib/bigquery/dataset.js +++ b/lib/bigquery/dataset.js @@ -73,8 +73,11 @@ function Dataset(bigQuery, id) { * schema: 'UNITID,INSTNM,ADDR,CITY,STABBR,ZIP,FIPS,OBEREG,CHFNM,...' * }; * - * var bigquery = gcloud.bigquery(); + * var bigquery = gcloud.bigquery({ + * projectId: 'grape-spaceship-123' + * }); * var dataset = bigquery.dataset(); + * * dataset.createTable(tableConfig, function(err, table, apiResponse) {}); */ Dataset.prototype.createTable = function(options, callback) { diff --git a/lib/bigquery/index.js b/lib/bigquery/index.js index dd4c3d57372..27620c7008f 100644 --- a/lib/bigquery/index.js +++ b/lib/bigquery/index.js @@ -95,6 +95,10 @@ function BigQuery(options) { options = options || {}; + if (!options.projectId) { + throw util.missingProjectIdError; + } + this.makeAuthorizedRequest_ = util.makeAuthorizedRequestFactory({ credentials: options.credentials, keyFile: options.keyFilename, diff --git a/lib/bigquery/job.js b/lib/bigquery/job.js index 54b3bd16a7d..bab5465c5fd 100644 --- a/lib/bigquery/job.js +++ b/lib/bigquery/job.js @@ -32,7 +32,7 @@ var util = require('../common/util'); * @param {string} id - The ID of the job. * * @example - * var bigquery = gcloud.bigquery(); + * var bigquery = gcloud.bigquery({ projectId: 'grape-spaceship-123' }); * var Job = require('gcloud/lib/bigquery/job'); * var job = new Job(bigquery, 'job-id'); */ diff --git a/lib/bigquery/table.js b/lib/bigquery/table.js index e580f0d76e6..95644a97d5e 100644 --- a/lib/bigquery/table.js +++ b/lib/bigquery/table.js @@ -46,7 +46,7 @@ var util = require('../common/util'); * @param {string} id - The ID of the table. * * @example - * var bigquery = gcloud.bigquery(); + * var bigquery = gcloud.bigquery({ projectId: 'grape-spaceship-123' }); * var Dataset = require('gcloud/lib/bigquery/dataset'); * var dataset = new Dataset(bigquery, 'dataset-id'); * var Table = require('gcloud/lib/bigquery/table'); @@ -369,7 +369,9 @@ Table.prototype.delete = function(callback) { * @throws {Error} If destination format isn't recongized. * * @example - * var storage = gcloud.storage(); + * var storage = gcloud.storage({ + * projectId: 'grape-spaceship-123' + * }); * var exportedFile = storage.bucket('institutions').file('2014.csv'); * * //- diff --git a/lib/common/util.js b/lib/common/util.js index 84a4f0d73cb..66ff0b5621d 100644 --- a/lib/common/util.js +++ b/lib/common/util.js @@ -39,6 +39,14 @@ var USER_AGENT = 'gcloud-node/' + PKG.version; var util = module.exports; +var missingProjectIdError = new Error([ + 'Sorry, we cannot connect to Google Cloud Services without a project ID.', + 'See https://googlecloudplatform.github.io/gcloud-node/#/authorization for', + 'a detailed guide on creating an authorized connection.' +].join(' ')); + +util.missingProjectIdError = missingProjectIdError; + /** * Extend a global configuration object with user options provided at the time * of sub-module instantiation. diff --git a/lib/datastore/dataset.js b/lib/datastore/dataset.js index 2b15fee4b1d..01aab03d366 100644 --- a/lib/datastore/dataset.js +++ b/lib/datastore/dataset.js @@ -104,6 +104,10 @@ function Dataset(options) { options = options || {}; + if (!options.projectId) { + throw util.missingProjectIdError; + } + this.makeAuthorizedRequest_ = util.makeAuthorizedRequestFactory({ customEndpoint: typeof options.apiEndpoint !== 'undefined', credentials: options.credentials, diff --git a/lib/datastore/index.js b/lib/datastore/index.js index 994c24daa73..b94789ab246 100644 --- a/lib/datastore/index.js +++ b/lib/datastore/index.js @@ -47,11 +47,14 @@ var Dataset = require('./dataset'); * @example * var datastore = gcloud.datastore; * - * var dataset = datastore.dataset(); - * // equal to: - * // datastore.dataset({ - * // keyFilename: '/path/to/keyfile.json' - * // }); + * // datastore.dataset(); + * // + * // is equal to... + * // + * // datastore.dataset({ + * // projectId: 'grape-spaceship-123', + * // keyFilename: '/path/to/keyfile.json' + * // }); */ /** * The example below will demonstrate the different usage patterns your app may @@ -64,8 +67,8 @@ var Dataset = require('./dataset'); * * @example * var gcloud = require('gcloud')({ - * keyFilename: '/path/to/keyfile.json', - * projectId: 'my-project' + * projectId: 'grape-spaceship-123', + * keyFilename: '/path/to/keyfile.json' * }); * * var datastore = gcloud.datastore; @@ -84,6 +87,7 @@ function Datastore(options) { * * // Create a Dataset object. * var dataset = datastore.dataset({ + * projectId: 'grape-spaceship-123', * keyFilename: '/path/to/keyfile.json' * }); */ diff --git a/lib/datastore/query.js b/lib/datastore/query.js index 607b0996119..f3edda66d19 100644 --- a/lib/datastore/query.js +++ b/lib/datastore/query.js @@ -44,7 +44,9 @@ var util = require('../common/util.js'); * @param {string} kind - Kind to query. * * @example - * var dataset = gcloud.datastore.dataset(); + * var dataset = gcloud.datastore.dataset({ + * projectId: 'grape-spaceship-123' + * }); * * // If your dataset was scoped to a namespace at initialization, your query * // will likewise be scoped to that namespace. diff --git a/lib/datastore/request.js b/lib/datastore/request.js index ad6e06b2ce2..f1f5d3d36bc 100644 --- a/lib/datastore/request.js +++ b/lib/datastore/request.js @@ -69,7 +69,7 @@ var MODE_TRANSACTIONAL = 'TRANSACTIONAL'; * // This is how to create a transaction object directly using this Transaction * // class. The following transaction object is created for use in the examples * // in this file below. - * var dataset = gcloud.datastore.dataset(); + * var dataset = gcloud.datastore.dataset({ projectId: 'project-id' }); * var Transaction = require('gcloud/lib/datastore/transaction'); * var transaction = new Transaction(dataset, 'my-project-id'); * transaction.id = '1234'; // Give the transaction an ID. @@ -655,7 +655,7 @@ DatastoreRequest.prototype.upsert = function(entities, callback) { * } * }; * - * var dataset = gcloud.datastore.dataset(); + * var dataset = gcloud.datastore.dataset({ projectId: 'project-id' }); * var callback = function(err, result, apiResponse) {}; * var Transaction = require('gcloud/lib/datastore/transaction'); * var transaction = new Transaction(dataset, 'my-project-id'); diff --git a/lib/datastore/transaction.js b/lib/datastore/transaction.js index dc5609e9c58..b9e3852858a 100644 --- a/lib/datastore/transaction.js +++ b/lib/datastore/transaction.js @@ -47,7 +47,7 @@ var extend = require('extend'); * // This is how to create a transaction object directly using this Transaction * // class. The following transaction object is created for use in the examples * // in this file below. - * var dataset = gcloud.datastore.dataset(); + * var dataset = gcloud.datastore.dataset({ projectId: 'project-id' }); * var Transaction = require('gcloud/lib/datastore/transaction'); * var transaction = new Transaction(dataset, 'my-project-id'); * transaction.id = '1234'; // Give the transaction an ID. diff --git a/lib/pubsub/index.js b/lib/pubsub/index.js index 44d332ab957..7a37933ae12 100644 --- a/lib/pubsub/index.js +++ b/lib/pubsub/index.js @@ -80,6 +80,10 @@ var SCOPES = [ function PubSub(options) { options = options || {}; + if (!options.projectId) { + throw util.missingProjectIdError; + } + this.makeAuthorizedRequest_ = util.makeAuthorizedRequestFactory({ credentials: options.credentials, keyFile: options.keyFilename, diff --git a/lib/pubsub/subscription.js b/lib/pubsub/subscription.js index 1740c1c468f..8280ed14b7a 100644 --- a/lib/pubsub/subscription.js +++ b/lib/pubsub/subscription.js @@ -62,7 +62,9 @@ var util = require('../common/util.js'); * @constructor * * @example - * var pubsub = gcloud.pubsub(); + * var pubsub = gcloud.pubsub({ + * projectId: 'grape-spaceship-123' + * }); * * //- * // From {@linkcode module:pubsub#getSubscriptions}: diff --git a/lib/pubsub/topic.js b/lib/pubsub/topic.js index 9789dd70f07..81d0e9fe044 100644 --- a/lib/pubsub/topic.js +++ b/lib/pubsub/topic.js @@ -47,7 +47,9 @@ var Subscription = require('./subscription.js'); * @alias module:pubsub/topic * * @example - * var pubsub = gcloud.pubsub(); + * var pubsub = gcloud.pubsub({ + * projectId: 'grape-spaceship-123' + * }); * * // From pubsub.topic: * var topic = pubsub.topic('my-existing-topic'); diff --git a/lib/storage/acl.js b/lib/storage/acl.js index f557fce6c43..84d5fecea38 100644 --- a/lib/storage/acl.js +++ b/lib/storage/acl.js @@ -99,7 +99,9 @@ function Acl(options) { * @return {object} * * @example - * var storage = gcloud.storage(); + * var storage = gcloud.storage({ + * projectId: 'grape-spaceship-123' + * }); * * //- * // Add a user as an owner of a file. @@ -381,7 +383,9 @@ Acl.prototype.get = function(options, callback) { * @alias acl.update * * @example - * var storage = gcloud.storage(); + * var storage = gcloud.storage({ + * projectId: 'grape-spaceship-123' + * }); * * myBucket.acl.update({ * entity: 'user-useremail@example.com', diff --git a/lib/storage/bucket.js b/lib/storage/bucket.js index bc1d48fbf01..435d98c7f08 100644 --- a/lib/storage/bucket.js +++ b/lib/storage/bucket.js @@ -77,16 +77,12 @@ var RESUMABLE_THRESHOLD = 5000000; * * @example * var gcloud = require('gcloud'); - * var storage = gcloud.storage(); * - * // From Google Compute Engine - * var albums = storage.bucket('albums'); - * - * // From elsewhere - * var photos = storage.bucket({ - * keyFilename: '/path/to/keyfile.json', // If you have not yet provided it. - * name: 'bucket' + * var storage = gcloud.storage({ + * projectId: 'grape-spaceship-123' * }); + * + * var albums = storage.bucket('albums'); */ function Bucket(storage, name) { this.metadata = {}; diff --git a/lib/storage/file.js b/lib/storage/file.js index 7a86fff2cef..d136da44a06 100644 --- a/lib/storage/file.js +++ b/lib/storage/file.js @@ -107,9 +107,13 @@ function File(bucket, name, options) { * //- * // Make a file publicly readable. * //- - * var storage = gcloud.storage(); + * var storage = gcloud.storage({ + * projectId: 'grape-spaceship-123' + * }); + * * var myFile = storage.bucket('my-bucket').file('my-file'); - * myFile.acl.add({ + * + * myFile.acl.add({ * scope: 'allUsers', * role: storage.acl.READER_ROLE * }, function(err, aclObject) {}); diff --git a/lib/storage/index.js b/lib/storage/index.js index d4c55d7d2a6..05d32dc798d 100644 --- a/lib/storage/index.js +++ b/lib/storage/index.js @@ -83,6 +83,10 @@ function Storage(options) { options = options || {}; + if (!options.projectId) { + throw util.missingProjectIdError; + } + this.makeAuthorizedRequest_ = util.makeAuthorizedRequestFactory({ credentials: options.credentials, keyFile: options.keyFilename, @@ -111,7 +115,10 @@ function Storage(options) { * @type {object} * * @example - * var storage = gcloud.storage(); + * var storage = gcloud.storage({ + * projectId: 'grape-spaceship-123' + * }); + * * var albums = storage.bucket('albums'); * * //- @@ -155,6 +162,7 @@ Storage.prototype.acl = Storage.acl; * * @example * var gcloud = require('gcloud')({ + * projectId: 'grape-spaceship-123', * keyFilename: '/path/to/keyfile.json' * }); * diff --git a/test/bigquery/index.js b/test/bigquery/index.js index 74098231566..47856181ad7 100644 --- a/test/bigquery/index.js +++ b/test/bigquery/index.js @@ -67,6 +67,14 @@ describe('BigQuery', function() { bq = new BigQuery({ projectId: PROJECT_ID }); }); + describe('instantiation', function() { + it('should throw if a projectId is not specified', function() { + assert.throws(function() { + new BigQuery(); + }, /Sorry, we cannot connect/); + }); + }); + describe('createDataset', function() { var DATASET_ID = 'kittens'; diff --git a/test/common/util.js b/test/common/util.js index 12eba95f002..b447c64a0cc 100644 --- a/test/common/util.js +++ b/test/common/util.js @@ -61,6 +61,10 @@ describe('common/util', function() { // Override all util methods, allowing them to be mocked. Overrides are // removed before each test. Object.keys(util).forEach(function(utilMethod) { + if (typeof util[utilMethod] !== 'function') { + return; + } + util[utilMethod] = function() { return (utilOverrides[utilMethod] || util_Cached[utilMethod]) .apply(this, arguments); @@ -83,6 +87,16 @@ describe('common/util', function() { assert.deepEqual(REQUEST_DEFAULT_CONF, { pool: { maxSockets: Infinity } }); }); + it('should export an error for module instantiation errors', function() { + var missingProjectIdError = new Error([ + 'Sorry, we cannot connect to Google Cloud Services without a project ID.', + 'See https://googlecloudplatform.github.io/gcloud-node/#/authorization', + 'for a detailed guide on creating an authorized connection.' + ].join(' ')); + + assert.deepEqual(util.missingProjectIdError, missingProjectIdError); + }); + describe('arrayize', function() { it('should arrayize if the input is not an array', function() { assert.deepEqual(util.arrayize('text'), ['text']); diff --git a/test/datastore/dataset.js b/test/datastore/dataset.js index 07cc2f2278d..e79e67bbad6 100644 --- a/test/datastore/dataset.js +++ b/test/datastore/dataset.js @@ -28,8 +28,14 @@ describe('Dataset', function() { }); describe('instantiation', function() { + it('should throw if a projectId is not specified', function() { + assert.throws(function() { + new Dataset(); + }, /Sorry, we cannot connect/); + }); + it('should set default API connection details', function() { - var options = { a: 'b', c: 'd' }; + var options = { a: 'b', c: 'd', projectId: 'project-id' }; var mockApiEndpoint = 'http://localhost:8080'; Dataset.determineApiEndpoint_ = function (opts) { diff --git a/test/pubsub/index.js b/test/pubsub/index.js index 9ec0e5fd31c..446d4a1958c 100644 --- a/test/pubsub/index.js +++ b/test/pubsub/index.js @@ -64,6 +64,14 @@ describe('PubSub', function() { }; }); + describe('instantiation', function() { + it('should throw if a projectId is not specified', function() { + assert.throws(function() { + new PubSub(); + }, /Sorry, we cannot connect/); + }); + }); + describe('getTopics', function() { beforeEach(function() { pubsub.makeReq_ = function(method, path, q, body, callback) { @@ -239,7 +247,7 @@ describe('PubSub', function() { describe('makeReq_', function() { it('should pass network requests to the connection object', function(done) { - var pubsub = new PubSub(); + var pubsub = new PubSub({ projectId: PROJECT_ID }); pubsub.makeAuthorizedRequest_ = function() { done(); diff --git a/test/storage/index.js b/test/storage/index.js index 3985eb6b731..1f632e1018f 100644 --- a/test/storage/index.js +++ b/test/storage/index.js @@ -31,7 +31,13 @@ describe('Storage', function() { storage = new Storage({ projectId: 'project-id' }); }); - describe('initialization', function() { + describe('instantiation', function() { + it('should throw if a projectId is not specified', function() { + assert.throws(function() { + new Storage(); + }, /Sorry, we cannot connect/); + }); + it('should set the project id', function() { assert.equal(storage.projectId, 'project-id'); });