Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .please/docs/tracks/active/use-actions-exec-20260329/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"track_id": "use-actions-exec-20260329",
"type": "refactor",
"status": "in_progress",
"created_at": "2026-03-29T16:37:09+09:00",
"updated_at": "2026-03-29T16:42:00+09:00",
"issue": "#317",
"pr": "",
"project": ""
}
89 changes: 89 additions & 0 deletions .please/docs/tracks/active/use-actions-exec-20260329/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Plan: Replace execSync with @actions/exec

> Track: use-actions-exec-20260329
> Spec: [spec.md](./spec.md)

## Overview

- **Source**: [spec.md](./spec.md)
- **Issue**: #317
- **Created**: 2026-03-29
- **Approach**: Minimal Change

## Purpose

After this change, all command execution in the codebase will use `@actions/exec` consistently, eliminating the `node:child_process` dependency from production code. This improves maintainability and leverages the toolkit's built-in logging.

## Context

The `getGitCommitMessage()` function in `src/index.ts` uses `execSync` from `node:child_process` to run `git log -1 --pretty=format:%B`. Every other command execution in the codebase uses `@actions/exec` (specifically in `src/vercel-cli.ts`). This inconsistency is unnecessary since `@actions/exec@1.1.1` provides `getExecOutput()` which returns `{ exitCode, stdout, stderr }` — a direct async replacement for `execSync`.

The function is called once, inside the already-async `getDeploymentContext()`, so converting to async has minimal ripple effect. The test file already mocks both `@actions/exec` and `node:child_process`, so the test changes involve removing the `child_process` mock and adding a `getExecOutput` mock.

Constraints: No behavior change. Error messages must remain identical.

## Architecture Decision

Replace `execSync(cmd).toString().trim()` with `await exec.getExecOutput(cmd, args).stdout.trim()`. This is the only viable approach — `@actions/exec` is already a dependency and `getExecOutput` is the exact API designed for capturing command output. No alternative approaches considered as this is a straightforward 1:1 replacement.

## Tasks

- [x] T001 Replace execSync with getExecOutput in getGitCommitMessage (file: src/index.ts)
- [x] T002 Update test mocks for @actions/exec.getExecOutput (file: src/__tests__/index.test.ts, depends on T001)

## Progress

- [x] (2026-03-29 16:55 KST) T001 Replace execSync with getExecOutput in getGitCommitMessage
Evidence: `pnpm test` → 117 tests passed, `grep child_process src/` → no matches
- [x] (2026-03-29 16:55 KST) T002 Update test mocks for @actions/exec.getExecOutput
Evidence: `pnpm test` → 117 tests passed, `pnpm run lint` → 0 errors

## Key Files

### Modify
- `src/index.ts` — Replace `execSync` import and `getGitCommitMessage()` implementation
- `src/__tests__/index.test.ts` — Remove `node:child_process` mock, add `getExecOutput` to `@actions/exec` mock

### Reuse (reference)
- `src/vercel-cli.ts` — Reference for existing `@actions/exec` usage patterns
- `node_modules/.pnpm/@actions+exec@1.1.1/node_modules/@actions/exec/lib/exec.d.ts` — `getExecOutput` API signature

## Verification

### Automated Tests
- [ ] All existing tests pass (`pnpm test`)
- [ ] No `node:child_process` imports in `src/index.ts`

### Observable Outcomes
- Running `grep -r 'child_process' src/` returns no matches in production code
- Running `pnpm test` shows all tests passing
- Running `pnpm run build` succeeds without errors

### Acceptance Criteria Check
- [ ] SC-1: No `node:child_process` imports in production source
- [ ] SC-2: All existing tests pass
- [ ] SC-3: `getGitCommitMessage()` produces identical output
- [ ] SC-4: Error handling preserves same error message format

## Outcomes & Retrospective

### What Was Shipped
Replaced `execSync` from `node:child_process` with `@actions/exec.getExecOutput()` in `getGitCommitMessage()`, making all command execution consistent across the codebase.

### What Went Well
- Minimal change scope — only 2 files modified with net reduction in code
- `getExecOutput` was already available in the installed version (1.1.1)
- Caller was already async, so no ripple effects
- Clean review with zero issues

### What Could Improve
- Nothing notable — this was a well-scoped refactor

### Tech Debt Created
- None

