mirror of
https://git.mirrors.martin98.com/https://github.com/actions/toolkit
synced 2026-04-07 18:03:16 +08:00
[Artifacts] Name validation + zip specification creation (#1482)
* Artifact name validation + zip specification creation * Fix linting issues * Grammar fix * Update test description
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
import * as fs from 'fs'
|
||||
import {info} from '@actions/core'
|
||||
import {normalize, resolve} from 'path'
|
||||
import {validateFilePath} from './path-and-artifact-name-validation'
|
||||
|
||||
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
|
||||
*/
|
||||
sourcePath: string | null
|
||||
|
||||
/**
|
||||
* The destination path in a zip for a file
|
||||
*/
|
||||
destinationPath: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a root directory exists and is valid
|
||||
* @param rootDirectory an absolute root directory path common to all input files that that will be trimmed from the final zip structure
|
||||
*/
|
||||
export function validateRootDirectory(rootDirectory: string): void {
|
||||
if (!fs.existsSync(rootDirectory)) {
|
||||
throw new Error(
|
||||
`The provided rootDirectory ${rootDirectory} does not exist`
|
||||
)
|
||||
}
|
||||
if (!fs.statSync(rootDirectory).isDirectory()) {
|
||||
throw new Error(
|
||||
`The provided rootDirectory ${rootDirectory} is not a valid directory`
|
||||
)
|
||||
}
|
||||
info(`Root directory input is valid!`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a specification that describes how a zip file will be created for a set of input files
|
||||
* @param filesToZip a list of file that should be included in the zip
|
||||
* @param rootDirectory an absolute root directory path common to all input files that that will be trimmed from the final zip structure
|
||||
*/
|
||||
export function getUploadZipSpecification(
|
||||
filesToZip: string[],
|
||||
rootDirectory: string
|
||||
): UploadZipSpecification[] {
|
||||
const specification: UploadZipSpecification[] = []
|
||||
|
||||
// Normalize and resolve, this allows for either absolute or relative paths to be used
|
||||
rootDirectory = normalize(rootDirectory)
|
||||
rootDirectory = resolve(rootDirectory)
|
||||
|
||||
/*
|
||||
Example
|
||||
|
||||
Input:
|
||||
rootDirectory: '/home/user/files/plz-upload'
|
||||
artifactFiles: [
|
||||
'/home/user/files/plz-upload/file1.txt',
|
||||
'/home/user/files/plz-upload/file2.txt',
|
||||
'/home/user/files/plz-upload/dir/file3.txt'
|
||||
]
|
||||
|
||||
Output:
|
||||
specifications: [
|
||||
['/home/user/files/plz-upload/file1.txt', '/file1.txt'],
|
||||
['/home/user/files/plz-upload/file1.txt', '/file2.txt'],
|
||||
['/home/user/files/plz-upload/file1.txt', '/dir/file3.txt']
|
||||
]
|
||||
|
||||
The final zip that is later uploaded will look like this:
|
||||
|
||||
my-artifact.zip
|
||||
- file.txt
|
||||
- file2.txt
|
||||
- dir/
|
||||
- file3.txt
|
||||
*/
|
||||
for (let file of filesToZip) {
|
||||
if (!fs.existsSync(file)) {
|
||||
throw new Error(`File ${file} does not exist`)
|
||||
}
|
||||
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
|
||||
const uploadPath = file.replace(rootDirectory, '')
|
||||
validateFilePath(uploadPath)
|
||||
|
||||
specification.push({
|
||||
sourcePath: file,
|
||||
destinationPath: uploadPath
|
||||
})
|
||||
} else {
|
||||
// Empty directory
|
||||
const directoryPath = file.replace(rootDirectory, '')
|
||||
validateFilePath(directoryPath)
|
||||
|
||||
specification.push({
|
||||
sourcePath: null,
|
||||
destinationPath: directoryPath
|
||||
})
|
||||
}
|
||||
}
|
||||
return specification
|
||||
}
|
||||
Reference in New Issue
Block a user