Skip to content

Commit

Permalink
Merge branch 'AndrewLeedham-master'
Browse files Browse the repository at this point in the history
  • Loading branch information
hannesrabo committed Jun 17, 2019
2 parents dc5f1c1 + 90d01b6 commit 329c85a
Show file tree
Hide file tree
Showing 4 changed files with 194 additions and 105 deletions.
30 changes: 26 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,29 @@ The `SLACK_WEBHOOK` variable has to be defined in the environment where you will

### Options

| Option | Description | Default |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------- |
| `notifyOnSuccess` | Determines if a succesfull release should trigger a slack message to be sent. If `false` this plugin does nothing on success. | false |
| `notifyOnFail` | Determines if a failed release should trigger a slack message to be sent. If `false` this plugin does nothing on fail. | false |
| Option | Description | Default |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------- | --------- |
| `notifyOnSuccess` | Determines if a succesfull release should trigger a slack message to be sent. If `false` this plugin does nothing on success. | false |
| `notifyOnFail` | Determines if a failed release should trigger a slack message to be sent. If `false` this plugin does nothing on fail. | false |
| `onSuccessTemplate` | Provides a template for the slack message object on success when `notifyOnSuccess` is `true`. See [templating](#templating). | undefined |
| `onFailTemplate` | Provides a template for the slack message object on fail when `notifyOnFail` is `true`. See [templating](#templating). | undefined |

### Templating

If a template is provided via either the `onSuccessTemplate` or `onFailTemplate` options, it will be used for the respective slack message. The template should be an object that follows the [Slack API message structure](https://api.slack.com/docs/message-formatting). Strings within the template will have keywords replaced:

| Keyword | Description | Example | Template |
| ---------------------- | --------------------------- | ------------------------------------------------- | ----------------- |
| `$package_name` | The name of the package. | semantic-release-test | Both |
| `$npm_package_version` | The version of the release. | 1.0.93 | onSuccessTemplate |
| `$repo_path` | The repository path. | juliuscc/semantic-release-test | Both |
| `$repo_url` | The repository URL. | https://github.com/juliuscc/semantic-release-test | Both |
| `$release_notes` | The notes of the release. | | onSuccessTemplate |

A sample configuration with template can look like this

```json
"onSuccessTemplate": {
"text": "A new version of $package_name with version $npm_package_version has been released at $repo_url!"
}
```
133 changes: 75 additions & 58 deletions lib/fail.js
Original file line number Diff line number Diff line change
@@ -1,90 +1,107 @@
/* eslint-disable camelcase */
const postMessage = require('./postMessage')
const template = require('./template')

module.exports = async (pluginConfig, context) => {
const { logger, options, errors } = context
const { npm_package_name } = context.env

let package_name = context.env.SEMANTIC_RELEASE_PACKAGE
if (!package_name) package_name = context.env.npm_package_name

if (!pluginConfig.notifyOnFail) {
logger.log('Notifying on fail skipped')
return
}

logger.log('Sending slack notification on fail')

const plural = errors.length > 1
let slackMessage = {}
const repoPath =
options.repositoryUrl.indexOf('[email protected]') !== -1
? options.repositoryUrl.split(':')[1].replace('.git', '')
: undefined
const repoURL = repoPath && `https://github.com/${repoPath}`

const messageSummaryLine = `${
plural ? 'Errors' : 'An error'
} occurred while trying to publish the new version of \`${npm_package_name}\`!`
// Override default fail template
if (pluginConfig.onFailTemplate) {
slackMessage = template(pluginConfig.onFailTemplate, {
package_name,
repo_path: repoPath,
repo_url: repoURL
})
} else {
const plural = errors.length > 1

const divider = {
type: 'divider'
}
const messageSummaryLine = `${
plural ? 'Errors' : 'An error'
} occurred while trying to publish the new version of \`${npm_package_name}\`!`

let messageBlocks = [
{
type: 'section',
text: {
type: 'mrkdwn',
text: messageSummaryLine
}
const divider = {
type: 'divider'
}
]

if (options.repositoryUrl.indexOf('[email protected]') !== -1) {
const repoPath = options.repositoryUrl.split(':')[1].replace('.git', '')
const repoURL = `https://github.com/${repoPath}`

const metadata = {
type: 'context',
elements: [
{
let messageBlocks = [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `*<${repoURL}|${repoPath}>*`
text: messageSummaryLine
}
]
}

messageBlocks.push(metadata)
}

// messageBlocks.push(divider)
}
]

const attachments = [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `:no_entry: *${plural ? 'Exceptions' : 'Exception'}*`
if (repoPath) {
const metadata = {
type: 'context',
elements: [
{
type: 'mrkdwn',
text: `*<${repoURL}|${repoPath}>*`
}
]
}
}
]

for (const error of errors) {
if (attachments.length > 2) {
attachments.push(divider)
messageBlocks.push(metadata)
}
attachments.push({
type: 'section',
text: {
type: 'mrkdwn',
text: `\`\`\`${error.stack}\`\`\``
}
})
}

let slackMessage = {
text: `${
plural ? 'Errors' : 'An error'
} occurred while trying to publish the new version of ${npm_package_name}!`,
blocks: messageBlocks,
attachments: [
// messageBlocks.push(divider)

const attachments = [
{
color: '#ff0000',
blocks: attachments
type: 'section',
text: {
type: 'mrkdwn',
text: `:no_entry: *${plural ? 'Exceptions' : 'Exception'}*`
}
}
]

for (const error of errors) {
if (attachments.length > 2) {
attachments.push(divider)
}
attachments.push({
type: 'section',
text: {
type: 'mrkdwn',
text: `\`\`\`${error.stack}\`\`\``
}
})
}

slackMessage = {
text: `${
plural ? 'Errors' : 'An error'
} occurred while trying to publish the new version of ${package_name}!`,
blocks: messageBlocks,
attachments: [
{
color: '#ff0000',
blocks: attachments
}
]
}
}

await postMessage(slackMessage, logger)
Expand Down
105 changes: 62 additions & 43 deletions lib/success.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable camelcase */
const postMessage = require('./postMessage')
const template = require('./template')

module.exports = async (pluginConfig, context) => {
const { logger, nextRelease, options } = context
Expand All @@ -14,54 +15,72 @@ module.exports = async (pluginConfig, context) => {

logger.log('Sending slack notification on success')

let messageBlocks = [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `A new version of \`${package_name}\` has been released!\nCurrent version is *#${
nextRelease.version
}*`
}
}
]

if (nextRelease.notes !== '') {
messageBlocks.push({
type: 'section',
text: {
type: 'mrkdwn',
text: `*Notes*: ${nextRelease.notes}`
}
})
}

let slackMessage = {
blocks: messageBlocks,
text: `A new version of ${package_name} has been released!`
}
let slackMessage = {}

if (options.repositoryUrl.indexOf('[email protected]') !== -1) {
const repoPath = options.repositoryUrl.split(':')[1].replace('.git', '')
const repoURL = `https://github.com/${repoPath}`
const gitTag = nextRelease.gitTag
const repoPath =
options.repositoryUrl.indexOf('[email protected]') !== -1
? options.repositoryUrl.split(':')[1].replace('.git', '')
: undefined
const repoURL = repoPath && `https://github.com/${repoPath}`

slackMessage.attachments = [
// Override default success template
if (pluginConfig.onSuccessTemplate) {
console.log(nextRelease.version)
slackMessage = template(pluginConfig.onSuccessTemplate, {
package_name,
npm_package_version: nextRelease.version,
repo_path: repoPath,
repo_url: repoURL,
release_notes: nextRelease.notes
})
} else {
let messageBlocks = [
{
color: '#2cbe4e',
blocks: [
{
type: 'context',
elements: [
{
type: 'mrkdwn',
text: `:package: *<${repoURL}|${repoPath}>:* <${repoURL}/releases/tag/${gitTag}|${gitTag}>`
}
]
}
]
type: 'section',
text: {
type: 'mrkdwn',
text: `A new version of \`${package_name}\` has been released!\nCurrent version is *#${
nextRelease.version
}*`
}
}
]

if (nextRelease.notes !== '') {
messageBlocks.push({
type: 'section',
text: {
type: 'mrkdwn',
text: `*Notes*: ${nextRelease.notes}`
}
})
}

slackMessage = {
blocks: messageBlocks,
text: `A new version of ${package_name} has been released!`
}

if (repoPath) {
const gitTag = nextRelease.gitTag

slackMessage.attachments = [
{
color: '#2cbe4e',
blocks: [
{
type: 'context',
elements: [
{
type: 'mrkdwn',
text: `:package: *<${repoURL}|${repoPath}>:* <${repoURL}/releases/tag/${gitTag}|${gitTag}>`
}
]
}
]
}
]
}
}

await postMessage(slackMessage, logger)
Expand Down
31 changes: 31 additions & 0 deletions lib/template.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
function template(input, variables) {
const type = typeof input
if (type === 'string') {
return Object.keys(variables).reduce(
(output, variable) =>
variables[variable]
? output.replace(`$${variable}`, variables[variable])
: output,
input
)
} else if (type === 'object') {
if (Array.isArray(input)) {
const out = []
for (const value of input) {
out.push(template(value, variables))
}
return out
} else {
const out = {}
for (let key of Object.keys(input)) {
const value = input[key]
out[key] = template(value, variables)
}
return out
}
} else {
return input
}
}

module.exports = template

0 comments on commit 329c85a

Please sign in to comment.