Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 73d8e12de2 | |||
| 31a98126a0 |
@@ -24,10 +24,10 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Set Node.js 16.x
|
- name: Set Node.js 12.x
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 16.x
|
node-version: 12.x
|
||||||
|
|
||||||
# In order to upload & download artifacts from a shell script, certain env variables need to be set that are only available in the
|
# In order to upload & download artifacts from a shell script, certain env variables need to be set that are only available in the
|
||||||
# node context. This runs a local action that gets and sets the necessary env variables that are needed
|
# node context. This runs a local action that gets and sets the necessary env variables that are needed
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Set Node.js 16.x
|
- name: Set Node.js 12.x
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 16.x
|
node-version: 12.x
|
||||||
|
|
||||||
- name: npm install
|
- name: npm install
|
||||||
run: npm install
|
run: npm install
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Set Node.js 16.x
|
- name: Set Node.js 12.x
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 16.x
|
node-version: 12.x
|
||||||
|
|
||||||
# In order to save & restore cache from a shell script, certain env variables need to be set that are only available in the
|
# In order to save & restore cache from a shell script, certain env variables need to be set that are only available in the
|
||||||
# node context. This runs a local action that gets and sets the necessary env variables that are needed
|
# node context. This runs a local action that gets and sets the necessary env variables that are needed
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ jobs:
|
|||||||
- name: verify package exists
|
- name: verify package exists
|
||||||
run: ls packages/${{ github.event.inputs.package }}
|
run: ls packages/${{ github.event.inputs.package }}
|
||||||
|
|
||||||
- name: Set Node.js 16.x
|
- name: Set Node.js 12.x
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 16.x
|
node-version: 12.x
|
||||||
|
|
||||||
- name: npm install
|
- name: npm install
|
||||||
run: npm install
|
run: npm install
|
||||||
|
|||||||
@@ -25,10 +25,10 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Set Node.js 16.x
|
- name: Set Node.js 12.x
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 16.x
|
node-version: 12.x
|
||||||
|
|
||||||
- name: npm install
|
- name: npm install
|
||||||
run: npm install
|
run: npm install
|
||||||
|
|||||||
Generated
+3110
-16400
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -15,7 +15,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^27.0.2",
|
"@types/jest": "^27.0.2",
|
||||||
"@types/node": "^16.11.7",
|
"@types/node": "^12.20.13",
|
||||||
"@types/signale": "^1.4.1",
|
"@types/signale": "^1.4.1",
|
||||||
"@typescript-eslint/parser": "^4.0.0",
|
"@typescript-eslint/parser": "^4.0.0",
|
||||||
"concurrently": "^6.1.0",
|
"concurrently": "^6.1.0",
|
||||||
|
|||||||
+1
-33
@@ -1,6 +1,5 @@
|
|||||||
import {retry, retryTypedResponse} from '../src/internal/requestUtils'
|
import {retry} from '../src/internal/requestUtils'
|
||||||
import {HttpClientError} from '@actions/http-client'
|
import {HttpClientError} from '@actions/http-client'
|
||||||
import * as requestUtils from '../src/internal/requestUtils'
|
|
||||||
|
|
||||||
interface ITestResponse {
|
interface ITestResponse {
|
||||||
statusCode: number
|
statusCode: number
|
||||||
@@ -146,34 +145,3 @@ test('retry converts errors to response object', async () => {
|
|||||||
null
|
null
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('retryTypedResponse gives an error with error message', async () => {
|
|
||||||
const httpClientError = new HttpClientError(
|
|
||||||
'The cache filesize must be between 0 and 10 * 1024 * 1024 bytes',
|
|
||||||
400
|
|
||||||
)
|
|
||||||
jest.spyOn(requestUtils, 'retry').mockReturnValue(
|
|
||||||
new Promise(resolve => {
|
|
||||||
resolve(httpClientError)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
try {
|
|
||||||
await retryTypedResponse<string>(
|
|
||||||
'reserveCache',
|
|
||||||
async () =>
|
|
||||||
new Promise(resolve => {
|
|
||||||
resolve({
|
|
||||||
statusCode: 400,
|
|
||||||
result: '',
|
|
||||||
headers: {},
|
|
||||||
error: httpClientError
|
|
||||||
})
|
|
||||||
})
|
|
||||||
)
|
|
||||||
} catch (error) {
|
|
||||||
expect(error).toHaveProperty(
|
|
||||||
'message',
|
|
||||||
'The cache filesize must be between 0 and 10 * 1024 * 1024 bytes'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|||||||
+13
-117
@@ -5,12 +5,6 @@ import * as cacheHttpClient from '../src/internal/cacheHttpClient'
|
|||||||
import * as cacheUtils from '../src/internal/cacheUtils'
|
import * as cacheUtils from '../src/internal/cacheUtils'
|
||||||
import {CacheFilename, CompressionMethod} from '../src/internal/constants'
|
import {CacheFilename, CompressionMethod} from '../src/internal/constants'
|
||||||
import * as tar from '../src/internal/tar'
|
import * as tar from '../src/internal/tar'
|
||||||
import {ITypedResponse} from '@actions/http-client/interfaces'
|
|
||||||
import {
|
|
||||||
ReserveCacheResponse,
|
|
||||||
ITypedResponseWithError
|
|
||||||
} from '../src/internal/contracts'
|
|
||||||
import {HttpClientError} from '@actions/http-client'
|
|
||||||
|
|
||||||
jest.mock('../src/internal/cacheHttpClient')
|
jest.mock('../src/internal/cacheHttpClient')
|
||||||
jest.mock('../src/internal/cacheUtils')
|
jest.mock('../src/internal/cacheUtils')
|
||||||
@@ -22,13 +16,16 @@ beforeAll(() => {
|
|||||||
jest.spyOn(core, 'info').mockImplementation(() => {})
|
jest.spyOn(core, 'info').mockImplementation(() => {})
|
||||||
jest.spyOn(core, 'warning').mockImplementation(() => {})
|
jest.spyOn(core, 'warning').mockImplementation(() => {})
|
||||||
jest.spyOn(core, 'error').mockImplementation(() => {})
|
jest.spyOn(core, 'error').mockImplementation(() => {})
|
||||||
|
|
||||||
jest.spyOn(cacheUtils, 'getCacheFileName').mockImplementation(cm => {
|
jest.spyOn(cacheUtils, 'getCacheFileName').mockImplementation(cm => {
|
||||||
const actualUtils = jest.requireActual('../src/internal/cacheUtils')
|
const actualUtils = jest.requireActual('../src/internal/cacheUtils')
|
||||||
return actualUtils.getCacheFileName(cm)
|
return actualUtils.getCacheFileName(cm)
|
||||||
})
|
})
|
||||||
|
|
||||||
jest.spyOn(cacheUtils, 'resolvePaths').mockImplementation(async filePaths => {
|
jest.spyOn(cacheUtils, 'resolvePaths').mockImplementation(async filePaths => {
|
||||||
return filePaths.map(x => path.resolve(x))
|
return filePaths.map(x => path.resolve(x))
|
||||||
})
|
})
|
||||||
|
|
||||||
jest.spyOn(cacheUtils, 'createTempDirectory').mockImplementation(async () => {
|
jest.spyOn(cacheUtils, 'createTempDirectory').mockImplementation(async () => {
|
||||||
return Promise.resolve('/foo/bar')
|
return Promise.resolve('/foo/bar')
|
||||||
})
|
})
|
||||||
@@ -73,98 +70,6 @@ test('save with large cache outputs should fail', async () => {
|
|||||||
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('save with large cache outputs should fail in GHES with error message', async () => {
|
|
||||||
const filePath = 'node_modules'
|
|
||||||
const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
|
|
||||||
const cachePaths = [path.resolve(filePath)]
|
|
||||||
|
|
||||||
const createTarMock = jest.spyOn(tar, 'createTar')
|
|
||||||
|
|
||||||
const cacheSize = 11 * 1024 * 1024 * 1024 //~11GB, over the 10GB limit
|
|
||||||
jest
|
|
||||||
.spyOn(cacheUtils, 'getArchiveFileSizeInBytes')
|
|
||||||
.mockReturnValueOnce(cacheSize)
|
|
||||||
const compression = CompressionMethod.Gzip
|
|
||||||
const getCompressionMock = jest
|
|
||||||
.spyOn(cacheUtils, 'getCompressionMethod')
|
|
||||||
.mockReturnValueOnce(Promise.resolve(compression))
|
|
||||||
|
|
||||||
jest.spyOn(cacheUtils, 'isGhes').mockReturnValueOnce(true)
|
|
||||||
|
|
||||||
const reserveCacheMock = jest
|
|
||||||
.spyOn(cacheHttpClient, 'reserveCache')
|
|
||||||
.mockImplementation(async () => {
|
|
||||||
const response: ITypedResponseWithError<ReserveCacheResponse> = {
|
|
||||||
statusCode: 400,
|
|
||||||
result: null,
|
|
||||||
headers: {},
|
|
||||||
error: new HttpClientError(
|
|
||||||
'The cache filesize must be between 0 and 1073741824 bytes',
|
|
||||||
400
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return response
|
|
||||||
})
|
|
||||||
|
|
||||||
await expect(saveCache([filePath], primaryKey)).rejects.toThrowError(
|
|
||||||
'The cache filesize must be between 0 and 1073741824 bytes'
|
|
||||||
)
|
|
||||||
|
|
||||||
const archiveFolder = '/foo/bar'
|
|
||||||
expect(reserveCacheMock).toHaveBeenCalledTimes(1)
|
|
||||||
expect(createTarMock).toHaveBeenCalledTimes(1)
|
|
||||||
expect(createTarMock).toHaveBeenCalledWith(
|
|
||||||
archiveFolder,
|
|
||||||
cachePaths,
|
|
||||||
compression
|
|
||||||
)
|
|
||||||
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('save with large cache outputs should fail in GHES without error message', async () => {
|
|
||||||
const filePath = 'node_modules'
|
|
||||||
const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
|
|
||||||
const cachePaths = [path.resolve(filePath)]
|
|
||||||
|
|
||||||
const createTarMock = jest.spyOn(tar, 'createTar')
|
|
||||||
|
|
||||||
const cacheSize = 11 * 1024 * 1024 * 1024 //~11GB, over the 10GB limit
|
|
||||||
jest
|
|
||||||
.spyOn(cacheUtils, 'getArchiveFileSizeInBytes')
|
|
||||||
.mockReturnValueOnce(cacheSize)
|
|
||||||
const compression = CompressionMethod.Gzip
|
|
||||||
const getCompressionMock = jest
|
|
||||||
.spyOn(cacheUtils, 'getCompressionMethod')
|
|
||||||
.mockReturnValueOnce(Promise.resolve(compression))
|
|
||||||
|
|
||||||
jest.spyOn(cacheUtils, 'isGhes').mockReturnValueOnce(true)
|
|
||||||
|
|
||||||
const reserveCacheMock = jest
|
|
||||||
.spyOn(cacheHttpClient, 'reserveCache')
|
|
||||||
.mockImplementation(async () => {
|
|
||||||
const response: ITypedResponseWithError<ReserveCacheResponse> = {
|
|
||||||
statusCode: 400,
|
|
||||||
result: null,
|
|
||||||
headers: {}
|
|
||||||
}
|
|
||||||
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 archiveFolder = '/foo/bar'
|
|
||||||
expect(reserveCacheMock).toHaveBeenCalledTimes(1)
|
|
||||||
expect(createTarMock).toHaveBeenCalledTimes(1)
|
|
||||||
expect(createTarMock).toHaveBeenCalledWith(
|
|
||||||
archiveFolder,
|
|
||||||
cachePaths,
|
|
||||||
compression
|
|
||||||
)
|
|
||||||
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('save with reserve cache failure should fail', async () => {
|
test('save with reserve cache failure should fail', async () => {
|
||||||
const paths = ['node_modules']
|
const paths = ['node_modules']
|
||||||
const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
|
const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
|
||||||
@@ -172,12 +77,7 @@ test('save with reserve cache failure should fail', async () => {
|
|||||||
const reserveCacheMock = jest
|
const reserveCacheMock = jest
|
||||||
.spyOn(cacheHttpClient, 'reserveCache')
|
.spyOn(cacheHttpClient, 'reserveCache')
|
||||||
.mockImplementation(async () => {
|
.mockImplementation(async () => {
|
||||||
const response: ITypedResponse<ReserveCacheResponse> = {
|
return -1
|
||||||
statusCode: 500,
|
|
||||||
result: null,
|
|
||||||
headers: {}
|
|
||||||
}
|
|
||||||
return response
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const createTarMock = jest.spyOn(tar, 'createTar')
|
const createTarMock = jest.spyOn(tar, 'createTar')
|
||||||
@@ -194,7 +94,7 @@ test('save with reserve cache failure should fail', async () => {
|
|||||||
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, paths, {
|
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, paths, {
|
||||||
compressionMethod: compression
|
compressionMethod: compression
|
||||||
})
|
})
|
||||||
expect(createTarMock).toHaveBeenCalledTimes(1)
|
expect(createTarMock).toHaveBeenCalledTimes(0)
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(0)
|
expect(saveCacheMock).toHaveBeenCalledTimes(0)
|
||||||
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
||||||
})
|
})
|
||||||
@@ -208,12 +108,7 @@ test('save with server error should fail', async () => {
|
|||||||
const reserveCacheMock = jest
|
const reserveCacheMock = jest
|
||||||
.spyOn(cacheHttpClient, 'reserveCache')
|
.spyOn(cacheHttpClient, 'reserveCache')
|
||||||
.mockImplementation(async () => {
|
.mockImplementation(async () => {
|
||||||
const response: ITypedResponse<ReserveCacheResponse> = {
|
return cacheId
|
||||||
statusCode: 500,
|
|
||||||
result: {cacheId},
|
|
||||||
headers: {}
|
|
||||||
}
|
|
||||||
return response
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const createTarMock = jest.spyOn(tar, 'createTar')
|
const createTarMock = jest.spyOn(tar, 'createTar')
|
||||||
@@ -235,14 +130,17 @@ test('save with server error should fail', async () => {
|
|||||||
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, [filePath], {
|
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, [filePath], {
|
||||||
compressionMethod: compression
|
compressionMethod: compression
|
||||||
})
|
})
|
||||||
|
|
||||||
const archiveFolder = '/foo/bar'
|
const archiveFolder = '/foo/bar'
|
||||||
const archiveFile = path.join(archiveFolder, CacheFilename.Zstd)
|
const archiveFile = path.join(archiveFolder, CacheFilename.Zstd)
|
||||||
|
|
||||||
expect(createTarMock).toHaveBeenCalledTimes(1)
|
expect(createTarMock).toHaveBeenCalledTimes(1)
|
||||||
expect(createTarMock).toHaveBeenCalledWith(
|
expect(createTarMock).toHaveBeenCalledWith(
|
||||||
archiveFolder,
|
archiveFolder,
|
||||||
cachePaths,
|
cachePaths,
|
||||||
compression
|
compression
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(1)
|
expect(saveCacheMock).toHaveBeenCalledTimes(1)
|
||||||
expect(saveCacheMock).toHaveBeenCalledWith(cacheId, archiveFile, undefined)
|
expect(saveCacheMock).toHaveBeenCalledWith(cacheId, archiveFile, undefined)
|
||||||
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
||||||
@@ -257,12 +155,7 @@ test('save with valid inputs uploads a cache', async () => {
|
|||||||
const reserveCacheMock = jest
|
const reserveCacheMock = jest
|
||||||
.spyOn(cacheHttpClient, 'reserveCache')
|
.spyOn(cacheHttpClient, 'reserveCache')
|
||||||
.mockImplementation(async () => {
|
.mockImplementation(async () => {
|
||||||
const response: ITypedResponse<ReserveCacheResponse> = {
|
return cacheId
|
||||||
statusCode: 500,
|
|
||||||
result: {cacheId},
|
|
||||||
headers: {}
|
|
||||||
}
|
|
||||||
return response
|
|
||||||
})
|
})
|
||||||
const createTarMock = jest.spyOn(tar, 'createTar')
|
const createTarMock = jest.spyOn(tar, 'createTar')
|
||||||
|
|
||||||
@@ -278,14 +171,17 @@ test('save with valid inputs uploads a cache', async () => {
|
|||||||
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, [filePath], {
|
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, [filePath], {
|
||||||
compressionMethod: compression
|
compressionMethod: compression
|
||||||
})
|
})
|
||||||
|
|
||||||
const archiveFolder = '/foo/bar'
|
const archiveFolder = '/foo/bar'
|
||||||
const archiveFile = path.join(archiveFolder, CacheFilename.Zstd)
|
const archiveFile = path.join(archiveFolder, CacheFilename.Zstd)
|
||||||
|
|
||||||
expect(createTarMock).toHaveBeenCalledTimes(1)
|
expect(createTarMock).toHaveBeenCalledTimes(1)
|
||||||
expect(createTarMock).toHaveBeenCalledWith(
|
expect(createTarMock).toHaveBeenCalledWith(
|
||||||
archiveFolder,
|
archiveFolder,
|
||||||
cachePaths,
|
cachePaths,
|
||||||
compression
|
compression
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(1)
|
expect(saveCacheMock).toHaveBeenCalledTimes(1)
|
||||||
expect(saveCacheMock).toHaveBeenCalledWith(cacheId, archiveFile, undefined)
|
expect(saveCacheMock).toHaveBeenCalledWith(cacheId, archiveFile, undefined)
|
||||||
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/cache",
|
"name": "@actions/cache",
|
||||||
"version": "2.0.2",
|
"version": "2.0.0",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/cache",
|
"name": "@actions/cache",
|
||||||
"version": "2.0.2",
|
"version": "2.0.0",
|
||||||
"preview": true,
|
"preview": true,
|
||||||
"description": "Actions cache lib",
|
"description": "Actions cache lib",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
|||||||
Vendored
+13
-29
@@ -152,7 +152,17 @@ export async function saveCache(
|
|||||||
checkKey(key)
|
checkKey(key)
|
||||||
|
|
||||||
const compressionMethod = await utils.getCompressionMethod()
|
const compressionMethod = await utils.getCompressionMethod()
|
||||||
let cacheId = null
|
|
||||||
|
core.debug('Reserving Cache')
|
||||||
|
const cacheId = await cacheHttpClient.reserveCache(key, paths, {
|
||||||
|
compressionMethod
|
||||||
|
})
|
||||||
|
if (cacheId === -1) {
|
||||||
|
throw new ReserveCacheError(
|
||||||
|
`Unable to reserve cache with key ${key}, another job may be creating this cache.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
core.debug(`Cache ID: ${cacheId}`)
|
||||||
|
|
||||||
const cachePaths = await utils.resolvePaths(paths)
|
const cachePaths = await utils.resolvePaths(paths)
|
||||||
core.debug('Cache Paths:')
|
core.debug('Cache Paths:')
|
||||||
@@ -171,12 +181,11 @@ export async function saveCache(
|
|||||||
if (core.isDebug()) {
|
if (core.isDebug()) {
|
||||||
await listTar(archivePath, compressionMethod)
|
await listTar(archivePath, compressionMethod)
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileSizeLimit = 10 * 1024 * 1024 * 1024 // 10GB per repo limit
|
const fileSizeLimit = 10 * 1024 * 1024 * 1024 // 10GB per repo limit
|
||||||
const archiveFileSize = utils.getArchiveFileSizeInBytes(archivePath)
|
const archiveFileSize = utils.getArchiveFileSizeInBytes(archivePath)
|
||||||
core.debug(`File Size: ${archiveFileSize}`)
|
core.debug(`File Size: ${archiveFileSize}`)
|
||||||
|
if (archiveFileSize > fileSizeLimit) {
|
||||||
// For GHES, this check will take place in ReserveCache API with enterprise file size limit
|
|
||||||
if (archiveFileSize > fileSizeLimit && !utils.isGhes()) {
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Cache size of ~${Math.round(
|
`Cache size of ~${Math.round(
|
||||||
archiveFileSize / (1024 * 1024)
|
archiveFileSize / (1024 * 1024)
|
||||||
@@ -184,31 +193,6 @@ export async function saveCache(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
core.debug('Reserving Cache')
|
|
||||||
const reserveCacheResponse = await cacheHttpClient.reserveCache(
|
|
||||||
key,
|
|
||||||
paths,
|
|
||||||
{
|
|
||||||
compressionMethod,
|
|
||||||
cacheSize: archiveFileSize
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (reserveCacheResponse?.result?.cacheId) {
|
|
||||||
cacheId = reserveCacheResponse?.result?.cacheId
|
|
||||||
} else if (reserveCacheResponse?.statusCode === 400) {
|
|
||||||
throw new Error(
|
|
||||||
reserveCacheResponse?.error?.message ??
|
|
||||||
`Cache size of ~${Math.round(
|
|
||||||
archiveFileSize / (1024 * 1024)
|
|
||||||
)} MB (${archiveFileSize} B) is over the data cap limit, not saving cache.`
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
throw new ReserveCacheError(
|
|
||||||
`Unable to reserve cache with key ${key}, another job may be creating this cache. More details: ${reserveCacheResponse?.error?.message}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
core.debug(`Saving Cache (ID: ${cacheId})`)
|
core.debug(`Saving Cache (ID: ${cacheId})`)
|
||||||
await cacheHttpClient.saveCache(cacheId, archivePath, options)
|
await cacheHttpClient.saveCache(cacheId, archivePath, options)
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
+4
-6
@@ -13,8 +13,7 @@ import {
|
|||||||
InternalCacheOptions,
|
InternalCacheOptions,
|
||||||
CommitCacheRequest,
|
CommitCacheRequest,
|
||||||
ReserveCacheRequest,
|
ReserveCacheRequest,
|
||||||
ReserveCacheResponse,
|
ReserveCacheResponse
|
||||||
ITypedResponseWithError
|
|
||||||
} from './contracts'
|
} from './contracts'
|
||||||
import {downloadCacheHttpClient, downloadCacheStorageSDK} from './downloadUtils'
|
import {downloadCacheHttpClient, downloadCacheStorageSDK} from './downloadUtils'
|
||||||
import {
|
import {
|
||||||
@@ -144,14 +143,13 @@ export async function reserveCache(
|
|||||||
key: string,
|
key: string,
|
||||||
paths: string[],
|
paths: string[],
|
||||||
options?: InternalCacheOptions
|
options?: InternalCacheOptions
|
||||||
): Promise<ITypedResponseWithError<ReserveCacheResponse>> {
|
): Promise<number> {
|
||||||
const httpClient = createHttpClient()
|
const httpClient = createHttpClient()
|
||||||
const version = getCacheVersion(paths, options?.compressionMethod)
|
const version = getCacheVersion(paths, options?.compressionMethod)
|
||||||
|
|
||||||
const reserveCacheRequest: ReserveCacheRequest = {
|
const reserveCacheRequest: ReserveCacheRequest = {
|
||||||
key,
|
key,
|
||||||
version,
|
version
|
||||||
cacheSize: options?.cacheSize
|
|
||||||
}
|
}
|
||||||
const response = await retryTypedResponse('reserveCache', async () =>
|
const response = await retryTypedResponse('reserveCache', async () =>
|
||||||
httpClient.postJson<ReserveCacheResponse>(
|
httpClient.postJson<ReserveCacheResponse>(
|
||||||
@@ -159,7 +157,7 @@ export async function reserveCache(
|
|||||||
reserveCacheRequest
|
reserveCacheRequest
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return response
|
return response?.result?.cacheId ?? -1
|
||||||
}
|
}
|
||||||
|
|
||||||
function getContentRange(start: number, end: number): string {
|
function getContentRange(start: number, end: number): string {
|
||||||
|
|||||||
-7
@@ -123,10 +123,3 @@ export function assertDefined<T>(name: string, value?: T): T {
|
|||||||
|
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isGhes(): boolean {
|
|
||||||
const ghUrl = new URL(
|
|
||||||
process.env['GITHUB_SERVER_URL'] || 'https://github.com'
|
|
||||||
)
|
|
||||||
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM'
|
|
||||||
}
|
|
||||||
|
|||||||
-8
@@ -1,10 +1,4 @@
|
|||||||
import {CompressionMethod} from './constants'
|
import {CompressionMethod} from './constants'
|
||||||
import {ITypedResponse} from '@actions/http-client/interfaces'
|
|
||||||
import {HttpClientError} from '@actions/http-client'
|
|
||||||
|
|
||||||
export interface ITypedResponseWithError<T> extends ITypedResponse<T> {
|
|
||||||
error?: HttpClientError
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ArtifactCacheEntry {
|
export interface ArtifactCacheEntry {
|
||||||
cacheKey?: string
|
cacheKey?: string
|
||||||
@@ -20,7 +14,6 @@ export interface CommitCacheRequest {
|
|||||||
export interface ReserveCacheRequest {
|
export interface ReserveCacheRequest {
|
||||||
key: string
|
key: string
|
||||||
version?: string
|
version?: string
|
||||||
cacheSize?: number
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ReserveCacheResponse {
|
export interface ReserveCacheResponse {
|
||||||
@@ -29,5 +22,4 @@ export interface ReserveCacheResponse {
|
|||||||
|
|
||||||
export interface InternalCacheOptions {
|
export interface InternalCacheOptions {
|
||||||
compressionMethod?: CompressionMethod
|
compressionMethod?: CompressionMethod
|
||||||
cacheSize?: number
|
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-7
@@ -1,8 +1,10 @@
|
|||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import {HttpCodes, HttpClientError} from '@actions/http-client'
|
import {HttpCodes, HttpClientError} from '@actions/http-client'
|
||||||
import {IHttpClientResponse} from '@actions/http-client/interfaces'
|
import {
|
||||||
|
IHttpClientResponse,
|
||||||
|
ITypedResponse
|
||||||
|
} from '@actions/http-client/interfaces'
|
||||||
import {DefaultRetryDelay, DefaultRetryAttempts} from './constants'
|
import {DefaultRetryDelay, DefaultRetryAttempts} from './constants'
|
||||||
import {ITypedResponseWithError} from './contracts'
|
|
||||||
|
|
||||||
export function isSuccessStatusCode(statusCode?: number): boolean {
|
export function isSuccessStatusCode(statusCode?: number): boolean {
|
||||||
if (!statusCode) {
|
if (!statusCode) {
|
||||||
@@ -92,14 +94,14 @@ export async function retry<T>(
|
|||||||
|
|
||||||
export async function retryTypedResponse<T>(
|
export async function retryTypedResponse<T>(
|
||||||
name: string,
|
name: string,
|
||||||
method: () => Promise<ITypedResponseWithError<T>>,
|
method: () => Promise<ITypedResponse<T>>,
|
||||||
maxAttempts = DefaultRetryAttempts,
|
maxAttempts = DefaultRetryAttempts,
|
||||||
delay = DefaultRetryDelay
|
delay = DefaultRetryDelay
|
||||||
): Promise<ITypedResponseWithError<T>> {
|
): Promise<ITypedResponse<T>> {
|
||||||
return await retry(
|
return await retry(
|
||||||
name,
|
name,
|
||||||
method,
|
method,
|
||||||
(response: ITypedResponseWithError<T>) => response.statusCode,
|
(response: ITypedResponse<T>) => response.statusCode,
|
||||||
maxAttempts,
|
maxAttempts,
|
||||||
delay,
|
delay,
|
||||||
// If the error object contains the statusCode property, extract it and return
|
// If the error object contains the statusCode property, extract it and return
|
||||||
@@ -109,8 +111,7 @@ export async function retryTypedResponse<T>(
|
|||||||
return {
|
return {
|
||||||
statusCode: error.statusCode,
|
statusCode: error.statusCode,
|
||||||
result: null,
|
result: null,
|
||||||
headers: {},
|
headers: {}
|
||||||
error
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return undefined
|
return undefined
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
# @actions/core Releases
|
# @actions/core Releases
|
||||||
|
|
||||||
### 1.7.0
|
|
||||||
- [Added `markdownSummary` extension](https://github.com/actions/toolkit/pull/1014)
|
|
||||||
|
|
||||||
### 1.6.0
|
### 1.6.0
|
||||||
- [Added OIDC Client function `getIDToken`](https://github.com/actions/toolkit/pull/919)
|
- [Added OIDC Client function `getIDToken`](https://github.com/actions/toolkit/pull/919)
|
||||||
- [Added `file` parameter to `AnnotationProperties`](https://github.com/actions/toolkit/pull/896)
|
- [Added `file` parameter to `AnnotationProperties`](https://github.com/actions/toolkit/pull/896)
|
||||||
|
|||||||
@@ -1,277 +0,0 @@
|
|||||||
import * as fs from 'fs'
|
|
||||||
import * as os from 'os'
|
|
||||||
import path from 'path'
|
|
||||||
import {markdownSummary, SUMMARY_ENV_VAR} from '../src/markdown-summary'
|
|
||||||
|
|
||||||
const testFilePath = path.join(__dirname, 'test', 'test-summary.md')
|
|
||||||
|
|
||||||
async function assertSummary(expected: string): Promise<void> {
|
|
||||||
const file = await fs.promises.readFile(testFilePath, {encoding: 'utf8'})
|
|
||||||
expect(file).toEqual(expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
const fixtures = {
|
|
||||||
text: 'hello world 🌎',
|
|
||||||
code: `func fork() {
|
|
||||||
for {
|
|
||||||
go fork()
|
|
||||||
}
|
|
||||||
}`,
|
|
||||||
list: ['foo', 'bar', 'baz', '💣'],
|
|
||||||
table: [
|
|
||||||
[
|
|
||||||
{
|
|
||||||
data: 'foo',
|
|
||||||
header: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: 'bar',
|
|
||||||
header: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: 'baz',
|
|
||||||
header: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: 'tall',
|
|
||||||
rowspan: '3'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
['one', 'two', 'three'],
|
|
||||||
[
|
|
||||||
{
|
|
||||||
data: 'wide',
|
|
||||||
colspan: '3'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
],
|
|
||||||
details: {
|
|
||||||
label: 'open me',
|
|
||||||
content: '🎉 surprise'
|
|
||||||
},
|
|
||||||
img: {
|
|
||||||
src: 'https://github.com/actions.png',
|
|
||||||
alt: 'actions logo',
|
|
||||||
options: {
|
|
||||||
width: '32',
|
|
||||||
height: '32'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
quote: {
|
|
||||||
text: 'Where the world builds software',
|
|
||||||
cite: 'https://github.com/about'
|
|
||||||
},
|
|
||||||
link: {
|
|
||||||
text: 'GitHub',
|
|
||||||
href: 'https://github.com/'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('@actions/core/src/markdown-summary', () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
process.env[SUMMARY_ENV_VAR] = testFilePath
|
|
||||||
await fs.promises.writeFile(testFilePath, '', {encoding: 'utf8'})
|
|
||||||
markdownSummary.emptyBuffer()
|
|
||||||
})
|
|
||||||
|
|
||||||
afterAll(async () => {
|
|
||||||
await fs.promises.unlink(testFilePath)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('throws if summary env var is undefined', async () => {
|
|
||||||
process.env[SUMMARY_ENV_VAR] = undefined
|
|
||||||
const write = markdownSummary.addRaw(fixtures.text).write()
|
|
||||||
|
|
||||||
await expect(write).rejects.toThrow()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('throws if summary file does not exist', async () => {
|
|
||||||
await fs.promises.unlink(testFilePath)
|
|
||||||
const write = markdownSummary.addRaw(fixtures.text).write()
|
|
||||||
|
|
||||||
await expect(write).rejects.toThrow()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('appends text to summary file', async () => {
|
|
||||||
await fs.promises.writeFile(testFilePath, '# ', {encoding: 'utf8'})
|
|
||||||
await markdownSummary.addRaw(fixtures.text).write()
|
|
||||||
await assertSummary(`# ${fixtures.text}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('overwrites text to summary file', async () => {
|
|
||||||
await fs.promises.writeFile(testFilePath, 'overwrite', {encoding: 'utf8'})
|
|
||||||
await markdownSummary.addRaw(fixtures.text).write({overwrite: true})
|
|
||||||
await assertSummary(fixtures.text)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('appends text with EOL to summary file', async () => {
|
|
||||||
await fs.promises.writeFile(testFilePath, '# ', {encoding: 'utf8'})
|
|
||||||
await markdownSummary.addRaw(fixtures.text, true).write()
|
|
||||||
await assertSummary(`# ${fixtures.text}${os.EOL}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('chains appends text to summary file', async () => {
|
|
||||||
await fs.promises.writeFile(testFilePath, '', {encoding: 'utf8'})
|
|
||||||
await markdownSummary
|
|
||||||
.addRaw(fixtures.text)
|
|
||||||
.addRaw(fixtures.text)
|
|
||||||
.addRaw(fixtures.text)
|
|
||||||
.write()
|
|
||||||
await assertSummary([fixtures.text, fixtures.text, fixtures.text].join(''))
|
|
||||||
})
|
|
||||||
|
|
||||||
it('empties buffer after write', async () => {
|
|
||||||
await fs.promises.writeFile(testFilePath, '', {encoding: 'utf8'})
|
|
||||||
await markdownSummary.addRaw(fixtures.text).write()
|
|
||||||
await assertSummary(fixtures.text)
|
|
||||||
expect(markdownSummary.isEmptyBuffer()).toBe(true)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('returns summary buffer as string', () => {
|
|
||||||
markdownSummary.addRaw(fixtures.text)
|
|
||||||
expect(markdownSummary.stringify()).toEqual(fixtures.text)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('return correct values for isEmptyBuffer', () => {
|
|
||||||
markdownSummary.addRaw(fixtures.text)
|
|
||||||
expect(markdownSummary.isEmptyBuffer()).toBe(false)
|
|
||||||
|
|
||||||
markdownSummary.emptyBuffer()
|
|
||||||
expect(markdownSummary.isEmptyBuffer()).toBe(true)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('clears a buffer and summary file', async () => {
|
|
||||||
await fs.promises.writeFile(testFilePath, 'content', {encoding: 'utf8'})
|
|
||||||
await markdownSummary.clear()
|
|
||||||
await assertSummary('')
|
|
||||||
expect(markdownSummary.isEmptyBuffer()).toBe(true)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('adds EOL', async () => {
|
|
||||||
await markdownSummary
|
|
||||||
.addRaw(fixtures.text)
|
|
||||||
.addEOL()
|
|
||||||
.write()
|
|
||||||
await assertSummary(fixtures.text + os.EOL)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('adds a code block without language', async () => {
|
|
||||||
await markdownSummary.addCodeBlock(fixtures.code).write()
|
|
||||||
const expected = `<pre><code>func fork() {\n for {\n go fork()\n }\n}</code></pre>${os.EOL}`
|
|
||||||
await assertSummary(expected)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('adds a code block with a language', async () => {
|
|
||||||
await markdownSummary.addCodeBlock(fixtures.code, 'go').write()
|
|
||||||
const expected = `<pre lang="go"><code>func fork() {\n for {\n go fork()\n }\n}</code></pre>${os.EOL}`
|
|
||||||
await assertSummary(expected)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('adds an unordered list', async () => {
|
|
||||||
await markdownSummary.addList(fixtures.list).write()
|
|
||||||
const expected = `<ul><li>foo</li><li>bar</li><li>baz</li><li>💣</li></ul>${os.EOL}`
|
|
||||||
await assertSummary(expected)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('adds an ordered list', async () => {
|
|
||||||
await markdownSummary.addList(fixtures.list, true).write()
|
|
||||||
const expected = `<ol><li>foo</li><li>bar</li><li>baz</li><li>💣</li></ol>${os.EOL}`
|
|
||||||
await assertSummary(expected)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('adds a table', async () => {
|
|
||||||
await markdownSummary.addTable(fixtures.table).write()
|
|
||||||
const expected = `<table><tr><th>foo</th><th>bar</th><th>baz</th><td rowspan="3">tall</td></tr><tr><td>one</td><td>two</td><td>three</td></tr><tr><td colspan="3">wide</td></tr></table>${os.EOL}`
|
|
||||||
await assertSummary(expected)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('adds a details element', async () => {
|
|
||||||
await markdownSummary
|
|
||||||
.addDetails(fixtures.details.label, fixtures.details.content)
|
|
||||||
.write()
|
|
||||||
const expected = `<details><summary>open me</summary>🎉 surprise</details>${os.EOL}`
|
|
||||||
await assertSummary(expected)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('adds an image with alt text', async () => {
|
|
||||||
await markdownSummary.addImage(fixtures.img.src, fixtures.img.alt).write()
|
|
||||||
const expected = `<img src="https://github.com/actions.png" alt="actions logo">${os.EOL}`
|
|
||||||
await assertSummary(expected)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('adds an image with custom dimensions', async () => {
|
|
||||||
await markdownSummary
|
|
||||||
.addImage(fixtures.img.src, fixtures.img.alt, fixtures.img.options)
|
|
||||||
.write()
|
|
||||||
const expected = `<img src="https://github.com/actions.png" alt="actions logo" width="32" height="32">${os.EOL}`
|
|
||||||
await assertSummary(expected)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('adds an image with custom dimensions', async () => {
|
|
||||||
await markdownSummary
|
|
||||||
.addImage(fixtures.img.src, fixtures.img.alt, fixtures.img.options)
|
|
||||||
.write()
|
|
||||||
const expected = `<img src="https://github.com/actions.png" alt="actions logo" width="32" height="32">${os.EOL}`
|
|
||||||
await assertSummary(expected)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('adds headings h1...h6', async () => {
|
|
||||||
for (const i of [1, 2, 3, 4, 5, 6]) {
|
|
||||||
markdownSummary.addHeading('heading', i)
|
|
||||||
}
|
|
||||||
await markdownSummary.write()
|
|
||||||
const expected = `<h1>heading</h1>${os.EOL}<h2>heading</h2>${os.EOL}<h3>heading</h3>${os.EOL}<h4>heading</h4>${os.EOL}<h5>heading</h5>${os.EOL}<h6>heading</h6>${os.EOL}`
|
|
||||||
await assertSummary(expected)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('adds h1 if heading level not specified', async () => {
|
|
||||||
await markdownSummary.addHeading('heading').write()
|
|
||||||
const expected = `<h1>heading</h1>${os.EOL}`
|
|
||||||
await assertSummary(expected)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('uses h1 if heading level is garbage or out of range', async () => {
|
|
||||||
await markdownSummary
|
|
||||||
.addHeading('heading', 'foobar')
|
|
||||||
.addHeading('heading', 1337)
|
|
||||||
.addHeading('heading', -1)
|
|
||||||
.addHeading('heading', Infinity)
|
|
||||||
.write()
|
|
||||||
const expected = `<h1>heading</h1>${os.EOL}<h1>heading</h1>${os.EOL}<h1>heading</h1>${os.EOL}<h1>heading</h1>${os.EOL}`
|
|
||||||
await assertSummary(expected)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('adds a separator', async () => {
|
|
||||||
await markdownSummary.addSeparator().write()
|
|
||||||
const expected = `<hr>${os.EOL}`
|
|
||||||
await assertSummary(expected)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('adds a break', async () => {
|
|
||||||
await markdownSummary.addBreak().write()
|
|
||||||
const expected = `<br>${os.EOL}`
|
|
||||||
await assertSummary(expected)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('adds a quote', async () => {
|
|
||||||
await markdownSummary.addQuote(fixtures.quote.text).write()
|
|
||||||
const expected = `<blockquote>Where the world builds software</blockquote>${os.EOL}`
|
|
||||||
await assertSummary(expected)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('adds a quote with citation', async () => {
|
|
||||||
await markdownSummary
|
|
||||||
.addQuote(fixtures.quote.text, fixtures.quote.cite)
|
|
||||||
.write()
|
|
||||||
const expected = `<blockquote cite="https://github.com/about">Where the world builds software</blockquote>${os.EOL}`
|
|
||||||
await assertSummary(expected)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('adds a link with href', async () => {
|
|
||||||
await markdownSummary
|
|
||||||
.addLink(fixtures.link.text, fixtures.link.href)
|
|
||||||
.write()
|
|
||||||
const expected = `<a href="https://github.com/">GitHub</a>${os.EOL}`
|
|
||||||
await assertSummary(expected)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
Generated
+60
-60
@@ -1,62 +1,62 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/core",
|
"name": "@actions/core",
|
||||||
"version": "1.7.0",
|
"version": "1.6.0",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@actions/core",
|
"name": "@actions/core",
|
||||||
"version": "1.7.0",
|
"version": "1.6.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/http-client": "^1.0.11"
|
"@actions/http-client": "^1.0.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^16.11.7"
|
"@types/node": "^12.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@actions/http-client": {
|
"node_modules/@actions/http-client": {
|
||||||
"version": "1.0.11",
|
"version": "1.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
|
||||||
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
|
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tunnel": "0.0.6"
|
"tunnel": "0.0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "16.11.32",
|
"version": "12.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.32.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.2.tgz",
|
||||||
"integrity": "sha512-+fnfNvG5JQdC1uGZiTx+0QVtoOHcggy6+epx65JYroPGsE1uhp+vo5kioiGKsAkor6ocwHteU2EvO7N8vtOZtA==",
|
"integrity": "sha512-5tabW/i+9mhrfEOUcLDu2xBPsHJ+X5Orqy9FKpale3SjDA17j5AEpYq5vfy3oAeAHGcvANRCO3NV3d2D6q3NiA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/tunnel": {
|
"node_modules/tunnel": {
|
||||||
"version": "0.0.6",
|
"version": "0.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
|
||||||
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
|
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
|
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/http-client": {
|
"@actions/http-client": {
|
||||||
"version": "1.0.11",
|
"version": "1.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
|
||||||
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
|
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"tunnel": "0.0.6"
|
"tunnel": "0.0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "16.11.32",
|
"version": "12.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.32.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.2.tgz",
|
||||||
"integrity": "sha512-+fnfNvG5JQdC1uGZiTx+0QVtoOHcggy6+epx65JYroPGsE1uhp+vo5kioiGKsAkor6ocwHteU2EvO7N8vtOZtA==",
|
"integrity": "sha512-5tabW/i+9mhrfEOUcLDu2xBPsHJ+X5Orqy9FKpale3SjDA17j5AEpYq5vfy3oAeAHGcvANRCO3NV3d2D6q3NiA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"tunnel": {
|
"tunnel": {
|
||||||
"version": "0.0.6",
|
"version": "0.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
|
||||||
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
|
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/core",
|
"name": "@actions/core",
|
||||||
"version": "1.7.0",
|
"version": "1.6.0",
|
||||||
"description": "Actions core lib",
|
"description": "Actions core lib",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"github",
|
"github",
|
||||||
@@ -39,6 +39,6 @@
|
|||||||
"@actions/http-client": "^1.0.11"
|
"@actions/http-client": "^1.0.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^16.11.7"
|
"@types/node": "^12.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -359,8 +359,3 @@ export function getState(name: string): string {
|
|||||||
export async function getIDToken(aud?: string): Promise<string> {
|
export async function getIDToken(aud?: string): Promise<string> {
|
||||||
return await OidcClient.getIDToken(aud)
|
return await OidcClient.getIDToken(aud)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Markdown summary exports
|
|
||||||
*/
|
|
||||||
export {markdownSummary} from './markdown-summary'
|
|
||||||
|
|||||||
@@ -1,362 +0,0 @@
|
|||||||
import {EOL} from 'os'
|
|
||||||
import {constants, promises} from 'fs'
|
|
||||||
const {access, appendFile, writeFile} = promises
|
|
||||||
|
|
||||||
export const SUMMARY_ENV_VAR = 'GITHUB_STEP_SUMMARY'
|
|
||||||
export const SUMMARY_DOCS_URL =
|
|
||||||
'https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-markdown-summary'
|
|
||||||
|
|
||||||
export type SummaryTableRow = (SummaryTableCell | string)[]
|
|
||||||
|
|
||||||
export interface SummaryTableCell {
|
|
||||||
/**
|
|
||||||
* Cell content
|
|
||||||
*/
|
|
||||||
data: string
|
|
||||||
/**
|
|
||||||
* Render cell as header
|
|
||||||
* (optional) default: false
|
|
||||||
*/
|
|
||||||
header?: boolean
|
|
||||||
/**
|
|
||||||
* Number of columns the cell extends
|
|
||||||
* (optional) default: '1'
|
|
||||||
*/
|
|
||||||
colspan?: string
|
|
||||||
/**
|
|
||||||
* Number of rows the cell extends
|
|
||||||
* (optional) default: '1'
|
|
||||||
*/
|
|
||||||
rowspan?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SummaryImageOptions {
|
|
||||||
/**
|
|
||||||
* The width of the image in pixels. Must be an integer without a unit.
|
|
||||||
* (optional)
|
|
||||||
*/
|
|
||||||
width?: string
|
|
||||||
/**
|
|
||||||
* The height of the image in pixels. Must be an integer without a unit.
|
|
||||||
* (optional)
|
|
||||||
*/
|
|
||||||
height?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SummaryWriteOptions {
|
|
||||||
/**
|
|
||||||
* Replace all existing content in summary file with buffer contents
|
|
||||||
* (optional) default: false
|
|
||||||
*/
|
|
||||||
overwrite?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
class MarkdownSummary {
|
|
||||||
private _buffer: string
|
|
||||||
private _filePath?: string
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this._buffer = ''
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds the summary file path from the environment, rejects if env var is not found or file does not exist
|
|
||||||
* Also checks r/w permissions.
|
|
||||||
*
|
|
||||||
* @returns step summary file path
|
|
||||||
*/
|
|
||||||
private async filePath(): Promise<string> {
|
|
||||||
if (this._filePath) {
|
|
||||||
return this._filePath
|
|
||||||
}
|
|
||||||
|
|
||||||
const pathFromEnv = process.env[SUMMARY_ENV_VAR]
|
|
||||||
if (!pathFromEnv) {
|
|
||||||
throw new Error(
|
|
||||||
`Unable to find environment variable for $${SUMMARY_ENV_VAR}. Check if your runtime environment supports markdown summaries.`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await access(pathFromEnv, constants.R_OK | constants.W_OK)
|
|
||||||
} catch {
|
|
||||||
throw new Error(
|
|
||||||
`Unable to access summary file: '${pathFromEnv}'. Check if the file has correct read/write permissions.`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
this._filePath = pathFromEnv
|
|
||||||
return this._filePath
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wraps content in an HTML tag, adding any HTML attributes
|
|
||||||
*
|
|
||||||
* @param {string} tag HTML tag to wrap
|
|
||||||
* @param {string | null} content content within the tag
|
|
||||||
* @param {[attribute: string]: string} attrs key-value list of HTML attributes to add
|
|
||||||
*
|
|
||||||
* @returns {string} content wrapped in HTML element
|
|
||||||
*/
|
|
||||||
private wrap(
|
|
||||||
tag: string,
|
|
||||||
content: string | null,
|
|
||||||
attrs: {[attribute: string]: string} = {}
|
|
||||||
): string {
|
|
||||||
const htmlAttrs = Object.entries(attrs)
|
|
||||||
.map(([key, value]) => ` ${key}="${value}"`)
|
|
||||||
.join('')
|
|
||||||
|
|
||||||
if (!content) {
|
|
||||||
return `<${tag}${htmlAttrs}>`
|
|
||||||
}
|
|
||||||
|
|
||||||
return `<${tag}${htmlAttrs}>${content}</${tag}>`
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes text in the buffer to the summary buffer file and empties buffer. Will append by default.
|
|
||||||
*
|
|
||||||
* @param {SummaryWriteOptions} [options] (optional) options for write operation
|
|
||||||
*
|
|
||||||
* @returns {Promise<MarkdownSummary>} markdown summary instance
|
|
||||||
*/
|
|
||||||
async write(options?: SummaryWriteOptions): Promise<MarkdownSummary> {
|
|
||||||
const overwrite = !!options?.overwrite
|
|
||||||
const filePath = await this.filePath()
|
|
||||||
const writeFunc = overwrite ? writeFile : appendFile
|
|
||||||
await writeFunc(filePath, this._buffer, {encoding: 'utf8'})
|
|
||||||
return this.emptyBuffer()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the summary buffer and wipes the summary file
|
|
||||||
*
|
|
||||||
* @returns {MarkdownSummary} markdown summary instance
|
|
||||||
*/
|
|
||||||
async clear(): Promise<MarkdownSummary> {
|
|
||||||
return this.emptyBuffer().write({overwrite: true})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current summary buffer as a string
|
|
||||||
*
|
|
||||||
* @returns {string} string of summary buffer
|
|
||||||
*/
|
|
||||||
stringify(): string {
|
|
||||||
return this._buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If the summary buffer is empty
|
|
||||||
*
|
|
||||||
* @returns {boolen} true if the buffer is empty
|
|
||||||
*/
|
|
||||||
isEmptyBuffer(): boolean {
|
|
||||||
return this._buffer.length === 0
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets the summary buffer without writing to summary file
|
|
||||||
*
|
|
||||||
* @returns {MarkdownSummary} markdown summary instance
|
|
||||||
*/
|
|
||||||
emptyBuffer(): MarkdownSummary {
|
|
||||||
this._buffer = ''
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds raw text to the summary buffer
|
|
||||||
*
|
|
||||||
* @param {string} text content to add
|
|
||||||
* @param {boolean} [addEOL=false] (optional) append an EOL to the raw text (default: false)
|
|
||||||
*
|
|
||||||
* @returns {MarkdownSummary} markdown summary instance
|
|
||||||
*/
|
|
||||||
addRaw(text: string, addEOL = false): MarkdownSummary {
|
|
||||||
this._buffer += text
|
|
||||||
return addEOL ? this.addEOL() : this
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the operating system-specific end-of-line marker to the buffer
|
|
||||||
*
|
|
||||||
* @returns {MarkdownSummary} markdown summary instance
|
|
||||||
*/
|
|
||||||
addEOL(): MarkdownSummary {
|
|
||||||
return this.addRaw(EOL)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an HTML codeblock to the summary buffer
|
|
||||||
*
|
|
||||||
* @param {string} code content to render within fenced code block
|
|
||||||
* @param {string} lang (optional) language to syntax highlight code
|
|
||||||
*
|
|
||||||
* @returns {MarkdownSummary} markdown summary instance
|
|
||||||
*/
|
|
||||||
addCodeBlock(code: string, lang?: string): MarkdownSummary {
|
|
||||||
const attrs = {
|
|
||||||
...(lang && {lang})
|
|
||||||
}
|
|
||||||
const element = this.wrap('pre', this.wrap('code', code), attrs)
|
|
||||||
return this.addRaw(element).addEOL()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an HTML list to the summary buffer
|
|
||||||
*
|
|
||||||
* @param {string[]} items list of items to render
|
|
||||||
* @param {boolean} [ordered=false] (optional) if the rendered list should be ordered or not (default: false)
|
|
||||||
*
|
|
||||||
* @returns {MarkdownSummary} markdown summary instance
|
|
||||||
*/
|
|
||||||
addList(items: string[], ordered = false): MarkdownSummary {
|
|
||||||
const tag = ordered ? 'ol' : 'ul'
|
|
||||||
const listItems = items.map(item => this.wrap('li', item)).join('')
|
|
||||||
const element = this.wrap(tag, listItems)
|
|
||||||
return this.addRaw(element).addEOL()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an HTML table to the summary buffer
|
|
||||||
*
|
|
||||||
* @param {SummaryTableCell[]} rows table rows
|
|
||||||
*
|
|
||||||
* @returns {MarkdownSummary} markdown summary instance
|
|
||||||
*/
|
|
||||||
addTable(rows: SummaryTableRow[]): MarkdownSummary {
|
|
||||||
const tableBody = rows
|
|
||||||
.map(row => {
|
|
||||||
const cells = row
|
|
||||||
.map(cell => {
|
|
||||||
if (typeof cell === 'string') {
|
|
||||||
return this.wrap('td', cell)
|
|
||||||
}
|
|
||||||
|
|
||||||
const {header, data, colspan, rowspan} = cell
|
|
||||||
const tag = header ? 'th' : 'td'
|
|
||||||
const attrs = {
|
|
||||||
...(colspan && {colspan}),
|
|
||||||
...(rowspan && {rowspan})
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.wrap(tag, data, attrs)
|
|
||||||
})
|
|
||||||
.join('')
|
|
||||||
|
|
||||||
return this.wrap('tr', cells)
|
|
||||||
})
|
|
||||||
.join('')
|
|
||||||
|
|
||||||
const element = this.wrap('table', tableBody)
|
|
||||||
return this.addRaw(element).addEOL()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a collapsable HTML details element to the summary buffer
|
|
||||||
*
|
|
||||||
* @param {string} label text for the closed state
|
|
||||||
* @param {string} content collapsable content
|
|
||||||
*
|
|
||||||
* @returns {MarkdownSummary} markdown summary instance
|
|
||||||
*/
|
|
||||||
addDetails(label: string, content: string): MarkdownSummary {
|
|
||||||
const element = this.wrap('details', this.wrap('summary', label) + content)
|
|
||||||
return this.addRaw(element).addEOL()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an HTML image tag to the summary buffer
|
|
||||||
*
|
|
||||||
* @param {string} src path to the image you to embed
|
|
||||||
* @param {string} alt text description of the image
|
|
||||||
* @param {SummaryImageOptions} options (optional) addition image attributes
|
|
||||||
*
|
|
||||||
* @returns {MarkdownSummary} markdown summary instance
|
|
||||||
*/
|
|
||||||
addImage(
|
|
||||||
src: string,
|
|
||||||
alt: string,
|
|
||||||
options?: SummaryImageOptions
|
|
||||||
): MarkdownSummary {
|
|
||||||
const {width, height} = options || {}
|
|
||||||
const attrs = {
|
|
||||||
...(width && {width}),
|
|
||||||
...(height && {height})
|
|
||||||
}
|
|
||||||
|
|
||||||
const element = this.wrap('img', null, {src, alt, ...attrs})
|
|
||||||
return this.addRaw(element).addEOL()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an HTML section heading element
|
|
||||||
*
|
|
||||||
* @param {string} text heading text
|
|
||||||
* @param {number | string} [level=1] (optional) the heading level, default: 1
|
|
||||||
*
|
|
||||||
* @returns {MarkdownSummary} markdown summary instance
|
|
||||||
*/
|
|
||||||
addHeading(text: string, level?: number | string): MarkdownSummary {
|
|
||||||
const tag = `h${level}`
|
|
||||||
const allowedTag = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(tag)
|
|
||||||
? tag
|
|
||||||
: 'h1'
|
|
||||||
const element = this.wrap(allowedTag, text)
|
|
||||||
return this.addRaw(element).addEOL()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an HTML thematic break (<hr>) to the summary buffer
|
|
||||||
*
|
|
||||||
* @returns {MarkdownSummary} markdown summary instance
|
|
||||||
*/
|
|
||||||
addSeparator(): MarkdownSummary {
|
|
||||||
const element = this.wrap('hr', null)
|
|
||||||
return this.addRaw(element).addEOL()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an HTML line break (<br>) to the summary buffer
|
|
||||||
*
|
|
||||||
* @returns {MarkdownSummary} markdown summary instance
|
|
||||||
*/
|
|
||||||
addBreak(): MarkdownSummary {
|
|
||||||
const element = this.wrap('br', null)
|
|
||||||
return this.addRaw(element).addEOL()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an HTML blockquote to the summary buffer
|
|
||||||
*
|
|
||||||
* @param {string} text quote text
|
|
||||||
* @param {string} cite (optional) citation url
|
|
||||||
*
|
|
||||||
* @returns {MarkdownSummary} markdown summary instance
|
|
||||||
*/
|
|
||||||
addQuote(text: string, cite?: string): MarkdownSummary {
|
|
||||||
const attrs = {
|
|
||||||
...(cite && {cite})
|
|
||||||
}
|
|
||||||
const element = this.wrap('blockquote', text, attrs)
|
|
||||||
return this.addRaw(element).addEOL()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an HTML anchor tag to the summary buffer
|
|
||||||
*
|
|
||||||
* @param {string} text link text/content
|
|
||||||
* @param {string} href hyperlink
|
|
||||||
*
|
|
||||||
* @returns {MarkdownSummary} markdown summary instance
|
|
||||||
*/
|
|
||||||
addLink(text: string, href: string): MarkdownSummary {
|
|
||||||
const element = this.wrap('a', text, {href})
|
|
||||||
return this.addRaw(element).addEOL()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// singleton export
|
|
||||||
export const markdownSummary = new MarkdownSummary()
|
|
||||||
@@ -1,8 +1,5 @@
|
|||||||
# @actions/glob Releases
|
# @actions/glob Releases
|
||||||
|
|
||||||
### 0.3.0
|
|
||||||
- Added a `verbose` option to HashFiles [#1052](https://github.com/actions/toolkit/pull/1052/files)
|
|
||||||
|
|
||||||
### 0.2.1
|
### 0.2.1
|
||||||
- Update `lockfileVersion` to `v2` in `package-lock.json [#1023](https://github.com/actions/toolkit/pull/1023)
|
- Update `lockfileVersion` to `v2` in `package-lock.json [#1023](https://github.com/actions/toolkit/pull/1023)
|
||||||
|
|
||||||
|
|||||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/glob",
|
"name": "@actions/glob",
|
||||||
"version": "0.3.0",
|
"version": "0.2.1",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/glob",
|
"name": "@actions/glob",
|
||||||
"version": "0.3.0",
|
"version": "0.2.1",
|
||||||
"preview": true,
|
"preview": true,
|
||||||
"description": "Actions glob lib",
|
"description": "Actions glob lib",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
|||||||
@@ -26,13 +26,12 @@ export async function create(
|
|||||||
*/
|
*/
|
||||||
export async function hashFiles(
|
export async function hashFiles(
|
||||||
patterns: string,
|
patterns: string,
|
||||||
options?: HashFileOptions,
|
options?: HashFileOptions
|
||||||
verbose: Boolean = false
|
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
let followSymbolicLinks = true
|
let followSymbolicLinks = true
|
||||||
if (options && typeof options.followSymbolicLinks === 'boolean') {
|
if (options && typeof options.followSymbolicLinks === 'boolean') {
|
||||||
followSymbolicLinks = options.followSymbolicLinks
|
followSymbolicLinks = options.followSymbolicLinks
|
||||||
}
|
}
|
||||||
const globber = await create(patterns, {followSymbolicLinks})
|
const globber = await create(patterns, {followSymbolicLinks})
|
||||||
return _hashFiles(globber, verbose)
|
return _hashFiles(globber)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,23 +6,19 @@ import * as util from 'util'
|
|||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import {Globber} from './glob'
|
import {Globber} from './glob'
|
||||||
|
|
||||||
export async function hashFiles(
|
export async function hashFiles(globber: Globber): Promise<string> {
|
||||||
globber: Globber,
|
|
||||||
verbose: Boolean = false
|
|
||||||
): Promise<string> {
|
|
||||||
const writeDelegate = verbose ? core.info : core.debug
|
|
||||||
let hasMatch = false
|
let hasMatch = false
|
||||||
const githubWorkspace = process.env['GITHUB_WORKSPACE'] ?? process.cwd()
|
const githubWorkspace = process.env['GITHUB_WORKSPACE'] ?? process.cwd()
|
||||||
const result = crypto.createHash('sha256')
|
const result = crypto.createHash('sha256')
|
||||||
let count = 0
|
let count = 0
|
||||||
for await (const file of globber.globGenerator()) {
|
for await (const file of globber.globGenerator()) {
|
||||||
writeDelegate(file)
|
core.debug(file)
|
||||||
if (!file.startsWith(`${githubWorkspace}${path.sep}`)) {
|
if (!file.startsWith(`${githubWorkspace}${path.sep}`)) {
|
||||||
writeDelegate(`Ignore '${file}' since it is not under GITHUB_WORKSPACE.`)
|
core.debug(`Ignore '${file}' since it is not under GITHUB_WORKSPACE.`)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (fs.statSync(file).isDirectory()) {
|
if (fs.statSync(file).isDirectory()) {
|
||||||
writeDelegate(`Skip directory '${file}'.`)
|
core.debug(`Skip directory '${file}'.`)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const hash = crypto.createHash('sha256')
|
const hash = crypto.createHash('sha256')
|
||||||
@@ -37,10 +33,10 @@ export async function hashFiles(
|
|||||||
result.end()
|
result.end()
|
||||||
|
|
||||||
if (hasMatch) {
|
if (hasMatch) {
|
||||||
writeDelegate(`Found ${count} files to hash.`)
|
core.debug(`Found ${count} files to hash.`)
|
||||||
return result.digest('hex')
|
return result.digest('hex')
|
||||||
} else {
|
} else {
|
||||||
writeDelegate(`No matches found for glob`)
|
core.debug(`No matches found for glob`)
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -332,9 +332,23 @@ describe('rmRF', () => {
|
|||||||
await assertExists(filePath)
|
await assertExists(filePath)
|
||||||
|
|
||||||
const fd = await fs.open(filePath, 'r')
|
const fd = await fs.open(filePath, 'r')
|
||||||
await io.rmRF(testPath)
|
|
||||||
|
|
||||||
await assertNotExists(testPath)
|
let worked: boolean
|
||||||
|
|
||||||
|
try {
|
||||||
|
await io.rmRF(testPath)
|
||||||
|
worked = true
|
||||||
|
} catch (err) {
|
||||||
|
worked = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (os.platform() === 'win32') {
|
||||||
|
expect(worked).toBe(false)
|
||||||
|
await assertExists(testPath)
|
||||||
|
} else {
|
||||||
|
expect(worked).toBe(true)
|
||||||
|
await assertNotExists(testPath)
|
||||||
|
}
|
||||||
|
|
||||||
await fd.close()
|
await fd.close()
|
||||||
await io.rmRF(testPath)
|
await io.rmRF(testPath)
|
||||||
|
|||||||
Generated
+12
-12
@@ -164,9 +164,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/minimist": {
|
"node_modules/minimist": {
|
||||||
"version": "1.2.6",
|
"version": "1.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||||
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
|
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/mkdirp": {
|
"node_modules/mkdirp": {
|
||||||
@@ -217,9 +217,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pathval": {
|
"node_modules/pathval": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz",
|
||||||
"integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
|
"integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "*"
|
"node": "*"
|
||||||
@@ -404,9 +404,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "1.2.6",
|
"version": "1.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||||
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
|
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"mkdirp": {
|
"mkdirp": {
|
||||||
@@ -450,9 +450,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pathval": {
|
"pathval": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz",
|
||||||
"integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
|
"integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"propagate": {
|
"propagate": {
|
||||||
|
|||||||
Reference in New Issue
Block a user