mirror of
				https://github.com/actions/cache.git
				synced 2025-11-04 13:29:10 +08:00 
			
		
		
		
	Add initial eslint setup (#88)
This commit is contained in:
		
							
								
								
									
										16
									
								
								.eslintrc.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								.eslintrc.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
{
 | 
			
		||||
  "env": { "node": true, "jest": true },
 | 
			
		||||
  "parser": "@typescript-eslint/parser",
 | 
			
		||||
  "parserOptions": { "ecmaVersion": 2020, "sourceType": "module" },
 | 
			
		||||
  "extends": [
 | 
			
		||||
    "eslint:recommended",
 | 
			
		||||
    "plugin:@typescript-eslint/eslint-recommended",
 | 
			
		||||
    "plugin:@typescript-eslint/recommended",
 | 
			
		||||
    "plugin:import/errors",
 | 
			
		||||
    "plugin:import/warnings",
 | 
			
		||||
    "plugin:import/typescript",
 | 
			
		||||
    "plugin:prettier/recommended",
 | 
			
		||||
    "prettier/@typescript-eslint"
 | 
			
		||||
  ],
 | 
			
		||||
  "plugins": ["@typescript-eslint", "jest"]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								.github/workflows/workflow.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								.github/workflows/workflow.yml
									
									
									
									
										vendored
									
									
								
							@@ -1,4 +1,5 @@
 | 
			
		||||
name: Tests
 | 
			
		||||
 | 
			
		||||
on:
 | 
			
		||||
  pull_request:
 | 
			
		||||
    branches:
 | 
			
		||||
@@ -14,14 +15,16 @@ on:
 | 
			
		||||
jobs:
 | 
			
		||||
  test:
 | 
			
		||||
    name: Test on ${{ matrix.os }}
 | 
			
		||||
 | 
			
		||||
    strategy:
 | 
			
		||||
      matrix:
 | 
			
		||||
        os: [ubuntu-latest, windows-latest, macOS-latest]
 | 
			
		||||
 | 
			
		||||
    runs-on: ${{ matrix.os }}
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v1
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
    - uses: actions/setup-node@v1
 | 
			
		||||
      with:
 | 
			
		||||
        node-version: '12.x'
 | 
			
		||||
@@ -29,7 +32,12 @@ jobs:
 | 
			
		||||
    - run: npm ci
 | 
			
		||||
 | 
			
		||||
    - name: Prettier Format Check
 | 
			
		||||
      if: matrix.os == 'ubuntu-latest'
 | 
			
		||||
      run: npm run format-check
 | 
			
		||||
 | 
			
		||||
    - name: ESLint Check
 | 
			
		||||
      if: matrix.os == 'ubuntu-latest'
 | 
			
		||||
      run: npm run lint
 | 
			
		||||
 | 
			
		||||
    - name: Build & Test
 | 
			
		||||
      run: npm run test
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,7 @@
 | 
			
		||||
import * as core from "@actions/core";
 | 
			
		||||
import * as exec from "@actions/exec";
 | 
			
		||||
import * as io from "@actions/io";
 | 
			
		||||
 | 
			
		||||
import * as path from "path";
 | 
			
		||||
 | 
			
		||||
import * as cacheHttpClient from "../src/cacheHttpClient";
 | 
			
		||||
import { Inputs } from "../src/constants";
 | 
			
		||||
import { ArtifactCacheEntry } from "../src/contracts";
 | 
			
		||||
@@ -107,7 +105,7 @@ test("restore with no cache found", async () => {
 | 
			
		||||
    const stateMock = jest.spyOn(core, "saveState");
 | 
			
		||||
 | 
			
		||||
    const clientMock = jest.spyOn(cacheHttpClient, "getCacheEntry");
 | 
			
		||||
    clientMock.mockImplementation(_ => {
 | 
			
		||||
    clientMock.mockImplementation(() => {
 | 
			
		||||
        return Promise.resolve(null);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
@@ -134,7 +132,7 @@ test("restore with server error should fail", async () => {
 | 
			
		||||
    const stateMock = jest.spyOn(core, "saveState");
 | 
			
		||||
 | 
			
		||||
    const clientMock = jest.spyOn(cacheHttpClient, "getCacheEntry");
 | 
			
		||||
    clientMock.mockImplementation(_ => {
 | 
			
		||||
    clientMock.mockImplementation(() => {
 | 
			
		||||
        throw new Error("HTTP Error Occurred");
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
@@ -168,7 +166,7 @@ test("restore with restore keys and no cache found", async () => {
 | 
			
		||||
    const stateMock = jest.spyOn(core, "saveState");
 | 
			
		||||
 | 
			
		||||
    const clientMock = jest.spyOn(cacheHttpClient, "getCacheEntry");
 | 
			
		||||
    clientMock.mockImplementation(_ => {
 | 
			
		||||
    clientMock.mockImplementation(() => {
 | 
			
		||||
        return Promise.resolve(null);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
@@ -202,7 +200,7 @@ test("restore with cache found", async () => {
 | 
			
		||||
        archiveLocation: "www.actionscache.test/download"
 | 
			
		||||
    };
 | 
			
		||||
    const getCacheMock = jest.spyOn(cacheHttpClient, "getCacheEntry");
 | 
			
		||||
    getCacheMock.mockImplementation(_ => {
 | 
			
		||||
    getCacheMock.mockImplementation(() => {
 | 
			
		||||
        return Promise.resolve(cacheEntry);
 | 
			
		||||
    });
 | 
			
		||||
    const tempPath = "/foo/bar";
 | 
			
		||||
@@ -278,7 +276,7 @@ test("restore with cache found for restore key", async () => {
 | 
			
		||||
        archiveLocation: "www.actionscache.test/download"
 | 
			
		||||
    };
 | 
			
		||||
    const getCacheMock = jest.spyOn(cacheHttpClient, "getCacheEntry");
 | 
			
		||||
    getCacheMock.mockImplementation(_ => {
 | 
			
		||||
    getCacheMock.mockImplementation(() => {
 | 
			
		||||
        return Promise.resolve(cacheEntry);
 | 
			
		||||
    });
 | 
			
		||||
    const tempPath = "/foo/bar";
 | 
			
		||||
 
 | 
			
		||||
@@ -1,22 +1,23 @@
 | 
			
		||||
require('nock').disableNetConnect();
 | 
			
		||||
require("nock").disableNetConnect();
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  clearMocks: true,
 | 
			
		||||
  moduleFileExtensions: ['js', 'ts'],
 | 
			
		||||
  testEnvironment: 'node',
 | 
			
		||||
  testMatch: ['**/*.test.ts'],
 | 
			
		||||
  testRunner: 'jest-circus/runner',
 | 
			
		||||
  transform: {
 | 
			
		||||
    '^.+\\.ts$': 'ts-jest'
 | 
			
		||||
  },
 | 
			
		||||
  verbose: true
 | 
			
		||||
}
 | 
			
		||||
    clearMocks: true,
 | 
			
		||||
    moduleFileExtensions: ["js", "ts"],
 | 
			
		||||
    testEnvironment: "node",
 | 
			
		||||
    testMatch: ["**/*.test.ts"],
 | 
			
		||||
    testRunner: "jest-circus/runner",
 | 
			
		||||
    transform: {
 | 
			
		||||
        "^.+\\.ts$": "ts-jest"
 | 
			
		||||
    },
 | 
			
		||||
    verbose: true
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const processStdoutWrite = process.stdout.write.bind(process.stdout)
 | 
			
		||||
const processStdoutWrite = process.stdout.write.bind(process.stdout);
 | 
			
		||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
 | 
			
		||||
process.stdout.write = (str, encoding, cb) => {
 | 
			
		||||
  // Core library will directly call process.stdout.write for commands
 | 
			
		||||
  // We don't want :: commands to be executed by the runner during tests
 | 
			
		||||
  if (!str.match(/^::/)) {
 | 
			
		||||
    return processStdoutWrite(str, encoding, cb);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
    // Core library will directly call process.stdout.write for commands
 | 
			
		||||
    // We don't want :: commands to be executed by the runner during tests
 | 
			
		||||
    if (!str.match(/^::/)) {
 | 
			
		||||
        return processStdoutWrite(str, encoding, cb);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										924
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										924
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										12
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								package.json
									
									
									
									
									
								
							@@ -7,8 +7,9 @@
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "build": "tsc",
 | 
			
		||||
    "test": "tsc --noEmit && jest --coverage",
 | 
			
		||||
    "format": "prettier --write **/*.ts",
 | 
			
		||||
    "format-check": "prettier --check **/*.ts",
 | 
			
		||||
    "lint": "eslint '**/*.ts' --cache",
 | 
			
		||||
    "format": "prettier --write '**/*.ts'",
 | 
			
		||||
    "format-check": "prettier --check '**/*.ts'",
 | 
			
		||||
    "release": "ncc build -o dist/restore src/restore.ts && ncc build -o dist/save src/save.ts && git add -f dist/"
 | 
			
		||||
  },
 | 
			
		||||
  "repository": {
 | 
			
		||||
@@ -34,7 +35,14 @@
 | 
			
		||||
    "@types/nock": "^11.1.0",
 | 
			
		||||
    "@types/node": "^12.0.4",
 | 
			
		||||
    "@types/uuid": "^3.4.5",
 | 
			
		||||
    "@typescript-eslint/eslint-plugin": "^2.7.0",
 | 
			
		||||
    "@typescript-eslint/parser": "^2.7.0",
 | 
			
		||||
    "@zeit/ncc": "^0.20.5",
 | 
			
		||||
    "eslint": "^6.6.0",
 | 
			
		||||
    "eslint-config-prettier": "^6.5.0",
 | 
			
		||||
    "eslint-plugin-import": "^2.18.2",
 | 
			
		||||
    "eslint-plugin-jest": "^23.0.3",
 | 
			
		||||
    "eslint-plugin-prettier": "^3.1.1",
 | 
			
		||||
    "jest": "^24.8.0",
 | 
			
		||||
    "jest-circus": "^24.7.1",
 | 
			
		||||
    "nock": "^11.7.0",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +1,40 @@
 | 
			
		||||
import * as core from "@actions/core";
 | 
			
		||||
import * as fs from "fs";
 | 
			
		||||
 | 
			
		||||
import { BearerCredentialHandler } from "typed-rest-client/Handlers";
 | 
			
		||||
import { HttpClient } from "typed-rest-client/HttpClient";
 | 
			
		||||
import { IHttpClientResponse } from "typed-rest-client/Interfaces";
 | 
			
		||||
import { RestClient, IRequestOptions } from "typed-rest-client/RestClient";
 | 
			
		||||
 | 
			
		||||
import { IRequestOptions, RestClient } from "typed-rest-client/RestClient";
 | 
			
		||||
import { ArtifactCacheEntry } from "./contracts";
 | 
			
		||||
 | 
			
		||||
function getCacheUrl(): string {
 | 
			
		||||
    // Ideally we just use ACTIONS_CACHE_URL
 | 
			
		||||
    const cacheUrl: string = (
 | 
			
		||||
        process.env["ACTIONS_CACHE_URL"] ||
 | 
			
		||||
        process.env["ACTIONS_RUNTIME_URL"] ||
 | 
			
		||||
        ""
 | 
			
		||||
    ).replace("pipelines", "artifactcache");
 | 
			
		||||
    if (!cacheUrl) {
 | 
			
		||||
        throw new Error(
 | 
			
		||||
            "Cache Service Url not found, unable to restore cache."
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    core.debug(`Cache Url: ${cacheUrl}`);
 | 
			
		||||
    return cacheUrl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function createAcceptHeader(type: string, apiVersion: string): string {
 | 
			
		||||
    return `${type};api-version=${apiVersion}`;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getRequestOptions(): IRequestOptions {
 | 
			
		||||
    const requestOptions: IRequestOptions = {
 | 
			
		||||
        acceptHeader: createAcceptHeader("application/json", "5.2-preview.1")
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return requestOptions;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function getCacheEntry(
 | 
			
		||||
    keys: string[]
 | 
			
		||||
): Promise<ArtifactCacheEntry | null> {
 | 
			
		||||
@@ -43,16 +70,6 @@ export async function getCacheEntry(
 | 
			
		||||
    return cacheResult;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function downloadCache(
 | 
			
		||||
    cacheEntry: ArtifactCacheEntry,
 | 
			
		||||
    archivePath: string
 | 
			
		||||
): Promise<void> {
 | 
			
		||||
    const stream = fs.createWriteStream(archivePath);
 | 
			
		||||
    const httpClient = new HttpClient("actions/cache");
 | 
			
		||||
    const downloadResponse = await httpClient.get(cacheEntry.archiveLocation!);
 | 
			
		||||
    await pipeResponseToStream(downloadResponse, stream);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function pipeResponseToStream(
 | 
			
		||||
    response: IHttpClientResponse,
 | 
			
		||||
    stream: NodeJS.WritableStream
 | 
			
		||||
@@ -64,7 +81,21 @@ async function pipeResponseToStream(
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function saveCache(stream: NodeJS.ReadableStream, key: string) {
 | 
			
		||||
export async function downloadCache(
 | 
			
		||||
    cacheEntry: ArtifactCacheEntry,
 | 
			
		||||
    archivePath: string
 | 
			
		||||
): Promise<void> {
 | 
			
		||||
    const stream = fs.createWriteStream(archivePath);
 | 
			
		||||
    const httpClient = new HttpClient("actions/cache");
 | 
			
		||||
    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
 | 
			
		||||
    const downloadResponse = await httpClient.get(cacheEntry.archiveLocation!);
 | 
			
		||||
    await pipeResponseToStream(downloadResponse, stream);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function saveCache(
 | 
			
		||||
    stream: NodeJS.ReadableStream,
 | 
			
		||||
    key: string
 | 
			
		||||
): Promise<void> {
 | 
			
		||||
    const cacheUrl = getCacheUrl();
 | 
			
		||||
    const token = process.env["ACTIONS_RUNTIME_TOKEN"] || "";
 | 
			
		||||
    const bearerCredentialHandler = new BearerCredentialHandler(token);
 | 
			
		||||
@@ -93,32 +124,3 @@ export async function saveCache(stream: NodeJS.ReadableStream, key: string) {
 | 
			
		||||
 | 
			
		||||
    core.info("Cache saved successfully");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getRequestOptions(): IRequestOptions {
 | 
			
		||||
    const requestOptions: IRequestOptions = {
 | 
			
		||||
        acceptHeader: createAcceptHeader("application/json", "5.2-preview.1")
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return requestOptions;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function createAcceptHeader(type: string, apiVersion: string): string {
 | 
			
		||||
    return `${type};api-version=${apiVersion}`;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getCacheUrl(): string {
 | 
			
		||||
    // Ideally we just use ACTIONS_CACHE_URL
 | 
			
		||||
    let cacheUrl: string = (
 | 
			
		||||
        process.env["ACTIONS_CACHE_URL"] ||
 | 
			
		||||
        process.env["ACTIONS_RUNTIME_URL"] ||
 | 
			
		||||
        ""
 | 
			
		||||
    ).replace("pipelines", "artifactcache");
 | 
			
		||||
    if (!cacheUrl) {
 | 
			
		||||
        throw new Error(
 | 
			
		||||
            "Cache Service Url not found, unable to restore cache."
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    core.debug(`Cache Url: ${cacheUrl}`);
 | 
			
		||||
    return cacheUrl;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
/* eslint-disable @typescript-eslint/no-namespace */
 | 
			
		||||
export namespace Inputs {
 | 
			
		||||
    export const Key = "key";
 | 
			
		||||
    export const Path = "path";
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,12 @@
 | 
			
		||||
import * as core from "@actions/core";
 | 
			
		||||
import { exec } from "@actions/exec";
 | 
			
		||||
import * as io from "@actions/io";
 | 
			
		||||
 | 
			
		||||
import * as path from "path";
 | 
			
		||||
 | 
			
		||||
import * as cacheHttpClient from "./cacheHttpClient";
 | 
			
		||||
import { Inputs, State } from "./constants";
 | 
			
		||||
import * as utils from "./utils/actionUtils";
 | 
			
		||||
 | 
			
		||||
async function run() {
 | 
			
		||||
async function run(): Promise<void> {
 | 
			
		||||
    try {
 | 
			
		||||
        // Validate inputs, this can cause task failure
 | 
			
		||||
        let cachePath = utils.resolvePath(
 | 
			
		||||
 
 | 
			
		||||
@@ -1,15 +1,13 @@
 | 
			
		||||
import * as core from "@actions/core";
 | 
			
		||||
import { exec } from "@actions/exec";
 | 
			
		||||
 | 
			
		||||
import * as io from "@actions/io";
 | 
			
		||||
import * as fs from "fs";
 | 
			
		||||
import * as path from "path";
 | 
			
		||||
 | 
			
		||||
import * as cacheHttpClient from "./cacheHttpClient";
 | 
			
		||||
import { Inputs, State } from "./constants";
 | 
			
		||||
import * as utils from "./utils/actionUtils";
 | 
			
		||||
 | 
			
		||||
async function run() {
 | 
			
		||||
async function run(): Promise<void> {
 | 
			
		||||
    try {
 | 
			
		||||
        const state = utils.getCacheState();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,6 @@ import * as fs from "fs";
 | 
			
		||||
import * as os from "os";
 | 
			
		||||
import * as path from "path";
 | 
			
		||||
import * as uuidV4 from "uuid/v4";
 | 
			
		||||
 | 
			
		||||
import { Outputs, State } from "../constants";
 | 
			
		||||
import { ArtifactCacheEntry } from "../contracts";
 | 
			
		||||
 | 
			
		||||
@@ -50,10 +49,18 @@ export function isExactKeyMatch(
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function setCacheState(state: ArtifactCacheEntry): void {
 | 
			
		||||
    core.saveState(State.CacheResult, JSON.stringify(state));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function setCacheHitOutput(isCacheHit: boolean): void {
 | 
			
		||||
    core.setOutput(Outputs.CacheHit, isCacheHit.toString());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function setOutputAndState(
 | 
			
		||||
    key: string,
 | 
			
		||||
    cacheResult?: ArtifactCacheEntry
 | 
			
		||||
) {
 | 
			
		||||
): void {
 | 
			
		||||
    setCacheHitOutput(isExactKeyMatch(key, cacheResult));
 | 
			
		||||
    // Store the cache result if it exists
 | 
			
		||||
    cacheResult && setCacheState(cacheResult);
 | 
			
		||||
@@ -65,14 +72,6 @@ export function getCacheState(): ArtifactCacheEntry | undefined {
 | 
			
		||||
    return (stateData && JSON.parse(stateData)) as ArtifactCacheEntry;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function setCacheState(state: ArtifactCacheEntry) {
 | 
			
		||||
    core.saveState(State.CacheResult, JSON.stringify(state));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function setCacheHitOutput(isCacheHit: boolean) {
 | 
			
		||||
    core.setOutput(Outputs.CacheHit, isCacheHit.toString());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function resolvePath(filePath: string): string {
 | 
			
		||||
    if (filePath[0] === "~") {
 | 
			
		||||
        const home = os.homedir();
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@ function getInputName(name: string): string {
 | 
			
		||||
    return `INPUT_${name.replace(/ /g, "_").toUpperCase()}`;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function setInput(name: string, value: string) {
 | 
			
		||||
export function setInput(name: string, value: string): void {
 | 
			
		||||
    process.env[getInputName(name)] = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -15,14 +15,14 @@ interface CacheInput {
 | 
			
		||||
    restoreKeys?: string[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function setInputs(input: CacheInput) {
 | 
			
		||||
export function setInputs(input: CacheInput): void {
 | 
			
		||||
    setInput(Inputs.Path, input.path);
 | 
			
		||||
    setInput(Inputs.Key, input.key);
 | 
			
		||||
    input.restoreKeys &&
 | 
			
		||||
        setInput(Inputs.RestoreKeys, input.restoreKeys.join("\n"));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function clearInputs() {
 | 
			
		||||
export function clearInputs(): void {
 | 
			
		||||
    delete process.env[getInputName(Inputs.Path)];
 | 
			
		||||
    delete process.env[getInputName(Inputs.Key)];
 | 
			
		||||
    delete process.env[getInputName(Inputs.RestoreKeys)];
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user