@gpc-cli/core 0.9.49 → 0.9.51
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/index.d.ts +72 -1
- package/dist/index.js +539 -3
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.d.ts
CHANGED
|
@@ -1255,6 +1255,77 @@ declare function fetchChangelog(options?: FetchChangelogOptions): Promise<Change
|
|
|
1255
1255
|
*/
|
|
1256
1256
|
declare function formatChangelogEntry(entry: ChangelogEntry): string;
|
|
1257
1257
|
|
|
1258
|
+
type OutputMode = "md" | "json" | "prompt";
|
|
1259
|
+
interface RawCommit {
|
|
1260
|
+
sha: string;
|
|
1261
|
+
subject: string;
|
|
1262
|
+
body: string;
|
|
1263
|
+
files: string[];
|
|
1264
|
+
additions: number;
|
|
1265
|
+
deletions: number;
|
|
1266
|
+
authorDate: string;
|
|
1267
|
+
}
|
|
1268
|
+
interface ParsedCommit {
|
|
1269
|
+
sha: string;
|
|
1270
|
+
type: string;
|
|
1271
|
+
scope?: string;
|
|
1272
|
+
subject: string;
|
|
1273
|
+
prRef?: string;
|
|
1274
|
+
files: string[];
|
|
1275
|
+
weight: number;
|
|
1276
|
+
isRevert: boolean;
|
|
1277
|
+
isFixup: boolean;
|
|
1278
|
+
authorDate: string;
|
|
1279
|
+
}
|
|
1280
|
+
interface CommitCluster {
|
|
1281
|
+
id: string;
|
|
1282
|
+
label: string;
|
|
1283
|
+
commits: ParsedCommit[];
|
|
1284
|
+
weight: number;
|
|
1285
|
+
primaryType: string;
|
|
1286
|
+
}
|
|
1287
|
+
interface GeneratedChangelog {
|
|
1288
|
+
from: string;
|
|
1289
|
+
to: string;
|
|
1290
|
+
repo: string | null;
|
|
1291
|
+
rawCommitCount: number;
|
|
1292
|
+
commits: ParsedCommit[];
|
|
1293
|
+
clusters: CommitCluster[];
|
|
1294
|
+
grouped: Record<string, ParsedCommit[]>;
|
|
1295
|
+
headlineCandidates: CommitCluster[];
|
|
1296
|
+
warnings: string[];
|
|
1297
|
+
}
|
|
1298
|
+
interface GenerateOptions {
|
|
1299
|
+
from?: string;
|
|
1300
|
+
to?: string;
|
|
1301
|
+
cwd?: string;
|
|
1302
|
+
repo?: string;
|
|
1303
|
+
}
|
|
1304
|
+
interface GitRunner {
|
|
1305
|
+
log(args: {
|
|
1306
|
+
from: string;
|
|
1307
|
+
to: string;
|
|
1308
|
+
cwd: string;
|
|
1309
|
+
}): Promise<RawCommit[]>;
|
|
1310
|
+
describeLatestTag(cwd: string): Promise<string | null>;
|
|
1311
|
+
verifyRef(ref: string, cwd: string): Promise<boolean>;
|
|
1312
|
+
remoteUrl(cwd: string): Promise<string | null>;
|
|
1313
|
+
}
|
|
1314
|
+
declare const SECTION_ORDER: readonly ["breaking", "feat", "fix", "perf", "docs", "ci", "release", "other"];
|
|
1315
|
+
declare const defaultGitRunner: GitRunner;
|
|
1316
|
+
declare function parseRemoteUrl(url: string | null): string | null;
|
|
1317
|
+
declare function parseCommit(raw: RawCommit): ParsedCommit;
|
|
1318
|
+
declare function generateChangelog(opts?: GenerateOptions, runner?: GitRunner): Promise<GeneratedChangelog>;
|
|
1319
|
+
|
|
1320
|
+
declare function renderMarkdown(g: GeneratedChangelog): string;
|
|
1321
|
+
|
|
1322
|
+
declare function renderJson(g: GeneratedChangelog): string;
|
|
1323
|
+
|
|
1324
|
+
declare function renderPrompt(g: GeneratedChangelog): string;
|
|
1325
|
+
|
|
1326
|
+
type Renderer = (g: GeneratedChangelog) => string;
|
|
1327
|
+
declare const RENDERERS: Record<OutputMode, Renderer>;
|
|
1328
|
+
|
|
1258
1329
|
interface RtdnStatus {
|
|
1259
1330
|
topicName: string | null;
|
|
1260
1331
|
enabled: boolean;
|
|
@@ -1300,4 +1371,4 @@ declare function decodeNotification(base64Payload: string): DecodedNotification;
|
|
|
1300
1371
|
*/
|
|
1301
1372
|
declare function formatNotification(notification: DecodedNotification): Record<string, unknown>;
|
|
1302
1373
|
|
|
1303
|
-
export { ApiError, type AppInfo, type AppStatus, type AuditEntry, type BatchSyncResult, type BundleAnalysis, type BundleComparison, type BundleEntry, type BundleSizeCheckResult, type BundleSizeConfig, type ChangelogEntry, type CommandContext, ConfigError, type CreateEnterpriseAppParams, DEFAULT_LIMITS, DEFAULT_PREFLIGHT_CONFIG, type DecodedNotification, type DiffToken, type DiscoverPluginsOptions, type DryRunPublishResult, type DryRunResult, type DryRunUploadResult, type ExportImagesOptions, type ExportImagesSummary, type FastlaneDetection, type FastlaneLane, type FetchChangelogOptions, type FieldLintResult, type FileValidationResult, type FindingSeverity, GOOGLE_PLAY_LANGUAGES, type GetAppStatusOptions, type GitNotesOptions, type GitReleaseNotes, GpcError, type ImageValidationResult, type InitOptions, type InitResult, type InternalSharingUploadResult, type ListIapOptions, type ListSubscriptionsOptions, type ListUsersOptions, type ListVoidedOptions, type ListingDiff, type ListingFieldLimits, type ListingLintResult, type ListingsResult, type LoadedPlugin, type MigrationResult, NetworkError, type OneTimeProductDiff, PERMISSION_PROPAGATION_WARNING, type ParsedManifest, type ParsedMonth, PluginManager, type PreflightConfig, type PreflightFinding, type PreflightOptions, type PreflightResult, type PreflightScanner, type PublishOptions, type PublishResult, type PushResult, type QuotaUsage, type ReleaseDiff, type ReleaseNotesValidation, type ReleaseStatusResult, type ReviewAnalysis, type ReviewExportOptions, type ReviewsFilterOptions, type RtdnStatus, SENSITIVE_ARG_KEYS, SENSITIVE_KEYS, SEVERITY_ORDER, type ScaffoldOptions, type ScaffoldResult, type Spinner, type StatusDiff, type StatusRelease, type StatusReviews, type StatusVitalMetric, type SubscriptionAnalytics, type SubscriptionDiff, type SyncResult, type ThresholdResult, type TrainConfig, type TrainState, type UploadResult, type ValidateCheck, type ValidateOptions, type ValidateResult, type VersionVitalsComparison, type VersionVitalsRow, type VitalsOverview, type VitalsQueryOptions, type VitalsTrendComparison, type WatchOptions, type WatchVitalsOptions, type WebhookPayload, abortTrain, acknowledgeProductPurchase, activateBasePlan, activateOffer, addRecoveryTargeting, addTesters, advanceTrain, analyzeBundle, analyzeRemoteListings, analyzeReviews, batchGetOrders, batchSyncInAppProducts, cancelRecoveryAction, cancelSubscriptionPurchase, cancelSubscriptionV2, checkBundleSize, checkThreshold, clearAuditLog, compareBundles, compareVersionVitals, compareVitalsTrend, computeStatusDiff, consumeProductPurchase, convertRegionPrices, createAuditEntry, createDeviceTier, createEnterpriseApp, createExternalTransaction, createGrant, createInAppProduct, createOffer, createOneTimeOffer, createOneTimeProduct, createRecoveryAction, createSpinner, createSubscription, createTrack, deactivateBasePlan, deactivateOffer, decodeNotification, deferSubscriptionPurchase, deferSubscriptionV2, deleteBasePlan, deleteGrant, deleteImage, deleteInAppProduct, deleteListing, deleteOffer, deleteOneTimeOffer, deleteOneTimeProduct, deleteSubscription, deployRecoveryAction, detectFastlane, detectOutputFormat, diffListings, diffListingsCommand, diffListingsEnhanced, diffOneTimeProduct, diffReleases, diffSubscription, discoverPlugins, downloadGeneratedApk, downloadReport, exportImages, exportReviews, fetchChangelog, fetchReleaseNotes, formatChangelogEntry, formatCustomPayload, formatDiscordPayload, formatJunit, formatNotification, formatOutput, formatSlackPayload, formatStatusDiff, formatStatusSummary, formatStatusTable, formatWordDiff, generateMigrationPlan, generateNotesFromGit, getAllScannerNames, getAppInfo, getAppStatus, getCountryAvailability, getDeviceTier, getExternalTransaction, getInAppProduct, getListings, getOffer, getOneTimeOffer, getOneTimeProduct, getOrderDetails, getProductPurchase, getProductPurchaseV2, getQuotaUsage, getReleasesStatus, getReview, getRtdnStatus, getSubscription, getSubscriptionAnalytics, getSubscriptionPurchase, getTrainStatus, getUser, getVitalsAnomalies, getVitalsAnr, getVitalsBattery, getVitalsCrashes, getVitalsErrorCount, getVitalsLmk, getVitalsMemory, getVitalsOverview, getVitalsRendering, getVitalsStartup, importDataSafety, importTestersFromCsv, initAudit, initProject, inviteUser, isFinancialReportType, isStatsReportType, isValidBcp47, isValidReportType, isValidStatsDimension, lintListing, lintListings, lintLocalListings, listAchievements, listAuditEvents, listDeviceTiers, listEvents, listGeneratedApks, listGrants, listImages, listInAppProducts, listLeaderboards, listOffers, listOneTimeOffers, listOneTimeProducts, listRecoveryActions, listReports, listReviews, listSubscriptions, listTesters, listTracks, listUsers, listVoidedPurchases, loadPreflightConfig, loadStatusCache, maybePaginate, migratePrices, parseAppfile, parseFastfile, parseGrantArg, parseMonth, pauseTrain, promoteRelease, publish, publishEnterpriseApp, pullListings, pushListings, readListingsFromDir, readReleaseNotesFromDir, redactAuditArgs, redactSensitive, refundExternalTransaction, refundOrder, relativeTime, removeTesters, removeUser, replyToReview, revokeSubscriptionPurchase, runPreflight, runWatchLoop, safePath, safePathWithin, saveStatusCache, scaffoldPlugin, searchAuditEvents, searchVitalsErrors, sendNotification, sendWebhook, sortResults, startTrain, statusHasBreach, syncInAppProducts, topFiles, trackBreachState, updateAppDetails, updateDataSafety, updateGrant, updateInAppProduct, updateListing, updateOffer, updateOneTimeOffer, updateOneTimeProduct, updateRollout, updateSubscription, updateTrackConfig, updateUser, uploadExternallyHosted, uploadImage, uploadInternalSharing, uploadRelease, validateImage, validateLanguageCode, validatePackageName, validatePreSubmission, validateReleaseNotes, validateSku, validateTrackName, validateUploadFile, validateVersionCode, watchVitalsWithAutoHalt, wordDiff, writeAuditLog, writeListingsToDir, writeMigrationOutput };
|
|
1374
|
+
export { ApiError, type AppInfo, type AppStatus, type AuditEntry, type BatchSyncResult, type BundleAnalysis, type BundleComparison, type BundleEntry, type BundleSizeCheckResult, type BundleSizeConfig, type ChangelogEntry, type CommandContext, type CommitCluster, ConfigError, type CreateEnterpriseAppParams, DEFAULT_LIMITS, DEFAULT_PREFLIGHT_CONFIG, type DecodedNotification, type DiffToken, type DiscoverPluginsOptions, type DryRunPublishResult, type DryRunResult, type DryRunUploadResult, type ExportImagesOptions, type ExportImagesSummary, type FastlaneDetection, type FastlaneLane, type FetchChangelogOptions, type FieldLintResult, type FileValidationResult, type FindingSeverity, GOOGLE_PLAY_LANGUAGES, type GenerateOptions, type GeneratedChangelog, type GetAppStatusOptions, type GitNotesOptions, type GitReleaseNotes, type GitRunner, GpcError, type ImageValidationResult, type InitOptions, type InitResult, type InternalSharingUploadResult, type ListIapOptions, type ListSubscriptionsOptions, type ListUsersOptions, type ListVoidedOptions, type ListingDiff, type ListingFieldLimits, type ListingLintResult, type ListingsResult, type LoadedPlugin, type MigrationResult, NetworkError, type OneTimeProductDiff, type OutputMode, PERMISSION_PROPAGATION_WARNING, type ParsedCommit, type ParsedManifest, type ParsedMonth, PluginManager, type PreflightConfig, type PreflightFinding, type PreflightOptions, type PreflightResult, type PreflightScanner, type PublishOptions, type PublishResult, type PushResult, type QuotaUsage, RENDERERS, type RawCommit, type ReleaseDiff, type ReleaseNotesValidation, type ReleaseStatusResult, type Renderer, type ReviewAnalysis, type ReviewExportOptions, type ReviewsFilterOptions, type RtdnStatus, SECTION_ORDER, SENSITIVE_ARG_KEYS, SENSITIVE_KEYS, SEVERITY_ORDER, type ScaffoldOptions, type ScaffoldResult, type Spinner, type StatusDiff, type StatusRelease, type StatusReviews, type StatusVitalMetric, type SubscriptionAnalytics, type SubscriptionDiff, type SyncResult, type ThresholdResult, type TrainConfig, type TrainState, type UploadResult, type ValidateCheck, type ValidateOptions, type ValidateResult, type VersionVitalsComparison, type VersionVitalsRow, type VitalsOverview, type VitalsQueryOptions, type VitalsTrendComparison, type WatchOptions, type WatchVitalsOptions, type WebhookPayload, abortTrain, acknowledgeProductPurchase, activateBasePlan, activateOffer, addRecoveryTargeting, addTesters, advanceTrain, analyzeBundle, analyzeRemoteListings, analyzeReviews, batchGetOrders, batchSyncInAppProducts, cancelRecoveryAction, cancelSubscriptionPurchase, cancelSubscriptionV2, checkBundleSize, checkThreshold, clearAuditLog, compareBundles, compareVersionVitals, compareVitalsTrend, computeStatusDiff, consumeProductPurchase, convertRegionPrices, createAuditEntry, createDeviceTier, createEnterpriseApp, createExternalTransaction, createGrant, createInAppProduct, createOffer, createOneTimeOffer, createOneTimeProduct, createRecoveryAction, createSpinner, createSubscription, createTrack, deactivateBasePlan, deactivateOffer, decodeNotification, defaultGitRunner, deferSubscriptionPurchase, deferSubscriptionV2, deleteBasePlan, deleteGrant, deleteImage, deleteInAppProduct, deleteListing, deleteOffer, deleteOneTimeOffer, deleteOneTimeProduct, deleteSubscription, deployRecoveryAction, detectFastlane, detectOutputFormat, diffListings, diffListingsCommand, diffListingsEnhanced, diffOneTimeProduct, diffReleases, diffSubscription, discoverPlugins, downloadGeneratedApk, downloadReport, exportImages, exportReviews, fetchChangelog, fetchReleaseNotes, formatChangelogEntry, formatCustomPayload, formatDiscordPayload, formatJunit, formatNotification, formatOutput, formatSlackPayload, formatStatusDiff, formatStatusSummary, formatStatusTable, formatWordDiff, generateChangelog, generateMigrationPlan, generateNotesFromGit, getAllScannerNames, getAppInfo, getAppStatus, getCountryAvailability, getDeviceTier, getExternalTransaction, getInAppProduct, getListings, getOffer, getOneTimeOffer, getOneTimeProduct, getOrderDetails, getProductPurchase, getProductPurchaseV2, getQuotaUsage, getReleasesStatus, getReview, getRtdnStatus, getSubscription, getSubscriptionAnalytics, getSubscriptionPurchase, getTrainStatus, getUser, getVitalsAnomalies, getVitalsAnr, getVitalsBattery, getVitalsCrashes, getVitalsErrorCount, getVitalsLmk, getVitalsMemory, getVitalsOverview, getVitalsRendering, getVitalsStartup, importDataSafety, importTestersFromCsv, initAudit, initProject, inviteUser, isFinancialReportType, isStatsReportType, isValidBcp47, isValidReportType, isValidStatsDimension, lintListing, lintListings, lintLocalListings, listAchievements, listAuditEvents, listDeviceTiers, listEvents, listGeneratedApks, listGrants, listImages, listInAppProducts, listLeaderboards, listOffers, listOneTimeOffers, listOneTimeProducts, listRecoveryActions, listReports, listReviews, listSubscriptions, listTesters, listTracks, listUsers, listVoidedPurchases, loadPreflightConfig, loadStatusCache, maybePaginate, migratePrices, parseAppfile, parseCommit, parseFastfile, parseGrantArg, parseMonth, parseRemoteUrl, pauseTrain, promoteRelease, publish, publishEnterpriseApp, pullListings, pushListings, readListingsFromDir, readReleaseNotesFromDir, redactAuditArgs, redactSensitive, refundExternalTransaction, refundOrder, relativeTime, removeTesters, removeUser, renderJson, renderMarkdown, renderPrompt, replyToReview, revokeSubscriptionPurchase, runPreflight, runWatchLoop, safePath, safePathWithin, saveStatusCache, scaffoldPlugin, searchAuditEvents, searchVitalsErrors, sendNotification, sendWebhook, sortResults, startTrain, statusHasBreach, syncInAppProducts, topFiles, trackBreachState, updateAppDetails, updateDataSafety, updateGrant, updateInAppProduct, updateListing, updateOffer, updateOneTimeOffer, updateOneTimeProduct, updateRollout, updateSubscription, updateTrackConfig, updateUser, uploadExternallyHosted, uploadImage, uploadInternalSharing, uploadRelease, validateImage, validateLanguageCode, validatePackageName, validatePreSubmission, validateReleaseNotes, validateSku, validateTrackName, validateUploadFile, validateVersionCode, watchVitalsWithAutoHalt, wordDiff, writeAuditLog, writeListingsToDir, writeMigrationOutput };
|
package/dist/index.js
CHANGED
|
@@ -3723,10 +3723,10 @@ ${bullets}`);
|
|
|
3723
3723
|
}
|
|
3724
3724
|
return { text, truncated };
|
|
3725
3725
|
}
|
|
3726
|
-
async function gitExec(args) {
|
|
3726
|
+
async function gitExec(args, opts) {
|
|
3727
3727
|
try {
|
|
3728
|
-
const {
|
|
3729
|
-
return stdout.trim();
|
|
3728
|
+
const result = opts?.cwd ? await execFile("git", args, { encoding: "utf8", cwd: opts.cwd }) : await execFile("git", args);
|
|
3729
|
+
return result.stdout.trim();
|
|
3730
3730
|
} catch (error) {
|
|
3731
3731
|
const err = error;
|
|
3732
3732
|
if (err.code === "ENOENT") {
|
|
@@ -7361,6 +7361,533 @@ function formatChangelogEntry(entry) {
|
|
|
7361
7361
|
return lines.join("\n");
|
|
7362
7362
|
}
|
|
7363
7363
|
|
|
7364
|
+
// src/commands/changelog-generate.ts
|
|
7365
|
+
var KNOWN_TYPES = /* @__PURE__ */ new Set([
|
|
7366
|
+
"feat",
|
|
7367
|
+
"fix",
|
|
7368
|
+
"perf",
|
|
7369
|
+
"breaking",
|
|
7370
|
+
"docs",
|
|
7371
|
+
"ci",
|
|
7372
|
+
"chore",
|
|
7373
|
+
"refactor",
|
|
7374
|
+
"test",
|
|
7375
|
+
"build",
|
|
7376
|
+
"style",
|
|
7377
|
+
"release"
|
|
7378
|
+
]);
|
|
7379
|
+
var FILTERED_TYPES = /* @__PURE__ */ new Set(["chore", "refactor", "test", "build", "style", "merge"]);
|
|
7380
|
+
var SECTION_ORDER = ["breaking", "feat", "fix", "perf", "docs", "ci", "release", "other"];
|
|
7381
|
+
var FIXUP_PATTERNS = [
|
|
7382
|
+
/^wip\b/i,
|
|
7383
|
+
/^fix\s+typo\b/i,
|
|
7384
|
+
/^fix\s+typos\b/i,
|
|
7385
|
+
/^address\s+review\b/i,
|
|
7386
|
+
/^review\s+fixes\b/i,
|
|
7387
|
+
/^fixup!/i,
|
|
7388
|
+
/^squash!/i
|
|
7389
|
+
];
|
|
7390
|
+
var REVERT_PATTERN = /^Revert\s+"(.+?)"\s*$/i;
|
|
7391
|
+
var VERB_CANONICALIZATIONS = [
|
|
7392
|
+
[/^Added\b/, "add"],
|
|
7393
|
+
[/^Adds\b/, "add"],
|
|
7394
|
+
[/^Add\b/, "add"],
|
|
7395
|
+
[/^Fixed\b/, "fix"],
|
|
7396
|
+
[/^Fixes\b/, "fix"],
|
|
7397
|
+
[/^Fix\b/, "fix"],
|
|
7398
|
+
[/^Updated\b/, "update"],
|
|
7399
|
+
[/^Updates\b/, "update"],
|
|
7400
|
+
[/^Update\b/, "update"],
|
|
7401
|
+
[/^Removed\b/, "remove"],
|
|
7402
|
+
[/^Removes\b/, "remove"],
|
|
7403
|
+
[/^Remove\b/, "remove"]
|
|
7404
|
+
];
|
|
7405
|
+
var EMOJI_PREFIX = /^(?:[\p{Emoji_Presentation}\p{Extended_Pictographic}]\s*)+/u;
|
|
7406
|
+
var INTERNAL_JARGON = [
|
|
7407
|
+
"mutex",
|
|
7408
|
+
"token bucket",
|
|
7409
|
+
"barrel export",
|
|
7410
|
+
"barrel exports",
|
|
7411
|
+
"homedir",
|
|
7412
|
+
"at module level",
|
|
7413
|
+
"ESM",
|
|
7414
|
+
"tsup",
|
|
7415
|
+
"vi.stubGlobal",
|
|
7416
|
+
"execFile",
|
|
7417
|
+
"lazy-import"
|
|
7418
|
+
];
|
|
7419
|
+
var RECORD_START = "";
|
|
7420
|
+
var FIELD_SEP = "";
|
|
7421
|
+
var COMMIT_FORMAT = `${RECORD_START}%H${FIELD_SEP}%s${FIELD_SEP}%aI${FIELD_SEP}%b`;
|
|
7422
|
+
function parseRawCommits(stdout) {
|
|
7423
|
+
if (!stdout.trim()) return [];
|
|
7424
|
+
const blocks = stdout.split(RECORD_START).filter((b) => b.trim());
|
|
7425
|
+
const commits = [];
|
|
7426
|
+
for (const block of blocks) {
|
|
7427
|
+
const headerEnd = block.indexOf("\n");
|
|
7428
|
+
const header = headerEnd === -1 ? block : block.slice(0, headerEnd);
|
|
7429
|
+
const rest = headerEnd === -1 ? "" : block.slice(headerEnd + 1);
|
|
7430
|
+
const parts = header.split(FIELD_SEP);
|
|
7431
|
+
const sha = parts[0]?.trim() ?? "";
|
|
7432
|
+
const subject = parts[1]?.trim() ?? "";
|
|
7433
|
+
const authorDate = parts[2]?.trim() ?? "";
|
|
7434
|
+
const body = (parts[3] ?? "").trim();
|
|
7435
|
+
if (!sha) continue;
|
|
7436
|
+
const files = [];
|
|
7437
|
+
let additions = 0;
|
|
7438
|
+
let deletions = 0;
|
|
7439
|
+
for (const line of rest.split("\n")) {
|
|
7440
|
+
const trimmed = line.trim();
|
|
7441
|
+
if (!trimmed) continue;
|
|
7442
|
+
const match = trimmed.match(/^(\d+|-)\s+(\d+|-)\s+(.+)$/);
|
|
7443
|
+
if (match) {
|
|
7444
|
+
const a = match[1] === "-" ? 0 : Number(match[1]);
|
|
7445
|
+
const d = match[2] === "-" ? 0 : Number(match[2]);
|
|
7446
|
+
additions += a;
|
|
7447
|
+
deletions += d;
|
|
7448
|
+
files.push(match[3] ?? "");
|
|
7449
|
+
}
|
|
7450
|
+
}
|
|
7451
|
+
commits.push({ sha, subject, body, files, additions, deletions, authorDate });
|
|
7452
|
+
}
|
|
7453
|
+
return commits;
|
|
7454
|
+
}
|
|
7455
|
+
var defaultGitRunner = {
|
|
7456
|
+
async log({ from, to, cwd }) {
|
|
7457
|
+
const stdout = await gitExec(
|
|
7458
|
+
[
|
|
7459
|
+
"log",
|
|
7460
|
+
"--no-merges",
|
|
7461
|
+
`--format=${COMMIT_FORMAT}`,
|
|
7462
|
+
"--numstat",
|
|
7463
|
+
"--end-of-options",
|
|
7464
|
+
`${from}..${to}`
|
|
7465
|
+
],
|
|
7466
|
+
{ cwd }
|
|
7467
|
+
);
|
|
7468
|
+
return parseRawCommits(stdout);
|
|
7469
|
+
},
|
|
7470
|
+
async describeLatestTag(cwd) {
|
|
7471
|
+
try {
|
|
7472
|
+
const out = await gitExec(["describe", "--tags", "--match", "v*", "--abbrev=0"], { cwd });
|
|
7473
|
+
return out.trim() || null;
|
|
7474
|
+
} catch {
|
|
7475
|
+
return null;
|
|
7476
|
+
}
|
|
7477
|
+
},
|
|
7478
|
+
async verifyRef(ref, cwd) {
|
|
7479
|
+
try {
|
|
7480
|
+
await gitExec(["rev-parse", "--verify", "--end-of-options", `${ref}^{commit}`], { cwd });
|
|
7481
|
+
return true;
|
|
7482
|
+
} catch {
|
|
7483
|
+
return false;
|
|
7484
|
+
}
|
|
7485
|
+
},
|
|
7486
|
+
async remoteUrl(cwd) {
|
|
7487
|
+
try {
|
|
7488
|
+
const out = await gitExec(["remote", "get-url", "origin"], { cwd });
|
|
7489
|
+
return out.trim() || null;
|
|
7490
|
+
} catch {
|
|
7491
|
+
return null;
|
|
7492
|
+
}
|
|
7493
|
+
}
|
|
7494
|
+
};
|
|
7495
|
+
function parseRemoteUrl(url) {
|
|
7496
|
+
if (!url) return null;
|
|
7497
|
+
const https = url.match(/^https?:\/\/github\.com\/([^/]+)\/([^/.]+?)(?:\.git)?\/?$/i);
|
|
7498
|
+
if (https) return `${https[1]}/${https[2]}`;
|
|
7499
|
+
const ssh = url.match(/^git@github\.com:([^/]+)\/([^/.]+?)(?:\.git)?$/i);
|
|
7500
|
+
if (ssh) return `${ssh[1]}/${ssh[2]}`;
|
|
7501
|
+
return null;
|
|
7502
|
+
}
|
|
7503
|
+
function stripEmojiAndCanonicalize(subject) {
|
|
7504
|
+
let s = subject.replace(EMOJI_PREFIX, "");
|
|
7505
|
+
for (const [pattern, replacement] of VERB_CANONICALIZATIONS) {
|
|
7506
|
+
if (pattern.test(s)) {
|
|
7507
|
+
s = s.replace(pattern, replacement);
|
|
7508
|
+
break;
|
|
7509
|
+
}
|
|
7510
|
+
}
|
|
7511
|
+
return s.trim();
|
|
7512
|
+
}
|
|
7513
|
+
function isFixupSubject(subject) {
|
|
7514
|
+
return FIXUP_PATTERNS.some((p) => p.test(subject));
|
|
7515
|
+
}
|
|
7516
|
+
var CONVENTIONAL_RE = /^(?<type>\w+)(?:\((?<scope>[^)]+)\))?(?<bang>!?):\s*(?<rest>.+)$/;
|
|
7517
|
+
var PR_REF_RE = /\s*\(#(\d+)\)\s*$/;
|
|
7518
|
+
function parseCommit(raw) {
|
|
7519
|
+
const subject = raw.subject;
|
|
7520
|
+
const revertMatch = subject.match(REVERT_PATTERN);
|
|
7521
|
+
const isRevert = !!revertMatch;
|
|
7522
|
+
const effectiveSubject = revertMatch?.[1] ?? subject;
|
|
7523
|
+
const match = effectiveSubject.match(CONVENTIONAL_RE);
|
|
7524
|
+
let type = "other";
|
|
7525
|
+
let scope;
|
|
7526
|
+
let rest = effectiveSubject;
|
|
7527
|
+
if (match?.groups) {
|
|
7528
|
+
const rawType = match.groups["type"]?.toLowerCase() ?? "other";
|
|
7529
|
+
type = KNOWN_TYPES.has(rawType) ? rawType : "other";
|
|
7530
|
+
scope = match.groups["scope"];
|
|
7531
|
+
rest = match.groups["rest"] ?? effectiveSubject;
|
|
7532
|
+
if (match.groups["bang"]) type = "breaking";
|
|
7533
|
+
}
|
|
7534
|
+
let prRef;
|
|
7535
|
+
const prMatch = rest.match(PR_REF_RE);
|
|
7536
|
+
if (prMatch) {
|
|
7537
|
+
prRef = `#${prMatch[1]}`;
|
|
7538
|
+
rest = rest.replace(PR_REF_RE, "").trim();
|
|
7539
|
+
}
|
|
7540
|
+
const cleaned = stripEmojiAndCanonicalize(rest);
|
|
7541
|
+
const finalSubject = prRef ? `${cleaned} (${prRef})` : cleaned;
|
|
7542
|
+
return {
|
|
7543
|
+
sha: raw.sha,
|
|
7544
|
+
type,
|
|
7545
|
+
scope,
|
|
7546
|
+
subject: finalSubject,
|
|
7547
|
+
prRef,
|
|
7548
|
+
files: raw.files,
|
|
7549
|
+
weight: raw.additions + raw.deletions,
|
|
7550
|
+
isRevert,
|
|
7551
|
+
isFixup: isFixupSubject(rest) || isFixupSubject(subject),
|
|
7552
|
+
authorDate: raw.authorDate
|
|
7553
|
+
};
|
|
7554
|
+
}
|
|
7555
|
+
function dedupRevertPairs(commits) {
|
|
7556
|
+
const reverted = /* @__PURE__ */ new Set();
|
|
7557
|
+
for (const c of commits) {
|
|
7558
|
+
if (c.isRevert) reverted.add(c.subject);
|
|
7559
|
+
}
|
|
7560
|
+
return commits.filter((c) => {
|
|
7561
|
+
if (c.isRevert) return false;
|
|
7562
|
+
if (reverted.has(c.subject)) return false;
|
|
7563
|
+
return true;
|
|
7564
|
+
});
|
|
7565
|
+
}
|
|
7566
|
+
function topPathPrefix(file, depth = 2) {
|
|
7567
|
+
return file.split("/").slice(0, depth).join("/");
|
|
7568
|
+
}
|
|
7569
|
+
function tokenize2(subject) {
|
|
7570
|
+
const STOP = /* @__PURE__ */ new Set([
|
|
7571
|
+
"the",
|
|
7572
|
+
"a",
|
|
7573
|
+
"an",
|
|
7574
|
+
"and",
|
|
7575
|
+
"or",
|
|
7576
|
+
"of",
|
|
7577
|
+
"to",
|
|
7578
|
+
"in",
|
|
7579
|
+
"on",
|
|
7580
|
+
"for",
|
|
7581
|
+
"with",
|
|
7582
|
+
"is",
|
|
7583
|
+
"be",
|
|
7584
|
+
"by",
|
|
7585
|
+
"at"
|
|
7586
|
+
]);
|
|
7587
|
+
return new Set(
|
|
7588
|
+
subject.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((w) => w.length > 2 && !STOP.has(w))
|
|
7589
|
+
);
|
|
7590
|
+
}
|
|
7591
|
+
function jaccard(a, b) {
|
|
7592
|
+
if (a.size === 0 && b.size === 0) return 0;
|
|
7593
|
+
let inter = 0;
|
|
7594
|
+
for (const t of a) if (b.has(t)) inter++;
|
|
7595
|
+
const union = a.size + b.size - inter;
|
|
7596
|
+
return union === 0 ? 0 : inter / union;
|
|
7597
|
+
}
|
|
7598
|
+
function shouldCluster(a, b, ta, tb) {
|
|
7599
|
+
const aPrefixes = new Set(a.files.map((f) => topPathPrefix(f)));
|
|
7600
|
+
for (const f of b.files) {
|
|
7601
|
+
if (aPrefixes.has(topPathPrefix(f))) return true;
|
|
7602
|
+
}
|
|
7603
|
+
if (jaccard(ta, tb) > 0.4) return true;
|
|
7604
|
+
const aDate = Date.parse(a.authorDate);
|
|
7605
|
+
const bDate = Date.parse(b.authorDate);
|
|
7606
|
+
if (!Number.isNaN(aDate) && !Number.isNaN(bDate)) {
|
|
7607
|
+
const dayDiff = Math.abs(aDate - bDate) / 864e5;
|
|
7608
|
+
if (dayDiff <= 2) {
|
|
7609
|
+
const aFiles = new Set(a.files);
|
|
7610
|
+
for (const f of b.files) if (aFiles.has(f)) return true;
|
|
7611
|
+
}
|
|
7612
|
+
}
|
|
7613
|
+
return false;
|
|
7614
|
+
}
|
|
7615
|
+
var TYPE_PRIORITY = {
|
|
7616
|
+
breaking: 0,
|
|
7617
|
+
feat: 1,
|
|
7618
|
+
fix: 2,
|
|
7619
|
+
perf: 3,
|
|
7620
|
+
docs: 4,
|
|
7621
|
+
ci: 5,
|
|
7622
|
+
release: 6,
|
|
7623
|
+
other: 7
|
|
7624
|
+
};
|
|
7625
|
+
function clusterCommits(commits) {
|
|
7626
|
+
const n = commits.length;
|
|
7627
|
+
const parent = Array.from({ length: n }, (_, i) => i);
|
|
7628
|
+
const find = (i) => {
|
|
7629
|
+
while (parent[i] !== i) {
|
|
7630
|
+
parent[i] = parent[parent[i]];
|
|
7631
|
+
i = parent[i];
|
|
7632
|
+
}
|
|
7633
|
+
return i;
|
|
7634
|
+
};
|
|
7635
|
+
const union = (i, j) => {
|
|
7636
|
+
const ri = find(i);
|
|
7637
|
+
const rj = find(j);
|
|
7638
|
+
if (ri !== rj) parent[ri] = rj;
|
|
7639
|
+
};
|
|
7640
|
+
const tokens = commits.map((c) => tokenize2(c.subject));
|
|
7641
|
+
for (let i = 0; i < n; i++) {
|
|
7642
|
+
for (let j = i + 1; j < n; j++) {
|
|
7643
|
+
if (shouldCluster(commits[i], commits[j], tokens[i], tokens[j])) union(i, j);
|
|
7644
|
+
}
|
|
7645
|
+
}
|
|
7646
|
+
const groups = /* @__PURE__ */ new Map();
|
|
7647
|
+
for (let i = 0; i < n; i++) {
|
|
7648
|
+
const root = find(i);
|
|
7649
|
+
if (!groups.has(root)) groups.set(root, []);
|
|
7650
|
+
groups.get(root).push(commits[i]);
|
|
7651
|
+
}
|
|
7652
|
+
const clusters = [];
|
|
7653
|
+
for (const [, members] of groups) {
|
|
7654
|
+
const weight = members.reduce((s, m) => s + m.weight, 0);
|
|
7655
|
+
const primaryType = members.map((m) => m.type).sort((a, b) => (TYPE_PRIORITY[a] ?? 99) - (TYPE_PRIORITY[b] ?? 99))[0];
|
|
7656
|
+
const label = clusterLabel(members);
|
|
7657
|
+
clusters.push({
|
|
7658
|
+
id: label.toLowerCase().replace(/\s+/g, "-"),
|
|
7659
|
+
label,
|
|
7660
|
+
commits: members,
|
|
7661
|
+
weight,
|
|
7662
|
+
primaryType
|
|
7663
|
+
});
|
|
7664
|
+
}
|
|
7665
|
+
return clusters;
|
|
7666
|
+
}
|
|
7667
|
+
function clusterLabel(members) {
|
|
7668
|
+
const pathCounts = /* @__PURE__ */ new Map();
|
|
7669
|
+
for (const m of members) {
|
|
7670
|
+
for (const f of m.files) {
|
|
7671
|
+
const top = topPathPrefix(f, 2);
|
|
7672
|
+
pathCounts.set(top, (pathCounts.get(top) ?? 0) + 1);
|
|
7673
|
+
}
|
|
7674
|
+
}
|
|
7675
|
+
let bestPath = null;
|
|
7676
|
+
let bestPathCount = 0;
|
|
7677
|
+
for (const [p, c] of pathCounts) {
|
|
7678
|
+
if (c > bestPathCount) {
|
|
7679
|
+
bestPath = p;
|
|
7680
|
+
bestPathCount = c;
|
|
7681
|
+
}
|
|
7682
|
+
}
|
|
7683
|
+
if (bestPath) return bestPath;
|
|
7684
|
+
const tokenCounts = /* @__PURE__ */ new Map();
|
|
7685
|
+
for (const m of members) {
|
|
7686
|
+
for (const t of tokenize2(m.subject)) {
|
|
7687
|
+
tokenCounts.set(t, (tokenCounts.get(t) ?? 0) + 1);
|
|
7688
|
+
}
|
|
7689
|
+
}
|
|
7690
|
+
let bestToken = null;
|
|
7691
|
+
let bestTokenCount = 0;
|
|
7692
|
+
for (const [t, c] of tokenCounts) {
|
|
7693
|
+
if (c > bestTokenCount) {
|
|
7694
|
+
bestToken = t;
|
|
7695
|
+
bestTokenCount = c;
|
|
7696
|
+
}
|
|
7697
|
+
}
|
|
7698
|
+
return bestToken ?? members[0].subject.slice(0, 30);
|
|
7699
|
+
}
|
|
7700
|
+
function scoreHeadlines(clusters) {
|
|
7701
|
+
return [...clusters].sort((a, b) => {
|
|
7702
|
+
if (b.weight !== a.weight) return b.weight - a.weight;
|
|
7703
|
+
return (TYPE_PRIORITY[a.primaryType] ?? 99) - (TYPE_PRIORITY[b.primaryType] ?? 99);
|
|
7704
|
+
}).slice(0, 3);
|
|
7705
|
+
}
|
|
7706
|
+
function lintJargon(commits) {
|
|
7707
|
+
const warnings = [];
|
|
7708
|
+
for (const c of commits) {
|
|
7709
|
+
const lower = c.subject.toLowerCase();
|
|
7710
|
+
for (const word of INTERNAL_JARGON) {
|
|
7711
|
+
if (lower.includes(word.toLowerCase())) {
|
|
7712
|
+
warnings.push(`jargon: "${word}" in subject "${c.subject}" (${c.sha.slice(0, 7)})`);
|
|
7713
|
+
}
|
|
7714
|
+
}
|
|
7715
|
+
}
|
|
7716
|
+
return warnings;
|
|
7717
|
+
}
|
|
7718
|
+
async function generateChangelog(opts = {}, runner = defaultGitRunner) {
|
|
7719
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
7720
|
+
let from = opts.from;
|
|
7721
|
+
if (!from) {
|
|
7722
|
+
from = await runner.describeLatestTag(cwd) ?? void 0;
|
|
7723
|
+
if (!from) {
|
|
7724
|
+
throw new GpcError(
|
|
7725
|
+
"No git tags found and --from was not provided",
|
|
7726
|
+
"CHANGELOG_NO_TAG",
|
|
7727
|
+
1,
|
|
7728
|
+
"Pass --from <ref> explicitly, or create an initial tag (e.g., git tag v0.0.1)."
|
|
7729
|
+
);
|
|
7730
|
+
}
|
|
7731
|
+
}
|
|
7732
|
+
const to = opts.to ?? "HEAD";
|
|
7733
|
+
if (!await runner.verifyRef(from, cwd)) {
|
|
7734
|
+
throw new GpcError(
|
|
7735
|
+
`Invalid --from ref: "${from}"`,
|
|
7736
|
+
"CHANGELOG_BAD_REF",
|
|
7737
|
+
1,
|
|
7738
|
+
"Verify the ref exists with: git rev-parse --verify <ref>"
|
|
7739
|
+
);
|
|
7740
|
+
}
|
|
7741
|
+
if (!await runner.verifyRef(to, cwd)) {
|
|
7742
|
+
throw new GpcError(
|
|
7743
|
+
`Invalid --to ref: "${to}"`,
|
|
7744
|
+
"CHANGELOG_BAD_REF",
|
|
7745
|
+
1,
|
|
7746
|
+
"Verify the ref exists with: git rev-parse --verify <ref>"
|
|
7747
|
+
);
|
|
7748
|
+
}
|
|
7749
|
+
const repo = opts.repo ?? parseRemoteUrl(await runner.remoteUrl(cwd));
|
|
7750
|
+
const raw = await runner.log({ from, to, cwd });
|
|
7751
|
+
const rawCommitCount = raw.length;
|
|
7752
|
+
const parsed = raw.map(parseCommit);
|
|
7753
|
+
const warnings = [];
|
|
7754
|
+
const scopeLeak = parsed.find((c) => c.scope);
|
|
7755
|
+
if (scopeLeak) {
|
|
7756
|
+
warnings.push(
|
|
7757
|
+
`scope: dropped per project convention (e.g., "${scopeLeak.scope}" in ${scopeLeak.sha.slice(0, 7)})`
|
|
7758
|
+
);
|
|
7759
|
+
}
|
|
7760
|
+
const afterRevert = dedupRevertPairs(parsed);
|
|
7761
|
+
const nonFixup = afterRevert.filter((c) => !c.isFixup);
|
|
7762
|
+
const visible = nonFixup.filter((c) => !FILTERED_TYPES.has(c.type));
|
|
7763
|
+
const clusters = clusterCommits(visible);
|
|
7764
|
+
const headlineCandidates = scoreHeadlines(clusters);
|
|
7765
|
+
const grouped = {};
|
|
7766
|
+
for (const c of visible) {
|
|
7767
|
+
if (!grouped[c.type]) grouped[c.type] = [];
|
|
7768
|
+
grouped[c.type].push(c);
|
|
7769
|
+
}
|
|
7770
|
+
warnings.push(...lintJargon(visible));
|
|
7771
|
+
return {
|
|
7772
|
+
from,
|
|
7773
|
+
to,
|
|
7774
|
+
repo,
|
|
7775
|
+
rawCommitCount,
|
|
7776
|
+
commits: parsed,
|
|
7777
|
+
clusters,
|
|
7778
|
+
grouped,
|
|
7779
|
+
headlineCandidates,
|
|
7780
|
+
warnings
|
|
7781
|
+
};
|
|
7782
|
+
}
|
|
7783
|
+
|
|
7784
|
+
// src/commands/changelog-renderers/markdown.ts
|
|
7785
|
+
function safeSubject(s) {
|
|
7786
|
+
return s.replace(/[\r\n]+/g, " ").trim();
|
|
7787
|
+
}
|
|
7788
|
+
function renderMarkdown(g) {
|
|
7789
|
+
if (g.commits.length === 0) {
|
|
7790
|
+
const compare2 = g.repo ? `
|
|
7791
|
+
**Full Changelog**: https://github.com/${g.repo}/compare/${g.from}...${g.to}` : "";
|
|
7792
|
+
return `## What's Changed
|
|
7793
|
+
|
|
7794
|
+
_No notable changes._
|
|
7795
|
+
${compare2}`.trim();
|
|
7796
|
+
}
|
|
7797
|
+
const lines = ["## What's Changed", ""];
|
|
7798
|
+
let emittedAny = false;
|
|
7799
|
+
for (const type of SECTION_ORDER) {
|
|
7800
|
+
const commits = g.grouped[type] ?? [];
|
|
7801
|
+
if (commits.length === 0) continue;
|
|
7802
|
+
for (const commit of commits) {
|
|
7803
|
+
lines.push(`- ${type}: ${safeSubject(commit.subject)}`);
|
|
7804
|
+
emittedAny = true;
|
|
7805
|
+
}
|
|
7806
|
+
}
|
|
7807
|
+
if (!emittedAny) {
|
|
7808
|
+
lines.push("_No notable changes._");
|
|
7809
|
+
}
|
|
7810
|
+
if (g.repo) {
|
|
7811
|
+
lines.push("");
|
|
7812
|
+
lines.push(`**Full Changelog**: https://github.com/${g.repo}/compare/${g.from}...${g.to}`);
|
|
7813
|
+
}
|
|
7814
|
+
return lines.join("\n");
|
|
7815
|
+
}
|
|
7816
|
+
|
|
7817
|
+
// src/commands/changelog-renderers/json.ts
|
|
7818
|
+
function renderJson(g) {
|
|
7819
|
+
return JSON.stringify(g, null, 2);
|
|
7820
|
+
}
|
|
7821
|
+
|
|
7822
|
+
// src/commands/changelog-renderers/prompt.ts
|
|
7823
|
+
function safeLine(s) {
|
|
7824
|
+
return s.replace(/[\r\n]+/g, " ").trim();
|
|
7825
|
+
}
|
|
7826
|
+
function renderPrompt(g) {
|
|
7827
|
+
const lines = [];
|
|
7828
|
+
lines.push("You are writing a draft of GitHub Release notes from clustered git commits.");
|
|
7829
|
+
lines.push("");
|
|
7830
|
+
lines.push("VOICE RULES (from project conventions):");
|
|
7831
|
+
lines.push("- Terse, present tense, user-facing language");
|
|
7832
|
+
lines.push('- No internal jargon (no "mutex", "token bucket", "barrel exports", "homedir")');
|
|
7833
|
+
lines.push("- One bullet per feature/fix, not one per commit");
|
|
7834
|
+
lines.push("- Drop conventional-commit scopes (e.g., feat(cli) \u2192 feat:)");
|
|
7835
|
+
lines.push("- Open with a single-sentence highlight describing the release theme");
|
|
7836
|
+
lines.push("");
|
|
7837
|
+
lines.push(`RANGE: ${g.from}..${g.to}`);
|
|
7838
|
+
if (g.repo) lines.push(`REPO: ${g.repo}`);
|
|
7839
|
+
lines.push(`COMMITS: ${g.rawCommitCount} raw, ${g.clusters.length} clusters after dedup`);
|
|
7840
|
+
lines.push("");
|
|
7841
|
+
if (g.headlineCandidates.length > 0) {
|
|
7842
|
+
lines.push("HEADLINE CANDIDATES (largest first):");
|
|
7843
|
+
for (const c of g.headlineCandidates) {
|
|
7844
|
+
lines.push(` ${c.label} (weight ${c.weight}, ${c.commits.length} commits, primary ${c.primaryType})`);
|
|
7845
|
+
}
|
|
7846
|
+
lines.push("");
|
|
7847
|
+
}
|
|
7848
|
+
lines.push("CLUSTERED COMMITS:");
|
|
7849
|
+
lines.push("");
|
|
7850
|
+
for (const cluster of g.clusters) {
|
|
7851
|
+
lines.push(`[cluster: ${cluster.label}, weight ${cluster.weight}, ${cluster.commits.length} commits, primary ${cluster.primaryType}]`);
|
|
7852
|
+
for (const commit of cluster.commits) {
|
|
7853
|
+
lines.push(`- ${commit.type}: ${safeLine(commit.subject)} (${commit.sha.slice(0, 7)})`);
|
|
7854
|
+
if (commit.files.length > 0) {
|
|
7855
|
+
const fileSummary = commit.files.slice(0, 3).join(", ");
|
|
7856
|
+
const more = commit.files.length > 3 ? ` (+${commit.files.length - 3} more)` : "";
|
|
7857
|
+
lines.push(` files: ${fileSummary}${more}`);
|
|
7858
|
+
}
|
|
7859
|
+
}
|
|
7860
|
+
lines.push("");
|
|
7861
|
+
}
|
|
7862
|
+
if (g.warnings.length > 0) {
|
|
7863
|
+
lines.push("LINTER WARNINGS (review before publishing):");
|
|
7864
|
+
for (const w of g.warnings) lines.push(` - ${w}`);
|
|
7865
|
+
lines.push("");
|
|
7866
|
+
}
|
|
7867
|
+
const compare2 = g.repo ? `https://github.com/${g.repo}/compare/${g.from}...${g.to}` : `${g.from}..${g.to}`;
|
|
7868
|
+
lines.push("OUTPUT FORMAT (match exactly):");
|
|
7869
|
+
lines.push("```markdown");
|
|
7870
|
+
lines.push("<one-sentence highlight>");
|
|
7871
|
+
lines.push("");
|
|
7872
|
+
lines.push("## What's Changed");
|
|
7873
|
+
lines.push("");
|
|
7874
|
+
lines.push("- breaking: ...");
|
|
7875
|
+
lines.push("- feat: ...");
|
|
7876
|
+
lines.push("- fix: ...");
|
|
7877
|
+
lines.push("- perf: ...");
|
|
7878
|
+
lines.push("");
|
|
7879
|
+
lines.push(`**Full Changelog**: ${compare2}`);
|
|
7880
|
+
lines.push("```");
|
|
7881
|
+
return lines.join("\n");
|
|
7882
|
+
}
|
|
7883
|
+
|
|
7884
|
+
// src/commands/changelog-renderers/index.ts
|
|
7885
|
+
var RENDERERS = {
|
|
7886
|
+
md: renderMarkdown,
|
|
7887
|
+
json: renderJson,
|
|
7888
|
+
prompt: renderPrompt
|
|
7889
|
+
};
|
|
7890
|
+
|
|
7364
7891
|
// src/commands/rtdn.ts
|
|
7365
7892
|
var SUBSCRIPTION_NOTIFICATION_TYPES = {
|
|
7366
7893
|
1: "SUBSCRIPTION_RECOVERED",
|
|
@@ -7463,6 +7990,8 @@ export {
|
|
|
7463
7990
|
NetworkError,
|
|
7464
7991
|
PERMISSION_PROPAGATION_WARNING,
|
|
7465
7992
|
PluginManager,
|
|
7993
|
+
RENDERERS,
|
|
7994
|
+
SECTION_ORDER,
|
|
7466
7995
|
SENSITIVE_ARG_KEYS,
|
|
7467
7996
|
SENSITIVE_KEYS,
|
|
7468
7997
|
SEVERITY_ORDER,
|
|
@@ -7506,6 +8035,7 @@ export {
|
|
|
7506
8035
|
deactivateBasePlan,
|
|
7507
8036
|
deactivateOffer,
|
|
7508
8037
|
decodeNotification,
|
|
8038
|
+
defaultGitRunner,
|
|
7509
8039
|
deferSubscriptionPurchase,
|
|
7510
8040
|
deferSubscriptionV2,
|
|
7511
8041
|
deleteBasePlan,
|
|
@@ -7544,6 +8074,7 @@ export {
|
|
|
7544
8074
|
formatStatusSummary,
|
|
7545
8075
|
formatStatusTable,
|
|
7546
8076
|
formatWordDiff,
|
|
8077
|
+
generateChangelog,
|
|
7547
8078
|
generateMigrationPlan,
|
|
7548
8079
|
generateNotesFromGit,
|
|
7549
8080
|
getAllScannerNames,
|
|
@@ -7617,9 +8148,11 @@ export {
|
|
|
7617
8148
|
maybePaginate,
|
|
7618
8149
|
migratePrices,
|
|
7619
8150
|
parseAppfile,
|
|
8151
|
+
parseCommit,
|
|
7620
8152
|
parseFastfile,
|
|
7621
8153
|
parseGrantArg,
|
|
7622
8154
|
parseMonth,
|
|
8155
|
+
parseRemoteUrl,
|
|
7623
8156
|
pauseTrain,
|
|
7624
8157
|
promoteRelease,
|
|
7625
8158
|
publish,
|
|
@@ -7635,6 +8168,9 @@ export {
|
|
|
7635
8168
|
relativeTime,
|
|
7636
8169
|
removeTesters,
|
|
7637
8170
|
removeUser,
|
|
8171
|
+
renderJson,
|
|
8172
|
+
renderMarkdown,
|
|
8173
|
+
renderPrompt,
|
|
7638
8174
|
replyToReview,
|
|
7639
8175
|
revokeSubscriptionPurchase,
|
|
7640
8176
|
runPreflight,
|