diff --git a/packages/core/src/shared/codelens/javaCodeLensProvider.ts b/packages/core/src/shared/codelens/javaCodeLensProvider.ts index 58eda7fc4b2..d233a52ef45 100644 --- a/packages/core/src/shared/codelens/javaCodeLensProvider.ts +++ b/packages/core/src/shared/codelens/javaCodeLensProvider.ts @@ -14,7 +14,7 @@ export const javaAllfiles: vscode.DocumentFilter[] = [ language: javaLanguage, }, ] -export const gradleBasePattern = '**/build.gradle' +export const gradleBasePattern = '**/*.gradle{,.kts}' export const mavenBasePattern = '**/pom.xml' const regexpReservedWordPublic = /\bpublic \b/ @@ -32,7 +32,7 @@ export interface JavaLambdaHandlerComponents { export async function getLambdaHandlerCandidates(document: vscode.TextDocument): Promise { const rootUri = (await findParentProjectFile(document.uri, /^.*pom.xml$/)) ?? - (await findParentProjectFile(document.uri, /^.*build.gradle$/)) + (await findParentProjectFile(document.uri, /^.*\.gradle(\.kts)?$/)) if (!rootUri) { return [] } diff --git a/packages/core/src/test/shared/codelens/javaCodeLensProvider.test.ts b/packages/core/src/test/shared/codelens/javaCodeLensProvider.test.ts index f7d42d516b6..db7d21ee7c2 100644 --- a/packages/core/src/test/shared/codelens/javaCodeLensProvider.test.ts +++ b/packages/core/src/test/shared/codelens/javaCodeLensProvider.test.ts @@ -9,7 +9,9 @@ import * as path from 'path' import * as vscode from 'vscode' import { generateJavaLambdaHandler, + getLambdaHandlerCandidates, getLambdaHandlerComponents, + gradleBasePattern, isValidClassSymbol, isValidLambdaHandler, JavaLambdaHandlerComponents, @@ -21,6 +23,97 @@ import { fs } from '../../../shared' const fakeRange = new vscode.Range(0, 0, 0, 0) describe('javaCodeLensProvider', () => { + describe('gradleBasePattern', () => { + // The regex used in getLambdaHandlerCandidates to match Gradle build files. + const gradleRegex = /^.*\.gradle(\.kts)?$/ + + it('matches build.gradle', () => { + assert.ok(gradleRegex.test('build.gradle'), 'Expected pattern to match build.gradle') + assert.ok(gradleRegex.test('/path/to/build.gradle'), 'Expected pattern to match path/to/build.gradle') + }) + + it('matches build.gradle.kts', () => { + assert.ok(gradleRegex.test('build.gradle.kts'), 'Expected pattern to match build.gradle.kts') + assert.ok( + gradleRegex.test('/path/to/build.gradle.kts'), + 'Expected pattern to match path/to/build.gradle.kts' + ) + }) + + it('matches custom-named gradle files like brazil.gradle.kts', () => { + assert.ok(gradleRegex.test('brazil.gradle.kts'), 'Expected pattern to match brazil.gradle.kts') + assert.ok( + gradleRegex.test('/path/to/brazil.gradle.kts'), + 'Expected pattern to match path/to/brazil.gradle.kts' + ) + assert.ok(gradleRegex.test('brazil.gradle'), 'Expected pattern to match brazil.gradle') + }) + + it('gradleBasePattern glob matches any *.gradle and *.gradle.kts files', () => { + assert.strictEqual(gradleBasePattern, '**/*.gradle{,.kts}') + }) + }) + + describe('getLambdaHandlerCandidates', () => { + let tempFolder: string + + beforeEach(async () => { + tempFolder = await makeTemporaryToolkitFolder() + }) + + afterEach(async () => { + await fs.delete(tempFolder, { recursive: true }) + }) + + it('returns empty array when no gradle build file exists', async function () { + const programFile = path.join(tempFolder, 'App.java') + await fs.writeFile(programFile, SampleJavaSamProgram.getFunctionText()) + const textDoc = await vscode.workspace.openTextDocument(programFile) + + const candidates = await getLambdaHandlerCandidates(textDoc) + assert.strictEqual(candidates.length, 0, 'Expected no candidates when no build file exists') + }) + + it('detects handler candidates when build.gradle exists', async function () { + const buildFile = path.join(tempFolder, 'build.gradle') + await fs.writeFile(buildFile, '') + const programFile = path.join(tempFolder, 'App.java') + await fs.writeFile(programFile, SampleJavaSamProgram.getFunctionText()) + const textDoc = await vscode.workspace.openTextDocument(programFile) + + // getLambdaHandlerCandidates calls vscode.executeDocumentSymbolProvider which + // requires a real language server; we verify it at least finds the project root + // (i.e. does not return early with an empty array due to missing build file). + // The function will return [] only if rootUri is falsy, so a non-empty result + // (or a result that didn't throw) confirms the build file was found. + // Since we can't easily mock the symbol provider in unit tests, we just assert + // the function resolves without error. + await assert.doesNotReject(getLambdaHandlerCandidates(textDoc)) + }) + + it('detects handler candidates when build.gradle.kts exists', async function () { + const buildFile = path.join(tempFolder, 'build.gradle.kts') + await fs.writeFile(buildFile, '') + const programFile = path.join(tempFolder, 'App.java') + await fs.writeFile(programFile, SampleJavaSamProgram.getFunctionText()) + const textDoc = await vscode.workspace.openTextDocument(programFile) + + await assert.doesNotReject(getLambdaHandlerCandidates(textDoc)) + }) + + it('detects handler candidates when a custom-named gradle file like brazil.gradle.kts exists', async function () { + const buildFile = path.join(tempFolder, 'brazil.gradle.kts') + await fs.writeFile(buildFile, '') + const programFile = path.join(tempFolder, 'App.java') + await fs.writeFile(programFile, SampleJavaSamProgram.getFunctionText()) + const textDoc = await vscode.workspace.openTextDocument(programFile) + + // Before the fix, the extension only checked for 'build.gradle' and would not + // recognize 'brazil.gradle.kts' as a valid Gradle build file. + await assert.doesNotReject(getLambdaHandlerCandidates(textDoc)) + }) + }) + describe('getLambdaHandlerComponents', () => { let tempFolder: string diff --git a/packages/core/src/testInteg/sam.test.ts b/packages/core/src/testInteg/sam.test.ts index 4f80d550df8..a3787452ccf 100644 --- a/packages/core/src/testInteg/sam.test.ts +++ b/packages/core/src/testInteg/sam.test.ts @@ -441,7 +441,7 @@ describe('SAM Integration Tests', async function () { manifestFile = /^.*pom\.xml$/ break } else if (scenario.dependencyManager === 'gradle') { - manifestFile = /^.*build\.gradle$/ + manifestFile = /^.*\.gradle(\.kts)?$/ break } assert.fail(`invalid dependency manager for java: ${scenario.dependencyManager}`) diff --git a/packages/toolkit/.changes/next-release/Feature-bf620753-052f-41f8-9055-74bc0e23630a.json b/packages/toolkit/.changes/next-release/Feature-bf620753-052f-41f8-9055-74bc0e23630a.json new file mode 100644 index 00000000000..02012a3635c --- /dev/null +++ b/packages/toolkit/.changes/next-release/Feature-bf620753-052f-41f8-9055-74bc0e23630a.json @@ -0,0 +1,4 @@ +{ + "type": "Feature", + "description": "SAM Codelens to support gradle.kts format" +}