Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/post-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,13 @@ jobs:
develop_branch: "develop"
main_branch: "main"
# if you want to post to slack
slack_channel: "hoang-test"
slack: >
{
"channel": "hoang-test",
"username_mapping": {
"hoangvvo": "U03B3E4UPV3"
}
}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# if you want to post to slack
Expand Down
25 changes: 24 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,30 @@ You should have your own deployment workflow as this action will not handle it.

### Post to Slack

It is often that an anouncement is made to a Slack channel after a release. To do so, specify `SLACK_TOKEN` env and `slack_channel` input.
It is often that an anouncement is made to a Slack channel after a release. To do so, specify `SLACK_TOKEN` env and `slack` input.

```yaml
jobs:
post_release:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
name: Post Release
steps:
- name: gitflow-workflow-action post-release
uses: hoangvvo/gitflow-workflow-action@v0
with:
develop_branch: "develop"
main_branch: "main"
slack: >
{
"channel": "hoang-test",
"username_mapping": {
"hoangvvo": "U03B3E4UPV3"
}
}
env:
SLACK_TOKEN: ${{ secrets.SLACK_TOKEN }}
```

## License

Expand Down
9 changes: 5 additions & 4 deletions action.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: "Git Workflow Release Action"
description: "Create a Deploy to Production pull request with changelog"
name: "Git Workflow Action"
description: "Create PR for release + Create GH release and send Slack message on merge"

inputs:
version:
Expand All @@ -12,9 +12,10 @@ inputs:
main_branch:
description: The branch that would release to production
required: true
slack_channel:
description: The slack channel to post the release message to
slack:
description: The slack options (channel, name mapping)
required: false

runs:
using: "node16"
main: "dist/index.js"
72 changes: 55 additions & 17 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19091,6 +19091,11 @@ const { WebClient: SlackWebClient } = __nccwpck_require__(431);
const { Config, octokit } = __nccwpck_require__(9297);

