Compare commits
330 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cf5677ba88 | |||
| 830c827471 | |||
| ffae274475 | |||
| 1c20378379 | |||
| 0be0a6ef89 | |||
| ae29a2751b | |||
| b48854e1ac | |||
| 9d912b1840 | |||
| 7a0147b5c6 | |||
| 5793b08cd9 | |||
| ed3ea3b5ba | |||
| c9c663babe | |||
| 0fc1805b46 | |||
| a6e9f4bab2 | |||
| 758b556388 | |||
| 9e060cb3e1 | |||
| 5501ba08b7 | |||
| 4446f00fc7 | |||
| 965dcc7493 | |||
| d464f9dd60 | |||
| c9ab4f9548 | |||
| a2986ee511 | |||
| e827417593 | |||
| b05d26b3fa | |||
| ecdfc18bf2 | |||
| e8e0ce7ad8 | |||
| dc6427f3c3 | |||
| 76339b5f68 | |||
| c0ef67ec49 | |||
| 968fd7f8d3 | |||
| 9b27fa97f9 | |||
| 065cf9f0b1 | |||
| b77f226465 | |||
| f61ae48376 | |||
| 4236fc3e78 | |||
| f366966232 | |||
| bd561a6765 | |||
| 26490f0d3b | |||
| ee91adfbc4 | |||
| a039cff4a1 | |||
| 9dd77993e7 | |||
| dd1bb93c72 | |||
| 7292b3508f | |||
| 4a47af6481 | |||
| a68693e20a | |||
| acf4bd70fb | |||
| 7ae5c2f423 | |||
| d5470e6023 | |||
| e68ab4b91a | |||
| d3a48dd52f | |||
| c4d47c1922 | |||
| 5fc5cdde44 | |||
| 2a9d836b08 | |||
| 3a3b073ef2 | |||
| d3a0fb260e | |||
| be4fdc505f | |||
| 6be37922c5 | |||
| dfc20acda2 | |||
| dc1fec82a6 | |||
| 9339b3573b | |||
| 67a08de5c7 | |||
| d73fffceed | |||
| 16f0b3d28e | |||
| 398e2cb68b | |||
| 4b9031fa77 | |||
| 959cb66bd5 | |||
| 3e0b611f99 | |||
| 83c13c81ba | |||
| bccbba401a | |||
| 3a191eecf6 | |||
| 97f5a6f0dc | |||
| 48a7cdbf9c | |||
| 3f1933edf9 | |||
| 2215c8e5aa | |||
| af6de2cb95 | |||
| 1dc58e3080 | |||
| 20596c1d96 | |||
| 557f80fd03 | |||
| 32c52bb78a | |||
| 6d9a3fe547 | |||
| 4e1c194b34 | |||
| 09cb71a033 | |||
| 2506e78e82 | |||
| f8003d52ff | |||
| e263dfb89d | |||
| 2e53bd8485 | |||
| b5e3b25b34 | |||
| b71834a510 | |||
| c6f0239e63 | |||
| c655f38a0f | |||
| cf8caa4e0d | |||
| 8734e578c6 | |||
| 74ac6db523 | |||
| 6fc2f678c8 | |||
| 5ef62e14dd | |||
| 7b29e67278 | |||
| 9d2227dbb0 | |||
| 5a8462ec27 | |||
| fcaf488df6 | |||
| 2b48e40e62 | |||
| 44ec738e27 | |||
| 3af0128b01 | |||
| e74405f68c | |||
| cc6abe3c3a | |||
| c6502bc679 | |||
| bdd6eb4293 | |||
| 6785788751 | |||
| ddf2d52556 | |||
| 7c1b12a15e | |||
| fdbf9e3ec2 | |||
| 369aa55cdc | |||
| e1191599bb | |||
| c043714a35 | |||
| 3ac6e0fdf2 | |||
| d9f9074fee | |||
| 2c52220624 | |||
| b2e6a5a284 | |||
| e48877e66c | |||
| bdddd872e3 | |||
| 8a2701f328 | |||
| eb7ff8401e | |||
| 45ec4a2087 | |||
| 02869fefb4 | |||
| 701191f50e | |||
| 539724611c | |||
| 3d01d7ed69 | |||
| d75223fd4a | |||
| 056c217a52 | |||
| d795a0ad0d | |||
| b0464628c0 | |||
| 0380590fdd | |||
| 5e183dabac | |||
| 97b7fa81c8 | |||
| 87afd16bb2 | |||
| c40fa0d905 | |||
| dc9f635a0d | |||
| 7847d31696 | |||
| 10d3b034e0 | |||
| 8eca440361 | |||
| 6ec87f46b7 | |||
| d1f9584cda | |||
| b8933d0495 | |||
| 0a988d204e | |||
| 136f9dfe37 | |||
| ed78411ffb | |||
| dd097c7f4e | |||
| f01262913d | |||
| c034e76488 | |||
| 9ca26d4946 | |||
| 417dbfff73 | |||
| 8883833d6d | |||
| 79efd648ac | |||
| e8c242695d | |||
| 48f166f6d5 | |||
| 4bc377e1b4 | |||
| bf1b64008f | |||
| 894f77901e | |||
| 7993066184 | |||
| f014075da9 | |||
| 4500de75c1 | |||
| 47017fa24b | |||
| d97deb1f60 | |||
| df111e1104 | |||
| a3588a70ba | |||
| 6b63a2bfc3 | |||
| 290017ff81 | |||
| 2a876cd69d | |||
| 7cba4c8084 | |||
| f79b906406 | |||
| 1bcc453b44 | |||
| dcae869a03 | |||
| 23769d04c7 | |||
| d3ab50471b | |||
| 1388fd1cac | |||
| 5b446d2657 | |||
| 006d6978c1 | |||
| 02afeb1577 | |||
| d47594b536 | |||
| 2823824b94 | |||
| cbc06d6766 | |||
| 9bb6708527 | |||
| be1151df02 | |||
| 130842f4e8 | |||
| ab82301c62 | |||
| fea4f6b5c5 | |||
| d3ade9ecfc | |||
| fb592eec03 | |||
| 70e79399a2 | |||
| acb230b99a | |||
| 5e0fa1aaaa | |||
| ac2468e605 | |||
| 3c8fcfce19 | |||
| 45467b9199 | |||
| 700a55077d | |||
| 6fa8f07827 | |||
| d16e86a709 | |||
| ae3ac0db0c | |||
| b319d6afff | |||
| b8ac8fc14a | |||
| 028d621193 | |||
| b0d901f9c2 | |||
| 394e804dc8 | |||
| d402248c45 | |||
| 66e8437b3e | |||
| 9c7501a5f3 | |||
| 3b4b5725f0 | |||
| 9a364e607b | |||
| 625c3f4856 | |||
| 1c3a637017 | |||
| ec0ca1b19b | |||
| 57cd003e61 | |||
| b5befc6c6d | |||
| 88a490d2ce | |||
| a8d1fb0687 | |||
| 347c887e54 | |||
| d5af54ee78 | |||
| 44b9401378 | |||
| fb5ae2a0e0 | |||
| 8024983ab0 | |||
| d44f9b8f13 | |||
| 9b4ee219ef | |||
| ee5d8970ad | |||
| 2874e3a741 | |||
| ad4afeeff1 | |||
| f9bdf6a054 | |||
| 59c7ebde79 | |||
| 0c907a43d3 | |||
| d1c1fc4108 | |||
| 36f30e6d37 | |||
| 308e05bc50 | |||
| 33a9b6c09c | |||
| ddc5fa4ae8 | |||
| 9b08f07cd3 | |||
| d26e9423f4 | |||
| 714f93aedc | |||
| 844423665b | |||
| f2ba502b92 | |||
| 1db3130eb3 | |||
| ca8a35d78f | |||
| f7f057193f | |||
| 8e146e124e | |||
| 1ea77a84d7 | |||
| 7da95b182e | |||
| 7c689a5156 | |||
| 8c6c662cda | |||
| 3898ed70c4 | |||
| 9a41b33065 | |||
| 7aea3e735f | |||
| b1eb18b224 | |||
| 48e42b1fdd | |||
| b738f10ef3 | |||
| 8f32f385e0 | |||
| 011f07d1dc | |||
| aa7077acfb | |||
| 86207b5042 | |||
| 523ce8ccda | |||
| f58042f9cc | |||
| 091616a0b8 | |||
| 8da1e670b6 | |||
| 06f7fd9df1 | |||
| 0fe20e9d56 | |||
| f82db4c00b | |||
| b8cca0c71f | |||
| 6f0cb0c45e | |||
| 944ede4d09 | |||
| 227b1ce741 | |||
| 447ee85f36 | |||
| a6be3de743 | |||
| 26b94036cb | |||
| f3e6fb165e | |||
| 3a607d0f00 | |||
| c9316bb4a7 | |||
| ec43e5810d | |||
| 01715621b0 | |||
| 6c64260c6d | |||
| bf3fc9226a | |||
| c6723084aa | |||
| bcb928642f | |||
| 8c3fc9ed99 | |||
| 1ef3214cee | |||
| ece2273b24 | |||
| 717b895584 | |||
| 8ff772deb1 | |||
| 8a3652e16d | |||
| eb6226501b | |||
| d65ee66d9b | |||
| 6d3feab2bf | |||
| 79e1d8bb74 | |||
| a0907ed2e2 | |||
| bd54a2413a | |||
| 89397db14b | |||
| d48d6b62a4 | |||
| bab3dcf7f3 | |||
| c51178a15e | |||
| bbc6082700 | |||
| cf3aaeb491 | |||
| cf4886cccb | |||
| 0c5da92b52 | |||
| 513216f1dd | |||
| 3c90578c30 | |||
| be5a2ce677 | |||
| 683703c114 | |||
| c28e7d4d5f | |||
| 12e323ae30 | |||
| dbb1ea35ff | |||
| f31c2921c1 | |||
| 41b3ce3141 | |||
| 8d8a914a94 | |||
| 36db4d62ad | |||
| a25b686a45 | |||
| 957610a37a | |||
| 6ed621e7d1 | |||
| 8007c1c535 | |||
| 6444290c57 | |||
| f32d6bc043 | |||
| 2e4ab87130 | |||
| ef199a9ab0 | |||
| 917a43eb6e | |||
| 07cac0a6b3 | |||
| 2046ee6d6b | |||
| 2b476323c4 | |||
| aebe304a19 | |||
| e8f276a715 | |||
| d156bcaa78 | |||
| 5ae4c5be28 | |||
| d50f1ac1b9 | |||
| 87cb7035bb | |||
| 1b1e81526b | |||
| 525ebf0c50 | |||
| 07341e11d8 |
@@ -0,0 +1,27 @@
|
|||||||
|
# To get started with Dependabot version updates, you'll need to specify which
|
||||||
|
# package ecosystems to update and where the package manifests are located.
|
||||||
|
# Please see the documentation for all configuration options:
|
||||||
|
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "npm"
|
||||||
|
directory: "/packages/artifact"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
groups:
|
||||||
|
# Group minor and patch updates together but keep major separate
|
||||||
|
artifact-minor-patch:
|
||||||
|
update-types:
|
||||||
|
- "minor"
|
||||||
|
- "patch"
|
||||||
|
- package-ecosystem: "npm"
|
||||||
|
directory: "/packages/cache"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
groups:
|
||||||
|
# Group minor and patch updates together but keep major separate
|
||||||
|
cache-minor-patch:
|
||||||
|
update-types:
|
||||||
|
- "minor"
|
||||||
|
- "patch"
|
||||||
@@ -22,12 +22,12 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Set Node.js 20.x
|
- name: Set Node.js 24.x
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v5
|
||||||
with:
|
with:
|
||||||
node-version: 20.x
|
node-version: 24.x
|
||||||
|
|
||||||
# Need root node_modules because certain npm packages like jest are configured for the entire repository and it won't be possible
|
# Need root node_modules because certain npm packages like jest are configured for the entire repository and it won't be possible
|
||||||
# without these to just compile the artifacts package
|
# without these to just compile the artifacts package
|
||||||
@@ -47,7 +47,7 @@ jobs:
|
|||||||
echo -n 'hello from file 2' > artifact-path/second.txt
|
echo -n 'hello from file 2' > artifact-path/second.txt
|
||||||
|
|
||||||
- name: Upload Artifacts
|
- name: Upload Artifacts
|
||||||
uses: actions/github-script@v7
|
uses: actions/github-script@v8
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const {default: artifact} = require('./packages/artifact/lib/artifact')
|
const {default: artifact} = require('./packages/artifact/lib/artifact')
|
||||||
@@ -77,12 +77,12 @@ jobs:
|
|||||||
needs: [upload]
|
needs: [upload]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Set Node.js 20.x
|
- name: Set Node.js 24.x
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v5
|
||||||
with:
|
with:
|
||||||
node-version: 20.x
|
node-version: 24.x
|
||||||
|
|
||||||
# Need root node_modules because certain npm packages like jest are configured for the entire repository and it won't be possible
|
# Need root node_modules because certain npm packages like jest are configured for the entire repository and it won't be possible
|
||||||
# without these to just compile the artifacts package
|
# without these to just compile the artifacts package
|
||||||
@@ -96,7 +96,7 @@ jobs:
|
|||||||
working-directory: packages/artifact
|
working-directory: packages/artifact
|
||||||
|
|
||||||
- name: List and Download Artifacts
|
- name: List and Download Artifacts
|
||||||
uses: actions/github-script@v7
|
uses: actions/github-script@v8
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const {default: artifactClient} = require('./packages/artifact/lib/artifact')
|
const {default: artifactClient} = require('./packages/artifact/lib/artifact')
|
||||||
@@ -165,7 +165,7 @@ jobs:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
- name: Delete Artifacts
|
- name: Delete Artifacts
|
||||||
uses: actions/github-script@v7
|
uses: actions/github-script@v8
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const {default: artifactClient} = require('./packages/artifact/lib/artifact')
|
const {default: artifactClient} = require('./packages/artifact/lib/artifact')
|
||||||
|
|||||||
@@ -18,12 +18,12 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Set Node.js 20.x
|
- name: Set Node.js 24.x
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v5
|
||||||
with:
|
with:
|
||||||
node-version: 20.x
|
node-version: 24.x
|
||||||
|
|
||||||
- name: npm install
|
- name: npm install
|
||||||
run: npm install
|
run: npm install
|
||||||
|
|||||||
@@ -22,12 +22,12 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Set Node.js 20.x
|
- name: Set Node.js 24.x
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v5
|
||||||
with:
|
with:
|
||||||
node-version: 20.x
|
node-version: 24.x
|
||||||
|
|
||||||
# In order to save & restore cache from a shell script, certain env variables need to be set that are only available in the
|
# In order to save & restore cache from a shell script, certain env variables need to be set that are only available in the
|
||||||
# node context. This runs a local action that gets and sets the necessary env variables that are needed
|
# node context. This runs a local action that gets and sets the necessary env variables that are needed
|
||||||
@@ -39,9 +39,11 @@ jobs:
|
|||||||
- name: Install root npm packages
|
- name: Install root npm packages
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
||||||
|
# We need to install only runtime dependencies (omit dev dependencies) to verify that what we're shipping is all
|
||||||
|
# that is needed
|
||||||
- name: Compile cache package
|
- name: Compile cache package
|
||||||
run: |
|
run: |
|
||||||
npm ci
|
npm ci --omit=dev
|
||||||
npm run tsc
|
npm run tsc
|
||||||
working-directory: packages/cache
|
working-directory: packages/cache
|
||||||
|
|
||||||
@@ -53,10 +55,8 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
run: packages/cache/__tests__/create-cache-files.sh ${{ runner.os }} ~/test-cache
|
run: packages/cache/__tests__/create-cache-files.sh ${{ runner.os }} ~/test-cache
|
||||||
|
|
||||||
# We're using node -e to call the functions directly available in the @actions/cache package
|
|
||||||
- name: Save cache using saveCache()
|
- name: Save cache using saveCache()
|
||||||
run: |
|
run: node packages/cache/__tests__/save-cache.mjs ${{ runner.os }} ${{ github.run_id }}
|
||||||
node -e "Promise.resolve(require('./packages/cache/lib/cache').saveCache(['test-cache','~/test-cache'],'test-${{ runner.os }}-${{ github.run_id }}'))"
|
|
||||||
|
|
||||||
- name: Delete cache folders before restoring
|
- name: Delete cache folders before restoring
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -65,8 +65,7 @@ jobs:
|
|||||||
rm -rf ~/test-cache
|
rm -rf ~/test-cache
|
||||||
|
|
||||||
- name: Restore cache using restoreCache() with http-client
|
- name: Restore cache using restoreCache() with http-client
|
||||||
run: |
|
run: node packages/cache/__tests__/restore-cache.mjs ${{ runner.os }} ${{ github.run_id }} false
|
||||||
node -e "Promise.resolve(require('./packages/cache/lib/cache').restoreCache(['test-cache','~/test-cache'],'test-${{ runner.os }}-${{ github.run_id }}',[],{useAzureSdk: false}))"
|
|
||||||
|
|
||||||
- name: Verify cache restored with http-client
|
- name: Verify cache restored with http-client
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -81,8 +80,7 @@ jobs:
|
|||||||
rm -rf ~/test-cache
|
rm -rf ~/test-cache
|
||||||
|
|
||||||
- name: Restore cache using restoreCache() with Azure SDK
|
- name: Restore cache using restoreCache() with Azure SDK
|
||||||
run: |
|
run: node packages/cache/__tests__/restore-cache.mjs ${{ runner.os }} ${{ github.run_id }} true
|
||||||
node -e "Promise.resolve(require('./packages/cache/lib/cache').restoreCache(['test-cache','~/test-cache'],'test-${{ runner.os }}-${{ github.run_id }}'))"
|
|
||||||
|
|
||||||
- name: Verify cache restored with Azure SDK
|
- name: Verify cache restored with Azure SDK
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|||||||
@@ -17,16 +17,16 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- shell: bash
|
- shell: bash
|
||||||
run: |
|
run: |
|
||||||
rm "C:\Program Files\Git\usr\bin\tar.exe"
|
rm "C:\Program Files\Git\usr\bin\tar.exe"
|
||||||
|
|
||||||
- name: Set Node.js 20.x
|
- name: Set Node.js 24.x
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v5
|
||||||
with:
|
with:
|
||||||
node-version: 20.x
|
node-version: 24.x
|
||||||
|
|
||||||
# In order to save & restore cache from a shell script, certain env variables need to be set that are only available in the
|
# In order to save & restore cache from a shell script, certain env variables need to be set that are only available in the
|
||||||
# node context. This runs a local action that gets and sets the necessary env variables that are needed
|
# node context. This runs a local action that gets and sets the necessary env variables that are needed
|
||||||
@@ -52,10 +52,8 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
run: packages/cache/__tests__/create-cache-files.sh ${{ runner.os }} ~/test-cache
|
run: packages/cache/__tests__/create-cache-files.sh ${{ runner.os }} ~/test-cache
|
||||||
|
|
||||||
# We're using node -e to call the functions directly available in the @actions/cache package
|
|
||||||
- name: Save cache using saveCache()
|
- name: Save cache using saveCache()
|
||||||
run: |
|
run: node packages/cache/__tests__/save-cache.mjs ${{ runner.os }} ${{ github.run_id }}
|
||||||
node -e "Promise.resolve(require('./packages/cache/lib/cache').saveCache(['test-cache','~/test-cache'],'test-${{ runner.os }}-${{ github.run_id }}'))"
|
|
||||||
|
|
||||||
- name: Delete cache folders before restoring
|
- name: Delete cache folders before restoring
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -64,8 +62,7 @@ jobs:
|
|||||||
rm -rf ~/test-cache
|
rm -rf ~/test-cache
|
||||||
|
|
||||||
- name: Restore cache using restoreCache() with http-client
|
- name: Restore cache using restoreCache() with http-client
|
||||||
run: |
|
run: node packages/cache/__tests__/restore-cache.mjs ${{ runner.os }} ${{ github.run_id }} false
|
||||||
node -e "Promise.resolve(require('./packages/cache/lib/cache').restoreCache(['test-cache','~/test-cache'],'test-${{ runner.os }}-${{ github.run_id }}',[],{useAzureSdk: false}))"
|
|
||||||
|
|
||||||
- name: Verify cache restored with http-client
|
- name: Verify cache restored with http-client
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -80,8 +77,7 @@ jobs:
|
|||||||
rm -rf ~/test-cache
|
rm -rf ~/test-cache
|
||||||
|
|
||||||
- name: Restore cache using restoreCache() with Azure SDK
|
- name: Restore cache using restoreCache() with Azure SDK
|
||||||
run: |
|
run: node packages/cache/__tests__/restore-cache.mjs ${{ runner.os }} ${{ github.run_id }} true
|
||||||
node -e "Promise.resolve(require('./packages/cache/lib/cache').restoreCache(['test-cache','~/test-cache'],'test-${{ runner.os }}-${{ github.run_id }}'))"
|
|
||||||
|
|
||||||
- name: Verify cache restored with Azure SDK
|
- name: Verify cache restored with Azure SDK
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
|
|||||||
@@ -28,15 +28,15 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: setup repo
|
- name: setup repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: verify package exists
|
- name: verify package exists
|
||||||
run: ls packages/${{ github.event.inputs.package }}
|
run: ls packages/${{ github.event.inputs.package }}
|
||||||
|
|
||||||
- name: Set Node.js 20.x
|
- name: Set Node.js 24.x
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v5
|
||||||
with:
|
with:
|
||||||
node-version: 20.x
|
node-version: 24.x
|
||||||
|
|
||||||
- name: npm install
|
- name: npm install
|
||||||
run: npm install
|
run: npm install
|
||||||
@@ -69,16 +69,16 @@ jobs:
|
|||||||
id-token: write
|
id-token: write
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
|
- name: Set Node.js 24.x
|
||||||
|
uses: actions/setup-node@v5
|
||||||
|
with:
|
||||||
|
node-version: 24.x
|
||||||
|
|
||||||
- name: download artifact
|
- name: download artifact
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ github.event.inputs.package }}
|
name: ${{ github.event.inputs.package }}
|
||||||
|
|
||||||
- name: setup authentication
|
|
||||||
run: echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" >> .npmrc
|
|
||||||
env:
|
|
||||||
NPM_TOKEN: ${{ secrets.TOKEN }}
|
|
||||||
|
|
||||||
- name: publish
|
- name: publish
|
||||||
run: npm publish --provenance *.tgz
|
run: npm publish --provenance *.tgz
|
||||||
|
|
||||||
|
|||||||
@@ -18,19 +18,19 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
runs-on: [ubuntu-latest, macos-latest-large, windows-latest]
|
runs-on: [ubuntu-latest, macos-latest-large, windows-latest]
|
||||||
|
|
||||||
# Node 18 is the current default Node version in hosted runners, so users may still use the toolkit with it when running tests (see https://github.com/actions/toolkit/issues/1841)
|
# Node 20 is the currently supported stable Node version for actions - https://docs.github.com/actions/sharing-automations/creating-actions/metadata-syntax-for-github-actions#runsusing-for-javascript-actions
|
||||||
# Node 20 is the currently support Node version for actions - https://docs.github.com/actions/sharing-automations/creating-actions/metadata-syntax-for-github-actions#runsusing-for-javascript-actions
|
# Node 24 is the new version being added with support in actions runners
|
||||||
node-version: [18.x, 20.x]
|
node-version: [20.x, 24.x]
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
|
||||||
runs-on: ${{ matrix.runs-on }}
|
runs-on: ${{ matrix.runs-on }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Set up Node ${{ matrix.node-version }}
|
- name: Set up Node ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v5
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ jobs:
|
|||||||
if: ${{ github.repository_owner == 'actions' }}
|
if: ${{ github.repository_owner == 'actions' }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
- name: Update Octokit
|
- name: Update Octokit
|
||||||
working-directory: packages/github
|
working-directory: packages/github
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ The GitHub Actions ToolKit provides a set of packages to make creating actions e
|
|||||||
Provides functions for inputs, outputs, results, logging, secrets and variables. Read more [here](packages/core)
|
Provides functions for inputs, outputs, results, logging, secrets and variables. Read more [here](packages/core)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ npm install @actions/core
|
npm install @actions/core
|
||||||
```
|
```
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ $ npm install @actions/core
|
|||||||
Provides functions to exec cli tools and process output. Read more [here](packages/exec)
|
Provides functions to exec cli tools and process output. Read more [here](packages/exec)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ npm install @actions/exec
|
npm install @actions/exec
|
||||||
```
|
```
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ $ npm install @actions/exec
|
|||||||
Provides functions to search for files matching glob patterns. Read more [here](packages/glob)
|
Provides functions to search for files matching glob patterns. Read more [here](packages/glob)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ npm install @actions/glob
|
npm install @actions/glob
|
||||||
```
|
```
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ $ npm install @actions/glob
|
|||||||
A lightweight HTTP client optimized for building actions. Read more [here](packages/http-client)
|
A lightweight HTTP client optimized for building actions. Read more [here](packages/http-client)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ npm install @actions/http-client
|
npm install @actions/http-client
|
||||||
```
|
```
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ $ npm install @actions/http-client
|
|||||||
Provides disk i/o functions like cp, mv, rmRF, which etc. Read more [here](packages/io)
|
Provides disk i/o functions like cp, mv, rmRF, which etc. Read more [here](packages/io)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ npm install @actions/io
|
npm install @actions/io
|
||||||
```
|
```
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ Provides functions for downloading and caching tools. e.g. setup-* actions. Rea
|
|||||||
See @actions/cache for caching workflow dependencies.
|
See @actions/cache for caching workflow dependencies.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ npm install @actions/tool-cache
|
npm install @actions/tool-cache
|
||||||
```
|
```
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ $ npm install @actions/tool-cache
|
|||||||
Provides an Octokit client hydrated with the context that the current action is being run in. Read more [here](packages/github)
|
Provides an Octokit client hydrated with the context that the current action is being run in. Read more [here](packages/github)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ npm install @actions/github
|
npm install @actions/github
|
||||||
```
|
```
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ $ npm install @actions/github
|
|||||||
Provides functions to interact with actions artifacts. Read more [here](packages/artifact)
|
Provides functions to interact with actions artifacts. Read more [here](packages/artifact)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ npm install @actions/artifact
|
npm install @actions/artifact
|
||||||
```
|
```
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ $ npm install @actions/artifact
|
|||||||
Provides functions to cache dependencies and build outputs to improve workflow execution time. Read more [here](packages/cache)
|
Provides functions to cache dependencies and build outputs to improve workflow execution time. Read more [here](packages/cache)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ npm install @actions/cache
|
npm install @actions/cache
|
||||||
```
|
```
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ $ npm install @actions/cache
|
|||||||
Provides functions to write attestations for workflow artifacts. Read more [here](packages/attest)
|
Provides functions to write attestations for workflow artifacts. Read more [here](packages/attest)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ npm install @actions/attest
|
npm install @actions/attest
|
||||||
```
|
```
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
@@ -227,9 +227,23 @@ console.log(`We can even get context data, like the repo: ${context.repo.repo}`)
|
|||||||
```
|
```
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
## Contributing
|
## Note
|
||||||
|
|
||||||
We welcome contributions. See [how to contribute](.github/CONTRIBUTING.md).
|
Thank you for your interest in this GitHub repo, however, right now we are not taking contributions.
|
||||||
|
|
||||||
|
We continue to focus our resources on strategic areas that help our customers be successful while making developers' lives easier. While GitHub Actions remains a key part of this vision, we are allocating resources towards other areas of Actions and are not taking contributions to this repository at this time. The GitHub public roadmap is the best place to follow along for any updates on features we’re working on and what stage they’re in.
|
||||||
|
|
||||||
|
We are taking the following steps to better direct requests related to GitHub Actions, including:
|
||||||
|
|
||||||
|
1. We will be directing questions and support requests to our [Community Discussions area](https://github.com/orgs/community/discussions/categories/actions)
|
||||||
|
|
||||||
|
2. High Priority bugs can be reported through Community Discussions or you can report these to our support team https://support.github.com/contact/bug-report.
|
||||||
|
|
||||||
|
3. Security Issues should be handled as per our [security.md](SECURITY.md).
|
||||||
|
|
||||||
|
We will still provide security updates for this project and fix major breaking changes during this time.
|
||||||
|
|
||||||
|
You are welcome to still raise bugs in this repo.
|
||||||
|
|
||||||
## Code of Conduct
|
## Code of Conduct
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ jobs:
|
|||||||
os: [ubuntu-16.04, windows-2019]
|
os: [ubuntu-16.04, windows-2019]
|
||||||
runs-on: ${{matrix.os}}
|
runs-on: ${{matrix.os}}
|
||||||
actions:
|
actions:
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v5
|
||||||
with:
|
with:
|
||||||
version: ${{matrix.node}}
|
version: ${{matrix.node}}
|
||||||
- run: |
|
- run: |
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ e.g. To use https://github.com/actions/setup-node, users will author:
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
using: actions/setup-node@v4
|
using: actions/setup-node@v5
|
||||||
```
|
```
|
||||||
|
|
||||||
# Define Metadata
|
# Define Metadata
|
||||||
|
|||||||
+29
-2
@@ -4,8 +4,35 @@ module.exports = {
|
|||||||
roots: ['<rootDir>/packages'],
|
roots: ['<rootDir>/packages'],
|
||||||
testEnvironment: 'node',
|
testEnvironment: 'node',
|
||||||
testMatch: ['**/__tests__/*.test.ts'],
|
testMatch: ['**/__tests__/*.test.ts'],
|
||||||
transform: {
|
moduleNameMapper: {
|
||||||
'^.+\\.ts$': 'ts-jest'
|
'^(\\.{1,2}/.*)\\.js$': '$1',
|
||||||
|
'^@actions/core$': '<rootDir>/packages/core/lib/core.js',
|
||||||
|
'^@actions/exec$': '<rootDir>/packages/exec/lib/exec.js',
|
||||||
|
'^@actions/io$': '<rootDir>/packages/io/lib/io.js',
|
||||||
|
'^@actions/io/lib/io-util$': '<rootDir>/packages/io/lib/io-util.js',
|
||||||
|
'^@actions/http-client$': '<rootDir>/packages/http-client/lib/index.js',
|
||||||
|
'^@actions/http-client/lib/auth$': '<rootDir>/packages/http-client/lib/auth.js',
|
||||||
|
'^@actions/http-client/lib/interfaces$': '<rootDir>/packages/http-client/lib/interfaces.js',
|
||||||
|
'^@actions/github$': '<rootDir>/packages/github/lib/github.js',
|
||||||
|
'^@actions/github/lib/utils$': '<rootDir>/packages/github/lib/utils.js',
|
||||||
|
'^@actions/glob$': '<rootDir>/packages/glob/lib/glob.js',
|
||||||
|
'^@actions/tool-cache$': '<rootDir>/packages/tool-cache/lib/tool-cache.js',
|
||||||
|
'^@actions/cache$': '<rootDir>/packages/cache/lib/cache.js',
|
||||||
|
'^@actions/attest$': '<rootDir>/packages/attest/lib/index.js'
|
||||||
},
|
},
|
||||||
|
transform: {
|
||||||
|
'^.+\\.(ts|js)$': ['ts-jest', {
|
||||||
|
diagnostics: {warnOnly: true},
|
||||||
|
tsconfig: {
|
||||||
|
allowJs: true,
|
||||||
|
esModuleInterop: true,
|
||||||
|
module: 'commonjs',
|
||||||
|
moduleResolution: 'node'
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
transformIgnorePatterns: [
|
||||||
|
'/node_modules/(?!(@octokit|@actions/github|@actions/http-client|@actions/io|@actions/exec|@actions/core|@actions/glob|@actions/tool-cache|@actions/cache|@actions/attest|universal-user-agent|before-after-hook)/)'
|
||||||
|
],
|
||||||
verbose: true
|
verbose: true
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+6734
-5185
File diff suppressed because it is too large
Load Diff
+19
-9
@@ -17,24 +17,34 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^29.5.4",
|
"@types/jest": "^29.5.4",
|
||||||
"@types/node": "^20.5.7",
|
"@types/node": "^24.1.0",
|
||||||
"@types/signale": "^1.4.1",
|
"@types/signale": "^1.4.1",
|
||||||
"concurrently": "^6.1.0",
|
"concurrently": "^9.0.0",
|
||||||
"eslint": "^8.0.1",
|
"eslint": "^8.0.1",
|
||||||
"eslint-config-prettier": "^8.9.0",
|
"eslint-config-prettier": "^8.9.0",
|
||||||
"eslint-plugin-github": "^4.9.2",
|
"eslint-plugin-github": "^4.9.2",
|
||||||
"eslint-plugin-jest": "^27.2.3",
|
"eslint-plugin-jest": "^27.2.3",
|
||||||
"eslint-plugin-prettier": "^5.0.0",
|
"eslint-plugin-prettier": "^5.5.0",
|
||||||
"flow-bin": "^0.115.0",
|
"flow-bin": "^0.115.0",
|
||||||
"jest": "^29.6.4",
|
"jest": "^29.6.4",
|
||||||
"lerna": "^6.4.1",
|
"lerna": "^6.4.1",
|
||||||
"nx": "16.6.0",
|
"nx": "16.6.0",
|
||||||
"prettier": "^3.0.0",
|
"prettier": "^3.8.0",
|
||||||
"ts-jest": "^29.1.1",
|
"ts-jest": "^29.4.0",
|
||||||
"typescript": "^5.2.2"
|
"typescript": "^5.9.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"overrides": {
|
||||||
"@actions/core": "^1.11.1",
|
"semver": "^7.6.0",
|
||||||
"@actions/github": "^6.0.0"
|
"tar": "^6.2.1",
|
||||||
|
"@octokit/plugin-paginate-rest": "^14.0.0",
|
||||||
|
"@octokit/request": "^10.0.7",
|
||||||
|
"@octokit/request-error": "^7.1.0",
|
||||||
|
"@octokit/core": "^7.0.6",
|
||||||
|
"tmp": "^0.2.4",
|
||||||
|
"@types/node": "^24.1.0",
|
||||||
|
"brace-expansion": "^2.0.2",
|
||||||
|
"form-data": "^4.0.4",
|
||||||
|
"uri-js": "npm:uri-js-replace@^1.0.1",
|
||||||
|
"node-fetch": "^3.3.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,6 @@ Interact programmatically with [Actions Artifacts](https://docs.github.com/en/ac
|
|||||||
|
|
||||||
This is the core library that powers the [`@actions/upload-artifact`](https://github.com/actions/upload-artifact) and [`@actions/download-artifact`](https://github.com/actions/download-artifact) actions.
|
This is the core library that powers the [`@actions/upload-artifact`](https://github.com/actions/upload-artifact) and [`@actions/download-artifact`](https://github.com/actions/download-artifact) actions.
|
||||||
|
|
||||||
|
|
||||||
- [`@actions/artifact`](#actionsartifact)
|
- [`@actions/artifact`](#actionsartifact)
|
||||||
- [v2 - What's New](#v2---whats-new)
|
- [v2 - What's New](#v2---whats-new)
|
||||||
- [Improvements](#improvements)
|
- [Improvements](#improvements)
|
||||||
|
|||||||
@@ -1,118 +1,144 @@
|
|||||||
# @actions/artifact Releases
|
# @actions/artifact Releases
|
||||||
|
|
||||||
### 2.3.2
|
## 5.0.3
|
||||||
|
|
||||||
|
- Bump `@actions/http-client` to `3.0.2`
|
||||||
|
|
||||||
|
## 5.0.1
|
||||||
|
|
||||||
|
- Fix Node.js 24 punycode deprecation warning by updating `@azure/storage-blob` from `^12.15.0` to `^12.29.1` [#2211](https://github.com/actions/toolkit/pull/2211)
|
||||||
|
- Removed direct `@azure/core-http` dependency (now uses `@azure/core-rest-pipeline` via storage-blob)
|
||||||
|
|
||||||
|
## 5.0.0
|
||||||
|
|
||||||
|
- Dependency updates for Node.js 24 runtime support
|
||||||
|
- Update `@actions/core` to v2
|
||||||
|
- Update `@actions/http-client` to v3
|
||||||
|
|
||||||
|
## 4.0.0
|
||||||
|
|
||||||
|
- Add support for Node 24 [#2110](https://github.com/actions/toolkit/pull/2110)
|
||||||
|
- Fix: artifact pagination bugs and configurable artifact count limits [#2165](https://github.com/actions/toolkit/pull/2165)
|
||||||
|
- Fix: reject the promise on timeout [#2124](https://github.com/actions/toolkit/pull/2124)
|
||||||
|
- Update dependency versions
|
||||||
|
|
||||||
|
## 2.3.3
|
||||||
|
|
||||||
|
- Dependency updates [#2049](https://github.com/actions/toolkit/pull/2049)
|
||||||
|
|
||||||
|
## 2.3.2
|
||||||
|
|
||||||
- Added masking for Shared Access Signature (SAS) artifact URLs [#1982](https://github.com/actions/toolkit/pull/1982)
|
- Added masking for Shared Access Signature (SAS) artifact URLs [#1982](https://github.com/actions/toolkit/pull/1982)
|
||||||
- Change hash to digest for consistent terminology across runner logs [#1991](https://github.com/actions/toolkit/pull/1991)
|
- Change hash to digest for consistent terminology across runner logs [#1991](https://github.com/actions/toolkit/pull/1991)
|
||||||
|
|
||||||
### 2.3.1
|
## 2.3.1
|
||||||
|
|
||||||
- Fix comment typo on expectedHash. [#1986](https://github.com/actions/toolkit/pull/1986)
|
- Fix comment typo on expectedHash. [#1986](https://github.com/actions/toolkit/pull/1986)
|
||||||
|
|
||||||
### 2.3.0
|
## 2.3.0
|
||||||
|
|
||||||
- Allow ArtifactClient to perform digest comparisons, if supplied. [#1975](https://github.com/actions/toolkit/pull/1975)
|
- Allow ArtifactClient to perform digest comparisons, if supplied. [#1975](https://github.com/actions/toolkit/pull/1975)
|
||||||
|
|
||||||
### 2.2.2
|
## 2.2.2
|
||||||
|
|
||||||
- Default concurrency to 5 for uploading artifacts [#1962](https://github.com/actions/toolkit/pull/1962
|
- Default concurrency to 5 for uploading artifacts [#1962](https://github.com/actions/toolkit/pull/1962)
|
||||||
|
|
||||||
### 2.2.1
|
## 2.2.1
|
||||||
|
|
||||||
- Add `ACTIONS_ARTIFACT_UPLOAD_CONCURRENCY` and `ACTIONS_ARTIFACT_UPLOAD_TIMEOUT_MS` environment variables [#1928](https://github.com/actions/toolkit/pull/1928)
|
- Add `ACTIONS_ARTIFACT_UPLOAD_CONCURRENCY` and `ACTIONS_ARTIFACT_UPLOAD_TIMEOUT_MS` environment variables [#1928](https://github.com/actions/toolkit/pull/1928)
|
||||||
|
|
||||||
### 2.2.0
|
## 2.2.0
|
||||||
|
|
||||||
- Return artifact digest on upload [#1896](https://github.com/actions/toolkit/pull/1896)
|
- Return artifact digest on upload [#1896](https://github.com/actions/toolkit/pull/1896)
|
||||||
|
|
||||||
### 2.1.11
|
## 2.1.11
|
||||||
|
|
||||||
- Fixed a bug with relative symlinks resolution [#1844](https://github.com/actions/toolkit/pull/1844)
|
- Fixed a bug with relative symlinks resolution [#1844](https://github.com/actions/toolkit/pull/1844)
|
||||||
- Use native `crypto` [#1815](https://github.com/actions/toolkit/pull/1815)
|
- Use native `crypto` [#1815](https://github.com/actions/toolkit/pull/1815)
|
||||||
|
|
||||||
### 2.1.10
|
## 2.1.10
|
||||||
|
|
||||||
- Fixed a regression with symlinks not being automatically resolved [#1830](https://github.com/actions/toolkit/pull/1830)
|
- Fixed a regression with symlinks not being automatically resolved [#1830](https://github.com/actions/toolkit/pull/1830)
|
||||||
- Fixed a regression with chunk timeout [#1786](https://github.com/actions/toolkit/pull/1786)
|
- Fixed a regression with chunk timeout [#1786](https://github.com/actions/toolkit/pull/1786)
|
||||||
|
|
||||||
### 2.1.9
|
## 2.1.9
|
||||||
|
|
||||||
- Fixed artifact upload chunk timeout logic [#1774](https://github.com/actions/toolkit/pull/1774)
|
- Fixed artifact upload chunk timeout logic [#1774](https://github.com/actions/toolkit/pull/1774)
|
||||||
- Use lazy stream to prevent issues with open file limits [#1771](https://github.com/actions/toolkit/pull/1771)
|
- Use lazy stream to prevent issues with open file limits [#1771](https://github.com/actions/toolkit/pull/1771)
|
||||||
|
|
||||||
### 2.1.8
|
## 2.1.8
|
||||||
|
|
||||||
- Allows `*.localhost` domains for hostname checks for local development.
|
- Allows `*.localhost` domains for hostname checks for local development.
|
||||||
|
|
||||||
### 2.1.7
|
## 2.1.7
|
||||||
|
|
||||||
- Update unzip-stream dependency and reverted to using `unzip.Extract()`
|
- Update unzip-stream dependency and reverted to using `unzip.Extract()`
|
||||||
|
|
||||||
### 2.1.6
|
## 2.1.6
|
||||||
|
|
||||||
- Will retry on invalid request responses.
|
- Will retry on invalid request responses.
|
||||||
|
|
||||||
### 2.1.5
|
## 2.1.5
|
||||||
|
|
||||||
- Bumped `archiver` dependency to 7.0.1
|
- Bumped `archiver` dependency to 7.0.1
|
||||||
|
|
||||||
### 2.1.4
|
## 2.1.4
|
||||||
|
|
||||||
- Adds info-level logging for zip extraction
|
- Adds info-level logging for zip extraction
|
||||||
|
|
||||||
### 2.1.3
|
## 2.1.3
|
||||||
|
|
||||||
- Fixes a bug in the extract logic updated in 2.1.2
|
- Fixes a bug in the extract logic updated in 2.1.2
|
||||||
|
|
||||||
### 2.1.2
|
## 2.1.2
|
||||||
|
|
||||||
- Updated the stream extract functionality to use `unzip.Parse()` instead of `unzip.Extract()` for greater control of unzipping artifacts
|
- Updated the stream extract functionality to use `unzip.Parse()` instead of `unzip.Extract()` for greater control of unzipping artifacts
|
||||||
|
|
||||||
### 2.1.1
|
## 2.1.1
|
||||||
|
|
||||||
- Updated `isGhes` check to include `.ghe.com` and `.ghe.localhost` as accepted hosts
|
- Updated `isGhes` check to include `.ghe.com` and `.ghe.localhost` as accepted hosts
|
||||||
|
|
||||||
### 2.1.0
|
## 2.1.0
|
||||||
|
|
||||||
- Added `ArtifactClient#deleteArtifact` to delete artifacts by name [#1626](https://github.com/actions/toolkit/pull/1626)
|
- Added `ArtifactClient#deleteArtifact` to delete artifacts by name [#1626](https://github.com/actions/toolkit/pull/1626)
|
||||||
- Update error messaging to be more useful [#1628](https://github.com/actions/toolkit/pull/1628)
|
- Update error messaging to be more useful [#1628](https://github.com/actions/toolkit/pull/1628)
|
||||||
|
|
||||||
### 2.0.1
|
## 2.0.1
|
||||||
|
|
||||||
- Patch to fix transient request timeouts https://github.com/actions/download-artifact/issues/249
|
- Patch to fix transient request timeouts <https://github.com/actions/download-artifact/issues/249>
|
||||||
|
|
||||||
### 2.0.0
|
## 2.0.0
|
||||||
|
|
||||||
- Major release. Supports new Artifact backend for improved speed, reliability and behavior.
|
- Major release. Supports new Artifact backend for improved speed, reliability and behavior.
|
||||||
- Numerous API changes, [some breaking](./README.md#breaking-changes).
|
- Numerous API changes, [some breaking](./README.md#breaking-changes).
|
||||||
|
|
||||||
- [Blog post with more info](https://github.blog/2024-02-12-get-started-with-v4-of-github-actions-artifacts/)
|
- [Blog post with more info](https://github.blog/2024-02-12-get-started-with-v4-of-github-actions-artifacts/)
|
||||||
|
|
||||||
### 1.1.1
|
## 1.1.1
|
||||||
|
|
||||||
- Fixed a bug in Node16 where if an HTTP download finished too quickly (<1ms, e.g. when it's mocked) we attempt to delete a temp file that has not been created yet [#1278](https://github.com/actions/toolkit/pull/1278/commits/b9de68a590daf37c6747e38d3cb4f1dd2cfb791c)
|
- Fixed a bug in Node16 where if an HTTP download finished too quickly (<1ms, e.g. when it's mocked) we attempt to delete a temp file that has not been created yet [#1278](https://github.com/actions/toolkit/pull/1278/commits/b9de68a590daf37c6747e38d3cb4f1dd2cfb791c)
|
||||||
|
|
||||||
### 1.1.0
|
## 1.1.0
|
||||||
|
|
||||||
- Add `x-actions-results-crc64` and `x-actions-results-md5` checksum headers on upload [#1063](https://github.com/actions/toolkit/pull/1063)
|
- Add `x-actions-results-crc64` and `x-actions-results-md5` checksum headers on upload [#1063](https://github.com/actions/toolkit/pull/1063)
|
||||||
|
|
||||||
### 1.0.2
|
## 1.0.2
|
||||||
|
|
||||||
- Update to v2.0.1 of `@actions/http-client` [#1087](https://github.com/actions/toolkit/pull/1087)
|
- Update to v2.0.1 of `@actions/http-client` [#1087](https://github.com/actions/toolkit/pull/1087)
|
||||||
|
|
||||||
### 1.0.1
|
## 1.0.1
|
||||||
|
|
||||||
- Update to v2.0.0 of `@actions/http-client`
|
- Update to v2.0.0 of `@actions/http-client`
|
||||||
|
|
||||||
### 1.0.0
|
## 1.0.0
|
||||||
|
|
||||||
- Update `lockfileVersion` to `v2` in `package-lock.json` [#1009](https://github.com/actions/toolkit/pull/1009)
|
- Update `lockfileVersion` to `v2` in `package-lock.json` [#1009](https://github.com/actions/toolkit/pull/1009)
|
||||||
|
|
||||||
### 0.6.1
|
## 0.6.1
|
||||||
|
|
||||||
- Fix for failing 0 byte file uploads on Windows [#962](https://github.com/actions/toolkit/pull/962)
|
- Fix for failing 0 byte file uploads on Windows [#962](https://github.com/actions/toolkit/pull/962)
|
||||||
|
|
||||||
### 0.6.0
|
## 0.6.0
|
||||||
|
|
||||||
- Support upload from named pipes [#748](https://github.com/actions/toolkit/pull/748)
|
- Support upload from named pipes [#748](https://github.com/actions/toolkit/pull/748)
|
||||||
- Fixes to percentage values being greater than 100% when downloading all artifacts [#889](https://github.com/actions/toolkit/pull/889)
|
- Fixes to percentage values being greater than 100% when downloading all artifacts [#889](https://github.com/actions/toolkit/pull/889)
|
||||||
@@ -121,49 +147,49 @@
|
|||||||
- Faster upload speeds for certain types of large files by exempting gzip compression [#956](https://github.com/actions/toolkit/pull/956)
|
- Faster upload speeds for certain types of large files by exempting gzip compression [#956](https://github.com/actions/toolkit/pull/956)
|
||||||
- More detailed logging when dealing with chunked uploads [#957](https://github.com/actions/toolkit/pull/957)
|
- More detailed logging when dealing with chunked uploads [#957](https://github.com/actions/toolkit/pull/957)
|
||||||
|
|
||||||
### 0.5.2
|
## 0.5.2
|
||||||
|
|
||||||
- Add HTTP 500 as a retryable status code for artifact upload and download.
|
- Add HTTP 500 as a retryable status code for artifact upload and download.
|
||||||
|
|
||||||
### 0.5.1
|
## 0.5.1
|
||||||
|
|
||||||
- Bump @actions/http-client to version 1.0.11 to fix proxy related issues during artifact upload and download
|
- Bump @actions/http-client to version 1.0.11 to fix proxy related issues during artifact upload and download
|
||||||
|
|
||||||
### 0.5.0
|
## 0.5.0
|
||||||
|
|
||||||
- Improved retry-ability for all http calls during artifact upload and download if an error is encountered
|
- Improved retry-ability for all http calls during artifact upload and download if an error is encountered
|
||||||
|
|
||||||
### 0.4.2
|
## 0.4.2
|
||||||
|
|
||||||
- Improved retry-ability when a partial artifact download is encountered
|
- Improved retry-ability when a partial artifact download is encountered
|
||||||
|
|
||||||
### 0.4.1
|
## 0.4.1
|
||||||
|
|
||||||
- Update to latest @actions/core version
|
- Update to latest @actions/core version
|
||||||
|
|
||||||
### 0.4.0
|
## 0.4.0
|
||||||
|
|
||||||
- Add option to specify custom retentions on artifacts
|
- Add option to specify custom retentions on artifacts
|
||||||
-
|
|
||||||
### 0.3.5
|
## 0.3.5
|
||||||
|
|
||||||
- Retry in the event of a 413 response
|
- Retry in the event of a 413 response
|
||||||
|
|
||||||
### 0.3.3
|
## 0.3.3
|
||||||
|
|
||||||
- Increase chunk size during upload from 4MB to 8MB
|
- Increase chunk size during upload from 4MB to 8MB
|
||||||
- Improve user-agent strings during API calls to help internally diagnose issues
|
- Improve user-agent strings during API calls to help internally diagnose issues
|
||||||
|
|
||||||
### 0.3.2
|
## 0.3.2
|
||||||
|
|
||||||
- Fix to ensure readstreams get correctly reset in the event of a retry
|
- Fix to ensure readstreams get correctly reset in the event of a retry
|
||||||
|
|
||||||
### 0.3.1
|
## 0.3.1
|
||||||
|
|
||||||
- Fix to ensure temporary gzip files get correctly deleted during artifact upload
|
- Fix to ensure temporary gzip files get correctly deleted during artifact upload
|
||||||
- Remove spaces as a forbidden character during upload
|
- Remove spaces as a forbidden character during upload
|
||||||
|
|
||||||
### 0.3.0
|
## 0.3.0
|
||||||
|
|
||||||
- Fixes to gzip decompression when downloading artifacts
|
- Fixes to gzip decompression when downloading artifacts
|
||||||
- Support handling 429 response codes
|
- Support handling 429 response codes
|
||||||
@@ -172,13 +198,13 @@
|
|||||||
- Clearer error message if storage quota has been reached
|
- Clearer error message if storage quota has been reached
|
||||||
- Improved logging and output during artifact download
|
- Improved logging and output during artifact download
|
||||||
|
|
||||||
### 0.2.0
|
## 0.2.0
|
||||||
|
|
||||||
- Fixes to TCP connections not closing
|
- Fixes to TCP connections not closing
|
||||||
- GZip file compression to speed up downloads
|
- GZip file compression to speed up downloads
|
||||||
- Improved logging and output
|
- Improved logging and output
|
||||||
- Extra documentation
|
- Extra documentation
|
||||||
|
|
||||||
### 0.1.0
|
## 0.1.0
|
||||||
|
|
||||||
- Initial release
|
- Initial release
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import * as http from 'http'
|
import * as http from 'http'
|
||||||
import * as net from 'net'
|
import * as net from 'net'
|
||||||
import {HttpClient} from '@actions/http-client'
|
import {HttpClient} from '@actions/http-client'
|
||||||
import * as config from '../src/internal/shared/config'
|
import * as config from '../src/internal/shared/config.js'
|
||||||
import {internalArtifactTwirpClient} from '../src/internal/shared/artifact-twirp-client'
|
import {internalArtifactTwirpClient} from '../src/internal/shared/artifact-twirp-client.js'
|
||||||
import {noopLogs} from './common'
|
import {noopLogs} from './common.js'
|
||||||
import {NetworkError, UsageError} from '../src/internal/shared/errors'
|
import {NetworkError, UsageError} from '../src/internal/shared/errors.js'
|
||||||
|
|
||||||
jest.mock('@actions/http-client')
|
jest.mock('@actions/http-client')
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
import * as config from '../src/internal/shared/config'
|
import * as config from '../src/internal/shared/config.js'
|
||||||
import os from 'os'
|
import os from 'os'
|
||||||
|
|
||||||
// Mock the 'os' module
|
// Mock the `cpus()` function in the `os` module
|
||||||
jest.mock('os', () => ({
|
jest.mock('os', () => {
|
||||||
cpus: jest.fn()
|
const osActual = jest.requireActual('os')
|
||||||
}))
|
return {
|
||||||
|
...osActual,
|
||||||
|
cpus: jest.fn()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.resetModules()
|
jest.resetModules()
|
||||||
@@ -101,3 +105,45 @@ describe('uploadConcurrencyEnv', () => {
|
|||||||
}).toThrow()
|
}).toThrow()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('getMaxArtifactListCount', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
delete process.env.ACTIONS_ARTIFACT_MAX_ARTIFACT_COUNT
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return default 1000 when no env set', () => {
|
||||||
|
expect(config.getMaxArtifactListCount()).toBe(1000)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return value set in ACTIONS_ARTIFACT_MAX_ARTIFACT_COUNT', () => {
|
||||||
|
process.env.ACTIONS_ARTIFACT_MAX_ARTIFACT_COUNT = '2000'
|
||||||
|
expect(config.getMaxArtifactListCount()).toBe(2000)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw if value set in ACTIONS_ARTIFACT_MAX_ARTIFACT_COUNT is invalid', () => {
|
||||||
|
process.env.ACTIONS_ARTIFACT_MAX_ARTIFACT_COUNT = 'abc'
|
||||||
|
expect(() => {
|
||||||
|
config.getMaxArtifactListCount()
|
||||||
|
}).toThrow(
|
||||||
|
'Invalid value set for ACTIONS_ARTIFACT_MAX_ARTIFACT_COUNT env variable'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw if ACTIONS_ARTIFACT_MAX_ARTIFACT_COUNT is < 1', () => {
|
||||||
|
process.env.ACTIONS_ARTIFACT_MAX_ARTIFACT_COUNT = '0'
|
||||||
|
expect(() => {
|
||||||
|
config.getMaxArtifactListCount()
|
||||||
|
}).toThrow(
|
||||||
|
'Invalid value set for ACTIONS_ARTIFACT_MAX_ARTIFACT_COUNT env variable'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw if ACTIONS_ARTIFACT_MAX_ARTIFACT_COUNT is negative', () => {
|
||||||
|
process.env.ACTIONS_ARTIFACT_MAX_ARTIFACT_COUNT = '-100'
|
||||||
|
expect(() => {
|
||||||
|
config.getMaxArtifactListCount()
|
||||||
|
}).toThrow(
|
||||||
|
'Invalid value set for ACTIONS_ARTIFACT_MAX_ARTIFACT_COUNT env variable'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ import type {RequestInterface} from '@octokit/types'
|
|||||||
import {
|
import {
|
||||||
deleteArtifactInternal,
|
deleteArtifactInternal,
|
||||||
deleteArtifactPublic
|
deleteArtifactPublic
|
||||||
} from '../src/internal/delete/delete-artifact'
|
} from '../src/internal/delete/delete-artifact.js'
|
||||||
import * as config from '../src/internal/shared/config'
|
import * as config from '../src/internal/shared/config.js'
|
||||||
import {ArtifactServiceClientJSON, Timestamp} from '../src/generated'
|
import {ArtifactServiceClientJSON, Timestamp} from '../src/generated/index.js'
|
||||||
import * as util from '../src/internal/shared/util'
|
import * as util from '../src/internal/shared/util.js'
|
||||||
import {noopLogs} from './common'
|
import {noopLogs} from './common.js'
|
||||||
|
|
||||||
type MockedRequest = jest.MockedFunction<RequestInterface<object>>
|
type MockedRequest = jest.MockedFunction<RequestInterface<object>>
|
||||||
|
|
||||||
|
|||||||
@@ -11,12 +11,12 @@ import {
|
|||||||
downloadArtifactInternal,
|
downloadArtifactInternal,
|
||||||
downloadArtifactPublic,
|
downloadArtifactPublic,
|
||||||
streamExtractExternal
|
streamExtractExternal
|
||||||
} from '../src/internal/download/download-artifact'
|
} from '../src/internal/download/download-artifact.js'
|
||||||
import {getUserAgentString} from '../src/internal/shared/user-agent'
|
import {getUserAgentString} from '../src/internal/shared/user-agent.js'
|
||||||
import {noopLogs} from './common'
|
import {noopLogs} from './common.js'
|
||||||
import * as config from '../src/internal/shared/config'
|
import * as config from '../src/internal/shared/config.js'
|
||||||
import {ArtifactServiceClientJSON} from '../src/generated'
|
import {ArtifactServiceClientJSON} from '../src/generated/index.js'
|
||||||
import * as util from '../src/internal/shared/util'
|
import * as util from '../src/internal/shared/util.js'
|
||||||
|
|
||||||
type MockedDownloadArtifact = jest.MockedFunction<
|
type MockedDownloadArtifact = jest.MockedFunction<
|
||||||
RestEndpointMethods['actions']['downloadArtifact']
|
RestEndpointMethods['actions']['downloadArtifact']
|
||||||
@@ -111,6 +111,16 @@ const mockGetArtifactSuccess = jest.fn(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const mockGetArtifactHung = jest.fn(() => {
|
||||||
|
const message = new http.IncomingMessage(new net.Socket())
|
||||||
|
message.statusCode = 200
|
||||||
|
// Don't push any data or call push(null) to end the stream
|
||||||
|
// This creates a stream that hangs and never completes
|
||||||
|
return {
|
||||||
|
message
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const mockGetArtifactFailure = jest.fn(() => {
|
const mockGetArtifactFailure = jest.fn(() => {
|
||||||
const message = new http.IncomingMessage(new net.Socket())
|
const message = new http.IncomingMessage(new net.Socket())
|
||||||
message.statusCode = 500
|
message.statusCode = 500
|
||||||
@@ -611,4 +621,32 @@ describe('download-artifact', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('streamExtractExternal', () => {
|
||||||
|
it('should fail if the timeout is exceeded', async () => {
|
||||||
|
const mockSlowGetArtifact = jest.fn(mockGetArtifactHung)
|
||||||
|
|
||||||
|
const mockHttpClient = (HttpClient as jest.Mock).mockImplementation(
|
||||||
|
() => {
|
||||||
|
return {
|
||||||
|
get: mockSlowGetArtifact
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
try {
|
||||||
|
await streamExtractExternal(
|
||||||
|
fixtures.blobStorageUrl,
|
||||||
|
fixtures.workspaceDir,
|
||||||
|
{timeout: 2}
|
||||||
|
)
|
||||||
|
expect(true).toBe(false) // should not be called
|
||||||
|
} catch (e) {
|
||||||
|
expect(e).toBeInstanceOf(Error)
|
||||||
|
expect(e.message).toContain('did not respond in 2ms')
|
||||||
|
expect(mockHttpClient).toHaveBeenCalledWith(getUserAgentString())
|
||||||
|
expect(mockSlowGetArtifact).toHaveBeenCalledTimes(1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,15 +3,15 @@ import type {RequestInterface} from '@octokit/types'
|
|||||||
import {
|
import {
|
||||||
getArtifactInternal,
|
getArtifactInternal,
|
||||||
getArtifactPublic
|
getArtifactPublic
|
||||||
} from '../src/internal/find/get-artifact'
|
} from '../src/internal/find/get-artifact.js'
|
||||||
import * as config from '../src/internal/shared/config'
|
import * as config from '../src/internal/shared/config.js'
|
||||||
import {ArtifactServiceClientJSON, Timestamp} from '../src/generated'
|
import {ArtifactServiceClientJSON, Timestamp} from '../src/generated/index.js'
|
||||||
import * as util from '../src/internal/shared/util'
|
import * as util from '../src/internal/shared/util.js'
|
||||||
import {noopLogs} from './common'
|
import {noopLogs} from './common.js'
|
||||||
import {
|
import {
|
||||||
ArtifactNotFoundError,
|
ArtifactNotFoundError,
|
||||||
InvalidResponseError
|
InvalidResponseError
|
||||||
} from '../src/internal/shared/errors'
|
} from '../src/internal/shared/errors.js'
|
||||||
|
|
||||||
type MockedRequest = jest.MockedFunction<RequestInterface<object>>
|
type MockedRequest = jest.MockedFunction<RequestInterface<object>>
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ import type {RestEndpointMethodTypes} from '@octokit/plugin-rest-endpoint-method
|
|||||||
import {
|
import {
|
||||||
listArtifactsInternal,
|
listArtifactsInternal,
|
||||||
listArtifactsPublic
|
listArtifactsPublic
|
||||||
} from '../src/internal/find/list-artifacts'
|
} from '../src/internal/find/list-artifacts.js'
|
||||||
import * as config from '../src/internal/shared/config'
|
import * as config from '../src/internal/shared/config.js'
|
||||||
import {ArtifactServiceClientJSON, Timestamp} from '../src/generated'
|
import {ArtifactServiceClientJSON, Timestamp} from '../src/generated/index.js'
|
||||||
import * as util from '../src/internal/shared/util'
|
import * as util from '../src/internal/shared/util.js'
|
||||||
import {noopLogs} from './common'
|
import {noopLogs} from './common.js'
|
||||||
import {Artifact} from '../src/internal/shared/interfaces'
|
import {Artifact} from '../src/internal/shared/interfaces.js'
|
||||||
import {RequestInterface} from '@octokit/types'
|
import {RequestInterface} from '@octokit/types'
|
||||||
|
|
||||||
type MockedRequest = jest.MockedFunction<RequestInterface<object>>
|
type MockedRequest = jest.MockedFunction<RequestInterface<object>>
|
||||||
@@ -170,6 +170,125 @@ describe('list-artifact', () => {
|
|||||||
)
|
)
|
||||||
).rejects.toThrow('boom')
|
).rejects.toThrow('boom')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should handle pagination correctly when fetching multiple pages', async () => {
|
||||||
|
const mockRequest = github.getOctokit(fixtures.token)
|
||||||
|
.request as MockedRequest
|
||||||
|
|
||||||
|
const manyArtifacts = Array.from({length: 150}, (_, i) => ({
|
||||||
|
id: i + 1,
|
||||||
|
name: `artifact-${i + 1}`,
|
||||||
|
size: 100,
|
||||||
|
createdAt: new Date('2023-12-01')
|
||||||
|
}))
|
||||||
|
|
||||||
|
mockRequest
|
||||||
|
.mockResolvedValueOnce({
|
||||||
|
status: 200,
|
||||||
|
headers: {},
|
||||||
|
url: '',
|
||||||
|
data: {
|
||||||
|
...artifactsToListResponse(manyArtifacts.slice(0, 100)),
|
||||||
|
total_count: 150
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.mockResolvedValueOnce({
|
||||||
|
status: 200,
|
||||||
|
headers: {},
|
||||||
|
url: '',
|
||||||
|
data: {
|
||||||
|
...artifactsToListResponse(manyArtifacts.slice(100, 150)),
|
||||||
|
total_count: 150
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const response = await listArtifactsPublic(
|
||||||
|
fixtures.runId,
|
||||||
|
fixtures.owner,
|
||||||
|
fixtures.repo,
|
||||||
|
fixtures.token,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
|
// Verify that both API calls were made
|
||||||
|
expect(mockRequest).toHaveBeenCalledTimes(2)
|
||||||
|
|
||||||
|
// Should return all 150 artifacts across both pages
|
||||||
|
expect(response.artifacts).toHaveLength(150)
|
||||||
|
|
||||||
|
// Verify we got artifacts from both pages
|
||||||
|
expect(response.artifacts[0].name).toBe('artifact-1')
|
||||||
|
expect(response.artifacts[99].name).toBe('artifact-100')
|
||||||
|
expect(response.artifacts[100].name).toBe('artifact-101')
|
||||||
|
expect(response.artifacts[149].name).toBe('artifact-150')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should respect ACTIONS_ARTIFACT_MAX_ARTIFACT_COUNT environment variable', async () => {
|
||||||
|
const originalEnv = process.env.ACTIONS_ARTIFACT_MAX_ARTIFACT_COUNT
|
||||||
|
process.env.ACTIONS_ARTIFACT_MAX_ARTIFACT_COUNT = '150'
|
||||||
|
|
||||||
|
jest.resetModules()
|
||||||
|
|
||||||
|
try {
|
||||||
|
const {listArtifactsPublic: listArtifactsPublicReloaded} =
|
||||||
|
await import('../src/internal/find/list-artifacts')
|
||||||
|
const githubReloaded = await import('@actions/github')
|
||||||
|
|
||||||
|
const mockRequest = (githubReloaded.getOctokit as jest.Mock)(
|
||||||
|
fixtures.token
|
||||||
|
).request as MockedRequest
|
||||||
|
|
||||||
|
const manyArtifacts = Array.from({length: 200}, (_, i) => ({
|
||||||
|
id: i + 1,
|
||||||
|
name: `artifact-${i + 1}`,
|
||||||
|
size: 100,
|
||||||
|
createdAt: new Date('2023-12-01')
|
||||||
|
}))
|
||||||
|
|
||||||
|
mockRequest
|
||||||
|
.mockResolvedValueOnce({
|
||||||
|
status: 200,
|
||||||
|
headers: {},
|
||||||
|
url: '',
|
||||||
|
data: {
|
||||||
|
...artifactsToListResponse(manyArtifacts.slice(0, 100)),
|
||||||
|
total_count: 200
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.mockResolvedValueOnce({
|
||||||
|
status: 200,
|
||||||
|
headers: {},
|
||||||
|
url: '',
|
||||||
|
data: {
|
||||||
|
...artifactsToListResponse(manyArtifacts.slice(100, 150)),
|
||||||
|
total_count: 200
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const response = await listArtifactsPublicReloaded(
|
||||||
|
fixtures.runId,
|
||||||
|
fixtures.owner,
|
||||||
|
fixtures.repo,
|
||||||
|
fixtures.token,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
|
// Should only return 150 artifacts due to the limit
|
||||||
|
expect(response.artifacts).toHaveLength(150)
|
||||||
|
expect(response.artifacts[0].name).toBe('artifact-1')
|
||||||
|
expect(response.artifacts[149].name).toBe('artifact-150')
|
||||||
|
} finally {
|
||||||
|
// Restore original environment variable
|
||||||
|
if (originalEnv !== undefined) {
|
||||||
|
process.env.ACTIONS_ARTIFACT_MAX_ARTIFACT_COUNT = originalEnv
|
||||||
|
} else {
|
||||||
|
delete process.env.ACTIONS_ARTIFACT_MAX_ARTIFACT_COUNT
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset modules again to restore original state
|
||||||
|
jest.resetModules()
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('internal', () => {
|
describe('internal', () => {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import {
|
import {
|
||||||
validateArtifactName,
|
validateArtifactName,
|
||||||
validateFilePath
|
validateFilePath
|
||||||
} from '../src/internal/upload/path-and-artifact-name-validation'
|
} from '../src/internal/upload/path-and-artifact-name-validation.js'
|
||||||
|
|
||||||
import {noopLogs} from './common'
|
import {noopLogs} from './common.js'
|
||||||
|
|
||||||
describe('Path and artifact name validation', () => {
|
describe('Path and artifact name validation', () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {Timestamp} from '../src/generated'
|
import {Timestamp} from '../src/generated/index.js'
|
||||||
import * as retention from '../src/internal/upload/retention'
|
import * as retention from '../src/internal/upload/retention.js'
|
||||||
|
|
||||||
describe('retention', () => {
|
describe('retention', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import * as uploadZipSpecification from '../src/internal/upload/upload-zip-specification'
|
import * as uploadZipSpecification from '../src/internal/upload/upload-zip-specification.js'
|
||||||
import * as zip from '../src/internal/upload/zip'
|
import * as zip from '../src/internal/upload/zip.js'
|
||||||
import * as util from '../src/internal/shared/util'
|
import * as util from '../src/internal/shared/util.js'
|
||||||
import * as config from '../src/internal/shared/config'
|
import * as config from '../src/internal/shared/config.js'
|
||||||
import {ArtifactServiceClientJSON} from '../src/generated'
|
import {ArtifactServiceClientJSON} from '../src/generated/index.js'
|
||||||
import * as blobUpload from '../src/internal/upload/blob-upload'
|
import * as blobUpload from '../src/internal/upload/blob-upload.js'
|
||||||
import {uploadArtifact} from '../src/internal/upload/upload-artifact'
|
import {uploadArtifact} from '../src/internal/upload/upload-artifact.js'
|
||||||
import {noopLogs} from './common'
|
import {noopLogs} from './common.js'
|
||||||
import {FilesNotFoundError} from '../src/internal/shared/errors'
|
import {FilesNotFoundError} from '../src/internal/shared/errors.js'
|
||||||
import {BlockBlobUploadStreamOptions} from '@azure/storage-blob'
|
import {BlockBlobUploadStreamOptions} from '@azure/storage-blob'
|
||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
@@ -108,7 +108,7 @@ describe('upload-artifact', () => {
|
|||||||
fixtures.files.map(file => ({
|
fixtures.files.map(file => ({
|
||||||
sourcePath: path.join(fixtures.uploadDirectory, file.name),
|
sourcePath: path.join(fixtures.uploadDirectory, file.name),
|
||||||
destinationPath: file.name,
|
destinationPath: file.name,
|
||||||
stats: new fs.Stats()
|
stats: fs.statSync(path.join(fixtures.uploadDirectory, file.name))
|
||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
jest.spyOn(config, 'getRuntimeToken').mockReturnValue(fixtures.runtimeToken)
|
jest.spyOn(config, 'getRuntimeToken').mockReturnValue(fixtures.runtimeToken)
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import {promises as fs} from 'fs'
|
|||||||
import {
|
import {
|
||||||
getUploadZipSpecification,
|
getUploadZipSpecification,
|
||||||
validateRootDirectory
|
validateRootDirectory
|
||||||
} from '../src/internal/upload/upload-zip-specification'
|
} from '../src/internal/upload/upload-zip-specification.js'
|
||||||
import {noopLogs} from './common'
|
import {noopLogs} from './common.js'
|
||||||
|
|
||||||
const root = path.join(__dirname, '_temp', 'upload-specification')
|
const root = path.join(__dirname, '_temp', 'upload-specification')
|
||||||
const goodItem1Path = path.join(
|
const goodItem1Path = path.join(
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as config from '../src/internal/shared/config'
|
import * as config from '../src/internal/shared/config.js'
|
||||||
import * as util from '../src/internal/shared/util'
|
import * as util from '../src/internal/shared/util.js'
|
||||||
import {maskSigUrl, maskSecretUrls} from '../src/internal/shared/util'
|
import {maskSigUrl, maskSecretUrls} from '../src/internal/shared/util.js'
|
||||||
import {setSecret, debug} from '@actions/core'
|
import {setSecret, debug} from '@actions/core'
|
||||||
|
|
||||||
export const testRuntimeToken =
|
export const testRuntimeToken =
|
||||||
|
|||||||
Generated
+934
-691
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/artifact",
|
"name": "@actions/artifact",
|
||||||
"version": "2.3.2",
|
"version": "6.0.0",
|
||||||
"preview": true,
|
"preview": true,
|
||||||
"description": "Actions artifact lib",
|
"description": "Actions artifact lib",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@@ -10,8 +10,15 @@
|
|||||||
],
|
],
|
||||||
"homepage": "https://github.com/actions/toolkit/tree/main/packages/artifact",
|
"homepage": "https://github.com/actions/toolkit/tree/main/packages/artifact",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"type": "module",
|
||||||
"main": "lib/artifact.js",
|
"main": "lib/artifact.js",
|
||||||
"types": "lib/artifact.d.ts",
|
"types": "lib/artifact.d.ts",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"types": "./lib/artifact.d.ts",
|
||||||
|
"import": "./lib/artifact.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"directories": {
|
"directories": {
|
||||||
"lib": "lib",
|
"lib": "lib",
|
||||||
"test": "__tests__"
|
"test": "__tests__"
|
||||||
@@ -32,7 +39,7 @@
|
|||||||
"audit-moderate": "npm install && npm audit --json --audit-level=moderate > audit.json",
|
"audit-moderate": "npm install && npm audit --json --audit-level=moderate > audit.json",
|
||||||
"test": "cd ../../ && npm run test ./packages/artifact",
|
"test": "cd ../../ && npm run test ./packages/artifact",
|
||||||
"bootstrap": "cd ../../ && npm run bootstrap",
|
"bootstrap": "cd ../../ && npm run bootstrap",
|
||||||
"tsc-run": "tsc",
|
"tsc-run": "tsc && cp src/internal/shared/package-version.cjs lib/internal/shared/",
|
||||||
"tsc": "npm run bootstrap && npm run tsc-run",
|
"tsc": "npm run bootstrap && npm run tsc-run",
|
||||||
"gen:docs": "typedoc --plugin typedoc-plugin-markdown --out docs/generated src/artifact.ts --githubPages false --readme none"
|
"gen:docs": "typedoc --plugin typedoc-plugin-markdown --out docs/generated src/artifact.ts --githubPages false --readme none"
|
||||||
},
|
},
|
||||||
@@ -40,24 +47,30 @@
|
|||||||
"url": "https://github.com/actions/toolkit/issues"
|
"url": "https://github.com/actions/toolkit/issues"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.10.0",
|
"@actions/core": "^3.0.0",
|
||||||
"@actions/github": "^5.1.1",
|
"@actions/github": "^9.0.0",
|
||||||
"@actions/http-client": "^2.1.0",
|
"@actions/http-client": "^4.0.0",
|
||||||
"@azure/storage-blob": "^12.15.0",
|
"@azure/storage-blob": "^12.30.0",
|
||||||
"@octokit/core": "^3.5.1",
|
"@octokit/core": "^7.0.6",
|
||||||
"@octokit/plugin-request-log": "^1.0.4",
|
"@octokit/plugin-request-log": "^6.0.0",
|
||||||
"@octokit/plugin-retry": "^3.0.9",
|
"@octokit/plugin-retry": "^8.0.0",
|
||||||
"@octokit/request-error": "^5.0.0",
|
"@octokit/request": "^10.0.7",
|
||||||
|
"@octokit/request-error": "^7.1.0",
|
||||||
"@protobuf-ts/plugin": "^2.2.3-alpha.1",
|
"@protobuf-ts/plugin": "^2.2.3-alpha.1",
|
||||||
|
"@protobuf-ts/runtime": "^2.9.4",
|
||||||
"archiver": "^7.0.1",
|
"archiver": "^7.0.1",
|
||||||
"jwt-decode": "^3.1.2",
|
"jwt-decode": "^4.0.0",
|
||||||
"unzip-stream": "^0.3.1"
|
"unzip-stream": "^0.3.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/archiver": "^5.3.2",
|
"@types/archiver": "^7.0.0",
|
||||||
"@types/unzip-stream": "^0.3.4",
|
"@types/unzip-stream": "^0.3.4",
|
||||||
"typedoc": "^0.25.4",
|
"typedoc": "^0.28.16",
|
||||||
"typedoc-plugin-markdown": "^3.17.1",
|
"typedoc-plugin-markdown": "^4.9.0",
|
||||||
"typescript": "^5.2.2"
|
"typescript": "^5.9.3"
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"uri-js": "npm:uri-js-replace@^1.0.1",
|
||||||
|
"node-fetch": "^3.3.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import {ArtifactClient, DefaultArtifactClient} from './internal/client'
|
import {ArtifactClient, DefaultArtifactClient} from './internal/client.js'
|
||||||
|
|
||||||
export * from './internal/shared/interfaces'
|
export * from './internal/shared/interfaces.js'
|
||||||
export * from './internal/shared/errors'
|
export * from './internal/shared/errors.js'
|
||||||
export * from './internal/client'
|
export * from './internal/client.js'
|
||||||
|
|
||||||
const client: ArtifactClient = new DefaultArtifactClient()
|
const client: ArtifactClient = new DefaultArtifactClient()
|
||||||
export default client
|
export default client
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export * from './google/protobuf/timestamp'
|
export * from './google/protobuf/timestamp.js'
|
||||||
export * from './google/protobuf/wrappers'
|
export * from './google/protobuf/wrappers.js'
|
||||||
export * from './results/api/v1/artifact'
|
export * from './results/api/v1/artifact.js'
|
||||||
export * from './results/api/v1/artifact.twirp-client'
|
export * from './results/api/v1/artifact.twirp-client.js'
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ import type { PartialMessage } from "@protobuf-ts/runtime";
|
|||||||
import { reflectionMergePartial } from "@protobuf-ts/runtime";
|
import { reflectionMergePartial } from "@protobuf-ts/runtime";
|
||||||
import { MESSAGE_TYPE } from "@protobuf-ts/runtime";
|
import { MESSAGE_TYPE } from "@protobuf-ts/runtime";
|
||||||
import { MessageType } from "@protobuf-ts/runtime";
|
import { MessageType } from "@protobuf-ts/runtime";
|
||||||
import { Int64Value } from "../../../google/protobuf/wrappers";
|
import { Int64Value } from "../../../google/protobuf/wrappers.js";
|
||||||
import { StringValue } from "../../../google/protobuf/wrappers";
|
import { StringValue } from "../../../google/protobuf/wrappers.js";
|
||||||
import { Timestamp } from "../../../google/protobuf/timestamp";
|
import { Timestamp } from "../../../google/protobuf/timestamp.js";
|
||||||
/**
|
/**
|
||||||
* @generated from protobuf message github.actions.results.api.v1.MigrateArtifactRequest
|
* @generated from protobuf message github.actions.results.api.v1.MigrateArtifactRequest
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
GetSignedArtifactURLResponse,
|
GetSignedArtifactURLResponse,
|
||||||
DeleteArtifactRequest,
|
DeleteArtifactRequest,
|
||||||
DeleteArtifactResponse,
|
DeleteArtifactResponse,
|
||||||
} from "./artifact";
|
} from "./artifact.js";
|
||||||
|
|
||||||
//==================================//
|
//==================================//
|
||||||
// Client Code //
|
// Client Code //
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {warning} from '@actions/core'
|
import {warning} from '@actions/core'
|
||||||
import {isGhes} from './shared/config'
|
import {isGhes} from './shared/config.js'
|
||||||
import {
|
import {
|
||||||
UploadArtifactOptions,
|
UploadArtifactOptions,
|
||||||
UploadArtifactResponse,
|
UploadArtifactResponse,
|
||||||
@@ -10,19 +10,22 @@ import {
|
|||||||
DownloadArtifactResponse,
|
DownloadArtifactResponse,
|
||||||
FindOptions,
|
FindOptions,
|
||||||
DeleteArtifactResponse
|
DeleteArtifactResponse
|
||||||
} from './shared/interfaces'
|
} from './shared/interfaces.js'
|
||||||
import {uploadArtifact} from './upload/upload-artifact'
|
import {uploadArtifact} from './upload/upload-artifact.js'
|
||||||
import {
|
import {
|
||||||
downloadArtifactPublic,
|
downloadArtifactPublic,
|
||||||
downloadArtifactInternal
|
downloadArtifactInternal
|
||||||
} from './download/download-artifact'
|
} from './download/download-artifact.js'
|
||||||
import {
|
import {
|
||||||
deleteArtifactPublic,
|
deleteArtifactPublic,
|
||||||
deleteArtifactInternal
|
deleteArtifactInternal
|
||||||
} from './delete/delete-artifact'
|
} from './delete/delete-artifact.js'
|
||||||
import {getArtifactPublic, getArtifactInternal} from './find/get-artifact'
|
import {getArtifactPublic, getArtifactInternal} from './find/get-artifact.js'
|
||||||
import {listArtifactsPublic, listArtifactsInternal} from './find/list-artifacts'
|
import {
|
||||||
import {GHESNotSupportedError} from './shared/errors'
|
listArtifactsPublic,
|
||||||
|
listArtifactsInternal
|
||||||
|
} from './find/list-artifacts.js'
|
||||||
|
import {GHESNotSupportedError} from './shared/errors.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic interface for the artifact client.
|
* Generic interface for the artifact client.
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
import {info, debug} from '@actions/core'
|
import {info, debug} from '@actions/core'
|
||||||
import {getOctokit} from '@actions/github'
|
import {getOctokit} from '@actions/github'
|
||||||
import {DeleteArtifactResponse} from '../shared/interfaces'
|
import {DeleteArtifactResponse} from '../shared/interfaces.js'
|
||||||
import {getUserAgentString} from '../shared/user-agent'
|
import {getUserAgentString} from '../shared/user-agent.js'
|
||||||
import {getRetryOptions} from '../find/retry-options'
|
import {getRetryOptions} from '../find/retry-options.js'
|
||||||
import {defaults as defaultGitHubOptions} from '@actions/github/lib/utils'
|
import {defaults as defaultGitHubOptions} from '@actions/github/lib/utils'
|
||||||
import {requestLog} from '@octokit/plugin-request-log'
|
import {requestLog} from '@octokit/plugin-request-log'
|
||||||
import {retry} from '@octokit/plugin-retry'
|
import {retry} from '@octokit/plugin-retry'
|
||||||
import {OctokitOptions} from '@octokit/core/dist-types/types'
|
import type {OctokitOptions} from '@octokit/core/types'
|
||||||
import {internalArtifactTwirpClient} from '../shared/artifact-twirp-client'
|
import {internalArtifactTwirpClient} from '../shared/artifact-twirp-client.js'
|
||||||
import {getBackendIdsFromToken} from '../shared/util'
|
import {getBackendIdsFromToken} from '../shared/util.js'
|
||||||
import {
|
import {
|
||||||
DeleteArtifactRequest,
|
DeleteArtifactRequest,
|
||||||
ListArtifactsRequest,
|
ListArtifactsRequest,
|
||||||
StringValue
|
StringValue
|
||||||
} from '../../generated'
|
} from '../../generated/index.js'
|
||||||
import {getArtifactPublic} from '../find/get-artifact'
|
import {getArtifactPublic} from '../find/get-artifact.js'
|
||||||
import {ArtifactNotFoundError, InvalidResponseError} from '../shared/errors'
|
import {ArtifactNotFoundError, InvalidResponseError} from '../shared/errors.js'
|
||||||
|
|
||||||
export async function deleteArtifactPublic(
|
export async function deleteArtifactPublic(
|
||||||
artifactName: string,
|
artifactName: string,
|
||||||
|
|||||||
@@ -10,17 +10,17 @@ import {
|
|||||||
DownloadArtifactOptions,
|
DownloadArtifactOptions,
|
||||||
DownloadArtifactResponse,
|
DownloadArtifactResponse,
|
||||||
StreamExtractResponse
|
StreamExtractResponse
|
||||||
} from '../shared/interfaces'
|
} from '../shared/interfaces.js'
|
||||||
import {getUserAgentString} from '../shared/user-agent'
|
import {getUserAgentString} from '../shared/user-agent.js'
|
||||||
import {getGitHubWorkspaceDir} from '../shared/config'
|
import {getGitHubWorkspaceDir} from '../shared/config.js'
|
||||||
import {internalArtifactTwirpClient} from '../shared/artifact-twirp-client'
|
import {internalArtifactTwirpClient} from '../shared/artifact-twirp-client.js'
|
||||||
import {
|
import {
|
||||||
GetSignedArtifactURLRequest,
|
GetSignedArtifactURLRequest,
|
||||||
Int64Value,
|
Int64Value,
|
||||||
ListArtifactsRequest
|
ListArtifactsRequest
|
||||||
} from '../../generated'
|
} from '../../generated/index.js'
|
||||||
import {getBackendIdsFromToken} from '../shared/util'
|
import {getBackendIdsFromToken} from '../shared/util.js'
|
||||||
import {ArtifactNotFoundError} from '../shared/errors'
|
import {ArtifactNotFoundError} from '../shared/errors.js'
|
||||||
|
|
||||||
const scrubQueryParameters = (url: string): string => {
|
const scrubQueryParameters = (url: string): string => {
|
||||||
const parsed = new URL(url)
|
const parsed = new URL(url)
|
||||||
@@ -64,7 +64,8 @@ async function streamExtract(
|
|||||||
|
|
||||||
export async function streamExtractExternal(
|
export async function streamExtractExternal(
|
||||||
url: string,
|
url: string,
|
||||||
directory: string
|
directory: string,
|
||||||
|
opts: {timeout: number} = {timeout: 30 * 1000}
|
||||||
): Promise<StreamExtractResponse> {
|
): Promise<StreamExtractResponse> {
|
||||||
const client = new httpClient.HttpClient(getUserAgentString())
|
const client = new httpClient.HttpClient(getUserAgentString())
|
||||||
const response = await client.get(url)
|
const response = await client.get(url)
|
||||||
@@ -74,16 +75,17 @@ export async function streamExtractExternal(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const timeout = 30 * 1000 // 30 seconds
|
|
||||||
let sha256Digest: string | undefined = undefined
|
let sha256Digest: string | undefined = undefined
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const timerFn = (): void => {
|
const timerFn = (): void => {
|
||||||
response.message.destroy(
|
const timeoutError = new Error(
|
||||||
new Error(`Blob storage chunk did not respond in ${timeout}ms`)
|
`Blob storage chunk did not respond in ${opts.timeout}ms`
|
||||||
)
|
)
|
||||||
|
response.message.destroy(timeoutError)
|
||||||
|
reject(timeoutError)
|
||||||
}
|
}
|
||||||
const timer = setTimeout(timerFn, timeout)
|
const timer = setTimeout(timerFn, opts.timeout)
|
||||||
|
|
||||||
const hashStream = crypto.createHash('sha256').setEncoding('hex')
|
const hashStream = crypto.createHash('sha256').setEncoding('hex')
|
||||||
const passThrough = new stream.PassThrough()
|
const passThrough = new stream.PassThrough()
|
||||||
|
|||||||
@@ -1,16 +1,20 @@
|
|||||||
import {getOctokit} from '@actions/github'
|
import {getOctokit} from '@actions/github'
|
||||||
import {retry} from '@octokit/plugin-retry'
|
import {retry} from '@octokit/plugin-retry'
|
||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import {OctokitOptions} from '@octokit/core/dist-types/types'
|
import type {OctokitOptions} from '@octokit/core/types'
|
||||||
import {defaults as defaultGitHubOptions} from '@actions/github/lib/utils'
|
import {defaults as defaultGitHubOptions} from '@actions/github/lib/utils'
|
||||||
import {getRetryOptions} from './retry-options'
|
import {getRetryOptions} from './retry-options.js'
|
||||||
import {requestLog} from '@octokit/plugin-request-log'
|
import {requestLog} from '@octokit/plugin-request-log'
|
||||||
import {GetArtifactResponse} from '../shared/interfaces'
|
import {GetArtifactResponse} from '../shared/interfaces.js'
|
||||||
import {getBackendIdsFromToken} from '../shared/util'
|
import {getBackendIdsFromToken} from '../shared/util.js'
|
||||||
import {getUserAgentString} from '../shared/user-agent'
|
import {getUserAgentString} from '../shared/user-agent.js'
|
||||||
import {internalArtifactTwirpClient} from '../shared/artifact-twirp-client'
|
import {internalArtifactTwirpClient} from '../shared/artifact-twirp-client.js'
|
||||||
import {ListArtifactsRequest, StringValue, Timestamp} from '../../generated'
|
import {
|
||||||
import {ArtifactNotFoundError, InvalidResponseError} from '../shared/errors'
|
ListArtifactsRequest,
|
||||||
|
StringValue,
|
||||||
|
Timestamp
|
||||||
|
} from '../../generated/index.js'
|
||||||
|
import {ArtifactNotFoundError, InvalidResponseError} from '../shared/errors.js'
|
||||||
|
|
||||||
export async function getArtifactPublic(
|
export async function getArtifactPublic(
|
||||||
artifactName: string,
|
artifactName: string,
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
import {info, warning, debug} from '@actions/core'
|
import {info, warning, debug} from '@actions/core'
|
||||||
import {getOctokit} from '@actions/github'
|
import {getOctokit} from '@actions/github'
|
||||||
import {ListArtifactsResponse, Artifact} from '../shared/interfaces'
|
import {ListArtifactsResponse, Artifact} from '../shared/interfaces.js'
|
||||||
import {getUserAgentString} from '../shared/user-agent'
|
import {getUserAgentString} from '../shared/user-agent.js'
|
||||||
import {getRetryOptions} from './retry-options'
|
import {getRetryOptions} from './retry-options.js'
|
||||||
import {defaults as defaultGitHubOptions} from '@actions/github/lib/utils'
|
import {defaults as defaultGitHubOptions} from '@actions/github/lib/utils'
|
||||||
import {requestLog} from '@octokit/plugin-request-log'
|
import {requestLog} from '@octokit/plugin-request-log'
|
||||||
import {retry} from '@octokit/plugin-retry'
|
import {retry} from '@octokit/plugin-retry'
|
||||||
import {OctokitOptions} from '@octokit/core/dist-types/types'
|
import type {OctokitOptions} from '@octokit/core/types'
|
||||||
import {internalArtifactTwirpClient} from '../shared/artifact-twirp-client'
|
import {internalArtifactTwirpClient} from '../shared/artifact-twirp-client.js'
|
||||||
import {getBackendIdsFromToken} from '../shared/util'
|
import {getBackendIdsFromToken} from '../shared/util.js'
|
||||||
import {ListArtifactsRequest, Timestamp} from '../../generated'
|
import {getMaxArtifactListCount} from '../shared/config.js'
|
||||||
|
import {ListArtifactsRequest, Timestamp} from '../../generated/index.js'
|
||||||
|
|
||||||
// Limiting to 1000 for perf reasons
|
const maximumArtifactCount = getMaxArtifactListCount()
|
||||||
const maximumArtifactCount = 1000
|
|
||||||
const paginationCount = 100
|
const paginationCount = 100
|
||||||
const maxNumberOfPages = maximumArtifactCount / paginationCount
|
const maxNumberOfPages = Math.ceil(maximumArtifactCount / paginationCount)
|
||||||
|
|
||||||
export async function listArtifactsPublic(
|
export async function listArtifactsPublic(
|
||||||
workflowRunId: number,
|
workflowRunId: number,
|
||||||
@@ -59,7 +59,7 @@ export async function listArtifactsPublic(
|
|||||||
const totalArtifactCount = listArtifactResponse.total_count
|
const totalArtifactCount = listArtifactResponse.total_count
|
||||||
if (totalArtifactCount > maximumArtifactCount) {
|
if (totalArtifactCount > maximumArtifactCount) {
|
||||||
warning(
|
warning(
|
||||||
`Workflow run ${workflowRunId} has more than 1000 artifacts. Results will be incomplete as only the first ${maximumArtifactCount} artifacts will be returned`
|
`Workflow run ${workflowRunId} has ${totalArtifactCount} artifacts, exceeding the limit of ${maximumArtifactCount}. Results will be incomplete as only the first ${maximumArtifactCount} artifacts will be returned`
|
||||||
)
|
)
|
||||||
numberOfPages = maxNumberOfPages
|
numberOfPages = maxNumberOfPages
|
||||||
}
|
}
|
||||||
@@ -81,7 +81,7 @@ export async function listArtifactsPublic(
|
|||||||
// Iterate over any remaining pages
|
// Iterate over any remaining pages
|
||||||
for (
|
for (
|
||||||
currentPageNumber;
|
currentPageNumber;
|
||||||
currentPageNumber < numberOfPages;
|
currentPageNumber <= numberOfPages;
|
||||||
currentPageNumber++
|
currentPageNumber++
|
||||||
) {
|
) {
|
||||||
debug(`Fetching page ${currentPageNumber} of artifact list`)
|
debug(`Fetching page ${currentPageNumber} of artifact list`)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import {OctokitOptions} from '@octokit/core/dist-types/types'
|
import type {OctokitOptions} from '@octokit/core/types'
|
||||||
import {RequestRequestOptions} from '@octokit/types'
|
import {RequestRequestOptions} from '@octokit/types'
|
||||||
|
|
||||||
export type RetryOptions = {
|
export type RetryOptions = {
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import {HttpClient, HttpClientResponse, HttpCodes} from '@actions/http-client'
|
import {HttpClient, HttpClientResponse, HttpCodes} from '@actions/http-client'
|
||||||
import {BearerCredentialHandler} from '@actions/http-client/lib/auth'
|
import {BearerCredentialHandler} from '@actions/http-client/lib/auth'
|
||||||
import {info, debug} from '@actions/core'
|
import {info, debug} from '@actions/core'
|
||||||
import {ArtifactServiceClientJSON} from '../../generated'
|
import {ArtifactServiceClientJSON} from '../../generated/index.js'
|
||||||
import {getResultsServiceUrl, getRuntimeToken} from './config'
|
import {getResultsServiceUrl, getRuntimeToken} from './config.js'
|
||||||
import {getUserAgentString} from './user-agent'
|
import {getUserAgentString} from './user-agent.js'
|
||||||
import {NetworkError, UsageError} from './errors'
|
import {NetworkError, UsageError} from './errors.js'
|
||||||
import {maskSecretUrls} from './util'
|
import {maskSecretUrls} from './util.js'
|
||||||
|
|
||||||
// The twirp http client must implement this interface
|
// The twirp http client must implement this interface
|
||||||
interface Rpc {
|
interface Rpc {
|
||||||
|
|||||||
@@ -97,3 +97,19 @@ export function getUploadChunkTimeout(): number {
|
|||||||
|
|
||||||
return timeout
|
return timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This value can be changed with ACTIONS_ARTIFACT_MAX_ARTIFACT_COUNT variable.
|
||||||
|
// Defaults to 1000 as a safeguard for rate limiting.
|
||||||
|
export function getMaxArtifactListCount(): number {
|
||||||
|
const maxCountVar =
|
||||||
|
process.env['ACTIONS_ARTIFACT_MAX_ARTIFACT_COUNT'] || '1000'
|
||||||
|
|
||||||
|
const maxCount = parseInt(maxCountVar)
|
||||||
|
if (isNaN(maxCount) || maxCount < 1) {
|
||||||
|
throw new Error(
|
||||||
|
'Invalid value set for ACTIONS_ARTIFACT_MAX_ARTIFACT_COUNT env variable'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxCount
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
// This file exists as a CommonJS module to read the version from package.json.
|
||||||
|
// In an ESM package, using `require()` directly in .ts files requires disabling
|
||||||
|
// ESLint rules and doesn't work reliably across all Node.js versions.
|
||||||
|
// By keeping this as a .cjs file, we can use require() naturally and export
|
||||||
|
// the version for the ESM modules to import.
|
||||||
|
const packageJson = require('../../../package.json')
|
||||||
|
module.exports = { version: packageJson.version }
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports
|
import {version} from './package-version.cjs'
|
||||||
const packageJson = require('../../../package.json')
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure that this User Agent String is used in all HTTP calls so that we can monitor telemetry between different versions of this package
|
* Ensure that this User Agent String is used in all HTTP calls so that we can monitor telemetry between different versions of this package
|
||||||
*/
|
*/
|
||||||
export function getUserAgentString(): string {
|
export function getUserAgentString(): string {
|
||||||
return `@actions/artifact-${packageJson.version}`
|
return `@actions/artifact-${version}`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import {getRuntimeToken} from './config'
|
import {getRuntimeToken} from './config.js'
|
||||||
import jwt_decode from 'jwt-decode'
|
import {jwtDecode} from 'jwt-decode'
|
||||||
import {debug, setSecret} from '@actions/core'
|
import {debug, setSecret} from '@actions/core'
|
||||||
|
|
||||||
export interface BackendIds {
|
export interface BackendIds {
|
||||||
@@ -20,7 +20,7 @@ const InvalidJwtError = new Error(
|
|||||||
// workflow run and workflow job run backend ids
|
// workflow run and workflow job run backend ids
|
||||||
export function getBackendIdsFromToken(): BackendIds {
|
export function getBackendIdsFromToken(): BackendIds {
|
||||||
const token = getRuntimeToken()
|
const token = getRuntimeToken()
|
||||||
const decoded = jwt_decode<ActionsToken>(token)
|
const decoded = jwtDecode<ActionsToken>(token)
|
||||||
if (!decoded.scp) {
|
if (!decoded.scp) {
|
||||||
throw InvalidJwtError
|
throw InvalidJwtError
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import {BlobClient, BlockBlobUploadStreamOptions} from '@azure/storage-blob'
|
import {BlobClient, BlockBlobUploadStreamOptions} from '@azure/storage-blob'
|
||||||
import {TransferProgressEvent} from '@azure/core-http'
|
import {TransferProgressEvent} from '@azure/core-http-compat'
|
||||||
import {ZipUploadStream} from './zip'
|
import {ZipUploadStream} from './zip.js'
|
||||||
import {
|
import {
|
||||||
getUploadChunkSize,
|
getUploadChunkSize,
|
||||||
getConcurrency,
|
getConcurrency,
|
||||||
getUploadChunkTimeout
|
getUploadChunkTimeout
|
||||||
} from '../shared/config'
|
} from '../shared/config.js'
|
||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import * as crypto from 'crypto'
|
import * as crypto from 'crypto'
|
||||||
import * as stream from 'stream'
|
import * as stream from 'stream'
|
||||||
import {NetworkError} from '../shared/errors'
|
import {NetworkError} from '../shared/errors.js'
|
||||||
|
|
||||||
export interface BlobUploadResponse {
|
export interface BlobUploadResponse {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {Timestamp} from '../../generated'
|
import {Timestamp} from '../../generated/index.js'
|
||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
|
|
||||||
export function getExpiration(retentionDays?: number): Timestamp | undefined {
|
export function getExpiration(retentionDays?: number): Timestamp | undefined {
|
||||||
|
|||||||
@@ -2,24 +2,24 @@ import * as core from '@actions/core'
|
|||||||
import {
|
import {
|
||||||
UploadArtifactOptions,
|
UploadArtifactOptions,
|
||||||
UploadArtifactResponse
|
UploadArtifactResponse
|
||||||
} from '../shared/interfaces'
|
} from '../shared/interfaces.js'
|
||||||
import {getExpiration} from './retention'
|
import {getExpiration} from './retention.js'
|
||||||
import {validateArtifactName} from './path-and-artifact-name-validation'
|
import {validateArtifactName} from './path-and-artifact-name-validation.js'
|
||||||
import {internalArtifactTwirpClient} from '../shared/artifact-twirp-client'
|
import {internalArtifactTwirpClient} from '../shared/artifact-twirp-client.js'
|
||||||
import {
|
import {
|
||||||
UploadZipSpecification,
|
UploadZipSpecification,
|
||||||
getUploadZipSpecification,
|
getUploadZipSpecification,
|
||||||
validateRootDirectory
|
validateRootDirectory
|
||||||
} from './upload-zip-specification'
|
} from './upload-zip-specification.js'
|
||||||
import {getBackendIdsFromToken} from '../shared/util'
|
import {getBackendIdsFromToken} from '../shared/util.js'
|
||||||
import {uploadZipToBlobStorage} from './blob-upload'
|
import {uploadZipToBlobStorage} from './blob-upload.js'
|
||||||
import {createZipUploadStream} from './zip'
|
import {createZipUploadStream} from './zip.js'
|
||||||
import {
|
import {
|
||||||
CreateArtifactRequest,
|
CreateArtifactRequest,
|
||||||
FinalizeArtifactRequest,
|
FinalizeArtifactRequest,
|
||||||
StringValue
|
StringValue
|
||||||
} from '../../generated'
|
} from '../../generated/index.js'
|
||||||
import {FilesNotFoundError, InvalidResponseError} from '../shared/errors'
|
import {FilesNotFoundError, InvalidResponseError} from '../shared/errors.js'
|
||||||
|
|
||||||
export async function uploadArtifact(
|
export async function uploadArtifact(
|
||||||
name: string,
|
name: string,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
import {info} from '@actions/core'
|
import {info} from '@actions/core'
|
||||||
import {normalize, resolve} from 'path'
|
import {normalize, resolve} from 'path'
|
||||||
import {validateFilePath} from './path-and-artifact-name-validation'
|
import {validateFilePath} from './path-and-artifact-name-validation.js'
|
||||||
|
|
||||||
export interface UploadZipSpecification {
|
export interface UploadZipSpecification {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import * as stream from 'stream'
|
import * as stream from 'stream'
|
||||||
import {realpath} from 'fs/promises'
|
import {realpath} from 'fs/promises'
|
||||||
import * as archiver from 'archiver'
|
import archiver from 'archiver'
|
||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import {UploadZipSpecification} from './upload-zip-specification'
|
import {UploadZipSpecification} from './upload-zip-specification.js'
|
||||||
import {getUploadChunkSize} from '../shared/config'
|
import {getUploadChunkSize} from '../shared/config.js'
|
||||||
|
|
||||||
export const DEFAULT_COMPRESSION_LEVEL = 6
|
export const DEFAULT_COMPRESSION_LEVEL = 6
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
"baseUrl": "./",
|
"baseUrl": "./",
|
||||||
"outDir": "./lib",
|
"outDir": "./lib",
|
||||||
"rootDir": "./src",
|
"rootDir": "./src",
|
||||||
|
"module": "node16",
|
||||||
|
"moduleResolution": "node16",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@actions/core": [
|
"@actions/core": [
|
||||||
"../core"
|
"../core"
|
||||||
|
|||||||
@@ -15,6 +15,14 @@ initiated.
|
|||||||
See [Using artifact attestations to establish provenance for builds](https://docs.github.com/en/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds)
|
See [Using artifact attestations to establish provenance for builds](https://docs.github.com/en/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds)
|
||||||
for more information on artifact attestations.
|
for more information on artifact attestations.
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
- [Usage](#usage)
|
||||||
|
- [attest](#attest)
|
||||||
|
- [attestProvenance](#attestprovenance)
|
||||||
|
- [Attestation](#attestation)
|
||||||
|
- [Sigstore Instance](#sigstore-instance)
|
||||||
|
- [Storage](#storage)
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### `attest`
|
### `attest`
|
||||||
@@ -165,6 +173,74 @@ export type Attestation = {
|
|||||||
For details about the Sigstore bundle format, see the [Bundle protobuf
|
For details about the Sigstore bundle format, see the [Bundle protobuf
|
||||||
specification](https://github.com/sigstore/protobuf-specs/blob/main/protos/sigstore_bundle.proto).
|
specification](https://github.com/sigstore/protobuf-specs/blob/main/protos/sigstore_bundle.proto).
|
||||||
|
|
||||||
|
### createStorageRecord
|
||||||
|
|
||||||
|
The `createStorageRecord` function creates an
|
||||||
|
[artifact metadata storage record](https://docs.github.com/en/rest/orgs/artifact-metadata?apiVersion=2022-11-28#create-artifact-metadata-storage-record)
|
||||||
|
on behalf of an attested artifact. It accepts parameters defining artifact
|
||||||
|
and package registry details. The storage record contains metadata about where the artifact is stored on a given package registry.
|
||||||
|
|
||||||
|
```js
|
||||||
|
const { createStorageRecord } = require('@actions/attest');
|
||||||
|
const core = require('@actions/core');
|
||||||
|
|
||||||
|
async function run() {
|
||||||
|
// In order to persist attestations to the repo, this should be a token with
|
||||||
|
// repository write permissions.
|
||||||
|
const ghToken = core.getInput('gh-token');
|
||||||
|
|
||||||
|
const record = await createStorageRecord(
|
||||||
|
artifactOptions: {
|
||||||
|
name: 'my-artifact-name',
|
||||||
|
digest: { 'sha256': '36ab4667...'},
|
||||||
|
version: "v1.0.0"
|
||||||
|
},
|
||||||
|
packageRegistryOptions: {
|
||||||
|
registryUrl: "https://my-fave-pkg-registry.com"
|
||||||
|
},
|
||||||
|
token: ghToken
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
run();
|
||||||
|
```
|
||||||
|
|
||||||
|
The `createStorageRecord` function supports the following options:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Artifact details to associate the record with
|
||||||
|
export type ArtifactOptions = {
|
||||||
|
// The name of the artifact
|
||||||
|
name: string
|
||||||
|
// The digest of the artifact
|
||||||
|
digest: string
|
||||||
|
// The version of the artifact
|
||||||
|
version?: string
|
||||||
|
// The status of the artifact
|
||||||
|
status?: string
|
||||||
|
}
|
||||||
|
// Includes details about the package registry the artifact was published to
|
||||||
|
export type PackageRegistryOptions = {
|
||||||
|
// The URL of the package registry
|
||||||
|
registryUrl: string
|
||||||
|
// The URL of the artifact in the package registry
|
||||||
|
artifactUrl?: string
|
||||||
|
// The package registry repository the artifact was published to.
|
||||||
|
repo?: string
|
||||||
|
// The path of the artifact in the package registry repository.
|
||||||
|
path?: string
|
||||||
|
}
|
||||||
|
// GitHub token for writing attestations.
|
||||||
|
token: string
|
||||||
|
// Optional parameters for the write operation.
|
||||||
|
// The number of times to retry the request.
|
||||||
|
retryAttempts?: number
|
||||||
|
// HTTP headers to include in request to Artifact Metadata API.
|
||||||
|
headers?: RequestHeaders
|
||||||
|
```
|
||||||
|
|
||||||
## Sigstore Instance
|
## Sigstore Instance
|
||||||
|
|
||||||
When generating the signed attestation there are two different Sigstore
|
When generating the signed attestation there are two different Sigstore
|
||||||
|
|||||||
+37
-11
@@ -1,10 +1,35 @@
|
|||||||
# @actions/attest Releases
|
# @actions/attest Releases
|
||||||
|
|
||||||
### 1.6.0
|
## 3.0.0
|
||||||
|
|
||||||
|
- **Breaking change**: Package is now ESM-only
|
||||||
|
- CommonJS consumers must use dynamic `import()` instead of `require()`
|
||||||
|
- Bump `@actions/core` to `^3.0.0`
|
||||||
|
- Bump `@actions/http-client` to `^4.0.0`
|
||||||
|
|
||||||
|
## 2.2.1
|
||||||
|
|
||||||
|
- Bump `@actions/http-client` to `3.0.2`
|
||||||
|
- Bump `undici` to `6.23.0`
|
||||||
|
|
||||||
|
## 2.2.0
|
||||||
|
|
||||||
|
- Bump @actions/core from 1.11.1 to 2.0.2
|
||||||
|
- Bump @actions/github from 6.0.0 to 7.0.0
|
||||||
|
- Bump @actions/http-client from 2.2.3 to 3.0.1
|
||||||
|
|
||||||
|
## 2.0.0
|
||||||
|
|
||||||
|
- Add support for Node 24 [#2110](https://github.com/actions/toolkit/pull/2110)
|
||||||
|
- Bump @sigstore/bundle from 3.0.0 to 3.1.0
|
||||||
|
- Bump @sigstore/sign from 3.0.0 to 3.1.0
|
||||||
|
- Bump jose from 5.2.3 to 5.10.0
|
||||||
|
|
||||||
|
## 1.6.0
|
||||||
|
|
||||||
- Update `buildSLSAProvenancePredicate` to populate `workflow.ref` field from the `ref` claim in the OIDC token [#1969](https://github.com/actions/toolkit/pull/1969)
|
- Update `buildSLSAProvenancePredicate` to populate `workflow.ref` field from the `ref` claim in the OIDC token [#1969](https://github.com/actions/toolkit/pull/1969)
|
||||||
|
|
||||||
### 1.5.0
|
## 1.5.0
|
||||||
|
|
||||||
- Bump @actions/core from 1.10.1 to 1.11.1 [#1847](https://github.com/actions/toolkit/pull/1847)
|
- Bump @actions/core from 1.10.1 to 1.11.1 [#1847](https://github.com/actions/toolkit/pull/1847)
|
||||||
- Bump @sigstore/bundle from 2.3.2 to 3.0.0 [#1846](https://github.com/actions/toolkit/pull/1846)
|
- Bump @sigstore/bundle from 2.3.2 to 3.0.0 [#1846](https://github.com/actions/toolkit/pull/1846)
|
||||||
@@ -12,23 +37,24 @@
|
|||||||
- Support for generating multi-subject attestations [#1864](https://github.com/actions/toolkit/pull/1865)
|
- Support for generating multi-subject attestations [#1864](https://github.com/actions/toolkit/pull/1865)
|
||||||
- Fix bug in `buildSLSAProvenancePredicate` related to `workflow_ref` OIDC token claims containing the "@" symbol in the tag name [#1863](https://github.com/actions/toolkit/pull/1863)
|
- Fix bug in `buildSLSAProvenancePredicate` related to `workflow_ref` OIDC token claims containing the "@" symbol in the tag name [#1863](https://github.com/actions/toolkit/pull/1863)
|
||||||
|
|
||||||
### 1.4.2
|
## 1.4.2
|
||||||
|
|
||||||
- Fix bug in `buildSLSAProvenancePredicate`/`attestProvenance` when generating provenance statement for enterprise account using customized OIDC issuer value [#1823](https://github.com/actions/toolkit/pull/1823)
|
- Fix bug in `buildSLSAProvenancePredicate`/`attestProvenance` when generating provenance statement for enterprise account using customized OIDC issuer value [#1823](https://github.com/actions/toolkit/pull/1823)
|
||||||
|
|
||||||
### 1.4.1
|
## 1.4.1
|
||||||
|
|
||||||
- Bump @actions/http-client from 2.2.1 to 2.2.3 [#1805](https://github.com/actions/toolkit/pull/1805)
|
- Bump @actions/http-client from 2.2.1 to 2.2.3 [#1805](https://github.com/actions/toolkit/pull/1805)
|
||||||
|
|
||||||
### 1.4.0
|
## 1.4.0
|
||||||
|
|
||||||
- Add new `headers` parameter to the `attest` and `attestProvenance` functions [#1790](https://github.com/actions/toolkit/pull/1790)
|
- Add new `headers` parameter to the `attest` and `attestProvenance` functions [#1790](https://github.com/actions/toolkit/pull/1790)
|
||||||
- Update `buildSLSAProvenancePredicate`/`attestProvenance` to automatically derive default OIDC issuer URL from current execution context [#1796](https://github.com/actions/toolkit/pull/1796)
|
- Update `buildSLSAProvenancePredicate`/`attestProvenance` to automatically derive default OIDC issuer URL from current execution context [#1796](https://github.com/actions/toolkit/pull/1796)
|
||||||
### 1.3.1
|
|
||||||
|
## 1.3.1
|
||||||
|
|
||||||
- Fix bug with proxy support when retrieving JWKS for OIDC issuer [#1776](https://github.com/actions/toolkit/pull/1776)
|
- Fix bug with proxy support when retrieving JWKS for OIDC issuer [#1776](https://github.com/actions/toolkit/pull/1776)
|
||||||
|
|
||||||
### 1.3.0
|
## 1.3.0
|
||||||
|
|
||||||
- Dynamic construction of Sigstore API URLs [#1735](https://github.com/actions/toolkit/pull/1735)
|
- Dynamic construction of Sigstore API URLs [#1735](https://github.com/actions/toolkit/pull/1735)
|
||||||
- Switch to new GH provenance build type [#1745](https://github.com/actions/toolkit/pull/1745)
|
- Switch to new GH provenance build type [#1745](https://github.com/actions/toolkit/pull/1745)
|
||||||
@@ -36,21 +62,21 @@
|
|||||||
- Bump @sigstore/bundle from 2.3.0 to 2.3.2 [#1738](https://github.com/actions/toolkit/pull/1738)
|
- Bump @sigstore/bundle from 2.3.0 to 2.3.2 [#1738](https://github.com/actions/toolkit/pull/1738)
|
||||||
- Bump @sigstore/sign from 2.3.0 to 2.3.2 [#1738](https://github.com/actions/toolkit/pull/1738)
|
- Bump @sigstore/sign from 2.3.0 to 2.3.2 [#1738](https://github.com/actions/toolkit/pull/1738)
|
||||||
|
|
||||||
### 1.2.1
|
## 1.2.1
|
||||||
|
|
||||||
- Retry request on attestation persistence failure [#1725](https://github.com/actions/toolkit/pull/1725)
|
- Retry request on attestation persistence failure [#1725](https://github.com/actions/toolkit/pull/1725)
|
||||||
|
|
||||||
### 1.2.0
|
## 1.2.0
|
||||||
|
|
||||||
- Generate attestations using the v0.3 Sigstore bundle format [#1701](https://github.com/actions/toolkit/pull/1701)
|
- Generate attestations using the v0.3 Sigstore bundle format [#1701](https://github.com/actions/toolkit/pull/1701)
|
||||||
- Bump @sigstore/bundle from 2.2.0 to 2.3.0 [#1701](https://github.com/actions/toolkit/pull/1701)
|
- Bump @sigstore/bundle from 2.2.0 to 2.3.0 [#1701](https://github.com/actions/toolkit/pull/1701)
|
||||||
- Bump @sigstore/sign from 2.2.3 to 2.3.0 [#1701](https://github.com/actions/toolkit/pull/1701)
|
- Bump @sigstore/sign from 2.2.3 to 2.3.0 [#1701](https://github.com/actions/toolkit/pull/1701)
|
||||||
- Remove dependency on make-fetch-happen [#1714](https://github.com/actions/toolkit/pull/1714)
|
- Remove dependency on make-fetch-happen [#1714](https://github.com/actions/toolkit/pull/1714)
|
||||||
|
|
||||||
### 1.1.0
|
## 1.1.0
|
||||||
|
|
||||||
- Updates the `attestProvenance` function to retrieve a token from the GitHub OIDC provider and use the token claims to populate the provenance statement [#1693](https://github.com/actions/toolkit/pull/1693)
|
- Updates the `attestProvenance` function to retrieve a token from the GitHub OIDC provider and use the token claims to populate the provenance statement [#1693](https://github.com/actions/toolkit/pull/1693)
|
||||||
|
|
||||||
### 1.0.0
|
## 1.0.0
|
||||||
|
|
||||||
- Initial release
|
- Initial release
|
||||||
|
|||||||
@@ -0,0 +1,137 @@
|
|||||||
|
import {MockAgent, setGlobalDispatcher} from 'undici'
|
||||||
|
import {createStorageRecord} from '../src/artifactMetadata'
|
||||||
|
|
||||||
|
describe('createStorageRecord', () => {
|
||||||
|
const originalEnv = process.env
|
||||||
|
const token = 'token'
|
||||||
|
const headers = {'X-GitHub-Foo': 'true'}
|
||||||
|
|
||||||
|
const artifactOptions = {
|
||||||
|
name: 'my-lib',
|
||||||
|
version: '1.0.0',
|
||||||
|
digest: `sha256:${'a'.repeat(64)}`
|
||||||
|
}
|
||||||
|
const packageRegistryOptions = {
|
||||||
|
registryUrl: 'https://my-registry.org'
|
||||||
|
}
|
||||||
|
|
||||||
|
const mockAgent = new MockAgent()
|
||||||
|
setGlobalDispatcher(mockAgent)
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
process.env = {
|
||||||
|
...originalEnv,
|
||||||
|
GITHUB_REPOSITORY: 'foo/bar'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
process.env = originalEnv
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('when the api call is successful', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mockAgent
|
||||||
|
.get('https://api.github.com')
|
||||||
|
.intercept({
|
||||||
|
path: '/orgs/foo/artifacts/metadata/storage-record',
|
||||||
|
method: 'POST',
|
||||||
|
headers: {authorization: `token ${token}`, ...headers},
|
||||||
|
body: JSON.stringify({
|
||||||
|
name: 'my-lib',
|
||||||
|
version: '1.0.0',
|
||||||
|
digest: `sha256:${'a'.repeat(64)}`,
|
||||||
|
registry_url: 'https://my-registry.org'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.reply(200, {storage_records: [{id: 123}, {id: 456}]})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('persists the storage record', async () => {
|
||||||
|
await expect(
|
||||||
|
createStorageRecord(
|
||||||
|
artifactOptions,
|
||||||
|
packageRegistryOptions,
|
||||||
|
token,
|
||||||
|
undefined,
|
||||||
|
headers
|
||||||
|
)
|
||||||
|
).resolves.toEqual([123, 456])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('when the api call fails', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mockAgent
|
||||||
|
.get('https://api.github.com')
|
||||||
|
.intercept({
|
||||||
|
path: '/orgs/foo/artifacts/metadata/storage-record',
|
||||||
|
method: 'POST',
|
||||||
|
headers: {authorization: `token ${token}`},
|
||||||
|
body: JSON.stringify({
|
||||||
|
name: 'my-lib',
|
||||||
|
version: '1.0.0',
|
||||||
|
digest: `sha256:${'a'.repeat(64)}`,
|
||||||
|
registry_url: 'https://my-registry.org'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.reply(500, 'oops')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws an error', async () => {
|
||||||
|
await expect(
|
||||||
|
createStorageRecord(
|
||||||
|
artifactOptions,
|
||||||
|
packageRegistryOptions,
|
||||||
|
token,
|
||||||
|
0,
|
||||||
|
headers
|
||||||
|
)
|
||||||
|
).rejects.toThrow(/oops/)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('when the api call fails but succeeds on retry', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const pool = mockAgent.get('https://api.github.com')
|
||||||
|
|
||||||
|
pool
|
||||||
|
.intercept({
|
||||||
|
path: '/orgs/foo/artifacts/metadata/storage-record',
|
||||||
|
method: 'POST',
|
||||||
|
headers: {authorization: `token ${token}`},
|
||||||
|
body: JSON.stringify({
|
||||||
|
...artifactOptions,
|
||||||
|
registry_url: packageRegistryOptions.registryUrl
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.reply(500, 'oops')
|
||||||
|
.times(1)
|
||||||
|
|
||||||
|
pool
|
||||||
|
.intercept({
|
||||||
|
path: '/orgs/foo/artifacts/metadata/storage-record',
|
||||||
|
method: 'POST',
|
||||||
|
headers: {authorization: `token ${token}`},
|
||||||
|
body: JSON.stringify({
|
||||||
|
...artifactOptions,
|
||||||
|
registry_url: packageRegistryOptions.registryUrl
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.reply(200, {storage_records: [{id: 123}, {id: 456}]})
|
||||||
|
.times(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('persists the storage record', async () => {
|
||||||
|
await expect(
|
||||||
|
createStorageRecord(
|
||||||
|
artifactOptions,
|
||||||
|
packageRegistryOptions,
|
||||||
|
token,
|
||||||
|
undefined,
|
||||||
|
headers
|
||||||
|
)
|
||||||
|
).resolves.toEqual([123, 456])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
Generated
+413
-1829
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/attest",
|
"name": "@actions/attest",
|
||||||
"version": "1.6.0",
|
"version": "3.0.0",
|
||||||
"description": "Actions attestation lib",
|
"description": "Actions attestation lib",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"github",
|
"github",
|
||||||
@@ -9,8 +9,15 @@
|
|||||||
],
|
],
|
||||||
"homepage": "https://github.com/actions/toolkit/tree/main/packages/attest",
|
"homepage": "https://github.com/actions/toolkit/tree/main/packages/attest",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"type": "module",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "lib/index.d.ts",
|
"types": "lib/index.d.ts",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"types": "./lib/index.d.ts",
|
||||||
|
"import": "./lib/index.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"directories": {
|
"directories": {
|
||||||
"lib": "lib",
|
"lib": "lib",
|
||||||
"test": "__tests__"
|
"test": "__tests__"
|
||||||
@@ -35,24 +42,19 @@
|
|||||||
"url": "https://github.com/actions/toolkit/issues"
|
"url": "https://github.com/actions/toolkit/issues"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sigstore/mock": "^0.8.0",
|
"@sigstore/mock": "^0.10.0",
|
||||||
"@sigstore/rekor-types": "^3.0.0",
|
"@sigstore/rekor-types": "^3.0.0",
|
||||||
"@types/jsonwebtoken": "^9.0.6",
|
"@types/jsonwebtoken": "^9.0.6",
|
||||||
"nock": "^13.5.1",
|
"nock": "^13.5.1",
|
||||||
"undici": "^5.28.5"
|
"undici": "^6.23.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.11.1",
|
"@actions/core": "^3.0.0",
|
||||||
"@actions/github": "^6.0.0",
|
"@actions/github": "^9.0.0",
|
||||||
"@actions/http-client": "^2.2.3",
|
"@actions/http-client": "^4.0.0",
|
||||||
"@octokit/plugin-retry": "^6.0.1",
|
"@octokit/plugin-retry": "^8.0.3",
|
||||||
"@sigstore/bundle": "^3.0.0",
|
"@sigstore/bundle": "^3.1.0",
|
||||||
"@sigstore/sign": "^3.0.0",
|
"@sigstore/sign": "^3.1.0",
|
||||||
"jose": "^5.2.3"
|
"jose": "^5.10.0"
|
||||||
},
|
|
||||||
"overrides": {
|
|
||||||
"@octokit/plugin-retry": {
|
|
||||||
"@octokit/core": "^5.2.0"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
import * as github from '@actions/github'
|
||||||
|
import {retry} from '@octokit/plugin-retry'
|
||||||
|
import {RequestHeaders} from '@octokit/types'
|
||||||
|
|
||||||
|
const CREATE_STORAGE_RECORD_REQUEST =
|
||||||
|
'POST /orgs/{owner}/artifacts/metadata/storage-record'
|
||||||
|
const DEFAULT_RETRY_COUNT = 5
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options for creating a storage record for an attested artifact.
|
||||||
|
*/
|
||||||
|
export type ArtifactOptions = {
|
||||||
|
// Includes details about the attested artifact
|
||||||
|
// The name of the artifact
|
||||||
|
name: string
|
||||||
|
// The digest of the artifact
|
||||||
|
digest: string
|
||||||
|
// The version of the artifact
|
||||||
|
version?: string
|
||||||
|
// The status of the artifact
|
||||||
|
status?: string
|
||||||
|
}
|
||||||
|
// Includes details about the package registry the artifact was published to
|
||||||
|
export type PackageRegistryOptions = {
|
||||||
|
// The URL of the package registry
|
||||||
|
registryUrl: string
|
||||||
|
// The URL of the artifact in the package registry
|
||||||
|
artifactUrl?: string
|
||||||
|
// The package registry repository the artifact was published to.
|
||||||
|
repo?: string
|
||||||
|
// The path of the artifact in the package registry repository.
|
||||||
|
path?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes a storage record on behalf of an artifact that has been attested
|
||||||
|
* @param artifactOptions - parameters for the storage record API request.
|
||||||
|
* @param packageRegistryOptions - parameters for the package registry API request.
|
||||||
|
* @param token - GitHub token used to authenticate the request.
|
||||||
|
* @param retryAttempts - The number of retries to attempt if the request fails.
|
||||||
|
* @param headers - Additional headers to include in the request.
|
||||||
|
*
|
||||||
|
* @returns The ID of the storage record.
|
||||||
|
* @throws Error if the storage record fails to persist.
|
||||||
|
*/
|
||||||
|
export async function createStorageRecord(
|
||||||
|
artifactOptions: ArtifactOptions,
|
||||||
|
packageRegistryOptions: PackageRegistryOptions,
|
||||||
|
token: string,
|
||||||
|
retryAttempts?: number,
|
||||||
|
headers?: RequestHeaders
|
||||||
|
): Promise<number[]> {
|
||||||
|
const retries = retryAttempts ?? DEFAULT_RETRY_COUNT
|
||||||
|
const octokit = github.getOctokit(token, {retry: {retries}}, retry)
|
||||||
|
try {
|
||||||
|
const response = await octokit.request(CREATE_STORAGE_RECORD_REQUEST, {
|
||||||
|
owner: github.context.repo.owner,
|
||||||
|
headers,
|
||||||
|
...buildRequestParams(artifactOptions, packageRegistryOptions)
|
||||||
|
})
|
||||||
|
|
||||||
|
const data =
|
||||||
|
typeof response.data == 'string'
|
||||||
|
? JSON.parse(response.data)
|
||||||
|
: response.data
|
||||||
|
|
||||||
|
return data?.storage_records.map((r: {id: number}) => r.id)
|
||||||
|
} catch (err) {
|
||||||
|
const message = err instanceof Error ? err.message : err
|
||||||
|
throw new Error(`Failed to persist storage record: ${message}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildRequestParams(
|
||||||
|
artifactOptions: ArtifactOptions,
|
||||||
|
packageRegistryOptions: PackageRegistryOptions
|
||||||
|
): Record<string, unknown> {
|
||||||
|
const {registryUrl, artifactUrl, ...rest} = packageRegistryOptions
|
||||||
|
return {
|
||||||
|
...artifactOptions,
|
||||||
|
registry_url: registryUrl,
|
||||||
|
artifact_url: artifactUrl,
|
||||||
|
...rest
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
import {bundleToJSON} from '@sigstore/bundle'
|
import {bundleToJSON} from '@sigstore/bundle'
|
||||||
import {X509Certificate} from 'crypto'
|
import {X509Certificate} from 'crypto'
|
||||||
import {SigstoreInstance, signingEndpoints} from './endpoints'
|
import {SigstoreInstance, signingEndpoints} from './endpoints.js'
|
||||||
import {buildIntotoStatement} from './intoto'
|
import {buildIntotoStatement} from './intoto.js'
|
||||||
import {Payload, signPayload} from './sign'
|
import {Payload, signPayload} from './sign.js'
|
||||||
import {writeAttestation} from './store'
|
import {writeAttestation} from './store.js'
|
||||||
|
|
||||||
import type {Bundle} from '@sigstore/sign'
|
import type {Bundle} from '@sigstore/sign'
|
||||||
import type {Attestation, Predicate, Subject} from './shared.types'
|
import type {Attestation, Predicate, Subject} from './shared.types.js'
|
||||||
|
|
||||||
const INTOTO_PAYLOAD_TYPE = 'application/vnd.in-toto+json'
|
const INTOTO_PAYLOAD_TYPE = 'application/vnd.in-toto+json'
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
export {AttestOptions, attest} from './attest'
|
export {
|
||||||
|
createStorageRecord,
|
||||||
|
ArtifactOptions,
|
||||||
|
PackageRegistryOptions
|
||||||
|
} from './artifactMetadata.js'
|
||||||
|
export {AttestOptions, attest} from './attest.js'
|
||||||
export {
|
export {
|
||||||
AttestProvenanceOptions,
|
AttestProvenanceOptions,
|
||||||
attestProvenance,
|
attestProvenance,
|
||||||
buildSLSAProvenancePredicate
|
buildSLSAProvenancePredicate
|
||||||
} from './provenance'
|
} from './provenance.js'
|
||||||
|
|
||||||
export type {SerializedBundle} from '@sigstore/bundle'
|
export type {SerializedBundle} from '@sigstore/bundle'
|
||||||
export type {Attestation, Predicate, Subject} from './shared.types'
|
export type {Attestation, Predicate, Subject} from './shared.types.js'
|
||||||
|
export type {SigstoreInstance} from './endpoints.js'
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {Predicate, Subject} from './shared.types'
|
import {Predicate, Subject} from './shared.types.js'
|
||||||
|
|
||||||
const INTOTO_STATEMENT_V1_TYPE = 'https://in-toto.io/Statement/v1'
|
const INTOTO_STATEMENT_V1_TYPE = 'https://in-toto.io/Statement/v1'
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {attest, AttestOptions} from './attest'
|
import {attest, AttestOptions} from './attest.js'
|
||||||
import {getIDTokenClaims} from './oidc'
|
import {getIDTokenClaims} from './oidc.js'
|
||||||
import type {Attestation, Predicate} from './shared.types'
|
import type {Attestation, Predicate} from './shared.types.js'
|
||||||
|
|
||||||
const SLSA_PREDICATE_V1_TYPE = 'https://slsa.dev/provenance/v1'
|
const SLSA_PREDICATE_V1_TYPE = 'https://slsa.dev/provenance/v1'
|
||||||
const GITHUB_BUILD_TYPE = 'https://actions.github.io/buildtypes/workflow/v1'
|
const GITHUB_BUILD_TYPE = 'https://actions.github.io/buildtypes/workflow/v1'
|
||||||
|
|||||||
@@ -29,7 +29,11 @@ export const writeAttestation = async (
|
|||||||
owner: github.context.repo.owner,
|
owner: github.context.repo.owner,
|
||||||
repo: github.context.repo.repo,
|
repo: github.context.repo.repo,
|
||||||
headers: options.headers,
|
headers: options.headers,
|
||||||
data: {bundle: attestation}
|
bundle: attestation as {
|
||||||
|
mediaType?: string
|
||||||
|
verificationMaterial?: {[key: string]: unknown}
|
||||||
|
dsseEnvelope?: {[key: string]: unknown}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const data =
|
const data =
|
||||||
|
|||||||
@@ -4,7 +4,9 @@
|
|||||||
"baseUrl": "./",
|
"baseUrl": "./",
|
||||||
"outDir": "./lib",
|
"outDir": "./lib",
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"rootDir": "./src"
|
"rootDir": "./src",
|
||||||
|
"module": "node16",
|
||||||
|
"moduleResolution": "node16"
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"./src"
|
"./src"
|
||||||
|
|||||||
Vendored
+97
-46
@@ -1,22 +1,73 @@
|
|||||||
# @actions/cache Releases
|
# @actions/cache Releases
|
||||||
|
|
||||||
### 4.0.3
|
## 6.0.0
|
||||||
|
|
||||||
|
- **Breaking change**: Package is now ESM-only
|
||||||
|
- CommonJS consumers must use dynamic `import()` instead of `require()`
|
||||||
|
|
||||||
|
## 5.0.5
|
||||||
|
|
||||||
|
- Bump `@actions/glob` to `0.5.1`
|
||||||
|
|
||||||
|
## 5.0.4
|
||||||
|
|
||||||
|
- Bump `@actions/http-client` to `3.0.2`
|
||||||
|
|
||||||
|
## 5.0.3
|
||||||
|
|
||||||
|
Prevent retries for rate limited cache operations [2243](https://github.com/actions/toolkit/pull/2243).
|
||||||
|
|
||||||
|
## 5.0.1
|
||||||
|
|
||||||
|
- Fix Node.js 24 punycode deprecation warning by updating `@azure/storage-blob` from `^12.13.0` to `^12.29.1` [#2213](https://github.com/actions/toolkit/pull/2213)
|
||||||
|
- Newer storage-blob uses `@azure/core-rest-pipeline` instead of deprecated `@azure/core-http`, which eliminates the transitive dependency on `node-fetch@2` → `whatwg-url@5` → `tr46@0.0.3` that used the deprecated punycode module
|
||||||
|
|
||||||
|
## 5.0.0
|
||||||
|
|
||||||
|
- Remove `@azure/ms-rest-js` dependency [#2197](https://github.com/actions/toolkit/pull/2197)
|
||||||
|
- The `TransferProgressEvent` type is now imported from `@azure/core-rest-pipeline` instead of `@azure/ms-rest-js`
|
||||||
|
- Bump `@actions/core` from `^1.11.1` to `^2.0.0` [#2198](https://github.com/actions/toolkit/pull/2198)
|
||||||
|
- Bump `@actions/exec` from `^1.0.1` to `^2.0.0` [#2198](https://github.com/actions/toolkit/pull/2198)
|
||||||
|
- Bump `@actions/glob` from `^0.1.0` to `^0.5.0` [#2198](https://github.com/actions/toolkit/pull/2198)
|
||||||
|
- Bump `@actions/http-client` from `^2.1.1` to `^3.0.0` [#2198](https://github.com/actions/toolkit/pull/2198)
|
||||||
|
- Bump `@actions/io` from `^1.0.1` to `^2.0.0` [#2198](https://github.com/actions/toolkit/pull/2198)
|
||||||
|
- Add support for Node.js 24 [#2110](https://github.com/actions/toolkit/pull/2110)
|
||||||
|
- Add `node-fetch` override to resolve audit vulnerabilities [#2110](https://github.com/actions/toolkit/pull/2110)
|
||||||
|
|
||||||
|
## 4.1.0
|
||||||
|
|
||||||
|
- Remove client side 10GiB cache size limit check & update twirp client [#2118](https://github.com/actions/toolkit/pull/2118)
|
||||||
|
|
||||||
|
## 4.0.5
|
||||||
|
|
||||||
|
- Reintroduce @protobuf-ts/runtime-rpc as a runtime dependency [#2113](https://github.com/actions/toolkit/pull/2113)
|
||||||
|
|
||||||
|
## 4.0.4
|
||||||
|
|
||||||
|
⚠️ Faulty patch release. Upgrade to 4.0.5 instead.
|
||||||
|
|
||||||
|
- Optimized cache dependencies by moving `@protobuf-ts/plugin` to dev dependencies [#2106](https://github.com/actions/toolkit/pull/2106)
|
||||||
|
- Improved cache service availability determination for different cache service versions (v1 and v2) [#2100](https://github.com/actions/toolkit/pull/2100)
|
||||||
|
- Enhanced server error handling: 5xx HTTP errors are now logged as errors instead of warnings [#2099](https://github.com/actions/toolkit/pull/2099)
|
||||||
|
- Fixed cache hit logging to properly distinguish between exact key matches and restore key matches [#2101](https://github.com/actions/toolkit/pull/2101)
|
||||||
|
|
||||||
|
## 4.0.3
|
||||||
|
|
||||||
- Added masking for Shared Access Signature (SAS) cache entry URLs [#1982](https://github.com/actions/toolkit/pull/1982)
|
- Added masking for Shared Access Signature (SAS) cache entry URLs [#1982](https://github.com/actions/toolkit/pull/1982)
|
||||||
- Improved debugging by logging both the cache version alongside the keys requested when a cache restore fails [#1994](https://github.com/actions/toolkit/pull/1994)
|
- Improved debugging by logging both the cache version alongside the keys requested when a cache restore fails [#1994](https://github.com/actions/toolkit/pull/1994)
|
||||||
|
|
||||||
### 4.0.2
|
## 4.0.2
|
||||||
|
|
||||||
- Wrap create failures in ReserveCacheError [#1966](https://github.com/actions/toolkit/pull/1966)
|
- Wrap create failures in ReserveCacheError [#1966](https://github.com/actions/toolkit/pull/1966)
|
||||||
|
|
||||||
### 4.0.1
|
## 4.0.1
|
||||||
|
|
||||||
- Remove runtime dependency on `twirp-ts` [#1947](https://github.com/actions/toolkit/pull/1947)
|
- Remove runtime dependency on `twirp-ts` [#1947](https://github.com/actions/toolkit/pull/1947)
|
||||||
- Cache miss as debug, not warning annotation [#1954](https://github.com/actions/toolkit/pull/1954)
|
- Cache miss as debug, not warning annotation [#1954](https://github.com/actions/toolkit/pull/1954)
|
||||||
|
|
||||||
### 4.0.0
|
## 4.0.0
|
||||||
|
|
||||||
#### Important changes
|
### Important changes
|
||||||
|
|
||||||
The cache backend service has been rewritten from the ground up for improved performance and reliability. The [@actions/cache](https://github.com/actions/toolkit/tree/main/packages/cache) package now integrates with the new cache service (v2) APIs.
|
The cache backend service has been rewritten from the ground up for improved performance and reliability. The [@actions/cache](https://github.com/actions/toolkit/tree/main/packages/cache) package now integrates with the new cache service (v2) APIs.
|
||||||
|
|
||||||
@@ -30,182 +81,182 @@ Upgrading to the recommended version should not break or require any changes to
|
|||||||
|
|
||||||
Read more about the change & access the migration guide: [reference to the announcement](https://github.com/actions/toolkit/discussions/1890).
|
Read more about the change & access the migration guide: [reference to the announcement](https://github.com/actions/toolkit/discussions/1890).
|
||||||
|
|
||||||
#### Minor changes
|
### Minor changes
|
||||||
|
|
||||||
- Update `@actions/core` to `1.11.0`
|
- Update `@actions/core` to `1.11.0`
|
||||||
- Update `semver` `6.3.1`
|
- Update `semver` `6.3.1`
|
||||||
- Add `twirp-ts` `2.5.0` to dependencies
|
- Add `twirp-ts` `2.5.0` to dependencies
|
||||||
|
|
||||||
### 3.3.0
|
## 3.3.0
|
||||||
|
|
||||||
- Update `@actions/core` to `1.11.1`
|
- Update `@actions/core` to `1.11.1`
|
||||||
- Remove dependency on `uuid` package [#1824](https://github.com/actions/toolkit/pull/1824), [#1842](https://github.com/actions/toolkit/pull/1842)
|
- Remove dependency on `uuid` package [#1824](https://github.com/actions/toolkit/pull/1824), [#1842](https://github.com/actions/toolkit/pull/1842)
|
||||||
|
|
||||||
### 3.2.4
|
## 3.2.4
|
||||||
|
|
||||||
- Updated `isGhes` check to include `.ghe.com` and `.ghe.localhost` as accepted hosts
|
- Updated `isGhes` check to include `.ghe.com` and `.ghe.localhost` as accepted hosts
|
||||||
|
|
||||||
### 3.2.3
|
## 3.2.3
|
||||||
|
|
||||||
- Fixed a bug that mutated path arguments to `getCacheVersion` [#1378](https://github.com/actions/toolkit/pull/1378)
|
- Fixed a bug that mutated path arguments to `getCacheVersion` [#1378](https://github.com/actions/toolkit/pull/1378)
|
||||||
|
|
||||||
### 3.2.2
|
## 3.2.2
|
||||||
|
|
||||||
- Add new default cache download method to improve performance and reduce hangs [#1484](https://github.com/actions/toolkit/pull/1484)
|
- Add new default cache download method to improve performance and reduce hangs [#1484](https://github.com/actions/toolkit/pull/1484)
|
||||||
|
|
||||||
### 3.2.1
|
## 3.2.1
|
||||||
|
|
||||||
- Updated @azure/storage-blob to `v12.13.0`
|
- Updated @azure/storage-blob to `v12.13.0`
|
||||||
|
|
||||||
### 3.2.0
|
## 3.2.0
|
||||||
|
|
||||||
- Add `lookupOnly` to cache restore `DownloadOptions`.
|
- Add `lookupOnly` to cache restore `DownloadOptions`.
|
||||||
|
|
||||||
### 3.1.4
|
## 3.1.4
|
||||||
|
|
||||||
- Fix zstd not being used due to `zstd --version` output change in zstd 1.5.4 release. See [#1353](https://github.com/actions/toolkit/pull/1353).
|
- Fix zstd not being used due to `zstd --version` output change in zstd 1.5.4 release. See [#1353](https://github.com/actions/toolkit/pull/1353).
|
||||||
|
|
||||||
### 3.1.3
|
## 3.1.3
|
||||||
|
|
||||||
- Fix to prevent from setting MYSYS environement variable globally [#1329](https://github.com/actions/toolkit/pull/1329).
|
- Fix to prevent from setting MYSYS environement variable globally [#1329](https://github.com/actions/toolkit/pull/1329).
|
||||||
|
|
||||||
### 3.1.2
|
## 3.1.2
|
||||||
|
|
||||||
- Fix issue with symlink restoration on windows.
|
- Fix issue with symlink restoration on windows.
|
||||||
|
|
||||||
### 3.1.1
|
## 3.1.1
|
||||||
|
|
||||||
- Reverted changes in 3.1.0 to fix issue with symlink restoration on windows.
|
- Reverted changes in 3.1.0 to fix issue with symlink restoration on windows.
|
||||||
- Added support for verbose logging about cache version during cache miss.
|
- Added support for verbose logging about cache version during cache miss.
|
||||||
|
|
||||||
### 3.1.0
|
## 3.1.0
|
||||||
|
|
||||||
- Update actions/cache on windows to use gnu tar and zstd by default
|
- Update actions/cache on windows to use gnu tar and zstd by default
|
||||||
- Update actions/cache on windows to fallback to bsdtar and zstd if gnu tar is not available.
|
- Update actions/cache on windows to fallback to bsdtar and zstd if gnu tar is not available.
|
||||||
- Added support for fallback to gzip to restore old caches on windows.
|
- Added support for fallback to gzip to restore old caches on windows.
|
||||||
|
|
||||||
### 3.1.0-beta.3
|
## 3.1.0-beta.3
|
||||||
|
|
||||||
- Bug Fixes for fallback to gzip to restore old caches on windows and bsdtar if gnutar is not available.
|
- Bug Fixes for fallback to gzip to restore old caches on windows and bsdtar if gnutar is not available.
|
||||||
|
|
||||||
### 3.1.0-beta.2
|
## 3.1.0-beta.2
|
||||||
|
|
||||||
- Added support for fallback to gzip to restore old caches on windows.
|
- Added support for fallback to gzip to restore old caches on windows.
|
||||||
|
|
||||||
### 3.0.6
|
## 3.0.6
|
||||||
|
|
||||||
- Added `@azure/abort-controller` to dependencies to fix compatibility issue with ESM [#1208](https://github.com/actions/toolkit/issues/1208)
|
- Added `@azure/abort-controller` to dependencies to fix compatibility issue with ESM [#1208](https://github.com/actions/toolkit/issues/1208)
|
||||||
|
|
||||||
### 3.0.5
|
## 3.0.5
|
||||||
|
|
||||||
- Update `@actions/cache` to use `@actions/core@^1.10.0`
|
- Update `@actions/cache` to use `@actions/core@^1.10.0`
|
||||||
|
|
||||||
### 3.0.4
|
## 3.0.4
|
||||||
|
|
||||||
- Fix zstd not working for windows on gnu tar in issues [#888](https://github.com/actions/cache/issues/888) and [#891](https://github.com/actions/cache/issues/891).
|
- Fix zstd not working for windows on gnu tar in issues [#888](https://github.com/actions/cache/issues/888) and [#891](https://github.com/actions/cache/issues/891).
|
||||||
- Allowing users to provide a custom timeout as input for aborting download of a cache segment using an environment variable `SEGMENT_DOWNLOAD_TIMEOUT_MINS`. Default is 60 minutes.
|
- Allowing users to provide a custom timeout as input for aborting download of a cache segment using an environment variable `SEGMENT_DOWNLOAD_TIMEOUT_MINS`. Default is 60 minutes.
|
||||||
|
|
||||||
### 3.0.3
|
## 3.0.3
|
||||||
|
|
||||||
- Bug fixes for download stuck issue [#810](https://github.com/actions/cache/issues/810).
|
- Bug fixes for download stuck issue [#810](https://github.com/actions/cache/issues/810).
|
||||||
|
|
||||||
### 3.0.2
|
## 3.0.2
|
||||||
|
|
||||||
- Added 1 hour timeout for the download stuck issue [#810](https://github.com/actions/cache/issues/810).
|
- Added 1 hour timeout for the download stuck issue [#810](https://github.com/actions/cache/issues/810).
|
||||||
|
|
||||||
### 3.0.1
|
## 3.0.1
|
||||||
|
|
||||||
- Fix [#833](https://github.com/actions/cache/issues/833) - cache doesn't work with github workspace directory.
|
- Fix [#833](https://github.com/actions/cache/issues/833) - cache doesn't work with github workspace directory.
|
||||||
- Fix [#809](https://github.com/actions/cache/issues/809) `zstd -d: no such file or directory` error on AWS self-hosted runners.
|
- Fix [#809](https://github.com/actions/cache/issues/809) `zstd -d: no such file or directory` error on AWS self-hosted runners.
|
||||||
|
|
||||||
### 3.0.0
|
## 3.0.0
|
||||||
|
|
||||||
- Updated actions/cache to suppress Actions cache server error and log warning for those error [#1122](https://github.com/actions/toolkit/pull/1122)
|
- Updated actions/cache to suppress Actions cache server error and log warning for those error [#1122](https://github.com/actions/toolkit/pull/1122)
|
||||||
|
|
||||||
### 2.0.6
|
## 2.0.6
|
||||||
|
|
||||||
- Fix `Tar failed with error: The process '/usr/bin/tar' failed with exit code 1` issue when temp directory where tar is getting created is actually the subdirectory of the path mentioned by the user for caching. ([issue](https://github.com/actions/cache/issues/689))
|
- Fix `Tar failed with error: The process '/usr/bin/tar' failed with exit code 1` issue when temp directory where tar is getting created is actually the subdirectory of the path mentioned by the user for caching. ([issue](https://github.com/actions/cache/issues/689))
|
||||||
|
|
||||||
### 2.0.5
|
## 2.0.5
|
||||||
|
|
||||||
- Fix to avoid saving empty cache when no files are available for caching. ([issue](https://github.com/actions/cache/issues/624))
|
- Fix to avoid saving empty cache when no files are available for caching. ([issue](https://github.com/actions/cache/issues/624))
|
||||||
|
|
||||||
### 2.0.4
|
## 2.0.4
|
||||||
|
|
||||||
- Update to v2.0.1 of `@actions/http-client` [#1087](https://github.com/actions/toolkit/pull/1087)
|
- Update to v2.0.1 of `@actions/http-client` [#1087](https://github.com/actions/toolkit/pull/1087)
|
||||||
|
|
||||||
### 2.0.3
|
## 2.0.3
|
||||||
|
|
||||||
- Update to v2.0.0 of `@actions/http-client`
|
- Update to v2.0.0 of `@actions/http-client`
|
||||||
|
|
||||||
### 2.0.0
|
## 2.0.0
|
||||||
|
|
||||||
- Added support to check if Actions cache service feature is available or not [#1028](https://github.com/actions/toolkit/pull/1028)
|
- Added support to check if Actions cache service feature is available or not [#1028](https://github.com/actions/toolkit/pull/1028)
|
||||||
|
|
||||||
### 1.0.11
|
## 1.0.11
|
||||||
|
|
||||||
- Fix file downloads > 2GB([issue](https://github.com/actions/cache/issues/773))
|
- Fix file downloads > 2GB([issue](https://github.com/actions/cache/issues/773))
|
||||||
|
|
||||||
### 1.0.10
|
## 1.0.10
|
||||||
|
|
||||||
- Update `lockfileVersion` to `v2` in `package-lock.json [#1022](https://github.com/actions/toolkit/pull/1022)
|
- Update `lockfileVersion` to `v2` in `package-lock.json [#1022](https://github.com/actions/toolkit/pull/1022)
|
||||||
|
|
||||||
### 1.0.9
|
## 1.0.9
|
||||||
|
|
||||||
- Use @azure/ms-rest-js v2.6.0
|
- Use @azure/ms-rest-js v2.6.0
|
||||||
- Use @azure/storage-blob v12.8.0
|
- Use @azure/storage-blob v12.8.0
|
||||||
|
|
||||||
### 1.0.8
|
## 1.0.8
|
||||||
|
|
||||||
- Increase the allowed artifact cache size from 5GB to 10GB ([issue](https://github.com/actions/cache/discussions/497))
|
- Increase the allowed artifact cache size from 5GB to 10GB ([issue](https://github.com/actions/cache/discussions/497))
|
||||||
|
|
||||||
### 1.0.7
|
## 1.0.7
|
||||||
|
|
||||||
- Fixes permissions issue extracting archives with GNU tar on macOS ([issue](https://github.com/actions/cache/issues/527))
|
- Fixes permissions issue extracting archives with GNU tar on macOS ([issue](https://github.com/actions/cache/issues/527))
|
||||||
|
|
||||||
### 1.0.6
|
## 1.0.6
|
||||||
|
|
||||||
- Make caching more verbose [#650](https://github.com/actions/toolkit/pull/650)
|
- Make caching more verbose [#650](https://github.com/actions/toolkit/pull/650)
|
||||||
- Use GNU tar on macOS if available [#701](https://github.com/actions/toolkit/pull/701)
|
- Use GNU tar on macOS if available [#701](https://github.com/actions/toolkit/pull/701)
|
||||||
|
|
||||||
### 1.0.5
|
## 1.0.5
|
||||||
|
|
||||||
- Fix to ensure Windows cache paths get resolved correctly
|
- Fix to ensure Windows cache paths get resolved correctly
|
||||||
|
|
||||||
### 1.0.4
|
## 1.0.4
|
||||||
|
|
||||||
- Use @actions/core v1.2.6
|
- Use @actions/core v1.2.6
|
||||||
- Fixes uploadChunk to throw an error if any unsuccessful response code is received
|
- Fixes uploadChunk to throw an error if any unsuccessful response code is received
|
||||||
|
|
||||||
### 1.0.3
|
## 1.0.3
|
||||||
|
|
||||||
- Use http-client v1.0.9
|
- Use http-client v1.0.9
|
||||||
- Fixes error handling so retries are not attempted on non-retryable errors (409 Conflict, for example)
|
- Fixes error handling so retries are not attempted on non-retryable errors (409 Conflict, for example)
|
||||||
- Adds 5 second delay between retry attempts
|
- Adds 5 second delay between retry attempts
|
||||||
|
|
||||||
### 1.0.2
|
## 1.0.2
|
||||||
|
|
||||||
- Use posix archive format to add support for some tools
|
- Use posix archive format to add support for some tools
|
||||||
|
|
||||||
### 1.0.1
|
## 1.0.1
|
||||||
|
|
||||||
- Fix bug in downloading large files (> 2 GBs) with the Azure SDK
|
- Fix bug in downloading large files (> 2 GBs) with the Azure SDK
|
||||||
|
|
||||||
### 1.0.0
|
## 1.0.0
|
||||||
|
|
||||||
- Downloads Azure-hosted caches using the Azure SDK for speed and reliability
|
- Downloads Azure-hosted caches using the Azure SDK for speed and reliability
|
||||||
- Displays download progress
|
- Displays download progress
|
||||||
- Includes changes that break compatibility with earlier versions, including:
|
- Includes changes that break compatibility with earlier versions, including:
|
||||||
- `retry`, `retryTypedResponse`, and `retryHttpClientResponse` moved from `cacheHttpClient` to `requestUtils`
|
- `retry`, `retryTypedResponse`, and `retryHttpClientResponse` moved from `cacheHttpClient` to `requestUtils`
|
||||||
|
|
||||||
### 0.2.1
|
## 0.2.1
|
||||||
|
|
||||||
- Fix to await async function getCompressionMethod
|
- Fix to await async function getCompressionMethod
|
||||||
|
|
||||||
### 0.2.0
|
## 0.2.0
|
||||||
|
|
||||||
- Fixes issues with the zstd compression algorithm on Windows and Ubuntu 16.04 [#469](https://github.com/actions/toolkit/pull/469)
|
- Fixes issues with the zstd compression algorithm on Windows and Ubuntu 16.04 [#469](https://github.com/actions/toolkit/pull/469)
|
||||||
|
|
||||||
### 0.1.0
|
## 0.1.0
|
||||||
|
|
||||||
- Initial release
|
- Initial release
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
name: 'Set env variables'
|
name: 'Set env variables'
|
||||||
description: 'Sets certain env variables so that e2e restore and save cache can be tested in a shell'
|
description: 'Sets certain env variables so that e2e restore and save cache can be tested in a shell'
|
||||||
runs:
|
runs:
|
||||||
using: 'node12'
|
using: 'node20'
|
||||||
main: 'index.js'
|
main: 'index.js'
|
||||||
+9
-5
@@ -1,12 +1,16 @@
|
|||||||
// Certain env variables are not set by default in a shell context and are only available in a node context from a running action
|
// Certain env variables are not set by default in a shell context and are only available in a node context from a running action
|
||||||
// In order to be able to restore and save cache e2e in a shell when running CI tests, we need these env variables set
|
// In order to be able to restore and save cache e2e in a shell when running CI tests, we need these env variables set
|
||||||
const fs = require('fs');
|
import fs from 'fs'
|
||||||
const os = require('os');
|
import os from 'os'
|
||||||
const filePath = process.env[`GITHUB_ENV`]
|
|
||||||
fs.appendFileSync(filePath, `ACTIONS_RUNTIME_TOKEN=${process.env.ACTIONS_RUNTIME_TOKEN}${os.EOL}`, {
|
const filePath = process.env['GITHUB_ENV']
|
||||||
|
fs.appendFileSync(filePath, `ACTIONS_CACHE_SERVICE_V2=true${os.EOL}`, {
|
||||||
encoding: 'utf8'
|
encoding: 'utf8'
|
||||||
})
|
})
|
||||||
fs.appendFileSync(filePath, `ACTIONS_CACHE_URL=${process.env.ACTIONS_CACHE_URL}${os.EOL}`, {
|
fs.appendFileSync(filePath, `ACTIONS_RESULTS_URL=${process.env.ACTIONS_RESULTS_URL}${os.EOL}`, {
|
||||||
|
encoding: 'utf8'
|
||||||
|
})
|
||||||
|
fs.appendFileSync(filePath, `ACTIONS_RUNTIME_TOKEN=${process.env.ACTIONS_RUNTIME_TOKEN}${os.EOL}`, {
|
||||||
encoding: 'utf8'
|
encoding: 'utf8'
|
||||||
})
|
})
|
||||||
fs.appendFileSync(filePath, `GITHUB_RUN_ID=${process.env.GITHUB_RUN_ID}${os.EOL}`, {
|
fs.appendFileSync(filePath, `GITHUB_RUN_ID=${process.env.GITHUB_RUN_ID}${os.EOL}`, {
|
||||||
|
|||||||
+63
-8
@@ -1,14 +1,69 @@
|
|||||||
import * as cache from '../src/cache'
|
import * as cache from '../src/cache'
|
||||||
|
|
||||||
test('isFeatureAvailable returns true if server url is set', () => {
|
describe('isFeatureAvailable', () => {
|
||||||
try {
|
const originalEnv = process.env
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.resetModules()
|
||||||
|
process.env = {...originalEnv}
|
||||||
|
// Clean cache-related environment variables
|
||||||
|
delete process.env['ACTIONS_CACHE_URL']
|
||||||
|
delete process.env['ACTIONS_RESULTS_URL']
|
||||||
|
delete process.env['ACTIONS_CACHE_SERVICE_V2']
|
||||||
|
delete process.env['GITHUB_SERVER_URL']
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
process.env = originalEnv
|
||||||
|
})
|
||||||
|
|
||||||
|
test('returns true for cache service v1 when ACTIONS_CACHE_URL is set', () => {
|
||||||
process.env['ACTIONS_CACHE_URL'] = 'http://cache.com'
|
process.env['ACTIONS_CACHE_URL'] = 'http://cache.com'
|
||||||
expect(cache.isFeatureAvailable()).toBe(true)
|
expect(cache.isFeatureAvailable()).toBe(true)
|
||||||
} finally {
|
})
|
||||||
delete process.env['ACTIONS_CACHE_URL']
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
test('isFeatureAvailable returns false if server url is not set', () => {
|
test('returns false for cache service v1 when only ACTIONS_RESULTS_URL is set', () => {
|
||||||
expect(cache.isFeatureAvailable()).toBe(false)
|
process.env['ACTIONS_RESULTS_URL'] = 'http://results.com'
|
||||||
|
expect(cache.isFeatureAvailable()).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('returns true for cache service v1 when both URLs are set', () => {
|
||||||
|
process.env['ACTIONS_CACHE_URL'] = 'http://cache.com'
|
||||||
|
process.env['ACTIONS_RESULTS_URL'] = 'http://results.com'
|
||||||
|
expect(cache.isFeatureAvailable()).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('returns true for cache service v2 when ACTIONS_RESULTS_URL is set', () => {
|
||||||
|
process.env['ACTIONS_CACHE_SERVICE_V2'] = 'true'
|
||||||
|
process.env['ACTIONS_RESULTS_URL'] = 'http://results.com'
|
||||||
|
expect(cache.isFeatureAvailable()).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('returns false for cache service v2 when only ACTIONS_CACHE_URL is set', () => {
|
||||||
|
process.env['ACTIONS_CACHE_SERVICE_V2'] = 'true'
|
||||||
|
process.env['ACTIONS_CACHE_URL'] = 'http://cache.com'
|
||||||
|
expect(cache.isFeatureAvailable()).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('returns false when no cache URLs are set', () => {
|
||||||
|
expect(cache.isFeatureAvailable()).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('returns false for cache service v2 when no URLs are set', () => {
|
||||||
|
process.env['ACTIONS_CACHE_SERVICE_V2'] = 'true'
|
||||||
|
expect(cache.isFeatureAvailable()).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('returns true for GHES with v1 even when v2 flag is set', () => {
|
||||||
|
process.env['GITHUB_SERVER_URL'] = 'https://my-enterprise.github.com'
|
||||||
|
process.env['ACTIONS_CACHE_SERVICE_V2'] = 'true'
|
||||||
|
process.env['ACTIONS_CACHE_URL'] = 'http://cache.com'
|
||||||
|
expect(cache.isFeatureAvailable()).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('returns false for GHES with only ACTIONS_RESULTS_URL', () => {
|
||||||
|
process.env['GITHUB_SERVER_URL'] = 'https://my-enterprise.github.com'
|
||||||
|
process.env['ACTIONS_RESULTS_URL'] = 'http://results.com'
|
||||||
|
expect(cache.isFeatureAvailable()).toBe(false)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
+174
@@ -0,0 +1,174 @@
|
|||||||
|
import * as http from 'http'
|
||||||
|
import * as net from 'net'
|
||||||
|
import {HttpClient} from '@actions/http-client'
|
||||||
|
import * as core from '@actions/core'
|
||||||
|
import * as config from '../src/internal/config'
|
||||||
|
import * as cacheUtils from '../src/internal/cacheUtils'
|
||||||
|
import {internalCacheTwirpClient} from '../src/internal/shared/cacheTwirpClient'
|
||||||
|
|
||||||
|
jest.mock('@actions/http-client')
|
||||||
|
|
||||||
|
const clientOptions = {
|
||||||
|
maxAttempts: 5,
|
||||||
|
retryIntervalMs: 1,
|
||||||
|
retryMultiplier: 1.5
|
||||||
|
}
|
||||||
|
|
||||||
|
// noopLogs mocks the console.log and core.* functions to prevent output in the console while testing
|
||||||
|
const noopLogs = (): void => {
|
||||||
|
jest.spyOn(console, 'log').mockImplementation(() => {})
|
||||||
|
jest.spyOn(core, 'debug').mockImplementation(() => {})
|
||||||
|
jest.spyOn(core, 'info').mockImplementation(() => {})
|
||||||
|
jest.spyOn(core, 'warning').mockImplementation(() => {})
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('cacheTwirpClient', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
noopLogs()
|
||||||
|
jest
|
||||||
|
.spyOn(config, 'getCacheServiceURL')
|
||||||
|
.mockReturnValue('http://localhost:8080')
|
||||||
|
jest.spyOn(cacheUtils, 'getRuntimeToken').mockReturnValue('token')
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should fail immediately on 429 rate limit without retrying', async () => {
|
||||||
|
const mockPost = jest.fn(() => {
|
||||||
|
const msg = new http.IncomingMessage(new net.Socket())
|
||||||
|
msg.statusCode = 429
|
||||||
|
msg.statusMessage = 'Too Many Requests'
|
||||||
|
return {
|
||||||
|
message: msg,
|
||||||
|
readBody: async () => {
|
||||||
|
return Promise.resolve(`{"ok": false}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
;(HttpClient as unknown as jest.Mock).mockImplementation(() => {
|
||||||
|
return {
|
||||||
|
post: mockPost
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const client = internalCacheTwirpClient(clientOptions)
|
||||||
|
await expect(
|
||||||
|
client.CreateCacheEntry({
|
||||||
|
key: 'test-key',
|
||||||
|
version: 'test-version'
|
||||||
|
})
|
||||||
|
).rejects.toThrow(
|
||||||
|
'Failed to CreateCacheEntry: Rate limited: Failed request: (429) Too Many Requests'
|
||||||
|
)
|
||||||
|
|
||||||
|
// Should only be called once - no retries for 429
|
||||||
|
expect(mockPost).toHaveBeenCalledTimes(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should log warning with retry-after header on 429', async () => {
|
||||||
|
const warningSpy = jest.spyOn(core, 'warning')
|
||||||
|
|
||||||
|
const mockPost = jest.fn(() => {
|
||||||
|
const msg = new http.IncomingMessage(new net.Socket())
|
||||||
|
msg.statusCode = 429
|
||||||
|
msg.statusMessage = 'Too Many Requests'
|
||||||
|
msg.headers = {'retry-after': '60'}
|
||||||
|
return {
|
||||||
|
message: msg,
|
||||||
|
readBody: async () => {
|
||||||
|
return Promise.resolve(`{"ok": false}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
;(HttpClient as unknown as jest.Mock).mockImplementation(() => {
|
||||||
|
return {
|
||||||
|
post: mockPost
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const client = internalCacheTwirpClient(clientOptions)
|
||||||
|
await expect(
|
||||||
|
client.CreateCacheEntry({
|
||||||
|
key: 'test-key',
|
||||||
|
version: 'test-version'
|
||||||
|
})
|
||||||
|
).rejects.toThrow('Rate limited')
|
||||||
|
|
||||||
|
expect(mockPost).toHaveBeenCalledTimes(1)
|
||||||
|
expect(warningSpy).toHaveBeenCalledWith(
|
||||||
|
"You've hit a rate limit, your rate limit will reset in 60 seconds"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not log warning if retry-after header is missing on 429', async () => {
|
||||||
|
const warningSpy = jest.spyOn(core, 'warning')
|
||||||
|
|
||||||
|
const mockPost = jest.fn(() => {
|
||||||
|
const msg = new http.IncomingMessage(new net.Socket())
|
||||||
|
msg.statusCode = 429
|
||||||
|
msg.statusMessage = 'Too Many Requests'
|
||||||
|
// No retry-after header
|
||||||
|
return {
|
||||||
|
message: msg,
|
||||||
|
readBody: async () => {
|
||||||
|
return Promise.resolve(`{"ok": false}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
;(HttpClient as unknown as jest.Mock).mockImplementation(() => {
|
||||||
|
return {
|
||||||
|
post: mockPost
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const client = internalCacheTwirpClient(clientOptions)
|
||||||
|
await expect(
|
||||||
|
client.CreateCacheEntry({
|
||||||
|
key: 'test-key',
|
||||||
|
version: 'test-version'
|
||||||
|
})
|
||||||
|
).rejects.toThrow('Rate limited')
|
||||||
|
|
||||||
|
expect(mockPost).toHaveBeenCalledTimes(1)
|
||||||
|
expect(warningSpy).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not log warning if retry-after header is invalid on 429', async () => {
|
||||||
|
const warningSpy = jest.spyOn(core, 'warning')
|
||||||
|
|
||||||
|
const mockPost = jest.fn(() => {
|
||||||
|
const msg = new http.IncomingMessage(new net.Socket())
|
||||||
|
msg.statusCode = 429
|
||||||
|
msg.statusMessage = 'Too Many Requests'
|
||||||
|
msg.headers = {'retry-after': 'invalid'}
|
||||||
|
return {
|
||||||
|
message: msg,
|
||||||
|
readBody: async () => {
|
||||||
|
return Promise.resolve(`{"ok": false}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
;(HttpClient as unknown as jest.Mock).mockImplementation(() => {
|
||||||
|
return {
|
||||||
|
post: mockPost
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const client = internalCacheTwirpClient(clientOptions)
|
||||||
|
await expect(
|
||||||
|
client.CreateCacheEntry({
|
||||||
|
key: 'test-key',
|
||||||
|
version: 'test-version'
|
||||||
|
})
|
||||||
|
).rejects.toThrow('Rate limited')
|
||||||
|
|
||||||
|
expect(mockPost).toHaveBeenCalledTimes(1)
|
||||||
|
expect(warningSpy).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
})
|
||||||
+45
@@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
// Helper script to restore cache for e2e testing
|
||||||
|
import * as cache from '../lib/cache.js'
|
||||||
|
|
||||||
|
const [prefix, runId, useAzureSdk] = process.argv.slice(2)
|
||||||
|
|
||||||
|
if (!prefix || !runId) {
|
||||||
|
console.error('Usage: restore-cache.mjs <prefix> <runId> [useAzureSdk]')
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = `test-${prefix}-${runId}`
|
||||||
|
const paths = ['test-cache', '~/test-cache']
|
||||||
|
const options = {useAzureSdk: useAzureSdk !== 'false'}
|
||||||
|
|
||||||
|
console.log(`Restoring cache with key: ${key}`)
|
||||||
|
console.log(`Paths: ${paths.join(', ')}`)
|
||||||
|
console.log(`Using Azure SDK: ${options.useAzureSdk}`)
|
||||||
|
|
||||||
|
const maxRetries = 3
|
||||||
|
const retryDelayMs = 5000
|
||||||
|
|
||||||
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
||||||
|
try {
|
||||||
|
console.log(`Attempt ${attempt} of ${maxRetries}`)
|
||||||
|
const restoredKey = await cache.restoreCache(paths, key, [], options)
|
||||||
|
|
||||||
|
if (restoredKey) {
|
||||||
|
console.log(`Cache restored with key: ${restoredKey}`)
|
||||||
|
process.exit(0)
|
||||||
|
} else {
|
||||||
|
console.log('Cache not found on this attempt')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error on attempt ${attempt}:`, error.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attempt < maxRetries) {
|
||||||
|
console.log(`Waiting ${retryDelayMs / 1000}s before retry...`)
|
||||||
|
await new Promise(resolve => setTimeout(resolve, retryDelayMs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.error(`Failed to restore cache after ${maxRetries} attempts`)
|
||||||
|
process.exit(1)
|
||||||
+18
-6
@@ -6,6 +6,8 @@ import * as cacheUtils from '../src/internal/cacheUtils'
|
|||||||
import {CacheFilename, CompressionMethod} from '../src/internal/constants'
|
import {CacheFilename, CompressionMethod} from '../src/internal/constants'
|
||||||
import {ArtifactCacheEntry} from '../src/internal/contracts'
|
import {ArtifactCacheEntry} from '../src/internal/contracts'
|
||||||
import * as tar from '../src/internal/tar'
|
import * as tar from '../src/internal/tar'
|
||||||
|
import {HttpClientError} from '@actions/http-client'
|
||||||
|
import {CacheServiceClientJSON} from '../src/generated/results/api/v1/cache.twirp-client'
|
||||||
|
|
||||||
jest.mock('../src/internal/cacheHttpClient')
|
jest.mock('../src/internal/cacheHttpClient')
|
||||||
jest.mock('../src/internal/cacheUtils')
|
jest.mock('../src/internal/cacheUtils')
|
||||||
@@ -73,18 +75,28 @@ test('restore with no cache found', async () => {
|
|||||||
test('restore with server error should fail', async () => {
|
test('restore with server error should fail', async () => {
|
||||||
const paths = ['node_modules']
|
const paths = ['node_modules']
|
||||||
const key = 'node-test'
|
const key = 'node-test'
|
||||||
const logWarningMock = jest.spyOn(core, 'warning')
|
const logErrorMock = jest.spyOn(core, 'error')
|
||||||
|
|
||||||
jest.spyOn(cacheHttpClient, 'getCacheEntry').mockImplementation(() => {
|
// Set cache service to V2 to test error logging for server errors
|
||||||
throw new Error('HTTP Error Occurred')
|
process.env['ACTIONS_CACHE_SERVICE_V2'] = 'true'
|
||||||
})
|
process.env['ACTIONS_RESULTS_URL'] = 'https://results.local/'
|
||||||
|
|
||||||
|
jest
|
||||||
|
.spyOn(CacheServiceClientJSON.prototype, 'GetCacheEntryDownloadURL')
|
||||||
|
.mockImplementation(() => {
|
||||||
|
throw new HttpClientError('HTTP Error Occurred', 500)
|
||||||
|
})
|
||||||
|
|
||||||
const cacheKey = await restoreCache(paths, key)
|
const cacheKey = await restoreCache(paths, key)
|
||||||
expect(cacheKey).toBe(undefined)
|
expect(cacheKey).toBe(undefined)
|
||||||
expect(logWarningMock).toHaveBeenCalledTimes(1)
|
expect(logErrorMock).toHaveBeenCalledTimes(1)
|
||||||
expect(logWarningMock).toHaveBeenCalledWith(
|
expect(logErrorMock).toHaveBeenCalledWith(
|
||||||
'Failed to restore: HTTP Error Occurred'
|
'Failed to restore: HTTP Error Occurred'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Clean up environment
|
||||||
|
delete process.env['ACTIONS_CACHE_SERVICE_V2']
|
||||||
|
delete process.env['ACTIONS_RESULTS_URL']
|
||||||
})
|
})
|
||||||
|
|
||||||
test('restore with restore keys and no cache found', async () => {
|
test('restore with restore keys and no cache found', async () => {
|
||||||
|
|||||||
+9
-4
@@ -8,6 +8,7 @@ import {restoreCache} from '../src/cache'
|
|||||||
import {CacheFilename, CompressionMethod} from '../src/internal/constants'
|
import {CacheFilename, CompressionMethod} from '../src/internal/constants'
|
||||||
import {CacheServiceClientJSON} from '../src/generated/results/api/v1/cache.twirp-client'
|
import {CacheServiceClientJSON} from '../src/generated/results/api/v1/cache.twirp-client'
|
||||||
import {DownloadOptions} from '../src/options'
|
import {DownloadOptions} from '../src/options'
|
||||||
|
import {HttpClientError} from '@actions/http-client'
|
||||||
|
|
||||||
jest.mock('../src/internal/cacheHttpClient')
|
jest.mock('../src/internal/cacheHttpClient')
|
||||||
jest.mock('../src/internal/cacheUtils')
|
jest.mock('../src/internal/cacheUtils')
|
||||||
@@ -95,18 +96,18 @@ test('restore with no cache found', async () => {
|
|||||||
test('restore with server error should fail', async () => {
|
test('restore with server error should fail', async () => {
|
||||||
const paths = ['node_modules']
|
const paths = ['node_modules']
|
||||||
const key = 'node-test'
|
const key = 'node-test'
|
||||||
const logWarningMock = jest.spyOn(core, 'warning')
|
const logErrorMock = jest.spyOn(core, 'error')
|
||||||
|
|
||||||
jest
|
jest
|
||||||
.spyOn(CacheServiceClientJSON.prototype, 'GetCacheEntryDownloadURL')
|
.spyOn(CacheServiceClientJSON.prototype, 'GetCacheEntryDownloadURL')
|
||||||
.mockImplementation(() => {
|
.mockImplementation(() => {
|
||||||
throw new Error('HTTP Error Occurred')
|
throw new HttpClientError('HTTP Error Occurred', 500)
|
||||||
})
|
})
|
||||||
|
|
||||||
const cacheKey = await restoreCache(paths, key)
|
const cacheKey = await restoreCache(paths, key)
|
||||||
expect(cacheKey).toBe(undefined)
|
expect(cacheKey).toBe(undefined)
|
||||||
expect(logWarningMock).toHaveBeenCalledTimes(1)
|
expect(logErrorMock).toHaveBeenCalledTimes(1)
|
||||||
expect(logWarningMock).toHaveBeenCalledWith(
|
expect(logErrorMock).toHaveBeenCalledWith(
|
||||||
'Failed to restore: HTTP Error Occurred'
|
'Failed to restore: HTTP Error Occurred'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -265,6 +266,7 @@ test('restore with zstd compressed cache found', async () => {
|
|||||||
const cacheKey = await restoreCache(paths, key, [], options)
|
const cacheKey = await restoreCache(paths, key, [], options)
|
||||||
|
|
||||||
expect(cacheKey).toBe(key)
|
expect(cacheKey).toBe(key)
|
||||||
|
expect(logInfoMock).toHaveBeenCalledWith(`Cache hit for: ${key}`)
|
||||||
expect(getCacheVersionMock).toHaveBeenCalledWith(
|
expect(getCacheVersionMock).toHaveBeenCalledWith(
|
||||||
paths,
|
paths,
|
||||||
compressionMethod,
|
compressionMethod,
|
||||||
@@ -342,6 +344,9 @@ test('restore with cache found for restore key', async () => {
|
|||||||
const cacheKey = await restoreCache(paths, key, restoreKeys, options)
|
const cacheKey = await restoreCache(paths, key, restoreKeys, options)
|
||||||
|
|
||||||
expect(cacheKey).toBe(restoreKeys[0])
|
expect(cacheKey).toBe(restoreKeys[0])
|
||||||
|
expect(logInfoMock).toHaveBeenCalledWith(
|
||||||
|
`Cache hit for restore-key: ${restoreKeys[0]}`
|
||||||
|
)
|
||||||
expect(getCacheVersionMock).toHaveBeenCalledWith(
|
expect(getCacheVersionMock).toHaveBeenCalledWith(
|
||||||
paths,
|
paths,
|
||||||
compressionMethod,
|
compressionMethod,
|
||||||
|
|||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
// Helper script to save cache for e2e testing
|
||||||
|
import * as cache from '../lib/cache.js'
|
||||||
|
|
||||||
|
const [prefix, runId] = process.argv.slice(2)
|
||||||
|
|
||||||
|
if (!prefix || !runId) {
|
||||||
|
console.error('Usage: save-cache.mjs <prefix> <runId>')
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = `test-${prefix}-${runId}`
|
||||||
|
const paths = ['test-cache', '~/test-cache']
|
||||||
|
|
||||||
|
console.log(`Saving cache with key: ${key}`)
|
||||||
|
console.log(`Paths: ${paths.join(', ')}`)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const cacheId = await cache.saveCache(paths, key)
|
||||||
|
console.log(`Cache saved with ID: ${cacheId}`)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error saving cache:', error)
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
+37
-30
@@ -7,11 +7,12 @@ import * as config from '../src/internal/config'
|
|||||||
import {CacheFilename, CompressionMethod} from '../src/internal/constants'
|
import {CacheFilename, CompressionMethod} from '../src/internal/constants'
|
||||||
import * as tar from '../src/internal/tar'
|
import * as tar from '../src/internal/tar'
|
||||||
import {TypedResponse} from '@actions/http-client/lib/interfaces'
|
import {TypedResponse} from '@actions/http-client/lib/interfaces'
|
||||||
|
import {HttpClientError} from '@actions/http-client'
|
||||||
import {
|
import {
|
||||||
ReserveCacheResponse,
|
ReserveCacheResponse,
|
||||||
ITypedResponseWithError
|
ITypedResponseWithError
|
||||||
} from '../src/internal/contracts'
|
} from '../src/internal/contracts'
|
||||||
import {HttpClientError} from '@actions/http-client'
|
import {CacheServiceClientJSON} from '../src/generated/results/api/v1/cache.twirp-client'
|
||||||
|
|
||||||
jest.mock('../src/internal/cacheHttpClient')
|
jest.mock('../src/internal/cacheHttpClient')
|
||||||
jest.mock('../src/internal/cacheUtils')
|
jest.mock('../src/internal/cacheUtils')
|
||||||
@@ -223,46 +224,55 @@ test('save with reserve cache failure should fail', async () => {
|
|||||||
test('save with server error should fail', async () => {
|
test('save with server error should fail', async () => {
|
||||||
const filePath = 'node_modules'
|
const filePath = 'node_modules'
|
||||||
const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
|
const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
|
||||||
const cachePaths = [path.resolve(filePath)]
|
const logErrorMock = jest.spyOn(core, 'error')
|
||||||
const logWarningMock = jest.spyOn(core, 'warning')
|
|
||||||
const cacheId = 4
|
// Mock cache service version to V2
|
||||||
const reserveCacheMock = jest
|
const getCacheServiceVersionMock = jest
|
||||||
.spyOn(cacheHttpClient, 'reserveCache')
|
.spyOn(config, 'getCacheServiceVersion')
|
||||||
.mockImplementation(async () => {
|
.mockReturnValue('v2')
|
||||||
const response: TypedResponse<ReserveCacheResponse> = {
|
|
||||||
statusCode: 500,
|
// Mock V2 CreateCacheEntry to succeed
|
||||||
result: {cacheId},
|
const createCacheEntryMock = jest
|
||||||
headers: {}
|
.spyOn(CacheServiceClientJSON.prototype, 'CreateCacheEntry')
|
||||||
}
|
.mockReturnValue(
|
||||||
return response
|
Promise.resolve({
|
||||||
})
|
ok: true,
|
||||||
|
signedUploadUrl: 'https://blob-storage.local?signed=true',
|
||||||
|
message: ''
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
// Mock the FinalizeCacheEntryUpload to succeed (since the error should happen in saveCache)
|
||||||
|
jest
|
||||||
|
.spyOn(CacheServiceClientJSON.prototype, 'FinalizeCacheEntryUpload')
|
||||||
|
.mockReturnValue(
|
||||||
|
Promise.resolve({ok: true, entryId: '4', message: 'Success'})
|
||||||
|
)
|
||||||
|
|
||||||
const createTarMock = jest.spyOn(tar, 'createTar')
|
const createTarMock = jest.spyOn(tar, 'createTar')
|
||||||
|
|
||||||
|
// Mock the saveCache call to throw a server error
|
||||||
const saveCacheMock = jest
|
const saveCacheMock = jest
|
||||||
.spyOn(cacheHttpClient, 'saveCache')
|
.spyOn(cacheHttpClient, 'saveCache')
|
||||||
.mockImplementationOnce(() => {
|
.mockImplementationOnce(() => {
|
||||||
throw new Error('HTTP Error Occurred')
|
throw new HttpClientError('HTTP Error Occurred', 500)
|
||||||
})
|
})
|
||||||
|
|
||||||
const compression = CompressionMethod.Zstd
|
const compression = CompressionMethod.Zstd
|
||||||
const getCompressionMock = jest
|
const getCompressionMock = jest
|
||||||
.spyOn(cacheUtils, 'getCompressionMethod')
|
.spyOn(cacheUtils, 'getCompressionMethod')
|
||||||
.mockReturnValueOnce(Promise.resolve(compression))
|
.mockReturnValueOnce(Promise.resolve(compression))
|
||||||
|
|
||||||
await saveCache([filePath], primaryKey)
|
await saveCache([filePath], primaryKey)
|
||||||
expect(logWarningMock).toHaveBeenCalledTimes(1)
|
|
||||||
expect(logWarningMock).toHaveBeenCalledWith(
|
expect(logErrorMock).toHaveBeenCalledTimes(1)
|
||||||
|
expect(logErrorMock).toHaveBeenCalledWith(
|
||||||
'Failed to save: HTTP Error Occurred'
|
'Failed to save: HTTP Error Occurred'
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(reserveCacheMock).toHaveBeenCalledTimes(1)
|
expect(createCacheEntryMock).toHaveBeenCalledTimes(1)
|
||||||
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, [filePath], {
|
|
||||||
cacheSize: undefined,
|
|
||||||
compressionMethod: compression,
|
|
||||||
enableCrossOsArchive: false
|
|
||||||
})
|
|
||||||
const archiveFolder = '/foo/bar'
|
const archiveFolder = '/foo/bar'
|
||||||
const archiveFile = path.join(archiveFolder, CacheFilename.Zstd)
|
const cachePaths = [path.resolve(filePath)]
|
||||||
expect(createTarMock).toHaveBeenCalledTimes(1)
|
expect(createTarMock).toHaveBeenCalledTimes(1)
|
||||||
expect(createTarMock).toHaveBeenCalledWith(
|
expect(createTarMock).toHaveBeenCalledWith(
|
||||||
archiveFolder,
|
archiveFolder,
|
||||||
@@ -270,13 +280,10 @@ test('save with server error should fail', async () => {
|
|||||||
compression
|
compression
|
||||||
)
|
)
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(1)
|
expect(saveCacheMock).toHaveBeenCalledTimes(1)
|
||||||
expect(saveCacheMock).toHaveBeenCalledWith(
|
|
||||||
cacheId,
|
|
||||||
archiveFile,
|
|
||||||
'',
|
|
||||||
undefined
|
|
||||||
)
|
|
||||||
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
||||||
|
|
||||||
|
// Restore the getCacheServiceVersion mock to its original state
|
||||||
|
getCacheServiceVersionMock.mockRestore()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('save with valid inputs uploads a cache', async () => {
|
test('save with valid inputs uploads a cache', async () => {
|
||||||
|
|||||||
+254
-39
@@ -59,39 +59,6 @@ test('save with missing input should fail', async () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('save with large cache outputs should fail using', async () => {
|
|
||||||
const paths = 'node_modules'
|
|
||||||
const key = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
|
|
||||||
const cachePaths = [path.resolve(paths)]
|
|
||||||
|
|
||||||
const createTarMock = jest.spyOn(tar, 'createTar')
|
|
||||||
const logWarningMock = jest.spyOn(core, 'warning')
|
|
||||||
|
|
||||||
const cacheSize = 11 * 1024 * 1024 * 1024 //~11GB, over the 10GB limit
|
|
||||||
jest
|
|
||||||
.spyOn(cacheUtils, 'getArchiveFileSizeInBytes')
|
|
||||||
.mockReturnValueOnce(cacheSize)
|
|
||||||
const compression = CompressionMethod.Gzip
|
|
||||||
const getCompressionMock = jest
|
|
||||||
.spyOn(cacheUtils, 'getCompressionMethod')
|
|
||||||
.mockReturnValueOnce(Promise.resolve(compression))
|
|
||||||
|
|
||||||
const cacheId = await saveCache([paths], key)
|
|
||||||
expect(cacheId).toBe(-1)
|
|
||||||
expect(logWarningMock).toHaveBeenCalledWith(
|
|
||||||
'Failed to save: Cache size of ~11264 MB (11811160064 B) is over the 10GB limit, not saving cache.'
|
|
||||||
)
|
|
||||||
|
|
||||||
const archiveFolder = '/foo/bar'
|
|
||||||
|
|
||||||
expect(createTarMock).toHaveBeenCalledWith(
|
|
||||||
archiveFolder,
|
|
||||||
cachePaths,
|
|
||||||
compression
|
|
||||||
)
|
|
||||||
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('create cache entry failure on non-ok response', async () => {
|
test('create cache entry failure on non-ok response', async () => {
|
||||||
const paths = ['node_modules']
|
const paths = ['node_modules']
|
||||||
const key = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
|
const key = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
|
||||||
@@ -99,7 +66,7 @@ test('create cache entry failure on non-ok response', async () => {
|
|||||||
|
|
||||||
const createCacheEntryMock = jest
|
const createCacheEntryMock = jest
|
||||||
.spyOn(CacheServiceClientJSON.prototype, 'CreateCacheEntry')
|
.spyOn(CacheServiceClientJSON.prototype, 'CreateCacheEntry')
|
||||||
.mockResolvedValue({ok: false, signedUploadUrl: ''})
|
.mockResolvedValue({ok: false, signedUploadUrl: '', message: ''})
|
||||||
|
|
||||||
const createTarMock = jest.spyOn(tar, 'createTar')
|
const createTarMock = jest.spyOn(tar, 'createTar')
|
||||||
const finalizeCacheEntryMock = jest.spyOn(
|
const finalizeCacheEntryMock = jest.spyOn(
|
||||||
@@ -182,7 +149,7 @@ test('save cache fails if a signedUploadURL was not passed', async () => {
|
|||||||
const createCacheEntryMock = jest
|
const createCacheEntryMock = jest
|
||||||
.spyOn(CacheServiceClientJSON.prototype, 'CreateCacheEntry')
|
.spyOn(CacheServiceClientJSON.prototype, 'CreateCacheEntry')
|
||||||
.mockReturnValue(
|
.mockReturnValue(
|
||||||
Promise.resolve({ok: true, signedUploadUrl: signedUploadURL})
|
Promise.resolve({ok: true, signedUploadUrl: signedUploadURL, message: ''})
|
||||||
)
|
)
|
||||||
|
|
||||||
const createTarMock = jest.spyOn(tar, 'createTar')
|
const createTarMock = jest.spyOn(tar, 'createTar')
|
||||||
@@ -240,7 +207,7 @@ test('finalize save cache failure', async () => {
|
|||||||
const createCacheEntryMock = jest
|
const createCacheEntryMock = jest
|
||||||
.spyOn(CacheServiceClientJSON.prototype, 'CreateCacheEntry')
|
.spyOn(CacheServiceClientJSON.prototype, 'CreateCacheEntry')
|
||||||
.mockReturnValue(
|
.mockReturnValue(
|
||||||
Promise.resolve({ok: true, signedUploadUrl: signedUploadURL})
|
Promise.resolve({ok: true, signedUploadUrl: signedUploadURL, message: ''})
|
||||||
)
|
)
|
||||||
|
|
||||||
const createTarMock = jest.spyOn(tar, 'createTar')
|
const createTarMock = jest.spyOn(tar, 'createTar')
|
||||||
@@ -260,7 +227,7 @@ test('finalize save cache failure', async () => {
|
|||||||
|
|
||||||
const finalizeCacheEntryMock = jest
|
const finalizeCacheEntryMock = jest
|
||||||
.spyOn(CacheServiceClientJSON.prototype, 'FinalizeCacheEntryUpload')
|
.spyOn(CacheServiceClientJSON.prototype, 'FinalizeCacheEntryUpload')
|
||||||
.mockReturnValue(Promise.resolve({ok: false, entryId: ''}))
|
.mockReturnValue(Promise.resolve({ok: false, entryId: '', message: ''}))
|
||||||
|
|
||||||
const cacheId = await saveCache([paths], key, options)
|
const cacheId = await saveCache([paths], key, options)
|
||||||
|
|
||||||
@@ -319,7 +286,7 @@ test('save with valid inputs uploads a cache', async () => {
|
|||||||
jest
|
jest
|
||||||
.spyOn(CacheServiceClientJSON.prototype, 'CreateCacheEntry')
|
.spyOn(CacheServiceClientJSON.prototype, 'CreateCacheEntry')
|
||||||
.mockReturnValue(
|
.mockReturnValue(
|
||||||
Promise.resolve({ok: true, signedUploadUrl: signedUploadURL})
|
Promise.resolve({ok: true, signedUploadUrl: signedUploadURL, message: ''})
|
||||||
)
|
)
|
||||||
|
|
||||||
const saveCacheMock = jest.spyOn(cacheHttpClient, 'saveCache')
|
const saveCacheMock = jest.spyOn(cacheHttpClient, 'saveCache')
|
||||||
@@ -332,7 +299,9 @@ test('save with valid inputs uploads a cache', async () => {
|
|||||||
|
|
||||||
const finalizeCacheEntryMock = jest
|
const finalizeCacheEntryMock = jest
|
||||||
.spyOn(CacheServiceClientJSON.prototype, 'FinalizeCacheEntryUpload')
|
.spyOn(CacheServiceClientJSON.prototype, 'FinalizeCacheEntryUpload')
|
||||||
.mockReturnValue(Promise.resolve({ok: true, entryId: cacheId.toString()}))
|
.mockReturnValue(
|
||||||
|
Promise.resolve({ok: true, entryId: cacheId.toString(), message: ''})
|
||||||
|
)
|
||||||
|
|
||||||
const expectedCacheId = await saveCache([paths], key)
|
const expectedCacheId = await saveCache([paths], key)
|
||||||
|
|
||||||
@@ -360,6 +329,252 @@ test('save with valid inputs uploads a cache', async () => {
|
|||||||
expect(expectedCacheId).toBe(cacheId)
|
expect(expectedCacheId).toBe(cacheId)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('save with extremely large cache should succeed in v2 (no size limit)', async () => {
|
||||||
|
const paths = 'node_modules'
|
||||||
|
const key = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
|
||||||
|
const cachePaths = [path.resolve(paths)]
|
||||||
|
const signedUploadURL = 'https://blob-storage.local?signed=true'
|
||||||
|
const createTarMock = jest.spyOn(tar, 'createTar')
|
||||||
|
// Simulate a very large cache (20GB)
|
||||||
|
const archiveFileSize = 20 * 1024 * 1024 * 1024 // 20GB
|
||||||
|
const options: UploadOptions = {
|
||||||
|
archiveSizeBytes: archiveFileSize,
|
||||||
|
useAzureSdk: true,
|
||||||
|
uploadChunkSize: 64 * 1024 * 1024,
|
||||||
|
uploadConcurrency: 8
|
||||||
|
}
|
||||||
|
|
||||||
|
jest
|
||||||
|
.spyOn(cacheUtils, 'getArchiveFileSizeInBytes')
|
||||||
|
.mockReturnValueOnce(archiveFileSize)
|
||||||
|
|
||||||
|
const cacheId = 4
|
||||||
|
jest
|
||||||
|
.spyOn(CacheServiceClientJSON.prototype, 'CreateCacheEntry')
|
||||||
|
.mockReturnValue(
|
||||||
|
Promise.resolve({ok: true, signedUploadUrl: signedUploadURL, message: ''})
|
||||||
|
)
|
||||||
|
|
||||||
|
const saveCacheMock = jest.spyOn(cacheHttpClient, 'saveCache')
|
||||||
|
|
||||||
|
const compression = CompressionMethod.Zstd
|
||||||
|
const getCompressionMock = jest
|
||||||
|
.spyOn(cacheUtils, 'getCompressionMethod')
|
||||||
|
.mockReturnValue(Promise.resolve(compression))
|
||||||
|
const cacheVersion = cacheUtils.getCacheVersion([paths], compression)
|
||||||
|
|
||||||
|
const finalizeCacheEntryMock = jest
|
||||||
|
.spyOn(CacheServiceClientJSON.prototype, 'FinalizeCacheEntryUpload')
|
||||||
|
.mockReturnValue(
|
||||||
|
Promise.resolve({ok: true, entryId: cacheId.toString(), message: ''})
|
||||||
|
)
|
||||||
|
|
||||||
|
const expectedCacheId = await saveCache([paths], key)
|
||||||
|
|
||||||
|
const archiveFolder = '/foo/bar'
|
||||||
|
const archiveFile = path.join(archiveFolder, CacheFilename.Zstd)
|
||||||
|
expect(saveCacheMock).toHaveBeenCalledWith(
|
||||||
|
-1,
|
||||||
|
archiveFile,
|
||||||
|
signedUploadURL,
|
||||||
|
options
|
||||||
|
)
|
||||||
|
expect(createTarMock).toHaveBeenCalledWith(
|
||||||
|
archiveFolder,
|
||||||
|
cachePaths,
|
||||||
|
compression
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(finalizeCacheEntryMock).toHaveBeenCalledWith({
|
||||||
|
key,
|
||||||
|
version: cacheVersion,
|
||||||
|
sizeBytes: archiveFileSize.toString()
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
||||||
|
expect(expectedCacheId).toBe(cacheId)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('save with create cache entry failure and specific error message', async () => {
|
||||||
|
const paths = ['node_modules']
|
||||||
|
const key = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
|
||||||
|
const infoLogMock = jest.spyOn(core, 'info')
|
||||||
|
const warningLogMock = jest.spyOn(core, 'warning')
|
||||||
|
const errorMessage = 'Cache storage quota exceeded for repository'
|
||||||
|
|
||||||
|
const createCacheEntryMock = jest
|
||||||
|
.spyOn(CacheServiceClientJSON.prototype, 'CreateCacheEntry')
|
||||||
|
.mockResolvedValue({ok: false, signedUploadUrl: '', message: errorMessage})
|
||||||
|
|
||||||
|
const createTarMock = jest.spyOn(tar, 'createTar')
|
||||||
|
const compression = CompressionMethod.Zstd
|
||||||
|
const getCompressionMock = jest
|
||||||
|
.spyOn(cacheUtils, 'getCompressionMethod')
|
||||||
|
.mockResolvedValueOnce(compression)
|
||||||
|
const archiveFileSize = 1024
|
||||||
|
jest
|
||||||
|
.spyOn(cacheUtils, 'getArchiveFileSizeInBytes')
|
||||||
|
.mockReturnValueOnce(archiveFileSize)
|
||||||
|
|
||||||
|
const cacheId = await saveCache(paths, key)
|
||||||
|
expect(cacheId).toBe(-1)
|
||||||
|
expect(warningLogMock).toHaveBeenCalledWith(
|
||||||
|
`Cache reservation failed: ${errorMessage}`
|
||||||
|
)
|
||||||
|
expect(infoLogMock).toHaveBeenCalledWith(
|
||||||
|
`Failed to save: Unable to reserve cache with key ${key}, another job may be creating this cache.`
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(createCacheEntryMock).toHaveBeenCalledWith({
|
||||||
|
key,
|
||||||
|
version: cacheUtils.getCacheVersion(paths, compression)
|
||||||
|
})
|
||||||
|
expect(createTarMock).toHaveBeenCalledTimes(1)
|
||||||
|
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('save with finalize cache entry failure and specific error message', async () => {
|
||||||
|
const paths = 'node_modules'
|
||||||
|
const key = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
|
||||||
|
const cachePaths = [path.resolve(paths)]
|
||||||
|
const logWarningMock = jest.spyOn(core, 'warning')
|
||||||
|
const signedUploadURL = 'https://blob-storage.local?signed=true'
|
||||||
|
const archiveFileSize = 1024
|
||||||
|
const errorMessage =
|
||||||
|
'Cache entry finalization failed due to concurrent access'
|
||||||
|
const options: UploadOptions = {
|
||||||
|
archiveSizeBytes: archiveFileSize,
|
||||||
|
useAzureSdk: true,
|
||||||
|
uploadChunkSize: 64 * 1024 * 1024,
|
||||||
|
uploadConcurrency: 8
|
||||||
|
}
|
||||||
|
|
||||||
|
const createCacheEntryMock = jest
|
||||||
|
.spyOn(CacheServiceClientJSON.prototype, 'CreateCacheEntry')
|
||||||
|
.mockReturnValue(
|
||||||
|
Promise.resolve({ok: true, signedUploadUrl: signedUploadURL, message: ''})
|
||||||
|
)
|
||||||
|
|
||||||
|
const createTarMock = jest.spyOn(tar, 'createTar')
|
||||||
|
const saveCacheMock = jest
|
||||||
|
.spyOn(cacheHttpClient, 'saveCache')
|
||||||
|
.mockResolvedValue()
|
||||||
|
|
||||||
|
const compression = CompressionMethod.Zstd
|
||||||
|
const getCompressionMock = jest
|
||||||
|
.spyOn(cacheUtils, 'getCompressionMethod')
|
||||||
|
.mockReturnValueOnce(Promise.resolve(compression))
|
||||||
|
|
||||||
|
const cacheVersion = cacheUtils.getCacheVersion([paths], compression)
|
||||||
|
jest
|
||||||
|
.spyOn(cacheUtils, 'getArchiveFileSizeInBytes')
|
||||||
|
.mockReturnValueOnce(archiveFileSize)
|
||||||
|
|
||||||
|
const finalizeCacheEntryMock = jest
|
||||||
|
.spyOn(CacheServiceClientJSON.prototype, 'FinalizeCacheEntryUpload')
|
||||||
|
.mockReturnValue(
|
||||||
|
Promise.resolve({ok: false, entryId: '', message: errorMessage})
|
||||||
|
)
|
||||||
|
|
||||||
|
const cacheId = await saveCache([paths], key, options)
|
||||||
|
|
||||||
|
expect(createCacheEntryMock).toHaveBeenCalledWith({
|
||||||
|
key,
|
||||||
|
version: cacheVersion
|
||||||
|
})
|
||||||
|
|
||||||
|
const archiveFolder = '/foo/bar'
|
||||||
|
const archiveFile = path.join(archiveFolder, CacheFilename.Zstd)
|
||||||
|
expect(createTarMock).toHaveBeenCalledWith(
|
||||||
|
archiveFolder,
|
||||||
|
cachePaths,
|
||||||
|
compression
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(saveCacheMock).toHaveBeenCalledWith(
|
||||||
|
-1,
|
||||||
|
archiveFile,
|
||||||
|
signedUploadURL,
|
||||||
|
options
|
||||||
|
)
|
||||||
|
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
||||||
|
|
||||||
|
expect(finalizeCacheEntryMock).toHaveBeenCalledWith({
|
||||||
|
key,
|
||||||
|
version: cacheVersion,
|
||||||
|
sizeBytes: archiveFileSize.toString()
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(cacheId).toBe(-1)
|
||||||
|
expect(logWarningMock).toHaveBeenCalledWith(errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('save with multiple large caches should succeed in v2 (testing 50GB)', async () => {
|
||||||
|
const paths = ['large-dataset', 'node_modules', 'build-artifacts']
|
||||||
|
const key = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
|
||||||
|
const cachePaths = paths.map(p => path.resolve(p))
|
||||||
|
const signedUploadURL = 'https://blob-storage.local?signed=true'
|
||||||
|
const createTarMock = jest.spyOn(tar, 'createTar')
|
||||||
|
// Simulate an extremely large cache (50GB)
|
||||||
|
const archiveFileSize = 50 * 1024 * 1024 * 1024 // 50GB
|
||||||
|
const options: UploadOptions = {
|
||||||
|
archiveSizeBytes: archiveFileSize,
|
||||||
|
useAzureSdk: true,
|
||||||
|
uploadChunkSize: 64 * 1024 * 1024,
|
||||||
|
uploadConcurrency: 8
|
||||||
|
}
|
||||||
|
|
||||||
|
jest
|
||||||
|
.spyOn(cacheUtils, 'getArchiveFileSizeInBytes')
|
||||||
|
.mockReturnValueOnce(archiveFileSize)
|
||||||
|
|
||||||
|
const cacheId = 7
|
||||||
|
jest
|
||||||
|
.spyOn(CacheServiceClientJSON.prototype, 'CreateCacheEntry')
|
||||||
|
.mockReturnValue(
|
||||||
|
Promise.resolve({ok: true, signedUploadUrl: signedUploadURL, message: ''})
|
||||||
|
)
|
||||||
|
|
||||||
|
const saveCacheMock = jest.spyOn(cacheHttpClient, 'saveCache')
|
||||||
|
|
||||||
|
const compression = CompressionMethod.Zstd
|
||||||
|
const getCompressionMock = jest
|
||||||
|
.spyOn(cacheUtils, 'getCompressionMethod')
|
||||||
|
.mockReturnValue(Promise.resolve(compression))
|
||||||
|
const cacheVersion = cacheUtils.getCacheVersion(paths, compression)
|
||||||
|
|
||||||
|
const finalizeCacheEntryMock = jest
|
||||||
|
.spyOn(CacheServiceClientJSON.prototype, 'FinalizeCacheEntryUpload')
|
||||||
|
.mockReturnValue(
|
||||||
|
Promise.resolve({ok: true, entryId: cacheId.toString(), message: ''})
|
||||||
|
)
|
||||||
|
|
||||||
|
const expectedCacheId = await saveCache(paths, key)
|
||||||
|
|
||||||
|
const archiveFolder = '/foo/bar'
|
||||||
|
const archiveFile = path.join(archiveFolder, CacheFilename.Zstd)
|
||||||
|
expect(saveCacheMock).toHaveBeenCalledWith(
|
||||||
|
-1,
|
||||||
|
archiveFile,
|
||||||
|
signedUploadURL,
|
||||||
|
options
|
||||||
|
)
|
||||||
|
expect(createTarMock).toHaveBeenCalledWith(
|
||||||
|
archiveFolder,
|
||||||
|
cachePaths,
|
||||||
|
compression
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(finalizeCacheEntryMock).toHaveBeenCalledWith({
|
||||||
|
key,
|
||||||
|
version: cacheVersion,
|
||||||
|
sizeBytes: archiveFileSize.toString()
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
||||||
|
expect(expectedCacheId).toBe(cacheId)
|
||||||
|
})
|
||||||
|
|
||||||
test('save with non existing path should not save cache using v2 saveCache', async () => {
|
test('save with non existing path should not save cache using v2 saveCache', async () => {
|
||||||
const path = 'node_modules'
|
const path = 'node_modules'
|
||||||
const key = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
|
const key = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
import * as uploadUtils from '../src/internal/uploadUtils'
|
import * as uploadUtils from '../src/internal/uploadUtils'
|
||||||
import {TransferProgressEvent} from '@azure/ms-rest-js'
|
import {TransferProgressEvent} from '@azure/core-rest-pipeline'
|
||||||
|
|
||||||
test('upload progress tracked correctly', () => {
|
test('upload progress tracked correctly', () => {
|
||||||
const progress = new uploadUtils.UploadProgress(1000)
|
const progress = new uploadUtils.UploadProgress(1000)
|
||||||
|
|||||||
+371
-817
File diff suppressed because it is too large
Load Diff
Vendored
+25
-15
@@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/cache",
|
"name": "@actions/cache",
|
||||||
"version": "4.0.3",
|
"version": "6.0.0",
|
||||||
"preview": true,
|
|
||||||
"description": "Actions cache lib",
|
"description": "Actions cache lib",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"github",
|
"github",
|
||||||
@@ -10,8 +9,15 @@
|
|||||||
],
|
],
|
||||||
"homepage": "https://github.com/actions/toolkit/tree/main/packages/cache",
|
"homepage": "https://github.com/actions/toolkit/tree/main/packages/cache",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"type": "module",
|
||||||
"main": "lib/cache.js",
|
"main": "lib/cache.js",
|
||||||
"types": "lib/cache.d.ts",
|
"types": "lib/cache.d.ts",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"types": "./lib/cache.d.ts",
|
||||||
|
"import": "./lib/cache.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"directories": {
|
"directories": {
|
||||||
"lib": "lib",
|
"lib": "lib",
|
||||||
"test": "__tests__"
|
"test": "__tests__"
|
||||||
@@ -31,26 +37,30 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"audit-moderate": "npm install && npm audit --json --audit-level=moderate > audit.json",
|
"audit-moderate": "npm install && npm audit --json --audit-level=moderate > audit.json",
|
||||||
"test": "echo \"Error: run tests from root\" && exit 1",
|
"test": "echo \"Error: run tests from root\" && exit 1",
|
||||||
"tsc": "tsc"
|
"tsc": "tsc && cp src/internal/shared/package-version.cjs lib/internal/shared/"
|
||||||
},
|
},
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/actions/toolkit/issues"
|
"url": "https://github.com/actions/toolkit/issues"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.11.1",
|
"@actions/core": "^3.0.0",
|
||||||
"@actions/exec": "^1.0.1",
|
"@actions/exec": "^3.0.0",
|
||||||
"@actions/glob": "^0.1.0",
|
"@actions/glob": "^0.6.1",
|
||||||
"@actions/http-client": "^2.1.1",
|
"@actions/http-client": "^4.0.0",
|
||||||
"@actions/io": "^1.0.1",
|
"@actions/io": "^3.0.0",
|
||||||
"@azure/abort-controller": "^1.1.0",
|
"@azure/core-rest-pipeline": "^1.22.0",
|
||||||
"@azure/ms-rest-js": "^2.6.0",
|
"@azure/storage-blob": "^12.30.0",
|
||||||
"@azure/storage-blob": "^12.13.0",
|
"@protobuf-ts/runtime-rpc": "^2.11.1",
|
||||||
"@protobuf-ts/plugin": "^2.9.4",
|
"semver": "^7.7.3"
|
||||||
"semver": "^6.3.1"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^22.13.9",
|
"@protobuf-ts/plugin": "^2.9.4",
|
||||||
"@types/semver": "^6.0.0",
|
"@types/node": "^25.1.0",
|
||||||
|
"@types/semver": "^7.7.1",
|
||||||
"typescript": "^5.2.2"
|
"typescript": "^5.2.2"
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"uri-js": "npm:uri-js-replace@^1.0.1",
|
||||||
|
"node-fetch": "^3.3.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+86
-25
@@ -1,18 +1,20 @@
|
|||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import * as utils from './internal/cacheUtils'
|
import * as utils from './internal/cacheUtils.js'
|
||||||
import * as cacheHttpClient from './internal/cacheHttpClient'
|
import * as cacheHttpClient from './internal/cacheHttpClient.js'
|
||||||
import * as cacheTwirpClient from './internal/shared/cacheTwirpClient'
|
import * as cacheTwirpClient from './internal/shared/cacheTwirpClient.js'
|
||||||
import {getCacheServiceVersion, isGhes} from './internal/config'
|
import {getCacheServiceVersion, isGhes} from './internal/config.js'
|
||||||
import {DownloadOptions, UploadOptions} from './options'
|
import {DownloadOptions, UploadOptions} from './options.js'
|
||||||
import {createTar, extractTar, listTar} from './internal/tar'
|
import {createTar, extractTar, listTar} from './internal/tar.js'
|
||||||
import {
|
import {
|
||||||
CreateCacheEntryRequest,
|
CreateCacheEntryRequest,
|
||||||
FinalizeCacheEntryUploadRequest,
|
FinalizeCacheEntryUploadRequest,
|
||||||
FinalizeCacheEntryUploadResponse,
|
FinalizeCacheEntryUploadResponse,
|
||||||
GetCacheEntryDownloadURLRequest
|
GetCacheEntryDownloadURLRequest
|
||||||
} from './generated/results/api/v1/cache'
|
} from './generated/results/api/v1/cache.js'
|
||||||
import {CacheFileSizeLimit} from './internal/constants'
|
import {HttpClientError} from '@actions/http-client'
|
||||||
|
|
||||||
|
export type {DownloadOptions, UploadOptions}
|
||||||
export class ValidationError extends Error {
|
export class ValidationError extends Error {
|
||||||
constructor(message: string) {
|
constructor(message: string) {
|
||||||
super(message)
|
super(message)
|
||||||
@@ -29,6 +31,14 @@ export class ReserveCacheError extends Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class FinalizeCacheError extends Error {
|
||||||
|
constructor(message: string) {
|
||||||
|
super(message)
|
||||||
|
this.name = 'FinalizeCacheError'
|
||||||
|
Object.setPrototypeOf(this, FinalizeCacheError.prototype)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function checkPaths(paths: string[]): void {
|
function checkPaths(paths: string[]): void {
|
||||||
if (!paths || paths.length === 0) {
|
if (!paths || paths.length === 0) {
|
||||||
throw new ValidationError(
|
throw new ValidationError(
|
||||||
@@ -57,7 +67,18 @@ function checkKey(key: string): void {
|
|||||||
* @returns boolean return true if Actions cache service feature is available, otherwise false
|
* @returns boolean return true if Actions cache service feature is available, otherwise false
|
||||||
*/
|
*/
|
||||||
export function isFeatureAvailable(): boolean {
|
export function isFeatureAvailable(): boolean {
|
||||||
return !!process.env['ACTIONS_CACHE_URL']
|
const cacheServiceVersion = getCacheServiceVersion()
|
||||||
|
|
||||||
|
// Check availability based on cache service version
|
||||||
|
switch (cacheServiceVersion) {
|
||||||
|
case 'v2':
|
||||||
|
// For v2, we need ACTIONS_RESULTS_URL
|
||||||
|
return !!process.env['ACTIONS_RESULTS_URL']
|
||||||
|
case 'v1':
|
||||||
|
default:
|
||||||
|
// For v1, we only need ACTIONS_CACHE_URL
|
||||||
|
return !!process.env['ACTIONS_CACHE_URL']
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -186,8 +207,17 @@ async function restoreCacheV1(
|
|||||||
if (typedError.name === ValidationError.name) {
|
if (typedError.name === ValidationError.name) {
|
||||||
throw error
|
throw error
|
||||||
} else {
|
} else {
|
||||||
// Supress all non-validation cache related errors because caching should be optional
|
// warn on cache restore failure and continue build
|
||||||
core.warning(`Failed to restore: ${(error as Error).message}`)
|
// Log server errors (5xx) as errors, all other errors as warnings
|
||||||
|
if (
|
||||||
|
typedError instanceof HttpClientError &&
|
||||||
|
typeof typedError.statusCode === 'number' &&
|
||||||
|
typedError.statusCode >= 500
|
||||||
|
) {
|
||||||
|
core.error(`Failed to restore: ${(error as Error).message}`)
|
||||||
|
} else {
|
||||||
|
core.warning(`Failed to restore: ${(error as Error).message}`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
// Try to delete the archive to save space
|
// Try to delete the archive to save space
|
||||||
@@ -264,7 +294,12 @@ async function restoreCacheV2(
|
|||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
core.info(`Cache hit for: ${request.key}`)
|
const isRestoreKeyMatch = request.key !== response.matchedKey
|
||||||
|
if (isRestoreKeyMatch) {
|
||||||
|
core.info(`Cache hit for restore-key: ${response.matchedKey}`)
|
||||||
|
} else {
|
||||||
|
core.info(`Cache hit for: ${response.matchedKey}`)
|
||||||
|
}
|
||||||
|
|
||||||
if (options?.lookupOnly) {
|
if (options?.lookupOnly) {
|
||||||
core.info('Lookup only - skipping download')
|
core.info('Lookup only - skipping download')
|
||||||
@@ -305,7 +340,16 @@ async function restoreCacheV2(
|
|||||||
throw error
|
throw error
|
||||||
} else {
|
} else {
|
||||||
// Supress all non-validation cache related errors because caching should be optional
|
// Supress all non-validation cache related errors because caching should be optional
|
||||||
core.warning(`Failed to restore: ${(error as Error).message}`)
|
// Log server errors (5xx) as errors, all other errors as warnings
|
||||||
|
if (
|
||||||
|
typedError instanceof HttpClientError &&
|
||||||
|
typeof typedError.statusCode === 'number' &&
|
||||||
|
typedError.statusCode >= 500
|
||||||
|
) {
|
||||||
|
core.error(`Failed to restore: ${(error as Error).message}`)
|
||||||
|
} else {
|
||||||
|
core.warning(`Failed to restore: ${(error as Error).message}`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
@@ -437,7 +481,16 @@ async function saveCacheV1(
|
|||||||
} else if (typedError.name === ReserveCacheError.name) {
|
} else if (typedError.name === ReserveCacheError.name) {
|
||||||
core.info(`Failed to save: ${typedError.message}`)
|
core.info(`Failed to save: ${typedError.message}`)
|
||||||
} else {
|
} else {
|
||||||
core.warning(`Failed to save: ${typedError.message}`)
|
// Log server errors (5xx) as errors, all other errors as warnings
|
||||||
|
if (
|
||||||
|
typedError instanceof HttpClientError &&
|
||||||
|
typeof typedError.statusCode === 'number' &&
|
||||||
|
typedError.statusCode >= 500
|
||||||
|
) {
|
||||||
|
core.error(`Failed to save: ${typedError.message}`)
|
||||||
|
} else {
|
||||||
|
core.warning(`Failed to save: ${typedError.message}`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
// Try to delete the archive to save space
|
// Try to delete the archive to save space
|
||||||
@@ -506,15 +559,6 @@ async function saveCacheV2(
|
|||||||
const archiveFileSize = utils.getArchiveFileSizeInBytes(archivePath)
|
const archiveFileSize = utils.getArchiveFileSizeInBytes(archivePath)
|
||||||
core.debug(`File Size: ${archiveFileSize}`)
|
core.debug(`File Size: ${archiveFileSize}`)
|
||||||
|
|
||||||
// For GHES, this check will take place in ReserveCache API with enterprise file size limit
|
|
||||||
if (archiveFileSize > CacheFileSizeLimit && !isGhes()) {
|
|
||||||
throw new Error(
|
|
||||||
`Cache size of ~${Math.round(
|
|
||||||
archiveFileSize / (1024 * 1024)
|
|
||||||
)} MB (${archiveFileSize} B) is over the 10GB limit, not saving cache.`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the archive size in the options, will be used to display the upload progress
|
// Set the archive size in the options, will be used to display the upload progress
|
||||||
options.archiveSizeBytes = archiveFileSize
|
options.archiveSizeBytes = archiveFileSize
|
||||||
|
|
||||||
@@ -534,7 +578,10 @@ async function saveCacheV2(
|
|||||||
try {
|
try {
|
||||||
const response = await twirpClient.CreateCacheEntry(request)
|
const response = await twirpClient.CreateCacheEntry(request)
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error('Response was not ok')
|
if (response.message) {
|
||||||
|
core.warning(`Cache reservation failed: ${response.message}`)
|
||||||
|
}
|
||||||
|
throw new Error(response.message || 'Response was not ok')
|
||||||
}
|
}
|
||||||
signedUploadUrl = response.signedUploadUrl
|
signedUploadUrl = response.signedUploadUrl
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -563,6 +610,9 @@ async function saveCacheV2(
|
|||||||
core.debug(`FinalizeCacheEntryUploadResponse: ${finalizeResponse.ok}`)
|
core.debug(`FinalizeCacheEntryUploadResponse: ${finalizeResponse.ok}`)
|
||||||
|
|
||||||
if (!finalizeResponse.ok) {
|
if (!finalizeResponse.ok) {
|
||||||
|
if (finalizeResponse.message) {
|
||||||
|
throw new FinalizeCacheError(finalizeResponse.message)
|
||||||
|
}
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unable to finalize cache with key ${key}, another job may be finalizing this cache.`
|
`Unable to finalize cache with key ${key}, another job may be finalizing this cache.`
|
||||||
)
|
)
|
||||||
@@ -575,8 +625,19 @@ async function saveCacheV2(
|
|||||||
throw error
|
throw error
|
||||||
} else if (typedError.name === ReserveCacheError.name) {
|
} else if (typedError.name === ReserveCacheError.name) {
|
||||||
core.info(`Failed to save: ${typedError.message}`)
|
core.info(`Failed to save: ${typedError.message}`)
|
||||||
|
} else if (typedError.name === FinalizeCacheError.name) {
|
||||||
|
core.warning(typedError.message)
|
||||||
} else {
|
} else {
|
||||||
core.warning(`Failed to save: ${typedError.message}`)
|
// Log server errors (5xx) as errors, all other errors as warnings
|
||||||
|
if (
|
||||||
|
typedError instanceof HttpClientError &&
|
||||||
|
typeof typedError.statusCode === 'number' &&
|
||||||
|
typedError.statusCode >= 500
|
||||||
|
) {
|
||||||
|
core.error(`Failed to save: ${typedError.message}`)
|
||||||
|
} else {
|
||||||
|
core.warning(`Failed to save: ${typedError.message}`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
// Try to delete the archive to save space
|
// Try to delete the archive to save space
|
||||||
|
|||||||
+31
-5
@@ -12,7 +12,7 @@ import type { PartialMessage } from "@protobuf-ts/runtime";
|
|||||||
import { reflectionMergePartial } from "@protobuf-ts/runtime";
|
import { reflectionMergePartial } from "@protobuf-ts/runtime";
|
||||||
import { MESSAGE_TYPE } from "@protobuf-ts/runtime";
|
import { MESSAGE_TYPE } from "@protobuf-ts/runtime";
|
||||||
import { MessageType } from "@protobuf-ts/runtime";
|
import { MessageType } from "@protobuf-ts/runtime";
|
||||||
import { CacheMetadata } from "../../entities/v1/cachemetadata";
|
import { CacheMetadata } from "../../entities/v1/cachemetadata.js";
|
||||||
/**
|
/**
|
||||||
* @generated from protobuf message github.actions.results.api.v1.CreateCacheEntryRequest
|
* @generated from protobuf message github.actions.results.api.v1.CreateCacheEntryRequest
|
||||||
*/
|
*/
|
||||||
@@ -50,6 +50,12 @@ export interface CreateCacheEntryResponse {
|
|||||||
* @generated from protobuf field: string signed_upload_url = 2;
|
* @generated from protobuf field: string signed_upload_url = 2;
|
||||||
*/
|
*/
|
||||||
signedUploadUrl: string;
|
signedUploadUrl: string;
|
||||||
|
/**
|
||||||
|
* When !ok, this field may contain a human-readable error message used to create an annotation
|
||||||
|
*
|
||||||
|
* @generated from protobuf field: string message = 3;
|
||||||
|
*/
|
||||||
|
message: string;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @generated from protobuf message github.actions.results.api.v1.FinalizeCacheEntryUploadRequest
|
* @generated from protobuf message github.actions.results.api.v1.FinalizeCacheEntryUploadRequest
|
||||||
@@ -94,6 +100,12 @@ export interface FinalizeCacheEntryUploadResponse {
|
|||||||
* @generated from protobuf field: int64 entry_id = 2;
|
* @generated from protobuf field: int64 entry_id = 2;
|
||||||
*/
|
*/
|
||||||
entryId: string;
|
entryId: string;
|
||||||
|
/**
|
||||||
|
* When !ok, this field may contain a human-readable error message used to create an annotation
|
||||||
|
*
|
||||||
|
* @generated from protobuf field: string message = 3;
|
||||||
|
*/
|
||||||
|
message: string;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @generated from protobuf message github.actions.results.api.v1.GetCacheEntryDownloadURLRequest
|
* @generated from protobuf message github.actions.results.api.v1.GetCacheEntryDownloadURLRequest
|
||||||
@@ -211,11 +223,12 @@ class CreateCacheEntryResponse$Type extends MessageType<CreateCacheEntryResponse
|
|||||||
constructor() {
|
constructor() {
|
||||||
super("github.actions.results.api.v1.CreateCacheEntryResponse", [
|
super("github.actions.results.api.v1.CreateCacheEntryResponse", [
|
||||||
{ no: 1, name: "ok", kind: "scalar", T: 8 /*ScalarType.BOOL*/ },
|
{ no: 1, name: "ok", kind: "scalar", T: 8 /*ScalarType.BOOL*/ },
|
||||||
{ no: 2, name: "signed_upload_url", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
{ no: 2, name: "signed_upload_url", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||||
|
{ no: 3, name: "message", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
create(value?: PartialMessage<CreateCacheEntryResponse>): CreateCacheEntryResponse {
|
create(value?: PartialMessage<CreateCacheEntryResponse>): CreateCacheEntryResponse {
|
||||||
const message = { ok: false, signedUploadUrl: "" };
|
const message = { ok: false, signedUploadUrl: "", message: "" };
|
||||||
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
||||||
if (value !== undefined)
|
if (value !== undefined)
|
||||||
reflectionMergePartial<CreateCacheEntryResponse>(this, message, value);
|
reflectionMergePartial<CreateCacheEntryResponse>(this, message, value);
|
||||||
@@ -232,6 +245,9 @@ class CreateCacheEntryResponse$Type extends MessageType<CreateCacheEntryResponse
|
|||||||
case /* string signed_upload_url */ 2:
|
case /* string signed_upload_url */ 2:
|
||||||
message.signedUploadUrl = reader.string();
|
message.signedUploadUrl = reader.string();
|
||||||
break;
|
break;
|
||||||
|
case /* string message */ 3:
|
||||||
|
message.message = reader.string();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
let u = options.readUnknownField;
|
let u = options.readUnknownField;
|
||||||
if (u === "throw")
|
if (u === "throw")
|
||||||
@@ -250,6 +266,9 @@ class CreateCacheEntryResponse$Type extends MessageType<CreateCacheEntryResponse
|
|||||||
/* string signed_upload_url = 2; */
|
/* string signed_upload_url = 2; */
|
||||||
if (message.signedUploadUrl !== "")
|
if (message.signedUploadUrl !== "")
|
||||||
writer.tag(2, WireType.LengthDelimited).string(message.signedUploadUrl);
|
writer.tag(2, WireType.LengthDelimited).string(message.signedUploadUrl);
|
||||||
|
/* string message = 3; */
|
||||||
|
if (message.message !== "")
|
||||||
|
writer.tag(3, WireType.LengthDelimited).string(message.message);
|
||||||
let u = options.writeUnknownFields;
|
let u = options.writeUnknownFields;
|
||||||
if (u !== false)
|
if (u !== false)
|
||||||
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||||
@@ -333,11 +352,12 @@ class FinalizeCacheEntryUploadResponse$Type extends MessageType<FinalizeCacheEnt
|
|||||||
constructor() {
|
constructor() {
|
||||||
super("github.actions.results.api.v1.FinalizeCacheEntryUploadResponse", [
|
super("github.actions.results.api.v1.FinalizeCacheEntryUploadResponse", [
|
||||||
{ no: 1, name: "ok", kind: "scalar", T: 8 /*ScalarType.BOOL*/ },
|
{ no: 1, name: "ok", kind: "scalar", T: 8 /*ScalarType.BOOL*/ },
|
||||||
{ no: 2, name: "entry_id", kind: "scalar", T: 3 /*ScalarType.INT64*/ }
|
{ no: 2, name: "entry_id", kind: "scalar", T: 3 /*ScalarType.INT64*/ },
|
||||||
|
{ no: 3, name: "message", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
create(value?: PartialMessage<FinalizeCacheEntryUploadResponse>): FinalizeCacheEntryUploadResponse {
|
create(value?: PartialMessage<FinalizeCacheEntryUploadResponse>): FinalizeCacheEntryUploadResponse {
|
||||||
const message = { ok: false, entryId: "0" };
|
const message = { ok: false, entryId: "0", message: "" };
|
||||||
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
||||||
if (value !== undefined)
|
if (value !== undefined)
|
||||||
reflectionMergePartial<FinalizeCacheEntryUploadResponse>(this, message, value);
|
reflectionMergePartial<FinalizeCacheEntryUploadResponse>(this, message, value);
|
||||||
@@ -354,6 +374,9 @@ class FinalizeCacheEntryUploadResponse$Type extends MessageType<FinalizeCacheEnt
|
|||||||
case /* int64 entry_id */ 2:
|
case /* int64 entry_id */ 2:
|
||||||
message.entryId = reader.int64().toString();
|
message.entryId = reader.int64().toString();
|
||||||
break;
|
break;
|
||||||
|
case /* string message */ 3:
|
||||||
|
message.message = reader.string();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
let u = options.readUnknownField;
|
let u = options.readUnknownField;
|
||||||
if (u === "throw")
|
if (u === "throw")
|
||||||
@@ -372,6 +395,9 @@ class FinalizeCacheEntryUploadResponse$Type extends MessageType<FinalizeCacheEnt
|
|||||||
/* int64 entry_id = 2; */
|
/* int64 entry_id = 2; */
|
||||||
if (message.entryId !== "0")
|
if (message.entryId !== "0")
|
||||||
writer.tag(2, WireType.Varint).int64(message.entryId);
|
writer.tag(2, WireType.Varint).int64(message.entryId);
|
||||||
|
/* string message = 3; */
|
||||||
|
if (message.message !== "")
|
||||||
|
writer.tag(3, WireType.LengthDelimited).string(message.message);
|
||||||
let u = options.writeUnknownFields;
|
let u = options.writeUnknownFields;
|
||||||
if (u !== false)
|
if (u !== false)
|
||||||
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
FinalizeCacheEntryUploadResponse,
|
FinalizeCacheEntryUploadResponse,
|
||||||
GetCacheEntryDownloadURLRequest,
|
GetCacheEntryDownloadURLRequest,
|
||||||
GetCacheEntryDownloadURLResponse,
|
GetCacheEntryDownloadURLResponse,
|
||||||
} from "./cache";
|
} from "./cache.js";
|
||||||
|
|
||||||
//==================================//
|
//==================================//
|
||||||
// Client Code //
|
// Client Code //
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import type { PartialMessage } from "@protobuf-ts/runtime";
|
|||||||
import { reflectionMergePartial } from "@protobuf-ts/runtime";
|
import { reflectionMergePartial } from "@protobuf-ts/runtime";
|
||||||
import { MESSAGE_TYPE } from "@protobuf-ts/runtime";
|
import { MESSAGE_TYPE } from "@protobuf-ts/runtime";
|
||||||
import { MessageType } from "@protobuf-ts/runtime";
|
import { MessageType } from "@protobuf-ts/runtime";
|
||||||
import { CacheScope } from "./cachescope";
|
import { CacheScope } from "./cachescope.js";
|
||||||
/**
|
/**
|
||||||
* @generated from protobuf message github.actions.results.entities.v1.CacheMetadata
|
* @generated from protobuf message github.actions.results.entities.v1.CacheMetadata
|
||||||
*/
|
*/
|
||||||
|
|||||||
+8
-8
@@ -7,8 +7,8 @@ import {
|
|||||||
} from '@actions/http-client/lib/interfaces'
|
} from '@actions/http-client/lib/interfaces'
|
||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
import {URL} from 'url'
|
import {URL} from 'url'
|
||||||
import * as utils from './cacheUtils'
|
import * as utils from './cacheUtils.js'
|
||||||
import {uploadCacheArchiveSDK} from './uploadUtils'
|
import {uploadCacheArchiveSDK} from './uploadUtils.js'
|
||||||
import {
|
import {
|
||||||
ArtifactCacheEntry,
|
ArtifactCacheEntry,
|
||||||
InternalCacheOptions,
|
InternalCacheOptions,
|
||||||
@@ -17,25 +17,25 @@ import {
|
|||||||
ReserveCacheResponse,
|
ReserveCacheResponse,
|
||||||
ITypedResponseWithError,
|
ITypedResponseWithError,
|
||||||
ArtifactCacheList
|
ArtifactCacheList
|
||||||
} from './contracts'
|
} from './contracts.js'
|
||||||
import {
|
import {
|
||||||
downloadCacheHttpClient,
|
downloadCacheHttpClient,
|
||||||
downloadCacheHttpClientConcurrent,
|
downloadCacheHttpClientConcurrent,
|
||||||
downloadCacheStorageSDK
|
downloadCacheStorageSDK
|
||||||
} from './downloadUtils'
|
} from './downloadUtils.js'
|
||||||
import {
|
import {
|
||||||
DownloadOptions,
|
DownloadOptions,
|
||||||
UploadOptions,
|
UploadOptions,
|
||||||
getDownloadOptions,
|
getDownloadOptions,
|
||||||
getUploadOptions
|
getUploadOptions
|
||||||
} from '../options'
|
} from '../options.js'
|
||||||
import {
|
import {
|
||||||
isSuccessStatusCode,
|
isSuccessStatusCode,
|
||||||
retryHttpClientResponse,
|
retryHttpClientResponse,
|
||||||
retryTypedResponse
|
retryTypedResponse
|
||||||
} from './requestUtils'
|
} from './requestUtils.js'
|
||||||
import {getCacheServiceURL} from './config'
|
import {getCacheServiceURL} from './config.js'
|
||||||
import {getUserAgentString} from './shared/user-agent'
|
import {getUserAgentString} from './shared/user-agent.js'
|
||||||
|
|
||||||
function getCacheApiUrl(resource: string): string {
|
function getCacheApiUrl(resource: string): string {
|
||||||
const baseUrl: string = getCacheServiceURL()
|
const baseUrl: string = getCacheServiceURL()
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ import {
|
|||||||
CacheFilename,
|
CacheFilename,
|
||||||
CompressionMethod,
|
CompressionMethod,
|
||||||
GnuTarPathOnWindows
|
GnuTarPathOnWindows
|
||||||
} from './constants'
|
} from './constants.js'
|
||||||
|
|
||||||
const versionSalt = '1.0'
|
const versionSalt = '1.0'
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import {CompressionMethod} from './constants'
|
import {CompressionMethod} from './constants.js'
|
||||||
import {TypedResponse} from '@actions/http-client/lib/interfaces'
|
import {TypedResponse} from '@actions/http-client/lib/interfaces'
|
||||||
import {HttpClientError} from '@actions/http-client'
|
import {HttpClientError} from '@actions/http-client'
|
||||||
|
|
||||||
+5
-7
@@ -1,18 +1,16 @@
|
|||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import {HttpClient, HttpClientResponse} from '@actions/http-client'
|
import {HttpClient, HttpClientResponse} from '@actions/http-client'
|
||||||
import {BlockBlobClient} from '@azure/storage-blob'
|
import {BlockBlobClient} from '@azure/storage-blob'
|
||||||
import {TransferProgressEvent} from '@azure/ms-rest-js'
|
import {TransferProgressEvent} from '@azure/core-rest-pipeline'
|
||||||
import * as buffer from 'buffer'
|
import * as buffer from 'buffer'
|
||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
import * as stream from 'stream'
|
import * as stream from 'stream'
|
||||||
import * as util from 'util'
|
import * as util from 'util'
|
||||||
|
|
||||||
import * as utils from './cacheUtils'
|
import * as utils from './cacheUtils.js'
|
||||||
import {SocketTimeout} from './constants'
|
import {SocketTimeout} from './constants.js'
|
||||||
import {DownloadOptions} from '../options'
|
import {DownloadOptions} from '../options.js'
|
||||||
import {retryHttpClientResponse} from './requestUtils'
|
import {retryHttpClientResponse} from './requestUtils.js'
|
||||||
|
|
||||||
import {AbortController} from '@azure/abort-controller'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pipes the body of a HTTP response to a stream
|
* Pipes the body of a HTTP response to a stream
|
||||||
|
|||||||
+2
-2
@@ -4,8 +4,8 @@ import {
|
|||||||
HttpClientError,
|
HttpClientError,
|
||||||
HttpClientResponse
|
HttpClientResponse
|
||||||
} from '@actions/http-client'
|
} from '@actions/http-client'
|
||||||
import {DefaultRetryDelay, DefaultRetryAttempts} from './constants'
|
import {DefaultRetryDelay, DefaultRetryAttempts} from './constants.js'
|
||||||
import {ITypedResponseWithError} from './contracts'
|
import {ITypedResponseWithError} from './contracts.js'
|
||||||
|
|
||||||
export function isSuccessStatusCode(statusCode?: number): boolean {
|
export function isSuccessStatusCode(statusCode?: number): boolean {
|
||||||
if (!statusCode) {
|
if (!statusCode) {
|
||||||
|
|||||||
+27
-9
@@ -1,12 +1,12 @@
|
|||||||
import {info, debug} from '@actions/core'
|
import {info, debug, warning} from '@actions/core'
|
||||||
import {getUserAgentString} from './user-agent'
|
import {getUserAgentString} from './user-agent.js'
|
||||||
import {NetworkError, UsageError} from './errors'
|
import {NetworkError, RateLimitError, UsageError} from './errors.js'
|
||||||
import {getCacheServiceURL} from '../config'
|
import {getCacheServiceURL} from '../config.js'
|
||||||
import {getRuntimeToken} from '../cacheUtils'
|
import {getRuntimeToken} from '../cacheUtils.js'
|
||||||
import {BearerCredentialHandler} from '@actions/http-client/lib/auth'
|
import {BearerCredentialHandler} from '@actions/http-client/lib/auth'
|
||||||
import {HttpClient, HttpClientResponse, HttpCodes} from '@actions/http-client'
|
import {HttpClient, HttpClientResponse, HttpCodes} from '@actions/http-client'
|
||||||
import {CacheServiceClientJSON} from '../../generated/results/api/v1/cache.twirp-client'
|
import {CacheServiceClientJSON} from '../../generated/results/api/v1/cache.twirp-client.js'
|
||||||
import {maskSecretUrls} from './util'
|
import {maskSecretUrls} from './util.js'
|
||||||
|
|
||||||
// The twirp http client must implement this interface
|
// The twirp http client must implement this interface
|
||||||
interface Rpc {
|
interface Rpc {
|
||||||
@@ -109,6 +109,21 @@ class CacheServiceClient implements Rpc {
|
|||||||
|
|
||||||
errorMessage = `${errorMessage}: ${body.msg}`
|
errorMessage = `${errorMessage}: ${body.msg}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle rate limiting - don't retry, just warn and exit
|
||||||
|
// For more info, see https://docs.github.com/en/actions/reference/limits
|
||||||
|
if (statusCode === HttpCodes.TooManyRequests) {
|
||||||
|
const retryAfterHeader = response.message.headers['retry-after']
|
||||||
|
if (retryAfterHeader) {
|
||||||
|
const parsedSeconds = parseInt(retryAfterHeader, 10)
|
||||||
|
if (!isNaN(parsedSeconds) && parsedSeconds > 0) {
|
||||||
|
warning(
|
||||||
|
`You've hit a rate limit, your rate limit will reset in ${parsedSeconds} seconds`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new RateLimitError(`Rate limited: ${errorMessage}`)
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof SyntaxError) {
|
if (error instanceof SyntaxError) {
|
||||||
debug(`Raw Body: ${rawBody}`)
|
debug(`Raw Body: ${rawBody}`)
|
||||||
@@ -118,6 +133,10 @@ class CacheServiceClient implements Rpc {
|
|||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (error instanceof RateLimitError) {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
|
||||||
if (NetworkError.isNetworkErrorCode(error?.code)) {
|
if (NetworkError.isNetworkErrorCode(error?.code)) {
|
||||||
throw new NetworkError(error?.code)
|
throw new NetworkError(error?.code)
|
||||||
}
|
}
|
||||||
@@ -162,8 +181,7 @@ class CacheServiceClient implements Rpc {
|
|||||||
HttpCodes.BadGateway,
|
HttpCodes.BadGateway,
|
||||||
HttpCodes.GatewayTimeout,
|
HttpCodes.GatewayTimeout,
|
||||||
HttpCodes.InternalServerError,
|
HttpCodes.InternalServerError,
|
||||||
HttpCodes.ServiceUnavailable,
|
HttpCodes.ServiceUnavailable
|
||||||
HttpCodes.TooManyRequests
|
|
||||||
]
|
]
|
||||||
|
|
||||||
return retryableStatusCodes.includes(statusCode)
|
return retryableStatusCodes.includes(statusCode)
|
||||||
|
|||||||
@@ -70,3 +70,10 @@ export class UsageError extends Error {
|
|||||||
return msg.includes('insufficient usage')
|
return msg.includes('insufficient usage')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class RateLimitError extends Error {
|
||||||
|
constructor(message: string) {
|
||||||
|
super(message)
|
||||||
|
this.name = 'RateLimitError'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
// This file exists as a CommonJS module to read the version from package.json.
|
||||||
|
// In an ESM package, using `require()` directly in .ts files requires disabling
|
||||||
|
// ESLint rules and doesn't work reliably across all Node.js versions.
|
||||||
|
// By keeping this as a .cjs file, we can use require() naturally and export
|
||||||
|
// the version for the ESM modules to import.
|
||||||
|
const packageJson = require('../../../package.json')
|
||||||
|
module.exports = { version: packageJson.version }
|
||||||
+2
-3
@@ -1,9 +1,8 @@
|
|||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports
|
import {version} from './package-version.cjs'
|
||||||
const packageJson = require('../../../package.json')
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure that this User Agent String is used in all HTTP calls so that we can monitor telemetry between different versions of this package
|
* Ensure that this User Agent String is used in all HTTP calls so that we can monitor telemetry between different versions of this package
|
||||||
*/
|
*/
|
||||||
export function getUserAgentString(): string {
|
export function getUserAgentString(): string {
|
||||||
return `@actions/cache-${packageJson.version}`
|
return `@actions/cache-${version}`
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+3
-3
@@ -2,15 +2,15 @@ import {exec} from '@actions/exec'
|
|||||||
import * as io from '@actions/io'
|
import * as io from '@actions/io'
|
||||||
import {existsSync, writeFileSync} from 'fs'
|
import {existsSync, writeFileSync} from 'fs'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import * as utils from './cacheUtils'
|
import * as utils from './cacheUtils.js'
|
||||||
import {ArchiveTool} from './contracts'
|
import {ArchiveTool} from './contracts.js'
|
||||||
import {
|
import {
|
||||||
CompressionMethod,
|
CompressionMethod,
|
||||||
SystemTarPathOnWindows,
|
SystemTarPathOnWindows,
|
||||||
ArchiveToolType,
|
ArchiveToolType,
|
||||||
TarFilename,
|
TarFilename,
|
||||||
ManifestFilename
|
ManifestFilename
|
||||||
} from './constants'
|
} from './constants.js'
|
||||||
|
|
||||||
const IS_WINDOWS = process.platform === 'win32'
|
const IS_WINDOWS = process.platform === 'win32'
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -5,9 +5,9 @@ import {
|
|||||||
BlockBlobClient,
|
BlockBlobClient,
|
||||||
BlockBlobParallelUploadOptions
|
BlockBlobParallelUploadOptions
|
||||||
} from '@azure/storage-blob'
|
} from '@azure/storage-blob'
|
||||||
import {TransferProgressEvent} from '@azure/ms-rest-js'
|
import {TransferProgressEvent} from '@azure/core-rest-pipeline'
|
||||||
import {InvalidResponseError} from './shared/errors'
|
import {InvalidResponseError} from './shared/errors.js'
|
||||||
import {UploadOptions} from '../options'
|
import {UploadOptions} from '../options.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for tracking the upload state and displaying stats.
|
* Class for tracking the upload state and displaying stats.
|
||||||
|
|||||||
Vendored
+2
@@ -4,6 +4,8 @@
|
|||||||
"baseUrl": "./",
|
"baseUrl": "./",
|
||||||
"outDir": "./lib",
|
"outDir": "./lib",
|
||||||
"rootDir": "./src",
|
"rootDir": "./src",
|
||||||
|
"module": "node16",
|
||||||
|
"moduleResolution": "node16",
|
||||||
"lib": [
|
"lib": [
|
||||||
"es6",
|
"es6",
|
||||||
"dom"
|
"dom"
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import * as core from '@actions/core';
|
|||||||
|
|
||||||
#### Inputs/Outputs
|
#### Inputs/Outputs
|
||||||
|
|
||||||
Action inputs can be read with `getInput` which returns a `string` or `getBooleanInput` which parses a boolean based on the [yaml 1.2 specification](https://yaml.org/spec/1.2/spec.html#id2804923). If `required` set to be false, the input should have a default value in `action.yml`.
|
Action inputs can be read with `getInput` which returns a `string` or `getBooleanInput` which parses a boolean based on the [yaml 1.2 specification](https://yaml.org/spec/1.2/spec.html#id2804923). If `required` is set to be false, the input should have a default value in `action.yml`.
|
||||||
|
|
||||||
Outputs can be set with `setOutput` which makes them available to be mapped into inputs of other actions to ensure they are decoupled.
|
Outputs can be set with `setOutput` which makes them available to be mapped into inputs of other actions to ensure they are decoupled.
|
||||||
|
|
||||||
|
|||||||
@@ -1,66 +1,99 @@
|
|||||||
# @actions/core Releases
|
# @actions/core Releases
|
||||||
|
|
||||||
### 1.12.0
|
## 3.0.0
|
||||||
- Adds optional functionality to `core.error` to allow for the logging of stack traces.
|
|
||||||
|
- **Breaking change**: Package is now ESM-only
|
||||||
|
- CommonJS consumers must use dynamic `import()` instead of `require()`
|
||||||
|
|
||||||
|
## 2.0.3
|
||||||
|
|
||||||
|
- Bump `@actions/http-client` to `3.0.2`
|
||||||
|
|
||||||
|
## 2.0.1
|
||||||
|
|
||||||
|
- Bump @actions/exec from 1.1.1 to 2.0.0 [#2199](https://github.com/actions/toolkit/pull/2199)
|
||||||
|
|
||||||
|
## 2.0.0
|
||||||
|
|
||||||
|
- Add support for Node 24 [#2110](https://github.com/actions/toolkit/pull/2110)
|
||||||
|
- Bump @actions/http-client from 2.0.1 to 3.0.0
|
||||||
|
|
||||||
|
## 1.11.1
|
||||||
|
|
||||||
### 1.11.1
|
|
||||||
- Fix uses of `crypto.randomUUID` on Node 18 and earlier [#1842](https://github.com/actions/toolkit/pull/1842)
|
- Fix uses of `crypto.randomUUID` on Node 18 and earlier [#1842](https://github.com/actions/toolkit/pull/1842)
|
||||||
|
|
||||||
### 1.11.0
|
### 1.11.0
|
||||||
|
|
||||||
- Add platform info utilities [#1551](https://github.com/actions/toolkit/pull/1551)
|
- Add platform info utilities [#1551](https://github.com/actions/toolkit/pull/1551)
|
||||||
- Remove dependency on `uuid` package [#1824](https://github.com/actions/toolkit/pull/1824)
|
- Remove dependency on `uuid` package [#1824](https://github.com/actions/toolkit/pull/1824)
|
||||||
|
|
||||||
### 1.10.1
|
### 1.10.1
|
||||||
|
|
||||||
- Fix error message reference in oidc utils [#1511](https://github.com/actions/toolkit/pull/1511)
|
- Fix error message reference in oidc utils [#1511](https://github.com/actions/toolkit/pull/1511)
|
||||||
|
|
||||||
### 1.10.0
|
### 1.10.0
|
||||||
|
|
||||||
- `saveState` and `setOutput` now use environment files if available [#1178](https://github.com/actions/toolkit/pull/1178)
|
- `saveState` and `setOutput` now use environment files if available [#1178](https://github.com/actions/toolkit/pull/1178)
|
||||||
- `getMultilineInput` now correctly trims whitespace by default [#1185](https://github.com/actions/toolkit/pull/1185)
|
- `getMultilineInput` now correctly trims whitespace by default [#1185](https://github.com/actions/toolkit/pull/1185)
|
||||||
|
|
||||||
### 1.9.1
|
### 1.9.1
|
||||||
|
|
||||||
- Randomize delimiter when calling `core.exportVariable`
|
- Randomize delimiter when calling `core.exportVariable`
|
||||||
|
|
||||||
### 1.9.0
|
### 1.9.0
|
||||||
|
|
||||||
- Added `toPosixPath`, `toWin32Path` and `toPlatformPath` utilities [#1102](https://github.com/actions/toolkit/pull/1102)
|
- Added `toPosixPath`, `toWin32Path` and `toPlatformPath` utilities [#1102](https://github.com/actions/toolkit/pull/1102)
|
||||||
|
|
||||||
### 1.8.2
|
### 1.8.2
|
||||||
|
|
||||||
- Update to v2.0.1 of `@actions/http-client` [#1087](https://github.com/actions/toolkit/pull/1087)
|
- Update to v2.0.1 of `@actions/http-client` [#1087](https://github.com/actions/toolkit/pull/1087)
|
||||||
|
|
||||||
### 1.8.1
|
### 1.8.1
|
||||||
|
|
||||||
- Update to v2.0.0 of `@actions/http-client`
|
- Update to v2.0.0 of `@actions/http-client`
|
||||||
|
|
||||||
### 1.8.0
|
### 1.8.0
|
||||||
|
|
||||||
- Deprecate `markdownSummary` extension export in favor of `summary`
|
- Deprecate `markdownSummary` extension export in favor of `summary`
|
||||||
- https://github.com/actions/toolkit/pull/1072
|
- <https://github.com/actions/toolkit/pull/1072>
|
||||||
- https://github.com/actions/toolkit/pull/1073
|
- <https://github.com/actions/toolkit/pull/1073>
|
||||||
|
|
||||||
### 1.7.0
|
### 1.7.0
|
||||||
|
|
||||||
- [Added `markdownSummary` extension](https://github.com/actions/toolkit/pull/1014)
|
- [Added `markdownSummary` extension](https://github.com/actions/toolkit/pull/1014)
|
||||||
|
|
||||||
### 1.6.0
|
### 1.6.0
|
||||||
|
|
||||||
- [Added OIDC Client function `getIDToken`](https://github.com/actions/toolkit/pull/919)
|
- [Added OIDC Client function `getIDToken`](https://github.com/actions/toolkit/pull/919)
|
||||||
- [Added `file` parameter to `AnnotationProperties`](https://github.com/actions/toolkit/pull/896)
|
- [Added `file` parameter to `AnnotationProperties`](https://github.com/actions/toolkit/pull/896)
|
||||||
|
|
||||||
### 1.5.0
|
### 1.5.0
|
||||||
|
|
||||||
- [Added support for notice annotations and more annotation fields](https://github.com/actions/toolkit/pull/855)
|
- [Added support for notice annotations and more annotation fields](https://github.com/actions/toolkit/pull/855)
|
||||||
|
|
||||||
### 1.4.0
|
### 1.4.0
|
||||||
|
|
||||||
- [Added the `getMultilineInput` function](https://github.com/actions/toolkit/pull/829)
|
- [Added the `getMultilineInput` function](https://github.com/actions/toolkit/pull/829)
|
||||||
|
|
||||||
### 1.3.0
|
### 1.3.0
|
||||||
|
|
||||||
- [Added the trimWhitespace option to getInput](https://github.com/actions/toolkit/pull/802)
|
- [Added the trimWhitespace option to getInput](https://github.com/actions/toolkit/pull/802)
|
||||||
- [Added the getBooleanInput function](https://github.com/actions/toolkit/pull/725)
|
- [Added the getBooleanInput function](https://github.com/actions/toolkit/pull/725)
|
||||||
|
|
||||||
### 1.2.7
|
### 1.2.7
|
||||||
|
|
||||||
- [Prepend newline for set-output](https://github.com/actions/toolkit/pull/772)
|
- [Prepend newline for set-output](https://github.com/actions/toolkit/pull/772)
|
||||||
|
|
||||||
### 1.2.6
|
### 1.2.6
|
||||||
|
|
||||||
- [Update `exportVariable` and `addPath` to use environment files](https://github.com/actions/toolkit/pull/571)
|
- [Update `exportVariable` and `addPath` to use environment files](https://github.com/actions/toolkit/pull/571)
|
||||||
|
|
||||||
### 1.2.5
|
### 1.2.5
|
||||||
|
|
||||||
- [Correctly bundle License File with package](https://github.com/actions/toolkit/pull/548)
|
- [Correctly bundle License File with package](https://github.com/actions/toolkit/pull/548)
|
||||||
|
|
||||||
### 1.2.4
|
### 1.2.4
|
||||||
|
|
||||||
- [Be more lenient in accepting non-string command inputs](https://github.com/actions/toolkit/pull/405)
|
- [Be more lenient in accepting non-string command inputs](https://github.com/actions/toolkit/pull/405)
|
||||||
- [Add Echo commands](https://github.com/actions/toolkit/pull/411)
|
- [Add Echo commands](https://github.com/actions/toolkit/pull/411)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as command from '../src/command'
|
import * as command from '../src/command.js'
|
||||||
import * as os from 'os'
|
import * as os from 'os'
|
||||||
|
|
||||||
/* eslint-disable @typescript-eslint/unbound-method */
|
/* eslint-disable @typescript-eslint/unbound-method */
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
import * as os from 'os'
|
import * as os from 'os'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import * as core from '../src/core'
|
import * as core from '../src/core.js'
|
||||||
import {HttpClient} from '@actions/http-client'
|
import {HttpClient} from '@actions/http-client'
|
||||||
import {toCommandProperties} from '../src/utils'
|
import {toCommandProperties} from '../src/utils.js'
|
||||||
|
|
||||||
/* eslint-disable @typescript-eslint/unbound-method */
|
/* eslint-disable @typescript-eslint/unbound-method */
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
|
|
||||||
import {toPlatformPath, toPosixPath, toWin32Path} from '../src/path-utils'
|
import {toPlatformPath, toPosixPath, toWin32Path} from '../src/path-utils.js'
|
||||||
|
|
||||||
describe('#toPosixPath', () => {
|
describe('#toPosixPath', () => {
|
||||||
const cases: {
|
const cases: {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import os from 'os'
|
import os from 'os'
|
||||||
import {platform} from '../src/core'
|
import {platform} from '../src/core.js'
|
||||||
|
|
||||||
describe('getInfo', () => {
|
describe('getInfo', () => {
|
||||||
it('returns the platform info', async () => {
|
it('returns the platform info', async () => {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
import * as os from 'os'
|
import * as os from 'os'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import {summary, SUMMARY_ENV_VAR} from '../src/summary'
|
import {summary, SUMMARY_ENV_VAR} from '../src/summary.js'
|
||||||
|
|
||||||
const testDirectoryPath = path.join(__dirname, 'test')
|
const testDirectoryPath = path.join(__dirname, 'test')
|
||||||
const testFilePath = path.join(testDirectoryPath, 'test-summary.md')
|
const testFilePath = path.join(testDirectoryPath, 'test-summary.md')
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user