Skip to content

Release v4.0.4 #342

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

Merged
merged 4 commits into from
Jan 4, 2025
Merged
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
42 changes: 42 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,47 @@
# Jira.js changelog

### 4.0.4

- **#320:** Resolved a tree-shaking issue where importing a single client would still include all clients in the output bundle when using bundlers. Now, only the required client code is included. Thanks to [Nao Yonashiro](https://github.com/orisano) for [reporting the issue](https://github.com/MrRefactoring/jira.js/issues/320) and proposing a fix.
- **#327:** Replaced the `form-data` library with `formdata-node` to enable compatibility with `ESM` projects when adding attachments via the `issueAttachment.addAttachment` method. Thanks to [Paweł Król](https://github.com/xpawk) for [reporting the issue](https://github.com/MrRefactoring/jira.js/issues/327) and [Matyáš Kroupa](https://github.com/krouma) for implementing the fix.
- **Improvement:** The type of the `projectIdOrKey` property was updated from `string` to `number | string` for project update operations. This enhancement improves type safety and flexibility when handling project identifiers.
- **Enhancement:** Added a `mimeType` property to the `version2.issueAttachments.addAttachment`, `version3.issueAttachments.addAttachment`, and `serviceDesk.serviceDesk.attachTemporaryFile` methods. This allows specifying the file type. If `mimeType` is not provided, a default type is inferred from the filename.

#### Examples:

**👎 Before:**

```typescript
const client = new Version2Client() || new Version3Client() || new ServiceDeskClient();

const attachment = await client.issueAttachments.addAttachment({
issueIdOrKey: issue.key,
attachment: {
filename: 'issueAttachments.test.ts',
file: fs.readFileSync('./tests/integration/version2/issueAttachments.test.ts'),
},
});

console.log(attachment[0].mimeType); // Will be 'video/mp2t'
```

**👍 Now:**

```typescript
const client = new Version2Client() || new Version3Client() || new ServiceDeskClient();

const attachment = await client.issueAttachments.addAttachment({
issueIdOrKey: issue.key,
attachment: {
filename: 'issueAttachments.test.ts',
file: fs.readFileSync('./tests/integration/version2/issueAttachments.test.ts'),
mimeType: 'application/typescript',
},
});

console.log(attachment[0].mimeType); // Will be 'application/typescript'
```

### 4.0.3

- **Bug Fix:** Fixed an issue with the `Users.createUser` method by adding the required `products` property. Thanks to [Appelberg-s](https://github.com/Appelberg-s) for the [fix](https://github.com/MrRefactoring/jira.js/commit/362918093c20036049db334743e2a0f5f41cbcd4#diff-6960050bc2a3d9ffad9eb5e307145969dc4a38eb5434eebf39da545fd18e01b7R12).
178 changes: 118 additions & 60 deletions package-lock.json
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "jira.js",
"version": "4.0.3",
"version": "4.0.4",
"description": "A comprehensive JavaScript/TypeScript library designed for both Node.JS and browsers, facilitating seamless interaction with the Atlassian Jira API.",
"main": "out/index.js",
"types": "out/index.d.ts",
@@ -53,6 +53,7 @@
"code:formatting": "npm run replace:all && npm run prettier && npm run lint:fix"
},
"devDependencies": {
"@types/mime-types": "^2.1.4",
"@types/node": "^18.19.69",
"@types/sinon": "^17.0.3",
"@typescript-eslint/eslint-plugin": "^8.19.0",
@@ -63,7 +64,7 @@
"eslint-import-resolver-typescript": "^3.7.0",
"eslint-plugin-import": "^2.31.0",
"prettier": "^3.4.2",
"prettier-plugin-jsdoc": "^1.3.0",
"prettier-plugin-jsdoc": "^1.3.2",
"sinon": "^18.0.1",
"typedoc": "^0.27.6",
"typescript": "^5.7.2",
@@ -72,7 +73,8 @@
},
"dependencies": {
"axios": "^1.7.9",
"form-data": "^4.0.1",
"formdata-node": "^6.0.3",
"mime-types": "^2.1.35",
"tslib": "^2.8.1"
}
}
30 changes: 14 additions & 16 deletions src/agile/client/agileClient.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
import { BaseClient } from '../../clients';
import {
Backlog,
Board,
Builds,
Deployments,
DevelopmentInformation,
DevopsComponents,
Epic,
FeatureFlags,
Issue,
Operations,
RemoteLinks,
SecurityInformation,
Sprint,
} from '..';
import { BaseClient } from '../../clients/baseClient';
import { Backlog } from '../backlog';
import { Board } from '../board';
import { Builds } from '../builds';
import { Deployments } from '../deployments';
import { DevelopmentInformation } from '../developmentInformation';
import { DevopsComponents } from '../devopsComponents';
import { Epic } from '../epic';
import { FeatureFlags } from '../featureFlags';
import { Issue } from '../issue';
import { Operations } from '../operations';
import { RemoteLinks } from '../remoteLinks';
import { SecurityInformation } from '../securityInformation';
import { Sprint } from '../sprint';

export class AgileClient extends BaseClient {
backlog = new Backlog(this);
2 changes: 1 addition & 1 deletion src/serviceDesk/client/serviceDeskClient.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BaseClient } from '../../clients';
import { BaseClient } from '../../clients/baseClient';
import { Customer } from '../customer';
import { Info } from '../info';
import { Insight } from '../insight';
92 changes: 91 additions & 1 deletion src/serviceDesk/parameters/attachTemporaryFile.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,103 @@
/**
* Represents an attachment to be temporarily attached to a Service Desk.
*
* @example
* ```typescript
* const attachment: Attachment = {
* filename: 'example.txt',
* file: Buffer.from('Temporary file content'),
* mimeType: 'text/plain',
* };
* ```
*/
export interface Attachment {
/**
* The name of the attachment file.
*
* @example
* ```typescript
* const filename = 'example.png';
* ```
*/
filename: string;

/**
* The content of the attachment. Can be one of the following:
*
* - `Buffer`: For binary data.
* - `ReadableStream`: For streaming large files.
* - `string`: For text-based content.
* - `Blob`: For browser-like blob objects.
* - `File`: For file objects with metadata (e.g., in web environments).
*
* @example
* ```typescript
* const fileContent = Buffer.from('Example content here');
* ```
*/
file: Buffer | ReadableStream | string | Blob | File;

/**
* Optional MIME type of the attachment. Example values include:
*
* - 'application/pdf'
* - 'image/jpeg' If not provided, the MIME type will be automatically detected based on the filename.
*
* @example
* ```typescript
* const mimeType = 'image/jpeg';
* ```
*/
mimeType?: string;
}

