Skip to content

Commit

Permalink
feat: generate changelog file
Browse files Browse the repository at this point in the history
  • Loading branch information
ReenigneArcher committed Oct 29, 2023
1 parent 361a8a8 commit 436b27f
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 13 deletions.
15 changes: 13 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,22 @@ jobs:
id: vars
run: |
if [ "${{ github.event_name }}" == "pull_request" ]; then
changelog_branch=pr-changelogs
changelog_file=PR-${{ github.event.pull_request.number }}-CHANGELOG.md
discussion_category=tests
publish_pre_release=true
release_tag=pr-${{ github.event.pull_request.number }}-${{ github.run_id }}
else
changelog_branch=changelog
changelog_file=CHANGELOG.md
discussion_category=announcements
publish_pre_release=${{ steps.setup-release.outputs.publish_pre_release }}
release_tag=${{ steps.setup-release.outputs.release_tag }}
fi
# set outputs
echo "changelog_branch=$changelog_branch" >> $GITHUB_OUTPUT
echo "changelog_file=$changelog_file" >> $GITHUB_OUTPUT
echo "discussion_category=$discussion_category" >> $GITHUB_OUTPUT
echo "publish_stable_release=$publish_stable_release" >> $GITHUB_OUTPUT
echo "release_tag=$release_tag" >> $GITHUB_OUTPUT
Expand All @@ -57,21 +63,26 @@ jobs:
allowUpdates: false
artifacts: ''
body: ''
changelogBranch: ${{ steps.vars.outputs.changelog_branch }}
changelogFile: ${{ steps.vars.outputs.changelog_file }}
discussionCategory: ${{ steps.vars.outputs.discussion_category }}
generateReleaseNotes: true
name: ${{ steps.vars.outputs.release_tag }}
prerelease: ${{ steps.vars.outputs.publish_pre_release == 'true' }}
tag: ${{ steps.vars.outputs.release_tag }}
token: ${{ secrets.GH_BOT_TOKEN }}

- name: Print changelog
run: |
echo "${{ steps.action.outputs.changelog }}"
- name: Sleep
if: ${{ always() && github.event_name == 'pull_request' }}
run: sleep 60

- name: Delete Release
env:
GITHUB_TOKEN: ${{ secrets.GH_BOT_TOKEN }}
if: ${{ always() && github.event_name == 'pull_request' }}
uses: dev-drprasad/delete-tag-and-release@v1.0.1
with:
github_token: ${{ secrets.GH_BOT_TOKEN }}
tag_name: ${{ steps.vars.outputs.release_tag }}
31 changes: 20 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,26 @@ steps:
## Inputs
| Name | Description | Default | Required |
|----------------------|--------------------------------------------------------------------------------------|-----------------|----------|
| allowUpdates | An optional flag which indicates if we should update a release if it already exists. | `true` | `false` |
| artifacts | The artifacts to upload. | `*artifacts/*` | `false` |
| body | The body of the release. | | `false` |
| discussionCategory | The category for the discussion. | `announcements` | `false` |
| generateReleaseNotes | Indicates if release notes should be automatically generated. | `false` | `false` |
| name | The version to create. | | `true` |
| prerelease | Whether the release is a prerelease. | `false` | `false` |
| tag | The tag to create. | | `true` |
| token | GitHub Token. | | `true` |
| Name | Description | Default | Required |
|----------------------|---------------------------------------------------------------------------------------------------|-----------------|----------|
| allowUpdates | An optional flag which indicates if we should update a release if it already exists. | `true` | `false` |
| artifacts | The artifacts to upload. | `*artifacts/*` | `false` |
| body | The body of the release. | | `false` |
| changelog | Whether to create a changelog file. The changelog will be generated from the GitHub releases API. | `true` | `false` |
| changelogBranch | The branch to store the changelog in. | `changelog` | `false` |
| changelogFile | The file to store the changelog in. | `CHANGELOG.md` | `false` |
| discussionCategory | The category for the discussion. | `announcements` | `false` |
| generateReleaseNotes | Indicates if release notes should be automatically generated. | `false` | `false` |
| name | The version to create. | | `true` |
| prerelease | Whether the release is a prerelease. | `false` | `false` |
| tag | The tag to create. | | `true` |
| token | GitHub Token. | | `true` |

## Outputs

| Name | Description |
|-----------|------------------------------------------|
| changelog | The contents of the generated changelog. |

## See Also

