diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d70f0a60a7..895410453a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -40,7 +40,8 @@ jobs: uses: googleapis/release-please-action@a02a34c4d625f9be7cb89156071d8567266a2445 # v4.2.0 with: target-branch: ${{ steps.branch.outputs.name }} - release-type: terraform-module + manifest-file: .release-please-manifest.json + config-file: .release-please-config.json token: ${{ steps.token.outputs.token }} - name: Attest if: ${{ steps.release.outputs.releases_created == 'true' }} diff --git a/.release-please-config.json b/.release-please-config.json new file mode 100644 index 0000000000..7c55680405 --- /dev/null +++ b/.release-please-config.json @@ -0,0 +1,34 @@ +{ + "release-type": "simple", + "packages": { + ".": { + "extra-files": [ + { + "type": "json", + "path": "lambdas/functions/ami-housekeeper/package.json", + "jsonpath": "$.version" + }, + { + "type": "json", + "path": "lambdas/functions/control-plane/package.json", + "jsonpath": "$.version" + }, + { + "type": "json", + "path": "lambdas/functions/gh-agent-syncer/package.json", + "jsonpath": "$.version" + }, + { + "type": "json", + "path": "lambdas/functions/termination-watcher/package.json", + "jsonpath": "$.version" + }, + { + "type": "json", + "path": "lambdas/functions/webhook/package.json", + "jsonpath": "$.version" + } + ] + } + } +} diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000000..2f0a9c430f --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "6.6.0" +} diff --git a/lambdas/libs/aws-powertools-util/src/logger/index.ts b/lambdas/libs/aws-powertools-util/src/logger/index.ts index 195b552a74..f3fdbe3c6e 100644 --- a/lambdas/libs/aws-powertools-util/src/logger/index.ts +++ b/lambdas/libs/aws-powertools-util/src/logger/index.ts @@ -1,17 +1,34 @@ import { Logger } from '@aws-lambda-powertools/logger'; import { Context } from 'aws-lambda'; +import * as fs from 'fs'; +import * as path from 'path'; +import { fileURLToPath } from 'url'; const childLoggers: Logger[] = []; +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + const defaultValues = { region: process.env.AWS_REGION, environment: process.env.ENVIRONMENT || 'N/A', }; +function getReleaseVersion(): string { + let version = 'unknown'; + try { + const packageFilePath = path.resolve(__dirname, 'package.json'); + version = JSON.parse(fs.readFileSync(packageFilePath, 'utf-8')).version || 'unknown'; + } catch (error) { + logger.debug(`Failed to read package.json for version: ${(error as Error)?.message ?? 'Unknown error'}`); + } + return version; +} + function setContext(context: Context, module?: string) { logger.addPersistentLogAttributes({ 'aws-request-id': context.awsRequestId, 'function-name': context.functionName, + version: getReleaseVersion(), module: module, }); @@ -20,6 +37,7 @@ function setContext(context: Context, module?: string) { childLogger.addPersistentLogAttributes({ 'aws-request-id': context.awsRequestId, 'function-name': context.functionName, + version: getReleaseVersion(), }); }); } diff --git a/lambdas/libs/aws-powertools-util/src/logger/logger.test.ts b/lambdas/libs/aws-powertools-util/src/logger/logger.test.ts index bcdc44f677..b68668b2a1 100644 --- a/lambdas/libs/aws-powertools-util/src/logger/logger.test.ts +++ b/lambdas/libs/aws-powertools-util/src/logger/logger.test.ts @@ -1,7 +1,8 @@ import { Context } from 'aws-lambda'; +import * as fs from 'fs'; +import * as path from 'path'; -import { logger, setContext } from '../'; -import { describe, test, expect, beforeEach, vi } from 'vitest'; +import { describe, test, expect, beforeEach, afterEach, vi } from 'vitest'; beforeEach(() => { vi.clearAllMocks(); @@ -29,6 +30,31 @@ const context: Context = { }, }; +const versionFilePath = path.resolve(__dirname, 'package.json'); + +let logger: typeof import('../').logger; +let setContext: typeof import('../').setContext; + +beforeEach(async () => { + // Clear the module cache and reload the logger module + vi.resetModules(); + const loggerModule = await import('../'); + logger = loggerModule.logger; + setContext = loggerModule.setContext; + + // Ensure a clean state before each test + if (fs.existsSync(versionFilePath)) { + fs.unlinkSync(versionFilePath); + } +}); + +afterEach(() => { + // Clean up after each test + if (fs.existsSync(versionFilePath)) { + fs.unlinkSync(versionFilePath); + } +}); + describe('A root logger.', () => { test('Should log set context.', async () => { setContext(context, 'unit-test'); @@ -42,3 +68,48 @@ describe('A root logger.', () => { ); }); }); + +describe('Logger version handling', () => { + test('Should not fail if package.json does not exist', () => { + // Temporarily rename package.json to simulate its absence + const tempFilePath = `${versionFilePath}.bak`; + if (fs.existsSync(versionFilePath)) { + fs.renameSync(versionFilePath, tempFilePath); + } + + setContext(context, 'unit-test'); + + expect(logger.getPersistentLogAttributes()).toEqual( + expect.objectContaining({ + version: 'unknown', + }), + ); + + // Restore package.json + if (fs.existsSync(tempFilePath)) { + fs.renameSync(tempFilePath, versionFilePath); + } + }); + + test('Should log version from package.json', () => { + // Create a mock package.json file + const originalPackageData = fs.existsSync(versionFilePath) ? fs.readFileSync(packageFilePath, 'utf-8') : null; + const mockPackageData = JSON.stringify({ version: '1.0.0' }); + fs.writeFileSync(versionFilePath, mockPackageData); + + setContext(context, 'unit-test'); + + expect(logger.getPersistentLogAttributes()).toEqual( + expect.objectContaining({ + version: '1.0.0', + }), + ); + + // Restore the original package.json file + if (originalPackageData) { + fs.writeFileSync(versionFilePath, originalPackageData); + } else { + fs.unlinkSync(versionFilePath); + } + }); +});