From 42f6962d281169337387809eaaa34c8ecc0df5ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Magrin?= Date: Mon, 2 Mar 2026 15:19:37 +0100 Subject: [PATCH] feat(chore): add CI/CD and templates --- .editorconfig | 12 ++ .github/ISSUE_TEMPLATE/bug_report.yml | 51 +++++++++ .github/ISSUE_TEMPLATE/feature_request.yml | 28 +++++ .github/pull_request_template.md | 18 +++ .github/workflows/ci.yml | 103 ++++++++++++++++++ bun.lock | 11 ++ .../extraction/hooks/useExtraction.ts | 2 +- .../results/hooks/useSupportPrompt.ts | 9 +- package.json | 1 + 9 files changed, 231 insertions(+), 4 deletions(-) create mode 100644 .editorconfig create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml create mode 100644 .github/pull_request_template.md create mode 100644 .github/workflows/ci.yml diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..4a7ea30 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..9b2f081 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,51 @@ +name: Bug Report +description: Report a bug in LinkPull +labels: [bug] + +body: + - type: textarea + id: description + attributes: + label: Describe the bug + description: A clear and concise description of what the bug is. + validations: + required: true + + - type: textarea + id: steps + attributes: + label: Steps to reproduce + description: Steps to reproduce the behavior. + placeholder: | + 1. Go to '...' + 2. Click on '...' + 3. See error + validations: + required: true + + - type: dropdown + id: browser + attributes: + label: Browser + options: + - Chrome + - Firefox + - Other + validations: + required: true + + - type: input + id: version + attributes: + label: Extension version + placeholder: e.g. 1.2.0 + validations: + required: true + + - type: textarea + id: context + attributes: + label: Additional context + description: Add any other context, screenshots, or screen recordings. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..1ffb294 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,28 @@ +name: Feature Request +description: Suggest a new feature for LinkPull +labels: [enhancement] + +body: + - type: textarea + id: description + attributes: + label: Describe the feature + description: A clear and concise description of the feature you'd like. + validations: + required: true + + - type: textarea + id: motivation + attributes: + label: Why is this useful? + description: Explain the problem this feature would solve or the value it would add. + validations: + required: true + + - type: textarea + id: alternatives + attributes: + label: Alternatives considered + description: Describe any alternative solutions or features you've considered. + validations: + required: false diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..49acc4a --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,18 @@ +## What + + + +## Why + + + +## How to test + + + +## Checklist + +- [ ] `npx eslint .` passes +- [ ] `npx tsc --noEmit` passes +- [ ] Tested in Chrome +- [ ] Tested in Firefox (if applicable) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..80dc440 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,103 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + install: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version-file: .nvmrc + + - uses: oven-sh/setup-bun@v2 + + - name: Install dependencies + run: bun install --ignore-scripts + + - name: Prepare WXT + run: npx wxt prepare + + - name: Cache node_modules and .wxt + uses: actions/cache/save@v4 + with: + path: | + node_modules + .wxt + key: deps-${{ github.sha }} + + lint: + needs: install + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version-file: .nvmrc + + - name: Restore cache + uses: actions/cache/restore@v4 + with: + path: | + node_modules + .wxt + key: deps-${{ github.sha }} + + - name: Lint + run: npx eslint . + + typecheck: + needs: install + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version-file: .nvmrc + + - name: Restore cache + uses: actions/cache/restore@v4 + with: + path: | + node_modules + .wxt + key: deps-${{ github.sha }} + + - name: Type-check + run: npx tsc --noEmit + + build: + needs: install + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version-file: .nvmrc + + - name: Restore cache + uses: actions/cache/restore@v4 + with: + path: | + node_modules + .wxt + key: deps-${{ github.sha }} + + - name: Build (Chrome) + run: npx wxt build + + - name: Build (Firefox) + run: npx wxt build -b firefox diff --git a/bun.lock b/bun.lock index 1087a3e..9d56620 100644 --- a/bun.lock +++ b/bun.lock @@ -19,6 +19,7 @@ "eslint": "^9.39.3", "eslint-config-prettier": "^10.1.8", "eslint-plugin-perfectionist": "^5.6.0", + "eslint-plugin-prettier": "^5.5.5", "eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-refresh": "^0.5.2", "globals": "^17.4.0", @@ -180,6 +181,8 @@ "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], + "@pkgr/core": ["@pkgr/core@0.2.9", "", {}, "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA=="], + "@pnpm/config.env-replace": ["@pnpm/config.env-replace@1.1.0", "", {}, "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w=="], "@pnpm/network.ca-file": ["@pnpm/network.ca-file@1.0.2", "", { "dependencies": { "graceful-fs": "4.2.10" } }, "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA=="], @@ -516,6 +519,8 @@ "eslint-plugin-perfectionist": ["eslint-plugin-perfectionist@5.6.0", "", { "dependencies": { "@typescript-eslint/utils": "^8.56.0", "natural-orderby": "^5.0.0" }, "peerDependencies": { "eslint": "^8.45.0 || ^9.0.0 || ^10.0.0" } }, "sha512-pxrLrfRp5wl1Vol1fAEa/G5yTXxefTPJjz07qC7a8iWFXcOZNuWBItMQ2OtTzfQIvMq6bMyYcrzc3Wz++na55Q=="], + "eslint-plugin-prettier": ["eslint-plugin-prettier@5.5.5", "", { "dependencies": { "prettier-linter-helpers": "^1.0.1", "synckit": "^0.11.12" }, "peerDependencies": { "@types/eslint": ">=8.0.0", "eslint": ">=8.0.0", "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", "prettier": ">=3.0.0" }, "optionalPeers": ["@types/eslint", "eslint-config-prettier"] }, "sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw=="], + "eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@7.0.1", "", { "dependencies": { "@babel/core": "^7.24.4", "@babel/parser": "^7.24.4", "hermes-parser": "^0.25.1", "zod": "^3.25.0 || ^4.0.0", "zod-validation-error": "^3.5.0 || ^4.0.0" }, "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA=="], "eslint-plugin-react-refresh": ["eslint-plugin-react-refresh@0.5.2", "", { "peerDependencies": { "eslint": "^9 || ^10" } }, "sha512-hmgTH57GfzoTFjVN0yBwTggnsVUF2tcqi7RJZHqi9lIezSs4eFyAMktA68YD4r5kNw1mxyY4dmkyoFDb3FIqrA=="], @@ -542,6 +547,8 @@ "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + "fast-diff": ["fast-diff@1.3.0", "", {}, "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw=="], + "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], @@ -882,6 +889,8 @@ "prettier": ["prettier@3.8.1", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg=="], + "prettier-linter-helpers": ["prettier-linter-helpers@1.0.1", "", { "dependencies": { "fast-diff": "^1.1.2" } }, "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg=="], + "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], "process-warning": ["process-warning@5.0.0", "", {}, "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA=="], @@ -1006,6 +1015,8 @@ "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + "synckit": ["synckit@0.11.12", "", { "dependencies": { "@pkgr/core": "^0.2.9" } }, "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ=="], + "tailwindcss": ["tailwindcss@4.2.1", "", {}, "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw=="], "tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="], diff --git a/entrypoints/sidepanel/features/extraction/hooks/useExtraction.ts b/entrypoints/sidepanel/features/extraction/hooks/useExtraction.ts index e02483d..2e497a2 100644 --- a/entrypoints/sidepanel/features/extraction/hooks/useExtraction.ts +++ b/entrypoints/sidepanel/features/extraction/hooks/useExtraction.ts @@ -79,7 +79,7 @@ export const useExtraction = (settings: Settings) => { try { await browser.scripting.executeScript({ target: { tabId: tab.id }, - files: ['content-scripts/content.js'], + files: ['/content-scripts/content.js'], }) await new Promise((r) => setTimeout(r, 500)) context = await sendMessage('get-context', undefined, tab.id) diff --git a/entrypoints/sidepanel/features/results/hooks/useSupportPrompt.ts b/entrypoints/sidepanel/features/results/hooks/useSupportPrompt.ts index 03b7862..8f0c2b6 100644 --- a/entrypoints/sidepanel/features/results/hooks/useSupportPrompt.ts +++ b/entrypoints/sidepanel/features/results/hooks/useSupportPrompt.ts @@ -26,7 +26,8 @@ export const useSupportPrompt = (postCount: number) => { ;(async () => { try { const stored = await browser.storage.local.get(SUPPORT_KEY) - const state: SupportState = { ...DEFAULT_STATE, ...stored[SUPPORT_KEY] } + const prev = stored[SUPPORT_KEY] as Partial | undefined + const state: SupportState = { ...DEFAULT_STATE, ...prev } // Increment extraction count state.extractionCount++ @@ -59,7 +60,8 @@ export const useSupportPrompt = (postCount: number) => { setVisible(false) try { const stored = await browser.storage.local.get(SUPPORT_KEY) - const state: SupportState = { ...DEFAULT_STATE, ...stored[SUPPORT_KEY] } + const prev = stored[SUPPORT_KEY] as Partial | undefined + const state: SupportState = { ...DEFAULT_STATE, ...prev } state.lastDismissed = Date.now() await browser.storage.local.set({ [SUPPORT_KEY]: state }) } catch { @@ -71,7 +73,8 @@ export const useSupportPrompt = (postCount: number) => { setVisible(false) try { const stored = await browser.storage.local.get(SUPPORT_KEY) - const state: SupportState = { ...DEFAULT_STATE, ...stored[SUPPORT_KEY] } + const prev = stored[SUPPORT_KEY] as Partial | undefined + const state: SupportState = { ...DEFAULT_STATE, ...prev } state.ratedOrSupported = true await browser.storage.local.set({ [SUPPORT_KEY]: state }) } catch { diff --git a/package.json b/package.json index 8b26751..177a678 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "autoprefixer": "^10.4.24", "eslint": "^9.39.3", "eslint-config-prettier": "^10.1.8", + "eslint-plugin-prettier": "^5.5.5", "eslint-plugin-perfectionist": "^5.6.0", "eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-refresh": "^0.5.2",