mirror of https://github.com/actions/toolkit
fix regression, auto readlink on symlinks again
parent
6dd369c0e6
commit
7f19a7886a
|
@ -1,5 +1,9 @@
|
||||||
# @actions/artifact Releases
|
# @actions/artifact Releases
|
||||||
|
|
||||||
|
### 2.1.10
|
||||||
|
|
||||||
|
- Fixed a bug with symlinks not being automatically resolved.
|
||||||
|
|
||||||
### 2.1.9
|
### 2.1.9
|
||||||
|
|
||||||
- Fixed artifact upload chunk timeout logic [#1774](https://github.com/actions/toolkit/pull/1774)
|
- Fixed artifact upload chunk timeout logic [#1774](https://github.com/actions/toolkit/pull/1774)
|
||||||
|
|
|
@ -27,9 +27,14 @@ jest.mock('@azure/storage-blob', () => ({
|
||||||
const fixtures = {
|
const fixtures = {
|
||||||
uploadDirectory: path.join(__dirname, '_temp', 'plz-upload'),
|
uploadDirectory: path.join(__dirname, '_temp', 'plz-upload'),
|
||||||
files: [
|
files: [
|
||||||
['file1.txt', 'test 1 file content'],
|
{name: 'file1.txt', content: 'test 1 file content'},
|
||||||
['file2.txt', 'test 2 file content'],
|
{name: 'file2.txt', content: 'test 2 file content'},
|
||||||
['file3.txt', 'test 3 file content']
|
{name: 'file3.txt', content: 'test 3 file content'},
|
||||||
|
{
|
||||||
|
name: 'from_symlink.txt',
|
||||||
|
content: 'from a symlink',
|
||||||
|
symlink: '../symlinked.txt'
|
||||||
|
}
|
||||||
],
|
],
|
||||||
backendIDs: {
|
backendIDs: {
|
||||||
workflowRunBackendId: '67dbcc20-e851-4452-a7c3-2cc0d2e0ec67',
|
workflowRunBackendId: '67dbcc20-e851-4452-a7c3-2cc0d2e0ec67',
|
||||||
|
@ -54,8 +59,23 @@ describe('upload-artifact', () => {
|
||||||
fs.mkdirSync(fixtures.uploadDirectory, {recursive: true})
|
fs.mkdirSync(fixtures.uploadDirectory, {recursive: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [file, content] of fixtures.files) {
|
for (const file of fixtures.files) {
|
||||||
fs.writeFileSync(path.join(fixtures.uploadDirectory, file), content)
|
if (file.symlink) {
|
||||||
|
const symlinkPath = path.join(fixtures.uploadDirectory, file.symlink)
|
||||||
|
fs.writeFileSync(symlinkPath, file.content)
|
||||||
|
if (!fs.existsSync(path.join(fixtures.uploadDirectory, file.name))) {
|
||||||
|
fs.symlinkSync(
|
||||||
|
symlinkPath,
|
||||||
|
path.join(fixtures.uploadDirectory, file.name),
|
||||||
|
'file'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fs.writeFileSync(
|
||||||
|
path.join(fixtures.uploadDirectory, file.name),
|
||||||
|
file.content
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -71,8 +91,9 @@ describe('upload-artifact', () => {
|
||||||
.spyOn(uploadZipSpecification, 'getUploadZipSpecification')
|
.spyOn(uploadZipSpecification, 'getUploadZipSpecification')
|
||||||
.mockReturnValue(
|
.mockReturnValue(
|
||||||
fixtures.files.map(file => ({
|
fixtures.files.map(file => ({
|
||||||
sourcePath: path.join(fixtures.uploadDirectory, file[0]),
|
sourcePath: path.join(fixtures.uploadDirectory, file.name),
|
||||||
destinationPath: file[0]
|
destinationPath: file.name,
|
||||||
|
stats: new fs.Stats()
|
||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
jest.spyOn(config, 'getRuntimeToken').mockReturnValue(fixtures.runtimeToken)
|
jest.spyOn(config, 'getRuntimeToken').mockReturnValue(fixtures.runtimeToken)
|
||||||
|
@ -185,6 +206,10 @@ describe('upload-artifact', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should successfully upload an artifact', async () => {
|
it('should successfully upload an artifact', async () => {
|
||||||
|
jest
|
||||||
|
.spyOn(uploadZipSpecification, 'getUploadZipSpecification')
|
||||||
|
.mockRestore()
|
||||||
|
|
||||||
jest
|
jest
|
||||||
.spyOn(ArtifactServiceClientJSON.prototype, 'CreateArtifact')
|
.spyOn(ArtifactServiceClientJSON.prototype, 'CreateArtifact')
|
||||||
.mockReturnValue(
|
.mockReturnValue(
|
||||||
|
@ -228,8 +253,10 @@ describe('upload-artifact', () => {
|
||||||
|
|
||||||
const {id, size} = await uploadArtifact(
|
const {id, size} = await uploadArtifact(
|
||||||
fixtures.inputs.artifactName,
|
fixtures.inputs.artifactName,
|
||||||
fixtures.inputs.files,
|
fixtures.files.map(file =>
|
||||||
fixtures.inputs.rootDirectory
|
path.join(fixtures.uploadDirectory, file.name)
|
||||||
|
),
|
||||||
|
fixtures.uploadDirectory
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(id).toBe(1)
|
expect(id).toBe(1)
|
||||||
|
|
|
@ -305,4 +305,20 @@ describe('Search', () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Upload Specification - Includes symlinks', async () => {
|
||||||
|
const targetPath = path.join(root, 'link-dir', 'symlink-me.txt')
|
||||||
|
await fs.mkdir(path.dirname(targetPath), {recursive: true})
|
||||||
|
await fs.writeFile(targetPath, 'symlink file content')
|
||||||
|
|
||||||
|
const uploadPath = path.join(root, 'upload-dir', 'symlink.txt')
|
||||||
|
await fs.mkdir(path.dirname(uploadPath), {recursive: true})
|
||||||
|
await fs.symlink(targetPath, uploadPath, 'file')
|
||||||
|
|
||||||
|
const specifications = getUploadZipSpecification([uploadPath], root)
|
||||||
|
expect(specifications.length).toEqual(1)
|
||||||
|
expect(specifications[0].sourcePath).toEqual(uploadPath)
|
||||||
|
expect(specifications[0].destinationPath).toEqual('/upload-dir/symlink.txt')
|
||||||
|
expect(specifications[0].stats.isSymbolicLink()).toBe(true)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@actions/artifact",
|
"name": "@actions/artifact",
|
||||||
"version": "2.1.9",
|
"version": "2.1.10",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
|
@ -1315,9 +1315,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/path-to-regexp": {
|
"node_modules/path-to-regexp": {
|
||||||
"version": "6.2.1",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz",
|
||||||
"integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw=="
|
"integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ=="
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "2.8.8",
|
"version": "2.8.8",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@actions/artifact",
|
"name": "@actions/artifact",
|
||||||
"version": "2.1.9",
|
"version": "2.1.10",
|
||||||
"preview": true,
|
"preview": true,
|
||||||
"description": "Actions artifact lib",
|
"description": "Actions artifact lib",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
|
|
@ -13,6 +13,12 @@ export interface UploadZipSpecification {
|
||||||
* 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
|
||||||
|
* https://nodejs.org/api/fs.html#class-fsstats
|
||||||
|
*/
|
||||||
|
stats: fs.Stats
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -75,10 +81,11 @@ export function getUploadZipSpecification(
|
||||||
- file3.txt
|
- file3.txt
|
||||||
*/
|
*/
|
||||||
for (let file of filesToZip) {
|
for (let file of filesToZip) {
|
||||||
if (!fs.existsSync(file)) {
|
const stats = fs.lstatSync(file, {throwIfNoEntry: false})
|
||||||
|
if (!stats) {
|
||||||
throw new Error(`File ${file} does not exist`)
|
throw new Error(`File ${file} does not exist`)
|
||||||
}
|
}
|
||||||
if (!fs.statSync(file).isDirectory()) {
|
if (!stats.isDirectory()) {
|
||||||
// Normalize and resolve, this allows for either absolute or relative paths to be used
|
// Normalize and resolve, this allows for either absolute or relative paths to be used
|
||||||
file = normalize(file)
|
file = normalize(file)
|
||||||
file = resolve(file)
|
file = resolve(file)
|
||||||
|
@ -94,7 +101,8 @@ export function getUploadZipSpecification(
|
||||||
|
|
||||||
specification.push({
|
specification.push({
|
||||||
sourcePath: file,
|
sourcePath: file,
|
||||||
destinationPath: uploadPath
|
destinationPath: uploadPath,
|
||||||
|
stats
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// Empty directory
|
// Empty directory
|
||||||
|
@ -103,7 +111,8 @@ export function getUploadZipSpecification(
|
||||||
|
|
||||||
specification.push({
|
specification.push({
|
||||||
sourcePath: null,
|
sourcePath: null,
|
||||||
destinationPath: directoryPath
|
destinationPath: directoryPath,
|
||||||
|
stats
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import * as stream from 'stream'
|
import * as stream from 'stream'
|
||||||
|
import {readlink} from 'fs/promises'
|
||||||
import * as archiver from 'archiver'
|
import * as archiver from 'archiver'
|
||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import {UploadZipSpecification} from './upload-zip-specification'
|
import {UploadZipSpecification} from './upload-zip-specification'
|
||||||
|
@ -42,8 +43,14 @@ export async function createZipUploadStream(
|
||||||
|
|
||||||
for (const file of uploadSpecification) {
|
for (const file of uploadSpecification) {
|
||||||
if (file.sourcePath !== null) {
|
if (file.sourcePath !== null) {
|
||||||
// Add a normal file to the zip
|
// Check if symlink and resolve the source path
|
||||||
zip.file(file.sourcePath, {
|
let sourcePath = file.sourcePath
|
||||||
|
if (file.stats.isSymbolicLink()) {
|
||||||
|
sourcePath = await readlink(file.sourcePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the file to the zip
|
||||||
|
zip.file(sourcePath, {
|
||||||
name: file.destinationPath
|
name: file.destinationPath
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue