diff --git a/dist/dead-code.d.ts.map b/dist/dead-code.d.ts.map index 987c001..dfa18c0 100644 --- a/dist/dead-code.d.ts.map +++ b/dist/dead-code.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"","sourceRoot":"","sources":["file:///Users/jag/dead-code-hunter/src/dead-code.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE5E;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,0EAA0E;AAC1E,eAAO,MAAM,wBAAwB,UAiBpC,CAAC;AAEF,gEAAgE;AAChE,eAAO,MAAM,oBAAoB,UAUhC,CAAC;AAEF,uDAAuD;AACvD,eAAO,MAAM,0BAA0B,UAUtC,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAG1D;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,GAAE,MAAM,EAAO,GAAG,OAAO,CAGzF;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,aAAa,EAAE,EACtB,aAAa,EAAE,qBAAqB,EAAE,EACtC,cAAc,GAAE,MAAM,EAAO,GAC5B,cAAc,EAAE,CA6ClB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,MAAM,CAiClE"} \ No newline at end of file +{"version":3,"file":"","sourceRoot":"","sources":["file:///private/tmp/dead-code-hunter/src/dead-code.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE5E;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,0EAA0E;AAC1E,eAAO,MAAM,wBAAwB,UAiBpC,CAAC;AAEF,gEAAgE;AAChE,eAAO,MAAM,oBAAoB,UAUhC,CAAC;AAEF,uDAAuD;AACvD,eAAO,MAAM,0BAA0B,UAUtC,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAG1D;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,GAAE,MAAM,EAAO,GAAG,OAAO,CAGzF;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,aAAa,EAAE,EACtB,aAAa,EAAE,qBAAqB,EAAE,EACtC,cAAc,GAAE,MAAM,EAAO,GAC5B,cAAc,EAAE,CA6ClB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,MAAM,CAiClE"} \ No newline at end of file diff --git a/dist/index.d.ts.map b/dist/index.d.ts.map index 650454b..1e04742 100644 --- a/dist/index.d.ts.map +++ b/dist/index.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"","sourceRoot":"","sources":["file:///Users/jag/dead-code-hunter/src/index.ts"],"names":[],"mappings":""} \ No newline at end of file +{"version":3,"file":"","sourceRoot":"","sources":["file:///private/tmp/dead-code-hunter/src/index.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/dist/index.js b/dist/index.js index aba9b31..1d6c40a 100644 --- a/dist/index.js +++ b/dist/index.js @@ -32607,13 +32607,36 @@ async function run() { const api = new sdk_1.DefaultApi(config); const zipBuffer = await fs.readFile(zipPath); const zipBlob = new Blob([zipBuffer], { type: 'application/zip' }); - const response = await api.generateSupermodelGraph({ + // Submit graph generation job (async API returns an envelope with status) + let response = await api.generateSupermodelGraph({ idempotencyKey, file: zipBlob, }); + // Poll until the job completes or fails + const maxPollTime = 5 * 60 * 1000; // 5 minutes max + const startTime = Date.now(); + while (response.status === 'pending' || response.status === 'processing') { + if (Date.now() - startTime > maxPollTime) { + throw new Error('Graph generation timed out after 5 minutes'); + } + const waitSeconds = response.retryAfter || 5; + core.info(`Job ${response.jobId} is ${response.status}, retrying in ${waitSeconds}s...`); + await new Promise(resolve => setTimeout(resolve, waitSeconds * 1000)); + response = await api.generateSupermodelGraph({ + idempotencyKey, + file: zipBlob, + }); + } + if (response.status === 'failed') { + throw new Error(`Graph generation failed: ${response.error || 'Unknown error'}`); + } + if (response.status !== 'completed') { + throw new Error(`Unexpected job status: ${response.status}`); + } // Step 4: Analyze for dead code - const nodes = response.graph?.nodes || []; - const relationships = response.graph?.relationships || []; + const graphData = response.result?.graph || response.graph; + const nodes = graphData?.nodes || []; + const relationships = graphData?.relationships || []; const deadCode = (0, dead_code_1.findDeadCode)(nodes, relationships, ignorePatterns); core.info(`Found ${deadCode.length} potentially unused functions`); // Step 5: Set outputs diff --git a/src/__tests__/integration.test.ts b/src/__tests__/integration.test.ts index 11dc794..b0af73e 100644 --- a/src/__tests__/integration.test.ts +++ b/src/__tests__/integration.test.ts @@ -29,40 +29,72 @@ describe.skipIf(SKIP_INTEGRATION)('Integration Tests', () => { const commitHash = execSync('git rev-parse --short HEAD', { cwd: repoRoot }) .toString() .trim(); - idempotencyKey = `dead-code-hunter:call:${commitHash}`; + idempotencyKey = `dead-code-hunter:supermodel:${commitHash}`; }); - it('should call the Supermodel API and get a call graph', async () => { + it('should call the Supermodel API and get a supermodel graph', async () => { const zipBuffer = await fs.readFile(zipPath); const zipBlob = new Blob([zipBuffer], { type: 'application/zip' }); - const response = await api.generateCallGraph({ + let response = await api.generateSupermodelGraph({ idempotencyKey, file: zipBlob, - }); + }) as any; + + // Poll until job completes (with timeout) + const startTime = Date.now(); + const maxPollTime = 100_000; // 100s (within the vitest timeout) + while (response.status === 'pending' || response.status === 'processing') { + if (Date.now() - startTime > maxPollTime) { + throw new Error('Polling timed out in test'); + } + const waitSeconds = response.retryAfter || 5; + console.log(`Job ${response.jobId} is ${response.status}, waiting ${waitSeconds}s...`); + await new Promise(resolve => setTimeout(resolve, waitSeconds * 1000)); + response = await api.generateSupermodelGraph({ + idempotencyKey, + file: zipBlob, + }) as any; + } - expect(response).toBeDefined(); - expect(response.graph).toBeDefined(); - expect(response.graph?.nodes).toBeDefined(); - expect(response.graph?.relationships).toBeDefined(); - expect(response.stats).toBeDefined(); + expect(response.status).toBe('completed'); + const graph = response.result?.graph || response.graph; + expect(graph).toBeDefined(); + expect(graph?.nodes).toBeDefined(); + expect(graph?.relationships).toBeDefined(); - console.log('API Stats:', response.stats); - console.log('Nodes:', response.graph?.nodes?.length); - console.log('Relationships:', response.graph?.relationships?.length); - }, 60000); // 60 second timeout for API call + console.log('Nodes:', graph?.nodes?.length); + console.log('Relationships:', graph?.relationships?.length); + }, 120000); // 120 second timeout for async API it('should find dead code in the dead-code-hunter repo itself', async () => { const zipBuffer = await fs.readFile(zipPath); const zipBlob = new Blob([zipBuffer], { type: 'application/zip' }); - const response = await api.generateCallGraph({ + let response = await api.generateSupermodelGraph({ idempotencyKey, file: zipBlob, - }); + }) as any; + + // Poll until job completes (with timeout) + const startTime = Date.now(); + const maxPollTime = 100_000; + while (response.status === 'pending' || response.status === 'processing') { + if (Date.now() - startTime > maxPollTime) { + throw new Error('Polling timed out in test'); + } + const waitSeconds = response.retryAfter || 5; + await new Promise(resolve => setTimeout(resolve, waitSeconds * 1000)); + response = await api.generateSupermodelGraph({ + idempotencyKey, + file: zipBlob, + }) as any; + } - const nodes = response.graph?.nodes || []; - const relationships = response.graph?.relationships || []; + expect(response.status).toBe('completed'); + const graph = response.result?.graph || response.graph; + const nodes = graph?.nodes || []; + const relationships = graph?.relationships || []; const deadCode = findDeadCode(nodes, relationships); @@ -80,7 +112,7 @@ describe.skipIf(SKIP_INTEGRATION)('Integration Tests', () => { // The test passes regardless of dead code count - we just want to verify the flow works expect(Array.isArray(deadCode)).toBe(true); - }, 60000); + }, 120000); }); describe('Integration Test Prerequisites', () => { diff --git a/src/index.ts b/src/index.ts index f9d35f3..af296c8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -153,14 +153,43 @@ async function run(): Promise { const zipBuffer = await fs.readFile(zipPath); const zipBlob = new Blob([zipBuffer], { type: 'application/zip' }); - const response = await api.generateSupermodelGraph({ + // Submit graph generation job (async API returns an envelope with status) + let response = await api.generateSupermodelGraph({ idempotencyKey, file: zipBlob, - }); + }) as any; + + // Poll until the job completes or fails + const maxPollTime = 5 * 60 * 1000; // 5 minutes max + const startTime = Date.now(); + + while (response.status === 'pending' || response.status === 'processing') { + if (Date.now() - startTime > maxPollTime) { + throw new Error('Graph generation timed out after 5 minutes'); + } + + const waitSeconds = response.retryAfter || 5; + core.info(`Job ${response.jobId} is ${response.status}, retrying in ${waitSeconds}s...`); + await new Promise(resolve => setTimeout(resolve, waitSeconds * 1000)); + + response = await api.generateSupermodelGraph({ + idempotencyKey, + file: zipBlob, + }) as any; + } + + if (response.status === 'failed') { + throw new Error(`Graph generation failed: ${response.error || 'Unknown error'}`); + } + + if (response.status !== 'completed') { + throw new Error(`Unexpected job status: ${response.status}`); + } // Step 4: Analyze for dead code - const nodes = response.graph?.nodes || []; - const relationships = response.graph?.relationships || []; + const graphData = response.result?.graph || response.graph; + const nodes = graphData?.nodes || []; + const relationships = graphData?.relationships || []; const deadCode = findDeadCode(nodes, relationships, ignorePatterns);