mirror of
https://github.com/marocchino/sticky-pull-request-comment.git
synced 2025-12-16 21:18:27 +00:00
Compare commits
No commits in common. "main" and "v2.9.1" have entirely different histories.
20 changed files with 6739 additions and 3285 deletions
4
.eslintignore
Normal file
4
.eslintignore
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
dist/
|
||||||
|
lib/
|
||||||
|
node_modules/
|
||||||
|
jest.config.js
|
||||||
59
.eslintrc.json
Normal file
59
.eslintrc.json
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
{
|
||||||
|
"root": true,
|
||||||
|
"plugins": ["jest", "@typescript-eslint"],
|
||||||
|
"extends": ["plugin:github/recommended"],
|
||||||
|
"parser": "@typescript-eslint/parser",
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 9,
|
||||||
|
"sourceType": "module",
|
||||||
|
"project": "./tsconfig.json"
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"eslint-comments/no-use": "off",
|
||||||
|
"import/no-namespace": "off",
|
||||||
|
"i18n-text/no-en": "off",
|
||||||
|
"no-unused-vars": "off",
|
||||||
|
"@typescript-eslint/no-unused-vars": "error",
|
||||||
|
"@typescript-eslint/explicit-member-accessibility": [
|
||||||
|
"error",
|
||||||
|
{"accessibility": "no-public"}
|
||||||
|
],
|
||||||
|
"@typescript-eslint/no-require-imports": "error",
|
||||||
|
"@typescript-eslint/array-type": "error",
|
||||||
|
"@typescript-eslint/await-thenable": "error",
|
||||||
|
"@typescript-eslint/ban-ts-comment": "error",
|
||||||
|
"camelcase": "off",
|
||||||
|
"@typescript-eslint/consistent-type-assertions": "error",
|
||||||
|
"@typescript-eslint/explicit-function-return-type": [
|
||||||
|
"error",
|
||||||
|
{"allowExpressions": true}
|
||||||
|
],
|
||||||
|
"@typescript-eslint/no-array-constructor": "error",
|
||||||
|
"@typescript-eslint/no-empty-interface": "error",
|
||||||
|
"@typescript-eslint/no-explicit-any": "error",
|
||||||
|
"@typescript-eslint/no-extraneous-class": "error",
|
||||||
|
"@typescript-eslint/no-for-in-array": "error",
|
||||||
|
"@typescript-eslint/no-inferrable-types": "error",
|
||||||
|
"@typescript-eslint/no-misused-new": "error",
|
||||||
|
"@typescript-eslint/no-namespace": "error",
|
||||||
|
"@typescript-eslint/no-non-null-assertion": "warn",
|
||||||
|
"@typescript-eslint/no-unnecessary-qualifier": "error",
|
||||||
|
"@typescript-eslint/no-unnecessary-type-assertion": "error",
|
||||||
|
"@typescript-eslint/no-useless-constructor": "error",
|
||||||
|
"@typescript-eslint/no-var-requires": "error",
|
||||||
|
"@typescript-eslint/prefer-for-of": "warn",
|
||||||
|
"@typescript-eslint/prefer-function-type": "warn",
|
||||||
|
"@typescript-eslint/prefer-includes": "error",
|
||||||
|
"@typescript-eslint/prefer-string-starts-ends-with": "error",
|
||||||
|
"@typescript-eslint/promise-function-async": "error",
|
||||||
|
"@typescript-eslint/require-array-sort-compare": "error",
|
||||||
|
"@typescript-eslint/restrict-plus-operands": "error",
|
||||||
|
"semi": "off",
|
||||||
|
"@typescript-eslint/unbound-method": "error"
|
||||||
|
},
|
||||||
|
"env": {
|
||||||
|
"node": true,
|
||||||
|
"es6": true,
|
||||||
|
"jest/globals": true
|
||||||
|
}
|
||||||
|
}
|
||||||
13
.github/workflows/test.yml
vendored
13
.github/workflows/test.yml
vendored
|
|
@ -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>
|
||||||
|
|
@ -42,7 +43,3 @@ jobs:
|
||||||
hide_details: true
|
hide_details: true
|
||||||
message: |
|
message: |
|
||||||
The build is over.
|
The build is over.
|
||||||
- name: Lint
|
|
||||||
run: npm run lint
|
|
||||||
- name: Format Check
|
|
||||||
run: npm run format-check
|
|
||||||
|
|
|
||||||
3
.prettierignore
Normal file
3
.prettierignore
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
dist/
|
||||||
|
lib/
|
||||||
|
node_modules/
|
||||||
9
.prettierrc.json
Normal file
9
.prettierrc.json
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"printWidth": 80,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"useTabs": false,
|
||||||
|
"semi": false,
|
||||||
|
"trailingComma": "none",
|
||||||
|
"bracketSpacing": false,
|
||||||
|
"arrowParens": "avoid"
|
||||||
|
}
|
||||||
|
|
@ -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: {
|
||||||
|
|
@ -91,8 +90,12 @@ it("findPreviousComment", async () => {
|
||||||
} as any)
|
} as any)
|
||||||
|
|
||||||
expect(await findPreviousComment(octokit, repo, 123, "")).toBe(comment)
|
expect(await findPreviousComment(octokit, repo, 123, "")).toBe(comment)
|
||||||
expect(await findPreviousComment(octokit, repo, 123, "TypeA")).toBe(commentWithCustomHeader)
|
expect(await findPreviousComment(octokit, repo, 123, "TypeA")).toBe(
|
||||||
expect(await findPreviousComment(octokit, repo, 123, "LegacyComment")).toBe(headerFirstComment)
|
commentWithCustomHeader
|
||||||
|
)
|
||||||
|
expect(await findPreviousComment(octokit, repo, 123, "LegacyComment")).toBe(
|
||||||
|
headerFirstComment
|
||||||
|
)
|
||||||
expect(octokit.graphql).toBeCalledWith(expect.any(String), {
|
expect(octokit.graphql).toBeCalledWith(expect.any(String), {
|
||||||
after: null,
|
after: null,
|
||||||
number: 123,
|
number: 123,
|
||||||
|
|
@ -105,18 +108,22 @@ 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 () => {
|
||||||
expect(await updateComment(octokit, "456", "hello there", "")).toBeUndefined()
|
expect(
|
||||||
|
await updateComment(octokit, "456", "hello there", "")
|
||||||
|
).toBeUndefined()
|
||||||
expect(octokit.graphql).toBeCalledWith(expect.any(String), {
|
expect(octokit.graphql).toBeCalledWith(expect.any(String), {
|
||||||
input: {
|
input: {
|
||||||
id: "456",
|
id: "456",
|
||||||
body: "hello there\n<!-- Sticky Pull Request Comment -->"
|
body: "hello there\n<!-- Sticky Pull Request Comment -->"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
expect(await updateComment(octokit, "456", "hello there", "TypeA")).toBeUndefined()
|
expect(
|
||||||
|
await updateComment(octokit, "456", "hello there", "TypeA")
|
||||||
|
).toBeUndefined()
|
||||||
expect(octokit.graphql).toBeCalledWith(expect.any(String), {
|
expect(octokit.graphql).toBeCalledWith(expect.any(String), {
|
||||||
input: {
|
input: {
|
||||||
id: "456",
|
id: "456",
|
||||||
|
|
@ -151,21 +158,24 @@ 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",
|
||||||
repo: "sticky-pull-request-comment",
|
repo: "sticky-pull-request-comment",
|
||||||
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(
|
||||||
{ data: "<return value>" }
|
await createComment(octokit, repo, 456, "hello there", "TypeA")
|
||||||
)
|
).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",
|
||||||
|
|
@ -183,7 +193,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 +203,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 +236,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 +253,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 -->",
|
||||||
|
|
|
||||||
|
|
@ -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,14 @@ 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 +272,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 +293,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 +313,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 +333,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("")
|
||||||
})
|
})
|
||||||
|
|
|
||||||
33
biome.json
33
biome.json
|
|
@ -1,33 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "https://biomejs.dev/schemas/2.0.4/schema.json",
|
|
||||||
"files": {
|
|
||||||
"includes": ["src/**/*.ts"]
|
|
||||||
},
|
|
||||||
"formatter": {
|
|
||||||
"enabled": true,
|
|
||||||
"formatWithErrors": false,
|
|
||||||
"indentStyle": "space",
|
|
||||||
"indentWidth": 2,
|
|
||||||
"lineEnding": "lf",
|
|
||||||
"lineWidth": 100
|
|
||||||
},
|
|
||||||
"linter": {
|
|
||||||
"enabled": true,
|
|
||||||
"rules": {
|
|
||||||
"recommended": true
|
|
||||||
},
|
|
||||||
"includes": ["vitest.config.ts", "src/**/*.ts", "__tests__/**/*.ts"]
|
|
||||||
},
|
|
||||||
"javascript": {
|
|
||||||
"formatter": {
|
|
||||||
"jsxQuoteStyle": "double",
|
|
||||||
"quoteProperties": "asNeeded",
|
|
||||||
"semicolons": "asNeeded",
|
|
||||||
"arrowParentheses": "asNeeded",
|
|
||||||
"bracketSameLine": false,
|
|
||||||
"quoteStyle": "double",
|
|
||||||
"bracketSpacing": false
|
|
||||||
},
|
|
||||||
"globals": ["jest"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
4095
dist/index.js
generated
vendored
4095
dist/index.js
generated
vendored
File diff suppressed because it is too large
Load diff
2
dist/index.js.map
generated
vendored
2
dist/index.js.map
generated
vendored
File diff suppressed because one or more lines are too long
25
dist/licenses.txt
generated
vendored
25
dist/licenses.txt
generated
vendored
|
|
@ -573,6 +573,31 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
|
is-plain-object
|
||||||
|
MIT
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014-2017, Jon Schlinkert.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
minimatch
|
minimatch
|
||||||
ISC
|
ISC
|
||||||
The ISC License
|
The ISC License
|
||||||
|
|
|
||||||
10
jest.config.js
Normal file
10
jest.config.js
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
module.exports = {
|
||||||
|
clearMocks: true,
|
||||||
|
moduleFileExtensions: ['js', 'ts'],
|
||||||
|
testEnvironment: 'node',
|
||||||
|
testMatch: ['**/*.test.ts'],
|
||||||
|
transform: {
|
||||||
|
'^.+\\.ts$': 'ts-jest'
|
||||||
|
},
|
||||||
|
verbose: true
|
||||||
|
}
|
||||||
33
package.json
33
package.json
|
|
@ -6,15 +6,12 @@
|
||||||
"main": "lib/main.js",
|
"main": "lib/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"format": "biome format --write .",
|
"format": "prettier --write **/*.ts",
|
||||||
"format-check": "biome format --write .",
|
"format-check": "prettier --check **/*.ts",
|
||||||
"lint": "biome check .",
|
"lint": "eslint src/**/*.ts",
|
||||||
"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 +27,24 @@
|
||||||
"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": "^14.52.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "2.3.4",
|
"@types/jest": "^29.5.14",
|
||||||
"@types/node": "^24.5.2",
|
"@types/node": "^22.10.7",
|
||||||
|
"@typescript-eslint/parser": "^8.20.0",
|
||||||
"@vercel/ncc": "^0.38.3",
|
"@vercel/ncc": "^0.38.3",
|
||||||
|
"eslint": "^8.56.0",
|
||||||
|
"eslint-plugin-github": "^5.1.5",
|
||||||
|
"eslint-plugin-jest": "^28.11.0",
|
||||||
|
"eslint-plugin-prettier": "^5.2.2",
|
||||||
|
"jest": "^29.7.0",
|
||||||
|
"jest-circus": "^29.7.0",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"typescript": "^5.9.2",
|
"prettier": "3.4.2",
|
||||||
"vitest": "^3.2.4"
|
"ts-jest": "^29.2.5",
|
||||||
|
"typescript": "^5.7.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
import * as core from "@actions/core"
|
import * as core from "@actions/core"
|
||||||
import type {GitHub} from "@actions/github/lib/utils"
|
import {
|
||||||
import type {
|
|
||||||
IssueComment,
|
IssueComment,
|
||||||
ReportedContentClassifiers,
|
ReportedContentClassifiers,
|
||||||
Repository,
|
Repository,
|
||||||
User,
|
User
|
||||||
} from "@octokit/graphql-schema"
|
} from "@octokit/graphql-schema"
|
||||||
|
import {GitHub} from "@actions/github/lib/utils"
|
||||||
|
|
||||||
type CreateCommentResponse = Awaited<
|
type CreateCommentResponse = Awaited<
|
||||||
ReturnType<InstanceType<typeof GitHub>["rest"]["issues"]["createComment"]>
|
ReturnType<InstanceType<typeof GitHub>["rest"]["issues"]["createComment"]>
|
||||||
>
|
>
|
||||||
|
|
||||||
function headerComment(header: string): string {
|
function headerComment(header: String): string {
|
||||||
return `<!-- Sticky Pull Request Comment${header} -->`
|
return `<!-- Sticky Pull Request Comment${header} -->`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -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,13 +70,14 @@ 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
|
||||||
}
|
}
|
||||||
after = repository.pullRequest?.comments?.pageInfo?.endCursor
|
after = repository.pullRequest?.comments?.pageInfo?.endCursor
|
||||||
hasNextPage = repository.pullRequest?.comments?.pageInfo?.hasNextPage ?? false
|
hasNextPage =
|
||||||
|
repository.pullRequest?.comments?.pageInfo?.hasNextPage ?? false
|
||||||
}
|
}
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
@ -86,11 +87,14 @@ 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")
|
||||||
|
|
||||||
const rawPreviousBody: string = previousBody ? bodyWithoutHeader(previousBody, header) : ""
|
const rawPreviousBody: String = previousBody
|
||||||
|
? bodyWithoutHeader(previousBody, header)
|
||||||
|
: ""
|
||||||
|
|
||||||
await octokit.graphql(
|
await octokit.graphql(
|
||||||
`
|
`
|
||||||
|
|
@ -108,9 +112,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 +126,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 +136,14 @@ 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 +153,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,27 +169,31 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hideDetails || !previous.body) {
|
if (!hideDetails) {
|
||||||
return previous.body
|
return previous.body
|
||||||
}
|
}
|
||||||
|
|
||||||
return previous.body.replace(/(<details.*?)\s*\bopen\b(.*>)/g, "$1$2")
|
return previous.body?.replace(/(<details.*?)\s*\bopen\b(.*>)/g, "$1$2")
|
||||||
}
|
}
|
||||||
|
|
||||||
export function commentsEqual(body: string, previous: string | undefined, header: string): boolean {
|
export function commentsEqual(
|
||||||
|
body: string,
|
||||||
|
previous: string,
|
||||||
|
header: string
|
||||||
|
): boolean {
|
||||||
const newBody = bodyWithHeader(body, header)
|
const newBody = bodyWithHeader(body, header)
|
||||||
return newBody === previous
|
return newBody === previous
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,60 +1,63 @@
|
||||||
import {readFileSync} from "node:fs"
|
|
||||||
import * as core from "@actions/core"
|
import * as core from "@actions/core"
|
||||||
|
import {ReportedContentClassifiers} from "@octokit/graphql-schema"
|
||||||
import {context} from "@actions/github"
|
import {context} from "@actions/github"
|
||||||
|
import {readFileSync} from "fs"
|
||||||
import {create} from "@actions/glob"
|
import {create} from "@actions/glob"
|
||||||
import type {ReportedContentClassifiers} from "@octokit/graphql-schema"
|
|
||||||
|
|
||||||
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})
|
||||||
|
|
||||||
export const repo = buildRepo()
|
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) {
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
core.setFailed(error.message)
|
core.setFailed(error.message)
|
||||||
|
|
|
||||||
57
src/main.ts
57
src/main.ts
|
|
@ -1,35 +1,35 @@
|
||||||
import * as core from "@actions/core"
|
import * as core from "@actions/core"
|
||||||
import * as github from "@actions/github"
|
import * as github from "@actions/github"
|
||||||
import {
|
|
||||||
commentsEqual,
|
|
||||||
createComment,
|
|
||||||
deleteComment,
|
|
||||||
findPreviousComment,
|
|
||||||
getBodyOf,
|
|
||||||
minimizeComment,
|
|
||||||
updateComment,
|
|
||||||
} from "./comment"
|
|
||||||
import {
|
import {
|
||||||
append,
|
append,
|
||||||
deleteOldComment,
|
|
||||||
getBody,
|
getBody,
|
||||||
|
deleteOldComment,
|
||||||
githubToken,
|
githubToken,
|
||||||
header,
|
header,
|
||||||
hideAndRecreate,
|
hideAndRecreate,
|
||||||
hideClassify,
|
hideClassify,
|
||||||
hideDetails,
|
hideDetails,
|
||||||
hideOldComment,
|
hideOldComment,
|
||||||
ignoreEmpty,
|
|
||||||
onlyCreateComment,
|
|
||||||
onlyUpdateComment,
|
|
||||||
pullRequestNumber,
|
pullRequestNumber,
|
||||||
recreate,
|
recreate,
|
||||||
repo,
|
repo,
|
||||||
|
ignoreEmpty,
|
||||||
skipUnchanged,
|
skipUnchanged,
|
||||||
|
onlyCreateComment,
|
||||||
|
onlyUpdateComment
|
||||||
} from "./config"
|
} from "./config"
|
||||||
|
import {
|
||||||
|
createComment,
|
||||||
|
deleteComment,
|
||||||
|
findPreviousComment,
|
||||||
|
getBodyOf,
|
||||||
|
minimizeComment,
|
||||||
|
updateComment,
|
||||||
|
commentsEqual
|
||||||
|
} from "./comment"
|
||||||
|
|
||||||
async function run(): Promise<undefined> {
|
async function run(): Promise<undefined> {
|
||||||
if (Number.isNaN(pullRequestNumber) || pullRequestNumber < 1) {
|
if (isNaN(pullRequestNumber) || pullRequestNumber < 1) {
|
||||||
core.info("no pull request numbers given: skip step")
|
core.info("no pull request numbers given: skip step")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -59,7 +59,12 @@ async function run(): Promise<undefined> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const octokit = github.getOctokit(githubToken)
|
const octokit = github.getOctokit(githubToken)
|
||||||
const previous = await findPreviousComment(octokit, repo, pullRequestNumber, header)
|
const previous = await findPreviousComment(
|
||||||
|
octokit,
|
||||||
|
repo,
|
||||||
|
pullRequestNumber,
|
||||||
|
header
|
||||||
|
)
|
||||||
|
|
||||||
core.setOutput("previous_comment_id", previous?.id)
|
core.setOutput("previous_comment_id", previous?.id)
|
||||||
|
|
||||||
|
|
@ -74,7 +79,13 @@ async function run(): Promise<undefined> {
|
||||||
if (onlyUpdateComment) {
|
if (onlyUpdateComment) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const created = await createComment(octokit, repo, pullRequestNumber, body, header)
|
const created = await createComment(
|
||||||
|
octokit,
|
||||||
|
repo,
|
||||||
|
pullRequestNumber,
|
||||||
|
body,
|
||||||
|
header
|
||||||
|
)
|
||||||
core.setOutput("created_comment_id", created?.data.id)
|
core.setOutput("created_comment_id", created?.data.id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -90,12 +101,12 @@ async function run(): Promise<undefined> {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skipUnchanged && commentsEqual(body, previous.body || "", header)) {
|
if (skipUnchanged && commentsEqual(body, previous.body, header)) {
|
||||||
// don't recreate or update if the message is unchanged
|
// don't recreate or update if the message is unchanged
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const previousBody = getBodyOf({body: previous.body || ""}, append, hideDetails)
|
const previousBody = getBodyOf(previous, append, hideDetails)
|
||||||
if (recreate) {
|
if (recreate) {
|
||||||
await deleteComment(octokit, previous.id)
|
await deleteComment(octokit, previous.id)
|
||||||
const created = await createComment(
|
const created = await createComment(
|
||||||
|
|
@ -104,7 +115,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
|
||||||
|
|
@ -112,7 +123,13 @@ async function run(): Promise<undefined> {
|
||||||
|
|
||||||
if (hideAndRecreate) {
|
if (hideAndRecreate) {
|
||||||
await minimizeComment(octokit, previous.id, hideClassify)
|
await minimizeComment(octokit, previous.id, hideClassify)
|
||||||
const created = await createComment(octokit, repo, pullRequestNumber, body, header)
|
const created = await createComment(
|
||||||
|
octokit,
|
||||||
|
repo,
|
||||||
|
pullRequestNumber,
|
||||||
|
body,
|
||||||
|
header
|
||||||
|
)
|
||||||
core.setOutput("created_comment_id", created?.data.id)
|
core.setOutput("created_comment_id", created?.data.id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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"]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
15
wallaby.js
Normal 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
|
||||||
|
};
|
||||||
|
};
|
||||||
Loading…
Reference in a new issue