Skip to content
This repository was archived by the owner on Dec 9, 2024. It is now read-only.

Commit 34db630

Browse files
authored
feat: List deployments sub-command for deploy plugin (#176)
Resolves [AB#352]
1 parent 0d32d2d commit 34db630

File tree

7 files changed

+109
-3
lines changed

7 files changed

+109
-3
lines changed

src/plugins/deploy/azureDeployPlugin.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ import { ResourceService } from "../../services/resourceService";
1010
import { Site } from "@azure/arm-appservice/esm/models";
1111

1212
describe("Deploy plugin", () => {
13+
14+
afterEach(() => {
15+
jest.resetAllMocks();
16+
})
17+
1318
it("calls deploy hook", async () => {
1419
const deployResourceGroup = jest.fn();
1520
const functionAppStub: Site = MockFactory.createTestSite();
@@ -30,4 +35,33 @@ describe("Deploy plugin", () => {
3035
expect(deploy).toBeCalled();
3136
expect(uploadFunctions).toBeCalledWith(functionAppStub);
3237
});
38+
39+
it("lists deployments", async () => {
40+
const deployments = MockFactory.createTestDeployments();
41+
ResourceService.prototype.getDeployments = jest.fn(() => Promise.resolve(deployments));
42+
const sls = MockFactory.createTestServerless();
43+
const options = MockFactory.createTestServerlessOptions();
44+
const plugin = new AzureDeployPlugin(sls, options);
45+
await invokeHook(plugin, "deploy:list:list");
46+
let expectedLogStatement = "\n\nDeployments";
47+
for (const dep of deployments) {
48+
expectedLogStatement += "\n-----------\n"
49+
expectedLogStatement += `Name: ${dep.name}\n`
50+
expectedLogStatement += `Timestamp: ${dep.properties.timestamp.getTime()}\n`;
51+
expectedLogStatement += `Datetime: ${dep.properties.timestamp.toISOString()}\n`
52+
}
53+
expectedLogStatement += "-----------\n"
54+
expect(sls.cli.log).lastCalledWith(expectedLogStatement);
55+
});
56+
57+
it("logs empty deployment list", async () => {
58+
const sls = MockFactory.createTestServerless();
59+
const resourceGroup = "rg1";
60+
ResourceService.prototype.getDeployments = jest.fn(() => Promise.resolve([])) as any;
61+
ResourceService.prototype.getResourceGroup = jest.fn(() => resourceGroup);
62+
const options = MockFactory.createTestServerlessOptions();
63+
const plugin = new AzureDeployPlugin(sls, options);
64+
await invokeHook(plugin, "deploy:list:list");
65+
expect(sls.cli.log).lastCalledWith(`No deployments found for resource group '${resourceGroup}'`);
66+
});
3367
});

src/plugins/deploy/azureDeployPlugin.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,46 @@ import { FunctionAppService } from "../../services/functionAppService";
44

55
export class AzureDeployPlugin {
66
public hooks: { [eventName: string]: Promise<any> };
7+
public commands: any;
78

89
public constructor(private serverless: Serverless, private options: Serverless.Options) {
910
this.hooks = {
10-
"deploy:deploy": this.deploy.bind(this)
11+
"deploy:deploy": this.deploy.bind(this),
12+
"deploy:list:list": this.list.bind(this),
1113
};
14+
15+
this.commands = {
16+
deploy: {
17+
commands: {
18+
list: {
19+
usage: "List deployments",
20+
lifecycleEvents: [
21+
"list"
22+
]
23+
}
24+
}
25+
}
26+
}
27+
}
28+
29+
private async list() {
30+
this.serverless.cli.log("Listing deployments");
31+
const resourceService = new ResourceService(this.serverless, this.options);
32+
const deployments = await resourceService.getDeployments();
33+
if (!deployments || deployments.length === 0) {
34+
this.serverless.cli.log(`No deployments found for resource group '${resourceService.getResourceGroup()}'`);
35+
return;
36+
}
37+
let stringDeployments = "\n\nDeployments";
38+
39+
for (const dep of deployments) {
40+
stringDeployments += "\n-----------\n"
41+
stringDeployments += `Name: ${dep.name}\n`
42+
stringDeployments += `Timestamp: ${dep.properties.timestamp.getTime()}\n`;
43+
stringDeployments += `Datetime: ${dep.properties.timestamp.toISOString()}\n`
44+
}
45+
stringDeployments += "-----------\n"
46+
this.serverless.cli.log(stringDeployments);
1247
}
1348

1449
private async deploy() {

src/plugins/login/loginPlugin.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ export class AzureLoginPlugin {
1010
this.provider = (this.serverless.getProvider("azure") as any) as AzureProvider;
1111

1212
this.hooks = {
13-
"before:package:initialize": this.login.bind(this)
13+
"before:package:initialize": this.login.bind(this),
14+
"before:deploy:list:list": this.login.bind(this),
1415
};
1516
}
1617

src/services/baseService.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ export abstract class BaseService {
3333
}
3434
}
3535

36+
public getResourceGroup(): string {
37+
return this.resourceGroup;
38+
}
39+
3640
/**
3741
* Sends an API request using axios HTTP library
3842
* @param method The HTTP method

src/services/resourceService.test.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ jest.mock("@azure/arm-resources")
66
import { ResourceManagementClient } from "@azure/arm-resources";
77

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

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

1617
ResourceManagementClient.prototype.deployments = {
17-
deleteMethod: jest.fn()
18+
deleteMethod: jest.fn(),
19+
listByResourceGroup: jest.fn(() => Promise.resolve(deployments)),
1820
} as any;
1921
});
2022

@@ -70,4 +72,15 @@ describe("Resource Service", () => {
7072
expect(ResourceManagementClient.prototype.resourceGroups.deleteMethod)
7173
.toBeCalledWith(resourceGroup);
7274
});
75+
76+
it("lists deployments", async () => {
77+
const sls = MockFactory.createTestServerless();
78+
const resourceGroup = "myResourceGroup";
79+
sls.service.provider["resourceGroup"] = resourceGroup
80+
sls.variables["azureCredentials"] = "fake credentials"
81+
const options = MockFactory.createTestServerlessOptions();
82+
const service = new ResourceService(sls, options);
83+
const deps = await service.getDeployments();
84+
expect(deps).toEqual(deployments);
85+
});
7386
});

src/services/resourceService.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ export class ResourceService extends BaseService {
1111
this.resourceClient = new ResourceManagementClient(this.credentials, this.subscriptionId);
1212
}
1313

14+
public async getDeployments() {
15+
this.log(`Listing deployments for resource group '${this.resourceGroup}':`);
16+
return await this.resourceClient.deployments.listByResourceGroup(this.resourceGroup);
17+
}
18+
1419
public async deployResourceGroup() {
1520
this.log(`Creating resource group: ${this.resourceGroup}`);
1621

src/test/mockFactory.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { ServerlessAzureConfig } from "../models/serverless";
1313
import { AzureServiceProvider, ServicePrincipalEnvVariables } from "../models/azureProvider"
1414
import { Logger } from "../models/generic";
1515
import { ApiCorsPolicy } from "../models/apiManagement";
16+
import { DeploymentsListByResourceGroupResponse } from "@azure/arm-resources/esm/models";
1617

1718
function getAttribute(object: any, prop: string, defaultValue: any): any {
1819
if (object && object[prop]) {
@@ -140,6 +141,19 @@ export class MockFactory {
140141
return credentials;
141142
}
142143

144+
public static createTestDeployments(count: number = 5): DeploymentsListByResourceGroupResponse {
145+
const result = [];
146+
for (let i = 0; i < count; i++) {
147+
result.push({
148+
name: `deployment${i+1}`,
149+
properties: {
150+
timestamp: new Date(),
151+
}
152+
})
153+
}
154+
return result as DeploymentsListByResourceGroupResponse
155+
}
156+
143157
public static createTestAxiosResponse<T>(
144158
config: AxiosRequestConfig,
145159
responseJson: T,

0 commit comments

Comments
 (0)