Compare commits

...

38 Commits

Author SHA1 Message Date
Gregorio Litenstein
bb91a1ccb0
Update build
Signed-off-by: Gregorio Litenstein <g.litenstein@gmail.com>
2026-02-05 14:29:41 -03:00
Gregorio Litenstein
9d55b4e130
Fix script invocations, lint and format.
Signed-off-by: Gregorio Litenstein <g.litenstein@gmail.com>
2026-02-05 14:18:53 -03:00
Gregorio Litenstein
d27c53e015
licenses
Signed-off-by: Gregorio Litenstein <g.litenstein@gmail.com>
2026-02-05 14:18:52 -03:00
Gregorio Litenstein
a823c680a0
Update @octokit/action to 5.x
Signed-off-by: Gregorio Litenstein <g.litenstein@gmail.com>
2026-02-05 14:18:52 -03:00
Gregorio Litenstein
44816f5267
Update tests for deleteCacheByKey.
And rebuild.

Signed-off-by: Gregorio Litenstein <g.litenstein@gmail.com>
2026-02-05 14:18:49 -03:00
Gregorio Litenstein
4aee8fbad8
Update documentation and licenses. 2026-02-05 14:15:11 -03:00
Gregorio Litenstein
2f8900dbfd
Update some dependencies.
Signed-off-by: Gregorio Litenstein <g.litenstein@gmail.com>
2026-02-05 10:47:58 -03:00
Gregorio Litenstein
29eae8b688
Don’t accidentally deleting cache from base branch
Signed-off-by: Gregorio Litenstein <g.litenstein@gmail.com>
2026-02-05 10:46:00 -03:00
Gregorio Litenstein
16da501126
Allow refreshing cache also with granular save. 2026-02-05 10:46:00 -03:00
Gregorio Litenstein
9b375e1f10
Add tests for cache refreshing. 2026-02-05 10:46:00 -03:00
Gregorio Litenstein
4a63031112
Allow updating caches 2026-02-05 10:45:59 -03:00
Bassem Dghaidi
b7e8d49f17
Merge pull request #1701 from actions/Link-/fix-proxy-integration-tests
Fix proxy integration tests
2026-01-30 16:37:01 +01:00
Bassem Dghaidi
984a21b1cb Add traffic sanity check step 2026-01-30 02:05:51 -08:00
Bassem Dghaidi
acf2f1f76a Fix resolution 2026-01-30 02:03:12 -08:00
Bassem Dghaidi
95a07c5132 Add wait for proxy 2026-01-30 02:00:09 -08:00
Bassem Dghaidi
90e4fae240 Rewrite and simplify 2026-01-30 01:56:07 -08:00
Bassem Dghaidi
b45623637f
Merge pull request #1690 from XZTDean/docs/v5-example-update
docs: Update examples to use the latest version
2026-01-29 11:36:35 +01:00
Bassem Dghaidi
bdb94ce451
Merge branch 'main' into docs/v5-example-update 2026-01-29 11:32:26 +01:00
Bassem Dghaidi
cb6ea63971
Merge pull request #1699 from actions/Link-/fix-workflow-permissions
Fix workflow permissions and cleanup workflow names / formatting
2026-01-29 11:31:19 +01:00
Bassem Dghaidi
49bc452f55 Merge branch 'Link-/fix-workflow-permissions' of github.com:actions/cache into Link-/fix-workflow-permissions 2026-01-29 02:27:40 -08:00
Bassem Dghaidi
1e06c934a1
Merge branch 'main' of github.com:actions/cache into Link-/fix-workflow-permissions 2026-01-29 02:27:32 -08:00
Bassem Dghaidi
a838313d22
Merge pull request #1697 from actions/alert-autofix-52
Potential fix for code scanning alert no. 52: Workflow does not contain permissions
2026-01-29 11:26:02 +01:00
Bassem Dghaidi
6e48a73476
Update .github/workflows/pr-opened-workflow.yml
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-29 11:25:11 +01:00
Bassem Dghaidi
9848277c90 Cleanup workflow file names 2026-01-29 02:19:45 -08:00
Bassem Dghaidi
94056f1871 Fix workflow permissions and cleanup 2026-01-29 02:17:35 -08:00
Bassem Dghaidi
b56bb3a202 Fix permissions for workflows/workflow.yml 2026-01-29 02:11:09 -08:00
Bassem Dghaidi
4a6586c009
Merge branch 'main' into alert-autofix-52 2026-01-29 11:04:16 +01:00
Bassem Dghaidi
0de23fd4eb
Merge pull request #1696 from actions/Link-/release-docs
Add release instructions and update maintainer docs
2026-01-29 11:03:40 +01:00
Bassem Dghaidi
4e38c8636e
Potential fix for code scanning alert no. 52: Workflow does not contain permissions
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2026-01-29 11:02:45 +01:00
Bassem Dghaidi
24e8b877a8 Add note 2026-01-29 01:58:41 -08:00
Bassem Dghaidi
3baa5f1c7b Update contribution docs 2026-01-29 01:58:05 -08:00
Bassem Dghaidi
cdf6c1fa76
Merge pull request #1695 from actions/Link-/prepare-5.0.3
Prepare v5.0.3 release
2026-01-29 10:43:43 +01:00
Bassem Dghaidi
a1bee22673 Add review for the @actions/http-client license 2026-01-29 01:39:24 -08:00
Bassem Dghaidi
46957638dc
Add licensed output 2026-01-29 01:31:38 -08:00
Bassem Dghaidi
dc73bb9f7b Upgrade dependencies and address security warnings
- Bump `@actions/cache` to v5.0.5
- Bump `@actions/core` to v2.0.3
2026-01-29 01:25:30 -08:00
Bassem Dghaidi
345d5c2f76
Add 5.0.3 builds 2026-01-29 01:24:44 -08:00
XZTDean
5b7a9f8ae5 docs: Update other actions in examples to the latest version 2025-12-15 06:34:21 -08:00
XZTDean
de99935c0c docs: Update examples to cache@v5 2025-12-15 06:15:33 -08:00
81 changed files with 94632 additions and 65285 deletions

View File

@ -1,4 +1,4 @@
name: Check dist/
name: Check dist content
on:
push:
@ -11,6 +11,9 @@ on:
- '**.md'
workflow_dispatch:
permissions:
contents: read
jobs:
call-check-dist:
name: Check dist/

View File

@ -1,4 +1,5 @@
name: Close inactive issues
on:
schedule:
- cron: "30 8 * * *"

View File

@ -1,4 +1,4 @@
name: "Code scanning - action"
name: Code scanning
on:
push:
@ -6,15 +6,14 @@ on:
schedule:
- cron: '0 19 * * 0'
permissions:
contents: read
security-events: write
jobs:
CodeQL-Build:
# CodeQL runs on ubuntu-latest, windows-latest, and macos-latest
runs-on: ubuntu-latest
permissions:
# required for all workflows
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@v5

View File

@ -1,16 +1,21 @@
name: Assign issue
on:
issues:
types: [opened]
permissions:
issues: write
jobs:
run-action:
runs-on: ubuntu-latest
steps:
- name: Get current oncall
id: oncall
run: |
echo "CURRENT=$(curl --request GET 'https://api.pagerduty.com/oncalls?include[]=users&schedule_ids[]=P5VG2BX&earliest=true' --header 'Authorization: Token token=${{ secrets.PAGERDUTY_TOKEN }}' --header 'Accept: application/vnd.pagerduty+json;version=2' --header 'Content-Type: application/json' | jq -r '.oncalls[].user.name')" >> $GITHUB_OUTPUT
- name: add_assignees
run: |
curl -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN}}" https://api.github.com/repos/${{github.repository}}/issues/${{ github.event.issue.number}}/assignees -d '{"assignees":["${{steps.oncall.outputs.CURRENT}}"]}'
- name: Get current oncall
id: oncall
run: |
echo "CURRENT=$(curl --request GET 'https://api.pagerduty.com/oncalls?include[]=users&schedule_ids[]=P5VG2BX&earliest=true' --header 'Authorization: Token token=${{ secrets.PAGERDUTY_TOKEN }}' --header 'Accept: application/vnd.pagerduty+json;version=2' --header 'Content-Type: application/json' | jq -r '.oncalls[].user.name')" >> $GITHUB_OUTPUT
- name: add_assignees
run: |
curl -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN}}" https://api.github.com/repos/${{github.repository}}/issues/${{ github.event.issue.number}}/assignees -d '{"assignees":["${{steps.oncall.outputs.CURRENT}}"]}'

View File

@ -1,4 +1,4 @@
name: Licensed
name: License check
on:
push:
@ -9,6 +9,9 @@ on:
- main
workflow_dispatch:
permissions:
contents: read
jobs:
validate-cached-dependency-records:
runs-on: ubuntu-latest

View File

@ -1,20 +1,25 @@
name: Add Reviewer PR
name: Assign pull request reviewer
on:
pull_request_target:
types: [opened]
permissions:
pull-requests: write
jobs:
run-action:
runs-on: ubuntu-latest
steps:
- name: Get current oncall
id: oncall
run: |
echo "CURRENT=$(curl --request GET 'https://api.pagerduty.com/oncalls?include[]=users&schedule_ids[]=P5VG2BX&earliest=true' --header 'Authorization: Token token=${{ secrets.PAGERDUTY_TOKEN }}' --header 'Accept: application/vnd.pagerduty+json;version=2' --header 'Content-Type: application/json' | jq -r '.oncalls[].user.name')" >> $GITHUB_OUTPUT
- name: Request Review
run: |
curl -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN}}" https://api.github.com/repos/${{github.repository}}/pulls/${{ github.event.pull_request.number}}/requested_reviewers -d '{"reviewers":["${{steps.oncall.outputs.CURRENT}}"]}'
- name: Add Assignee
run: |
curl -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN}}" https://api.github.com/repos/${{github.repository}}/issues/${{ github.event.pull_request.number}}/assignees -d '{"assignees":["${{steps.oncall.outputs.CURRENT}}"]}'
- name: Get current oncall
id: oncall
run: |
echo "CURRENT=$(curl --request GET 'https://api.pagerduty.com/oncalls?include[]=users&schedule_ids[]=P5VG2BX&earliest=true' --header 'Authorization: Token token=${{ secrets.PAGERDUTY_TOKEN }}' --header 'Accept: application/vnd.pagerduty+json;version=2' --header 'Content-Type: application/json' | jq -r '.oncalls[].user.name')" >> $GITHUB_OUTPUT
- name: Request Review
run: |
curl -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN}}" https://api.github.com/repos/${{github.repository}}/pulls/${{ github.event.pull_request.number}}/requested_reviewers -d '{"reviewers":["${{steps.oncall.outputs.CURRENT}}"]}'
- name: Add Assignee
run: |
curl -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN}}" https://api.github.com/repos/${{github.repository}}/issues/${{ github.event.pull_request.number}}/assignees -d '{"assignees":["${{steps.oncall.outputs.CURRENT}}"]}'

View File

@ -1,17 +1,17 @@
name: 'Publish Immutable Action Version'
name: Publish immutable action
on:
release:
types: [released]
permissions:
contents: read
id-token: write
packages: write
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
packages: write
steps:
- name: Checking out
uses: actions/checkout@v5

View File

@ -1,4 +1,5 @@
name: Release new action version
on:
release:
types: [released]
@ -10,6 +11,7 @@ on:
env:
TAG_NAME: ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }}
permissions:
contents: write

