mirror of https://github.com/actions/cache
Merge pull request #1 from Cula-Technologies/gcs-cache-support
Add GCS cache backend with GitHub fallback
This commit is contained in:
commit
7c01473a9b
|
|
@ -1 +0,0 @@
|
||||||
* @actions/actions-cache
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
name: Auto-tag main
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
tag:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Force-update v1 tag
|
||||||
|
run: |
|
||||||
|
git tag -f v1
|
||||||
|
git push -f origin v1
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
name: Close inactive issues
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: "30 8 * * *"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
close-issues:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
issues: write
|
|
||||||
pull-requests: write
|
|
||||||
steps:
|
|
||||||
- uses: actions/stale@v9
|
|
||||||
with:
|
|
||||||
days-before-issue-stale: 200
|
|
||||||
days-before-issue-close: 5
|
|
||||||
stale-issue-label: "stale"
|
|
||||||
stale-issue-message: "This issue is stale because it has been open for 200 days with no activity. Leave a comment to avoid closing this issue in 5 days."
|
|
||||||
close-issue-message: "This issue was closed because it has been inactive for 5 days since being marked as stale."
|
|
||||||
days-before-pr-stale: -1
|
|
||||||
days-before-pr-close: -1
|
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
name: Assign issue
|
|
||||||
|
|
||||||
on:
|
|
||||||
issues:
|
|
||||||
types: [opened]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
issues: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
run-action:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Get current oncall
|
|
||||||
id: oncall
|
|
||||||
run: |
|
|
||||||
echo "CURRENT=$(curl --request GET 'https://api.pagerduty.com/oncalls?include[]=users&schedule_ids[]=P5VG2BX&earliest=true' --header 'Authorization: Token token=${{ secrets.PAGERDUTY_TOKEN }}' --header 'Accept: application/vnd.pagerduty+json;version=2' --header 'Content-Type: application/json' | jq -r '.oncalls[].user.name')" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: add_assignees
|
|
||||||
run: |
|
|
||||||
curl -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN}}" https://api.github.com/repos/${{github.repository}}/issues/${{ github.event.issue.number}}/assignees -d '{"assignees":["${{steps.oncall.outputs.CURRENT}}"]}'
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
name: License check
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
validate-cached-dependency-records:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: Check licenses
|
|
||||||
steps:
|
|
||||||
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: npm ci --ignore-scripts
|
|
||||||
|
|
||||||
- name: Set up Ruby
|
|
||||||
uses: ruby/setup-ruby@v1
|
|
||||||
with:
|
|
||||||
ruby-version: '3.1.7'
|
|
||||||
|
|
||||||
- name: Install licensed tool
|
|
||||||
run: |
|
|
||||||
cd "$RUNNER_TEMP"
|
|
||||||
curl -Lfs -o licensed.tar.gz https://github.com/licensee/licensed/archive/refs/tags/v5.0.4.tar.gz
|
|
||||||
tar -xzf licensed.tar.gz
|
|
||||||
cd licensed-5.0.4
|
|
||||||
bundle install
|
|
||||||
|
|
||||||
- name: Check cached dependency records
|
|
||||||
run: |
|
|
||||||
cd ${{ github.workspace }}
|
|
||||||
BUNDLE_GEMFILE=$RUNNER_TEMP/licensed-5.0.4/Gemfile bundle exec $RUNNER_TEMP/licensed-5.0.4/exe/licensed status
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
name: Assign pull request reviewer
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request_target:
|
|
||||||
types: [opened]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
run-action:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Get current oncall
|
|
||||||
id: oncall
|
|
||||||
run: |
|
|
||||||
echo "CURRENT=$(curl --request GET 'https://api.pagerduty.com/oncalls?include[]=users&schedule_ids[]=P5VG2BX&earliest=true' --header 'Authorization: Token token=${{ secrets.PAGERDUTY_TOKEN }}' --header 'Accept: application/vnd.pagerduty+json;version=2' --header 'Content-Type: application/json' | jq -r '.oncalls[].user.name')" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Request Review
|
|
||||||
run: |
|
|
||||||
curl -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN}}" https://api.github.com/repos/${{github.repository}}/pulls/${{ github.event.pull_request.number}}/requested_reviewers -d '{"reviewers":["${{steps.oncall.outputs.CURRENT}}"]}'
|
|
||||||
|
|
||||||
- name: Add Assignee
|
|
||||||
run: |
|
|
||||||
curl -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN}}" https://api.github.com/repos/${{github.repository}}/issues/${{ github.event.pull_request.number}}/assignees -d '{"assignees":["${{steps.oncall.outputs.CURRENT}}"]}'
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
name: Publish immutable action
|
|
||||||
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types: [released]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
id-token: write
|
|
||||||
packages: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
publish:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checking out
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
- name: Publish
|
|
||||||
id: publish
|
|
||||||
uses: actions/publish-immutable-action@0.0.3
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
name: Release new action version
|
|
||||||
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types: [released]
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
TAG_NAME:
|
|
||||||
description: 'Tag name that the major tag will point to'
|
|
||||||
required: true
|
|
||||||
|
|
||||||
env:
|
|
||||||
TAG_NAME: ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }}
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
update_tag:
|
|
||||||
name: Update the major tag to include the ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }} changes
|
|
||||||
environment:
|
|
||||||
name: releaseNewActionVersion
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Update the ${{ env.TAG_NAME }} tag
|
|
||||||
id: update-major-tag
|
|
||||||
uses: actions/publish-action@v0.3.0
|
|
||||||
with:
|
|
||||||
source-tag: ${{ env.TAG_NAME }}
|
|
||||||
slack-webhook: ${{ secrets.SLACK_WEBHOOK }}
|
|
||||||
|
|
@ -1,276 +0,0 @@
|
||||||
name: Tests
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- releases/**
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- releases/**
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
# Build and unit test
|
|
||||||
build:
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
|
||||||
fail-fast: false
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
- name: Setup Node.js 24.x
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 24.x
|
|
||||||
cache: npm
|
|
||||||
- run: npm ci
|
|
||||||
- name: Prettier Format Check
|
|
||||||
run: npm run format-check
|
|
||||||
- name: ESLint Check
|
|
||||||
run: npm run lint
|
|
||||||
- name: Build & Test
|
|
||||||
run: npm run test
|
|
||||||
|
|
||||||
# End to end save and restore
|
|
||||||
test-save:
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
|
||||||
fail-fast: false
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
- name: Generate files in working directory
|
|
||||||
shell: bash
|
|
||||||
run: __tests__/create-cache-files.sh ${{ runner.os }} test-cache
|
|
||||||
- name: Generate files outside working directory
|
|
||||||
shell: bash
|
|
||||||
run: __tests__/create-cache-files.sh ${{ runner.os }} ~/test-cache
|
|
||||||
- name: Save cache
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
key: test-${{ runner.os }}-${{ github.run_id }}
|
|
||||||
path: |
|
|
||||||
test-cache
|
|
||||||
~/test-cache
|
|
||||||
|
|
||||||
test-restore:
|
|
||||||
needs: test-save
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
|
||||||
fail-fast: false
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
- name: Restore cache
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
key: test-${{ runner.os }}-${{ github.run_id }}
|
|
||||||
path: |
|
|
||||||
test-cache
|
|
||||||
~/test-cache
|
|
||||||
- name: Verify cache files in working directory
|
|
||||||
shell: bash
|
|
||||||
run: __tests__/verify-cache-files.sh ${{ runner.os }} test-cache
|
|
||||||
- name: Verify cache files outside working directory
|
|
||||||
shell: bash
|
|
||||||
run: __tests__/verify-cache-files.sh ${{ runner.os }} ~/test-cache
|
|
||||||
|
|
||||||
# End to end with proxy
|
|
||||||
test-proxy-save:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: ubuntu:latest
|
|
||||||
options: --cap-add=NET_ADMIN
|
|
||||||
services:
|
|
||||||
squid-proxy:
|
|
||||||
image: ubuntu/squid:latest
|
|
||||||
ports:
|
|
||||||
- 3128:3128
|
|
||||||
env:
|
|
||||||
http_proxy: http://squid-proxy:3128
|
|
||||||
https_proxy: http://squid-proxy:3128
|
|
||||||
steps:
|
|
||||||
- name: Wait for proxy to be ready
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "Waiting for squid proxy to be ready..."
|
|
||||||
echo "Resolving squid-proxy hostname:"
|
|
||||||
getent hosts squid-proxy || echo "DNS resolution failed"
|
|
||||||
for i in $(seq 1 30); do
|
|
||||||
if (echo > /dev/tcp/squid-proxy/3128) 2>/dev/null; then
|
|
||||||
echo "Proxy is ready!"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
echo "Attempt $i: Proxy not ready, waiting..."
|
|
||||||
sleep 2
|
|
||||||
done
|
|
||||||
echo "Proxy failed to become ready"
|
|
||||||
exit 1
|
|
||||||
env:
|
|
||||||
http_proxy: ""
|
|
||||||
https_proxy: ""
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
apt-get update
|
|
||||||
apt-get install -y iptables curl
|
|
||||||
- name: Verify proxy is working
|
|
||||||
run: |
|
|
||||||
echo "Testing proxy connectivity..."
|
|
||||||
curl -s -o /dev/null -w "%{http_code}" --proxy http://squid-proxy:3128 http://github.com || true
|
|
||||||
echo "Proxy verification complete"
|
|
||||||
- name: Block direct traffic (enforce proxy usage)
|
|
||||||
run: |
|
|
||||||
# Get the squid-proxy container IP
|
|
||||||
PROXY_IP=$(getent hosts squid-proxy | awk '{ print $1 }')
|
|
||||||
echo "Proxy IP: $PROXY_IP"
|
|
||||||
|
|
||||||
# Allow loopback traffic
|
|
||||||
iptables -A OUTPUT -o lo -j ACCEPT
|
|
||||||
|
|
||||||
# Allow traffic to the proxy container
|
|
||||||
iptables -A OUTPUT -d $PROXY_IP -j ACCEPT
|
|
||||||
|
|
||||||
# Allow established connections
|
|
||||||
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
|
|
||||||
|
|
||||||
# Allow DNS (needed for initial resolution)
|
|
||||||
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
|
|
||||||
iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT
|
|
||||||
|
|
||||||
# Block all other outbound traffic (HTTP/HTTPS)
|
|
||||||
iptables -A OUTPUT -p tcp --dport 80 -j REJECT
|
|
||||||
iptables -A OUTPUT -p tcp --dport 443 -j REJECT
|
|
||||||
|
|
||||||
# Log the iptables rules for debugging
|
|
||||||
iptables -L -v -n
|
|
||||||
- name: Verify direct HTTPS is blocked
|
|
||||||
run: |
|
|
||||||
echo "Testing that direct HTTPS requests fail..."
|
|
||||||
if curl --noproxy '*' -s --connect-timeout 5 https://github.com > /dev/null 2>&1; then
|
|
||||||
echo "ERROR: Direct HTTPS request succeeded - blocking is not working!"
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
echo "SUCCESS: Direct HTTPS request was blocked as expected"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Testing that HTTPS through proxy succeeds..."
|
|
||||||
if curl --proxy http://squid-proxy:3128 -s --connect-timeout 10 https://github.com > /dev/null 2>&1; then
|
|
||||||
echo "SUCCESS: HTTPS request through proxy succeeded"
|
|
||||||
else
|
|
||||||
echo "ERROR: HTTPS request through proxy failed!"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
- name: Generate files
|
|
||||||
run: __tests__/create-cache-files.sh proxy test-cache
|
|
||||||
- name: Save cache
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
key: test-proxy-${{ github.run_id }}
|
|
||||||
path: test-cache
|
|
||||||
|
|
||||||
test-proxy-restore:
|
|
||||||
needs: test-proxy-save
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: ubuntu:latest
|
|
||||||
options: --cap-add=NET_ADMIN
|
|
||||||
services:
|
|
||||||
squid-proxy:
|
|
||||||
image: ubuntu/squid:latest
|
|
||||||
ports:
|
|
||||||
- 3128:3128
|
|
||||||
env:
|
|
||||||
http_proxy: http://squid-proxy:3128
|
|
||||||
https_proxy: http://squid-proxy:3128
|
|
||||||
steps:
|
|
||||||
- name: Wait for proxy to be ready
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "Waiting for squid proxy to be ready..."
|
|
||||||
echo "Resolving squid-proxy hostname:"
|
|
||||||
getent hosts squid-proxy || echo "DNS resolution failed"
|
|
||||||
for i in $(seq 1 30); do
|
|
||||||
if (echo > /dev/tcp/squid-proxy/3128) 2>/dev/null; then
|
|
||||||
echo "Proxy is ready!"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
echo "Attempt $i: Proxy not ready, waiting..."
|
|
||||||
sleep 2
|
|
||||||
done
|
|
||||||
echo "Proxy failed to become ready"
|
|
||||||
exit 1
|
|
||||||
env:
|
|
||||||
http_proxy: ""
|
|
||||||
https_proxy: ""
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
apt-get update
|
|
||||||
apt-get install -y iptables curl
|
|
||||||
- name: Verify proxy is working
|
|
||||||
run: |
|
|
||||||
echo "Testing proxy connectivity..."
|
|
||||||
curl -s -o /dev/null -w "%{http_code}" --proxy http://squid-proxy:3128 http://github.com || true
|
|
||||||
echo "Proxy verification complete"
|
|
||||||
- name: Block direct traffic (enforce proxy usage)
|
|
||||||
run: |
|
|
||||||
# Get the squid-proxy container IP
|
|
||||||
PROXY_IP=$(getent hosts squid-proxy | awk '{ print $1 }')
|
|
||||||
echo "Proxy IP: $PROXY_IP"
|
|
||||||
|
|
||||||
# Allow loopback traffic
|
|
||||||
iptables -A OUTPUT -o lo -j ACCEPT
|
|
||||||
|
|
||||||
# Allow traffic to the proxy container
|
|
||||||
iptables -A OUTPUT -d $PROXY_IP -j ACCEPT
|
|
||||||
|
|
||||||
# Allow established connections
|
|
||||||
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
|
|
||||||
|
|
||||||
# Allow DNS (needed for initial resolution)
|
|
||||||
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
|
|
||||||
iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT
|
|
||||||
|
|
||||||
# Block all other outbound traffic (HTTP/HTTPS)
|
|
||||||
iptables -A OUTPUT -p tcp --dport 80 -j REJECT
|
|
||||||
iptables -A OUTPUT -p tcp --dport 443 -j REJECT
|
|
||||||
|
|
||||||
# Log the iptables rules for debugging
|
|
||||||
iptables -L -v -n
|
|
||||||
- name: Verify direct HTTPS is blocked
|
|
||||||
run: |
|
|
||||||
echo "Testing that direct HTTPS requests fail..."
|
|
||||||
if curl --noproxy '*' -s --connect-timeout 5 https://github.com > /dev/null 2>&1; then
|
|
||||||
echo "ERROR: Direct HTTPS request succeeded - blocking is not working!"
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
echo "SUCCESS: Direct HTTPS request was blocked as expected"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Testing that HTTPS through proxy succeeds..."
|
|
||||||
if curl --proxy http://squid-proxy:3128 -s --connect-timeout 10 https://github.com > /dev/null 2>&1; then
|
|
||||||
echo "SUCCESS: HTTPS request through proxy succeeded"
|
|
||||||
else
|
|
||||||
echo "ERROR: HTTPS request through proxy failed!"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
- name: Restore cache
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
key: test-proxy-${{ github.run_id }}
|
|
||||||
path: test-cache
|
|
||||||
- name: Verify cache
|
|
||||||
run: __tests__/verify-cache-files.sh proxy test-cache
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
sources:
|
|
||||||
npm: true
|
|
||||||
|
|
||||||
# Force UTF-8 encoding
|
|
||||||
encoding: 'utf-8'
|
|
||||||
|
|
||||||
# Ignore problematic packages with encoding issues
|
|
||||||
ignored:
|
|
||||||
npm:
|
|
||||||
- form-data
|
|
||||||
|
|
||||||
allowed:
|
|
||||||
- apache-2.0
|
|
||||||
- bsd-2-clause
|
|
||||||
- bsd-3-clause
|
|
||||||
- isc
|
|
||||||
- mit
|
|
||||||
- cc0-1.0
|
|
||||||
- unlicense
|
|
||||||
- 0bsd
|
|
||||||
|
|
||||||
reviewed:
|
|
||||||
npm:
|
|
||||||
- sax
|
|
||||||
- "@protobuf-ts/plugin-framework" # Apache-2.0
|
|
||||||
- "@protobuf-ts/runtime" # Apache-2.0
|
|
||||||
- fs.realpath # ISC
|
|
||||||
- glob # ISC
|
|
||||||
- prettier # MIT
|
|
||||||
- lodash # MIT
|
|
||||||
- "@actions/http-client" # MIT
|
|
||||||
13
action.yml
13
action.yml
|
|
@ -1,6 +1,6 @@
|
||||||
name: 'Cache'
|
name: 'Cache with GCS Support'
|
||||||
description: 'Cache artifacts like dependencies and build outputs to improve workflow execution time'
|
description: 'Cache artifacts to Google Cloud Storage or GitHub with automatic fallback'
|
||||||
author: 'GitHub'
|
author: 'danySam'
|
||||||
inputs:
|
inputs:
|
||||||
path:
|
path:
|
||||||
description: 'A list of files, directories, and wildcard patterns to cache and restore'
|
description: 'A list of files, directories, and wildcard patterns to cache and restore'
|
||||||
|
|
@ -26,6 +26,13 @@ inputs:
|
||||||
description: 'Check if a cache entry exists for the given input(s) (key, restore-keys) without downloading the cache'
|
description: 'Check if a cache entry exists for the given input(s) (key, restore-keys) without downloading the cache'
|
||||||
default: 'false'
|
default: 'false'
|
||||||
required: false
|
required: false
|
||||||
|
gcs-bucket:
|
||||||
|
description: 'Google Cloud Storage bucket name to use for caching. When provided, GCS will be used as the cache backend.'
|
||||||
|
required: false
|
||||||
|
gcs-path-prefix:
|
||||||
|
description: 'Optional prefix path within the GCS bucket for cache files'
|
||||||
|
required: false
|
||||||
|
default: 'github-cache'
|
||||||
save-always:
|
save-always:
|
||||||
description: 'Run the post step to save the cache even if another step before fails'
|
description: 'Run the post step to save the cache even if another step before fails'
|
||||||
default: 'false'
|
default: 'false'
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
42
package.json
42
package.json
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "cache",
|
"name": "cache",
|
||||||
"version": "5.0.4",
|
"version": "4.2.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "Cache dependencies and build outputs",
|
"description": "Cache dependencies and build outputs",
|
||||||
"main": "dist/restore/index.js",
|
"main": "dist/restore/index.js",
|
||||||
|
|
@ -23,32 +23,30 @@
|
||||||
"author": "GitHub",
|
"author": "GitHub",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/cache": "^5.0.5",
|
"@actions/cache": "^4.0.3",
|
||||||
"@actions/core": "^2.0.3",
|
"@actions/core": "^1.11.1",
|
||||||
"@actions/exec": "^2.0.0",
|
"@actions/exec": "^1.1.1",
|
||||||
"@actions/io": "^2.0.0"
|
"@actions/io": "^1.1.3",
|
||||||
|
"@google-cloud/storage": "^7.16.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^29.5.14",
|
"@types/jest": "^27.5.2",
|
||||||
"@types/nock": "^11.1.0",
|
"@types/nock": "^11.1.0",
|
||||||
"@types/node": "^24.1.0",
|
"@types/node": "^16.18.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
||||||
"@typescript-eslint/parser": "^7.2.0",
|
"@typescript-eslint/parser": "^5.45.0",
|
||||||
"@vercel/ncc": "^0.38.3",
|
"@vercel/ncc": "^0.38.3",
|
||||||
"eslint": "^8.28.0",
|
"eslint": "^8.28.0",
|
||||||
"eslint-config-prettier": "^9.1.2",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"eslint-plugin-import": "^2.32.0",
|
"eslint-plugin-import": "^2.26.0",
|
||||||
"eslint-plugin-jest": "^27.9.0",
|
"eslint-plugin-jest": "^26.9.0",
|
||||||
"eslint-plugin-prettier": "^5.5.3",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
"eslint-plugin-simple-import-sort": "^12.1.1",
|
"eslint-plugin-simple-import-sort": "^7.0.0",
|
||||||
"jest": "^29.7.0",
|
"jest": "^28.1.3",
|
||||||
"jest-circus": "^29.7.0",
|
"jest-circus": "^27.5.1",
|
||||||
"nock": "^13.2.9",
|
"nock": "^13.2.9",
|
||||||
"prettier": "^3.6.2",
|
"prettier": "^2.8.0",
|
||||||
"ts-jest": "^29.4.0",
|
"ts-jest": "^28.0.8",
|
||||||
"typescript": "^5.8.3"
|
"typescript": "^5.8.3"
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=24"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name: 'Restore Cache'
|
name: 'Restore Cache with GCS Support'
|
||||||
description: 'Restore Cache artifacts like dependencies and build outputs to improve workflow execution time'
|
description: 'Restore cache artifacts from Google Cloud Storage or GitHub with automatic fallback'
|
||||||
author: 'GitHub'
|
author: 'danySam'
|
||||||
inputs:
|
inputs:
|
||||||
path:
|
path:
|
||||||
description: 'A list of files, directories, and wildcard patterns to restore'
|
description: 'A list of files, directories, and wildcard patterns to restore'
|
||||||
|
|
@ -23,6 +23,13 @@ inputs:
|
||||||
description: 'Check if a cache entry exists for the given input(s) (key, restore-keys) without downloading the cache'
|
description: 'Check if a cache entry exists for the given input(s) (key, restore-keys) without downloading the cache'
|
||||||
default: 'false'
|
default: 'false'
|
||||||
required: false
|
required: false
|
||||||
|
gcs-bucket:
|
||||||
|
description: 'Google Cloud Storage bucket name to use for caching. When provided, GCS will be used as the cache backend.'
|
||||||
|
required: false
|
||||||
|
gcs-path-prefix:
|
||||||
|
description: 'Optional prefix path within the GCS bucket for cache files'
|
||||||
|
default: 'github-cache'
|
||||||
|
required: false
|
||||||
outputs:
|
outputs:
|
||||||
cache-hit:
|
cache-hit:
|
||||||
description: 'A boolean value to indicate an exact match was found for the primary key'
|
description: 'A boolean value to indicate an exact match was found for the primary key'
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name: 'Save a cache'
|
name: 'Save Cache with GCS Support'
|
||||||
description: 'Save Cache artifacts like dependencies and build outputs to improve workflow execution time'
|
description: 'Save cache artifacts to Google Cloud Storage or GitHub with automatic fallback'
|
||||||
author: 'GitHub'
|
author: 'danySam'
|
||||||
inputs:
|
inputs:
|
||||||
path:
|
path:
|
||||||
description: 'A list of files, directories, and wildcard patterns to cache'
|
description: 'A list of files, directories, and wildcard patterns to cache'
|
||||||
|
|
@ -15,6 +15,13 @@ inputs:
|
||||||
description: 'An optional boolean when enabled, allows windows runners to save caches that can be restored on other platforms'
|
description: 'An optional boolean when enabled, allows windows runners to save caches that can be restored on other platforms'
|
||||||
default: 'false'
|
default: 'false'
|
||||||
required: false
|
required: false
|
||||||
|
gcs-bucket:
|
||||||
|
description: 'Google Cloud Storage bucket name to use for caching. When provided, GCS will be used as the cache backend.'
|
||||||
|
required: false
|
||||||
|
gcs-path-prefix:
|
||||||
|
description: 'Optional prefix path within the GCS bucket for cache files'
|
||||||
|
default: 'github-cache'
|
||||||
|
required: false
|
||||||
runs:
|
runs:
|
||||||
using: 'node24'
|
using: 'node24'
|
||||||
main: '../dist/save-only/index.js'
|
main: '../dist/save-only/index.js'
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,9 @@ export enum Inputs {
|
||||||
UploadChunkSize = "upload-chunk-size", // Input for cache, save action
|
UploadChunkSize = "upload-chunk-size", // Input for cache, save action
|
||||||
EnableCrossOsArchive = "enableCrossOsArchive", // Input for cache, restore, save action
|
EnableCrossOsArchive = "enableCrossOsArchive", // Input for cache, restore, save action
|
||||||
FailOnCacheMiss = "fail-on-cache-miss", // Input for cache, restore action
|
FailOnCacheMiss = "fail-on-cache-miss", // Input for cache, restore action
|
||||||
LookupOnly = "lookup-only" // Input for cache, restore action
|
LookupOnly = "lookup-only", // Input for cache, restore action
|
||||||
|
GCSBucket = "gcs-bucket", // Input for cache, restore, save action
|
||||||
|
GCSPathPrefix = "gcs-path-prefix" // Input for cache, restore, save action
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Outputs {
|
export enum Outputs {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import * as cache from "@actions/cache";
|
|
||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
|
|
||||||
import { Events, Inputs, Outputs, State } from "./constants";
|
import { Events, Inputs, Outputs, State } from "./constants";
|
||||||
|
|
@ -8,6 +7,7 @@ import {
|
||||||
StateProvider
|
StateProvider
|
||||||
} from "./stateProvider";
|
} from "./stateProvider";
|
||||||
import * as utils from "./utils/actionUtils";
|
import * as utils from "./utils/actionUtils";
|
||||||
|
import * as cache from "./utils/gcsCache";
|
||||||
|
|
||||||
export async function restoreImpl(
|
export async function restoreImpl(
|
||||||
stateProvider: IStateProvider,
|
stateProvider: IStateProvider,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import * as cache from "@actions/cache";
|
|
||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
|
|
||||||
import { Events, Inputs, State } from "./constants";
|
import { Events, Inputs, State } from "./constants";
|
||||||
|
|
@ -8,6 +7,7 @@ import {
|
||||||
StateProvider
|
StateProvider
|
||||||
} from "./stateProvider";
|
} from "./stateProvider";
|
||||||
import * as utils from "./utils/actionUtils";
|
import * as utils from "./utils/actionUtils";
|
||||||
|
import * as cache from "./utils/gcsCache";
|
||||||
|
|
||||||
// Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in
|
// Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in
|
||||||
// @actions/toolkit when a failed upload closes the file descriptor causing any in-process reads to
|
// @actions/toolkit when a failed upload closes the file descriptor causing any in-process reads to
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import * as cache from "@actions/cache";
|
import * as cache from "@actions/cache";
|
||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
|
|
||||||
import { RefKey } from "../constants";
|
import { Inputs, RefKey } from "../constants";
|
||||||
|
|
||||||
export function isGhes(): boolean {
|
export function isGhes(): boolean {
|
||||||
const ghUrl = new URL(
|
const ghUrl = new URL(
|
||||||
|
|
@ -66,7 +66,42 @@ export function getInputAsBool(
|
||||||
return result.toLowerCase() === "true";
|
return result.toLowerCase() === "true";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if GCS is configured and available
|
||||||
|
export function isGCSAvailable(): boolean {
|
||||||
|
try {
|
||||||
|
const bucket = core.getInput(Inputs.GCSBucket);
|
||||||
|
if (!bucket) {
|
||||||
|
core.info(
|
||||||
|
"GCS bucket name not provided, falling back to GitHub cache"
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're not doing an actual authentication check here as it would require
|
||||||
|
// making an API call. The Storage client will handle authentication later
|
||||||
|
// via Application Default Credentials (ADC) which supports multiple auth methods:
|
||||||
|
// - Service account JSON key file (GOOGLE_APPLICATION_CREDENTIALS)
|
||||||
|
// - Workload Identity Federation
|
||||||
|
// - Metadata server-based auth (GCE, GKE)
|
||||||
|
// - User credentials from gcloud CLI
|
||||||
|
|
||||||
|
core.info(`GCS bucket configured: ${bucket}`);
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
logWarning(
|
||||||
|
`Failed to check GCS availability: ${(error as Error).message}`
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function isCacheFeatureAvailable(): boolean {
|
export function isCacheFeatureAvailable(): boolean {
|
||||||
|
// Check if GCS cache is available
|
||||||
|
if (isGCSAvailable()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, check GitHub cache
|
||||||
if (cache.isFeatureAvailable()) {
|
if (cache.isFeatureAvailable()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,275 @@
|
||||||
|
import * as cache from "@actions/cache";
|
||||||
|
import * as utils from "@actions/cache/lib/internal/cacheUtils";
|
||||||
|
import { CompressionMethod } from "@actions/cache/lib/internal/constants";
|
||||||
|
import {
|
||||||
|
createTar,
|
||||||
|
extractTar,
|
||||||
|
listTar
|
||||||
|
} from "@actions/cache/lib/internal/tar";
|
||||||
|
import { DownloadOptions, UploadOptions } from "@actions/cache/lib/options";
|
||||||
|
import * as core from "@actions/core";
|
||||||
|
import { Storage } from "@google-cloud/storage";
|
||||||
|
import * as path from "path";
|
||||||
|
|
||||||
|
import { Inputs } from "../constants";
|
||||||
|
import { isGCSAvailable } from "./actionUtils";
|
||||||
|
|
||||||
|
const DEFAULT_PATH_PREFIX = "github-cache";
|
||||||
|
|
||||||
|
// Function to initialize GCS client using Application Default Credentials
|
||||||
|
function getGCSClient(): Storage | null {
|
||||||
|
try {
|
||||||
|
core.info("Initializing GCS client");
|
||||||
|
return new Storage();
|
||||||
|
} catch (error) {
|
||||||
|
core.warning(
|
||||||
|
`Failed to initialize GCS client: ${(error as Error).message}`
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function restoreCache(
|
||||||
|
paths: string[],
|
||||||
|
primaryKey: string,
|
||||||
|
restoreKeys?: string[],
|
||||||
|
options?: DownloadOptions,
|
||||||
|
enableCrossOsArchive?: boolean
|
||||||
|
): Promise<string | undefined> {
|
||||||
|
// Check if GCS is available
|
||||||
|
if (isGCSAvailable()) {
|
||||||
|
try {
|
||||||
|
const result = await restoreFromGCS(
|
||||||
|
paths,
|
||||||
|
primaryKey,
|
||||||
|
restoreKeys,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
core.info(`Cache restored from GCS with key: ${result}`);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
core.info("Cache not found in GCS, falling back to GitHub cache");
|
||||||
|
} catch (error) {
|
||||||
|
core.warning(
|
||||||
|
`Failed to restore from GCS: ${(error as Error).message}`
|
||||||
|
);
|
||||||
|
core.info("Falling back to GitHub cache");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
core.info("GCS not configured, using GitHub cache");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to GitHub cache
|
||||||
|
return await cache.restoreCache(
|
||||||
|
paths,
|
||||||
|
primaryKey,
|
||||||
|
restoreKeys,
|
||||||
|
options,
|
||||||
|
enableCrossOsArchive
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function saveCache(
|
||||||
|
paths: string[],
|
||||||
|
key: string,
|
||||||
|
options?: UploadOptions,
|
||||||
|
enableCrossOsArchive?: boolean
|
||||||
|
): Promise<number> {
|
||||||
|
if (isGCSAvailable()) {
|
||||||
|
try {
|
||||||
|
const result = await saveToGCS(paths, key);
|
||||||
|
if (result) {
|
||||||
|
core.info(`Cache saved to GCS with key: [${key} | ${result}]`);
|
||||||
|
return 1; // Success ID
|
||||||
|
}
|
||||||
|
|
||||||
|
core.warning("Failed to save to GCS, falling back to GitHub cache");
|
||||||
|
return -1;
|
||||||
|
} catch (error) {
|
||||||
|
core.warning(`Failed to save to GCS: ${(error as Error).message}`);
|
||||||
|
core.info("Falling back to GitHub cache");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
core.info("GCS not configured, using GitHub cache");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to GitHub cache
|
||||||
|
return await cache.saveCache(paths, key, options, enableCrossOsArchive);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function that checks if the cache feature is available (either GCS or GitHub cache)
|
||||||
|
export function isFeatureAvailable(): boolean {
|
||||||
|
return isGCSAvailable() || cache.isFeatureAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function restoreFromGCS(
|
||||||
|
_paths: string[], // validate paths?
|
||||||
|
primaryKey: string,
|
||||||
|
restoreKeys: string[] = [],
|
||||||
|
options?: DownloadOptions
|
||||||
|
): Promise<string | undefined> {
|
||||||
|
const storage = getGCSClient();
|
||||||
|
if (!storage) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bucket = core.getInput(Inputs.GCSBucket);
|
||||||
|
const pathPrefix =
|
||||||
|
core.getInput(Inputs.GCSPathPrefix) || DEFAULT_PATH_PREFIX;
|
||||||
|
const compressionMethod = await utils.getCompressionMethod();
|
||||||
|
|
||||||
|
const archiveFolder = await utils.createTempDirectory();
|
||||||
|
const archivePath = path.join(
|
||||||
|
archiveFolder,
|
||||||
|
utils.getCacheFileName(compressionMethod)
|
||||||
|
);
|
||||||
|
|
||||||
|
const keys = [primaryKey, ...restoreKeys];
|
||||||
|
const gcsPath = await findFileOnGCS(
|
||||||
|
storage,
|
||||||
|
bucket,
|
||||||
|
pathPrefix,
|
||||||
|
keys,
|
||||||
|
compressionMethod
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!gcsPath) {
|
||||||
|
core.info(`No matching cache found`);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If lookup only, just return the key
|
||||||
|
if (options?.lookupOnly) {
|
||||||
|
core.info(`Cache found in GCS with key: ${gcsPath}`);
|
||||||
|
return gcsPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
core.info(`Downloading from GCS: ${bucket}/${gcsPath}`);
|
||||||
|
const file = storage.bucket(bucket).file(gcsPath);
|
||||||
|
await file.download({ destination: archivePath });
|
||||||
|
|
||||||
|
if (core.isDebug()) {
|
||||||
|
await listTar(archivePath, compressionMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
const archiveFileSize = utils.getArchiveFileSizeInBytes(archivePath);
|
||||||
|
core.info(
|
||||||
|
`Cache Size: ~${Math.round(
|
||||||
|
archiveFileSize / (1024 * 1024)
|
||||||
|
)} MB (${archiveFileSize} B)`
|
||||||
|
);
|
||||||
|
|
||||||
|
await extractTar(archivePath, compressionMethod);
|
||||||
|
core.info("Cache restored successfully");
|
||||||
|
|
||||||
|
return gcsPath;
|
||||||
|
} catch (error) {
|
||||||
|
core.warning(`Failed to restore: ${(error as Error).message}`);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
await utils.unlinkFile(archivePath);
|
||||||
|
} catch (error) {
|
||||||
|
core.debug(`Failed to delete archive: ${error}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getGCSPath(
|
||||||
|
pathPrefix: string,
|
||||||
|
key: string,
|
||||||
|
compressionMethod: CompressionMethod
|
||||||
|
): string {
|
||||||
|
return `${pathPrefix}/${key}.${utils.getCacheFileName(compressionMethod)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveToGCS(
|
||||||
|
paths: string[],
|
||||||
|
key: string
|
||||||
|
): Promise<string | undefined> {
|
||||||
|
const storage = getGCSClient();
|
||||||
|
if (!storage) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bucket = core.getInput(Inputs.GCSBucket);
|
||||||
|
const pathPrefix =
|
||||||
|
core.getInput(Inputs.GCSPathPrefix) || DEFAULT_PATH_PREFIX;
|
||||||
|
const compressionMethod = await utils.getCompressionMethod();
|
||||||
|
|
||||||
|
const cachePaths = await utils.resolvePaths(paths);
|
||||||
|
core.debug("Cache Paths:");
|
||||||
|
core.debug(`${JSON.stringify(cachePaths)}`);
|
||||||
|
|
||||||
|
if (cachePaths.length === 0) {
|
||||||
|
throw new Error(
|
||||||
|
`Path Validation Error: Path(s) specified in the action for caching do(es) not exist, hence no cache is being saved.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const archiveFolder = await utils.createTempDirectory();
|
||||||
|
const archivePath = path.join(
|
||||||
|
archiveFolder,
|
||||||
|
utils.getCacheFileName(compressionMethod)
|
||||||
|
);
|
||||||
|
|
||||||
|
core.debug(`Archive Path: ${archivePath}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await createTar(archiveFolder, cachePaths, compressionMethod);
|
||||||
|
if (core.isDebug()) {
|
||||||
|
await listTar(archivePath, compressionMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
const gcsPath = getGCSPath(pathPrefix, key, compressionMethod);
|
||||||
|
core.info(`Uploading to GCS: ${bucket}/${gcsPath}`);
|
||||||
|
const [file] = await storage.bucket(bucket).upload(archivePath, {
|
||||||
|
destination: gcsPath,
|
||||||
|
resumable: false
|
||||||
|
});
|
||||||
|
|
||||||
|
return file.metadata.id;
|
||||||
|
} catch (error) {
|
||||||
|
core.warning(
|
||||||
|
`Error creating or uploading cache: ${(error as Error).message}`
|
||||||
|
);
|
||||||
|
throw new Error(
|
||||||
|
`Error creating or uploading cache: ${(error as Error).message}`
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
await utils.unlinkFile(archivePath);
|
||||||
|
} catch (error) {
|
||||||
|
core.debug(`Failed to delete archive: ${error}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function findFileOnGCS(
|
||||||
|
storage: Storage,
|
||||||
|
bucket: string,
|
||||||
|
pathPrefix: string,
|
||||||
|
keys: string[],
|
||||||
|
compressionMethod: CompressionMethod
|
||||||
|
): Promise<string | undefined> {
|
||||||
|
for (const key of keys) {
|
||||||
|
const gcsPath = getGCSPath(pathPrefix, key, compressionMethod);
|
||||||
|
if (await checkFileExists(storage, bucket, gcsPath)) {
|
||||||
|
core.info(`Found file on bucket: ${bucket} with key: ${gcsPath}`);
|
||||||
|
return gcsPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkFileExists(
|
||||||
|
storage: Storage,
|
||||||
|
bucket: string,
|
||||||
|
path: string
|
||||||
|
): Promise<boolean> {
|
||||||
|
const [exists] = await storage.bucket(bucket).file(path).exists();
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue