mirror of
https://gitea.com/actions/upload-artifact.git
synced 2024-11-26 10:35:58 +01:00
add follow symbolic links options
This commit is contained in:
parent
ef09cdac3e
commit
264caab452
10 changed files with 133 additions and 7 deletions
|
@ -84,6 +84,11 @@ For assistance with breaking changes, see [MIGRATION.md](docs/MIGRATION.md).
|
|||
# Optional. Default is 'warn'
|
||||
if-no-files-found:
|
||||
|
||||
# If true, symlink directories will be used to search files.
|
||||
# If false, symlink directories will be ignored to search files.
|
||||
# Optional. Default is 'true'
|
||||
followSymbolicLinks:
|
||||
|
||||
# Duration after which artifact will expire in days. 0 means using default retention.
|
||||
# Minimum 1 day.
|
||||
# Maximum 90 days unless changed from the repository settings page.
|
||||
|
|
|
@ -61,6 +61,18 @@ const lonelyFilePath = path.join(
|
|||
'lonely-file.txt'
|
||||
)
|
||||
|
||||
const symbolicLinkExtraSearchItem4Path = path.join(
|
||||
root,
|
||||
'folder-l',
|
||||
'extraSearch-item4.txt'
|
||||
)
|
||||
|
||||
const symbolicLinkExtraSearchItem5Path = path.join(
|
||||
root,
|
||||
'folder-l',
|
||||
'extraSearch-item5.txt'
|
||||
)
|
||||
|
||||
describe('Search', () => {
|
||||
beforeAll(async () => {
|
||||
// mock all output so that there is less noise when running tests
|
||||
|
@ -110,6 +122,12 @@ describe('Search', () => {
|
|||
await fs.writeFile(amazingFileInFolderHPath, 'amazing file')
|
||||
|
||||
await fs.writeFile(lonelyFilePath, 'all by itself')
|
||||
|
||||
await fs.symlink(
|
||||
path.join(root, 'folder-h', 'folder-i'),
|
||||
path.join(root, 'folder-l'),
|
||||
'dir'
|
||||
)
|
||||
/*
|
||||
Directory structure of files that get created:
|
||||
root/
|
||||
|
@ -136,6 +154,7 @@ describe('Search', () => {
|
|||
folder-j/
|
||||
folder-k/
|
||||
lonely-file.txt
|
||||
folder-l/ (symbolic link to folder-i)
|
||||
search-item5.txt
|
||||
*/
|
||||
})
|
||||
|
@ -168,9 +187,36 @@ describe('Search', () => {
|
|||
)
|
||||
})
|
||||
|
||||
it('Single file search - Symbolic Link', async () => {
|
||||
const relativePath = path.join(
|
||||
'__tests__',
|
||||
'_temp',
|
||||
'search',
|
||||
'folder-l',
|
||||
'extraSearch-item4.txt'
|
||||
)
|
||||
|
||||
const searchResult = await findFilesToUpload(relativePath)
|
||||
expect(searchResult.filesToUpload.length).toEqual(1)
|
||||
expect(searchResult.filesToUpload[0]).toEqual(
|
||||
symbolicLinkExtraSearchItem4Path
|
||||
)
|
||||
expect(searchResult.rootDirectory).toEqual(path.join(root, 'folder-l'))
|
||||
})
|
||||
|
||||
it('Single file search - Symbolic Link - Ignore symbolic links', async () => {
|
||||
const relativePath = path.join('__tests__', '_temp', 'search', 'folder-l')
|
||||
|
||||
const searchResult = await findFilesToUpload(relativePath, {
|
||||
followSymbolicLinks: false
|
||||
})
|
||||
expect(searchResult.filesToUpload.length).toEqual(0)
|
||||
})
|
||||
|
||||
it('Single file using wildcard', async () => {
|
||||
const expectedRoot = path.join(root, 'folder-h')
|
||||
const searchPath = path.join(root, 'folder-h', '**/*lonely*')
|
||||
|
||||
const searchResult = await findFilesToUpload(searchPath)
|
||||
expect(searchResult.filesToUpload.length).toEqual(1)
|
||||
expect(searchResult.filesToUpload[0]).toEqual(lonelyFilePath)
|
||||
|
@ -224,10 +270,33 @@ describe('Search', () => {
|
|||
expect(searchResult.rootDirectory).toEqual(expectedRootDirectory)
|
||||
})
|
||||
|
||||
it('Directory search - Absolute Path - Symbolic Link', async () => {
|
||||
const relativePath = path.join('__tests__', '_temp', 'search', 'folder-l')
|
||||
|
||||
const searchResult = await findFilesToUpload(relativePath)
|
||||
expect(searchResult.filesToUpload.length).toEqual(2)
|
||||
|
||||
expect(
|
||||
searchResult.filesToUpload.includes(symbolicLinkExtraSearchItem4Path)
|
||||
).toEqual(true)
|
||||
expect(
|
||||
searchResult.filesToUpload.includes(symbolicLinkExtraSearchItem5Path)
|
||||
).toEqual(true)
|
||||
})
|
||||
|
||||
it('Directory search - Absolute Path - Symbolic Link - Ignore symbolic links', async () => {
|
||||
const relativePath = path.join('__tests__', '_temp', 'search', 'folder-l')
|
||||
|
||||
const searchResult = await findFilesToUpload(relativePath, {
|
||||
followSymbolicLinks: false
|
||||
})
|
||||
expect(searchResult.filesToUpload.length).toEqual(0)
|
||||
})
|
||||
|
||||
it('Wildcard search - Absolute Path', async () => {
|
||||
const searchPath = path.join(root, '**/*[Ss]earch*')
|
||||
const searchResult = await findFilesToUpload(searchPath)
|
||||
expect(searchResult.filesToUpload.length).toEqual(10)
|
||||
expect(searchResult.filesToUpload.length).toEqual(12)
|
||||
|
||||
expect(searchResult.filesToUpload.includes(searchItem1Path)).toEqual(true)
|
||||
expect(searchResult.filesToUpload.includes(searchItem2Path)).toEqual(true)
|
||||
|
@ -249,6 +318,12 @@ describe('Search', () => {
|
|||
expect(searchResult.filesToUpload.includes(extraSearchItem5Path)).toEqual(
|
||||
true
|
||||
)
|
||||
expect(
|
||||
searchResult.filesToUpload.includes(symbolicLinkExtraSearchItem4Path)
|
||||
).toEqual(true)
|
||||
expect(
|
||||
searchResult.filesToUpload.includes(symbolicLinkExtraSearchItem5Path)
|
||||
).toEqual(true)
|
||||
|
||||
expect(searchResult.rootDirectory).toEqual(root)
|
||||
})
|
||||
|
@ -261,7 +336,7 @@ describe('Search', () => {
|
|||
'**/*[Ss]earch*'
|
||||
)
|
||||
const searchResult = await findFilesToUpload(searchPath)
|
||||
expect(searchResult.filesToUpload.length).toEqual(10)
|
||||
expect(searchResult.filesToUpload.length).toEqual(12)
|
||||
|
||||
expect(searchResult.filesToUpload.includes(searchItem1Path)).toEqual(true)
|
||||
expect(searchResult.filesToUpload.includes(searchItem2Path)).toEqual(true)
|
||||
|
@ -283,6 +358,12 @@ describe('Search', () => {
|
|||
expect(searchResult.filesToUpload.includes(extraSearchItem5Path)).toEqual(
|
||||
true
|
||||
)
|
||||
expect(
|
||||
searchResult.filesToUpload.includes(symbolicLinkExtraSearchItem4Path)
|
||||
).toEqual(true)
|
||||
expect(
|
||||
searchResult.filesToUpload.includes(symbolicLinkExtraSearchItem5Path)
|
||||
).toEqual(true)
|
||||
|
||||
expect(searchResult.rootDirectory).toEqual(root)
|
||||
})
|
||||
|
|
|
@ -17,6 +17,11 @@ inputs:
|
|||
error: Fail the action with an error message
|
||||
ignore: Do not output any warnings or errors, the action does not fail
|
||||
default: 'warn'
|
||||
follow-symbolic-links:
|
||||
description: >
|
||||
If true, symlink directories will be used to search files.
|
||||
If false, symlink directories will be ignored to search files.
|
||||
default: 'true'
|
||||
retention-days:
|
||||
description: >
|
||||
Duration after which artifact will expire in days. 0 means using default retention.
|
||||
|
|
7
dist/merge/index.js
vendored
7
dist/merge/index.js
vendored
|
@ -129675,7 +129675,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.findFilesToUpload = void 0;
|
||||
exports.findFilesToUpload = exports.getGlobOptions = void 0;
|
||||
const glob = __importStar(__nccwpck_require__(28090));
|
||||
const path = __importStar(__nccwpck_require__(71017));
|
||||
const core_1 = __nccwpck_require__(42186);
|
||||
|
@ -129690,6 +129690,10 @@ function getDefaultGlobOptions() {
|
|||
omitBrokenSymbolicLinks: true
|
||||
};
|
||||
}
|
||||
function getGlobOptions(followSymbolicLinks) {
|
||||
return Object.assign({ followSymbolicLinks }, getDefaultGlobOptions());
|
||||
}
|
||||
exports.getGlobOptions = getGlobOptions;
|
||||
/**
|
||||
* If multiple paths are specific, the least common ancestor (LCA) of the search paths is used as
|
||||
* the delimiter to control the directory structure for the artifact. This function returns the LCA
|
||||
|
@ -129746,6 +129750,7 @@ function findFilesToUpload(searchPath, globOptions) {
|
|||
const searchResults = [];
|
||||
const globber = yield glob.create(searchPath, globOptions || getDefaultGlobOptions());
|
||||
const rawSearchResults = yield globber.glob();
|
||||
console.log(rawSearchResults);
|
||||
/*
|
||||
Files are saved with case insensitivity. Uploading both a.txt and A.txt will files to be overwritten
|
||||
Detect any files that could be overwritten for user awareness
|
||||
|
|
12
dist/upload/index.js
vendored
12
dist/upload/index.js
vendored
|
@ -129433,7 +129433,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.findFilesToUpload = void 0;
|
||||
exports.findFilesToUpload = exports.getGlobOptions = void 0;
|
||||
const glob = __importStar(__nccwpck_require__(28090));
|
||||
const path = __importStar(__nccwpck_require__(71017));
|
||||
const core_1 = __nccwpck_require__(42186);
|
||||
|
@ -129448,6 +129448,10 @@ function getDefaultGlobOptions() {
|
|||
omitBrokenSymbolicLinks: true
|
||||
};
|
||||
}
|
||||
function getGlobOptions(followSymbolicLinks) {
|
||||
return Object.assign({ followSymbolicLinks }, getDefaultGlobOptions());
|
||||
}
|
||||
exports.getGlobOptions = getGlobOptions;
|
||||
/**
|
||||
* If multiple paths are specific, the least common ancestor (LCA) of the search paths is used as
|
||||
* the delimiter to control the directory structure for the artifact. This function returns the LCA
|
||||
|
@ -129504,6 +129508,7 @@ function findFilesToUpload(searchPath, globOptions) {
|
|||
const searchResults = [];
|
||||
const globber = yield glob.create(searchPath, globOptions || getDefaultGlobOptions());
|
||||
const rawSearchResults = yield globber.glob();
|
||||
console.log(rawSearchResults);
|
||||
/*
|
||||
Files are saved with case insensitivity. Uploading both a.txt and A.txt will files to be overwritten
|
||||
Detect any files that could be overwritten for user awareness
|
||||
|
@ -129637,6 +129642,7 @@ var Inputs;
|
|||
Inputs["Name"] = "name";
|
||||
Inputs["Path"] = "path";
|
||||
Inputs["IfNoFilesFound"] = "if-no-files-found";
|
||||
Inputs["FollowSymbolicLinks"] = "follow-symbolic-links";
|
||||
Inputs["RetentionDays"] = "retention-days";
|
||||
Inputs["CompressionLevel"] = "compression-level";
|
||||
Inputs["Overwrite"] = "overwrite";
|
||||
|
@ -129739,6 +129745,7 @@ function getInputs() {
|
|||
const overwrite = core.getBooleanInput(constants_1.Inputs.Overwrite);
|
||||
const ifNoFilesFound = core.getInput(constants_1.Inputs.IfNoFilesFound);
|
||||
const noFileBehavior = constants_1.NoFileOptions[ifNoFilesFound];
|
||||
const followSymbolicLinks = core.getBooleanInput(constants_1.Inputs.FollowSymbolicLinks);
|
||||
if (!noFileBehavior) {
|
||||
core.setFailed(`Unrecognized ${constants_1.Inputs.IfNoFilesFound} input. Provided: ${ifNoFilesFound}. Available options: ${Object.keys(constants_1.NoFileOptions)}`);
|
||||
}
|
||||
|
@ -129746,6 +129753,7 @@ function getInputs() {
|
|||
artifactName: name,
|
||||
searchPath: path,
|
||||
ifNoFilesFound: noFileBehavior,
|
||||
followSymbolicLinks: followSymbolicLinks,
|
||||
overwrite: overwrite
|
||||
};
|
||||
const retentionDaysStr = core.getInput(constants_1.Inputs.RetentionDays);
|
||||
|
@ -129835,7 +129843,7 @@ function deleteArtifactIfExists(artifactName) {
|
|||
function run() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const inputs = (0, input_helper_1.getInputs)();
|
||||
const searchResult = yield (0, search_1.findFilesToUpload)(inputs.searchPath);
|
||||
const searchResult = yield (0, search_1.findFilesToUpload)(inputs.searchPath, (0, search_1.getGlobOptions)(inputs.followSymbolicLinks));
|
||||
if (searchResult.filesToUpload.length === 0) {
|
||||
// No files were found, different use cases warrant different types of behavior if nothing is found
|
||||
switch (inputs.ifNoFilesFound) {
|
||||
|
|
|
@ -19,6 +19,15 @@ function getDefaultGlobOptions(): glob.GlobOptions {
|
|||
}
|
||||
}
|
||||
|
||||
export function getGlobOptions(
|
||||
followSymbolicLinks?: boolean
|
||||
): glob.GlobOptions {
|
||||
return {
|
||||
followSymbolicLinks,
|
||||
...getDefaultGlobOptions()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If multiple paths are specific, the least common ancestor (LCA) of the search paths is used as
|
||||
* the delimiter to control the directory structure for the artifact. This function returns the LCA
|
||||
|
@ -88,6 +97,7 @@ export async function findFilesToUpload(
|
|||
globOptions || getDefaultGlobOptions()
|
||||
)
|
||||
const rawSearchResults: string[] = await globber.glob()
|
||||
console.log(rawSearchResults)
|
||||
|
||||
/*
|
||||
Files are saved with case insensitivity. Uploading both a.txt and A.txt will files to be overwritten
|
||||
|
|
|
@ -3,6 +3,7 @@ export enum Inputs {
|
|||
Name = 'name',
|
||||
Path = 'path',
|
||||
IfNoFilesFound = 'if-no-files-found',
|
||||
FollowSymbolicLinks = 'follow-symbolic-links',
|
||||
RetentionDays = 'retention-days',
|
||||
CompressionLevel = 'compression-level',
|
||||
Overwrite = 'overwrite'
|
||||
|
|
|
@ -13,6 +13,8 @@ export function getInputs(): UploadInputs {
|
|||
const ifNoFilesFound = core.getInput(Inputs.IfNoFilesFound)
|
||||
const noFileBehavior: NoFileOptions = NoFileOptions[ifNoFilesFound]
|
||||
|
||||
const followSymbolicLinks = core.getBooleanInput(Inputs.FollowSymbolicLinks)
|
||||
|
||||
if (!noFileBehavior) {
|
||||
core.setFailed(
|
||||
`Unrecognized ${
|
||||
|
@ -27,6 +29,7 @@ export function getInputs(): UploadInputs {
|
|||
artifactName: name,
|
||||
searchPath: path,
|
||||
ifNoFilesFound: noFileBehavior,
|
||||
followSymbolicLinks: followSymbolicLinks,
|
||||
overwrite: overwrite
|
||||
} as UploadInputs
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import artifact, {
|
|||
UploadArtifactOptions,
|
||||
ArtifactNotFoundError
|
||||
} from '@actions/artifact'
|
||||
import {findFilesToUpload} from '../shared/search'
|
||||
import {findFilesToUpload, getGlobOptions} from '../shared/search'
|
||||
import {getInputs} from './input-helper'
|
||||
import {NoFileOptions} from './constants'
|
||||
import {uploadArtifact} from '../shared/upload-artifact'
|
||||
|
@ -24,7 +24,10 @@ async function deleteArtifactIfExists(artifactName: string): Promise<void> {
|
|||
|
||||
export async function run(): Promise<void> {
|
||||
const inputs = getInputs()
|
||||
const searchResult = await findFilesToUpload(inputs.searchPath)
|
||||
const searchResult = await findFilesToUpload(
|
||||
inputs.searchPath,
|
||||
getGlobOptions(inputs.followSymbolicLinks)
|
||||
)
|
||||
if (searchResult.filesToUpload.length === 0) {
|
||||
// No files were found, different use cases warrant different types of behavior if nothing is found
|
||||
switch (inputs.ifNoFilesFound) {
|
||||
|
|
|
@ -16,6 +16,11 @@ export interface UploadInputs {
|
|||
*/
|
||||
ifNoFilesFound: NoFileOptions
|
||||
|
||||
/**
|
||||
* Wether or not to follow symbolic links when searching for files to upload
|
||||
*/
|
||||
followSymbolicLinks?: boolean
|
||||
|
||||
/**
|
||||
* Duration after which artifact will expire in days
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue