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
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export default {
key: "jira_service_desk-create-comment-on-request",
name: "Create Comment on Request",
description: "Create a comment on a customer request. [See the documentation](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-request/#api-rest-servicedeskapi-request-issueidorkey-comment-post)",
version: "0.1.3",
version: "0.1.4",
annotations: {
destructiveHint: false,
openWorldHint: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ export default {
+ " Use **List Sites** to get `cloudId`, **List Service Desks** to get `serviceDeskId`, and **List Request Types** to choose the `requestTypeId` whose name and description match the user's intent."
+ " Call **List Request Type Fields** to see which fields that request type requires; pass anything beyond summary and description in `additionalFieldValues`, keyed by Jira field ID."
+ " Worked example: on service desk `1`, request type `4` (\"Onboard new employees\") requires `summary` and also accepts a `duedate`, so call with Summary `Joseph Wilson starts on September 1`, Description `Needs a laptop and an email account`, and Additional Field Values `{ \"duedate\": \"2026-09-01\" }`."
+ " Returns the created request including its `issueKey` and `issueId`."
+ " Optionally attach one or more files at creation time via `attachments`; to add, replace, or delete attachments on a request that already exists, use **Manage Request Attachment** instead."
+ " Returns the created request including its `issueKey` and `issueId`. If `attachments` is set, the response also includes either an `attachments` array (on success) or an `attachmentError` string (if the request was created but the attachment step failed) — the request itself is never rolled back because of an attachment failure."
+ " [See the documentation](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-request/#api-rest-servicedeskapi-request-post)",
version: "1.0.3",
version: "1.1.0",
annotations: {
destructiveHint: false,
openWorldHint: true,
Expand Down Expand Up @@ -95,6 +96,26 @@ export default {
description: "Extra information about the channel the request came in on. Marked experimental by Atlassian.",
optional: true,
},
attachments: {
type: "string[]",
label: "Attachments",
description: "File(s) to attach to the request as it's created. Provide file URLs or paths to files in the /tmp directory (e.g. `/tmp/myFile.pdf`).",
format: "file-ref",
optional: true,
},
attachmentsPublic: {
type: "boolean",
label: "Attachments Public",
description: "Whether the attached file(s) are visible to the customer who raised the request. Defaults to `true`; set to `false` to attach internal-only files.",
optional: true,
default: true,
},
syncDir: {
type: "dir",
accessMode: "read",
sync: true,
optional: true,
},
},
async run({ $ }) {
const {
Expand All @@ -110,6 +131,8 @@ export default {
form,
isAdfRequest,
channel,
attachments,
attachmentsPublic,
} = this;

let extraFields = additionalFieldValues;
Expand Down Expand Up @@ -172,7 +195,32 @@ export default {
},
});

$.export("$summary", `Successfully created request ${response.issueKey}`);
return response;
if (!attachments?.length) {
$.export("$summary", `Successfully created request ${response.issueKey}`);
return response;
}

try {
const attachResponse = await jiraServiceDesk.attachFilesToRequestFromSource({
$,
cloudId,
serviceDeskId,
issueIdOrKey: response.issueKey,
files: attachments,
isPublic: attachmentsPublic,
});

$.export("$summary", `Created request ${response.issueKey} with ${attachments.length} attachment(s)`);
return {
...response,
attachments: attachResponse.attachments.values,
};
} catch (error) {
$.export("$summary", `Created request ${response.issueKey}, but attaching file(s) failed: ${error.message}`);
return {
...response,
attachmentError: error.message,
};
}
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default {
key: "jira_service_desk-download-issue-attachment",
name: "Download Issue Attachment",
description: "Download the binary content of a Jira Service Desk attachment to the file-stash directory, returning the saved path plus the attachment metadata (`filename`, `mimeType`, `size`). Run **List Issue Attachments** first to obtain the attachment `id`, then pass both it and the same `issueIdOrKey` here. Example: passing `issueIdOrKey` `IT-42` and `attachmentId` `10042` downloads `screenshot.png` to `/tmp/10042-screenshot.png` and returns `{ \"filedata\": [\"10042-screenshot.png\", \"/tmp/10042-screenshot.png\"], \"attachment\": { \"id\": \"10042\", \"filename\": \"screenshot.png\", \"mimeType\": \"image/png\", \"size\": 84213 } }`. [See the documentation](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-request/#api-rest-servicedeskapi-request-issueidorkey-attachment-attachmentid-get)",
version: "0.0.2",
version: "0.0.3",
type: "action",
ai: "optimized",
annotations: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default {
+ " Use this to identify who is logged in, or to filter requests by the current user's `account_id`."
+ " No `cloudId` required — this uses the Atlassian Identity API directly."
+ " [See the documentation](https://developer.atlassian.com/cloud/jira/platform/oauth-2-3lo-apps/)",
version: "0.0.6",
version: "0.0.7",
type: "action",
ai: "optimized",
annotations: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default {
+ " Use **List Sites** first to obtain the required `cloudId`."
+ " Use **List My Requests** to find the `issueKey` (e.g. `IT-42`)."
+ " [See the documentation](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-request/#api-rest-servicedeskapi-request-issueidorkey-status-get)",
version: "1.1.3",
version: "1.1.4",
type: "action",
ai: "optimized",
annotations: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default {
+ " Use **List Sites** first to obtain the required `cloudId`."
+ " Use **List My Requests** to find the `issueKey` of a request (e.g. `IT-42`)."
+ " [See the documentation](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-request/#api-rest-servicedeskapi-request-issueidorkey-get)",
version: "0.2.3",
version: "0.2.4",
type: "action",
ai: "optimized",
annotations: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export default {
key: "jira_service_desk-list-cloud-id-options",
name: "List Cloud ID Options",
description: "Lists the Atlassian sites you can raise requests on, as `{label, value}` options, to discover the `cloudId` every other Jira Service Desk tool needs. Takes no input beyond the account. Example: returns `[{ \"label\": \"acme\", \"value\": \"822faf0d-5427-420e-9016-999d3dc76918\" }]`. Use **List Sites** instead if you want the full site records. [See the documentation](https://developer.atlassian.com/cloud/jira/platform/oauth-2-3lo-apps/#3-1-get-the-cloudid-for-your-site)",
version: "0.1.2",
version: "0.1.3",
type: "action",
annotations: {
destructiveHint: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default {
key: "jira_service_desk-list-issue-attachments",
name: "List Issue Attachments",
description: "List metadata for every attachment on a Jira Service Desk request. `issueIdOrKey` accepts either a Jira issue key (e.g. `IT-42`) or a numeric Jira issue ID (e.g. `10001`). Results are paginated automatically up to `maxResults`. Returns `{ attachments, truncated }`, where each attachment includes `id`, `filename`, `size` (bytes), `mimeType`, and `content` (an opaque reference URL whose exact shape varies by account access level and is **not** directly fetchable through this connection's authentication), and `truncated` is `true` when more attachments remained unfetched. Use **Download Issue Attachment** with an attachment `id` and the same `issueIdOrKey` to fetch the binary content — do not call `content` directly. If this connection has customer-level access rather than agent access, only public attachments are returned; internal attachments exist but won't appear here. Returns `{ attachments: [], truncated: false }` (no error) when the request exists but has no visible attachments. Example: issue `IT-42` with one attachment returns `{ \"attachments\": [{ \"id\": \"10042\", \"filename\": \"screenshot.png\", \"size\": 84213, \"mimeType\": \"image/png\", \"content\": \"<opaque reference URL>\" }], \"truncated\": false }`. [See the documentation](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-request/#api-rest-servicedeskapi-request-issueidorkey-attachment-get)",
version: "0.0.2",
version: "0.0.3",
type: "action",
ai: "optimized",
annotations: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export default {
+ " `requestStatus`: `OPEN_REQUESTS` (default), `CLOSED_REQUESTS`, or `ALL_REQUESTS`."
+ " `requestOwnership`: `OWNED_REQUESTS` (default) or `PARTICIPATED_REQUESTS`."
+ " [See the documentation](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-request/#api-rest-servicedeskapi-request-get)",
version: "1.1.3",
version: "1.1.4",
type: "action",
ai: "optimized",
annotations: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default {
+ " Use **List Sites** first to obtain the required `cloudId`."
+ " Use **List My Requests** or **Get Request** to find the `issueKey` (e.g. `IT-42`)."
+ " [See the documentation](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-request/#api-rest-servicedeskapi-request-issueidorkey-transition-get)",
version: "1.1.3",
version: "1.1.4",
type: "action",
ai: "optimized",
annotations: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default {
+ " Also returns `canRaiseOnBehalfOf` and `canAddRequestParticipants`, which tell you whether the `raiseOnBehalfOf` and `requestParticipants` arguments of **Create Request** are usable with this account."
+ " Hidden fields are only visible to service desk administrators."
+ " [See the documentation](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-servicedesk/#api-rest-servicedeskapi-servicedesk-servicedeskid-requesttype-requesttypeid-field-get)",
version: "0.0.4",
version: "0.0.5",
type: "action",
ai: "optimized",
annotations: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export default {
+ " Types with `canCreateRequest: false` cannot be used to raise a request."
+ " Then call **List Request Type Fields** to see what the chosen type requires."
+ " [See the documentation](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-servicedesk/#api-rest-servicedeskapi-servicedesk-servicedeskid-requesttype-get)",
version: "0.0.4",
version: "0.0.5",
type: "action",
ai: "optimized",
annotations: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default {
+ " Returns `{ serviceDesks, truncated }`, where `truncated` is `true` when more desks remained unfetched."
+ " Example: a site with one desk returns `{ \"serviceDesks\": [{ \"id\": \"1\", \"projectName\": \"Support\", \"projectKey\": \"SUP\" }], \"truncated\": false }`."
+ " [See the documentation](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-servicedesk/#api-rest-servicedeskapi-servicedesk-get)",
version: "0.0.4",
version: "0.0.5",
type: "action",
ai: "optimized",
annotations: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default {
+ " **Call this tool first** to obtain the `cloudId` (returned as `id`) required by every other Jira Service Desk tool."
+ " Each site includes its `id` (cloudId), `name`, and `url`."
+ " [See the documentation](https://developer.atlassian.com/cloud/jira/platform/oauth-2-3lo-apps/#3-1-get-the-cloudid-for-your-site)",
version: "0.0.6",
version: "0.0.7",
type: "action",
ai: "optimized",
annotations: {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
import { ConfigurationError } from "@pipedream/platform";
import jiraServiceDesk from "../../jira_service_desk.app.mjs";
import constants from "../../common/constants.mjs";

export default {
key: "jira_service_desk-manage-request-attachment",
name: "Manage Request Attachment",
description:
"Adds, replaces, or deletes a single attachment on a customer request (ticket) that already exists."
+ " To attach file(s) while creating a brand-new request, use **Create Request**'s `attachments` prop instead — use this tool only for requests that already exist."
+ " Set `operation` to `add` to attach a new file, `update` to replace an existing attachment with a different file (there's no in-place replace in the API, so this uploads the new file and only deletes the old one once the new one is confirmed attached), or `delete` to remove an attachment."
+ " `add` and `update` require `serviceDeskId` (the temp-file upload step is scoped by service desk, not by issue) — use **List Service Desks** to find it, or read it off the response of the request that created the ticket."
+ " `update` and `delete` require `attachmentId`, the numeric ID of the attachment being replaced or removed; the `add`/`update` response doesn't expose this as a plain field, so use **List Issue Attachments** on the same request to look it up."
+ " Worked example: to replace an attachment `10050` on request `HD-12` with a new file, call with Operation `update`, Issue ID Or Key `HD-12`, Service Desk ID `1`, Attachment ID `10050`, and File `/tmp/revised-report.pdf`."
+ " For `update`, if the new file attaches successfully but removing the old attachment then fails, the response includes a `deleteError` string alongside the successful attachment data — the request ends up with both files rather than losing either one, and the error is never masked as a full failure."
+ " By default the attachment is visible to the customer who raised the request (`public: true`); set `public` to `false` to attach an internal-only file."
+ " [See the documentation](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-request/#api-rest-servicedeskapi-request-issueidorkey-attachment-post)",
version: "0.0.1",
annotations: {
destructiveHint: true,
openWorldHint: true,
readOnlyHint: false,
},
type: "action",
ai: "optimized",
props: {
jiraServiceDesk,
cloudId: {
propDefinition: [
jiraServiceDesk,
"cloudId",
],
},
operation: {
type: "string",
label: "Operation",
description: "Whether to add a new attachment, replace (`update`) an existing one, or delete one.",
options: [
"add",
"update",
"delete",
],
},
issueIdOrKey: {
propDefinition: [
jiraServiceDesk,
"issueIdOrKey",
],
},
serviceDeskId: {
propDefinition: [
jiraServiceDesk,
"serviceDeskId",
],
description: "Required for `add` and `update`. The service desk the request belongs to. Use **List Service Desks** to find valid IDs (e.g. `1`).",
optional: true,
},
file: {
type: "string",
label: "File",
description: "Required for `add` and `update`. The file to attach, as a file URL or a path to a file in the /tmp directory (e.g. `/tmp/myFile.pdf`).",
format: "file-ref",
optional: true,
},
attachmentId: {
type: "string",
label: "Attachment ID",
description: "Required for `update` and `delete`. The numeric ID of the attachment being replaced or removed, e.g. `10050`. The `add`/`update` response doesn't expose this as a plain field — the ID is only embedded in a `_links.jiraRest` URL nested under `attachments.values[]`. Use **List Issue Attachments** instead, which extracts the ID for you.",
optional: true,
},
public: {
type: "boolean",
label: "Public",
description: "Whether the attached file is visible to the customer who raised the request. Defaults to `true`; set to `false` to attach an internal-only file. Only applies to `add` and `update`.",
optional: true,
default: true,
},
syncDir: {
type: "dir",
accessMode: "read",
sync: true,
optional: true,
},
},
async run({ $ }) {
const {
jiraServiceDesk,
cloudId,
operation,
issueIdOrKey,
serviceDeskId,
file,
attachmentId,
public: isPublic,
} = this;

const verifyAttachmentBelongsToRequest = async () => {
const { attachments } = await jiraServiceDesk.getIssueAttachments({
$,
cloudId,
issueIdOrKey,
maxResults: constants.MAX_RESULTS_MAX,
});
if (!attachments.some(({ id }) => id === attachmentId)) {
throw new ConfigurationError(`Attachment ID "${attachmentId}" was not found on request "${issueIdOrKey}". Run List Issue Attachments to confirm the ID and issue match.`);
}
};

if (operation === "delete") {
if (!attachmentId) {
throw new ConfigurationError("Attachment ID is required to delete an attachment.");
}
await verifyAttachmentBelongsToRequest();
await jiraServiceDesk.deleteAttachment({
$,
cloudId,
attachmentId,
});
Comment thread
coderabbitai[bot] marked this conversation as resolved.
$.export("$summary", `Deleted attachment ${attachmentId} from request ${issueIdOrKey}`);
return {
deleted: true,
attachmentId,
};
}

if (!serviceDeskId) {
throw new ConfigurationError("Service Desk ID is required to add or update an attachment.");
}
if (!file) {
throw new ConfigurationError("File is required to add or update an attachment.");
}
if (operation === "update") {
if (!attachmentId) {
throw new ConfigurationError("Attachment ID is required to update (replace) an attachment.");
}
await verifyAttachmentBelongsToRequest();
}

const attachResponse = await jiraServiceDesk.attachFilesToRequestFromSource({
$,
cloudId,
serviceDeskId,
issueIdOrKey,
files: [
file,
],
isPublic,
});

// The new attachment must succeed before the old one is removed — deleting first
// would leave the request with no attachment at all if the upload then failed.
if (operation === "update") {
try {
await jiraServiceDesk.deleteAttachment({
$,
cloudId,
attachmentId,
});
} catch (error) {
$.export("$summary", `Added the new attachment on request ${issueIdOrKey}, but the old attachment (${attachmentId}) could not be removed: ${error.message}`);
return {
...attachResponse,
deleteError: error.message,
};
}
}

$.export("$summary", `${operation === "update"
? "Replaced"
: "Added"} attachment on request ${issueIdOrKey}`);
return attachResponse;
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default {
+ " Use **List My Requests** or **Get Request** to find the `issueKey` (e.g. `IT-42`)."
+ " Optionally include a comment to explain the transition."
+ " [See the documentation](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-request/#api-rest-servicedeskapi-request-issueidorkey-transition-post)",
version: "0.1.3",
version: "0.1.4",
type: "action",
ai: "optimized",
annotations: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default {
+ " `fields` is a JSON object of field name-value pairs."
+ " Example: `{\"summary\": \"Updated title\", \"priority\": {\"name\": \"High\"}}`."
+ " [See the documentation](https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/#api-rest-api-3-issue-issueidorkey-put)",
version: "0.1.3",
version: "0.1.4",
type: "action",
ai: "optimized",
annotations: {
Expand Down
Loading
Loading