/**
* Parameters for attaching temporary files to a Service Desk.
*
* @example
* ```typescript
* const attachTemporaryFileParams: AttachTemporaryFile = {
* serviceDeskId: '5',
* attachment: [
* {
* filename: 'example.txt',
* file: Buffer.from('Temporary file content'),
* mimeType: 'text/plain',
* },
* ],
* };
* ```
*/
export interface AttachTemporaryFile {
/**
* The ID of the Service Desk to which the file will be attached. This can alternatively be a [project
* identifier.](#project-identifiers)
* identifier](#project-identifiers).
*
* @example
* ```typescript
* const serviceDeskId = '5';
* ```
*/
serviceDeskId: string;

/**
* The attachment(s) to be added. Can be a single `Attachment` object or an array of `Attachment` objects.
*
* @example
* ```typescript
* const attachments = [
* {
* filename: 'file1.txt',
* file: Buffer.from('Temporary content 1'),
* mimeType: 'text/plain',
* },
* {
* filename: 'file2.jpeg',
* file: Buffer.from('Temporary content 2'),
* mimeType: 'image/jpeg',
* },
* ];
* ```
*/
attachment: Attachment | Attachment[];
}
13 changes: 10 additions & 3 deletions src/serviceDesk/serviceDesk.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as FormData from 'form-data';
import { FormData, File } from 'formdata-node';
import * as mime from 'mime-types';
import * as Models from './models';
import * as Parameters from './parameters';
import { Callback } from '../callback';
@@ -116,15 +117,21 @@ export class ServiceDesk {
const formData = new FormData();
const attachments = Array.isArray(parameters.attachment) ? parameters.attachment : [parameters.attachment];

attachments.forEach(attachment => formData.append('file', attachment.file, attachment.filename));
attachments.forEach(attachment => {
const mimeType = attachment.mimeType ?? (mime.lookup(attachment.filename) || undefined);
const file = Buffer.isBuffer(attachment.file)
? new File([attachment.file], attachment.filename, { type: mimeType })
: attachment.file;

formData.append('file', file, attachment.filename);
});

const config: RequestConfig = {
url: `/rest/servicedeskapi/servicedesk/${parameters.serviceDeskId}/attachTemporaryFile`,
method: 'POST',
headers: {
'X-Atlassian-Token': 'no-check',
'Content-Type': 'multipart/form-data',
...formData.getHeaders?.(),
},
data: formData,
};
174 changes: 86 additions & 88 deletions src/version2/client/version2Client.ts
Original file line number Diff line number Diff line change
@@ -1,91 +1,89 @@
import { BaseClient } from '../../clients';
import {
AnnouncementBanner,
ApplicationRoles,
AppMigration,
AppProperties,
AuditRecords,
Avatars,
Dashboards,
DynamicModules,
Filters,
FilterSharing,
GroupAndUserPicker,
Groups,
IssueAttachments,
IssueCommentProperties,
IssueComments,
IssueCustomFieldConfigurationApps,
IssueCustomFieldContexts,
IssueCustomFieldOptions,
IssueCustomFieldOptionsApps,
IssueCustomFieldValuesApps,
IssueFieldConfigurations,
IssueFields,
IssueLinks,
IssueLinkTypes,
IssueNavigatorSettings,
IssueNotificationSchemes,
IssuePriorities,
IssueProperties,
IssueRemoteLinks,
IssueResolutions,
Issues,
IssueSearch,
IssueSecurityLevel,
IssueSecuritySchemes,
IssueTypeProperties,
IssueTypes,
IssueTypeSchemes,
IssueTypeScreenSchemes,
IssueVotes,
IssueWatchers,
IssueWorklogProperties,
IssueWorklogs,
JiraExpressions,
JiraSettings,
JQL,
JqlFunctionsApps,
Labels,
LicenseMetrics,
Myself,
Permissions,
PermissionSchemes,
ProjectAvatars,
ProjectCategories,
ProjectComponents,
ProjectEmail,
ProjectFeatures,
ProjectKeyAndNameValidation,
ProjectPermissionSchemes,
ProjectProperties,
ProjectRoleActors,
ProjectRoles,
Projects,
ProjectTypes,
ProjectVersions,
Screens,
ScreenSchemes,
ScreenTabFields,
ScreenTabs,
ServerInfo,
Status,
Tasks,
TimeTracking,
UIModificationsApps,
UserProperties,
Users,
UserSearch,
Webhooks,
Workflows,
WorkflowSchemeDrafts,
WorkflowSchemeProjectAssociations,
WorkflowSchemes,
WorkflowStatusCategories,
WorkflowStatuses,
WorkflowTransitionProperties,
WorkflowTransitionRules,
} from '..';
import { BaseClient } from '../../clients/baseClient';
import { AnnouncementBanner } from '../announcementBanner';
import { ApplicationRoles } from '../applicationRoles';
import { AppMigration } from '../appMigration';
import { AppProperties } from '../appProperties';
import { AuditRecords } from '../auditRecords';
import { Avatars } from '../avatars';
import { Dashboards } from '../dashboards';
import { DynamicModules } from '../dynamicModules';
import { Filters } from '../filters';
import { FilterSharing } from '../filterSharing';
import { GroupAndUserPicker } from '../groupAndUserPicker';
import { Groups } from '../groups';
import { IssueAttachments } from '../issueAttachments';
import { IssueCommentProperties } from '../issueCommentProperties';
import { IssueComments } from '../issueComments';
import { IssueCustomFieldConfigurationApps } from '../issueCustomFieldConfigurationApps';
import { IssueCustomFieldContexts } from '../issueCustomFieldContexts';
import { IssueCustomFieldOptions } from '../issueCustomFieldOptions';
import { IssueCustomFieldOptionsApps } from '../issueCustomFieldOptionsApps';
import { IssueCustomFieldValuesApps } from '../issueCustomFieldValuesApps';
import { IssueFieldConfigurations } from '../issueFieldConfigurations';
import { IssueFields } from '../issueFields';
import { IssueLinks } from '../issueLinks';
import { IssueLinkTypes } from '../issueLinkTypes';
import { IssueNavigatorSettings } from '../issueNavigatorSettings';
import { IssueNotificationSchemes } from '../issueNotificationSchemes';
import { IssuePriorities } from '../issuePriorities';
import { IssueProperties } from '../issueProperties';
import { IssueRemoteLinks } from '../issueRemoteLinks';
import { IssueResolutions } from '../issueResolutions';
import { Issues } from '../issues';
import { IssueSearch } from '../issueSearch';
import { IssueSecurityLevel } from '../issueSecurityLevel';
import { IssueSecuritySchemes } from '../issueSecuritySchemes';
import { IssueTypeProperties } from '../issueTypeProperties';
import { IssueTypes } from '../issueTypes';
import { IssueTypeSchemes } from '../issueTypeSchemes';
import { IssueTypeScreenSchemes } from '../issueTypeScreenSchemes';
import { IssueVotes } from '../issueVotes';
import { IssueWatchers } from '../issueWatchers';
import { IssueWorklogProperties } from '../issueWorklogProperties';
import { IssueWorklogs } from '../issueWorklogs';
import { JiraExpressions } from '../jiraExpressions';
import { JiraSettings } from '../jiraSettings';
import { JQL } from '../jQL';
import { JqlFunctionsApps } from '../jqlFunctionsApps';
import { Labels } from '../labels';
import { LicenseMetrics } from '../licenseMetrics';
import { Myself } from '../myself';
import { Permissions } from '../permissions';
import { PermissionSchemes } from '../permissionSchemes';
import { ProjectAvatars } from '../projectAvatars';
import { ProjectCategories } from '../projectCategories';
import { ProjectComponents } from '../projectComponents';
import { ProjectEmail } from '../projectEmail';
import { ProjectFeatures } from '../projectFeatures';
import { ProjectKeyAndNameValidation } from '../projectKeyAndNameValidation';
import { ProjectPermissionSchemes } from '../projectPermissionSchemes';
import { ProjectProperties } from '../projectProperties';
import { ProjectRoleActors } from '../projectRoleActors';
import { ProjectRoles } from '../projectRoles';
import { Projects } from '../projects';
import { ProjectTypes } from '../projectTypes';
import { ProjectVersions } from '../projectVersions';
import { Screens } from '../screens';
import { ScreenSchemes } from '../screenSchemes';
import { ScreenTabFields } from '../screenTabFields';
import { ScreenTabs } from '../screenTabs';
import { ServerInfo } from '../serverInfo';
import { Status } from '../status';
import { Tasks } from '../tasks';
import { TimeTracking } from '../timeTracking';
import { UIModificationsApps } from '../uIModificationsApps';
import { UserProperties } from '../userProperties';
import { Users } from '../users';
import { UserSearch } from '../userSearch';
import { Webhooks } from '../webhooks';
import { Workflows } from '../workflows';
import { WorkflowSchemeDrafts } from '../workflowSchemeDrafts';
import { WorkflowSchemeProjectAssociations } from '../workflowSchemeProjectAssociations';
import { WorkflowSchemes } from '../workflowSchemes';
import { WorkflowStatusCategories } from '../workflowStatusCategories';
import { WorkflowStatuses } from '../workflowStatuses';
import { WorkflowTransitionProperties } from '../workflowTransitionProperties';
import { WorkflowTransitionRules } from '../workflowTransitionRules';

export class Version2Client extends BaseClient {
announcementBanner = new AnnouncementBanner(this);
14 changes: 10 additions & 4 deletions src/version2/issueAttachments.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @ts-expect-error Wrong form data typings
import FormData from 'form-data';
import { FormData, File } from 'formdata-node';
import * as mime from 'mime-types';
import * as Models from './models';
import * as Parameters from './parameters';
import { Callback } from '../callback';
@@ -426,15 +426,21 @@ export class IssueAttachments {
const formData = new FormData();
const attachments = Array.isArray(parameters.attachment) ? parameters.attachment : [parameters.attachment];

attachments.forEach(attachment => formData.append('file', attachment.file, attachment.filename));
attachments.forEach(attachment => {
const mimeType = attachment.mimeType ?? (mime.lookup(attachment.filename) || undefined);
const file = Buffer.isBuffer(attachment.file)
? new File([attachment.file], attachment.filename, { type: mimeType })
: attachment.file;

formData.append('file', file, attachment.filename);
});

const config: RequestConfig = {
url: `/rest/api/2/issue/${parameters.issueIdOrKey}/attachments`,
method: 'POST',
headers: {
'X-Atlassian-Token': 'no-check',
'Content-Type': 'multipart/form-data',
...formData.getHeaders?.(),
},
data: formData,
maxBodyLength: Infinity,
92 changes: 91 additions & 1 deletion src/version2/parameters/addAttachment.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,101 @@
/**
* Represents an attachment to be added to an issue.
*
* @example
* ```typescript
* const attachment: Attachment = {
* filename: 'example.txt',
* file: Buffer.from('Hello, world!'),
* mimeType: 'text/plain',
* };
* ```
*/
export interface Attachment {
/**
* The name of the attachment file.
*
* @example
* ```typescript
* const filename = 'document.pdf';
* ```
*/
filename: string;

/**
* The content of the attachment. Can be one of the following:
*
* - `Buffer`: For binary data.
* - `ReadableStream`: For streaming large files.
* - `string`: For text-based content.
* - `Blob`: For browser-like blob objects.
* - `File`: For file objects with metadata (e.g., in web environments).
*
* @example
* ```typescript
* const fileContent = fs.readFileSync('./document.pdf');
* ```
*/
file: Buffer | ReadableStream | string | Blob | File;

/**
* Optional MIME type of the attachment. Example values include:
*
* - 'application/pdf'
* - 'image/png'
*
* If not provided, the MIME type will be automatically detected based on the filename.
*
* @example
* ```typescript
* const mimeType = 'application/pdf';
* ```
*/
mimeType?: string;
}

/**
* Parameters for adding attachments to an issue.
*
* @example
* ```typescript
* const addAttachmentParams: AddAttachment = {
* issueIdOrKey: 'PROJECT-123',
* attachment: {
* filename: 'example.txt',
* file: 'Hello, world!',
* mimeType: 'text/plain',
* },
* };
* ```
*/
export interface AddAttachment {
/** The ID or key of the issue that attachments are added to. */
/**
* The ID or key of the issue to which the attachments will be added.
*
* @example
* ```typescript
* const issueIdOrKey = 'PROJECT-123';
* ```
*/
issueIdOrKey: string;

/**
* The attachment(s) to be added. Can be a single `Attachment` object or an array of `Attachment` objects.
*
* @example
* ```typescript
* const attachments = [
* {
* filename: 'file1.txt',
* file: Buffer.from('File 1 content'),
* mimeType: 'text/plain',
* },
* {
* filename: 'proof image.png',
* file: fs.readFileSync('./image.png'), // Reads the image file into a Buffer
* },
* ];
* ```
*/
attachment: Attachment | Attachment[];
}
4 changes: 2 additions & 2 deletions src/version2/parameters/updateProject.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { UpdateProjectDetails } from '../models';

export interface UpdateProject extends UpdateProjectDetails {
/** The project ID or project key (case sensitive). */
projectIdOrKey: string;
/** The project ID or project key (case-sensitive). */
projectIdOrKey: number | string;
/**
* The [project
* type](https://confluence.atlassian.com/x/GwiiLQ#Jiraapplicationsoverview-Productfeaturesandprojecttypes), which
176 changes: 87 additions & 89 deletions src/version3/client/version3Client.ts
Original file line number Diff line number Diff line change
@@ -1,92 +1,90 @@
import { BaseClient } from '../../clients';
import {
AnnouncementBanner,
ApplicationRoles,
AppMigration,
AppProperties,
AuditRecords,
Avatars,
Dashboards,
DynamicModules,
Filters,
FilterSharing,
GroupAndUserPicker,
Groups,
InstanceInformation,
IssueAttachments,
IssueCommentProperties,
IssueComments,
IssueCustomFieldConfigurationApps,
IssueCustomFieldContexts,
IssueCustomFieldOptions,
IssueCustomFieldOptionsApps,
IssueCustomFieldValuesApps,
IssueFieldConfigurations,
IssueFields,
IssueLinks,
IssueLinkTypes,
IssueNavigatorSettings,
IssueNotificationSchemes,
IssuePriorities,
IssueProperties,
IssueRemoteLinks,
IssueResolutions,
Issues,
IssueSearch,
IssueSecurityLevel,
IssueSecuritySchemes,
IssueTypeProperties,
IssueTypes,
IssueTypeSchemes,
IssueTypeScreenSchemes,
IssueVotes,
IssueWatchers,
IssueWorklogProperties,
IssueWorklogs,
JiraExpressions,
JiraSettings,
JQL,
JqlFunctionsApps,
Labels,
LicenseMetrics,
Myself,
Permissions,
PermissionSchemes,
ProjectAvatars,
ProjectCategories,
ProjectComponents,
ProjectEmail,
ProjectFeatures,
ProjectKeyAndNameValidation,
ProjectPermissionSchemes,
ProjectProperties,
ProjectRoleActors,
ProjectRoles,
Projects,
ProjectTypes,
ProjectVersions,
Screens,
ScreenSchemes,
ScreenTabFields,
ScreenTabs,
ServerInfo,
Status,
Tasks,
TimeTracking,
UIModificationsApps,
UserProperties,
Users,
UserSearch,
Webhooks,
Workflows,
WorkflowSchemeDrafts,
WorkflowSchemeProjectAssociations,
WorkflowSchemes,
WorkflowStatusCategories,
WorkflowStatuses,
WorkflowTransitionProperties,
WorkflowTransitionRules,
} from '..';
import { BaseClient } from '../../clients/baseClient';
import { AnnouncementBanner } from '../announcementBanner';
import { AppMigration } from '../appMigration';
import { AppProperties } from '../appProperties';
import { ApplicationRoles } from '../applicationRoles';
import { AuditRecords } from '../auditRecords';
import { Avatars } from '../avatars';
import { Dashboards } from '../dashboards';
import { DynamicModules } from '../dynamicModules';
import { FilterSharing } from '../filterSharing';
import { Filters } from '../filters';
import { GroupAndUserPicker } from '../groupAndUserPicker';
import { Groups } from '../groups';
import { InstanceInformation } from '../instanceInformation';
import { IssueAttachments } from '../issueAttachments';
import { IssueCommentProperties } from '../issueCommentProperties';
import { IssueComments } from '../issueComments';
import { IssueCustomFieldConfigurationApps } from '../issueCustomFieldConfigurationApps';
import { IssueCustomFieldContexts } from '../issueCustomFieldContexts';
import { IssueCustomFieldOptions } from '../issueCustomFieldOptions';
import { IssueCustomFieldOptionsApps } from '../issueCustomFieldOptionsApps';
import { IssueCustomFieldValuesApps } from '../issueCustomFieldValuesApps';
import { IssueFieldConfigurations } from '../issueFieldConfigurations';
import { IssueFields } from '../issueFields';
import { IssueLinkTypes } from '../issueLinkTypes';
import { IssueLinks } from '../issueLinks';
import { IssueNavigatorSettings } from '../issueNavigatorSettings';
import { IssueNotificationSchemes } from '../issueNotificationSchemes';
import { IssuePriorities } from '../issuePriorities';
import { IssueProperties } from '../issueProperties';
import { IssueRemoteLinks } from '../issueRemoteLinks';
import { IssueResolutions } from '../issueResolutions';
import { IssueSearch } from '../issueSearch';
import { IssueSecurityLevel } from '../issueSecurityLevel';
import { IssueSecuritySchemes } from '../issueSecuritySchemes';
import { IssueTypeProperties } from '../issueTypeProperties';
import { IssueTypeSchemes } from '../issueTypeSchemes';
import { IssueTypeScreenSchemes } from '../issueTypeScreenSchemes';
import { IssueTypes } from '../issueTypes';
import { IssueVotes } from '../issueVotes';
import { IssueWatchers } from '../issueWatchers';
import { IssueWorklogProperties } from '../issueWorklogProperties';
import { IssueWorklogs } from '../issueWorklogs';
import { Issues } from '../issues';
import { JiraExpressions } from '../jiraExpressions';
import { JiraSettings } from '../jiraSettings';
import { JQL } from '../jQL';
import { JqlFunctionsApps } from '../jqlFunctionsApps';
import { Labels } from '../labels';
import { LicenseMetrics } from '../licenseMetrics';
import { Myself } from '../myself';
import { PermissionSchemes } from '../permissionSchemes';
import { Permissions } from '../permissions';
import { ProjectAvatars } from '../projectAvatars';
import { ProjectCategories } from '../projectCategories';
import { ProjectComponents } from '../projectComponents';
import { ProjectEmail } from '../projectEmail';
import { ProjectFeatures } from '../projectFeatures';
import { ProjectKeyAndNameValidation } from '../projectKeyAndNameValidation';
import { ProjectPermissionSchemes } from '../projectPermissionSchemes';
import { ProjectProperties } from '../projectProperties';
import { ProjectRoleActors } from '../projectRoleActors';
import { ProjectRoles } from '../projectRoles';
import { ProjectTypes } from '../projectTypes';
import { ProjectVersions } from '../projectVersions';
import { Projects } from '../projects';
import { ScreenSchemes } from '../screenSchemes';
import { ScreenTabFields } from '../screenTabFields';
import { ScreenTabs } from '../screenTabs';
import { Screens } from '../screens';
import { ServerInfo } from '../serverInfo';
import { Status } from '../status';
import { Tasks } from '../tasks';
import { TimeTracking } from '../timeTracking';
import { UIModificationsApps } from '../uIModificationsApps';
import { UserProperties } from '../userProperties';
import { UserSearch } from '../userSearch';
import { Users } from '../users';
import { Webhooks } from '../webhooks';
import { Workflows } from '../workflows';
import { WorkflowSchemeDrafts } from '../workflowSchemeDrafts';
import { WorkflowSchemeProjectAssociations } from '../workflowSchemeProjectAssociations';
import { WorkflowSchemes } from '../workflowSchemes';
import { WorkflowStatusCategories } from '../workflowStatusCategories';
import { WorkflowStatuses } from '../workflowStatuses';
import { WorkflowTransitionProperties } from '../workflowTransitionProperties';
import { WorkflowTransitionRules } from '../workflowTransitionRules';

export class Version3Client extends BaseClient {
announcementBanner = new AnnouncementBanner(this);
14 changes: 10 additions & 4 deletions src/version3/issueAttachments.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @ts-expect-error Wrong form data typings
import FormData from 'form-data';
import { FormData, File } from 'formdata-node';
import * as mime from 'mime-types';
import * as Models from './models';
import * as Parameters from './parameters';
import { Callback } from '../callback';
@@ -426,15 +426,21 @@ export class IssueAttachments {
const formData = new FormData();
const attachments = Array.isArray(parameters.attachment) ? parameters.attachment : [parameters.attachment];

attachments.forEach(attachment => formData.append('file', attachment.file, attachment.filename));
attachments.forEach(attachment => {
const mimeType = attachment.mimeType ?? (mime.lookup(attachment.filename) || undefined);
const file = Buffer.isBuffer(attachment.file)
? new File([attachment.file], attachment.filename, { type: mimeType })
: attachment.file;

formData.append('file', file, attachment.filename);
});

const config: RequestConfig = {
url: `/rest/api/3/issue/${parameters.issueIdOrKey}/attachments`,
method: 'POST',
headers: {
'X-Atlassian-Token': 'no-check',
'Content-Type': 'multipart/form-data',
...formData.getHeaders?.(),
},
data: formData,
maxBodyLength: Infinity,
1 change: 0 additions & 1 deletion src/version3/models/index.ts
Original file line number Diff line number Diff line change
@@ -155,7 +155,6 @@ export * from './icon';
export * from './id';
export * from './idOrKey';
export * from './includedFields';
export * from './index';
export * from './issue';
export * from './issueArchivalSync';
export * from './issueArchivalSyncRequest';
92 changes: 91 additions & 1 deletion src/version3/parameters/addAttachment.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,101 @@
/**
* Represents an attachment to be added to an issue.
*
* @example
* ```typescript
* const attachment: Attachment = {
* filename: 'example.txt',
* file: Buffer.from('Hello, world!'),
* mimeType: 'text/plain',
* };
* ```
*/
export interface Attachment {
/**
* The name of the attachment file.
*
* @example
* ```typescript
* const filename = 'document.pdf';
* ```
*/
filename: string;

/**
* The content of the attachment. Can be one of the following:
*
* - `Buffer`: For binary data.
* - `ReadableStream`: For streaming large files.
* - `string`: For text-based content.
* - `Blob`: For browser-like blob objects.
* - `File`: For file objects with metadata (e.g., in web environments).
*
* @example
* ```typescript
* const fileContent = fs.readFileSync('./document.pdf');
* ```
*/
file: Buffer | ReadableStream | string | Blob | File;

/**
* Optional MIME type of the attachment. Example values include:
*
* - 'application/pdf'
* - 'image/png'
*
* If not provided, the MIME type will be automatically detected based on the filename.
*
* @example
* ```typescript
* const mimeType = 'application/pdf';
* ```
*/
mimeType?: string;
}

/**
* Parameters for adding attachments to an issue.
*
* @example
* ```typescript
* const addAttachmentParams: AddAttachment = {
* issueIdOrKey: 'PROJECT-123',
* attachment: {
* filename: 'example.txt',
* file: 'Hello, world!',
* mimeType: 'text/plain',
* },
* };
* ```
*/
export interface AddAttachment {
/** The ID or key of the issue that attachments are added to. */
/**
* The ID or key of the issue to which the attachments will be added.
*
* @example
* ```typescript
* const issueIdOrKey = 'PROJECT-123';
* ```
*/
issueIdOrKey: string;

/**
* The attachment(s) to be added. Can be a single `Attachment` object or an array of `Attachment` objects.
*
* @example
* ```typescript
* const attachments = [
* {
* filename: 'file1.txt',
* file: Buffer.from('File 1 content'),
* mimeType: 'text/plain',
* },
* {
* filename: 'proof image.png',
* file: fs.readFileSync('./image.png'), // Reads the image file into a Buffer
* },
* ];
* ```
*/
attachment: Attachment | Attachment[];
}
2 changes: 1 addition & 1 deletion src/version3/parameters/updateProject.ts
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ import { UpdateProjectDetails } from '../models';

export interface UpdateProject extends UpdateProjectDetails {
/** The project ID or project key (case-sensitive). */
projectIdOrKey: string;
projectIdOrKey: number | string;
projectTypeKey?: string;
projectTemplateKey?: string;
/**
19 changes: 18 additions & 1 deletion tests/integration/version2/issueAttachments.test.ts
Original file line number Diff line number Diff line change
@@ -45,12 +45,29 @@ test.sequential('should add attachment', async ({ expect }) => {
expect(attachments[0].mimeType).toBe('video/mp2t');
});

test.sequential('should add attachment with custom MIME type', async ({ expect }) => {
const customMimeType = 'application/typescript';

const customAttachment = await client.issueAttachments.addAttachment({
issueIdOrKey: issue.key,
attachment: {
filename: 'issueAttachments.test.ts',
file: fs.readFileSync('./tests/integration/version2/issueAttachments.test.ts'),
mimeType: customMimeType,
},
});

expect(!!customAttachment).toBeTruthy();
expect(customAttachment[0].filename).toBe('issueAttachments.test.ts');
expect(customAttachment[0].mimeType).toBe(customMimeType);
});

test.sequential('should getAttachmentContent', async ({ expect }) => {
const content = await client.issueAttachments.getAttachmentContent({ id: attachments[0].id });

expect(Buffer.isBuffer(content)).toBeTruthy();
});

test.sequential('should remove attachment', async ({ expect }) => {
test.sequential('should remove attachment', async () => {
await client.issues.deleteIssue({ issueIdOrKey: issue.key });
});
19 changes: 18 additions & 1 deletion tests/integration/version3/issueAttachments.test.ts
Original file line number Diff line number Diff line change
@@ -45,12 +45,29 @@ test.sequential('should add attachment', async ({ expect }) => {
expect(attachments[0].mimeType).toBe('video/mp2t');
});

test.sequential('should add attachment with custom MIME type', async ({ expect }) => {
const customMimeType = 'application/typescript';

const customAttachment = await client.issueAttachments.addAttachment({
issueIdOrKey: issue.key,
attachment: {
filename: 'issueAttachments.test.ts',
file: fs.readFileSync('./tests/integration/version2/issueAttachments.test.ts'),
mimeType: customMimeType,
},
});

expect(!!customAttachment).toBeTruthy();
expect(customAttachment[0].filename).toBe('issueAttachments.test.ts');
expect(customAttachment[0].mimeType).toBe(customMimeType);
});

test.sequential('should getAttachmentContent', async ({ expect }) => {
const content = await client.issueAttachments.getAttachmentContent({ id: attachments[0].id });

expect(Buffer.isBuffer(content)).toBeTruthy();
});

test.sequential('should remove attachment', async ({ expect }) => {
test.sequential('should remove attachment', async () => {
await client.issues.deleteIssue({ issueIdOrKey: issue.key });
});

Unchanged files with check annotations Beta

projectTypeKey: 'software',
})
.catch((error: AxiosError) => {
console.error(error.response?.data ?? error);

Check warning on line 19 in tests/integration/utils/createSoftwareProject.ts

GitHub Actions / Lint Code (20.x)

Unexpected console statement

Check warning on line 19 in tests/integration/utils/createSoftwareProject.ts

GitHub Actions / Lint Code (18.x)

Unexpected console statement

Check warning on line 19 in tests/integration/utils/createSoftwareProject.ts

GitHub Actions / Lint Code (20.x)

Unexpected console statement

Check warning on line 19 in tests/integration/utils/createSoftwareProject.ts

GitHub Actions / Lint Code (18.x)

Unexpected console statement
throw error;
});
};
enableUndo: false,
})
.catch((error: AxiosError) => {
console.error(error.response?.data ?? error);

Check warning on line 14 in tests/integration/utils/deleteSoftwareProject.ts

GitHub Actions / Lint Code (20.x)

Unexpected console statement

Check warning on line 14 in tests/integration/utils/deleteSoftwareProject.ts

GitHub Actions / Lint Code (18.x)

Unexpected console statement

Check warning on line 14 in tests/integration/utils/deleteSoftwareProject.ts

GitHub Actions / Lint Code (20.x)

Unexpected console statement

Check warning on line 14 in tests/integration/utils/deleteSoftwareProject.ts

GitHub Actions / Lint Code (18.x)

Unexpected console statement
throw error;
});
};
comment: 'this is a comment',
})
.catch((error: AxiosError) => {
console.error(error.response?.data ?? error);

Check warning on line 37 in tests/integration/version2/issueComments.test.ts

GitHub Actions / Lint Code (20.x)

Unexpected console statement

Check warning on line 37 in tests/integration/version2/issueComments.test.ts

GitHub Actions / Lint Code (18.x)

Unexpected console statement

Check warning on line 37 in tests/integration/version2/issueComments.test.ts

GitHub Actions / Lint Code (20.x)

Unexpected console statement

Check warning on line 37 in tests/integration/version2/issueComments.test.ts

GitHub Actions / Lint Code (18.x)

Unexpected console statement
throw error;
});
propertyValue: 'N/a',
});
console.log(fix);

Check warning on line 22 in examples/src/addFixVersion.ts

GitHub Actions / Lint Code (20.x)

Unexpected console statement

Check warning on line 22 in examples/src/addFixVersion.ts

GitHub Actions / Lint Code (18.x)

Unexpected console statement

Check warning on line 22 in examples/src/addFixVersion.ts

GitHub Actions / Lint Code (20.x)

Unexpected console statement

Check warning on line 22 in examples/src/addFixVersion.ts

GitHub Actions / Lint Code (18.x)

Unexpected console statement
}
addFixVersion().catch(e => {
console.error(e);

Check warning on line 26 in examples/src/addFixVersion.ts

GitHub Actions / Lint Code (20.x)

Unexpected console statement

Check warning on line 26 in examples/src/addFixVersion.ts

GitHub Actions / Lint Code (18.x)

Unexpected console statement

Check warning on line 26 in examples/src/addFixVersion.ts

GitHub Actions / Lint Code (20.x)

Unexpected console statement

Check warning on line 26 in examples/src/addFixVersion.ts

GitHub Actions / Lint Code (18.x)

Unexpected console statement
throw new Error(e.errorMessages?.join(' '));
});
timeSpentSeconds: 60, // Required one of `timeSpentSeconds` or `timeSpent`
});
console.log(`Worklog successfully added for Issue Id: ${worklog.issueId}`);

Check warning on line 23 in examples/src/addWorklog.ts

GitHub Actions / Lint Code (20.x)

Unexpected console statement

Check warning on line 23 in examples/src/addWorklog.ts

GitHub Actions / Lint Code (18.x)

Unexpected console statement

Check warning on line 23 in examples/src/addWorklog.ts

GitHub Actions / Lint Code (20.x)

Unexpected console statement

Check warning on line 23 in examples/src/addWorklog.ts

GitHub Actions / Lint Code (18.x)

Unexpected console statement
}
addWorklog().catch(e => {
console.error(e);

Check warning on line 27 in examples/src/addWorklog.ts

GitHub Actions / Lint Code (20.x)

Unexpected console statement

Check warning on line 27 in examples/src/addWorklog.ts

GitHub Actions / Lint Code (18.x)

Unexpected console statement

Check warning on line 27 in examples/src/addWorklog.ts

GitHub Actions / Lint Code (20.x)

Unexpected console statement

Check warning on line 27 in examples/src/addWorklog.ts

GitHub Actions / Lint Code (18.x)

Unexpected console statement
throw new Error(e.errorMessages.join(' '));
});
const issue = await client.issues.getIssue({ issueIdOrKey: id });
console.log(`Issue '${issue.fields.summary}' was successfully added to '${project.name}' project.`);

Check warning on line 31 in examples/src/basic.ts

GitHub Actions / Lint Code (20.x)

Unexpected console statement

Check warning on line 31 in examples/src/basic.ts

GitHub Actions / Lint Code (18.x)

Unexpected console statement

Check warning on line 31 in examples/src/basic.ts

GitHub Actions / Lint Code (20.x)

Unexpected console statement

Check warning on line 31 in examples/src/basic.ts

GitHub Actions / Lint Code (18.x)

Unexpected console statement
} else {
const myself = await client.myself.getCurrentUser();
const project = await client.projects.getProject({ projectIdOrKey: id.toString() });
console.log(`Project '${project.name}' was successfully created.`);

Check warning on line 44 in examples/src/basic.ts

GitHub Actions / Lint Code (20.x)

Unexpected console statement

Check warning on line 44 in examples/src/basic.ts

GitHub Actions / Lint Code (18.x)

Unexpected console statement

Check warning on line 44 in examples/src/basic.ts

GitHub Actions / Lint Code (20.x)

Unexpected console statement

Check warning on line 44 in examples/src/basic.ts

GitHub Actions / Lint Code (18.x)

Unexpected console statement
}
}
main()
.catch(e => {
console.error(e);

Check warning on line 50 in examples/src/basic.ts

GitHub Actions / Lint Code (20.x)

Unexpected console statement

Check warning on line 50 in examples/src/basic.ts

GitHub Actions / Lint Code (18.x)

Unexpected console statement

Check warning on line 50 in examples/src/basic.ts

GitHub Actions / Lint Code (20.x)

Unexpected console statement

Check warning on line 50 in examples/src/basic.ts

GitHub Actions / Lint Code (18.x)

Unexpected console statement
throw new Error(JSON.stringify(e));
});
private buildErrorHandlingResponse(e: unknown): Config.Error {
if (axios.isAxiosError(e) && e.response) {
return new HttpException(

Check failure on line 138 in src/clients/baseClient.ts

GitHub Actions / Integration Tests (18.x)

tests/integration/agile/sprint.test.ts

HttpException: Request failed with status code 500 ❯ Version3Client.buildErrorHandlingResponse src/clients/baseClient.ts:138:14 ❯ Version3Client.handleFailedResponse src/clients/baseClient.ts:122:22 ❯ Version3Client.sendRequest src/clients/baseClient.ts:94:19 ❯ tests/integration/agile/sprint.test.ts:17:3 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { response: { code: 'ERR_BAD_RESPONSE', message: 'Request failed with status code 500', data: { message: 'Project creation workflow completed but project not found in the database. ProjectId: 13925', 'status-code': 500, 'stack-trace': '' }, status: 500, statusText: 'Internal Server Error' }, code: 'ERR_BAD_RESPONSE', status: 500, statusText: 'Internal Server Error', initMessage: 'Function<initMessage>', initCause: 'Function<initCause>', initCode: 'Function<initCode>', initName: 'Function<initName>', initStatus: 'Function<initStatus>', initStatusText: 'Function<initStatusText>' } Caused by: Caused by: AxiosError: Request failed with status code 500 ❯ settle node_modules/axios/lib/core/settle.js:19:12 ❯ IncomingMessage.handleStreamEnd node_modules/axios/lib/adapters/http.js:599:11 ❯ Axios.request node_modules/axios/lib/core/Axios.js:45:41 ❯ Version3Client.sendRequest src/clients/baseClient.ts:90:24 ❯ tests/integration/agile/sprint.test.ts:17:3 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { description: undefined, number: undefined, fileName: undefined, lineNumber: undefined, columnNumber: undefined, config: { transitional: { silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false }, adapter: [ 'xhr', 'http', 'fetch' ], transformRequest: [ 'Function<transformRequest>' ], transformResponse: [ 'Function<transformResponse>' ], timeout: +0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, maxBodyLength: -1, env: { FormData: 'Function<FormData>', Blob: 'Function<Blob>' }, validateStatus: 'Function<validateStatus>', headers: { Accept: 'application/json, text/plain, */*', 'Content-Type': 'application/json', Authorization: 'Basic bXJyZWZhY3RvcmluZ0B5YW5kZXgucnU6***', 'User-Agent': 'axios/1.7.9', 'Content-Length': '190', 'Accept-Encoding': 'gzip, compress, deflate, br' }, paramsSerializer: { serialize: 'Function<bound paramSerializer>' }, baseURL: '***', url: '/rest/api/3/project', method: 'post', data: '{"key":"TAP","leadAccountId":"5b6d7f20e6dba529eefdbad9","name":"Test Agile Project","projectTemplateKey":"com.pyxis.greenhopper.jira:gh-simplified-agility-scrum","projectTypeKey":"software"}' }, code: 'ERR_BAD_RESPONSE', status: 500 }

Check failure on line 138 in src/clients/baseClient.ts

GitHub Actions / Integration Tests (18.x)

tests/integration/agile/sprint.test.ts

HttpException: Request failed with status code 404 ❯ Version3Client.buildErrorHandlingResponse src/clients/baseClient.ts:138:14 ❯ Version3Client.handleFailedResponse src/clients/baseClient.ts:122:22 ❯ Version3Client.sendRequest src/clients/baseClient.ts:94:19 ❯ tests/integration/agile/sprint.test.ts:21:3 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { response: { code: 'ERR_BAD_REQUEST', message: 'Request failed with status code 404', data: { errorMessages: [ 'No project could be found with key \'TAP\'.' ], errors: {} }, status: 404, statusText: 'Not Found' }, code: 'ERR_BAD_REQUEST', status: 404, statusText: 'Not Found', initMessage: 'Function<initMessage>', initCause: 'Function<initCause>', initCode: 'Function<initCode>', initName: 'Function<initName>', initStatus: 'Function<initStatus>', initStatusText: 'Function<initStatusText>' } Caused by: Caused by: AxiosError: Request failed with status code 404 ❯ settle node_modules/axios/lib/core/settle.js:19:12 ❯ BrotliDecompress.handleStreamEnd node_modules/axios/lib/adapters/http.js:599:11 ❯ Axios.request node_modules/axios/lib/core/Axios.js:45:41 ❯ Version3Client.sendRequest src/clients/baseClient.ts:90:24 ❯ tests/integration/agile/sprint.test.ts:21:3 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { description: undefined, number: undefined, fileName: undefined, lineNumber: undefined, columnNumber: undefined, config: { transitional: { silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false }, adapter: [ 'xhr', 'http', 'fetch' ], transformRequest: [ 'Function<transformRequest>' ], transformResponse: [ 'Function<transformResponse>' ], timeout: +0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, maxBodyLength: -1, env: { FormData: 'Function<FormData>', Blob: 'Function<Blob>' }, validateStatus: 'Function<validateStatus>', headers: { Accept: 'application/json, text/plain, */*', Authorization: 'Basic bXJyZWZhY3RvcmluZ0B5YW5kZXgucnU6***', 'User-Agent': 'axios/1.7.9', 'Accept-Encoding': 'gzip, compress, deflate, br' }, paramsSerializer: { serialize: 'Function<bound paramSerializer>' }, baseURL: '***', url: '/rest/api/3/project/TAP', method: 'delete', params: { enableUndo: false } }, code: 'ERR_BAD_REQUEST', status: 404 }

Check failure on line 138 in src/clients/baseClient.ts

GitHub Actions / Integration Tests (18.x)

tests/integration/version2/issueAttachments.test.ts

HttpException: Request failed with status code 500 ❯ Version2Client.buildErrorHandlingResponse src/clients/baseClient.ts:138:14 ❯ Version2Client.handleFailedResponse src/clients/baseClient.ts:122:22 ❯ Version2Client.sendRequest src/clients/baseClient.ts:94:19 ❯ Module.prepareEnvironment tests/integration/utils/prepareEnvironment.ts:4:3 ❯ tests/integration/version2/issueAttachments.test.ts:13:3 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { response: { code: 'ERR_BAD_RESPONSE', message: 'Request failed with status code 500', data: { message: 'Project creation workflow completed but project not found in the database. ProjectId: 13923', 'status-code': 500, 'stack-trace': '' }, status: 500, statusText: 'Internal Server Error' }, code: 'ERR_BAD_RESPONSE', status: 500, statusText: 'Internal Server Error', initMessage: 'Function<initMessage>', initCause: 'Function<initCause>', initCode: 'Function<initCode>', initName: 'Function<initName>', initStatus: 'Function<initStatus>', initStatusText: 'Function<initStatusText>' } Caused by: Caused by: AxiosError: Request failed with status code 500 ❯ settle node_modules/axios/lib/core/settle.js:19:12 ❯ IncomingMessage.handleStreamEnd node_modules/axios/lib/adapters/http.js:599:11 ❯ Axios.request node_modules/axios/lib/core/Axios.js:45:41 ❯ Version2Client.sendRequest src/clients/baseClient.ts:90:24 ❯ Module.prepareEnvironment tests/integration/utils/prepareEnvironment.ts:4:3 ❯ tests/integration/version2/issueAttachments.test.ts:13:3 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { description: undefined, number: undefined, fileName: undefined, lineNumber: undefined, columnNumber: undefined, config: { transitional: { silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false }, adapter: [ 'xhr', 'http', 'fetch' ], transformRequest: [ 'Function<transformRequest>' ], transformResponse: [ 'Function<transformResponse>' ], timeout: +0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, maxBodyLength: -1, env: { FormData: 'Function<FormData>', Blob: 'Function<Blob>' }, validateStatus: 'Function<validateStatus>', headers: { Accept: 'application/json, text/plain, */*', 'Content-Type': 'application/json', Authorization: 'Basic bXJyZWZhY3RvcmluZ0B5YW5kZXgucnU6***', 'User-Agent': 'axios/1.7.9', 'Content-Length': '138', 'Accept-Encoding': 'gzip, compress, deflate, br' }, paramsSerializer: { serialize: 'Function<bound paramSerializer>' }, baseURL: '***', url: '/rest/api/2/project', method: 'post', data: '{"key":"AUTOTEST","leadAccountId":"5b6d7f20e6dba529eefdbad9","name":"Jira.js project for lib automatic tests","projectTypeKey":"software"}' }, code: 'ERR_BAD_RESPONSE', status: 500 }

Check failure on line 138 in src/clients/baseClient.ts

GitHub Actions / Integration Tests (18.x)

tests/integration/version2/issueAttachments.test.ts

HttpException: Request failed with status code 404 ❯ Version2Client.buildErrorHandlingResponse src/clients/baseClient.ts:138:14 ❯ Version2Client.handleFailedResponse src/clients/baseClient.ts:122:22 ❯ Version2Client.sendRequest src/clients/baseClient.ts:94:19 ❯ Module.cleanupEnvironment tests/integration/utils/cleanupEnvironment.ts:4:3 ❯ tests/integration/version2/issueAttachments.test.ts:17:3 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { response: { code: 'ERR_BAD_REQUEST', message: 'Request failed with status code 404', data: { errorMessages: [ 'No project could be found with key \'AUTOTEST\'.' ], errors: {} }, status: 404, statusText: 'Not Found' }, code: 'ERR_BAD_REQUEST', status: 404, statusText: 'Not Found', initMessage: 'Function<initMessage>', initCause: 'Function<initCause>', initCode: 'Function<initCode>', initName: 'Function<initName>', initStatus: 'Function<initStatus>', initStatusText: 'Function<initStatusText>' } Caused by: Caused by: AxiosError: Request failed with status code 404 ❯ settle node_modules/axios/lib/core/settle.js:19:12 ❯ BrotliDecompress.handleStreamEnd node_modules/axios/lib/adapters/http.js:599:11 ❯ Axios.request node_modules/axios/lib/core/Axios.js:45:41 ❯ Version2Client.sendRequest src/clients/baseClient.ts:90:24 ❯ Module.cleanupEnvironment tests/integration/utils/cleanupEnvironment.ts:4:3 ❯ tests/integration/version2/issueAttachments.test.ts:17:3 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { description: undefined, number: undefined, fileName: undefined, lineNumber: undefined, columnNumber: undefined, config: { transitional: { silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false }, adapter: [ 'xhr', 'http', 'fetch' ], transformRequest: [ 'Function<transformRequest>' ], transformResponse: [ 'Function<transformResponse>' ], timeout: +0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, maxBodyLength: -1, env: { FormData: 'Function<FormData>', Blob: 'Function<Blob>' }, validateStatus: 'Function<validateStatus>', headers: { Accept: 'application/json, text/plain, */*', Authorization: 'Basic bXJyZWZhY3RvcmluZ0B5YW5kZXgucnU6***', 'User-Agent': 'axios/1.7.9', 'Accept-Encoding': 'gzip, compress, deflate, br' }, paramsSerializer: { serialize: 'Function<bound paramSerializer>' }, baseURL: '***', url: '/rest/api/2/project/AUTOTEST', method: 'delete', params: { enableUndo: false } }, code: 'ERR_BAD_REQUEST', status: 404 }

Check failure on line 138 in src/clients/baseClient.ts

GitHub Actions / Integration Tests (18.x)

tests/integration/version2/issues.test.ts

HttpException: Request failed with status code 500 ❯ Version2Client.buildErrorHandlingResponse src/clients/baseClient.ts:138:14 ❯ Version2Client.handleFailedResponse src/clients/baseClient.ts:122:22 ❯ Version2Client.sendRequest src/clients/baseClient.ts:94:19 ❯ Module.prepareEnvironment tests/integration/utils/prepareEnvironment.ts:4:3 ❯ tests/integration/version2/issues.test.ts:10:3 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { response: { code: 'ERR_BAD_RESPONSE', message: 'Request failed with status code 500', data: { message: 'Failed to create Project from async task. There is another task creating a project with the same key. Conflicting Task: eb9a8e0d-ea21-400a-8aed-920fc5107937', 'status-code': 500, 'stack-trace': '' }, status: 500, statusText: 'Internal Server Error' }, code: 'ERR_BAD_RESPONSE', status: 500, statusText: 'Internal Server Error', initMessage: 'Function<initMessage>', initCause: 'Function<initCause>', initCode: 'Function<initCode>', initName: 'Function<initName>', initStatus: 'Function<initStatus>', initStatusText: 'Function<initStatusText>' } Caused by: Caused by: AxiosError: Request failed with status code 500 ❯ settle node_modules/axios/lib/core/settle.js:19:12 ❯ IncomingMessage.handleStreamEnd node_modules/axios/lib/adapters/http.js:599:11 ❯ Axios.request node_modules/axios/lib/core/Axios.js:45:41 ❯ Version2Client.sendRequest src/clients/baseClient.ts:90:24 ❯ Module.prepareEnvironment tests/integration/utils/prepareEnvironment.ts:4:3 ❯ tests/integration/version2/issues.test.ts:10:3 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { description: undefined, number: undefined, fileName: undefined, lineNumber: undefined, columnNumber: undefined, config: { transitional: { silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false }, adapter: [ 'xhr', 'http', 'fetch' ], transformRequest: [ 'Function<transformRequest>' ], transformResponse: [ 'Function<transformResponse>' ], timeout: +0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, maxBodyLength: -1, env: { FormData: 'Function<FormData>', Blob: 'Function<Blob>' }, validateStatus: 'Function<validateStatus>', headers: { Accept: 'application/json, text/plain, */*', 'Content-Type': 'application/json', Authorization: 'Basic bXJyZWZhY3RvcmluZ0B5YW5kZXgucnU6***', 'User-Agent': 'axios/1.7.9', 'Content-Length': '138', 'Accept-Encoding': 'gzip, compress, deflate, br' }, paramsSerializer: { serialize: 'Function<bound paramSerializer>' }, baseURL: '***', url: '/rest/api/2/project', method: 'post', data: '{"key":"AUTOTEST","leadAccountId":"5b6d7f20e6dba529eefdbad9","name":"Jira.js project for lib automatic tests","projectTypeKey":"software"}' }, code: 'ERR_BAD_RESPONSE', status: 500 }

Check failure on line 138 in src/clients/baseClient.ts

GitHub Actions / Integration Tests (18.x)

tests/integration/version2/issues.test.ts

HttpException: Request failed with status code 404 ❯ Version2Client.buildErrorHandlingResponse src/clients/baseClient.ts:138:14 ❯ Version2Client.handleFailedResponse src/clients/baseClient.ts:122:22 ❯ Version2Client.sendRequest src/clients/baseClient.ts:94:19 ❯ Module.cleanupEnvironment tests/integration/utils/cleanupEnvironment.ts:4:3 ❯ tests/integration/version2/issues.test.ts:14:3 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { response: { code: 'ERR_BAD_REQUEST', message: 'Request failed with status code 404', data: { errorMessages: [ 'No project could be found with key \'AUTOTEST\'.' ], errors: {} }, status: 404, statusText: 'Not Found' }, code: 'ERR_BAD_REQUEST', status: 404, statusText: 'Not Found', initMessage: 'Function<initMessage>', initCause: 'Function<initCause>', initCode: 'Function<initCode>', initName: 'Function<initName>', initStatus: 'Function<initStatus>', initStatusText: 'Function<initStatusText>' } Caused by: Caused by: AxiosError: Request failed with status code 404 ❯ settle node_modules/axios/lib/core/settle.js:19:12 ❯ BrotliDecompress.handleStreamEnd node_modules/axios/lib/adapters/http.js:599:11 ❯ Axios.request node_modules/axios/lib/core/Axios.js:45:41 ❯ Version2Client.sendRequest src/clients/baseClient.ts:90:24 ❯ Module.cleanupEnvironment tests/integration/utils/cleanupEnvironment.ts:4:3 ❯ tests/integration/version2/issues.test.ts:14:3 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { description: undefined, number: undefined, fileName: undefined, lineNumber: undefined, columnNumber: undefined, config: { transitional: { silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false }, adapter: [ 'xhr', 'http', 'fetch' ], transformRequest: [ 'Function<transformRequest>' ], transformResponse: [ 'Function<transformResponse>' ], timeout: +0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, maxBodyLength: -1, env: { FormData: 'Function<FormData>', Blob: 'Function<Blob>' }, validateStatus: 'Function<validateStatus>', headers: { Accept: 'application/json, text/plain, */*', Authorization: 'Basic bXJyZWZhY3RvcmluZ0B5YW5kZXgucnU6***', 'User-Agent': 'axios/1.7.9', 'Accept-Encoding': 'gzip, compress, deflate, br' }, paramsSerializer: { serialize: 'Function<bound paramSerializer>' }, baseURL: '***', url: '/rest/api/2/project/AUTOTEST', method: 'delete', params: { enableUndo: false } }, code: 'ERR_BAD_REQUEST', status: 404 }

Check failure on line 138 in src/clients/baseClient.ts

GitHub Actions / Integration Tests (18.x)

tests/integration/version3/groups.test.ts > should create a group

HttpException: Request failed with status code 400 ❯ Version3Client.buildErrorHandlingResponse src/clients/baseClient.ts:138:14 ❯ Version3Client.handleFailedResponse src/clients/baseClient.ts:122:22 ❯ Version3Client.sendRequest src/clients/baseClient.ts:94:19 ❯ tests/integration/version3/groups.test.ts:8:17 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { response: { code: 'ERR_BAD_REQUEST', message: 'Request failed with status code 400', data: { errorMessages: [ 'An error occurred: com.atlassian.idp.client.exceptions.BadRequestException: {"schemas":["urn:ietf:params:scim:api:messages:2.0:Error"],"status":"409","detail":"Group with this name already exists","errorType":"conflict","message":"Group with this name already exists"}' ], errors: {} }, status: 400, statusText: 'Bad Request' }, code: 'ERR_BAD_REQUEST', status: 400, statusText: 'Bad Request', initMessage: 'Function<initMessage>', initCause: 'Function<initCause>', initCode: 'Function<initCode>', initName: 'Function<initName>', initStatus: 'Function<initStatus>', initStatusText: 'Function<initStatusText>' } Caused by: Caused by: AxiosError: Request failed with status code 400 ❯ settle node_modules/axios/lib/core/settle.js:19:12 ❯ BrotliDecompress.handleStreamEnd node_modules/axios/lib/adapters/http.js:599:11 ❯ Axios.request node_modules/axios/lib/core/Axios.js:45:41 ❯ Version3Client.sendRequest src/clients/baseClient.ts:90:24 ❯ tests/integration/version3/groups.test.ts:8:17 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { description: undefined, number: undefined, fileName: undefined, lineNumber: undefined, columnNumber: undefined, config: { transitional: { silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false }, adapter: [ 'xhr', 'http', 'fetch' ], transformRequest: [ 'Function<transformRequest>' ], transformResponse: [ 'Function<transformResponse>' ], timeout: +0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, maxBodyLength: -1, env: { FormData: 'Function<FormData>', Blob: 'Function<Blob>' }, validateStatus: 'Function<validateStatus>', headers: { Accept: 'application/json, text/plain, */*', 'Content-Type': 'application/json', Authorization: 'Basic bXJyZWZhY3RvcmluZ0B5YW5kZXgucnU6***', 'User-Agent': 'axios/1.7.9', 'Content-Length': '37', 'Accept-Encoding': 'gzip, compress, deflate, br' }, paramsSerializer: { serialize: 'Function<bound paramSerializer>' }, baseURL: '***', url: '/rest/api/3/group', method: 'post', data: '{"name":"Automated tests group name"}' }, code: 'ERR_BAD_REQUEST', status: 400 }

Check failure on line 138 in src/clients/baseClient.ts

GitHub Actions / Integration Tests (18.x)

tests/integration/version3/issueAttachments.test.ts

HttpException: Request failed with status code 500 ❯ Version2Client.buildErrorHandlingResponse src/clients/baseClient.ts:138:14 ❯ Version2Client.handleFailedResponse src/clients/baseClient.ts:122:22 ❯ Version2Client.sendRequest src/clients/baseClient.ts:94:19 ❯ Module.prepareEnvironment tests/integration/utils/prepareEnvironment.ts:4:3 ❯ tests/integration/version3/issueAttachments.test.ts:13:3 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { response: { code: 'ERR_BAD_RESPONSE', message: 'Request failed with status code 500', data: { message: 'Failed to create Project from async task. There is another task creating a project with the same key. Conflicting Task: eb9a8e0d-ea21-400a-8aed-920fc5107937', 'status-code': 500, 'stack-trace': '' }, status: 500, statusText: 'Internal Server Error' }, code: 'ERR_BAD_RESPONSE', status: 500, statusText: 'Internal Server Error', initMessage: 'Function<initMessage>', initCause: 'Function<initCause>', initCode: 'Function<initCode>', initName: 'Function<initName>', initStatus: 'Function<initStatus>', initStatusText: 'Function<initStatusText>' } Caused by: Caused by: AxiosError: Request failed with status code 500 ❯ settle node_modules/axios/lib/core/settle.js:19:12 ❯ IncomingMessage.handleStreamEnd node_modules/axios/lib/adapters/http.js:599:11 ❯ Axios.request node_modules/axios/lib/core/Axios.js:45:41 ❯ Version2Client.sendRequest src/clients/baseClient.ts:90:24 ❯ Module.prepareEnvironment tests/integration/utils/prepareEnvironment.ts:4:3 ❯ tests/integration/version3/issueAttachments.test.ts:13:3 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { description: undefined, number: undefined, fileName: undefined, lineNumber: undefined, columnNumber: undefined, config: { transitional: { silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false }, adapter: [ 'xhr', 'http', 'fetch' ], transformRequest: [ 'Function<transformRequest>' ], transformResponse: [ 'Function<transformResponse>' ], timeout: +0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, maxBodyLength: -1, env: { FormData: 'Function<FormData>', Blob: 'Function<Blob>' }, validateStatus: 'Function<validateStatus>', headers: { Accept: 'application/json, text/plain, */*', 'Content-Type': 'application/json', Authorization: 'Basic bXJyZWZhY3RvcmluZ0B5YW5kZXgucnU6***', 'User-Agent': 'axios/1.7.9', 'Content-Length': '138', 'Accept-Encoding': 'gzip, compress, deflate, br' }, paramsSerializer: { serialize: 'Function<bound paramSerializer>' }, baseURL: '***', url: '/rest/api/2/project', method: 'post', data: '{"key":"AUTOTEST","leadAccountId":"5b6d7f20e6dba529eefdbad9","name":"Jira.js project for lib automatic tests","projectTypeKey":"software"}' }, code: 'ERR_BAD_RESPONSE', status: 500 }

Check failure on line 138 in src/clients/baseClient.ts

GitHub Actions / Integration Tests (18.x)

tests/integration/version3/issues.test.ts

HttpException: Request failed with status code 400 ❯ Version2Client.buildErrorHandlingResponse src/clients/baseClient.ts:138:14 ❯ Version2Client.handleFailedResponse src/clients/baseClient.ts:122:22 ❯ Version2Client.sendRequest src/clients/baseClient.ts:94:19 ❯ Module.prepareEnvironment tests/integration/utils/prepareEnvironment.ts:4:3 ❯ tests/integration/version3/issues.test.ts:10:3 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { response: { code: 'ERR_BAD_REQUEST', message: 'Request failed with status code 400', data: { errorMessages: [], errors: { projectName: 'A project with that name already exists.', projectKey: 'Project \'Jira.js project for lib automatic tests\' uses this project key.' } }, status: 400, statusText: 'Bad Request' }, code: 'ERR_BAD_REQUEST', status: 400, statusText: 'Bad Request', initMessage: 'Function<initMessage>', initCause: 'Function<initCause>', initCode: 'Function<initCode>', initName: 'Function<initName>', initStatus: 'Function<initStatus>', initStatusText: 'Function<initStatusText>' } Caused by: Caused by: AxiosError: Request failed with status code 400 ❯ settle node_modules/axios/lib/core/settle.js:19:12 ❯ IncomingMessage.handleStreamEnd node_modules/axios/lib/adapters/http.js:599:11 ❯ Axios.request node_modules/axios/lib/core/Axios.js:45:41 ❯ Version2Client.sendRequest src/clients/baseClient.ts:90:24 ❯ Module.prepareEnvironment tests/integration/utils/prepareEnvironment.ts:4:3 ❯ tests/integration/version3/issues.test.ts:10:3 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { description: undefined, number: undefined, fileName: undefined, lineNumber: undefined, columnNumber: undefined, config: { transitional: { silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false }, adapter: [ 'xhr', 'http', 'fetch' ], transformRequest: [ 'Function<transformRequest>' ], transformResponse: [ 'Function<transformResponse>' ], timeout: +0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, maxBodyLength: -1, env: { FormData: 'Function<FormData>', Blob: 'Function<Blob>' }, validateStatus: 'Function<validateStatus>', headers: { Accept: 'application/json, text/plain, */*', 'Content-Type': 'application/json', Authorization: 'Basic bXJyZWZhY3RvcmluZ0B5YW5kZXgucnU6***', 'User-Agent': 'axios/1.7.9', 'Content-Length': '138', 'Accept-Encoding': 'gzip, compress, deflate, br' }, paramsSerializer: { serialize: 'Function<bound paramSerializer>' }, baseURL: '***', url: '/rest/api/2/project', method: 'post', data: '{"key":"AUTOTEST","leadAccountId":"5b6d7f20e6dba529eefdbad9","name":"Jira.js project for lib automatic tests","projectTypeKey":"software"}' }, code: 'ERR_BAD_REQUEST', status: 400 }
{
code: e.code,
message: e.message,