Compare commits

...

36 Commits

Author SHA1 Message Date
Lovepreet Singh bc772ce6eb Move zstd to use long-form flags instead of short-form 2022-07-14 22:17:00 +05:30
Shubham Tiwari c5278cdd08 new major version release (#1123) 2022-06-24 15:18:30 +05:30
Shubham Tiwari 46231a7da3 Graceful handling of error (non-validation one) (#1122)
* Initial changes

* added info error as well

* Format

* Unused package

* adding message field

* removed line

* Review comments

* review comment to add validation as errors handling
2022-06-24 10:46:20 +05:30
Thomas Boop 9b7bcb1567 actions/core 1.9.0 release (#1116)
* 1.9.0 release

* add link to pr
2022-06-15 11:34:58 -04:00
Seth Vargo 00282d6145 core: add helpers for working with paths across OSes (#1102) 2022-06-15 11:18:44 -04:00
Sankalp Kotewar b5f31bb5a2 Merge pull request #1108 from actions/users/kotewar/fix-tar-exit-with-code-1
Adding fix for tar exiting with code 1 issue
2022-06-06 14:41:07 +05:30
Sankalp Kotewar 41c667327d Reverted other package-lock.json 2022-06-06 08:03:56 +00:00
Sankalp Kotewar 2fd9a80bc1 Revert "Adding fix for tar exiting with code 1 issue"
This reverts commit 197f5a13a9.
2022-06-06 07:56:27 +00:00
Sankalp Kotewar ebfda315a5 Revert "Adding updated package-lock.json for cache"
This reverts commit 1d5b16aa38.
2022-06-06 07:56:25 +00:00
Sankalp Kotewar fe93288f85 Revert "Fixed test case for tar creation"
This reverts commit 91842768bd.
2022-06-06 07:56:23 +00:00
Sankalp Kotewar 2d6e5ecd7c Revert "Pushing updated package-lock.json for artifact"
This reverts commit 1fc4ec3274.
2022-06-06 07:56:21 +00:00
Sankalp Kotewar 49cd1ccc3f Revert "Fixed test case for Windows env"
This reverts commit a78bb30ca0.
2022-06-06 07:56:18 +00:00
Sankalp Kotewar 3cf35dbd46 Revert "Changed an import in test case to standard import"
This reverts commit 347d2e2a35.
2022-06-06 07:56:16 +00:00
Sankalp Kotewar 845770f824 Revert "Revert "Changed an import in test case to standard import""
This reverts commit c1bb3fb679.
2022-06-06 07:56:13 +00:00
Sankalp Kotewar c1bb3fb679 Revert "Changed an import in test case to standard import"
This reverts commit 347d2e2a35.
2022-06-03 09:05:12 +00:00
Sankalp Kotewar 347d2e2a35 Changed an import in test case to standard import 2022-06-03 07:45:12 +00:00
Sankalp Kotewar a78bb30ca0 Fixed test case for Windows env 2022-06-03 07:33:12 +00:00
Sankalp Kotewar 1fc4ec3274 Pushing updated package-lock.json for artifact 2022-06-03 07:26:28 +00:00
Sankalp Kotewar 91842768bd Fixed test case for tar creation 2022-06-03 07:19:54 +00:00
Sankalp Kotewar 1d5b16aa38 Adding updated package-lock.json for cache 2022-06-01 13:32:34 +00:00
Sankalp Kotewar 197f5a13a9 Adding fix for tar exiting with code 1 issue 2022-06-01 13:18:50 +00:00
Sankalp Kotewar 8263c4d15d Merge pull request #1097 from actions/users/kotewar/avoid-empty-cache-save
Avoid saving empty cache when there are no files to cache.
2022-05-24 13:27:13 +05:30
Sankalp Kotewar 4ee0048304 Updated RELEASES.md with release information 2022-05-24 06:55:11 +00:00
Sankalp Kotewar d618dc457e Added package-lock.json after version upgrade 2022-05-24 05:48:53 +00:00
Sankalp Kotewar 558edc0a3b Patch version bumped from 2.0.4 to 2.0.5 for cache 2022-05-24 05:45:53 +00:00
Sankalp Kotewar 92b210aced Test case fix for warning message changes 2022-05-23 12:05:31 +00:00
Sankalp Kotewar 6f6f4e7588 Enhanced warning description to make more sense. 2022-05-23 12:03:18 +00:00
Sankalp Kotewar 10a3934663 Fixed linting issues 2022-05-23 06:49:26 +00:00
Sankalp Kotewar 6421989639 Standardized test case input 2022-05-23 06:39:22 +00:00
Sankalp Kotewar 07b91eafe5 Added unit test case for #624 2022-05-23 06:32:13 +00:00
Sankalp Kotewar b9fefecf57 Formatting changes 2022-05-23 05:59:56 +00:00
Sankalp Kotewar 9aecf41d21 Updated error type to generic to show warning 2022-05-23 05:39:42 +00:00
Sankalp Kotewar da52b35800 Adding check for cache paths' existence. 2022-05-22 10:09:13 +00:00
Rob Herley 1e0f6285e5 Merge pull request #1095 from actions/robherley/artifact-1.1.0-release
@actions/artifact 1.1.0 release
2022-05-19 14:52:47 -04:00
Rob Herley dd4e856a4e @actions/artifact 1.1.0 release 2022-05-19 18:17:15 +00:00
Rob Herley a70804595b Merge pull request #1063 from actions/robherley/artifact-digest
Add checksum validation on artifact upload
2022-05-19 14:12:50 -04:00
18 changed files with 357 additions and 50 deletions
+5 -1
View File
@@ -85,4 +85,8 @@
### 1.0.2
- Update to v2.0.1 of `@actions/http-client` [#1087](https://github.com/actions/toolkit/pull/1087)
- Update to v2.0.1 of `@actions/http-client` [#1087](https://github.com/actions/toolkit/pull/1087)
### 1.1.0
- Add `x-actions-results-crc64` and `x-actions-results-md5` checksum headers on upload [#1063](https://github.com/actions/toolkit/pull/1063)
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@actions/artifact",
"version": "1.0.2",
"version": "1.1.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@actions/artifact",
"version": "1.0.2",
"version": "1.1.0",
"preview": true,
"description": "Actions artifact lib",
"keywords": [
+10 -1
View File
@@ -61,4 +61,13 @@
- Update to v2.0.0 of `@actions/http-client`
### 2.0.4
- Update to v2.0.1 of `@actions/http-client` [#1087](https://github.com/actions/toolkit/pull/1087)
- Update to v2.0.1 of `@actions/http-client` [#1087](https://github.com/actions/toolkit/pull/1087)
### 2.0.5
- Fix to avoid saving empty cache when no files are available for caching. ([issue](https://github.com/actions/cache/issues/624))
### 2.0.6
- Fix `Tar failed with error: The process '/usr/bin/tar' failed with exit code 1` issue when temp directory where tar is getting created is actually the subdirectory of the path mentioned by the user for caching. ([issue](https://github.com/actions/cache/issues/689))
### 3.0.0
- Updated actions/cache to suppress Actions cache server error and log warning for those error [#1122](https://github.com/actions/toolkit/pull/1122)
+6 -2
View File
@@ -73,13 +73,17 @@ test('restore with no cache found', async () => {
test('restore with server error should fail', async () => {
const paths = ['node_modules']
const key = 'node-test'
const logWarningMock = jest.spyOn(core, 'warning')
jest.spyOn(cacheHttpClient, 'getCacheEntry').mockImplementation(() => {
throw new Error('HTTP Error Occurred')
})
await expect(restoreCache(paths, key)).rejects.toThrowError(
'HTTP Error Occurred'
const cacheKey = await restoreCache(paths, key)
expect(cacheKey).toBe(undefined)
expect(logWarningMock).toHaveBeenCalledTimes(1)
expect(logWarningMock).toHaveBeenCalledWith(
'Failed to restore: HTTP Error Occurred'
)
})
+42 -11
View File
@@ -48,6 +48,7 @@ test('save with large cache outputs should fail', async () => {
const cachePaths = [path.resolve(filePath)]
const createTarMock = jest.spyOn(tar, 'createTar')
const logWarningMock = jest.spyOn(core, 'warning')
const cacheSize = 11 * 1024 * 1024 * 1024 //~11GB, over the 10GB limit
jest
@@ -58,8 +59,11 @@ test('save with large cache outputs should fail', async () => {
.spyOn(cacheUtils, 'getCompressionMethod')
.mockReturnValueOnce(Promise.resolve(compression))
await expect(saveCache([filePath], primaryKey)).rejects.toThrowError(
'Cache size of ~11264 MB (11811160064 B) is over the 10GB limit, not saving cache.'
const cacheId = await saveCache([filePath], primaryKey)
expect(cacheId).toBe(-1)
expect(logWarningMock).toHaveBeenCalledTimes(1)
expect(logWarningMock).toHaveBeenCalledWith(
'Failed to save: Cache size of ~11264 MB (11811160064 B) is over the 10GB limit, not saving cache.'
)
const archiveFolder = '/foo/bar'
@@ -79,6 +83,7 @@ test('save with large cache outputs should fail in GHES with error message', asy
const cachePaths = [path.resolve(filePath)]
const createTarMock = jest.spyOn(tar, 'createTar')
const logWarningMock = jest.spyOn(core, 'warning')
const cacheSize = 11 * 1024 * 1024 * 1024 //~11GB, over the 10GB limit
jest
@@ -106,8 +111,11 @@ test('save with large cache outputs should fail in GHES with error message', asy
return response
})
await expect(saveCache([filePath], primaryKey)).rejects.toThrowError(
'The cache filesize must be between 0 and 1073741824 bytes'
const cacheId = await saveCache([filePath], primaryKey)
expect(cacheId).toBe(-1)
expect(logWarningMock).toHaveBeenCalledTimes(1)
expect(logWarningMock).toHaveBeenCalledWith(
'Failed to save: The cache filesize must be between 0 and 1073741824 bytes'
)
const archiveFolder = '/foo/bar'
@@ -127,6 +135,7 @@ test('save with large cache outputs should fail in GHES without error message',
const cachePaths = [path.resolve(filePath)]
const createTarMock = jest.spyOn(tar, 'createTar')
const logWarningMock = jest.spyOn(core, 'warning')
const cacheSize = 11 * 1024 * 1024 * 1024 //~11GB, over the 10GB limit
jest
@@ -150,8 +159,11 @@ test('save with large cache outputs should fail in GHES without error message',
return response
})
await expect(saveCache([filePath], primaryKey)).rejects.toThrowError(
'Cache size of ~11264 MB (11811160064 B) is over the data cap limit, not saving cache.'
const cacheId = await saveCache([filePath], primaryKey)
expect(cacheId).toBe(-1)
expect(logWarningMock).toHaveBeenCalledTimes(1)
expect(logWarningMock).toHaveBeenCalledWith(
'Failed to save: Cache size of ~11264 MB (11811160064 B) is over the data cap limit, not saving cache.'
)
const archiveFolder = '/foo/bar'
@@ -168,6 +180,7 @@ test('save with large cache outputs should fail in GHES without error message',
test('save with reserve cache failure should fail', async () => {
const paths = ['node_modules']
const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
const logInfoMock = jest.spyOn(core, 'info')
const reserveCacheMock = jest
.spyOn(cacheHttpClient, 'reserveCache')
@@ -187,9 +200,13 @@ test('save with reserve cache failure should fail', async () => {
.spyOn(cacheUtils, 'getCompressionMethod')
.mockReturnValueOnce(Promise.resolve(compression))
await expect(saveCache(paths, primaryKey)).rejects.toThrowError(
`Unable to reserve cache with key ${primaryKey}, another job may be creating this cache.`
const cacheId = await saveCache(paths, primaryKey)
expect(cacheId).toBe(-1)
expect(logInfoMock).toHaveBeenCalledTimes(1)
expect(logInfoMock).toHaveBeenCalledWith(
`Failed to save: Unable to reserve cache with key ${primaryKey}, another job may be creating this cache. More details: undefined`
)
expect(reserveCacheMock).toHaveBeenCalledTimes(1)
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, paths, {
compressionMethod: compression
@@ -203,7 +220,7 @@ test('save with server error should fail', async () => {
const filePath = 'node_modules'
const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
const cachePaths = [path.resolve(filePath)]
const logWarningMock = jest.spyOn(core, 'warning')
const cacheId = 4
const reserveCacheMock = jest
.spyOn(cacheHttpClient, 'reserveCache')
@@ -228,9 +245,12 @@ test('save with server error should fail', async () => {
.spyOn(cacheUtils, 'getCompressionMethod')
.mockReturnValueOnce(Promise.resolve(compression))
await expect(saveCache([filePath], primaryKey)).rejects.toThrowError(
'HTTP Error Occurred'
await saveCache([filePath], primaryKey)
expect(logWarningMock).toHaveBeenCalledTimes(1)
expect(logWarningMock).toHaveBeenCalledWith(
'Failed to save: HTTP Error Occurred'
)
expect(reserveCacheMock).toHaveBeenCalledTimes(1)
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, [filePath], {
compressionMethod: compression
@@ -290,3 +310,14 @@ test('save with valid inputs uploads a cache', async () => {
expect(saveCacheMock).toHaveBeenCalledWith(cacheId, archiveFile, undefined)
expect(getCompressionMock).toHaveBeenCalledTimes(1)
})
test('save with non existing path should not save cache', async () => {
const path = 'node_modules'
const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
jest.spyOn(cacheUtils, 'resolvePaths').mockImplementation(async () => {
return []
})
await expect(saveCache([path], primaryKey)).rejects.toThrowError(
`Path Validation Error: Path(s) specified in the action for caching do(es) not exist, hence no cache is being saved.`
)
})
+4
View File
@@ -143,6 +143,8 @@ test('zstd create tar', async () => {
'zstd -T0 --long=30',
'-cf',
IS_WINDOWS ? CacheFilename.Zstd.replace(/\\/g, '/') : CacheFilename.Zstd,
'--exclude',
IS_WINDOWS ? CacheFilename.Zstd.replace(/\\/g, '/') : CacheFilename.Zstd,
'-P',
'-C',
IS_WINDOWS ? workspace?.replace(/\\/g, '/') : workspace,
@@ -180,6 +182,8 @@ test('gzip create tar', async () => {
'-z',
'-cf',
IS_WINDOWS ? CacheFilename.Gzip.replace(/\\/g, '/') : CacheFilename.Gzip,
'--exclude',
IS_WINDOWS ? CacheFilename.Gzip.replace(/\\/g, '/') : CacheFilename.Gzip,
'-P',
'-C',
IS_WINDOWS ? workspace?.replace(/\\/g, '/') : workspace,
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "@actions/cache",
"version": "2.0.4",
"version": "3.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@actions/cache",
"version": "2.0.3",
"version": "3.0.0",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.2.6",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@actions/cache",
"version": "2.0.4",
"version": "3.0.0",
"preview": true,
"description": "Actions cache lib",
"keywords": [
+44 -18
View File
@@ -86,23 +86,24 @@ export async function restoreCache(
}
const compressionMethod = await utils.getCompressionMethod()
// path are needed to compute version
const cacheEntry = await cacheHttpClient.getCacheEntry(keys, paths, {
compressionMethod
})
if (!cacheEntry?.archiveLocation) {
// Cache not found
return undefined
}
const archivePath = path.join(
await utils.createTempDirectory(),
utils.getCacheFileName(compressionMethod)
)
core.debug(`Archive Path: ${archivePath}`)
let archivePath = ''
try {
// path are needed to compute version
const cacheEntry = await cacheHttpClient.getCacheEntry(keys, paths, {
compressionMethod
})
if (!cacheEntry?.archiveLocation) {
// Cache not found
return undefined
}
archivePath = path.join(
await utils.createTempDirectory(),
utils.getCacheFileName(compressionMethod)
)
core.debug(`Archive Path: ${archivePath}`)
// Download the cache from the cache entry
await cacheHttpClient.downloadCache(
cacheEntry.archiveLocation,
@@ -123,6 +124,16 @@ export async function restoreCache(
await extractTar(archivePath, compressionMethod)
core.info('Cache restored successfully')
return cacheEntry.cacheKey
} catch (error) {
const typedError = error as Error
if (typedError.name === ValidationError.name) {
throw error
} else {
// Supress all non-validation cache related errors because caching should be optional
core.warning(`Failed to restore: ${(error as Error).message}`)
}
} finally {
// Try to delete the archive to save space
try {
@@ -132,7 +143,7 @@ export async function restoreCache(
}
}
return cacheEntry.cacheKey
return undefined
}
/**
@@ -152,12 +163,18 @@ export async function saveCache(
checkKey(key)
const compressionMethod = await utils.getCompressionMethod()
let cacheId = null
let cacheId = -1
const cachePaths = await utils.resolvePaths(paths)
core.debug('Cache Paths:')
core.debug(`${JSON.stringify(cachePaths)}`)
if (cachePaths.length === 0) {
throw new Error(
`Path Validation Error: Path(s) specified in the action for caching do(es) not exist, hence no cache is being saved.`
)
}
const archiveFolder = await utils.createTempDirectory()
const archivePath = path.join(
archiveFolder,
@@ -211,6 +228,15 @@ export async function saveCache(
core.debug(`Saving Cache (ID: ${cacheId})`)
await cacheHttpClient.saveCache(cacheId, archivePath, options)
} catch (error) {
const typedError = error as Error
if (typedError.name === ValidationError.name) {
throw error
} else if (typedError.name === ReserveCacheError.name) {
core.info(`Failed to save: ${typedError.message}`)
} else {
core.warning(`Failed to save: ${typedError.message}`)
}
} finally {
// Try to delete the archive to save space
try {
+10 -9
View File
@@ -61,15 +61,15 @@ export async function extractTar(
// Create directory to extract tar into
const workingDirectory = getWorkingDirectory()
await io.mkdirP(workingDirectory)
// --d: Decompress.
// --decompress: Decompress.
// --long=#: Enables long distance matching with # bits. Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit.
// Using 30 here because we also support 32-bit self-hosted runners.
function getCompressionProgram(): string[] {
switch (compressionMethod) {
case CompressionMethod.Zstd:
return ['--use-compress-program', 'zstd -d --long=30']
return ['--use-compress-program', 'zstd --decompress --long=30']
case CompressionMethod.ZstdWithoutLong:
return ['--use-compress-program', 'zstd -d']
return ['--use-compress-program', 'zstd --decompress']
default:
return ['-z']
}
@@ -99,16 +99,16 @@ export async function createTar(
)
const workingDirectory = getWorkingDirectory()
// -T#: Compress using # working thread. If # is 0, attempt to detect and use the number of physical CPU cores.
// --threads=#: Compress using # working thread. If # is 0, attempt to detect and use the number of physical CPU cores.
// --long=#: Enables long distance matching with # bits. Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit.
// Using 30 here because we also support 32-bit self-hosted runners.
// Long range mode is added to zstd in v1.3.2 release, so we will not use --long in older version of zstd.
function getCompressionProgram(): string[] {
switch (compressionMethod) {
case CompressionMethod.Zstd:
return ['--use-compress-program', 'zstd -T0 --long=30']
return ['--use-compress-program', 'zstd --threads=0 --long=30']
case CompressionMethod.ZstdWithoutLong:
return ['--use-compress-program', 'zstd -T0']
return ['--use-compress-program', 'zstd --threads=0']
default:
return ['-z']
}
@@ -118,6 +118,8 @@ export async function createTar(
...getCompressionProgram(),
'-cf',
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
'--exclude',
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
'-P',
'-C',
workingDirectory.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
@@ -131,16 +133,15 @@ export async function listTar(
archivePath: string,
compressionMethod: CompressionMethod
): Promise<void> {
// --d: Decompress.
// --long=#: Enables long distance matching with # bits.
// Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit.
// Using 30 here because we also support 32-bit self-hosted runners.
function getCompressionProgram(): string[] {
switch (compressionMethod) {
case CompressionMethod.Zstd:
return ['--use-compress-program', 'zstd -d --long=30']
return ['--use-compress-program', 'zstd --long=30']
case CompressionMethod.ZstdWithoutLong:
return ['--use-compress-program', 'zstd -d']
return ['--use-compress-program', 'zstd']
default:
return ['-z']
}
+24 -1
View File
@@ -309,4 +309,27 @@ outputs:
runs:
using: 'node12'
main: 'dist/index.js'
```
```
#### Filesystem path helpers
You can use these methods to manipulate file paths across operating systems.
The `toPosixPath` function converts input paths to Posix-style (Linux) paths.
The `toWin32Path` function converts input paths to Windows-style paths. These
functions work independently of the underlying runner operating system.
```js
toPosixPath('\\foo\\bar') // => /foo/bar
toWin32Path('/foo/bar') // => \foo\bar
```
The `toPlatformPath` function converts input paths to the expected value on the runner's operating system.
```js
// On a Windows runner.
toPlatformPath('/foo/bar') // => \foo\bar
// On a Linux runner.
toPlatformPath('\\foo\\bar') // => /foo/bar
```
+3
View File
@@ -1,5 +1,8 @@
# @actions/core Releases
### 1.9.0
- Added `toPosixPath`, `toWin32Path` and `toPlatformPath` utilities [#1102](https://github.com/actions/toolkit/pull/1102)
### 1.8.2
- Update to v2.0.1 of `@actions/http-client` [#1087](https://github.com/actions/toolkit/pull/1087)
+162
View File
@@ -0,0 +1,162 @@
import * as path from 'path'
import {toPlatformPath, toPosixPath, toWin32Path} from '../src/path-utils'
describe('#toPosixPath', () => {
const cases: {
only?: boolean
name: string
input: string
expected: string
}[] = [
{
name: 'empty string',
input: '',
expected: ''
},
{
name: 'single value',
input: 'foo',
expected: 'foo'
},
{
name: 'with posix relative',
input: 'foo/bar/baz',
expected: 'foo/bar/baz'
},
{
name: 'with posix absolute',
input: '/foo/bar/baz',
expected: '/foo/bar/baz'
},
{
name: 'with win32 relative',
input: 'foo\\bar\\baz',
expected: 'foo/bar/baz'
},
{
name: 'with win32 absolute',
input: '\\foo\\bar\\baz',
expected: '/foo/bar/baz'
},
{
name: 'with a mix',
input: '\\foo/bar/baz',
expected: '/foo/bar/baz'
}
]
for (const tc of cases) {
const fn = tc.only ? it.only : it
fn(tc.name, () => {
const result = toPosixPath(tc.input)
expect(result).toEqual(tc.expected)
})
}
})
describe('#toWin32Path', () => {
const cases: {
only?: boolean
name: string
input: string
expected: string
}[] = [
{
name: 'empty string',
input: '',
expected: ''
},
{
name: 'single value',
input: 'foo',
expected: 'foo'
},
{
name: 'with posix relative',
input: 'foo/bar/baz',
expected: 'foo\\bar\\baz'
},
{
name: 'with posix absolute',
input: '/foo/bar/baz',
expected: '\\foo\\bar\\baz'
},
{
name: 'with win32 relative',
input: 'foo\\bar\\baz',
expected: 'foo\\bar\\baz'
},
{
name: 'with win32 absolute',
input: '\\foo\\bar\\baz',
expected: '\\foo\\bar\\baz'
},
{
name: 'with a mix',
input: '\\foo/bar\\baz',
expected: '\\foo\\bar\\baz'
}
]
for (const tc of cases) {
const fn = tc.only ? it.only : it
fn(tc.name, () => {
const result = toWin32Path(tc.input)
expect(result).toEqual(tc.expected)
})
}
})
describe('#toPlatformPath', () => {
const cases: {
only?: boolean
name: string
input: string
expected: string
}[] = [
{
name: 'empty string',
input: '',
expected: ''
},
{
name: 'single value',
input: 'foo',
expected: 'foo'
},
{
name: 'with posix relative',
input: 'foo/bar/baz',
expected: path.join('foo', 'bar', 'baz')
},
{
name: 'with posix absolute',
input: '/foo/bar/baz',
expected: path.join(path.sep, 'foo', 'bar', 'baz')
},
{
name: 'with win32 relative',
input: 'foo\\bar\\baz',
expected: path.join('foo', 'bar', 'baz')
},
{
name: 'with win32 absolute',
input: '\\foo\\bar\\baz',
expected: path.join(path.sep, 'foo', 'bar', 'baz')
},
{
name: 'with a mix',
input: '\\foo/bar\\baz',
expected: path.join(path.sep, 'foo', 'bar', 'baz')
}
]
for (const tc of cases) {
const fn = tc.only ? it.only : it
fn(tc.name, () => {
const result = toPlatformPath(tc.input)
expect(result).toEqual(tc.expected)
})
}
})
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@actions/core",
"version": "1.8.2",
"version": "1.9.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@actions/core",
"version": "1.8.2",
"version": "1.9.0",
"description": "Actions core lib",
"keywords": [
"github",
+5
View File
@@ -369,3 +369,8 @@ export {summary} from './summary'
* @deprecated use core.summary
*/
export {markdownSummary} from './summary'
/**
* Path exports
*/
export {toPosixPath, toWin32Path, toPlatformPath} from './path-utils'
+35
View File
@@ -0,0 +1,35 @@
import * as path from 'path'
/**
* toPosixPath converts the given path to the posix form. On Windows, \\ will be
* replaced with /.
*
* @param pth. Path to transform.
* @return string Posix path.
*/
export function toPosixPath(pth: string): string {
return pth.replace(/[\\]/g, '/')
}
/**
* toWin32Path converts the given path to the win32 form. On Linux, / will be
* replaced with \\.
*
* @param pth. Path to transform.
* @return string Win32 path.
*/
export function toWin32Path(pth: string): string {
return pth.replace(/[/]/g, '\\')
}
/**
* toPlatformPath converts the given path to a platform-specific path. It does
* this by replacing instances of / and \ with the platform-specific path
* separator.
*
* @param pth The path to platformize.
* @return string The platform-specific path.
*/
export function toPlatformPath(pth: string): string {
return pth.replace(/[/\\]/g, path.sep)
}