From 04631cfa515f873cac726ca3adeb965376b28229 Mon Sep 17 00:00:00 2001 From: Andrey Helldar Date: Tue, 13 Jan 2026 22:20:33 +0300 Subject: [PATCH 1/2] Refactor codebase: enforce double quotes, improve readability, integrate Biome config, and enhance tests with updated fixtures. --- biome.json | 58 ++++++++++++ package.json | 5 +- src/types/config.ts | 4 +- src/utils/preview.ts | 7 +- src/utils/repository.ts | 160 ++++++++++++++++------------------ tests/helpers/filesystem.ts | 2 +- tests/unit/filesystem.test.ts | 114 +++++++++++++----------- 7 files changed, 208 insertions(+), 142 deletions(-) create mode 100644 biome.json diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..5a4a2d5 --- /dev/null +++ b/biome.json @@ -0,0 +1,58 @@ +{ + "$schema": "./node_modules/@biomejs/biome/configuration_schema.json", + "vcs": { + "enabled": false, + "clientKind": "git", + "useIgnoreFile": false + }, + "files": { + "ignoreUnknown": false, + "includes": [ + "**", + "!node_modules", + "!vendor", + "!composer.json", + "!composer.lock", + "!package.json", + "!package-lock.json", + "!analytics.*", + "!metrics.*", + "!coverage", + "!dist" + ] + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 4 + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true + } + }, + "javascript": { + "formatter": { + "quoteStyle": "double" + } + }, + "json": { + "formatter": { + "enabled": true, + "bracketSpacing": true, + "expand": "always" + }, + "parser": { + "allowComments": true + } + }, + "assist": { + "enabled": true, + "actions": { + "source": { + "organizeImports": "on" + } + } + } +} diff --git a/package.json b/package.json index 254361b..cacff3a 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,10 @@ "dev": "npm run build && node dist/index.js", "coverage": "jest --coverage", "test": "jest", - "type-check": "tsc --noEmit" + "type-check": "tsc --noEmit", + "lint": "npx @biomejs/biome lint --write", + "format": "npx @biomejs/biome format --write", + "style": "npm run lint && npm run format" }, "keywords": [ "preview", diff --git a/src/types/config.ts b/src/types/config.ts index 739d688..c599a61 100644 --- a/src/types/config.ts +++ b/src/types/config.ts @@ -1,3 +1,5 @@ +import type { GitHub } from "@actions/github/lib/utils"; + export interface ImageParameters { pattern: string; style: string; @@ -39,7 +41,7 @@ export interface PullRequest { export interface Repository { owner?: string; repo?: string; - octokit?: any; + octokit?: InstanceType; commit: Commit; pullRequest: PullRequest; diff --git a/src/utils/preview.ts b/src/utils/preview.ts index dbda915..1824438 100644 --- a/src/utils/preview.ts +++ b/src/utils/preview.ts @@ -19,5 +19,10 @@ export const setPreview = (content: string, config: Config) => { const images: string = getImages(config); - return cleanUp(content).replace(/^(#\s+.+[\n\s]+)/, "$1" + images + "\n\n"); + const replace = "$1"; + + return cleanUp(content).replace( + /^(#\s+.+[\n\s]+)/, + `${replace}${images}\n\n`, + ); }; diff --git a/src/utils/repository.ts b/src/utils/repository.ts index adb4ba9..9bc69c2 100644 --- a/src/utils/repository.ts +++ b/src/utils/repository.ts @@ -1,130 +1,121 @@ -import type { Config } from '../types/config' -import { exec } from './filesystem' -import { randomizer } from './randomizer' - -export class Repository -{ - private _config: Config - private _currentBranch: string = '' - private _newBranch: boolean = false - - constructor(config: Config) - { - this._config = config +import type { Config } from "../types/config"; +import { exec } from "./filesystem"; +import { randomizer } from "./randomizer"; + +export class Repository { + private _config: Config; + private _currentBranch: string = ""; + private _newBranch: boolean = false; + + constructor(config: Config) { + this._config = config; } - async authenticate() - { + async authenticate() { try { - const author = this._config.repository.commit.author + const author = this._config.repository.commit.author; - await exec(`git config user.name "${ author.name }"`) - await exec(`git config user.email "${ author.email }"`) + await exec(`git config user.name "${author.name}"`); + await exec(`git config user.email "${author.email}"`); } catch (error) { // @ts-expect-error - error.message = `Error authenticating user "${ author.name }" with e-mail "${ author.email }": ${ error.message }` + error.message = `Error authenticating user "${author.name}" with e-mail "${author.email}": ${error.message}`; - throw error + throw error; } } - async branchExists() - { + async branchExists() { try { const hasLocalBranch = async () => { const result = await exec( - `git branch --list "${ this.branchName() }"` - ) + `git branch --list "${this.branchName()}"`, + ); - return result.includes(this.branchName()) - } + return result.includes(this.branchName()); + }; const hasRemoteBranch = async () => { const result = await exec( - `git ls-remote --heads origin "${ this.branchName() }"` - ) + `git ls-remote --heads origin "${this.branchName()}"`, + ); - return result.includes(this.branchName()) - } + return result.includes(this.branchName()); + }; - return (await hasLocalBranch()) || (await hasRemoteBranch()) + return (await hasLocalBranch()) || (await hasRemoteBranch()); } catch (error) { // @ts-expect-error - error.message = `Error searching for branch "${ this.branchName() }": ${ error.message }` + error.message = `Error searching for branch "${this.branchName()}": ${error.message}`; - throw error + throw error; } } - async checkoutBranch(isNew: boolean) - { + async checkoutBranch(isNew: boolean) { try { - this._newBranch = isNew + this._newBranch = isNew; await exec( - `git switch ${ isNew ? '-c' : '' } "${ this.branchName() }"` - ) + `git switch ${isNew ? "-c" : ""} "${this.branchName()}"`, + ); } catch (error) { // @ts-expect-error - error.message = `Error checking out ${ isNew ? 'new' : 'existing' } branch "${ this.branchName() }": ${ error.message }` + error.message = `Error checking out ${isNew ? "new" : "existing"} branch "${this.branchName()}": ${error.message}`; - throw error + throw error; } } - async stage() - { + async stage() { try { - await exec('git add ' + this._config.path.readme) + await exec(`git add ${this._config.path.readme}`); } catch (error) { // @ts-expect-error - error.message = `Error staging file "${ this._config.path.readme }": ${ error.message }` + error.message = `Error staging file "${this._config.path.readme}": ${error.message}`; - throw error + throw error; } } - async commit() - { + async commit() { try { const message = this._config.repository.commit.title + - '\n' + - this._config.repository.commit.body + "\n" + + this._config.repository.commit.body; - await exec(`git commit -m "${ message }"`) + await exec(`git commit -m "${message}"`); } catch (error) { // @ts-expect-error - error.message = `Error committing file "${ this._config.path.readme }": ${ error.message }` + error.message = `Error committing file "${this._config.path.readme}": ${error.message}`; - throw error + throw error; } } - async push() - { + async push() { try { - let cmd = 'git push' + let cmd = "git push"; if (this._newBranch) { - cmd += ` --set-upstream origin ${ this.branchName() }` + cmd += ` --set-upstream origin ${this.branchName()}`; } - await exec(cmd) + await exec(cmd); } catch (error) { // @ts-expect-error - error.message = `Error pushing changes to "${ this.branchName() } branch": ${ error.message }` + error.message = `Error pushing changes to "${this.branchName()} branch": ${error.message}`; - throw error + throw error; } } - async createPullRequest() - { + async createPullRequest() { try { const defaultBranch = await exec( - `git remote show origin | grep 'HEAD branch' | cut -d ' ' -f5` - ) + `git remote show origin | grep 'HEAD branch' | cut -d ' ' -f5`, + ); return this._config.repository.octokit.rest.pulls.create({ owner: this._config.repository.owner, @@ -132,59 +123,56 @@ export class Repository title: this._config.repository.pullRequest.title, body: this._config.repository.pullRequest.body, head: this.branchName(), - base: defaultBranch - }) + base: defaultBranch, + }); } catch (error) { // @ts-expect-error - error.message = `Error when creating pull request from ${ this.branchName() }: ${ error.message }` + error.message = `Error when creating pull request from ${this.branchName()}: ${error.message}`; - throw error + throw error; } } - async assignee(issueNumber: number, assignees: string[]) - { + async assignee(issueNumber: number, assignees: string[]) { try { return this._config.repository.octokit.rest.issues.addAssignees({ owner: this._config.repository.owner, repo: this._config.repository.repo, issue_number: issueNumber, - assignees: assignees - }) + assignees: assignees, + }); } catch (error) { // @ts-expect-error - error.message = `Error when adding assignees to issue ${ issueNumber }: ${ error.message }` + error.message = `Error when adding assignees to issue ${issueNumber}: ${error.message}`; - throw error + throw error; } } - async addLabels(issueNumber: number, labels: string[]) - { + async addLabels(issueNumber: number, labels: string[]) { try { return this._config.repository.octokit.rest.issues.addLabels({ owner: this._config.repository.owner, repo: this._config.repository.repo, issue_number: issueNumber, - labels - }) + labels, + }); } catch (error) { // @ts-expect-error - error.message = `Error when adding labels to issue ${ issueNumber }: ${ error.message }` + error.message = `Error when adding labels to issue ${issueNumber}: ${error.message}`; - throw error + throw error; } } - branchName(): string - { - if (this._currentBranch === '') { + branchName(): string { + if (this._currentBranch === "") { this._currentBranch = this._config.repository.commit.branch.replace( - '{random}', - randomizer() - ) + "{random}", + randomizer(), + ); } - return this._currentBranch + return this._currentBranch; } } diff --git a/tests/helpers/filesystem.ts b/tests/helpers/filesystem.ts index 82562d9..bbee0af 100644 --- a/tests/helpers/filesystem.ts +++ b/tests/helpers/filesystem.ts @@ -3,7 +3,7 @@ import { setPreview } from "../../src/utils/preview"; import { testConfig } from "./config"; export const getReadme = (filename: string): string => { - const content = readFile(testConfig, "tests/fixtures/readme/" + filename); + const content = readFile(testConfig, `tests/fixtures/readme/${filename}`); return setPreview(content, testConfig); }; diff --git a/tests/unit/filesystem.test.ts b/tests/unit/filesystem.test.ts index 6367afe..6e0d5e1 100644 --- a/tests/unit/filesystem.test.ts +++ b/tests/unit/filesystem.test.ts @@ -1,66 +1,76 @@ -import { rawTestConfig } from '../helpers/config' -import { type Config, defaultConfig } from '../../src/types/config' -import { readConfig } from '../../src/utils/filesystem' -import { CONFIG_PATH } from '../../src/utils/inputs' +import { rawTestConfig } from "../helpers/config"; +import { type Config, defaultConfig } from "../../src/types/config"; +import { readConfig } from "../../src/utils/filesystem"; +import { CONFIG_PATH } from "../../src/utils/inputs"; -test('read config', () => { - const data: Config = readConfig(rawTestConfig, CONFIG_PATH.defaultValue) +test("read config", () => { + const data: Config = readConfig(rawTestConfig, CONFIG_PATH.defaultValue); - expect(data.directory).toBe(process.cwd()) + expect(data.directory).toBe(process.cwd()); expect(data.image.parameters.packageName).toBe( - 'TheDragonCode/preview-updater' - ) - expect(data.image.parameters.title).toBe('Preview Updater') + "TheDragonCode/preview-updater", + ); + expect(data.image.parameters.title).toBe("Preview Updater"); expect(data.image.parameters.description).toBe( - 'Lightweight preview update in your repository' - ) + "Lightweight preview update in your repository", + ); - expect(data.path.readme).toBe(defaultConfig.path.readme) - expect(data.image.url).toBe(defaultConfig.image.url) + expect(data.path.readme).toBe(defaultConfig.path.readme); + expect(data.image.url).toBe(defaultConfig.image.url); expect(data.image.parameters.pattern).toBe( - defaultConfig.image.parameters.pattern - ) + defaultConfig.image.parameters.pattern, + ); - expect(data.image.parameters.packageManager).toBe('none') - expect(data.image.parameters.icon).toBe('photograph') -}) + expect(data.image.parameters.packageManager).toBe("none"); + expect(data.image.parameters.icon).toBe("photograph"); +}); -test('custom config', () => { - const data: Config = readConfig({ - directory: process.cwd() - }, 'tests/fixtures/configs/preview.yml') +test("custom config", () => { + const data: Config = readConfig( + { + directory: process.cwd(), + }, + "tests/fixtures/configs/preview.yml", + ); - expect(data.path.readme).toBe('README-foo.md') + expect(data.path.readme).toBe("README-foo.md"); - expect(data.image.url).toBe('https://example.com/image.png') - expect(data.image.parameters.pattern).toBe('cage') - expect(data.image.parameters.style).toBe('style_1') + expect(data.image.url).toBe("https://example.com/image.png"); + expect(data.image.parameters.pattern).toBe("cage"); + expect(data.image.parameters.style).toBe("style_1"); - expect(data.image.parameters.fontSize).toBe('123px') - expect(data.image.parameters.icon).toBe('cog') + expect(data.image.parameters.fontSize).toBe("123px"); + expect(data.image.parameters.icon).toBe("cog"); - expect(data.image.parameters.packageManager).toBe('yarn') - expect(data.image.parameters.packageGlobal).toBe(true) - expect(data.image.parameters.packageName).toBe('foo/bar') + expect(data.image.parameters.packageManager).toBe("yarn"); + expect(data.image.parameters.packageGlobal).toBe(true); + expect(data.image.parameters.packageName).toBe("foo/bar"); - expect(data.image.parameters.title).toBe('Foo Bar') - expect(data.image.parameters.description).toBe('Lorem ipsum dolor sit amet.') - - expect(data.repository.commit.branch).toBe('qwerty') - expect(data.repository.commit.title).toBe('Foo Bar Commit') - expect(data.repository.commit.body).toBe('Eu assum suscipit, vel veniam eu sadipscing kasd invidunt elit wisi.') - - expect(data.repository.commit.author.name).toBe('some_username') - expect(data.repository.commit.author.email).toBe('some_username@example.com') - - expect(data.repository.pullRequest.title).toBe('Foo Bar Baz Pull Request') - expect(data.repository.pullRequest.body).toBe('Eu assum suscipit, vel veniam eu sadipscing kasd invidunt elit wisi.') - - expect(data.repository.pullRequest.assignees.length).toBe(2) - expect(data.repository.pullRequest.assignees.join('-')).toBe('foo1-foo2') - - expect(data.repository.pullRequest.labels.length).toBe(2) - expect(data.repository.pullRequest.labels.join('-')).toBe('foo3-foo4') - -}) + expect(data.image.parameters.title).toBe("Foo Bar"); + expect(data.image.parameters.description).toBe( + "Lorem ipsum dolor sit amet.", + ); + + expect(data.repository.commit.branch).toBe("qwerty"); + expect(data.repository.commit.title).toBe("Foo Bar Commit"); + expect(data.repository.commit.body).toBe( + "Eu assum suscipit, vel veniam eu sadipscing kasd invidunt elit wisi.", + ); + + expect(data.repository.commit.author.name).toBe("some_username"); + expect(data.repository.commit.author.email).toBe( + "some_username@example.com", + ); + + expect(data.repository.pullRequest.title).toBe("Foo Bar Baz Pull Request"); + expect(data.repository.pullRequest.body).toBe( + "Eu assum suscipit, vel veniam eu sadipscing kasd invidunt elit wisi.", + ); + + expect(data.repository.pullRequest.assignees.length).toBe(2); + expect(data.repository.pullRequest.assignees.join("-")).toBe("foo1-foo2"); + + expect(data.repository.pullRequest.labels.length).toBe(2); + expect(data.repository.pullRequest.labels.join("-")).toBe("foo3-foo4"); +}); From f84a21de86ae8c447efe2ca1ea0cc3175722492e Mon Sep 17 00:00:00 2001 From: Andrey Helldar Date: Tue, 13 Jan 2026 22:29:23 +0300 Subject: [PATCH 2/2] Fixed types --- dist/index.js | 39 ++++++++++++++++++++------------------- src/main.ts | 3 +-- src/types/config.ts | 3 --- src/utils/repository.ts | 18 ++++++++++++++---- 4 files changed, 35 insertions(+), 28 deletions(-) diff --git a/dist/index.js b/dist/index.js index b9c3b9f..8047e36 100644 --- a/dist/index.js +++ b/dist/index.js @@ -34392,7 +34392,6 @@ const previewUpdater = async () => { repository: { owner: github_1.context.repo.owner, repo: github_1.context.repo.repo, - octokit: (0, github_1.getOctokit)(token), }, }, configPath); // Read names @@ -34404,7 +34403,7 @@ const previewUpdater = async () => { // Show working directory (0, core_1.info)(`Working directory: ${config.directory}`); // Authenticate - const repo = new repository_1.Repository(config); + const repo = new repository_1.Repository(config, (0, github_1.getOctokit)(token)); await repo.authenticate(); // Read file const content = (0, filesystem_1.readFile)(config, config.path.readme); @@ -34463,8 +34462,8 @@ exports.defaultConfig = { fontSize: "100px", icon: "code", packageManager: "auto", - packageName: undefined, packageGlobal: false, + packageName: undefined, title: undefined, description: undefined, }, @@ -34754,7 +34753,8 @@ const setPreview = (content, config) => { content = `# ${title}\n\n${content}`; } const images = (0, image_1.getImages)(config); - return cleanUp(content).replace(/^(#\s+.+[\n\s]+)/, "$1" + images + "\n\n"); + const replace = "$1"; + return cleanUp(content).replace(/^(#\s+.+[\n\s]+)/, `${replace}${images}\n\n`); }; exports.setPreview = setPreview; @@ -34791,10 +34791,11 @@ exports.Repository = void 0; const filesystem_1 = __nccwpck_require__(9742); const randomizer_1 = __nccwpck_require__(3678); class Repository { - constructor(config) { - this._currentBranch = ''; + constructor(config, octokit) { + this._currentBranch = ""; this._newBranch = false; this._config = config; + this._octokit = octokit; } async authenticate() { try { @@ -34829,17 +34830,17 @@ class Repository { async checkoutBranch(isNew) { try { this._newBranch = isNew; - await (0, filesystem_1.exec)(`git switch ${isNew ? '-c' : ''} "${this.branchName()}"`); + await (0, filesystem_1.exec)(`git switch ${isNew ? "-c" : ""} "${this.branchName()}"`); } catch (error) { // @ts-expect-error - error.message = `Error checking out ${isNew ? 'new' : 'existing'} branch "${this.branchName()}": ${error.message}`; + error.message = `Error checking out ${isNew ? "new" : "existing"} branch "${this.branchName()}": ${error.message}`; throw error; } } async stage() { try { - await (0, filesystem_1.exec)('git add ' + this._config.path.readme); + await (0, filesystem_1.exec)(`git add ${this._config.path.readme}`); } catch (error) { // @ts-expect-error @@ -34850,7 +34851,7 @@ class Repository { async commit() { try { const message = this._config.repository.commit.title + - '\n' + + "\n" + this._config.repository.commit.body; await (0, filesystem_1.exec)(`git commit -m "${message}"`); } @@ -34862,7 +34863,7 @@ class Repository { } async push() { try { - let cmd = 'git push'; + let cmd = "git push"; if (this._newBranch) { cmd += ` --set-upstream origin ${this.branchName()}`; } @@ -34877,13 +34878,13 @@ class Repository { async createPullRequest() { try { const defaultBranch = await (0, filesystem_1.exec)(`git remote show origin | grep 'HEAD branch' | cut -d ' ' -f5`); - return this._config.repository.octokit.rest.pulls.create({ + return this._octokit.rest.pulls.create({ owner: this._config.repository.owner, repo: this._config.repository.repo, title: this._config.repository.pullRequest.title, body: this._config.repository.pullRequest.body, head: this.branchName(), - base: defaultBranch + base: defaultBranch, }); } catch (error) { @@ -34894,11 +34895,11 @@ class Repository { } async assignee(issueNumber, assignees) { try { - return this._config.repository.octokit.rest.issues.addAssignees({ + return this._octokit.rest.issues.addAssignees({ owner: this._config.repository.owner, repo: this._config.repository.repo, issue_number: issueNumber, - assignees: assignees + assignees: assignees, }); } catch (error) { @@ -34909,11 +34910,11 @@ class Repository { } async addLabels(issueNumber, labels) { try { - return this._config.repository.octokit.rest.issues.addLabels({ + return this._octokit.rest.issues.addLabels({ owner: this._config.repository.owner, repo: this._config.repository.repo, issue_number: issueNumber, - labels + labels, }); } catch (error) { @@ -34923,8 +34924,8 @@ class Repository { } } branchName() { - if (this._currentBranch === '') { - this._currentBranch = this._config.repository.commit.branch.replace('{random}', (0, randomizer_1.randomizer)()); + if (this._currentBranch === "") { + this._currentBranch = this._config.repository.commit.branch.replace("{random}", (0, randomizer_1.randomizer)()); } return this._currentBranch; } diff --git a/src/main.ts b/src/main.ts index cff1e2c..774787c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -21,7 +21,6 @@ const previewUpdater = async () => { repository: { owner: context.repo.owner, repo: context.repo.repo, - octokit: getOctokit(token), }, }, configPath, @@ -39,7 +38,7 @@ const previewUpdater = async () => { info(`Working directory: ${config.directory}`); // Authenticate - const repo = new Repository(config); + const repo = new Repository(config, getOctokit(token)); await repo.authenticate(); // Read file diff --git a/src/types/config.ts b/src/types/config.ts index c599a61..371cc22 100644 --- a/src/types/config.ts +++ b/src/types/config.ts @@ -1,5 +1,3 @@ -import type { GitHub } from "@actions/github/lib/utils"; - export interface ImageParameters { pattern: string; style: string; @@ -41,7 +39,6 @@ export interface PullRequest { export interface Repository { owner?: string; repo?: string; - octokit?: InstanceType; commit: Commit; pullRequest: PullRequest; diff --git a/src/utils/repository.ts b/src/utils/repository.ts index 9bc69c2..142c1ef 100644 --- a/src/utils/repository.ts +++ b/src/utils/repository.ts @@ -1,14 +1,18 @@ import type { Config } from "../types/config"; import { exec } from "./filesystem"; import { randomizer } from "./randomizer"; +import type { GitHub } from "@actions/github/lib/utils"; +import type { RestEndpointMethodTypes } from "@octokit/plugin-rest-endpoint-methods/dist-types/generated/parameters-and-response-types"; export class Repository { private _config: Config; private _currentBranch: string = ""; private _newBranch: boolean = false; + private _octokit: InstanceType; - constructor(config: Config) { + constructor(config: Config, octokit: InstanceType) { this._config = config; + this._octokit = octokit; } async authenticate() { @@ -117,7 +121,9 @@ export class Repository { `git remote show origin | grep 'HEAD branch' | cut -d ' ' -f5`, ); - return this._config.repository.octokit.rest.pulls.create({ + return this._octokit.rest.pulls.create(< + RestEndpointMethodTypes["pulls"]["create"]["parameters"] + >{ owner: this._config.repository.owner, repo: this._config.repository.repo, title: this._config.repository.pullRequest.title, @@ -135,7 +141,9 @@ export class Repository { async assignee(issueNumber: number, assignees: string[]) { try { - return this._config.repository.octokit.rest.issues.addAssignees({ + return this._octokit.rest.issues.addAssignees(< + RestEndpointMethodTypes["issues"]["addAssignees"]["parameters"] + >{ owner: this._config.repository.owner, repo: this._config.repository.repo, issue_number: issueNumber, @@ -151,7 +159,9 @@ export class Repository { async addLabels(issueNumber: number, labels: string[]) { try { - return this._config.repository.octokit.rest.issues.addLabels({ + return this._octokit.rest.issues.addLabels(< + RestEndpointMethodTypes["issues"]["addLabels"]["parameters"] + >{ owner: this._config.repository.owner, repo: this._config.repository.repo, issue_number: issueNumber,