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

Commit 8edcb89

Browse files
committed
Restructure with new packaging changes - fix func plugin with changes
1 parent 0e55904 commit 8edcb89

32 files changed

+1292
-782
lines changed

README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,35 @@ Please create issues in this repo for any problems or questions you find. Before
9696
9797
We're still in the process of getting everying running 100%, but please refer to the [Serverless contributing guidlines](https://github.com/serverless/serverless/blob/master/CONTRIBUTING.md) for information on how to contribute and code of conduct.
9898

99+
#### Local dev
100+
101+
1. Clone this repository to your local machine
102+
2. Navigate to the cloned folder
103+
3. Run `npm install`
104+
4. Run `npm run-script build`
105+
5. Navigate to a folder where you created a new Serverless project, run `npm install`, and then run `npm link {path to serverless-azure-functions folder}`. Running `npm install` after the link command may override the link.
106+
6. The npm modules should now contain your local version of this plugin.
107+
108+
#### Signing commits
109+
110+
All commits in your Pull Request will need to be signed. When looking at the commits in the pull request, you will see a green 'verified' icon next to your commit. Commit signature verification is discussed [here](https://help.github.com/en/articles/about-commit-signature-verification)
111+
112+
Follow the directions [here](https://help.github.com/en/articles/signing-commits) to configure commit signing.
113+
114+
If any of your commits are not signed, your pull request will not be able to be merged into the base branch. You can fix this by squashing any unsigned commits into signed commits using an interactive rebase, and force pushing your new commit history. More detail [here](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History)
115+
116+
When using Windows you may also encounter an error when trying to sign a commit, stating that a security key could not be found. Ensure that you have set the path the gpg in the git config: `git config --global gpg.program "C:\Program Files (x86)\GnuPG\bin\gpg.exe"`
117+
118+
#### Signing commits
119+
120+
All commits in your Pull Request will need to be signed. When looking at the commits in the pull request, you will see a green 'verified' icon next to your commit. Commit signature verification is discussed [here](https://help.github.com/en/articles/about-commit-signature-verification)
121+
122+
Follow the directions [here](https://help.github.com/en/articles/signing-commits) to configure commit signing.
123+
124+
If any of your commits are not signed, your pull request will not be able to be merged into the base branch. You can fix this by squashing any unsigned commits into signed commits using an interactive rebase, and force pushing your new commit history. More detail [here](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History)
125+
126+
When using Windows you may also encounter an error when trying to sign a commit, stating that a security key could not be found. Ensure that you have set the path the gpg in the git config: `git config --global gpg.program "C:\Program Files (x86)\GnuPG\bin\gpg.exe"`
127+
99128
## License
100129

101130
[MIT](LICENSE)

package-lock.json

Lines changed: 98 additions & 296 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"test": "jest",
1515
"test:ci": "npm run test -- --ci",
1616
"test:coverage": "npm run test -- --coverage",
17-
"prebuild": "rm lib/ -rf",
17+
"prebuild": "shx rm -rf lib/ && npm run test",
1818
"build": "tsc"
1919
},
2020
"repository": {
@@ -48,11 +48,13 @@
4848
"@babel/runtime": "^7.4.5",
4949
"@types/jest": "^24.0.13",
5050
"@types/lodash": "^4.14.130",
51+
"@types/mock-fs": "^3.6.30",
5152
"@types/open": "^6.1.0",
5253
"@types/request": "^2.48.1",
5354
"@types/serverless": "^1.18.2",
5455
"@typescript-eslint/eslint-plugin": "^1.9.0",
5556
"@typescript-eslint/parser": "^1.9.0",
57+
"axios-mock-adapter": "^1.16.0",
5658
"babel-jest": "^24.8.0",
5759
"babel-preset-react-app": "^9.0.0",
5860
"coveralls": "^3.0.3",
@@ -61,6 +63,7 @@
6163
"jest-cli": "^24.8.0",
6264
"mock-fs": "^4.10.0",
6365
"serverless": "^1.44.1",
66+
"shx": "^0.3.2",
6467
"typescript": "^3.4.5"
6568
},
6669
"optionalDependencies": {
@@ -70,4 +73,4 @@
7073
"engines": {
7174
"node": ">= 6.5.0"
7275
}
73-
}
76+
}

src/models/azureProvider.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
export interface FunctionEvent {
2+
http?: boolean;
3+
"x-azure-settings"?: {
4+
authLevel?: string;
5+
direction?: string;
6+
name?: string;
7+
};
8+
}
9+
10+
export interface ServicePrincipalEnvVariables {
11+
azureSubId: string;
12+
azureServicePrincipalClientId: string;
13+
azureServicePrincipalPassword: string;
14+
azureServicePrincipalTenantId: string;
15+
}
16+
17+
export interface FunctionMetadata {
18+
handler: string;
19+
events: FunctionEvent[];
20+
}
21+
22+
export interface AzureServiceProvider {
23+
resourceGroup: string;
24+
deploymentName: string;
25+
}

src/models/serverless.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export interface ServerlessAzureConfig {
2+
provider: {
3+
name: string;
4+
location: string;
5+
};
6+
plugins: string[];
7+
functions: any;
8+
}

src/plugins/func/azureFunc.test.ts

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
import fs from "fs";
22
import mockFs from "mock-fs";
3-
import path from "path";
3+
import rimraf from "rimraf";
44
import { MockFactory } from "../../test/mockFactory";
55
import { invokeHook } from "../../test/utils";
66
import { AzureFuncPlugin } from "./azureFunc";
7-
import rimraf from "rimraf";
87

98
describe("Azure Func Plugin", () => {
10-
9+
1110
it("displays a help message", async () => {
1211
const sls = MockFactory.createTestServerless();
1312
const options = MockFactory.createTestServerlessOptions();
13+
1414
const plugin = new AzureFuncPlugin(sls, options);
1515
await invokeHook(plugin, "func:func");
16+
1617
expect(sls.cli.log).toBeCalledWith("Use the func plugin to add or remove functions within Function App");
1718
})
1819

@@ -24,73 +25,82 @@ describe("Azure Func Plugin", () => {
2425
"index.js": "contents",
2526
"function.json": "contents",
2627
},
27-
"serverless.yml": MockFactory.createTestServerlessYml(true),
28-
}, {createCwd: true, createTmp: true})
28+
"serverless.yml": MockFactory.createTestServerlessYml(true) as any,
29+
});
2930
});
30-
31+
3132
afterAll(() => {
3233
mockFs.restore();
3334
});
3435