exports.executePostRelease = async function executePostRelease() {
/**
* Precheck
* Check if the pull request has a release label, targeting main branch, and if it was merged
*/

if (github.context.eventName !== "pull_request") {
console.log(`Not a pull request merge. Exiting...`);
return;
Expand All @@ -19109,7 +19114,7 @@ exports.executePostRelease = async function executePostRelease() {
});

if (pullRequest.base.ref !== Config.prodBranch) {
console.log("Request does not merge to main_branch. Exiting...");
console.log("PR does not merge to main_branch. Exiting...");
return;
}

Expand All @@ -19123,12 +19128,13 @@ exports.executePostRelease = async function executePostRelease() {
return;
}

// release branch always has the format
// `release/${version}`
const releaseBranch = pullRequest.head.ref;
const version = releaseBranch.substring("release/".length);

// Merge back to develop branch
/**
* Merging the release branch back to the develop branch if needed
*/

const { data: compareCommitsResult } =
await octokit.rest.repos.compareCommits({
...Config.repo,
Expand Down Expand Up @@ -19167,33 +19173,59 @@ exports.executePostRelease = async function executePostRelease() {
);
}

// Create a release
console.log(`Creating a release`);
const { data: release } = await octokit.rest.repos.createRelease({
/**
* Creating a release
*/

console.log(`Creating release ${version}`);
const { data: latestRelease } = await octokit.rest.repos
.getLatestRelease(Config.repo)
.catch(() => ({ data: null }));

const { data: releaseNotes } = await octokit.rest.repos.generateReleaseNotes({
...Config.repo,
tag_name: version,
target_commitish: Config.developBranch,
previous_tag_name: latestRelease?.tag_name,
});

await octokit.rest.repos.createRelease({
...Config.repo,
tag_name: version,
target_commitish: Config.prodBranch,
generate_release_notes: true,
body: releaseNotes.body,
});

// Post to slack if needed
const slackChannel = core.getInput("slack_channel");
if (slackChannel) {
console.log(`Posting to slack channel #${slackChannel}`);
/**
* Slack integration
*/

const slackStr = core.getInput("slack");
if (slackStr) {
const slackOpts = JSON.parse("slack");

console.log(`Posting to slack channel #${slackOpts.channel}`);
const slackToken = process.env.SLACK_TOKEN;
if (!slackToken) throw new Error("process.env.SLACK_TOKEN is not defined");

const slackWebClient = new SlackWebClient(slackToken);

const username_mapping = slackOpts["username_mapping"] || {};

let releaseBody = releaseNotes.body;

for (const [username, slackUserId] of Object.entries(username_mapping)) {
releaseBody = releaseBody.replaceAll(`@${username}`, `<@${slackUserId}>`);
}

await slackWebClient.chat.postMessage({
text: `*Release ${version} to ${Config.repo.owner}/${Config.repo.repo}*
text: `*[Release ${version} to ${Config.repo.owner}/${Config.repo.repo}](${pullRequest.url})*

${release.body}`,
channel: slackChannel,
${releaseBody}`,
channel: slackOpts.channel,
icon_url: "https://avatars.githubusercontent.com/in/15368?s=88&v=4",
});
}

// Merge back to develop branch
};


Expand All @@ -19213,12 +19245,18 @@ exports.createReleasePR = async function createReleasePR() {
if (!version) throw new Error(`Missing input.version`);

console.log(`Generating release notes`);

// developBranch and mainBranch are almost identical
// so we can use developBranch for ahead-of-time release note
const { data: latestRelease } = await octokit.rest.repos
.getLatestRelease(Config.repo)
.catch(() => ({ data: null }));

const { data: releaseNotes } = await octokit.rest.repos.generateReleaseNotes({
...Config.repo,
tag_name: version,
target_commitish: Config.developBranch,
previous_tag_name: latestRelease?.tag_name,
});

console.log(`Creating release branch`);
Expand Down
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fetch();
13 changes: 13 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@slack/web-api": "^6.7.2"
},
"devDependencies": {
"@tsconfig/node18": "^1.0.1",
"@types/node": "^18.7.13",
"@vercel/ncc": "^0.34.0",
"eslint": "^8.23.0",
Expand Down
66 changes: 49 additions & 17 deletions src/post-release.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ const { WebClient: SlackWebClient } = require("@slack/web-api");
const { Config, octokit } = require("./shared.js");

exports.executePostRelease = async function executePostRelease() {
/**
* Precheck
* Check if the pull request has a release label, targeting main branch, and if it was merged
*/

if (github.context.eventName !== "pull_request") {
console.log(`Not a pull request merge. Exiting...`);
return;
Expand All @@ -23,7 +28,7 @@ exports.executePostRelease = async function executePostRelease() {
});

if (pullRequest.base.ref !== Config.prodBranch) {
console.log("Request does not merge to main_branch. Exiting...");
console.log("PR does not merge to main_branch. Exiting...");
return;
}

Expand All @@ -37,12 +42,13 @@ exports.executePostRelease = async function executePostRelease() {
return;
}

// release branch always has the format
// `release/${version}`
const releaseBranch = pullRequest.head.ref;
const version = releaseBranch.substring("release/".length);

// Merge back to develop branch
/**
* Merging the release branch back to the develop branch if needed
*/

const { data: compareCommitsResult } =
await octokit.rest.repos.compareCommits({
...Config.repo,
Expand Down Expand Up @@ -81,31 +87,57 @@ exports.executePostRelease = async function executePostRelease() {
);
}

// Create a release
console.log(`Creating a release`);
const { data: release } = await octokit.rest.repos.createRelease({
/**
* Creating a release
*/

console.log(`Creating release ${version}`);
const { data: latestRelease } = await octokit.rest.repos
.getLatestRelease(Config.repo)
.catch(() => ({ data: null }));

const { data: releaseNotes } = await octokit.rest.repos.generateReleaseNotes({
...Config.repo,
tag_name: version,
target_commitish: Config.developBranch,
previous_tag_name: latestRelease?.tag_name,
});

await octokit.rest.repos.createRelease({
...Config.repo,
tag_name: version,
target_commitish: Config.prodBranch,
generate_release_notes: true,
body: releaseNotes.body,
});

// Post to slack if needed
const slackChannel = core.getInput("slack_channel");
if (slackChannel) {
console.log(`Posting to slack channel #${slackChannel}`);
/**
* Slack integration
*/

const slackStr = core.getInput("slack");
if (slackStr) {
const slackOpts = JSON.parse("slack");

console.log(`Posting to slack channel #${slackOpts.channel}`);
const slackToken = process.env.SLACK_TOKEN;
if (!slackToken) throw new Error("process.env.SLACK_TOKEN is not defined");

const slackWebClient = new SlackWebClient(slackToken);

const username_mapping = slackOpts["username_mapping"] || {};

let releaseBody = releaseNotes.body;

for (const [username, slackUserId] of Object.entries(username_mapping)) {
releaseBody = releaseBody.replaceAll(`@${username}`, `<@${slackUserId}>`);
}

await slackWebClient.chat.postMessage({
text: `*Release ${version} to ${Config.repo.owner}/${Config.repo.repo}*
text: `*[Release ${version} to ${Config.repo.owner}/${Config.repo.repo}](${pullRequest.url})*

${release.body}`,
channel: slackChannel,
${releaseBody}`,
channel: slackOpts.channel,
icon_url: "https://avatars.githubusercontent.com/in/15368?s=88&v=4",
});
}

// Merge back to develop branch
};
6 changes: 6 additions & 0 deletions src/pre-release.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,18 @@ exports.createReleasePR = async function createReleasePR() {
if (!version) throw new Error(`Missing input.version`);

console.log(`Generating release notes`);

// developBranch and mainBranch are almost identical
// so we can use developBranch for ahead-of-time release note
const { data: latestRelease } = await octokit.rest.repos
.getLatestRelease(Config.repo)
.catch(() => ({ data: null }));

const { data: releaseNotes } = await octokit.rest.repos.generateReleaseNotes({
...Config.repo,
tag_name: version,
target_commitish: Config.developBranch,
previous_tag_name: latestRelease?.tag_name,
});

console.log(`Creating release branch`);
Expand Down
10 changes: 10 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "@tsconfig/node18/tsconfig.json",
"compilerOptions": {
"lib": ["es2022", "DOM"],
"outDir": "dist",
"rootDir": "./src",
"allowJs": true
},
"include": ["./src/**/*"]
}