faf-taf-git 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.faf +126 -0
- package/.faf-dna +95 -0
- package/.fafignore +41 -0
- package/.taf +21 -0
- package/CHANGELOG.md +208 -0
- package/CLAUDE.md +30 -0
- package/CONTRIBUTING.md +286 -0
- package/LICENSE +21 -0
- package/README.md +496 -0
- package/action.yml +42 -0
- package/dist/bundle/index.js +36554 -0
- package/dist/cli.d.ts +31 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +380 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +36560 -0
- package/dist/index.js.map +1 -0
- package/dist/licenses.txt +148 -0
- package/dist/main.d.ts +7 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +147 -0
- package/dist/main.js.map +1 -0
- package/dist/parsers/jest.d.ts +38 -0
- package/dist/parsers/jest.d.ts.map +1 -0
- package/dist/parsers/jest.js +87 -0
- package/dist/parsers/jest.js.map +1 -0
- package/dist/sourcemap-register.js +1 -0
- package/dist/taf-core.d.ts +12 -0
- package/dist/taf-core.d.ts.map +1 -0
- package/dist/taf-core.js +136 -0
- package/dist/taf-core.js.map +1 -0
- package/docs/RELEASE-NOTES.md +200 -0
- package/docs/USER-GUIDE.md +301 -0
- package/jest.config.js +13 -0
- package/package.json +47 -0
- package/project.faf +259 -0
- package/src/cli.ts +393 -0
- package/src/index.ts +131 -0
- package/src/parsers/jest.ts +104 -0
- package/src/taf-core.ts +139 -0
- package/test-mcp.ts +83 -0
- package/test-standalone.ts +87 -0
- package/tests/jest-parser.test.ts +122 -0
- package/tests/wjttc-taf.test.ts +470 -0
- package/tsconfig.json +18 -0
package/project.faf
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
faf_version: 2.5.0
|
|
2
|
+
ai_scoring_system: 2025-09-20
|
|
3
|
+
ai_score: 65%
|
|
4
|
+
ai_confidence: MODERATE
|
|
5
|
+
ai_value: 30_seconds_replaces_20_minutes_of_questions
|
|
6
|
+
ai_tldr:
|
|
7
|
+
project: faf-taf-git v2.0.4 - Git-tracked testing timelines for ANY CI/CD
|
|
8
|
+
stack: TypeScript CLI + GitHub Action (pre-capture architecture)
|
|
9
|
+
quality_bar: ZERO_ERRORS_F1_STANDARDS
|
|
10
|
+
status: PRODUCTION_READY (working in faf-cli repo)
|
|
11
|
+
breakthrough: v2.0.0 pre-capture pattern (tested 19 methods before this)
|
|
12
|
+
current_focus: Ecosystem adoption and user onboarding
|
|
13
|
+
your_role: Support users, fix bugs, add test framework support
|
|
14
|
+
instant_context:
|
|
15
|
+
what_building: Platform-agnostic CLI + GitHub Action for TAF updates
|
|
16
|
+
tech_stack: TypeScript
|
|
17
|
+
main_language: TypeScript
|
|
18
|
+
deployment: npm + GitHub Actions Marketplace
|
|
19
|
+
architecture: v2.0.0 pre-capture pattern (separate test execution from receipt generation)
|
|
20
|
+
use_cases: Standalone CLI, GitHub Action, GitLab CI, Jenkins, CircleCI, Local
|
|
21
|
+
development
|
|
22
|
+
test_support: Jest (fully supported) with plans for Mocha, Vitest, Pytest, Go
|
|
23
|
+
test, Rust cargo
|
|
24
|
+
golden_triangle: .faf (project DNA) + repo (code) + .taf (test proof)
|
|
25
|
+
key_files:
|
|
26
|
+
- src/index.ts (v2.0.0 rewrite - reads test output file)
|
|
27
|
+
- src/parsers/jest.ts (v2.0.4 fix - correct pattern matching)
|
|
28
|
+
- src/taf-core.ts (MCP-portable core)
|
|
29
|
+
- action.yml (v2.0.2 fix - correct bundle path)
|
|
30
|
+
- README.md (6Ws format)
|
|
31
|
+
- CHANGELOG.md (22 versions documented)
|
|
32
|
+
documentation:
|
|
33
|
+
- README: 6Ws format (What/Who/Why/Where/When/How)
|
|
34
|
+
- CHANGELOG: Complete debugging journey (v1.0.4 โ v2.0.4)
|
|
35
|
+
- Migration guide: v1.x โ v2.x breaking changes
|
|
36
|
+
context_quality:
|
|
37
|
+
slots_filled: 11/21 (52%)
|
|
38
|
+
ai_confidence: MODERATE
|
|
39
|
+
handoff_ready: true
|
|
40
|
+
missing_context: []
|
|
41
|
+
project:
|
|
42
|
+
name: faf-taf-git
|
|
43
|
+
goal: Platform-agnostic TAF (Testing Activity Feed) updater - works in ANY CI/CD
|
|
44
|
+
innovation: On-the-fly Testing Audit Files - Unheard of in CI/CD
|
|
45
|
+
taf_meaning:
|
|
46
|
+
file: Testing Audit File (.taf)
|
|
47
|
+
feed: Testing Activity Feed (live updates)
|
|
48
|
+
main_language: TypeScript
|
|
49
|
+
type: typescript
|
|
50
|
+
generated: 2025-10-28T01:26:05.656Z
|
|
51
|
+
repository: https://github.com/Wolfe-Jam/faf-taf-git
|
|
52
|
+
license: MIT
|
|
53
|
+
author: wolfejam
|
|
54
|
+
keywords: testing, taf, ci-cd, github-actions, gitlab-ci, platform-agnostic,
|
|
55
|
+
jest, faf, git
|
|
56
|
+
mission: ๐ Make Your AI Happy! ๐งก Trust-Driven ๐ค
|
|
57
|
+
revolution: 30 seconds replaces 20 minutes of questions
|
|
58
|
+
brand: F1-Inspired Software Engineering - Championship AI Context
|
|
59
|
+
ai_instructions:
|
|
60
|
+
priority_order:
|
|
61
|
+
- 1. Read THIS .faf file first
|
|
62
|
+
- 2. Check CLAUDE.md for session context
|
|
63
|
+
- 3. Review package.json for dependencies
|
|
64
|
+
working_style:
|
|
65
|
+
code_first: true
|
|
66
|
+
explanations: minimal
|
|
67
|
+
quality_bar: zero_errors
|
|
68
|
+
testing: required
|
|
69
|
+
warnings:
|
|
70
|
+
- Never modify dial components without approval
|
|
71
|
+
- All TypeScript must pass strict mode
|
|
72
|
+
- Test coverage required for new features
|
|
73
|
+
stack:
|
|
74
|
+
frontend: None
|
|
75
|
+
css_framework: None
|
|
76
|
+
ui_library: None
|
|
77
|
+
state_management: None
|
|
78
|
+
backend: None
|
|
79
|
+
runtime: Node.js
|
|
80
|
+
database: None
|
|
81
|
+
build: TypeScript Compiler
|
|
82
|
+
package_manager: npm
|
|
83
|
+
api_type: REST
|
|
84
|
+
hosting: npm Registry
|
|
85
|
+
cicd: GitHub Actions
|
|
86
|
+
targetUser: developers
|
|
87
|
+
coreProblem: understanding project
|
|
88
|
+
missionPurpose: project documentation
|
|
89
|
+
packageManager: npm/yarn/pnpm
|
|
90
|
+
mainLanguage: JavaScript/TypeScript
|
|
91
|
+
cli_features:
|
|
92
|
+
commands:
|
|
93
|
+
- npx faf-taf-git
|
|
94
|
+
- --file (test output file - v2.0.0+)
|
|
95
|
+
- --command (custom test command - legacy v1.x)
|
|
96
|
+
- --commit (auto-commit .taf changes)
|
|
97
|
+
- --verbose (detailed output)
|
|
98
|
+
- --message (custom commit message)
|
|
99
|
+
- --cwd (working directory)
|
|
100
|
+
github_action_inputs:
|
|
101
|
+
test-output-file: required (v2.0.0+)
|
|
102
|
+
auto-commit: true (default)
|
|
103
|
+
commit-message: "chore(taf): update .taf receipt [skip ci] (default)"
|
|
104
|
+
architecture:
|
|
105
|
+
version: v2.0.0
|
|
106
|
+
pattern: pre-capture
|
|
107
|
+
breakthrough: Separate test execution from receipt generation
|
|
108
|
+
why: Avoids GitHub Actions execution context corruption
|
|
109
|
+
reliability: Tested 19 methods before this solution
|
|
110
|
+
benefits:
|
|
111
|
+
- More reliable (no execution context issues)
|
|
112
|
+
- Platform-agnostic (works everywhere)
|
|
113
|
+
- Simpler (400+ lines removed, 11KB smaller)
|
|
114
|
+
test_frameworks:
|
|
115
|
+
- Jest (fully supported)
|
|
116
|
+
supported_platforms:
|
|
117
|
+
- GitHub Actions
|
|
118
|
+
- GitLab CI
|
|
119
|
+
- Bitbucket Pipelines
|
|
120
|
+
- Jenkins
|
|
121
|
+
- CircleCI
|
|
122
|
+
- Travis CI
|
|
123
|
+
- Azure Pipelines
|
|
124
|
+
- Local development
|
|
125
|
+
taf_format:
|
|
126
|
+
format: YAML
|
|
127
|
+
file_location: .taf (hidden dotfile)
|
|
128
|
+
purpose: Git-tracked testing timeline - permanent proof your code works
|
|
129
|
+
links_to_faf: true
|
|
130
|
+
snapshots_faf_score: true
|
|
131
|
+
closed_loop_system: .faf (DNA) + repo (code) + .taf (proof) = Golden Triangle
|
|
132
|
+
deployment:
|
|
133
|
+
npm_package: faf-taf-git@2.0.4
|
|
134
|
+
github_action: Wolfe-Jam/faf-taf-git@v2.0.4
|
|
135
|
+
marketplaces:
|
|
136
|
+
- npm Registry
|
|
137
|
+
- GitHub Actions Marketplace
|
|
138
|
+
install: npx faf-taf-git
|
|
139
|
+
production_users:
|
|
140
|
+
- faf-cli (working in CI)
|
|
141
|
+
testing:
|
|
142
|
+
framework: Jest
|
|
143
|
+
coverage: Core functionality
|
|
144
|
+
ci_integration: GitHub Actions
|
|
145
|
+
test_files:
|
|
146
|
+
- tests/ (unit tests)
|
|
147
|
+
quality_gates:
|
|
148
|
+
- All tests must pass
|
|
149
|
+
- TypeScript strict mode
|
|
150
|
+
- Zero build errors
|
|
151
|
+
examples:
|
|
152
|
+
github_actions: README.md Quick Start section
|
|
153
|
+
standalone_cli: README.md Standalone CLI section
|
|
154
|
+
gitlab_ci: README.md GitLab CI section
|
|
155
|
+
jenkins: README.md Jenkins section
|
|
156
|
+
migration: README.md Migration from v1.x section
|
|
157
|
+
performance:
|
|
158
|
+
bundle_size: 1.2MB (v2.0.0 - reduced 11KB from v1.x)
|
|
159
|
+
startup_time: <100ms
|
|
160
|
+
parse_time: <10ms for typical Jest output
|
|
161
|
+
reliability: 100% success rate in faf-cli CI (after v2.0.4)
|
|
162
|
+
preferences:
|
|
163
|
+
quality_bar: zero_errors
|
|
164
|
+
commit_style: conventional_emoji
|
|
165
|
+
response_style: concise_code_first
|
|
166
|
+
explanation_level: minimal
|
|
167
|
+
communication: direct
|
|
168
|
+
testing: required
|
|
169
|
+
documentation: as_needed
|
|
170
|
+
contributing:
|
|
171
|
+
guidelines: CONTRIBUTING.md
|
|
172
|
+
code_style: TypeScript strict mode
|
|
173
|
+
pr_process: Fork, branch, PR with tests
|
|
174
|
+
commit_format: Conventional commits with Co-Authored-By
|
|
175
|
+
testing_required: true
|
|
176
|
+
documentation_required: For new features
|
|
177
|
+
resources:
|
|
178
|
+
readme: README.md (6Ws format)
|
|
179
|
+
changelog: CHANGELOG.md (22 versions documented)
|
|
180
|
+
license: MIT
|
|
181
|
+
repository: https://github.com/Wolfe-Jam/faf-taf-git
|
|
182
|
+
npm: https://npmjs.com/package/faf-taf-git
|
|
183
|
+
issues: https://github.com/Wolfe-Jam/faf-taf-git/issues
|
|
184
|
+
discussions: https://github.com/Wolfe-Jam/faf/discussions
|
|
185
|
+
state:
|
|
186
|
+
phase: production
|
|
187
|
+
version: 2.0.4
|
|
188
|
+
focus: ecosystem_adoption
|
|
189
|
+
status: production_ready
|
|
190
|
+
achievements:
|
|
191
|
+
- v2.0.0 architectural redesign (pre-capture pattern)
|
|
192
|
+
- v2.0.4 parser fix (working in CI)
|
|
193
|
+
- Updated README (6Ws format)
|
|
194
|
+
- Updated CHANGELOG (22 versions documented)
|
|
195
|
+
- TAF Receipt generating successfully in faf-cli repo
|
|
196
|
+
next_milestone: user_adoption
|
|
197
|
+
blockers: null
|
|
198
|
+
tags:
|
|
199
|
+
auto_generated:
|
|
200
|
+
- faf-taf-action
|
|
201
|
+
- none
|
|
202
|
+
- typescript
|
|
203
|
+
smart_defaults:
|
|
204
|
+
- .faf
|
|
205
|
+
- ai-ready
|
|
206
|
+
- "2025"
|
|
207
|
+
- software
|
|
208
|
+
- open-source
|
|
209
|
+
user_defined: null
|
|
210
|
+
human_context:
|
|
211
|
+
who: Development teams
|
|
212
|
+
what: TAF file updates in CI/CD pipelines
|
|
213
|
+
why: Improve development efficiency
|
|
214
|
+
where: Any CI/CD platform (GitHub, GitLab, Bitbucket)
|
|
215
|
+
when: During CI/CD test runs
|
|
216
|
+
how: Test-driven development
|
|
217
|
+
additional_context: Part of Golden Triangle (.faf + repo + .taf). Tracks test
|
|
218
|
+
runs permanently in git. Supports Jest, works as CLI or GitHub Action.
|
|
219
|
+
Platform-agnostic core - runs on ANY CI/CD with Node.js.
|
|
220
|
+
context_score: 0
|
|
221
|
+
total_prd_score: 65
|
|
222
|
+
success_rate: 50%
|
|
223
|
+
scores:
|
|
224
|
+
faf_score: 50
|
|
225
|
+
slot_based_percentage: 52
|
|
226
|
+
ai_score: 65
|
|
227
|
+
total_slots: 21
|
|
228
|
+
filled_slots: 11
|
|
229
|
+
scoring_method: Honest percentage - no fake minimums
|
|
230
|
+
trust_embedded: COUNT ONCE architecture - trust MY embedded scores
|
|
231
|
+
ai_scoring_details:
|
|
232
|
+
system_date: 2025-09-20
|
|
233
|
+
slot_based_percentage: 52
|
|
234
|
+
ai_score: 65
|
|
235
|
+
total_slots: 21
|
|
236
|
+
filled_slots: 11
|
|
237
|
+
scoring_method: Honest percentage - no fake minimums
|
|
238
|
+
trust_embedded: COUNT ONCE architecture - trust MY embedded scores
|
|
239
|
+
faf_dna:
|
|
240
|
+
birth_dna: 22
|
|
241
|
+
birth_certificate: FAF-2025-FAFTAFAC-TMZU
|
|
242
|
+
birth_date: 2025-10-28T01:26:05.692Z
|
|
243
|
+
current_score: 50
|
|
244
|
+
projectName: faf-taf-git
|
|
245
|
+
projectGoal: Platform-agnostic TAF (Testing Activity Feed) updater - works in ANY CI/CD
|
|
246
|
+
generated: 2026-02-17T20:14:09.215Z
|
|
247
|
+
last_major_update: v2.0.4 (2026-02-17)
|
|
248
|
+
production_status: Working in faf-cli repository
|
|
249
|
+
stack_signature: typescript-nodejs-javascript
|
|
250
|
+
detected_frameworks:
|
|
251
|
+
- Claude Code
|
|
252
|
+
- Jest
|
|
253
|
+
- Node.js
|
|
254
|
+
- JavaScript
|
|
255
|
+
- TypeScript
|
|
256
|
+
turbo_cat_intelligence: 260
|
|
257
|
+
stats:
|
|
258
|
+
last_auto_time: 0.6
|
|
259
|
+
times_run: 1
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* faf-taf-git - Standalone CLI for TAF operations
|
|
4
|
+
*
|
|
5
|
+
* Platform-agnostic core that works in ANY CI/CD environment
|
|
6
|
+
* Can be used standalone or as a library by wrappers
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import * as exec from '@actions/exec';
|
|
10
|
+
import * as fs from 'fs';
|
|
11
|
+
import * as os from 'os';
|
|
12
|
+
import * as path from 'path';
|
|
13
|
+
import { parseJestOutput } from './parsers/jest';
|
|
14
|
+
import { updateTafFile } from './taf-core';
|
|
15
|
+
|
|
16
|
+
export interface CLIOptions {
|
|
17
|
+
command?: string;
|
|
18
|
+
autoCommit?: boolean;
|
|
19
|
+
commitMessage?: string;
|
|
20
|
+
cwd?: string;
|
|
21
|
+
verbose?: boolean;
|
|
22
|
+
logger?: (message: string) => void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface CLIResult {
|
|
26
|
+
success: boolean;
|
|
27
|
+
testResults?: {
|
|
28
|
+
total: number;
|
|
29
|
+
passed: number;
|
|
30
|
+
failed: number;
|
|
31
|
+
result: string;
|
|
32
|
+
};
|
|
33
|
+
tafUpdated: boolean;
|
|
34
|
+
error?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Main CLI function - platform-agnostic
|
|
39
|
+
* Can be called from GitHub Actions, GitLab CI, or standalone
|
|
40
|
+
*/
|
|
41
|
+
export async function runTafGit(options: CLIOptions = {}): Promise<CLIResult> {
|
|
42
|
+
const {
|
|
43
|
+
command = 'npm test',
|
|
44
|
+
autoCommit = false,
|
|
45
|
+
commitMessage = 'chore: update .taf with test results',
|
|
46
|
+
cwd = process.cwd(),
|
|
47
|
+
verbose = false,
|
|
48
|
+
logger = console.log,
|
|
49
|
+
} = options;
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
if (verbose) console.log(`Running test command: ${command}`);
|
|
53
|
+
|
|
54
|
+
// Run tests and capture output using @actions/exec
|
|
55
|
+
let output = '';
|
|
56
|
+
let exitCode = 0;
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
// Parse command into executable and args
|
|
60
|
+
// For "npm test" -> ["npm", "test"]
|
|
61
|
+
const commandParts = command.split(' ');
|
|
62
|
+
const executable = commandParts[0];
|
|
63
|
+
const args = commandParts.slice(1);
|
|
64
|
+
|
|
65
|
+
const options: exec.ExecOptions = {
|
|
66
|
+
cwd,
|
|
67
|
+
silent: false, // Show output in logs
|
|
68
|
+
ignoreReturnCode: true // Don't throw on non-zero exit
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// --- [START NUCLEAR CANARY] ---
|
|
72
|
+
// Use getExecOutput to capture stdout/stderr
|
|
73
|
+
const result = await exec.getExecOutput(executable, args, options);
|
|
74
|
+
|
|
75
|
+
// THE NUCLEAR CANARY: Write directly to disk, bypassing stdout/stderr streams
|
|
76
|
+
// Write to MULTIPLE locations to ensure we find it!
|
|
77
|
+
const canaryContent = [
|
|
78
|
+
`=========================================`,
|
|
79
|
+
`TAF DEBUG CANARY REPORT`,
|
|
80
|
+
`Timestamp: ${new Date().toISOString()}`,
|
|
81
|
+
`CWD: ${cwd}`,
|
|
82
|
+
`Process CWD: ${process.cwd()}`,
|
|
83
|
+
`=========================================`,
|
|
84
|
+
`Exit Code: ${result.exitCode}`,
|
|
85
|
+
`Stdout Length: ${result.stdout.length}`,
|
|
86
|
+
`Stderr Length: ${result.stderr.length}`,
|
|
87
|
+
`-----------------------------------------`,
|
|
88
|
+
`STDOUT PREVIEW (First 500 chars):`,
|
|
89
|
+
`${result.stdout.substring(0, 500)}`,
|
|
90
|
+
`-----------------------------------------`,
|
|
91
|
+
`STDERR PREVIEW (First 500 chars):`,
|
|
92
|
+
`${result.stderr.substring(0, 500)}`,
|
|
93
|
+
`=========================================`
|
|
94
|
+
].join('\n');
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
// Try multiple locations!
|
|
98
|
+
const locations = [
|
|
99
|
+
path.join(cwd, 'TAF_DEBUG_CANARY.txt'), // Original cwd
|
|
100
|
+
path.join(process.cwd(), 'TAF_DEBUG_CANARY.txt'), // Process cwd
|
|
101
|
+
path.join(os.tmpdir(), 'TAF_DEBUG_CANARY.txt'), // OS temp directory
|
|
102
|
+
'TAF_DEBUG_CANARY.txt' // Current directory
|
|
103
|
+
];
|
|
104
|
+
|
|
105
|
+
let writeSuccess = false;
|
|
106
|
+
for (const loc of locations) {
|
|
107
|
+
try {
|
|
108
|
+
fs.writeFileSync(loc, canaryContent);
|
|
109
|
+
writeSuccess = true;
|
|
110
|
+
} catch (e) {
|
|
111
|
+
// Try next location
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (!writeSuccess) {
|
|
116
|
+
throw new Error('CRITICAL: Failed to write canary to ANY location!');
|
|
117
|
+
}
|
|
118
|
+
} catch (fsError: any) {
|
|
119
|
+
// If we can't write to disk, we are truly doomed
|
|
120
|
+
throw new Error(`CRITICAL: Failed to write canary file: ${fsError.message}`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Continue with original logic
|
|
124
|
+
exitCode = result.exitCode;
|
|
125
|
+
output = result.stdout + result.stderr;
|
|
126
|
+
// --- [END NUCLEAR CANARY] ---
|
|
127
|
+
} catch (error: any) {
|
|
128
|
+
exitCode = 1;
|
|
129
|
+
if (verbose) {
|
|
130
|
+
logger(`Test command failed with error: ${error.message}`);
|
|
131
|
+
logger(`Captured output length: ${output.length} bytes`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Debug: Write entire output to file for inspection
|
|
136
|
+
if (verbose) {
|
|
137
|
+
try {
|
|
138
|
+
const fs = require('fs');
|
|
139
|
+
const debugPath = path.join(os.tmpdir(), 'taf-debug-output.txt');
|
|
140
|
+
fs.writeFileSync(debugPath, output);
|
|
141
|
+
logger(`DEBUG: Wrote ${output.length} bytes to ${debugPath}`);
|
|
142
|
+
const lines = output.split('\n');
|
|
143
|
+
const testLine = lines.find(l => l.includes('Tests:'));
|
|
144
|
+
logger(`DEBUG: Output has ${lines.length} lines, Found "Tests:": ${testLine ? 'YES' : 'NO'}`);
|
|
145
|
+
if (testLine) {
|
|
146
|
+
logger(`DEBUG: Tests line: "${testLine}"`);
|
|
147
|
+
} else {
|
|
148
|
+
logger(`DEBUG: Last 10 lines of output:`);
|
|
149
|
+
lines.slice(-10).forEach((line, i) => {
|
|
150
|
+
logger(` ${i}: ${line.substring(0, 100)}`);
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
} catch (err) {
|
|
154
|
+
logger(`DEBUG: Error writing debug file: ${err}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Parse test output
|
|
159
|
+
const testResults = parseJestOutput(output);
|
|
160
|
+
|
|
161
|
+
if (!testResults) {
|
|
162
|
+
if (verbose) {
|
|
163
|
+
logger(`DEBUG: Parser returned null`);
|
|
164
|
+
logger(`DEBUG: Output sample (first 500 chars): ${output.slice(0, 500)}`);
|
|
165
|
+
logger(`DEBUG: Output sample (last 500 chars): ${output.slice(-500)}`);
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
success: false,
|
|
169
|
+
tafUpdated: false,
|
|
170
|
+
error: 'Could not parse test output. Ensure you are using Jest.',
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (verbose) {
|
|
175
|
+
logger(`Parsed results: ${testResults.passed}/${testResults.total} tests passing`);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Check if .taf file exists
|
|
179
|
+
const tafPath = path.join(cwd, '.taf');
|
|
180
|
+
if (!fs.existsSync(tafPath)) {
|
|
181
|
+
return {
|
|
182
|
+
success: false,
|
|
183
|
+
testResults: {
|
|
184
|
+
total: testResults.total,
|
|
185
|
+
passed: testResults.passed,
|
|
186
|
+
failed: testResults.failed,
|
|
187
|
+
result: testResults.result,
|
|
188
|
+
},
|
|
189
|
+
tafUpdated: false,
|
|
190
|
+
error: 'No .taf file found. Run `faf taf init` to create one.',
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Update .taf file
|
|
195
|
+
const updated = await updateTafFile(tafPath, testResults);
|
|
196
|
+
|
|
197
|
+
if (updated) {
|
|
198
|
+
if (verbose) logger('โ
.taf file updated successfully');
|
|
199
|
+
|
|
200
|
+
// Commit changes if enabled
|
|
201
|
+
if (autoCommit) {
|
|
202
|
+
await commitTafUpdate(cwd, commitMessage, verbose, logger);
|
|
203
|
+
if (verbose) logger('โ
Changes committed to git');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
success: true,
|
|
208
|
+
testResults: {
|
|
209
|
+
total: testResults.total,
|
|
210
|
+
passed: testResults.passed,
|
|
211
|
+
failed: testResults.failed,
|
|
212
|
+
result: testResults.result,
|
|
213
|
+
},
|
|
214
|
+
tafUpdated: true,
|
|
215
|
+
};
|
|
216
|
+
} else {
|
|
217
|
+
return {
|
|
218
|
+
success: false,
|
|
219
|
+
testResults: {
|
|
220
|
+
total: testResults.total,
|
|
221
|
+
passed: testResults.passed,
|
|
222
|
+
failed: testResults.failed,
|
|
223
|
+
result: testResults.result,
|
|
224
|
+
},
|
|
225
|
+
tafUpdated: false,
|
|
226
|
+
error: '.taf file was not updated',
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
} catch (error) {
|
|
230
|
+
return {
|
|
231
|
+
success: false,
|
|
232
|
+
tafUpdated: false,
|
|
233
|
+
error: error instanceof Error ? error.message : 'Unknown error occurred',
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Commit .taf file changes to git (platform-agnostic)
|
|
240
|
+
*/
|
|
241
|
+
async function commitTafUpdate(cwd: string, message: string, verbose: boolean, logger: (msg: string) => void = console.log): Promise<void> {
|
|
242
|
+
try {
|
|
243
|
+
const execOptions: exec.ExecOptions = { cwd };
|
|
244
|
+
|
|
245
|
+
// Configure git if needed
|
|
246
|
+
await exec.exec('git', ['config', '--global', 'user.name', 'faf-taf-git[bot]'], execOptions);
|
|
247
|
+
await exec.exec('git', ['config', '--global', 'user.email', 'faf-taf-git[bot]@users.noreply.github.com'], execOptions);
|
|
248
|
+
|
|
249
|
+
// Stage .taf file
|
|
250
|
+
await exec.exec('git', ['add', '.taf'], execOptions);
|
|
251
|
+
|
|
252
|
+
// Check if there are changes to commit
|
|
253
|
+
let diffOutput = '';
|
|
254
|
+
const diffOptions: exec.ExecOptions = {
|
|
255
|
+
cwd,
|
|
256
|
+
listeners: {
|
|
257
|
+
stdout: (data: Buffer) => {
|
|
258
|
+
diffOutput += data.toString();
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
await exec.exec('git', ['diff', '--cached', '--name-only'], diffOptions);
|
|
263
|
+
|
|
264
|
+
if (diffOutput.trim().length > 0) {
|
|
265
|
+
await exec.exec('git', ['commit', '-m', message], execOptions);
|
|
266
|
+
|
|
267
|
+
// Try to push (might fail in some environments, that's ok)
|
|
268
|
+
try {
|
|
269
|
+
await exec.exec('git', ['push'], execOptions);
|
|
270
|
+
} catch (error) {
|
|
271
|
+
if (verbose) {
|
|
272
|
+
logger('Could not push changes (this is ok in some CI environments)');
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
} else {
|
|
276
|
+
if (verbose) logger('No changes to commit');
|
|
277
|
+
}
|
|
278
|
+
} catch (error) {
|
|
279
|
+
if (verbose) {
|
|
280
|
+
logger(`Error committing changes: ${error}`);
|
|
281
|
+
}
|
|
282
|
+
throw error;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* CLI entry point - parse args and run
|
|
288
|
+
*/
|
|
289
|
+
async function main() {
|
|
290
|
+
const args = process.argv.slice(2);
|
|
291
|
+
|
|
292
|
+
const options: CLIOptions = {
|
|
293
|
+
verbose: args.includes('--verbose') || args.includes('-v'),
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
// Parse command flag
|
|
297
|
+
const commandIndex = args.indexOf('--command');
|
|
298
|
+
if (commandIndex !== -1 && args[commandIndex + 1]) {
|
|
299
|
+
options.command = args[commandIndex + 1];
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Parse auto-commit flag
|
|
303
|
+
if (args.includes('--commit')) {
|
|
304
|
+
options.autoCommit = true;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Parse commit message
|
|
308
|
+
const messageIndex = args.indexOf('--message');
|
|
309
|
+
if (messageIndex !== -1 && args[messageIndex + 1]) {
|
|
310
|
+
options.commitMessage = args[messageIndex + 1];
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Parse working directory
|
|
314
|
+
const cwdIndex = args.indexOf('--cwd');
|
|
315
|
+
if (cwdIndex !== -1 && args[cwdIndex + 1]) {
|
|
316
|
+
options.cwd = args[cwdIndex + 1];
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Show help
|
|
320
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
321
|
+
console.log(`
|
|
322
|
+
faf-taf-git - Platform-agnostic TAF updater
|
|
323
|
+
|
|
324
|
+
USAGE:
|
|
325
|
+
npx faf-taf-git [OPTIONS]
|
|
326
|
+
|
|
327
|
+
OPTIONS:
|
|
328
|
+
--command <cmd> Test command to run (default: npm test)
|
|
329
|
+
--commit Auto-commit .taf changes to git
|
|
330
|
+
--message <msg> Custom commit message
|
|
331
|
+
--cwd <dir> Working directory (default: current)
|
|
332
|
+
--verbose, -v Verbose output
|
|
333
|
+
--help, -h Show this help
|
|
334
|
+
|
|
335
|
+
EXAMPLES:
|
|
336
|
+
# Run tests and update .taf
|
|
337
|
+
npx faf-taf-git
|
|
338
|
+
|
|
339
|
+
# Custom test command
|
|
340
|
+
npx faf-taf-git --command "npm run test:unit"
|
|
341
|
+
|
|
342
|
+
# Auto-commit changes
|
|
343
|
+
npx faf-taf-git --commit
|
|
344
|
+
|
|
345
|
+
# Custom commit message
|
|
346
|
+
npx faf-taf-git --commit --message "test: update TAF"
|
|
347
|
+
|
|
348
|
+
# Verbose mode
|
|
349
|
+
npx faf-taf-git --verbose
|
|
350
|
+
|
|
351
|
+
PLATFORM SUPPORT:
|
|
352
|
+
โ
GitHub Actions
|
|
353
|
+
โ
GitLab CI
|
|
354
|
+
โ
Bitbucket Pipelines
|
|
355
|
+
โ
Jenkins
|
|
356
|
+
โ
CircleCI
|
|
357
|
+
โ
Local development
|
|
358
|
+
โ
Any CI/CD that runs Node.js
|
|
359
|
+
|
|
360
|
+
LEARN MORE:
|
|
361
|
+
https://github.com/Wolfe-Jam/faf-taf-git
|
|
362
|
+
`);
|
|
363
|
+
process.exit(0);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Run the tool
|
|
367
|
+
const result = await runTafGit(options);
|
|
368
|
+
|
|
369
|
+
if (result.success) {
|
|
370
|
+
if (result.testResults) {
|
|
371
|
+
console.log(`โ
Tests: ${result.testResults.passed}/${result.testResults.total} passing`);
|
|
372
|
+
console.log(`โ
Result: ${result.testResults.result}`);
|
|
373
|
+
}
|
|
374
|
+
if (result.tafUpdated) {
|
|
375
|
+
console.log('โ
.taf file updated');
|
|
376
|
+
}
|
|
377
|
+
process.exit(0);
|
|
378
|
+
} else {
|
|
379
|
+
console.error(`โ Error: ${result.error}`);
|
|
380
|
+
if (result.testResults) {
|
|
381
|
+
console.log(`Tests: ${result.testResults.passed}/${result.testResults.total} passing`);
|
|
382
|
+
}
|
|
383
|
+
process.exit(1);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Run CLI if called directly
|
|
388
|
+
if (require.main === module) {
|
|
389
|
+
main().catch((error) => {
|
|
390
|
+
console.error('Fatal error:', error);
|
|
391
|
+
process.exit(1);
|
|
392
|
+
});
|
|
393
|
+
}
|