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

Commit fe2e40c

Browse files
[FEATURE] add error code to validation function (#491)
* [FEATURE] Adding error code to validation lib * Update data.json Co-authored-by: Samiya Akhtar <[email protected]>
1 parent aa4cb12 commit fe2e40c

File tree

8 files changed

+300
-173
lines changed

8 files changed

+300
-173
lines changed

src/commands/deployment/onboard.test.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
validateValues,
2525
} from "./onboard";
2626
import * as onboardImpl from "./onboard";
27+
import { getErrorMessage } from "../../lib/errorBuilder";
2728

2829
beforeAll(() => {
2930
enableVerboseLogging();
@@ -237,9 +238,7 @@ describe("test validateValues function", () => {
237238
vals.storageAccountName = "#123";
238239
expect(() => {
239240
validateValues(vals);
240-
}).toThrow(
241-
"The value for storage account name is invalid. Lowercase letters and numbers are allowed."
242-
);
241+
}).toThrow(getErrorMessage("validation-err-storage-account-name-invalid"));
243242
});
244243
it("[-ve]: invalid storageTableName value", () => {
245244
const vals = getMockedValues();

src/commands/hld/pipeline.test.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as azdo from "../../lib/azdoClient";
33
import { BUILD_SCRIPT_URL } from "../../lib/constants";
44
import { getRepositoryName } from "../../lib/gitutils";
55
import { disableVerboseLogging, enableVerboseLogging } from "../../logger";
6+
import { getErrorMessage } from "../../lib/errorBuilder";
67
jest.mock("../../lib/pipelines/pipelines");
78

89
import {
@@ -88,7 +89,7 @@ const orgNameTest = (hasVal: boolean): void => {
8889

8990
if (hasVal) {
9091
expect(() => populateValues(data)).toThrow(
91-
"Organization names must start with a letter or number, followed by letters, numbers or hyphens, and must end with a letter or number."
92+
getErrorMessage("validation-err-org-name")
9293
);
9394
} else {
9495
expect(() => populateValues(data)).toThrow(

src/commands/setup.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ import { create as createSetupLog } from "../lib/setup/setupLog";
4040
import { logger } from "../logger";
4141
import decorator from "./setup.decorator.json";
4242
import { createStorage } from "../lib/setup/azureStorage";
43+
import { build as buildError, log as logError } from "../lib/errorBuilder";
44+
import { errorStatusCode } from "../lib/errorStatusCode";
4345
import { ConfigYaml } from "../types";
4446

4547
interface CommandOptions {
@@ -211,15 +213,15 @@ export const execute = async (
211213
createSetupLog(rc);
212214
await exitFn(0);
213215
} catch (err) {
216+
logError(buildError(errorStatusCode.CMD_EXE_ERR, "setup-cmd-failed", err));
217+
214218
const msg = getErrorMessage(requestContext, err);
215219

216220
// requestContext will not be created if input validation failed
217221
if (requestContext) {
218222
requestContext.error = msg;
219223
}
220224
createSetupLog(requestContext);
221-
222-
logger.error(msg);
223225
await exitFn(1);
224226
}
225227
};

src/lib/errorBuilder.ts

+31-22
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,36 @@ interface ErrorParam {
88
errorKey: string;
99
values: string[];
1010
}
11+
12+
/**
13+
* Returns error message
14+
*
15+
* @param errorInstance Error instance
16+
*/
17+
export const getErrorMessage = (errorInstance: string | ErrorParam): string => {
18+
let key = "";
19+
let values: string[] | undefined = undefined;
20+
21+
if (typeof errorInstance === "string") {
22+
key = errorInstance;
23+
} else {
24+
key = errorInstance.errorKey;
25+
values = errorInstance.values;
26+
}
27+
28+
// if key is found in i18n json
29+
if (key in errors) {
30+
let results = errors[key];
31+
if (values) {
32+
values.forEach((val, i) => {
33+
const re = new RegExp("\\{" + i + "}", "g");
34+
results = results.replace(re, val);
35+
});
36+
}
37+
return `${key}: ${results}`;
38+
}
39+
return key;
40+
};
1141
class ErrorChain extends Error {
1242
errorCode: number;
1343
details: string | undefined;
@@ -25,28 +55,7 @@ class ErrorChain extends Error {
2555
* @param errorInstance Error instance
2656
*/
2757
getErrorMessage(errorInstance: string | ErrorParam): string {
28-
let key = "";
29-
let values: string[] | undefined = undefined;
30-
31-
if (typeof errorInstance === "string") {
32-
key = errorInstance;
33-
} else {
34-
key = errorInstance.errorKey;
35-
values = errorInstance.values;
36-
}
37-
38-
// if key is found in i18n json
39-
if (key in errors) {
40-
let results = errors[key];
41-
if (values) {
42-
values.forEach((val, i) => {
43-
const re = new RegExp("\\{" + i + "}", "g");
44-
results = results.replace(re, val);
45-
});
46-
}
47-
return `${key}: ${results}`;
48-
}
49-
return key;
58+
return getErrorMessage(errorInstance);
5059
}
5160
/**
5261
* Generates error messages and have them in messages array.

src/lib/i18n.json

+42-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
"storageKeVaultName": "Enter key vault name (have the value as empty and hit enter key to skip)"
1717
},
1818
"errors": {
19+
"setup-cmd-failed": "Setup command was not successfully executed.",
20+
1921
"hld-init-cmd-failed": "Hld init command was not successfully executed.",
2022
"hld-init-cmd-project-path-missing": "Value for project path was not provided. Provide it.",
2123

@@ -96,6 +98,45 @@
9698
"deployment-table-update-manifest-commit-id-failed": "Could not update manifest commit Id.",
9799
"deployment-table-update-manifest-commit-id-failed-no-generation": "No manifest generation found to update manifest commit {0}.",
98100
"deployment-table-add-src-to-acr-pipeline": "Could not add source to ACR pipeline information to storage table.",
99-
"deployment-table-add-acr-to-hld-pipeline": "Could not add ACR to HLD pipeline information to storage table."
101+
"deployment-table-add-acr-to-hld-pipeline": "Could not add ACR to HLD pipeline information to storage table.",
102+
103+
"validation-err-org-name-missing": "Organization name was missing. Provide it.",
104+
"validation-err-org-name": "Organization name must start with a letter or number, followed by letters, numbers or hyphens, and must end with a letter or number.",
105+
"validation-err-password-missing": "Password was missing. Provide it.",
106+
"validation-err-password-too-short": "Password was too short, it must be more than 8 characters long. Reenter password.",
107+
"validation-err-project-name-missing": "Project name was missing. Provide it.",
108+
"validation-err-project-name-too-long": "Project name was too long, it cannot be longer than 64 characters.",
109+
"validation-err-project-name-begin-underscore": "Project name was invalid as it cannot begin with an underscore",
110+
"validation-err-project-name-period": "Project name was invalid as it cannot begin or end with a period",
111+
"validation-err-project-name-special-char": "Project name can't contain special characters, such as / : \\ ~ & % ; @ ' \" ? < > | # $ * } { , + = [ ]",
112+
"validation-err-personal-access-token-missing": "Personal access token was missing. Provide it",
113+
114+
"validation-err-service-principal-id-missing": "Service Principal Id was missing. Provide it.",
115+
"validation-err-service-principal-id-invalid": "Service Principal Id was invalid. Check and re-enter.",
116+
"validation-err-service-principal-pwd-missing": "Service Principal Password was missing. Provide it.",
117+
"validation-err-service-principal-pwd-invalid": "Service Principal Password was invalid. Check and re-enter.",
118+
"validation-err-service-principal-tenant-id-missing": "Service Principal Tenant Id was missing. Provide it.",
119+
"validation-err-service-principal-tenant-id-invalid": "Service Principal Tenant Id was invalid. Check and re-enter.",
120+
121+
"validation-err-subscription-id-missing": "Subscription Id was missing. Provide it.",
122+
"validation-err-subscription-id-invalid": "Subscription Id was invalid. Check and re-enter.",
123+
124+
"validation-err-storage-account-name-missing": "Storage Account Name was missing. Provide it.",
125+
"validation-err-storage-account-name-invalid": "Storage Account Name was invalid. Only lowercase letters and numbers are allowed.",
126+
"validation-err-storage-account-name-length": "Storage Account Name was invalid. It has to be between 3 and 24 characters long.",
127+
"validation-err-storage-table-name-missing": "Storage Table Name was missing. Provide it.",
128+
"validation-err-storage-table-name-invalid": "The value for storage table name is invalid. It has to be alphanumeric and start with an alphabet.",
129+
"validation-err-storage-table-name-length": "The value for storage table name is invalid. It has to be between 3 and 63 characters long.",
130+
"validation-err-storage-partition-key-missing": "Storage Partition Key was missing. Provide it.",
131+
"validation-err-storage-partition-key-invalid": "The value for storage partition key is invalid. /, \\, # and ? characters are not allowed.",
132+
"validation-err-acr-missing": "Azure Container Registry Name was missing. Provide it.",
133+
"validation-err-acr-invalid": "The value for Azure Container Registry name was invalid. It has to be alphanumeric.",
134+
"validation-err-acr-length": "The value for Azure Container Registry name was invalid as it has to be between 5 and 50 characters long.",
135+
"validation-err-storage-key-vault-invalid": "Storage Key Vault was invalid as it cannot only has dash and alphanumeric characters.",
136+
"validation-err-storage-key-vault-start-letter": "Storage Key Vault was invalid as it must start with a letter.",
137+
"validation-err-storage-key-vault-end-char": "Storage Key Vault was invalid as it must end with letter or digit.",
138+
"validation-err-storage-key-vault-hyphen": "Storage Key Vault was invalid as it cannot contain consecutive hyphens.",
139+
"validation-err-storage-key-vault-length": "Storage Key Vault was invalid as it has to be between 3 and 24 characters long.",
140+
"validation-err-storage-access-key-missing": "Storage Access Key was missing. Provide it."
100141
}
101142
}

src/lib/setup/prompt.ts

+18-52
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,16 @@ import fs from "fs";
22
import inquirer from "inquirer";
33
import * as promptBuilder from "../promptBuilder";
44
import {
5-
validateAccessToken,
5+
validateAccessTokenThrowable,
66
validateACRName,
7-
validateOrgName,
8-
validateProjectName,
9-
validateServicePrincipalId,
10-
validateServicePrincipalPassword,
11-
validateServicePrincipalTenantId,
12-
validateSubscriptionId,
13-
validateStorageAccountName,
14-
validateStorageTableName,
7+
validateOrgNameThrowable,
8+
validateProjectNameThrowable,
9+
validateServicePrincipalIdThrowable,
10+
validateServicePrincipalPasswordThrowable,
11+
validateServicePrincipalTenantIdThrowable,
12+
validateSubscriptionIdThrowable,
13+
validateStorageAccountNameThrowable,
14+
validateStorageTableNameThrowable,
1515
} from "../validator";
1616
import {
1717
ACR_NAME,
@@ -182,24 +182,12 @@ export const validationServicePrincipalInfoFromFile = (
182182
// file needs to contain sp information if user
183183
// choose not to create SP
184184
if (!rc.toCreateSP) {
185-
const vSPId = validateServicePrincipalId(map.az_sp_id);
186-
if (typeof vSPId === "string") {
187-
throw new Error(vSPId);
188-
}
189-
const vSPPassword = validateServicePrincipalPassword(map.az_sp_password);
190-
if (typeof vSPPassword === "string") {
191-
throw new Error(vSPPassword);
192-
}
193-
const vSPTenantId = validateServicePrincipalTenantId(map.az_sp_tenant);
194-
if (typeof vSPTenantId === "string") {
195-
throw new Error(vSPTenantId);
196-
}
185+
validateServicePrincipalIdThrowable(map.az_sp_id);
186+
validateServicePrincipalPasswordThrowable(map.az_sp_password);
187+
validateServicePrincipalTenantIdThrowable(map.az_sp_tenant);
197188
}
198189

199-
const vSubscriptionId = validateSubscriptionId(map.az_subscription_id);
200-
if (typeof vSubscriptionId === "string") {
201-
throw new Error(vSubscriptionId);
202-
}
190+
validateSubscriptionIdThrowable(map.az_subscription_id);
203191
rc.subscriptionId = map.az_subscription_id;
204192
}
205193
};
@@ -234,32 +222,11 @@ export const getAnswerFromFile = (file: string): RequestContext => {
234222
const map = parseInformationFromFile(file);
235223
map["azdo_project_name"] = map.azdo_project_name || DEFAULT_PROJECT_NAME;
236224

237-
const vOrgName = validateOrgName(map.azdo_org_name);
238-
if (typeof vOrgName === "string") {
239-
throw new Error(vOrgName);
240-
}
241-
242-
const vProjectName = validateProjectName(map.azdo_project_name);
243-
if (typeof vProjectName === "string") {
244-
throw new Error(vProjectName);
245-
}
246-
247-
const vToken = validateAccessToken(map.azdo_pat);
248-
if (typeof vToken === "string") {
249-
throw new Error(vToken);
250-
}
251-
252-
const vStorageAccountName = validateStorageAccountName(
253-
map.az_storage_account_name
254-
);
255-
if (typeof vStorageAccountName === "string") {
256-
throw new Error(vStorageAccountName);
257-
}
258-
259-
const vStorageTable = validateStorageTableName(map.az_storage_table);
260-
if (typeof vStorageTable === "string") {
261-
throw new Error(vStorageTable);
262-
}
225+
validateOrgNameThrowable(map.azdo_org_name);
226+
validateProjectNameThrowable(map.azdo_project_name);
227+
validateAccessTokenThrowable(map.azdo_pat);
228+
validateStorageAccountNameThrowable(map.az_storage_account_name);
229+
validateStorageTableNameThrowable(map.az_storage_table);
263230

264231
const rc: RequestContext = {
265232
accessToken: map.azdo_pat,
@@ -276,7 +243,6 @@ export const getAnswerFromFile = (file: string): RequestContext => {
276243

277244
rc.toCreateAppRepo = map.az_create_app === "true";
278245
validationServicePrincipalInfoFromFile(rc, map);
279-
280246
return rc;
281247
};
282248

0 commit comments

Comments
 (0)