Attempt at first version

This commit is contained in:
Dave Olsthoorn
2020-07-25 18:07:39 +02:00
parent 1b0d4d0266
commit 64495f005b
11 changed files with 663 additions and 5174 deletions

172
src/cache.ts Normal file
View File

@@ -0,0 +1,172 @@
import * as glob from '@actions/glob'
import * as cache from '@actions/cache'
import * as core from '@actions/core'
import * as crypto from 'crypto'
import * as fs from 'fs'
import {platform} from 'os'
import {
GRADLE_WRAPPER_GLOB,
GRADLE_CACHE_GLOB,
GRADLE_WRAPPER_DIR,
GRADLE_CACHE_DIR,
GRADLE_WRAPPER_KEY,
GRADLE_CACHE_KEY,
ANDROID_GLOB,
ANDROID_KEY,
COMMANDLINE_TOOLS_VERSION,
ANDROID_SDK_ROOT
} from './constants'
async function hashFiles(globs: string[]): Promise<string | undefined> {
const globber = await glob.create(globs.join('\n'), {
followSymbolicLinks: false
})
const hashes: Buffer[] = []
for await (const file of globber.globGenerator()) {
// skip directories
if (fs.statSync(file).isDirectory()) continue
core.debug(`hashFiles: found ${file}`)
const hash = crypto.createHash('sha256')
fs.createReadStream(file).pipe(hash)
hashes.push(hash.digest())
}
// No files hashed
if (hashes.length === 0) {
core.debug('hashFiles: no hashes in array')
return
}
// Loop trough files
const completeHash = crypto.createHash('sha256')
for (const hash of hashes) {
completeHash.update(hash)
}
completeHash.end()
return completeHash.digest('hex')
}
export async function preGradleWrapper(): Promise<void> {
const wrapperHash = await hashFiles(GRADLE_WRAPPER_GLOB)
const wrapperKey = `gradle-wrapper-${platform}-${wrapperHash}`
const wrapperRestoreKeys = [`gradle-wrapper-${platform}-`, `gradle-wrapper-`]
// if no wrapper is present skip trying to retrieve it
if (!wrapperHash) {
core.info('A hash for the gradle wrapper could not be generated')
return
}
core.saveState(GRADLE_WRAPPER_KEY, wrapperKey)
const wrapperCache = await cache.restoreCache(
[GRADLE_WRAPPER_DIR],
wrapperKey,
wrapperRestoreKeys
)
if (!wrapperCache) {
core.info(
'Gradle wrapper cache not found, expect a download from gradle wrapper.'
)
}
return
}
export async function postGradleWrapper(): Promise<void> {
const wrapperKey = core.getState(GRADLE_WRAPPER_KEY)
if (wrapperKey === '') {
core.info(
'A key for gradle wrapper was not defined, and thus there will not be a cache'
)
return
}
await cache.saveCache([GRADLE_WRAPPER_DIR], wrapperKey)
return
}
export async function preGradleCache(): Promise<void> {
const cacheHash = await hashFiles(GRADLE_CACHE_GLOB)
const cacheKey = `gradle-cache-${platform}-${cacheHash}`
const cacheRestoreKeys = [`gradle-cache-${platform}-`, `gradle-cache-`]
if (!cacheHash) {
core.info('A hash for the gradle dependencies could not be generated')
return
}
core.saveState(GRADLE_CACHE_KEY, cacheKey)
const cacheCache = await cache.restoreCache(
[GRADLE_CACHE_DIR],
cacheKey,
cacheRestoreKeys
)
if (!cacheCache) {
core.info('Gradle cache not found, expect dependency downloads from gradle')
}
return
}
export async function postGradleCache(): Promise<void> {
const cacheKey = core.getState(GRADLE_CACHE_KEY)
if (cacheKey === '') {
core.info(
'A key for gradle cache was not defined, and thus there will not be a cache'
)
return
}
await cache.saveCache([GRADLE_CACHE_DIR], cacheKey)
return
}
export async function preAndroidCache(): Promise<void> {
const androidHash = await hashFiles(ANDROID_GLOB)
const androidKey = `android-${platform}-${COMMANDLINE_TOOLS_VERSION}-${androidHash}`
const androidRestoreKeys = [
`android-${platform}-${COMMANDLINE_TOOLS_VERSION}-`,
`android-${platform}-`
]
if (!androidHash) {
core.info('A hash for the android sdk could not be generated')
return
}
core.saveState(ANDROID_KEY, androidKey)
const androidCache = await cache.restoreCache(
[GRADLE_CACHE_DIR],
androidKey,
androidRestoreKeys
)
if (!androidCache) {
core.info('Gradle cache not found, expect dependency downloads from gradle')
}
return
}
export async function postAndroidCache(): Promise<void> {
const androidKey = core.getState(ANDROID_KEY)
if (androidKey === '') {
core.info(
'A key for the android sdk was not defined, and thus there will not be a cache'
)
return
}
await cache.saveCache([ANDROID_SDK_ROOT], androidKey)
return
}

