-
Notifications
You must be signed in to change notification settings - Fork 0
feat: support restore keys #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,6 +11,7 @@ async function run() { | |
| try { | ||
| const s3Bucket = core.getInput('s3-bucket', { required: true }); | ||
| const cacheKey = core.getInput('cache-key', { required: true }); | ||
| const restoreKeys = core.getInput('restore-keys', { required: false }).split('\n').map(x => x.trim()).filter(x => x); | ||
| const paths = core.getInput('paths', { required: true }); | ||
| const command = core.getInput('command', { required: true }); | ||
| const tarOption = core.getInput('tar-option', { required: false }); | ||
|
|
@@ -31,33 +32,80 @@ async function run() { | |
| Key: fileName, | ||
| }; | ||
|
|
||
| let foundKey = null; | ||
| let exactMatch = false; | ||
| let contentLength; | ||
|
|
||
| try { | ||
| const headObject = await s3.headObject(params).promise(); | ||
| contentLength = headObject.ContentLength; | ||
| foundKey = fileName; | ||
| exactMatch = true; | ||
| } catch (headErr) { | ||
| // Not found exact match | ||
| } | ||
|
|
||
| if (!foundKey && restoreKeys.length > 0) { | ||
| for (const keyPrefix of restoreKeys) { | ||
| const listParams = { | ||
| Bucket: s3Bucket, | ||
| Prefix: keyPrefix | ||
| }; | ||
| const listedObjects = await s3.listObjectsV2(listParams).promise(); | ||
| if (listedObjects.Contents && listedObjects.Contents.length > 0) { | ||
| const matches = listedObjects.Contents | ||
| .filter(obj => obj.Key.endsWith('.tar.zst')) | ||
| .sort((a, b) => b.LastModified - a.LastModified); | ||
|
|
||
| if (matches.length > 0) { | ||
| foundKey = matches[0].Key; | ||
| contentLength = matches[0].Size; | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if (!foundKey) { | ||
| console.log(`No cache is found for key: ${fileName}`); | ||
| await exec.exec(command); // install or build command e.g. npm ci, npm run dev | ||
| core.saveState('cache-upload', true); | ||
| return; | ||
| } | ||
|
|
||
| // Skip command to save time | ||
| if (exactMatch && cacheHitSkip) { | ||
| console.log(`Cache found, skipping command: ${command}`); | ||
| return; | ||
| } | ||
xahhy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| // Cache found. Download and extract | ||
| console.log(`Found a cache for key: ${foundKey}`); | ||
| const fileStream = fs.createWriteStream(fileName); | ||
| const s3Stream = downloader.download(params, { | ||
| const s3Stream = downloader.download({ | ||
| Bucket: s3Bucket, | ||
| Key: foundKey | ||
| }, { | ||
| totalObjectSize: contentLength, | ||
| concurrentStreams: 20, | ||
| }); | ||
| s3Stream.pipe(fileStream); | ||
| s3Stream.on('downloaded', async () => { | ||
| console.log(`Found a cache for key: ${fileName}`); | ||
| if (cacheHitSkip) { | ||
| console.log(`Cache found, skipping command: ${command}`); | ||
| return; | ||
| } | ||
| await exec.exec(`tar ${untarOption} ${fileName}`); | ||
| await exec.exec(`rm -f ${fileName}`); | ||
|
|
||
| await new Promise((resolve, reject) => { | ||
| s3Stream.on('downloaded', resolve); | ||
| s3Stream.on('error', reject); | ||
| fileStream.on('error', reject); | ||
| }); | ||
|
|
||
| await exec.exec(`tar ${untarOption} ${fileName}`); | ||
| await exec.exec(`rm -f ${fileName}`); | ||
|
Comment on lines
+100
to
+101
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cat -n src/index.js | sed -n '95,110p'Repository: getjerry/actions-s3-cache Length of output: 841 🏁 Script executed: cat -n src/index.js | head -120 | tail -50Repository: getjerry/actions-s3-cache Length of output: 1958 🏁 Script executed: cat -n src/index.js | head -70Repository: getjerry/actions-s3-cache Length of output: 2966 🏁 Script executed: npm list @actions/exec 2>/dev/null || echo "Checking package.json"Repository: getjerry/actions-s3-cache Length of output: 140 🏁 Script executed: cat package.jsonRepository: getjerry/actions-s3-cache Length of output: 524 🌐 Web query:
💡 Result: The exec function accepts an arguments array as its second parameter: a string[] of individual arguments (no shell splitting). Usage example: 🏁 Script executed: # Verify graceful-fs supports fs.promises
grep -r "fs.promises" . --include="*.js" | head -5 || echo "Checking Node.js compatibility"Repository: getjerry/actions-s3-cache Length of output: 641 Avoid shell-string - await exec.exec(`tar ${untarOption} ${fileName}`);
- await exec.exec(`rm -f ${fileName}`);
+ const untarArgs = (untarOption || '').split(/\s+/).filter(Boolean);
+ await exec.exec('tar', [...untarArgs, fileName]);
+ await fs.promises.unlink(fileName).catch(() => {});🤖 Prompt for AI Agents |
||
| console.log(`Restored from restore-key: ${foundKey}`); | ||
xahhy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
xahhy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| // When fuzzy matched cache, will need to upload latest files in post step. | ||
xahhy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // Require workflow to run additional steps to update the cache files otherwise uploaded cache will not match | ||
| if(!exactMatch) { | ||
xahhy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| core.saveState('cache-upload', true); | ||
| } | ||
xahhy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } catch (error) { | ||
| core.setFailed(error.message); | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.