36+
afterEach(() => {
37+
jest.clearAllMocks();
38+
})
39+
3540
it("returns with missing name", async () => {
3641
const sls = MockFactory.createTestServerless();
3742
const options = MockFactory.createTestServerlessOptions();
43+
3844
const plugin = new AzureFuncPlugin(sls, options);
3945
await invokeHook(plugin, "func:add:add");
46+
4047
expect(sls.cli.log).toBeCalledWith("Need to provide a name of function to add")
4148
});
42-
49+
4350
it("returns with pre-existing function", async () => {
4451
const sls = MockFactory.createTestServerless();
4552
const options = MockFactory.createTestServerlessOptions();
46-
options["name"] = "myExistingFunction";
53+
options["name"] = "hello";
54+
4755
const plugin = new AzureFuncPlugin(sls, options);
4856
await invokeHook(plugin, "func:add:add");
49-
expect(sls.cli.log).toBeCalledWith("Function myExistingFunction already exists");
57+
58+
expect(sls.cli.log).toBeCalledWith("Function hello already exists");
5059
});
51-
52-
it("creates function directory and updates serverless.yml", async () => {
60+
61+
it("creates function handler and updates serverless.yml", async () => {
5362
const sls = MockFactory.createTestServerless();
5463
const options = MockFactory.createTestServerlessOptions();
5564
const functionName = "myFunction";
5665
options["name"] = functionName;
66+
const expectedFunctionsYml = MockFactory.createTestSlsFunctionConfig();
67+
expectedFunctionsYml[functionName] = MockFactory.createTestFunctionMetadata(functionName);
68+
5769
const plugin = new AzureFuncPlugin(sls, options);
58-
const mkdirSpy = jest.spyOn(fs, "mkdirSync");
70+
5971
await invokeHook(plugin, "func:add:add");
60-
expect(mkdirSpy).toBeCalledWith(functionName);
61-
const calls = (sls.utils.writeFileSync as any).mock.calls;
62-
expect(calls[0][0]).toBe(path.join(functionName, "index.js"));
63-
expect(calls[1][0]).toBe(path.join(functionName, "function.json"));
64-
const expectedFunctionsYml = MockFactory.createTestFunctionsMetadata();
65-
expectedFunctionsYml[functionName] = MockFactory.createTestFunctionMetadata();
66-
expect(calls[2][0]).toBe("serverless.yml");
67-
expect(calls[2][1]).toBe(MockFactory.createTestServerlessYml(true, expectedFunctionsYml));
72+
73+
const writeFileCalls = (sls.utils.writeFileSync as any).mock.calls;
74+
expect(writeFileCalls[0][0]).toBe(`./${functionName}.js`);
75+
76+
expect(writeFileCalls[1][0]).toBe("serverless.yml");
77+
expect(writeFileCalls[1][1]).toBe(MockFactory.createTestServerlessYml(true, expectedFunctionsYml));
6878
});
6979
});
7080

