add support for multiple paths in path input variable
This allows users to provide multiple filepaths to include in their action, whether they're files or folders.
This commit is contained in:
@@ -170,3 +170,47 @@ describe('removeDir', () => {
|
|||||||
expect(fs.existsSync(dir)).toEqual(false)
|
expect(fs.existsSync(dir)).toEqual(false)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('bundleFilesintoDirectory', () => {
|
||||||
|
let sourceDir: string
|
||||||
|
let targetDir: string
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
sourceDir = fsHelper.createTempDir()
|
||||||
|
targetDir = fsHelper.createTempDir()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
fs.rmSync(sourceDir, { recursive: true })
|
||||||
|
fs.rmSync(targetDir, { recursive: true })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('bundles files and folders into a directory', () => {
|
||||||
|
// Create some test files and folders in the sourceDir
|
||||||
|
const file1 = `${sourceDir}/file1.txt`
|
||||||
|
const folder1 = `${sourceDir}/folder1`
|
||||||
|
const file2 = `${folder1}/file3.txt`
|
||||||
|
|
||||||
|
fs.mkdirSync(folder1)
|
||||||
|
fs.writeFileSync(file1, fileContent)
|
||||||
|
fs.writeFileSync(file2, fileContent)
|
||||||
|
|
||||||
|
// Bundle the files and folders into the targetDir
|
||||||
|
fsHelper.bundleFilesintoDirectory([file1, folder1], targetDir)
|
||||||
|
|
||||||
|
// Check that the files and folders were copied
|
||||||
|
expect(fs.existsSync(file1)).toEqual(true)
|
||||||
|
expect(fsHelper.readFileContents(file1).toString()).toEqual(fileContent)
|
||||||
|
|
||||||
|
expect(fs.existsSync(`${targetDir}/folder1`)).toEqual(true)
|
||||||
|
|
||||||
|
expect(fs.existsSync(file2)).toEqual(true)
|
||||||
|
expect(fsHelper.readFileContents(file2).toString()).toEqual(fileContent)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws an error if a file or directory does not exist', () => {
|
||||||
|
expect(() => {
|
||||||
|
fsHelper.bundleFilesintoDirectory(['/does/not/exist'], targetDir)
|
||||||
|
}).toThrow('File /does/not/exist does not exist')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|||||||
+28
-12
@@ -23,6 +23,7 @@ let createTempDirMock: jest.SpyInstance
|
|||||||
let isDirectoryMock: jest.SpyInstance
|
let isDirectoryMock: jest.SpyInstance
|
||||||
let createArchivesMock: jest.SpyInstance
|
let createArchivesMock: jest.SpyInstance
|
||||||
let removeDirMock: jest.SpyInstance
|
let removeDirMock: jest.SpyInstance
|
||||||
|
let bundleFilesintoDirectoryMock: jest.SpyInstance
|
||||||
|
|
||||||
// Mock the GHCR Client
|
// Mock the GHCR Client
|
||||||
let publishOCIArtifactMock: jest.SpyInstance
|
let publishOCIArtifactMock: jest.SpyInstance
|
||||||
@@ -45,6 +46,9 @@ describe('action', () => {
|
|||||||
.spyOn(fsHelper, 'createArchives')
|
.spyOn(fsHelper, 'createArchives')
|
||||||
.mockImplementation()
|
.mockImplementation()
|
||||||
removeDirMock = jest.spyOn(fsHelper, 'removeDir').mockImplementation()
|
removeDirMock = jest.spyOn(fsHelper, 'removeDir').mockImplementation()
|
||||||
|
bundleFilesintoDirectoryMock = jest
|
||||||
|
.spyOn(fsHelper, 'bundleFilesintoDirectory')
|
||||||
|
.mockImplementation()
|
||||||
|
|
||||||
// GHCR Client mocks
|
// GHCR Client mocks
|
||||||
publishOCIArtifactMock = jest
|
publishOCIArtifactMock = jest
|
||||||
@@ -97,7 +101,7 @@ describe('action', () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('fails if path is not a directory', async () => {
|
it('fails if multiple paths are provided and staging files fails', async () => {
|
||||||
// Mock the environment
|
// Mock the environment
|
||||||
process.env.GITHUB_REPOSITORY = 'test/test'
|
process.env.GITHUB_REPOSITORY = 'test/test'
|
||||||
github.context.eventName = 'release'
|
github.context.eventName = 'release'
|
||||||
@@ -109,23 +113,24 @@ describe('action', () => {
|
|||||||
}
|
}
|
||||||
getInputMock.mockImplementation((name: string) => {
|
getInputMock.mockImplementation((name: string) => {
|
||||||
if (name === 'path') {
|
if (name === 'path') {
|
||||||
return 'not-a-directory'
|
return 'directory1 directory2'
|
||||||
} else if (name === 'registry') {
|
} else if (name === 'registry') {
|
||||||
return 'https://ghcr.io'
|
return 'https://ghcr.io'
|
||||||
}
|
}
|
||||||
return ''
|
return ''
|
||||||
})
|
})
|
||||||
|
|
||||||
isDirectoryMock.mockImplementation(() => false)
|
isDirectoryMock.mockImplementation(() => true)
|
||||||
|
|
||||||
|
bundleFilesintoDirectoryMock.mockImplementation(() => {
|
||||||
|
throw new Error('Something went wrong')
|
||||||
|
})
|
||||||
|
|
||||||
// Run the action
|
// Run the action
|
||||||
await main.run()
|
await main.run()
|
||||||
|
|
||||||
// Check the results
|
// Check the results
|
||||||
expect(isDirectoryMock).toHaveBeenCalledWith('not-a-directory')
|
expect(setFailedMock).toHaveBeenCalledWith('Something went wrong')
|
||||||
expect(setFailedMock).toHaveBeenCalledWith(
|
|
||||||
'The path not-a-directory is not a directory. Please provide a path to a valid directory.'
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('fails if an error is thrown from dependent code', async () => {
|
it('fails if an error is thrown from dependent code', async () => {
|
||||||
@@ -167,16 +172,20 @@ describe('action', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('successfully uploads if the release tag is a semver without v prefix', async () => {
|
it('successfully uploads if the release tag is a semver without v prefix', async () => {
|
||||||
await testHappyPath('1.0.0')
|
await testHappyPath('1.0.0', 'test')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('successfully uploads if the release tag is a semver with v prefix', async () => {
|
it('successfully uploads if the release tag is a semver with v prefix', async () => {
|
||||||
await testHappyPath('v1.0.0')
|
await testHappyPath('v1.0.0', 'test')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('successfully uploads if multiple paths are provided', async () => {
|
||||||
|
await testHappyPath('v1.0.0', 'test test2')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test that main successfully uploads and returns the manifest & package URL
|
// Test that main successfully uploads and returns the manifest & package URL
|
||||||
async function testHappyPath(version: string): Promise<void> {
|
async function testHappyPath(version: string, path: string): Promise<void> {
|
||||||
// Mock the environment
|
// Mock the environment
|
||||||
process.env.GITHUB_REPOSITORY = 'test/test'
|
process.env.GITHUB_REPOSITORY = 'test/test'
|
||||||
github.context.eventName = 'release'
|
github.context.eventName = 'release'
|
||||||
@@ -188,7 +197,7 @@ async function testHappyPath(version: string): Promise<void> {
|
|||||||
}
|
}
|
||||||
getInputMock.mockImplementation((name: string) => {
|
getInputMock.mockImplementation((name: string) => {
|
||||||
if (name === 'path') {
|
if (name === 'path') {
|
||||||
return 'test'
|
return path
|
||||||
} else if (name === 'registry') {
|
} else if (name === 'registry') {
|
||||||
return 'https://ghcr.io'
|
return 'https://ghcr.io'
|
||||||
}
|
}
|
||||||
@@ -197,6 +206,10 @@ async function testHappyPath(version: string): Promise<void> {
|
|||||||
|
|
||||||
isDirectoryMock.mockImplementation(() => true)
|
isDirectoryMock.mockImplementation(() => true)
|
||||||
|
|
||||||
|
bundleFilesintoDirectoryMock.mockImplementation(() => {
|
||||||
|
return '/tmp/test'
|
||||||
|
})
|
||||||
|
|
||||||
createTempDirMock.mockImplementation(() => '/tmp/test')
|
createTempDirMock.mockImplementation(() => '/tmp/test')
|
||||||
|
|
||||||
createArchivesMock.mockImplementation(() => {
|
createArchivesMock.mockImplementation(() => {
|
||||||
@@ -246,6 +259,9 @@ async function testHappyPath(version: string): Promise<void> {
|
|||||||
'actions_oci_pkg'
|
'actions_oci_pkg'
|
||||||
)
|
)
|
||||||
|
|
||||||
// Expect the files to be cleaned up
|
// Expect all the temp files to be cleaned up
|
||||||
expect(removeDirMock).toHaveBeenCalledWith('/tmp/test')
|
expect(removeDirMock).toHaveBeenCalledWith('/tmp/test')
|
||||||
|
expect(removeDirMock).toHaveBeenCalledTimes(
|
||||||
|
createTempDirMock.mock.calls.length
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+3410
-1543
File diff suppressed because one or more lines are too long
+62
@@ -1136,6 +1136,25 @@ Copyright (c) 2012 Felix Geisendörfer ([email protected]) and contributors
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
|
fs-extra
|
||||||
|
MIT
|
||||||
|
(The MIT License)
|
||||||
|
|
||||||
|
Copyright (c) 2011-2017 JP Richardson
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files
|
||||||
|
(the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify,
|
||||||
|
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||||
|
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
|
||||||
|
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
fs-minipass
|
fs-minipass
|
||||||
ISC
|
ISC
|
||||||
The ISC License
|
The ISC License
|
||||||
@@ -1320,6 +1339,25 @@ THE SOFTWARE.
|
|||||||
isarray
|
isarray
|
||||||
MIT
|
MIT
|
||||||
|
|
||||||
|
jsonfile
|
||||||
|
MIT
|
||||||
|
(The MIT License)
|
||||||
|
|
||||||
|
Copyright (c) 2012-2015, JP Richardson <[email protected]>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files
|
||||||
|
(the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify,
|
||||||
|
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||||
|
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
|
||||||
|
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
lazystream
|
lazystream
|
||||||
MIT
|
MIT
|
||||||
Copyright (c) 2013 J. Pommerening, contributors.
|
Copyright (c) 2013 J. Pommerening, contributors.
|
||||||
@@ -2198,6 +2236,30 @@ Permission to use, copy, modify, and/or distribute this software for any purpose
|
|||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
|
universalify
|
||||||
|
MIT
|
||||||
|
(The MIT License)
|
||||||
|
|
||||||
|
Copyright (c) 2017, Ryan Zimmerman <[email protected]>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the 'Software'), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
util-deprecate
|
util-deprecate
|
||||||
MIT
|
MIT
|
||||||
(The MIT License)
|
(The MIT License)
|
||||||
|
|||||||
Generated
+52
-3
@@ -12,9 +12,11 @@
|
|||||||
"@actions/core": "^1.10.1",
|
"@actions/core": "^1.10.1",
|
||||||
"@actions/exec": "^1.1.1",
|
"@actions/exec": "^1.1.1",
|
||||||
"@actions/github": "^6.0.0",
|
"@actions/github": "^6.0.0",
|
||||||
|
"@types/fs-extra": "^11.0.4",
|
||||||
"archiver": "^6.0.1",
|
"archiver": "^6.0.1",
|
||||||
"axios": "^1.6.2",
|
"axios": "^1.6.2",
|
||||||
"axios-debug-log": "^1.0.0",
|
"axios-debug-log": "^1.0.0",
|
||||||
|
"fs-extra": "^11.1.1",
|
||||||
"tar": "^6.2.0"
|
"tar": "^6.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -1598,6 +1600,15 @@
|
|||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/fs-extra": {
|
||||||
|
"version": "11.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz",
|
||||||
|
"integrity": "sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/jsonfile": "*",
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/graceful-fs": {
|
"node_modules/@types/graceful-fs": {
|
||||||
"version": "4.1.6",
|
"version": "4.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz",
|
||||||
@@ -1653,6 +1664,14 @@
|
|||||||
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
|
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/jsonfile": {
|
||||||
|
"version": "6.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.4.tgz",
|
||||||
|
"integrity": "sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/ms": {
|
"node_modules/@types/ms": {
|
||||||
"version": "0.7.34",
|
"version": "0.7.34",
|
||||||
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz",
|
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz",
|
||||||
@@ -1662,7 +1681,6 @@
|
|||||||
"version": "20.9.4",
|
"version": "20.9.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.4.tgz",
|
||||||
"integrity": "sha512-wmyg8HUhcn6ACjsn8oKYjkN/zUzQeNtMy44weTJSM6p4MMzEOuKbA3OjJ267uPCOW7Xex9dyrNTful8XTQYoDA==",
|
"integrity": "sha512-wmyg8HUhcn6ACjsn8oKYjkN/zUzQeNtMy44weTJSM6p4MMzEOuKbA3OjJ267uPCOW7Xex9dyrNTful8XTQYoDA==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~5.26.4"
|
"undici-types": "~5.26.4"
|
||||||
}
|
}
|
||||||
@@ -4113,6 +4131,19 @@
|
|||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fs-extra": {
|
||||||
|
"version": "11.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz",
|
||||||
|
"integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"graceful-fs": "^4.2.0",
|
||||||
|
"jsonfile": "^6.0.1",
|
||||||
|
"universalify": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/fs-minipass": {
|
"node_modules/fs-minipass": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
|
||||||
@@ -5627,6 +5658,17 @@
|
|||||||
"url": "https://github.com/sponsors/ota-meshi"
|
"url": "https://github.com/sponsors/ota-meshi"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jsonfile": {
|
||||||
|
"version": "6.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
|
||||||
|
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"universalify": "^2.0.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"graceful-fs": "^4.1.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/jsx-ast-utils": {
|
"node_modules/jsx-ast-utils": {
|
||||||
"version": "3.3.5",
|
"version": "3.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
|
||||||
@@ -7563,14 +7605,21 @@
|
|||||||
"node_modules/undici-types": {
|
"node_modules/undici-types": {
|
||||||
"version": "5.26.5",
|
"version": "5.26.5",
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/universal-user-agent": {
|
"node_modules/universal-user-agent": {
|
||||||
"version": "6.0.1",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz",
|
||||||
"integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="
|
"integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/universalify": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/untildify": {
|
"node_modules/untildify": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz",
|
||||||
|
|||||||
@@ -69,9 +69,11 @@
|
|||||||
"@actions/core": "^1.10.1",
|
"@actions/core": "^1.10.1",
|
||||||
"@actions/exec": "^1.1.1",
|
"@actions/exec": "^1.1.1",
|
||||||
"@actions/github": "^6.0.0",
|
"@actions/github": "^6.0.0",
|
||||||
|
"@types/fs-extra": "^11.0.4",
|
||||||
"archiver": "^6.0.1",
|
"archiver": "^6.0.1",
|
||||||
"axios": "^1.6.2",
|
"axios": "^1.6.2",
|
||||||
"axios-debug-log": "^1.0.0",
|
"axios-debug-log": "^1.0.0",
|
||||||
|
"fs-extra": "^11.1.1",
|
||||||
"tar": "^6.2.0"
|
"tar": "^6.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
+25
-1
@@ -1,4 +1,5 @@
|
|||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
|
import fsExtra from 'fs-extra'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import * as tar from 'tar'
|
import * as tar from 'tar'
|
||||||
import * as archiver from 'archiver'
|
import * as archiver from 'archiver'
|
||||||
@@ -17,7 +18,9 @@ export function createTempDir(): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function removeDir(dir: string): void {
|
export function removeDir(dir: string): void {
|
||||||
fs.rmSync(dir, { recursive: true })
|
if (fs.existsSync(dir)) {
|
||||||
|
fs.rmSync(dir, { recursive: true })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FileMetadata {
|
export interface FileMetadata {
|
||||||
@@ -92,6 +95,27 @@ export function readFileContents(filePath: string): Buffer {
|
|||||||
return fs.readFileSync(filePath)
|
return fs.readFileSync(filePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function bundleFilesintoDirectory(
|
||||||
|
files: string[],
|
||||||
|
targetDir: string = createTempDir()
|
||||||
|
): string {
|
||||||
|
for (const file of files) {
|
||||||
|
if (!fs.existsSync(file)) {
|
||||||
|
throw new Error(`File ${file} does not exist`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDirectory(file)) {
|
||||||
|
const targetFolder = path.join(targetDir, path.basename(file))
|
||||||
|
fsExtra.copySync(file, targetFolder)
|
||||||
|
} else {
|
||||||
|
const targetFile = path.join(targetDir, path.basename(file))
|
||||||
|
fs.copyFileSync(file, targetFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return targetDir
|
||||||
|
}
|
||||||
|
|
||||||
// Converts a file path to a filemetadata object by querying the fs for relevant metadata.
|
// Converts a file path to a filemetadata object by querying the fs for relevant metadata.
|
||||||
async function fileMetadata(filePath: string): Promise<FileMetadata> {
|
async function fileMetadata(filePath: string): Promise<FileMetadata> {
|
||||||
const stats = fs.statSync(filePath)
|
const stats = fs.statSync(filePath)
|
||||||
|
|||||||
+21
-12
@@ -10,7 +10,7 @@ import semver from 'semver'
|
|||||||
* @returns {Promise<void>} Resolves when the action is complete.
|
* @returns {Promise<void>} Resolves when the action is complete.
|
||||||
*/
|
*/
|
||||||
export async function run(): Promise<void> {
|
export async function run(): Promise<void> {
|
||||||
let tmpDir = ''
|
const tmpDirs: string[] = []
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Parse and validate Actions execution context, including the repository name, release name and event type
|
// Parse and validate Actions execution context, including the repository name, release name and event type
|
||||||
@@ -39,20 +39,27 @@ export async function run(): Promise<void> {
|
|||||||
|
|
||||||
// Gather & validate user inputs
|
// Gather & validate user inputs
|
||||||
const token: string = core.getInput('token')
|
const token: string = core.getInput('token')
|
||||||
const path: string = core.getInput('path')
|
|
||||||
const registryURL: URL = new URL(core.getInput('registry')) // TODO: Should this be dynamic? Maybe an API endpoint to grab the registry for GHES/proxima purposes.
|
const registryURL: URL = new URL(core.getInput('registry')) // TODO: Should this be dynamic? Maybe an API endpoint to grab the registry for GHES/proxima purposes.
|
||||||
|
|
||||||
if (!fsHelper.isDirectory(path)) {
|
// Paths to be included in the OCI image
|
||||||
core.setFailed(
|
const paths: string[] = core.getInput('path').split(' ')
|
||||||
`The path ${path} is not a directory. Please provide a path to a valid directory.`
|
let path = ''
|
||||||
)
|
|
||||||
return
|
if (paths.length === 1 && fsHelper.isDirectory(paths[0])) {
|
||||||
|
// If the path is a single directory, we can skip the bundling step
|
||||||
|
path = paths[0]
|
||||||
|
} else {
|
||||||
|
// Otherwise, we need to bundle the files & folders into a temporary directory
|
||||||
|
const bundleDir = fsHelper.createTempDir()
|
||||||
|
tmpDirs.push(bundleDir)
|
||||||
|
path = fsHelper.bundleFilesintoDirectory(paths, bundleDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a temporary directory to store the archives
|
// Create a temporary directory to store the archives
|
||||||
tmpDir = fsHelper.createTempDir()
|
const archiveDir = fsHelper.createTempDir()
|
||||||
|
tmpDirs.push(archiveDir)
|
||||||
|
|
||||||
const archives = await fsHelper.createArchives(path)
|
const archives = await fsHelper.createArchives(path, archiveDir)
|
||||||
|
|
||||||
const manifest = ociContainer.createActionPackageManifest(
|
const manifest = ociContainer.createActionPackageManifest(
|
||||||
archives.tarFile,
|
archives.tarFile,
|
||||||
@@ -84,9 +91,11 @@ export async function run(): Promise<void> {
|
|||||||
// Fail the workflow run if an error occurs
|
// Fail the workflow run if an error occurs
|
||||||
if (error instanceof Error) core.setFailed(error.message)
|
if (error instanceof Error) core.setFailed(error.message)
|
||||||
} finally {
|
} finally {
|
||||||
// Clean up the temporary directory if it exists
|
// Clean up any temporary directories that exist
|
||||||
if (tmpDir !== '') {
|
for (const tmpDir of tmpDirs) {
|
||||||
fsHelper.removeDir(tmpDir)
|
if (tmpDir !== '') {
|
||||||
|
fsHelper.removeDir(tmpDir)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user