diff --git a/.changeset/early-seahorses-stare.md b/.changeset/early-seahorses-stare.md deleted file mode 100644 index 963058a26f..0000000000 --- a/.changeset/early-seahorses-stare.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Fixing issue with `AzureUrlReader` that doesn't do `subpath` directories correctly diff --git a/packages/backend-common/src/reading/AzureUrlReader.test.ts b/packages/backend-common/src/reading/AzureUrlReader.test.ts index fc1f6a03f3..c7c8853929 100644 --- a/packages/backend-common/src/reading/AzureUrlReader.test.ts +++ b/packages/backend-common/src/reading/AzureUrlReader.test.ts @@ -220,21 +220,6 @@ describe('AzureUrlReader', () => { expect(indexMarkdownFile.toString()).toBe('# Test\n'); }); - it('returns the wanted files from an archive when a subpath is passed through', async () => { - const response = await processor.readTree( - 'https://dev.azure.com/organization/project/_git/repository?path=%2Fdocs', - ); - - expect(response.etag).toBe('123abc2'); - - const files = await response.files(); - - expect(files.length).toBe(1); - const indexMarkdownFile = await files[0].content(); - - expect(indexMarkdownFile.toString()).toBe('# Test\n'); - }); - it('creates a directory with the wanted files', async () => { const response = await processor.readTree( 'https://dev.azure.com/organization/project/_git/repository', diff --git a/packages/backend-common/src/reading/AzureUrlReader.ts b/packages/backend-common/src/reading/AzureUrlReader.ts index 2269393cbf..910e8e04a5 100644 --- a/packages/backend-common/src/reading/AzureUrlReader.ts +++ b/packages/backend-common/src/reading/AzureUrlReader.ts @@ -94,6 +94,8 @@ export class AzureUrlReader implements UrlReader { url: string, options?: ReadTreeOptions, ): Promise { + // TODO: Support filepath based reading tree feature like other providers + // Get latest commit SHA const commitsAzureResponse = await fetch( @@ -127,13 +129,10 @@ export class AzureUrlReader implements UrlReader { throw new Error(message); } - const { filepath } = parseGitUrl(url); - return await this.deps.treeResponseFactory.fromZipArchive({ stream: archiveAzureResponse.body as unknown as Readable, etag: commitSha, filter: options?.filter, - subpath: filepath, }); } diff --git a/packages/backend-common/src/reading/tree/ZipArchiveResponse.test.ts b/packages/backend-common/src/reading/tree/ZipArchiveResponse.test.ts index a54bac0c4a..f6f9a7845a 100644 --- a/packages/backend-common/src/reading/tree/ZipArchiveResponse.test.ts +++ b/packages/backend-common/src/reading/tree/ZipArchiveResponse.test.ts @@ -62,6 +62,36 @@ describe('ZipArchiveResponse', () => { ]); }); + it('should read files and strip root dir if requested', async () => { + const stream = fs.createReadStream('/test-archive-with-extra-root-dir.zip'); + + const res = new ZipArchiveResponse( + stream, + '', + '/tmp', + 'etag', + undefined, + true, + ); + const files = await res.files(); + + expect(files).toEqual([ + { + path: 'mkdocs.yml', + content: expect.any(Function), + }, + { + path: 'docs/index.md', + content: expect.any(Function), + }, + ]); + const contents = await Promise.all(files.map(f => f.content())); + expect(contents.map(c => c.toString('utf8').trim())).toEqual([ + 'site_name: Test', + '# Test', + ]); + }); + it('should read files with filter', async () => { const stream = fs.createReadStream('/test-archive.zip'); diff --git a/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts b/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts index e07cedde87..fb22f24b94 100644 --- a/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts +++ b/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts @@ -24,6 +24,7 @@ import { ReadTreeResponseDirOptions, ReadTreeResponseFile, } from '../types'; +import { stripFirstDirectoryFromPath } from './util'; /** * Wraps a zip archive stream into a tree response reader. @@ -37,6 +38,7 @@ export class ZipArchiveResponse implements ReadTreeResponse { private readonly workDir: string, public readonly etag: string, private readonly filter?: (path: string, info: { size: number }) => boolean, + private readonly stripFirstDirectory?: boolean, ) { if (subPath) { if (!subPath.endsWith('/')) { @@ -66,8 +68,12 @@ export class ZipArchiveResponse implements ReadTreeResponse { } private shouldBeIncluded(entry: Entry): boolean { + const strippedPath = this.stripFirstDirectory + ? stripFirstDirectoryFromPath(entry.path) + : entry.path; + if (this.subPath) { - if (!entry.path.startsWith(this.subPath)) { + if (!strippedPath.startsWith(this.subPath)) { return false; } } @@ -96,7 +102,11 @@ export class ZipArchiveResponse implements ReadTreeResponse { if (this.shouldBeIncluded(entry)) { files.push({ - path: this.getInnerPath(entry.path), + path: this.getInnerPath( + this.stripFirstDirectory + ? stripFirstDirectoryFromPath(entry.path) + : entry.path, + ), content: () => entry.buffer(), }); } else { @@ -144,7 +154,11 @@ export class ZipArchiveResponse implements ReadTreeResponse { // Ignore directory entries since we handle that with the file entries // as a zip can have files with directories without directory entries if (entry.type === 'File' && this.shouldBeIncluded(entry)) { - const entryPath = this.getInnerPath(entry.path); + const entryPath = this.getInnerPath( + this.stripFirstDirectory + ? stripFirstDirectoryFromPath(entry.path) + : entry.path, + ); const dirname = platformPath.dirname(entryPath); if (dirname) { await fs.mkdirp(platformPath.join(dir, dirname));