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

Commit 543e518

Browse files
samiyaakhtarevanlouieyradsmikham
authored
Adding spk service get-display-name command (#518)
* bedrock.yaml refactor & service create spec update - Updated bedrock.yaml `services` to contain a list of services instead of a map indexed by path. - Auto-migration of bedrock.yaml is hooked into `read()` function of the `bedrockYaml.ts` file. - `read()` is now the only function used for loading the bedrock.yaml file; `Bedrock()` in `config.ts` is now noted as deprecated and now calls `read()` under the hood. - `path` property for a service now tracks the path to the service. - Documentation references all updated. - `spk service create <service-name>` now follows the spec `spk service create <service-name> <service-path>` - Documentation references all updated. - Integration tests updated. * bedrock.yaml refactor & service create spec update - Updated bedrock.yaml `services` to contain a list of services instead of a map indexed by path. - Auto-migration of bedrock.yaml is hooked into `read()` function of the `bedrockYaml.ts` file. - `read()` is now the only function used for loading the bedrock.yaml file; `Bedrock()` in `config.ts` is now noted as deprecated and now calls `read()` under the hood. - `path` property for a service now tracks the path to the service. - Documentation references all updated. - `spk service create <service-name>` now follows the spec `spk service create <service-name> <service-path>` - Documentation references all updated. - Integration tests updated. * First pass to get display name for service from bedrock.yaml * Adding basic unit tests * Fixing generated yaml file * Removing the changes that will come after spk release is ready * Updating files * Command should be run from bedrock/yaml directory and move under * Minor changes * Use error chain * More feedback * Improve doc * Improve unit test * Separated out negative tests Co-authored-by: Evan Louie <[email protected]> Co-authored-by: Yvonne Radsmikham <[email protected]>
1 parent 69fdf8a commit 543e518

File tree

8 files changed

+172
-1
lines changed

8 files changed

+172
-1
lines changed

docs/commands/data.json

+13
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,19 @@
639639
],
640640
"markdown": "## Description\n\nAdd a new service into this initialized spk project repository.\n\n## Example\n\n```bash\nspk service create my-service . \\\n --display-name $app_name \\\n --helm-config-path $path_to_chart_in_repo \\\n --helm-config-git $helm_repo_url \\ # Needs to start with https and not contain user name\n --helm-config-branch master \\\n --helm-chart-access-token-variable $ENV_VAR_NAME\n```\n\n## Note\n\n- `--helm-chart-*` and `--helm-config-*` settings are mutually-exclusive. **You\n may only use one.**\n - If the git repository referenced in `--helm-config-git` is a private\n repository, you can specify an environment variable in your\n HLD-to-Materialized pipeline containing your a PAT to authenticate with via\n the `--helm-chart-access-token-variable` option.\n- `--middlewares`, `--k8s-backend-port`, `--path-prefix`,\n `--path-prefix-major-version`, and `--k8s-backend` are all used to configure\n the generated Traefik2 IngressRoutes. i.e.\n\n ```sh\n spk service create my-example-documents-service path/to/my/service \\\n --middlewares middleware \\\n --k8s-backend-port 3001 \\\n --k8s-backend docs-service \\\n --path-prefix documents \\\n --path-prefix-major-version v2\n ```\n\n will result in an IngressRoute that looks like:\n\n ```yaml\n apiVersion: traefik.containo.us/v1alpha1\n kind: IngressRoute\n metadata:\n name: my-example-documents-service-master\n spec:\n routes:\n - kind: Rule\n match: \"PathPrefix(`/v2/documents`) && Headers(`Ring`, `master`)\"\n middlewares:\n - name: my-example-documents-service-master\n - name: middlewareA\n services:\n - name: docs-service\n port: 3001\n ```\n"
641641
},
642+
"service get-display-name": {
643+
"command": "get-display-name",
644+
"alias": "gdn",
645+
"description": "Gets display name for a service",
646+
"options": [
647+
{
648+
"arg": "-p, --path <path>",
649+
"description": "Path to the service folder for which display name is to be extracted",
650+
"required": true
651+
}
652+
],
653+
"markdown": "## Description\n\nGets display name of a service based on the provided path by extracting this\ninformation from bedrock.yaml. This command tries to locate bedrock.yaml in the\ncurrent directory.\n\nIf bedrock.yaml is not found in current directory, the command will fail to\nextract display name.\n\nIf the specified path is not found in any services listed in bedrock.yaml, the\ndisplay name will not be extracted. Make sure that specified path matches the\npath in bedrock.yaml exactly.\n"
654+
},
642655
"service install-build-pipeline": {
643656
"command": "install-build-pipeline <service-name>",
644657
"alias": "p",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"command": "get-display-name",
3+
"alias": "gdn",
4+
"description": "Gets display name for a service",
5+
"options": [
6+
{
7+
"arg": "-p, --path <path>",
8+
"description": "Path to the service folder for which display name is to be extracted",
9+
"required": true
10+
}
11+
]
12+
}
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
## Description
2+
3+
Gets display name of a service based on the provided path by extracting this
4+
information from bedrock.yaml. This command tries to locate bedrock.yaml in the
5+
current directory.
6+
7+
If bedrock.yaml is not found in current directory, the command will fail to
8+
extract display name.
9+
10+
If the specified path is not found in any services listed in bedrock.yaml, the
11+
display name will not be extracted. Make sure that specified path matches the
12+
path in bedrock.yaml exactly.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { disableVerboseLogging, enableVerboseLogging } from "../../logger";
2+
import { execute } from "./get-display-name";
3+
import * as fs from "fs";
4+
import { createTestBedrockYaml } from "../../test/mockFactory";
5+
import { BedrockFile } from "../../types";
6+
import * as bedrockYaml from "../../lib/bedrockYaml";
7+
8+
beforeAll(() => {
9+
enableVerboseLogging();
10+
});
11+
12+
afterAll(() => {
13+
disableVerboseLogging();
14+
});
15+
16+
describe("get display name", () => {
17+
it("positive test", async () => {
18+
const exitFn = jest.fn();
19+
const defaultBedrockFileObject = createTestBedrockYaml(
20+
false
21+
) as BedrockFile;
22+
jest.spyOn(fs, "existsSync").mockReturnValue(true);
23+
jest.spyOn(bedrockYaml, "read").mockReturnValue(defaultBedrockFileObject);
24+
jest.spyOn(process, "cwd").mockReturnValue("bedrock.yaml/");
25+
const consoleSpy = jest.spyOn(console, "log");
26+
execute({ path: "./packages/service1" }, exitFn);
27+
expect(consoleSpy).toHaveBeenCalledWith("service1");
28+
expect(exitFn).toBeCalledTimes(1);
29+
expect(exitFn).toBeCalledWith(0);
30+
});
31+
it("negative test", async () => {
32+
const exitFn = jest.fn();
33+
execute({ path: "" }, exitFn);
34+
expect(exitFn).toBeCalledTimes(1);
35+
execute({ path: undefined }, exitFn);
36+
expect(exitFn).toBeCalledWith(1);
37+
const defaultBedrockFileObject = createTestBedrockYaml(
38+
false
39+
) as BedrockFile;
40+
jest.spyOn(fs, "existsSync").mockReturnValue(true);
41+
jest.spyOn(bedrockYaml, "read").mockReturnValue(defaultBedrockFileObject);
42+
jest.spyOn(process, "cwd").mockReturnValue("bedrock.yaml/");
43+
execute({ path: "./packages/service" }, exitFn); // should not exist
44+
expect(exitFn).toBeCalledTimes(3);
45+
expect(exitFn).toBeCalledWith(1);
46+
});
47+
});
+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import commander from "commander";
2+
import { read as readBedrockYaml } from "../../lib/bedrockYaml";
3+
import { build as buildCmd, exit as exitCmd } from "../../lib/commandBuilder";
4+
import { logger } from "../../logger";
5+
import decorator from "./get-display-name.decorator.json";
6+
import { build as buildError, log as logError } from "../../lib/errorBuilder";
7+
import { errorStatusCode } from "../../lib/errorStatusCode";
8+
9+
export interface CommandOptions {
10+
path: string | undefined;
11+
}
12+
13+
/**
14+
* Executes the command, can all exit function with 0 or 1
15+
* when command completed successfully or failed respectively.
16+
*
17+
* @param opts validated option values
18+
* @param exitFn exit function
19+
*/
20+
export const execute = async (
21+
opts: CommandOptions,
22+
exitFn: (status: number) => Promise<void>
23+
): Promise<void> => {
24+
// The assumption is that this command should be ran from the directory where bedrock.yaml exists
25+
try {
26+
if (!opts.path) {
27+
throw buildError(
28+
errorStatusCode.VALIDATION_ERR,
29+
"service-get-display-name-path-missing-param-err"
30+
);
31+
}
32+
const bedrockFile = readBedrockYaml(process.cwd());
33+
if (!bedrockFile) {
34+
throw buildError(
35+
errorStatusCode.FILE_IO_ERR,
36+
"service-get-display-name-bedrock-yaml-missing-err"
37+
);
38+
}
39+
40+
const serviceIndex = Object.keys(bedrockFile.services).find(
41+
(index) => opts.path === bedrockFile.services[+index].path
42+
);
43+
44+
if (serviceIndex) {
45+
console.log(bedrockFile.services[+serviceIndex].displayName);
46+
await exitFn(0);
47+
}
48+
49+
throw buildError(errorStatusCode.ENV_SETTING_ERR, {
50+
errorKey: "service-get-display-name-err",
51+
values: [opts.path],
52+
});
53+
} catch (err) {
54+
logError(
55+
buildError(
56+
errorStatusCode.VALIDATION_ERR,
57+
"service-get-display-name-generic-err",
58+
err
59+
)
60+
);
61+
await exitFn(1);
62+
}
63+
};
64+
65+
/**
66+
* Adds the get-display-name command to the commander command object
67+
* @param command Commander command object to decorate
68+
*/
69+
export const commandDecorator = (command: commander.Command): void => {
70+
buildCmd(command, decorator).action(async (opts: CommandOptions) => {
71+
await execute(opts, async (status: number) => {
72+
await exitCmd(logger, process.exit, status);
73+
});
74+
});
75+
};