Expand Down
155 changes: 155 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ inputs:
description: 'The body of the release.'
required: false
default: ''
changelog:
description: 'Whether to create a changelog file.'
required: false
default: 'true'
changelogBranch:
description: 'The branch to store the changelog in.'
required: false
default: 'changelog'
changelogFile:
description: 'The file to store the changelog in.'
required: false
default: 'CHANGELOG.md'
discussionCategory:
description: 'The category of the discussion.'
required: false
Expand Down Expand Up @@ -57,3 +69,146 @@ runs:
prerelease: ${{ inputs.prerelease }}
tag: ${{ inputs.tag }}
token: ${{ inputs.token }}

- name: Create Changelog
env:
changelog_branch: ${{ inputs.changelogBranch }}
changelog_file: ${{ inputs.changelogFile }}
if: >-
inputs.changelog == 'true' &&
(github.repository == 'LizardByte/create-release-action' ||
(github.event_name == 'push' && github.ref == 'refs/heads/master'))
uses: actions/github-script@v6
with:
github-token: ${{ inputs.token }}
script: |
// get inputs
const changelogBranch = process.env.changelog_branch
const changelogFile = process.env.changelog_file
// get all releases and sort by date created, page if required
let releases = []
let page = 1
let per_page = 100
let total = 0
do {
const response = await github.rest.repos.listReleases({
owner: context.repo.owner,
repo: context.repo.repo,
per_page: per_page,
page: page
})
releases = releases.concat(response.data)
total = response.data.length
page++
} while (total == per_page)
// sort releases by date created
releases.sort((a, b) => {
return new Date(a.created_at) - new Date(b.created_at)
})
// create a CHANGELOG.md and initialize it
let changelog = '# Changelog\n\n'
changelog += 'All notable changes to this project will be documented in this file.\n\n'
changelog += 'The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\n'
changelog += 'and this project adheres to [Calendar Versioning](https://calver.org/).\n\n'
changelog += 'This changelog was automatically generated by the\n'
changelog += '[create-release-action](https://github.com/LizardByte/create-release-action).\n\n'
// loop through each release
releases = releases.reverse()
for (const release of releases) {
// add release to changelog
let created_date = new Date(release.created_at)
let year = created_date.getFullYear()
let month = (created_date.getMonth() + 1).toString().padStart(2, '0')
let day = created_date.getDate().toString().padStart(2, '0')
let date = `${year}-${month}-${day}`
changelog += `## [${release.tag_name}] - ${date}\n\n${release.body.replace('## ', '### ')}\n\n`
}
// add urls to end of changelog
for (const release of releases) {
// add release url to changelog
changelog += `[${release.tag_name}]: ${release.html_url}\n`
}
try {
// Directly create a tree with CHANGELOG.md in it
const blob = await github.rest.git.createBlob({
owner: context.repo.owner,
repo: context.repo.repo,
content: changelog,
encoding: 'utf-8'
})
const tree = await github.rest.git.createTree({
owner: context.repo.owner,
repo: context.repo.repo,
tree: [{
path: changelogFile,
mode: '100644',
type: 'blob',
sha: blob.data.sha
}]
})
const commit = await github.rest.git.createCommit({
owner: context.repo.owner,
repo: context.repo.repo,
message: `chore: create ${changelogFile}`,
tree: tree.data.sha,
parents: [] // Empty parents array for a truly orphaned commit
})
await github.rest.git.createRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: `refs/heads/${changelogBranch}`,
sha: commit.data.sha
})
} catch (e) {
if (e.status === 422 && e.message.includes("Reference already exists")) {
let sha = null; // Initialize the sha to null by default
// Branch already exists, try to fetch the SHA of the specified changelogFile
try {
const fileData = await github.rest.repos.getContent({
owner: context.repo.owner,
repo: context.repo.repo,
path: changelogFile,
ref: changelogBranch
});
sha = fileData.data.sha; // Update the sha if the file exists
} catch (getFileError) {
if (getFileError.status !== 404) {
// If the error is not a 'not found' error, set the action as failed
core.setFailed(`Failed to fetch the file: ${getFileError.message}`);
return;
}
// If the error is 'not found' error, we'll continue with sha as null, resulting in file creation
}
try {
// Create or Update the file using the same call
await github.rest.repos.createOrUpdateFileContents({
owner: context.repo.owner,
repo: context.repo.repo,
path: changelogFile,
message: sha ? `chore: update ${changelogFile}` : `chore: create ${changelogFile}`,
content: Buffer.from(changelog).toString('base64'),
sha: sha, // if sha is null, it'll create a new file
branch: changelogBranch
});
} catch (updateError) {
core.setFailed(`Failed to create or update the file: ${updateError.message}`);
}
} else {
// Some other error occurred
core.setFailed(`Action failed with error: ${e.message}`);
}
}
// Set GitHub action output
core.setOutput('changelog', changelog);

0 comments on commit 436b27f

Please sign in to comment.