Skip to content

Commit

Permalink
feat: initial release
Browse files Browse the repository at this point in the history
  • Loading branch information
NGPixel committed Feb 16, 2022
1 parent ba9eee9 commit b9fffa2
Show file tree
Hide file tree
Showing 9 changed files with 2,080 additions and 0 deletions.
12 changes: 12 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

[*.md]
trim_trailing_whitespace = false
4 changes: 4 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"root": true,
"extends": "standard"
}
56 changes: 56 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: Deploy

on:
push:
tags:
- v[0-9]+.[0-9]+.[0-9]+

jobs:
deploy:
runs-on: ubuntu-latest

steps:
- name: Checkout Code
uses: actions/checkout@v2
if: ${{ !env.ACT }}

- name: Update CHANGELOG
if: ${{ !env.ACT }}
id: changelog
uses: ./
with:
token: ${{ github.token }}
tag: ${{ github.ref_name }}

- name: Create Release
if: ${{ !env.ACT }}
uses: ncipollo/release-action@v1
with:
allowUpdates: true
draft: false
name: ${{ github.ref_name }}
body: ${{ steps.changelog.outputs.changes }}
token: ${{ github.token }}

- name: Commit CHANGELOG.md
if: ${{ !env.ACT }}
uses: stefanzweifel/git-auto-commit-action@v4
with:
branch: main
commit_message: 'docs: update CHANGELOG.md for ${{ github.ref_name }} [skip ci]'
file_pattern: CHANGELOG.md

# LOCAL TEST

- name: (local) Checkout Code
uses: actions/checkout@v2
if: ${{ env.ACT }}
with:
path: changelog-action

- name: (local) Update CHANGELOG
if: ${{ env.ACT }}
uses: ./
with:
token: ${{ github.token }}
tag: ${{ env.GITHUB_REF_NAME }}
2 changes: 2 additions & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
save-exact = true
save-prefix = ""
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"yaml.schemas": {
"https://json.schemastore.org/github-workflow.json": "file:///x%3A/ietf/semver-action/.github/workflows/deploy.yml"
}
}
22 changes: 22 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: 'Semver Conventional Commits'
description: 'Calculate the next release version based on conventional commits since latest tag'
author: Nicolas Giard
inputs:
token:
description: GitHub Token
required: true
branch:
description: The branch to use when fetching list of commits to compare against
required: false
default: main
outputs:
next:
description: Next version number in format v0.0.0
nextStrict:
description: Next version number without the v prefix
runs:
using: 'node12'
main: 'dist/index.js'
branding:
icon: fast-forward
color: red
129 changes: 129 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
const github = require('@actions/github')
const core = require('@actions/core')
const _ = require('lodash')
const cc = require('@conventional-commits/parser')
const semver = require('semver')

const bumpTypes = {
major: [],
minor: ['feat', 'feature'],
patch: ['fix', 'bugfix', 'perf', 'refactor', 'test', 'tests']
}

async function main () {
const token = core.getInput('token')
const branch = core.getInput('branch')
const gh = github.getOctokit(token)
const owner = github.context.repo.owner
const repo = github.context.repo.repo

// GET LATEST + PREVIOUS TAGS

const tagsRaw = await gh.graphql(`
query lastTags ($owner: String!, $repo: String!) {
repository (owner: $owner, name: $repo) {
refs(first: 1, refPrefix: "refs/tags/", orderBy: { field: TAG_COMMIT_DATE, direction: DESC }) {
nodes {
name
target {
oid
}
}
}
}
}
`, {
owner,
repo
})

const latestTag = _.get(tagsRaw, 'repository.refs.nodes[0]')

if (!latestTag) {
return core.setFailed('Couldn\'t find the latest tag. Make sure you have at least one tag created first.')
}

core.info(`Comparing against latest tag: ${latestTag.name}`)

// GET COMMITS

let curPage = 0
let totalCommits = 0
let hasMoreCommits = false
const commits = []
do {
hasMoreCommits = false
curPage++
const commitsRaw = await gh.rest.repos.compareCommitsWithBasehead({
owner,
repo,
basehead: `${latestTag.name}...${branch}`,
page: curPage,
per_page: 100
})
totalCommits = _.get(commitsRaw, 'data.total_commits', 0)
const rangeCommits = _.get(commitsRaw, 'data.commits', [])
commits.push(...rangeCommits)
if ((curPage - 1) * 100 + rangeCommits.length < totalCommits) {
hasMoreCommits = true
}
} while (hasMoreCommits)

if (!commits || commits.length < 1) {
return core.setFailed('Couldn\'t find any commits between HEAD and latest tag.')
}

// PARSE COMMITS

let majorChanges = 0
let minorChanges = 0
let patchChanges = 0
for (const commit of commits) {
try {
const cAst = cc.toConventionalChangelogFormat(cc.parser(commit.commit.message))
if (bumpTypes.major.includes(cAst.type)) {
majorChanges++
core.info(`[MAJOR] Commit ${commit.sha} of type ${cAst.type} will cause a major version bump.`)
} else if (bumpTypes.minor.includes(cAst.type)) {
minorChanges++
core.info(`[MINOR] Commit ${commit.sha} of type ${cAst.type} will cause a minor version bump.`)
} else if (bumpTypes.patch.includes(cAst.type)) {
patchChanges++
core.info(`[PATCH] Commit ${commit.sha} of type ${cAst.type} will cause a patch version bump.`)
} else {
core.info(`[SKIP] Commit ${commit.sha} of type ${cAst.type} will not cause any version bump.`)
}
for (const note of cAst.notes) {
if (note.title === 'BREAKING CHANGE') {
majorChanges++
core.info(`[MAJOR] Commit ${commit.sha} has a BREAKING CHANGE mention, causing a major version bump.`)
}
}
} catch (err) {
core.info(`[INVALID] Skipping commit ${commit.sha} as it doesn't follow conventional commit format.`)
}
}

let bump = null
if (majorChanges > 0) {
bump = 'major'
} else if (minorChanges > 0) {
bump = 'minor'
} else if (patchChanges > 0) {
bump = 'patch'
} else {
return core.setFailed('No commit resulted in a version bump since last release!')
}
core.info(`\n>>> Will bump version ${latestTag.name} using ${bump.toUpperCase()}\n`)

// BUMP VERSION

const next = semver.inc(latestTag.name, bump)

core.info(`Next version is v${next}`)

core.exportVariable('next', `v${next}`)
core.exportVariable('nextStrict', next)
}

main()
35 changes: 35 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "semver-action",
"version": "1.0.0",
"description": "GitHub Action to calculate the next release version based conventional commits since latest tag",
"main": "dist/index.js",
"scripts": {
"build": "ncc build index.js -o dist"
},
"repository": {
"type": "git",
"url": "git+https://github.com/ietf-tools/semver-action.git"
},
"author": "IETF Trust",
"license": "ISC",
"bugs": {
"url": "https://github.com/ietf-tools/semver-action/issues"
},
"homepage": "https://github.com/ietf-tools/semver-action#readme",
"dependencies": {
"@actions/core": "1.6.0",
"@actions/github": "5.0.0",
"@conventional-commits/parser": "0.4.1",
"conventional-recommended-bump": "6.1.0",
"lodash": "4.17.21",
"semver": "7.3.5"
},
"devDependencies": {
"@vercel/ncc": "0.33.3",
"eslint": "8.9.0",
"eslint-config-standard": "16.0.3",
"eslint-plugin-import": "2.25.4",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-promise": "6.0.0"
}
}
Loading

0 comments on commit b9fffa2

Please sign in to comment.