From 135d94bfeade3a29df6fa1e78390a03d1302f03d Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Sun, 10 Oct 2021 18:50:27 +0200 Subject: [PATCH] ci: add semantic release (#1113) --- .github/workflows/release-automated.yml | 21 +++++ .gitignore | 5 ++ .releaserc/commit.hbs | 61 +++++++++++++ .releaserc/footer.hbs | 11 +++ .releaserc/header.hbs | 25 ++++++ .releaserc/template.hbs | 14 +++ release.config.js | 111 ++++++++++++++++++++++++ 7 files changed, 248 insertions(+) create mode 100644 .github/workflows/release-automated.yml create mode 100644 .releaserc/commit.hbs create mode 100644 .releaserc/footer.hbs create mode 100644 .releaserc/header.hbs create mode 100644 .releaserc/template.hbs create mode 100644 release.config.js diff --git a/.github/workflows/release-automated.yml b/.github/workflows/release-automated.yml new file mode 100644 index 000000000..7a9f0d997 --- /dev/null +++ b/.github/workflows/release-automated.yml @@ -0,0 +1,21 @@ +name: release-automated +on: + push: + branches: [ master, release, alpha, beta ] +jobs: + release: + runs-on: ubuntu-latest + outputs: + current_tag: ${{ steps.tag.outputs.current_tag }} + steps: + - uses: actions/checkout@v2 + with: + persist-credentials: false + - uses: actions/setup-node@v2 + with: + node-version: 14 + - run: npm install -g -E semantic-release@18.0.0 @semantic-release/changelog@6.0.0 @semantic-release/commit-analyzer@9.0.1 @semantic-release/git@10.0.0 @semantic-release/release-notes-generator@10.0.2 + - run: npx semantic-release + env: + GH_TOKEN: ${{ secrets.RELEASE_GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index d3f61de1c..61448040d 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,8 @@ jacoco.exec # VSC .project + +# Node +node_modules/ +npm-debug.log +package-lock.json \ No newline at end of file diff --git a/.releaserc/commit.hbs b/.releaserc/commit.hbs new file mode 100644 index 000000000..e10a0d901 --- /dev/null +++ b/.releaserc/commit.hbs @@ -0,0 +1,61 @@ +*{{#if scope}} **{{scope}}:** +{{~/if}} {{#if subject}} + {{~subject}} +{{~else}} + {{~header}} +{{~/if}} + +{{~!-- commit link --}} {{#if @root.linkReferences~}} + ([{{shortHash}}]( + {{~#if @root.repository}} + {{~#if @root.host}} + {{~@root.host}}/ + {{~/if}} + {{~#if @root.owner}} + {{~@root.owner}}/ + {{~/if}} + {{~@root.repository}} + {{~else}} + {{~@root.repoUrl}} + {{~/if}}/ + {{~@root.commit}}/{{hash}})) +{{~else}} + {{~shortHash}} +{{~/if}} + +{{~!-- commit references --}} +{{~#if references~}} + , closes + {{~#each references}} {{#if @root.linkReferences~}} + [ + {{~#if this.owner}} + {{~this.owner}}/ + {{~/if}} + {{~this.repository}}#{{this.issue}}]( + {{~#if @root.repository}} + {{~#if @root.host}} + {{~@root.host}}/ + {{~/if}} + {{~#if this.repository}} + {{~#if this.owner}} + {{~this.owner}}/ + {{~/if}} + {{~this.repository}} + {{~else}} + {{~#if @root.owner}} + {{~@root.owner}}/ + {{~/if}} + {{~@root.repository}} + {{~/if}} + {{~else}} + {{~@root.repoUrl}} + {{~/if}}/ + {{~@root.issue}}/{{this.issue}}) + {{~else}} + {{~#if this.owner}} + {{~this.owner}}/ + {{~/if}} + {{~this.repository}}#{{this.issue}} + {{~/if}}{{/each}} +{{~/if}} + diff --git a/.releaserc/footer.hbs b/.releaserc/footer.hbs new file mode 100644 index 000000000..575df456e --- /dev/null +++ b/.releaserc/footer.hbs @@ -0,0 +1,11 @@ +{{#if noteGroups}} +{{#each noteGroups}} + +### {{title}} + +{{#each notes}} +* {{#if commit.scope}}**{{commit.scope}}:** {{/if}}{{text}} ([{{commit.shortHash}}]({{commit.shortHash}})) +{{/each}} +{{/each}} + +{{/if}} diff --git a/.releaserc/header.hbs b/.releaserc/header.hbs new file mode 100644 index 000000000..fc781c4b5 --- /dev/null +++ b/.releaserc/header.hbs @@ -0,0 +1,25 @@ +{{#if isPatch~}} + ## +{{~else~}} + # +{{~/if}} {{#if @root.linkCompare~}} + [{{version}}]( + {{~#if @root.repository~}} + {{~#if @root.host}} + {{~@root.host}}/ + {{~/if}} + {{~#if @root.owner}} + {{~@root.owner}}/ + {{~/if}} + {{~@root.repository}} + {{~else}} + {{~@root.repoUrl}} + {{~/if~}} + /compare/{{previousTag}}...{{currentTag}}) +{{~else}} + {{~version}} +{{~/if}} +{{~#if title}} "{{title}}" +{{~/if}} +{{~#if date}} ({{date}}) +{{/if}} diff --git a/.releaserc/template.hbs b/.releaserc/template.hbs new file mode 100644 index 000000000..63610bdcb --- /dev/null +++ b/.releaserc/template.hbs @@ -0,0 +1,14 @@ +{{> header}} + +{{#each commitGroups}} + +{{#if title}} +### {{title}} + +{{/if}} +{{#each commits}} +{{> commit root=@root}} +{{/each}} +{{/each}} + +{{> footer}} diff --git a/release.config.js b/release.config.js new file mode 100644 index 000000000..3e54eca7a --- /dev/null +++ b/release.config.js @@ -0,0 +1,111 @@ +/** + * Semantic Release Config + */ + +const fs = require('fs').promises; +const path = require('path'); + +// Get env vars +const ref = process.env.GITHUB_REF; +const serverUrl = process.env.GITHUB_SERVER_URL; +const repository = process.env.GITHUB_REPOSITORY; +const repositoryUrl = serverUrl + '/' + repository; + +// Declare params +const resourcePath = './.releaserc/'; +const templates = { + main: { file: 'template.hbs', text: undefined }, + header: { file: 'header.hbs', text: undefined }, + commit: { file: 'commit.hbs', text: undefined }, + footer: { file: 'footer.hbs', text: undefined }, +}; + +// Declare semantic config +async function config() { + + // Get branch + const branch = ref.split('/').pop(); + console.log(`Running on branch: ${branch}`); + + // Set changelog file + const changelogFile = `./changelogs/CHANGELOG_${branch}.md`; + console.log(`Changelog file output to: ${changelogFile}`); + + // Load template file contents + await loadTemplates(); + + const config = { + branches: [ + 'master', + // { name: 'alpha', prerelease: true }, + // { name: 'beta', prerelease: true }, + 'next-major', + // Long-Term-Support branches + // { name: 'release-1', range: '1.x.x', channel: '1.x' }, + // { name: 'release-2', range: '2.x.x', channel: '2.x' }, + // { name: 'release-3', range: '3.x.x', channel: '3.x' }, + // { name: 'release-4', range: '4.x.x', channel: '4.x' }, + ], + dryRun: true, + debug: true, + ci: true, + tagFormat: '${version}', + plugins: [ + ['@semantic-release/commit-analyzer', { + preset: 'angular', + releaseRules: [ + { type: 'docs', scope: 'README', release: 'patch' }, + { scope: 'no-release', release: false }, + ], + parserOpts: { + noteKeywords: [ 'BREAKING CHANGE', 'BREAKING CHANGES', 'BREAKING' ], + }, + }], + ['@semantic-release/release-notes-generator', { + preset: 'angular', + parserOpts: { + noteKeywords: ['BREAKING CHANGE', 'BREAKING CHANGES', 'BREAKING'] + }, + writerOpts: { + commitsSort: ['subject', 'scope'], + mainTemplate: templates.main.text, + headerPartial: templates.header.text, + commitPartial: templates.commit.text, + footerPartial: templates.footer.text, + }, + }], + ['@semantic-release/changelog', { + 'changelogFile': changelogFile, + }], + ['@semantic-release/git', { + assets: [changelogFile], + }], + ['@semantic-release/github', { + successComment: getReleaseComment(), + labels: ['type:ci'], + releasedLabels: ['state:released<%= nextRelease.channel ? `-\${nextRelease.channel}` : "" %>'] + }], + ], + }; + + return config; +} + +async function loadTemplates() { + for (const template of Object.keys(templates)) { + const text = await readFile(path.resolve(__dirname, resourcePath, templates[template].file)); + templates[template].text = text; + } +} + +async function readFile(filePath) { + return await fs.readFile(filePath, 'utf-8'); +} + +function getReleaseComment() { + const url = repositoryUrl + '/releases/tag/${nextRelease.gitTag}'; + let comment = '🎉 This pull request has been released in version [${nextRelease.version}](' + url + ')'; + return comment; +} + +module.exports = config();