Skip to content

Commit

Permalink
feat: List deployments sub-command for deploy plugin (#176)
Browse files Browse the repository at this point in the history
Resolves [AB#352]
  • Loading branch information
tbarlow12 authored Jun 21, 2019
1 parent 0d32d2d commit 34db630
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 3 deletions.
34 changes: 34 additions & 0 deletions src/plugins/deploy/azureDeployPlugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ import { ResourceService } from "../../services/resourceService";
import { Site } from "@azure/arm-appservice/esm/models";

describe("Deploy plugin", () => {

afterEach(() => {
jest.resetAllMocks();
})

it("calls deploy hook", async () => {
const deployResourceGroup = jest.fn();
const functionAppStub: Site = MockFactory.createTestSite();
Expand All @@ -30,4 +35,33 @@ describe("Deploy plugin", () => {
expect(deploy).toBeCalled();
expect(uploadFunctions).toBeCalledWith(functionAppStub);
});

it("lists deployments", async () => {
const deployments = MockFactory.createTestDeployments();
ResourceService.prototype.getDeployments = jest.fn(() => Promise.resolve(deployments));
const sls = MockFactory.createTestServerless();
const options = MockFactory.createTestServerlessOptions();
const plugin = new AzureDeployPlugin(sls, options);
await invokeHook(plugin, "deploy:list:list");
let expectedLogStatement = "\n\nDeployments";
for (const dep of deployments) {
expectedLogStatement += "\n-----------\n"
expectedLogStatement += `Name: ${dep.name}\n`
expectedLogStatement += `Timestamp: ${dep.properties.timestamp.getTime()}\n`;
expectedLogStatement += `Datetime: ${dep.properties.timestamp.toISOString()}\n`
}
expectedLogStatement += "-----------\n"
expect(sls.cli.log).lastCalledWith(expectedLogStatement);
});

it("logs empty deployment list", async () => {
const sls = MockFactory.createTestServerless();
const resourceGroup = "rg1";
ResourceService.prototype.getDeployments = jest.fn(() => Promise.resolve([])) as any;
ResourceService.prototype.getResourceGroup = jest.fn(() => resourceGroup);
const options = MockFactory.createTestServerlessOptions();
const plugin = new AzureDeployPlugin(sls, options);
await invokeHook(plugin, "deploy:list:list");
expect(sls.cli.log).lastCalledWith(`No deployments found for resource group '${resourceGroup}'`);
});
});
37 changes: 36 additions & 1 deletion src/plugins/deploy/azureDeployPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,46 @@ import { FunctionAppService } from "../../services/functionAppService";

export class AzureDeployPlugin {
public hooks: { [eventName: string]: Promise<any> };
public commands: any;

public constructor(private serverless: Serverless, private options: Serverless.Options) {
this.hooks = {
"deploy:deploy": this.deploy.bind(this)
"deploy:deploy": this.deploy.bind(this),
"deploy:list:list": this.list.bind(this),
};

this.commands = {
deploy: {
commands: {
list: {
usage: "List deployments",
lifecycleEvents: [
"list"
]
}
}
}
}
}

private async list() {
this.serverless.cli.log("Listing deployments");
const resourceService = new ResourceService(this.serverless, this.options);
const deployments = await resourceService.getDeployments();
if (!deployments || deployments.length === 0) {
this.serverless.cli.log(`No deployments found for resource group '${resourceService.getResourceGroup()}'`);
return;
}
let stringDeployments = "\n\nDeployments";

for (const dep of deployments) {
stringDeployments += "\n-----------\n"
stringDeployments += `Name: ${dep.name}\n`
stringDeployments += `Timestamp: ${dep.properties.timestamp.getTime()}\n`;
stringDeployments += `Datetime: ${dep.properties.timestamp.toISOString()}\n`
}
stringDeployments += "-----------\n"
this.serverless.cli.log(stringDeployments);
}

private async deploy() {
Expand Down
3 changes: 2 additions & 1 deletion src/plugins/login/loginPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ export class AzureLoginPlugin {
this.provider = (this.serverless.getProvider("azure") as any) as AzureProvider;

this.hooks = {
"before:package:initialize": this.login.bind(this)
"before:package:initialize": this.login.bind(this),
"before:deploy:list:list": this.login.bind(this),
};
}

Expand Down
4 changes: 4 additions & 0 deletions src/services/baseService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ export abstract class BaseService {
}
}

public getResourceGroup(): string {
return this.resourceGroup;
}

/**
* Sends an API request using axios HTTP library
* @param method The HTTP method
Expand Down
15 changes: 14 additions & 1 deletion src/services/resourceService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ jest.mock("@azure/arm-resources")
import { ResourceManagementClient } from "@azure/arm-resources";

describe("Resource Service", () => {
const deployments = MockFactory.createTestDeployments();

beforeAll(() => {
ResourceManagementClient.prototype.resourceGroups = {
Expand All @@ -14,7 +15,8 @@ describe("Resource Service", () => {
} as any;

ResourceManagementClient.prototype.deployments = {
deleteMethod: jest.fn()
deleteMethod: jest.fn(),
listByResourceGroup: jest.fn(() => Promise.resolve(deployments)),
} as any;
});

Expand Down Expand Up @@ -70,4 +72,15 @@ describe("Resource Service", () => {
expect(ResourceManagementClient.prototype.resourceGroups.deleteMethod)
.toBeCalledWith(resourceGroup);
});

it("lists deployments", async () => {
const sls = MockFactory.createTestServerless();
const resourceGroup = "myResourceGroup";
sls.service.provider["resourceGroup"] = resourceGroup
sls.variables["azureCredentials"] = "fake credentials"
const options = MockFactory.createTestServerlessOptions();
const service = new ResourceService(sls, options);
const deps = await service.getDeployments();
expect(deps).toEqual(deployments);
});
});
5 changes: 5 additions & 0 deletions src/services/resourceService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ export class ResourceService extends BaseService {
this.resourceClient = new ResourceManagementClient(this.credentials, this.subscriptionId);
}

public async getDeployments() {
this.log(`Listing deployments for resource group '${this.resourceGroup}':`);
return await this.resourceClient.deployments.listByResourceGroup(this.resourceGroup);
}

public async deployResourceGroup() {
this.log(`Creating resource group: ${this.resourceGroup}`);

Expand Down
14 changes: 14 additions & 0 deletions src/test/mockFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { ServerlessAzureConfig } from "../models/serverless";
import { AzureServiceProvider, ServicePrincipalEnvVariables } from "../models/azureProvider"
import { Logger } from "../models/generic";
import { ApiCorsPolicy } from "../models/apiManagement";
import { DeploymentsListByResourceGroupResponse } from "@azure/arm-resources/esm/models";

function getAttribute(object: any, prop: string, defaultValue: any): any {
if (object && object[prop]) {
Expand Down Expand Up @@ -140,6 +141,19 @@ export class MockFactory {
return credentials;
}

public static createTestDeployments(count: number = 5): DeploymentsListByResourceGroupResponse {
const result = [];
for (let i = 0; i < count; i++) {
result.push({
name: `deployment${i+1}`,
properties: {
timestamp: new Date(),
}
})
}
return result as DeploymentsListByResourceGroupResponse
}

public static createTestAxiosResponse<T>(
config: AxiosRequestConfig,
responseJson: T,
Expand Down

0 comments on commit 34db630

Please sign in to comment.