Skip to content
This repository was archived by the owner on May 4, 2023. It is now read-only.

Commit 59f3b3a

Browse files
Merge pull request #3 from codiga/feat/rule-command
ruleset-add command
2 parents 37b2aed + b6ad8c4 commit 59f3b3a

File tree

18 files changed

+384
-25
lines changed

18 files changed

+384
-25
lines changed

DEVELOPMENT.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212

1313
```bash
1414
npm link
15+
16+
# if you have the NPM package installed
17+
# you'll need to force this link
18+
npm link --force
1519
```
1620

1721
- You're all set now, open help to see a list of commands

graphql/queries.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,12 @@ export const GET_RULESETS_FOR_CLIENT = gql`
2727
}
2828
}
2929
`;
30+
31+
export const GET_RULESET = gql`
32+
query getRuleset($name: String!) {
33+
ruleSet(name: $name) {
34+
id
35+
name
36+
}
37+
}
38+
`;

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@codiga/cli",
3-
"version": "1.0.6",
3+
"version": "1.0.7",
44
"description": "A Codiga CLI used to integrate Codiga easily in your projects",
55
"homepage": "https://github.com/codiga/codiga-cli",
66
"repository": {

src/addRuleset.js

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import { writeFile } from "fs/promises";
2+
import { isTestMode } from "../tests/test-utils";
3+
import {
4+
ACTION_RULESET_ADD,
5+
ACTION_TOKEN_ADD,
6+
CODIGA_CONFIG_FILE,
7+
} from "../utils/constants";
8+
import { readFile, parseYamlFile } from "../utils/file";
9+
import { getGitDirectory } from "../utils/git";
10+
import {
11+
printCommandSuggestion,
12+
printEmptyLine,
13+
printFailure,
14+
printInfo,
15+
printSuggestion,
16+
} from "../utils/print";
17+
import { convertRulesetsToString, getRuleset } from "../utils/ruleset";
18+
19+
/**
20+
* Creates a codiga.yml file's content with the rulesets given
21+
* Note: because this overrides the file, you need to pass any old rulesets that should remain
22+
* @param {string[]} rulesets
23+
*/
24+
export async function createCodigaYml(codigaFileLocation, rulesets) {
25+
if (isTestMode) return;
26+
try {
27+
await writeFile(codigaFileLocation, convertRulesetsToString(rulesets), {
28+
encoding: "utf-8",
29+
});
30+
} catch (err) {
31+
// console.debug(err);
32+
printEmptyLine();
33+
printFailure(`We were unable to write to: ${codigaFileLocation}`);
34+
printSuggestion(
35+
" ↳ Please try again and contact us, if the issue persists:",
36+
"https://app.codiga.io/support"
37+
);
38+
printEmptyLine();
39+
process.exit(1);
40+
}
41+
}
42+
43+
/**
44+
* Handles adding a ruleset to a codiga.yml file
45+
* @param {string[]} rulesetNames
46+
*/
47+
export async function addRuleset(rulesetNames) {
48+
// TODO - change to a prompt when no rulesets are given
49+
const rulesetName = rulesetNames[0];
50+
if (!rulesetName) {
51+
printEmptyLine();
52+
printFailure("You need to specify a ruleset to add");
53+
printSuggestion(
54+
" ↳ You can search for rulesets here:",
55+
"https://app.codiga.io/hub/rulesets"
56+
);
57+
printCommandSuggestion(
58+
" ↳ Then follow this command structure:",
59+
`${ACTION_RULESET_ADD} <ruleset-name>`
60+
);
61+
printEmptyLine();
62+
process.exit(1);
63+
}
64+
65+
// Check if the ruleset exists before continuing onwards
66+
const ruleset = await getRuleset({ name: rulesetName });
67+
if (!ruleset) {
68+
printEmptyLine();
69+
printFailure(
70+
"That ruleset either doesn't exist or you lack the permissions to access it"
71+
);
72+
printCommandSuggestion(
73+
" ↳ Ensure you have a Codiga API token set with one of the following commands:",
74+
ACTION_TOKEN_ADD
75+
);
76+
printSuggestion(
77+
" ↳ You can find more rulesets here:",
78+
"https://app.codiga.io/hub/rulesets"
79+
);
80+
printEmptyLine();
81+
process.exit(1);
82+
}
83+
84+
/**
85+
* Get the `codiga.yml` file location and content.
86+
* We'll look in the git directory, if it exists.
87+
* Otherwise, we'll look in the current directory
88+
*/
89+
const gitDirectory = getGitDirectory();
90+
const dir = gitDirectory || process.cwd();
91+
const codigaFileLocation = `${dir}/${CODIGA_CONFIG_FILE}`;
92+
const codigaFileContent = readFile(codigaFileLocation);
93+
94+
/**
95+
* If we found a `codiga.yml` file, add the rule to it
96+
* If we don't find a `codiga.yml` file, create the file and add the rule to it
97+
*/
98+
if (codigaFileContent) {
99+
const parsedFile = parseYamlFile(codigaFileContent, codigaFileLocation);
100+
const codigaRulesets = parsedFile.rulesets;
101+
if (codigaRulesets.includes(rulesetName)) {
102+
printEmptyLine();
103+
printInfo(
104+
`The ruleset (${rulesetName}) already exists in your \`codiga.yml\``
105+
);
106+
printSuggestion;
107+
printEmptyLine();
108+
process.exit(1);
109+
} else {
110+
// adding the new ruleset to the file
111+
await createCodigaYml(codigaFileLocation, [
112+
...codigaRulesets,
113+
rulesetName,
114+
]);
115+
printSuggestion(
116+
`We added ${rulesetName} to your codiga.yml file:`,
117+
codigaFileLocation
118+
);
119+
printSuggestion(
120+
" ↳ Find more rulesets to add here:",
121+
"https://app.codiga.io/hub/rulesets"
122+
);
123+
}
124+
} else {
125+
// creating a new codiga.yml with the ruleset here
126+
await createCodigaYml(codigaFileLocation, [rulesetName]);
127+
printSuggestion(
128+
`No codiga.yml file found, so we created one and added ${rulesetName} to it:`,
129+
codigaFileLocation
130+
);
131+
printSuggestion(
132+
" ↳ Find more rulesets to add here:",
133+
"https://app.codiga.io/hub/rulesets"
134+
);
135+
}
136+
137+
process.exit(0);
138+
}

src/checkPush.js

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {
22
executeGitCommand,
33
findClosestSha,
4-
getRootDirectory,
4+
getGitDirectoryRequired,
55
} from "../utils/git";
66
import {
77
getRulesetsFromCodigaFile,
@@ -34,6 +34,18 @@ function getChangedFilePaths(remoteSHA, localSHA) {
3434
remoteSHA,
3535
localSHA,
3636
]);
37+
if (!diff) {
38+
printEmptyLine();
39+
printFailure(
40+
`We were unable to get the difference between ${remoteSHA} and ${localSHA}`
41+
);
42+
printSuggestion(
43+
" ↳ Please review your SHAs above and contact support, if needed:",
44+
"https://app.codiga.io/support"
45+
);
46+
printEmptyLine();
47+
process.exit(1);
48+
}
3749
return diff.split("\n").filter((s) => s);
3850
}
3951

@@ -90,8 +102,17 @@ export function checkSHAs(remoteShaArg, localShaArg) {
90102
* @param {string} localSHA
91103
*/
92104
export async function checkPush(remoteShaArg, localShaArg) {
105+
if (!remoteShaArg || !localShaArg) {
106+
printFailure("You need to pass in both remote and local SHA values");
107+
printSuggestion(
108+
" ↳ Refer to our documentation for more info:",
109+
"https://doc.codiga.io/docs/cli/#analysis-and-report-issues-between-two-commits"
110+
);
111+
process.exit(1);
112+
}
113+
93114
// ensure that there's a git directory to continue
94-
getRootDirectory();
115+
getGitDirectoryRequired();
95116

96117
// check and verify the SHA args
97118
const { remoteSha, localSha } = checkSHAs(remoteShaArg, localShaArg);

src/cli.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
ACTION_TOKEN_ADD,
55
ACTION_TOKEN_CHECK,
66
ACTION_TOKEN_DELETE,
7+
ACTION_RULESET_ADD,
78
OPTION_LANGUAGE,
89
OPTION_LOCAL_SHA,
910
OPTION_REMOTE_SHA,
@@ -19,6 +20,7 @@ import {
1920
checkCodigaToken,
2021
deleteCodigaToken,
2122
} from "./codigaToken";
23+
import { addRuleset } from "./addRuleset";
2224

2325
/**
2426
* Parses the given command into a readable object to execute
@@ -50,6 +52,7 @@ function parseCommand(args) {
5052
},
5153
}
5254
)
55+
.command(ACTION_RULESET_ADD, "Add a ruleset to a `codiga.yml` file")
5356
.help(true).argv;
5457

5558
// format any actions into a single object with default values
@@ -58,6 +61,7 @@ function parseCommand(args) {
5861
[ACTION_TOKEN_CHECK]: yargV["_"].includes(ACTION_TOKEN_CHECK) || false,
5962
[ACTION_TOKEN_DELETE]: yargV["_"].includes(ACTION_TOKEN_DELETE) || false,
6063
[ACTION_GIT_PUSH_HOOK]: yargV["_"].includes(ACTION_GIT_PUSH_HOOK) || false,
64+
[ACTION_RULESET_ADD]: yargV["_"].includes(ACTION_RULESET_ADD) || false,
6165
};
6266

6367
// how many actions were detected in the command ran
@@ -90,10 +94,13 @@ function parseCommand(args) {
9094
[OPTION_LANGUAGE]: yargV[OPTION_LANGUAGE] || null,
9195
};
9296

97+
const parameters = yargV["_"].slice(1);
98+
9399
// the parsed/formatted result
94100
return {
95101
action: selectedAction,
96102
options,
103+
parameters,
97104
};
98105
}
99106

@@ -105,6 +112,7 @@ export async function cli(args) {
105112
[OPTION_REMOTE_SHA]: remoteSha,
106113
[OPTION_LANGUAGE]: language,
107114
},
115+
parameters,
108116
} = parseCommand(args);
109117

110118
switch (action) {
@@ -116,6 +124,8 @@ export async function cli(args) {
116124
return await deleteCodigaToken();
117125
case ACTION_GIT_PUSH_HOOK:
118126
return await checkPush(remoteSha, localSha);
127+
case ACTION_RULESET_ADD:
128+
return await addRuleset(parameters);
119129
default:
120130
return (() => {
121131
printEmptyLine();

tests/add-ruleset.test.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { ACTION_RULESET_ADD } from "../utils/constants";
2+
import { executeCommand } from "./test-utils";
3+
4+
describe("codiga ruleset-add", () => {
5+
test("an invalid ruleset name should throw", async () => {
6+
// run the command
7+
await executeCommand([ACTION_RULESET_ADD, "invalid-ruleset"])
8+
.then((output) => {
9+
expect(output).toBeUndefined();
10+
})
11+
.catch(({ stdout }) => {
12+
expect(stdout).toMatch(
13+
/That ruleset either doesn't exist or you lack the permissions to access it/
14+
);
15+
});
16+
});
17+
18+
test("a ruleset that's already present should throw", async () => {
19+
// run the command
20+
await executeCommand([ACTION_RULESET_ADD, "great-ruleset"])
21+
.then((output) => {
22+
expect(output).toBeUndefined();
23+
})
24+
.catch(({ stdout }) => {
25+
console.log(stdout);
26+
expect(stdout).toMatch(/already exists in your/);
27+
});
28+
});
29+
});

tests/check-push.test.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,15 @@ import { executeCommand } from "./test-utils";
44
describe("codiga git-push-hook", () => {
55
test("check for same SHAs", async () => {
66
// run the command
7-
await executeCommand([ACTION_GIT_PUSH_HOOK, "1234", "1234"]).then(
8-
(output) => {
9-
expect(output).toMatch(/Remote and local SHA are the same/);
10-
}
11-
);
7+
await executeCommand([
8+
ACTION_GIT_PUSH_HOOK,
9+
"--remote-sha",
10+
"1234",
11+
"--local-sha",
12+
"1234",
13+
]).then((output) => {
14+
expect(output).toMatch(/Remote and local SHA are the same/);
15+
});
1216
});
1317

1418
test("check for closest SHA", async () => {

tests/fixtures/codiga.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
rulesets:
22
- react-best-practices
3-
- jsx-a11y
3+
- jsx-a11y
4+
- great-ruleset
5+

0 commit comments

Comments
 (0)