diff --git a/.gitattributes b/.gitattributes index e5de65de..8059fadd 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,4 @@ -* text=auto eof=lf +* text=auto eol=lf ################################################################################ # The following files are binary and should be left untouched. @@ -25,7 +25,6 @@ cfn-init binary *.node binary *.wasm binary -*.bat binary # Documents *.pdf binary @@ -36,7 +35,6 @@ cfn-init binary *.ppt binary *.pptx binary *.odt binary -*.csv binary # Images *.png binary @@ -48,7 +46,6 @@ cfn-init binary *.tif binary *.tiff binary *.webp binary -*.svg binary # Audio & Video *.mp3 binary @@ -63,3 +60,10 @@ cfn-init binary *.jks binary *.db binary *.sqlite binary + +# Windows batch files must always use CRLF, or they may fail to execute. +*.bat text eol=crlf +*.cmd text eol=crlf + +# PowerShell can handle LF, but CRLF is safer for Windows-specific scripts +*.ps1 text eol=crlf diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 23166af3..18efdfe9 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -58,11 +58,9 @@ jobs: run: npm run build - name: Code Quality - if: runner.os != 'Windows' run: npm run lint && npm run check:duplicates - name: Test - if: runner.os != 'Windows' run: npm run test build-test-go: diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 5b4ac06b..9a312b0c 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -12,9 +12,9 @@ jobs: pr-build-test-nodejs: needs: [ get-configs ] strategy: - fail-fast: true + fail-fast: false matrix: - os: [ ubuntu-latest, macos-latest ] + os: [ ubuntu-latest, macos-latest, windows-latest ] runs-on: ${{ matrix.os }} permissions: contents: read @@ -35,7 +35,6 @@ jobs: run: npm run build - name: Code Quality - if: runner.os != 'Windows' run: npm run lint && npm run check:duplicates - name: Test @@ -44,9 +43,9 @@ jobs: pr-build-test-go: needs: [ get-configs ] strategy: - fail-fast: true + fail-fast: false matrix: - os: [ ubuntu-latest, macos-latest ] + os: [ ubuntu-latest, macos-latest, windows-latest ] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v5 diff --git a/src/utils/ErrorStackInfo.ts b/src/utils/ErrorStackInfo.ts index d70485fd..a2c0dff4 100644 --- a/src/utils/ErrorStackInfo.ts +++ b/src/utils/ErrorStackInfo.ts @@ -12,12 +12,12 @@ export function determineSensitiveInfo(): string[] { errorStackInfo = __dirname .replaceAll('\\\\', '/') .replaceAll('\\', '/') - .split('/') + .split(/[/:]/) .map((x) => { return x.trim(); }) .filter((x) => { - return x.length > 0; + return x.length > 1; }); } catch (err) { LoggerFactory.getLogger('SensitiveInfo').warn(err, 'Cannot get __dirname'); diff --git a/tst/unit/artifactexporter/ArtifactExporter.test.ts b/tst/unit/artifactexporter/ArtifactExporter.test.ts index a2b66b67..9b849c45 100644 --- a/tst/unit/artifactexporter/ArtifactExporter.test.ts +++ b/tst/unit/artifactexporter/ArtifactExporter.test.ts @@ -1,20 +1,17 @@ -import { existsSync, statSync, mkdtempSync, copyFileSync } from 'fs'; -import { tmpdir } from 'os'; -import { join, basename, extname } from 'path'; +import { join } from 'path'; +import { pathToFileURL } from 'url'; import { describe, it, expect, vi, beforeEach } from 'vitest'; import { ArtifactExporter } from '../../../src/artifactexporter/ArtifactExporter'; import { DocumentType } from '../../../src/document/Document'; import { S3Service } from '../../../src/services/S3Service'; vi.mock('../../../src/services/S3Service'); -vi.mock('fs'); -vi.mock('os'); -vi.mock('path'); -vi.mock('archiver'); + +const FIXTURES_DIR = join(__dirname, '..', '..', 'resources', 'templates', 'artifact'); describe('ArtifactExporter', () => { let mockS3Service: S3Service; - const templatePath = `file:///${join(__dirname, 'template.yaml')}`; + const templatePath = pathToFileURL(join(FIXTURES_DIR, 'template.yaml')).href; const BASIC_TEMPLATE = 'Resources:\n Bucket:\n Type: AWS::S3::Bucket'; @@ -23,7 +20,7 @@ Resources: MyFunction: Type: AWS::Lambda::Function Properties: - Code: ./src/lambda + Code: ./code Runtime: nodejs18.x Handler: index.handler FunctionName: MyTestFunction @@ -62,22 +59,6 @@ Resources: putObjectContent: vi.fn(), putObject: vi.fn().mockResolvedValue({ VersionId: 'v123' }), } as any; - - vi.mocked(existsSync).mockReturnValue(true); - vi.mocked(statSync).mockReturnValue({ - isFile: () => true, - isDirectory: () => false, - } as any); - vi.mocked(tmpdir).mockReturnValue('/tmp'); - vi.mocked(join).mockImplementation((...args) => args.join('/')); - vi.mocked(basename).mockImplementation((path) => path?.split('/').pop() ?? ''); - vi.mocked(extname).mockImplementation((path) => { - if (!path) return ''; - const parts = path.split('.'); - return parts.length > 1 ? '.' + parts[parts.length - 1] : ''; - }); - vi.mocked(mkdtempSync).mockReturnValue('/tmp/cfn-123'); - vi.mocked(copyFileSync).mockImplementation(() => {}); }); describe('getTemplateArtifacts', () => { @@ -88,7 +69,7 @@ Resources: expect(artifacts).toEqual([ { resourceType: 'AWS::Lambda::Function', - filePath: './src/lambda', + filePath: './code', }, ]); }); @@ -111,7 +92,7 @@ Resources: const template = new ArtifactExporter( mockS3Service, DocumentType.YAML, - `file:///${join(__dirname, 'path/to/template.yaml')}`, + pathToFileURL(join(FIXTURES_DIR, 'path/to/template.yaml')).href, BASIC_TEMPLATE, ); expect(template).toBeDefined(); @@ -121,7 +102,7 @@ Resources: const template = new ArtifactExporter( mockS3Service, DocumentType.YAML, - `file:///${join(__dirname, 'path/to/template.yaml')}`, + pathToFileURL(join(FIXTURES_DIR, 'path/to/template.yaml')).href, BASIC_TEMPLATE, ); const result = await template.export('test-bucket'); @@ -133,10 +114,15 @@ Resources: const result = await exporter.export('test-bucket'); + expect(mockS3Service.putObject).toHaveBeenCalledWith( + expect.stringMatching(/\.zip$/), + expect.stringMatching(/^s3:\/\/test-bucket\/artifact\/.*\.zip$/), + ); + const resources = (result as any).Resources; expect(resources.MyFunction.Properties.Code).toEqual({ S3Bucket: 'test-bucket', - S3Key: expect.stringMatching(/^artifact\/cfn-123-\d+$/), + S3Key: expect.stringMatching(/^artifact\/.*\.zip$/), S3ObjectVersion: 'v123', }); expect(resources.MyFunction.Properties.Runtime).toBe('nodejs18.x'); @@ -147,17 +133,17 @@ Resources: }); it('should update Serverless function CodeUri to S3 URL', async () => { - const exporter = new ArtifactExporter( - mockS3Service, - DocumentType.YAML, - `file:///${join(__dirname, 'template.yaml')}`, - SERVERLESS_TEMPLATE, - ); + const exporter = new ArtifactExporter(mockS3Service, DocumentType.YAML, templatePath, SERVERLESS_TEMPLATE); const result = await exporter.export('my-bucket'); + expect(mockS3Service.putObject).toHaveBeenCalledWith( + expect.stringMatching(/\.zip$/), + expect.stringMatching(/^s3:\/\/my-bucket\/artifact\/.*\.zip$/), + ); + const resources = (result as any).Resources; - expect(resources.MyFunction.Properties.CodeUri).toMatch(/^s3:\/\/my-bucket\/artifact\/cfn-123-\d+$/); + expect(resources.MyFunction.Properties.CodeUri).toMatch(/^s3:\/\/my-bucket\/artifact\/.*\.zip$/); expect(resources.MyFunction.Properties.Runtime).toBe('python3.9'); expect(resources.MyFunction.Properties.Handler).toBe('app.lambda_handler'); expect(resources.MyFunction.Properties.Description).toBe('Test serverless function'); diff --git a/tst/unit/services/cfnLint/PyodideWorkerManager.test.ts b/tst/unit/services/cfnLint/PyodideWorkerManager.test.ts index b37663c5..e619b827 100644 --- a/tst/unit/services/cfnLint/PyodideWorkerManager.test.ts +++ b/tst/unit/services/cfnLint/PyodideWorkerManager.test.ts @@ -925,7 +925,7 @@ describe('PyodideWorkerManager', () => { }); // Expect initialization to fail with timeout error - await expect(retryWorkerManager.initialize()).rejects.toThrow(/Pyodide initialization timed out after 3/); + await expect(retryWorkerManager.initialize()).rejects.toThrow(/Pyodide initialization timed out after/); const totalTime = Date.now() - startTime; diff --git a/vitest.config.ts b/vitest.config.ts index 271cc84f..87991e15 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -13,10 +13,10 @@ export default defineConfig({ include: ['src/**/*.{js,ts}'], enabled: true, thresholds: { - statements: 85, - branches: 85, - functions: 85, - lines: 85, + statements: 88, + branches: 88, + functions: 88, + lines: 88, }, exclude: [ 'src/ai/**',