diff --git a/README.md b/README.md index ab79c4a..bde00d8 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,9 @@ A Gitlab release note generator that generates release note on latest tag *(Note. if an issue or merge request that has 2 or more labels, that issue or merge request will be displayed again under the corresponding title)* -- Can be integrated as a CD service. Tutorial below +- Ability to send the generated release notes to Slack +- Can be integrated as a CD service. Tutorial below ## How it works 1. Find the latest tag @@ -35,7 +36,7 @@ docker container run -e GITLAB_PERSONAL_TOKEN=gitlabSampleToken -e GITLAB_PROJEC ``` ### Nodejs Method -- Fill in the parameters mainly `GITLAB_PERSONAL_TOKEN`, `GITLAB_PROJECT_ID`, `TARGET_BRANCH`(optional. Use it only if you want to find tags in the same specific branch) and `TARGET_TAG_REGEX` (optional. Can use it to distinguish master or develop branch version bump) in `app/env.js` or feed it in `process.env` through npm +- Fill in the parameters mainly `GITLAB_PERSONAL_TOKEN`, `GITLAB_PROJECT_ID`, `TARGET_BRANCH`(optional. Use it only if you want to find tags in the same specific branch), `TARGET_TAG_REGEX` (optional. Can use it to distinguish master or develop branch version bump), `PUBLISH_TO_SLACK` (optional) and `SLACK_WEBHOOK_URL` (optional) in `app/env.js` or feed it in `process.env` through npm - `npm install` - `npm start` - After couple seconds, latest tag should have a release note @@ -43,13 +44,14 @@ docker container run -e GITLAB_PERSONAL_TOKEN=gitlabSampleToken -e GITLAB_PROJEC ### Gitlab CI method 1. Need to pass in `gitlab personal access token` as a CI variable -2. c/p the `.sample.gitlab-ci.yml` to your gitlab ci. - +2. Need to pass in `SLACK_WEBHOOK_URL` as a CI variable (optional) +3. c/p the `.sample.gitlab-ci.yml` to your gitlab ci. + What's included in the sample gitlab CI script - + - `generate-release-note` job. Generates a release note on the tag after detecting tag push with this regex `/^[0-9]+.[0-9]+.[0-9]+(-[0-9]+)?$/` - `tag-after-deployment` job (optional). Tag the commit that contains a version bump with this regex `/^[0-9]+.[0-9]+.[0-9]+(-[0-9]+)?$/`. **Require ssh key to work.** -3. Customise the gitlab ci script to your need +4. Customise the gitlab ci script to your need Reference gitlab repo: [generator test](https://gitlab.com/jackzhang/generator-test) @@ -58,7 +60,7 @@ Reference gitlab repo: [generator test](https://gitlab.com/jackzhang/generator-t These can be specified using environment variables -* GITLAB_API_ENDPOINT: Your gitlab instaqnce's endpoint +* GITLAB_API_ENDPOINT: Your gitlab instance's endpoint * Default https://gitlab.com/api/v4 * GITLAB_PERSONAL_TOKEN: Grant api read/access permission * GITLAB_PROJECT_ID: Your project id that is located under settings > general @@ -68,6 +70,8 @@ These can be specified using environment variables * Default "Australia/Melbourne" * ISSUE_CLOSED_SECONDS: The amount of seconds to search after the last commit, useful for Merge Requests that close their tickets a second after the commit. * Default 0 +* PUBLISH_TO_SLACK: Feature flag to turn on or off publishing release notes to Slack. (optional). +* SLACK_WEBHOOK_URL: Your Slack webhook URL to send the generated release notes to Slack (optional). ## Building and Running locally @@ -87,6 +91,8 @@ docker container run \ -e GITLAB_PROJECT_ID=$GITLAB_PROJECT_ID \ -e TARGET_BRANCH=master \ -e TARGET_TAG_REGEX=^release-.*$ \ + -e PUBLISH_TO_SLACK=true \ + -e SLACK_WEBHOOK_URL=$SLACK_WEBHOOK_URL \ local-gitlab-release-note-generator ``` diff --git a/app/adapters/gitlab.js b/app/adapters/gitlab.js index efdd18c..7e445e1 100644 --- a/app/adapters/gitlab.js +++ b/app/adapters/gitlab.js @@ -73,3 +73,7 @@ exports.updateTagReleaseByProjectIdTagNameAndTagId = async (projectId, tagName, return Request({uri: `${Env.GITLAB_API_ENDPOINT}/projects/${projectId}/repository/tags/${tagName}/release`, method: "PUT", body, ...options}); }; +exports.getProjectByProjectID = async (projectId) => { + return Request({uri: `${Env.GITLAB_API_ENDPOINT}/projects/${projectId}`, ...options}); +}; + diff --git a/app/env.js b/app/env.js index 1842839..57d6b2b 100644 --- a/app/env.js +++ b/app/env.js @@ -8,4 +8,6 @@ exports.NODE_ENV = process.env.NODE_ENV; // will looks for issues closed this many seconds after the tag, this may happen if the issue is merged via a MR and automatially closed // example -e GITLAB_ISSUE_SECOND_DELAY=60 will catch issues closed up to 60 seconds after the tag is created. -exports.ISSUE_CLOSED_SECONDS = process.env.ISSUE_CLOSED_SECONDS || "0" +exports.ISSUE_CLOSED_SECONDS = process.env.ISSUE_CLOSED_SECONDS || "0" +exports.PUBLISH_TO_SLACK = process.env.PUBLISH_TO_SLACK || false; +exports.SLACK_WEBHOOK_URL = process.env.SLACK_WEBHOOK_URL; diff --git a/app/index.js b/app/index.js index a3c6816..c84d7b1 100644 --- a/app/index.js +++ b/app/index.js @@ -1,6 +1,7 @@ const Generator = require("./lib/generator"); +const Publisher = require("./lib/publisher"); const Logger = require("./logger"); -Generator.generate().then().catch(err => { +Generator.generate().then(notes => Publisher.publish(notes)).catch(err => { Logger.error(err); }); \ No newline at end of file diff --git a/app/lib/generator.js b/app/lib/generator.js index 8ecb3f5..69017b6 100644 --- a/app/lib/generator.js +++ b/app/lib/generator.js @@ -26,7 +26,7 @@ exports.generate = async () => { } const changeLog = await ChangelogLib.getChangelogByStartAndEndDate(startDate, endDate); - const changeLogContent = await ChangelogLib.generateChangeLogContent(changeLog, {useSlack: false}); + const changeLogContent = await ChangelogLib.generateChangeLogContent(changeLog, {useSlack: Env.PUBLISH_TO_SLACK}); Logger.debug(`Changelog: ${changeLogContent}`); return await TagLib.upsertTagDescriptionByProjectIdAndTag(Env.GITLAB_PROJECT_ID, latestTag, changeLogContent); }; diff --git a/app/lib/project.js b/app/lib/project.js new file mode 100644 index 0000000..0b6de07 --- /dev/null +++ b/app/lib/project.js @@ -0,0 +1,7 @@ +const Gitlab = require("../adapters/gitlab"); + +exports.getProjectName = async (projectId) => { + const { name } = await Gitlab.getProjectByProjectID(projectId); + + return name; +}; diff --git a/app/lib/publisher.js b/app/lib/publisher.js new file mode 100644 index 0000000..2d9fe33 --- /dev/null +++ b/app/lib/publisher.js @@ -0,0 +1,39 @@ +const _ = require("lodash"); +const request = require("request"); +const Project = require("./project"); +const Logger = require("../logger"); +const Env = require("../env"); + +exports.publish = async (notes) => { + if (!Env.PUBLISH_TO_SLACK) { + Logger.info('PUBLISH_TO_SLACK is disabled. Skipping...'); + return; + } + + if (!Env.SLACK_WEBHOOK_URL) { + throw new Error('SLACK_WEBHOOK_URL is not defined. Skipping...'); + } + + Logger.info('Preparing Slack payload'); + + let projectName = await Project.getProjectName(Env.GITLAB_PROJECT_ID); + + request({ + method: 'POST', + uri: Env.SLACK_WEBHOOK_URL, + body: { + text: `*${projectName} Version ${notes.tag_name}* was just released! :tada:\n\n ${notes.description}` + }, + json: true + }, (error, response) => { + if (error) { + throw new Error("An error occurred while sending Slack message. Slack Result: " + JSON.stringify(response)); + } + + if(response.statusCode != 200) { + return Logger.error(`An error occurred while sending Slack message - ${response.statusCode}: ${response.body}`); + } + + return Logger.info(`Slack message sent successfully`); + }); +};