Skip to content

Commit 4069db1

Browse files
Remove certain maven metadata from uploaded dependencies. (aws#4704)
* Remove certain maven metadata from uploaded dependencies. * Add test ensuring correct dependencies added to Q Code Transform upload zip. * Address comments and fix ci. * Add changelog. --------- Co-authored-by: Leonardo Araneda Freccero <[email protected]>
1 parent b7dc203 commit 4069db1

File tree

3 files changed

+90
-1
lines changed

3 files changed

+90
-1
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Bug Fix",
3+
"description": "Amazon Q Code Transformation - Omit Maven metadata files when uploading dependencies to fix certain build failures in backend."
4+
}

packages/core/src/codewhisperer/service/transformByQ/transformApiHandler.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,27 @@ export async function uploadPayload(payloadFileName: string) {
195195
return response.uploadId
196196
}
197197

198+
/**
199+
* Array of file extensions used by Maven as metadata in the local repository.
200+
* Files with these extensions influence Maven's behavior during compile time,
201+
* particularly in checking the availability of source repositories and potentially
202+
* re-downloading dependencies if the source is not accessible. Removing these
203+
* files can prevent Maven from attempting to download dependencies again.
204+
*/
205+
const MavenExcludedExtensions = ['.repositories', '.sha1']
206+
207+
/**
208+
* Determines if the specified file path corresponds to a Maven metadata file
209+
* by checking against known metadata file extensions. This is used to identify
210+
* files that might trigger Maven to recheck or redownload dependencies from source repositories.
211+
*
212+
* @param path The file path to evaluate for exclusion based on its extension.
213+
* @returns {boolean} Returns true if the path ends with an extension associated with Maven metadata files; otherwise, false.
214+
*/
215+
function isExcludedDependencyFile(path: string): boolean {
216+
return MavenExcludedExtensions.some(extension => path.endsWith(extension))
217+
}
218+
198219
/**
199220
* Gets all files in dir. We use this method to get the source code, then we run a mvn command to
200221
* copy over dependencies into their own folder, then we use this method again to get those
@@ -252,6 +273,9 @@ export async function zipCode(dependenciesFolder: FolderInfo) {
252273

253274
if (dependencyFiles.length > 0) {
254275
for (const file of dependencyFiles) {
276+
if (isExcludedDependencyFile(file)) {
277+
continue
278+
}
255279
const relativePath = path.relative(dependenciesFolder.path, file)
256280
const paddedPath = path.join(`dependencies/${dependenciesFolder.name}`, relativePath)
257281
zip.addLocalFile(file, path.dirname(paddedPath))

packages/core/src/test/codewhisperer/commands/transformByQ.test.ts

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@
55

66
import assert from 'assert'
77
import * as vscode from 'vscode'
8+
import * as fs from 'fs-extra'
89
import * as sinon from 'sinon'
10+
import { makeTemporaryToolkitFolder } from '../../../shared/filesystemUtilities'
911
import * as model from '../../../codewhisperer/models/model'
1012
import * as startTransformByQ from '../../../codewhisperer/commands/startTransformByQ'
1113
import { HttpResponse } from 'aws-sdk'
1214
import * as codeWhisperer from '../../../codewhisperer/client/codewhisperer'
1315
import * as CodeWhispererConstants from '../../../codewhisperer/models/constants'
1416
import { getTestWindow } from '../../shared/vscode/window'
17+
import AdmZip from 'adm-zip'
1518
import { stopTransformByQMessage } from '../../../codewhisperer/models/constants'
1619
import { convertToTimeString, convertDateToTimestamp } from '../../../shared/utilities/textUtilities'
1720
import path from 'path'
@@ -26,6 +29,7 @@ import {
2629
pollTransformationJob,
2730
getHeadersObj,
2831
throwIfCancelled,
32+
zipCode,
2933
} from '../../../codewhisperer/service/transformByQ/transformApiHandler'
3034
import {
3135
validateOpenProjects,
@@ -34,8 +38,15 @@ import {
3438
import { TransformationCandidateProject } from '../../../codewhisperer/models/model'
3539

3640
describe('transformByQ', function () {
37-
afterEach(function () {
41+
let tempDir: string
42+
43+
beforeEach(async function () {
44+
tempDir = await makeTemporaryToolkitFolder()
45+
})
46+
47+
afterEach(async function () {
3848
sinon.restore()
49+
await fs.remove(tempDir)
3950
})
4051

4152
it('WHEN converting short duration in milliseconds THEN converts correctly', async function () {
@@ -199,4 +210,54 @@ describe('transformByQ', function () {
199210
}
200211
assert.deepStrictEqual(actual, expected)
201212
})
213+
214+
it(`WHEN zip created THEN dependencies contains no .sha1 or .repositories files`, async function () {
215+
const m2Folders = [
216+
'com/groupid1/artifactid1/version1',
217+
'com/groupid1/artifactid1/version2',
218+
'com/groupid1/artifactid2/version1',
219+
'com/groupid2/artifactid1/version1',
220+
'com/groupid2/artifactid1/version2',
221+
]
222+
// List of files that exist in m2 artifact directory
223+
const filesToAdd = [
224+
'_remote.repositories',
225+
'test-0.0.1-20240315.145420-18.pom',
226+
'test-0.0.1-20240315.145420-18.pom.sha1',
227+
'test-0.0.1-SNAPSHOT.pom',
228+
'maven-metadata-test-repo.xml',
229+
'maven-metadata-test-repo.xml.sha1',
230+
'resolver-status.properties',
231+
]
232+
const expectedFilesAfterClean = [
233+
'test-0.0.1-20240315.145420-18.pom',
234+
'test-0.0.1-SNAPSHOT.pom',
235+
'maven-metadata-test-repo.xml',
236+
'resolver-status.properties',
237+
]
238+
239+
m2Folders.forEach(folder => {
240+
const folderPath = path.join(tempDir, folder)
241+
fs.mkdirSync(folderPath, { recursive: true })
242+
filesToAdd.forEach(file => {
243+
fs.writeFileSync(path.join(folderPath, file), 'sample content for the test file')
244+
})
245+
})
246+
247+
const tempFileName = `testfile-${Date.now()}.zip`
248+
model.transformByQState.setProjectPath(tempDir)
249+
return zipCode({
250+
path: tempDir,
251+
name: tempFileName,
252+
}).then(zipFile => {
253+
const zip = new AdmZip(zipFile)
254+
const dependenciesToUpload = zip.getEntries().filter(entry => entry.entryName.startsWith('dependencies'))
255+
// Each dependency version folder contains each expected file, thus we multiply
256+
const expectedNumberOfDependencyFiles = m2Folders.length * expectedFilesAfterClean.length
257+
assert.strictEqual(expectedNumberOfDependencyFiles, dependenciesToUpload.length)
258+
dependenciesToUpload.forEach(dependency => {
259+
assert(expectedFilesAfterClean.includes(dependency.name))
260+
})
261+
})
262+
})
202263
})

0 commit comments

Comments
 (0)