Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
880be3d0a7 | ||
|
|
d1125b4510 | ||
|
|
15abc13cc4 |
@@ -13,6 +13,18 @@ jest.mock('@actions/core', () => {
|
|||||||
return {warning: warnMock};
|
return {warning: warnMock};
|
||||||
})
|
})
|
||||||
|
|
||||||
|
jest.mock('fs', () => {
|
||||||
|
return {
|
||||||
|
statSync: () => {
|
||||||
|
return {
|
||||||
|
isDirectory(): boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
describe("ArtifactGlobber", () => {
|
describe("ArtifactGlobber", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
globMock.mockClear()
|
globMock.mockClear()
|
||||||
|
|||||||
60
__tests__/ArtifactPathValidator.test.ts
Normal file
60
__tests__/ArtifactPathValidator.test.ts
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
const directoryMock = jest.fn()
|
||||||
|
const warnMock = jest.fn()
|
||||||
|
|
||||||
|
import {ArtifactPathValidator} from "../src/ArtifactPathValidator";
|
||||||
|
|
||||||
|
const pattern = 'pattern'
|
||||||
|
|
||||||
|
jest.mock('@actions/core', () => {
|
||||||
|
return {warning: warnMock};
|
||||||
|
})
|
||||||
|
|
||||||
|
jest.mock('fs', () => {
|
||||||
|
return {
|
||||||
|
statSync: () => {
|
||||||
|
return {isDirectory: directoryMock}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("ArtifactPathValidator", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
warnMock.mockClear()
|
||||||
|
directoryMock.mockClear()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("warns and filters out path which points to a directory", () => {
|
||||||
|
const paths = ['path1', 'path2']
|
||||||
|
directoryMock.mockReturnValueOnce(true).mockReturnValueOnce(false)
|
||||||
|
|
||||||
|
const validator = new ArtifactPathValidator(false, paths, pattern)
|
||||||
|
|
||||||
|
const result = validator.validate()
|
||||||
|
expect(warnMock).toBeCalled()
|
||||||
|
expect(result).toEqual(['path2'])
|
||||||
|
})
|
||||||
|
|
||||||
|
it("warns when no glob results are produced and empty results shouldn't throw", () => {
|
||||||
|
const validator = new ArtifactPathValidator(false, [], pattern)
|
||||||
|
const result = validator.validate()
|
||||||
|
expect(warnMock).toBeCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("throws when no glob results are produced and empty results shouild throw", () => {
|
||||||
|
const validator = new ArtifactPathValidator(true, [], pattern)
|
||||||
|
expect(() => {
|
||||||
|
validator.validate()
|
||||||
|
}).toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("throws when path points to directory", () => {
|
||||||
|
const paths = ['path1', 'path2']
|
||||||
|
directoryMock.mockReturnValueOnce(true).mockReturnValueOnce(false)
|
||||||
|
|
||||||
|
const validator = new ArtifactPathValidator(true, paths, pattern)
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
validator.validate()
|
||||||
|
}).toThrow()
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -70,7 +70,7 @@ describe.skip('Integration Test', () => {
|
|||||||
function artifacts() {
|
function artifacts() {
|
||||||
const globber = new FileArtifactGlobber()
|
const globber = new FileArtifactGlobber()
|
||||||
const artifactPath = path.join(__dirname, 'Integration.test.ts')
|
const artifactPath = path.join(__dirname, 'Integration.test.ts')
|
||||||
const artifactString = `~/Desktop/test.txt,blarg.tx, ${artifactPath}`
|
const artifactString = `~/Desktop,~/Desktop/test.txt,blarg.tx, ${artifactPath}`
|
||||||
return globber.globArtifactString(artifactString, "raw", false)
|
return globber.globArtifactString(artifactString, "raw", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,28 +27,34 @@ const core = __importStar(require("@actions/core"));
|
|||||||
const Globber_1 = require("./Globber");
|
const Globber_1 = require("./Globber");
|
||||||
const Artifact_1 = require("./Artifact");
|
const Artifact_1 = require("./Artifact");
|
||||||
const untildify_1 = __importDefault(require("untildify"));
|
const untildify_1 = __importDefault(require("untildify"));
|
||||||
|
const ArtifactPathValidator_1 = require("./ArtifactPathValidator");
|
||||||
class FileArtifactGlobber {
|
class FileArtifactGlobber {
|
||||||
constructor(globber = new Globber_1.FileGlobber()) {
|
constructor(globber = new Globber_1.FileGlobber()) {
|
||||||
this.globber = globber;
|
this.globber = globber;
|
||||||
}
|
}
|
||||||
globArtifactString(artifact, contentType, throwsWhenNoFiles) {
|
globArtifactString(artifact, contentType, errorsFailBuild) {
|
||||||
return artifact.split(',')
|
return artifact.split(',')
|
||||||
.map(path => FileArtifactGlobber.expandPath(path))
|
.map(path => FileArtifactGlobber.expandPath(path))
|
||||||
.map(pattern => this.globPattern(pattern, throwsWhenNoFiles))
|
.map(pattern => this.globPattern(pattern, errorsFailBuild))
|
||||||
|
.map((globResult) => FileArtifactGlobber.validatePattern(errorsFailBuild, globResult[1], globResult[0]))
|
||||||
.reduce((accumulated, current) => accumulated.concat(current))
|
.reduce((accumulated, current) => accumulated.concat(current))
|
||||||
.map(path => new Artifact_1.Artifact(path, contentType));
|
.map(path => new Artifact_1.Artifact(path, contentType));
|
||||||
}
|
}
|
||||||
globPattern(pattern, throwsWhenNoFiles) {
|
globPattern(pattern, errorsFailBuild) {
|
||||||
const paths = this.globber.glob(pattern);
|
const paths = this.globber.glob(pattern);
|
||||||
if (paths.length == 0) {
|
if (paths.length == 0) {
|
||||||
if (throwsWhenNoFiles) {
|
if (errorsFailBuild) {
|
||||||
FileArtifactGlobber.throwGlobError(pattern);
|
FileArtifactGlobber.throwGlobError(pattern);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
FileArtifactGlobber.reportGlobWarning(pattern);
|
FileArtifactGlobber.reportGlobWarning(pattern);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return paths;
|
return [pattern, paths];
|
||||||
|
}
|
||||||
|
static validatePattern(errorsFailBuild, paths, pattern) {
|
||||||
|
const validator = new ArtifactPathValidator_1.ArtifactPathValidator(errorsFailBuild, paths, pattern);
|
||||||
|
return validator.validate();
|
||||||
}
|
}
|
||||||
static reportGlobWarning(pattern) {
|
static reportGlobWarning(pattern) {
|
||||||
core.warning(`Artifact pattern :${pattern} did not match any files`);
|
core.warning(`Artifact pattern :${pattern} did not match any files`);
|
||||||
|
|||||||
58
lib/ArtifactPathValidator.js
Normal file
58
lib/ArtifactPathValidator.js
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
"use strict";
|
||||||
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||||
|
}) : (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
o[k2] = m[k];
|
||||||
|
}));
|
||||||
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||||
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||||
|
}) : function(o, v) {
|
||||||
|
o["default"] = v;
|
||||||
|
});
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||||
|
__setModuleDefault(result, mod);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.ArtifactPathValidator = void 0;
|
||||||
|
const core = __importStar(require("@actions/core"));
|
||||||
|
const fs_1 = require("fs");
|
||||||
|
class ArtifactPathValidator {
|
||||||
|
constructor(errorsFailBuild, paths, pattern) {
|
||||||
|
this.paths = paths;
|
||||||
|
this.pattern = pattern;
|
||||||
|
this.errorsFailBuild = errorsFailBuild;
|
||||||
|
}
|
||||||
|
validate() {
|
||||||
|
this.verifyPathsNotEmpty();
|
||||||
|
return this.paths.filter((path) => this.verifyNotDirectory(path));
|
||||||
|
}
|
||||||
|
verifyPathsNotEmpty() {
|
||||||
|
if (this.paths.length == 0) {
|
||||||
|
const message = `Artifact pattern:${this.pattern} did not match any files`;
|
||||||
|
this.reportError(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
verifyNotDirectory(path) {
|
||||||
|
const isDir = fs_1.statSync(path).isDirectory();
|
||||||
|
if (isDir) {
|
||||||
|
const message = `Artifact is a directory:${path}. Directories can not be uploaded to a release.`;
|
||||||
|
this.reportError(message);
|
||||||
|
}
|
||||||
|
return !isDir;
|
||||||
|
}
|
||||||
|
reportError(message) {
|
||||||
|
if (this.errorsFailBuild) {
|
||||||
|
throw Error(message);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
core.warning(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.ArtifactPathValidator = ArtifactPathValidator;
|
||||||
@@ -2,9 +2,10 @@ import * as core from '@actions/core';
|
|||||||
import {Globber, FileGlobber} from "./Globber";
|
import {Globber, FileGlobber} from "./Globber";
|
||||||
import {Artifact} from "./Artifact";
|
import {Artifact} from "./Artifact";
|
||||||
import untildify from "untildify";
|
import untildify from "untildify";
|
||||||
|
import {ArtifactPathValidator} from "./ArtifactPathValidator";
|
||||||
|
|
||||||
export interface ArtifactGlobber {
|
export interface ArtifactGlobber {
|
||||||
globArtifactString(artifact: string, contentType: string, throwsWhenNoFiles: boolean): Artifact[]
|
globArtifactString(artifact: string, contentType: string, errorsFailBuild: boolean): Artifact[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FileArtifactGlobber implements ArtifactGlobber {
|
export class FileArtifactGlobber implements ArtifactGlobber {
|
||||||
@@ -14,24 +15,30 @@ export class FileArtifactGlobber implements ArtifactGlobber {
|
|||||||
this.globber = globber
|
this.globber = globber
|
||||||
}
|
}
|
||||||
|
|
||||||
globArtifactString(artifact: string, contentType: string, throwsWhenNoFiles: boolean): Artifact[] {
|
globArtifactString(artifact: string, contentType: string, errorsFailBuild: boolean): Artifact[] {
|
||||||
return artifact.split(',')
|
return artifact.split(',')
|
||||||
.map(path => FileArtifactGlobber.expandPath(path))
|
.map(path => FileArtifactGlobber.expandPath(path))
|
||||||
.map(pattern => this.globPattern(pattern, throwsWhenNoFiles))
|
.map(pattern => this.globPattern(pattern, errorsFailBuild))
|
||||||
|
.map((globResult) => FileArtifactGlobber.validatePattern(errorsFailBuild, globResult[1], globResult[0]))
|
||||||
.reduce((accumulated, current) => accumulated.concat(current))
|
.reduce((accumulated, current) => accumulated.concat(current))
|
||||||
.map(path => new Artifact(path, contentType))
|
.map(path => new Artifact(path, contentType))
|
||||||
}
|
}
|
||||||
|
|
||||||
private globPattern(pattern: string, throwsWhenNoFiles: boolean): string[] {
|
private globPattern(pattern: string, errorsFailBuild: boolean): [string, string[]] {
|
||||||
const paths = this.globber.glob(pattern)
|
const paths = this.globber.glob(pattern)
|
||||||
if (paths.length == 0) {
|
if (paths.length == 0) {
|
||||||
if (throwsWhenNoFiles) {
|
if (errorsFailBuild) {
|
||||||
FileArtifactGlobber.throwGlobError(pattern)
|
FileArtifactGlobber.throwGlobError(pattern)
|
||||||
} else {
|
} else {
|
||||||
FileArtifactGlobber.reportGlobWarning(pattern)
|
FileArtifactGlobber.reportGlobWarning(pattern)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return paths
|
return [pattern, paths]
|
||||||
|
}
|
||||||
|
|
||||||
|
private static validatePattern(errorsFailBuild: boolean, paths: string[], pattern: string): string[] {
|
||||||
|
const validator = new ArtifactPathValidator(errorsFailBuild, paths, pattern)
|
||||||
|
return validator.validate()
|
||||||
}
|
}
|
||||||
|
|
||||||
private static reportGlobWarning(pattern: string) {
|
private static reportGlobWarning(pattern: string) {
|
||||||
|
|||||||
43
src/ArtifactPathValidator.ts
Normal file
43
src/ArtifactPathValidator.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import * as core from "@actions/core";
|
||||||
|
import {statSync} from "fs";
|
||||||
|
|
||||||
|
export class ArtifactPathValidator {
|
||||||
|
private readonly errorsFailBuild: boolean;
|
||||||
|
private paths: string[];
|
||||||
|
private readonly pattern: string
|
||||||
|
|
||||||
|
constructor(errorsFailBuild: boolean, paths: string[], pattern: string) {
|
||||||
|
this.paths = paths;
|
||||||
|
this.pattern = pattern
|
||||||
|
this.errorsFailBuild = errorsFailBuild;
|
||||||
|
}
|
||||||
|
|
||||||
|
validate(): string[] {
|
||||||
|
this.verifyPathsNotEmpty()
|
||||||
|
return this.paths.filter((path) => this.verifyNotDirectory(path))
|
||||||
|
}
|
||||||
|
|
||||||
|
private verifyPathsNotEmpty() {
|
||||||
|
if (this.paths.length == 0) {
|
||||||
|
const message = `Artifact pattern:${this.pattern} did not match any files`
|
||||||
|
this.reportError(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private verifyNotDirectory(path: string): boolean {
|
||||||
|
const isDir = statSync(path).isDirectory()
|
||||||
|
if (isDir) {
|
||||||
|
const message = `Artifact is a directory:${path}. Directories can not be uploaded to a release.`
|
||||||
|
this.reportError(message)
|
||||||
|
}
|
||||||
|
return !isDir
|
||||||
|
}
|
||||||
|
|
||||||
|
private reportError(message: string) {
|
||||||
|
if (this.errorsFailBuild) {
|
||||||
|
throw Error(message)
|
||||||
|
} else {
|
||||||
|
core.warning(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user