1
0
Fork 0

Include fs stats in zip archive

pull/1609/head
Dan 2023-12-17 01:48:14 -06:00
parent 68f22927e7
commit 307f360e0e
4 changed files with 64 additions and 50 deletions

View File

@ -8,6 +8,7 @@ import * as blobUpload from '../src/internal/upload/blob-upload'
import {uploadArtifact} from '../src/internal/upload/upload-artifact' import {uploadArtifact} from '../src/internal/upload/upload-artifact'
import {noopLogs} from './common' import {noopLogs} from './common'
import {FilesNotFoundError} from '../src/internal/shared/errors' import {FilesNotFoundError} from '../src/internal/shared/errors'
import {Stats} from 'fs'
describe('upload-artifact', () => { describe('upload-artifact', () => {
beforeEach(() => { beforeEach(() => {
@ -28,15 +29,18 @@ describe('upload-artifact', () => {
.mockReturnValue([ .mockReturnValue([
{ {
sourcePath: '/home/user/files/plz-upload/file1.txt', sourcePath: '/home/user/files/plz-upload/file1.txt',
destinationPath: 'file1.txt' destinationPath: 'file1.txt',
stats: new Stats()
}, },
{ {
sourcePath: '/home/user/files/plz-upload/file2.txt', sourcePath: '/home/user/files/plz-upload/file2.txt',
destinationPath: 'file2.txt' destinationPath: 'file2.txt',
stats: new Stats()
}, },
{ {
sourcePath: '/home/user/files/plz-upload/dir/file3.txt', sourcePath: '/home/user/files/plz-upload/dir/file3.txt',
destinationPath: 'dir/file3.txt' destinationPath: 'dir/file3.txt',
stats: new Stats()
} }
]) ])
@ -136,15 +140,18 @@ describe('upload-artifact', () => {
.mockReturnValue([ .mockReturnValue([
{ {
sourcePath: '/home/user/files/plz-upload/file1.txt', sourcePath: '/home/user/files/plz-upload/file1.txt',
destinationPath: 'file1.txt' destinationPath: 'file1.txt',
stats: new Stats()
}, },
{ {
sourcePath: '/home/user/files/plz-upload/file2.txt', sourcePath: '/home/user/files/plz-upload/file2.txt',
destinationPath: 'file2.txt' destinationPath: 'file2.txt',
stats: new Stats()
}, },
{ {
sourcePath: '/home/user/files/plz-upload/dir/file3.txt', sourcePath: '/home/user/files/plz-upload/dir/file3.txt',
destinationPath: 'dir/file3.txt' destinationPath: 'dir/file3.txt',
stats: new Stats()
} }
]) ])
@ -175,15 +182,18 @@ describe('upload-artifact', () => {
.mockReturnValue([ .mockReturnValue([
{ {
sourcePath: '/home/user/files/plz-upload/file1.txt', sourcePath: '/home/user/files/plz-upload/file1.txt',
destinationPath: 'file1.txt' destinationPath: 'file1.txt',
stats: Stats.prototype
}, },
{ {
sourcePath: '/home/user/files/plz-upload/file2.txt', sourcePath: '/home/user/files/plz-upload/file2.txt',
destinationPath: 'file2.txt' destinationPath: 'file2.txt',
stats: Stats.prototype
}, },
{ {
sourcePath: '/home/user/files/plz-upload/dir/file3.txt', sourcePath: '/home/user/files/plz-upload/dir/file3.txt',
destinationPath: 'dir/file3.txt' destinationPath: 'dir/file3.txt',
stats: Stats.prototype
} }
]) ])
@ -230,15 +240,18 @@ describe('upload-artifact', () => {
.mockReturnValue([ .mockReturnValue([
{ {
sourcePath: '/home/user/files/plz-upload/file1.txt', sourcePath: '/home/user/files/plz-upload/file1.txt',
destinationPath: 'file1.txt' destinationPath: 'file1.txt',
stats: new Stats()
}, },
{ {
sourcePath: '/home/user/files/plz-upload/file2.txt', sourcePath: '/home/user/files/plz-upload/file2.txt',
destinationPath: 'file2.txt' destinationPath: 'file2.txt',
stats: new Stats()
}, },
{ {
sourcePath: '/home/user/files/plz-upload/dir/file3.txt', sourcePath: '/home/user/files/plz-upload/dir/file3.txt',
destinationPath: 'dir/file3.txt' destinationPath: 'dir/file3.txt',
stats: new Stats()
} }
]) ])
@ -293,15 +306,18 @@ describe('upload-artifact', () => {
.mockReturnValue([ .mockReturnValue([
{ {
sourcePath: '/home/user/files/plz-upload/file1.txt', sourcePath: '/home/user/files/plz-upload/file1.txt',
destinationPath: 'file1.txt' destinationPath: 'file1.txt',
stats: new Stats()
}, },
{ {
sourcePath: '/home/user/files/plz-upload/file2.txt', sourcePath: '/home/user/files/plz-upload/file2.txt',
destinationPath: 'file2.txt' destinationPath: 'file2.txt',
stats: new Stats()
}, },
{ {
sourcePath: '/home/user/files/plz-upload/dir/file3.txt', sourcePath: '/home/user/files/plz-upload/dir/file3.txt',
destinationPath: 'dir/file3.txt' destinationPath: 'dir/file3.txt',
stats: new Stats()
} }
]) ])

View File

@ -287,14 +287,14 @@ describe('Search', () => {
expect(specifications.length).toEqual(2) expect(specifications.length).toEqual(2)
const absolutePaths = specifications.map(item => item.sourcePath) const absolutePaths = specifications.map(item => item.sourcePath)
expect(absolutePaths).toContain(goodItem1Path) expect(absolutePaths).toContain(goodItem1Path)
expect(absolutePaths).toContain(null) expect(absolutePaths).toContain(folderEPath)
for (const specification of specifications) { for (const specification of specifications) {
if (specification.sourcePath === goodItem1Path) { if (specification.sourcePath === goodItem1Path) {
expect(specification.destinationPath).toEqual( expect(specification.destinationPath).toEqual(
path.join('/folder-a', 'folder-b', 'folder-c', 'good-item1.txt') path.join('/folder-a', 'folder-b', 'folder-c', 'good-item1.txt')
) )
} else if (specification.sourcePath === null) { } else if (specification.sourcePath === folderEPath) {
expect(specification.destinationPath).toEqual( expect(specification.destinationPath).toEqual(
path.join('/folder-a', 'folder-b', 'folder-e') path.join('/folder-a', 'folder-b', 'folder-e')
) )

View File

@ -5,14 +5,19 @@ import {validateFilePath} from './path-and-artifact-name-validation'
export interface UploadZipSpecification { export interface UploadZipSpecification {
/** /**
* An absolute source path that points to a file that will be added to a zip. Null if creating a new directory * An absolute source path that points to a file that will be added to a zip.
*/ */
sourcePath: string | null sourcePath: string
/** /**
* The destination path in a zip for a file * The destination path in a zip for a file
*/ */
destinationPath: string destinationPath: string
/**
* Information about the file on disk
*/
stats: fs.Stats
} }
/** /**
@ -75,37 +80,26 @@ export function getUploadZipSpecification(
- file3.txt - file3.txt
*/ */
for (let file of filesToZip) { for (let file of filesToZip) {
if (!fs.existsSync(file)) { const stats = fs.statSync(file, {throwIfNoEntry: false})
throw new Error(`File ${file} does not exist`) if (!stats) throw new Error(`File ${file} does not exist`)
// Normalize and resolve, this allows for either absolute or relative paths to be used
file = normalize(file)
file = resolve(file)
if (!file.startsWith(rootDirectory)) {
throw new Error(
`The rootDirectory: ${rootDirectory} is not a parent directory of the file: ${file}`
)
} }
if (!fs.statSync(file).isDirectory()) {
// Normalize and resolve, this allows for either absolute or relative paths to be used
file = normalize(file)
file = resolve(file)
if (!file.startsWith(rootDirectory)) {
throw new Error(
`The rootDirectory: ${rootDirectory} is not a parent directory of the file: ${file}`
)
}
// Check for forbidden characters in file paths that may cause ambiguous behavior if downloaded on different file systems // Check for forbidden characters in file paths that may cause ambiguous behavior if downloaded on different file systems
const uploadPath = file.replace(rootDirectory, '') const destinationPath = file.replace(rootDirectory, '')
validateFilePath(uploadPath) validateFilePath(destinationPath)
specification.push({ specification.push({
sourcePath: file, sourcePath: file,
destinationPath: uploadPath destinationPath,
}) stats
} else { })
// Empty directory
const directoryPath = file.replace(rootDirectory, '')
validateFilePath(directoryPath)
specification.push({
sourcePath: null,
destinationPath: directoryPath
})
}
} }
return specification return specification
} }

View File

@ -42,14 +42,18 @@ export async function createZipUploadStream(
zip.on('end', zipEndCallback) zip.on('end', zipEndCallback)
for (const file of uploadSpecification) { for (const file of uploadSpecification) {
if (file.sourcePath !== null) { if (!file.stats.isDirectory()) {
// Add a normal file to the zip // Add a normal file to the zip
zip.append(createReadStream(file.sourcePath), { zip.append(createReadStream(file.sourcePath), {
name: file.destinationPath name: file.destinationPath,
stats: file.stats
}) })
} else { } else {
// Add a directory to the zip // Add a directory to the zip
zip.append('', {name: file.destinationPath}) zip.append('', {
name: file.destinationPath,
stats: file.stats
})
} }
} }