Skip to content

Commit

Permalink
add fail-fast implementation
Browse files Browse the repository at this point in the history
Signed-off-by: Akhil Mohan <akhil.mohan@mayadata.io>
  • Loading branch information
akhilerm committed Mar 31, 2021
1 parent cd21e2d commit b2133b6
Show file tree
Hide file tree
Showing 7 changed files with 214 additions and 106 deletions.
39 changes: 39 additions & 0 deletions __tests__/release.test.ts
@@ -0,0 +1,39 @@
import * as release from '../src/release';

describe('isReleaseAlreadyExist', () => {
it('multiple errors along with release already exists error', () => {
const errorString = '{\n' +
'"message": "Validation Failed",\n' +
'"errors": [\n' +
' {\n' +
'"resource": "Release",\n' +
'"code": "already_exists",\n' +
'"field": "tag_name"\n' +
'},\n' +
' {\n' +
'"resource": "Release",\n' +
'"code": "invalid",\n' +
'"field": "target_commitish"\n' +
'}\n' +
'],\n' +
'"documentation_url": "https://docs.github.com/rest/reference/repos#create-a-release"\n' +
'}'
const errorObject = JSON.parse(errorString)
expect(release.isReleaseAlreadyExist(errorObject)).toEqual(false);
});
it('only release already exists error', () => {
const errorString = '{\n' +
'"message": "Validation Failed",\n' +
'"errors": [\n' +
' {\n' +
'"resource": "Release",\n' +
'"code": "already_exists",\n' +
'"field": "tag_name"\n' +
'}\n' +
'],\n' +
'"documentation_url": "https://docs.github.com/rest/reference/repos#create-a-release"\n' +
'}'
const errorObject = JSON.parse(errorString)
expect(release.isReleaseAlreadyExist(errorObject)).toEqual(true);
});
});
75 changes: 54 additions & 21 deletions dist/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

68 changes: 34 additions & 34 deletions src/context.ts
@@ -1,51 +1,51 @@
import * as core from '@actions/core';
import csvparse from 'csv-parse/lib/sync';
import * as core from '@actions/core'
import csvparse from 'csv-parse/lib/sync'

export interface Inputs {
tagName: string
body: string;
repositories: string[];
owner: string;
githubToken: string;
failFast: boolean;
body: string
repositories: string[]
owner: string
githubToken: string
failFast: boolean
}

export async function getInputs(): Promise<Inputs> {
return {
tagName: getTag(),
body: core.getInput('body'),
repositories: await getRepositoryList(),
owner: core.getInput('owner'),
githubToken: core.getInput('github-token'),
failFast: /true/i.test(core.getInput('fail-fast'))
};
return {
tagName: getTag(),
body: core.getInput('body'),
repositories: await getRepositoryList(),
owner: core.getInput('owner'),
githubToken: core.getInput('github-token'),
failFast: /true/i.test(core.getInput('fail-fast'))
}
}

export function getTag(): string {
const tagName = core.getInput('tag-name');
// This removes the 'refs/tags' portion of the string if present, i.e. from 'refs/tags/v1.10.15' to 'v1.10.15'
return tagName.replace('refs/tags/', '');
const tagName = core.getInput('tag-name')
// This removes the 'refs/tags' portion of the string if present, i.e. from 'refs/tags/v1.10.15' to 'v1.10.15'
return tagName.replace('refs/tags/', '')
}