## Decision Log

- Decision: Use `getExecOutput` over manual `exec` with listeners
Rationale: `getExecOutput` is the official API for capturing stdout/stderr, simpler than wiring up listeners (as done in vercel-cli.ts)
Date/Author: 2026-03-29 / Claude
32 changes: 32 additions & 0 deletions .please/docs/tracks/active/use-actions-exec-20260329/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Replace execSync with @actions/exec

> Track: use-actions-exec-20260329

## Overview

Replace the `execSync` call from `node:child_process` in `src/index.ts` with `@actions/exec` from the GitHub Actions toolkit. This aligns all command execution in the codebase to use the same library, improving consistency and leveraging the toolkit's built-in logging and error handling.

## Scope

- Replace `execSync('git log -1 --pretty=format:%B')` in `getGitCommitMessage()` with async `@actions/exec.getExecOutput()`
- Convert `getGitCommitMessage()` from sync to async
- Remove `import { execSync } from 'node:child_process'` from `src/index.ts`
- Update all callers of `getGitCommitMessage()` to await the result

## Success Criteria

- [ ] SC-1: No `node:child_process` imports remain in production source code
- [ ] SC-2: All existing tests pass without modification (or with minimal test updates for async signature)
- [ ] SC-3: `getGitCommitMessage()` produces identical output as before
- [ ] SC-4: Error handling preserves the same error message format

## Constraints

- No external behavior change — deployment output, PR comments, and error messages must remain identical
- `@actions/exec` is already a dependency; no new dependencies required

## Out of Scope

- Refactoring exec patterns in `src/vercel-cli.ts` (already uses `@actions/exec`)
- Adding new features or changing command execution logic
- Modifying the Vercel CLI invocation patterns
1 change: 1 addition & 0 deletions .please/docs/tracks/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
| [emulate-integration-test-20260326](active/emulate-integration-test-20260326/) | Integration Tests with emulate.dev | feature | — | 2026-03-26 | in_progress |
| [improve-github-comment-20260329](active/improve-github-comment-20260329/) | Improve GitHub Deployment Comments | feature | #319 | 2026-03-29 | in_progress |
| [github-deployment-20260329](active/github-deployment-20260329/) | GitHub Deployment Integration | feature | #321 | 2026-03-29 | in_progress |
| [use-actions-exec-20260329](active/use-actions-exec-20260329/) | Replace execSync with @actions/exec | refactor | #317 | 2026-03-29 | in_progress |

## Recently Completed

