1
0
Fork 0

feat: Add option to modify whether symlink if followed in ZIP archive

Signed-off-by: eXhumer <exhumer@exhumer.cc>
pull/1803/head
eXhumer 2024-08-22 05:58:12 -06:00
parent 7298ff3219
commit 49751122cf
No known key found for this signature in database
GPG Key ID: 8F333578DECA236F
7 changed files with 57 additions and 13 deletions

View File

@ -38,6 +38,7 @@ const extraFileInFolderCPath = path.join(
'extra-file-in-folder-c.txt'
)
const amazingFileInFolderHPath = path.join(root, 'folder-h', 'amazing-item.txt')
const symlinkToFolderDPath = path.join(root, 'symlink-to-folder-d')
const artifactFilesToUpload = [
goodItem1Path,
@ -46,7 +47,8 @@ const artifactFilesToUpload = [
goodItem4Path,
goodItem5Path,
extraFileInFolderCPath,
amazingFileInFolderHPath
amazingFileInFolderHPath,
symlinkToFolderDPath
]
describe('Search', () => {
@ -89,6 +91,8 @@ describe('Search', () => {
await fs.writeFile(extraFileInFolderCPath, 'extra file')
await fs.writeFile(amazingFileInFolderHPath, 'amazing file')
await fs.symlink(path.join(root, 'folder-d'), symlinkToFolderDPath)
/*
Directory structure of files that get created:
root/
@ -112,6 +116,7 @@ describe('Search', () => {
folder-i/
bad-item4.txt
bad-item5.txt
symlink-to-folder-d -> folder-d/
good-item5.txt
*/
})
@ -168,7 +173,7 @@ describe('Search', () => {
artifactFilesToUpload,
root
)
expect(specifications.length).toEqual(7)
expect(specifications.length).toEqual(8)
const absolutePaths = specifications.map(item => item.sourcePath)
expect(absolutePaths).toContain(goodItem1Path)
@ -178,6 +183,7 @@ describe('Search', () => {
expect(absolutePaths).toContain(goodItem5Path)
expect(absolutePaths).toContain(extraFileInFolderCPath)
expect(absolutePaths).toContain(amazingFileInFolderHPath)
expect(absolutePaths).toContain(symlinkToFolderDPath)
for (const specification of specifications) {
if (specification.sourcePath === goodItem1Path) {
@ -213,6 +219,13 @@ describe('Search', () => {
expect(specification.destinationPath).toEqual(
path.join('/folder-h', 'amazing-item.txt')
)
} else if (specification.sourcePath === symlinkToFolderDPath) {
expect(specification.destinationPath).toEqual(
path.join('/symlink-to-folder-d')
)
expect(specification.symlinkTargetPath).toEqual(
path.join(root, '/folder-d')
)
} else {
throw new Error(
'Invalid specification found. This should never be reached'
@ -227,7 +240,7 @@ describe('Search', () => {
artifactFilesToUpload,
rootWithSlash
)
expect(specifications.length).toEqual(7)
expect(specifications.length).toEqual(8)
const absolutePaths = specifications.map(item => item.sourcePath)
expect(absolutePaths).toContain(goodItem1Path)
@ -237,6 +250,7 @@ describe('Search', () => {
expect(absolutePaths).toContain(goodItem5Path)
expect(absolutePaths).toContain(extraFileInFolderCPath)
expect(absolutePaths).toContain(amazingFileInFolderHPath)
expect(absolutePaths).toContain(symlinkToFolderDPath)
for (const specification of specifications) {
if (specification.sourcePath === goodItem1Path) {
@ -272,6 +286,13 @@ describe('Search', () => {
expect(specification.destinationPath).toEqual(
path.join('/folder-h', 'amazing-item.txt')
)
} else if (specification.sourcePath === symlinkToFolderDPath) {
expect(specification.destinationPath).toEqual(
path.join('/symlink-to-folder-d')
)
expect(specification.symlinkTargetPath).toEqual(
path.join(root, '/folder-d')
)
} else {
throw new Error(
'Invalid specification found. This should never be reached'

View File

@ -45,6 +45,13 @@ export interface UploadArtifactOptions {
* For large files that are not easily compressed, a value of 0 is recommended for significantly faster uploads.
*/
compressionLevel?: number
/**
* Whether or not symlinks in artifact ZIP should be followed.
*
* By default, artifact ZIP will follow symlinks.
*/
followSymlinks?: boolean
}
/**

View File

@ -70,7 +70,8 @@ export async function uploadArtifact(
const zipUploadStream = await createZipUploadStream(
zipSpecification,
options?.compressionLevel
options?.compressionLevel,
options?.followSymlinks
)
// Upload zip to blob storage

View File

@ -13,6 +13,11 @@ export interface UploadZipSpecification {
* The destination path in a zip for a file
*/
destinationPath: string
/**
* The relative path to a symlink target (file or directory) in a zip
*/
symlinkTargetPath?: string
}
/**
@ -78,7 +83,8 @@ export function getUploadZipSpecification(
if (!fs.existsSync(file)) {
throw new Error(`File ${file} does not exist`)
}
if (!fs.statSync(file).isDirectory()) {
const fileLstat = fs.lstatSync(file)
if (!fileLstat.isDirectory()) {
// Normalize and resolve, this allows for either absolute or relative paths to be used
file = normalize(file)
file = resolve(file)
@ -94,7 +100,10 @@ export function getUploadZipSpecification(
specification.push({
sourcePath: file,
destinationPath: uploadPath
destinationPath: uploadPath,
symlinkTargetPath: fileLstat.isSymbolicLink()
? fs.readlinkSync(file)
: undefined
})
} else {
// Empty directory

View File

@ -23,7 +23,8 @@ export class ZipUploadStream extends stream.Transform {
export async function createZipUploadStream(
uploadSpecification: UploadZipSpecification[],
compressionLevel: number = DEFAULT_COMPRESSION_LEVEL
compressionLevel: number = DEFAULT_COMPRESSION_LEVEL,
followSymlinks = true
): Promise<ZipUploadStream> {
core.debug(
`Creating Artifact archive with compressionLevel: ${compressionLevel}`
@ -42,10 +43,15 @@ export async function createZipUploadStream(
for (const file of uploadSpecification) {
if (file.sourcePath !== null) {
// Add a normal file to the zip
zip.file(file.sourcePath, {
name: file.destinationPath
})
if (file.symlinkTargetPath !== undefined && !followSymlinks) {
// Add a symlink to the zip
zip.symlink(file.destinationPath, file.symlinkTargetPath)
} else {
// Add a normal file to the zip
zip.file(file.sourcePath, {
name: file.destinationPath
})
}
} else {
// Add a directory to the zip
zip.append('', {name: file.destinationPath})

View File

@ -21,7 +21,7 @@
"packages": {
"": {
"name": "@actions/glob",
"version": "0.4.0",
"version": "0.5.0",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.9.1",

View File

@ -6,7 +6,7 @@
"packages": {
"": {
"name": "@actions/http-client",
"version": "2.2.1",
"version": "2.2.2",
"license": "MIT",
"dependencies": {
"tunnel": "^0.0.6",