mirror of
https://github.com/marocchino/sticky-pull-request-comment.git
synced 2026-04-08 15:30:05 +00:00
Compare commits
13 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
159c67730e | ||
|
|
b37c1a1c07 | ||
|
|
d4d6b09364 | ||
|
|
3868baa51f | ||
|
|
26f73b083d | ||
|
|
f6e304e904 | ||
|
|
a7709b6781 | ||
|
|
0746c6f4b6 | ||
|
|
2a4b1c3f04 | ||
|
|
1ab42d29a9 | ||
|
|
5a61de79c6 | ||
|
|
7cb1e16d25 | ||
|
|
14d4f1e429 |
15 changed files with 706 additions and 765 deletions
17
README.md
17
README.md
|
|
@ -91,6 +91,19 @@ If for some reason, triggering on pr is not possible, you can use push.
|
||||||
This message is from a push.
|
This message is from a push.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Override pull request number
|
||||||
|
|
||||||
|
Use `number_force` to comment on a different pull request than the one that triggered the event.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- uses: marocchino/sticky-pull-request-comment@v2
|
||||||
|
with:
|
||||||
|
number_force: 123
|
||||||
|
message: |
|
||||||
|
This comment will be posted to PR #123,
|
||||||
|
regardless of which PR triggered this workflow.
|
||||||
|
```
|
||||||
|
|
||||||
### Read comment from a file
|
### Read comment from a file
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
|
|
@ -217,6 +230,10 @@ For more detailed information about permissions, you can read from the link belo
|
||||||
|
|
||||||
**Optional** Pull request number for push event. Note that this has a **lower priority** than the number of a pull_request event.
|
**Optional** Pull request number for push event. Note that this has a **lower priority** than the number of a pull_request event.
|
||||||
|
|
||||||
|
### `number_force`
|
||||||
|
|
||||||
|
**Optional** Pull request number for any event. Note that this has the **highest priority** and will override the number from a pull_request event.
|
||||||
|
|
||||||
### `owner`
|
### `owner`
|
||||||
|
|
||||||
**Optional** Another repository owner, If not set, the current repository owner is used by default. Note that when you trying changing a repo, be aware that `GITHUB_TOKEN` should also have permission for that repository.
|
**Optional** Another repository owner, If not set, the current repository owner is used by default. Note that when you trying changing a repo, be aware that `GITHUB_TOKEN` should also have permission for that repository.
|
||||||
|
|
|
||||||
|
|
@ -1,430 +1,213 @@
|
||||||
import { beforeEach, afterEach, test, expect, vi, describe } from 'vitest'
|
import {afterEach, describe, expect, test, vi} from "vitest"
|
||||||
|
import {resolve} from "node:path"
|
||||||
|
|
||||||
const mockConfig = {
|
vi.mock("@actions/core", () => ({
|
||||||
pullRequestNumber: 123,
|
getInput: vi.fn().mockReturnValue(""),
|
||||||
repo: {owner: "marocchino", repo: "stick-pull-request-comment"},
|
getBooleanInput: vi.fn().mockReturnValue(false),
|
||||||
header: "",
|
getMultilineInput: vi.fn().mockReturnValue([]),
|
||||||
append: false,
|
setFailed: vi.fn(),
|
||||||
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', () => {
|
const mockContext = vi.hoisted(() => ({
|
||||||
return mockConfig
|
repo: {owner: "marocchino", repo: "sticky-pull-request-comment"},
|
||||||
})
|
payload: {} as Record<string, unknown>,
|
||||||
|
}))
|
||||||
|
|
||||||
beforeEach(() => {
|
vi.mock("@actions/github", () => ({
|
||||||
// Set up default environment variables for each test
|
context: mockContext,
|
||||||
process.env["GITHUB_REPOSITORY"] = "marocchino/stick-pull-request-comment"
|
}))
|
||||||
process.env["INPUT_NUMBER"] = "123"
|
|
||||||
process.env["INPUT_APPEND"] = "false"
|
const mockGlobCreate = vi.hoisted(() => vi.fn())
|
||||||
process.env["INPUT_RECREATE"] = "false"
|
|
||||||
process.env["INPUT_DELETE"] = "false"
|
vi.mock("@actions/glob", () => ({
|
||||||
process.env["INPUT_ONLY_CREATE"] = "false"
|
create: mockGlobCreate,
|
||||||
process.env["INPUT_ONLY_UPDATE"] = "false"
|
}))
|
||||||
process.env["INPUT_HIDE"] = "false"
|
|
||||||
process.env["INPUT_HIDE_AND_RECREATE"] = "false"
|
|
||||||
process.env["INPUT_HIDE_CLASSIFY"] = "OUTDATED"
|
|
||||||
process.env["INPUT_HIDE_DETAILS"] = "false"
|
|
||||||
process.env["INPUT_GITHUB_TOKEN"] = "some-token"
|
|
||||||
process.env["INPUT_IGNORE_EMPTY"] = "false"
|
|
||||||
process.env["INPUT_SKIP_UNCHANGED"] = "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()
|
mockContext.payload = {}
|
||||||
delete process.env["GITHUB_REPOSITORY"]
|
mockContext.repo = {owner: "marocchino", repo: "sticky-pull-request-comment"}
|
||||||
delete process.env["INPUT_OWNER"]
|
mockGlobCreate.mockReset()
|
||||||
delete process.env["INPUT_REPO"]
|
|
||||||
delete process.env["INPUT_HEADER"]
|
|
||||||
delete process.env["INPUT_MESSAGE"]
|
|
||||||
delete process.env["INPUT_NUMBER"]
|
|
||||||
delete process.env["INPUT_APPEND"]
|
|
||||||
delete process.env["INPUT_RECREATE"]
|
|
||||||
delete process.env["INPUT_DELETE"]
|
|
||||||
delete process.env["INPUT_ONLY_CREATE"]
|
|
||||||
delete process.env["INPUT_ONLY_UPDATE"]
|
|
||||||
delete process.env["INPUT_HIDE"]
|
|
||||||
delete process.env["INPUT_HIDE_AND_RECREATE"]
|
|
||||||
delete process.env["INPUT_HIDE_CLASSIFY"]
|
|
||||||
delete process.env["INPUT_HIDE_DETAILS"]
|
|
||||||
delete process.env["INPUT_GITHUB_TOKEN"]
|
|
||||||
delete process.env["INPUT_PATH"]
|
|
||||||
delete process.env["INPUT_IGNORE_EMPTY"]
|
|
||||||
delete process.env["INPUT_SKIP_UNCHANGED"]
|
|
||||||
delete process.env["INPUT_FOLLOW_SYMBOLIC_LINKS"]
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test("repo", async () => {
|
async function loadConfig(
|
||||||
process.env["INPUT_OWNER"] = "jin"
|
setup?: (mocks: {core: typeof import("@actions/core")}) => void,
|
||||||
process.env["INPUT_REPO"] = "other"
|
) {
|
||||||
|
vi.resetModules()
|
||||||
mockConfig.repo = {owner: "jin", repo: "other"}
|
const core = await import("@actions/core")
|
||||||
|
// vi.resetModules clears the config module cache but not mock instances,
|
||||||
const config = await import('../src/config')
|
// so reset core back to default values before each test.
|
||||||
expect(config).toMatchObject({
|
vi.mocked(core.getInput).mockReturnValue("")
|
||||||
pullRequestNumber: expect.any(Number),
|
vi.mocked(core.getBooleanInput).mockReturnValue(false)
|
||||||
repo: {owner: "jin", repo: "other"},
|
vi.mocked(core.getMultilineInput).mockReturnValue([])
|
||||||
header: "",
|
setup?.({core})
|
||||||
append: false,
|
const config = await import("../src/config")
|
||||||
recreate: false,
|
return {config, core}
|
||||||
deleteOldComment: false,
|
}
|
||||||
hideOldComment: false,
|
|
||||||
hideAndRecreate: false,
|
describe("pullRequestNumber", () => {
|
||||||
hideClassify: "OUTDATED",
|
test("number_force takes highest priority", async () => {
|
||||||
hideDetails: false,
|
mockContext.payload = {pull_request: {number: 789}}
|
||||||
githubToken: "some-token",
|
const {config} = await loadConfig(({core}) => {
|
||||||
ignoreEmpty: false,
|
vi.mocked(core.getInput).mockImplementation(name => {
|
||||||
skipUnchanged: false
|
if (name === "number_force") return "456"
|
||||||
|
if (name === "number") return "123"
|
||||||
|
return ""
|
||||||
|
})
|
||||||
|
})
|
||||||
|
expect(config.pullRequestNumber).toBe(456)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("falls back to context.payload.pull_request.number", async () => {
|
||||||
|
mockContext.payload = {pull_request: {number: 789}}
|
||||||
|
const {config} = await loadConfig()
|
||||||
|
expect(config.pullRequestNumber).toBe(789)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("falls back to number input", async () => {
|
||||||
|
const {config} = await loadConfig(({core}) => {
|
||||||
|
vi.mocked(core.getInput).mockImplementation(name => (name === "number" ? "123" : ""))
|
||||||
|
})
|
||||||
|
expect(config.pullRequestNumber).toBe(123)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("repo", () => {
|
||||||
|
test("defaults to context.repo", async () => {
|
||||||
|
const {config} = await loadConfig()
|
||||||
|
expect(config.repo).toEqual({owner: "marocchino", repo: "sticky-pull-request-comment"})
|
||||||
|
})
|
||||||
|
|
||||||
|
test("uses owner and repo inputs when provided", async () => {
|
||||||
|
const {config} = await loadConfig(({core}) => {
|
||||||
|
vi.mocked(core.getInput).mockImplementation(name => {
|
||||||
|
if (name === "owner") return "jin"
|
||||||
|
if (name === "repo") return "other"
|
||||||
|
return ""
|
||||||
|
})
|
||||||
|
})
|
||||||
|
expect(config.repo).toEqual({owner: "jin", repo: "other"})
|
||||||
})
|
})
|
||||||
expect(await config.getBody()).toEqual("")
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test("header", async () => {
|
test("header", async () => {
|
||||||
process.env["INPUT_HEADER"] = "header"
|
const {config} = await loadConfig(({core}) => {
|
||||||
mockConfig.header = "header"
|
vi.mocked(core.getInput).mockImplementation(name => (name === "header" ? "my-header" : ""))
|
||||||
|
|
||||||
const config = await import('../src/config')
|
|
||||||
expect(config).toMatchObject({
|
|
||||||
pullRequestNumber: expect.any(Number),
|
|
||||||
repo: {owner: "marocchino", repo: "stick-pull-request-comment"},
|
|
||||||
header: "header",
|
|
||||||
append: false,
|
|
||||||
recreate: false,
|
|
||||||
deleteOldComment: false,
|
|
||||||
hideOldComment: false,
|
|
||||||
hideAndRecreate: false,
|
|
||||||
hideClassify: "OUTDATED",
|
|
||||||
hideDetails: false,
|
|
||||||
githubToken: "some-token",
|
|
||||||
ignoreEmpty: false,
|
|
||||||
skipUnchanged: false
|
|
||||||
})
|
})
|
||||||
expect(await config.getBody()).toEqual("")
|
expect(config.header).toBe("my-header")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("append", async () => {
|
test("append", async () => {
|
||||||
process.env["INPUT_APPEND"] = "true"
|
const {config} = await loadConfig(({core}) => {
|
||||||
mockConfig.append = true
|
vi.mocked(core.getBooleanInput).mockImplementation(name => name === "append")
|
||||||
|
|
||||||
const config = await import('../src/config')
|
|
||||||
expect(config).toMatchObject({
|
|
||||||
pullRequestNumber: expect.any(Number),
|
|
||||||
repo: {owner: "marocchino", repo: "stick-pull-request-comment"},
|
|
||||||
header: "",
|
|
||||||
append: true,
|
|
||||||
recreate: false,
|
|
||||||
deleteOldComment: false,
|
|
||||||
hideOldComment: false,
|
|
||||||
hideAndRecreate: false,
|
|
||||||
hideClassify: "OUTDATED",
|
|
||||||
hideDetails: false,
|
|
||||||
githubToken: "some-token",
|
|
||||||
ignoreEmpty: false,
|
|
||||||
skipUnchanged: false
|
|
||||||
})
|
})
|
||||||
expect(await config.getBody()).toEqual("")
|
expect(config.append).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("recreate", async () => {
|
test("recreate", async () => {
|
||||||
process.env["INPUT_RECREATE"] = "true"
|
const {config} = await loadConfig(({core}) => {
|
||||||
mockConfig.recreate = true
|
vi.mocked(core.getBooleanInput).mockImplementation(name => name === "recreate")
|
||||||
|
|
||||||
const config = await import('../src/config')
|
|
||||||
expect(config).toMatchObject({
|
|
||||||
pullRequestNumber: expect.any(Number),
|
|
||||||
repo: {owner: "marocchino", repo: "stick-pull-request-comment"},
|
|
||||||
header: "",
|
|
||||||
append: false,
|
|
||||||
recreate: true,
|
|
||||||
deleteOldComment: false,
|
|
||||||
hideOldComment: false,
|
|
||||||
hideAndRecreate: false,
|
|
||||||
hideClassify: "OUTDATED",
|
|
||||||
hideDetails: false,
|
|
||||||
githubToken: "some-token",
|
|
||||||
ignoreEmpty: false,
|
|
||||||
skipUnchanged: false
|
|
||||||
})
|
})
|
||||||
expect(await config.getBody()).toEqual("")
|
expect(config.recreate).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("delete", async () => {
|
test("deleteOldComment", async () => {
|
||||||
process.env["INPUT_DELETE"] = "true"
|
const {config} = await loadConfig(({core}) => {
|
||||||
mockConfig.deleteOldComment = true
|
vi.mocked(core.getBooleanInput).mockImplementation(name => name === "delete")
|
||||||
|
|
||||||
const config = await import('../src/config')
|
|
||||||
expect(config).toMatchObject({
|
|
||||||
pullRequestNumber: expect.any(Number),
|
|
||||||
repo: {owner: "marocchino", repo: "stick-pull-request-comment"},
|
|
||||||
header: "",
|
|
||||||
append: false,
|
|
||||||
recreate: false,
|
|
||||||
deleteOldComment: true,
|
|
||||||
hideOldComment: false,
|
|
||||||
hideAndRecreate: false,
|
|
||||||
hideClassify: "OUTDATED",
|
|
||||||
hideDetails: false,
|
|
||||||
githubToken: "some-token",
|
|
||||||
ignoreEmpty: false,
|
|
||||||
skipUnchanged: false
|
|
||||||
})
|
})
|
||||||
expect(await config.getBody()).toEqual("")
|
expect(config.deleteOldComment).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("hideOldComment", async () => {
|
test("hideOldComment", async () => {
|
||||||
process.env["INPUT_HIDE"] = "true"
|
const {config} = await loadConfig(({core}) => {
|
||||||
mockConfig.hideOldComment = true
|
vi.mocked(core.getBooleanInput).mockImplementation(name => name === "hide")
|
||||||
|
|
||||||
const config = await import('../src/config')
|
|
||||||
expect(config).toMatchObject({
|
|
||||||
pullRequestNumber: expect.any(Number),
|
|
||||||
repo: {owner: "marocchino", repo: "stick-pull-request-comment"},
|
|
||||||
header: "",
|
|
||||||
append: false,
|
|
||||||
recreate: false,
|
|
||||||
deleteOldComment: false,
|
|
||||||
hideOldComment: true,
|
|
||||||
hideAndRecreate: false,
|
|
||||||
hideClassify: "OUTDATED",
|
|
||||||
hideDetails: false,
|
|
||||||
githubToken: "some-token",
|
|
||||||
ignoreEmpty: false,
|
|
||||||
skipUnchanged: false
|
|
||||||
})
|
})
|
||||||
expect(await config.getBody()).toEqual("")
|
expect(config.hideOldComment).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("hideAndRecreate", async () => {
|
test("hideAndRecreate", async () => {
|
||||||
process.env["INPUT_HIDE_AND_RECREATE"] = "true"
|
const {config} = await loadConfig(({core}) => {
|
||||||
mockConfig.hideAndRecreate = true
|
vi.mocked(core.getBooleanInput).mockImplementation(name => name === "hide_and_recreate")
|
||||||
|
|
||||||
const config = await import('../src/config')
|
|
||||||
expect(config).toMatchObject({
|
|
||||||
pullRequestNumber: expect.any(Number),
|
|
||||||
repo: {owner: "marocchino", repo: "stick-pull-request-comment"},
|
|
||||||
header: "",
|
|
||||||
append: false,
|
|
||||||
recreate: false,
|
|
||||||
deleteOldComment: false,
|
|
||||||
hideOldComment: false,
|
|
||||||
hideAndRecreate: true,
|
|
||||||
hideClassify: "OUTDATED",
|
|
||||||
hideDetails: false,
|
|
||||||
githubToken: "some-token",
|
|
||||||
ignoreEmpty: false,
|
|
||||||
skipUnchanged: false
|
|
||||||
})
|
})
|
||||||
expect(await config.getBody()).toEqual("")
|
expect(config.hideAndRecreate).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("hideClassify", async () => {
|
test("hideClassify", async () => {
|
||||||
process.env["INPUT_HIDE_CLASSIFY"] = "OFF_TOPIC"
|
const {config} = await loadConfig(({core}) => {
|
||||||
mockConfig.hideClassify = "OFF_TOPIC"
|
vi.mocked(core.getInput).mockImplementation(name => (name === "hide_classify" ? "OFF_TOPIC" : ""))
|
||||||
|
|
||||||
const config = await import('../src/config')
|
|
||||||
expect(config).toMatchObject({
|
|
||||||
pullRequestNumber: expect.any(Number),
|
|
||||||
repo: {owner: "marocchino", repo: "stick-pull-request-comment"},
|
|
||||||
header: "",
|
|
||||||
append: false,
|
|
||||||
recreate: false,
|
|
||||||
deleteOldComment: false,
|
|
||||||
hideOldComment: false,
|
|
||||||
hideAndRecreate: false,
|
|
||||||
hideClassify: "OFF_TOPIC",
|
|
||||||
hideDetails: false,
|
|
||||||
githubToken: "some-token",
|
|
||||||
ignoreEmpty: false,
|
|
||||||
skipUnchanged: false
|
|
||||||
})
|
})
|
||||||
expect(await config.getBody()).toEqual("")
|
expect(config.hideClassify).toBe("OFF_TOPIC")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("hideDetails", async () => {
|
test("hideDetails", async () => {
|
||||||
process.env["INPUT_HIDE_DETAILS"] = "true"
|
const {config} = await loadConfig(({core}) => {
|
||||||
mockConfig.hideDetails = true
|
vi.mocked(core.getBooleanInput).mockImplementation(name => name === "hide_details")
|
||||||
|
|
||||||
const config = await import('../src/config')
|
|
||||||
expect(config).toMatchObject({
|
|
||||||
pullRequestNumber: expect.any(Number),
|
|
||||||
repo: {owner: "marocchino", repo: "stick-pull-request-comment"},
|
|
||||||
header: "",
|
|
||||||
append: false,
|
|
||||||
recreate: false,
|
|
||||||
deleteOldComment: false,
|
|
||||||
hideOldComment: false,
|
|
||||||
hideAndRecreate: false,
|
|
||||||
hideClassify: "OUTDATED",
|
|
||||||
hideDetails: true,
|
|
||||||
githubToken: "some-token",
|
|
||||||
ignoreEmpty: false,
|
|
||||||
skipUnchanged: false
|
|
||||||
})
|
})
|
||||||
expect(await config.getBody()).toEqual("")
|
expect(config.hideDetails).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("path", () => {
|
test("ignoreEmpty", async () => {
|
||||||
test("when exists return content of a file", async () => {
|
const {config} = await loadConfig(({core}) => {
|
||||||
process.env["INPUT_PATH"] = "./__tests__/assets/result"
|
vi.mocked(core.getBooleanInput).mockImplementation(name => name === "ignore_empty")
|
||||||
mockConfig.getBody.mockResolvedValue("hi there\n")
|
})
|
||||||
|
expect(config.ignoreEmpty).toBe(true)
|
||||||
const config = await import('../src/config')
|
})
|
||||||
expect(config).toMatchObject({
|
|
||||||
pullRequestNumber: expect.any(Number),
|
test("skipUnchanged", async () => {
|
||||||
repo: {owner: "marocchino", repo: "stick-pull-request-comment"},
|
const {config} = await loadConfig(({core}) => {
|
||||||
header: "",
|
vi.mocked(core.getBooleanInput).mockImplementation(name => name === "skip_unchanged")
|
||||||
append: false,
|
})
|
||||||
recreate: false,
|
expect(config.skipUnchanged).toBe(true)
|
||||||
deleteOldComment: false,
|
})
|
||||||
hideOldComment: false,
|
|
||||||
hideAndRecreate: false,
|
test("githubToken", async () => {
|
||||||
hideClassify: "OUTDATED",
|
const {config} = await loadConfig(({core}) => {
|
||||||
hideDetails: false,
|
vi.mocked(core.getInput).mockImplementation(name => (name === "GITHUB_TOKEN" ? "my-token" : ""))
|
||||||
githubToken: "some-token",
|
})
|
||||||
ignoreEmpty: false,
|
expect(config.githubToken).toBe("my-token")
|
||||||
skipUnchanged: false
|
})
|
||||||
|
|
||||||
|
describe("getBody", () => {
|
||||||
|
test("returns message when no path is provided", async () => {
|
||||||
|
const {config, core} = await loadConfig()
|
||||||
|
vi.mocked(core.getInput).mockImplementation(name => (name === "message" ? "hello there" : ""))
|
||||||
|
expect(await config.getBody()).toBe("hello there")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("returns file content when path exists", async () => {
|
||||||
|
const {config, core} = await loadConfig()
|
||||||
|
vi.mocked(core.getMultilineInput).mockReturnValue(["__tests__/assets/result"])
|
||||||
|
mockGlobCreate.mockResolvedValue({
|
||||||
|
glob: vi.fn().mockResolvedValue([resolve("__tests__/assets/result")]),
|
||||||
})
|
})
|
||||||
expect(await config.getBody()).toEqual("hi there\n")
|
expect(await config.getBody()).toBe("hi there\n")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("glob match files", async () => {
|
test("glob matches multiple files", async () => {
|
||||||
process.env["INPUT_PATH"] = "./__tests__/assets/*"
|
const {config, core} = await loadConfig()
|
||||||
mockConfig.getBody.mockResolvedValue("hi there\n\nhey there\n")
|
vi.mocked(core.getMultilineInput).mockReturnValue(["__tests__/assets/*"])
|
||||||
|
mockGlobCreate.mockResolvedValue({
|
||||||
const config = await import('../src/config')
|
glob: vi
|
||||||
expect(config).toMatchObject({
|
.fn()
|
||||||
pullRequestNumber: expect.any(Number),
|
.mockResolvedValue([
|
||||||
repo: {owner: "marocchino", repo: "stick-pull-request-comment"},
|
resolve("__tests__/assets/result"),
|
||||||
header: "",
|
resolve("__tests__/assets/result2"),
|
||||||
append: false,
|
]),
|
||||||
recreate: false,
|
|
||||||
deleteOldComment: false,
|
|
||||||
hideOldComment: false,
|
|
||||||
hideAndRecreate: false,
|
|
||||||
hideClassify: "OUTDATED",
|
|
||||||
hideDetails: false,
|
|
||||||
githubToken: "some-token",
|
|
||||||
ignoreEmpty: false,
|
|
||||||
skipUnchanged: false
|
|
||||||
})
|
})
|
||||||
expect(await config.getBody()).toEqual("hi there\n\nhey there\n")
|
expect(await config.getBody()).toBe("hi there\n\nhey there\n")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("when not exists return null string", async () => {
|
test("returns empty string when path matches no files", async () => {
|
||||||
process.env["INPUT_PATH"] = "./__tests__/assets/not_exists"
|
const {config, core} = await loadConfig()
|
||||||
mockConfig.getBody.mockResolvedValue("")
|
vi.mocked(core.getMultilineInput).mockReturnValue(["__tests__/assets/not_exists"])
|
||||||
|
mockGlobCreate.mockResolvedValue({glob: vi.fn().mockResolvedValue([])})
|
||||||
const config = await import('../src/config')
|
expect(await config.getBody()).toBe("")
|
||||||
expect(config).toMatchObject({
|
|
||||||
pullRequestNumber: expect.any(Number),
|
|
||||||
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
|
|
||||||
})
|
|
||||||
expect(await config.getBody()).toEqual("")
|
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
test("message", async () => {
|
test("returns empty string and calls setFailed when glob throws", async () => {
|
||||||
process.env["INPUT_MESSAGE"] = "hello there"
|
const {config, core} = await loadConfig()
|
||||||
mockConfig.getBody.mockResolvedValue("hello there")
|
vi.mocked(core.getMultilineInput).mockReturnValue(["__tests__/assets/result"])
|
||||||
|
mockGlobCreate.mockRejectedValue(new Error("glob error"))
|
||||||
const config = await import('../src/config')
|
expect(await config.getBody()).toBe("")
|
||||||
expect(config).toMatchObject({
|
expect(core.setFailed).toHaveBeenCalledWith("glob error")
|
||||||
pullRequestNumber: expect.any(Number),
|
|
||||||
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
|
|
||||||
})
|
})
|
||||||
expect(await config.getBody()).toEqual("hello there")
|
|
||||||
})
|
|
||||||
|
|
||||||
test("ignore_empty", async () => {
|
|
||||||
process.env["INPUT_IGNORE_EMPTY"] = "true"
|
|
||||||
mockConfig.ignoreEmpty = true
|
|
||||||
|
|
||||||
const config = await import('../src/config')
|
|
||||||
expect(config).toMatchObject({
|
|
||||||
pullRequestNumber: expect.any(Number),
|
|
||||||
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: true,
|
|
||||||
skipUnchanged: false
|
|
||||||
})
|
|
||||||
expect(await config.getBody()).toEqual("")
|
|
||||||
})
|
|
||||||
|
|
||||||
test("skip_unchanged", async () => {
|
|
||||||
process.env["INPUT_SKIP_UNCHANGED"] = "true"
|
|
||||||
mockConfig.skipUnchanged = true
|
|
||||||
|
|
||||||
const config = await import('../src/config')
|
|
||||||
expect(config).toMatchObject({
|
|
||||||
pullRequestNumber: expect.any(Number),
|
|
||||||
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: true
|
|
||||||
})
|
|
||||||
expect(await config.getBody()).toEqual("")
|
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -115,8 +115,9 @@ describe("run", () => {
|
||||||
mockConfig.recreate = true
|
mockConfig.recreate = true
|
||||||
const {core} = await runMain()
|
const {core} = await runMain()
|
||||||
expect(core.setFailed).toHaveBeenCalledWith(
|
expect(core.setFailed).toHaveBeenCalledWith(
|
||||||
"delete and recreate cannot be both set to true",
|
"delete and recreate cannot be set to true simultaneously",
|
||||||
)
|
)
|
||||||
|
expect(mockConfig.getBody).not.toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
test("fails when deleteOldComment and onlyCreateComment are both true", async () => {
|
test("fails when deleteOldComment and onlyCreateComment are both true", async () => {
|
||||||
|
|
@ -124,8 +125,9 @@ describe("run", () => {
|
||||||
mockConfig.onlyCreateComment = true
|
mockConfig.onlyCreateComment = true
|
||||||
const {core} = await runMain()
|
const {core} = await runMain()
|
||||||
expect(core.setFailed).toHaveBeenCalledWith(
|
expect(core.setFailed).toHaveBeenCalledWith(
|
||||||
"delete and only_create cannot be both set to true",
|
"delete and only_create cannot be set to true simultaneously",
|
||||||
)
|
)
|
||||||
|
expect(mockConfig.getBody).not.toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
test("fails when deleteOldComment and hideOldComment are both true", async () => {
|
test("fails when deleteOldComment and hideOldComment are both true", async () => {
|
||||||
|
|
@ -133,8 +135,9 @@ describe("run", () => {
|
||||||
mockConfig.hideOldComment = true
|
mockConfig.hideOldComment = true
|
||||||
const {core} = await runMain()
|
const {core} = await runMain()
|
||||||
expect(core.setFailed).toHaveBeenCalledWith(
|
expect(core.setFailed).toHaveBeenCalledWith(
|
||||||
"delete and hide cannot be both set to true",
|
"delete and hide cannot be set to true simultaneously",
|
||||||
)
|
)
|
||||||
|
expect(mockConfig.getBody).not.toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
test("fails when onlyCreateComment and onlyUpdateComment are both true", async () => {
|
test("fails when onlyCreateComment and onlyUpdateComment are both true", async () => {
|
||||||
|
|
@ -142,8 +145,9 @@ describe("run", () => {
|
||||||
mockConfig.onlyUpdateComment = true
|
mockConfig.onlyUpdateComment = true
|
||||||
const {core} = await runMain()
|
const {core} = await runMain()
|
||||||
expect(core.setFailed).toHaveBeenCalledWith(
|
expect(core.setFailed).toHaveBeenCalledWith(
|
||||||
"only_create and only_update cannot be both set to true",
|
"only_create and only_update cannot be set to true simultaneously",
|
||||||
)
|
)
|
||||||
|
expect(mockConfig.getBody).not.toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
test("fails when hideOldComment and hideAndRecreate are both true", async () => {
|
test("fails when hideOldComment and hideAndRecreate are both true", async () => {
|
||||||
|
|
@ -151,8 +155,19 @@ describe("run", () => {
|
||||||
mockConfig.hideAndRecreate = true
|
mockConfig.hideAndRecreate = true
|
||||||
const {core} = await runMain()
|
const {core} = await runMain()
|
||||||
expect(core.setFailed).toHaveBeenCalledWith(
|
expect(core.setFailed).toHaveBeenCalledWith(
|
||||||
"hide and hide_and_recreate cannot be both set to true",
|
"hide and hide_and_recreate cannot be set to true simultaneously",
|
||||||
)
|
)
|
||||||
|
expect(mockConfig.getBody).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
test("fails when deleteOldComment and hideAndRecreate are both true", async () => {
|
||||||
|
mockConfig.deleteOldComment = true
|
||||||
|
mockConfig.hideAndRecreate = true
|
||||||
|
const {core} = await runMain()
|
||||||
|
expect(core.setFailed).toHaveBeenCalledWith(
|
||||||
|
"delete and hide_and_recreate cannot be set to true simultaneously",
|
||||||
|
)
|
||||||
|
expect(mockConfig.getBody).not.toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
test("deletes previous comment when deleteOldComment is true and previous comment exists", async () => {
|
test("deletes previous comment when deleteOldComment is true and previous comment exists", async () => {
|
||||||
|
|
|
||||||
85
__tests__/validate.test.ts
Normal file
85
__tests__/validate.test.ts
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
import {describe, expect, test} from "vitest"
|
||||||
|
import {validateBody, validateExclusiveModes} from "../src/validate"
|
||||||
|
|
||||||
|
describe("validateBody", () => {
|
||||||
|
test("throws when body is empty and neither delete nor hide is set", () => {
|
||||||
|
expect(() => validateBody("", false, false)).toThrow(
|
||||||
|
"Either message or path input is required",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("does not throw when body is provided", () => {
|
||||||
|
expect(() => validateBody("some body", false, false)).not.toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
test("does not throw when body is empty but deleteOldComment is true", () => {
|
||||||
|
expect(() => validateBody("", true, false)).not.toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
test("does not throw when body is empty but hideOldComment is true", () => {
|
||||||
|
expect(() => validateBody("", false, true)).not.toThrow()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("validateExclusiveModes", () => {
|
||||||
|
test("does not throw when no modes are enabled", () => {
|
||||||
|
expect(() => validateExclusiveModes(false, false, false, false, false, false)).not.toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
test("does not throw when exactly one mode is enabled", () => {
|
||||||
|
expect(() => validateExclusiveModes(true, false, false, false, false, false)).not.toThrow()
|
||||||
|
expect(() => validateExclusiveModes(false, true, false, false, false, false)).not.toThrow()
|
||||||
|
expect(() => validateExclusiveModes(false, false, true, false, false, false)).not.toThrow()
|
||||||
|
expect(() => validateExclusiveModes(false, false, false, true, false, false)).not.toThrow()
|
||||||
|
expect(() => validateExclusiveModes(false, false, false, false, true, false)).not.toThrow()
|
||||||
|
expect(() => validateExclusiveModes(false, false, false, false, false, true)).not.toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
test("throws when delete and recreate are both true", () => {
|
||||||
|
expect(() => validateExclusiveModes(true, true, false, false, false, false)).toThrow(
|
||||||
|
"delete and recreate cannot be set to true simultaneously",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("throws when delete and only_create are both true", () => {
|
||||||
|
expect(() => validateExclusiveModes(true, false, true, false, false, false)).toThrow(
|
||||||
|
"delete and only_create cannot be set to true simultaneously",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("throws when delete and only_update are both true", () => {
|
||||||
|
expect(() => validateExclusiveModes(true, false, false, true, false, false)).toThrow(
|
||||||
|
"delete and only_update cannot be set to true simultaneously",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("throws when delete and hide are both true", () => {
|
||||||
|
expect(() => validateExclusiveModes(true, false, false, false, true, false)).toThrow(
|
||||||
|
"delete and hide cannot be set to true simultaneously",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("throws when delete and hide_and_recreate are both true", () => {
|
||||||
|
expect(() => validateExclusiveModes(true, false, false, false, false, true)).toThrow(
|
||||||
|
"delete and hide_and_recreate cannot be set to true simultaneously",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("throws when only_create and only_update are both true", () => {
|
||||||
|
expect(() => validateExclusiveModes(false, false, true, true, false, false)).toThrow(
|
||||||
|
"only_create and only_update cannot be set to true simultaneously",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("throws when hide and hide_and_recreate are both true", () => {
|
||||||
|
expect(() => validateExclusiveModes(false, false, false, false, true, true)).toThrow(
|
||||||
|
"hide and hide_and_recreate cannot be set to true simultaneously",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("uses Oxford comma when three or more modes are enabled", () => {
|
||||||
|
expect(() => validateExclusiveModes(true, true, true, false, false, false)).toThrow(
|
||||||
|
"delete, recreate, and only_create cannot be set to true simultaneously",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
@ -72,6 +72,9 @@ inputs:
|
||||||
number:
|
number:
|
||||||
description: "pull request number for push event"
|
description: "pull request number for push event"
|
||||||
required: false
|
required: false
|
||||||
|
number_force:
|
||||||
|
description: "pull request number for any event"
|
||||||
|
required: false
|
||||||
owner:
|
owner:
|
||||||
description: "Another repo owner, If not set, the current repo owner is used by default. Note that when you trying changing a repo, be aware that GITHUB_TOKEN should also have permission for that repository."
|
description: "Another repo owner, If not set, the current repo owner is used by default. Note that when you trying changing a repo, be aware that GITHUB_TOKEN should also have permission for that repository."
|
||||||
required: false
|
required: false
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://biomejs.dev/schemas/2.4.6/schema.json",
|
"$schema": "https://biomejs.dev/schemas/2.4.10/schema.json",
|
||||||
"files": {
|
"files": {
|
||||||
"includes": ["src/**/*.ts"]
|
"includes": ["src/**/*.ts"]
|
||||||
},
|
},
|
||||||
|
|
|
||||||
85
dist/index.js
generated
vendored
85
dist/index.js
generated
vendored
|
|
@ -27925,7 +27925,7 @@ function requireUndici () {
|
||||||
var undiciExports = requireUndici();
|
var undiciExports = requireUndici();
|
||||||
|
|
||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
(undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
(globalThis && globalThis.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
|
@ -27986,7 +27986,7 @@ var MediaTypes;
|
||||||
HttpCodes.GatewayTimeout
|
HttpCodes.GatewayTimeout
|
||||||
];
|
];
|
||||||
|
|
||||||
(undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
(globalThis && globalThis.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
|
@ -27996,7 +27996,7 @@ var MediaTypes;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
(undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
(globalThis && globalThis.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
|
@ -28006,7 +28006,7 @@ var MediaTypes;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
(undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
(globalThis && globalThis.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
|
@ -28017,7 +28017,7 @@ var MediaTypes;
|
||||||
};
|
};
|
||||||
const { access, appendFile, writeFile } = fs.promises;
|
const { access, appendFile, writeFile } = fs.promises;
|
||||||
|
|
||||||
(undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
(globalThis && globalThis.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
|
@ -28031,7 +28031,7 @@ const { chmod, copyFile, lstat, mkdir, open, readdir, rename, rm, rmdir, stat, s
|
||||||
process.platform === 'win32';
|
process.platform === 'win32';
|
||||||
fs__namespace.constants.O_RDONLY;
|
fs__namespace.constants.O_RDONLY;
|
||||||
|
|
||||||
(undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
(globalThis && globalThis.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
|
@ -28041,7 +28041,7 @@ fs__namespace.constants.O_RDONLY;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
(undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
(globalThis && globalThis.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
|
@ -28053,7 +28053,7 @@ fs__namespace.constants.O_RDONLY;
|
||||||
/* eslint-disable @typescript-eslint/unbound-method */
|
/* eslint-disable @typescript-eslint/unbound-method */
|
||||||
process.platform === 'win32';
|
process.platform === 'win32';
|
||||||
|
|
||||||
(undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
(globalThis && globalThis.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
|
@ -28063,7 +28063,7 @@ process.platform === 'win32';
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
(undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
(globalThis && globalThis.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
|
@ -28075,7 +28075,7 @@ process.platform === 'win32';
|
||||||
os.platform();
|
os.platform();
|
||||||
os.arch();
|
os.arch();
|
||||||
|
|
||||||
(undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
(globalThis && globalThis.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
|
@ -29114,7 +29114,7 @@ function requireLib () {
|
||||||
|
|
||||||
var libExports = requireLib();
|
var libExports = requireLib();
|
||||||
|
|
||||||
var __awaiter$2 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
var __awaiter$2 = (globalThis && globalThis.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
|
@ -33728,7 +33728,7 @@ function requireBraceExpansion () {
|
||||||
var y = numeric(n[1]);
|
var y = numeric(n[1]);
|
||||||
var width = Math.max(n[0].length, n[1].length);
|
var width = Math.max(n[0].length, n[1].length);
|
||||||
var incr = n.length == 3
|
var incr = n.length == 3
|
||||||
? Math.abs(numeric(n[2]))
|
? Math.max(Math.abs(numeric(n[2])), 1)
|
||||||
: 1;
|
: 1;
|
||||||
var test = lte;
|
var test = lte;
|
||||||
var reverse = y < x;
|
var reverse = y < x;
|
||||||
|
|
@ -35108,7 +35108,7 @@ class SearchState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var __awaiter$1 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
var __awaiter$1 = (globalThis && globalThis.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
|
@ -35117,15 +35117,15 @@ var __awaiter$1 = (undefined && undefined.__awaiter) || function (thisArg, _argu
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
var __asyncValues = (undefined && undefined.__asyncValues) || function (o) {
|
var __asyncValues = (globalThis && globalThis.__asyncValues) || function (o) {
|
||||||
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
||||||
var m = o[Symbol.asyncIterator], i;
|
var m = o[Symbol.asyncIterator], i;
|
||||||
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
||||||
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
||||||
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
||||||
};
|
};
|
||||||
var __await = (undefined && undefined.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); };
|
var __await = (globalThis && globalThis.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); };
|
||||||
var __asyncGenerator = (undefined && undefined.__asyncGenerator) || function (thisArg, _arguments, generator) {
|
var __asyncGenerator = (globalThis && globalThis.__asyncGenerator) || function (thisArg, _arguments, generator) {
|
||||||
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
||||||
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
||||||
return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
|
return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
|
||||||
|
|
@ -35319,7 +35319,7 @@ class DefaultGlobber {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
(globalThis && globalThis.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
|
@ -35328,7 +35328,7 @@ class DefaultGlobber {
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
(undefined && undefined.__asyncValues) || function (o) {
|
(globalThis && globalThis.__asyncValues) || function (o) {
|
||||||
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
||||||
var m = o[Symbol.asyncIterator], i;
|
var m = o[Symbol.asyncIterator], i;
|
||||||
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
||||||
|
|
@ -35336,7 +35336,7 @@ class DefaultGlobber {
|
||||||
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
||||||
};
|
};
|
||||||
|
|
||||||
var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
var __awaiter = (globalThis && globalThis.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
|
@ -35357,7 +35357,9 @@ function create(patterns, options) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const pullRequestNumber = context?.payload?.pull_request?.number || +getInput("number", { required: false });
|
const pullRequestNumber = +getInput("number_force", { required: false }) ||
|
||||||
|
context?.payload?.pull_request?.number ||
|
||||||
|
+getInput("number", { required: false });
|
||||||
const repo = buildRepo();
|
const repo = buildRepo();
|
||||||
const header = getInput("header", { required: false });
|
const header = getInput("header", { required: false });
|
||||||
const append = getBooleanInput("append", { required: true });
|
const append = getBooleanInput("append", { required: true });
|
||||||
|
|
@ -35417,35 +35419,42 @@ async function getBody() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function validateBody(body, deleteOldComment, hideOldComment) {
|
||||||
|
if (!deleteOldComment && !hideOldComment && !body) {
|
||||||
|
throw new Error("Either message or path input is required");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function validateExclusiveModes(deleteOldComment, recreate, onlyCreateComment, onlyUpdateComment, hideOldComment, hideAndRecreate) {
|
||||||
|
const exclusiveModes = [
|
||||||
|
["delete", deleteOldComment],
|
||||||
|
["recreate", recreate],
|
||||||
|
["only_create", onlyCreateComment],
|
||||||
|
["only_update", onlyUpdateComment],
|
||||||
|
["hide", hideOldComment],
|
||||||
|
["hide_and_recreate", hideAndRecreate],
|
||||||
|
];
|
||||||
|
const enabledModes = exclusiveModes.filter(([, flag]) => flag).map(([name]) => name);
|
||||||
|
if (enabledModes.length > 1) {
|
||||||
|
const last = enabledModes[enabledModes.length - 1];
|
||||||
|
const rest = enabledModes.slice(0, -1);
|
||||||
|
const joined = enabledModes.length === 2 ? `${rest[0]} and ${last}` : `${rest.join(", ")}, and ${last}`;
|
||||||
|
throw new Error(`${joined} cannot be set to true simultaneously`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
if (Number.isNaN(pullRequestNumber) || pullRequestNumber < 1) {
|
if (Number.isNaN(pullRequestNumber) || pullRequestNumber < 1) {
|
||||||
info("no pull request numbers given: skip step");
|
info("no pull request numbers given: skip step");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
validateExclusiveModes(deleteOldComment, recreate, onlyCreateComment, onlyUpdateComment, hideOldComment, hideAndRecreate);
|
||||||
const body = await getBody();
|
const body = await getBody();
|
||||||
if (!body && ignoreEmpty) {
|
if (!body && ignoreEmpty) {
|
||||||
info("no body given: skip step by ignoreEmpty");
|
info("no body given: skip step by ignoreEmpty");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!deleteOldComment && !hideOldComment && !body) {
|
validateBody(body, deleteOldComment, hideOldComment);
|
||||||
throw new Error("Either message or path input is required");
|
|
||||||
}
|
|
||||||
if (deleteOldComment && recreate) {
|
|
||||||
throw new Error("delete and recreate cannot be both set to true");
|
|
||||||
}
|
|
||||||
if (deleteOldComment && onlyCreateComment) {
|
|
||||||
throw new Error("delete and only_create cannot be both set to true");
|
|
||||||
}
|
|
||||||
if (deleteOldComment && hideOldComment) {
|
|
||||||
throw new Error("delete and hide cannot be both set to true");
|
|
||||||
}
|
|
||||||
if (onlyCreateComment && onlyUpdateComment) {
|
|
||||||
throw new Error("only_create and only_update cannot be both set to true");
|
|
||||||
}
|
|
||||||
if (hideOldComment && hideAndRecreate) {
|
|
||||||
throw new Error("hide and hide_and_recreate cannot be both set to true");
|
|
||||||
}
|
|
||||||
const octokit = getOctokit(githubToken);
|
const octokit = getOctokit(githubToken);
|
||||||
const previous = await findPreviousComment(octokit, repo, pullRequestNumber, header);
|
const previous = await findPreviousComment(octokit, repo, pullRequestNumber, header);
|
||||||
setOutput("previous_comment_id", previous?.id);
|
setOutput("previous_comment_id", previous?.id);
|
||||||
|
|
|
||||||
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
621
package-lock.json
generated
621
package-lock.json
generated
File diff suppressed because it is too large
Load diff
12
package.json
12
package.json
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "sticky-pull-request-comment",
|
"name": "sticky-pull-request-comment",
|
||||||
"version": "3.0.1",
|
"version": "3.0.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "Create comment on pull request, if exists update that comment.",
|
"description": "Create comment on pull request, if exists update that comment.",
|
||||||
"main": "lib/main.js",
|
"main": "lib/main.js",
|
||||||
|
|
@ -35,15 +35,15 @@
|
||||||
"@octokit/graphql-schema": "^15.26.1"
|
"@octokit/graphql-schema": "^15.26.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "2.4.6",
|
"@biomejs/biome": "2.4.10",
|
||||||
"@rollup/plugin-commonjs": "^29.0.2",
|
"@rollup/plugin-commonjs": "^29.0.2",
|
||||||
"@rollup/plugin-node-resolve": "^16.0.3",
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
||||||
"@rollup/plugin-typescript": "^12.3.0",
|
"@rollup/plugin-typescript": "^12.3.0",
|
||||||
"@types/node": "^25.5.0",
|
"@types/node": "^25.5.2",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"rimraf": "^6.1.3",
|
"rimraf": "^6.1.3",
|
||||||
"rollup": "^4.59.0",
|
"rollup": "^4.60.1",
|
||||||
"typescript": "^5.9.2",
|
"typescript": "^6.0.2",
|
||||||
"vitest": "^4.0.16"
|
"vitest": "^4.1.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import nodeResolve from "@rollup/plugin-node-resolve"
|
||||||
import typescript from "@rollup/plugin-typescript"
|
import typescript from "@rollup/plugin-typescript"
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
|
context: "globalThis",
|
||||||
input: "src/main.ts",
|
input: "src/main.ts",
|
||||||
output: {
|
output: {
|
||||||
exports: "auto",
|
exports: "auto",
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,9 @@ import {create} from "@actions/glob"
|
||||||
import type {ReportedContentClassifiers} from "@octokit/graphql-schema"
|
import type {ReportedContentClassifiers} from "@octokit/graphql-schema"
|
||||||
|
|
||||||
export const pullRequestNumber =
|
export const pullRequestNumber =
|
||||||
context?.payload?.pull_request?.number || +core.getInput("number", {required: false})
|
+core.getInput("number_force", {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})
|
||||||
|
|
|
||||||
34
src/main.ts
34
src/main.ts
|
|
@ -27,6 +27,7 @@ import {
|
||||||
repo,
|
repo,
|
||||||
skipUnchanged,
|
skipUnchanged,
|
||||||
} from "./config"
|
} from "./config"
|
||||||
|
import {validateBody, validateExclusiveModes} from "./validate"
|
||||||
|
|
||||||
async function run(): Promise<undefined> {
|
async function run(): Promise<undefined> {
|
||||||
if (Number.isNaN(pullRequestNumber) || pullRequestNumber < 1) {
|
if (Number.isNaN(pullRequestNumber) || pullRequestNumber < 1) {
|
||||||
|
|
@ -35,6 +36,15 @@ async function run(): Promise<undefined> {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
validateExclusiveModes(
|
||||||
|
deleteOldComment,
|
||||||
|
recreate,
|
||||||
|
onlyCreateComment,
|
||||||
|
onlyUpdateComment,
|
||||||
|
hideOldComment,
|
||||||
|
hideAndRecreate,
|
||||||
|
)
|
||||||
|
|
||||||
const body = await getBody()
|
const body = await getBody()
|
||||||
|
|
||||||
if (!body && ignoreEmpty) {
|
if (!body && ignoreEmpty) {
|
||||||
|
|
@ -42,29 +52,7 @@ async function run(): Promise<undefined> {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!deleteOldComment && !hideOldComment && !body) {
|
validateBody(body, deleteOldComment, hideOldComment)
|
||||||
throw new Error("Either message or path input is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (deleteOldComment && recreate) {
|
|
||||||
throw new Error("delete and recreate cannot be both set to true")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (deleteOldComment && onlyCreateComment) {
|
|
||||||
throw new Error("delete and only_create cannot be both set to true")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (deleteOldComment && hideOldComment) {
|
|
||||||
throw new Error("delete and hide cannot be both set to true")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (onlyCreateComment && onlyUpdateComment) {
|
|
||||||
throw new Error("only_create and only_update cannot be both set to true")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hideOldComment && hideAndRecreate) {
|
|
||||||
throw new Error("hide and hide_and_recreate cannot be both set to true")
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
||||||
35
src/validate.ts
Normal file
35
src/validate.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
export function validateBody(
|
||||||
|
body: string,
|
||||||
|
deleteOldComment: boolean,
|
||||||
|
hideOldComment: boolean,
|
||||||
|
): void {
|
||||||
|
if (!deleteOldComment && !hideOldComment && !body) {
|
||||||
|
throw new Error("Either message or path input is required")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function validateExclusiveModes(
|
||||||
|
deleteOldComment: boolean,
|
||||||
|
recreate: boolean,
|
||||||
|
onlyCreateComment: boolean,
|
||||||
|
onlyUpdateComment: boolean,
|
||||||
|
hideOldComment: boolean,
|
||||||
|
hideAndRecreate: boolean,
|
||||||
|
): void {
|
||||||
|
const exclusiveModes: [string, boolean][] = [
|
||||||
|
["delete", deleteOldComment],
|
||||||
|
["recreate", recreate],
|
||||||
|
["only_create", onlyCreateComment],
|
||||||
|
["only_update", onlyUpdateComment],
|
||||||
|
["hide", hideOldComment],
|
||||||
|
["hide_and_recreate", hideAndRecreate],
|
||||||
|
]
|
||||||
|
const enabledModes = exclusiveModes.filter(([, flag]) => flag).map(([name]) => name)
|
||||||
|
if (enabledModes.length > 1) {
|
||||||
|
const last = enabledModes[enabledModes.length - 1]
|
||||||
|
const rest = enabledModes.slice(0, -1)
|
||||||
|
const joined =
|
||||||
|
enabledModes.length === 2 ? `${rest[0]} and ${last}` : `${rest.join(", ")}, and ${last}`
|
||||||
|
throw new Error(`${joined} cannot be set to true simultaneously`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,9 +17,11 @@
|
||||||
"outDir": "./dist",
|
"outDir": "./dist",
|
||||||
"pretty": true,
|
"pretty": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
|
"rootDir": "./src",
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"strictNullChecks": true,
|
"strictNullChecks": true,
|
||||||
"target": "ES2022"
|
"target": "ES2022",
|
||||||
|
"types": ["node"]
|
||||||
},
|
},
|
||||||
"exclude": ["node_modules", "**/*.test.ts", "dist"],
|
"exclude": ["node_modules", "**/*.test.ts", "dist"],
|
||||||
"include": ["src"]
|
"include": ["src"]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue