Compare commits

..

No commits in common. "main" and "v2.9.2" have entirely different histories.
main ... v2.9.2

15 changed files with 4467 additions and 2852 deletions

View file

@ -11,14 +11,15 @@ jobs:
permissions: permissions:
pull-requests: write pull-requests: write
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- run: yarn install - run: yarn install
- run: | - run: |
set -o pipefail set -o pipefail
mkdir -p ./pr mkdir -p ./pr
echo ${{ github.event.number }} | tee ./pr/number
EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64) EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64)
echo "all_result<<$EOF" >> "$GITHUB_ENV" echo "all_result<<$EOF" >> "$GITHUB_ENV"
yarn all >> "$GITHUB_ENV" 2>&1 || true # proceed even if yarn fails yarn all >> "$GITHUB_ENV" 2&>1 || true # proceed even if yarn fails
echo >> "$GITHUB_ENV" # yarn all doesn't necessarily produce a newline echo >> "$GITHUB_ENV" # yarn all doesn't necessarily produce a newline
echo "$EOF" >> "$GITHUB_ENV" echo "$EOF" >> "$GITHUB_ENV"
id: all id: all
@ -28,9 +29,9 @@ jobs:
header: All header: All
message: | message: |
<details open> <details open>
<summary>Output of yarn all</summary> <summary>output of yarn all</summary>
```shell ```
${{ env.all_result }} ${{ env.all_result }}
``` ```
</details> </details>

View file

