@bragduck/cli 2.10.2 → 2.12.1
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 +208 -29
- package/dist/bin/bragduck.js.map +1 -1
- package/package.json +1 -1
package/dist/bin/bragduck.js
CHANGED
|
@@ -3411,6 +3411,52 @@ var JiraService = class {
|
|
|
3411
3411
|
};
|
|
3412
3412
|
return typeScores[issue.fields.issuetype.name] || 100;
|
|
3413
3413
|
}
|
|
3414
|
+
/**
|
|
3415
|
+
* Determine the type of contribution the current user made to an issue
|
|
3416
|
+
* Returns: 'created' | 'assigned-resolved' | 'edited'
|
|
3417
|
+
*/
|
|
3418
|
+
async determineJiraContributionType(issue, userEmail) {
|
|
3419
|
+
if (issue.fields.creator.emailAddress === userEmail) {
|
|
3420
|
+
return {
|
|
3421
|
+
type: "created",
|
|
3422
|
+
details: `Created ${issue.fields.issuetype.name}: ${issue.fields.status.name}`
|
|
3423
|
+
};
|
|
3424
|
+
}
|
|
3425
|
+
const isAssigned = issue.fields.assignee?.emailAddress === userEmail;
|
|
3426
|
+
const isResolved = issue.fields.resolutiondate !== null && issue.fields.resolutiondate !== void 0;
|
|
3427
|
+
const userEdits = issue.changelog?.histories?.filter((history) => history.author.emailAddress === userEmail) || [];
|
|
3428
|
+
const hasEdits = userEdits.length > 0;
|
|
3429
|
+
if (isAssigned && isResolved) {
|
|
3430
|
+
return {
|
|
3431
|
+
type: "assigned-resolved",
|
|
3432
|
+
details: `Assigned and resolved ${issue.fields.issuetype.name}${hasEdits ? ` with ${userEdits.length} update${userEdits.length > 1 ? "s" : ""}` : ""}`
|
|
3433
|
+
};
|
|
3434
|
+
}
|
|
3435
|
+
if (hasEdits) {
|
|
3436
|
+
return {
|
|
3437
|
+
type: "edited",
|
|
3438
|
+
details: `Updated ${issue.fields.issuetype.name} (${userEdits.length} change${userEdits.length > 1 ? "s" : ""})`
|
|
3439
|
+
};
|
|
3440
|
+
}
|
|
3441
|
+
return {
|
|
3442
|
+
type: "edited",
|
|
3443
|
+
details: `Contributed to ${issue.fields.issuetype.name}`
|
|
3444
|
+
};
|
|
3445
|
+
}
|
|
3446
|
+
/**
|
|
3447
|
+
* Calculate impact score based on contribution type
|
|
3448
|
+
*/
|
|
3449
|
+
calculateJiraContributionImpact(contributionType, baseComplexity) {
|
|
3450
|
+
const multipliers = {
|
|
3451
|
+
created: 1,
|
|
3452
|
+
// 100% - highest impact (created the issue)
|
|
3453
|
+
"assigned-resolved": 0.8,
|
|
3454
|
+
// 80% - high impact (owned and resolved)
|
|
3455
|
+
edited: 0.4
|
|
3456
|
+
// 40% - medium impact (contributed updates)
|
|
3457
|
+
};
|
|
3458
|
+
return Math.ceil(baseComplexity * multipliers[contributionType]);
|
|
3459
|
+
}
|
|
3414
3460
|
/**
|
|
3415
3461
|
* Fetch issues with optional filtering
|
|
3416
3462
|
*/
|
|
@@ -3424,6 +3470,7 @@ var JiraService = class {
|
|
|
3424
3470
|
"updated",
|
|
3425
3471
|
"resolutiondate",
|
|
3426
3472
|
"creator",
|
|
3473
|
+
"assignee",
|
|
3427
3474
|
"status",
|
|
3428
3475
|
"issuetype"
|
|
3429
3476
|
];
|
|
@@ -3441,7 +3488,7 @@ var JiraService = class {
|
|
|
3441
3488
|
);
|
|
3442
3489
|
break;
|
|
3443
3490
|
}
|
|
3444
|
-
const endpoint = `/rest/api/2/search?jql=${encodeURIComponent(jql)}&startAt=${startAt}&maxResults=${maxResults}&fields=${fields.join(",")}`;
|
|
3491
|
+
const endpoint = `/rest/api/2/search?jql=${encodeURIComponent(jql)}&startAt=${startAt}&maxResults=${maxResults}&fields=${fields.join(",")}&expand=changelog`;
|
|
3445
3492
|
try {
|
|
3446
3493
|
const response = await this.request(endpoint);
|
|
3447
3494
|
if (response.issues.length === 0) {
|
|
@@ -3467,7 +3514,14 @@ var JiraService = class {
|
|
|
3467
3514
|
break;
|
|
3468
3515
|
}
|
|
3469
3516
|
if (options.limit && allIssues.length >= options.limit) {
|
|
3470
|
-
|
|
3517
|
+
const email2 = await this.getCurrentUser();
|
|
3518
|
+
const limitedIssues = allIssues.slice(0, options.limit);
|
|
3519
|
+
const commits2 = [];
|
|
3520
|
+
for (const issue of limitedIssues) {
|
|
3521
|
+
const commit = await this.transformIssueToCommit(issue, void 0, email2);
|
|
3522
|
+
commits2.push(commit);
|
|
3523
|
+
}
|
|
3524
|
+
return commits2;
|
|
3471
3525
|
}
|
|
3472
3526
|
startAt += maxResults;
|
|
3473
3527
|
} catch (error) {
|
|
@@ -3491,7 +3545,13 @@ var JiraService = class {
|
|
|
3491
3545
|
throw error;
|
|
3492
3546
|
}
|
|
3493
3547
|
}
|
|
3494
|
-
|
|
3548
|
+
const email = await this.getCurrentUser();
|
|
3549
|
+
const commits = [];
|
|
3550
|
+
for (const issue of allIssues) {
|
|
3551
|
+
const commit = await this.transformIssueToCommit(issue, void 0, email);
|
|
3552
|
+
commits.push(commit);
|
|
3553
|
+
}
|
|
3554
|
+
return commits;
|
|
3495
3555
|
}
|
|
3496
3556
|
/**
|
|
3497
3557
|
* Fetch issues for the current authenticated user
|
|
@@ -3507,17 +3567,51 @@ var JiraService = class {
|
|
|
3507
3567
|
});
|
|
3508
3568
|
}
|
|
3509
3569
|
/**
|
|
3510
|
-
* Transform Jira issue to GitCommit format with
|
|
3570
|
+
* Transform Jira issue to GitCommit format with contribution-specific data
|
|
3511
3571
|
*/
|
|
3512
|
-
transformIssueToCommit(issue, instanceUrl) {
|
|
3513
|
-
let
|
|
3514
|
-
if (
|
|
3515
|
-
|
|
3516
|
-
|
|
3572
|
+
async transformIssueToCommit(issue, instanceUrl, userEmail) {
|
|
3573
|
+
let contribution = null;
|
|
3574
|
+
if (userEmail) {
|
|
3575
|
+
contribution = await this.determineJiraContributionType(issue, userEmail);
|
|
3576
|
+
}
|
|
3577
|
+
let message;
|
|
3578
|
+
let contributionPrefix = "";
|
|
3579
|
+
if (contribution) {
|
|
3580
|
+
if (contribution.type === "created") {
|
|
3581
|
+
contributionPrefix = "\u{1F3AB} Created: ";
|
|
3582
|
+
} else if (contribution.type === "assigned-resolved") {
|
|
3583
|
+
contributionPrefix = "\u2705 Resolved: ";
|
|
3584
|
+
} else {
|
|
3585
|
+
contributionPrefix = "\u270F\uFE0F Updated: ";
|
|
3586
|
+
}
|
|
3587
|
+
message = `${contributionPrefix}${issue.fields.summary}
|
|
3588
|
+
|
|
3589
|
+
${contribution.details}`;
|
|
3590
|
+
if (contribution.type === "created" && issue.fields.description) {
|
|
3591
|
+
const truncatedDesc = issue.fields.description.substring(0, this.MAX_DESCRIPTION_LENGTH);
|
|
3592
|
+
message = `${contributionPrefix}${issue.fields.summary}
|
|
3593
|
+
|
|
3594
|
+
${truncatedDesc}
|
|
3595
|
+
|
|
3596
|
+
${contribution.details}`;
|
|
3597
|
+
}
|
|
3598
|
+
} else {
|
|
3599
|
+
message = issue.fields.summary;
|
|
3600
|
+
if (issue.fields.description) {
|
|
3601
|
+
const truncatedDesc = issue.fields.description.substring(0, this.MAX_DESCRIPTION_LENGTH);
|
|
3602
|
+
message = `${issue.fields.summary}
|
|
3517
3603
|
|
|
3518
3604
|
${truncatedDesc}`;
|
|
3605
|
+
}
|
|
3606
|
+
}
|
|
3607
|
+
let date;
|
|
3608
|
+
if (contribution?.type === "created") {
|
|
3609
|
+
date = issue.fields.created;
|
|
3610
|
+
} else if (contribution?.type === "assigned-resolved" && issue.fields.resolutiondate) {
|
|
3611
|
+
date = issue.fields.resolutiondate;
|
|
3612
|
+
} else {
|
|
3613
|
+
date = issue.fields.updated;
|
|
3519
3614
|
}
|
|
3520
|
-
const date = issue.fields.resolutiondate || issue.fields.updated;
|
|
3521
3615
|
let baseUrl = "https://jira.atlassian.net";
|
|
3522
3616
|
if (instanceUrl) {
|
|
3523
3617
|
baseUrl = instanceUrl.startsWith("http") ? instanceUrl : `https://${instanceUrl}`;
|
|
@@ -3531,6 +3625,8 @@ ${truncatedDesc}`;
|
|
|
3531
3625
|
}
|
|
3532
3626
|
}
|
|
3533
3627
|
const url = `${baseUrl}/browse/${issue.key}`;
|
|
3628
|
+
const baseComplexity = this.estimateComplexity(issue);
|
|
3629
|
+
const impactScore = contribution ? this.calculateJiraContributionImpact(contribution.type, baseComplexity) : baseComplexity;
|
|
3534
3630
|
return {
|
|
3535
3631
|
sha: issue.key,
|
|
3536
3632
|
message,
|
|
@@ -3540,11 +3636,11 @@ ${truncatedDesc}`;
|
|
|
3540
3636
|
url,
|
|
3541
3637
|
diffStats: {
|
|
3542
3638
|
filesChanged: 0,
|
|
3543
|
-
insertions:
|
|
3639
|
+
insertions: impactScore,
|
|
3544
3640
|
deletions: 0
|
|
3545
3641
|
},
|
|
3546
3642
|
externalId: issue.key,
|
|
3547
|
-
externalType: "issue",
|
|
3643
|
+
externalType: contribution?.type || "issue",
|
|
3548
3644
|
externalSource: "jira",
|
|
3549
3645
|
externalUrl: url
|
|
3550
3646
|
};
|
|
@@ -3712,23 +3808,22 @@ var ConfluenceService = class {
|
|
|
3712
3808
|
}
|
|
3713
3809
|
const queries = [];
|
|
3714
3810
|
queries.push("type = page");
|
|
3715
|
-
queries.push("status = current");
|
|
3716
3811
|
if (options.days) {
|
|
3717
|
-
queries.push(`
|
|
3812
|
+
queries.push(`lastmodified > startOfDay("-${options.days}d")`);
|
|
3718
3813
|
}
|
|
3719
3814
|
if (options.author) {
|
|
3720
3815
|
if (options.author.includes("@")) {
|
|
3721
|
-
queries.push("(creator = currentUser()
|
|
3816
|
+
queries.push("(creator = currentUser() or contributor = currentUser())");
|
|
3722
3817
|
} else {
|
|
3723
|
-
queries.push(`(creator = "${options.author}"
|
|
3818
|
+
queries.push(`(creator = "${options.author}" or contributor = "${options.author}")`);
|
|
3724
3819
|
}
|
|
3725
3820
|
} else {
|
|
3726
|
-
queries.push("(creator = currentUser()
|
|
3821
|
+
queries.push("(creator = currentUser() or contributor = currentUser())");
|
|
3727
3822
|
}
|
|
3728
3823
|
if (options.cql) {
|
|
3729
3824
|
queries.push(`(${options.cql})`);
|
|
3730
3825
|
}
|
|
3731
|
-
return queries.join("
|
|
3826
|
+
return queries.join(" and ");
|
|
3732
3827
|
}
|
|
3733
3828
|
/**
|
|
3734
3829
|
* Estimate page size for impact scoring
|
|
@@ -3737,6 +3832,59 @@ var ConfluenceService = class {
|
|
|
3737
3832
|
const content = page.body?.storage?.value || "";
|
|
3738
3833
|
return Math.ceil(content.length / 80);
|
|
3739
3834
|
}
|
|
3835
|
+
/**
|
|
3836
|
+
* Determine the type of contribution the current user made to a page
|
|
3837
|
+
* Returns: 'created' | 'edited' | 'commented'
|
|
3838
|
+
*/
|
|
3839
|
+
async determineContributionType(page, userEmail) {
|
|
3840
|
+
if (page.history?.createdBy?.email === userEmail) {
|
|
3841
|
+
return {
|
|
3842
|
+
type: "created",
|
|
3843
|
+
details: `Created page with ${page.version.number} version${page.version.number > 1 ? "s" : ""}`
|
|
3844
|
+
};
|
|
3845
|
+
}
|
|
3846
|
+
const hasEdits = page.version.by.email === userEmail && page.version.number > 1;
|
|
3847
|
+
const userComments = page.children?.comment?.results?.filter(
|
|
3848
|
+
(comment) => comment.version.by.email === userEmail
|
|
3849
|
+
) || [];
|
|
3850
|
+
const hasComments = userComments.length > 0;
|
|
3851
|
+
if (hasEdits && hasComments) {
|
|
3852
|
+
return {
|
|
3853
|
+
type: "edited",
|
|
3854
|
+
details: `Edited page (v${page.version.number}) and added ${userComments.length} comment${userComments.length > 1 ? "s" : ""}`
|
|
3855
|
+
};
|
|
3856
|
+
}
|
|
3857
|
+
if (hasEdits) {
|
|
3858
|
+
return {
|
|
3859
|
+
type: "edited",
|
|
3860
|
+
details: `Edited page to version ${page.version.number}`
|
|
3861
|
+
};
|
|
3862
|
+
}
|
|
3863
|
+
if (hasComments) {
|
|
3864
|
+
return {
|
|
3865
|
+
type: "commented",
|
|
3866
|
+
details: `Added ${userComments.length} comment${userComments.length > 1 ? "s" : ""}`
|
|
3867
|
+
};
|
|
3868
|
+
}
|
|
3869
|
+
return {
|
|
3870
|
+
type: "edited",
|
|
3871
|
+
details: "Contributed to page"
|
|
3872
|
+
};
|
|
3873
|
+
}
|
|
3874
|
+
/**
|
|
3875
|
+
* Calculate impact score based on contribution type
|
|
3876
|
+
*/
|
|
3877
|
+
calculateContributionImpact(contributionType, baseSize) {
|
|
3878
|
+
const multipliers = {
|
|
3879
|
+
created: 1,
|
|
3880
|
+
// 100% - highest impact
|
|
3881
|
+
edited: 0.6,
|
|
3882
|
+
// 60% - medium impact
|
|
3883
|
+
commented: 0.3
|
|
3884
|
+
// 30% - lowest impact
|
|
3885
|
+
};
|
|
3886
|
+
return Math.ceil(baseSize * multipliers[contributionType]);
|
|
3887
|
+
}
|
|
3740
3888
|
/**
|
|
3741
3889
|
* Fetch pages with optional filtering
|
|
3742
3890
|
*/
|
|
@@ -3766,7 +3914,7 @@ var ConfluenceService = class {
|
|
|
3766
3914
|
cql,
|
|
3767
3915
|
start: start.toString(),
|
|
3768
3916
|
limit: limit.toString(),
|
|
3769
|
-
expand: "version,body.storage"
|
|
3917
|
+
expand: "version,history,children.comment,body.storage"
|
|
3770
3918
|
};
|
|
3771
3919
|
const queryString = Object.entries(params).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&");
|
|
3772
3920
|
endpoint = `/wiki/rest/api/content/search?${queryString}`;
|
|
@@ -3777,7 +3925,7 @@ var ConfluenceService = class {
|
|
|
3777
3925
|
status: "current",
|
|
3778
3926
|
start: start.toString(),
|
|
3779
3927
|
limit: limit.toString(),
|
|
3780
|
-
expand: "version,body.storage"
|
|
3928
|
+
expand: "version,history,children.comment,body.storage"
|
|
3781
3929
|
};
|
|
3782
3930
|
const queryString = Object.entries(params).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&");
|
|
3783
3931
|
endpoint = `/wiki/rest/api/content?${queryString}`;
|
|
@@ -3831,7 +3979,13 @@ var ConfluenceService = class {
|
|
|
3831
3979
|
throw error;
|
|
3832
3980
|
}
|
|
3833
3981
|
}
|
|
3834
|
-
|
|
3982
|
+
const email = await this.getCurrentUser();
|
|
3983
|
+
const commits = [];
|
|
3984
|
+
for (const page of allPages) {
|
|
3985
|
+
const commit = await this.transformPageToCommit(page, void 0, email);
|
|
3986
|
+
commits.push(commit);
|
|
3987
|
+
}
|
|
3988
|
+
return commits;
|
|
3835
3989
|
}
|
|
3836
3990
|
/**
|
|
3837
3991
|
* Fetch pages for the current authenticated user (created or contributed to)
|
|
@@ -3847,12 +4001,32 @@ var ConfluenceService = class {
|
|
|
3847
4001
|
});
|
|
3848
4002
|
}
|
|
3849
4003
|
/**
|
|
3850
|
-
* Transform Confluence page to GitCommit format with
|
|
4004
|
+
* Transform Confluence page to GitCommit format with contribution-specific data
|
|
3851
4005
|
*/
|
|
3852
|
-
transformPageToCommit(page, instanceUrl) {
|
|
3853
|
-
|
|
4006
|
+
async transformPageToCommit(page, instanceUrl, userEmail) {
|
|
4007
|
+
let contribution = null;
|
|
4008
|
+
if (userEmail) {
|
|
4009
|
+
contribution = await this.determineContributionType(page, userEmail);
|
|
4010
|
+
}
|
|
4011
|
+
let message;
|
|
4012
|
+
let contributionPrefix = "";
|
|
4013
|
+
if (contribution) {
|
|
4014
|
+
if (contribution.type === "created") {
|
|
4015
|
+
contributionPrefix = "\u{1F4DD} Created: ";
|
|
4016
|
+
} else if (contribution.type === "edited") {
|
|
4017
|
+
contributionPrefix = "\u270F\uFE0F Edited: ";
|
|
4018
|
+
} else {
|
|
4019
|
+
contributionPrefix = "\u{1F4AC} Commented on: ";
|
|
4020
|
+
}
|
|
4021
|
+
message = `${contributionPrefix}${page.title}
|
|
3854
4022
|
|
|
4023
|
+
${contribution.details}
|
|
3855
4024
|
[Confluence Page v${page.version.number}]`;
|
|
4025
|
+
} else {
|
|
4026
|
+
message = `${page.title}
|
|
4027
|
+
|
|
4028
|
+
[Confluence Page v${page.version.number}]`;
|
|
4029
|
+
}
|
|
3856
4030
|
let baseUrl = "https://confluence.atlassian.net";
|
|
3857
4031
|
if (instanceUrl) {
|
|
3858
4032
|
baseUrl = instanceUrl.startsWith("http") ? instanceUrl : `https://${instanceUrl}`;
|
|
@@ -3866,20 +4040,25 @@ var ConfluenceService = class {
|
|
|
3866
4040
|
}
|
|
3867
4041
|
}
|
|
3868
4042
|
const url = `${baseUrl}/wiki${page._links.webui}`;
|
|
4043
|
+
const baseSize = this.estimatePageSize(page);
|
|
4044
|
+
const impactScore = contribution ? this.calculateContributionImpact(contribution.type, baseSize) : baseSize;
|
|
4045
|
+
const author = page.history?.createdBy?.displayName || page.version.by.displayName;
|
|
4046
|
+
const authorEmail = page.history?.createdBy?.email || page.version.by.email;
|
|
4047
|
+
const date = contribution?.type === "created" ? page.history?.createdDate || page.version.when : page.version.when;
|
|
3869
4048
|
return {
|
|
3870
4049
|
sha: page.id,
|
|
3871
4050
|
message,
|
|
3872
|
-
author
|
|
3873
|
-
authorEmail
|
|
3874
|
-
date
|
|
4051
|
+
author,
|
|
4052
|
+
authorEmail,
|
|
4053
|
+
date,
|
|
3875
4054
|
url,
|
|
3876
4055
|
diffStats: {
|
|
3877
4056
|
filesChanged: 1,
|
|
3878
|
-
insertions:
|
|
4057
|
+
insertions: impactScore,
|
|
3879
4058
|
deletions: 0
|
|
3880
4059
|
},
|
|
3881
4060
|
externalId: page.id,
|
|
3882
|
-
externalType: "page",
|
|
4061
|
+
externalType: contribution?.type || "page",
|
|
3883
4062
|
externalSource: "confluence",
|
|
3884
4063
|
externalUrl: url
|
|
3885
4064
|
};
|