From bda6aca7695daf5faf33835c399f3f8de61c9dc2 Mon Sep 17 00:00:00 2001 From: Christophe Clermont Date: Wed, 27 Mar 2024 17:44:59 +0100 Subject: [PATCH] Added buildinfo files upload. --- __tests__/run.test.js | 5 +- __tests__/upload.test.js | 103 ++++++++++++++++++++++++++++++++++++++- dist/index.js | 63 +++++++++++++++++++++++- src/run.js | 4 +- src/upload.js | 59 ++++++++++++++++++++++ 5 files changed, 229 insertions(+), 5 deletions(-) diff --git a/__tests__/run.test.js b/__tests__/run.test.js index 15acf38..4a93c2a 100644 --- a/__tests__/run.test.js +++ b/__tests__/run.test.js @@ -3,7 +3,7 @@ const core = require('@actions/core'); const { readBuildInfoFiles } = require('../src/buildinfo.js'); const { run } = require('../src/run.js'); const { searchBuildinfo } = require('../src/search.js'); -const { uploadArtifact } = require('../src/upload.js'); +const { uploadArtifact, uploadBuildInfo } = require('../src/upload.js'); // Mock dependencies jest.mock('@actions/core', () => ({ @@ -20,6 +20,7 @@ jest.mock('../src/search.js', () => ({ })); jest.mock('../src/upload.js', () => ({ uploadArtifact: jest.fn(), + uploadBuildInfo: jest.fn(), })); describe('test run', () => { @@ -36,6 +37,7 @@ describe('test run', () => { expect(searchBuildinfo).toHaveBeenCalled(); expect(readBuildInfoFiles).toHaveBeenCalledWith(['path/to/buildinfo1', 'path/to/buildinfo2']); + expect(uploadBuildInfo).toHaveBeenCalledWith(['path/to/buildinfo1', 'path/to/buildinfo2']); expect(uploadArtifact).toHaveBeenCalledTimes(2); // Assuming two artifacts are found and uploaded }); @@ -49,6 +51,7 @@ describe('test run', () => { expect(searchBuildinfo).toHaveBeenCalled(); expect(readBuildInfoFiles).toHaveBeenCalledWith([]); expect(core.warning).toHaveBeenCalledWith('No output file found for upload.'); + expect(uploadBuildInfo).toHaveBeenCalledWith([]); expect(uploadArtifact).not.toHaveBeenCalled(); }); diff --git a/__tests__/upload.test.js b/__tests__/upload.test.js index 7aaf0d0..04cf3b3 100644 --- a/__tests__/upload.test.js +++ b/__tests__/upload.test.js @@ -2,7 +2,7 @@ const artifact = require('@actions/artifact'); const core = require('@actions/core'); const github = require('@actions/github'); -const { uploadArtifact } = require('../src/upload.js'); +const { findCommonDirectory, uploadArtifact, uploadBuildInfo } = require('../src/upload.js'); const inputs = require('../src/inputs.js'); jest.mock('path', () => ({ @@ -18,6 +18,52 @@ jest.mock('@actions/core'); jest.mock('@actions/artifact'); jest.mock('@actions/github'); +describe('test findCommonDirectory', () => { + + test('common base directory', () => { + const paths = [ + "/home/user/project/src/index.js", + "/home/user/project/src/app/app.js", + "/home/user/project/src/app/components/button.js" + ]; + expect(findCommonDirectory(paths)).toBe("/home/user/project/src"); + }); + + test('no common directory', () => { + const paths = [ + "/home/user/project/src/index.js", + "/root/docs/readme.md" + ]; + expect(findCommonDirectory(paths)).toBe(""); + }); + + test('mixed separators', () => { + const paths = [ + "/home/user/project/file1.txt", + "\\home\\user\\project\\file2.txt" + ]; + expect(findCommonDirectory(paths)).toBe("/home/user/project"); + }); + + test('single path', () => { + const paths = ["/home/user/project/src/index.js"]; + expect(findCommonDirectory(paths)).toBe("/home/user/project/src/index.js"); + }); + + test('empty array', () => { + const paths = []; + expect(findCommonDirectory(paths)).toBe(""); + }); + + test('root directory', () => { + const paths = [ + "/", + "/home", + ]; + expect(findCommonDirectory(paths)).toBe(""); + }); +}); + describe('test uploadArtifact', () => { beforeEach(() => { jest.resetAllMocks(); @@ -49,7 +95,7 @@ describe('test uploadArtifact', () => { }); test('upload error', () => { - + // Mock other modules jest.spyOn(inputs, 'getUploadOptions').mockImplementation(() => {}); @@ -66,3 +112,56 @@ describe('test uploadArtifact', () => { }); }); + +describe('test uploadBuildInfo', () => { + beforeEach(() => { + jest.clearAllMocks(); + + github.context.repo = { owner: 'ownerName', repo: 'repoName' }; + github.context.serverUrl = 'https://github.com'; + github.context.runId = '123456'; + }); + + test('upload success', async () => { + // Mock other modules + global.findCommonDirectory = jest.fn().mockReturnValue('/path/to'); + global.getUploadOptions = jest.fn().mockReturnValue({}); + + // Setup default mocks for artifact client and GitHub context + const mockUploadArtifact = jest.fn().mockResolvedValue({ + size: 100, + id: 'artifact123' + }); + artifact.DefaultArtifactClient.mockReturnValue({ + uploadArtifact: mockUploadArtifact + }); + + uploadBuildInfo(['/path/to/file1', '/path/to/file2']); + + expect(mockUploadArtifact).toHaveBeenCalledWith( + 'buildinfo.zip', + ['/path/to/file1', '/path/to/file2'], + '/path/to', + {} + ); + + }); + + test('upload error', async () => { + // Mock other modules + global.findCommonDirectory = jest.fn().mockReturnValue('/path/to'); + global.getUploadOptions = jest.fn().mockReturnValue({}); + + const errorMessage = 'Upload failed'; + + const mockUploadArtifact = jest.fn().mockRejectedValue(new Error(errorMessage)); + artifact.DefaultArtifactClient.mockReturnValue({ + uploadArtifact: mockUploadArtifact + }); + + uploadBuildInfo(['/path/to/file1', '/path/to/file2']); + + expect(artifact.DefaultArtifactClient).toHaveBeenCalled(); + }); + +}); \ No newline at end of file diff --git a/dist/index.js b/dist/index.js index 55db76c..dca50a2 100644 --- a/dist/index.js +++ b/dist/index.js @@ -127406,7 +127406,7 @@ module.exports = { const core = __nccwpck_require__(42186); const { readBuildInfoFiles } = __nccwpck_require__(52451); const { searchBuildinfo } = __nccwpck_require__(32506); -const { uploadArtifact } = __nccwpck_require__(39265); +const { uploadArtifact, uploadBuildInfo } = __nccwpck_require__(39265); function run() { try { @@ -127414,6 +127414,8 @@ function run() { let outputs = readBuildInfoFiles(buildInfoPaths); + uploadBuildInfo(buildInfoPaths); + if (outputs) { outputs.forEach(output => { uploadArtifact(output); @@ -127465,6 +127467,30 @@ const github = __nccwpck_require__(95438); const { getUploadOptions } = __nccwpck_require__(97229); +function findCommonDirectory(paths) { + // Split each path into parts + const pathParts = paths.map(path => path.split(/\/|\\/)); + const shortestPathLength = Math.min(...pathParts.map(parts => parts.length)); + + let commonParts = []; + if (pathParts.length > 0) { + for (let i = 0; i < shortestPathLength; i++) { + let currentPart = pathParts[0][i]; + + // Check if the current part is common to all paths + if (pathParts.every(parts => parts[i] === currentPart)) { + commonParts.push(currentPart); + } else { + // If a non-matching part is found, stop the search + break; + } + } + } + + const commonPath = commonParts.join("/"); + return commonPath; +} + function uploadArtifact(filePath) { core.info(`uploadArtifact(${filePath})`); @@ -127506,8 +127532,43 @@ function uploadArtifact(filePath) { } +function uploadBuildInfo(buildInfoPaths) { + + core.info(`uploadBuildInfo(${buildInfoPaths})`); + + const rootDirectory = findCommonDirectory(buildInfoPaths); + + const options = getUploadOptions(); + + const client = new artifact.DefaultArtifactClient(); + const uploadPromise = client.uploadArtifact( + 'buildinfo.zip', + buildInfoPaths, + rootDirectory, + options + ); + + core.info('Started artifact buildinfo.zip upload'); + + uploadPromise.then(uploadResponse => { + core.info( + `Artifact buildinfo.zip has been successfully uploaded! Final size is ${uploadResponse.size} bytes. Artifact ID is ${uploadResponse.id}` + ); + + const repository = github.context.repo; + const artifactURL = `${github.context.serverUrl}/${repository.owner}/${repository.repo}/actions/runs/${github.context.runId}/artifacts/${uploadResponse.id}`; + core.info(`Artifact download URL: ${artifactURL}`); + + }).catch(err => { + core.error(err); + }); + +} + module.exports = { + findCommonDirectory, uploadArtifact, + uploadBuildInfo, }; diff --git a/src/run.js b/src/run.js index 630aae1..70114a6 100644 --- a/src/run.js +++ b/src/run.js @@ -1,7 +1,7 @@ const core = require('@actions/core'); const { readBuildInfoFiles } = require('./buildinfo.js'); const { searchBuildinfo } = require('./search.js'); -const { uploadArtifact } = require('./upload.js'); +const { uploadArtifact, uploadBuildInfo } = require('./upload.js'); function run() { try { @@ -9,6 +9,8 @@ function run() { let outputs = readBuildInfoFiles(buildInfoPaths); + uploadBuildInfo(buildInfoPaths); + if (outputs) { outputs.forEach(output => { uploadArtifact(output); diff --git a/src/upload.js b/src/upload.js index 45531bf..cdfb3ce 100644 --- a/src/upload.js +++ b/src/upload.js @@ -5,6 +5,30 @@ const github = require('@actions/github'); const { getUploadOptions } = require('./inputs.js'); +function findCommonDirectory(paths) { + // Split each path into parts + const pathParts = paths.map(path => path.split(/\/|\\/)); + const shortestPathLength = Math.min(...pathParts.map(parts => parts.length)); + + let commonParts = []; + if (pathParts.length > 0) { + for (let i = 0; i < shortestPathLength; i++) { + let currentPart = pathParts[0][i]; + + // Check if the current part is common to all paths + if (pathParts.every(parts => parts[i] === currentPart)) { + commonParts.push(currentPart); + } else { + // If a non-matching part is found, stop the search + break; + } + } + } + + const commonPath = commonParts.join("/"); + return commonPath; +} + function uploadArtifact(filePath) { core.info(`uploadArtifact(${filePath})`); @@ -46,6 +70,41 @@ function uploadArtifact(filePath) { } +function uploadBuildInfo(buildInfoPaths) { + + core.info(`uploadBuildInfo(${buildInfoPaths})`); + + const rootDirectory = findCommonDirectory(buildInfoPaths); + + const options = getUploadOptions(); + + const client = new artifact.DefaultArtifactClient(); + const uploadPromise = client.uploadArtifact( + 'buildinfo.zip', + buildInfoPaths, + rootDirectory, + options + ); + + core.info('Started artifact buildinfo.zip upload'); + + uploadPromise.then(uploadResponse => { + core.info( + `Artifact buildinfo.zip has been successfully uploaded! Final size is ${uploadResponse.size} bytes. Artifact ID is ${uploadResponse.id}` + ); + + const repository = github.context.repo; + const artifactURL = `${github.context.serverUrl}/${repository.owner}/${repository.repo}/actions/runs/${github.context.runId}/artifacts/${uploadResponse.id}`; + core.info(`Artifact download URL: ${artifactURL}`); + + }).catch(err => { + core.error(err); + }); + +} + module.exports = { + findCommonDirectory, uploadArtifact, + uploadBuildInfo, };