Skip to content

Commit feb50fe

Browse files
amondnetCopilot
andauthored
refactor: migrate to TypeScript with Vitest and modern tooling (#311)
* refactor: migrate to TypeScript with Vitest and modern tooling BREAKING CHANGE: @actions/github upgraded from v2 to v6 - Convert index.js to src/index.ts with strict TypeScript mode - Extract pure utility functions to src/utils.ts for testability - Add tsconfig.json with strict compiler options - Replace Jest with Vitest for faster, ESM-native testing - Add comprehensive unit tests for utility functions (43 tests) - Add integration tests for GitHub Action structure (12 tests) - Target: 80%+ code coverage - Migrate from deprecated `new github.GitHub(token)` to `github.getOctokit(token)` - Update all API calls from `octokit.repos.*` to `octokit.rest.repos.*` - Update all API calls from `octokit.issues.*` to `octokit.rest.issues.*` - Update all API calls from `octokit.git.*` to `octokit.rest.git.*` - Enable TypeScript support in @antfu/eslint-config - Replace Jest globals with Vitest globals (vi instead of jest) - Add lib/ to ignore patterns - Update ncc build to compile TypeScript directly - Add source maps and licenses to dist output - Add typecheck script for standalone type checking - Update all npm scripts for TypeScript workflow - index.js (migrated to src/index.ts) - index.test.js (migrated to src/__tests__/*.test.ts) - jest.config.js (replaced by vitest.config.ts) - now.js (unused legacy file) Closes #291 * chore: apply AI code review suggestions - Move PullRequestPayload and ReleasePayload interfaces to top of file - Use PullRequestPayload type instead of inline type assertion - Simplify parseArgs regex match logic (remove redundant fallback) * refactor: split index.ts into smaller modules - Extract types to src/types.ts - Extract config and initialization to src/config.ts - Extract Vercel functions to src/vercel.ts - Extract GitHub comment functions to src/github-comments.ts - Refactor run() into smaller focused functions (< 50 LOC each) - Add try-catch around execSync for git log with descriptive error - Add error handling for GitHub API calls - Make alias failures explicit with warning messages - Extract magic numbers to named constants (RETRY_DELAY_MS, ALIAS_RETRY_COUNT) - Use buildCommentPrefix() consistently in both comment functions All files now under 300 LOC limit, all functions under 50 LOC limit. * build: rebuild dist after refactoring * build: update vercel to v50 * fix: improve error handling in vercel deploy and comment functions - Extract and validate deployment URL from vercel CLI stdout - Wrap vercelInspect exec in try-catch to prevent action failure - Expand try-catch scope in comment functions to cover API lookups - Route stderr to core.warning for better error visibility * test: add tests for vercel, config, and github-comments modules - Add vercel.test.ts: URL extraction, inspect regex, alias retry - Add config.test.ts: alias domain substitution, env export - Add github-comments.test.ts: comment create/update, error handling - Total tests: 55 → 100 * fix: port personal account scope error handling from PR #297/#298 - Add core.setSecret for vercel token to prevent log exposure - Disable telemetry with VERCEL_TELEMETRY_DISABLED env var - Require both org and project IDs together (v41+ compat) - Auto-retry deployment on personal account scope error - Sanitize commit message newlines and quotes in metadata - Add ignoreReturnCode for proper exit code handling - Update tests for new behavior (105 total) * refactor: use DeploymentContext object in vercelDeploy signature Reduce parameter count from 6 to 2 by passing DeploymentContext object instead of individual ref, commit, sha, commitOrg, commitRepo arguments. Aligns with AGENTS.md parameter limit of 5. * fix: port alias retry without --scope for personal accounts (#310) Capture stderr in alias exec and retry without --scope when Vercel CLI rejects personal account scope, matching the deploy retry pattern. Add tests for alias scope retry, retry failure, and non-scope failures. * fix: remove declaration maps to fix check-dist CI failure Source map files (.d.ts.map) contain absolute local paths that differ between local builds and CI runners, causing check-dist to fail. Disable declarationMap in tsconfig.json since these files are not needed for GitHub Action runtime execution. * chore: apply AI code review suggestions - Implement exponential backoff in retry function (was constant delay) - Fix debug log for head_commit to use JSON.stringify - Change vercelInspect stderr logging from warning to info level - Fix retry after PERSONAL_ACCOUNT_SCOPE_ERROR to omit --scope - Bump @types/node from ^20.0.0 to ^24.0.0 to match Node 24 runtime - Add setSecret to @actions/core mock in index.test.ts - Fix mock path in config.test.ts from ../package.json to ../../package.json - Update test expectation to match mocked vercel version (30.0.0) - Remove pull_request_target from PullRequestPayload (always undefined) - Add per_page: 100 to comment listing API calls to reduce duplicate risk - Fix Node version in session-summary.md (20 → 24) * fix: make vercelScope optional to clean up retry cast in vercelDeploy Co-authored-by: amondnet <1964421+amondnet@users.noreply.github.com> Agent-Logs-Url: https://github.com/amondnet/vercel-action/sessions/16d171b4-3be8-43f8-a736-b5f3ff13deba --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: amondnet <1964421+amondnet@users.noreply.github.com>
1 parent 1043003 commit feb50fe

32 files changed

+11071
-34118
lines changed

.please/memory/session-summary.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Session Summary: TypeScript and Vitest Migration
2+
3+
## Feature Description
4+
Migrate vercel-action from JavaScript to TypeScript with modern tooling:
5+
1. Convert index.js to TypeScript (src/index.ts)
6+
2. Replace Jest with Vitest for testing
7+
3. Update @antfu/eslint-config for TypeScript support
8+
9+
## Requirements Summary
10+
- TypeScript source files in `src/` directory
11+
- Strict TypeScript mode enabled
12+
- Delete deprecated `now.js` file
13+
- Maintain backward compatibility with action inputs/outputs
14+
- Keep dist/index.js as bundled output
15+
16+
## Constraints
17+
- GitHub Action must remain functional
18+
- Node 24 runtime requirement
19+
- ncc bundling for dist/
20+
21+
## Current Phase: Codebase Exploration
22+
23+
## Key Decisions
24+
- [x] Source directory: `src/`
25+
- [x] TypeScript strict mode: enabled
26+
- [x] Delete now.js: yes
27+
28+
## Files to Modify
29+
- index.js → src/index.ts
30+
- index.test.js → src/index.test.ts
31+
- package.json (scripts, dependencies)
32+
- eslint.config.mjs (TypeScript support)
33+
- jest.config.js → vitest.config.ts
34+
- action.yml (verify dist path)
35+
- tsconfig.json (new)
36+
37+
## Progress
38+
- [x] Phase 1: Discovery - Complete
39+
- [ ] Phase 2: Codebase Exploration - In Progress

.please/memory/tasklist.json

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{
2+
"session_id": "20251212-typescript-vitest-migration",
3+
"feature_name": "TypeScript and Vitest Migration",
4+
"created_at": "2025-12-12T00:00:00Z",
5+
"updated_at": "2025-12-12T00:00:00Z",
6+
"status": "in_progress",
7+
"current_phase": 6,
8+
"issue_number": 291,
9+
"branch": "291-refactor-migrate-to-typescript-with-vitest-and-modern-tooling",
10+
"phases": [
11+
{ "number": 1, "name": "Discovery", "status": "completed", "started_at": "2025-12-12T00:00:00Z", "completed_at": "2025-12-12T00:01:00Z" },
12+
{ "number": 2, "name": "Codebase Exploration", "status": "completed", "started_at": "2025-12-12T00:01:00Z", "completed_at": "2025-12-12T00:02:00Z" },
13+
{ "number": 3, "name": "Clarifying Questions", "status": "completed", "completed_at": "2025-12-12T00:03:00Z" },
14+
{ "number": 4, "name": "Architecture Design", "status": "completed", "completed_at": "2025-12-12T00:04:00Z" },
15+
{ "number": 5, "name": "GitHub Issue & PR", "status": "completed", "completed_at": "2025-12-12T00:05:00Z" },
16+
{ "number": 6, "name": "Implementation", "status": "completed", "completed_at": "2025-12-12T00:22:00Z" },
17+
{ "number": 7, "name": "Quality Review", "status": "in_progress", "started_at": "2025-12-12T00:22:00Z" },
18+
{ "number": 8, "name": "PR Finalization", "status": "pending" }
19+
],
20+
"tasks": [
21+
{ "id": "T001", "title": "Create tsconfig.json with strict settings", "phase": 6, "status": "pending", "parallel": true, "dependencies": [] },
22+
{ "id": "T002", "title": "Update package.json (add TypeScript, Vitest; remove Jest)", "phase": 6, "status": "pending", "parallel": true, "dependencies": [] },
23+
{ "id": "T003", "title": "Update eslint.config.mjs for TypeScript + Vitest globals", "phase": 6, "status": "pending", "parallel": true, "dependencies": [] },
24+
{ "id": "T004", "title": "Create vitest.config.ts", "phase": 6, "status": "pending", "parallel": true, "dependencies": [] },
25+
{ "id": "T005", "title": "Create src/utils.ts with pure utility functions", "phase": 6, "status": "pending", "parallel": false, "dependencies": ["T001", "T002", "T003", "T004"] },
26+
{ "id": "T006", "title": "Create src/__tests__/utils.test.ts with unit tests", "phase": 6, "status": "pending", "parallel": false, "dependencies": ["T005"] },
27+
{ "id": "T007", "title": "Create src/index.ts with main action logic", "phase": 6, "status": "pending", "parallel": false, "dependencies": ["T005"] },
28+
{ "id": "T008", "title": "Upgrade @actions/github to v6 and update API calls", "phase": 6, "status": "pending", "parallel": false, "dependencies": ["T007"] },
29+
{ "id": "T009", "title": "Create src/__tests__/index.test.ts", "phase": 6, "status": "pending", "parallel": false, "dependencies": ["T007", "T008"] },
30+
{ "id": "T010", "title": "Delete old files (index.js, index.test.js, jest.config.js, now.js)", "phase": 6, "status": "pending", "parallel": false, "dependencies": ["T007", "T009"] },
31+
{ "id": "T011", "title": "Build and verify dist/index.js", "phase": 6, "status": "pending", "parallel": false, "dependencies": ["T010"] },
32+
{ "id": "T012", "title": "Run all quality checks (lint, typecheck, test)", "phase": 6, "status": "pending", "parallel": false, "dependencies": ["T011"] }
33+
],
34+
"decisions": {
35+
"source_directory": "src/",
36+
"keep_now_js": false,
37+
"typescript_strict": true,
38+
"modularize": false,
39+
"add_comprehensive_tests": true,
40+
"upgrade_github_api": true,
41+
"split_utils": true
42+
}
43+
}

dist/config.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import type { ActionConfig, OctokitClient } from './types';
2+
export declare function getActionConfig(): ActionConfig;
3+
export declare function createOctokitClient(githubToken: string): OctokitClient | undefined;
4+
export declare function setVercelEnv(config: ActionConfig): void;

dist/github-comments.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import type { ActionConfig, OctokitClient } from './types';
2+
export declare function createCommentOnCommit(octokit: OctokitClient, config: ActionConfig, deploymentCommit: string, deploymentUrl: string, deploymentName: string): Promise<void>;
3+
export declare function createCommentOnPullRequest(octokit: OctokitClient, config: ActionConfig, deploymentCommit: string, deploymentUrl: string, deploymentName: string): Promise<void>;

dist/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export {};

0 commit comments

Comments
 (0)