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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ When using the _GITHUB_TOKEN_, the **minimum required permissions** are:
| `releasedLabels` | The [labels](https://help.github.com/articles/about-labels) to add to each issue and pull request resolved by the release. Set to `false` to not add any label. See [releasedLabels](#releasedlabels). | `['released<%= nextRelease.channel ? \` on @\${nextRelease.channel}\` : "" %>']- |
| `addReleases` | Will add release links to the GitHub Release. Can be `false`, `"bottom"` or `"top"`. See [addReleases](#addReleases). | `false` |
| `draftRelease` | A boolean indicating if a GitHub Draft Release should be created instead of publishing an actual GitHub Release. | `false` |
| `releaseNameTemplate` | A [Lodash template](https://lodash.com/docs#template) to customize the github release's name | `<%= nextverison.name %>` |
| `releaseBodyTemplate` | A [Lodash template](https://lodash.com/docs#template) to customize the github release's body | `<%= nextverison.notes %>` |

#### proxy

Expand Down
26 changes: 26 additions & 0 deletions lib/definitions/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,29 @@ export function ENOGHTOKEN({ owner, repo }) {
Please make sure to create a [GitHub personal token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line) and to set it in the \`GH_TOKEN\` or \`GITHUB_TOKEN\` environment variable on your CI environment. The token must allow to push to the repository ${owner}/${repo}.`,
};
}

export function EINVALIDRELEASEBODYTEMPLATE({ releaseBodyTemplate }) {
return {
message: "Invalid `releaseBodyTemplate` option.",
details: `The [releaseBodyTemplate option](${linkify(
"README.md#releaseBodyTemplate",
)}) must be a non empty \`String\`.

Your configuration for the \`releaseBodyTemplate\` option is \`${stringify(
releaseBodyTemplate,
)}\`.`,
};
}

export function EINVALIDRELEASENAMETEMPLATE({ releaseNameTemplate }) {
return {
message: "Invalid `releaseNameTemplate` option.",
details: `The [releaseNameTemplate option](${linkify(
"README.md#releaseNameTemplate",
)}) must be a non empty \`String\`.

Your configuration for the \`releaseNameTemplate\` option is \`${stringify(
releaseNameTemplate,
)}\`.`,
};
}
8 changes: 5 additions & 3 deletions lib/publish.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default async function publish(pluginConfig, context, { Octokit }) {
cwd,
options: { repositoryUrl },
branch,
nextRelease: { name, gitTag, notes },
nextRelease: { gitTag },
logger,
} = context;
const {
Expand All @@ -29,6 +29,8 @@ export default async function publish(pluginConfig, context, { Octokit }) {
proxy,
assets,
draftRelease,
releaseNameTemplate,
releaseBodyTemplate,
} = resolveConfig(pluginConfig, context);
const { owner, repo } = parseGithubUrl(repositoryUrl);
const octokit = new Octokit(
Expand All @@ -44,8 +46,8 @@ export default async function publish(pluginConfig, context, { Octokit }) {
repo,
tag_name: gitTag,
target_commitish: branch.name,
name,
body: notes,
name: template(releaseNameTemplate)(context),
body: template(releaseBodyTemplate)(context),
prerelease: isPrerelease(branch),
};

Expand Down
8 changes: 8 additions & 0 deletions lib/resolve-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export default function resolveConfig(
releasedLabels,
addReleases,
draftRelease,
releaseNameTemplate,
releaseBodyTemplate,
},
{ env },
) {
Expand Down Expand Up @@ -44,5 +46,11 @@ export default function resolveConfig(
: castArray(releasedLabels),
addReleases: isNil(addReleases) ? false : addReleases,
draftRelease: isNil(draftRelease) ? false : draftRelease,
releaseBodyTemplate: !isNil(releaseBodyTemplate)
? releaseBodyTemplate
: "<%= nextRelease.notes %>",
releaseNameTemplate: !isNil(releaseNameTemplate)
? releaseNameTemplate
: "<%= nextRelease.name %>",
};
}
2 changes: 2 additions & 0 deletions lib/verify.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ const VALIDATORS = {
releasedLabels: canBeDisabled(isArrayOf(isNonEmptyString)),
addReleases: canBeDisabled(oneOf(["bottom", "top"])),
draftRelease: isBoolean,
releaseBodyTemplate: isNonEmptyString,
releaseNameTemplate: isNonEmptyString,
};

export default async function verify(pluginConfig, context, { Octokit }) {
Expand Down
126 changes: 126 additions & 0 deletions test/publish.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -720,3 +720,129 @@ test("Publish a release when env.GITHUB_URL is set to https://github.com (Defaul
]);
t.true(fetch.done());
});

test("Publish a custom release body", async (t) => {
const owner = "test_user";
const repo = "test_repo";
const env = { GITHUB_TOKEN: "github_token" };
const pluginConfig = {
releaseBodyTemplate:
"To install this run npm install package@<%= nextRelease.name %>\n\n<%= nextRelease.notes %>",
};
const nextRelease = {
gitTag: "v1.0.0",
name: "v1.0.0",
notes: "Test release note body",
};
const options = { repositoryUrl: `https://github.com/${owner}/${repo}.git` };
const releaseUrl = `https://github.com/${owner}/${repo}/releases/${nextRelease.version}`;
const releaseId = 1;
const uploadUri = `/api/uploads/repos/${owner}/${repo}/releases/${releaseId}/assets`;
const uploadUrl = `https://github.com${uploadUri}{?name,label}`;
const branch = "test_branch";

const fetch = fetchMock.sandbox().postOnce(
`https://api.github.local/repos/${owner}/${repo}/releases`,
{
upload_url: uploadUrl,
html_url: releaseUrl,
},
{
body: {
tag_name: nextRelease.gitTag,
target_commitish: branch,
name: nextRelease.name,
body: `To install this run npm install package@${nextRelease.name}\n\n${nextRelease.notes}`,
prerelease: false,
},
},
);

const result = await publish(
pluginConfig,
{
cwd,
env,
options,
branch: { name: branch, type: "release", main: true },
nextRelease,
logger: t.context.logger,
},
{
Octokit: TestOctokit.defaults((options) => ({
...options,
request: { ...options.request, fetch },
})),
},
);

t.is(result.url, releaseUrl);
t.deepEqual(t.context.log.args[0], [
"Published GitHub release: %s",
releaseUrl,
]);
t.true(fetch.done());
});

test("Publish a custom release name", async (t) => {
const owner = "test_user";
const repo = "test_repo";
const env = { GITHUB_TOKEN: "github_token" };
const pluginConfig = {
releaseNameTemplate:
"omg its the best release: <%= nextRelease.name %> 🌈🌈",
};
const nextRelease = {
gitTag: "v1.0.0",
name: "v1.0.0",
notes: "Test release note body",
};
const options = { repositoryUrl: `https://github.com/${owner}/${repo}.git` };
const releaseUrl = `https://github.com/${owner}/${repo}/releases/${nextRelease.version}`;
const releaseId = 1;
const uploadUri = `/api/uploads/repos/${owner}/${repo}/releases/${releaseId}/assets`;
const uploadUrl = `https://github.com${uploadUri}{?name,label}`;
const branch = "test_branch";

const fetch = fetchMock.sandbox().postOnce(
`https://api.github.local/repos/${owner}/${repo}/releases`,
{
upload_url: uploadUrl,
html_url: releaseUrl,
},
{
body: {
tag_name: nextRelease.gitTag,
target_commitish: branch,
name: `omg its the best release: ${nextRelease.name} 🌈🌈`,
body: nextRelease.notes,
prerelease: false,
},
},
);

const result = await publish(
pluginConfig,
{
cwd,
env,
options,
branch: { name: branch, type: "release", main: true },
nextRelease,
logger: t.context.logger,
},
{
Octokit: TestOctokit.defaults((options) => ({
...options,
request: { ...options.request, fetch },
})),
},
);

t.is(result.url, releaseUrl);
t.deepEqual(t.context.log.args[0], [
"Published GitHub release: %s",
releaseUrl,
]);
t.true(fetch.done());
});
72 changes: 72 additions & 0 deletions test/verify.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2050,3 +2050,75 @@ test('Throw SemanticReleaseError if "draftRelease" option is not a valid boolean
t.is(error.code, "EINVALIDDRAFTRELEASE");
t.true(fetch.done());
});

test('Throw SemanticReleaseError if "releaseBodyTemplate" option is an empty string', async (t) => {
const owner = "test_user";
const repo = "test_repo";
const env = { GH_TOKEN: "github_token" };

const fetch = fetchMock
.sandbox()
.getOnce(`https://api.github.local/repos/${owner}/${repo}`, {
permissions: { push: true },
});

const {
errors: [error, ...errors],
} = await t.throwsAsync(
verify(
{ releaseBodyTemplate: "" },
{
env,
options: { repositoryUrl: `https://github.com/${owner}/${repo}.git` },
logger: t.context.logger,
},
{
Octokit: TestOctokit.defaults((options) => ({
...options,
request: { ...options.request, fetch },
})),
},
),
);

t.is(errors.length, 0);
t.is(error.name, "SemanticReleaseError");
t.is(error.code, "EINVALIDRELEASEBODYTEMPLATE");
t.true(fetch.done());
});

test('Throw SemanticReleaseError if "releaseNameTemplate" option is an empty string', async (t) => {
const owner = "test_user";
const repo = "test_repo";
const env = { GH_TOKEN: "github_token" };

const fetch = fetchMock
.sandbox()
.getOnce(`https://api.github.local/repos/${owner}/${repo}`, {
permissions: { push: true },
});

const {
errors: [error, ...errors],
} = await t.throwsAsync(
verify(
{ releaseNameTemplate: "" },
{
env,
options: { repositoryUrl: `https://github.com/${owner}/${repo}.git` },
logger: t.context.logger,
},
{
Octokit: TestOctokit.defaults((options) => ({
...options,
request: { ...options.request, fetch },
})),
},
),
);

t.is(errors.length, 0);
t.is(error.name, "SemanticReleaseError");
t.is(error.code, "EINVALIDRELEASENAMETEMPLATE");
t.true(fetch.done());
});