71-
describe("Remove command", () => {
72-
81+
describe("Remove command", () => {
82+
7383
beforeAll(() => {
7484
mockFs({
85+
"index.js": "contents",
7586
"function1": {
76-
"index.js": "contents",
7787
"function.json": "contents",
7888
},
79-
}, {createCwd: true, createTmp: true});
89+
});
8090
});
81-
91+
8292
afterAll(() => {
8393
mockFs.restore();
8494
});
85-
95+
8696
it("returns with missing name", async () => {
8797
const sls = MockFactory.createTestServerless();
8898
const options = MockFactory.createTestServerlessOptions();
8999
const plugin = new AzureFuncPlugin(sls, options);
90100
await invokeHook(plugin, "func:remove:remove");
91101
expect(sls.cli.log).toBeCalledWith("Need to provide a name of function to remove")
92102
});
93-
103+
94104
it("returns with non-existing function", async () => {
95105
const sls = MockFactory.createTestServerless();
96106
const options = MockFactory.createTestServerlessOptions();
@@ -99,17 +109,25 @@ describe("Azure Func Plugin", () => {
99109
await invokeHook(plugin, "func:remove:remove");
100110
expect(sls.cli.log).toBeCalledWith("Function myNonExistingFunction does not exist");
101111
});
102-
112+
103113
it("deletes directory and updates serverless.yml", async () => {
114+
mockFs({
115+
"hello.js": "contents",
116+
hello: {
117+
"function.json": "contents",
118+
}
119+
})
104120
const sls = MockFactory.createTestServerless();
105121
const options = MockFactory.createTestServerlessOptions();
106122
const plugin = new AzureFuncPlugin(sls, options);
107-
const functionName = "function1";
123+
const functionName = "hello";
108124
options["name"] = functionName;
125+
const unlinkSpy = jest.spyOn(fs, "unlinkSync");
109126
const rimrafSpy = jest.spyOn(rimraf, "sync");
110127
await invokeHook(plugin, "func:remove:remove");
128+
expect(unlinkSpy).toBeCalledWith(`${functionName}.js`)
111129
expect(rimrafSpy).toBeCalledWith(functionName);
112-
const expectedFunctionsYml = MockFactory.createTestFunctionsMetadata();
130+
const expectedFunctionsYml = MockFactory.createTestSlsFunctionConfig();
113131
delete expectedFunctionsYml[functionName];
114132
expect(sls.utils.writeFileSync).toBeCalledWith("serverless.yml", MockFactory.createTestServerlessYml(true, expectedFunctionsYml))
115133
});

src/plugins/func/azureFunc.ts

Lines changed: 6 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
import fs from "fs";
2-
import path from "path";
3-
import rimraf from "rimraf";
41
import Serverless from "serverless";
5-
import { FuncPluginUtils } from "./funcUtils";
2+
import { FuncService } from "../../services/funcService";
63

74
export class AzureFuncPlugin {
85
public hooks: { [eventName: string]: Promise<any> };
96
public commands: any;
7+
private service: FuncService;
108

119

1210
public constructor(private serverless: Serverless, private options: Serverless.Options) {
@@ -50,64 +48,19 @@ export class AzureFuncPlugin {
5048
}
5149
}
5250
}
51+
52+
this.service = new FuncService(serverless, options);
5353
}
5454

5555
private async func() {
5656
this.serverless.cli.log("Use the func plugin to add or remove functions within Function App");
5757
}
5858

5959
private async add() {
60-
if (!("name" in this.options)) {
61-
this.serverless.cli.log("Need to provide a name of function to add");
62-
return;
63-
}
64-
const funcToAdd = this.options["name"]
65-
const exists = fs.existsSync(funcToAdd);
66-
if (exists) {
67-
this.serverless.cli.log(`Function ${funcToAdd} already exists`);
68-
return;
69-
}
70-
this.createFunctionDir(funcToAdd);
71-
this.addToServerlessYml(funcToAdd);
72-
}
73-
74-
private createFunctionDir(name: string) {
75-
this.serverless.cli.log("Creating function dir");
76-
try {
77-
fs.mkdirSync(name);
78-
} catch (e) {
79-
this.serverless.cli.log(`Error making directory ${e}`);
80-
}
81-
this.serverless.utils.writeFileSync(path.join(name, "index.js"), FuncPluginUtils.getFunctionHandler(name));
82-
this.serverless.utils.writeFileSync(path.join(name, "function.json"), FuncPluginUtils.getFunctionJsonString(name, this.options));
83-
}
84-
85-
private addToServerlessYml(name: string) {
86-
this.serverless.cli.log("Adding to serverless.yml");
87-
const functionYml = FuncPluginUtils.getFunctionsYml(this.serverless);
88-
functionYml[name] = FuncPluginUtils.getFunctionSlsObject(name, this.options);
89-
FuncPluginUtils.updateFunctionsYml(this.serverless, functionYml);
60+
this.service.add();
9061
}
9162

9263
private async remove() {
93-
if (!("name" in this.options)) {
94-
this.serverless.cli.log("Need to provide a name of function to remove");
95-
return;
96-
}
97-
const funcToRemove = this.options["name"];
98-
const exists = fs.existsSync(funcToRemove);
99-
if (!exists) {
100-
this.serverless.cli.log(`Function ${funcToRemove} does not exist`);
101-
return;
102-
}
103-
this.serverless.cli.log(`Removing ${funcToRemove}`);
104-
rimraf.sync(funcToRemove);
105-
await this.removeFromServerlessYml(funcToRemove);
106-
}
107-
108-
private async removeFromServerlessYml(name: string) {
109-
const functionYml = FuncPluginUtils.getFunctionsYml(this.serverless);
110-
delete functionYml[name];
111-
FuncPluginUtils.updateFunctionsYml(this.serverless, functionYml)
64+
this.service.remove();
11265
}
11366
}

src/plugins/func/funcUtils.test.ts

Lines changed: 0 additions & 32 deletions
This file was deleted.

0 commit comments

Comments
 (0)