Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Block Kit for slack messages #1815

Merged
merged 13 commits into from Mar 2, 2021
Binary file added docs/public/logo-large-dark.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/public/logo-large.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Expand Up @@ -105,3 +105,12 @@ Found unknown configuration keys: types.doc
",
]
`;

exports[`validatePlugin should validate plugin configuration - union 1`] = `
Array [
"\\"test-plugin\\"

Found missing configuration keys: when using auth you must also provide channels
",
]
`;
57 changes: 57 additions & 0 deletions packages/core/src/__tests__/validate-config.test.ts
Expand Up @@ -427,6 +427,63 @@ describe("validatePlugin", () => {
).toMatchSnapshot();
});

test("should validate plugin configuration - union", async () => {
const hook: ValidatePluginHook = new AsyncSeriesBailHook([
"name",
"options",
]);

const basePluginOptions = t.partial({
/** URL of the slack to post to */
url: t.string,
/** Who to bother when posting to the channel */
atTarget: t.string,
/** Allow users to opt into having prereleases posted to slack */
publishPreRelease: t.boolean,
/** Additional Title to add at the start of the slack message */
title: t.string,
});

const appPluginOptions = t.intersection([
t.interface({
/** Marks we are gonna use app auth */
auth: t.literal("app"),
/** Channels to post */
channels: t.array(t.string),
}),
basePluginOptions,
]);

const pluginOptions = t.union([basePluginOptions, appPluginOptions]);

hook.tapPromise("test", async (name, options) => {
if (name === "test-plugin") {
return validatePluginConfiguration(
"test-plugin",
pluginOptions,
options
);
}
});

expect(
await validatePlugins(hook, {
plugins: [["test-plugin", { url: "foo" }]],
})
).toStrictEqual([]);
expect(
await validatePlugins(hook, {
plugins: [["test-plugin", { auth: "app" }]],
})
).toMatchSnapshot();
// Check no validation issues with intersected options
expect(
await validatePlugins(hook, {
plugins: [["test-plugin", { auth: "app", channels: ['foo'] }]],
})
).toStrictEqual([]);
});

test("should validate plugin configuration - array of configurations", async () => {
const hook: ValidatePluginHook = new AsyncSeriesBailHook([
"name",
Expand Down
44 changes: 43 additions & 1 deletion packages/core/src/validate-config.ts
Expand Up @@ -228,7 +228,8 @@ export const validateIoConfiguration = (
return errors;
}

const exactRc = makeExactType(configDeceleration).decode(rc);
const exactDeclaration = makeExactType(configDeceleration);
const exactRc = exactDeclaration.decode(rc);

if (!isRight(looseRc) || !isRight(exactRc)) {
return [];
Expand All @@ -247,6 +248,47 @@ export const validateIoConfiguration = (
return [];
}

if (
(exactDeclaration as any)._tag === "UnionType" &&
"types" in exactDeclaration &&
exactDeclaration.types.every(
(type) =>
type._tag === "IntersectionType" || (type as any)._tag === "ExactType"
)
) {
const decodedTypes = exactDeclaration.types.map((t) => t.decode(rc));
const matchingMissingMember = decodedTypes.filter((t) => "left" in t)[0];

if (matchingMissingMember && "left" in matchingMissingMember) {
const correct = Object.keys(
matchingMissingMember.left[0].context[0].actual as any
);
const missing =
matchingMissingMember.left[0].context[
matchingMissingMember.left[0].context.length - 1
].key;

return [
`${errorPath(
`"${name}"`
)}\n\nFound missing configuration keys: when using ${chalk.greenBright.bold(
correct.join(", ")
)} you must also provide ${unexpectedValue(missing)}\n`,
];
}

const matchingCorrectMember = decodedTypes.filter(
(t) =>
"right" in t &&
Object.keys(t.right).length &&
Object.keys(t.right).every((key) => unknownKeys.includes(key))
)[0];

if (matchingCorrectMember) {
return [];
}
}

return [
`${errorPath(
`"${name}"`
Expand Down
21 changes: 21 additions & 0 deletions plugins/microsoft-teams/__tests__/__snapshots__/index.test.ts.snap
@@ -0,0 +1,21 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`createPost should add more indents to nested lists - 2 spaces 1`] = `"{\\"@context\\":\\"http://schema.org/extensions\\",\\"@type\\":\\"MessageCard\\",\\"text\\":\\"@channel: New release *<https://git.hub/some/project/releases/v1.0.0|v1.0.0>*\\\\n*My Notes*\\\\n• PR <google.com|some link>\\\\n • Another note\\"}"`;

exports[`createPost should add more indents to nested lists 1`] = `"{\\"@context\\":\\"http://schema.org/extensions\\",\\"@type\\":\\"MessageCard\\",\\"text\\":\\"@channel: New release *<https://git.hub/some/project/releases/v1.0.0|v1.0.0>*\\\\n*My Notes*\\\\n• PR <google.com|some link>\\\\n • Another note\\"}"`;

exports[`createPost should add title 1`] = `"{\\"@context\\":\\"http://schema.org/extensions\\",\\"@type\\":\\"MessageCard\\",\\"text\\":\\"@channel: New release *<https://git.hub/some/project/releases/v1.0.0|v1.0.0>*\\\\n*My Notes*\\\\n• PR <google.com|some link>\\"}"`;

exports[`createPost should call slack api 1`] = `"{\\"@context\\":\\"http://schema.org/extensions\\",\\"@type\\":\\"MessageCard\\",\\"text\\":\\"@channel: New release *<https://git.hub/some/project/releases/v1.0.0|v1.0.0>*\\\\n*My Notes*\\\\n• PR <google.com|some link>\\"}"`;

exports[`createPost should call slack api in env var 1`] = `"{\\"@context\\":\\"http://schema.org/extensions\\",\\"@type\\":\\"MessageCard\\",\\"text\\":\\"@channel: New release *<https://git.hub/some/project/releases/v1.0.0|v1.0.0>*\\\\n*My Notes*\\\\n• PR <google.com|some link>\\"}"`;

exports[`createPost should call slack api through http proxy 1`] = `"{\\"@context\\":\\"http://schema.org/extensions\\",\\"@type\\":\\"MessageCard\\",\\"text\\":\\"@channel: New release *<https://git.hub/some/project/releases/v1.0.0|v1.0.0>*\\\\n*My Notes*\\\\n• PR <google.com|some link>\\"}"`;

exports[`createPost should call slack api through https proxy 1`] = `"{\\"@context\\":\\"http://schema.org/extensions\\",\\"@type\\":\\"MessageCard\\",\\"text\\":\\"@channel: New release *<https://git.hub/some/project/releases/v1.0.0|v1.0.0>*\\\\n*My Notes*\\\\n• PR <google.com|some link>\\"}"`;

exports[`createPost should call slack api with custom atTarget 1`] = `"{\\"@context\\":\\"http://schema.org/extensions\\",\\"@type\\":\\"MessageCard\\",\\"text\\":\\"@here: New release *<https://git.hub/some/project/releases/v1.0.0|v1.0.0>*\\\\n*My Notes*\\\\n• PR <google.com|some link>\\"}"`;

exports[`createPost should call slack api with minimal config 1`] = `"{\\"@context\\":\\"http://schema.org/extensions\\",\\"@type\\":\\"MessageCard\\",\\"text\\":\\"@channel: New release *<https://git.hub/some/project/releases/v1.0.0|v1.0.0>*\\\\n*My Notes*\\\\n• PR <google.com|some link>\\"}"`;

exports[`createPost should remove markdown code types from block 1`] = `"{\\"@context\\":\\"http://schema.org/extensions\\",\\"@type\\":\\"MessageCard\\",\\"text\\":\\"@channel: New release *<https://git.hub/some/project/releases/v1.0.0|v1.0.0>*\\\\n*My Notes*\\\\n\`json\`:\\\\n\\\\n\`\`\`\\\\n{ \\\\\\"foo\\\\\\": \\\\\\"bar\\\\\\" }\`\`\`\\\\n• PR <google.com|some link>\\"}"`;