Fixes #1 Allow for multiple artifacts

This commit is contained in:
Nick Cipollo
2019-09-02 17:20:04 -04:00
parent 261c1fc08b
commit a698287254
24 changed files with 462 additions and 167 deletions

View File

@@ -1,13 +1,17 @@
import { Action } from "../src/Action";
import { Artifact } from "../src/Artifact";
import { Inputs } from "../src/Inputs";
import { Releases } from "../src/Releases";
import { ArtifactUploader } from "../src/ArtifactUploader";
const createMock = jest.fn()
const uploadMock = jest.fn()
const artifactPath = 'a/path'
const artifactName = 'path'
const artifactData = Buffer.from('blob','utf-8')
const artifacts = [
new Artifact('a/art1'),
new Artifact('b/art2')
]
const artifactData = Buffer.from('blob', 'utf-8')
const body = 'body'
const commit = 'commit'
const contentType = "raw"
@@ -44,7 +48,7 @@ describe("Action", () => {
await action.perform()
expect(createMock).toBeCalledWith(tag, body, commit, draft, name)
expect(uploadMock).toBeCalledWith(url, contentLength, contentType, artifactData, 'path')
expect(uploadMock).toBeCalledWith(artifacts, url)
})
it('throws error when create fails', async () => {
@@ -79,28 +83,25 @@ describe("Action", () => {
}
expect(createMock).toBeCalledWith(tag, body, commit, draft, name)
expect(uploadMock).toBeCalledWith(url, contentLength, contentType, artifactData, 'path')
expect(uploadMock).toBeCalledWith(artifacts, url)
})
function createAction(hasArtifact: boolean): Action {
let artifact: string
let inputArtifact: Artifact[]
if (hasArtifact) {
artifact = artifactPath
inputArtifact = artifacts
} else {
artifact = ''
inputArtifact = []
}
const MockReleases = jest.fn<Releases, any>(() => {
return {
create: createMock,
uploadArtifact: uploadMock
uploadArtifact: jest.fn()
}
})
const MockInputs = jest.fn<Inputs, any>(() => {
return {
artifact: artifact,
artifactName: artifactName,
artifactContentType: contentType,
artifactContentLength: contentLength,
artifacts: inputArtifact,
body: body,
commit: commit,
draft: draft,
@@ -110,9 +111,16 @@ describe("Action", () => {
readArtifact: () => artifactData
}
})
const MockUploader = jest.fn<ArtifactUploader, any>(() => {
return {
uploadArtifacts: uploadMock
}
})
const inputs = new MockInputs()
const releases = new MockReleases()
const uploader = new MockUploader()
return new Action(inputs, releases)
return new Action(inputs, releases, uploader)
}
})

View File

@@ -0,0 +1,38 @@
import { Artifact } from "../src/Artifact";
const fileContents = Buffer.from('artful facts', 'utf-8')
const contentLength = 42
jest.mock('fs', () => {
return {
readFileSync: () => fileContents,
statSync: () => { return { size: contentLength } }
};
})
describe("Artifact", () => {
it('defaults contentType to raw', () => {
const artifact = new Artifact('')
expect(artifact.contentType).toBe('raw')
})
it('generates name from path', () => {
const artifact = new Artifact('some/artifact')
expect(artifact.name).toBe('artifact')
})
it('provides contentLength', () => {
const artifact = new Artifact('some/artifact')
expect(artifact.contentLength).toBe(contentLength)
})
it('provides path', () => {
const artifact = new Artifact('some/artifact')
expect(artifact.path).toBe('some/artifact')
})
it('reads artifact', () => {
const artifact = new Artifact('some/artifact')
expect(artifact.readFile()).toBe(fileContents)
})
})

View File

@@ -0,0 +1,39 @@
import { FileArtifactGlobber } from "../src/ArtifactGlobber"
import { Globber } from "../src/Globber";
import { Artifact } from "../src/Artifact";
const contentType = "raw"
const globResults = ["file1", "file2"]
describe("ArtifactGlobber", () => {
it("globs simple path", () => {
const globber = createArtifactGlobber()
const expectedArtifacts =
globResults.map((path) => new Artifact(path, contentType))
expect(globber.globArtifactString('path', 'raw'))
.toEqual(expectedArtifacts)
})
it("splits multiple paths", () => {
const globber = createArtifactGlobber()
const expectedArtifacts =
globResults
.concat(globResults)
.map((path) => new Artifact(path, contentType))
expect(globber.globArtifactString('path1,path2', 'raw'))
.toEqual(expectedArtifacts)
})
function createArtifactGlobber(): FileArtifactGlobber {
const MockGlobber = jest.fn<Globber, any>(() => {
return {
glob: () => globResults
}
})
return new FileArtifactGlobber(new MockGlobber())
}
})

View File

@@ -0,0 +1,43 @@
import { Artifact } from "../src/Artifact"
import { GithubArtifactUploader } from "../src/ArtifactUploader"
import { Releases } from "../src/Releases";
const artifacts = [
new Artifact('a/art1'),
new Artifact('b/art2')
]
const fileContents = Buffer.from('artful facts', 'utf-8')
const contentLength = 42
const uploadMock = jest.fn()
const url = 'http://api.example.com'
jest.mock('fs', () => {
return {
readFileSync: () => fileContents,
statSync: () => { return { size: contentLength } }
};
})
describe('ArtifactUploader', () => {
it('uploads artifacts', () => {
const uploader = createUploader()
uploader.uploadArtifacts(artifacts, url)
expect(uploadMock).toBeCalledTimes(2)
expect(uploadMock)
.toBeCalledWith(url, contentLength, 'raw', fileContents, 'art1')
expect(uploadMock)
.toBeCalledWith(url, contentLength, 'raw', fileContents, 'art2')
})
function createUploader(): GithubArtifactUploader {
const MockReleases = jest.fn<Releases, any>(() => {
return {
create: jest.fn(),
uploadArtifact: uploadMock
}
})
return new GithubArtifactUploader(new MockReleases())
}
});

View File

@@ -1,89 +1,100 @@
const mockGetInput = jest.fn();
const mockGlob = jest.fn()
const mockReadFileSync = jest.fn();
const mockStatSync = jest.fn();
import { Inputs, CoreInputs } from "../src/Inputs";
import { Artifact } from "../src/Artifact";
import { ArtifactGlobber } from "../src/ArtifactGlobber";
import { Context } from "@actions/github/lib/context";
import { Inputs, CoreInputs } from "../src/Inputs";
const artifacts = [
new Artifact('a/art1'),
new Artifact('b/art2')
]
jest.mock('@actions/core', () => {
return { getInput: mockGetInput };
})
jest.mock('fs', () => {
return {
return {
readFileSync: mockReadFileSync,
statSync: mockStatSync
};
};
})
describe('Inputs', () => {
let context: Context;
let inputs: Inputs;
beforeEach(() => {
mockGetInput.mockReturnValue(null)
mockGetInput.mockReset()
context = new Context()
inputs = new CoreInputs(context)
})
it('reads artifact', () => {
mockGetInput.mockReturnValue("a/path")
mockReadFileSync.mockReturnValue('file')
expect(inputs.artifact).toBe("a/path")
})
it('returns artifact', () => {
mockGetInput.mockReturnValue("a/path")
expect(inputs.artifact).toBe("a/path")
})
it('returns artifactContentLength', () => {
mockGetInput.mockReturnValue("a/path")
mockStatSync.mockReturnValue({size: 100})
expect(inputs.artifactContentLength).toBe(100)
})
it('returns artifactName', () => {
mockGetInput.mockReturnValue("a/path")
expect(inputs.artifactName).toBe("path")
inputs = new CoreInputs(createGlobber(), context)
})
it('returns targetCommit', () => {
mockGetInput.mockReturnValue("42")
expect(inputs.commit).toBe("42")
mockGetInput.mockReturnValue('42')
expect(inputs.commit).toBe('42')
})
it('returns token', () => {
mockGetInput.mockReturnValue("42")
expect(inputs.token).toBe("42")
mockGetInput.mockReturnValue('42')
expect(inputs.token).toBe('42')
})
describe('artifactContentType', () => {
it('returns input content-type', () => {
mockGetInput.mockReturnValue("type")
expect(inputs.artifactContentType).toBe("type")
describe('artifacts', () => {
it('returns empty artifacts', () => {
mockGetInput.mockReturnValueOnce('')
.mockReturnValueOnce('')
expect(inputs.artifacts).toEqual([])
expect(mockGlob).toBeCalledTimes(0)
})
it('returns raw as default', () => {
expect(inputs.artifactContentType).toBe("raw")
it('returns input.artifacts', () => {
mockGetInput.mockReturnValueOnce('art1')
.mockReturnValueOnce('contentType')
expect(inputs.artifacts).toEqual(artifacts)
expect(mockGlob).toBeCalledTimes(1)
expect(mockGlob).toBeCalledWith('art1', 'contentType')
})
it('returns input.artifacts with default contentType', () => {
mockGetInput.mockReturnValueOnce('art1')
expect(inputs.artifacts).toEqual(artifacts)
expect(mockGlob).toBeCalledTimes(1)
expect(mockGlob).toBeCalledWith('art1', 'raw')
})
it('returns input.artifact', () => {
mockGetInput.mockReturnValueOnce('')
.mockReturnValueOnce('art2')
.mockReturnValueOnce('contentType')
expect(inputs.artifacts).toEqual(artifacts)
expect(mockGlob).toBeCalledTimes(1)
expect(mockGlob).toBeCalledWith('art2', 'contentType')
})
})
describe('body', () => {
it('returns input body', () => {
mockGetInput.mockReturnValue("body")
expect(inputs.body).toBe("body")
mockGetInput.mockReturnValue('body')
expect(inputs.body).toBe('body')
})
it('returns body file contents', () => {
mockGetInput.mockReturnValueOnce("").mockReturnValueOnce("a/path")
mockReadFileSync.mockReturnValue("file")
mockGetInput.mockReturnValueOnce('').mockReturnValueOnce('a/path')
mockReadFileSync.mockReturnValue('file')
expect(inputs.body).toBe("file")
expect(inputs.body).toBe('file')
})
it('returns empty', () => {
expect(inputs.body).toBe("")
expect(inputs.body).toBe('')
})
})
@@ -91,43 +102,53 @@ describe('Inputs', () => {
it('returns false', () => {
expect(inputs.draft).toBe(false)
})
it('returns true', () => {
mockGetInput.mockReturnValue("true")
mockGetInput.mockReturnValue('true')
expect(inputs.draft).toBe(true)
})
})
describe('name', () => {
it('returns input name', () => {
mockGetInput.mockReturnValue("name")
expect(inputs.name).toBe("name")
mockGetInput.mockReturnValue('name')
expect(inputs.name).toBe('name')
})
it('returns tag', () => {
mockGetInput.mockReturnValue("")
context.ref = "refs/tags/sha-tag"
expect(inputs.name).toBe("sha-tag")
mockGetInput.mockReturnValue('')
context.ref = 'refs/tags/sha-tag'
expect(inputs.name).toBe('sha-tag')
})
})
describe('tag', () => {
it('returns input tag', () => {
mockGetInput.mockReturnValue("tag")
expect(inputs.tag).toBe("tag")
mockGetInput.mockReturnValue('tag')
expect(inputs.tag).toBe('tag')
})
it('returns context sha when input is empty', () => {
mockGetInput.mockReturnValue("")
context.ref = "refs/tags/sha-tag"
expect(inputs.tag).toBe("sha-tag")
mockGetInput.mockReturnValue('')
context.ref = 'refs/tags/sha-tag'
expect(inputs.tag).toBe('sha-tag')
})
it('returns context sha when input is null', () => {
mockGetInput.mockReturnValue(null)
context.ref = "refs/tags/sha-tag"
expect(inputs.tag).toBe("sha-tag")
context.ref = 'refs/tags/sha-tag'
expect(inputs.tag).toBe('sha-tag')
})
it('throws if no tag', () => {
expect(() => inputs.tag).toThrow()
})
})
function createGlobber(): ArtifactGlobber {
const MockGlobber = jest.fn<ArtifactGlobber, any>(() => {
return {
globArtifactString: mockGlob
}
})
mockGlob.mockImplementation(() => artifacts)
return new MockGlobber()
}
})