Expand Down
26 changes: 13 additions & 13 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32068,24 +32068,32 @@ var __importStar = (this && this.__importStar) || (function () {
};
})();
Object.defineProperty(exports, "__esModule", ({ value: true }));
const node_child_process_1 = __nccwpck_require__(7718);
const core = __importStar(__nccwpck_require__(1078));
const exec = __importStar(__nccwpck_require__(1757));
const github = __importStar(__nccwpck_require__(9848));
const config_1 = __nccwpck_require__(7296);
const github_comments_1 = __nccwpck_require__(4019);
const github_deployment_1 = __nccwpck_require__(1859);
const utils_1 = __nccwpck_require__(3924);
const vercel_1 = __nccwpck_require__(3597);
const { context } = github;
function getGitCommitMessage() {
async function getGitCommitMessage() {
let result;
try {
return (0, node_child_process_1.execSync)('git log -1 --pretty=format:%B').toString().trim();
result = await exec.getExecOutput('git', ['log', '-1', '--pretty=format:%B'], { silent: true, ignoreReturnCode: true });
}
catch (error) {
const message = error instanceof Error ? error.message : String(error);
throw new Error(`Failed to retrieve git commit message: ${message}. `
+ 'Ensure this action runs in a git repository with at least one commit.');
}
if (result.exitCode !== 0) {
const detail = result.stderr.trim()
|| `git exited with code ${result.exitCode}`;
throw new Error(`Failed to retrieve git commit message: ${detail}. `
+ 'Ensure this action runs in a git repository with at least one commit.');
}
return result.stdout.trim();
}
function logContextDebug() {
core.debug(`action : ${context.action}`);
Expand Down Expand Up @@ -32152,7 +32160,7 @@ async function getDeploymentContext(octokit) {
const baseContext = {
ref: context.ref,
sha: context.sha,
commit: getGitCommitMessage(),
commit: await getGitCommitMessage(),
commitOrg: context.repo.owner,
commitRepo: context.repo.repo,
};
Expand Down Expand Up @@ -32888,14 +32896,6 @@ module.exports = require("net");

/***/ }),

/***/ 7718:
/***/ ((module) => {

"use strict";
module.exports = require("node:child_process");

/***/ }),

/***/ 6005:
/***/ ((module) => {

Expand Down Expand Up @@ -34669,7 +34669,7 @@ module.exports = parseParams
/***/ ((module) => {

"use strict";
module.exports = JSON.parse('{"name":"vercel-action","version":"42.1.0","private":true,"packageManager":"pnpm@10.15.0","author":{"name":"Minsu Lee","email":"amond@amond.net","url":"https://amond.dev"},"license":"MIT","repository":{"type":"git","url":"https://github.com/amondnet/vercel-action"},"keywords":["GitHub","Actions","Vercel","Zeit","Now"],"main":"dist/index.js","engines":{"node":"24.x"},"scripts":{"lint":"eslint .","lint:fix":"eslint . --fix","typecheck":"tsc --noEmit","start":"node ./dist/index.js","build":"ncc build src/index.ts -o dist --source-map --license licenses.txt","test":"vitest run","test:unit":"vitest run --project unit","test:integration":"vitest run --project integration","test:watch":"vitest","test:coverage":"vitest run --coverage","all":"pnpm lint && pnpm typecheck && pnpm build && pnpm test","prepare":"husky"},"dependencies":{"@actions/core":"^1.10.0","@actions/exec":"^1.0.3","@actions/github":"^6.0.0","@actions/http-client":"^4.0.0","@octokit/webhooks":"latest","axios":"^1.6.8","common-tags":"^1.8.0","vercel":"^50.0.0"},"devDependencies":{"@antfu/eslint-config":"^3.0.0","@commitlint/cli":"^19.8.1","@commitlint/config-conventional":"^19.8.1","@octokit/rest":"^22.0.1","@types/common-tags":"^1.8.4","@types/node":"^24.0.0","@vercel/ncc":"^0.36.0","@vitest/coverage-v8":"^3.0.0","emulate":"^0.2.0","eslint":"^9.9.0","husky":"^9.1.7","typescript":"^5.7.0","vitest":"^3.0.0","yaml":"^2.8.3"}}');
module.exports = JSON.parse('{"name":"vercel-action","version":"42.1.0","private":true,"packageManager":"pnpm@10.15.0","author":{"name":"Minsu Lee","email":"amond@amond.net","url":"https://amond.dev"},"license":"MIT","repository":{"type":"git","url":"https://github.com/amondnet/vercel-action"},"keywords":["GitHub","Actions","Vercel","Zeit","Now"],"main":"dist/index.js","engines":{"node":"24.x"},"scripts":{"lint":"eslint .","lint:fix":"eslint . --fix","typecheck":"tsc --noEmit","start":"node ./dist/index.js","build":"ncc build src/index.ts -o dist --source-map --license licenses.txt --transpile-only","test":"vitest run","test:unit":"vitest run --project unit","test:integration":"vitest run --project integration","test:watch":"vitest","test:coverage":"vitest run --coverage","all":"pnpm lint && pnpm typecheck && pnpm build && pnpm test","prepare":"husky"},"dependencies":{"@actions/core":"^1.10.0","@actions/exec":"^1.0.3","@actions/github":"^6.0.0","@actions/http-client":"^4.0.0","@octokit/webhooks":"latest","axios":"^1.6.8","common-tags":"^1.8.0","vercel":"^50.0.0"},"devDependencies":{"@antfu/eslint-config":"^3.0.0","@commitlint/cli":"^19.8.1","@commitlint/config-conventional":"^19.8.1","@octokit/rest":"^22.0.1","@types/common-tags":"^1.8.4","@types/node":"^24.0.0","@vercel/ncc":"^0.36.0","@vitest/coverage-v8":"^3.0.0","emulate":"^0.2.0","eslint":"^9.9.0","husky":"^9.1.7","typescript":"^5.7.0","vitest":"^3.0.0","yaml":"^2.8.3"}}');

/***/ })

Expand Down
2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

Loading
Loading