diff --git a/actions/setup/js/check_stop_time.cjs b/actions/setup/js/check_stop_time.cjs
index 4e86da0f8a..96dff917c9 100644
--- a/actions/setup/js/check_stop_time.cjs
+++ b/actions/setup/js/check_stop_time.cjs
@@ -1,9 +1,21 @@
// @ts-check
///
+/**
+ * Validates date format and returns true if valid
+ * @param {Date} date - Date to validate
+ * @returns {boolean} True if date is valid
+ */
+function isValidDate(date) {
+ return !isNaN(date.getTime());
+}
+
+/**
+ * Checks if workflow execution should stop based on configured stop time
+ * @returns {Promise}
+ */
async function main() {
- const stopTime = process.env.GH_AW_STOP_TIME;
- const workflowName = process.env.GH_AW_WORKFLOW_NAME;
+ const { GH_AW_STOP_TIME: stopTime, GH_AW_WORKFLOW_NAME: workflowName } = process.env;
if (!stopTime) {
core.setFailed("Configuration error: GH_AW_STOP_TIME not specified.");
@@ -17,10 +29,9 @@ async function main() {
core.info(`Checking stop-time limit: ${stopTime}`);
- // Parse the stop time (format: "YYYY-MM-DD HH:MM:SS")
const stopTimeDate = new Date(stopTime);
- if (isNaN(stopTimeDate.getTime())) {
+ if (!isValidDate(stopTimeDate)) {
core.setFailed(`Invalid stop-time format: ${stopTime}. Expected format: YYYY-MM-DD HH:MM:SS`);
return;
}
diff --git a/actions/setup/js/check_stop_time.test.cjs b/actions/setup/js/check_stop_time.test.cjs
index bfa82031f4..074c833aca 100644
--- a/actions/setup/js/check_stop_time.test.cjs
+++ b/actions/setup/js/check_stop_time.test.cjs
@@ -1,101 +1,141 @@
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
import fs from "fs";
import path from "path";
+
const mockCore = {
- debug: vi.fn(),
- info: vi.fn(),
- notice: vi.fn(),
- warning: vi.fn(),
- error: vi.fn(),
- setFailed: vi.fn(),
- setOutput: vi.fn(),
- exportVariable: vi.fn(),
- setSecret: vi.fn(),
- setCancelled: vi.fn(),
- setError: vi.fn(),
- getInput: vi.fn(),
- getBooleanInput: vi.fn(),
- getMultilineInput: vi.fn(),
- getState: vi.fn(),
- saveState: vi.fn(),
- startGroup: vi.fn(),
- endGroup: vi.fn(),
- group: vi.fn(),
- addPath: vi.fn(),
- setCommandEcho: vi.fn(),
- isDebug: vi.fn().mockReturnValue(!1),
- getIDToken: vi.fn(),
- toPlatformPath: vi.fn(),
- toPosixPath: vi.fn(),
- toWin32Path: vi.fn(),
- summary: { addRaw: vi.fn().mockReturnThis(), write: vi.fn().mockResolvedValue() },
- },
- mockGithub = { rest: { actions: { listRepoWorkflows: vi.fn(), disableWorkflow: vi.fn() } } },
- mockContext = { repo: { owner: "testowner", repo: "testrepo" } };
-((global.core = mockCore),
- (global.github = mockGithub),
- (global.context = mockContext),
- describe("check_stop_time.cjs", () => {
- let checkStopTimeScript, originalEnv;
- (beforeEach(() => {
- (vi.clearAllMocks(), (originalEnv = { GH_AW_STOP_TIME: process.env.GH_AW_STOP_TIME, GH_AW_WORKFLOW_NAME: process.env.GH_AW_WORKFLOW_NAME }));
- const scriptPath = path.join(process.cwd(), "check_stop_time.cjs");
- checkStopTimeScript = fs.readFileSync(scriptPath, "utf8");
- }),
- afterEach(() => {
- (void 0 !== originalEnv.GH_AW_STOP_TIME ? (process.env.GH_AW_STOP_TIME = originalEnv.GH_AW_STOP_TIME) : delete process.env.GH_AW_STOP_TIME,
- void 0 !== originalEnv.GH_AW_WORKFLOW_NAME ? (process.env.GH_AW_WORKFLOW_NAME = originalEnv.GH_AW_WORKFLOW_NAME) : delete process.env.GH_AW_WORKFLOW_NAME);
- }),
- describe("when stop time is not configured", () => {
- (it("should fail if GH_AW_STOP_TIME is not set", async () => {
- (delete process.env.GH_AW_STOP_TIME,
- (process.env.GH_AW_WORKFLOW_NAME = "test-workflow"),
- await eval(`(async () => { ${checkStopTimeScript}; await main(); })()`),
- expect(mockCore.setFailed).toHaveBeenCalledWith(expect.stringContaining("GH_AW_STOP_TIME not specified")),
- expect(mockCore.setOutput).not.toHaveBeenCalled());
- }),
- it("should fail if GH_AW_WORKFLOW_NAME is not set", async () => {
- ((process.env.GH_AW_STOP_TIME = "2025-12-31 23:59:59"),
- delete process.env.GH_AW_WORKFLOW_NAME,
- await eval(`(async () => { ${checkStopTimeScript}; await main(); })()`),
- expect(mockCore.setFailed).toHaveBeenCalledWith(expect.stringContaining("GH_AW_WORKFLOW_NAME not specified")),
- expect(mockCore.setOutput).not.toHaveBeenCalled());
- }));
- }),
- describe("when stop time format is invalid", () => {
- it("should fail with error for invalid format", async () => {
- ((process.env.GH_AW_STOP_TIME = "invalid-date"),
- (process.env.GH_AW_WORKFLOW_NAME = "test-workflow"),
- await eval(`(async () => { ${checkStopTimeScript}; await main(); })()`),
- expect(mockCore.setFailed).toHaveBeenCalledWith(expect.stringContaining("Invalid stop-time format")),
- expect(mockCore.setOutput).not.toHaveBeenCalled());
- });
- }),
- describe("when stop time is in the future", () => {
- it("should allow execution", async () => {
- const futureDate = new Date();
- futureDate.setFullYear(futureDate.getFullYear() + 1);
- const stopTime = futureDate.toISOString().replace("T", " ").substring(0, 19);
- ((process.env.GH_AW_STOP_TIME = stopTime),
- (process.env.GH_AW_WORKFLOW_NAME = "test-workflow"),
- await eval(`(async () => { ${checkStopTimeScript}; await main(); })()`),
- expect(mockCore.setOutput).toHaveBeenCalledWith("stop_time_ok", "true"),
- expect(mockCore.setFailed).not.toHaveBeenCalled());
- });
- }),
- describe("when stop time has been reached", () => {
- it("should set stop_time_ok to false without attempting to disable workflow", async () => {
- const pastDate = new Date();
- pastDate.setFullYear(pastDate.getFullYear() - 1);
- const stopTime = pastDate.toISOString().replace("T", " ").substring(0, 19);
- ((process.env.GH_AW_STOP_TIME = stopTime),
- (process.env.GH_AW_WORKFLOW_NAME = "test-workflow"),
- await eval(`(async () => { ${checkStopTimeScript}; await main(); })()`),
- expect(mockCore.warning).toHaveBeenCalledWith(expect.stringContaining("Stop time reached")),
- expect(mockGithub.rest.actions.listRepoWorkflows).not.toHaveBeenCalled(),
- expect(mockGithub.rest.actions.disableWorkflow).not.toHaveBeenCalled(),
- expect(mockCore.setOutput).toHaveBeenCalledWith("stop_time_ok", "false"),
- expect(mockCore.setFailed).not.toHaveBeenCalled());
- });
- }));
- }));
+ debug: vi.fn(),
+ info: vi.fn(),
+ notice: vi.fn(),
+ warning: vi.fn(),
+ error: vi.fn(),
+ setFailed: vi.fn(),
+ setOutput: vi.fn(),
+ exportVariable: vi.fn(),
+ setSecret: vi.fn(),
+ setCancelled: vi.fn(),
+ setError: vi.fn(),
+ getInput: vi.fn(),
+ getBooleanInput: vi.fn(),
+ getMultilineInput: vi.fn(),
+ getState: vi.fn(),
+ saveState: vi.fn(),
+ startGroup: vi.fn(),
+ endGroup: vi.fn(),
+ group: vi.fn(),
+ addPath: vi.fn(),
+ setCommandEcho: vi.fn(),
+ isDebug: vi.fn().mockReturnValue(false),
+ getIDToken: vi.fn(),
+ toPlatformPath: vi.fn(),
+ toPosixPath: vi.fn(),
+ toWin32Path: vi.fn(),
+ summary: { addRaw: vi.fn().mockReturnThis(), write: vi.fn().mockResolvedValue() },
+};
+
+const mockGithub = {
+ rest: { actions: { listRepoWorkflows: vi.fn(), disableWorkflow: vi.fn() } },
+};
+
+const mockContext = { repo: { owner: "testowner", repo: "testrepo" } };
+
+global.core = mockCore;
+global.github = mockGithub;
+global.context = mockContext;
+
+describe("check_stop_time.cjs", () => {
+ let checkStopTimeScript;
+ let originalEnv;
+
+ beforeEach(() => {
+ vi.clearAllMocks();
+ originalEnv = {
+ GH_AW_STOP_TIME: process.env.GH_AW_STOP_TIME,
+ GH_AW_WORKFLOW_NAME: process.env.GH_AW_WORKFLOW_NAME,
+ };
+ const scriptPath = path.join(process.cwd(), "check_stop_time.cjs");
+ checkStopTimeScript = fs.readFileSync(scriptPath, "utf8");
+ });
+
+ afterEach(() => {
+ if (originalEnv.GH_AW_STOP_TIME !== undefined) {
+ process.env.GH_AW_STOP_TIME = originalEnv.GH_AW_STOP_TIME;
+ } else {
+ delete process.env.GH_AW_STOP_TIME;
+ }
+
+ if (originalEnv.GH_AW_WORKFLOW_NAME !== undefined) {
+ process.env.GH_AW_WORKFLOW_NAME = originalEnv.GH_AW_WORKFLOW_NAME;
+ } else {
+ delete process.env.GH_AW_WORKFLOW_NAME;
+ }
+ });
+
+ describe("when stop time is not configured", () => {
+ it("should fail if GH_AW_STOP_TIME is not set", async () => {
+ delete process.env.GH_AW_STOP_TIME;
+ process.env.GH_AW_WORKFLOW_NAME = "test-workflow";
+
+ await eval(`(async () => { ${checkStopTimeScript}; await main(); })()`);
+
+ expect(mockCore.setFailed).toHaveBeenCalledWith(expect.stringContaining("GH_AW_STOP_TIME not specified"));
+ expect(mockCore.setOutput).not.toHaveBeenCalled();
+ });
+
+ it("should fail if GH_AW_WORKFLOW_NAME is not set", async () => {
+ process.env.GH_AW_STOP_TIME = "2025-12-31 23:59:59";
+ delete process.env.GH_AW_WORKFLOW_NAME;
+
+ await eval(`(async () => { ${checkStopTimeScript}; await main(); })()`);
+
+ expect(mockCore.setFailed).toHaveBeenCalledWith(expect.stringContaining("GH_AW_WORKFLOW_NAME not specified"));
+ expect(mockCore.setOutput).not.toHaveBeenCalled();
+ });
+ });
+
+ describe("when stop time format is invalid", () => {
+ it("should fail with error for invalid format", async () => {
+ process.env.GH_AW_STOP_TIME = "invalid-date";
+ process.env.GH_AW_WORKFLOW_NAME = "test-workflow";
+
+ await eval(`(async () => { ${checkStopTimeScript}; await main(); })()`);
+
+ expect(mockCore.setFailed).toHaveBeenCalledWith(expect.stringContaining("Invalid stop-time format"));
+ expect(mockCore.setOutput).not.toHaveBeenCalled();
+ });
+ });
+
+ describe("when stop time is in the future", () => {
+ it("should allow execution", async () => {
+ const futureDate = new Date();
+ futureDate.setFullYear(futureDate.getFullYear() + 1);
+ const stopTime = futureDate.toISOString().replace("T", " ").substring(0, 19);
+
+ process.env.GH_AW_STOP_TIME = stopTime;
+ process.env.GH_AW_WORKFLOW_NAME = "test-workflow";
+
+ await eval(`(async () => { ${checkStopTimeScript}; await main(); })()`);
+
+ expect(mockCore.setOutput).toHaveBeenCalledWith("stop_time_ok", "true");
+ expect(mockCore.setFailed).not.toHaveBeenCalled();
+ });
+ });
+
+ describe("when stop time has been reached", () => {
+ it("should set stop_time_ok to false without attempting to disable workflow", async () => {
+ const pastDate = new Date();
+ pastDate.setFullYear(pastDate.getFullYear() - 1);
+ const stopTime = pastDate.toISOString().replace("T", " ").substring(0, 19);
+
+ process.env.GH_AW_STOP_TIME = stopTime;
+ process.env.GH_AW_WORKFLOW_NAME = "test-workflow";
+
+ await eval(`(async () => { ${checkStopTimeScript}; await main(); })()`);
+
+ expect(mockCore.warning).toHaveBeenCalledWith(expect.stringContaining("Stop time reached"));
+ expect(mockGithub.rest.actions.listRepoWorkflows).not.toHaveBeenCalled();
+ expect(mockGithub.rest.actions.disableWorkflow).not.toHaveBeenCalled();
+ expect(mockCore.setOutput).toHaveBeenCalledWith("stop_time_ok", "false");
+ expect(mockCore.setFailed).not.toHaveBeenCalled();
+ });
+ });
+});