From da3805bd257d006512797aef40398a21aecba54b Mon Sep 17 00:00:00 2001 From: usimd <11619247+usimd@users.noreply.github.com> Date: Mon, 14 Oct 2024 14:04:42 +0200 Subject: [PATCH] Relaxe required stage directory check for Buster --- __test__/pi-gen.test.ts | 78 ++++++++++++++++++++++++++--------------- src/pi-gen.ts | 25 ++++++++----- 2 files changed, 65 insertions(+), 38 deletions(-) diff --git a/__test__/pi-gen.test.ts b/__test__/pi-gen.test.ts index 561c6ef..1ce09c9 100644 --- a/__test__/pi-gen.test.ts +++ b/__test__/pi-gen.test.ts @@ -16,23 +16,22 @@ jest.mock('../src/pi-gen-config', () => ({ })) const mockPiGenDependencies = ( - stageDirectories = Object.values(PiGenStages) + stageDirectories = Object.values(PiGenStages), + buildFiles = ['build-docker.sh', 'Dockerfile'] ) => { jest .spyOn(fs.promises, 'stat') .mockResolvedValueOnce({isDirectory: () => true} as fs.Stats) jest.spyOn(fs.promises, 'readdir').mockResolvedValueOnce([ - { - name: 'Dockerfile', - isFile: () => true, - isDirectory: () => false - } as Dirent, - { - name: 'build-docker.sh', - isFile: () => true, - isDirectory: () => false - } as Dirent, + ...buildFiles.map( + fileName => + ({ + name: fileName, + isFile: () => true, + isDirectory: () => false + }) as Dirent + ), ...(stageDirectories.map(stage => ({ name: stage, isDirectory: () => true, @@ -53,23 +52,20 @@ describe('PiGen', () => { } ) - it('should fail on missing entries at pi-gen path', async () => { - jest - .spyOn(fs.promises, 'stat') - .mockResolvedValue({isDirectory: () => true} as fs.Stats) - jest.spyOn(fs.promises, 'readdir').mockResolvedValue([ - { - name: 'Dockerfile', - isFile: () => true, - isDirectory: () => false - } as Dirent, - {name: 'stage0', isDirectory: () => true, isFile: () => false} as Dirent - ]) + it.each(['build-docker.sh', 'Dockerfile'])( + 'should fail if only pi-gen core build file %s is present and others missing', + async buildFile => { + mockPiGenDependencies(Object.values(PiGenStages), [buildFile]) - await expect( - async () => await PiGen.getInstance('pi-gen-dir', DEFAULT_CONFIG) - ).rejects.toThrow() - }) + await expect( + async () => + await PiGen.getInstance('pi-gen-dir', { + ...DEFAULT_CONFIG, + stageList: ['stage0'] + }) + ).rejects.toThrow() + } + ) it('should fail on missing required stage entries at pi-gen path', async () => { mockPiGenDependencies(['stage0', 'stage1']) @@ -78,7 +74,11 @@ describe('PiGen', () => { .mockResolvedValue({isDirectory: () => true} as fs.Stats) await expect( - async () => await PiGen.getInstance('pi-gen-dir', DEFAULT_CONFIG) + async () => + await PiGen.getInstance('pi-gen-dir', { + ...DEFAULT_CONFIG, + stageList: ['stage0', 'stage1', 'stage2'] + }) ).rejects.toThrow() }) @@ -172,6 +172,23 @@ describe('PiGen', () => { expect(fs.existsSync(`${stageList[1]}/EXPORT_NOOBS`)).toBeFalsy() }) + it('does not require a stage5 directory for Buster', async () => { + const piGenDir = 'pi-gen' + const busterStages = ['stage0', 'stage1', 'stage2', 'stage3', 'stage4'] + mockPiGenDependencies(busterStages) + jest.spyOn(fs, 'realpathSync').mockReturnValueOnce('/pi-gen/stage0') + // If user added a 'stage5', don't fail + let config = { + ...DEFAULT_CONFIG, + release: 'buster', + stageList: [...busterStages, 'stage5'] + } as PiGenConfig + + const pigen = PiGen.getInstance(piGenDir, config) + + await expect(pigen).resolves.not.toThrow() + }) + it.each([ [ false, @@ -219,7 +236,10 @@ describe('PiGen', () => { jest.spyOn(core, 'warning').mockImplementation(s => {}) mockPiGenDependencies() - const piGenSut = new PiGen('pi-gen', DEFAULT_CONFIG) + const piGenSut = new PiGen('pi-gen', { + ...DEFAULT_CONFIG, + stageList: ['stage0'] + }) piGenSut.logOutput(line, verbose, stream as 'info' | 'warning') expect( diff --git a/src/pi-gen.ts b/src/pi-gen.ts index 947020b..a5c1d3d 100644 --- a/src/pi-gen.ts +++ b/src/pi-gen.ts @@ -22,11 +22,12 @@ export class PiGen { piGenDirectory: string, config: PiGenConfig ): Promise { - if (!(await PiGen.validatePigenDirectory(piGenDirectory))) { + const instance = new PiGen(piGenDirectory, config) + + if (!(await instance.validatePigenDirectory())) { throw new Error(`pi-gen directory at ${piGenDirectory} is invalid`) } - const instance = new PiGen(piGenDirectory, config) core.debug(`Writing user config to ${instance.configFilePath}`) await writeToFile( instance.config, @@ -105,27 +106,33 @@ export class PiGen { return foundImages.length > 0 ? path.dirname(foundImages[0]) : undefined } - private static async validatePigenDirectory( - piGenDirectory: string - ): Promise { + private async validatePigenDirectory(): Promise { try { - const dirStat = await fs.promises.stat(piGenDirectory) + const dirStat = await fs.promises.stat(this.piGenDirectory) if (!dirStat.isDirectory()) { - core.debug(`Not a directory: ${piGenDirectory}`) + core.debug(`Not a directory: ${this.piGenDirectory}`) return false } } catch (error) { return false } - const piGenDirContent = await fs.promises.readdir(piGenDirectory, { + const piGenDirContent = await fs.promises.readdir(this.piGenDirectory, { withFileTypes: true }) const requiredFiles = ['build-docker.sh', 'Dockerfile'] - const requiredDirectories = Object.values(PiGenStages).filter( + let requiredDirectories = Object.values(PiGenStages).filter( value => typeof value === 'string' ) as string[] + + // https://github.com/usimd/pi-gen-action/issues/125 + // It seems like RaspiOS based on Buster is lacking a `stage5` while all + // other versions include one. + if (this.config.release?.toLowerCase().trim() == 'buster') { + requiredDirectories = requiredDirectories.filter(dir => dir !== 'stage5') + } + const existingFiles = piGenDirContent .filter(entry => entry.isFile()) .map(entry => entry.name)