Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/cache-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,13 @@ jobs:
run: |
node -e "Promise.resolve(require('./packages/cache/lib/cache').saveCache(['test-cache','~/test-cache'],'test-${{ runner.os }}-${{ github.run_id }}'))"

- name: Restore cache using restoreCache()
- name: Restore cache using restoreCache() with http-client
env:
DISABLE_AZCOPY: true
run: |
node -e "Promise.resolve(require('./packages/cache/lib/cache').restoreCache(['test-cache','~/test-cache'],'test-${{ runner.os }}-${{ github.run_id }}'))"

- name: Restore cache using restoreCache() with AzCopy
run: |
node -e "Promise.resolve(require('./packages/cache/lib/cache').restoreCache(['test-cache','~/test-cache'],'test-${{ runner.os }}-${{ github.run_id }}'))"

Expand Down
5 changes: 4 additions & 1 deletion packages/cache/RELEASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@
- Fixes issues with the zstd compression algorithm on Windows and Ubuntu 16.04 [#469](https://github.com/actions/toolkit/pull/469)

### 0.2.1
- Fix to await async function getCompressionMethod
- Fix to await async function getCompressionMethod

### 0.3.0
- Downloads Azure-hosted caches using AzCopy when available
2 changes: 1 addition & 1 deletion packages/cache/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@actions/cache",
"version": "0.2.1",
"version": "0.3.0",
"preview": true,
"description": "Actions cache lib",
"keywords": [
Expand Down
31 changes: 29 additions & 2 deletions packages/cache/src/internal/cacheHttpClient.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as core from '@actions/core'
import {exec} from '@actions/exec'
import {HttpClient, HttpCodes} from '@actions/http-client'
import {BearerCredentialHandler} from '@actions/http-client/auth'
import {
Expand All @@ -9,6 +10,7 @@ import {
import * as crypto from 'crypto'
import * as fs from 'fs'
import * as stream from 'stream'
import {URL} from 'url'
import * as util from 'util'

import * as utils from './cacheUtils'
Expand Down Expand Up @@ -220,7 +222,7 @@ async function pipeResponseToStream(
await pipeline(response.message, output)
}

export async function downloadCache(
async function downloadCacheHttpClient(
archiveLocation: string,
archivePath: string
): Promise<void> {
Expand Down Expand Up @@ -256,6 +258,31 @@ export async function downloadCache(
}
}

export async function downloadCache(
archiveLocation: string,
archivePath: string
): Promise<void> {
const archiveUrl = new URL(archiveLocation)
const disableAzCopy = process.env['DISABLE_AZCOPY'] ?? ''

// Use AzCopy to download caches hosted on Azure to improve speed and reliability.
if (
archiveUrl.hostname.endsWith('.blob.core.windows.net') &&
disableAzCopy !== 'true'
) {
const command = await utils.getAzCopyCommand()

if (command) {
core.info(`Downloading cache using ${command}...`)
await exec(command, ['copy', archiveLocation, archivePath])
return
}
}

// Otherwise, download using the Actions http-client.
await downloadCacheHttpClient(archiveLocation, archivePath)
}

// Reserve Cache
export async function reserveCache(
key: string,
Expand Down Expand Up @@ -360,7 +387,7 @@ async function uploadFile(
})
.on('error', error => {
throw new Error(
`Cache upload failed because file read failed with ${error.Message}`
`Cache upload failed because file read failed with ${error.message}`
)
}),
start,
Expand Down
25 changes: 25 additions & 0 deletions packages/cache/src/internal/cacheUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,28 @@ export async function isGnuTarInstalled(): Promise<boolean> {
const versionOutput = await getVersion('tar')
return versionOutput.toLowerCase().includes('gnu tar')
}

export async function getAzCopyCommand(): Promise<string | undefined> {
// Always prefer the azcopy10 alias first, which is the correct version on Ubuntu.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean by correct version? What happens if we just do the version 10 or newer check?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

azcopy on Ubuntu is version 7.x.x, which uses a completely different CLI. So we need to use the azcopy10 alias on Ubuntu to get to version 10.

This is different on a Mac, where azcopy is v10. Windows currently does not have AzCopy installed, but I already filed an issue to fix that.

I'm not sure why it's setup this way, but this logic is needed to ensure we get the correct version on Ubuntu.

let versionOutput = await getVersion('azcopy10')

if (versionOutput.toLowerCase().startsWith('azcopy version')) {
return 'azcopy10'
}

// Fall back to any azcopy that is version 10 or newer.
versionOutput = await getVersion('azcopy')

if (versionOutput.toLowerCase().startsWith('azcopy version')) {
const version = versionOutput.substring(15)

if (semver.gte(version, '10.0.0')) {
return 'azcopy'
} else {
core.debug(`Found azcopy but version is not supported: ${version}`)
}
}

// Otherwise, azcopy is not available.
return undefined
}