Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(no recent worklog): account for subtask's worklog when calculating 'no recent worklog' #260

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,3 +174,14 @@ You can create a Jira API token for your account [here](https://id.atlassian.com
"qualityReasonFieldName": "customfield_12346"
}
```

## Pull Requests
### Commits
In order to conform to the JiraLint PR standard, commits should be done with
``` sh
npm run commit
```
### Windows
Windows users will need to make an alteration to the package.json in the lib folder in order to run this script and/or the npm run test --workspaces script.
Change the test script to "test": "SET TZ=Australia/Canberra jest",

150 changes: 78 additions & 72 deletions cli/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,72 +1,78 @@
module.exports = {
parser: "@typescript-eslint/parser",
parserOptions: {
project: "tsconfig.json",
tsconfigRootDir: __dirname,
ecmaVersion: 2018,
sourceType: "module",
},
extends: ["typed-fp", "agile-digital"],
env: {
"jest/globals": true,
es6: true,
},
plugins: [
"jest",
"sonarjs",
"functional",
"@typescript-eslint",
"prettier",
"total-functions",
],
rules: {
// https://github.com/aotaduy/eslint-plugin-spellcheck
"spellcheck/spell-checker": [
"warn",
{
skipWords: [
"Argv",
"Authorised",
"assignee",
"changelog",
"changelogs",
"clc",
"codec",
"Codec",
"globals",
"io",
"issuetype",
"jira",
"Jira",
"jiralint",
"jiralintrc",
"jql",
"Kanban",
"Nullable",
"oauth",
"proxied",
"Readonly",
"readonly",
"servlet",
"sonarjs",
"subtask",
"subtasks",
"timetracking",
"unicode",
"utf8",
"Urls",
"versioned",
"worklog",
"Worklog",
"worklogs",
"yargs",
],
},
],
},
settings: {
jest: {
version: 28,
},
},
};
module.exports = {
parser: "@typescript-eslint/parser",
parserOptions: {
project: "tsconfig.json",
tsconfigRootDir: __dirname,
ecmaVersion: 2018,
sourceType: "module",
},
extends: ["typed-fp", "agile-digital"],
env: {
"jest/globals": true,
es6: true,
},
plugins: [
"jest",
"sonarjs",
"functional",
"@typescript-eslint",
"prettier",
"total-functions",
],
rules: {
"functional/prefer-immutable-types" : "off",
// https://github.com/aotaduy/eslint-plugin-spellcheck
"spellcheck/spell-checker": [
"warn",
{
skipWords: [
"Argv",
"Authorised",
"assignee",
"changelog",
"changelogs",
"clc",
"codec",
"Codec",
"globals",
"io",
"issuetype",
"jira",
"Jira",
"jiralint",
"jiralintrc",
"jql",
"Kanban",
"Nullable",
"oauth",
"proxied",
"Readonly",
"readonly",
"servlet",
"sonarjs",
"subtask",
"subtasks",
"timetracking",
"unicode",
"utf8",
"Urls",
"versioned",
"worklog",
"Worklog",
"worklogs",
"yargs",
"monday",
"tuesday",
"sunday",
"aggregatetimeoriginalestimate",
"aggregatetimespent",
],
},
],
},
settings: {
jest: {
version: 28,
},
},
};
5 changes: 0 additions & 5 deletions cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ export type RootCommand = typeof rootCommand;
* Add global arguments here using the .option function.
* E.g. const rootCommand = yargs.option('example', {type: 'string'});
*/
// eslint-disable-next-line functional/prefer-immutable-types
const rootCommand = yargs;

const CliConfig = T.readonly(
Expand Down Expand Up @@ -298,7 +297,6 @@ const verifyClient = (builder: JiraClientBuilder): JiraClient =>
*/
const config: CliConfig | undefined = findConfig(process.cwd());

// eslint-disable-next-line functional/prefer-immutable-types
export const withCommonOptions = <C extends RootCommand>(command: C) =>
command
.option(jiraProtocolOptionKey, {
Expand Down Expand Up @@ -329,13 +327,11 @@ export const withCommonOptions = <C extends RootCommand>(command: C) =>
})
.group([jiraHostOptionKey, jiraProtocolOptionKey], "Common Required:");

// eslint-disable-next-line functional/prefer-immutable-types
export const withAuthenticationOptions = <C extends RootCommand>(command: C) =>
withCommonOptions(command)
.group([jiraConsumerKeyOptionKey, jiraConsumerSecretOptionKey], "Auth:")
.demandOption([jiraHostOptionKey, jiraConsumerSecretOptionKey]);

// eslint-disable-next-line functional/prefer-immutable-types
export const withAuthOptions = <C extends RootCommand>(command: C) =>
withCommonOptions(command)
.option(jiraAccessTokenOptionKey, {
Expand Down Expand Up @@ -407,7 +403,6 @@ export const withAuthOptions = <C extends RootCommand>(command: C) =>
)
.demandOption("jira");

// eslint-disable-next-line functional/prefer-immutable-types
export const withQualityFieldsOption = <C extends RootCommand>(command: C) =>
withAuthOptions(command)
.option("qualityFieldName", {
Expand Down
4 changes: 1 addition & 3 deletions cli/src/scripts/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,13 @@ const auth = async (
: console.info(JSON.stringify(user.right, null, 2));
};

// eslint-disable-next-line functional/prefer-immutable-types
export default ({ command }: RootCommand): Argv<unknown> =>
command(
"auth",
// eslint-disable-next-line spellcheck/spell-checker
"authorises the linter to call Jira APIs and outputs the access token and secret",
// eslint-disable-next-line functional/prefer-immutable-types
(yargs) => withAuthenticationOptions(yargs),
// eslint-disable-next-line functional/no-return-void, functional/prefer-immutable-types
// eslint-disable-next-line functional/no-return-void
(args) => {
const protocol = args["jira.protocol"];
// eslint-disable-next-line functional/no-expression-statements
Expand Down
4 changes: 1 addition & 3 deletions cli/src/scripts/rate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,10 @@ const rate = async (
console.log(`Updated [${JSON.stringify(update, null, 2)}]`);
};

// eslint-disable-next-line functional/prefer-immutable-types
export default ({ command }: RootCommand): Argv<unknown> =>
command(
"rate",
"records the quality of a jira issue",
// eslint-disable-next-line functional/prefer-immutable-types
(yargs) =>
withQualityFieldsOption(yargs)
.option("key", {
Expand All @@ -45,7 +43,7 @@ export default ({ command }: RootCommand): Argv<unknown> =>
describe: "reason for assessment",
})
.demandOption(["key", "quality", "reason"]),
// eslint-disable-next-line functional/prefer-immutable-types, functional/no-return-void
// eslint-disable-next-line functional/no-return-void
(args) => {
// eslint-disable-next-line functional/no-expression-statements
void rate(
Expand Down
17 changes: 6 additions & 11 deletions cli/src/scripts/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import * as clc from "cli-color";
// eslint-disable-next-line functional/no-expression-statements
require("cli-color");

// eslint-disable-next-line functional/type-declaration-immutability
type CheckedIssue = EnhancedIssue & {
readonly action: IssueAction;
readonly reasons: readonly string[];
Expand All @@ -31,14 +32,12 @@ const checkedIssues = (
): readonly CheckedIssue[] => {
const now = readonlyDate(readonlyNow());

// eslint-disable-next-line functional/prefer-immutable-types
return issues.map((issue) => {
const customChecks: readonly Check[] = [] as const; // TODO ability to dynamically load custom checks
const issueAction = issueActionRequired(issue, now, customChecks);

const issueQuality = quality(issueAction);

// eslint-disable-next-line functional/prefer-immutable-types
const reasons: readonly string[] = issueAction.checks.flatMap((check) =>
check.outcome === "warn" || check.outcome === "fail" ? check.reasons : []
);
Expand Down Expand Up @@ -86,7 +85,7 @@ const renderTable = (
// Simple visual representation of the degree of alarm a viewer should feel.
// More whimsical emoji (e.g. 👀) raise some issues with rendering of wide
// unicode characters.
// eslint-disable-next-line functional/prefer-immutable-types

const alarm = ["⠀", "⠁", "⠉", "⠋", "⠛", "⣿"] as const;

const tableHeaderWidths: readonly number[] = tableHeaders.map(
Expand All @@ -105,7 +104,6 @@ const renderTable = (
const data: readonly (readonly (readonly [
string,
readonly clc.Format[]
// eslint-disable-next-line functional/prefer-immutable-types
])[])[] = checkedIssues(issues).map((issue) => {
const originalEstimateSeconds =
issue.fields.timetracking.originalEstimateSeconds ?? 0;
Expand Down Expand Up @@ -157,9 +155,7 @@ const renderTable = (
];
});

// eslint-disable-next-line functional/prefer-immutable-types
const calculatedWidths = data.reduce((previous, current) => {
// eslint-disable-next-line functional/prefer-immutable-types
return current.map(([value], index) =>
Math.max(stringLength(value) + 1, previous[index] ?? 0)
);
Expand All @@ -170,7 +166,7 @@ const renderTable = (
// eslint-disable-next-line functional/no-return-void
): void => {
const initialValue: Readonly<CLUI.Line> = new CLUI.Line(outputBuffer);
// eslint-disable-next-line functional/prefer-immutable-types

const columns: Readonly<CLUI.Line> = row.reduce((line, [text], index) => {
const columnWidth = calculatedWidths[index] ?? 0;
return line.column(text, columnWidth);
Expand All @@ -180,7 +176,7 @@ const renderTable = (
columns.fill().store();
};

// eslint-disable-next-line functional/no-expression-statements, functional/prefer-immutable-types
// eslint-disable-next-line functional/no-expression-statements
renderRow(tableHeaders.map((header) => [header, [clc.cyan]]));

// eslint-disable-next-line functional/no-expression-statements
Expand Down Expand Up @@ -228,12 +224,11 @@ type OutputMode = "json" | "table";

const DEFAULT_OUTPUT_MODE: OutputMode = "table";

// eslint-disable-next-line functional/prefer-immutable-types
export default ({ command }: RootCommand): Argv<unknown> =>
command(
"search",
"searches for jira issues using JQL and then lints",
// eslint-disable-next-line functional/prefer-immutable-types

(yargs) =>
withQualityFieldsOption(yargs)
.option("jql", {
Expand Down Expand Up @@ -262,7 +257,7 @@ export default ({ command }: RootCommand): Argv<unknown> =>
default: [],
})
.demandOption(["jql"]),
// eslint-disable-next-line functional/no-return-void, functional/prefer-immutable-types
// eslint-disable-next-line functional/no-return-void
(args) => {
// eslint-disable-next-line functional/no-expression-statements
void search(
Expand Down
6 changes: 6 additions & 0 deletions lib/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ module.exports = {
"total-functions",
],
rules: {
"functional/prefer-immutable-types" : "off",
// https://github.com/aotaduy/eslint-plugin-spellcheck
"spellcheck/spell-checker": [
"warn",
Expand Down Expand Up @@ -66,6 +67,11 @@ module.exports = {
"Worklog",
"worklogs",
"yargs",
"monday",
"tuesday",
"sunday",
"aggregatetimeoriginalestimate",
"aggregatetimespent",
],
},
],
Expand Down
1 change: 0 additions & 1 deletion lib/src/codecs/null_or_missing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,5 @@ import * as ITT from "io-ts-types";
* @param t the type of the property - if it is supplied and not null.
* @returns a codec that will treat missing property or null value as undefined.
*/
// eslint-disable-next-line functional/prefer-immutable-types
export const nullOrMissingToUndefined = <P, O = P>(t: T.Type<P, O>) =>
T.readonly(ITT.fromNullable(T.union([t, T.undefined]), undefined));
4 changes: 0 additions & 4 deletions lib/src/codecs/readonly_date.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@ import fc from "fast-check";
describe("decoding a Date", () => {
it("should decode a date to a readonly date", () => {
fc.assert(
// eslint-disable-next-line functional/prefer-immutable-types
fc.property(fc.date(), (d) => {
// Given a date,

// When it is decoded to a readonly date.
const actual = readonlyDateFromDate.decode(d);

Expand All @@ -31,10 +29,8 @@ describe("decoding a Date", () => {
describe("decoding a string", () => {
it("should decode an ISO formatted string to a readonly date", () => {
fc.assert(
// eslint-disable-next-line functional/prefer-immutable-types
fc.property(fc.date(), (d) => {
// Given a date,

// That has been encoded as a ISO string.
const isoDate = ITT.DateFromISOString.encode(d);

Expand Down
Loading