src/commands/service/index.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { Command } from "../command";
22

3-
const subfolders = ["create", "create-revision", "pipeline"];
3+
const subfolders = [
4+
"create",
5+
"create-revision",
6+
"pipeline",
7+
"get-display-name",
8+
];
49

510
export const commandDecorator = Command(
611
"service",

src/lib/i18n.json

+4
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,10 @@
159159
"introspect-dashboard-cmd-launch-pre-req-err": "Requirements to launch dashboard were not met.",
160160
"introspect-dashboard-cmd-launch-err": "Could not launch dashboard docker container.",
161161

162+
"service-get-display-name-path-missing-param-err": "Value for path parameter was missing. This is required for running get-display-command. Provide it.",
163+
"service-get-display-name-bedrock-yaml-missing-err": "Could not find bedrock.yaml in current directory. Make sure to run this from a directory that contains bedrock.yaml.",
164+
"service-get-display-name-err": "Could not find a service for path {0}. Make sure that the specified path is valid.",
165+
"service-get-display-name-generic-err": "Error occurred while getting display name.",
162166
"az-cli-login-err": "Could not login through azure cli.",
163167
"az-cli-create-sp-err": "Could not create service principal with azure cli",
164168

src/test/mockFactory.ts

+3
Original file line numberDiff line numberDiff line change
@@ -291,16 +291,19 @@ export const createTestBedrockYaml = (
291291
path: "./",
292292
helm: service1HelmConfig,
293293
k8sBackendPort: 80,
294+
displayName: "root",
294295
},
295296
{
296297
path: "./packages/service1",
297298
helm: service2HelmConfig,
298299
k8sBackendPort: 80,
300+
displayName: "service1",
299301
},
300302
{
301303
path: "./zookeeper",
302304
helm: zookeeperHelmConfig,
303305
k8sBackendPort: 80,
306+
displayName: "zookeeper",
304307
},
305308
],
306309
variableGroups: [],

0 commit comments

Comments
 (0)