mirror of
https://github.com/matrix-org/matrix-hookshot.git
synced 2025-03-10 21:19:13 +00:00
Add commands to remove/list Jira connections (#503)
* Add commands to remove/list Jira connections * Add docs page for Jira connections * Clarify "instance" and webhook reqs in Jira docs - Jira has "instances" instead of "organizations", so use the former term - Don't suggest that webhook support can work for multiple instances - Mention that webhooks require special access - Make some minor grammar changes
This commit is contained in:
parent
80a26283e9
commit
fa85dc070b
1
changelog.d/503.feature
Normal file
1
changelog.d/503.feature
Normal file
@ -0,0 +1 @@
|
||||
Add bot commands to list and remove Jira connections.
|
@ -15,6 +15,7 @@
|
||||
- [Room Configuration](./usage/room_configuration.md)
|
||||
- [GitHub Repo](./usage/room_configuration/github_repo.md)
|
||||
- [GitLab Project](./usage/room_configuration/gitlab_project.md)
|
||||
- [JIRA Project](./usage/room_configuration/jira_project.md)
|
||||
- [📊 Metrics](./metrics.md)
|
||||
|
||||
# 🧑💻 Development
|
||||
|
@ -1,21 +1,22 @@
|
||||
# JIRA
|
||||
|
||||
## Adding a webhook to a JIRA Organisation
|
||||
## Adding a webhook to a JIRA Instance
|
||||
|
||||
This should be done for all JIRA organisations you wish to bridge. The setup steps are the same for both On-Prem and Cloud.
|
||||
This should be done for the JIRA instance you wish to bridge. The setup steps are the same for both On-Prem and Cloud.
|
||||
|
||||
You need to go to the `WebHooks` configuration page under Settings > System.
|
||||
Note that this may require administrative access to the JIRA instance.
|
||||
|
||||
Next, add a webhook that points to `/` on the public webhooks address for hookshot. You should also include a
|
||||
secret value by appending `?secret=your-webhook-secret`. The secret value can be anything, but should
|
||||
be reasonably secure and should also be stored in the `config.yml` file.
|
||||
|
||||
Ensure that you enable all the events that you wish to be bridge.
|
||||
Ensure that you enable all the events that you wish to be bridged.
|
||||
|
||||
|
||||
## Configuration
|
||||
|
||||
You can now set some configuration in the bridge `config.yml`
|
||||
You can now set some configuration in the bridge `config.yml`:
|
||||
|
||||
```yaml
|
||||
jira:
|
||||
|
38
docs/usage/room_configuration/jira_project.md
Normal file
38
docs/usage/room_configuration/jira_project.md
Normal file
@ -0,0 +1,38 @@
|
||||
JIRA Project
|
||||
=================
|
||||
|
||||
This connection type connects a JIRA project to a room.
|
||||
|
||||
You can run commands to create and assign issues, and receive notifications when issues are created.
|
||||
|
||||
## Setting up
|
||||
|
||||
To set up a connection to a JIRA project in a new room:
|
||||
|
||||
(NB you must have permission to bridge JIRA projects before you can use this command, see [auth](../auth.html#jira).)
|
||||
|
||||
1. Create a new, unencrypted room. It can be public or private.
|
||||
1. Invite the bridge bot (e.g. `@hookshot:example.com`).
|
||||
1. Give the bridge bot moderator permissions or higher (power level 50) (or otherwise configure the room so the bot can edit room state).
|
||||
1. Send the command `!hookshot jira project https://jira-instance/.../projects/PROJECTKEY/...`.
|
||||
1. If you have permission to bridge this repo, the bridge will respond with a confirmation message.
|
||||
|
||||
## Managing connections
|
||||
|
||||
Send the command `!hookshot jira list project` to list all of a room's connections to JIRA projects.
|
||||
|
||||
Send the command `!hookshot jira remove project <url>` to remove a room's connection to a JIRA project at a given URL.
|
||||
|
||||
## Configuration
|
||||
|
||||
This connection supports a few options which can be defined in the room state:
|
||||
|
||||
| Option | Description | Allowed values | Default |
|
||||
|--------|-------------|----------------|---------|
|
||||
|events|Choose to include notifications for some event types|Array of: [Supported event types](#supported-event-types) |*empty*|
|
||||
|commandPrefix|Choose the prefix to use when sending commands to the bot|A string, ideally starts with "!"|`!jira`|
|
||||
|
||||
|
||||
### Supported event types
|
||||
|
||||
This connection currently supports sending messages only when a `issue.created` action happens on the project.
|
@ -1,7 +1,7 @@
|
||||
// We need to instantiate some functions which are not directly called, which confuses typescript.
|
||||
import { BotCommands, botCommand, compileBotCommands, HelpFunction } from "../BotCommands";
|
||||
import { CommandConnection } from "./CommandConnection";
|
||||
import { GenericHookConnection, GitHubRepoConnection, JiraProjectConnection } from ".";
|
||||
import { GenericHookConnection, GitHubRepoConnection, JiraProjectConnection, JiraProjectConnectionState } from ".";
|
||||
import { CommandError } from "../errors";
|
||||
import { v4 as uuid } from "uuid";
|
||||
import { BridgePermissionLevel } from "../Config/Config";
|
||||
@ -112,29 +112,93 @@ export class SetupConnection extends CommandConnection {
|
||||
await this.as.botClient.sendNotice(this.roomId, `Room configured to bridge ${connection.path}`);
|
||||
}
|
||||
|
||||
private async checkJiraLogin(userId: string, urlStr: string) {
|
||||
const jiraClient = await this.provisionOpts.tokenStore.getJiraForUser(userId, urlStr);
|
||||
if (!jiraClient) {
|
||||
throw new CommandError("User not logged in", "You are not logged into Jira. Start a DM with this bot and use the command `jira login`.");
|
||||
}
|
||||
}
|
||||
|
||||
private async getJiraProjectSafeUrl(userId: string, urlStr: string) {
|
||||
const url = new URL(urlStr);
|
||||
const urlParts = /\/projects\/(\w+)\/?(\w+\/?)*$/.exec(url.pathname);
|
||||
const projectKey = urlParts?.[1] || url.searchParams.get('projectKey');
|
||||
if (!projectKey) {
|
||||
throw new CommandError("Invalid Jira url", "The JIRA project url you entered was not valid. It should be in the format of `https://jira-instance/.../projects/PROJECTKEY/...` or `.../RapidBoard.jspa?projectKey=TEST`.");
|
||||
}
|
||||
return `https://${url.host}/projects/${projectKey}`;
|
||||
}
|
||||
|
||||
@botCommand("jira project", { help: "Create a connection for a JIRA project. (You must be logged in with JIRA to do this.)", requiredArgs: ["url"], includeUserId: true, category: "jira"})
|
||||
public async onJiraProject(userId: string, urlStr: string) {
|
||||
const url = new URL(urlStr);
|
||||
if (!this.config.jira) {
|
||||
throw new CommandError("not-configured", "The bridge is not configured to support Jira.");
|
||||
}
|
||||
|
||||
await this.checkUserPermissions(userId, "jira", JiraProjectConnection.CanonicalEventType);
|
||||
await this.checkJiraLogin(userId, urlStr);
|
||||
const safeUrl = await this.getJiraProjectSafeUrl(userId, urlStr);
|
||||
|
||||
const jiraClient = await this.provisionOpts.tokenStore.getJiraForUser(userId, urlStr);
|
||||
if (!jiraClient) {
|
||||
throw new CommandError("User not logged in", "You are not logged into Jira. Start a DM with this bot and use the command `jira login`.");
|
||||
}
|
||||
const urlParts = /.+\/projects\/(\w+)\/?(\w+\/?)*$/.exec(url.pathname.toLowerCase());
|
||||
const projectKey = urlParts?.[1] || url.searchParams.get('projectKey');
|
||||
if (!projectKey) {
|
||||
throw new CommandError("Invalid Jira url", "The JIRA project url you entered was not valid. It should be in the format of `https://jira-instance/.../projects/PROJECTKEY/...` or `.../RapidBoard.jspa?projectKey=TEST`.");
|
||||
}
|
||||
const safeUrl = `https://${url.host}/projects/${projectKey}`;
|
||||
const res = await JiraProjectConnection.provisionConnection(this.roomId, userId, { url: safeUrl }, this.provisionOpts);
|
||||
await this.as.botClient.sendNotice(this.roomId, `Room configured to bridge Jira project ${res.connection.projectKey}.`);
|
||||
}
|
||||
|
||||
@botCommand("jira list project", { help: "Show JIRA projects currently connected to.", category: "jira"})
|
||||
public async onJiraListProject() {
|
||||
const projects: JiraProjectConnectionState[] = await this.as.botClient.getRoomState(this.roomId).catch((err: any) => {
|
||||
if (err.body.errcode === 'M_NOT_FOUND') {
|
||||
return []; // not an error to us
|
||||
}
|
||||
throw err;
|
||||
}).then(events =>
|
||||
events.filter(
|
||||
(ev: any) => (
|
||||
ev.type === JiraProjectConnection.CanonicalEventType ||
|
||||
ev.type === JiraProjectConnection.LegacyCanonicalEventType
|
||||
) && ev.content.url
|
||||
).map(ev => ev.content)
|
||||
);
|
||||
|
||||
if (projects.length === 0) {
|
||||
return this.as.botClient.sendHtmlNotice(this.roomId, md.renderInline('Not connected to any JIRA projects'));
|
||||
} else {
|
||||
return this.as.botClient.sendHtmlNotice(this.roomId, md.render(
|
||||
'Currently connected to these JIRA projects:\n\n' +
|
||||
projects.map(project => ` - ${project.url}`).join('\n')
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@botCommand("jira remove project", { help: "Remove a connection for a JIRA project.", requiredArgs: ["url"], includeUserId: true, category: "jira"})
|
||||
public async onJiraRemoveProject(userId: string, urlStr: string) {
|
||||
await this.checkUserPermissions(userId, "jira", JiraProjectConnection.CanonicalEventType);
|
||||
await this.checkJiraLogin(userId, urlStr);
|
||||
const safeUrl = await this.getJiraProjectSafeUrl(userId, urlStr);
|
||||
|
||||
const eventTypes = [
|
||||
JiraProjectConnection.CanonicalEventType,
|
||||
JiraProjectConnection.LegacyCanonicalEventType,
|
||||
];
|
||||
let event = null;
|
||||
let eventType = "";
|
||||
for (eventType of eventTypes) {
|
||||
try {
|
||||
event = await this.as.botClient.getRoomStateEvent(this.roomId, eventType, safeUrl);
|
||||
break;
|
||||
} catch (err: any) {
|
||||
if (err.body.errcode !== 'M_NOT_FOUND') {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!event || Object.keys(event).length === 0) {
|
||||
throw new CommandError("Invalid Jira project URL", `Feed "${urlStr}" is not currently bridged to this room`);
|
||||
}
|
||||
|
||||
await this.as.botClient.sendStateEvent(this.roomId, eventType, safeUrl, {});
|
||||
return this.as.botClient.sendHtmlNotice(this.roomId, md.renderInline(`Room no longer bridged to Jira project \`${safeUrl}\`.`));
|
||||
}
|
||||
|
||||
@botCommand("webhook", { help: "Create an inbound webhook.", requiredArgs: ["name"], includeUserId: true, category: "webhook"})
|
||||
public async onWebhook(userId: string, name: string) {
|
||||
if (!this.config.generic?.enabled) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user