@ -1,6 +1,5 @@
import {getOctokit} from "@actions/github" import {getOctokit} from "@actions/github"
import * as core from "@actions/core" import * as core from "@actions/core"
import { vi, describe, it, expect, beforeEach } from 'vitest'
import { import {
createComment, createComment,
@ -12,8 +11,8 @@ import {
commentsEqual commentsEqual
} from "../src/comment" } from "../src/comment"
vi.mock("@actions/core", () => ({ jest.mock("@actions/core", () => ({
warning: vi.fn() warning: jest.fn()
})) }))
const repo = { const repo = {
@ -69,7 +68,7 @@ it("findPreviousComment", async () => {
} }
] ]
const octokit = getOctokit("github-token") const octokit = getOctokit("github-token")
vi.spyOn(octokit, "graphql").mockResolvedValue({ jest.spyOn(octokit, "graphql").mockResolvedValue({
viewer: authenticatedBotUser, viewer: authenticatedBotUser,
repository: { repository: {
pullRequest: { pullRequest: {
@ -105,7 +104,7 @@ describe("updateComment", () => {
const octokit = getOctokit("github-token") const octokit = getOctokit("github-token")
beforeEach(() => { beforeEach(() => {
vi.spyOn(octokit, "graphql").mockResolvedValue("") jest.spyOn<any, string>(octokit, "graphql").mockResolvedValue("")
}) })
it("with comment body", async () => { it("with comment body", async () => {
@ -151,12 +150,13 @@ describe("createComment", () => {
const octokit = getOctokit("github-token") const octokit = getOctokit("github-token")
beforeEach(() => { beforeEach(() => {
vi.spyOn(octokit.rest.issues, "createComment") jest
.mockResolvedValue({ data: "<return value>" } as any) .spyOn<any, string>(octokit.rest.issues, "createComment")
.mockResolvedValue("<return value>")
}) })
it("with comment body or previousBody", async () => { it("with comment body or previousBody", async () => {
expect(await createComment(octokit, repo, 456, "hello there", "")).toEqual({ data: "<return value>" }) expect(await createComment(octokit, repo, 456, "hello there", "")).toEqual("<return value>")
expect(octokit.rest.issues.createComment).toBeCalledWith({ expect(octokit.rest.issues.createComment).toBeCalledWith({
issue_number: 456, issue_number: 456,
owner: "marocchino", owner: "marocchino",
@ -164,7 +164,7 @@ describe("createComment", () => {
body: "hello there\n<!-- Sticky Pull Request Comment -->" body: "hello there\n<!-- Sticky Pull Request Comment -->"
}) })
expect(await createComment(octokit, repo, 456, "hello there", "TypeA")).toEqual( expect(await createComment(octokit, repo, 456, "hello there", "TypeA")).toEqual(
{ data: "<return value>" } "<return value>"
) )
expect(octokit.rest.issues.createComment).toBeCalledWith({ expect(octokit.rest.issues.createComment).toBeCalledWith({
issue_number: 456, issue_number: 456,
@ -183,7 +183,7 @@ describe("createComment", () => {
it("deleteComment", async () => { it("deleteComment", async () => {
const octokit = getOctokit("github-token") const octokit = getOctokit("github-token")
vi.spyOn(octokit, "graphql").mockReturnValue(undefined as any) jest.spyOn(octokit, "graphql").mockReturnValue(undefined as any)
expect(await deleteComment(octokit, "456")).toBeUndefined() expect(await deleteComment(octokit, "456")).toBeUndefined()
expect(octokit.graphql).toBeCalledWith(expect.any(String), { expect(octokit.graphql).toBeCalledWith(expect.any(String), {
id: "456" id: "456"
@ -193,7 +193,7 @@ it("deleteComment", async () => {
it("minimizeComment", async () => { it("minimizeComment", async () => {
const octokit = getOctokit("github-token") const octokit = getOctokit("github-token")
vi.spyOn(octokit, "graphql").mockReturnValue(undefined as any) jest.spyOn(octokit, "graphql").mockReturnValue(undefined as any)
expect(await minimizeComment(octokit, "456", "OUTDATED")).toBeUndefined() expect(await minimizeComment(octokit, "456", "OUTDATED")).toBeUndefined()
expect(octokit.graphql).toBeCalledWith(expect.any(String), { expect(octokit.graphql).toBeCalledWith(expect.any(String), {
input: { input: {
@ -226,7 +226,7 @@ describe("getBodyOf", () => {
</details> </details>
<!-- Sticky Pull Request CommentTypeA --> <!-- Sticky Pull Request CommentTypeA -->
` `
it.each` test.each`
append | hideDetails | previous | expected append | hideDetails | previous | expected
${false} | ${false} | ${detailsPrevious} | ${undefined} ${false} | ${false} | ${detailsPrevious} | ${undefined}
${true} | ${false} | ${nullPrevious} | ${undefined} ${true} | ${false} | ${nullPrevious} | ${undefined}
@ -243,7 +243,7 @@ describe("getBodyOf", () => {
}) })
describe("commentsEqual", () => { describe("commentsEqual", () => {
it.each([ test.each([
{ {
body: "body", body: "body",
previous: "body\n<!-- Sticky Pull Request Commentheader -->", previous: "body\n<!-- Sticky Pull Request Commentheader -->",

View file

@ -1,28 +1,4 @@
import { beforeEach, afterEach, test, expect, vi, describe } from 'vitest'
const mockConfig = {
pullRequestNumber: 123,
repo: {owner: "marocchino", repo: "stick-pull-request-comment"},
header: "",
append: false,
recreate: false,
deleteOldComment: false,
hideOldComment: false,
hideAndRecreate: false,
hideClassify: "OUTDATED",
hideDetails: false,
githubToken: "some-token",
ignoreEmpty: false,
skipUnchanged: false,
getBody: vi.fn().mockResolvedValue("")
}
vi.mock('../src/config', () => {
return mockConfig
})
beforeEach(() => { beforeEach(() => {
// Set up default environment variables for each test
process.env["GITHUB_REPOSITORY"] = "marocchino/stick-pull-request-comment" process.env["GITHUB_REPOSITORY"] = "marocchino/stick-pull-request-comment"
process.env["INPUT_NUMBER"] = "123" process.env["INPUT_NUMBER"] = "123"
process.env["INPUT_APPEND"] = "false" process.env["INPUT_APPEND"] = "false"
@ -38,26 +14,10 @@ beforeEach(() => {
process.env["INPUT_IGNORE_EMPTY"] = "false" process.env["INPUT_IGNORE_EMPTY"] = "false"
process.env["INPUT_SKIP_UNCHANGED"] = "false" process.env["INPUT_SKIP_UNCHANGED"] = "false"
process.env["INPUT_FOLLOW_SYMBOLIC_LINKS"] = "false" process.env["INPUT_FOLLOW_SYMBOLIC_LINKS"] = "false"
// 모킹된 값 초기화
mockConfig.pullRequestNumber = 123
mockConfig.repo = {owner: "marocchino", repo: "stick-pull-request-comment"}
mockConfig.header = ""
mockConfig.append = false
mockConfig.recreate = false
mockConfig.deleteOldComment = false
mockConfig.hideOldComment = false
mockConfig.hideAndRecreate = false
mockConfig.hideClassify = "OUTDATED"
mockConfig.hideDetails = false
mockConfig.githubToken = "some-token"
mockConfig.ignoreEmpty = false
mockConfig.skipUnchanged = false
mockConfig.getBody.mockResolvedValue("")
}) })
afterEach(() => { afterEach(() => {
vi.resetModules() jest.resetModules()
delete process.env["GITHUB_REPOSITORY"] delete process.env["GITHUB_REPOSITORY"]
delete process.env["INPUT_OWNER"] delete process.env["INPUT_OWNER"]
delete process.env["INPUT_REPO"] delete process.env["INPUT_REPO"]
@ -83,11 +43,7 @@ afterEach(() => {
test("repo", async () => { test("repo", async () => {
process.env["INPUT_OWNER"] = "jin" process.env["INPUT_OWNER"] = "jin"
process.env["INPUT_REPO"] = "other" process.env["INPUT_REPO"] = "other"
expect(require("../src/config")).toMatchObject({
mockConfig.repo = {owner: "jin", repo: "other"}
const config = await import('../src/config')
expect(config).toMatchObject({
pullRequestNumber: expect.any(Number), pullRequestNumber: expect.any(Number),
repo: {owner: "jin", repo: "other"}, repo: {owner: "jin", repo: "other"},
header: "", header: "",
@ -102,15 +58,11 @@ test("repo", async () => {
ignoreEmpty: false, ignoreEmpty: false,
skipUnchanged: false skipUnchanged: false
}) })
expect(await config.getBody()).toEqual("") expect(await require("../src/config").getBody()).toEqual("")
}) })
test("header", async () => { test("header", async () => {
process.env["INPUT_HEADER"] = "header" process.env["INPUT_HEADER"] = "header"
mockConfig.header = "header" expect(require("../src/config")).toMatchObject({
const config = await import('../src/config')
expect(config).toMatchObject({
pullRequestNumber: expect.any(Number), pullRequestNumber: expect.any(Number),
repo: {owner: "marocchino", repo: "stick-pull-request-comment"}, repo: {owner: "marocchino", repo: "stick-pull-request-comment"},
header: "header", header: "header",
@ -125,15 +77,11 @@ test("header", async () => {
ignoreEmpty: false, ignoreEmpty: false,
skipUnchanged: false skipUnchanged: false
}) })
expect(await config.getBody()).toEqual("") expect(await require("../src/config").getBody()).toEqual("")
}) })
test("append", async () => { test("append", async () => {
process.env["INPUT_APPEND"] = "true" process.env["INPUT_APPEND"] = "true"
mockConfig.append = true expect(require("../src/config")).toMatchObject({
const config = await import('../src/config')
expect(config).toMatchObject({
pullRequestNumber: expect.any(Number), pullRequestNumber: expect.any(Number),
repo: {owner: "marocchino", repo: "stick-pull-request-comment"}, repo: {owner: "marocchino", repo: "stick-pull-request-comment"},
header: "", header: "",
@ -148,15 +96,11 @@ test("append", async () => {
ignoreEmpty: false, ignoreEmpty: false,
skipUnchanged: false skipUnchanged: false
}) })
expect(await config.getBody()).toEqual("") expect(await require("../src/config").getBody()).toEqual("")
}) })
test("recreate", async () => { test("recreate", async () => {
process.env["INPUT_RECREATE"] = "true" process.env["INPUT_RECREATE"] = "true"
mockConfig.recreate = true expect(require("../src/config")).toMatchObject({
const config = await import('../src/config')
expect(config).toMatchObject({
pullRequestNumber: expect.any(Number), pullRequestNumber: expect.any(Number),
repo: {owner: "marocchino", repo: "stick-pull-request-comment"}, repo: {owner: "marocchino", repo: "stick-pull-request-comment"},
header: "", header: "",
@ -171,15 +115,11 @@ test("recreate", async () => {
ignoreEmpty: false, ignoreEmpty: false,
skipUnchanged: false skipUnchanged: false
}) })
expect(await config.getBody()).toEqual("") expect(await require("../src/config").getBody()).toEqual("")
}) })
test("delete", async () => { test("delete", async () => {
process.env["INPUT_DELETE"] = "true" process.env["INPUT_DELETE"] = "true"
mockConfig.deleteOldComment = true expect(require("../src/config")).toMatchObject({
const config = await import('../src/config')
expect(config).toMatchObject({
pullRequestNumber: expect.any(Number), pullRequestNumber: expect.any(Number),
repo: {owner: "marocchino", repo: "stick-pull-request-comment"}, repo: {owner: "marocchino", repo: "stick-pull-request-comment"},
header: "", header: "",
@ -194,15 +134,11 @@ test("delete", async () => {
ignoreEmpty: false, ignoreEmpty: false,
skipUnchanged: false skipUnchanged: false
}) })
expect(await config.getBody()).toEqual("") expect(await require("../src/config").getBody()).toEqual("")
}) })
test("hideOldComment", async () => { test("hideOldComment", async () => {
process.env["INPUT_HIDE"] = "true" process.env["INPUT_HIDE"] = "true"
mockConfig.hideOldComment = true expect(require("../src/config")).toMatchObject({
const config = await import('../src/config')
expect(config).toMatchObject({
pullRequestNumber: expect.any(Number), pullRequestNumber: expect.any(Number),
repo: {owner: "marocchino", repo: "stick-pull-request-comment"}, repo: {owner: "marocchino", repo: "stick-pull-request-comment"},
header: "", header: "",
@ -217,15 +153,11 @@ test("hideOldComment", async () => {
ignoreEmpty: false, ignoreEmpty: false,
skipUnchanged: false skipUnchanged: false
}) })
expect(await config.getBody()).toEqual("") expect(await require("../src/config").getBody()).toEqual("")
}) })
test("hideAndRecreate", async () => { test("hideAndRecreate", async () => {
process.env["INPUT_HIDE_AND_RECREATE"] = "true" process.env["INPUT_HIDE_AND_RECREATE"] = "true"
mockConfig.hideAndRecreate = true expect(require("../src/config")).toMatchObject({
const config = await import('../src/config')
expect(config).toMatchObject({
pullRequestNumber: expect.any(Number), pullRequestNumber: expect.any(Number),
repo: {owner: "marocchino", repo: "stick-pull-request-comment"}, repo: {owner: "marocchino", repo: "stick-pull-request-comment"},
header: "", header: "",
@ -240,15 +172,11 @@ test("hideAndRecreate", async () => {
ignoreEmpty: false, ignoreEmpty: false,
skipUnchanged: false skipUnchanged: false
}) })
expect(await config.getBody()).toEqual("") expect(await require("../src/config").getBody()).toEqual("")
}) })
test("hideClassify", async () => { test("hideClassify", async () => {
process.env["INPUT_HIDE_CLASSIFY"] = "OFF_TOPIC" process.env["INPUT_HIDE_CLASSIFY"] = "OFF_TOPIC"
mockConfig.hideClassify = "OFF_TOPIC" expect(require("../src/config")).toMatchObject({
const config = await import('../src/config')
expect(config).toMatchObject({
pullRequestNumber: expect.any(Number), pullRequestNumber: expect.any(Number),
repo: {owner: "marocchino", repo: "stick-pull-request-comment"}, repo: {owner: "marocchino", repo: "stick-pull-request-comment"},
header: "", header: "",
@ -263,15 +191,11 @@ test("hideClassify", async () => {
ignoreEmpty: false, ignoreEmpty: false,
skipUnchanged: false skipUnchanged: false
}) })
expect(await config.getBody()).toEqual("") expect(await require("../src/config").getBody()).toEqual("")
}) })
test("hideDetails", async () => { test("hideDetails", async () => {
process.env["INPUT_HIDE_DETAILS"] = "true" process.env["INPUT_HIDE_DETAILS"] = "true"
mockConfig.hideDetails = true expect(require("../src/config")).toMatchObject({
const config = await import('../src/config')
expect(config).toMatchObject({
pullRequestNumber: expect.any(Number), pullRequestNumber: expect.any(Number),
repo: {owner: "marocchino", repo: "stick-pull-request-comment"}, repo: {owner: "marocchino", repo: "stick-pull-request-comment"},
header: "", header: "",
@ -286,16 +210,12 @@ test("hideDetails", async () => {
ignoreEmpty: false, ignoreEmpty: false,
skipUnchanged: false skipUnchanged: false
}) })
expect(await config.getBody()).toEqual("") expect(await require("../src/config").getBody()).toEqual("")
}) })
describe("path", () => { describe("path", () => {
test("when exists return content of a file", async () => { test("when exists return content of a file", async () => {
process.env["INPUT_PATH"] = "./__tests__/assets/result" process.env["INPUT_PATH"] = "./__tests__/assets/result"
mockConfig.getBody.mockResolvedValue("hi there\n") expect(require("../src/config")).toMatchObject({
const config = await import('../src/config')
expect(config).toMatchObject({
pullRequestNumber: expect.any(Number), pullRequestNumber: expect.any(Number),
repo: {owner: "marocchino", repo: "stick-pull-request-comment"}, repo: {owner: "marocchino", repo: "stick-pull-request-comment"},
header: "", header: "",
@ -310,15 +230,12 @@ describe("path", () => {
ignoreEmpty: false, ignoreEmpty: false,
skipUnchanged: false skipUnchanged: false
}) })
expect(await config.getBody()).toEqual("hi there\n") expect(await require("../src/config").getBody()).toEqual("hi there\n")
}) })
test("glob match files", async () => { test("glob match files", async () => {
process.env["INPUT_PATH"] = "./__tests__/assets/*" process.env["INPUT_PATH"] = "./__tests__/assets/*"
mockConfig.getBody.mockResolvedValue("hi there\n\nhey there\n") expect(require("../src/config")).toMatchObject({
const config = await import('../src/config')
expect(config).toMatchObject({
pullRequestNumber: expect.any(Number), pullRequestNumber: expect.any(Number),
repo: {owner: "marocchino", repo: "stick-pull-request-comment"}, repo: {owner: "marocchino", repo: "stick-pull-request-comment"},
header: "", header: "",
@ -333,15 +250,12 @@ describe("path", () => {
ignoreEmpty: false, ignoreEmpty: false,
skipUnchanged: false skipUnchanged: false
}) })
expect(await config.getBody()).toEqual("hi there\n\nhey there\n") expect(await require("../src/config").getBody()).toEqual("hi there\n\nhey there\n")
}) })
test("when not exists return null string", async () => { test("when not exists return null string", async () => {
process.env["INPUT_PATH"] = "./__tests__/assets/not_exists" process.env["INPUT_PATH"] = "./__tests__/assets/not_exists"
mockConfig.getBody.mockResolvedValue("") expect(require("../src/config")).toMatchObject({
const config = await import('../src/config')
expect(config).toMatchObject({
pullRequestNumber: expect.any(Number), pullRequestNumber: expect.any(Number),
repo: {owner: "marocchino", repo: "stick-pull-request-comment"}, repo: {owner: "marocchino", repo: "stick-pull-request-comment"},
header: "", header: "",
@ -356,16 +270,13 @@ describe("path", () => {
ignoreEmpty: false, ignoreEmpty: false,
skipUnchanged: false skipUnchanged: false
}) })
expect(await config.getBody()).toEqual("") expect(await require("../src/config").getBody()).toEqual("")
}) })
}) })
test("message", async () => { test("message", async () => {
process.env["INPUT_MESSAGE"] = "hello there" process.env["INPUT_MESSAGE"] = "hello there"
mockConfig.getBody.mockResolvedValue("hello there") expect(require("../src/config")).toMatchObject({
const config = await import('../src/config')
expect(config).toMatchObject({
pullRequestNumber: expect.any(Number), pullRequestNumber: expect.any(Number),
repo: {owner: "marocchino", repo: "stick-pull-request-comment"}, repo: {owner: "marocchino", repo: "stick-pull-request-comment"},
header: "", header: "",
@ -380,15 +291,12 @@ test("message", async () => {
ignoreEmpty: false, ignoreEmpty: false,
skipUnchanged: false skipUnchanged: false
}) })
expect(await config.getBody()).toEqual("hello there") expect(await require("../src/config").getBody()).toEqual("hello there")
}) })
test("ignore_empty", async () => { test("ignore_empty", async () => {
process.env["INPUT_IGNORE_EMPTY"] = "true" process.env["INPUT_IGNORE_EMPTY"] = "true"
mockConfig.ignoreEmpty = true expect(require("../src/config")).toMatchObject({
const config = await import('../src/config')
expect(config).toMatchObject({
pullRequestNumber: expect.any(Number), pullRequestNumber: expect.any(Number),
repo: {owner: "marocchino", repo: "stick-pull-request-comment"}, repo: {owner: "marocchino", repo: "stick-pull-request-comment"},
header: "", header: "",
@ -403,15 +311,12 @@ test("ignore_empty", async () => {
ignoreEmpty: true, ignoreEmpty: true,
skipUnchanged: false skipUnchanged: false
}) })
expect(await config.getBody()).toEqual("") expect(await require("../src/config").getBody()).toEqual("")
}) })
test("skip_unchanged", async () => { test("skip_unchanged", async () => {
process.env["INPUT_SKIP_UNCHANGED"] = "true" process.env["INPUT_SKIP_UNCHANGED"] = "true"
mockConfig.skipUnchanged = true expect(require("../src/config")).toMatchObject({
const config = await import('../src/config')
expect(config).toMatchObject({
pullRequestNumber: expect.any(Number), pullRequestNumber: expect.any(Number),
repo: {owner: "marocchino", repo: "stick-pull-request-comment"}, repo: {owner: "marocchino", repo: "stick-pull-request-comment"},
header: "", header: "",
@ -426,5 +331,5 @@ test("skip_unchanged", async () => {
ignoreEmpty: false, ignoreEmpty: false,
skipUnchanged: true skipUnchanged: true
}) })
expect(await config.getBody()).toEqual("") expect(await require("../src/config").getBody()).toEqual("")
}) })

View file

@ -1,31 +1,103 @@
{ {
"$schema": "https://biomejs.dev/schemas/2.0.4/schema.json", "$schema": "https://biomejs.dev/schemas/1.5.3/schema.json",
"files": { "files": {
"includes": ["src/**/*.ts"] "include": ["src/**/*.ts"],
"ignore": ["node_modules", "dist", "lib", "**/__tests__/**"]
}, },
"formatter": { "formatter": {
"enabled": true, "enabled": true,
"useEditorconfig": true,
"formatWithErrors": false, "formatWithErrors": false,
"indentStyle": "space", "indentStyle": "space",
"indentWidth": 2, "indentWidth": 2,
"lineEnding": "lf", "lineEnding": "lf",
"lineWidth": 100 "lineWidth": 100,
"attributePosition": "auto",
"bracketSpacing": true,
"ignore": ["**/dist/", "**/lib/", "**/node_modules/"]
}, },
"organizeImports": { "enabled": true },
"linter": { "linter": {
"enabled": true, "enabled": true,
"rules": { "rules": {
"recommended": true "recommended": true,
"complexity": {
"noExtraBooleanCast": "error",
"noMultipleSpacesInRegularExpressionLiterals": "error",
"noStaticOnlyClass": "error",
"noUselessConstructor": "error",
"noUselessStringConcat": "error"
}, },
"includes": ["vitest.config.ts", "src/**/*.ts", "__tests__/**/*.ts"] "correctness": {
"noConstAssign": "error",
"noConstantCondition": "error",
"noEmptyCharacterClassInRegex": "error",
"noEmptyPattern": "error",
"noGlobalObjectCalls": "error",
"noInnerDeclarations": "error",
"noInvalidConstructorSuper": "error",
"noNewSymbol": "error",
"noSelfAssign": "error",
"noSwitchDeclarations": "error",
"noUndeclaredVariables": "error",
"noUnreachable": "error",
"noUnreachableSuper": "error",
"noUnsafeFinally": "error",
"noUnusedLabels": "error",
"noUnusedVariables": "error",
"useIsNan": "error",
"useYield": "error"
},
"style": {
"noArguments": "error",
"noCommaOperator": "error",
"noInferrableTypes": "error",
"noNamespace": "error",
"noNonNullAssertion": "warn",
"noVar": "error",
"useConsistentArrayType": "error",
"useConst": "error",
"useForOf": "warn",
"useShorthandFunctionType": "warn",
"useSingleVarDeclarator": "error",
"useTemplate": "error"
},
"suspicious": {
"noCatchAssign": "error",
"noClassAssign": "error",
"noCompareNegZero": "error",
"noConsole": "error",
"noControlCharactersInRegex": "error",
"noDebugger": "error",
"noDoubleEquals": "error",
"noDuplicateCase": "error",
"noDuplicateClassMembers": "error",
"noDuplicateObjectKeys": "error",
"noDuplicateParameters": "error",
"noEmptyBlockStatements": "error",
"noExplicitAny": "warn",
"noFallthroughSwitchClause": "error",
"noFunctionAssign": "error",
"noGlobalAssign": "error",
"noMisleadingInstantiator": "error",
"noRedeclare": "error",
"noSparseArray": "error",
"noUnsafeNegation": "error",
"useValidTypeof": "error"
}
},
"ignore": ["**/dist/", "**/lib/", "**/node_modules/", "**/jest.config.js"]
}, },
"javascript": { "javascript": {
"formatter": { "formatter": {
"jsxQuoteStyle": "double", "jsxQuoteStyle": "double",
"quoteProperties": "asNeeded", "quoteProperties": "asNeeded",
"trailingCommas": "none",
"semicolons": "asNeeded", "semicolons": "asNeeded",
"arrowParentheses": "asNeeded", "arrowParentheses": "asNeeded",
"bracketSameLine": false, "bracketSameLine": false,
"quoteStyle": "double", "quoteStyle": "double",
"attributePosition": "auto",
"bracketSpacing": false "bracketSpacing": false
}, },
"globals": ["jest"] "globals": ["jest"]

3411
dist/index.js generated vendored

File diff suppressed because it is too large Load diff

2
dist/index.js.map generated vendored

File diff suppressed because one or more lines are too long

10
jest.config.js Normal file
View file

@ -0,0 +1,10 @@
module.exports = {
clearMocks: true,
moduleFileExtensions: ['js', 'ts'],
testEnvironment: 'node',
testMatch: ['**/*.test.ts'],
transform: {
'^.+\\.ts$': 'ts-jest'
},
verbose: true
}

View file

@ -11,10 +11,8 @@
"lint": "biome check .", "lint": "biome check .",
"lint:fix": "biome check --apply .", "lint:fix": "biome check --apply .",
"package": "ncc build --source-map --license licenses.txt", "package": "ncc build --source-map --license licenses.txt",
"test": "vitest run", "test": "jest",
"test:watch": "vitest", "build_test": "tsc && jest",
"coverage": "vitest run --coverage",
"build_test": "tsc && vitest run",
"all": "yarn build && yarn format && yarn lint && yarn package && yarn test" "all": "yarn build && yarn format && yarn lint && yarn package && yarn test"
}, },
"repository": { "repository": {
@ -30,16 +28,19 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.11.1", "@actions/core": "^1.11.1",
"@actions/github": "^6.0.1", "@actions/github": "^6.0.0",
"@actions/glob": "^0.5.0", "@actions/glob": "^0.5.0",
"@octokit/graphql-schema": "^15.26.0" "@octokit/graphql-schema": "^15.26.0"
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "2.3.4", "@biomejs/biome": "1.9.4",
"@types/node": "^24.5.2", "@types/jest": "^29.5.14",
"@types/node": "^22.14.0",
"@vercel/ncc": "^0.38.3", "@vercel/ncc": "^0.38.3",
"jest": "^29.7.0",
"jest-circus": "^29.7.0",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"typescript": "^5.9.2", "ts-jest": "^29.3.1",
"vitest": "^3.2.4" "typescript": "^5.8.3"
} }
} }

View file

@ -4,8 +4,8 @@ import type {
IssueComment, IssueComment,
ReportedContentClassifiers, ReportedContentClassifiers,
Repository, Repository,
User, User
} from "@octokit/graphql-schema" } from "@octokit/graphql-schema/schema.d"
type CreateCommentResponse = Awaited< type CreateCommentResponse = Awaited<
ReturnType<InstanceType<typeof GitHub>["rest"]["issues"]["createComment"]> ReturnType<InstanceType<typeof GitHub>["rest"]["issues"]["createComment"]>
@ -30,7 +30,7 @@ export async function findPreviousComment(
repo: string repo: string
}, },
number: number, number: number,
header: string, header: string
): Promise<IssueComment | undefined> { ): Promise<IssueComment | undefined> {
let after = null let after = null
let hasNextPage = true let hasNextPage = true
@ -60,7 +60,7 @@ export async function findPreviousComment(
} }
} }
`, `,
{...repo, after, number}, {...repo, after, number}
) )
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
const viewer = data.viewer as User const viewer = data.viewer as User
@ -70,7 +70,7 @@ export async function findPreviousComment(
(node: IssueComment | null | undefined) => (node: IssueComment | null | undefined) =>
node?.author?.login === viewer.login.replace("[bot]", "") && node?.author?.login === viewer.login.replace("[bot]", "") &&
!node?.isMinimized && !node?.isMinimized &&
node?.body?.includes(h), node?.body?.includes(h)
) )
if (target) { if (target) {
return target return target
@ -86,7 +86,7 @@ export async function updateComment(
id: string, id: string,
body: string, body: string,
header: string, header: string,
previousBody?: string, previousBody?: string
): Promise<void> { ): Promise<void> {
if (!body && !previousBody) return core.warning("Comment body cannot be blank") if (!body && !previousBody) return core.warning("Comment body cannot be blank")
@ -108,9 +108,9 @@ export async function updateComment(
id, id,
body: previousBody body: previousBody
? bodyWithHeader(`${rawPreviousBody}\n${body}`, header) ? bodyWithHeader(`${rawPreviousBody}\n${body}`, header)
: bodyWithHeader(body, header), : bodyWithHeader(body, header)
}, }
}, }
) )
} }
export async function createComment( export async function createComment(
@ -122,7 +122,7 @@ export async function createComment(
issue_number: number, issue_number: number,
body: string, body: string,
header: string, header: string,
previousBody?: string, previousBody?: string
): Promise<CreateCommentResponse | undefined> { ): Promise<CreateCommentResponse | undefined> {
if (!body && !previousBody) { if (!body && !previousBody) {
core.warning("Comment body cannot be blank") core.warning("Comment body cannot be blank")
@ -132,12 +132,12 @@ export async function createComment(
return await octokit.rest.issues.createComment({ return await octokit.rest.issues.createComment({
...repo, ...repo,
issue_number, issue_number,
body: previousBody ? `${previousBody}\n${body}` : bodyWithHeader(body, header), body: previousBody ? `${previousBody}\n${body}` : bodyWithHeader(body, header)
}) })
} }
export async function deleteComment( export async function deleteComment(
octokit: InstanceType<typeof GitHub>, octokit: InstanceType<typeof GitHub>,
id: string, id: string
): Promise<void> { ): Promise<void> {
await octokit.graphql( await octokit.graphql(
` `
@ -147,13 +147,13 @@ export async function deleteComment(
} }
} }
`, `,
{id}, {id}
) )
} }
export async function minimizeComment( export async function minimizeComment(
octokit: InstanceType<typeof GitHub>, octokit: InstanceType<typeof GitHub>,
subjectId: string, subjectId: string,
classifier: ReportedContentClassifiers, classifier: ReportedContentClassifiers
): Promise<void> { ): Promise<void> {
await octokit.graphql( await octokit.graphql(
` `
@ -163,14 +163,14 @@ export async function minimizeComment(
} }
} }
`, `,
{input: {subjectId, classifier}}, {input: {subjectId, classifier}}
) )
} }
export function getBodyOf( export function getBodyOf(
previous: {body?: string}, previous: {body?: string},
append: boolean, append: boolean,
hideDetails: boolean, hideDetails: boolean
): string | undefined { ): string | undefined {
if (!append) { if (!append) {
return undefined return undefined

View file

@ -2,7 +2,7 @@ import {readFileSync} from "node:fs"
import * as core from "@actions/core" import * as core from "@actions/core"
import {context} from "@actions/github" import {context} from "@actions/github"
import {create} from "@actions/glob" import {create} from "@actions/glob"
import type {ReportedContentClassifiers} from "@octokit/graphql-schema" import type {ReportedContentClassifiers} from "@octokit/graphql-schema/schema.d"
export const pullRequestNumber = export const pullRequestNumber =
context?.payload?.pull_request?.number || +core.getInput("number", {required: false}) context?.payload?.pull_request?.number || +core.getInput("number", {required: false})
@ -11,48 +11,48 @@ export const repo = buildRepo()
export const header = core.getInput("header", {required: false}) export const header = core.getInput("header", {required: false})
export const append = core.getBooleanInput("append", {required: true}) export const append = core.getBooleanInput("append", {required: true})
export const hideDetails = core.getBooleanInput("hide_details", { export const hideDetails = core.getBooleanInput("hide_details", {
required: true, required: true
}) })
export const recreate = core.getBooleanInput("recreate", {required: true}) export const recreate = core.getBooleanInput("recreate", {required: true})
export const hideAndRecreate = core.getBooleanInput("hide_and_recreate", { export const hideAndRecreate = core.getBooleanInput("hide_and_recreate", {
required: true, required: true
}) })
export const hideClassify = core.getInput("hide_classify", { export const hideClassify = core.getInput("hide_classify", {
required: true, required: true
}) as ReportedContentClassifiers }) as ReportedContentClassifiers
export const deleteOldComment = core.getBooleanInput("delete", {required: true}) export const deleteOldComment = core.getBooleanInput("delete", {required: true})
export const onlyCreateComment = core.getBooleanInput("only_create", { export const onlyCreateComment = core.getBooleanInput("only_create", {
required: true, required: true
}) })
export const onlyUpdateComment = core.getBooleanInput("only_update", { export const onlyUpdateComment = core.getBooleanInput("only_update", {
required: true, required: true
}) })
export const skipUnchanged = core.getBooleanInput("skip_unchanged", { export const skipUnchanged = core.getBooleanInput("skip_unchanged", {
required: true, required: true
}) })
export const hideOldComment = core.getBooleanInput("hide", {required: true}) export const hideOldComment = core.getBooleanInput("hide", {required: true})
export const githubToken = core.getInput("GITHUB_TOKEN", {required: true}) export const githubToken = core.getInput("GITHUB_TOKEN", {required: true})
export const ignoreEmpty = core.getBooleanInput("ignore_empty", { export const ignoreEmpty = core.getBooleanInput("ignore_empty", {
required: true, required: true
}) })
function buildRepo(): {repo: string; owner: string} { function buildRepo(): {repo: string; owner: string} {
return { return {
owner: core.getInput("owner", {required: false}) || context.repo.owner, owner: core.getInput("owner", {required: false}) || context.repo.owner,
repo: core.getInput("repo", {required: false}) || context.repo.repo, repo: core.getInput("repo", {required: false}) || context.repo.repo
} }
} }
export async function getBody(): Promise<string> { export async function getBody(): Promise<string> {
const pathInput = core.getMultilineInput("path", {required: false}) const pathInput = core.getMultilineInput("path", {required: false})
const followSymbolicLinks = core.getBooleanInput("follow_symbolic_links", { const followSymbolicLinks = core.getBooleanInput("follow_symbolic_links", {
required: true, required: true
}) })
if (pathInput && pathInput.length > 0) { if (pathInput && pathInput.length > 0) {
try { try {
const globber = await create(pathInput.join("\n"), { const globber = await create(pathInput.join("\n"), {
followSymbolicLinks, followSymbolicLinks,
matchDirectories: false, matchDirectories: false
}) })
return (await globber.glob()).map(path => readFileSync(path, "utf-8")).join("\n") return (await globber.glob()).map(path => readFileSync(path, "utf-8")).join("\n")
} catch (error) { } catch (error) {

View file

@ -7,7 +7,7 @@ import {
findPreviousComment, findPreviousComment,
getBodyOf, getBodyOf,
minimizeComment, minimizeComment,
updateComment, updateComment
} from "./comment" } from "./comment"
import { import {
append, append,
@ -25,7 +25,7 @@ import {
pullRequestNumber, pullRequestNumber,
recreate, recreate,
repo, repo,
skipUnchanged, skipUnchanged
} from "./config" } from "./config"
async function run(): Promise<undefined> { async function run(): Promise<undefined> {
@ -104,7 +104,7 @@ async function run(): Promise<undefined> {
pullRequestNumber, pullRequestNumber,
body, body,
header, header,
previousBody, previousBody
) )
core.setOutput("created_comment_id", created?.data.id) core.setOutput("created_comment_id", created?.data.id)
return return

View file

@ -1,25 +1,12 @@
{ {
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": { "compilerOptions": {
"allowSyntheticDefaultImports": true, "target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */,
"declaration": false, "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
"declarationMap": false, "outDir": "./lib" /* Redirect output structure to the directory. */,
"esModuleInterop": true, "rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,
"forceConsistentCasingInFileNames": true, "strict": true /* Enable all strict type-checking options. */,
"lib": ["ES2022"], "noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */,
"module": "NodeNext", "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
"moduleResolution": "NodeNext",
"newLine": "lf",
"noImplicitAny": true,
"noUnusedLocals": true,
"noUnusedParameters": false,
"pretty": true,
"resolveJsonModule": true,
"strict": true,
"strictNullChecks": true,
"target": "ES2022",
"outDir": "./lib",
"rootDir": "./src"
}, },
"exclude": ["node_modules", "**/*.test.ts", "vitest.config.ts"] "exclude": ["node_modules", "**/*.test.ts"]
} }

View file

@ -1,21 +0,0 @@
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
clearMocks: true,
coverage: {
provider: 'v8',
reporter: ['json', 'lcov', 'text', 'clover'],
exclude: ['/node_modules/'],
},
environment: 'node',
include: ['**/__tests__/**/*.test.ts'],
globals: true,
testTimeout: 10000,
poolOptions: {
threads: {
maxThreads: 10,
},
},
},
});

15
wallaby.js Normal file
View file

@ -0,0 +1,15 @@
module.exports = function(wallaby) {
return {
files: ["src/**/*.js?(x)", "!src/**/*.spec.ts?(x)"],
tests: ["__tests__/**/*.test.ts?(x)"],
env: {
type: "node",
runner: "node"
},
testFramework: "jest",
debug: true
};
};

3276
yarn.lock

File diff suppressed because it is too large Load diff