37
src/constants.ts Normal file
View File

@@ -0,0 +1,37 @@
import * as os from 'os'
import * as path from 'path'
export const ANNOTATION_MATCHERS = [
'android-lint-file-matcher.json',
'android-lint-line-matcher.json',
'gradle-matcher.json',
'kotlin-error-matcher.json',
'kotlin-warning-matcher.json'
]
export const HOME = os.homedir()
// Gradle constants
// For caching the gradle cache in ~/.gradle/cache
export const GRADLE_CACHE_GLOB = [
'**/*.gradle',
'**.gradle',
'gradle.properties'
]
export const GRADLE_CACHE_DIR = path.join(HOME, '.gradle', 'cache')
export const GRADLE_CACHE_KEY = 'GRADLE_CACHE_KEY'
// For caching the gradle wrapper in ~/.gradle/wrapper
export const GRADLE_WRAPPER_GLOB = ['gradle/wrapper/**', 'gradlew*']
export const GRADLE_WRAPPER_DIR = path.join(HOME, '.gradle', 'wrapper')
export const GRADLE_WRAPPER_KEY = 'GRADLE_WRAPPER_KEY'
// Android constants
export const ANDROID_SDK_ROOT = path.join(HOME, 'android')
export const ANDROID_GLOB = GRADLE_CACHE_GLOB
export const ANDROID_KEY = 'ANDROID_KEY'
export const COMMANDLINE_TOOLS_VERSION = '6609375'
export const COMMANDLINE_TOOLS_WIN_URL = `https://dl.google.com/android/repository/commandlinetools-win-${COMMANDLINE_TOOLS_VERSION}_latest.zip`
export const COMMANDLINE_TOOLS_MAC_URL = `https://dl.google.com/android/repository/commandlinetools-mac-${COMMANDLINE_TOOLS_VERSION}_latest.zip`
export const COMMANDLINE_TOOLS_LIN_URL = `https://dl.google.com/android/repository/commandlinetools-linux-${COMMANDLINE_TOOLS_VERSION}_latest.zip`

63
src/install.ts Normal file
View File

@@ -0,0 +1,63 @@
import * as fs from 'fs'
import * as path from 'path'
import * as core from '@actions/core'
import * as exec from '@actions/exec'
import * as tc from '@actions/tool-cache'
import {
ANDROID_SDK_ROOT,
COMMANDLINE_TOOLS_LIN_URL,
COMMANDLINE_TOOLS_MAC_URL,
COMMANDLINE_TOOLS_WIN_URL
} from './constants'
export async function install(): Promise<void> {
const licenseDir = path.join(ANDROID_SDK_ROOT, 'licenses')
// If the licences exist, the rest does too
if (fs.existsSync(licenseDir)) {
core.debug(`Skipping install, licenseDir found: ${licenseDir}`)
return
}
const acceptBuffer = Buffer.from('y\ny\ny\ny\ny\n\ny', 'utf8')
if (process.platform === 'linux') {
const cmdlineToolsZip = await tc.downloadTool(COMMANDLINE_TOOLS_LIN_URL)
const cmdlineTools = await tc.extractZip(cmdlineToolsZip)
const sdkManager = path.join(cmdlineTools, 'tools', 'sdkmanager')
exec.exec(
sdkManager,
['--include_obsolete', `--sdk_root=${ANDROID_SDK_ROOT}`, 'tools'],
{
input: acceptBuffer
}
)
} else if (process.platform === 'darwin') {
const cmdlineToolsZip = await tc.downloadTool(COMMANDLINE_TOOLS_MAC_URL)
const cmdlineTools = await tc.extractZip(cmdlineToolsZip)
const sdkManager = path.join(cmdlineTools, 'tools', 'sdkmanager')
exec.exec(
sdkManager,
['--include_obsolete', `--sdk_root=${ANDROID_SDK_ROOT}`, 'tools'],
{
input: acceptBuffer
}
)
} else if (process.platform === 'win32') {
const cmdlineToolsZip = await tc.downloadTool(COMMANDLINE_TOOLS_WIN_URL)
const cmdlineTools = await tc.extractZip(cmdlineToolsZip)
const sdkManager = path.join(cmdlineTools, 'tools', 'sdkmanager.bat')
exec.exec(
sdkManager,
['--include_obsolete', `--sdk_root=${ANDROID_SDK_ROOT}`, 'tools'],
{
input: acceptBuffer
}
)
} else {
core.error(`Unsupported platform: ${process.platform}`)
}
}