View File

@ -10,6 +10,9 @@ on:
- main
- releases/**
permissions:
contents: read
jobs:
# Build and unit test
build:
@ -57,6 +60,7 @@ jobs:
path: |
test-cache
~/test-cache
test-restore:
needs: test-save
strategy:
@ -86,15 +90,86 @@ jobs:
runs-on: ubuntu-latest
container:
image: ubuntu:latest
options: --dns 127.0.0.1
options: --cap-add=NET_ADMIN
services:
squid-proxy:
image: ubuntu/squid:latest
ports:
- 3128:3128
env:
http_proxy: http://squid-proxy:3128
https_proxy: http://squid-proxy:3128
steps:
- name: Wait for proxy to be ready
shell: bash
run: |
echo "Waiting for squid proxy to be ready..."
echo "Resolving squid-proxy hostname:"
getent hosts squid-proxy || echo "DNS resolution failed"
for i in $(seq 1 30); do
if (echo > /dev/tcp/squid-proxy/3128) 2>/dev/null; then
echo "Proxy is ready!"
exit 0
fi
echo "Attempt $i: Proxy not ready, waiting..."
sleep 2
done
echo "Proxy failed to become ready"
exit 1
env:
http_proxy: ""
https_proxy: ""
- name: Install dependencies
run: |
apt-get update
apt-get install -y iptables curl
- name: Verify proxy is working
run: |
echo "Testing proxy connectivity..."
curl -s -o /dev/null -w "%{http_code}" --proxy http://squid-proxy:3128 http://github.com || true
echo "Proxy verification complete"
- name: Block direct traffic (enforce proxy usage)
run: |
# Get the squid-proxy container IP
PROXY_IP=$(getent hosts squid-proxy | awk '{ print $1 }')
echo "Proxy IP: $PROXY_IP"
# Allow loopback traffic
iptables -A OUTPUT -o lo -j ACCEPT
# Allow traffic to the proxy container
iptables -A OUTPUT -d $PROXY_IP -j ACCEPT
# Allow established connections
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allow DNS (needed for initial resolution)
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT
# Block all other outbound traffic (HTTP/HTTPS)
iptables -A OUTPUT -p tcp --dport 80 -j REJECT
iptables -A OUTPUT -p tcp --dport 443 -j REJECT
# Log the iptables rules for debugging
iptables -L -v -n
- name: Verify direct HTTPS is blocked
run: |
echo "Testing that direct HTTPS requests fail..."
if curl --noproxy '*' -s --connect-timeout 5 https://github.com > /dev/null 2>&1; then
echo "ERROR: Direct HTTPS request succeeded - blocking is not working!"
exit 1
else
echo "SUCCESS: Direct HTTPS request was blocked as expected"
fi
echo "Testing that HTTPS through proxy succeeds..."
if curl --proxy http://squid-proxy:3128 -s --connect-timeout 10 https://github.com > /dev/null 2>&1; then
echo "SUCCESS: HTTPS request through proxy succeeded"
else
echo "ERROR: HTTPS request through proxy failed!"
exit 1
fi
- name: Checkout
uses: actions/checkout@v5
- name: Generate files
@ -104,20 +179,92 @@ jobs:
with:
key: test-proxy-${{ github.run_id }}
path: test-cache
test-proxy-restore:
needs: test-proxy-save
runs-on: ubuntu-latest
container:
image: ubuntu:latest
options: --dns 127.0.0.1
options: --cap-add=NET_ADMIN
services:
squid-proxy:
image: ubuntu/squid:latest
ports:
- 3128:3128
env:
http_proxy: http://squid-proxy:3128
https_proxy: http://squid-proxy:3128
steps:
- name: Wait for proxy to be ready
shell: bash
run: |
echo "Waiting for squid proxy to be ready..."
echo "Resolving squid-proxy hostname:"
getent hosts squid-proxy || echo "DNS resolution failed"
for i in $(seq 1 30); do
if (echo > /dev/tcp/squid-proxy/3128) 2>/dev/null; then
echo "Proxy is ready!"
exit 0
fi
echo "Attempt $i: Proxy not ready, waiting..."
sleep 2
done
echo "Proxy failed to become ready"
exit 1
env:
http_proxy: ""
https_proxy: ""
- name: Install dependencies
run: |
apt-get update
apt-get install -y iptables curl
- name: Verify proxy is working
run: |
echo "Testing proxy connectivity..."
curl -s -o /dev/null -w "%{http_code}" --proxy http://squid-proxy:3128 http://github.com || true
echo "Proxy verification complete"
- name: Block direct traffic (enforce proxy usage)
run: |
# Get the squid-proxy container IP
PROXY_IP=$(getent hosts squid-proxy | awk '{ print $1 }')
echo "Proxy IP: $PROXY_IP"
# Allow loopback traffic
iptables -A OUTPUT -o lo -j ACCEPT
# Allow traffic to the proxy container
iptables -A OUTPUT -d $PROXY_IP -j ACCEPT
# Allow established connections
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allow DNS (needed for initial resolution)
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT
# Block all other outbound traffic (HTTP/HTTPS)
iptables -A OUTPUT -p tcp --dport 80 -j REJECT
iptables -A OUTPUT -p tcp --dport 443 -j REJECT
# Log the iptables rules for debugging
iptables -L -v -n
- name: Verify direct HTTPS is blocked
run: |
echo "Testing that direct HTTPS requests fail..."
if curl --noproxy '*' -s --connect-timeout 5 https://github.com > /dev/null 2>&1; then
echo "ERROR: Direct HTTPS request succeeded - blocking is not working!"
exit 1
else
echo "SUCCESS: Direct HTTPS request was blocked as expected"
fi
echo "Testing that HTTPS through proxy succeeds..."
if curl --proxy http://squid-proxy:3128 -s --connect-timeout 10 https://github.com > /dev/null 2>&1; then
echo "SUCCESS: HTTPS request through proxy succeeded"
else
echo "ERROR: HTTPS request through proxy failed!"
exit 1
fi
- name: Checkout
uses: actions/checkout@v5
- name: Restore cache

View File

@ -27,4 +27,5 @@ reviewed:
- fs.realpath # ISC
- glob # ISC
- prettier # MIT
- lodash # MIT
- lodash # MIT
- "@actions/http-client" # MIT

View File

@ -1,6 +1,6 @@
---
name: "@actions/cache"
version: 5.0.3
version: 5.0.5
type: npm
summary: Actions cache lib
homepage: https://github.com/actions/toolkit/tree/main/packages/cache

View File

@ -1,9 +1,13 @@
---
name: "@actions/core"
version: 1.11.1
name: "@actions/cache"
<<<<<<< HEAD
version: 5.0.3
=======
version: 4.0.0
>>>>>>> 0e80100 (Update licensed cache)
type: npm
summary: Actions core lib
homepage: https://github.com/actions/toolkit/tree/main/packages/core
summary: Actions cache lib
homepage: https://github.com/actions/toolkit/tree/main/packages/cache
license: mit
licenses:
- sources: LICENSE.md

View File

@ -1,6 +1,6 @@
---
name: "@actions/core"
version: 2.0.1
version: 2.0.3
type: npm
summary: Actions core lib
homepage: https://github.com/actions/toolkit/tree/main/packages/core

View File

@ -1,6 +1,6 @@
---
name: "@actions/glob"
version: 0.5.0
version: 0.5.1
type: npm
summary: Actions glob lib
homepage: https://github.com/actions/toolkit/tree/main/packages/glob

View File

@ -1,32 +0,0 @@
---
name: "@actions/http-client"
version: 2.2.3
type: npm
summary: Actions Http Client
homepage: https://github.com/actions/toolkit/tree/main/packages/http-client
license: mit
licenses:
- sources: LICENSE
text: |
Actions Http Client for Node.js
Copyright (c) GitHub, Inc.
All rights reserved.
MIT License
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.
notices: []

View File

@ -1,10 +1,10 @@
---
name: "@actions/http-client"
version: 3.0.1
version: 3.0.2
type: npm
summary: Actions Http Client
homepage: https://github.com/actions/toolkit/tree/main/packages/http-client
license: mit
license: other
licenses:
- sources: LICENSE
text: |

View File

@ -1,6 +1,6 @@
---
name: "@azure/storage-blob"
version: 12.29.1
version: 12.30.0
type: npm
summary: Microsoft Azure Storage SDK for JavaScript - Blob
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/storage/storage-blob/

View File

@ -1,6 +1,6 @@
---
name: "@azure/storage-common"
version: 12.1.1
version: 12.3.0
type: npm
summary: Azure Storage Common Client Library for JavaScript
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/storage/storage-internal-avro/
@ -30,3 +30,4 @@ licenses:
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
notices: []
...

34
.licenses/npm/@octokit/action.dep.yml generated Normal file
View File

@ -0,0 +1,34 @@
---
name: "@octokit/action"
version: 5.0.6
type: npm
summary: GitHub API client for GitHub Actions
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
MIT License
Copyright (c) 2019 Octokit contributors
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.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@ -1,20 +1,22 @@
---
name: "@fastify/busboy"
name: "@octokit/auth-action"
version: 2.1.1
type: npm
summary: A streaming parser for HTML form data for node.js
summary: GitHub API token authentication for GitHub Actions
homepage:
license: mit
licenses:
- sources: LICENSE
text: |-
Copyright Brian White. All rights reserved.
text: |
The MIT License
Copyright (c) 2019 Octokit contributors
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
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
@ -24,7 +26,9 @@ licenses:
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.
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.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@ -0,0 +1,34 @@
---
name: "@octokit/auth-token"
version: 3.0.4
type: npm
summary: GitHub API token authentication for browsers and Node.js
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
The MIT License
Copyright (c) 2019 Octokit contributors
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.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

34
.licenses/npm/@octokit/core.dep.yml generated Normal file
View File

@ -0,0 +1,34 @@
---
name: "@octokit/core"
version: 4.2.4
type: npm
summary: Extendable client for GitHub's REST & GraphQL APIs
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
The MIT License
Copyright (c) 2019 Octokit contributors
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.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

34
.licenses/npm/@octokit/endpoint.dep.yml generated Normal file
View File

@ -0,0 +1,34 @@
---
name: "@octokit/endpoint"
version: 7.0.6
type: npm
summary: Turns REST API endpoints into generic request options
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
The MIT License
Copyright (c) 2018 Octokit contributors
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.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

34
.licenses/npm/@octokit/graphql.dep.yml generated Normal file
View File

@ -0,0 +1,34 @@
---
name: "@octokit/graphql"
version: 5.0.6
type: npm
summary: GitHub GraphQL API client for browsers and Node
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
The MIT License
Copyright (c) 2018 Octokit contributors
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.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@ -1,20 +1,20 @@
---
name: "@actions/exec"
version: 1.1.1
name: "@octokit/openapi-types"
version: 18.1.1
type: npm
summary: Actions exec lib
homepage: https://github.com/actions/toolkit/tree/main/packages/exec
summary: Generated TypeScript definitions based on GitHub's OpenAPI spec for api.github.com
homepage:
license: mit
licenses:
- sources: LICENSE.md
- sources: LICENSE
text: |-
The MIT License (MIT)
Copyright 2019 GitHub
Copyright 2020 Gregor Martynus
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.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@ -0,0 +1,20 @@
---
name: "@octokit/plugin-paginate-rest"
version: 6.1.2
type: npm
summary: Octokit plugin to paginate REST API endpoint responses
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
MIT License Copyright (c) 2019 Octokit contributors
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 (including the next paragraph) 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.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@ -0,0 +1,20 @@
---
name: "@octokit/plugin-rest-endpoint-methods"
version: 7.2.3
type: npm
summary: Octokit plugin adding one method for all of api.github.com REST API endpoints
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
MIT License Copyright (c) 2019 Octokit contributors
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 (including the next paragraph) 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.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@ -0,0 +1,34 @@
---
name: "@octokit/request-error"
version: 3.0.3
type: npm
summary: Error class for Octokit request errors
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
The MIT License
Copyright (c) 2019 Octokit contributors
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.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

35
.licenses/npm/@octokit/request.dep.yml generated Normal file
View File

@ -0,0 +1,35 @@
---
name: "@octokit/request"
version: 6.2.8
type: npm
summary: Send parameterized requests to GitHub's APIs with sensible defaults in browsers
and Node
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
The MIT License
Copyright (c) 2018 Octokit contributors
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.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@ -1,20 +1,20 @@
---
name: "@actions/io"
version: 1.1.3
name: "@octokit/tsconfig"
version: 1.0.2
type: npm
summary: Actions io lib
homepage: https://github.com/actions/toolkit/tree/main/packages/io
summary: TypeScript configuration for Octokit packages
homepage:
license: mit
licenses:
- sources: LICENSE.md
text: |-
The MIT License (MIT)
Copyright 2019 GitHub
- sources: LICENSE
text: |
MIT License Copyright (c) 2020 Octokit contributors
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 above copyright notice and this permission notice (including the next paragraph) 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.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@ -0,0 +1,20 @@
---
name: "@octokit/types"
version: 10.0.0
type: npm
summary: Shared TypeScript definitions for Octokit projects
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
MIT License Copyright (c) 2019 Octokit contributors
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 (including the next paragraph) 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.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@ -0,0 +1,20 @@
---
name: "@octokit/types"
version: 9.3.2
type: npm
summary: Shared TypeScript definitions for Octokit projects
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
MIT License Copyright (c) 2019 Octokit contributors
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 (including the next paragraph) 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.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

214
.licenses/npm/before-after-hook.dep.yml generated Normal file
View File

@ -0,0 +1,214 @@
---
name: before-after-hook
version: 2.2.3
type: npm
summary: asynchronous before/error/after hooks for internal functionality
homepage:
license: apache-2.0
licenses:
- sources: LICENSE
text: |2
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2018 Gregor Martynus and other contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
- sources: README.md
text: "[Apache 2.0](LICENSE)"
notices: []

View File

@ -3,7 +3,7 @@ name: concat-map
version: 0.0.1
type: npm
summary: concatenative mapdashery
homepage: https://github.com/substack/node-concat-map#readme
homepage:
license: other
licenses:
- sources: LICENSE

28
.licenses/npm/deprecation.dep.yml generated Normal file
View File

@ -0,0 +1,28 @@
---
name: deprecation
version: 2.3.1
type: npm
summary: Log a deprecation message with stack
homepage:
license: isc
licenses:
- sources: LICENSE
text: |
The ISC License
Copyright (c) Gregor Martynus and contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
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.
- sources: README.md
text: "[ISC](LICENSE)"
notices: []

View File

@ -3,7 +3,7 @@ name: events
version: 3.3.0
type: npm
summary: Node's event emitter for all engines.
homepage: https://github.com/Gozala/events#readme
homepage:
license: mit
licenses:
- sources: LICENSE

View File

@ -1,6 +1,6 @@
---
name: fast-xml-parser
version: 5.3.3
version: 5.3.4
type: npm
summary: Validate XML, Parse XML, Build XML without C/C++ based libraries
homepage:

40
.licenses/npm/is-plain-object.dep.yml generated Normal file
View File

@ -0,0 +1,40 @@
---
name: is-plain-object
version: 5.0.0
type: npm
summary: Returns true if an object was created by the `Object` constructor, or Object.create(null).
homepage: https://github.com/jonschlinkert/is-plain-object
license: mit
licenses:
- sources: LICENSE
text: |
The MIT License (MIT)
Copyright (c) 2014-2017, Jon Schlinkert.
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.
- sources: README.md
text: |-
Copyright © 2019, [Jon Schlinkert](https://github.com/jonschlinkert).
Released under the [MIT License](LICENSE).
***
_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.8.0, on April 28, 2019._
notices: []

View File

@ -3,7 +3,7 @@ name: minimatch
version: 3.1.2
type: npm
summary: a glob matcher in javascript
homepage:
homepage:
license: isc
licenses:
- sources: LICENSE

View File

@ -12,12 +12,8 @@ licenses:
Copyright (c) 2020 Vercel, Inc.
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 above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

56
.licenses/npm/node-fetch.dep.yml generated Normal file
View File

@ -0,0 +1,56 @@
---
name: node-fetch
version: 2.7.0
type: npm
summary: A light-weight module that brings window.fetch to node.js
homepage: https://github.com/bitinn/node-fetch
license: mit
licenses:
- sources: LICENSE.md
text: |+
The MIT License (MIT)
Copyright (c) 2016 David Frank
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.
- sources: README.md
text: |-
MIT
[npm-image]: https://flat.badgen.net/npm/v/node-fetch
[npm-url]: https://www.npmjs.com/package/node-fetch
[travis-image]: https://flat.badgen.net/travis/bitinn/node-fetch
[travis-url]: https://travis-ci.org/bitinn/node-fetch
[codecov-image]: https://flat.badgen.net/codecov/c/github/bitinn/node-fetch/master
[codecov-url]: https://codecov.io/gh/bitinn/node-fetch
[install-size-image]: https://flat.badgen.net/packagephobia/install/node-fetch
[install-size-url]: https://packagephobia.now.sh/result?p=node-fetch
[discord-image]: https://img.shields.io/discord/619915844268326952?color=%237289DA&label=Discord&style=flat-square
[discord-url]: https://discord.gg/Zxbndcm
[opencollective-image]: https://opencollective.com/node-fetch/backers.svg
[opencollective-url]: https://opencollective.com/node-fetch
[whatwg-fetch]: https://fetch.spec.whatwg.org/
[response-init]: https://fetch.spec.whatwg.org/#responseinit
[node-readable]: https://nodejs.org/api/stream.html#stream_readable_streams
[mdn-headers]: https://developer.mozilla.org/en-US/docs/Web/API/Headers
[LIMITS.md]: https://github.com/bitinn/node-fetch/blob/master/LIMITS.md
[ERROR-HANDLING.md]: https://github.com/bitinn/node-fetch/blob/master/ERROR-HANDLING.md
[UPGRADE-GUIDE.md]: https://github.com/bitinn/node-fetch/blob/master/UPGRADE-GUIDE.md
notices: []

26
.licenses/npm/once.dep.yml generated Normal file
View File

@ -0,0 +1,26 @@
---
name: once
version: 1.4.0
type: npm
summary: Run a function exactly one time
homepage:
license: isc
licenses:
- sources: LICENSE
text: |
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
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.
notices: []

View File

@ -3,7 +3,7 @@ name: semver
version: 6.3.1
type: npm
summary: The semantic version parser used by npm.
homepage:
homepage:
license: isc
licenses:
- sources: LICENSE

30
.licenses/npm/tr46.dep.yml generated Normal file
View File

@ -0,0 +1,30 @@
---
name: tr46
version: 0.0.3
type: npm
summary: An implementation of the Unicode TR46 spec
homepage: https://github.com/Sebmaster/tr46.js#readme
license: mit
licenses:
- sources: Auto-generated MIT license text
text: |
MIT License
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.
notices: []

View File

@ -1,6 +1,6 @@
---
name: undici
version: 5.29.0
version: 6.23.0
type: npm
summary: An HTTP/1.1 client, written from scratch for Node.js
homepage: https://undici.nodejs.org

View File

@ -0,0 +1,20 @@
---
name: universal-user-agent
version: 6.0.1
type: npm
summary: Get a user agent string in both browser and node
homepage:
license: isc
licenses:
- sources: LICENSE.md
text: |
# [ISC License](https://spdx.org/licenses/ISC)
Copyright (c) 2018, Gregor Martynus (https://github.com/gr2m)
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
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.
- sources: README.md
text: "[ISC](LICENSE.md)"
notices: []

23
.licenses/npm/webidl-conversions.dep.yml generated Normal file
View File

@ -0,0 +1,23 @@
---
name: webidl-conversions
version: 3.0.1
type: npm
summary: Implements the WebIDL algorithms for converting to and from JavaScript values
homepage:
license: bsd-2-clause
licenses:
- sources: LICENSE.md
text: |
# The BSD 2-Clause License
Copyright (c) 2014, Domenic Denicola
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
notices: []

32
.licenses/npm/whatwg-url.dep.yml generated Normal file
View File

@ -0,0 +1,32 @@
---
name: whatwg-url
version: 5.0.0
type: npm
summary: An implementation of the WHATWG URL Standard's URL API and parsing machinery
homepage:
license: mit
licenses:
- sources: LICENSE.txt
text: |
The MIT License (MIT)
Copyright (c) 20152016 Sebastian Mayr
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.
notices: []

26
.licenses/npm/wrappy.dep.yml generated Normal file
View File

@ -0,0 +1,26 @@
---
name: wrappy
version: 1.0.2
type: npm
summary: Callback wrapping utility
homepage: https://github.com/npm/wrappy
license: isc
licenses:
- sources: LICENSE
text: |
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
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.
notices: []

View File

@ -7,5 +7,6 @@
"trailingComma": "none",
"bracketSpacing": true,
"arrowParens": "avoid",
"parser": "typescript"
"parser": "typescript",
"endOfLine": "lf"
}

View File

@ -16,7 +16,7 @@ Please note that this project is released with a [Contributor Code of Conduct][c
1. [Fork][fork] and clone the repository
2. Configure and install the dependencies: `npm install`
3. Make sure the tests pass on your machine: `npm run test`
4. Create a new branch: `git checkout -b my-branch-name`
4. Create a new branch: `git switch -c my-branch-name`
5. Make your change, add tests, and make sure the tests still pass
6. Push to your fork and [submit a pull request][pr]
7. Pat your self on the back and wait for your pull request to be reviewed and merged.

View File

@ -50,6 +50,7 @@ Read more about the change & access the migration guide: [reference to the annou
### v3
* Added a workaround to allow updating/refreshing existing caches, via the `refresh-cache` option and requiring a valid Github API token.
* Integrated with the new cache service (v2) APIs.
* Added support for caching in GHES 3.5+.
* Fixed download issue for files > 2GB during restore.
@ -90,10 +91,12 @@ If you are using a `self-hosted` Windows runner, `GNU tar` and `zstd` are requir
* `enableCrossOsArchive` - An optional boolean when enabled, allows Windows runners to save or restore caches that can be restored or saved respectively on other platforms. Default: `false`
* `fail-on-cache-miss` - Fail the workflow if cache entry is not found. Default: `false`
* `lookup-only` - If true, only checks if cache entry exists and skips download. Does not change save cache behavior. Default: `false`
* `refresh-cache` - An optional boolean, when enabled it will result in a matched key being deleted after being restored, allowing it to be reused with refreshed/updated content. Default: false
#### Environment Variables
* `SEGMENT_DOWNLOAD_TIMEOUT_MINS` - Segment download timeout (in minutes, default `10`) to abort download of the segment if not completed in the defined number of minutes. [Read more](https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout)
* `GITHUB_TOKEN` - A Github API token, required for authenticating to the API when the `refresh-cache` option is enabled.
### Outputs
@ -123,11 +126,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Cache Primes
id: cache-primes
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: prime-numbers
key: ${{ runner.os }}-primes
@ -154,11 +157,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Restore cached Primes
id: cache-primes-restore
uses: actions/cache/restore@v4
uses: actions/cache/restore@v5
with:
path: |
path/to/dependencies
@ -169,7 +172,7 @@ jobs:
.
- name: Save Primes
id: cache-primes-save
uses: actions/cache/save@v4
uses: actions/cache/save@v5
with:
path: |
path/to/dependencies
@ -224,7 +227,7 @@ A cache key can include any of the contexts, functions, literals, and operators
For example, using the [`hashFiles`](https://docs.github.com/en/actions/learn-github-actions/expressions#hashfiles) function allows you to create a new cache when dependencies change.
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: |
path/to/dependencies
@ -242,7 +245,7 @@ Additionally, you can use arbitrary command output in a cache key, such as a dat
echo "date=$(/bin/date -u "+%Y%m%d")" >> $GITHUB_OUTPUT
shell: bash
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: path/to/dependencies
key: ${{ runner.os }}-${{ steps.get-date.outputs.date }}-${{ hashFiles('**/lockfiles') }}
@ -262,9 +265,9 @@ Example:
```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: actions/cache@v4
- uses: actions/cache@v5
id: cache
with:
path: path/to/dependencies
@ -292,11 +295,11 @@ jobs:
build-linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Cache Primes
id: cache-primes
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: prime-numbers
key: primes
@ -307,7 +310,7 @@ jobs:
- name: Cache Numbers
id: cache-numbers
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: numbers
key: primes
@ -319,11 +322,11 @@ jobs:
build-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Cache Primes
id: cache-primes
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: prime-numbers
key: primes

View File

@ -1,7 +1,35 @@
# Releases
## How to prepare a release
> [!NOTE]
> Relevant for maintainers with write access only.
1. Switch to a new branch from `main`.
1. Run `npm test` to ensure all tests are passing.
1. Update the version in [`package.json`](package.json).
1. Run `npm run build` to update the compiled files.
1. Update this [`RELEASES.md`](RELEASES.md) with the new version and changes in the `## Changelog` section.
1. Run `licensed cache` to update the license report.
1. Run `licensed status` and resolve any warnings by updating the [`.licensed.yml`](.licensed.yml) file with the exceptions.
1. Commit your changes and push your branch upstream.
1. Open a pull request against `main` and get it reviewed and merged.
1. Draft a new release https://github.com/actions/cache/releases use the same version number used in `package.json`
1. Create a new tag with the version number.
1. Auto generate release notes and update them to match the changes you made in `RELEASES.md`.
1. Toggle the set as the latest release option.
1. Publish the release.
1. Navigate to https://github.com/actions/cache/actions/workflows/release-new-action-version.yml
1. There should be a workflow run queued with the same version number.
1. Approve the run to publish the new version and update the major tags for this action.
## Changelog
### 5.0.3
- Bump `@actions/cache` to v5.0.5 (Resolves: https://github.com/actions/cache/security/dependabot/33)
- Bump `@actions/core` to v2.0.3
### 5.0.2
- Bump `@actions/cache` to v5.0.3 [#1692](https://github.com/actions/cache/pull/1692)

View File

@ -1,5 +1,6 @@
import * as cache from "@actions/cache";
import * as core from "@actions/core";
import nock from "nock";
import { Events, RefKey } from "../src/constants";
import * as actionUtils from "../src/utils/actionUtils";
@ -12,9 +13,13 @@ let pristineEnv: NodeJS.ProcessEnv;
beforeAll(() => {
pristineEnv = process.env;
nock.disableNetConnect();
jest.spyOn(core, "getInput").mockImplementation((name, options) => {
return jest.requireActual("@actions/core").getInput(name, options);
});
testUtils.mockServer.listen({
onUnhandledRequest: "warn"
});
});
beforeEach(() => {
@ -22,10 +27,15 @@ beforeEach(() => {
process.env = pristineEnv;
delete process.env[Events.Key];
delete process.env[RefKey];
delete process.env["GITHUB_REPOSITORY"];
delete process.env["GITHUB_TOKEN"];
delete process.env["GITHUB_ACTION"];
});
afterAll(() => {
process.env = pristineEnv;
testUtils.mockServer.close();
nock.enableNetConnect();
});
test("isGhes returns true if server url is not github.com", () => {
@ -203,6 +213,133 @@ test("getInputAsBool throws if required and value missing", () => {
).toThrowError();
});
test("deleteCacheByKey produces 'HttpError: 404' when cache is not found.", async () => {
const event = Events.Push;
process.env["GITHUB_REPOSITORY"] = "owner/repo";
process.env["GITHUB_TOKEN"] =
"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";
process.env["GITHUB_ACTION"] = "__owner___run-repo";
process.env[Events.Key] = event;
process.env[RefKey] = "ref/heads/feature";
const logWarningMock = jest.spyOn(actionUtils, "logWarning");
const response = await actionUtils.deleteCacheByKey(
testUtils.failureCacheKey,
"owner",
"repo"
);
expect(logWarningMock).toHaveBeenCalledWith(
expect.stringMatching(/404: Not Found/i)
);
expect(response).toBe(undefined);
});
test("deleteCacheByKey does not delete anything if it finds more than one entry for the given key.", async () => {
const event = Events.Push;
process.env["GITHUB_REPOSITORY"] = "owner/repo";
process.env["GITHUB_TOKEN"] =
"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";
process.env["GITHUB_ACTION"] = "__owner___run-repo";
process.env[Events.Key] = event;
process.env[RefKey] = "";
const logWarningMock = jest.spyOn(actionUtils, "logWarning");
const response = await actionUtils.deleteCacheByKey(
testUtils.failureCacheKey,
"owner",
"repo"
);
expect(logWarningMock).toHaveBeenCalledWith(
`More than one cache entry found for key ${testUtils.failureCacheKey}`
);
expect(response).toBe(undefined);
});
test("deleteCacheByKey does not delete anything if the key matches a cache belonging to another ref.", async () => {
const event = Events.Push;
process.env["GITHUB_REPOSITORY"] = "owner/repo";
process.env["GITHUB_TOKEN"] =
"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";
process.env["GITHUB_ACTION"] = "__owner___run-repo";
process.env[Events.Key] = event;
process.env[RefKey] = "ref/heads/feature";
const logWarningMock = jest.spyOn(actionUtils, "logWarning");
const response = await actionUtils.deleteCacheByKey(
testUtils.wrongRefCacheKey,
"owner",
"repo"
);
expect(logWarningMock).toHaveBeenCalledWith(
`No cache entries for key ${testUtils.wrongRefCacheKey} belong to gitref ${process.env[RefKey]}.`
);
expect(response).toBe(undefined);
});
test("deleteCacheByKey produces 'HttpError: 404' when cache is not found.", async () => {
const event = Events.Push;
process.env["GITHUB_REPOSITORY"] = "owner/repo";
process.env["GITHUB_TOKEN"] =
"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";
process.env["GITHUB_ACTION"] = "__owner___run-repo";
process.env[Events.Key] = event;
process.env[RefKey] = "ref/heads/feature";
const logWarningMock = jest.spyOn(actionUtils, "logWarning");
const response = await actionUtils.deleteCacheByKey(
testUtils.failureCacheKey,
"owner",
"repo"
);
expect(logWarningMock).toHaveBeenCalledWith(
expect.stringMatching(/404: Not Found/i)
);
expect(response).toBe(undefined);
});
test("deleteCacheByKey produces 'HttpError: 401' on an invalid non-mocked request.", async () => {
const event = Events.Push;
process.env["GITHUB_REPOSITORY"] = "owner/repo";
process.env["GITHUB_TOKEN"] =
"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";
process.env["GITHUB_ACTION"] = "__owner___run-repo";
process.env[Events.Key] = event;
process.env[RefKey] = "ref/heads/feature";
await nock.enableNetConnect();
const logWarningMock = jest.spyOn(actionUtils, "logWarning");
const response = await actionUtils.deleteCacheByKey(
testUtils.passThroughCacheKey,
"owner",
"repo"
);
expect(logWarningMock).toHaveBeenCalledWith(
expect.stringMatching(/401: Bad Credentials/i)
);
expect(response).toBe(undefined);
nock.disableNetConnect();
});
test("deleteCacheByKey returns 204 / No Content when successful.", async () => {
const event = Events.Push;
process.env["GITHUB_REPOSITORY"] = "owner/repo";
process.env["GITHUB_TOKEN"] =
"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";
process.env["GITHUB_ACTION"] = "__owner___run-repo";
process.env[Events.Key] = event;
process.env[RefKey] = "ref/heads/feature";
const logWarningMock = jest.spyOn(actionUtils, "logWarning");
const response = await actionUtils.deleteCacheByKey(
testUtils.successCacheKey,
"owner",
"repo"
);
expect(response).toBe(204);
expect(logWarningMock).toHaveBeenCalledTimes(0);
});
test("isCacheFeatureAvailable for ac enabled", () => {
jest.spyOn(cache, "isFeatureAvailable").mockImplementation(() => true);

View File

@ -1,5 +1,6 @@
import * as cache from "@actions/cache";
import * as core from "@actions/core";
import nock from "nock";
import { Events, RefKey } from "../src/constants";
import { restoreRun } from "../src/restoreImpl";
@ -9,6 +10,7 @@ import * as testUtils from "../src/utils/testUtils";
jest.mock("../src/utils/actionUtils");
beforeAll(() => {
nock.disableNetConnect();
jest.spyOn(actionUtils, "isExactKeyMatch").mockImplementation(
(key, cacheResult) => {
const actualUtils = jest.requireActual("../src/utils/actionUtils");
@ -53,6 +55,10 @@ afterEach(() => {
delete process.env[RefKey];
});
afterAll(() => {
nock.enableNetConnect();
});
test("restore with no cache found", async () => {
const path = "node_modules";
const key = "node-test";

View File

@ -1,5 +1,6 @@
import * as cache from "@actions/cache";
import * as core from "@actions/core";
import nock from "nock";
import { Events, Inputs, RefKey } from "../src/constants";
import { restoreImpl } from "../src/restoreImpl";
@ -10,6 +11,7 @@ import * as testUtils from "../src/utils/testUtils";
jest.mock("../src/utils/actionUtils");
beforeAll(() => {
nock.disableNetConnect();
jest.spyOn(actionUtils, "isExactKeyMatch").mockImplementation(
(key, cacheResult) => {
const actualUtils = jest.requireActual("../src/utils/actionUtils");
@ -54,6 +56,10 @@ afterEach(() => {
delete process.env[RefKey];
});
afterAll(() => {
nock.enableNetConnect();
});
test("restore with invalid event outputs warning", async () => {
const logWarningMock = jest.spyOn(actionUtils, "logWarning");
const failedMock = jest.spyOn(core, "setFailed");

View File

@ -1,5 +1,6 @@
import * as cache from "@actions/cache";
import * as core from "@actions/core";
import nock from "nock";
import { Events, RefKey } from "../src/constants";
import { restoreOnlyRun } from "../src/restoreImpl";
@ -9,6 +10,7 @@ import * as testUtils from "../src/utils/testUtils";
jest.mock("../src/utils/actionUtils");
beforeAll(() => {
nock.disableNetConnect();
jest.spyOn(actionUtils, "isExactKeyMatch").mockImplementation(
(key, cacheResult) => {
const actualUtils = jest.requireActual("../src/utils/actionUtils");
@ -54,6 +56,10 @@ afterEach(() => {
delete process.env[RefKey];
});
afterAll(() => {
nock.enableNetConnect();
});
test("restore with no cache found", async () => {
const path = "node_modules";
const key = "node-test";

View File

@ -1,5 +1,6 @@
import * as cache from "@actions/cache";
import * as core from "@actions/core";
import nock from "nock";
import { Events, Inputs, RefKey } from "../src/constants";
import { saveRun } from "../src/saveImpl";
@ -11,6 +12,7 @@ jest.mock("@actions/cache");
jest.mock("../src/utils/actionUtils");
beforeAll(() => {
nock.disableNetConnect();
jest.spyOn(core, "getInput").mockImplementation((name, options) => {
return jest.requireActual("@actions/core").getInput(name, options);
});
@ -73,10 +75,14 @@ afterEach(() => {
delete process.env[RefKey];
});
afterAll(() => {
nock.enableNetConnect();
});
test("save with valid inputs uploads a cache", async () => {
const failedMock = jest.spyOn(core, "setFailed");
const primaryKey = "Linux-node-bb828da54c148048dd17899ba9fda624811cfb43";
const primaryKey = testUtils.successCacheKey;
const savedCacheKey = "Linux-node-";
jest.spyOn(core, "getState")

View File

@ -1,9 +1,10 @@
import * as cache from "@actions/cache";
import * as core from "@actions/core";
import nock from "nock";
import { Events, Inputs, RefKey } from "../src/constants";
import { saveImpl } from "../src/saveImpl";
import { StateProvider } from "../src/stateProvider";
import { NullStateProvider, StateProvider } from "../src/stateProvider";
import * as actionUtils from "../src/utils/actionUtils";
import * as testUtils from "../src/utils/testUtils";
@ -12,6 +13,19 @@ jest.mock("@actions/cache");
jest.mock("../src/utils/actionUtils");
beforeAll(() => {
nock.disableNetConnect();
testUtils.mockServer.listen({
onUnhandledRequest: "warn"
});
jest.spyOn(actionUtils, "deleteCacheByKey").mockImplementation(
(key: string, owner: string, repo: string) => {
return jest
.requireActual("../src/utils/actionUtils")
.deleteCacheByKey(key, owner, repo);
}
);
jest.spyOn(core, "getInput").mockImplementation((name, options) => {
return jest.requireActual("@actions/core").getInput(name, options);
});
@ -52,6 +66,14 @@ beforeAll(() => {
const actualUtils = jest.requireActual("../src/utils/actionUtils");
return actualUtils.isValidEvent();
});
jest.spyOn(actionUtils, "logWarning").mockImplementation(
(message: string) => {
return jest
.requireActual("../src/utils/actionUtils")
.logWarning(message);
}
);
});
beforeEach(() => {
@ -69,6 +91,13 @@ afterEach(() => {
testUtils.clearInputs();
delete process.env[Events.Key];
delete process.env[RefKey];
delete process.env["GITHUB_TOKEN"];
delete process.env["GITHUB_REPOSITORY"];
});
afterAll(() => {
testUtils.mockServer.close();
nock.enableNetConnect();
});
test("save with invalid event outputs warning", async () => {
@ -88,7 +117,7 @@ test("save with no primary key in state outputs warning", async () => {
const logWarningMock = jest.spyOn(actionUtils, "logWarning");
const failedMock = jest.spyOn(core, "setFailed");
const savedCacheKey = "Linux-node-bb828da54c148048dd17899ba9fda624811cfb43";
const savedCacheKey = testUtils.successCacheKey;
jest.spyOn(core, "getState")
// Cache Entry State
.mockImplementationOnce(() => {
@ -137,7 +166,7 @@ test("save on GHES with AC available", async () => {
jest.spyOn(actionUtils, "isGhes").mockImplementation(() => true);
const failedMock = jest.spyOn(core, "setFailed");
const primaryKey = "Linux-node-bb828da54c148048dd17899ba9fda624811cfb43";
const primaryKey = testUtils.successCacheKey;
const savedCacheKey = "Linux-node-";
jest.spyOn(core, "getState")
@ -179,8 +208,10 @@ test("save on GHES with AC available", async () => {
test("save with exact match returns early", async () => {
const infoMock = jest.spyOn(core, "info");
const failedMock = jest.spyOn(core, "setFailed");
testUtils.setInput(Inputs.RefreshCache, "false");
const primaryKey = testUtils.successCacheKey;
const primaryKey = "Linux-node-bb828da54c148048dd17899ba9fda624811cfb43";
const savedCacheKey = primaryKey;
jest.spyOn(core, "getState")
@ -207,7 +238,7 @@ test("save with missing input outputs warning", async () => {
const logWarningMock = jest.spyOn(actionUtils, "logWarning");
const failedMock = jest.spyOn(core, "setFailed");
const primaryKey = "Linux-node-bb828da54c148048dd17899ba9fda624811cfb43";
const primaryKey = testUtils.successCacheKey;
const savedCacheKey = "Linux-node-";
jest.spyOn(core, "getState")
@ -235,7 +266,7 @@ test("save with large cache outputs warning", async () => {
const logWarningMock = jest.spyOn(actionUtils, "logWarning");
const failedMock = jest.spyOn(core, "setFailed");
const primaryKey = "Linux-node-bb828da54c148048dd17899ba9fda624811cfb43";
const primaryKey = testUtils.successCacheKey;
const savedCacheKey = "Linux-node-";
jest.spyOn(core, "getState")
@ -280,7 +311,7 @@ test("save with reserve cache failure outputs warning", async () => {
const logWarningMock = jest.spyOn(actionUtils, "logWarning");
const failedMock = jest.spyOn(core, "setFailed");
const primaryKey = "Linux-node-bb828da54c148048dd17899ba9fda624811cfb43";
const primaryKey = testUtils.successCacheKey;
const savedCacheKey = "Linux-node-";
jest.spyOn(core, "getState")
@ -327,7 +358,7 @@ test("save with server error outputs warning", async () => {
const logWarningMock = jest.spyOn(actionUtils, "logWarning");
const failedMock = jest.spyOn(core, "setFailed");
const primaryKey = "Linux-node-bb828da54c148048dd17899ba9fda624811cfb43";
const primaryKey = testUtils.successCacheKey;
const savedCacheKey = "Linux-node-";
jest.spyOn(core, "getState")
@ -368,7 +399,7 @@ test("save with server error outputs warning", async () => {
test("save with valid inputs uploads a cache", async () => {
const failedMock = jest.spyOn(core, "setFailed");
const primaryKey = "Linux-node-bb828da54c148048dd17899ba9fda624811cfb43";
const primaryKey = testUtils.successCacheKey;
const savedCacheKey = "Linux-node-";
jest.spyOn(core, "getState")
@ -406,3 +437,179 @@ test("save with valid inputs uploads a cache", async () => {
expect(failedMock).toHaveBeenCalledTimes(0);
});
test("save with cache hit and refresh-cache will try to delete and re-create entry", async () => {
process.env["GITHUB_REPOSITORY"] = "owner/repo";
process.env["GITHUB_TOKEN"] =
"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";
process.env["GITHUB_ACTION"] = "__owner___run-repo";
const infoMock = jest.spyOn(core, "info");
const logWarningMock = jest.spyOn(actionUtils, "logWarning");
const failedMock = jest.spyOn(core, "setFailed");
const primaryKey = testUtils.successCacheKey;
const savedCacheKey = primaryKey;
jest.spyOn(core, "getState")
// Cache Entry State
.mockImplementationOnce(() => {
return savedCacheKey;
})
.mockImplementationOnce(() => {
return primaryKey;
});
const inputPath = "node_modules";
testUtils.setInput(Inputs.RefreshCache, "true");
testUtils.setInput(Inputs.Path, inputPath);
testUtils.setInput(Inputs.UploadChunkSize, "4000000");
const cacheId = 4;
const saveCacheMock = jest
.spyOn(cache, "saveCache")
.mockImplementationOnce(() => {
return Promise.resolve(cacheId);
});
await saveImpl(new StateProvider());
expect(saveCacheMock).toHaveBeenCalledTimes(1);
expect(saveCacheMock).toHaveBeenCalledWith(
[inputPath],
primaryKey,
{
uploadChunkSize: 4000000
},
false
);
expect(logWarningMock).toHaveBeenCalledTimes(0);
expect(infoMock).toHaveBeenCalledTimes(3);
expect(infoMock).toHaveBeenNthCalledWith(
1,
`Cache hit occurred on the primary key ${primaryKey}, attempting to refresh the contents of the cache.`
);
expect(infoMock).toHaveBeenNthCalledWith(
2,
expect.stringMatching(
new RegExp(
`Succesfully deleted cache with key: ${primaryKey}, id: \\d+`
)
)
);
expect(infoMock).toHaveBeenNthCalledWith(
3,
`Cache saved with key: ${primaryKey}`
);
expect(failedMock).toHaveBeenCalledTimes(0);
});
test("Granular save will use lookup to determine if cache needs to be updated or (not) saved.", async () => {
process.env["GITHUB_REPOSITORY"] = "owner/repo";
process.env["GITHUB_TOKEN"] =
"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";
process.env["GITHUB_ACTION"] = "__owner___run-repo";
const infoMock = jest.spyOn(core, "info");
const logWarningMock = jest.spyOn(actionUtils, "logWarning");
const failedMock = jest.spyOn(core, "setFailed");
const primaryKey = testUtils.successCacheKey;
const inputPath = "node_modules";
testUtils.setInput(Inputs.Key, primaryKey);
testUtils.setInput(Inputs.RefreshCache, "true");
testUtils.setInput(Inputs.Path, inputPath);
testUtils.setInput(Inputs.UploadChunkSize, "4000000");
const restoreCacheMock = jest
.spyOn(cache, "restoreCache")
.mockImplementation(() => {
return Promise.resolve(primaryKey);
});
const cacheId = 4;
const saveCacheMock = jest
.spyOn(cache, "saveCache")
.mockImplementationOnce(() => {
return Promise.resolve(cacheId);
});
await saveImpl(new NullStateProvider());
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
expect(restoreCacheMock).toHaveBeenCalledWith(
[inputPath],
primaryKey,
[],
{
lookupOnly: true
},
false
);
expect(saveCacheMock).toHaveBeenCalledTimes(1);
expect(saveCacheMock).toHaveBeenCalledWith(
[inputPath],
primaryKey,
{
uploadChunkSize: 4000000
},
false
);
expect(logWarningMock).toHaveBeenCalledTimes(0);
expect(infoMock).toHaveBeenCalledTimes(3);
expect(infoMock).toHaveBeenNthCalledWith(
1,
`Cache hit occurred on the primary key ${primaryKey}, attempting to refresh the contents of the cache.`
);
expect(infoMock).toHaveBeenNthCalledWith(
2,
expect.stringMatching(
new RegExp(
`Succesfully deleted cache with key: ${primaryKey}, id: \\d+`
)
)
);
expect(infoMock).toHaveBeenNthCalledWith(
3,
`Cache saved with key: ${primaryKey}`
);
expect(failedMock).toHaveBeenCalledTimes(0);
});
test("save with cache hit and refresh-cache will throw a warning if there's no GITHUB_TOKEN", async () => {
const logWarningMock = jest.spyOn(actionUtils, "logWarning");
const failedMock = jest.spyOn(core, "setFailed");
const primaryKey = testUtils.successCacheKey;
const savedCacheKey = primaryKey;
const inputPath = "node_modules";
testUtils.setInput(Inputs.Path, inputPath);
testUtils.setInput(Inputs.RefreshCache, "true");
jest.spyOn(core, "getState")
// Cache Entry State
.mockImplementationOnce(() => {
return savedCacheKey;
})
// Cache Key State
.mockImplementationOnce(() => {
return primaryKey;
});
const saveCacheMock = jest.spyOn(cache, "saveCache");
await saveImpl(new StateProvider());
expect(saveCacheMock).toHaveBeenCalledTimes(0);
expect(logWarningMock).toHaveBeenCalledWith(
`Can't refresh cache, either the repository info or a valid token are missing.`
);
expect(failedMock).toHaveBeenCalledTimes(0);
});

View File

@ -1,5 +1,6 @@
import * as cache from "@actions/cache";
import * as core from "@actions/core";
import nock from "nock";
import { Events, Inputs, RefKey } from "../src/constants";
import { saveOnlyRun } from "../src/saveImpl";
@ -11,6 +12,7 @@ jest.mock("@actions/cache");
jest.mock("../src/utils/actionUtils");
beforeAll(() => {
nock.disableNetConnect();
jest.spyOn(core, "getInput").mockImplementation((name, options) => {
return jest.requireActual("@actions/core").getInput(name, options);
});
@ -73,6 +75,10 @@ afterEach(() => {
delete process.env[RefKey];
});
afterAll(() => {
nock.enableNetConnect();
});
test("save with valid inputs uploads a cache", async () => {
const failedMock = jest.spyOn(core, "setFailed");
@ -105,6 +111,45 @@ test("save with valid inputs uploads a cache", async () => {
expect(failedMock).toHaveBeenCalledTimes(0);
});
test("Granular save with refreshCache is able to save cache", async () => {
process.env["GITHUB_REPOSITORY"] = "owner/repo";
process.env["GITHUB_TOKEN"] =
"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";
process.env["GITHUB_ACTION"] = "__owner___run-repo";
const failedMock = jest.spyOn(core, "setFailed");
const primaryKey = "Linux-node-bb828da54c148048dd17899ba9fda624811cfb43";
const inputPath = "node_modules";
process.env.CACHE_RESTORE_ONLY_MATCHED_KEY = primaryKey;
testUtils.setInput(Inputs.Key, primaryKey);
testUtils.setInput(Inputs.RefreshCache, "true");
testUtils.setInput(Inputs.Path, inputPath);
testUtils.setInput(Inputs.UploadChunkSize, "4000000");
const cacheId = 4;
const saveCacheMock = jest
.spyOn(cache, "saveCache")
.mockImplementationOnce(() => {
return Promise.resolve(cacheId);
});
await saveOnlyRun();
expect(saveCacheMock).toHaveBeenCalledTimes(1);
expect(saveCacheMock).toHaveBeenCalledWith(
[inputPath],
primaryKey,
{
uploadChunkSize: 4000000
},
false
);
expect(failedMock).toHaveBeenCalledTimes(0);
});
test("save failing logs the warning message", async () => {
const warningMock = jest.spyOn(core, "warning");

View File

@ -34,6 +34,10 @@ inputs:
save-always does not work as intended and will be removed in a future release.
A separate `actions/cache/restore` step should be used instead.
See https://github.com/actions/cache/tree/main/save#always-save-cache for more details.
refresh-cache:
description: 'An optional boolean, when enabled it will result in a matched key being deleted after being restored, allowing it to be reused with refreshed/updated content. Default: false'
required: false
default: 'false'
outputs:
cache-hit:
description: 'A boolean value to indicate an exact match was found for the primary key'

View File

@ -12,7 +12,7 @@ This document lists some of the strategies (and example workflows if possible) w
jobs:
build:
runs-on: ubuntu-latest
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
key: ${{ some-metadata }}-cache
```
@ -24,7 +24,7 @@ In your workflows, you can use different strategies to name your key depending o
One of the most common use case is to use hash for lockfile as key. This way, same cache will be restored for a lockfile until there's a change in dependencies listed in lockfile.
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: |
path/to/dependencies
@ -37,7 +37,7 @@ One of the most common use case is to use hash for lockfile as key. This way, sa
If cache is not found matching the primary key, restore keys can be used to download the closest matching cache that was recently created. This ensures that the build/install step will need to additionally fetch just a handful of newer dependencies, and hence saving build time.
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: |
path/to/dependencies
@ -54,7 +54,7 @@ The restore keys can be provided as a complete name, or a prefix, read more [her
In case of workflows with matrix running for multiple Operating Systems, the caches can be stored separately for each of them. This can be used in combination with hashfiles in case multiple caches are being generated per OS.
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: |
path/to/dependencies
@ -73,7 +73,7 @@ Caches scoped to the particular workflow run id or run attempt can be stored and
On similar lines, commit sha can be used to create a very specialized and short lived cache.
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: |
path/to/dependencies
@ -86,7 +86,7 @@ On similar lines, commit sha can be used to create a very specialized and short
Cache key can be formed by combination of more than one metadata, evaluated info.
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: |
path/to/dependencies
@ -146,9 +146,9 @@ In case you are using a centralized job to create and save your cache that can b
```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: actions/cache/restore@v4
- uses: actions/cache/restore@v5
id: cache
with:
path: path/to/dependencies
@ -171,9 +171,9 @@ You can use the output of this action to exit the workflow on cache miss. This w
```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: actions/cache/restore@v4
- uses: actions/cache/restore@v5
id: cache
with:
path: path/to/dependencies
@ -194,7 +194,7 @@ steps:
If you want to avoid re-computing the cache key again in `save` action, the outputs from `restore` action can be used as input to the `save` action.
```yaml
- uses: actions/cache/restore@v4
- uses: actions/cache/restore@v5
id: restore-cache
with:
path: |
@ -204,7 +204,7 @@ If you want to avoid re-computing the cache key again in `save` action, the outp
.
.
.
- uses: actions/cache/save@v4
- uses: actions/cache/save@v5
with:
path: |
path/to/dependencies
@ -219,7 +219,7 @@ On the other hand, the key can also be explicitly re-computed while executing th
Let's say we have a restore step that computes key at runtime
```yaml
uses: actions/cache/restore@v4
uses: actions/cache/restore@v5
id: restore-cache
with:
key: cache-${{ hashFiles('**/lockfiles') }}
@ -228,7 +228,7 @@ with:
Case 1: Where an user would want to reuse the key as it is
```yaml
uses: actions/cache/save@v4
uses: actions/cache/save@v5
with:
key: ${{ steps.restore-cache.outputs.cache-primary-key }}
```
@ -236,7 +236,7 @@ with:
Case 2: Where the user would want to re-evaluate the key
```yaml
uses: actions/cache/save@v4
uses: actions/cache/save@v5
with:
key: npm-cache-${{hashfiles(package-lock.json)}}
```
@ -253,12 +253,12 @@ In case of multi-module projects, where the built artifact of one project needs
```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Build
run: ./build-parent-module.sh
- uses: actions/cache/save@v4
- uses: actions/cache/save@v5
id: cache
with:
path: path/to/dependencies
@ -269,9 +269,9 @@ steps:
```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: actions/cache/restore@v4
- uses: actions/cache/restore@v5
id: cache
with:
path: path/to/dependencies
@ -280,7 +280,7 @@ steps:
- name: Install Dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: ./install.sh
- name: Build
run: ./build-child-module.sh

File diff suppressed because one or more lines are too long

39061
dist/restore/index.js vendored

File diff suppressed because one or more lines are too long

39096
dist/save-only/index.js vendored

File diff suppressed because one or more lines are too long

39096
dist/save/index.js vendored

File diff suppressed because one or more lines are too long

View File

@ -45,7 +45,7 @@
## Bun
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: |
~/.bun/install/cache
@ -55,7 +55,7 @@
### Windows
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: |
~\.bun
@ -67,7 +67,7 @@
Using [NuGet lock files](https://docs.microsoft.com/nuget/consume-packages/package-references-in-project-files#locking-dependencies):
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
@ -76,10 +76,10 @@ Using [NuGet lock files](https://docs.microsoft.com/nuget/consume-packages/packa
```
Depending on the environment, huge packages might be pre-installed in the global cache folder.
With `actions/cache@v4` you can now exclude unwanted packages with [exclude pattern](https://github.com/actions/toolkit/tree/main/packages/glob#exclude-patterns)
From `actions/cache@v3` onwards, you can now exclude unwanted packages with [exclude pattern](https://github.com/actions/toolkit/tree/main/packages/glob#exclude-patterns)
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: |
~/.nuget/packages
@ -96,7 +96,7 @@ Or you could move the cache folder like below.
env:
NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages
steps:
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: ${{ github.workspace }}/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
@ -108,7 +108,7 @@ steps:
```yaml
- name: Cache lein project dependencies
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: ~/.m2/repository
key: ${{ runner.os }}-clojure-${{ hashFiles('**/project.clj') }}
@ -122,7 +122,7 @@ steps:
### POSIX
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: ~/.dub
key: ${{ runner.os }}-dub-${{ hashFiles('**/dub.selections.json') }}
@ -133,7 +133,7 @@ steps:
### Windows
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: ~\AppData\Local\dub
key: ${{ runner.os }}-dub-${{ hashFiles('**/dub.selections.json') }}
@ -146,7 +146,7 @@ steps:
### Linux
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: |
~/.deno
@ -157,7 +157,7 @@ steps:
### macOS
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: |
~/.deno
@ -168,7 +168,7 @@ steps:
### Windows
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: |
~\.deno
@ -179,7 +179,7 @@ steps:
## Elixir - Mix
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: |
deps
@ -191,7 +191,7 @@ steps:
## Erlang - Rebar3
```yaml
- uses: actions/cache@v2
- uses: actions/cache@v5
with:
path: |
~/.cache/rebar3
@ -206,7 +206,7 @@ steps:
### Linux
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: |
~/.cache/go-build
@ -219,7 +219,7 @@ steps:
### macOS
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: |
~/Library/Caches/go-build
@ -232,7 +232,7 @@ steps:
### Windows
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: |
~\AppData\Local\go-build
@ -248,7 +248,7 @@ We cache the elements of the Cabal store separately, as the entirety of `~/.caba
```yaml
- name: Cache ~/.cabal/packages, ~/.cabal/store and dist-newstyle
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: |
~/.cabal/packages
@ -263,14 +263,14 @@ We cache the elements of the Cabal store separately, as the entirety of `~/.caba
### Linux or macOS
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
name: Cache ~/.stack
with:
path: ~/.stack
key: ${{ runner.os }}-stack-global-${{ hashFiles('stack.yaml') }}-${{ hashFiles('package.yaml') }}
restore-keys: |
${{ runner.os }}-stack-global-
- uses: actions/cache@v4
- uses: actions/cache@v5
name: Cache .stack-work
with:
path: .stack-work
@ -282,16 +282,16 @@ We cache the elements of the Cabal store separately, as the entirety of `~/.caba
### Windows
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
name: Cache %APPDATA%\stack %LOCALAPPDATA%\Programs\stack
with:
path: |
~\AppData\Roaming\stack
~\AppData\Local\Programs\stack
~\AppData\Local\Programs\stack
key: ${{ runner.os }}-stack-global-${{ hashFiles('stack.yaml') }}-${{ hashFiles('package.yaml') }}
restore-keys: |
${{ runner.os }}-stack-global-
- uses: actions/cache@v4
- uses: actions/cache@v5
name: Cache .stack-work
with:
path: .stack-work
@ -305,7 +305,7 @@ We cache the elements of the Cabal store separately, as the entirety of `~/.caba
> **Note** Ensure no Gradle daemons are running anymore when your workflow completes. Creating the cache package might fail due to locks being held by Gradle. Refer to the [Gradle Daemon documentation](https://docs.gradle.org/current/userguide/gradle_daemon.html) on how to disable or stop the Gradle Daemons.
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: |
~/.gradle/caches
@ -319,7 +319,7 @@ We cache the elements of the Cabal store separately, as the entirety of `~/.caba
```yaml
- name: Cache local Maven repository
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
@ -355,7 +355,7 @@ After [deprecation](https://github.blog/changelog/2022-10-11-github-actions-depr
`Get npm cache directory` step can then be used with `actions/cache` as shown below
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
id: npm-cache # use this to check for `cache-hit` ==> if: steps.npm-cache.outputs.cache-hit != 'true'
with:
path: ${{ steps.npm-cache-dir.outputs.dir }}
@ -368,7 +368,7 @@ After [deprecation](https://github.blog/changelog/2022-10-11-github-actions-depr
```yaml
- name: restore lerna
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: '**/node_modules'
key: ${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
@ -382,7 +382,7 @@ The yarn cache directory will depend on your operating system and version of `ya
id: yarn-cache-dir-path
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
- uses: actions/cache@v4
- uses: actions/cache@v5
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
@ -400,7 +400,7 @@ The yarn 2 cache directory will depend on your config. See https://yarnpkg.com/c
id: yarn-cache-dir-path
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
- uses: actions/cache@v4
- uses: actions/cache@v5
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
@ -415,7 +415,7 @@ Esy allows you to export built dependencies and import pre-built dependencies.
```yaml
- name: Restore Cache
id: restore-cache
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: _export
key: ${{ runner.os }}-esy-${{ hashFiles('esy.lock/index.json') }}
@ -444,7 +444,7 @@ Esy allows you to export built dependencies and import pre-built dependencies.
id: composer-cache
run: |
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
@ -465,7 +465,7 @@ Locations:
### Simple example
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
@ -478,7 +478,7 @@ Replace `~/.cache/pip` with the correct `path` if not using Ubuntu.
### Multiple OS's in a workflow
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
if: startsWith(runner.os, 'Linux')
with:
path: ~/.cache/pip
@ -486,7 +486,7 @@ Replace `~/.cache/pip` with the correct `path` if not using Ubuntu.
restore-keys: |
${{ runner.os }}-pip-
- uses: actions/cache@v4
- uses: actions/cache@v5
if: startsWith(runner.os, 'macOS')
with:
path: ~/Library/Caches/pip
@ -494,7 +494,7 @@ Replace `~/.cache/pip` with the correct `path` if not using Ubuntu.
restore-keys: |
${{ runner.os }}-pip-
- uses: actions/cache@v4
- uses: actions/cache@v5
if: startsWith(runner.os, 'Windows')
with:
path: ~\AppData\Local\pip\Cache
@ -520,7 +520,7 @@ jobs:
- os: windows-latest
path: ~\AppData\Local\pip\Cache
steps:
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: ${{ matrix.path }}
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
@ -539,7 +539,7 @@ jobs:
echo "dir=$(pip cache dir)" >> $GITHUB_OUTPUT
- name: pip cache
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: ${{ steps.pip-cache.outputs.dir }}
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
@ -553,11 +553,11 @@ jobs:
- name: Set up Python
# The actions/cache step below uses this id to get the exact python version
id: setup-python
uses: actions/setup-python@v2
uses: actions/setup-python@v6
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: ~/.local/share/virtualenvs
key: ${{ runner.os }}-python-${{ steps.setup-python.outputs.python-version }}-pipenv-${{ hashFiles('Pipfile.lock') }}
@ -584,7 +584,7 @@ For renv, the cache directory will vary by OS. The `RENV_PATHS_ROOT` environment
cat("##[set-output name=r-version;]", R.Version()$version.string, sep = "")
shell: Rscript {0}
- name: Restore Renv package cache
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: ${{ env.RENV_PATHS_ROOT }}
key: ${{ steps.get-version.outputs.os-version }}-${{ steps.get-version.outputs.r-version }}-${{ inputs.cache-version }}-${{ hashFiles('renv.lock') }}
@ -610,7 +610,7 @@ whenever possible:
## Rust - Cargo
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: |
~/.cargo/bin/
@ -625,7 +625,7 @@ whenever possible:
```yaml
- name: Cache SBT
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: |
~/.ivy2/cache
@ -636,7 +636,7 @@ whenever possible:
## Swift, Objective-C - Carthage
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: Carthage
key: ${{ runner.os }}-carthage-${{ hashFiles('**/Cartfile.resolved') }}
@ -647,7 +647,7 @@ whenever possible:
## Swift, Objective-C - CocoaPods
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: Pods
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
@ -658,7 +658,7 @@ whenever possible:
## Swift - Swift Package Manager
```yaml
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: .build
key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}
@ -673,7 +673,7 @@ env:
MINT_PATH: .mint/lib
MINT_LINK_PATH: .mint/bin
steps:
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
path: .mint
key: ${{ runner.os }}-mint-${{ hashFiles('**/Mintfile') }}
@ -689,7 +689,7 @@ steps:
```yaml
- name: Cache Bazel
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: |
~/.cache/bazel
@ -703,7 +703,7 @@ steps:
```yaml
- name: Cache Bazel
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: |
/private/var/tmp/_bazel_runner/

View File

@ -1,5 +1,3 @@
require("nock").disableNetConnect();
module.exports = {
clearMocks: true,
moduleFileExtensions: ["js", "ts"],

1449
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,15 @@
{
"name": "cache",
"version": "5.0.2",
"version": "5.0.3",
"private": true,
"description": "Cache dependencies and build outputs",
"main": "dist/restore/index.js",
"scripts": {
"build": "tsc && ncc build -o dist/restore src/restore.ts && ncc build -o dist/save src/save.ts && ncc build -o dist/restore-only src/restoreOnly.ts && ncc build -o dist/save-only src/saveOnly.ts",
"test": "tsc --noEmit && jest --coverage",
"lint": "eslint **/*.ts --cache",
"format": "prettier --write **/*.ts",
"format-check": "prettier --check **/*.ts"
"lint": "eslint src/**/*.ts --cache __tests__/*.ts --cache",
"format": "prettier --write **/**/*.ts",
"format-check": "prettier --check **/**/*.ts"
},
"repository": {
"type": "git",
@ -23,10 +23,11 @@
"author": "GitHub",
"license": "MIT",
"dependencies": {
"@actions/cache": "^5.0.3",
"@actions/core": "^2.0.0",
"@actions/cache": "^5.0.5",
"@actions/core": "^2.0.3",
"@actions/exec": "^2.0.0",
"@actions/io": "^2.0.0"
"@actions/io": "^2.0.0",
"@octokit/action": "^5.0.6"
},
"devDependencies": {
"@types/jest": "^29.5.14",
@ -43,6 +44,7 @@
"eslint-plugin-simple-import-sort": "^12.1.1",
"jest": "^29.7.0",
"jest-circus": "^29.7.0",
"msw": "^1.3.5",
"nock": "^13.2.9",
"prettier": "^3.6.2",
"ts-jest": "^29.4.0",

View File

@ -35,9 +35,9 @@ If you are using separate jobs to create and save your cache(s) to be reused by
```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: actions/cache/restore@v4
- uses: actions/cache/restore@v5
id: cache
with:
path: path/to/dependencies
@ -64,12 +64,12 @@ In case of multi-module projects, where the built artifact of one project needs
```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Build
run: /build-parent-module.sh
- uses: actions/cache/save@v4
- uses: actions/cache/save@v5
id: cache
with:
path: path/to/dependencies
@ -80,9 +80,9 @@ steps:
```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: actions/cache/restore@v4
- uses: actions/cache/restore@v5
id: cache
with:
path: path/to/dependencies
@ -107,9 +107,9 @@ To fail if there is no cache hit for the primary key, leave `restore-keys` empty
```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: actions/cache/restore@v4
- uses: actions/cache/restore@v5
id: cache
with:
path: path/to/dependencies

View File

@ -9,6 +9,11 @@ The save action saves a cache. It works similarly to the `cache` action except t
* `key` - An explicit key for a cache entry. See [creating a cache key](../README.md#creating-a-cache-key).
* `path` - A list of files, directories, and wildcard patterns to cache. See [`@actions/glob`](https://github.com/actions/toolkit/tree/main/packages/glob) for supported patterns.
* `upload-chunk-size` - The chunk size used to split up large files during upload, in bytes
* `refresh-cache` - An optional boolean, when enabled it will result in a matched key being deleted after being restored, allowing it to be reused with refreshed/updated content. Default: false
#### Environment Variables
* `GITHUB_TOKEN` - A Github API token, required for authenticating to the API when the `refresh-cache` option is enabled.
### Outputs
@ -23,7 +28,7 @@ If you are using separate jobs for generating common artifacts and sharing them
```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Install Dependencies
run: /install.sh
@ -31,7 +36,7 @@ steps:
- name: Build artifacts
run: /build.sh
- uses: actions/cache/save@v4
- uses: actions/cache/save@v5
id: cache
with:
path: path/to/dependencies
@ -47,7 +52,7 @@ Let's say we have a restore step that computes a key at runtime.
#### Restore a cache
```yaml
uses: actions/cache/restore@v4
uses: actions/cache/restore@v5
id: restore-cache
with:
key: cache-${{ hashFiles('**/lockfiles') }}
@ -55,7 +60,7 @@ with:
#### Case 1 - Where a user would want to reuse the key as it is
```yaml
uses: actions/cache/save@v4
uses: actions/cache/save@v5
with:
key: ${{ steps.restore-cache.outputs.cache-primary-key }}
```
@ -63,7 +68,7 @@ with:
#### Case 2 - Where the user would want to re-evaluate the key
```yaml
uses: actions/cache/save@v4
uses: actions/cache/save@v5
with:
key: npm-cache-${{hashfiles(package-lock.json)}}
```
@ -91,11 +96,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Restore cached Prime Numbers
id: cache-prime-numbers-restore
uses: actions/cache/restore@v4
uses: actions/cache/restore@v5
with:
key: ${{ runner.os }}-prime-numbers
path: |
@ -107,7 +112,7 @@ jobs:
- name: Always Save Prime Numbers
id: cache-prime-numbers-save
if: always() && steps.cache-prime-numbers-restore.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
uses: actions/cache/save@v5
with:
key: ${{ steps.cache-prime-numbers-restore.outputs.cache-primary-key }}
path: |

View File

@ -15,6 +15,10 @@ inputs:
description: 'An optional boolean when enabled, allows windows runners to save caches that can be restored on other platforms'
default: 'false'
required: false
refresh-cache:
description: 'An optional boolean, when enabled it will result in a matched key being deleted after being restored, allowing it to be reused with refreshed/updated content. Default: false'
required: false
default: 'false'
runs:
using: 'node24'
main: '../dist/save-only/index.js'

View File

@ -5,7 +5,8 @@ export enum Inputs {
UploadChunkSize = "upload-chunk-size", // Input for cache, save action
EnableCrossOsArchive = "enableCrossOsArchive", // Input for cache, restore, save action
FailOnCacheMiss = "fail-on-cache-miss", // Input for cache, restore action
LookupOnly = "lookup-only" // Input for cache, restore action
LookupOnly = "lookup-only", // Input for cache, restore action
RefreshCache = "refresh-cache" // Input for cache, save action
}
export enum Outputs {

View File

@ -82,7 +82,6 @@ export async function restoreImpl(
} else {
core.info(`Cache restored from key: ${cacheKey}`);
}
return cacheKey;
} catch (error: unknown) {
core.setFailed((error as Error).message);

View File

@ -43,15 +43,55 @@ export async function saveImpl(
return;
}
// If matched restore key is same as primary key, then do not save cache
// NO-OP in case of SaveOnly action
const restoredKey = stateProvider.getCacheState();
const refreshCache: boolean = utils.getInputAsBool(
Inputs.RefreshCache,
{ required: false }
);
if (utils.isExactKeyMatch(primaryKey, restoredKey)) {
core.info(
`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`
// If matched restore key is same as primary key, either try to refresh the cache, or just notify and do not save.
let restoredKey = stateProvider.getCacheState();
if (refreshCache && !restoredKey) {
// If getCacheState didn't give us a key, we're likely using granular actions. Do a lookup to see if we need to refresh or just do a regular save.
const cachePaths = utils.getInputAsArray(Inputs.Path, {
required: true
});
const enableCrossOsArchive = utils.getInputAsBool(
Inputs.EnableCrossOsArchive
);
return;
restoredKey = await cache.restoreCache(
cachePaths,
primaryKey,
[],
{ lookupOnly: true },
enableCrossOsArchive
);
}
if (utils.isExactKeyMatch(primaryKey, restoredKey)) {
/* istanbul ignore next */
const { GITHUB_TOKEN, GITHUB_REPOSITORY } = process.env || null;
if (GITHUB_TOKEN && GITHUB_REPOSITORY && refreshCache === true) {
core.info(
`Cache hit occurred on the primary key ${primaryKey}, attempting to refresh the contents of the cache.`
);
const [_owner, _repo] = GITHUB_REPOSITORY.split(`/`);
if (_owner && _repo) {
await utils.deleteCacheByKey(primaryKey, _owner, _repo);
}
} else {
if (refreshCache === true) {
utils.logWarning(
`Can't refresh cache, either the repository info or a valid token are missing.`
);
return;
} else {
core.info(
`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`
);
return;
}
}
}
const cachePaths = utils.getInputAsArray(Inputs.Path, {

View File

@ -1,5 +1,7 @@
import * as cache from "@actions/cache";
import * as core from "@actions/core";
import { Octokit } from "@octokit/action";
import { RequestError } from "@octokit/request-error";
import { RefKey } from "../constants";
@ -30,6 +32,73 @@ export function logWarning(message: string): void {
core.info(`${warningPrefix}${message}`);
}
export async function deleteCacheByKey(
key: string,
owner: string,
repo: string
): Promise<number | void> {
const octokit = new Octokit();
let response;
try {
const gitRef = process.env[RefKey];
const cacheEntry = await octokit.rest.actions.getActionsCacheList({
owner: owner,
repo: repo,
key: key,
ref: gitRef
});
const {
data: { total_count, actions_caches }
} = cacheEntry;
if (total_count !== 1 || total_count !== actions_caches.length) {
// leave all find logic to the actual cache implementation. We just want to make sure we're returned a single element so we don't accidentally delete an entry that belongs to a different gitref.
if (total_count > 1) {
exports.logWarning(
`More than one cache entry found for key ${key}`
);
} else if (total_count === 0 || actions_caches.length === 0) {
exports.logWarning(
`No cache entries for key ${key} belong to gitref ${gitRef}.`
);
}
// This situation is likely never actually going to come up.
// Istanbul is being dumb and I can't ignore this path.
else if (total_count !== actions_caches.length) {
exports.logWarning(
`Reported cache entry matches for ${key} does not match length of 'actions_caches' array in API response.`
);
}
core.info(`Skip trying to delete cache entry for key ${key}.`);
return;
}
const id = actions_caches[0].id;
if (id) {
response = await octokit.rest.actions.deleteActionsCacheById({
owner: owner,
repo: repo,
cache_id: id
});
if (response.status === 204) {
core.info(
`Succesfully deleted cache with key: ${key}, id: ${id}`
);
return 204;
}
}
} catch (e) {
if (e instanceof RequestError) {
const err = e as RequestError;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const errMessage = (err.response?.data as any).message;
exports.logWarning(
`Github API reported error: ${err.name} '${err.status}: ${errMessage}'`
);
}
core.info(`Couldn't delete cache entry for key ${key}.`);
return;
}
}
// Cache token authorized for all events that are tied to a ref
// See GitHub Context https://help.github.com/actions/automating-your-workflow-with-github-actions/contexts-and-expression-syntax-for-github-actions#github-context
export function isValidEvent(): boolean {

View File

@ -1,5 +1,21 @@
/* istanbul ignore file */
import { rest } from "msw";
import { setupServer } from "msw/node";
import { Inputs } from "../constants";
export const successCacheKey =
"Linux-node-bb828da54c148048dd17899ba9fda624811cfb43";
export const wrongRefCacheKey =
"Linux-latest-node-bb828da54c148048dd17899ba9fda624811cfb43";
export const failureCacheKey =
"Windows-node-bb828da54c148048dd17899ba9fda624811cfb43";
export const passThroughCacheKey =
"macOS-node-bb828da54c148048dd17899ba9fda624811cfb43";
const successCacheId = 1337;
const failureCacheId = 69;
// See: https://github.com/actions/toolkit/blob/master/packages/core/src/core.ts#L67
function getInputName(name: string): string {
return `INPUT_${name.replace(/ /g, "_").toUpperCase()}`;
@ -16,6 +32,7 @@ interface CacheInput {
enableCrossOsArchive?: boolean;
failOnCacheMiss?: boolean;
lookupOnly?: boolean;
refreshCache?: boolean;
}
export function setInputs(input: CacheInput): void {
@ -32,6 +49,8 @@ export function setInputs(input: CacheInput): void {
setInput(Inputs.FailOnCacheMiss, input.failOnCacheMiss.toString());
input.lookupOnly !== undefined &&
setInput(Inputs.LookupOnly, input.lookupOnly.toString());
input.refreshCache !== undefined &&
setInput(Inputs.RefreshCache, input.refreshCache.toString());
}
export function clearInputs(): void {
@ -42,4 +61,113 @@ export function clearInputs(): void {
delete process.env[getInputName(Inputs.EnableCrossOsArchive)];
delete process.env[getInputName(Inputs.FailOnCacheMiss)];
delete process.env[getInputName(Inputs.LookupOnly)];
delete process.env[getInputName(Inputs.RefreshCache)];
}
export const mockServer = setupServer(
rest.delete(
"https://api.github.com/repos/owner/repo/actions/caches/",
(req, res, ctx) => {
return res(
ctx.status(422),
ctx.json({
message:
"Invalid request.\n\nMissing required query parameter key",
documentation_url:
"https://docs.github.com/rest/actions/cache#delete-github-actions-caches-for-a-repository-using-a-cache-key"
})
);
}
),
rest.delete(
"https://api.github.com/repos/owner/repo/actions/caches/:id",
(req, res, ctx) => {
const { id } = req.params;
if (parseInt(id as string) === failureCacheId) {
return res(
ctx.status(404),
ctx.json({
message: "Not Found",
documentation_url:
"https://docs.github.com/rest/actions/cache#delete-a-github-actions-cache-for-a-repository-using-a-cache-id"
})
);
}
return res(ctx.status(204));
}
),
// This endpoint always returns 200/OK, what we're checking here is whether we can get a unique cache ID, to avoid deleting the wrong entry.
rest.get(
"https://api.github.com/repos/owner/repo/actions/caches",
(req, res, ctx) => {
const key: string = req.url?.searchParams?.get("key") || "";
const ref: string = req.url?.searchParams?.get("ref") || "";
if (key === "" || ref === "") {
return res(
ctx.status(200),
ctx.json({
total_count: 2,
actions_caches: [
{
id: 15,
ref: "refs/heads/main",
key: failureCacheKey,
version:
"73885106f58cc52a7df9ec4d4a5622a5614813162cb516c759a30af6bf56e6f0",
last_accessed_at:
"2022-12-29T22:06:42.683333300Z",
created_at: "2022-12-29T22:06:42.683333300Z",
size_in_bytes: 6057793
},
{
id: 16,
ref: "refs/heads/another-feature-branch",
key: failureCacheKey,
version:
"73885106f58cc52a7df9ec4d4a5622a5614813162cb516c759a30af6bf56e6f0",
last_accessed_at:
"2022-12-29T22:06:42.683333300Z",
created_at: "2022-12-29T22:06:42.683333300Z",
size_in_bytes: 6057793
}
]
})
);
}
// This is the behavior seen when search doesn't find anything, but it is seen both when no key matches, as well as when the key matches but the entry belongs to another (likely the base) branch.
else if (key === wrongRefCacheKey) {
return res(
ctx.status(200),
ctx.json({
total_count: 0,
actions_caches: []
})
);
} else if (key === successCacheKey || key === failureCacheKey) {
return res(
ctx.status(200),
ctx.json({
total_count: 1,
actions_caches: [
{
id:
key === successCacheKey
? successCacheId
: failureCacheId,
ref: ref,
key: key,
version:
"93a0f912fdb70083e929c1bf564bca2050be1c4e0932f7f9e78465ddcfbcc8f6",
last_accessed_at:
"2022-12-29T22:06:42.683333300Z",
created_at: "2022-12-29T22:06:42.683333300Z",
size_in_bytes: 6057793
}
]
})
);
}
return req.passthrough();
}
)
);

View File

@ -12,7 +12,7 @@ A cache today is immutable and cannot be updated. But some use cases require the
```yaml
- name: update cache on every commit
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: prime-numbers
key: primes-${{ runner.os }}-${{ github.run_id }} # Can use time based key as well
@ -21,7 +21,9 @@ A cache today is immutable and cannot be updated. But some use cases require the
```
Please note that this will create a new cache on every run and hence will consume the cache [quota](./README.md#cache-limits).
As a way to get around this limitation, the `refresh-cache` option exists. The way this works is, after matching a key and restoring a cache, it makes a request directly to the Github API and deletes the contents of that cache entry, then leaving said key free to be updated.
- Note, however, that this requires the `actions: write` permission on your workflow.
## Use cache across feature branches
Reusing cache across feature branches is not allowed today to provide cache [isolation](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#restrictions-for-accessing-a-cache). However if both feature branches are from the default branch, a good way to achieve this is to ensure that the default branch has a cache. This cache will then be consumable by both feature branches.