Compare commits

...

165 Commits

Author SHA1 Message Date
dependabot[bot] 9d35d648e8
Bump ws from 7.5.5 to 7.5.10 (#216)
Bumps [ws](https://github.com/websockets/ws) from 7.5.5 to 7.5.10.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/7.5.5...7.5.10)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-18 09:28:43 +02:00
dependabot[bot] 17d01dc92c
Bump braces from 3.0.2 to 3.0.3 (#215)
Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3.
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)

---
updated-dependencies:
- dependency-name: braces
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-18 09:28:29 +02:00
mathieudutour f36074fe49
version 6.2 2024-03-11 10:22:39 +01:00
Essau Ramirez f40d7eefd8
match latest tag regex (#171)
* match latest tag regex

* Lint fixes
2024-03-11 09:58:22 +01:00
Yoshikawa Teru 1bf7977a3d
fix: add previous_version to action.yml (#183) 2024-03-11 09:53:34 +01:00
dependabot[bot] 5a16d14432
Bump tough-cookie from 4.0.0 to 4.1.3 (#184)
Bumps [tough-cookie](https://github.com/salesforce/tough-cookie) from 4.0.0 to 4.1.3.
- [Release notes](https://github.com/salesforce/tough-cookie/releases)
- [Changelog](https://github.com/salesforce/tough-cookie/blob/master/CHANGELOG.md)
- [Commits](https://github.com/salesforce/tough-cookie/compare/v4.0.0...v4.1.3)

---
updated-dependencies:
- dependency-name: tough-cookie
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-11 09:52:34 +01:00
Filipe Veloso 71c3689659
Update README.md (#205)
update gh action checkout  version in example
2024-03-11 09:52:15 +01:00
naresh-gn a079ba461d
Update Node version to 20 (#202)
* Update Node version to 20

* Update Node version to 20

* Update Node version to 20

* Update .github/workflows/test.yml

Co-authored-by: cawfeecake <48775802+cawfeecake@users.noreply.github.com>

---------

Co-authored-by: Naresh Nagarajan <naresh-gn@gmail.com>
Co-authored-by: cawfeecake <48775802+cawfeecake@users.noreply.github.com>
2024-03-11 09:51:45 +01:00
Mathieu Dutour 86301c823d
Revert "Use `${{github.token}}` as default" (#167) 2023-02-06 13:16:45 +01:00
dependabot[bot] 5bd9038fd1
Bump minimatch from 3.0.4 to 3.1.2 (#162)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-22 17:27:02 +01:00
Chris Hilton ac8cb38838
getValidTags() should exclude tags that do not match the prefixRegex (#158) 2023-01-22 17:26:50 +01:00
dependabot[bot] 664437484d
Bump json5 from 2.1.3 to 2.2.3 (#161)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-22 17:25:57 +01:00
kzrnm 87d9c10c43
Use `${{github.token}}` as default (#154)
Co-authored-by: Mathieu Dutour <mathieu@dutour.me>
2023-01-22 17:25:46 +01:00
mathieudutour dbd80d2e9d
version 6.1 2022-10-26 11:00:15 +02:00
James Phillips a1afa112d3
Correctly parse `create_annotated_tag` (#137) 2022-10-26 10:57:31 +02:00
Mathieu Dutour 3f9dffdaa0
Merge pull request #147 from JohnTitor/nodejs16 2022-10-26 10:52:06 +02:00
Mathieu Dutour c4f56e7003
Merge pull request #146 from JohnTitor/actions-core 2022-10-26 10:51:42 +02:00
Yuki Okushi 923acce875
Update `@actions/core` to v1.10.0
Signed-off-by: Yuki Okushi <jtitor@2k36.org>
2022-10-14 11:46:39 +09:00
Yuki Okushi c5ababce46
Update to Node.js 16
Signed-off-by: Yuki Okushi <jtitor@2k36.org>
2022-10-14 11:44:46 +09:00
Mathieu Dutour e923a6115f
Merge pull request #142 from mathieudutour/dependabot/npm_and_yarn/actions/core-1.9.1 2022-08-19 08:49:47 +02:00
dependabot[bot] 8bee2b2289
Bump @actions/core from 1.6.0 to 1.9.1
Bumps [@actions/core](https://github.com/actions/toolkit/tree/HEAD/packages/core) from 1.6.0 to 1.9.1.
- [Release notes](https://github.com/actions/toolkit/releases)
- [Changelog](https://github.com/actions/toolkit/blob/main/packages/core/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/core)

---
updated-dependencies:
- dependency-name: "@actions/core"
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-18 19:17:35 +00:00
Mathieu Dutour 92dc56ebab
Merge pull request #124 from mathieudutour/dependabot/npm_and_yarn/node-fetch-2.6.7
Bump node-fetch from 2.6.1 to 2.6.7
2022-04-12 13:58:28 +02:00
dependabot[bot] 15886d3d8c
Bump node-fetch from 2.6.1 to 2.6.7
Bumps [node-fetch](https://github.com/node-fetch/node-fetch) from 2.6.1 to 2.6.7.
- [Release notes](https://github.com/node-fetch/node-fetch/releases)
- [Commits](https://github.com/node-fetch/node-fetch/compare/v2.6.1...v2.6.7)

---
updated-dependencies:
- dependency-name: node-fetch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-12 09:50:07 +00:00
Mathieu Dutour f1a52e6b0e
Merge pull request #123 from mathieudutour/dependabot/npm_and_yarn/minimist-1.2.6
Bump minimist from 1.2.5 to 1.2.6
2022-04-12 11:49:30 +02:00
dependabot[bot] 672968b48d
Bump minimist from 1.2.5 to 1.2.6
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-11 19:34:53 +00:00
Mathieu Dutour ba54fd76a5
Create FUNDING.yml 2021-11-17 12:21:25 +01:00
Mathieu Dutour 4cf1d6f51d
fix assignment 2021-11-17 12:15:07 +01:00
Mathieu Dutour c0f9097516
Merge pull request #83 from jimrazmus/sanitize-github-ref
fix:issue #81 - sanitize semver in branch name
2021-11-17 12:11:35 +01:00
Mathieu Dutour e4770866d6
Merge pull request #89 from amplifysa/feature/commit_sha
Allow to pass a commit SHA instead using GITHUB_SHA.
2021-11-17 12:11:09 +01:00
Yann Savary aff4bff53d Updated README.md 2021-11-16 19:44:56 +01:00
Yann Savary 1b8ac6a7b8 Fixed code style and documentation 2021-11-16 19:41:49 +01:00
Yann Savary 438b61463e Merge branch 'master' into feature/commit_sha 2021-11-16 19:16:42 +01:00
Mathieu Dutour 917867a4e1
prepare version 6.0 2021-11-16 19:14:05 +01:00
Mathieu Dutour 6f05ce192f
update deps 2021-11-16 19:07:40 +01:00
Mathieu Dutour 74942d5347
Merge pull request #102 from JonErickson/master
Support for incrementing the prerelease number when no automatic bumps are encountered.
2021-11-16 18:44:48 +01:00
Jon Erickson f26971f09b Run prettier 2021-10-29 20:37:48 -07:00
Jon Erickson 8614426b27 Updated action to include default_prerelease_bump to separate out options. 2021-10-29 20:34:06 -07:00
Jon Erickson a5ae58c758 Added more tags to prerelease test 2021-10-29 16:48:10 -07:00
Yann Savary 2fca5fd609 Merge branch 'master' into feature/commit_sha
# Conflicts:
#	src/action.ts
2021-10-28 14:07:53 +02:00
Jon Erickson 204025ad5b Test setting default_bump to prerelease increments prerelease number when no bump encountered 2021-10-18 15:35:24 -07:00
Jon Erickson c52d722673 Make sure we are only changing the bump var if it is a known prerelease commit. 2021-10-18 15:10:53 -07:00
Jon Erickson c791a95a0b Support for incrementing the prerelease number when no automatic bumps are encountered. 2021-10-18 15:06:11 -07:00
Jim Razmus II 8e69e12fa1
fix: replace returns a string
Replace is not an in-place edit AFAIK. Consequently, we need to overwrite the identifier value to get the desired sanitization effect.
2021-09-15 12:01:24 -05:00
Jim Razmus II 3cc0072f45
fix: indentation 2021-09-14 12:38:01 -05:00
Mathieu Dutour 772bd6d2ca
Merge pull request #95 from slidoapp/miluoshi-update-outdated-example-code
Update outdated example in README.md
2021-09-13 18:54:10 +02:00
Mathieu Dutour 27a5f3aa9b
Merge pull request #96 from olink78/master
use GITHUB_SERVER_URL instead of hardcoded url
2021-09-13 18:53:41 +02:00
olilin f05041888b use GITHUB_SERVER_URL instead of hardcoded url 2021-09-13 13:31:15 +02:00
Jim Razmus II caef8f4d8b
fix: consistently sanitize identifier
Guards against branch names including a semver as well as branch names having characters not allowed by the semver specification.

Co-authored-by: folex <0xdxdy@gmail.com>
2021-09-03 11:15:28 -05:00
Miloš Lajtman c5cc34d0bd
Update outdated example in README.md
`actions/create-release` action in the example snippet has been archived and replaced by `ncipollo/release-action` as can be seen in [original action's readme](https://github.com/marketplace/actions/create-release#example) in the marketplace.
Also, since [the last release](https://github.com/ncipollo/release-action/releases/tag/v1.8.8) a `token` input is not required because a github token from `github` context is set as a default input value.
2021-09-01 12:41:33 +02:00
Mathieu Dutour f5c2b1475c
v5.6 2021-07-22 17:05:38 +02:00
Mathieu Dutour 9b6fc6e3a0
Merge pull request #90 from jonathanhublo/fetch_all_tags
feat(tag fetching): support for more than a 100 tag at a time
2021-07-22 17:04:01 +02:00
Jonathan Jayet a21ccc490d feat(tag fetching): support for more than a 100 tag at a time 2021-07-21 18:03:01 +02:00
Yann Savary 58d61ff5ab Updated README.md 2021-07-15 16:06:42 +02:00
Yann Savary aca73cf197 Added 'commit_sha' input to use this commit SHA instead GITHUB_SHA. 2021-07-15 15:41:03 +02:00
Jim Razmus II c443da5e30 fix:issue #81 - sanitize semver in branch name
PRs with branch names containing a semver break later valid'ation calls.
2021-05-06 10:49:24 -05:00
Mathieu Dutour 745081026c
add doc 2021-04-20 07:53:18 +02:00
Mathieu Dutour d02237e777
v5.5 2021-04-20 07:52:27 +02:00
Mathieu Dutour ee587589b4
Merge pull request #79 from davidolrik/return-release-type
feat: Add release_type to outputs
2021-04-20 07:50:54 +02:00
David Jack Wange Olrik c7025fccaf
feat: Add release_type to outputs
Fixes #78
2021-04-18 21:54:19 +02:00
Mathieu Dutour 77da7030b0 v5.4 2021-04-01 15:48:39 +02:00
Mathieu Dutour 60e1f8df56
Merge pull request #69 from koiralakiran1/custom-release-rule-changelog
Feat: Support Custom Changelog rules
2021-04-01 15:46:35 +02:00
Mathieu Dutour 514c51bfe1
Update action.ts 2021-04-01 15:45:42 +02:00
Mathieu Dutour 08141c4e6c
actually need ? 2021-04-01 15:37:52 +02:00
Mathieu Dutour 8fe38641cc
use mappedReleaseRules directly 2021-04-01 15:31:52 +02:00
Mathieu Dutour ddafd83108
remove unused types 2021-04-01 15:30:58 +02:00
Mathieu Dutour f1313dce02
move type in defaults 2021-04-01 15:30:07 +02:00
Mathieu Dutour ca34e578f6
clean rules parsing 2021-04-01 15:28:16 +02:00
Mathieu Dutour b0dfd30a23
reword doc 2021-04-01 15:09:16 +02:00
Mathieu Dutour 4d778776af
Merge pull request #74 from mathieudutour/dependabot/npm_and_yarn/y18n-4.0.1
Bump y18n from 4.0.0 to 4.0.1
2021-03-31 11:01:55 +02:00
dependabot[bot] e0a61d83b2
Bump y18n from 4.0.0 to 4.0.1
Bumps [y18n](https://github.com/yargs/y18n) from 4.0.0 to 4.0.1.
- [Release notes](https://github.com/yargs/y18n/releases)
- [Changelog](https://github.com/yargs/y18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yargs/y18n/commits)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-31 04:43:02 +00:00
Kiran Koirala 7654e2d2c4 Add unit tests 2021-03-23 20:05:55 +05:45
Kiran Koirala 85ae0059c0 Fix unit tests + Remove unwanted types 2021-03-22 00:26:38 +05:45
Kiran Koirala 2cfa3f0604 Update README 2021-03-20 22:11:06 +05:45
Kiran Koirala 413032fe57 Fix prettier issues 2021-03-20 21:54:13 +05:45
Kiran Koirala 4b936d9f59 Custom Release rule changelog 2021-03-20 21:37:58 +05:45
Mathieu Dutour 87322e4eff v5.3 2021-03-09 08:56:35 +01:00
Mathieu Dutour 21f8d79d2f
Merge pull request #66 from chrisjohnson00/pr-check
fix: allow running the action on a PR
2021-03-09 08:53:59 +01:00
Chris Johnson 3cc1a97bc2 chore: PR feedback
Calls to `inc` don't need to be conditional based on if it's a PR or not since releaseType is already conditional
2021-03-08 11:09:10 -08:00
Chris Johnson c627331682 fix: allow running the action on a PR 2021-03-05 17:42:51 -08:00
Mathieu Dutour 8dc6c0deb2
Merge pull request #63 from onpointglobal/fix/62-contextualize-commits-analysis
#62 - commits analyzed repeatedly
2021-02-24 17:50:57 +01:00
Andres Pache f8a4419607 fix():Issue #62 - commits analyzed repeatedly 2021-02-24 10:31:50 -03:00
Mathieu Dutour 5961cf9c4d fix typo 2021-02-18 10:32:06 +01:00
Mathieu Dutour 7037405dba v5.2 2021-02-18 10:15:36 +01:00
Mathieu Dutour 2d739a69ac add previous_version output 2021-02-18 10:15:23 +01:00
Mathieu Dutour 5c83261308
Merge pull request #61 from koiralakiran1/master
Issue #54: Fix(Compare GITHUB_SHA instead of 'HEAD' to baseRef/latest tag ref)
2021-02-18 09:53:46 +01:00
Kiran Koirala 63ff928afe fix prettier error 2021-02-18 12:28:30 +05:45
Kiran Koirala 93b037fc64 Fix(Compare GITHUB_SHA instead of 'HEAD' to baseRef/latest tag ref) 2021-02-18 12:17:15 +05:45
Mathieu Dutour f9c1f5572a fix custom tag prefix 2021-01-04 11:02:35 +01:00
Mathieu Dutour 4011b0c046 try renaming files 2021-01-04 10:42:46 +01:00
Mathieu Dutour 27ff796862 fix tests 2021-01-04 10:30:49 +01:00
Mathieu Dutour c713842b07 fix more types 2021-01-04 10:21:30 +01:00
Mathieu Dutour 2abed9daf5 fix types 2021-01-04 10:05:54 +01:00
Mathieu Dutour ac7062e04c
Merge pull request #49 from mathieudutour/dependabot/npm_and_yarn/node-notifier-8.0.1
Bump node-notifier from 8.0.0 to 8.0.1
2020-12-22 12:11:47 +01:00
dependabot[bot] d2337ee650
Bump node-notifier from 8.0.0 to 8.0.1
Bumps [node-notifier](https://github.com/mikaelbr/node-notifier) from 8.0.0 to 8.0.1.
- [Release notes](https://github.com/mikaelbr/node-notifier/releases)
- [Changelog](https://github.com/mikaelbr/node-notifier/blob/v8.0.1/CHANGELOG.md)
- [Commits](https://github.com/mikaelbr/node-notifier/compare/v8.0.0...v8.0.1)

Signed-off-by: dependabot[bot] <support@github.com>
2020-12-22 10:21:55 +00:00
Mathieu Dutour 1db9b7fb61
Update README.md 2020-12-02 18:19:26 +01:00
Mathieu Dutour 2f68951eb2
Merge pull request #41 from boxcee/add-tests
Add some tests and custom_release_rules
2020-11-23 12:14:30 +01:00
Moritz Schmitz von Hülst d2826f6b74 I was hoping for MORE readability... 2020-11-17 13:28:47 +01:00
Moritz Schmitz von Hülst a500a890f9 consistency 2020-11-17 13:22:59 +01:00
Moritz Schmitz von Hülst a4b921efd9 mock debug and refactor mapping function 2020-11-17 13:22:00 +01:00
Moritz Schmitz von Hülst 243e30c098 ignore lib with prettier 2020-11-17 13:13:33 +01:00
Moritz Schmitz von Hülst 485c833698 add prettier and warning for invalid release types 2020-11-17 13:12:06 +01:00
Moritz Schmitz von Hülst 2744b2948f Merge branch 'master' of github.com:mathieudutour/github-tag-action into add-tests 2020-11-17 12:42:10 +01:00
Moritz Schmitz von Hülst 44796f5a02 add README 2020-11-13 11:55:18 +01:00
Moritz Schmitz von Hülst 158d2b0407 add custom_release_rules and more tests 2020-11-13 11:51:00 +01:00
Moritz Schmitz von Hülst 169b215c7c more tests 2020-11-13 11:09:36 +01:00
Moritz Schmitz von Hülst 79e0ea271c forgot package.json 2020-11-12 22:54:52 +01:00
Moritz Schmitz von Hülst 953789d88f more tests 2020-11-12 22:54:32 +01:00
Moritz Schmitz von Hülst c9d97025ca add some initial tests 2020-11-12 17:05:47 +01:00
Moritz Schmitz von Hülst 39fb6943f4
Improve doc (#39) 2020-11-12 10:30:38 +01:00
Mathieu Dutour 808cb0be59 let's stay on v5 2020-11-11 18:31:08 +01:00
Moritz Schmitz von Hülst bcf1629a1f
Fix issue when append_to_pre_release_tag is set (#38)
* If append_to_prerelease_tag is set it should be used as identifier to lookup the latest prerelease tag.

* 5.0.1

* small refactor
2020-11-11 18:30:29 +01:00
Mathieu Dutour a2cbb4e42e
Prereleases (#37)
Co-authored-by: Moritz Schmitz von Hülst <moritz@hauptstadtoffice.com>
2020-11-10 12:18:53 +01:00
Mathieu Dutour 23d84076bf
Merge pull request #35 from orenkl/patch-1
Update README.md
2020-10-22 14:25:39 +02:00
Oren Klichevsky 6f71c79ac5
Update README.md 2020-10-22 15:12:38 +03:00
Mathieu Dutour 4d3f3c89c4
Merge pull request #34 from mathieudutour/dependabot/npm_and_yarn/actions/core-1.2.6
Bump @actions/core from 1.2.4 to 1.2.6
2020-10-02 08:47:05 +02:00
dependabot[bot] 3c98f714e3
Bump @actions/core from 1.2.4 to 1.2.6
Bumps [@actions/core](https://github.com/actions/toolkit/tree/HEAD/packages/core) from 1.2.4 to 1.2.6.
- [Release notes](https://github.com/actions/toolkit/releases)
- [Changelog](https://github.com/actions/toolkit/blob/main/packages/core/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/core)

Signed-off-by: dependabot[bot] <support@github.com>
2020-10-01 17:23:20 +00:00
Mathieu Dutour c5a62eade8
Merge pull request #31 from mathieudutour/dependabot/npm_and_yarn/node-fetch-2.6.1
Bump node-fetch from 2.6.0 to 2.6.1
2020-09-14 08:31:52 +02:00
Mathieu Dutour 5a7ee2645a
custom_tag not required 2020-09-14 08:31:42 +02:00
dependabot[bot] dcaf34722b
Bump node-fetch from 2.6.0 to 2.6.1
Bumps [node-fetch](https://github.com/bitinn/node-fetch) from 2.6.0 to 2.6.1.
- [Release notes](https://github.com/bitinn/node-fetch/releases)
- [Changelog](https://github.com/node-fetch/node-fetch/blob/master/docs/CHANGELOG.md)
- [Commits](https://github.com/bitinn/node-fetch/compare/v2.6.0...v2.6.1)

Signed-off-by: dependabot[bot] <support@github.com>
2020-09-12 09:58:30 +00:00
Mathieu Dutour 247b5405c2
Merge pull request #29 from bissim/master
Introduce 'custom_tag' input
2020-09-08 13:31:19 +02:00
Simone B 5e9c060b75 Update README.md
Fix typo in 'custom_tag' description.
2020-09-06 10:21:28 +00:00
Simone B 6f346ca75f Update README.md
Define 'custom_tag' input according to 0f551ad
2020-09-06 10:19:52 +00:00
Simone B e4ab737554 Introduce 'custom_tag' input
Inspired by commit 0f551ad of laputansoft/github-tag_action fork.

In action.yml:
  - Define inputs.custom_tag with no default

In main.ts run() function:
  - Define a 'customTag' variable which value is extracted from input.custom_tag
  - Define 'newVersion' variable value according to whether 'customTag' variable has a value or not
2020-09-06 10:18:27 +00:00
Mathieu Dutour 32d5841de6
Merge pull request #24 from mathieudutour/dependabot/npm_and_yarn/lodash-4.17.19
Bump lodash from 4.17.15 to 4.17.19
2020-07-18 18:56:42 +02:00
dependabot[bot] f80379c935
Bump lodash from 4.17.15 to 4.17.19
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19)

Signed-off-by: dependabot[bot] <support@github.com>
2020-07-18 16:36:50 +00:00
Mathieu Dutour 335dc07cbc
Merge pull request #20 from sebbacon/fetch-all-history
docs: arguments required to work with latest `actions/checkout`
2020-07-07 13:10:24 +02:00
Seb Bacon a845af27dd docs: arguments required to work with latest `actions/checkout` 2020-07-07 12:03:53 +01:00
Mathieu Dutour 357d900cbc
Merge pull request #19 from alexesprit/replace-github
Replace "Github" with "GitHub"
2020-06-26 19:33:29 +02:00
alexesprit b246e02acc Replace "Github" with "GitHub" 2020-06-26 19:48:20 +03:00
mathieudutour 378af747dd fix when data is empty 2020-05-27 18:35:14 +02:00
mathieudutour 0b57d04197 get commit hash as well 2020-05-27 18:18:53 +02:00
mathieudutour 1ba75e94d8 add a `false` option for default_bump 2020-05-27 15:30:18 +02:00
mathieudutour f498350328 v4.3 2020-05-27 15:21:27 +02:00
mathieudutour fcbdb4900a update readme 2020-05-27 15:10:23 +02:00
mathieudutour 9862d97046 v4.2 2020-05-07 16:45:13 +02:00
mathieudutour 0c680c5a9f update deps 2020-05-07 16:44:48 +02:00
Mathieu Dutour 5b82560611
Merge pull request #13 from dragonraid/master 2020-05-07 16:30:57 +02:00
Mathieu Dutour 29406317d5
Merge pull request #12 from hennejg/bugfix/#11_evaluate_dryRun_as_boolean 2020-05-07 16:08:10 +02:00
dragonraid 3093d7874d Always set previous_tag output 2020-05-07 13:42:36 +02:00
Jörg Henne 37d688c7f5 fix: evaluation of dryRun as boolean 2020-05-07 13:06:08 +02:00
Mathieu Dutour 61723be3c9
Merge pull request #10 from ssoerensen/master
Added dry_run option
2020-03-28 21:01:05 +01:00
Steffen F. Qvistgaard dbe810aa0a Added dry_run option 2020-03-28 20:22:44 +01:00
Mathieu Dutour 8a2b37b15b wait for changelog 2020-02-25 12:52:52 +01:00
Mathieu Dutour e33b12f4b0 don't create tag if already exists 2020-02-25 11:27:21 +01:00
Mathieu Dutour 84a0a2a774 update lock file 2020-02-24 19:20:48 +01:00
Mathieu Dutour db3f178993 add changelog output 2020-02-24 18:55:02 +01:00
Mathieu Dutour eaba27db28 v3.1.0 2020-02-24 12:12:35 +01:00
Mathieu Dutour 466c73e94c v0.3.1 2020-02-24 12:12:16 +01:00
Mathieu Dutour 76537e6a66 for some reason there is a ' at the beginning 2020-02-24 12:05:52 +01:00
Mathieu Dutour 575d299bec use console because we need string substitution 2020-02-13 20:39:36 +01:00
Mathieu Dutour 83c4cf4236 make sure to trim the commit messages 2020-02-13 17:07:09 +01:00
mathieudutour 00d74c7984 get latest tag
fix #4
2020-01-13 10:35:30 +01:00
mathieudutour 1308fda634 fetch tags before looking for them
in case tags were created outside this action (see #5)
2020-01-13 10:34:57 +01:00
mathieudutour 861ef9e87f add new_version output 2020-01-10 17:29:30 +01:00
Mathieu Dutour d6742e8d44
add annotated tag support (#3)
add annotated tag support
2020-01-08 20:40:29 +01:00
Shane Schmaltz 891051c8d8
Fix annotated tag check
Co-Authored-By: Mathieu Dutour <mathieu@dutour.me>
2020-01-08 12:33:36 -07:00
Shane 5a380ff488 add annotated tag support and update docs to reference new version 2020-01-07 14:48:44 -07:00
mathieudutour 7c5c50eb39 update package-lock 2020-01-06 16:35:37 +01:00
mathieudutour 5308ace8c4 v0.2.0 2020-01-06 16:33:51 +01:00
mathieudutour 085ca3ed37 use semantic-release to get the bump 2020-01-06 16:33:39 +01:00
Mathieu Dutour f6b1bf32ae add previous_tag output 2019-11-28 11:58:17 +01:00
Mathieu Dutour ed5ada44f8 fix syntax highlight 2019-10-31 12:02:20 -07:00
Mathieu Dutour 54afd1e9a8 fix typo 2019-10-31 11:59:05 -07:00
Mathieu Dutour f87f1caeca fix typo 2019-10-31 11:58:23 -07:00
Mathieu Dutour e05737e474 fix typo 2019-10-31 11:53:07 -07:00
22 changed files with 12457 additions and 4128 deletions

1
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1 @@
github: [mathieudutour]

View File

@ -4,13 +4,16 @@ on:
push:
branches:
- master
- "releases/*"
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: package.json
- run: npm ci
- run: npm run test
- run: npm run check
- run: npm run build

3
.gitignore vendored
View File

@ -92,3 +92,6 @@ typings/
# DynamoDB Local files
.dynamodb/
# IntelliJ
.idea/

8
.prettierignore Normal file
View File

@ -0,0 +1,8 @@
/.github/
/.vscode/
/lib/
/docs/
/*.json
/*.js
/*.yml
/*.md

4
.prettierrc.json Normal file
View File

@ -0,0 +1,4 @@
{
"singleQuote": true,
"parser": "typescript"
}

10
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,10 @@
{
"spellright.language": [
"en"
],
"spellright.documentTypes": [
"markdown",
"latex",
"plaintext"
]
}

121
README.md
View File

@ -1,10 +1,10 @@
# GitHub Tag Action
A Github Action to automatically bump and tag master, on merge, with the latest SemVer formatted version. Works on any platform.
A GitHub Action to automatically bump and tag master, on merge, with the latest SemVer formatted version. Works on any platform.
## Usage
```Dockerfile
```yaml
name: Bump version
on:
push:
@ -14,26 +14,119 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Bump version and push tag
uses: mathieudutour/github-tag-action@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/checkout@v4
- name: Bump version and push tag
id: tag_version
uses: mathieudutour/github-tag-action@v6.2
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Create a GitHub release
uses: ncipollo/release-action@v1
with:
tag: ${{ steps.tag_version.outputs.new_tag }}
name: Release ${{ steps.tag_version.outputs.new_tag }}
body: ${{ steps.tag_version.outputs.changelog }}
```
### Inputs
### 📥 Inputs
- **github_token** _(required)_ - Required for permission to tag the repo. Usually `${{ secrets.GITHUB_TOKEN }}`.
- **default_bump** _(optional)_ - Which type of bump to use when none explicitly provided (default: `minor`).
- **commit_sha** _(optional)_ - The commit SHA value to add the tag. If specified, it uses this value instead GITHUB_SHA. It could be useful when a previous step merged a branch into github.ref.
#### Fetch all tags
- **fetch_all_tags** _(optional)_ - By default, this action fetch the last 100 tags from Github. Sometimes, this is not enough and using this action will fetch all tags recursively (default: `false`).
#### Filter branches
- **release_branches** _(optional)_ - Comma separated list of branches (JavaScript regular expression accepted) that will generate the release tags. Other branches and pull-requests generate versions postfixed with the commit hash and do not generate any repository tag. Examples: `master` or `.*` or `release.*,hotfix.*,master`... (default: `master,main`).
- **pre_release_branches** _(optional)_ - Comma separated list of branches (JavaScript regular expression accepted) that will generate the pre-release tags.
#### Customize the tag
- **default_bump** _(optional)_ - Which type of bump to use when [none is explicitly provided](#bumping) when commiting to a release branch (default: `patch`). You can also set `false` to avoid generating a new tag when none is explicitly provided. Can be `patch, minor or major`.
- **default_prerelease_bump** _(optional)_ - Which type of bump to use when [none is explicitly provided](#bumping) when commiting to a prerelease branch (default: `prerelease`). You can also set `false` to avoid generating a new tag when none is explicitly provided. Can be `prerelease, prepatch, preminor or premajor`.
- **custom_tag** _(optional)_ - Custom tag name. If specified, it overrides bump settings.
- **create_annotated_tag** _(optional)_ - Boolean to create an annotated rather than a lightweight one (default: `false`).
- **tag_prefix** _(optional)_ - A prefix to the tag name (default: `v`).
- **release_branches** _(optional)_ - Comma separated list of branches (bash reg exp accepted) that will generate the release tags. Other branches and pull-requests generate versions postfixed with the commit hash and do not generate any tag. Examples: `master` or `.*` or `release.*,hotfix.*,master` ...
- **append_to_pre_release_tag** _(optional)_ - A suffix to the pre-release tag name (default: `<branch>`).
### Outputs
#### Customize the conventional commit messages & titles of changelog sections
- **new_tag** - The value of the newly created tag.
- **custom_release_rules** _(optional)_ - Comma separated list of release rules.
> **_Note:_** This action creates a [lightweight tag](https://developer.github.com/v3/git/refs/#create-a-reference).
__Format__: `<keyword>:<release_type>:<changelog_section>` where `<changelog_section>` is optional and will default to [Angular's conventions](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular).
__Examples__:
1. `hotfix:patch,pre-feat:preminor`,
2. `bug:patch:Bug Fixes,chore:patch:Chores`
#### Debugging
- **dry_run** _(optional)_ - Do not perform tagging, just calculate next version and changelog, then exit
### 📤 Outputs
- **new_tag** - The value of the newly calculated tag. Note that if there hasn't been any new commit, this will be `undefined`.
- **new_version** - The value of the newly created tag without the prefix. Note that if there hasn't been any new commit, this will be `undefined`.
- **previous_tag** - The value of the previous tag (or `v0.0.0` if none). Note that if `custom_tag` is set, this will be `undefined`.
- **previous_version** - The value of the previous tag (or `0.0.0` if none) without the prefix. Note that if `custom_tag` is set, this will be `undefined`.
- **release_type** - The computed release type (`major`, `minor`, `patch` or `custom` - can be prefixed with `pre`).
- **changelog** - The [conventional changelog](https://github.com/conventional-changelog/conventional-changelog) since the previous tag.
> **_Note:_** This action creates a [lightweight tag](https://developer.github.com/v3/git/refs/#create-a-reference) by default.
### Bumping
The action will parse the new commits since the last tag using the [semantic-release](https://github.com/semantic-release/semantic-release) conventions.
semantic-release uses the commit messages to determine the type of changes in the codebase. Following formalized conventions for commit messages, semantic-release automatically determines the next [semantic version](https://semver.org) number.
By default semantic-release uses [Angular Commit Message Conventions](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#-git-commit-guidelines).
Here is an example of the release type that will be done based on a commit messages:
<table>
<tr>
<td> Commit message </td> <td> Release type </td>
</tr>
<tr>
<td>
```
fix(pencil): stop graphite breaking when too much pressure applied
```
</td>
<td>Patch Release</td>
</tr>
<tr>
<td>
```
feat(pencil): add 'graphiteWidth' option
```
</td>
<td>Minor Release</td>
</tr>
<tr>
<td>
```
perf(pencil): remove graphiteWidth option
BREAKING CHANGE: The graphiteWidth option has been removed.
The default graphite width of 10mm is always used for performance reasons.
```
</td>
<td>Major Release</td>
</tr>
</table>
If no commit message contains any information, then **default_bump** will be used.
## Credits
[anothrNick/github-tag-action](https://github.com/anothrNick/github-tag-action) - a similar action using a Dockerfile
[anothrNick/github-tag-action](https://github.com/anothrNick/github-tag-action) - a similar action using a Dockerfile (hence not working on macOS)

View File

@ -1,27 +1,69 @@
name: "Github Tag"
name: "GitHub Tag"
description: "Bump and push git tag on merge"
author: "Mathieu Dutour"
outputs:
new_tag:
description: "Generated tag"
new_version:
description: "Generated tag without the prefix"
previous_tag:
description: "Previous tag (or `0.0.0`)"
previous_version:
description: "The value of the previous tag (or 0.0.0 if none) without the prefix. Note that if custom_tag is set, this will be undefined."
release_type:
description: "The computed release type (`major`, `minor`, `patch` or `custom` - can be prefixed with `pre`)"
changelog:
description: "The conventional changelog since the previous tag"
inputs:
github_token:
description: "Required for permission to tag the repo."
required: true
default_bump:
description: "Which type of bump to use when none explicitly provided (default: `minor`)."
description: "Which type of bump to use when none explicitly provided when commiting to a release branch (default: `patch`)."
required: false
default: "minor"
default: "patch"
default_prerelease_bump:
description: "Which type of bump to use when none explicitly provided when commiting to a prerelease branch (default: `prerelease`)."
required: false
default: "prerelease"
tag_prefix:
description: "A prefix to the tag name (default: `v`)."
required: false
default: "v"
append_to_pre_release_tag:
description: "A suffix to a pre-release tag name (default: `<branch>`)."
required: false
custom_tag:
description: "Custom tag name. If specified, it overrides bump settings."
required: false
custom_release_rules:
description: "Comma separated list of release rules. Format: `<keyword>:<release_type>`. Example: `hotfix:patch,pre-feat:preminor`."
required: false
release_branches:
description: "Comma separated list of branches (bash reg exp accepted) that will generate the release tags. Other branches and pull-requests generate versions postfixed with the commit hash and do not generate any tag. Examples: `master` or `.*` or `release.*,hotfix.*,master`..."
required: false
default: "master"
default: "master,main"
pre_release_branches:
description: "Comma separated list of branches (bash reg exp accepted) that will generate pre-release tags."
required: false
commit_sha:
description: "The commit SHA value to add the tag. If specified, it uses this value instead GITHUB_SHA. It could be useful when a previous step merged a branch into github.ref."
required: false
create_annotated_tag:
description: "Boolean to create an annotated tag rather than lightweight."
required: false
default: "false"
fetch_all_tags:
description: "Boolean to fetch all tags for a repo (if false, only the last 100 will be fetched)."
required: false
default: "false"
dry_run:
description: "Do not perform tagging, just calculate next version and changelog, then exit."
required: false
default: "false"
runs:
using: "node12"
using: "node20"
main: "lib/main.js"
branding:
icon: "git-merge"

14324
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,13 @@
{
"name": "github-tag-action",
"version": "0.1.0",
"version": "6.2.0",
"private": true,
"description": "A Github Action to automatically bump and tag master, on merge, with the latest SemVer formatted version.",
"description": "A GitHub Action to automatically bump and tag master, on merge, with the latest SemVer formatted version.",
"main": "lib/main.js",
"scripts": {
"build": "tsc"
"build": "tsc",
"test": "jest --testTimeout 10000",
"check": "prettier --check ."
},
"repository": {
"type": "git",
@ -16,21 +18,31 @@
"node",
"setup"
],
"engines": {
"node": ">=20"
},
"author": "Mathieu Dutour",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.0.0",
"@actions/exec": "^1.0.1",
"@actions/github": "^1.1.0",
"semver": "^6.3.0"
"@actions/core": "^1.10.0",
"@actions/exec": "^1.1.0",
"@actions/github": "^4.0.0",
"@semantic-release/commit-analyzer": "^8.0.1",
"@semantic-release/release-notes-generator": "^9.0.1",
"conventional-changelog-conventionalcommits": "^4.6.1",
"semver": "^7.3.5"
},
"devDependencies": {
"@types/jest": "^24.0.13",
"@types/node": "^12.0.4",
"@types/semver": "^6.2.0",
"jest": "^24.8.0",
"jest-circus": "^24.7.1",
"ts-jest": "^24.0.2",
"typescript": "^3.5.1"
"@octokit/rest": "^18.12.0",
"@types/jest": "^27.0.2",
"@types/js-yaml": "^4.0.4",
"@types/node": "^20.11.16",
"@types/semver": "^7.3.9",
"jest": "^27.3.1",
"jest-circus": "^27.3.1",
"js-yaml": "^4.1.0",
"prettier": "2.4.1",
"ts-jest": "^27.0.7",
"typescript": "^4.4.4"
}
}

232
src/action.ts Normal file
View File

@ -0,0 +1,232 @@
import * as core from '@actions/core';
import { gte, inc, parse, ReleaseType, SemVer, valid } from 'semver';
import { analyzeCommits } from '@semantic-release/commit-analyzer';
import { generateNotes } from '@semantic-release/release-notes-generator';
import {
getBranchFromRef,
isPr,
getCommits,
getLatestPrereleaseTag,
getLatestTag,
getValidTags,
mapCustomReleaseRules,
mergeWithDefaultChangelogRules,
} from './utils';
import { createTag } from './github';
import { Await } from './ts';
export default async function main() {
const defaultBump = core.getInput('default_bump') as ReleaseType | 'false';
const defaultPreReleaseBump = core.getInput('default_prerelease_bump') as
| ReleaseType
| 'false';
const tagPrefix = core.getInput('tag_prefix');
const customTag = core.getInput('custom_tag');
const releaseBranches = core.getInput('release_branches');
const preReleaseBranches = core.getInput('pre_release_branches');
const appendToPreReleaseTag = core.getInput('append_to_pre_release_tag');
const createAnnotatedTag = /true/i.test(
core.getInput('create_annotated_tag')
);
const dryRun = core.getInput('dry_run');
const customReleaseRules = core.getInput('custom_release_rules');
const shouldFetchAllTags = core.getInput('fetch_all_tags');
const commitSha = core.getInput('commit_sha');
let mappedReleaseRules;
if (customReleaseRules) {
mappedReleaseRules = mapCustomReleaseRules(customReleaseRules);
}
const { GITHUB_REF, GITHUB_SHA } = process.env;
if (!GITHUB_REF) {
core.setFailed('Missing GITHUB_REF.');
return;
}
const commitRef = commitSha || GITHUB_SHA;
if (!commitRef) {
core.setFailed('Missing commit_sha or GITHUB_SHA.');
return;
}
const currentBranch = getBranchFromRef(GITHUB_REF);
const isReleaseBranch = releaseBranches
.split(',')
.some((branch) => currentBranch.match(branch));
const isPreReleaseBranch = preReleaseBranches
.split(',')
.some((branch) => currentBranch.match(branch));
const isPullRequest = isPr(GITHUB_REF);
const isPrerelease = !isReleaseBranch && !isPullRequest && isPreReleaseBranch;
// Sanitize identifier according to
// https://semver.org/#backusnaur-form-grammar-for-valid-semver-versions
const identifier = (
appendToPreReleaseTag ? appendToPreReleaseTag : currentBranch
).replace(/[^a-zA-Z0-9-]/g, '-');
const prefixRegex = new RegExp(`^${tagPrefix}`);
const validTags = await getValidTags(
prefixRegex,
/true/i.test(shouldFetchAllTags)
);
const latestTag = getLatestTag(validTags, prefixRegex, tagPrefix);
const latestPrereleaseTag = getLatestPrereleaseTag(
validTags,
identifier,
prefixRegex
);
let commits: Await<ReturnType<typeof getCommits>>;
let newVersion: string;
if (customTag) {
commits = await getCommits(latestTag.commit.sha, commitRef);
core.setOutput('release_type', 'custom');
newVersion = customTag;
} else {
let previousTag: ReturnType<typeof getLatestTag> | null;
let previousVersion: SemVer | null;
if (!latestPrereleaseTag) {
previousTag = latestTag;
} else {
previousTag = gte(
latestTag.name.replace(prefixRegex, ''),
latestPrereleaseTag.name.replace(prefixRegex, '')
)
? latestTag
: latestPrereleaseTag;
}
if (!previousTag) {
core.setFailed('Could not find previous tag.');
return;
}
previousVersion = parse(previousTag.name.replace(prefixRegex, ''));
if (!previousVersion) {
core.setFailed('Could not parse previous tag.');
return;
}
core.info(
`Previous tag was ${previousTag.name}, previous version was ${previousVersion.version}.`
);
core.setOutput('previous_version', previousVersion.version);
core.setOutput('previous_tag', previousTag.name);
commits = await getCommits(previousTag.commit.sha, commitRef);
let bump = await analyzeCommits(
{
releaseRules: mappedReleaseRules
? // analyzeCommits doesn't appreciate rules with a section /shrug
mappedReleaseRules.map(({ section, ...rest }) => ({ ...rest }))
: undefined,
},
{ commits, logger: { log: console.info.bind(console) } }
);
// Determine if we should continue with tag creation based on main vs prerelease branch
let shouldContinue = true;
if (isPrerelease) {
if (!bump && defaultPreReleaseBump === 'false') {
shouldContinue = false;
}
} else {
if (!bump && defaultBump === 'false') {
shouldContinue = false;
}
}
// Default bump is set to false and we did not find an automatic bump
if (!shouldContinue) {
core.debug(
'No commit specifies the version bump. Skipping the tag creation.'
);
return;
}
// If we don't have an automatic bump for the prerelease, just set our bump as the default
if (isPrerelease && !bump) {
bump = defaultPreReleaseBump;
}
// If somebody uses custom release rules on a prerelease branch they might create a 'preprepatch' bump.
const preReg = /^pre/;
if (isPrerelease && preReg.test(bump)) {
bump = bump.replace(preReg, '');
}
const releaseType: ReleaseType = isPrerelease
? `pre${bump}`
: bump || defaultBump;
core.setOutput('release_type', releaseType);
const incrementedVersion = inc(previousVersion, releaseType, identifier);
if (!incrementedVersion) {
core.setFailed('Could not increment version.');
return;
}
if (!valid(incrementedVersion)) {
core.setFailed(`${incrementedVersion} is not a valid semver.`);
return;
}
newVersion = incrementedVersion;
}
core.info(`New version is ${newVersion}.`);
core.setOutput('new_version', newVersion);
const newTag = `${tagPrefix}${newVersion}`;
core.info(`New tag after applying prefix is ${newTag}.`);
core.setOutput('new_tag', newTag);
const changelog = await generateNotes(
{
preset: 'conventionalcommits',
presetConfig: {
types: mergeWithDefaultChangelogRules(mappedReleaseRules),
},
},
{
commits,
logger: { log: console.info.bind(console) },
options: {
repositoryUrl: `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}`,
},
lastRelease: { gitTag: latestTag.name },
nextRelease: { gitTag: newTag, version: newVersion },
}
);
core.info(`Changelog is ${changelog}.`);
core.setOutput('changelog', changelog);
if (!isReleaseBranch && !isPreReleaseBranch) {
core.info(
'This branch is neither a release nor a pre-release branch. Skipping the tag creation.'
);
return;
}
if (validTags.map((tag) => tag.name).includes(newTag)) {
core.info('This tag already exists. Skipping the tag creation.');
return;
}
if (/true/i.test(dryRun)) {
core.info('Dry run: not performing tag action.');
return;
}
await createTag(newTag, createAnnotatedTag, commitRef);
}

32
src/defaults.ts Normal file
View File

@ -0,0 +1,32 @@
type ChangelogRule = {
/**
* Commit type.
* Eg: feat, fix etc.
*/
type: string;
/**
* Section in changelog to group commits by type.
* Eg: 'Bug Fix', 'Features' etc.
*/
section?: string;
};
/**
* Default sections & changelog rules mentioned in `conventional-changelog-angular` & `conventional-changelog-conventionalcommits`.
* References:
* https://github.com/conventional-changelog/conventional-changelog/blob/master/packages/conventional-changelog-angular/writer-opts.js
* https://github.com/conventional-changelog/conventional-changelog/blob/master/packages/conventional-changelog-conventionalcommits/writer-opts.js
*/
export const defaultChangelogRules: Readonly<Record<string, ChangelogRule>> =
Object.freeze({
feat: { type: 'feat', section: 'Features' },
fix: { type: 'fix', section: 'Bug Fixes' },
perf: { type: 'perf', section: 'Performance Improvements' },
revert: { type: 'revert', section: 'Reverts' },
docs: { type: 'docs', section: 'Documentation' },
style: { type: 'style', section: 'Styles' },
refactor: { type: 'refactor', section: 'Code Refactoring' },
test: { type: 'test', section: 'Tests' },
build: { type: 'build', section: 'Build Systems' },
ci: { type: 'ci', section: 'Continuous Integration' },
});

94
src/github.ts Normal file
View File

@ -0,0 +1,94 @@
import { context, getOctokit } from '@actions/github';
import * as core from '@actions/core';
import { Await } from './ts';
let octokitSingleton: ReturnType<typeof getOctokit>;
type Tag = {
name: string;
commit: {
sha: string;
url: string;
};
zipball_url: string;
tarball_url: string;
node_id: string;
};
export function getOctokitSingleton() {
if (octokitSingleton) {
return octokitSingleton;
}
const githubToken = core.getInput('github_token');
octokitSingleton = getOctokit(githubToken);
return octokitSingleton;
}
/**
* Fetch all tags for a given repository recursively
*/
export async function listTags(
shouldFetchAllTags = false,
fetchedTags: Tag[] = [],
page = 1
): Promise<Tag[]> {
const octokit = getOctokitSingleton();
const tags = await octokit.repos.listTags({
...context.repo,
per_page: 100,
page,
});
if (tags.data.length < 100 || shouldFetchAllTags === false) {
return [...fetchedTags, ...tags.data];
}
return listTags(shouldFetchAllTags, [...fetchedTags, ...tags.data], page + 1);
}
/**
* Compare `headRef` to `baseRef` (i.e. baseRef...headRef)
* @param baseRef - old commit
* @param headRef - new commit
*/
export async function compareCommits(baseRef: string, headRef: string) {
const octokit = getOctokitSingleton();
core.debug(`Comparing commits (${baseRef}...${headRef})`);
const commits = await octokit.repos.compareCommits({
...context.repo,
base: baseRef,
head: headRef,
});
return commits.data.commits;
}
export async function createTag(
newTag: string,
createAnnotatedTag: boolean,
GITHUB_SHA: string
) {
const octokit = getOctokitSingleton();
let annotatedTag:
| Await<ReturnType<typeof octokit.git.createTag>>
| undefined = undefined;
if (createAnnotatedTag) {
core.debug(`Creating annotated tag.`);
annotatedTag = await octokit.git.createTag({
...context.repo,
tag: newTag,
message: newTag,
object: GITHUB_SHA,
type: 'commit',
});
}
core.debug(`Pushing new tag to the repo.`);
await octokit.git.createRef({
...context.repo,
ref: `refs/tags/${newTag}`,
sha: annotatedTag ? annotatedTag.data.sha : GITHUB_SHA,
});
}

View File

@ -1,109 +1,10 @@
import * as core from "@actions/core";
import { exec as _exec } from "@actions/exec";
import { context, GitHub } from "@actions/github";
import semver, { ReleaseType } from "semver";
async function exec(command: string) {
let stdout = "";
let stderr = "";
try {
const options = {
listeners: {
stdout: (data: Buffer) => {
stdout += data.toString();
},
stderr: (data: Buffer) => {
stderr += data.toString();
}
}
};
const code = await _exec(
"git describe --tags `git rev-list --tags --max-count=1`",
undefined,
options
);
return {
code,
stdout,
stderr
};
} catch (err) {
return {
code: 1,
stdout,
stderr,
error: err
};
}
}
import * as core from '@actions/core';
import action from './action';
async function run() {
try {
// @ts-ignore
const bump: ReleaseType = core.getInput("default_bump");
const tagPrefix = core.getInput("tag_prefix");
const releaseBranches = core.getInput("release_branches");
const { GITHUB_REF, GITHUB_SHA } = process.env;
if (!GITHUB_REF) {
core.setFailed("Missing GITHUB_REF");
return;
}
if (!GITHUB_SHA) {
core.setFailed("Missing GITHUB_SHA");
return;
}
const preRelease = releaseBranches
.split(",")
.every(branch => !GITHUB_REF.replace("refs/heads/", "").match(branch));
const hasTag = !!(await exec("git tags")).stdout;
let tag = "";
if (hasTag) {
const previousTagSha = (await exec("git rev-list --tags --max-count=1"))
.stdout;
tag = (await exec(`git describe --tags ${previousTagSha}`)).stdout;
if (previousTagSha === GITHUB_SHA) {
core.debug("No new commits since previous tag. Skipping...");
return;
}
} else {
tag = "0.0.0";
}
const newTag = `${tagPrefix}${semver.inc(tag, bump)}${
preRelease ? `-${GITHUB_SHA.slice(0, 7)}` : ""
}`;
core.setOutput("new_tag", newTag);
core.debug(`New tag: ${newTag}`);
if (preRelease) {
core.debug(
"This branch is not a release branch. Skipping the tag creation."
);
return;
}
const octokit = new GitHub(core.getInput("github_token"));
core.debug(`Pushing new tag to the repo`);
await octokit.git.createRef({
...context.repo,
ref: `refs/tags/${newTag}`,
sha: GITHUB_SHA
});
} catch (error) {
await action();
} catch (error: any) {
core.setFailed(error.message);
}
}

5
src/ts.ts Normal file
View File

@ -0,0 +1,5 @@
export type Await<T> = T extends {
then(onfulfilled?: (value: infer U) => unknown): unknown;
}
? U
: T;

149
src/utils.ts Normal file
View File

@ -0,0 +1,149 @@
import * as core from '@actions/core';
import { prerelease, rcompare, valid } from 'semver';
// @ts-ignore
import DEFAULT_RELEASE_TYPES from '@semantic-release/commit-analyzer/lib/default-release-types';
import { compareCommits, listTags } from './github';
import { defaultChangelogRules } from './defaults';
import { Await } from './ts';
type Tags = Await<ReturnType<typeof listTags>>;
export async function getValidTags(
prefixRegex: RegExp,
shouldFetchAllTags: boolean
) {
const tags = await listTags(shouldFetchAllTags);
const invalidTags = tags.filter(
(tag) =>
!prefixRegex.test(tag.name) || !valid(tag.name.replace(prefixRegex, ''))
);
invalidTags.forEach((name) => core.debug(`Found Invalid Tag: ${name}.`));
const validTags = tags
.filter(
(tag) =>
prefixRegex.test(tag.name) && valid(tag.name.replace(prefixRegex, ''))
)
.sort((a, b) =>
rcompare(a.name.replace(prefixRegex, ''), b.name.replace(prefixRegex, ''))
);
validTags.forEach((tag) => core.debug(`Found Valid Tag: ${tag.name}.`));
return validTags;
}
export async function getCommits(
baseRef: string,
headRef: string
): Promise<{ message: string; hash: string | null }[]> {
const commits = await compareCommits(baseRef, headRef);
return commits
.filter((commit) => !!commit.commit.message)
.map((commit) => ({
message: commit.commit.message,
hash: commit.sha,
}));
}
export function getBranchFromRef(ref: string) {
return ref.replace('refs/heads/', '');
}
export function isPr(ref: string) {
return ref.includes('refs/pull/');
}
export function getLatestTag(
tags: Tags,
prefixRegex: RegExp,
tagPrefix: string
) {
return (
tags.find(
(tag) =>
prefixRegex.test(tag.name) &&
!prerelease(tag.name.replace(prefixRegex, ''))
) || {
name: `${tagPrefix}0.0.0`,
commit: {
sha: 'HEAD',
},
}
);
}
export function getLatestPrereleaseTag(
tags: Tags,
identifier: string,
prefixRegex: RegExp
) {
return tags
.filter((tag) => prerelease(tag.name.replace(prefixRegex, '')))
.find((tag) => tag.name.replace(prefixRegex, '').match(identifier));
}
export function mapCustomReleaseRules(customReleaseTypes: string) {
const releaseRuleSeparator = ',';
const releaseTypeSeparator = ':';
return customReleaseTypes
.split(releaseRuleSeparator)
.filter((customReleaseRule) => {
const parts = customReleaseRule.split(releaseTypeSeparator);
if (parts.length < 2) {
core.warning(
`${customReleaseRule} is not a valid custom release definition.`
);
return false;
}
const defaultRule = defaultChangelogRules[parts[0].toLowerCase()];
if (customReleaseRule.length !== 3) {
core.debug(
`${customReleaseRule} doesn't mention the section for the changelog.`
);
core.debug(
defaultRule
? `Default section (${defaultRule.section}) will be used instead.`
: "The commits matching this rule won't be included in the changelog."
);
}
if (!DEFAULT_RELEASE_TYPES.includes(parts[1])) {
core.warning(`${parts[1]} is not a valid release type.`);
return false;
}
return true;
})
.map((customReleaseRule) => {
const [type, release, section] =
customReleaseRule.split(releaseTypeSeparator);
const defaultRule = defaultChangelogRules[type.toLowerCase()];
return {
type,
release,
section: section || defaultRule?.section,
};
});
}
export function mergeWithDefaultChangelogRules(
mappedReleaseRules: ReturnType<typeof mapCustomReleaseRules> = []
) {
const mergedRules = mappedReleaseRules.reduce(
(acc, curr) => ({
...acc,
[curr.type]: curr,
}),
{ ...defaultChangelogRules }
);
return Object.values(mergedRules).filter((rule) => !!rule.section);
}

876
tests/action.test.ts Normal file
View File

@ -0,0 +1,876 @@
import action from '../src/action';
import * as utils from '../src/utils';
import * as github from '../src/github';
import * as core from '@actions/core';
import {
loadDefaultInputs,
setBranch,
setCommitSha,
setInput,
setRepository,
} from './helper.test';
jest.spyOn(core, 'debug').mockImplementation(() => {});
jest.spyOn(core, 'info').mockImplementation(() => {});
jest.spyOn(console, 'info').mockImplementation(() => {});
beforeAll(() => {
setRepository('https://github.com', 'org/repo');
});
const mockCreateTag = jest
.spyOn(github, 'createTag')
.mockResolvedValue(undefined);
const mockSetOutput = jest
.spyOn(core, 'setOutput')
.mockImplementation(() => {});
const mockSetFailed = jest.spyOn(core, 'setFailed');
describe('github-tag-action', () => {
beforeEach(() => {
jest.clearAllMocks();
setBranch('master');
setCommitSha('79e0ea271c26aa152beef77c3275ff7b8f8d8274');
loadDefaultInputs();
});
describe('special cases', () => {
it('does create initial tag', async () => {
/*
* Given
*/
const commits = [{ message: 'fix: this is my first fix', hash: null }];
jest
.spyOn(utils, 'getCommits')
.mockImplementation(async (sha) => commits);
const validTags: any[] = [];
jest
.spyOn(utils, 'getValidTags')
.mockImplementation(async () => validTags);
/*
* When
*/
await action();
/*
* Then
*/
expect(mockCreateTag).toHaveBeenCalledWith(
'v0.0.1',
expect.any(Boolean),
expect.any(String)
);
expect(mockSetFailed).not.toBeCalled();
});
it('does create patch tag without commits', async () => {
/*
* Given
*/
const commits: any[] = [];
jest
.spyOn(utils, 'getCommits')
.mockImplementation(async (sha) => commits);
const validTags: any[] = [];
jest
.spyOn(utils, 'getValidTags')
.mockImplementation(async () => validTags);
/*
* When
*/
await action();
/*
* Then
*/
expect(mockCreateTag).toHaveBeenCalledWith(
'v0.0.1',
expect.any(Boolean),
expect.any(String)
);
expect(mockSetFailed).not.toBeCalled();
});
it('does not create tag without commits and default_bump set to false', async () => {
/*
* Given
*/
setInput('default_bump', 'false');
const commits: any[] = [];
jest
.spyOn(utils, 'getCommits')
.mockImplementation(async (sha) => commits);
const validTags = [
{
name: 'v1.2.3',
commit: { sha: '012345', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
];
jest
.spyOn(utils, 'getValidTags')
.mockImplementation(async () => validTags);
/*
* When
*/
await action();
/*
* Then
*/
expect(mockCreateTag).not.toBeCalled();
expect(mockSetFailed).not.toBeCalled();
});
it('does create tag using custom release types', async () => {
/*
* Given
*/
setInput('custom_release_rules', 'james:patch,bond:major');
const commits = [
{ message: 'james: is the new cool guy', hash: null },
{ message: 'bond: is his last name', hash: null },
];
jest
.spyOn(utils, 'getCommits')
.mockImplementation(async (sha) => commits);
const validTags = [
{
name: 'v1.2.3',
commit: { sha: '012345', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
];
jest
.spyOn(utils, 'getValidTags')
.mockImplementation(async () => validTags);
/*
* When
*/
await action();
/*
* Then
*/
expect(mockCreateTag).toHaveBeenCalledWith(
'v2.0.0',
expect.any(Boolean),
expect.any(String)
);
expect(mockSetFailed).not.toBeCalled();
});
it('does create tag using custom release types but non-custom commit message', async () => {
/*
* Given
*/
setInput('custom_release_rules', 'james:patch,bond:major');
const commits = [
{ message: 'fix: is the new cool guy', hash: null },
{ message: 'feat: is his last name', hash: null },
];
jest
.spyOn(utils, 'getCommits')
.mockImplementation(async (sha) => commits);
const validTags = [
{
name: 'v1.2.3',
commit: { sha: '012345', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
];
jest
.spyOn(utils, 'getValidTags')
.mockImplementation(async () => validTags);
/*
* When
*/
await action();
/*
* Then
*/
expect(mockCreateTag).toHaveBeenCalledWith(
'v1.3.0',
expect.any(Boolean),
expect.any(String)
);
expect(mockSetFailed).not.toBeCalled();
});
});
describe('release branches', () => {
beforeEach(() => {
jest.clearAllMocks();
setBranch('release');
setInput('release_branches', 'release');
});
it('does create patch tag', async () => {
/*
* Given
*/
const commits = [{ message: 'fix: this is my first fix', hash: null }];
jest
.spyOn(utils, 'getCommits')
.mockImplementation(async (sha) => commits);
const validTags = [
{
name: 'v1.2.3',
commit: { sha: '012345', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
];
jest
.spyOn(utils, 'getValidTags')
.mockImplementation(async () => validTags);
/*
* When
*/
await action();
/*
* Then
*/
expect(mockCreateTag).toHaveBeenCalledWith(
'v1.2.4',
expect.any(Boolean),
expect.any(String)
);
expect(mockSetFailed).not.toBeCalled();
});
it('does create minor tag', async () => {
/*
* Given
*/
const commits = [
{ message: 'feat: this is my first feature', hash: null },
];
jest
.spyOn(utils, 'getCommits')
.mockImplementation(async (sha) => commits);
const validTags = [
{
name: 'v1.2.3',
commit: { sha: '012345', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
];
jest
.spyOn(utils, 'getValidTags')
.mockImplementation(async () => validTags);
/*
* When
*/
await action();
/*
* Then
*/
expect(mockCreateTag).toHaveBeenCalledWith(
'v1.3.0',
expect.any(Boolean),
expect.any(String)
);
expect(mockSetFailed).not.toBeCalled();
});
it('does create major tag', async () => {
/*
* Given
*/
const commits = [
{
message:
'my commit message\nBREAKING CHANGE:\nthis is a breaking change',
hash: null,
},
];
jest
.spyOn(utils, 'getCommits')
.mockImplementation(async (sha) => commits);
const validTags = [
{
name: 'v1.2.3',
commit: { sha: '012345', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
];
jest
.spyOn(utils, 'getValidTags')
.mockImplementation(async () => validTags);
/*
* When
*/
await action();
/*
* Then
*/
expect(mockCreateTag).toHaveBeenCalledWith(
'v2.0.0',
expect.any(Boolean),
expect.any(String)
);
expect(mockSetFailed).not.toBeCalled();
});
it('does create tag when pre-release tag is newer', async () => {
/*
* Given
*/
const commits = [
{ message: 'feat: some new feature on a release branch', hash: null },
];
jest
.spyOn(utils, 'getCommits')
.mockImplementation(async (sha) => commits);
const validTags = [
{
name: 'v1.2.3',
commit: { sha: '012345', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
{
name: 'v2.1.3-prerelease.0',
commit: { sha: '678901', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
{
name: 'v2.1.3-prerelease.1',
commit: { sha: '234567', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
];
jest
.spyOn(utils, 'getValidTags')
.mockImplementation(async () => validTags);
/*
* When
*/
await action();
/*
* Then
*/
expect(mockCreateTag).toHaveBeenCalledWith(
'v2.2.0',
expect.any(Boolean),
expect.any(String)
);
expect(mockSetFailed).not.toBeCalled();
});
it('does create tag with custom release rules', async () => {
/*
* Given
*/
setInput('custom_release_rules', 'james:preminor');
const commits = [
{
message: 'feat: some new feature on a pre-release branch',
hash: null,
},
{ message: 'james: this should make a preminor', hash: null },
];
jest
.spyOn(utils, 'getCommits')
.mockImplementation(async (sha) => commits);
const validTags = [
{
name: 'v1.2.3',
commit: { sha: '012345', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
];
jest
.spyOn(utils, 'getValidTags')
.mockImplementation(async () => validTags);
/*
* When
*/
await action();
/*
* Then
*/
expect(mockCreateTag).toHaveBeenCalledWith(
'v1.3.0',
expect.any(Boolean),
expect.any(String)
);
expect(mockSetFailed).not.toBeCalled();
});
});
describe('pre-release branches', () => {
beforeEach(() => {
jest.clearAllMocks();
setBranch('prerelease');
setInput('pre_release_branches', 'prerelease');
});
it('does not create tag without commits and default_bump set to false', async () => {
/*
* Given
*/
setInput('default_prerelease_bump', 'false');
const commits: any[] = [];
jest
.spyOn(utils, 'getCommits')
.mockImplementation(async (sha) => commits);
const validTags = [
{
name: 'v1.2.3',
commit: { sha: '012345', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
];
jest
.spyOn(utils, 'getValidTags')
.mockImplementation(async () => validTags);
/*
* When
*/
await action();
/*
* Then
*/
expect(mockCreateTag).not.toBeCalled();
expect(mockSetFailed).not.toBeCalled();
});
it('does create prerelease tag', async () => {
/*
* Given
*/
setInput('default_prerelease_bump', 'prerelease');
const commits = [{ message: 'this is my first fix', hash: null }];
jest
.spyOn(utils, 'getCommits')
.mockImplementation(async (sha) => commits);
const validTags = [
{
name: 'v1.2.3',
commit: { sha: '012345', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
];
jest
.spyOn(utils, 'getValidTags')
.mockImplementation(async () => validTags);
/*
* When
*/
await action();
/*
* Then
*/
expect(mockCreateTag).toHaveBeenCalledWith(
'v1.2.4-prerelease.0',
expect.any(Boolean),
expect.any(String)
);
expect(mockSetFailed).not.toBeCalled();
});
it('does create prepatch tag', async () => {
/*
* Given
*/
const commits = [{ message: 'fix: this is my first fix', hash: null }];
jest
.spyOn(utils, 'getCommits')
.mockImplementation(async (sha) => commits);
const validTags = [
{
name: 'v1.2.3',
commit: { sha: '012345', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
];
jest
.spyOn(utils, 'getValidTags')
.mockImplementation(async () => validTags);
/*
* When
*/
await action();
/*
* Then
*/
expect(mockCreateTag).toHaveBeenCalledWith(
'v1.2.4-prerelease.0',
expect.any(Boolean),
expect.any(String)
);
expect(mockSetFailed).not.toBeCalled();
});
it('does create preminor tag', async () => {
/*
* Given
*/
const commits = [
{ message: 'feat: this is my first feature', hash: null },
];
jest
.spyOn(utils, 'getCommits')
.mockImplementation(async (sha) => commits);
const validTags = [
{
name: 'v1.2.3',
commit: { sha: '012345', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
];
jest
.spyOn(utils, 'getValidTags')
.mockImplementation(async () => validTags);
/*
* When
*/
await action();
/*
* Then
*/
expect(mockCreateTag).toHaveBeenCalledWith(
'v1.3.0-prerelease.0',
expect.any(Boolean),
expect.any(String)
);
expect(mockSetFailed).not.toBeCalled();
});
it('does create premajor tag', async () => {
/*
* Given
*/
const commits = [
{
message:
'my commit message\nBREAKING CHANGE:\nthis is a breaking change',
hash: null,
},
];
jest
.spyOn(utils, 'getCommits')
.mockImplementation(async (sha) => commits);
const validTags = [
{
name: 'v1.2.3',
commit: { sha: '012345', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
];
jest
.spyOn(utils, 'getValidTags')
.mockImplementation(async () => validTags);
/*
* When
*/
await action();
/*
* Then
*/
expect(mockCreateTag).toHaveBeenCalledWith(
'v2.0.0-prerelease.0',
expect.any(Boolean),
expect.any(String)
);
expect(mockSetFailed).not.toBeCalled();
});
it('does create tag when release tag is newer', async () => {
/*
* Given
*/
const commits = [
{
message: 'feat: some new feature on a pre-release branch',
hash: null,
},
];
jest
.spyOn(utils, 'getCommits')
.mockImplementation(async (sha) => commits);
const validTags = [
{
name: 'v1.2.3-prerelease.0',
commit: { sha: '012345', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
{
name: 'v3.1.2-feature.0',
commit: { sha: '012345', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
{
name: 'v2.1.4',
commit: { sha: '234567', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
];
jest
.spyOn(utils, 'getValidTags')
.mockImplementation(async () => validTags);
/*
* When
*/
await action();
/*
* Then
*/
expect(mockCreateTag).toHaveBeenCalledWith(
'v2.2.0-prerelease.0',
expect.any(Boolean),
expect.any(String)
);
expect(mockSetFailed).not.toBeCalled();
});
it('does create tag with custom release rules', async () => {
/*
* Given
*/
setInput('custom_release_rules', 'james:preminor');
const commits = [
{
message: 'feat: some new feature on a pre-release branch',
hash: null,
},
{ message: 'james: this should make a preminor', hash: null },
];
jest
.spyOn(utils, 'getCommits')
.mockImplementation(async (sha) => commits);
const validTags = [
{
name: 'v1.2.3',
commit: { sha: '012345', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
];
jest
.spyOn(utils, 'getValidTags')
.mockImplementation(async () => validTags);
/*
* When
*/
await action();
/*
* Then
*/
expect(mockCreateTag).toHaveBeenCalledWith(
'v1.3.0-prerelease.0',
expect.any(Boolean),
expect.any(String)
);
expect(mockSetFailed).not.toBeCalled();
});
});
describe('other branches', () => {
beforeEach(() => {
jest.clearAllMocks();
setBranch('development');
setInput('pre_release_branches', 'prerelease');
setInput('release_branches', 'release');
});
it('does output patch tag', async () => {
/*
* Given
*/
const commits = [{ message: 'fix: this is my first fix', hash: null }];
jest
.spyOn(utils, 'getCommits')
.mockImplementation(async (sha) => commits);
const validTags = [
{
name: 'v1.2.3',
commit: { sha: '012345', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
];
jest
.spyOn(utils, 'getValidTags')
.mockImplementation(async () => validTags);
/*
* When
*/
await action();
/*
* Then
*/
expect(mockSetOutput).toHaveBeenCalledWith('new_version', '1.2.4');
expect(mockCreateTag).not.toBeCalled();
expect(mockSetFailed).not.toBeCalled();
});
it('does output minor tag', async () => {
/*
* Given
*/
const commits = [
{ message: 'feat: this is my first feature', hash: null },
];
jest
.spyOn(utils, 'getCommits')
.mockImplementation(async (sha) => commits);
const validTags = [
{
name: 'v1.2.3',
commit: { sha: '012345', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
];
jest
.spyOn(utils, 'getValidTags')
.mockImplementation(async () => validTags);
/*
* When
*/
await action();
/*
* Then
*/
expect(mockSetOutput).toHaveBeenCalledWith('new_version', '1.3.0');
expect(mockCreateTag).not.toBeCalled();
expect(mockSetFailed).not.toBeCalled();
});
it('does output major tag', async () => {
/*
* Given
*/
const commits = [
{
message:
'my commit message\nBREAKING CHANGE:\nthis is a breaking change',
hash: null,
},
];
jest
.spyOn(utils, 'getCommits')
.mockImplementation(async (sha) => commits);
const validTags = [
{
name: 'v1.2.3',
commit: { sha: '012345', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
];
jest
.spyOn(utils, 'getValidTags')
.mockImplementation(async () => validTags);
/*
* When
*/
await action();
/*
* Then
*/
expect(mockSetOutput).toHaveBeenCalledWith('new_version', '2.0.0');
expect(mockCreateTag).not.toBeCalled();
expect(mockSetFailed).not.toBeCalled();
});
});
});

55
tests/github.test.ts Normal file
View File

@ -0,0 +1,55 @@
import { listTags } from '../src/github';
jest.mock(
'@actions/github',
jest.fn().mockImplementation(() => ({
context: { repo: { owner: 'mock-owner', repo: 'mock-repo' } },
getOctokit: jest.fn().mockReturnValue({
repos: {
listTags: jest.fn().mockImplementation(({ page }: { page: number }) => {
if (page === 6) {
return { data: [] };
}
const res = [...new Array(100).keys()].map((_) => ({
name: `v0.0.${_ + (page - 1) * 100}`,
commit: { sha: 'string', url: 'string' },
zipball_url: 'string',
tarball_url: 'string',
node_id: 'string',
}));
return { data: res };
}),
},
}),
}))
);
describe('github', () => {
it('returns all tags', async () => {
const tags = await listTags(true);
expect(tags.length).toEqual(500);
expect(tags[499]).toEqual({
name: 'v0.0.499',
commit: { sha: 'string', url: 'string' },
zipball_url: 'string',
tarball_url: 'string',
node_id: 'string',
});
});
it('returns only the last 100 tags', async () => {
const tags = await listTags(true);
expect(tags.length).toEqual(500);
expect(tags[99]).toEqual({
name: 'v0.0.99',
commit: { sha: 'string', url: 'string' },
zipball_url: 'string',
tarball_url: 'string',
node_id: 'string',
});
});
});

49
tests/helper.test.ts Normal file
View File

@ -0,0 +1,49 @@
import yaml from 'js-yaml';
import fs from 'fs';
import path from 'path';
export function setRepository(
GITHUB_SERVER_URL: string,
GITHUB_REPOSITORY: string
) {
process.env['GITHUB_SERVER_URL'] = GITHUB_SERVER_URL;
process.env['GITHUB_REPOSITORY'] = GITHUB_REPOSITORY;
}
export function setBranch(branch: string) {
process.env['GITHUB_REF'] = `refs/heads/${branch}`;
}
export function setCommitSha(sha: string) {
process.env['GITHUB_SHA'] = sha;
}
export function setInput(key: string, value: string) {
process.env[`INPUT_${key.toUpperCase()}`] = value;
}
export function setInputs(map: { [key: string]: string }) {
Object.keys(map).forEach((key) => setInput(key, map[key]));
}
export function loadDefaultInputs() {
const actionYaml = fs.readFileSync(
path.join(process.cwd(), 'action.yml'),
'utf-8'
);
const actionJson = yaml.load(actionYaml) as {
inputs: { [key: string]: { default?: string } };
};
const defaultInputs = Object.keys(actionJson['inputs'])
.filter((key) => actionJson['inputs'][key].default)
.reduce(
(obj, key) => ({ ...obj, [key]: actionJson['inputs'][key].default }),
{}
);
setInputs(defaultInputs);
}
// Don't know how to have this file only for test but not have 'tsc' complain. So I made it a test file...
describe('helper', () => {
it('works', () => {});
});

301
tests/utils.test.ts Normal file
View File

@ -0,0 +1,301 @@
import * as utils from '../src/utils';
import { getValidTags } from '../src/utils';
import * as core from '@actions/core';
import * as github from '../src/github';
import { defaultChangelogRules } from '../src/defaults';
jest.spyOn(core, 'debug').mockImplementation(() => {});
jest.spyOn(core, 'warning').mockImplementation(() => {});
const regex = /^v/;
describe('utils', () => {
it('extracts branch from ref', () => {
/*
* Given
*/
const remoteRef = 'refs/heads/master';
/*
* When
*/
const branch = utils.getBranchFromRef(remoteRef);
/*
* Then
*/
expect(branch).toEqual('master');
});
it('test if ref is PR', () => {
/*
* Given
*/
const remoteRef = 'refs/pull/123/merge';
/*
* When
*/
const isPullRequest = utils.isPr(remoteRef);
/*
* Then
*/
expect(isPullRequest).toEqual(true);
});
it('returns valid tags', async () => {
/*
* Given
*/
const testTags = [
{
name: 'release-1.2.3',
commit: { sha: 'string', url: 'string' },
zipball_url: 'string',
tarball_url: 'string',
node_id: 'string',
},
{
name: 'v1.2.3',
commit: { sha: 'string', url: 'string' },
zipball_url: 'string',
tarball_url: 'string',
node_id: 'string',
},
];
const mockListTags = jest
.spyOn(github, 'listTags')
.mockImplementation(async () => testTags);
/*
* When
*/
const validTags = await getValidTags(regex, false);
/*
* Then
*/
expect(mockListTags).toHaveBeenCalled();
expect(validTags).toHaveLength(1);
});
it('returns sorted tags', async () => {
/*
* Given
*/
const testTags = [
{
name: 'v1.2.4-prerelease.1',
commit: { sha: 'string', url: 'string' },
zipball_url: 'string',
tarball_url: 'string',
node_id: 'string',
},
{
name: 'v1.2.4-prerelease.2',
commit: { sha: 'string', url: 'string' },
zipball_url: 'string',
tarball_url: 'string',
node_id: 'string',
},
{
name: 'v1.2.4-prerelease.0',
commit: { sha: 'string', url: 'string' },
zipball_url: 'string',
tarball_url: 'string',
node_id: 'string',
},
{
name: 'v1.2.3',
commit: { sha: 'string', url: 'string' },
zipball_url: 'string',
tarball_url: 'string',
node_id: 'string',
},
];
const mockListTags = jest
.spyOn(github, 'listTags')
.mockImplementation(async () => testTags);
/*
* When
*/
const validTags = await getValidTags(regex, false);
/*
* Then
*/
expect(mockListTags).toHaveBeenCalled();
expect(validTags[0]).toEqual({
name: 'v1.2.4-prerelease.2',
commit: { sha: 'string', url: 'string' },
zipball_url: 'string',
tarball_url: 'string',
node_id: 'string',
});
});
it('returns only prefixed tags', async () => {
/*
* Given
*/
const testTags = [
{
name: 'app2/5.0.0',
commit: { sha: 'string', url: 'string' },
zipball_url: 'string',
tarball_url: 'string',
node_id: 'string',
},
{
name: '7.0.0',
commit: { sha: 'string', url: 'string' },
zipball_url: 'string',
tarball_url: 'string',
node_id: 'string',
},
{
name: 'app1/3.0.0',
commit: { sha: 'string', url: 'string' },
zipball_url: 'string',
tarball_url: 'string',
node_id: 'string',
},
];
const mockListTags = jest
.spyOn(github, 'listTags')
.mockImplementation(async () => testTags);
/*
* When
*/
const validTags = await getValidTags(/^app1\//, false);
/*
* Then
*/
expect(mockListTags).toHaveBeenCalled();
expect(validTags).toHaveLength(1);
expect(validTags[0]).toEqual({
name: 'app1/3.0.0',
commit: { sha: 'string', url: 'string' },
zipball_url: 'string',
tarball_url: 'string',
node_id: 'string',
});
});
describe('custom release types', () => {
it('maps custom release types', () => {
/*
* Given
*/
const customReleasesString =
'james:preminor,bond:premajor,007:major:Breaking Changes,feat:minor';
/*
* When
*/
const mappedReleases = utils.mapCustomReleaseRules(customReleasesString);
/*
* Then
*/
expect(mappedReleases).toEqual([
{ type: 'james', release: 'preminor' },
{ type: 'bond', release: 'premajor' },
{ type: '007', release: 'major', section: 'Breaking Changes' },
{
type: 'feat',
release: 'minor',
section: defaultChangelogRules['feat'].section,
},
]);
});
it('filters out invalid custom release types', () => {
/*
* Given
*/
const customReleasesString = 'james:pre-release,bond:premajor';
/*
* When
*/
const mappedReleases = utils.mapCustomReleaseRules(customReleasesString);
/*
* Then
*/
expect(mappedReleases).toEqual([{ type: 'bond', release: 'premajor' }]);
});
});
describe('method: mergeWithDefaultChangelogRules', () => {
it('combines non-existing type rules with default rules', () => {
/**
* Given
*/
const newRule = {
type: 'james',
release: 'major',
section: '007 Changes',
};
/**
* When
*/
const result = utils.mergeWithDefaultChangelogRules([newRule]);
/**
* Then
*/
expect(result).toEqual([
...Object.values(defaultChangelogRules),
newRule,
]);
});
it('overwrites existing default type rules with provided rules', () => {
/**
* Given
*/
const newRule = {
type: 'feat',
release: 'minor',
section: '007 Changes',
};
/**
* When
*/
const result = utils.mergeWithDefaultChangelogRules([newRule]);
const overWrittenRule = result.find((rule) => rule.type === 'feat');
/**
* Then
*/
expect(overWrittenRule?.section).toBe(newRule.section);
});
it('returns only the rules having changelog section', () => {
/**
* Given
*/
const mappedReleaseRules = [
{ type: 'james', release: 'major', section: '007 Changes' },
{ type: 'bond', release: 'minor', section: undefined },
];
/**
* When
*/
const result = utils.mergeWithDefaultChangelogRules(mappedReleaseRules);
/**
* Then
*/
expect(result).toContainEqual(mappedReleaseRules[0]);
expect(result).not.toContainEqual(mappedReleaseRules[1]);
});
});
});

View File

@ -1,63 +1,11 @@
{
"compilerOptions": {
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"target": "es6",
"module": "commonjs", /* Concatenate and emit output to single file. */
"outDir": "./lib", /* Redirect output structure to the directory. */
"rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
"noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
"rootDir": "./src",
"strict": true,
"esModuleInterop": true
},
"exclude": ["node_modules", "**/*.test.ts"]
}

51
types/semantic.d.ts vendored Normal file
View File

@ -0,0 +1,51 @@
/// <reference types="semver" />
declare module '@semantic-release/commit-analyzer' {
export function analyzeCommits(
config: {
preset?: string;
config?: string;
parserOpts?: any;
releaseRules?:
| string
| {
type: string;
release: string;
scope?: string;
}[];
presetConfig?: string;
},
args: {
commits: { message: string; hash: string | null }[];
logger: { log: (args: any) => void };
}
): Promise<any>;
}
declare module '@semantic-release/release-notes-generator' {
export function generateNotes(
config: {
preset?: string;
config?: string;
parserOpts?: any;
writerOpts?: any;
releaseRules?:
| string
| {
type: string;
release: string;
scope?: string;
}[];
presetConfig?: any; // Depends on used preset
},
args: {
commits: { message: string; hash: string | null }[];
logger: { log: (args: any) => void };
options: {
repositoryUrl: string;
};
lastRelease: { gitTag: string };
nextRelease: { gitTag: string; version: string };
}
): Promise<string>;
}