Skip to content
This repository was archived by the owner on Apr 13, 2020. It is now read-only.

Commit cca8c28

Browse files
mtarngdennisseah
andauthored
Scaffolding base spk ring commands (#362)
* Scaffolding base spk ring commands * disabling ring commands * add -> create * removing rings from spk command Co-authored-by: Dennis Seah <dennis.seah@gmail.com>
1 parent 2d28e0e commit cca8c28

File tree

14 files changed

+590
-0
lines changed

14 files changed

+590
-0
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"command": "create <ring-name>",
3+
"alias": "c",
4+
"description": "Create a new ring for the current working directory project repository. This will affect all services within the project repository.",
5+
"disabled": true
6+
}

src/commands/ring/create.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
## Description
2+
3+
SPK command to create a ring into an initialized bedrock project.
4+
5+
## Example
6+
7+
For a bedrock.yaml file that looks like this:
8+
9+
```yaml
10+
rings:
11+
dev:
12+
isDefault: true
13+
qa:
14+
prod:
15+
services:
16+
./:
17+
displayName: "fabrikam"
18+
helm:
19+
chart:
20+
branch: master
21+
git: "https://dev.azure.com/fabrikam/frontend/_git/charts"
22+
path: frontend
23+
k8sBackend: "fabrikam-k8s-svc"
24+
k8sBackendPort: 80
25+
middlewares: []
26+
pathPrefix: "fabrikam-service"
27+
pathPrefixMajorVersion: "v1"
28+
variableGroups:
29+
- fabrikam-vg
30+
```
31+
32+
running `spk ring create stage` will result in a few changes:
33+
34+
1. `stage` will be added into `bedrock.yaml` rings component:
35+
```yaml
36+
rings:
37+
dev:
38+
isDefault: true
39+
qa:
40+
prod:
41+
stage:
42+
services:
43+
./:
44+
displayName: "fabrikam"
45+
helm:
46+
chart:
47+
branch: master
48+
git: "https://dev.azure.com/fabrikam/frontend/_git/charts"
49+
path: frontend
50+
k8sBackend: "fabrikam-k8s-svc"
51+
k8sBackendPort: 80
52+
middlewares: []
53+
pathPrefix: "fabrikam-service"
54+
pathPrefixMajorVersion: "v1"
55+
variableGroups:
56+
- fabrikam-vg
57+
```
58+
2. Each of the referenced services within `bedrock.yaml` will have their
59+
`build-update-hld.yaml` updated to include the new ring, `stage` in their
60+
branch triggers:
61+
62+
```yaml
63+
trigger:
64+
branches:
65+
include:
66+
- dev
67+
- qa
68+
- prod
69+
- stage <-- NEW -->
70+
variables:
71+
- group: fabrikam-vg
72+
73+
```
74+
75+
3. Commiting these changes will trigger the project's lifecycle pipeline, which
76+
will then scaffold out the newly created ring, along with the appropriate
77+
IngressRoutes in the linked HLD repository.

src/commands/ring/create.test.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { create as createBedrockYaml } from "../../lib/bedrockYaml";
2+
import { createTempDir } from "../../lib/ioUtil";
3+
import { disableVerboseLogging, enableVerboseLogging } from "../../logger";
4+
5+
import { checkDependencies, execute } from "./create";
6+
7+
beforeAll(() => {
8+
enableVerboseLogging();
9+
});
10+
11+
afterAll(() => {
12+
disableVerboseLogging();
13+
});
14+
15+
describe("test valid function", () => {
16+
it("negative test", async () => {
17+
try {
18+
const tmpDir = createBedrockYaml();
19+
checkDependencies(tmpDir);
20+
expect(true).toBe(false);
21+
} catch (e) {
22+
expect(e).not.toBeNull();
23+
}
24+
});
25+
});
26+
27+
describe("test execute function and logic", () => {
28+
it("test execute function: missing project path", async () => {
29+
const exitFn = jest.fn();
30+
await execute("ring", "", exitFn);
31+
expect(exitFn).toBeCalledTimes(1);
32+
expect(exitFn.mock.calls).toEqual([[1]]);
33+
});
34+
it("test execute function: working path with bedrock.yaml", async () => {
35+
const exitFn = jest.fn();
36+
37+
const tmpDir = createTempDir();
38+
createBedrockYaml(tmpDir, {
39+
rings: {
40+
master: {
41+
isDefault: true
42+
}
43+
},
44+
services: {},
45+
variableGroups: ["testvg"]
46+
});
47+
await execute("ring", tmpDir, exitFn);
48+
49+
expect(exitFn).toBeCalledTimes(1);
50+
expect(exitFn.mock.calls).toEqual([[0]]);
51+
});
52+
});

