Skip to content

Commit

Permalink
Fix #499: Support for fail-fast mode
Browse files Browse the repository at this point in the history
  • Loading branch information
madhead committed Sep 21, 2022
1 parent dc1fa2d commit 6636d3f
Show file tree
Hide file tree
Showing 11 changed files with 150 additions and 80 deletions.
1 change: 1 addition & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"project": "./tsconfig.json"
},
"rules": {
"i18n-text/no-en": "off",
"eslint-comments/no-use": "off",
"github/array-foreach": "off",
"import/no-namespace": "off",
Expand Down
93 changes: 61 additions & 32 deletions .github/workflows/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,58 +16,87 @@ jobs:
- run: npm run all

- uses: ./
id: test-0
id: test-1
with:
version: wrong
- run: '[[ "" == "${{ steps.test-1.outputs.release }}" ]]'
- run: '[[ "" == "${{ steps.test-1.outputs.major }}" ]]'
- run: '[[ "" == "${{ steps.test-1.outputs.minor }}" ]]'
- run: '[[ "" == "${{ steps.test-1.outputs.patch }}" ]]'
- run: '[[ "" == "${{ steps.test-1.outputs.any_other_property }}" ]]'
lenient: false
continue-on-error: true
- run: '[[ "failure" == "${{ steps.test-1.outcome }}" ]]'
- run: '[[ "success" == "${{ steps.test-1.conclusion }}" ]]'

- uses: ./
id: test-1
id: test-2
with:
version: wrong
lenient: 'false'
continue-on-error: true
- run: '[[ "failure" == "${{ steps.test-2.outcome }}" ]]'
- run: '[[ "success" == "${{ steps.test-2.conclusion }}" ]]'

- uses: ./
id: test-3
with:
version: wrong
- run: '[[ "" == "${{ steps.test-3.outputs.release }}" ]]'
- run: '[[ "" == "${{ steps.test-3.outputs.major }}" ]]'
- run: '[[ "" == "${{ steps.test-3.outputs.minor }}" ]]'
- run: '[[ "" == "${{ steps.test-3.outputs.patch }}" ]]'
- run: '[[ "" == "${{ steps.test-3.outputs.any_other_property }}" ]]'

- uses: ./
id: test-4
with:
version: wrong
lenient: true
- run: '[[ "" == "${{ steps.test-4.outputs.release }}" ]]'
- run: '[[ "" == "${{ steps.test-4.outputs.major }}" ]]'
- run: '[[ "" == "${{ steps.test-4.outputs.minor }}" ]]'
- run: '[[ "" == "${{ steps.test-4.outputs.patch }}" ]]'
- run: '[[ "" == "${{ steps.test-4.outputs.any_other_property }}" ]]'

- uses: ./
id: test-5
with:
version: 1.2.3-alpha.gamma+4.5.6
- run: '[[ "1.2.3" == "${{ steps.test-1.outputs.release }}" ]]'
- run: '[[ "1" == "${{ steps.test-1.outputs.major }}" ]]'
- run: '[[ "2" == "${{ steps.test-1.outputs.minor }}" ]]'
- run: '[[ "3" == "${{ steps.test-1.outputs.patch }}" ]]'
- run: '[[ "alpha.gamma" == "${{ steps.test-1.outputs.prerelease }}" ]]'
- run: '[[ "2" == "${{ steps.test-1.outputs.prerelease-parts }}" ]]'
- run: '[[ "alpha" == "${{ steps.test-1.outputs.prerelease-0 }}" ]]'
- run: '[[ "gamma" == "${{ steps.test-1.outputs.prerelease-1 }}" ]]'
- run: '[[ "4.5.6" == "${{ steps.test-1.outputs.build }}" ]]'
- run: '[[ "3" == "${{ steps.test-1.outputs.build-parts }}" ]]'
- run: '[[ "4" == "${{ steps.test-1.outputs.build-0 }}" ]]'
- run: '[[ "5" == "${{ steps.test-1.outputs.build-1 }}" ]]'
- run: '[[ "6" == "${{ steps.test-1.outputs.build-2 }}" ]]'
- run: '[[ "1.2.3" == "${{ steps.test-5.outputs.release }}" ]]'
- run: '[[ "1" == "${{ steps.test-5.outputs.major }}" ]]'
- run: '[[ "2" == "${{ steps.test-5.outputs.minor }}" ]]'
- run: '[[ "3" == "${{ steps.test-5.outputs.patch }}" ]]'
- run: '[[ "alpha.gamma" == "${{ steps.test-5.outputs.prerelease }}" ]]'
- run: '[[ "2" == "${{ steps.test-5.outputs.prerelease-parts }}" ]]'
- run: '[[ "alpha" == "${{ steps.test-5.outputs.prerelease-0 }}" ]]'
- run: '[[ "gamma" == "${{ steps.test-5.outputs.prerelease-1 }}" ]]'
- run: '[[ "4.5.6" == "${{ steps.test-5.outputs.build }}" ]]'
- run: '[[ "3" == "${{ steps.test-5.outputs.build-parts }}" ]]'
- run: '[[ "4" == "${{ steps.test-5.outputs.build-0 }}" ]]'
- run: '[[ "5" == "${{ steps.test-5.outputs.build-1 }}" ]]'
- run: '[[ "6" == "${{ steps.test-5.outputs.build-2 }}" ]]'

- uses: ./
id: test-2
id: test-6
with:
version: 1.0.0
compare-to: 2.0.0
- run: '[[ "<" == "${{ steps.test-2.outputs.comparison-result }}" ]]'
- run: '[[ "<" == "${{ steps.test-6.outputs.comparison-result }}" ]]'

- uses: ./
id: test-3
id: test-7
with:
version: 1.2.3
satisfies: 1.x
- run: '[[ "true" == "${{ steps.test-3.outputs.satisfies }}" ]]'
- run: '[[ "true" == "${{ steps.test-7.outputs.satisfies }}" ]]'

- uses: ./
id: test-4
id: test-8
with:
version: 1.2.3
- run: '[[ "2.0.0" == "${{ steps.test-4.outputs.inc-major }}" ]]'
- run: '[[ "2.0.0-0" == "${{ steps.test-4.outputs.inc-premajor }}" ]]'
- run: '[[ "1.3.0" == "${{ steps.test-4.outputs.inc-minor }}" ]]'
- run: '[[ "1.3.0-0" == "${{ steps.test-4.outputs.inc-preminor }}" ]]'
- run: '[[ "1.2.4" == "${{ steps.test-4.outputs.inc-patch }}" ]]'
- run: '[[ "1.2.4-0" == "${{ steps.test-4.outputs.inc-prepatch }}" ]]'
- run: '[[ "1.2.4-0" == "${{ steps.test-4.outputs.inc-prerelease }}" ]]'
- run: '[[ "2.0.0" == "${{ steps.test-8.outputs.inc-major }}" ]]'
- run: '[[ "2.0.0-0" == "${{ steps.test-8.outputs.inc-premajor }}" ]]'
- run: '[[ "1.3.0" == "${{ steps.test-8.outputs.inc-minor }}" ]]'
- run: '[[ "1.3.0-0" == "${{ steps.test-8.outputs.inc-preminor }}" ]]'
- run: '[[ "1.2.4" == "${{ steps.test-8.outputs.inc-patch }}" ]]'
- run: '[[ "1.2.4-0" == "${{ steps.test-8.outputs.inc-prepatch }}" ]]'
- run: '[[ "1.2.4-0" == "${{ steps.test-8.outputs.inc-prerelease }}" ]]'

actions-typing:
name: Validate actions typing
Expand Down
22 changes: 19 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,26 @@ A wrapper around [semver](https://www.npmjs.com/package/semver), so read [its do
echo "${{ steps.version.outputs.inc-prerelease }}" # 1.2.4-0
```
If the version cannot be parsed, all the outputs [will be equal to an empty string](.github/workflows/default.yml#L18-L26).
If the version cannot be parsed, all the outputs [will be equal to an empty string](.github/workflows/default.yml#L27-L35), unless `lenient` is set to `false` explicitly.
If `lenient` is `false`, the action [will fail](.github/workflows/default.yml#L18-L25).

If any of the inputs cannot be parsed, it is just silently ignored.
This action tries its best not to fail.
```yml
- uses: madhead/semver-utils@latest
id: lenient
with:
version: invalid
- run: |
echo "${{ steps.lenient.outputs.release }}" # (empty string)
- uses: madhead/semver-utils@latest
id: strict
with:
version: invalid
lenient: false
continue-on-error: true # failure is expected and acceptable for this example
- run: |
echo "${{ steps.strict.outcome }}" # failure
```

To see the list of available versions (`latest` in the example above), navigate to the [Releases & Tags](https://github.com/madhead/semver-utils/tags) page of this repo.
Whenever a new version is released, corresponding tags are created / updated.
Expand Down
88 changes: 49 additions & 39 deletions __tests__/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@ import {execPath} from 'process'
import {execFileSync} from 'child_process'
import {join} from 'path'
import {parse, satisfies} from 'semver'
import {type} from 'os'

interface TestData {
version: string
compareTo?: string
satisfies?: string
identifier?: string
lenient?: boolean
}

const data: TestData[] = [
{version: 'Forty-two'},
{version: 'Forty-two', lenient: true},
{version: 'Forty-two', lenient: false},
{version: '1.2'},
{version: '1'},

Expand Down Expand Up @@ -92,52 +96,58 @@ const data: TestData[] = [
]

function validate(env: NodeJS.ProcessEnv, validate: (stdout: string) => void) {
validate(
execFileSync(execPath, [join(__dirname, '..', 'lib', 'main.js')], {
env: env
}).toString()
)
try {
validate(
execFileSync(execPath, [join(__dirname, '..', 'lib', 'main.js')], {
env: env
}).toString()
)
} catch (e: any) {
expect(env).toHaveProperty('INPUT_LENIENT', 'false')
}
}

describe('parse', () => {
data.forEach(item => {
test(`parse(${item.version})`, () => {
validate(
{
INPUT_VERSION: item.version
},
(stdout: string) => {
const parsedVersion = parse(item.version)
const env: NodeJS.ProcessEnv = {
INPUT_VERSION: item.version
}

if (parsedVersion) {
expect(stdout).toContain(`::set-output name=release::${parsedVersion.major}.${parsedVersion.minor}.${parsedVersion.patch}`)
expect(stdout).toContain(`::set-output name=major::${parsedVersion.major}`)
expect(stdout).toContain(`::set-output name=minor::${parsedVersion.minor}`)
expect(stdout).toContain(`::set-output name=patch::${parsedVersion.patch}`)
if (parsedVersion.build.length > 0) {
expect(stdout).toContain(`::set-output name=build::${parsedVersion.build.join('.')}`)
expect(stdout).toContain(`::set-output name=build-parts::${parsedVersion.build.length}`)
parsedVersion.build.forEach((buildPart, index) => {
;`::set-output name=build-${index}::${buildPart}`
})
}
if (parsedVersion.prerelease.length > 0) {
expect(stdout).toContain(`::set-output name=prerelease::${parsedVersion.prerelease.join('.')}`)
expect(stdout).toContain(`::set-output name=prerelease-parts::${parsedVersion.prerelease.length}`)
parsedVersion.build.forEach((prereleasePart, index) => {
;`::set-output name=prerelease-${index}::${prereleasePart}`
})
}
} else {
expect(stdout).not.toContain(`::set-output name=release::`)
expect(stdout).not.toContain(`::set-output name=major::`)
expect(stdout).not.toContain(`::set-output name=minor::`)
expect(stdout).not.toContain(`::set-output name=patch::`)
expect(stdout).not.toContain(`::set-output name=build`)
expect(stdout).not.toContain(`::set-output name=prerelease`)
if (item.lenient === false) {
env['INPUT_LENIENT'] = 'false'
}

test(`parse(${item.version} (lenient: ${env['INPUT_LENIENT']})`, () => {
validate(env, (stdout: string) => {
const parsedVersion = parse(item.version)
if (parsedVersion) {
expect(stdout).toContain(`::set-output name=release::${parsedVersion.major}.${parsedVersion.minor}.${parsedVersion.patch}`)
expect(stdout).toContain(`::set-output name=major::${parsedVersion.major}`)
expect(stdout).toContain(`::set-output name=minor::${parsedVersion.minor}`)
expect(stdout).toContain(`::set-output name=patch::${parsedVersion.patch}`)
if (parsedVersion.build.length > 0) {
expect(stdout).toContain(`::set-output name=build::${parsedVersion.build.join('.')}`)
expect(stdout).toContain(`::set-output name=build-parts::${parsedVersion.build.length}`)
parsedVersion.build.forEach((buildPart, index) => {
;`::set-output name=build-${index}::${buildPart}`
})
}
if (parsedVersion.prerelease.length > 0) {
expect(stdout).toContain(`::set-output name=prerelease::${parsedVersion.prerelease.join('.')}`)
expect(stdout).toContain(`::set-output name=prerelease-parts::${parsedVersion.prerelease.length}`)
parsedVersion.build.forEach((prereleasePart, index) => {
;`::set-output name=prerelease-${index}::${prereleasePart}`
})
}
} else {
expect(stdout).not.toContain(`::set-output name=release::`)
expect(stdout).not.toContain(`::set-output name=major::`)
expect(stdout).not.toContain(`::set-output name=minor::`)
expect(stdout).not.toContain(`::set-output name=patch::`)
expect(stdout).not.toContain(`::set-output name=build`)
expect(stdout).not.toContain(`::set-output name=prerelease`)
}
)
})
})
})
})
Expand Down
2 changes: 2 additions & 0 deletions action-types.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ inputs:
type: string
identifier:
type: string
lenient:
type: boolean
outputs:
release:
type: string
Expand Down
4 changes: 4 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ inputs:
identifier:
required: false
description: An identifier to pass to the semver's inc function
lenient:
required: false
description: Do not fail on incorrect input
default: 'true'
outputs:
release:
description: Version's release (major.minor.patch)
Expand Down
6 changes: 5 additions & 1 deletion 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.

4 changes: 2 additions & 2 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "semver-utils",
"version": "2.3.0",
"version": "2.4.0",
"private": true,
"description": "One-stop shop for working with semantic versions in your workflows",
"main": "lib/main.js",
Expand Down
6 changes: 5 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ import {parse, satisfies} from 'semver'

async function run(): Promise<void> {
try {
const versionInput = core.getInput('version')
const lenient = core.getInput('lenient').toLowerCase() !== 'false'
const versionInput = core.getInput('version', {required: true})
const version = parse(versionInput)

if (version === null) {
if (!lenient) {
core.setFailed(`Invalid version: ${versionInput}`)
}
return
}

Expand Down

0 comments on commit 6636d3f

Please sign in to comment.