@bragduck/cli 2.10.3 → 2.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/bragduck.js +226 -27
- package/dist/bin/bragduck.js.map +1 -1
- package/package.json +1 -1
package/dist/bin/bragduck.js
CHANGED
|
@@ -3381,17 +3381,23 @@ var JiraService = class {
|
|
|
3381
3381
|
const queries = [];
|
|
3382
3382
|
if (options.days) {
|
|
3383
3383
|
queries.push(
|
|
3384
|
-
`(created >= -${options.days}d OR
|
|
3384
|
+
`(created >= -${options.days}d OR resolutiondate >= -${options.days}d OR updated >= -${options.days}d)`
|
|
3385
3385
|
);
|
|
3386
3386
|
}
|
|
3387
3387
|
if (options.author) {
|
|
3388
3388
|
if (options.author.includes("@")) {
|
|
3389
|
-
queries.push(
|
|
3389
|
+
queries.push(
|
|
3390
|
+
"(creator = currentUser() OR reporter = currentUser() OR assignee = currentUser())"
|
|
3391
|
+
);
|
|
3390
3392
|
} else {
|
|
3391
|
-
queries.push(
|
|
3393
|
+
queries.push(
|
|
3394
|
+
`(creator = "${options.author}" OR reporter = "${options.author}" OR assignee = "${options.author}")`
|
|
3395
|
+
);
|
|
3392
3396
|
}
|
|
3393
3397
|
} else {
|
|
3394
|
-
queries.push(
|
|
3398
|
+
queries.push(
|
|
3399
|
+
"(creator = currentUser() OR reporter = currentUser() OR assignee = currentUser())"
|
|
3400
|
+
);
|
|
3395
3401
|
}
|
|
3396
3402
|
if (options.jql) {
|
|
3397
3403
|
queries.push(`(${options.jql})`);
|
|
@@ -3411,6 +3417,62 @@ var JiraService = class {
|
|
|
3411
3417
|
};
|
|
3412
3418
|
return typeScores[issue.fields.issuetype.name] || 100;
|
|
3413
3419
|
}
|
|
3420
|
+
/**
|
|
3421
|
+
* Determine the type of contribution the current user made to an issue
|
|
3422
|
+
* Returns: 'created' | 'reported' | 'assigned-resolved' | 'edited'
|
|
3423
|
+
*/
|
|
3424
|
+
async determineJiraContributionType(issue, userEmail) {
|
|
3425
|
+
const isCreator = issue.fields.creator.emailAddress === userEmail;
|
|
3426
|
+
const isReporter = issue.fields.reporter?.emailAddress === userEmail;
|
|
3427
|
+
if (isCreator) {
|
|
3428
|
+
return {
|
|
3429
|
+
type: "created",
|
|
3430
|
+
details: `Created ${issue.fields.issuetype.name}: ${issue.fields.status.name}`
|
|
3431
|
+
};
|
|
3432
|
+
}
|
|
3433
|
+
if (isReporter && !isCreator) {
|
|
3434
|
+
return {
|
|
3435
|
+
type: "reported",
|
|
3436
|
+
details: `Reported ${issue.fields.issuetype.name}: ${issue.fields.status.name}`
|
|
3437
|
+
};
|
|
3438
|
+
}
|
|
3439
|
+
const isAssigned = issue.fields.assignee?.emailAddress === userEmail;
|
|
3440
|
+
const isResolved = issue.fields.resolutiondate !== null && issue.fields.resolutiondate !== void 0;
|
|
3441
|
+
const userEdits = issue.changelog?.histories?.filter((history) => history.author.emailAddress === userEmail) || [];
|
|
3442
|
+
const hasEdits = userEdits.length > 0;
|
|
3443
|
+
if (isAssigned && isResolved) {
|
|
3444
|
+
return {
|
|
3445
|
+
type: "assigned-resolved",
|
|
3446
|
+
details: `Assigned and resolved ${issue.fields.issuetype.name}${hasEdits ? ` with ${userEdits.length} update${userEdits.length > 1 ? "s" : ""}` : ""}`
|
|
3447
|
+
};
|
|
3448
|
+
}
|
|
3449
|
+
if (hasEdits) {
|
|
3450
|
+
return {
|
|
3451
|
+
type: "edited",
|
|
3452
|
+
details: `Updated ${issue.fields.issuetype.name} (${userEdits.length} change${userEdits.length > 1 ? "s" : ""})`
|
|
3453
|
+
};
|
|
3454
|
+
}
|
|
3455
|
+
return {
|
|
3456
|
+
type: "edited",
|
|
3457
|
+
details: `Contributed to ${issue.fields.issuetype.name}`
|
|
3458
|
+
};
|
|
3459
|
+
}
|
|
3460
|
+
/**
|
|
3461
|
+
* Calculate impact score based on contribution type
|
|
3462
|
+
*/
|
|
3463
|
+
calculateJiraContributionImpact(contributionType, baseComplexity) {
|
|
3464
|
+
const multipliers = {
|
|
3465
|
+
created: 1,
|
|
3466
|
+
// 100% - highest impact (created the issue)
|
|
3467
|
+
reported: 0.9,
|
|
3468
|
+
// 90% - very high impact (reported/initiated the issue)
|
|
3469
|
+
"assigned-resolved": 0.8,
|
|
3470
|
+
// 80% - high impact (owned and resolved)
|
|
3471
|
+
edited: 0.4
|
|
3472
|
+
// 40% - medium impact (contributed updates)
|
|
3473
|
+
};
|
|
3474
|
+
return Math.ceil(baseComplexity * multipliers[contributionType]);
|
|
3475
|
+
}
|
|
3414
3476
|
/**
|
|
3415
3477
|
* Fetch issues with optional filtering
|
|
3416
3478
|
*/
|
|
@@ -3424,6 +3486,8 @@ var JiraService = class {
|
|
|
3424
3486
|
"updated",
|
|
3425
3487
|
"resolutiondate",
|
|
3426
3488
|
"creator",
|
|
3489
|
+
"reporter",
|
|
3490
|
+
"assignee",
|
|
3427
3491
|
"status",
|
|
3428
3492
|
"issuetype"
|
|
3429
3493
|
];
|
|
@@ -3441,7 +3505,7 @@ var JiraService = class {
|
|
|
3441
3505
|
);
|
|
3442
3506
|
break;
|
|
3443
3507
|
}
|
|
3444
|
-
const endpoint = `/rest/api/2/search?jql=${encodeURIComponent(jql)}&startAt=${startAt}&maxResults=${maxResults}&fields=${fields.join(",")}`;
|
|
3508
|
+
const endpoint = `/rest/api/2/search?jql=${encodeURIComponent(jql)}&startAt=${startAt}&maxResults=${maxResults}&fields=${fields.join(",")}&expand=changelog`;
|
|
3445
3509
|
try {
|
|
3446
3510
|
const response = await this.request(endpoint);
|
|
3447
3511
|
if (response.issues.length === 0) {
|
|
@@ -3467,7 +3531,14 @@ var JiraService = class {
|
|
|
3467
3531
|
break;
|
|
3468
3532
|
}
|
|
3469
3533
|
if (options.limit && allIssues.length >= options.limit) {
|
|
3470
|
-
|
|
3534
|
+
const email2 = await this.getCurrentUser();
|
|
3535
|
+
const limitedIssues = allIssues.slice(0, options.limit);
|
|
3536
|
+
const commits2 = [];
|
|
3537
|
+
for (const issue of limitedIssues) {
|
|
3538
|
+
const commit = await this.transformIssueToCommit(issue, void 0, email2);
|
|
3539
|
+
commits2.push(commit);
|
|
3540
|
+
}
|
|
3541
|
+
return commits2;
|
|
3471
3542
|
}
|
|
3472
3543
|
startAt += maxResults;
|
|
3473
3544
|
} catch (error) {
|
|
@@ -3491,7 +3562,13 @@ var JiraService = class {
|
|
|
3491
3562
|
throw error;
|
|
3492
3563
|
}
|
|
3493
3564
|
}
|
|
3494
|
-
|
|
3565
|
+
const email = await this.getCurrentUser();
|
|
3566
|
+
const commits = [];
|
|
3567
|
+
for (const issue of allIssues) {
|
|
3568
|
+
const commit = await this.transformIssueToCommit(issue, void 0, email);
|
|
3569
|
+
commits.push(commit);
|
|
3570
|
+
}
|
|
3571
|
+
return commits;
|
|
3495
3572
|
}
|
|
3496
3573
|
/**
|
|
3497
3574
|
* Fetch issues for the current authenticated user
|
|
@@ -3507,17 +3584,53 @@ var JiraService = class {
|
|
|
3507
3584
|
});
|
|
3508
3585
|
}
|
|
3509
3586
|
/**
|
|
3510
|
-
* Transform Jira issue to GitCommit format with
|
|
3587
|
+
* Transform Jira issue to GitCommit format with contribution-specific data
|
|
3511
3588
|
*/
|
|
3512
|
-
transformIssueToCommit(issue, instanceUrl) {
|
|
3513
|
-
let
|
|
3514
|
-
if (
|
|
3515
|
-
|
|
3516
|
-
|
|
3589
|
+
async transformIssueToCommit(issue, instanceUrl, userEmail) {
|
|
3590
|
+
let contribution = null;
|
|
3591
|
+
if (userEmail) {
|
|
3592
|
+
contribution = await this.determineJiraContributionType(issue, userEmail);
|
|
3593
|
+
}
|
|
3594
|
+
let message;
|
|
3595
|
+
let contributionPrefix = "";
|
|
3596
|
+
if (contribution) {
|
|
3597
|
+
if (contribution.type === "created") {
|
|
3598
|
+
contributionPrefix = "\u{1F3AB} Created: ";
|
|
3599
|
+
} else if (contribution.type === "reported") {
|
|
3600
|
+
contributionPrefix = "\u{1F4CB} Reported: ";
|
|
3601
|
+
} else if (contribution.type === "assigned-resolved") {
|
|
3602
|
+
contributionPrefix = "\u2705 Resolved: ";
|
|
3603
|
+
} else {
|
|
3604
|
+
contributionPrefix = "\u270F\uFE0F Updated: ";
|
|
3605
|
+
}
|
|
3606
|
+
message = `${contributionPrefix}${issue.fields.summary}
|
|
3607
|
+
|
|
3608
|
+
${contribution.details}`;
|
|
3609
|
+
if (contribution.type === "created" && issue.fields.description) {
|
|
3610
|
+
const truncatedDesc = issue.fields.description.substring(0, this.MAX_DESCRIPTION_LENGTH);
|
|
3611
|
+
message = `${contributionPrefix}${issue.fields.summary}
|
|
3612
|
+
|
|
3613
|
+
${truncatedDesc}
|
|
3614
|
+
|
|
3615
|
+
${contribution.details}`;
|
|
3616
|
+
}
|
|
3617
|
+
} else {
|
|
3618
|
+
message = issue.fields.summary;
|
|
3619
|
+
if (issue.fields.description) {
|
|
3620
|
+
const truncatedDesc = issue.fields.description.substring(0, this.MAX_DESCRIPTION_LENGTH);
|
|
3621
|
+
message = `${issue.fields.summary}
|
|
3517
3622
|
|
|
3518
3623
|
${truncatedDesc}`;
|
|
3624
|
+
}
|
|
3625
|
+
}
|
|
3626
|
+
let date;
|
|
3627
|
+
if (contribution?.type === "created" || contribution?.type === "reported") {
|
|
3628
|
+
date = issue.fields.created;
|
|
3629
|
+
} else if (contribution?.type === "assigned-resolved" && issue.fields.resolutiondate) {
|
|
3630
|
+
date = issue.fields.resolutiondate;
|
|
3631
|
+
} else {
|
|
3632
|
+
date = issue.fields.updated;
|
|
3519
3633
|
}
|
|
3520
|
-
const date = issue.fields.resolutiondate || issue.fields.updated;
|
|
3521
3634
|
let baseUrl = "https://jira.atlassian.net";
|
|
3522
3635
|
if (instanceUrl) {
|
|
3523
3636
|
baseUrl = instanceUrl.startsWith("http") ? instanceUrl : `https://${instanceUrl}`;
|
|
@@ -3531,6 +3644,8 @@ ${truncatedDesc}`;
|
|
|
3531
3644
|
}
|
|
3532
3645
|
}
|
|
3533
3646
|
const url = `${baseUrl}/browse/${issue.key}`;
|
|
3647
|
+
const baseComplexity = this.estimateComplexity(issue);
|
|
3648
|
+
const impactScore = contribution ? this.calculateJiraContributionImpact(contribution.type, baseComplexity) : baseComplexity;
|
|
3534
3649
|
return {
|
|
3535
3650
|
sha: issue.key,
|
|
3536
3651
|
message,
|
|
@@ -3540,11 +3655,11 @@ ${truncatedDesc}`;
|
|
|
3540
3655
|
url,
|
|
3541
3656
|
diffStats: {
|
|
3542
3657
|
filesChanged: 0,
|
|
3543
|
-
insertions:
|
|
3658
|
+
insertions: impactScore,
|
|
3544
3659
|
deletions: 0
|
|
3545
3660
|
},
|
|
3546
3661
|
externalId: issue.key,
|
|
3547
|
-
externalType: "issue",
|
|
3662
|
+
externalType: contribution?.type || "issue",
|
|
3548
3663
|
externalSource: "jira",
|
|
3549
3664
|
externalUrl: url
|
|
3550
3665
|
};
|
|
@@ -3736,6 +3851,59 @@ var ConfluenceService = class {
|
|
|
3736
3851
|
const content = page.body?.storage?.value || "";
|
|
3737
3852
|
return Math.ceil(content.length / 80);
|
|
3738
3853
|
}
|
|
3854
|
+
/**
|
|
3855
|
+
* Determine the type of contribution the current user made to a page
|
|
3856
|
+
* Returns: 'created' | 'edited' | 'commented'
|
|
3857
|
+
*/
|
|
3858
|
+
async determineContributionType(page, userEmail) {
|
|
3859
|
+
if (page.history?.createdBy?.email === userEmail) {
|
|
3860
|
+
return {
|
|
3861
|
+
type: "created",
|
|
3862
|
+
details: `Created page with ${page.version.number} version${page.version.number > 1 ? "s" : ""}`
|
|
3863
|
+
};
|
|
3864
|
+
}
|
|
3865
|
+
const hasEdits = page.version.by.email === userEmail && page.version.number > 1;
|
|
3866
|
+
const userComments = page.children?.comment?.results?.filter(
|
|
3867
|
+
(comment) => comment.version.by.email === userEmail
|
|
3868
|
+
) || [];
|
|
3869
|
+
const hasComments = userComments.length > 0;
|
|
3870
|
+
if (hasEdits && hasComments) {
|
|
3871
|
+
return {
|
|
3872
|
+
type: "edited",
|
|
3873
|
+
details: `Edited page (v${page.version.number}) and added ${userComments.length} comment${userComments.length > 1 ? "s" : ""}`
|
|
3874
|
+
};
|
|
3875
|
+
}
|
|
3876
|
+
if (hasEdits) {
|
|
3877
|
+
return {
|
|
3878
|
+
type: "edited",
|
|
3879
|
+
details: `Edited page to version ${page.version.number}`
|
|
3880
|
+
};
|
|
3881
|
+
}
|
|
3882
|
+
if (hasComments) {
|
|
3883
|
+
return {
|
|
3884
|
+
type: "commented",
|
|
3885
|
+
details: `Added ${userComments.length} comment${userComments.length > 1 ? "s" : ""}`
|
|
3886
|
+
};
|
|
3887
|
+
}
|
|
3888
|
+
return {
|
|
3889
|
+
type: "edited",
|
|
3890
|
+
details: "Contributed to page"
|
|
3891
|
+
};
|
|
3892
|
+
}
|
|
3893
|
+
/**
|
|
3894
|
+
* Calculate impact score based on contribution type
|
|
3895
|
+
*/
|
|
3896
|
+
calculateContributionImpact(contributionType, baseSize) {
|
|
3897
|
+
const multipliers = {
|
|
3898
|
+
created: 1,
|
|
3899
|
+
// 100% - highest impact
|
|
3900
|
+
edited: 0.6,
|
|
3901
|
+
// 60% - medium impact
|
|
3902
|
+
commented: 0.3
|
|
3903
|
+
// 30% - lowest impact
|
|
3904
|
+
};
|
|
3905
|
+
return Math.ceil(baseSize * multipliers[contributionType]);
|
|
3906
|
+
}
|
|
3739
3907
|
/**
|
|
3740
3908
|
* Fetch pages with optional filtering
|
|
3741
3909
|
*/
|
|
@@ -3765,7 +3933,7 @@ var ConfluenceService = class {
|
|
|
3765
3933
|
cql,
|
|
3766
3934
|
start: start.toString(),
|
|
3767
3935
|
limit: limit.toString(),
|
|
3768
|
-
expand: "version,body.storage"
|
|
3936
|
+
expand: "version,history,children.comment,body.storage"
|
|
3769
3937
|
};
|
|
3770
3938
|
const queryString = Object.entries(params).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&");
|
|
3771
3939
|
endpoint = `/wiki/rest/api/content/search?${queryString}`;
|
|
@@ -3776,7 +3944,7 @@ var ConfluenceService = class {
|
|
|
3776
3944
|
status: "current",
|
|
3777
3945
|
start: start.toString(),
|
|
3778
3946
|
limit: limit.toString(),
|
|
3779
|
-
expand: "version,body.storage"
|
|
3947
|
+
expand: "version,history,children.comment,body.storage"
|
|
3780
3948
|
};
|
|
3781
3949
|
const queryString = Object.entries(params).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&");
|
|
3782
3950
|
endpoint = `/wiki/rest/api/content?${queryString}`;
|
|
@@ -3830,7 +3998,13 @@ var ConfluenceService = class {
|
|
|
3830
3998
|
throw error;
|
|
3831
3999
|
}
|
|
3832
4000
|
}
|
|
3833
|
-
|
|
4001
|
+
const email = await this.getCurrentUser();
|
|
4002
|
+
const commits = [];
|
|
4003
|
+
for (const page of allPages) {
|
|
4004
|
+
const commit = await this.transformPageToCommit(page, void 0, email);
|
|
4005
|
+
commits.push(commit);
|
|
4006
|
+
}
|
|
4007
|
+
return commits;
|
|
3834
4008
|
}
|
|
3835
4009
|
/**
|
|
3836
4010
|
* Fetch pages for the current authenticated user (created or contributed to)
|
|
@@ -3846,12 +4020,32 @@ var ConfluenceService = class {
|
|
|
3846
4020
|
});
|
|
3847
4021
|
}
|
|
3848
4022
|
/**
|
|
3849
|
-
* Transform Confluence page to GitCommit format with
|
|
4023
|
+
* Transform Confluence page to GitCommit format with contribution-specific data
|
|
3850
4024
|
*/
|
|
3851
|
-
transformPageToCommit(page, instanceUrl) {
|
|
3852
|
-
|
|
4025
|
+
async transformPageToCommit(page, instanceUrl, userEmail) {
|
|
4026
|
+
let contribution = null;
|
|
4027
|
+
if (userEmail) {
|
|
4028
|
+
contribution = await this.determineContributionType(page, userEmail);
|
|
4029
|
+
}
|
|
4030
|
+
let message;
|
|
4031
|
+
let contributionPrefix = "";
|
|
4032
|
+
if (contribution) {
|
|
4033
|
+
if (contribution.type === "created") {
|
|
4034
|
+
contributionPrefix = "\u{1F4DD} Created: ";
|
|
4035
|
+
} else if (contribution.type === "edited") {
|
|
4036
|
+
contributionPrefix = "\u270F\uFE0F Edited: ";
|
|
4037
|
+
} else {
|
|
4038
|
+
contributionPrefix = "\u{1F4AC} Commented on: ";
|
|
4039
|
+
}
|
|
4040
|
+
message = `${contributionPrefix}${page.title}
|
|
4041
|
+
|
|
4042
|
+
${contribution.details}
|
|
4043
|
+
[Confluence Page v${page.version.number}]`;
|
|
4044
|
+
} else {
|
|
4045
|
+
message = `${page.title}
|
|
3853
4046
|
|
|
3854
4047
|
[Confluence Page v${page.version.number}]`;
|
|
4048
|
+
}
|
|
3855
4049
|
let baseUrl = "https://confluence.atlassian.net";
|
|
3856
4050
|
if (instanceUrl) {
|
|
3857
4051
|
baseUrl = instanceUrl.startsWith("http") ? instanceUrl : `https://${instanceUrl}`;
|
|
@@ -3865,20 +4059,25 @@ var ConfluenceService = class {
|
|
|
3865
4059
|
}
|
|
3866
4060
|
}
|
|
3867
4061
|
const url = `${baseUrl}/wiki${page._links.webui}`;
|
|
4062
|
+
const baseSize = this.estimatePageSize(page);
|
|
4063
|
+
const impactScore = contribution ? this.calculateContributionImpact(contribution.type, baseSize) : baseSize;
|
|
4064
|
+
const author = page.history?.createdBy?.displayName || page.version.by.displayName;
|
|
4065
|
+
const authorEmail = page.history?.createdBy?.email || page.version.by.email;
|
|
4066
|
+
const date = contribution?.type === "created" ? page.history?.createdDate || page.version.when : page.version.when;
|
|
3868
4067
|
return {
|
|
3869
4068
|
sha: page.id,
|
|
3870
4069
|
message,
|
|
3871
|
-
author
|
|
3872
|
-
authorEmail
|
|
3873
|
-
date
|
|
4070
|
+
author,
|
|
4071
|
+
authorEmail,
|
|
4072
|
+
date,
|
|
3874
4073
|
url,
|
|
3875
4074
|
diffStats: {
|
|
3876
4075
|
filesChanged: 1,
|
|
3877
|
-
insertions:
|
|
4076
|
+
insertions: impactScore,
|
|
3878
4077
|
deletions: 0
|
|
3879
4078
|
},
|
|
3880
4079
|
externalId: page.id,
|
|
3881
|
-
externalType: "page",
|
|
4080
|
+
externalType: contribution?.type || "page",
|
|
3882
4081
|
externalSource: "confluence",
|
|
3883
4082
|
externalUrl: url
|
|
3884
4083
|
};
|