src/commands/ring/create.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import commander from "commander";
2+
import { fileInfo as bedrockFileInfo } from "../../lib/bedrockYaml";
3+
import { build as buildCmd, exit as exitCmd } from "../../lib/commandBuilder";
4+
import { PROJECT_INIT_DEPENDENCY_ERROR_MESSAGE } from "../../lib/constants";
5+
import { hasValue } from "../../lib/validator";
6+
import { logger } from "../../logger";
7+
import { IBedrockFileInfo } from "../../types";
8+
9+
import decorator from "./create.decorator.json";
10+
11+
/**
12+
* Executes the command.
13+
*
14+
* @param ringName
15+
* @param projectPath
16+
*/
17+
export const execute = async (
18+
ringName: string,
19+
projectPath: string,
20+
exitFn: (status: number) => Promise<void>
21+
) => {
22+
if (!hasValue(ringName)) {
23+
await exitFn(1);
24+
return;
25+
}
26+
27+
try {
28+
logger.info(`project path: ${projectPath}`);
29+
30+
checkDependencies(projectPath);
31+
32+
// Check if ring already exists, if it does, warn and exit
33+
// Add ring to bedrock.yaml
34+
// Add ring to all linked service build pipelines' branch triggers
35+
36+
logger.info(`Successfully created ring: ${ringName} for this project!`);
37+
await exitFn(0);
38+
} catch (err) {
39+
logger.error(`Error occurred while creating ring: ${ringName}`);
40+
logger.error(err);
41+
await exitFn(1);
42+
}
43+
};
44+
45+
export const commandDecorator = (command: commander.Command): void => {
46+
buildCmd(command, decorator).action(async (ringName: string) => {
47+
await execute(ringName, process.cwd(), async (status: number) => {
48+
await exitCmd(logger, process.exit, status);
49+
});
50+
});
51+
};
52+
53+
/**
54+
* Check for bedrock.yaml
55+
* @param projectPath
56+
*/
57+
export const checkDependencies = (projectPath: string) => {
58+
const fileInfo: IBedrockFileInfo = bedrockFileInfo(projectPath);
59+
if (fileInfo.exist === false) {
60+
throw new Error(PROJECT_INIT_DEPENDENCY_ERROR_MESSAGE);
61+
}
62+
};
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"command": "delete <ring-name>",
3+
"alias": "d",
4+
"description": "Delete a ring from the current working directory project repository. This will affect all services within the project repository. The default ring cannot be deleted.",
5+
"disabled": true
6+
}

src/commands/ring/delete.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
## Description
2+
3+
SPK command to remove a ring from an initialized bedrock project.
4+
5+
_Note:_ A default ring cannot be removed. First set another ring as the default
6+
via `spk ring set-default` before deleting.
7+
8+
## Example
9+
10+
For a bedrock.yaml file that looks like this:
11+
12+
```yaml
13+
rings:
14+
dev:
15+
isDefault: true
16+
qa:
17+
prod:
18+
services:
19+
./:
20+
displayName: "fabrikam"
21+
helm:
22+
chart:
23+
branch: master
24+
git: "https://dev.azure.com/fabrikam/frontend/_git/charts"
25+
path: frontend
26+
k8sBackend: "fabrikam-k8s-svc"
27+
k8sBackendPort: 80
28+
middlewares: []
29+
pathPrefix: "fabrikam-service"
30+
pathPrefixMajorVersion: "v1"
31+
variableGroups:
32+
- fabrikam-vg
33+
```
34+
35+
running `spk ring delete prod` will result in a few changes:
36+
37+
1. `prod` will be removed from `bedrock.yaml`:
38+
```yaml
39+
rings:
40+
dev:
41+
isDefault: true
42+
qa:
43+
services:
44+
./:
45+
displayName: "fabrikam"
46+
helm:
47+
chart:
48+
branch: master
49+
git: "https://dev.azure.com/fabrikam/frontend/_git/charts"
50+
path: frontend
51+
k8sBackend: "fabrikam-k8s-svc"
52+
k8sBackendPort: 80
53+
middlewares: []
54+
pathPrefix: "fabrikam-service"
55+
pathPrefixMajorVersion: "v1"
56+
variableGroups:
57+
- fabrikam-vg
58+
```
59+
2. Each of the referenced services within `bedrock.yaml` will have their
60+
`build-update-hld.yaml` updated to remove the ring, `prod` in their branch
61+
triggers:
62+
63+
```yaml
64+
trigger:
65+
branches:
66+
include:
67+
- dev
68+
- qa
69+
# - prod <-- THIS WILL BE DELETED! -->
70+
variables:
71+
- group: fabrikam-vg
72+
73+
```
74+
75+
3. Commiting these changes will trigger the project's lifecycle pipeline, which
76+
will then remove the ring from linked services in this project,
77+
[pending this epic](https://github.com/microsoft/bedrock/issues/858).

src/commands/ring/delete.test.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { create as createBedrockYaml } from "../../lib/bedrockYaml";
2+
import { createTempDir } from "../../lib/ioUtil";
3+
import { disableVerboseLogging, enableVerboseLogging } from "../../logger";
4+
5+
import { checkDependencies, execute } from "./delete";
6+
7+
beforeAll(() => {
8+
enableVerboseLogging();
9+
});
10+
11+
afterAll(() => {
12+
disableVerboseLogging();
13+
});
14+
15+
describe("test valid function", () => {
16+
it("negative test", async () => {
17+
try {
18+
const tmpDir = createBedrockYaml();
19+
checkDependencies(tmpDir);
20+
expect(true).toBe(false);
21+
} catch (e) {
22+
expect(e).not.toBeNull();
23+
}
24+
});
25+
});
26+
27+
describe("test execute function and logic", () => {
28+
it("test execute function: missing project path", async () => {
29+
const exitFn = jest.fn();
30+
await execute("ring", "", exitFn);
31+
expect(exitFn).toBeCalledTimes(1);
32+
expect(exitFn.mock.calls).toEqual([[1]]);
33+
});
34+
it("test execute function: working path with bedrock.yaml", async () => {
35+
const exitFn = jest.fn();
36+
37+
const tmpDir = createTempDir();
38+
createBedrockYaml(tmpDir, {
39+
rings: {
40+
master: {
41+
isDefault: true
42+
}
43+
},
44+
services: {},
45+
variableGroups: ["testvg"]
46+
});
47+
await execute("ring", tmpDir, exitFn);
48+
49+
expect(exitFn).toBeCalledTimes(1);
50+
expect(exitFn.mock.calls).toEqual([[0]]);
51+
});
52+
});

0 commit comments

Comments
 (0)