Skip to content

Commit

Permalink
BREAKING: rewrite action
Browse files Browse the repository at this point in the history
  • Loading branch information
boywithkeyboard committed Mar 16, 2024
1 parent 9c3dab2 commit 38d68ac
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 285 deletions.
318 changes: 33 additions & 285 deletions src/action.ts
Original file line number Diff line number Diff line change
@@ -1,306 +1,54 @@
import { getBooleanInput, getInput, setFailed, setOutput } from '@actions/core'
import { context, getOctokit } from '@actions/github'
import indentString from 'indent-string'
import semver from 'semver'
import { config } from './config'
import { existsSync, readFileSync } from 'node:fs'
import { setOutput } from '@actions/core'

async function action() {
const config = {
token: getInput('token'),
kind: getInput('kind', { required: true }),
draft: getBooleanInput('draft'),
includeAuthor: getBooleanInput('include_author'),
includeDescription: getBooleanInput('include_description'),
prereleasePrefix: getInput('prerelease_prefix'),
mentionContributors: getBooleanInput('mention_contributors'),
}

const { rest } = getOctokit(config.token)

// const fetchChangelog = async () => {
// try {
// const { data } = await rest.repos.getContent({
// ...context.repo,
// path: 'changelog.md',
// })

// // @ts-ignore:
// return [data.sha, await readFile('changelog.md', { encoding: 'utf-8' })]
// } catch (err) {
// return [null, '']
// }
// }

const d = new Date()

d.setDate(d.getDate() - 365)

let latestRelease: {
tag_name: string
created_at: string
[key: string]: unknown
} = {
tag_name: 'v0.0.0',
created_at: d.toString(),
}
export async function action() {
const { rest } = getOctokit(config().token)

try {
const result = await rest.repos.listReleases({
...context.repo,
})
let tag = config().tag

if (
result.status === 200 && result.data instanceof Array &&
result.data.length > 0
) {
latestRelease = result.data[0]
if (!tag) {
if (/^refs\/tags\/[^\/]+$/.test(context.ref) === false) {
throw new Error('Invalid context ref: ' + context.ref)
}
} catch (err) {}

let currentVersion = latestRelease?.tag_name ?? 'v0.0.0'
let nextVersion = 'v'

if (config.kind === 'prepatch') {
nextVersion += semver.prerelease(currentVersion)
? semver.inc(
currentVersion,
'prerelease',
undefined,
config.prereleasePrefix,
)
: semver.inc(
currentVersion,
'prepatch',
undefined,
config.prereleasePrefix,
)
} else if (config.kind === 'patch') {
nextVersion += semver.inc(currentVersion, 'patch')
} else if (config.kind === 'preminor') {
nextVersion += semver.prerelease(currentVersion)
? semver.inc(
currentVersion,
'prerelease',
undefined,
config.prereleasePrefix,
)
: semver.inc(
currentVersion,
'preminor',
undefined,
config.prereleasePrefix,
)
} else if (config.kind === 'minor') {
nextVersion += semver.inc(currentVersion, 'minor')
} else if (config.kind === 'premajor') {
nextVersion += semver.prerelease(currentVersion)
? semver.inc(
currentVersion,
'prerelease',
undefined,
config.prereleasePrefix,
)
: semver.inc(
currentVersion,
'premajor',
undefined,
config.prereleasePrefix,
)
} else if (config.kind === 'major') {
nextVersion += semver.inc(currentVersion, 'major')
} else {
throw new Error('Invalid kind.')
tag = context.ref.replace('refs/tags/', '')
}

console.info(
`previous release - ${latestRelease?.tag_name} (${latestRelease?.created_at})`,
)

let { data } = await rest.pulls.list({
...context.repo,
per_page: 100,
sort: 'updated',
state: 'closed',
direction: 'desc',
})

data = [
...data,
...(await rest.pulls.list({
...context.repo,
per_page: 100,
sort: 'updated',
state: 'closed',
direction: 'desc',
page: 2,
})).data,
]

const year = new Date().getUTCFullYear(),
month = new Date().getUTCMonth() + 1,
day = new Date().getUTCDate()

// let changelogBody =
// `## [${tag}](https://github.com/${context.repo.owner}/${context.repo.repo}/releases/tag/${tag})\n`,
let releaseBody = `### ${nextVersion} / ${year}.${
month < 10 ? `0${month}` : month
}.${day < 10 ? `0${day}` : day}\n`

data.sort((a, b) => {
const x = a.title.toLowerCase(),
y = b.title.toLowerCase()

if (x < y) {
return -1
}

if (x > y) {
return 1
}

return 0
})

const contributors = new Set<string>()

for (const { user, merged_at, number, body, merge_commit_sha } of data) {
if (
merged_at === null || user?.type === 'Bot' || merge_commit_sha === null
) {
continue
}

if (
latestRelease && new Date(latestRelease.created_at).getTime() >=
new Date(merged_at).getTime()
) {
continue
}

const c = await rest.repos.getCommit({
...context.repo,
ref: merge_commit_sha,
})
let changelogPath: string | undefined

if (c.status !== 200) {
continue
}

if (
latestRelease && c.data.commit.committer?.date &&
new Date(c.data.commit.committer?.date).getTime() <=
new Date(latestRelease.created_at).getTime()
) {
continue
}

const linkifyReferences = (commit: string) => {
const issueRegex =
/(?<!\w)(?:(?<organization>[a-z\d](?:[a-z\d-]{0,37}[a-z\d])?)\/(?<repository>[\w.-]{1,100}))?(?<!(?:\/\.{1,2}))#(?<issueNumber>[1-9]\d{0,9})\b/g

const matches = commit.match(issueRegex)

if (!matches) {
return commit
}

for (const m of matches) {
commit = commit.replace(
`(${m})`,
`([${m}](https://github.com/${context.repo.owner}/${context.repo.repo}/pull/${
m.slice(1)
}))`,
)
}

return commit
}

const i = c.data.commit.message.indexOf(')\n\n')
let title = c.data.commit.message.substring(0, i > 0 ? i + 1 : undefined)

const comments = (await rest.issues.listComments({
...context.repo,
issue_number: number,
})).data

if (
comments.length > 0 &&
comments.some((c) =>
c.body !== undefined && c.body === '?log ignore' &&
(c.author_association === 'COLLABORATOR' ||
c.author_association === 'MEMBER' || c.author_association === 'OWNER')
)
) {
continue
}

title = linkifyReferences(title)
title = title.replace(': ', ': **').replace(' ([#', '** ([#')
if (existsSync('./changelog.md')) {
changelogPath = './changelog.md'
} else if (existsSync('./CHANGELOG.md')) {
changelogPath = './CHANGELOG.md'
}

// changelogBody += `\n* ${linkifyReferences(title)}`
if (!changelogPath) {
throw new Error('No changelog found.')
}

releaseBody += `\n* ${title}`
let changelog = readFileSync(changelogPath, { encoding: 'utf-8' })

if (config.includeAuthor && user?.login) {
// changelogBody += user?.login
// ? ` by [@${user?.login}](https://github.com/${user?.login})`
// : ''
const startIndex = changelog.indexOf(`## [${tag}]`) + `## [${tag}](https://github.com/${context.repo.owner}/${context.repo.repo}/releases/tag/${tag})\n\n`.length

contributors.add(`, @${user.login}`)
releaseBody += ` by @${user.login}`
}

if (config.includeDescription && body !== null && body.length > 0) {
// changelogBody += `\n\n${indentString(body, 2)}\n`
releaseBody += `\n\n${indentString(body, 2)}\n`
}
}
changelog = changelog.substring(startIndex)

if (config.mentionContributors) {
const arr = [...contributors.values()]
const endIndex = changelog.indexOf('\n\n## [')

arr[0] = arr[0].replace(', ', '')
arr[arr.length - 1] = arr.length > 2
? arr[arr.length - 1].replace(', ', ', & ')
: arr[arr.length - 1].replace(', ', ' & ')
changelog = changelog.substring(0, endIndex < 0 ? undefined : endIndex)

releaseBody += `\n\nContributed by ${arr.join('')}`
}

const { data: release } = await rest.repos.createRelease({
const { data } = await rest.repos.createRelease({
owner: context.repo.owner,
repo: context.repo.repo,
tag_name: nextVersion,
name: nextVersion,
body: releaseBody,
draft: config.draft,
prerelease: config.kind.startsWith('pre'),
target_commitish: context.sha,
tag_name: tag,
name: tag,
body: changelog,
draft: config().draft,
prerelease: config().prerelease
})

// const [sha, content] = await fetchChangelog()

// await rest.repos.createOrUpdateFileContents({
// ...context.repo,
// path: 'changelog.md',
// content: Buffer.from(
// `${changelogBody}${content === '' ? '\n' : `\n\n${content}`}`,
// ).toString('base64'),
// message: getInput('commit_message').replace('{tag}', tag),
// ...(sha !== null && { sha }),
// })

setOutput('release_id', release.id)
setOutput('tag_name', nextVersion)
setOutput('created_at', release.created_at)
// setOutput('release_body', releaseBody)
// setOutput('changelog_body', changelogBody)
}

try {
action()
} catch (err) {
setFailed(
err instanceof Error ? err.message : 'Something unexpected happened.',
)
setOutput('release_id', data.id)
setOutput('tag_name', data.tag_name)
setOutput('created_at', data.created_at)
}
25 changes: 25 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { getBooleanInput, getInput } from '@actions/core'

type Config = {
token: string
draft: boolean
prerelease: boolean
tag: string | null
}

let CONFIG: Config | undefined

export function config() {
if (CONFIG) {
return CONFIG
}

CONFIG = {
token: getInput('token'),
draft: getBooleanInput('draft'),
prerelease: getBooleanInput('prerelease'),
tag: getInput('tag') === '<tag>' ? null : getInput('tag')
}

return CONFIG
}
12 changes: 12 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { setFailed } from '@actions/core'
import { action } from './action'

try {
action()
} catch (err) {
setFailed(
err instanceof Error
? err.message
: 'Something unexpected happened.'
)
}

0 comments on commit 38d68ac

Please sign in to comment.