export async function getRepositoryList(): Promise<string[]> {
let res: Array<string> = [];
const res: string[] = []

const items = core.getInput('repo');
if (items == '') {
return res;
}
const items = core.getInput('repo')
if (items == '') {
return res
}

for (let output of (await csvparse(items, {
columns: false,
relaxColumnCount: true,
skipLinesWithEmptyValues: true
})) as Array<string[]>) {
if (output.length == 1) {
res.push(output[0]);
} else {
res.push(...output);
}
for (const output of (await csvparse(items, {
columns: false,
relaxColumnCount: true,
skipLinesWithEmptyValues: true
})) as string[][]) {
if (output.length == 1) {
res.push(output[0])
} else {
res.push(...output)
}
}

return res.filter(item => item).map(pat => pat.trim());
return res.filter(item => item).map(pat => pat.trim())
}
32 changes: 16 additions & 16 deletions src/helper.ts
Expand Up @@ -8,27 +8,27 @@
// v1.9.0-custom => should be v1.9.x-custom
// v1.9.1-custom => should be v1.9.x-custom
export function getBranchName(tag: string): string {
const t = tag.split('-')
const semanticVersion = t[0].split('.')
let branch = `${semanticVersion[0]}.${semanticVersion[1]}.x`
if (t[1]) {
if (!isRCBuild(tag)) {
branch = `${branch}-${t[1]}`
}
const t = tag.split('-')
const semanticVersion = t[0].split('.')
let branch = `${semanticVersion[0]}.${semanticVersion[1]}.x`
if (t[1]) {
if (!isRCBuild(tag)) {
branch = `${branch}-${t[1]}`
}
return branch
}
return branch
}

// checks if the given tag corresponds to an RC build
export function isRCBuild(tag: string): boolean {
const t = tag.split('-')
const t = tag.split('-')

// take the last custom suffix
// can be v0.0.1-RC1 or v0.0.1-custom-RC1
const tagSuffix = t[t.length - 1]
// take the last custom suffix
// can be v0.0.1-RC1 or v0.0.1-custom-RC1
const tagSuffix = t[t.length - 1]

if (tagSuffix.substr(0, 2) === 'RC') {
return true
}
return false
if (tagSuffix.substr(0, 2) === 'RC') {
return true
}
return false
}
14 changes: 6 additions & 8 deletions src/main.ts
@@ -1,16 +1,14 @@
import * as core from '@actions/core';
import * as context from './context';
import {createRelease} from './release';
import * as core from '@actions/core'
import * as context from './context'
import {createRelease} from './release'

async function run(): Promise<void> {
try {
const inputs: context.Inputs = await context.getInputs();
await createRelease(inputs);

const inputs: context.Inputs = await context.getInputs()
await createRelease(inputs)
} catch (error) {
core.setFailed(error.message);
core.setFailed(error.message)
}
}


run()
90 changes: 64 additions & 26 deletions src/release.ts
@@ -1,33 +1,71 @@
import * as context from './context';
import * as github from '@actions/github';
import * as helper from './helper';
import * as core from '@actions/core';
import * as context from './context'
import * as github from '@actions/github'
import * as helper from './helper'
import * as core from '@actions/core'

export async function createRelease(ctx: context.Inputs) {
const octokit = github.getOctokit(ctx.githubToken);
const branchName = helper.getBranchName(ctx.tagName);
const preRelease = helper.isRCBuild(ctx.tagName);
const octokit = github.getOctokit(ctx.githubToken)
const branchName = helper.getBranchName(ctx.tagName)
const preRelease = helper.isRCBuild(ctx.tagName)

let isSuccess = true
let failureMessage = `Tagging failed for: `

for (const repo of ctx.repositories) {
const result = await octokit.repos.createRelease({
owner: ctx.owner,
repo: repo,
tag_name: ctx.tagName,
name: ctx.tagName,
body: ctx.body,
target_commitish: branchName,
prerelease: preRelease,
draft: false
});
if (result.status != 201) {
core.error(`Creating release failed for ${ctx.owner}/${repo}`);
// when failFast is set, if tagging of one repository fails, all the further
// repository tagging is cancelled
if (ctx.failFast) {
core.setFailed(`Aborting release tagging..`);
try {
const result = await octokit.repos.createRelease({
owner: ctx.owner,
repo,
tag_name: ctx.tagName,
name: ctx.tagName,
body: ctx.body,
target_commitish: branchName,
prerelease: preRelease,
draft: false
})

if (result.status === 201) {
core.info(`Created release for ${ctx.owner}/${repo}`)
} else {
if (ctx.failFast) {
core.setFailed(
`Tagging failed for ${ctx.owner}/${repo}. Error: ${result}`
)
core.error(`Aborting tagging for further repositories`)
return
} else {
isSuccess = false
failureMessage = failureMessage.concat(`${repo}, `)
}
}
} catch (error) {
if (!isReleaseAlreadyExist(error)) {
if (ctx.failFast) {
core.setFailed(
`Tagging failed for ${ctx.owner}/${repo}. Error: ${error}`
)
core.error(`Aborting tagging for further repositories`)
return
} else {
isSuccess = false
failureMessage = failureMessage.concat(`${repo}, `)
}
} else {
core.info(`Release tag ${ctx.tagName} already exists for ${ctx.owner}/${repo}`)
}
}
else {
core.info(`Created release ${ctx.tagName} for ${ctx.owner}/${repo}`);
}
}

if (!isSuccess) {
core.setFailed(failureMessage)
}
}

// checks if the release tag already exists
export function isReleaseAlreadyExist(error: any): boolean {
return (
error.errors.length === 1 &&
error.errors[0].resource === 'Release' &&
error.errors[0].code === 'already_exists'
)
}

0 comments on commit b2133b6

Please sign in to comment.