From 77d61d6b3d153ecbc6fbe479950cbeddccd84462 Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Mon, 18 Mar 2024 01:23:07 +0000 Subject: [PATCH 1/6] feat: empty string warning --- .github/workflows/empty-string-warning.yml | 46 +++++++++++++++++ tests/empty-strings/empty-strings.test.ts | 60 ++++++++++++++++++++++ tests/empty-strings/empty-strings.ts | 45 ++++++++++++++++ tests/empty-strings/test.config.ts | 5 ++ tests/empty-strings/test.ts | 3 ++ 5 files changed, 159 insertions(+) create mode 100644 .github/workflows/empty-string-warning.yml create mode 100644 tests/empty-strings/empty-strings.test.ts create mode 100644 tests/empty-strings/empty-strings.ts create mode 100644 tests/empty-strings/test.config.ts create mode 100644 tests/empty-strings/test.ts diff --git a/.github/workflows/empty-string-warning.yml b/.github/workflows/empty-string-warning.yml new file mode 100644 index 0000000..8ab6181 --- /dev/null +++ b/.github/workflows/empty-string-warning.yml @@ -0,0 +1,46 @@ +name: Warn for Empty Strings + +on: [push, pull_request, workflow_dispatch] + +jobs: + check-empty-strings: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Check for empty strings in TypeScript files + id: check_empty + run: | + output=$(grep -Rn --include=\*.ts "''\|\"\"" --exclude-dir={node_modules,dist,out} .) + if [ -z "$output" ]; then + echo "No empty strings found." + echo "::set-output name=found::false" + else + echo "$output" + echo "::set-output name=found::true" + echo "::set-output name=result::$(echo "$output")" + fi + continue-on-error: true + + - name: Post comment if empty strings are found + if: steps.check_empty.outputs.found == 'true' + uses: actions/github-script@v6 + with: + script: | + const output = `${{ steps.check_empty.outputs.result }}`; + const formattedOutput = output.split('\n').map(line => line.trim()).join('\n'); + const commentBody = `**Empty strings found in TypeScript files**\n` + + 'Please review the usage of empty strings to ensure it is necessary. ' + + 'Below are the occurrences:\n' + + '```\n' + formattedOutput + '\n```'; + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: commentBody, + }); diff --git a/tests/empty-strings/empty-strings.test.ts b/tests/empty-strings/empty-strings.test.ts new file mode 100644 index 0000000..30c31c5 --- /dev/null +++ b/tests/empty-strings/empty-strings.test.ts @@ -0,0 +1,60 @@ +import { expect, describe, beforeEach, it } from "@jest/globals"; +import { CheckEmptyStringsOptions, checkForEmptyStringsInFiles } from "./empty-strings"; + +const mockReadDir = jest.fn(); +const mockReadFile = jest.fn(); + +const options: CheckEmptyStringsOptions = { + readDir: mockReadDir, + readFile: mockReadFile, + ignorePatterns: [], +}; + +describe("checkForEmptyStringsInFiles", () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it("identifies files with empty strings", async () => { + mockReadDir.mockResolvedValue(["file1.ts", "file2.ts"]); + mockReadFile.mockImplementation((path) => { + if (path.includes("file1.ts")) { + return Promise.resolve('const a = "";'); + } + return Promise.resolve('const b = "notEmpty";'); + }); + + const result = await checkForEmptyStringsInFiles(".", options); + expect(result).toEqual(["file1.ts"]); + }); + + it("ignores files based on ignorePatterns and .gitignore", async () => { + options.ignorePatterns = ["file2.ts"]; + mockReadDir.mockResolvedValue(["file1.ts", "file2.ts", "file3.ts"]); + mockReadFile.mockImplementation((path) => { + if (path === ".gitignore") { + return Promise.resolve("file3.ts"); + } else if (path.includes("file1.ts")) { + return Promise.resolve('const a = "";'); + } + return Promise.resolve('const b = "notEmpty";'); + }); + + const result = await checkForEmptyStringsInFiles(".", options); + expect(result).toEqual(["file1.ts"]); + }); + + it("returns an empty array when no empty strings are found", async () => { + mockReadDir.mockResolvedValue(["file1.ts"]); + mockReadFile.mockResolvedValue('const a = "notEmpty";'); + + const result = await checkForEmptyStringsInFiles(".", options); + expect(result).toHaveLength(0); + }); + + it("handles errors gracefully", async () => { + mockReadDir.mockRejectedValue(new Error("Error reading directory")); + + await expect(checkForEmptyStringsInFiles(".", options)).resolves.toEqual([]); + }); +}); diff --git a/tests/empty-strings/empty-strings.ts b/tests/empty-strings/empty-strings.ts new file mode 100644 index 0000000..f3f1939 --- /dev/null +++ b/tests/empty-strings/empty-strings.ts @@ -0,0 +1,45 @@ +export interface CheckEmptyStringsOptions { + readDir: (path: string) => Promise; + readFile: (path: string, encoding: string) => Promise; + ignorePatterns?: string[]; +} + +export async function checkForEmptyStringsInFiles(dir: string, options: CheckEmptyStringsOptions): Promise { + const { readDir, readFile, ignorePatterns = [] } = options; + const filesWithEmptyStrings: string[] = []; + const ignoreList: string[] = ["^\\.\\/\\.git", "^\\.\\/\\..*", "^\\.\\/node_modules", "^\\.\\/dist", "^\\.\\/out", ".*\\.test\\.ts$", ...ignorePatterns]; + + try { + const gitignoreContent = await readFile(".gitignore", "utf8"); + gitignoreContent.split("\n").forEach((line) => { + if (line.trim() !== "") { + ignoreList.push(`^\\.\\/${line.replace(/\./g, "\\.").replace(/\//g, "\\/")}`); + } + }); + } catch (error) { + console.error("Error reading .gitignore file:", error); + } + + try { + const files = await readDir(dir); + for (const fileName of files) { + let shouldIgnore = false; + for (const pattern of ignoreList) { + if (new RegExp(pattern).test(fileName)) { + shouldIgnore = true; + break; + } + } + if (shouldIgnore || !fileName.endsWith(".ts")) continue; + + const fileContent = await readFile(`${dir}/${fileName}`, "utf8"); + if (fileContent.includes('""') || fileContent.includes("''")) { + filesWithEmptyStrings.push(fileName); + } + } + } catch (error) { + console.error("Error reading directory or file contents:", error); + } + + return filesWithEmptyStrings; +} diff --git a/tests/empty-strings/test.config.ts b/tests/empty-strings/test.config.ts new file mode 100644 index 0000000..4f277cb --- /dev/null +++ b/tests/empty-strings/test.config.ts @@ -0,0 +1,5 @@ +module.exports = { + test: { + test: "", + }, +}; diff --git a/tests/empty-strings/test.ts b/tests/empty-strings/test.ts new file mode 100644 index 0000000..220545b --- /dev/null +++ b/tests/empty-strings/test.ts @@ -0,0 +1,3 @@ +export function testfunc() { + return ""; +} From 05073fba6df432151bb570a29fed1b0faa9a3532 Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Thu, 21 Mar 2024 10:10:48 +0000 Subject: [PATCH 2/6] chore: workflow update --- .github/workflows/build.yml | 4 +- .github/workflows/cypress-testing.yml | 2 +- .github/workflows/empty-string-warning.yml | 68 +++++++++++-------- .github/workflows/jest-testing.yml | 4 +- .github/workflows/release-please.yml | 2 +- README.md | 5 ++ tests/empty-strings/test.ts | 3 - .../empty-strings/empty-strings.test.ts | 0 .../empty-strings/empty-strings.ts | 0 .../workflows/empty-strings/test-function.ts | 3 + .../empty-strings/test.config.ts | 1 + tsconfig.json | 2 +- 12 files changed, 55 insertions(+), 39 deletions(-) delete mode 100644 tests/empty-strings/test.ts rename tests/{ => workflows}/empty-strings/empty-strings.test.ts (100%) rename tests/{ => workflows}/empty-strings/empty-strings.ts (100%) create mode 100644 tests/workflows/empty-strings/test-function.ts rename tests/{ => workflows}/empty-strings/test.config.ts (78%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e18a40e..8cbf377 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -29,8 +29,8 @@ jobs: yarn yarn build # env: # Set environment variables for the build - # SUPABASE_URL: "https://wfzpewmlyiozupulbuur.supabase.co" - # SUPABASE_ANON_KEY: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6IndmenBld21seWlvenVwdWxidXVyIiwicm9sZSI6ImFub24iLCJpYXQiOjE2OTU2NzQzMzksImV4cCI6MjAxMTI1MDMzOX0.SKIL3Q0NOBaMehH0ekFspwgcu3afp3Dl9EDzPqs1nKs" + # SUPABASE_URL: "https://wfzpewmlyiozupulbuur.supabase.co" + # SUPABASE_ANON_KEY: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6IndmenBld21seWlvenVwdWxidXVyIiwicm9sZSI6ImFub24iLCJpYXQiOjE2OTU2NzQzMzksImV4cCI6MjAxMTI1MDMzOX0.SKIL3Q0NOBaMehH0ekFspwgcu3afp3Dl9EDzPqs1nKs" - name: Deploy to Cloudflare uses: ubiquity/cloudflare-deploy-action@main diff --git a/.github/workflows/cypress-testing.yml b/.github/workflows/cypress-testing.yml index eadd68e..1cf9d5a 100644 --- a/.github/workflows/cypress-testing.yml +++ b/.github/workflows/cypress-testing.yml @@ -2,7 +2,7 @@ name: Run Cypress testing suite on: workflow_dispatch: pull_request: - types: [ opened, synchronize ] + types: [opened, synchronize] jobs: cypress-run: diff --git a/.github/workflows/empty-string-warning.yml b/.github/workflows/empty-string-warning.yml index 8ab6181..6f5f5c6 100644 --- a/.github/workflows/empty-string-warning.yml +++ b/.github/workflows/empty-string-warning.yml @@ -1,46 +1,56 @@ name: Warn for Empty Strings -on: [push, pull_request, workflow_dispatch] +on: + pull_request: + paths: + - "**/*.ts" + - "**/*.tsx" + +permissions: + issues: write + pull-requests: write jobs: check-empty-strings: runs-on: ubuntu-latest - permissions: - issues: write - pull-requests: write steps: - name: Checkout code uses: actions/checkout@v3 - - name: Check for empty strings in TypeScript files - id: check_empty + - name: Find empty strings in TypeScript files + id: find_empty_strings run: | - output=$(grep -Rn --include=\*.ts "''\|\"\"" --exclude-dir={node_modules,dist,out} .) + # Find empty strings and mark them explicitly + output=$(grep -Rn --include=\*.ts "''\|\"\"" --exclude-dir={node_modules,dist,out} . || true) + if [ -z "$output" ]; then - echo "No empty strings found." - echo "::set-output name=found::false" + echo "::set-output name=results::No empty strings found." + exit 0 + else + output=$(echo "$output" | sed 's/""/"[EMPTY STRING]"/g' | sed "s/''/'[EMPTY STRING]'/g") + echo "::set-output name=results::${output//$'\n'/%0A}" + fi + + - name: findings + if: steps.find_empty_strings.outputs.results != 'No empty strings found.' + run: | + if [ "${{ steps.find_empty_strings.outputs.results }}" == "No empty strings found." ]; then + echo "No empty strings found. No action required." else - echo "$output" - echo "::set-output name=found::true" - echo "::set-output name=result::$(echo "$output")" + echo "::warning::Empty strings found in the following files:" + echo "${{ steps.find_empty_strings.outputs.results }}" fi - continue-on-error: true - - name: Post comment if empty strings are found - if: steps.check_empty.outputs.found == 'true' - uses: actions/github-script@v6 + - name: Comment on PR + if: steps.find_empty_strings.outputs.results != 'No empty strings found.' + uses: KeisukeYamashita/create-comment@v1 with: - script: | - const output = `${{ steps.check_empty.outputs.result }}`; - const formattedOutput = output.split('\n').map(line => line.trim()).join('\n'); - const commentBody = `**Empty strings found in TypeScript files**\n` + - 'Please review the usage of empty strings to ensure it is necessary. ' + - 'Below are the occurrences:\n' + - '```\n' + formattedOutput + '\n```'; - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: commentBody, - }); + comment: | + ## Empty String Usage Detected + + The following occurrences of empty strings were detected. Please review them to ensure their usage is necessary: + + \```plaintext + ${{ steps.find_empty_strings.outputs.results }} + \``` diff --git a/.github/workflows/jest-testing.yml b/.github/workflows/jest-testing.yml index 1671cd4..a7e36fa 100644 --- a/.github/workflows/jest-testing.yml +++ b/.github/workflows/jest-testing.yml @@ -2,7 +2,7 @@ name: Run Jest testing suite on: workflow_dispatch: pull_request_target: - types: [ opened, synchronize ] + types: [opened, synchronize] env: NODE_ENV: "test" @@ -14,7 +14,7 @@ jobs: steps: - uses: actions/setup-node@v4 with: - node-version: '20.10.0' + node-version: "20.10.0" - uses: actions/checkout@master with: fetch-depth: 0 diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 75d28f0..a5b40f7 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -20,7 +20,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-node@v4 with: - node-version: '20.10.0' + node-version: "20.10.0" registry-url: https://registry.npmjs.org/ - run: | yarn install --immutable --immutable-cache --check-cache diff --git a/README.md b/README.md index fb15148..7b0867a 100644 --- a/README.md +++ b/README.md @@ -10,18 +10,23 @@ This template repository includes support for the following: ## Testing ### Cypress + To test with Cypress Studio UI, run + ```shell yarn cy:open ``` Otherwise to simply run the tests through the console, run + ```shell yarn cy:run ``` ### Jest + To start Jest tests, run + ```shell yarn test ``` diff --git a/tests/empty-strings/test.ts b/tests/empty-strings/test.ts deleted file mode 100644 index 220545b..0000000 --- a/tests/empty-strings/test.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function testfunc() { - return ""; -} diff --git a/tests/empty-strings/empty-strings.test.ts b/tests/workflows/empty-strings/empty-strings.test.ts similarity index 100% rename from tests/empty-strings/empty-strings.test.ts rename to tests/workflows/empty-strings/empty-strings.test.ts diff --git a/tests/empty-strings/empty-strings.ts b/tests/workflows/empty-strings/empty-strings.ts similarity index 100% rename from tests/empty-strings/empty-strings.ts rename to tests/workflows/empty-strings/empty-strings.ts diff --git a/tests/workflows/empty-strings/test-function.ts b/tests/workflows/empty-strings/test-function.ts new file mode 100644 index 0000000..f89d4f9 --- /dev/null +++ b/tests/workflows/empty-strings/test-function.ts @@ -0,0 +1,3 @@ +export function testFunction() { + return ""; +} diff --git a/tests/empty-strings/test.config.ts b/tests/workflows/empty-strings/test.config.ts similarity index 78% rename from tests/empty-strings/test.config.ts rename to tests/workflows/empty-strings/test.config.ts index 4f277cb..86686fc 100644 --- a/tests/empty-strings/test.config.ts +++ b/tests/workflows/empty-strings/test.config.ts @@ -2,4 +2,5 @@ module.exports = { test: { test: "", }, + tester: "", }; diff --git a/tsconfig.json b/tsconfig.json index f9ab3da..c6d3097 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -104,7 +104,7 @@ /* Completeness */ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true, /* Skip type checking all .d.ts files. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */, "resolveJsonModule": true } } From af57518ea1b1236e0e7c9867399e5df04aa8ec87 Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Thu, 21 Mar 2024 11:10:01 +0000 Subject: [PATCH 3/6] Update empty-string-warning.yml --- .github/workflows/empty-string-warning.yml | 29 +++++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/.github/workflows/empty-string-warning.yml b/.github/workflows/empty-string-warning.yml index 6f5f5c6..8b70e3c 100644 --- a/.github/workflows/empty-string-warning.yml +++ b/.github/workflows/empty-string-warning.yml @@ -42,15 +42,36 @@ jobs: echo "${{ steps.find_empty_strings.outputs.results }}" fi + - name: Find Comment + uses: peter-evans/find-comment@v3 + id: find_comment + with: + issue-number: ${{ github.event.pull_request.number }} + body-includes: Empty String Usage Detected + comment-author: github-actions[bot] + - name: Comment on PR if: steps.find_empty_strings.outputs.results != 'No empty strings found.' - uses: KeisukeYamashita/create-comment@v1 + uses: peter-evans/create-or-update-comment@v4 with: - comment: | + issue-number: ${{ github.event.pull_request.number }} + comment-id: ${{ steps.find_comment.outputs.comment-id }} + edit-mode: replace + body: | ## Empty String Usage Detected The following occurrences of empty strings were detected. Please review them to ensure their usage is necessary: - \```plaintext + ```plaintext ${{ steps.find_empty_strings.outputs.results }} - \``` + ``` + + - name: Remove comment + if: steps.find_empty_strings.outputs.results == 'No empty strings found.' + uses: actions/github-script@v7 + with: + script: | + const { owner, repo } = context.repo; + const { number } = context.issue; + const comment_id = ${{ steps.find_comment.outputs.comment-id }} + github.rest.issues.deleteComment({ owner, repo, comment_id }); From a61d62df687f800dc0054a4c922d1378331bafaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=82=A2=E3=83=AC=E3=82=AF=E3=82=B5=E3=83=B3=E3=83=80?= =?UTF-8?q?=E3=83=BC=2Eeth?= <4975670+pavlovcik@users.noreply.github.com> Date: Fri, 22 Mar 2024 06:25:04 +0900 Subject: [PATCH 4/6] Update .github/workflows/empty-string-warning.yml --- .github/workflows/empty-string-warning.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/empty-string-warning.yml b/.github/workflows/empty-string-warning.yml index 8b70e3c..9aa50c5 100644 --- a/.github/workflows/empty-string-warning.yml +++ b/.github/workflows/empty-string-warning.yml @@ -16,7 +16,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Find empty strings in TypeScript files id: find_empty_strings From 68ae659e0f640201345c645d587367833c23fb88 Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Thu, 21 Mar 2024 21:27:31 +0000 Subject: [PATCH 5/6] Update empty-string-warning.yml --- .github/workflows/empty-string-warning.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/empty-string-warning.yml b/.github/workflows/empty-string-warning.yml index 9aa50c5..408c58a 100644 --- a/.github/workflows/empty-string-warning.yml +++ b/.github/workflows/empty-string-warning.yml @@ -22,7 +22,7 @@ jobs: id: find_empty_strings run: | # Find empty strings and mark them explicitly - output=$(grep -Rn --include=\*.ts "''\|\"\"" --exclude-dir={node_modules,dist,out} . || true) + output=$(grep -Rn --include=\*.ts "''\|\"\"" --exclude-dir={node_modules,dist,out,tests} . || true) if [ -z "$output" ]; then echo "::set-output name=results::No empty strings found." From 42e19f9d663d8e3fccd023e9c267777bc971f358 Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Mon, 25 Mar 2024 08:03:29 +0000 Subject: [PATCH 6/6] chore: review comments --- .github/workflows/empty-string-warning.yml | 48 +++++++++------------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/.github/workflows/empty-string-warning.yml b/.github/workflows/empty-string-warning.yml index 408c58a..0092038 100644 --- a/.github/workflows/empty-string-warning.yml +++ b/.github/workflows/empty-string-warning.yml @@ -42,36 +42,26 @@ jobs: echo "${{ steps.find_empty_strings.outputs.results }}" fi - - name: Find Comment - uses: peter-evans/find-comment@v3 - id: find_comment - with: - issue-number: ${{ github.event.pull_request.number }} - body-includes: Empty String Usage Detected - comment-author: github-actions[bot] - - - name: Comment on PR + - name: Post review comments for findings if: steps.find_empty_strings.outputs.results != 'No empty strings found.' - uses: peter-evans/create-or-update-comment@v4 - with: - issue-number: ${{ github.event.pull_request.number }} - comment-id: ${{ steps.find_comment.outputs.comment-id }} - edit-mode: replace - body: | - ## Empty String Usage Detected - - The following occurrences of empty strings were detected. Please review them to ensure their usage is necessary: - - ```plaintext - ${{ steps.find_empty_strings.outputs.results }} - ``` - - - name: Remove comment - if: steps.find_empty_strings.outputs.results == 'No empty strings found.' uses: actions/github-script@v7 with: script: | - const { owner, repo } = context.repo; - const { number } = context.issue; - const comment_id = ${{ steps.find_comment.outputs.comment-id }} - github.rest.issues.deleteComment({ owner, repo, comment_id }); + const findings = `${{ steps.find_empty_strings.outputs.results }}`.split('\n'); + for (const finding of findings) { + const [path, line] = finding.split(':'); + const body = "Empty string detected!"; + const prNumber = context.payload.pull_request.number; + const owner = context.repo.owner; + const repo = context.repo.repo; + + await github.rest.pulls.createReviewComment({ + owner, + repo, + pull_number: prNumber, + body, + commit_id: context.payload.pull_request.head.sha, + path, + line: parseInt(line, 10), + }); + }