diff --git a/.eslintrc.json b/.eslintrc.json index ec222d2..2b6ae05 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -16,6 +16,7 @@ "@typescript-eslint/no-empty-function": "off", "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-non-null-assertion": "off", "prettier/prettier": ["error", {"endOfLine": "auto"}] }, "plugins": ["@typescript-eslint", "jest"] diff --git a/__tests__/app.test.ts b/__tests__/app.test.ts index 8d11ab7..bccbbdb 100644 --- a/__tests__/app.test.ts +++ b/__tests__/app.test.ts @@ -1,48 +1,57 @@ -import {getLatestArtifactFile, matchRule, validateSize, run} from '../src/app' -import {WorkflowArgs} from '../src/WorkflowArgs' +import {getLatestArtifact, matchRule, run, validateSize} from '../src/app' describe('Get latest artifact', () => { it('should throw an error due to invalid name', async () => { await expect( - getLatestArtifactFile({ + getLatestArtifact({ name: 'invalid', - owner: 'caponetto', - repo: 'vscode-diff-viewer' + repository: { + owner: 'caponetto', + name: 'vscode-diff-viewer' + } }) ).rejects.toThrowError() }) it('should throw an error due to invalid owner', async () => { await expect( - getLatestArtifactFile({ + getLatestArtifact({ name: 'artifact-name', - owner: 'invalid-owner-12345', - repo: 'vscode-diff-viewer' + repository: { + owner: 'invalid-owner-12345', + name: 'vscode-diff-viewer' + } }) ).rejects.toThrowError() }) it('should throw an error due to invalid repository', async () => { await expect( - getLatestArtifactFile({ + getLatestArtifact({ name: 'artifact-name', - owner: 'caponetto', - repo: 'invalid-repo-12345' + repository: { + owner: 'caponetto', + name: 'invalid-repo-12345' + } }) ).rejects.toThrowError() }) it('should find the expected artifact - Part of the name', async () => { const name = 'vscode_diff_viewer' - const file = await getLatestArtifactFile({ + const file = await getLatestArtifact({ name: name, - owner: 'caponetto', - repo: 'vscode-diff-viewer' + repository: { + owner: 'caponetto', + name: 'vscode-diff-viewer' + } }) expect(file.name).toMatch(name) }) it('should find the expected artifact - Wildcard', async () => { - const file = await getLatestArtifactFile({ + const file = await getLatestArtifact({ name: 'vscode_diff_viewer*.vsix', - owner: 'caponetto', - repo: 'vscode-diff-viewer' + repository: { + owner: 'caponetto', + name: 'vscode-diff-viewer' + } }) expect(file.name).toMatch('vscode_diff_viewer') }) @@ -87,3 +96,30 @@ describe('Match rule', () => { expect(matchRule('StartABCDEnd', '*Start*End*')).toBeTruthy() }) }) + +describe('App run flow', () => { + const testArtifactPath = '__tests__/resources/vscode_diff_viewer_1.1.2.zip' + const testReleasedArtifactName = 'vscode_diff_viewer*.vsix' + const testRepository = { + owner: 'caponetto', + name: 'vscode-diff-viewer' + } + it('should pass without errors', async () => { + await run({ + releasedArtifactName: testReleasedArtifactName, + artifactPath: testArtifactPath, + maxIncreasePercentage: 70, + repository: testRepository + }) + }) + it('should throw an error', async () => { + await expect( + run({ + releasedArtifactName: testReleasedArtifactName, + artifactPath: testArtifactPath, + maxIncreasePercentage: 10, + repository: testRepository + }) + ).rejects.toThrowError() + }) +}) diff --git a/__tests__/inputs.test.ts b/__tests__/inputs.test.ts new file mode 100644 index 0000000..88b5c47 --- /dev/null +++ b/__tests__/inputs.test.ts @@ -0,0 +1,53 @@ +import {join} from 'path' +import * as inputs from '../src/inputs' + +describe('Resolve path', () => { + it('should return a valid path - Full path', async () => { + const expected = '__tests__/resources/vscode_diff_viewer_1.1.2.zip' + const path = await inputs.resolvePath( + '__tests__/resources/vscode_diff_viewer_1.1.2.zip' + ) + expect(path).toMatch(expected) + }) + it('should return a valid path - Full path with wildcard', async () => { + const expected = join( + '__tests__', + 'resources', + 'vscode_diff_viewer_1.1.2.zip' + ) + const path = await inputs.resolvePath( + '__tests__/resources/vscode_diff_viewer_*.zip' + ) + expect(path).toMatch(expected) + }) + it('should return a valid path - Any folder', async () => { + const expected = join( + '__tests__', + 'resources', + 'vscode_diff_viewer_1.1.2.zip' + ) + const path = await inputs.resolvePath('**/vscode_diff_viewer_1.1.2.zip') + expect(path).toMatch(expected) + }) + it('should return a valid path - Any folder with wildcard', async () => { + const expected = join( + '__tests__', + 'resources', + 'vscode_diff_viewer_1.1.2.zip' + ) + const path = await inputs.resolvePath('**/vscode_diff_viewer_*.zip') + expect(path).toMatch(expected) + }) + it('should not find any path - Invalid full path', async () => { + const path = await inputs.resolvePath( + '__tests__/resources/vscode_diff_viewer_1.1.2.tar.gz' + ) + expect(path).toBeUndefined() + }) + it('should not find any path - Invalid path with wildcard', async () => { + const path = await inputs.resolvePath( + '__tests__/resources/vscode_diff_viewer_*.tar.gz' + ) + expect(path).toBeUndefined() + }) +}) diff --git a/__tests__/integration.test.ts b/__tests__/integration.test.ts deleted file mode 100644 index 55498c1..0000000 --- a/__tests__/integration.test.ts +++ /dev/null @@ -1,24 +0,0 @@ -import {run} from '../src/app' - -describe('Entire flow', () => { - it('should pass without errors', async () => { - await run({ - releasedArtifactName: 'vscode_diff_viewer*.vsix', - artifactPath: '__tests__/resources/vscode_diff_viewer_1.1.2.zip', - maxIncreasePercentage: 70, - owner: 'caponetto', - repo: 'vscode-diff-viewer' - }) - }) - it('should throw an error', async () => { - await expect( - run({ - releasedArtifactName: 'vscode_diff_viewer*.vsix', - artifactPath: 'test-resources/vscode_diff_viewer_1.1.2.zip', - maxIncreasePercentage: 10, - owner: 'caponetto', - repo: 'vscode-diff-viewer' - }) - ).rejects.toThrowError() - }) -}) diff --git a/licenses.txt b/licenses.txt index 4166fb2..469de3f 100644 --- a/licenses.txt +++ b/licenses.txt @@ -8,6 +8,11 @@ │ ├─ repository: https://github.com/actions/toolkit │ ├─ path: /home/guilherme/dev/caponetto/less-is-more/node_modules/@actions/github │ └─ licenseFile: /home/guilherme/dev/caponetto/less-is-more/node_modules/@actions/github/README.md +├─ @actions/glob@0.1.1 +│ ├─ licenses: MIT +│ ├─ repository: https://github.com/actions/toolkit +│ ├─ path: /home/guilherme/dev/caponetto/less-is-more/node_modules/@actions/glob +│ └─ licenseFile: /home/guilherme/dev/caponetto/less-is-more/node_modules/@actions/glob/LICENSE.md ├─ @actions/http-client@1.0.11 │ ├─ licenses: MIT │ ├─ repository: https://github.com/actions/http-client @@ -2898,7 +2903,7 @@ │ ├─ url: lukeed.com │ ├─ path: /home/guilherme/dev/caponetto/less-is-more/node_modules/kleur │ └─ licenseFile: /home/guilherme/dev/caponetto/less-is-more/node_modules/kleur/license -├─ less-is-more@0.0.4 +├─ less-is-more@0.0.5 │ ├─ licenses: MIT │ ├─ repository: https://github.com/caponetto/less-is-more │ ├─ publisher: Guilherme H. Caponetto diff --git a/package-lock.json b/package-lock.json index ce96d9f..ee87648 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "less-is-more", - "version": "0.0.4", + "version": "0.0.5", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -20,6 +20,15 @@ "@octokit/plugin-rest-endpoint-methods": "^4.0.0" } }, + "@actions/glob": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@actions/glob/-/glob-0.1.1.tgz", + "integrity": "sha512-ikM4GVZOgSGDNTjv0ECJ8AOqmDqQwtO4K1M4P465C9iikRq34+FwCjUVSwzgOYDP85qtddyWpzBw5lTub/9Xmg==", + "requires": { + "@actions/core": "^1.2.6", + "minimatch": "^3.0.4" + } + }, "@actions/http-client": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz", @@ -2010,8 +2019,7 @@ "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "base": { "version": "0.11.2", @@ -2086,7 +2094,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2339,8 +2346,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "concurrently": { "version": "5.3.0", @@ -6542,7 +6548,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } diff --git a/package.json b/package.json index b0cf4b5..4726d22 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "less-is-more", - "version": "0.0.4", + "version": "0.0.5", "license": "MIT", "author": "Guilherme H. Caponetto", "keywords": [ @@ -32,6 +32,7 @@ "dependencies": { "@actions/core": "1.2.6", "@actions/github": "4.0.0", + "@actions/glob": "0.1.1", "@octokit/core": "^3.4.0" }, "devDependencies": { diff --git a/src/WorkflowArgs.ts b/src/WorkflowArgs.ts deleted file mode 100644 index e1197c7..0000000 --- a/src/WorkflowArgs.ts +++ /dev/null @@ -1,8 +0,0 @@ -export interface WorkflowArgs { - releasedArtifactName: string - artifactPath: string - maxIncreasePercentage: number - owner: string - repo: string - token?: string -} diff --git a/src/api.ts b/src/api.ts new file mode 100644 index 0000000..97bbc64 --- /dev/null +++ b/src/api.ts @@ -0,0 +1,24 @@ +export interface Artifact { + name: string + repository?: RepositoryInfo + size?: number +} + +export type SizeCheckResult = + | 'decreased' + | 'same' + | 'increase_allowed' + | 'increase_not_allowed' + +export interface WorkflowArgs { + releasedArtifactName: string + artifactPath: string + maxIncreasePercentage: number + repository: RepositoryInfo + token?: string +} + +export interface RepositoryInfo { + owner: string + name: string +} diff --git a/src/app.ts b/src/app.ts index 164cd75..bc3d0a7 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,34 +1,17 @@ import {request} from '@octokit/request' import {statSync} from 'fs' import {basename} from 'path' -import {WorkflowArgs} from './WorkflowArgs' +import {Artifact, SizeCheckResult, WorkflowArgs} from './api' -interface File { - name: string - size: number -} - -export interface Artifact { - name: string - owner: string - repo: string -} - -export type SizeCheckResult = - | 'decreased' - | 'same' - | 'increase_allowed' - | 'increase_not_allowed' - -export async function getLatestArtifactFile( +export async function getLatestArtifact( releasedArtifact: Artifact, token?: string -): Promise { +): Promise { const response = await request({ method: 'GET', url: '/repos/{owner}/{repo}/releases', - owner: releasedArtifact.owner, - repo: releasedArtifact.repo, + owner: releasedArtifact.repository!.owner, + repo: releasedArtifact.repository!.name, ...(token && { headers: { authorization: `token ${token}` @@ -48,7 +31,8 @@ export async function getLatestArtifactFile( return { name: latestArtifact.name, - size: latestArtifact.size + size: latestArtifact.size, + repository: releasedArtifact.repository } } @@ -95,35 +79,37 @@ export function matchRule(target: string, rule: string): boolean { ).test(target) } -function printInfo(current: File, released: File): void { +function printInfo(current: Artifact, released: Artifact): void { console.log( - `The size of the current file "${current.name}" is ${current.size} bytes.` + `The size of the current artifact "${current.name}" is ${current.size} bytes.` ) console.log( - `The size of the released file "${released.name}" is ${released.size} bytes.` + `The size of the released artifact "${released.name}" is ${released.size} bytes.` ) } export async function run(args: WorkflowArgs): Promise { - const latestReleasedFile = await getLatestArtifactFile( + const latestReleasedArtifact = await getLatestArtifact( { name: args.releasedArtifactName, - owner: args.owner, - repo: args.repo + repository: { + owner: args.repository.owner, + name: args.repository.name + } }, args.token ) - const currentFile = { + const currentArtifact = { name: basename(args.artifactPath), size: statSync(args.artifactPath).size } - printInfo(currentFile, latestReleasedFile) + printInfo(currentArtifact, latestReleasedArtifact) const result = validateSize( - currentFile.size, - latestReleasedFile.size, + currentArtifact.size, + latestReleasedArtifact.size!, args.maxIncreasePercentage ) diff --git a/src/index.ts b/src/index.ts index 56a2483..c09cb9b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,35 +1,7 @@ -import {getInput, setFailed} from '@actions/core' -import {context} from '@actions/github' -import {existsSync} from 'fs' +import {setFailed} from '@actions/core' import {run} from './app' -import {WorkflowArgs} from './WorkflowArgs' +import {resolveArgs} from './inputs' -function resolveArgs(): WorkflowArgs { - const releasedArtifactName = getInput('released_artifact_name') - const artifactPath = getInput('artifact_path') - const maxIncreasePercentage = +getInput('max_increase_percentage') - const githubToken = getInput('github_token') - - if (!existsSync(artifactPath)) { - throw new Error( - `The artifact could not be found at "${artifactPath}". Have you built it already?` - ) - } - - if (maxIncreasePercentage <= 0) { - throw new Error( - 'The input `max_increase_percentage` must be an integer greater than zero.' - ) - } - - return { - releasedArtifactName: releasedArtifactName, - artifactPath: artifactPath, - maxIncreasePercentage: maxIncreasePercentage, - owner: context.repo.owner, - repo: context.repo.repo, - token: githubToken - } -} - -run(resolveArgs()).catch(e => setFailed(e.message)) +resolveArgs() + .then(args => run(args)) + .catch(e => setFailed(e.message)) diff --git a/src/inputs.ts b/src/inputs.ts new file mode 100644 index 0000000..9d8b74a --- /dev/null +++ b/src/inputs.ts @@ -0,0 +1,56 @@ +import {getInput} from '@actions/core' +import {context} from '@actions/github' +import {create} from '@actions/glob' +import {existsSync} from 'fs' +import {WorkflowArgs} from './api' + +export async function resolvePath(path: string): Promise { + if (!existsSync(path)) { + const globber = await create(path) + const files = await globber.glob() + if (files.length === 0) { + return + } + return files[0] + } + return path +} + +export async function resolveArgs(): Promise { + const releasedArtifactName = getInput('released_artifact_name', { + required: true + }) + const artifactPath = getInput('artifact_path', { + required: true + }) + const maxIncreasePercentage = +getInput('max_increase_percentage', { + required: true + }) + const githubToken = getInput('github_token', { + required: false + }) + + const resolvedArtifactPath = await resolvePath(artifactPath) + if (!resolvedArtifactPath) { + throw new Error( + `The artifact could not be found at "${artifactPath}". Have you built it already?` + ) + } + + if (maxIncreasePercentage <= 0) { + throw new Error( + 'The input `max_increase_percentage` must be an integer greater than zero.' + ) + } + + return { + releasedArtifactName: releasedArtifactName, + artifactPath: resolvedArtifactPath!, + maxIncreasePercentage: maxIncreasePercentage, + repository: { + owner: context.repo.owner, + name: context.repo.repo + }, + token: githubToken + } +}