diff --git a/packages/google-cloud-resourcemanager/package.json b/packages/google-cloud-resourcemanager/package.json index f2d26d01f51..f1fbc49bdab 100644 --- a/packages/google-cloud-resourcemanager/package.json +++ b/packages/google-cloud-resourcemanager/package.json @@ -54,7 +54,7 @@ "check": "gts check", "clean": "gts clean", "compile": "tsc -p .", - "fix": "gts fix", + "fix": "eslint 'samples/**/*.js' --fix && npm run prettier && gts fix", "prepare": "npm run compile", "pretest": "npm run compile", "presystem-test": "npm run compile" diff --git a/packages/google-cloud-resourcemanager/src/index.ts b/packages/google-cloud-resourcemanager/src/index.ts index 0fec6b2151b..9278a847c81 100644 --- a/packages/google-cloud-resourcemanager/src/index.ts +++ b/packages/google-cloud-resourcemanager/src/index.ts @@ -16,7 +16,7 @@ 'use strict'; -import {Service, Operation} from '@google-cloud/common'; +import {Service, Operation, GoogleAuthOptions} from '@google-cloud/common'; import {paginator} from '@google-cloud/paginator'; import {promisifyAll} from '@google-cloud/promisify'; import * as extend from 'extend'; @@ -25,6 +25,55 @@ import {Project} from './project'; import * as r from 'request'; // Only for type declarations. import {teenyRequest} from 'teeny-request'; +export type CreateProjectCallback = + (err: Error|null, project?: Project|null, operation?: Operation, + apiResponse?: r.Response) => void; +export type CreateProjectResponse = [Project, Operation, r.Response]; +export type GetProjectsResponse = [Project[], r.Response]; +export type GetProjectsCallback = + (err: Error|null, projects?: Project[]|null, nextQuery?: {}|null, + apiResponse?: r.Response) => void; + +export interface GetProjectOptions { + autoPaginate?: boolean; + filter?: string; + maxApiCalls?: number; + maxResults?: number; + pageSize?: number; + pageToken?: string; +} + +export enum LifecylceState { + /** + * Unspecified state. This is only used/useful for distinguishing unset + * values. + */ + 'LIFECYCLE_STATE_UNSPECIFIED', + /** + * The normal and active state. + */ + 'ACTIVE', + /** + * The project has been marked for deletion by the user (by invoking + * projects.delete) or by the system (Google Cloud Platform). This can + * generally be reversed by invoking projects.undelete. + */ + 'DELETE_REQUESTED', + /** + * This lifecycle state is no longer used and not returned by the API. + */ + 'DELETE_IN_PROGRESS', +} + +export interface CreateProjectOptions { + projectNumber?: string; + projectId?: string; + lifecycleState?: LifecylceState; + name: string; + createTime: string; + labels: {[index: string]: string}; + parent: {type: string, id: string}; +} /** * @typedef {object} ClientConfig @@ -52,6 +101,10 @@ import {teenyRequest} from 'teeny-request'; * @property {Constructor} [promise] Custom promise module to use instead of * native Promises. */ +export interface ClientConfig extends GoogleAuthOptions { + autoRetry?: boolean; + maxRetries?: boolean; +} /** * The [Cloud Resource Manager](https://cloud.google.com/resource-manager/) @@ -88,9 +141,8 @@ import {teenyRequest} from 'teeny-request'; * Full quickstart example: */ class Resource extends Service { - getProjectsStream; - constructor(options?) { - options = options || {}; + getProjectsStream: Function; + constructor(options: ClientConfig = {}) { const config = { baseUrl: 'https://cloudresourcemanager.googleapis.com/v1', scopes: ['https://www.googleapis.com/auth/cloud-platform'], @@ -190,12 +242,20 @@ class Resource extends Service { * // Project created successfully! * }); */ - createProject(id, options, callback) { - if (is.fn(options)) { - callback = options; - options = {}; - } - + createProject(id: string, options?: CreateProjectOptions): + Promise; + createProject( + id: string, options: CreateProjectOptions, + callback: CreateProjectCallback): void; + createProject(id: string, callback: CreateProjectCallback): void; + createProject( + id: string, + optionsOrCallback?: CreateProjectOptions|CreateProjectCallback, + callback?: CreateProjectCallback): void|Promise { + const options = + typeof optionsOrCallback === 'object' ? optionsOrCallback : {}; + callback = + typeof optionsOrCallback === 'function' ? optionsOrCallback : callback; this.request( { method: 'POST', @@ -206,13 +266,13 @@ class Resource extends Service { }, (err, resp) => { if (err) { - callback(err, null, resp); + callback!(err, null, resp); return; } const project = this.project(resp.projectId); const operation = this.operation(resp.name); operation.metadata = resp; - callback(null, project, operation, resp); + callback!(null, project, operation, resp); }); } @@ -267,14 +327,16 @@ class Resource extends Service { * const projects = data[0]; * }); */ - getProjects(options, callback?) { - if (is.fn(options)) { - callback = options; - options = {}; - } - - options = options || {}; - + getProjects(options?: GetProjectOptions): Promise; + getProjects(options: GetProjectOptions, callback: GetProjectsCallback): void; + getProjects(callback: GetProjectsCallback): void; + getProjects( + optionsOrCallback?: GetProjectOptions|GetProjectsCallback, + callback?: GetProjectsCallback): void|Promise { + const options = + typeof optionsOrCallback === 'object' ? optionsOrCallback : {}; + callback = + typeof optionsOrCallback === 'function' ? optionsOrCallback : callback; this.request( { uri: '/projects', @@ -282,11 +344,11 @@ class Resource extends Service { }, (err, resp) => { if (err) { - callback(err, null, null, resp); + callback!(err, null, null, resp); return; } - let nextQuery = null; + let nextQuery: GetProjectOptions; if (resp.nextPageToken) { nextQuery = extend({}, options, { @@ -294,13 +356,13 @@ class Resource extends Service { }); } - const projects = (resp.projects || []).map(project => { + const projects = (resp.projects || []).map((project: Project) => { const projectInstance = this.project(project.projectId); projectInstance.metadata = project; return projectInstance; }); - callback(null, projects, nextQuery, resp); + callback!(null, projects, nextQuery!, resp); }); } @@ -321,7 +383,7 @@ class Resource extends Service { * * const operation = resource.operation('68850831366825'); */ - operation(name) { + operation(name: string) { if (!name) { throw new Error('A name must be specified for an operation.'); } diff --git a/packages/google-cloud-resourcemanager/src/project.ts b/packages/google-cloud-resourcemanager/src/project.ts index d547c9dceb4..3057d375766 100644 --- a/packages/google-cloud-resourcemanager/src/project.ts +++ b/packages/google-cloud-resourcemanager/src/project.ts @@ -22,6 +22,10 @@ import {Resource} from '.'; import * as r from 'request'; // Only for type declarations. import {teenyRequest} from 'teeny-request'; +export type RestoreCallback = (err: Error|null, apiResonse?: r.Response) => + void; +export type RestoreResponse = [r.Response]; + /** * A Project object allows you to interact with a Google Cloud Platform project. * @@ -296,16 +300,17 @@ class Project extends ServiceObject { * const apiResponse = data[0]; * }); */ - restore(callback) { + restore(): Promise; + restore(callback: RestoreCallback): void; + restore(callback?: RestoreCallback): void|Promise { callback = callback || util.noop; - this.request( { method: 'POST', uri: ':undelete', }, (err, resp) => { - callback(err, resp); + callback!(err, resp); }); } } diff --git a/packages/google-cloud-resourcemanager/system-test/resource.ts b/packages/google-cloud-resourcemanager/system-test/resource.ts index 3ce1bdb8974..c8fb7f39c9b 100644 --- a/packages/google-cloud-resourcemanager/system-test/resource.ts +++ b/packages/google-cloud-resourcemanager/system-test/resource.ts @@ -23,6 +23,7 @@ import {GoogleAuth} from 'google-auth-library'; import * as uuid from 'uuid'; import {Resource, Project} from '../src'; +import {Operation} from '@google-cloud/common'; describe('Resource', () => { const PREFIX = 'gcloud-tests-'; @@ -33,7 +34,7 @@ describe('Resource', () => { it('should get a list of projects', done => { resource.getProjects((err, projects) => { assert.ifError(err); - assert(projects.length > 0); + assert(projects!.length > 0); done(); }); }); @@ -58,8 +59,7 @@ describe('Resource', () => { it('should get metadata', done => { project.getMetadata((err, metadata) => { assert.ifError(err); - // tslint:disable-next-line no-any - assert.notStrictEqual((metadata as any).projectId, undefined); + assert.notStrictEqual(metadata.projectId, undefined); done(); }); }); @@ -104,16 +104,17 @@ describe('Resource', () => { return; } - project.create((err, project, operation) => { - if (err) { - done(err); - return; - } - testProjects.push(project); - operation.on('error', done).on('complete', () => { - done(); - }); - }); + project.create( + (err: Error, project: Project, operation: Operation) => { + if (err) { + done(err); + return; + } + testProjects.push(project); + operation.on('error', done).on('complete', () => { + done(); + }); + }); }); }); @@ -134,30 +135,25 @@ describe('Resource', () => { it('should have created the project', done => { project.getMetadata((err, metadata) => { assert.ifError(err); - // tslint:disable-next-line no-any - assert.strictEqual((metadata as any).projectId, (project as any).id); + assert.strictEqual(metadata.projectId, project.id); done(); }); }); it('should run operation as a promise', done => { const project = resource.project(generateName('project')); - // tslint:disable-next-line no-any - (project as any) - .create() + project.create() .then(response => { - const operation = response[1]; + const operation = response[1] as {} as Operation; return operation.promise(); }) .then(() => { testProjects.push(project); - // tslint:disable-next-line no-any - return (project as any).getMetadata(); + return project.getMetadata(); }) .then(response => { const metadata = response[0]; - // tslint:disable-next-line no-any - assert.strictEqual(metadata.projectId, (project as any).id); + assert.strictEqual(metadata.projectId, project.id); done(); }); }); @@ -166,25 +162,12 @@ describe('Resource', () => { const newProjectName = 'gcloud-tests-project-name'; project.getMetadata((err, metadata) => { assert.ifError(err); - // tslint:disable-next-line no-any - const originalProjectName = (metadata as any).name; + const originalProjectName = metadata.name; assert.notStrictEqual(originalProjectName, newProjectName); - // tslint:disable-next-line no-any - (project as any) - .setMetadata( - { - name: newProjectName, - }, - (err) => { - assert.ifError(err); - // tslint:disable-next-line no-any - (project as any) - .setMetadata( - { - name: originalProjectName, - }, - done); - }); + project.setMetadata({name: newProjectName}, err => { + assert.ifError(err); + project.setMetadata({name: originalProjectName}, done); + }); }); }); @@ -195,7 +178,7 @@ describe('Resource', () => { }); }); - function deleteTestProjects(callback) { + function deleteTestProjects(callback: (err?: Error) => void) { if (!CAN_RUN_TESTS) { callback(); return; @@ -211,8 +194,8 @@ describe('Resource', () => { callback(err); return; } - const projectsToDelete = projects.filter(project => { - const isTestProject = project.id.indexOf(PREFIX) === 0; + const projectsToDelete = projects!.filter(project => { + const isTestProject = project.id!.indexOf(PREFIX) === 0; const deleted = project.metadata.lifecycleState === 'DELETE_REQUESTED'; return isTestProject && !deleted; @@ -224,7 +207,7 @@ describe('Resource', () => { callback); } - function generateName(resourceType) { + function generateName(resourceType: string) { return PREFIX + resourceType + '-' + uuid.v1().substr(0, 8); } }); diff --git a/packages/google-cloud-resourcemanager/test/index.ts b/packages/google-cloud-resourcemanager/test/index.ts index 8ed0f118691..9ba076e175c 100644 --- a/packages/google-cloud-resourcemanager/test/index.ts +++ b/packages/google-cloud-resourcemanager/test/index.ts @@ -20,25 +20,27 @@ import * as arrify from 'arrify'; import * as assert from 'assert'; import * as extend from 'extend'; import * as proxyquire from 'proxyquire'; -import {util} from '@google-cloud/common'; +import {util, DecorateRequestOptions, Operation} from '@google-cloud/common'; import {teenyRequest} from 'teeny-request'; +import {Project} from '../src'; +import {Response} from 'request'; class FakeOperation { - calledWith_; + calledWith_: IArguments; constructor() { this.calledWith_ = arguments; } } class FakeProject { - calledWith_; + calledWith_: IArguments; constructor() { this.calledWith_ = arguments; } } class FakeService { - calledWith_; + calledWith_: IArguments; constructor() { this.calledWith_ = arguments; } @@ -48,7 +50,7 @@ let extended = false; const fakePaginator = { paginator: { // tslint:disable-next-line variable-name - extend(Class, methods) { + extend(Class: Function, methods: string[]) { if (Class.name !== 'Resource') { return; } @@ -57,7 +59,7 @@ const fakePaginator = { assert.deepStrictEqual(methods, ['getProjects']); extended = true; }, - streamify(methodName) { + streamify(methodName: string) { return methodName; }, } @@ -66,7 +68,7 @@ const fakePaginator = { let promisified = true; const fakePromisify = { // tslint:disable-next-line variable-name - promisifyAll(Class, options) { + promisifyAll(Class: Function, options: {exclude?: {}}) { if (Class.name !== 'Resource') { return; } @@ -75,7 +77,7 @@ const fakePromisify = { }, }; -let makeAuthenticatedRequestFactoryOverride; +let makeAuthenticatedRequestFactoryOverride: Function|null; const fakeUtil = extend({}, util, { makeAuthenticatedRequestFactory() { if (makeAuthenticatedRequestFactoryOverride) { @@ -89,9 +91,10 @@ const originalFakeUtil = extend(true, {}, fakeUtil); describe('Resource', () => { const PROJECT_ID = 'test-project-id'; - // tslint:disable-next-line variable-name - let Resource; - let resource; + // tslint:disable-next-line variable-name no-any + let Resource: any; + // tslint:disable-next-line no-any + let resource: any; before(() => { Resource = proxyquire('../src', { @@ -153,7 +156,7 @@ describe('Resource', () => { it('should not require any options', done => { const expectedBody = {projectId: NEW_PROJECT_ID}; - resource.request = reqOpts => { + resource.request = (reqOpts: DecorateRequestOptions) => { assert.deepStrictEqual(reqOpts.json, expectedBody); done(); }; @@ -162,7 +165,7 @@ describe('Resource', () => { }); it('should make the correct API request', done => { - resource.request = reqOpts => { + resource.request = (reqOpts: DecorateRequestOptions) => { assert.strictEqual(reqOpts.method, 'POST'); assert.strictEqual(reqOpts.uri, '/projects'); assert.deepStrictEqual(reqOpts.json, EXPECTED_BODY); @@ -178,18 +181,21 @@ describe('Resource', () => { const apiResponse = {a: 'b', c: 'd'}; beforeEach(() => { - resource.request = (reqOpts, callback) => { - callback(error, apiResponse); - }; + resource.request = + (reqOpts: DecorateRequestOptions, callback: Function) => { + callback(error, apiResponse); + }; }); it('should execute callback with error & API response', done => { - resource.createProject(NEW_PROJECT_ID, OPTIONS, (err, p, res) => { - assert.strictEqual(err, error); - assert.strictEqual(p, null); - assert.strictEqual(res, apiResponse); - done(); - }); + resource.createProject( + NEW_PROJECT_ID, OPTIONS, + (err: Error, p: Project, res: Response) => { + assert.strictEqual(err, error); + assert.strictEqual(p, null); + assert.strictEqual(res, apiResponse); + done(); + }); }); }); @@ -197,40 +203,43 @@ describe('Resource', () => { const apiResponse = {name: 'operation-name', projectId: undefined}; beforeEach(() => { - resource.request = (reqOpts, callback) => { - callback(null, apiResponse); - }; + resource.request = + (reqOpts: DecorateRequestOptions, callback: Function) => { + callback(null, apiResponse); + }; }); it('should exec callback with Project & API response', done => { const project = {}; const fakeOperation = {}; - resource.project = (id) => { + resource.project = (id: string) => { assert.strictEqual(id, apiResponse.projectId); return project; }; - resource.operation = (name) => { + resource.operation = (name: string) => { assert.strictEqual(name, apiResponse.name); return fakeOperation; }; - resource.createProject(NEW_PROJECT_ID, OPTIONS, (e, p, o, res) => { - assert.ifError(e); - assert.strictEqual(p, project); - assert.strictEqual(o, fakeOperation); - assert.strictEqual(o.metadata, apiResponse); - assert.strictEqual(res, apiResponse); - done(); - }); + resource.createProject( + NEW_PROJECT_ID, OPTIONS, + (e: Error, p: Project, o: Operation, res: Response) => { + assert.ifError(e); + assert.strictEqual(p, project); + assert.strictEqual(o, fakeOperation); + assert.strictEqual(o.metadata, apiResponse); + assert.strictEqual(res, apiResponse); + done(); + }); }); }); }); describe('getProjects', () => { it('should accept only a callback', done => { - resource.request = reqOpts => { + resource.request = (reqOpts: DecorateRequestOptions) => { assert.deepStrictEqual(reqOpts.qs, {}); done(); }; @@ -239,7 +248,7 @@ describe('Resource', () => { it('should make the correct API request', done => { const query = {a: 'b', c: 'd'}; - resource.request = reqOpts => { + resource.request = (reqOpts: DecorateRequestOptions) => { assert.strictEqual(reqOpts.uri, '/projects'); assert.strictEqual(reqOpts.qs, query); done(); @@ -252,19 +261,23 @@ describe('Resource', () => { const apiResponse = {a: 'b', c: 'd'}; beforeEach(() => { - resource.request = (reqOpts, callback) => { - callback(error, apiResponse); - }; + resource.request = + (reqOpts: DecorateRequestOptions, callback: Function) => { + callback(error, apiResponse); + }; }); it('should execute callback with error & API response', done => { - resource.getProjects({}, (err, projects, nextQuery, apiResp) => { - assert.strictEqual(err, error); - assert.strictEqual(projects, null); - assert.strictEqual(nextQuery, null); - assert.strictEqual(apiResp, apiResponse); - done(); - }); + resource.getProjects( + {}, + (err: Error, projects: Project[], nextQuery: {}, + apiResp: Response) => { + assert.strictEqual(err, error); + assert.strictEqual(projects, null); + assert.strictEqual(nextQuery, null); + assert.strictEqual(apiResp, apiResponse); + done(); + }); }); }); @@ -274,9 +287,10 @@ describe('Resource', () => { }; beforeEach(() => { - resource.request = (reqOpts, callback) => { - callback(null, apiResponse); - }; + resource.request = + (reqOpts: DecorateRequestOptions, callback: Function) => { + callback(null, apiResponse); + }; }); it('should build a nextQuery if necessary', done => { @@ -288,34 +302,39 @@ describe('Resource', () => { pageToken: nextPageToken, }; - resource.request = (reqOpts, callback) => { - callback(null, apiResponseWithNextPageToken); - }; + resource.request = + (reqOpts: DecorateRequestOptions, callback: Function) => { + callback(null, apiResponseWithNextPageToken); + }; - resource.getProjects({}, (err, projects, nextQuery) => { - assert.ifError(err); + resource.getProjects( + {}, (err: Error, projects: Project[], nextQuery: {}) => { + assert.ifError(err); - assert.deepStrictEqual(nextQuery, expectedNextQuery); + assert.deepStrictEqual(nextQuery, expectedNextQuery); - done(); - }); + done(); + }); }); it('should execute callback with Projects & API resp', done => { const project = {}; - resource.project = (name) => { + resource.project = (name: string) => { assert.strictEqual(name, apiResponse.projects[0].projectId); return project; }; - resource.getProjects({}, (err, projects, nextQuery, apiResp) => { - assert.ifError(err); - assert.strictEqual(projects[0], project); - assert.strictEqual(projects[0].metadata, apiResponse.projects[0]); - assert.strictEqual(apiResp, apiResponse); - done(); - }); + resource.getProjects( + {}, + (err: Error, projects: Project[], nextQuery: {}, + apiResp: Response) => { + assert.ifError(err); + assert.strictEqual(projects[0], project); + assert.strictEqual(projects[0].metadata, apiResponse.projects[0]); + assert.strictEqual(apiResp, apiResponse); + done(); + }); }); }); }); diff --git a/packages/google-cloud-resourcemanager/test/project.ts b/packages/google-cloud-resourcemanager/test/project.ts index da8884a9d41..acd6cf329df 100644 --- a/packages/google-cloud-resourcemanager/test/project.ts +++ b/packages/google-cloud-resourcemanager/test/project.ts @@ -19,13 +19,14 @@ import * as assert from 'assert'; import * as extend from 'extend'; import * as proxyquire from 'proxyquire'; -import {ServiceObject, util} from '@google-cloud/common'; +import {ServiceObject, util, ServiceObjectConfig, DecorateRequestOptions} from '@google-cloud/common'; import * as promisify from '@google-cloud/promisify'; +import {RequestCallback, Response} from 'request'; let promisified = false; const fakePromisify = extend({}, promisify, { // tslint:disable-next-line variable-name - promisifyAll(Class) { + promisifyAll(Class: Function) { if (Class.name === 'Project') { promisified = true; } @@ -33,17 +34,18 @@ const fakePromisify = extend({}, promisify, { }); class FakeServiceObject extends ServiceObject { - calledWith_; - constructor(config) { + calledWith_: IArguments; + constructor(config: ServiceObjectConfig) { super(config); this.calledWith_ = arguments; } } describe('Project', () => { - // tslint:disable-next-line variable-name - let Project; - let project; + // tslint:disable-next-line variable-name no-any + let Project: any; + // tslint:disable-next-line no-any + let project: any; const RESOURCE = { createProject: util.noop, @@ -67,7 +69,7 @@ describe('Project', () => { it('should inherit from ServiceObject', done => { const resourceInstance = extend({}, RESOURCE, { createProject: { - bind(context) { + bind(context: {}) { assert.strictEqual(context, resourceInstance); done(); }, @@ -106,13 +108,14 @@ describe('Project', () => { const apiResponse = {a: 'b', c: 'd'}; beforeEach(() => { - project.request = (reqOpts, callback) => { - callback(error, apiResponse); - }; + project.request = + (reqOpts: DecorateRequestOptions, callback: Function) => { + callback(error, apiResponse); + }; }); it('should make the correct API request', done => { - project.request = reqOpts => { + project.request = (reqOpts: DecorateRequestOptions) => { assert.strictEqual(reqOpts.method, 'POST'); assert.strictEqual(reqOpts.uri, ':undelete'); done(); @@ -121,7 +124,7 @@ describe('Project', () => { }); it('should execute the callback with error & API response', done => { - project.restore((err, apiResponse_) => { + project.restore((err: Error, apiResponse_: Response) => { assert.strictEqual(err, error); assert.strictEqual(apiResponse_, apiResponse); done(); diff --git a/packages/google-cloud-resourcemanager/tsconfig.json b/packages/google-cloud-resourcemanager/tsconfig.json index 1942ae08fa2..b10ee498aef 100644 --- a/packages/google-cloud-resourcemanager/tsconfig.json +++ b/packages/google-cloud-resourcemanager/tsconfig.json @@ -2,9 +2,7 @@ "extends": "./node_modules/gts/tsconfig-google.json", "compilerOptions": { "rootDir": ".", - "outDir": "build", - "noImplicitAny": false, - "noImplicitThis": false + "outDir": "build" }, "include": [ "src/*.ts",