View File

@@ -1,83 +1,24 @@
import * as core from '@actions/core'
import * as path from 'path'
import * as tc from '@actions/tool-cache'
import * as fs from 'fs'
const matchers = [
'android-lint-file-matcher.json',
'android-lint-line-matcher.json',
'gradle-matcher.json',
'kotlin-error-matcher.json',
'kotlin-warning-matcher.json'
]
const licenses = {
'android-sdk-license': '\n24333f8a63b6825ea9c5514f83c2829b004d1fee'
}
let tempDirectory = process.env['RUNNER_TEMP'] || ''
const IS_WINDOWS = process.platform === 'win32'
const cmdToolsVersion = '6609375'
let cmdToolsOS: string
if (process.platform === 'win32') {
cmdToolsOS = 'win'
}
if (process.platform === 'darwin') {
cmdToolsOS = 'mac'
}
if (process.platform === 'linux') {
cmdToolsOS = 'linux'
}
if (!tempDirectory) {
let baseLocation
if (IS_WINDOWS) {
// On windows use the USERPROFILE env variable
baseLocation = process.env['USERPROFILE'] || 'C:\\'
} else {
if (process.platform === 'darwin') {
baseLocation = '/Users'
} else {
baseLocation = '/home'
}
}
tempDirectory = path.join(baseLocation, 'actions', 'temp')
}
import {ANDROID_SDK_ROOT, ANNOTATION_MATCHERS} from './constants'
import {preGradleCache, preAndroidCache, preGradleWrapper} from './cache'
import {install} from './install'
async function run(): Promise<void> {
const tempDir: string = path.join(
tempDirectory,
`temp_${Math.floor(Math.random() * 2000000000)}`
)
// process all caching but wait for them to all complete
await Promise.all([preGradleWrapper(), preGradleCache(), preAndroidCache()])
const androidHome = path.join(tempDir, 'android')
const cmdlineTools = path.join(androidHome, 'cmdline-tools')
await install()
const cmdToolsZip = await tc.downloadTool(
`https://dl.google.com/android/repository/commandlinetools-${cmdToolsOS}-${cmdToolsVersion}_latest.zip`
)
core.exportVariable('ANDROID_HOME', ANDROID_SDK_ROOT)
core.exportVariable('ANDROID_SDK_ROOT', ANDROID_SDK_ROOT)
core.debug('extract android commandlinetools')
await tc.extractZip(cmdToolsZip, cmdlineTools)
core.exportVariable('ANDROID_HOME', androidHome)
core.exportVariable('ANDROID_SDK_ROOT', androidHome)
core.addPath(path.join(cmdlineTools, 'tools', 'bin'))
const licenseDir = path.join(androidHome, 'licenses')
fs.existsSync(licenseDir) || fs.mkdirSync(licenseDir)
for (const [licenseName, licenseHash] of Object.entries(licenses)) {
const licenseFile = path.join(licenseDir, licenseName)
fs.appendFileSync(licenseFile, licenseHash)
}
core.addPath(path.join(ANDROID_SDK_ROOT, 'tools', 'bin'))
core.addPath(path.join(ANDROID_SDK_ROOT, 'platform-tools'))
core.debug('add matchers')
const matchersPath = path.join(__dirname, '..', '.github')
for (const matcher of matchers) {
const matchersPath = path.join(__dirname, '..', '..', '.github')
for (const matcher of ANNOTATION_MATCHERS) {
console.log(`##[add-matcher]${path.join(matchersPath, matcher)}`)
}
}

13
src/post.ts Normal file
View File

@@ -0,0 +1,13 @@
import {postAndroidCache, postGradleCache, postGradleWrapper} from './cache'
async function run(): Promise<void> {
await Promise.all([
postGradleCache(),
postGradleWrapper(),
postAndroidCache()
])
return
}
run()