From 204f23755cd009a4773bed48e9327984e112da92 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Dec 2025 02:49:53 +0000 Subject: [PATCH 1/7] Initial plan From b430af04bc39da11478936fab8b0f09f719a36d5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Dec 2025 03:00:08 +0000 Subject: [PATCH 2/7] Initial plan for fixing JavaScript packaging and invocation Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/issue-classifier.lock.yml | 2 +- .github/workflows/release.lock.yml | 6 +++--- .github/workflows/stale-repo-identifier.lock.yml | 2 +- .github/workflows/super-linter.lock.yml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/issue-classifier.lock.yml b/.github/workflows/issue-classifier.lock.yml index 44eafee6c7c..02134fb672e 100644 --- a/.github/workflows/issue-classifier.lock.yml +++ b/.github/workflows/issue-classifier.lock.yml @@ -2204,7 +2204,7 @@ jobs: path: /tmp/gh-aw/aw_info.json if-no-files-found: warn - name: Run AI Inference - uses: actions/ai-inference@334892bb203895caaed82ec52d23c1ed9385151e # v2.0.4 + uses: actions/ai-inference@334892bb203895caaed82ec52d23c1ed9385151e # v1 env: GH_AW_MCP_CONFIG: /tmp/gh-aw/mcp-config/mcp-servers.json GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt diff --git a/.github/workflows/release.lock.yml b/.github/workflows/release.lock.yml index 658d3b9a1d0..0be3614def2 100644 --- a/.github/workflows/release.lock.yml +++ b/.github/workflows/release.lock.yml @@ -6017,13 +6017,13 @@ jobs: - name: Download Go modules run: go mod download - name: Generate SBOM (SPDX format) - uses: anchore/sbom-action@43a17d6e7add2b5535efe4dcae9952337c479a93 # v0.20.11 + uses: anchore/sbom-action@43a17d6e7add2b5535efe4dcae9952337c479a93 # v0.20.10 with: artifact-name: sbom.spdx.json format: spdx-json output-file: sbom.spdx.json - name: Generate SBOM (CycloneDX format) - uses: anchore/sbom-action@43a17d6e7add2b5535efe4dcae9952337c479a93 # v0.20.11 + uses: anchore/sbom-action@43a17d6e7add2b5535efe4dcae9952337c479a93 # v0.20.10 with: artifact-name: sbom.cdx.json format: cyclonedx-json @@ -6227,7 +6227,7 @@ jobs: fetch-depth: 0 persist-credentials: false - name: Release with gh-extension-precompile - uses: cli/gh-extension-precompile@9e2237c30f869ad3bcaed6a4be2cd43564dd421b # v2.1.0 + uses: cli/gh-extension-precompile@9e2237c30f869ad3bcaed6a4be2cd43564dd421b # v2 with: build_script_override: scripts/build-release.sh go_version_file: go.mod diff --git a/.github/workflows/stale-repo-identifier.lock.yml b/.github/workflows/stale-repo-identifier.lock.yml index 144161022a3..eee179e885b 100644 --- a/.github/workflows/stale-repo-identifier.lock.yml +++ b/.github/workflows/stale-repo-identifier.lock.yml @@ -174,7 +174,7 @@ jobs: ORGANIZATION: ${{ env.ORGANIZATION }} id: stale-repos name: Run stale_repos tool - uses: github/stale-repos@a21e55567b83cf3c3f3f9085d3038dc6cee02598 # v3.0.2 + uses: github/stale-repos@a21e55567b83cf3c3f3f9085d3038dc6cee02598 # v3 - env: INACTIVE_REPOS: ${{ steps.stale-repos.outputs.inactiveRepos }} name: Save stale repos output diff --git a/.github/workflows/super-linter.lock.yml b/.github/workflows/super-linter.lock.yml index 52078342001..4d0e7e71fe1 100644 --- a/.github/workflows/super-linter.lock.yml +++ b/.github/workflows/super-linter.lock.yml @@ -6146,7 +6146,7 @@ jobs: persist-credentials: false - name: Super-linter id: super-linter - uses: super-linter/super-linter@47984f49b4e87383eed97890fe2dca6063bbd9c3 # v8.3.1 + uses: super-linter/super-linter@47984f49b4e87383eed97890fe2dca6063bbd9c3 # v8.2.1 env: CREATE_LOG_FILE: "true" DEFAULT_BRANCH: main From d439115d154a04987013396188b9540e7dff56e4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Dec 2025 03:05:05 +0000 Subject: [PATCH 3/7] Fix changeset.js to export main and use await in inline execution Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/issue-classifier.lock.yml | 2 +- .github/workflows/release.lock.yml | 6 +++--- .github/workflows/stale-repo-identifier.lock.yml | 2 +- .github/workflows/super-linter.lock.yml | 2 +- scripts/changeset.js | 10 +++++++++- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/.github/workflows/issue-classifier.lock.yml b/.github/workflows/issue-classifier.lock.yml index 02134fb672e..44eafee6c7c 100644 --- a/.github/workflows/issue-classifier.lock.yml +++ b/.github/workflows/issue-classifier.lock.yml @@ -2204,7 +2204,7 @@ jobs: path: /tmp/gh-aw/aw_info.json if-no-files-found: warn - name: Run AI Inference - uses: actions/ai-inference@334892bb203895caaed82ec52d23c1ed9385151e # v1 + uses: actions/ai-inference@334892bb203895caaed82ec52d23c1ed9385151e # v2.0.4 env: GH_AW_MCP_CONFIG: /tmp/gh-aw/mcp-config/mcp-servers.json GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt diff --git a/.github/workflows/release.lock.yml b/.github/workflows/release.lock.yml index 0be3614def2..658d3b9a1d0 100644 --- a/.github/workflows/release.lock.yml +++ b/.github/workflows/release.lock.yml @@ -6017,13 +6017,13 @@ jobs: - name: Download Go modules run: go mod download - name: Generate SBOM (SPDX format) - uses: anchore/sbom-action@43a17d6e7add2b5535efe4dcae9952337c479a93 # v0.20.10 + uses: anchore/sbom-action@43a17d6e7add2b5535efe4dcae9952337c479a93 # v0.20.11 with: artifact-name: sbom.spdx.json format: spdx-json output-file: sbom.spdx.json - name: Generate SBOM (CycloneDX format) - uses: anchore/sbom-action@43a17d6e7add2b5535efe4dcae9952337c479a93 # v0.20.10 + uses: anchore/sbom-action@43a17d6e7add2b5535efe4dcae9952337c479a93 # v0.20.11 with: artifact-name: sbom.cdx.json format: cyclonedx-json @@ -6227,7 +6227,7 @@ jobs: fetch-depth: 0 persist-credentials: false - name: Release with gh-extension-precompile - uses: cli/gh-extension-precompile@9e2237c30f869ad3bcaed6a4be2cd43564dd421b # v2 + uses: cli/gh-extension-precompile@9e2237c30f869ad3bcaed6a4be2cd43564dd421b # v2.1.0 with: build_script_override: scripts/build-release.sh go_version_file: go.mod diff --git a/.github/workflows/stale-repo-identifier.lock.yml b/.github/workflows/stale-repo-identifier.lock.yml index eee179e885b..144161022a3 100644 --- a/.github/workflows/stale-repo-identifier.lock.yml +++ b/.github/workflows/stale-repo-identifier.lock.yml @@ -174,7 +174,7 @@ jobs: ORGANIZATION: ${{ env.ORGANIZATION }} id: stale-repos name: Run stale_repos tool - uses: github/stale-repos@a21e55567b83cf3c3f3f9085d3038dc6cee02598 # v3 + uses: github/stale-repos@a21e55567b83cf3c3f3f9085d3038dc6cee02598 # v3.0.2 - env: INACTIVE_REPOS: ${{ steps.stale-repos.outputs.inactiveRepos }} name: Save stale repos output diff --git a/.github/workflows/super-linter.lock.yml b/.github/workflows/super-linter.lock.yml index 4d0e7e71fe1..52078342001 100644 --- a/.github/workflows/super-linter.lock.yml +++ b/.github/workflows/super-linter.lock.yml @@ -6146,7 +6146,7 @@ jobs: persist-credentials: false - name: Super-linter id: super-linter - uses: super-linter/super-linter@47984f49b4e87383eed97890fe2dca6063bbd9c3 # v8.2.1 + uses: super-linter/super-linter@47984f49b4e87383eed97890fe2dca6063bbd9c3 # v8.3.1 env: CREATE_LOG_FILE: "true" DEFAULT_BRANCH: main diff --git a/scripts/changeset.js b/scripts/changeset.js index 5461c029145..a41854255ac 100755 --- a/scripts/changeset.js +++ b/scripts/changeset.js @@ -732,4 +732,12 @@ async function main() { } } -main(); +// Export main for use as a module +module.exports = { main }; + +// If run directly, execute main +if (require.main === module) { + (async () => { + await main(); + })(); +} From 0c44fba3f842c6f43611d3460e3443f6afdec23a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Dec 2025 03:20:42 +0000 Subject: [PATCH 4/7] Add validation test to ensure scripts export main when required Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/issue-classifier.lock.yml | 2 +- .github/workflows/release.lock.yml | 6 +- .../workflows/stale-repo-identifier.lock.yml | 2 +- .github/workflows/super-linter.lock.yml | 2 +- pkg/workflow/main_export_validation_test.go | 102 ++++++++++++++++++ 5 files changed, 108 insertions(+), 6 deletions(-) create mode 100644 pkg/workflow/main_export_validation_test.go diff --git a/.github/workflows/issue-classifier.lock.yml b/.github/workflows/issue-classifier.lock.yml index 44eafee6c7c..02134fb672e 100644 --- a/.github/workflows/issue-classifier.lock.yml +++ b/.github/workflows/issue-classifier.lock.yml @@ -2204,7 +2204,7 @@ jobs: path: /tmp/gh-aw/aw_info.json if-no-files-found: warn - name: Run AI Inference - uses: actions/ai-inference@334892bb203895caaed82ec52d23c1ed9385151e # v2.0.4 + uses: actions/ai-inference@334892bb203895caaed82ec52d23c1ed9385151e # v1 env: GH_AW_MCP_CONFIG: /tmp/gh-aw/mcp-config/mcp-servers.json GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt diff --git a/.github/workflows/release.lock.yml b/.github/workflows/release.lock.yml index 658d3b9a1d0..0be3614def2 100644 --- a/.github/workflows/release.lock.yml +++ b/.github/workflows/release.lock.yml @@ -6017,13 +6017,13 @@ jobs: - name: Download Go modules run: go mod download - name: Generate SBOM (SPDX format) - uses: anchore/sbom-action@43a17d6e7add2b5535efe4dcae9952337c479a93 # v0.20.11 + uses: anchore/sbom-action@43a17d6e7add2b5535efe4dcae9952337c479a93 # v0.20.10 with: artifact-name: sbom.spdx.json format: spdx-json output-file: sbom.spdx.json - name: Generate SBOM (CycloneDX format) - uses: anchore/sbom-action@43a17d6e7add2b5535efe4dcae9952337c479a93 # v0.20.11 + uses: anchore/sbom-action@43a17d6e7add2b5535efe4dcae9952337c479a93 # v0.20.10 with: artifact-name: sbom.cdx.json format: cyclonedx-json @@ -6227,7 +6227,7 @@ jobs: fetch-depth: 0 persist-credentials: false - name: Release with gh-extension-precompile - uses: cli/gh-extension-precompile@9e2237c30f869ad3bcaed6a4be2cd43564dd421b # v2.1.0 + uses: cli/gh-extension-precompile@9e2237c30f869ad3bcaed6a4be2cd43564dd421b # v2 with: build_script_override: scripts/build-release.sh go_version_file: go.mod diff --git a/.github/workflows/stale-repo-identifier.lock.yml b/.github/workflows/stale-repo-identifier.lock.yml index 144161022a3..eee179e885b 100644 --- a/.github/workflows/stale-repo-identifier.lock.yml +++ b/.github/workflows/stale-repo-identifier.lock.yml @@ -174,7 +174,7 @@ jobs: ORGANIZATION: ${{ env.ORGANIZATION }} id: stale-repos name: Run stale_repos tool - uses: github/stale-repos@a21e55567b83cf3c3f3f9085d3038dc6cee02598 # v3.0.2 + uses: github/stale-repos@a21e55567b83cf3c3f3f9085d3038dc6cee02598 # v3 - env: INACTIVE_REPOS: ${{ steps.stale-repos.outputs.inactiveRepos }} name: Save stale repos output diff --git a/.github/workflows/super-linter.lock.yml b/.github/workflows/super-linter.lock.yml index 52078342001..4d0e7e71fe1 100644 --- a/.github/workflows/super-linter.lock.yml +++ b/.github/workflows/super-linter.lock.yml @@ -6146,7 +6146,7 @@ jobs: persist-credentials: false - name: Super-linter id: super-linter - uses: super-linter/super-linter@47984f49b4e87383eed97890fe2dca6063bbd9c3 # v8.3.1 + uses: super-linter/super-linter@47984f49b4e87383eed97890fe2dca6063bbd9c3 # v8.2.1 env: CREATE_LOG_FILE: "true" DEFAULT_BRANCH: main diff --git a/pkg/workflow/main_export_validation_test.go b/pkg/workflow/main_export_validation_test.go new file mode 100644 index 00000000000..6f569bc65e9 --- /dev/null +++ b/pkg/workflow/main_export_validation_test.go @@ -0,0 +1,102 @@ +package workflow + +import ( + "os" + "path/filepath" + "regexp" + "strings" + "testing" +) + +// TestScriptsExportMain validates that all JavaScript files that are required +// with `const { main } = require(...)` actually export a main function. +// This prevents runtime errors where code tries to destructure main from +// a module that doesn't export it. +func TestScriptsExportMain(t *testing.T) { + // List of scripts that should export main based on compiler usage + // These are extracted from places where Go code generates: + // const { main } = require('...') + requiredMainExports := []string{ + "check_stop_time.cjs", + "check_skip_if_match.cjs", + "check_command_position.cjs", + "check_workflow_timestamp_api.cjs", + "compute_text.cjs", + "add_reaction_and_edit_comment.cjs", + "lock-issue.cjs", + "unlock-issue.cjs", + "checkout_pr_branch.cjs", + } + + jsDir := "js" + + // Pattern to match: module.exports = { main }; or module.exports = { main, ... }; + mainExportPattern := regexp.MustCompile(`module\.exports\s*=\s*\{[^}]*\bmain\b[^}]*\}`) + + for _, scriptName := range requiredMainExports { + t.Run(scriptName, func(t *testing.T) { + scriptPath := filepath.Join(jsDir, scriptName) + content, err := os.ReadFile(scriptPath) + if err != nil { + t.Fatalf("Failed to read %s: %v", scriptPath, err) + } + + scriptContent := string(content) + + // Check if the script exports main + if !mainExportPattern.MatchString(scriptContent) { + t.Errorf("Script %s is required with 'const { main } = require(...)' but does not export main.\n"+ + "Add 'module.exports = { main };' to the script.", scriptName) + } + + // Also verify that an async function main exists + if !strings.Contains(scriptContent, "async function main()") && + !strings.Contains(scriptContent, "async function main ()") && + !strings.Contains(scriptContent, "function main()") && + !strings.Contains(scriptContent, "function main ()") { + t.Errorf("Script %s exports main but does not define a main function", scriptName) + } + }) + } +} + +// TestScriptsWithMainExportPattern checks that scripts exporting main +// follow the correct pattern and include the require.main check for direct execution +func TestScriptsWithMainExportPattern(t *testing.T) { + jsDir := "js" + + // Pattern to match: module.exports = { main } + mainExportPattern := regexp.MustCompile(`module\.exports\s*=\s*\{[^}]*\bmain\b[^}]*\}`) + + // Pattern to check for require.main === module check + requireMainPattern := regexp.MustCompile(`require\.main\s*===\s*module`) + + entries, err := os.ReadDir(jsDir) + if err != nil { + t.Fatalf("Failed to read js directory: %v", err) + } + + for _, entry := range entries { + if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".cjs") { + continue + } + + scriptPath := filepath.Join(jsDir, entry.Name()) + content, err := os.ReadFile(scriptPath) + if err != nil { + continue // Skip files we can't read + } + + scriptContent := string(content) + + // If script exports main, it should have proper execution guard + if mainExportPattern.MatchString(scriptContent) { + t.Run(entry.Name()+"_has_execution_guard", func(t *testing.T) { + if !requireMainPattern.MatchString(scriptContent) { + t.Logf("Script %s exports main but lacks 'if (require.main === module)' guard for direct execution.\n"+ + "This is acceptable if the script is only meant to be used as a module.", entry.Name()) + } + }) + } + } +} From f2601f33aed8e306a6e01b2223aa94b7776b5705 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Dec 2025 03:44:18 +0000 Subject: [PATCH 5/7] Remove require.main check and use unconditional async IIFE execution Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- scripts/changeset.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/scripts/changeset.js b/scripts/changeset.js index a41854255ac..d0b31d1323b 100755 --- a/scripts/changeset.js +++ b/scripts/changeset.js @@ -735,9 +735,7 @@ async function main() { // Export main for use as a module module.exports = { main }; -// If run directly, execute main -if (require.main === module) { - (async () => { - await main(); - })(); -} +// Execute main +(async () => { + await main(); +})(); From ebfd7c45007a1d7bf72a6487bc27bb0627e78edf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Dec 2025 03:53:11 +0000 Subject: [PATCH 6/7] Revert to original pattern: remove export and call main directly Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- scripts/changeset.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/scripts/changeset.js b/scripts/changeset.js index d0b31d1323b..5461c029145 100755 --- a/scripts/changeset.js +++ b/scripts/changeset.js @@ -732,10 +732,4 @@ async function main() { } } -// Export main for use as a module -module.exports = { main }; - -// Execute main -(async () => { - await main(); -})(); +main(); From 579ef5749500af8ac0366231fbcb84574e8a7db4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Dec 2025 04:06:40 +0000 Subject: [PATCH 7/7] Export main without calling it, update test to invoke via require Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- scripts/changeset.js | 2 +- scripts/changeset.test.js | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/changeset.js b/scripts/changeset.js index 5461c029145..5e6d541d52f 100755 --- a/scripts/changeset.js +++ b/scripts/changeset.js @@ -732,4 +732,4 @@ async function main() { } } -main(); +module.exports = { main }; diff --git a/scripts/changeset.test.js b/scripts/changeset.test.js index a39febd8572..27c6fe4307c 100755 --- a/scripts/changeset.test.js +++ b/scripts/changeset.test.js @@ -77,8 +77,9 @@ function runChangesetVersion() { execSync('git config user.email "test@example.com"', { cwd: TEST_DIR, stdio: 'ignore' }); execSync('git config user.name "Test User"', { cwd: TEST_DIR, stdio: 'ignore' }); - // Run version command - const output = execSync(`node "${CHANGESET_SCRIPT}" version`, { + // Run version command by requiring and calling main + // Need to set up process.argv properly: [node, scriptname, command, ...] + const output = execSync(`node -e "process.argv.splice(1, 0, 'changeset.js', 'version'); const {main} = require('${CHANGESET_SCRIPT}'); main().catch(console.error);"`, { cwd: TEST_DIR, encoding: 'utf8', env: { ...process.env, GH_AW_CURRENT_VERSION: 'v0.1.0' }