diff --git a/.gitignore b/.gitignore index 8b694cb..8598652 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,4 @@ commitfile.txt logs.html buildData.json __temporaryTestData__/ -log*.html \ No newline at end of file +*.html \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index 9d060d3..2e30805 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -16,6 +16,13 @@ "request": "launch", "type": "node-terminal" }, + { + "command": "scope --find-refs src/ts/models/Model.ts", + "name": "scope --find-refs", + "request": "launch", + "type": "node-terminal", + "cwd": "${workspaceFolder}/test/_repo" + }, { "name": "Debug Jest Tests (Windows)", "type": "node", diff --git a/README.md b/README.md index 5bf0a69..19f5ecb 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,11 @@ From the repository you want to test the package run npm i scope-tags -D ``` +Make sure your Git configuration has case-sensitivity enabled +``` +git config --global core.ignorecase false +``` + ### How to run From the repository you want to test the package run diff --git a/adf.json b/adf.json new file mode 100644 index 0000000..4f8e1c9 --- /dev/null +++ b/adf.json @@ -0,0 +1 @@ + {"type":"doc","version":1,"content":[{"type":"expand","attrs":{"title":"'Project' scope tags v0.3.0 │ 20.05.2024 13:57 │ -"},"content":[{"type":"table","content":[{"type":"tableRow","content":[{"type":"tableHeader","content":[{"type":"paragraph","content":[{"type":"text","text":"Affected tags","marks":[{"type":"strong"}]}]}]},{"type":"tableHeader","attrs":{"colwidth":[20]},"content":[{"type":"paragraph","content":[{"type":"text","text":"Lines","marks":[{"type":"strong"}]}]}]},{"type":"tableHeader","content":[{"type":"paragraph","content":[{"type":"text","text":"Used by module","marks":[{"type":"strong"}]}]}]},{"type":"tableHeader","content":[{"type":"paragraph","content":[{"type":"text","text":"Used by tags","marks":[{"type":"strong"}]}]}]}]},{"type":"tableRow","content":[{"type":"tableHeader","attrs":{},"content":[{"type":"paragraph","content":[{"type":"text","text":"Default module / Tag"}]}]},{"type":"tableHeader","attrs":{},"content":[{"type":"paragraph","content":[{"type":"text","text":"++ 60\n-- 27"}]}]},{"type":"tableHeader","attrs":{},"content":[{"type":"nestedExpand","attrs":{"title":"Default module"},"content":[{"type":"paragraph","content":[{"type":"text","text":"Tag"}]}]},{"type":"nestedExpand","attrs":{"title":"Third module"},"content":[{"type":"paragraph","content":[{"type":"text","text":"Some new tag"}]}]},{"type":"nestedExpand","attrs":{"title":"Fourth module"},"content":[{"type":"paragraph","content":[{"type":"text","text":"Fourth tag"}]}]},{"type":"nestedExpand","attrs":{"title":"5 untagged files"},"content":[{"type":"paragraph","content":[{"type":"text","text":"src/Relevancy/RelevancyManager.ts\nsrc/References/TSReferenceFinder.ts\nsrc/Logger/Logger.ts\nsrc/Git/Types.ts\nsrc/HTMLCreator/HTMLCreator.ts"}]}]}]},{"type":"tableHeader","attrs":{},"content":[{"type":"nestedExpand","attrs":{"title":"Tag"},"content":[{"type":"paragraph","content":[{"type":"text","text":"Default module"}]}]},{"type":"nestedExpand","attrs":{"title":"Some new tag"},"content":[{"type":"paragraph","content":[{"type":"text","text":"Third module"}]}]},{"type":"nestedExpand","attrs":{"title":"Fourth tag"},"content":[{"type":"paragraph","content":[{"type":"text","text":"Fourth module"}]}]}]}]},{"type":"tableRow","content":[{"type":"tableHeader","attrs":{},"content":[{"type":"paragraph","content":[{"type":"text","text":"Fourth module / Fourth tag"}]}]},{"type":"tableHeader","attrs":{},"content":[{"type":"paragraph","content":[{"type":"text","text":"++ 56\n-- 21"}]}]},{"type":"tableHeader","attrs":{},"content":[{"type":"paragraph","content":[{"type":"text","text":"1 modules hidden by low relevancy"}]}]},{"type":"tableHeader","attrs":{},"content":[{"type":"paragraph","content":[{"type":"text","text":"1 tags hidden by low relevancy"}]}]}]},{"type":"tableRow","content":[{"type":"tableHeader","attrs":{},"content":[{"type":"paragraph","content":[{"type":"text","text":"Third module / Some new tag"}]}]},{"type":"tableHeader","attrs":{},"content":[{"type":"paragraph","content":[{"type":"text","text":"++ 21\n-- 12"}]}]},{"type":"tableHeader","attrs":{},"content":[{"type":"nestedExpand","attrs":{"title":"Default module"},"content":[{"type":"paragraph","content":[{"type":"text","text":"Tag"}]}]},{"type":"nestedExpand","attrs":{"title":"Fourth module"},"content":[{"type":"paragraph","content":[{"type":"text","text":"Fourth tag"}]}]},{"type":"nestedExpand","attrs":{"title":"Second module"},"content":[{"type":"paragraph","content":[{"type":"text","text":"asdflkj"}]}]},{"type":"nestedExpand","attrs":{"title":"2 untagged files"},"content":[{"type":"paragraph","content":[{"type":"text","text":"src/Logger/Logger.ts\nsrc/HTMLCreator/HTMLCreator.ts"}]}]}]},{"type":"tableHeader","attrs":{},"content":[{"type":"nestedExpand","attrs":{"title":"Tag"},"content":[{"type":"paragraph","content":[{"type":"text","text":"Default module"}]}]},{"type":"nestedExpand","attrs":{"title":"Fourth tag"},"content":[{"type":"paragraph","content":[{"type":"text","text":"Fourth module"}]}]},{"type":"nestedExpand","attrs":{"title":"asdflkj"},"content":[{"type":"paragraph","content":[{"type":"text","text":"Second module"}]}]}]}]},{"type":"tableRow","content":[{"type":"tableHeader","attrs":{},"content":[{"type":"nestedExpand","attrs":{"title":"1 untagged file"},"content":[{"type":"paragraph","content":[{"type":"text","text":"src/Relevancy/RelevancyManager.ts"}]}]}]},{"type":"tableHeader","attrs":{},"content":[{"type":"paragraph","content":[{"type":"text","text":"++ 1\n-- 1"}]}]},{"type":"tableHeader","attrs":{},"content":[{"type":"nestedExpand","attrs":{"title":"Default module"},"content":[{"type":"paragraph","content":[{"type":"text","text":"Tag"}]}]},{"type":"nestedExpand","attrs":{"title":"Fourth module"},"content":[{"type":"paragraph","content":[{"type":"text","text":"Fourth tag"}]}]},{"type":"nestedExpand","attrs":{"title":"Second module"},"content":[{"type":"paragraph","content":[{"type":"text","text":"asdflkj"}]}]},{"type":"nestedExpand","attrs":{"title":"5 untagged files"},"content":[{"type":"paragraph","content":[{"type":"text","text":"src/Git/GitRepository.ts\nsrc/Commands/runVerifyCommand.ts\nsrc/Commands/runVerifyUnpushedCommitsCommand.ts\nsrc/Logger/Logger.ts\nsrc/Commands/runLogCommitCommand.ts"}]}]}]},{"type":"tableHeader","attrs":{},"content":[{"type":"nestedExpand","attrs":{"title":"Tag"},"content":[{"type":"paragraph","content":[{"type":"text","text":"Default module"}]}]},{"type":"nestedExpand","attrs":{"title":"Fourth tag"},"content":[{"type":"paragraph","content":[{"type":"text","text":"Fourth module"}]}]},{"type":"nestedExpand","attrs":{"title":"asdflkj"},"content":[{"type":"paragraph","content":[{"type":"text","text":"Second module"}]}]}]}]}],"attrs":{"layout":"full-width"}}]}]} \ No newline at end of file diff --git a/log.html b/log.html deleted file mode 100644 index b44febc..0000000 --- a/log.html +++ /dev/null @@ -1,391 +0,0 @@ - - - - - - - - build-123 - Scope Tags - - -
- Instructions -

build-123

-
-
- - - - - - - - - - - - - - - - - - - - - - - - - -
Configuration
Package version0.2.9
Current date2024-5-15 15:34:14
Build data file locationC:\Users\mateusz.duda\scope-tags\buildData.json
Build tagbuild-123
Posted reports0 of 1 generated
-
-
-
-

Issues to be updated

- -
-
-
-
-

JIRA-KEY

- Back to top -
-
-

- From commit: added tests for tags definition file - (35077cb91ab71c20eef1d13482c26af45a51238b) -

-

Has relevancy data?: no

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
File pathChangeRenamed - Relevancy - LinesModule / TagReferenced files
- package.json - MODIFIED--++1 -

- Default module / Tag
Second module / - asdflkj -

-
-
- src/Commands/runAddCommand.ts - MODIFIED--++8 -

Default module / Tag

-
-
src/scope.ts
-
- src/Commands/runVerifyUnpushedCommitsCommand.ts - MODIFIED--++12

-
src/scope.ts
-
- src/Git/GitRepository.ts - MODIFIED--++6

-
- src/Console/FileTagger.ts -
-
- src/Commands/runCommitCommand.ts -
-
- src/Commands/runAddCommand.ts -
-
- src/Commands/runVerifyCommand.ts -
-
- src/Commands/runVerifyUnpushedCommitsCommand.ts -
-
- src/Report/ReportGenerator.ts -
-
- src/Commands/runReportForCommitCommand.ts -
-
- src/Commands/runReportForCommitListCommand.ts -
-
- src/Commands/runTagCommand.ts -
-
- src/Commands/runSkipVerificationAndPushCommand.ts -
-
- src/Commands/runLogCommitCommand.ts -
-
- src/Commands/runListUnpushedCommitsCommand.ts -
-
- src/Git/Types.ts - MODIFIED--++1

-
- src/Relevancy/Relevancy.ts -
-
- src/Scope/FileTagsDatabase.ts -
-
- src/Relevancy/RelevancyManager.ts -
-
- src/Git/GitRepository.ts -
-
- src/Console/FileTagger.ts -
-
- src/Commands/runAddCommand.ts -
-
- src/Logger/Logger.ts -
-
- src/Report/ReportGenerator.ts -
-
- src/Commands/runLogCommitCommand.ts -
-
- src/Commands/runVerifyUnpushedCommitsCommand.ts -
-
- src/Scope/TagsDefinitionFile.ts - MODIFIED--++20

-
- src/Scope/FileTagsDatabase.ts -
-
- src/Console/TagManager.ts -
-
- src/Report/ReportGenerator.ts -
-
- src/Console/ModuleManager.ts -
-
- src/Console/Menu.ts -
-
- src/Console/FileTagger.ts -
-
- src/Commands/runCommitCommand.ts -
-
- src/Commands/runAddCommand.ts -
-
- src/Commands/runReportForCommitCommand.ts -
-
- src/Commands/runReportForCommitListCommand.ts -
-
- src/Commands/runStartCommandLineInterfaceCommand.ts -
-
- src/Commands/runTagCommand.ts -
-
- test/scope/tagsDefinitionFile.test.ts - ADDED--++60

-
-
-
-
-
-

Instructions

-
- Reading additional data - Some entries have additional data on hover. You can hover over them to read the associated data - full commit - message, tags associated with a file, etc. -
-
-
-
- - diff --git a/logs.html b/logs.html index 09b5676..c669985 100644 --- a/logs.html +++ b/logs.html @@ -63,11 +63,11 @@

build-123

Package version - 0.2.9 + 0.3.1 Current date - 2024-5-15 14:54:17 + 2024-5-20 17:32:42 Build data file location @@ -100,16 +100,18 @@

JIRA-KEY

From commit: added tests for tags definition file + >testing new relevancy (35077cb91ab71c20eef1d13482c26af45a51238b)(161671d540ffe9de3b1480efb4e2dff35ee677e5)

-

Has relevancy data?: no

+

Has relevancy data?: yes

@@ -117,257 +119,220 @@

JIRA-KEY

- + - + - + - - + + - - + + - - - - - - - - - - - - - - - - - - - + - - - + + + + + + + + + + + + - - - - - - - - -
File path Renamed Relevancy Lines Module / TagReferenced filesUsed by
package.json.scope/database.json MODIFIEDIGNORED - -++1 -

- Default module / Tag
Second module / - asdflkj -

-
++3

-
src/Commands/runAddCommand.tssrc/Relevancy/Relevancy.ts MODIFIED --++8HIGH++4 --6

Default module / Tag

-
src/scope.ts
-
- src/Commands/runVerifyUnpushedCommitsCommand.ts + src/Relevancy/RelevancyManager.ts + +
-
MODIFIED--++12

-
src/scope.ts
-
- src/Git/GitRepository.ts +
-
MODIFIED--++6

+ src/References/IReferenceFinder.ts +
- src/Console/FileTagger.ts + src/References/ExternalMapReferenceFinder.ts
- src/Commands/runCommitCommand.ts + src/References/TSReferenceFinder.ts
- src/Commands/runAddCommand.ts -
-
- src/Commands/runVerifyCommand.ts + src/Report/JiraBuilder.ts
- src/Commands/runVerifyUnpushedCommitsCommand.ts + src/Logger/Logger.ts
-
+
src/Report/ReportGenerator.ts
-
- src/Commands/runReportForCommitCommand.ts -
-
- src/Commands/runReportForCommitListCommand.ts -
-
- src/Commands/runTagCommand.ts -
-
- src/Commands/runSkipVerificationAndPushCommand.ts -
-
- src/Commands/runLogCommitCommand.ts +
+ src/Commands/runFindReferencesCommand.ts
+
src/Git/Types.ts
- src/Commands/runListUnpushedCommitsCommand.ts + src/HTMLCreator/HTMLCreator.ts
src/Git/Types.tssrc/Relevancy/RelevancyManager.ts MODIFIED - -++1++1 --1

- src/Relevancy/Relevancy.ts + src/Git/GitRepository.ts +
+
+ src/Commands/runAddCommand.ts
- src/Scope/FileTagsDatabase.ts + src/Commands/runVerifyCommand.ts
- src/Relevancy/RelevancyManager.ts + src/Commands/runVerifyUnpushedCommitsCommand.ts
- src/Git/GitRepository.ts + src/Logger/Logger.ts
- src/Console/FileTagger.ts + src/Commands/runReportForCommitCommand.ts
- src/Commands/runAddCommand.ts -
-
- src/Logger/Logger.ts -
-
- src/Report/ReportGenerator.ts + src/Commands/runReportForCommitListCommand.ts
src/Commands/runLogCommitCommand.ts
-
- src/Commands/runVerifyUnpushedCommitsCommand.ts -
src/Scope/TagsDefinitionFile.tssrc/Report/JiraBuilder.ts MODIFIED --++20

LOW++56 --21 -
- src/Scope/FileTagsDatabase.ts +

+ Default module / Tag
Fourth module / + Fourth tag +

+
+
+ src/Report/ReportGenerator.ts
+
+ src/Report/ReportGenerator.ts + MODIFIED-HIGH++21 --12 +

+ Third module / Some new tag +

+
- src/Console/TagManager.ts + src/Report/JiraBuilder.ts
- src/Report/ReportGenerator.ts -
-
- src/Console/ModuleManager.ts + src/Logger/Logger.ts
- src/Console/Menu.ts + src/HTMLCreator/HTMLCreator.ts
- src/Console/FileTagger.ts -
-
- src/Commands/runCommitCommand.ts + src/Commands/runReportForCommitCommand.ts
- src/Commands/runAddCommand.ts -
-
- src/Commands/runReportForCommitCommand.ts -
-
src/Commands/runReportForCommitListCommand.ts
-
- src/Commands/runStartCommandLineInterfaceCommand.ts -
-
- src/Commands/runTagCommand.ts -
- test/scope/tagsDefinitionFile.test.ts - ADDED--++60

-

diff --git a/package.json b/package.json index 6c988e4..daf2030 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "local-build": "npm run build && npm link", "start": "npm run build && scope", "tag": "npm run build && scope --tag-unpushed-commits", - "test": "jest ./test --verbose --silent=false --runInBand", + "test": "jest -i test/report/* --verbose --silent=false --runInBand", "clean": "rimraf .scope/" }, "repository": { diff --git a/src/Commands/runFindReferencesCommand.ts b/src/Commands/runFindReferencesCommand.ts index b5df3b4..8043a1a 100644 --- a/src/Commands/runFindReferencesCommand.ts +++ b/src/Commands/runFindReferencesCommand.ts @@ -4,10 +4,40 @@ import { Relevancy } from "../Relevancy/Relevancy"; export function runFindReferencesCommand(args: Array, root: string) { const filePath = args[1]; if (!filePath) { - console.log("--report-for-commit-list requires a path to build metadata, use: --report-for-commit-list "); + console.log("--find-refs requires a path to a file, use: --find-refs "); process.exit(1); } const tsReferenceFinder = new TSReferenceFinder(root, "tsconfig.json"); - tsReferenceFinder.findReferences(filePath, Relevancy.HIGH); + + debugger; + + const references = tsReferenceFinder.findReferences(filePath, Relevancy.HIGH); + + if (!references.length) { + console.log("No references found"); + } else { + console.log(`Found ${references.length} references`); + } + + references + .sort((entryA, entryB) => { + const pathA = entryA.filename.toUpperCase(); // ignore upper and lowercase + const pathB = entryB.filename.toUpperCase(); // ignore upper and lowercase + if (pathA < pathB) { + return -1; + } + if (pathA > pathB) { + return 1; + } + return 0; + }) + .forEach(reference => { + let info = `- ${reference.filename}`; + + if (reference.unused) { + info += " (unused)"; + } + console.log(info); + }) } diff --git a/src/Commands/runHelpCommand.ts b/src/Commands/runHelpCommand.ts index d523763..a521d15 100644 --- a/src/Commands/runHelpCommand.ts +++ b/src/Commands/runHelpCommand.ts @@ -1,6 +1,6 @@ export function runHelpCommand(args: Array) { console.log(` - scope\t\t\tStarts command line interface, which enables you to add and remove tags and modules, and assign tags between modules + npx scope\t\t\tStarts command line interface, which enables you to add and remove tags and modules, and assign tags between modules Definitions: @@ -14,16 +14,19 @@ Definitions: Options: - --tag\t\t\tEnables to tag specific files or directories, usage: scope --tag - --untag\t\t\tRemoves tags for files (single or directory) in database, also removes 'ignored' status, usage: scope --untag + --tag\t\t\tEnables to tag specific files or directories, usage: npx scope --tag + --untag\t\t\tRemoves tags for files (single or directory) in database, also removes 'ignored' status, usage: npx scope --untag - --see\t\t\tPrints the tags assigned to file or directory, usage: scope --see -\t\t\t\tIf path is ommited, lists the commits which are currently "observed" by the script, usage: scope --see + --see\t\t\tPrints the tags assigned to file or directory, usage: npx scope --see +\t\t\t\tIf path is ommited, lists the commits which are currently "observed" by the script, usage: npx scope --see + --find-refs\t\t\tUses ts-morph to find .ts file references, usage: npx scope --find-references + --logcommit\t\t\tLogs files associated with a commit, usage: npx scope --logcommit + --add\t\t\tLists files which were modified in commits, which are not yet pushed to remote, and tags them - --commit\t\t\tLists files which were modified by a specific commit and tags them, usage: scope --commit + --commit\t\t\tLists files which were modified by a specific commit and tags them, usage: npx scope --commit - --verify\t\t\tReturns 0 if all files modified by a commit were tagged or ignored and 1 otherwise, usage: scope --verify + --verify\t\t\tReturns 0 if all files modified by a commit were tagged or ignored and 1 otherwise, usage: npx scope --verify --verify-unpushed-commits\tWorks similar to --verify, but checks for commits no yet pushed to remote, returns 0 or 1 analogous to --verify --report-for-commit\t\tGenerates human readable report with statistics for files modified in a commit, usage: --report-for-commit diff --git a/src/Commands/runReportForCommitCommand.ts b/src/Commands/runReportForCommitCommand.ts index 2e07af4..addce39 100644 --- a/src/Commands/runReportForCommitCommand.ts +++ b/src/Commands/runReportForCommitCommand.ts @@ -45,12 +45,12 @@ export function runReportForCommitCommand(args: Array, root: string) { } }) - const generator = new ReportGenerator(repository, tagsDefinitionFile, fileTagsDatabase, configFile, referenceFinders); + const generator = new ReportGenerator(repository, tagsDefinitionFile, fileTagsDatabase, configFile, referenceFinders, true); const relevancyManager = new RelevancyManager(); repository.getCommitByHash(hash).then(async (commit: Commit) => { const relevancyMap = relevancyManager.loadRelevancyMapFromCommits([commit]); - const report = await generator.generateReportForCommit(commit, projects[0].name, relevancyMap); + const report = await generator.generateReportForCommit(commit, projects[0].name, relevancyMap, false); if (generator.isReportEmpty(report)) { console.log("Report is empty (no tags were found in modified files)."); return; diff --git a/src/Commands/runReportForCommitListCommand.ts b/src/Commands/runReportForCommitListCommand.ts index 232b34c..c9e7b3f 100644 --- a/src/Commands/runReportForCommitListCommand.ts +++ b/src/Commands/runReportForCommitListCommand.ts @@ -93,7 +93,7 @@ export async function runReportForCommitListCommand(args: Array, root: s const relevancyMap = relevancyTagger.loadRelevancyMapFromCommits(commits); console.log(`[Scope tags]: Generating report for issue '${issue}'...'`); - const report = await generator.generateReportForCommits(commits, projects[0].name, buildTag, false, relevancyMap); + const report = await generator.generateReportForCommits(commits, projects[0].name, buildTag, relevancyMap); if (generator.isReportEmpty(report)) { console.log(`[Scope tags]: Report ommited because no tags for modified files were found`); diff --git a/src/Git/GitRepository.ts b/src/Git/GitRepository.ts index b06fe78..1083976 100644 --- a/src/Git/GitRepository.ts +++ b/src/Git/GitRepository.ts @@ -176,11 +176,14 @@ export class GitRepository { return fileDataArray; } - public async getFileDataForCommits(commits: Array): Promise { + public async getFileDataForCommits(commits: Array, useGitNatively = false): Promise { const fileDataForCommits: Array = []; for (const commit of commits) { - const fileDataForCommit = await this.getFileDataForCommit(commit); + const fileDataForCommit = useGitNatively + ? this.getFileDataUsingNativeGitCommand(commit) + : await this.getFileDataForCommit(commit); + fileDataForCommit.forEach(fileData => fileDataForCommits.push(fileData)); } diff --git a/src/Report/JiraBuilder.ts b/src/Report/JiraBuilder.ts index 35d562d..97af117 100644 --- a/src/Report/JiraBuilder.ts +++ b/src/Report/JiraBuilder.ts @@ -1,10 +1,10 @@ import { formatDate } from "./TimeUtils"; import { expand, table, doc, tableRow, tableHeader, p, strong, text, link, nestedExpand } from "./AdfUtils"; -import { getScriptVersion } from "../scope"; import { ReferencedFileInfo } from "../References/IReferenceFinder"; import { TagIdentifier } from "../Scope/FileTagsDatabase"; import { FileInfo } from "./ReportGenerator"; import { Relevancy } from "../Relevancy/Relevancy"; +import { Utils } from "../Scope/Utils"; export type TagIdentifierWithRelevancy = TagIdentifier & { relevancy: Relevancy; @@ -60,7 +60,7 @@ export class JiraBuilder { adfDocument: string, comment: string } { - let tableTitle = `'${projectName}' scope tags v${getScriptVersion()} │ ${formatDate(date, "Europe/Warsaw")}`; + let tableTitle = `'${projectName}' scope tags v${Utils.getScriptVersion()} │ ${formatDate(date, "Europe/Warsaw")}`; tableTitle += buildTag ? ` │ ${buildTag}` : ""; let reportTable = { diff --git a/src/Report/ReportGenerator.ts b/src/Report/ReportGenerator.ts index 72ba172..1f54158 100644 --- a/src/Report/ReportGenerator.ts +++ b/src/Report/ReportGenerator.ts @@ -48,20 +48,21 @@ export class ReportGenerator { private _fileTagsDatabase: FileTagsDatabase, private _configFile: ConfigFile, private _referenceFinders: Array, + private _printDebugInfo: boolean = false ) { } - public async generateReportForCommit(commit: Commit, projectName: string, relevancyMap: RelevancyMap): Promise { - return this.generateReportForCommits([commit], projectName, "-", true, relevancyMap); + public async generateReportForCommit(commit: Commit, projectName: string, relevancyMap: RelevancyMap, useGitNatively = false): Promise { + return this.generateReportForCommits([commit], projectName, "-", relevancyMap, useGitNatively); } public async generateReportForCommits( commits: Array, projectName: string = "undefined", jobName: string = "undefined", - printDebugInfo: boolean = false, relevancyMap?: RelevancyMap, + useGitNatively = false ): Promise { - const filesAffectedByCommits: Array = await this._repository.getFileDataForCommits(commits); + const filesAffectedByCommits: Array = await this._repository.getFileDataForCommits(commits, useGitNatively); return new Promise(async (resolve, reject) => { @@ -70,7 +71,7 @@ export class ReportGenerator { const affectedModules = this._getAffectedModules(fileInfoArray); - if (printDebugInfo) { + if (this._printDebugInfo) { console.log("---- File Info ----") console.log(fileInfoArray); console.log("---- Affected Modules ----") @@ -125,14 +126,18 @@ export class ReportGenerator { const commitRelevancyArray = relevancyMap.get(fileData.commitedIn.sha()); if (!commitRelevancyArray) { - console.log(`[ReportGenerator]: No relevancy data for commit '${fileData.commitedIn}'`); + if (this._printDebugInfo) { + console.log(`[ReportGenerator]: No relevancy data for commit '${fileData.commitedIn}'`); + } return null; } const fileRelevancy = commitRelevancyArray.find(entry => entry.path === fileData.newPath); if (!fileRelevancy) { - console.log(`[ReportGenerator]: No relevancy found for file '${fileData.newPath}'`); + if (this._printDebugInfo) { + console.log(`[ReportGenerator]: No relevancy found for file '${fileData.newPath}'`); + } return null; } @@ -153,7 +158,7 @@ export class ReportGenerator { linesRemoved: fileData.linesRemoved, usedIn: this._getUsedIn(fileData, relevancy), relevancy: relevancy, - ignored: this._configFile.isFileExtensionIgnored(fileData.newPath), + ignored: this._fileTagsDatabase.isIgnored(fileData.newPath, this._configFile.getIgnoredFileExtenstions()), }; Logger.pushFileInfo(fileData, fileInfo); @@ -204,7 +209,9 @@ export class ReportGenerator { } }; - console.log(fileReference.toString()); + if (this._printDebugInfo) { + console.log(fileReference.toString()); + } references.push(fileReference); }); diff --git a/src/Scope/Utils.ts b/src/Scope/Utils.ts index 2696164..3ca563b 100644 --- a/src/Scope/Utils.ts +++ b/src/Scope/Utils.ts @@ -6,4 +6,8 @@ export class Utils { public static getEnumKeyByEnumValue(enumObj: any, value: any) { return Object.keys(enumObj).find(x => enumObj[x] === value); } + + public static getScriptVersion(): string { + return require('../package.json').version; + } } \ No newline at end of file diff --git a/src/scope.ts b/src/scope.ts index c94dea1..162dff2 100644 --- a/src/scope.ts +++ b/src/scope.ts @@ -14,6 +14,7 @@ import { getGitProjectRoot } from "./Git/Project"; import { runSkipVerificationForCommits } from "./Commands/runSkipVerificationAndPushCommand"; import { runLogCommitCommand } from "./Commands/runLogCommitCommand"; import { runSeeCommand } from "./Commands/runSeeCommand"; +import { Utils } from "./Scope/Utils"; // Will be needed to get output from script const [, , ...args] = process.argv; @@ -25,9 +26,11 @@ if (!root) { process.exit(1); } +// IMPORTANT: Do not export anything from here, is breaks tests + switch (args[0]) { case "--version": { - console.log(getScriptVersion()); + console.log(Utils.getScriptVersion()); break; } case "--tag": { @@ -66,7 +69,7 @@ switch (args[0]) { runReportForCommitListCommand(args, root); break; } - case "--find-references": { + case "--find-refs": { runFindReferencesCommand(args, root); break; } @@ -86,8 +89,4 @@ switch (args[0]) { runStartCommandLineInterfaceCommand(args, root); break; } -} - -export function getScriptVersion(): string { - return require('../package.json').version; } \ No newline at end of file diff --git a/test/_repo b/test/_repo index b8abe9d..1a6f4d7 160000 --- a/test/_repo +++ b/test/_repo @@ -1 +1 @@ -Subproject commit b8abe9d640ebc36b8efc3204ca8eb8e6c3a4dde0 +Subproject commit 1a6f4d7d908158c595c4b08755bec54577ab1518 diff --git a/test/commits/fileData.test.ts b/test/commits/fileData.test.ts index be3f179..19cfb99 100644 --- a/test/commits/fileData.test.ts +++ b/test/commits/fileData.test.ts @@ -1,4 +1,4 @@ -import { cloneMockRepositoryToFolder, commitEmptyFiles, makeUniqueFolderForTest } from "../_utils/utils"; +import { cloneMockRepositoryToFolder, commitEmptyFiles, makeUniqueFolderForTest } from "../utils/utils"; import { FileData, GitDeltaType } from "../../src/Git/Types"; describe("Tesing if file data is retrieved correctly", () => { diff --git a/test/commits/verification.test.ts b/test/commits/verification.test.ts index 0dde933..14468c7 100644 --- a/test/commits/verification.test.ts +++ b/test/commits/verification.test.ts @@ -1,4 +1,4 @@ -import { appendSomeTextToFile, cloneMockRepositoryToFolder, commitEmptyFiles, commitFiles, commitModitication, createEmptyFiles, makeUniqueFolderForTest, mergeBranchToCurrent } from "../_utils/utils"; +import { appendSomeTextToFile, cloneMockRepositoryToFolder, commitEmptyFiles, commitFiles, commitModitication, createEmptyFiles, makeUniqueFolderForTest, mergeBranchToCurrent } from "../utils/utils"; import { VerificationStatus, verifyUnpushedCommits } from "../../src/Commands/runVerifyUnpushedCommitsCommand"; import { GitRepository } from "../../src/Git/GitRepository"; import { ConfigFile } from "../../src/Scope/ConfigFile"; diff --git a/test/git/nodegit.test.ts b/test/git/nodegit.test.ts index 7d6df50..ec0715a 100644 --- a/test/git/nodegit.test.ts +++ b/test/git/nodegit.test.ts @@ -1,6 +1,6 @@ import { Repository } from "nodegit"; -import { TEST_DATA_FOLDER } from "../_utils/globals"; -import { createFolder } from "../_utils/utils"; +import { TEST_DATA_FOLDER } from "../utils/globals"; +import { createFolder } from "../utils/utils"; const execSync = require('child_process').execSync; describe("nodegit is correctly initialized", () => { diff --git a/test/report/reportGenerator.test.ts b/test/report/reportGenerator.test.ts new file mode 100644 index 0000000..f2f2b58 --- /dev/null +++ b/test/report/reportGenerator.test.ts @@ -0,0 +1,264 @@ +import { cloneMockRepositoryToFolder, commitModitication, makeUniqueFolderForTest } from "../utils/utils"; +import { GitRepository } from "../../src/Git/GitRepository"; +import { ConfigFile } from "../../src/Scope/ConfigFile"; +import { FileTagsDatabase } from "../../src/Scope/FileTagsDatabase"; +import { TagsDefinitionFile } from "../../src/Scope/TagsDefinitionFile"; +import { TSReferenceFinder } from "../../src/References/TSReferenceFinder"; +import { ReportGenerator } from "../../src/Report/ReportGenerator"; +import { RelevancyManager } from "../../src/Relevancy/RelevancyManager"; + +// Testing only ReportGenerator class, which is responsible for gathering data for each commit + +const PRINT_DEBUG_INFO = false; + +const initReportGenerator = (root: string) => { + + const repository = new GitRepository(root); + const config = new ConfigFile(root); + const database = new FileTagsDatabase(root); + const tags = new TagsDefinitionFile(root); + const tsReferenceFinder = new TSReferenceFinder(root, "/tsconfig.json"); + + config.load(); + database.load(); + tags.load(); + + return new ReportGenerator(repository, tags, database, config, [tsReferenceFinder], PRINT_DEBUG_INFO); +} + + +describe("Report generation works as expected", async () => { + it("After making a change in a tagged file, the change is correctly described by generated report", async () => { + const FOLDER_PATH = makeUniqueFolderForTest(); + const REPO_PATH = cloneMockRepositoryToFolder(FOLDER_PATH); + + const testFile = "src/tagged-file.js"; + + const repository = await commitModitication([testFile], REPO_PATH); + + const unpushedCommits = await repository.getUnpushedCommits(); + expect(unpushedCommits.length).toBe(1); + + const commit = unpushedCommits[0]; + + const generator = initReportGenerator(REPO_PATH); + + const relevancy = new RelevancyManager(); + const relevancyMap = relevancy.loadRelevancyMapFromCommits([commit]); + + const report = await generator.generateReportForCommit(commit, "Project", relevancyMap, true); + + expect(report).toBeDefined(); + + // { "path": "src/tagged-file.js", + // "tags": [ + // { "tag": "Tag", "module": "Default module" }]}], + + expect(report.allModules.length).toBe(1); + expect(report.untaggedFilesAsModule.files.length).toBe(0); + + const foundModule = report.allModules[0]; + + expect(foundModule.module).toBe("Default module"); + expect(foundModule.files.length).toBe(1); + + const fileInfo = foundModule.files[0]; + + expect(fileInfo.file).toBe(testFile); + expect(fileInfo.tagIdentifiers.length).toBe(1); + expect(fileInfo.tagIdentifiers[0].module).toBe("Default module"); + expect(fileInfo.tagIdentifiers[0].tag).toBe("Tag"); + }); + + it("After making a change with only ignored files, the report does not contain any data", async () => { + const FOLDER_PATH = makeUniqueFolderForTest(); + const REPO_PATH = cloneMockRepositoryToFolder(FOLDER_PATH); + + const ignoredFiles = [ + "src/file-ignored-by-database.js", + "assets/image.jpg", + "assets/newimage.jpg", + ]; + + + const repository = await commitModitication(ignoredFiles, REPO_PATH); + + const unpushedCommits = await repository.getUnpushedCommits(); + expect(unpushedCommits.length).toBe(1); + + const commit = unpushedCommits[0]; + + const generator = initReportGenerator(REPO_PATH); + + const relevancy = new RelevancyManager(); + const relevancyMap = relevancy.loadRelevancyMapFromCommits([commit]); + + const report = await generator.generateReportForCommit(commit, "Project", relevancyMap, true); + + expect(report).toBeDefined(); + expect(report.allModules.length).toBe(0); + expect(report.untaggedFilesAsModule.files.length).toBe(0); + }); + + it("After making a change in an untagged file, the change is visible in untagged module", async () => { + const FOLDER_PATH = makeUniqueFolderForTest(); + const REPO_PATH = cloneMockRepositoryToFolder(FOLDER_PATH); + + const testFileCount = 20; + const testFiles: string[] = []; + + for (let i = 0; i < testFileCount; i++) { + testFiles.push(`src/test-file-${i}`); + } + + const repository = await commitModitication(testFiles, REPO_PATH); + + const unpushedCommits = await repository.getUnpushedCommits(); + expect(unpushedCommits.length).toBe(1); + + const commit = unpushedCommits[0]; + + const generator = initReportGenerator(REPO_PATH); + + const relevancy = new RelevancyManager(); + const relevancyMap = relevancy.loadRelevancyMapFromCommits([commit]); + + const report = await generator.generateReportForCommit(commit, "Project", relevancyMap, true); + + expect(report).toBeDefined(); + + expect(report.allModules.length).toBe(0); + + expect(report.untaggedFilesAsModule.files.length).toBe(testFileCount); + + testFiles.forEach(file => { + expect(report.untaggedFilesAsModule.files.some(moduleFile => moduleFile.file === file)).toBe(true); + }); + }); + + + it("Correctly separates tagged and untagged files in the report", async () => { + const FOLDER_PATH = makeUniqueFolderForTest(); + const REPO_PATH = cloneMockRepositoryToFolder(FOLDER_PATH); + + const files = ["src/tagged-file.js", "src/untagged-file.js"]; + const repository = await commitModitication(files, REPO_PATH); + + const unpushedCommits = await repository.getUnpushedCommits(); + expect(unpushedCommits.length).toBe(1); + + const commit = unpushedCommits[0]; + + const generator = initReportGenerator(REPO_PATH); + + const relevancy = new RelevancyManager(); + const relevancyMap = relevancy.loadRelevancyMapFromCommits([commit]); + + const report = await generator.generateReportForCommit(commit, "Project", relevancyMap, true); + + expect(report).toBeDefined(); + expect(report.allModules.length).toBe(1); + + const taggedModule = report.allModules[0]; + expect(taggedModule.files.length).toBe(1); + expect(taggedModule.files[0].file).toBe("src/tagged-file.js"); + + expect(report.untaggedFilesAsModule.files.length).toBe(1); + expect(report.untaggedFilesAsModule.files[0].file).toBe("src/untagged-file.js"); + }); + + it("After making a change in tagged and untagged, their references are correctly reported", async () => { + const FOLDER_PATH = makeUniqueFolderForTest(); + const REPO_PATH = cloneMockRepositoryToFolder(FOLDER_PATH); + + /** + * File structure description + * + * src/ + * ├─ ts/ + * │ ├─ controllers/ + * │ │ ├─ Controller.ts 2 dependencies: View.ts and Model.ts, 1 tag: Controllers / AController + * │ ├─ models/ + * │ │ ├─ Model.ts No dependencies, 1 tag: Models / AModel + * │ ├─ views/ + * │ │ ├─ View.ts 1 dependency: Modal, 1 tag: Views / AView + * │ │ ├─ ModalWindow.ts No dependencies, no tags + * + */ + + const filesToModify = [ + "src/ts/controllers/Controller.ts", + "src/ts/models/Model.ts", + "src/ts/views/View.ts", + "src/ts/views/ModalWindow.ts", + ]; + + const repository = await commitModitication(filesToModify, REPO_PATH); + + const unpushedCommits = await repository.getUnpushedCommits(); + expect(unpushedCommits.length).toBe(1); + + const commit = unpushedCommits[0]; + + const generator = initReportGenerator(REPO_PATH); + + const relevancy = new RelevancyManager(); + const relevancyMap = relevancy.loadRelevancyMapFromCommits([commit]); + + const report = await generator.generateReportForCommit(commit, "Project", relevancyMap, true); + + expect(report).toBeDefined(); + + expect(report.allModules.length).toBe(3); + + const controllerModule = report.allModules.find(reportModule => reportModule.module === "Controllers"); + const viewsModule = report.allModules.find(reportModule => reportModule.module === "Views"); + const modelsModule = report.allModules.find(reportModule => reportModule.module === "Models"); + + expect(controllerModule).toBeDefined(); + expect(viewsModule).toBeDefined(); + expect(modelsModule).toBeDefined(); + + if (!controllerModule || !viewsModule || !modelsModule) { + return; + } + + expect(controllerModule.files.length).toBe(1); + expect(viewsModule.files.length).toBe(1); + expect(modelsModule.files.length).toBe(1); + + // Controller.ts checks + const controllerFileInfo = controllerModule.files[0]; + + expect(controllerFileInfo.file).toBe("src/ts/controllers/Controller.ts"); + expect(controllerFileInfo.ignored).toBe(false); + expect(controllerFileInfo.tagIdentifiers.length).toBeGreaterThan(0); + expect(controllerFileInfo.tagIdentifiers.some(identifier => identifier.module === "Controllers" && identifier.tag === "AController")).toBe(true); + expect(controllerFileInfo.usedIn.length).toBe(0); + + // Model.ts checks + const modelsFileInfo = modelsModule.files[0]; + + expect(modelsFileInfo.file).toBe("src/ts/models/Model.ts"); + expect(modelsFileInfo.ignored).toBe(false); + expect(modelsFileInfo.tagIdentifiers.length).toBeGreaterThan(0); + expect(modelsFileInfo.tagIdentifiers.some(identifier => identifier.module === "Models" && identifier.tag === "AModel")).toBe(true); + + expect(modelsFileInfo.usedIn.length).toBe(1); + expect(modelsFileInfo.usedIn[0].fileInfo.filename).toBe("src/ts/controllers/Controller.ts"); + expect(modelsFileInfo.usedIn[0].fileInfo.unused).toBe(false); + + // View.ts checks + const viewFileInfo = viewsModule.files[0]; + + expect(viewFileInfo.file).toBe("src/ts/view/View.ts"); + + // Check if ModalWindow is marked as untagged + expect(report.untaggedFilesAsModule.files.length).toBe(1); + expect(report.untaggedFilesAsModule.files[0].file).toBe("src/ts/view/ModalWindow.ts"); + + // Check references + }); +}); + + diff --git a/test/scope/scopeFolder.test.ts b/test/scope/scopeFolder.test.ts index 1d8b317..4dd8033 100644 --- a/test/scope/scopeFolder.test.ts +++ b/test/scope/scopeFolder.test.ts @@ -1,5 +1,5 @@ -import { TEST_DATA_FOLDER } from "../_utils/globals"; -import { createFolder } from "../_utils/utils"; +import { TEST_DATA_FOLDER } from "../utils/globals"; +import { createFolder } from "../utils/utils"; import { ensureScopeFolderExists, scopeFolderExists } from "../../src/FileSystem/fileSystemUtils"; import { existsSync, mkdirSync } from "fs"; import { join } from "path"; diff --git a/test/scope/tagsDefinitionFile.test.ts b/test/scope/tagsDefinitionFile.test.ts index 08505a4..106bfc6 100644 --- a/test/scope/tagsDefinitionFile.test.ts +++ b/test/scope/tagsDefinitionFile.test.ts @@ -1,4 +1,4 @@ -import { cloneMockRepositoryToFolder, makeUniqueFolderForTest } from "../_utils/utils"; +import { cloneMockRepositoryToFolder, makeUniqueFolderForTest } from "../utils/utils"; import { join } from "path"; import { TagsDatabaseType, TagsDefinitionFile } from "../../src/Scope/TagsDefinitionFile"; import { JSONFile } from "../../src/FileSystem/JSONFile"; diff --git a/test/_utils/globals.ts b/test/utils/globals.ts similarity index 100% rename from test/_utils/globals.ts rename to test/utils/globals.ts diff --git a/test/_utils/utils.ts b/test/utils/utils.ts similarity index 100% rename from test/_utils/utils.ts rename to test/utils/utils.ts