Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add follow symbolic links options #544

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,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:
PepeANZ marked this conversation as resolved.
Show resolved Hide resolved

# 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.
Expand Down
85 changes: 83 additions & 2 deletions __tests__/search.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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/
Expand All @@ -136,6 +154,7 @@ describe('Search', () => {
folder-j/
folder-k/
lonely-file.txt
folder-l/ (symbolic link to folder-i)
search-item5.txt
*/
})
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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)
})
Expand All @@ -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)
Expand All @@ -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)
})
Expand Down
5 changes: 5 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 6 additions & 1 deletion dist/merge/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -125817,7 +125817,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);
Expand All @@ -125832,6 +125832,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
Expand Down Expand Up @@ -125888,6 +125892,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
Expand Down
12 changes: 10 additions & 2 deletions dist/upload/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -125575,7 +125575,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);
Expand All @@ -125590,6 +125590,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
Expand Down Expand Up @@ -125646,6 +125650,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
Expand Down Expand Up @@ -125779,6 +125784,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";
Expand Down Expand Up @@ -125881,13 +125887,15 @@ 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)}`);
}
const inputs = {
artifactName: name,
searchPath: path,
ifNoFilesFound: noFileBehavior,
followSymbolicLinks: followSymbolicLinks,
overwrite: overwrite
};
const retentionDaysStr = core.getInput(constants_1.Inputs.RetentionDays);
Expand Down Expand Up @@ -125977,7 +125985,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) {
Expand Down
10 changes: 10 additions & 0 deletions src/shared/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ function getDefaultGlobOptions(): glob.GlobOptions {
}
}

export function getGlobOptions(
followSymbolicLinks?: boolean
): glob.GlobOptions {
return {
followSymbolicLinks,
...getDefaultGlobOptions()
PepeANZ marked this conversation as resolved.
Show resolved Hide resolved
}
}

/**
* 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
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/upload/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
3 changes: 3 additions & 0 deletions src/upload/input-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 ${
Expand All @@ -27,6 +29,7 @@ export function getInputs(): UploadInputs {
artifactName: name,
searchPath: path,
ifNoFilesFound: noFileBehavior,
followSymbolicLinks: followSymbolicLinks,
overwrite: overwrite
} as UploadInputs

Expand Down
7 changes: 5 additions & 2 deletions src/upload/upload-artifact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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) {
Expand Down
5 changes: 5 additions & 0 deletions src/upload/upload-inputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down