relizy 1.3.3 → 1.4.0-beta.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/cli.mjs CHANGED
@@ -5,7 +5,7 @@ import process from 'node:process';
5
5
  import { fileURLToPath } from 'node:url';
6
6
  import { printBanner, logger } from '@maz-ui/node';
7
7
  import { Command } from 'commander';
8
- import { am as isInCI, an as getCIName, b as bump, c as changelog, g as publish, e as providerRelease, h as social, p as prComment, r as release } from './shared/relizy.BRFiG2GH.mjs';
8
+ import { ao as isInCI, ap as getCIName, b as bump, c as changelog, g as publish, e as providerRelease, h as social, p as prComment, r as release } from './shared/relizy.CxbwJj6k.mjs';
9
9
  import 'node:child_process';
10
10
  import '@maz-ui/utils';
11
11
  import 'c12';
package/dist/index.d.mts CHANGED
@@ -60,6 +60,8 @@ declare function getDefaultConfig(): {
60
60
  slack: {
61
61
  enabled: boolean;
62
62
  onlyStable: boolean;
63
+ postMaxLength: number;
64
+ noAuthors: boolean;
63
65
  };
64
66
  };
65
67
  prComment: Required<PrCommentConfig>;
@@ -233,6 +235,16 @@ declare function buildChangelogBody({ commits, config, minify }: {
233
235
  config: ResolvedRelizyConfig;
234
236
  minify?: boolean;
235
237
  }): string;
238
+ /**
239
+ * Collect unique contributor names from a set of commits.
240
+ * Respects `config.noAuthors`, filters `[bot]` authors, and applies `config.excludeAuthors`.
241
+ * Returns plain formatted names (no emails, no GitHub handles) — useful for lightweight
242
+ * rendering contexts like Slack messages.
243
+ */
244
+ declare function collectContributorNames({ commits, config }: {
245
+ commits: GitCommit[];
246
+ config: ResolvedRelizyConfig;
247
+ }): string[];
236
248
  declare function buildContributors({ commits, config }: {
237
249
  commits: GitCommit[];
238
250
  config: ResolvedRelizyConfig;
@@ -347,6 +359,13 @@ declare function getSlackToken(options: {
347
359
  socialCredentials?: SlackCredentials;
348
360
  tokenCredential?: string;
349
361
  }): string | null;
362
+ /**
363
+ * Get Slack Incoming Webhook URL from config or environment variables.
364
+ * Priority: social.slack.webhookUrl > RELIZY_SLACK_WEBHOOK_URL > SLACK_WEBHOOK_URL.
365
+ */
366
+ declare function getSlackWebhookUrl(options: {
367
+ socialWebhookUrl?: string;
368
+ }): string | null;
350
369
  /**
351
370
  * Format changelog for Slack (convert markdown to Slack's mrkdwn format)
352
371
  */
@@ -354,18 +373,25 @@ declare function formatChangelogForSlack(changelog: string, maxLength?: number):
354
373
  /**
355
374
  * Format the Slack message using blocks
356
375
  */
357
- declare function formatSlackMessage({ projectName, version, changelog, releaseUrl, changelogUrl, template }: {
376
+ declare function formatSlackMessage({ projectName, version, changelog, releaseUrl, changelogUrl, template, contributors, postMaxLength }: {
358
377
  template?: string;
359
378
  projectName: string;
360
379
  version: string;
361
380
  changelog: string;
362
381
  releaseUrl?: string;
363
382
  changelogUrl?: string;
383
+ contributors?: string[];
384
+ postMaxLength?: number;
364
385
  }): any[];
365
386
  /**
366
- * Post a release announcement to Slack
387
+ * Post a release announcement to Slack.
388
+ * Dispatches to Incoming Webhook (if `webhookUrl` is set) or Web API (`token` + `channel`).
389
+ * When both are provided, the webhook takes priority.
367
390
  */
368
- declare function postReleaseToSlack({ version, projectName, changelog, releaseUrl, changelogUrl, channel, token, template, dryRun, }: SlackOptions): Promise<_slack_web_api.ChatPostMessageResponse | undefined>;
391
+ declare function postReleaseToSlack({ version, projectName, changelog, releaseUrl, changelogUrl, channel, token, webhookUrl, template, contributors, postMaxLength, dryRun, }: SlackOptions): Promise<{
392
+ ok: true;
393
+ transport: "webhook";
394
+ } | _slack_web_api.ChatPostMessageResponse | undefined>;
369
395
 
370
396
  /**
371
397
  * Extract a summary from changelog content
@@ -1269,8 +1295,10 @@ interface TwitterSocialConfig {
1269
1295
  }
1270
1296
  interface SlackCredentials {
1271
1297
  /**
1272
- * Slack Bot Token or User OAuth Token
1273
- * Required scopes: chat:write, chat:write.public (for public channels)
1298
+ * Slack Bot Token or User OAuth Token (starts with `xoxb-`).
1299
+ * Required scopes: chat:write (and chat:write.public for public channels without bot invite).
1300
+ * Env fallback: SLACK_TOKEN, RELIZY_SLACK_TOKEN.
1301
+ * Ignored when social.slack.webhookUrl is set (webhook takes priority).
1274
1302
  */
1275
1303
  token?: string;
1276
1304
  }
@@ -1287,18 +1315,38 @@ interface SlackSocialConfig {
1287
1315
  */
1288
1316
  onlyStable?: boolean;
1289
1317
  /**
1290
- * Slack channel ID or name (e.g., "#releases" or "C1234567890")
1318
+ * Slack channel ID or name (e.g., "#releases" or "C1234567890").
1319
+ * Required when using token-based authentication.
1320
+ * Ignored (with warning) when webhookUrl is set — the channel is baked into the webhook URL.
1291
1321
  */
1292
- channel: string;
1322
+ channel?: string;
1323
+ /**
1324
+ * Slack Incoming Webhook URL. When set, takes priority over token-based auth.
1325
+ * Env fallback: SLACK_WEBHOOK_URL, RELIZY_SLACK_WEBHOOK_URL.
1326
+ * See: https://api.slack.com/messaging/webhooks
1327
+ */
1328
+ webhookUrl?: string;
1293
1329
  /**
1294
1330
  * Custom message template
1295
- * Available variables: {{projectName}}, {{newVersion}}, {{changelog}}, {{releaseUrl}}, {{changelogUrl}}
1331
+ * Available variables: {{projectName}}, {{newVersion}}, {{changelog}}, {{releaseUrl}}, {{changelogUrl}}, {{contributors}}
1296
1332
  */
1297
1333
  template?: string;
1298
1334
  /**
1299
1335
  * Slack credentials (optional - falls back to environment variables)
1300
1336
  */
1301
1337
  credentials?: SlackCredentials;
1338
+ /**
1339
+ * Maximum length (in characters) of the changelog rendered inside the Slack message.
1340
+ * Slack's per-section-block limit is 3000; default 2500 leaves margin for emoji/formatting.
1341
+ * @default 2500
1342
+ */
1343
+ postMaxLength?: number;
1344
+ /**
1345
+ * Hide the contributors block in Slack messages.
1346
+ * If config.noAuthors is true globally, contributors are always hidden regardless of this setting.
1347
+ * @default false
1348
+ */
1349
+ noAuthors?: boolean;
1302
1350
  }
1303
1351
  type AIProviderName = 'claude-code';
1304
1352
  interface ClaudeCodeProviderOptions {
@@ -1462,17 +1510,30 @@ interface SlackOptions {
1462
1510
  */
1463
1511
  changelogUrl?: string;
1464
1512
  /**
1465
- * Slack channel ID or name
1513
+ * Slack channel ID or name. Required when using token-based auth.
1466
1514
  */
1467
- channel: string;
1515
+ channel?: string;
1468
1516
  /**
1469
- * Slack token (required)
1517
+ * Slack Bot Token. Ignored if webhookUrl is set.
1470
1518
  */
1471
- token: string;
1519
+ token?: string;
1520
+ /**
1521
+ * Slack Incoming Webhook URL. Takes priority over token.
1522
+ */
1523
+ webhookUrl?: string;
1472
1524
  /**
1473
1525
  * Custom message template
1474
1526
  */
1475
1527
  template?: string;
1528
+ /**
1529
+ * Maximum chars of the changelog rendered in the message.
1530
+ * @default 2500
1531
+ */
1532
+ postMaxLength?: number;
1533
+ /**
1534
+ * Contributor names (plain strings, no email/handle). Empty array or undefined → no contributors block.
1535
+ */
1536
+ contributors?: string[];
1476
1537
  /**
1477
1538
  * Run without side effects
1478
1539
  * @default false
@@ -1754,5 +1815,5 @@ declare function socialSafetyCheck({ config }: {
1754
1815
  }): Promise<void>;
1755
1816
  declare function social(options?: Partial<SocialOptions>): Promise<SocialResult>;
1756
1817
 
1757
- export { NEW_PACKAGE_MARKER, PR_COMMENT_MARKER, buildChangelogBody, buildCommentBody, buildCompareLink, buildContributors, bump, capReleaseTypeForZeroMajor, changelog, checkGitStatusIfDirty, confirmBump, createCommitAndTags, createGitlabRelease, defineConfig, detectGitProvider, detectPackageManager, detectPullRequest, determinePublishTag, determineReleaseType, determineSemverChange, executeBuildCmd, executeFormatCmd, executeHook, expandPackagesToBumpWithDependents, extractChangelogSummary, extractVersionFromPackageTag, extractVersionFromTag, fetchGitTags, filterOutPrivatePackages, findGitHubPR, findGitLabMR, formatChangelogForSlack, formatSlackMessage, formatTweetMessage, generateChangelog, generateMarkDown, getAuthCommand, getBumpedIndependentPackages, getBumpedPackageIndependently, getCIName, getCanaryVersion, getCurrentGitBranch, getCurrentGitRef, getDefaultConfig, getDependentsOf, getFirstCommit, getGitStatus, getIndependentTag, getLastPackageTag, getLastRepoTag, getLastStableTag, getLastTag, getModifiedReleaseFilePatterns, getPackageCommits, getPackageDependencies, getPackageNewVersion, getPackages, getPackagesOrBumpedPackages, getPackagesToPublishInIndependentMode, getPackagesToPublishInSelectiveMode, getPreid, getReleaseUrl, getRootPackage, getShortCommitSha, getSlackToken, getTwitterCredentials, github, gitlab, hasLernaJson, isBumpedPackage, isChangedPreid, isGraduating, isGraduatingToStableBetweenVersion, isInCI, isPrerelease, isPrereleaseReleaseType, isStableReleaseType, isTagVersionCompatibleWithCurrent, loadRelizyConfig, mergeTypes, parseChangelogMarkdown, parseGitRemoteUrl, postPrComment, postReleaseToSlack, postReleaseToTwitter, prComment, providerRelease, providerReleaseSafetyCheck, publish, publishPackage, publishSafetyCheck, pushCommitAndTags, readPackageJson, readPackages, release, resolveTags, rollbackModifiedFiles, shouldFilterPrereleaseTags, social, socialSafetyCheck, topologicalSort, updateLernaVersion, writeChangelogToFile, writeVersion };
1818
+ export { NEW_PACKAGE_MARKER, PR_COMMENT_MARKER, buildChangelogBody, buildCommentBody, buildCompareLink, buildContributors, bump, capReleaseTypeForZeroMajor, changelog, checkGitStatusIfDirty, collectContributorNames, confirmBump, createCommitAndTags, createGitlabRelease, defineConfig, detectGitProvider, detectPackageManager, detectPullRequest, determinePublishTag, determineReleaseType, determineSemverChange, executeBuildCmd, executeFormatCmd, executeHook, expandPackagesToBumpWithDependents, extractChangelogSummary, extractVersionFromPackageTag, extractVersionFromTag, fetchGitTags, filterOutPrivatePackages, findGitHubPR, findGitLabMR, formatChangelogForSlack, formatSlackMessage, formatTweetMessage, generateChangelog, generateMarkDown, getAuthCommand, getBumpedIndependentPackages, getBumpedPackageIndependently, getCIName, getCanaryVersion, getCurrentGitBranch, getCurrentGitRef, getDefaultConfig, getDependentsOf, getFirstCommit, getGitStatus, getIndependentTag, getLastPackageTag, getLastRepoTag, getLastStableTag, getLastTag, getModifiedReleaseFilePatterns, getPackageCommits, getPackageDependencies, getPackageNewVersion, getPackages, getPackagesOrBumpedPackages, getPackagesToPublishInIndependentMode, getPackagesToPublishInSelectiveMode, getPreid, getReleaseUrl, getRootPackage, getShortCommitSha, getSlackToken, getSlackWebhookUrl, getTwitterCredentials, github, gitlab, hasLernaJson, isBumpedPackage, isChangedPreid, isGraduating, isGraduatingToStableBetweenVersion, isInCI, isPrerelease, isPrereleaseReleaseType, isStableReleaseType, isTagVersionCompatibleWithCurrent, loadRelizyConfig, mergeTypes, parseChangelogMarkdown, parseGitRemoteUrl, postPrComment, postReleaseToSlack, postReleaseToTwitter, prComment, providerRelease, providerReleaseSafetyCheck, publish, publishPackage, publishSafetyCheck, pushCommitAndTags, readPackageJson, readPackages, release, resolveTags, rollbackModifiedFiles, shouldFilterPrereleaseTags, social, socialSafetyCheck, topologicalSort, updateLernaVersion, writeChangelogToFile, writeVersion };
1758
1819
  export type { AIConfig, AIPromptTarget, AIProviderName, AISocialConfig, AISystemPromptOverrides, AITargetConfig, BumpConfig, BumpOptions, BumpResult, BumpResultFalsy, BumpResultTruthy, ChangelogConfig, ChangelogOptions, ClaudeCodeProviderOptions, ConfigType, GitProvider, GitlabRelease, GitlabReleaseResponse, HookConfig, HookStep, HookType, MonorepoConfig, PackageBase, PackageManager, PostedRelease, PrCommentConfig, PrCommentMode, PrCommentOptions, PrCommentStatus, ProviderReleaseOptions, ProviderReleaseResult, PublishConfig, PublishOptions, PublishResponse, PullRequestInfo, ReadPackage, Reference, ReleaseConfig, ReleaseContext, ReleaseOptions, RelizyConfig, RepoConfig, ResolvedConfig, ResolvedRelizyConfig, ResolvedTags, ResolvedTwitterCredentials, RootPackage, SlackCredentials, SlackOptions, SlackSocialConfig, SocialConfig, SocialNetworkResult, SocialOptions, SocialResult, Step, TemplatesConfig, TokensConfig, TwitterCredentials, TwitterOptions, TwitterSocialConfig, VersionMode };
package/dist/index.d.ts CHANGED
@@ -60,6 +60,8 @@ declare function getDefaultConfig(): {
60
60
  slack: {
61
61
  enabled: boolean;
62
62
  onlyStable: boolean;
63
+ postMaxLength: number;
64
+ noAuthors: boolean;
63
65
  };
64
66
  };
65
67
  prComment: Required<PrCommentConfig>;
@@ -233,6 +235,16 @@ declare function buildChangelogBody({ commits, config, minify }: {
233
235
  config: ResolvedRelizyConfig;
234
236
  minify?: boolean;
235
237
  }): string;
238
+ /**
239
+ * Collect unique contributor names from a set of commits.
240
+ * Respects `config.noAuthors`, filters `[bot]` authors, and applies `config.excludeAuthors`.
241
+ * Returns plain formatted names (no emails, no GitHub handles) — useful for lightweight
242
+ * rendering contexts like Slack messages.
243
+ */
244
+ declare function collectContributorNames({ commits, config }: {
245
+ commits: GitCommit[];
246
+ config: ResolvedRelizyConfig;
247
+ }): string[];
236
248
  declare function buildContributors({ commits, config }: {
237
249
  commits: GitCommit[];
238
250
  config: ResolvedRelizyConfig;
@@ -347,6 +359,13 @@ declare function getSlackToken(options: {
347
359
  socialCredentials?: SlackCredentials;
348
360
  tokenCredential?: string;
349
361
  }): string | null;
362
+ /**
363
+ * Get Slack Incoming Webhook URL from config or environment variables.
364
+ * Priority: social.slack.webhookUrl > RELIZY_SLACK_WEBHOOK_URL > SLACK_WEBHOOK_URL.
365
+ */
366
+ declare function getSlackWebhookUrl(options: {
367
+ socialWebhookUrl?: string;
368
+ }): string | null;
350
369
  /**
351
370
  * Format changelog for Slack (convert markdown to Slack's mrkdwn format)
352
371
  */
@@ -354,18 +373,25 @@ declare function formatChangelogForSlack(changelog: string, maxLength?: number):
354
373
  /**
355
374
  * Format the Slack message using blocks
356
375
  */
357
- declare function formatSlackMessage({ projectName, version, changelog, releaseUrl, changelogUrl, template }: {
376
+ declare function formatSlackMessage({ projectName, version, changelog, releaseUrl, changelogUrl, template, contributors, postMaxLength }: {
358
377
  template?: string;
359
378
  projectName: string;
360
379
  version: string;
361
380
  changelog: string;
362
381
  releaseUrl?: string;
363
382
  changelogUrl?: string;
383
+ contributors?: string[];
384
+ postMaxLength?: number;
364
385
  }): any[];
365
386
  /**
366
- * Post a release announcement to Slack
387
+ * Post a release announcement to Slack.
388
+ * Dispatches to Incoming Webhook (if `webhookUrl` is set) or Web API (`token` + `channel`).
389
+ * When both are provided, the webhook takes priority.
367
390
  */
368
- declare function postReleaseToSlack({ version, projectName, changelog, releaseUrl, changelogUrl, channel, token, template, dryRun, }: SlackOptions): Promise<_slack_web_api.ChatPostMessageResponse | undefined>;
391
+ declare function postReleaseToSlack({ version, projectName, changelog, releaseUrl, changelogUrl, channel, token, webhookUrl, template, contributors, postMaxLength, dryRun, }: SlackOptions): Promise<{
392
+ ok: true;
393
+ transport: "webhook";
394
+ } | _slack_web_api.ChatPostMessageResponse | undefined>;
369
395
 
370
396
  /**
371
397
  * Extract a summary from changelog content
@@ -1269,8 +1295,10 @@ interface TwitterSocialConfig {
1269
1295
  }
1270
1296
  interface SlackCredentials {
1271
1297
  /**
1272
- * Slack Bot Token or User OAuth Token
1273
- * Required scopes: chat:write, chat:write.public (for public channels)
1298
+ * Slack Bot Token or User OAuth Token (starts with `xoxb-`).
1299
+ * Required scopes: chat:write (and chat:write.public for public channels without bot invite).
1300
+ * Env fallback: SLACK_TOKEN, RELIZY_SLACK_TOKEN.
1301
+ * Ignored when social.slack.webhookUrl is set (webhook takes priority).
1274
1302
  */
1275
1303
  token?: string;
1276
1304
  }
@@ -1287,18 +1315,38 @@ interface SlackSocialConfig {
1287
1315
  */
1288
1316
  onlyStable?: boolean;
1289
1317
  /**
1290
- * Slack channel ID or name (e.g., "#releases" or "C1234567890")
1318
+ * Slack channel ID or name (e.g., "#releases" or "C1234567890").
1319
+ * Required when using token-based authentication.
1320
+ * Ignored (with warning) when webhookUrl is set — the channel is baked into the webhook URL.
1291
1321
  */
1292
- channel: string;
1322
+ channel?: string;
1323
+ /**
1324
+ * Slack Incoming Webhook URL. When set, takes priority over token-based auth.
1325
+ * Env fallback: SLACK_WEBHOOK_URL, RELIZY_SLACK_WEBHOOK_URL.
1326
+ * See: https://api.slack.com/messaging/webhooks
1327
+ */
1328
+ webhookUrl?: string;
1293
1329
  /**
1294
1330
  * Custom message template
1295
- * Available variables: {{projectName}}, {{newVersion}}, {{changelog}}, {{releaseUrl}}, {{changelogUrl}}
1331
+ * Available variables: {{projectName}}, {{newVersion}}, {{changelog}}, {{releaseUrl}}, {{changelogUrl}}, {{contributors}}
1296
1332
  */
1297
1333
  template?: string;
1298
1334
  /**
1299
1335
  * Slack credentials (optional - falls back to environment variables)
1300
1336
  */
1301
1337
  credentials?: SlackCredentials;
1338
+ /**
1339
+ * Maximum length (in characters) of the changelog rendered inside the Slack message.
1340
+ * Slack's per-section-block limit is 3000; default 2500 leaves margin for emoji/formatting.
1341
+ * @default 2500
1342
+ */
1343
+ postMaxLength?: number;
1344
+ /**
1345
+ * Hide the contributors block in Slack messages.
1346
+ * If config.noAuthors is true globally, contributors are always hidden regardless of this setting.
1347
+ * @default false
1348
+ */
1349
+ noAuthors?: boolean;
1302
1350
  }
1303
1351
  type AIProviderName = 'claude-code';
1304
1352
  interface ClaudeCodeProviderOptions {
@@ -1462,17 +1510,30 @@ interface SlackOptions {
1462
1510
  */
1463
1511
  changelogUrl?: string;
1464
1512
  /**
1465
- * Slack channel ID or name
1513
+ * Slack channel ID or name. Required when using token-based auth.
1466
1514
  */
1467
- channel: string;
1515
+ channel?: string;
1468
1516
  /**
1469
- * Slack token (required)
1517
+ * Slack Bot Token. Ignored if webhookUrl is set.
1470
1518
  */
1471
- token: string;
1519
+ token?: string;
1520
+ /**
1521
+ * Slack Incoming Webhook URL. Takes priority over token.
1522
+ */
1523
+ webhookUrl?: string;
1472
1524
  /**
1473
1525
  * Custom message template
1474
1526
  */
1475
1527
  template?: string;
1528
+ /**
1529
+ * Maximum chars of the changelog rendered in the message.
1530
+ * @default 2500
1531
+ */
1532
+ postMaxLength?: number;
1533
+ /**
1534
+ * Contributor names (plain strings, no email/handle). Empty array or undefined → no contributors block.
1535
+ */
1536
+ contributors?: string[];
1476
1537
  /**
1477
1538
  * Run without side effects
1478
1539
  * @default false
@@ -1754,5 +1815,5 @@ declare function socialSafetyCheck({ config }: {
1754
1815
  }): Promise<void>;
1755
1816
  declare function social(options?: Partial<SocialOptions>): Promise<SocialResult>;
1756
1817
 
1757
- export { NEW_PACKAGE_MARKER, PR_COMMENT_MARKER, buildChangelogBody, buildCommentBody, buildCompareLink, buildContributors, bump, capReleaseTypeForZeroMajor, changelog, checkGitStatusIfDirty, confirmBump, createCommitAndTags, createGitlabRelease, defineConfig, detectGitProvider, detectPackageManager, detectPullRequest, determinePublishTag, determineReleaseType, determineSemverChange, executeBuildCmd, executeFormatCmd, executeHook, expandPackagesToBumpWithDependents, extractChangelogSummary, extractVersionFromPackageTag, extractVersionFromTag, fetchGitTags, filterOutPrivatePackages, findGitHubPR, findGitLabMR, formatChangelogForSlack, formatSlackMessage, formatTweetMessage, generateChangelog, generateMarkDown, getAuthCommand, getBumpedIndependentPackages, getBumpedPackageIndependently, getCIName, getCanaryVersion, getCurrentGitBranch, getCurrentGitRef, getDefaultConfig, getDependentsOf, getFirstCommit, getGitStatus, getIndependentTag, getLastPackageTag, getLastRepoTag, getLastStableTag, getLastTag, getModifiedReleaseFilePatterns, getPackageCommits, getPackageDependencies, getPackageNewVersion, getPackages, getPackagesOrBumpedPackages, getPackagesToPublishInIndependentMode, getPackagesToPublishInSelectiveMode, getPreid, getReleaseUrl, getRootPackage, getShortCommitSha, getSlackToken, getTwitterCredentials, github, gitlab, hasLernaJson, isBumpedPackage, isChangedPreid, isGraduating, isGraduatingToStableBetweenVersion, isInCI, isPrerelease, isPrereleaseReleaseType, isStableReleaseType, isTagVersionCompatibleWithCurrent, loadRelizyConfig, mergeTypes, parseChangelogMarkdown, parseGitRemoteUrl, postPrComment, postReleaseToSlack, postReleaseToTwitter, prComment, providerRelease, providerReleaseSafetyCheck, publish, publishPackage, publishSafetyCheck, pushCommitAndTags, readPackageJson, readPackages, release, resolveTags, rollbackModifiedFiles, shouldFilterPrereleaseTags, social, socialSafetyCheck, topologicalSort, updateLernaVersion, writeChangelogToFile, writeVersion };
1818
+ export { NEW_PACKAGE_MARKER, PR_COMMENT_MARKER, buildChangelogBody, buildCommentBody, buildCompareLink, buildContributors, bump, capReleaseTypeForZeroMajor, changelog, checkGitStatusIfDirty, collectContributorNames, confirmBump, createCommitAndTags, createGitlabRelease, defineConfig, detectGitProvider, detectPackageManager, detectPullRequest, determinePublishTag, determineReleaseType, determineSemverChange, executeBuildCmd, executeFormatCmd, executeHook, expandPackagesToBumpWithDependents, extractChangelogSummary, extractVersionFromPackageTag, extractVersionFromTag, fetchGitTags, filterOutPrivatePackages, findGitHubPR, findGitLabMR, formatChangelogForSlack, formatSlackMessage, formatTweetMessage, generateChangelog, generateMarkDown, getAuthCommand, getBumpedIndependentPackages, getBumpedPackageIndependently, getCIName, getCanaryVersion, getCurrentGitBranch, getCurrentGitRef, getDefaultConfig, getDependentsOf, getFirstCommit, getGitStatus, getIndependentTag, getLastPackageTag, getLastRepoTag, getLastStableTag, getLastTag, getModifiedReleaseFilePatterns, getPackageCommits, getPackageDependencies, getPackageNewVersion, getPackages, getPackagesOrBumpedPackages, getPackagesToPublishInIndependentMode, getPackagesToPublishInSelectiveMode, getPreid, getReleaseUrl, getRootPackage, getShortCommitSha, getSlackToken, getSlackWebhookUrl, getTwitterCredentials, github, gitlab, hasLernaJson, isBumpedPackage, isChangedPreid, isGraduating, isGraduatingToStableBetweenVersion, isInCI, isPrerelease, isPrereleaseReleaseType, isStableReleaseType, isTagVersionCompatibleWithCurrent, loadRelizyConfig, mergeTypes, parseChangelogMarkdown, parseGitRemoteUrl, postPrComment, postReleaseToSlack, postReleaseToTwitter, prComment, providerRelease, providerReleaseSafetyCheck, publish, publishPackage, publishSafetyCheck, pushCommitAndTags, readPackageJson, readPackages, release, resolveTags, rollbackModifiedFiles, shouldFilterPrereleaseTags, social, socialSafetyCheck, topologicalSort, updateLernaVersion, writeChangelogToFile, writeVersion };
1758
1819
  export type { AIConfig, AIPromptTarget, AIProviderName, AISocialConfig, AISystemPromptOverrides, AITargetConfig, BumpConfig, BumpOptions, BumpResult, BumpResultFalsy, BumpResultTruthy, ChangelogConfig, ChangelogOptions, ClaudeCodeProviderOptions, ConfigType, GitProvider, GitlabRelease, GitlabReleaseResponse, HookConfig, HookStep, HookType, MonorepoConfig, PackageBase, PackageManager, PostedRelease, PrCommentConfig, PrCommentMode, PrCommentOptions, PrCommentStatus, ProviderReleaseOptions, ProviderReleaseResult, PublishConfig, PublishOptions, PublishResponse, PullRequestInfo, ReadPackage, Reference, ReleaseConfig, ReleaseContext, ReleaseOptions, RelizyConfig, RepoConfig, ResolvedConfig, ResolvedRelizyConfig, ResolvedTags, ResolvedTwitterCredentials, RootPackage, SlackCredentials, SlackOptions, SlackSocialConfig, SocialConfig, SocialNetworkResult, SocialOptions, SocialResult, Step, TemplatesConfig, TokensConfig, TwitterCredentials, TwitterOptions, TwitterSocialConfig, VersionMode };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { ag as NEW_PACKAGE_MARKER, Z as PR_COMMENT_MARKER, M as buildChangelogBody, a as buildCommentBody, L as buildCompareLink, N as buildContributors, b as bump, au as capReleaseTypeForZeroMajor, c as changelog, v as checkGitStatusIfDirty, aI as confirmBump, B as createCommitAndTags, J as createGitlabRelease, k as defineConfig, y as detectGitProvider, Q as detectPackageManager, Y as detectPullRequest, R as determinePublishTag, aw as determineReleaseType, av as determineSemverChange, ap as executeBuildCmd, ao as executeFormatCmd, al as executeHook, q as expandPackagesToBumpWithDependents, a9 as extractChangelogSummary, aA as extractVersionFromPackageTag, aL as extractVersionFromTag, x as fetchGitTags, ar as filterOutPrivatePackages, W as findGitHubPR, X as findGitLabMR, a6 as formatChangelogForSlack, a7 as formatSlackMessage, aj as formatTweetMessage, i as generateChangelog, O as generateMarkDown, U as getAuthCommand, aJ as getBumpedIndependentPackages, aH as getBumpedPackageIndependently, an as getCIName, aM as getCanaryVersion, F as getCurrentGitBranch, G as getCurrentGitRef, j as getDefaultConfig, o as getDependentsOf, E as getFirstCommit, u as getGitStatus, ab as getIndependentTag, af as getLastPackageTag, ae as getLastRepoTag, ac as getLastStableTag, ad as getLastTag, A as getModifiedReleaseFilePatterns, a3 as getPackageCommits, n as getPackageDependencies, ay as getPackageNewVersion, a2 as getPackages, as as getPackagesOrBumpedPackages, T as getPackagesToPublishInIndependentMode, S as getPackagesToPublishInSelectiveMode, aF as getPreid, aa as getReleaseUrl, a0 as getRootPackage, H as getShortCommitSha, a5 as getSlackToken, ai as getTwitterCredentials, I as github, K as gitlab, a4 as hasLernaJson, aq as isBumpedPackage, aG as isChangedPreid, aE as isGraduating, at as isGraduatingToStableBetweenVersion, am as isInCI, aB as isPrerelease, aD as isPrereleaseReleaseType, aC as isStableReleaseType, aN as isTagVersionCompatibleWithCurrent, l as loadRelizyConfig, m as mergeTypes, P as parseChangelogMarkdown, z as parseGitRemoteUrl, _ as postPrComment, a8 as postReleaseToSlack, ak as postReleaseToTwitter, p as prComment, e as providerRelease, d as providerReleaseSafetyCheck, g as publish, V as publishPackage, f as publishSafetyCheck, C as pushCommitAndTags, $ as readPackageJson, a1 as readPackages, r as release, ah as resolveTags, D as rollbackModifiedFiles, aK as shouldFilterPrereleaseTags, h as social, s as socialSafetyCheck, t as topologicalSort, az as updateLernaVersion, w as writeChangelogToFile, ax as writeVersion } from './shared/relizy.BRFiG2GH.mjs';
1
+ export { ai as NEW_PACKAGE_MARKER, _ as PR_COMMENT_MARKER, M as buildChangelogBody, a as buildCommentBody, L as buildCompareLink, O as buildContributors, b as bump, aw as capReleaseTypeForZeroMajor, c as changelog, v as checkGitStatusIfDirty, N as collectContributorNames, aK as confirmBump, B as createCommitAndTags, J as createGitlabRelease, k as defineConfig, y as detectGitProvider, R as detectPackageManager, Z as detectPullRequest, S as determinePublishTag, ay as determineReleaseType, ax as determineSemverChange, ar as executeBuildCmd, aq as executeFormatCmd, an as executeHook, q as expandPackagesToBumpWithDependents, ab as extractChangelogSummary, aC as extractVersionFromPackageTag, aN as extractVersionFromTag, x as fetchGitTags, at as filterOutPrivatePackages, X as findGitHubPR, Y as findGitLabMR, a8 as formatChangelogForSlack, a9 as formatSlackMessage, al as formatTweetMessage, i as generateChangelog, P as generateMarkDown, V as getAuthCommand, aL as getBumpedIndependentPackages, aJ as getBumpedPackageIndependently, ap as getCIName, aO as getCanaryVersion, F as getCurrentGitBranch, G as getCurrentGitRef, j as getDefaultConfig, o as getDependentsOf, E as getFirstCommit, u as getGitStatus, ad as getIndependentTag, ah as getLastPackageTag, ag as getLastRepoTag, ae as getLastStableTag, af as getLastTag, A as getModifiedReleaseFilePatterns, a4 as getPackageCommits, n as getPackageDependencies, aA as getPackageNewVersion, a3 as getPackages, au as getPackagesOrBumpedPackages, U as getPackagesToPublishInIndependentMode, T as getPackagesToPublishInSelectiveMode, aH as getPreid, ac as getReleaseUrl, a1 as getRootPackage, H as getShortCommitSha, a6 as getSlackToken, a7 as getSlackWebhookUrl, ak as getTwitterCredentials, I as github, K as gitlab, a5 as hasLernaJson, as as isBumpedPackage, aI as isChangedPreid, aG as isGraduating, av as isGraduatingToStableBetweenVersion, ao as isInCI, aD as isPrerelease, aF as isPrereleaseReleaseType, aE as isStableReleaseType, aP as isTagVersionCompatibleWithCurrent, l as loadRelizyConfig, m as mergeTypes, Q as parseChangelogMarkdown, z as parseGitRemoteUrl, $ as postPrComment, aa as postReleaseToSlack, am as postReleaseToTwitter, p as prComment, e as providerRelease, d as providerReleaseSafetyCheck, g as publish, W as publishPackage, f as publishSafetyCheck, C as pushCommitAndTags, a0 as readPackageJson, a2 as readPackages, r as release, aj as resolveTags, D as rollbackModifiedFiles, aM as shouldFilterPrereleaseTags, h as social, s as socialSafetyCheck, t as topologicalSort, aB as updateLernaVersion, w as writeChangelogToFile, az as writeVersion } from './shared/relizy.CxbwJj6k.mjs';
2
2
  import '@maz-ui/node';
3
3
  import 'node:child_process';
4
4
  import 'node:process';
@@ -1914,7 +1914,9 @@ function getDefaultConfig() {
1914
1914
  },
1915
1915
  slack: {
1916
1916
  enabled: false,
1917
- onlyStable: true
1917
+ onlyStable: true,
1918
+ postMaxLength: 2500,
1919
+ noAuthors: false
1918
1920
  }
1919
1921
  },
1920
1922
  prComment: {
@@ -2382,11 +2384,11 @@ function buildChangelogBody({ commits, config, minify }) {
2382
2384
  }
2383
2385
  return convert(markdown.join("\n").trim(), true);
2384
2386
  }
2385
- async function buildContributors({ commits, config }) {
2387
+ function collectContributorNames({ commits, config }) {
2386
2388
  if (config.noAuthors) {
2387
- return "";
2389
+ return [];
2388
2390
  }
2389
- const _authors = /* @__PURE__ */ new Map();
2391
+ const names = /* @__PURE__ */ new Set();
2390
2392
  for (const commit of commits) {
2391
2393
  if (!commit.author) {
2392
2394
  continue;
@@ -2400,11 +2402,26 @@ async function buildContributors({ commits, config }) {
2400
2402
  )) {
2401
2403
  continue;
2402
2404
  }
2403
- if (_authors.has(name)) {
2404
- const entry = _authors.get(name);
2405
- entry?.email.add(commit.author.email);
2406
- } else {
2407
- _authors.set(name, { email: /* @__PURE__ */ new Set([commit.author.email]), name });
2405
+ names.add(name);
2406
+ }
2407
+ return Array.from(names);
2408
+ }
2409
+ async function buildContributors({ commits, config }) {
2410
+ const names = collectContributorNames({ commits, config });
2411
+ if (names.length === 0) {
2412
+ return "";
2413
+ }
2414
+ const _authors = /* @__PURE__ */ new Map();
2415
+ for (const name of names) {
2416
+ _authors.set(name, { email: /* @__PURE__ */ new Set(), name });
2417
+ }
2418
+ for (const commit of commits) {
2419
+ if (!commit.author)
2420
+ continue;
2421
+ const name = formatName(commit.author.name);
2422
+ const entry = _authors.get(name);
2423
+ if (entry && commit.author.email) {
2424
+ entry.email.add(commit.author.email);
2408
2425
  }
2409
2426
  }
2410
2427
  if (config.repo?.provider === "github") {
@@ -3717,7 +3734,10 @@ function getSlackToken(options) {
3717
3734
  }
3718
3735
  return token;
3719
3736
  }
3720
- function formatChangelogForSlack(changelog, maxLength = 500) {
3737
+ function getSlackWebhookUrl(options) {
3738
+ return options.socialWebhookUrl || process.env.RELIZY_SLACK_WEBHOOK_URL || process.env.SLACK_WEBHOOK_URL || null;
3739
+ }
3740
+ function formatChangelogForSlack(changelog, maxLength = 2500) {
3721
3741
  let formatted = changelog.replace(/^### (.+)$/gm, "*$1*").replace(/^## (.+)$/gm, "*$1*").replace(/^# (.+)$/gm, "*$1*").replace(/\*\*(.+?)\*\*/g, "*$1*");
3722
3742
  const linkPattern = /\[([^\]]*)]\(([^)]*)\)/g;
3723
3743
  formatted = formatted.replace(linkPattern, (_, text, url) => `<${url}|${text}>`);
@@ -3726,10 +3746,11 @@ function formatChangelogForSlack(changelog, maxLength = 500) {
3726
3746
  }
3727
3747
  return formatted;
3728
3748
  }
3729
- function formatSlackMessage({ projectName, version, changelog, releaseUrl, changelogUrl, template }) {
3749
+ function formatSlackMessage({ projectName, version, changelog, releaseUrl, changelogUrl, template, contributors = [], postMaxLength = 2500 }) {
3750
+ const contributorsLine = contributors.length > 0 ? contributors.map((n) => `\u2022 ${n}`).join("\n") : "";
3730
3751
  if (template) {
3731
- const summary = extractChangelogSummary(changelog, { maxLength: 500 });
3732
- let message = template.replace("{{projectName}}", projectName).replace("{{newVersion}}", version).replace("{{changelog}}", summary);
3752
+ const summary = extractChangelogSummary(changelog, { maxLength: postMaxLength });
3753
+ let message = template.replace("{{projectName}}", projectName).replace("{{newVersion}}", version).replace("{{changelog}}", summary).replace("{{contributors}}", contributorsLine);
3733
3754
  if (releaseUrl) {
3734
3755
  message = message.replace("{{releaseUrl}}", releaseUrl);
3735
3756
  } else {
@@ -3760,7 +3781,7 @@ function formatSlackMessage({ projectName, version, changelog, releaseUrl, chang
3760
3781
  }
3761
3782
  }
3762
3783
  ];
3763
- const formattedChangelog = formatChangelogForSlack(changelog, 500);
3784
+ const formattedChangelog = formatChangelogForSlack(changelog, postMaxLength);
3764
3785
  if (formattedChangelog) {
3765
3786
  blocks.push({
3766
3787
  type: "section",
@@ -3770,6 +3791,17 @@ function formatSlackMessage({ projectName, version, changelog, releaseUrl, chang
3770
3791
  }
3771
3792
  });
3772
3793
  }
3794
+ if (contributors.length > 0) {
3795
+ blocks.push({
3796
+ type: "section",
3797
+ text: {
3798
+ type: "mrkdwn",
3799
+ text: `*\u2764\uFE0F Contributors*
3800
+
3801
+ ${contributorsLine}`
3802
+ }
3803
+ });
3804
+ }
3773
3805
  blocks.push({
3774
3806
  type: "divider"
3775
3807
  });
@@ -3806,44 +3838,44 @@ function formatSlackMessage({ projectName, version, changelog, releaseUrl, chang
3806
3838
  }
3807
3839
  return blocks;
3808
3840
  }
3809
- async function postReleaseToSlack({
3810
- version,
3811
- projectName,
3812
- changelog,
3813
- releaseUrl,
3814
- changelogUrl,
3815
- channel,
3816
- token,
3817
- template,
3818
- dryRun = false
3819
- }) {
3820
- logger.debug("Preparing Slack post...");
3821
- const blocks = formatSlackMessage({
3822
- template,
3823
- projectName,
3824
- version,
3825
- changelog,
3826
- releaseUrl,
3827
- changelogUrl
3841
+ function mapWebhookError(status, body) {
3842
+ if (status === 404 || body.includes("no_service")) {
3843
+ return "The webhook URL is invalid or has been deactivated. Regenerate it in your Slack app settings.";
3844
+ }
3845
+ if (body.includes("invalid_payload")) {
3846
+ return "The message payload was rejected by Slack (likely exceeds 3000 chars per block). Lower social.slack.postMaxLength.";
3847
+ }
3848
+ if (body.includes("channel_not_found")) {
3849
+ return "The channel bound to this webhook was archived or removed. Create a new webhook.";
3850
+ }
3851
+ if (body.includes("action_prohibited")) {
3852
+ return "Your workspace has blocked the webhook. Check workspace settings.";
3853
+ }
3854
+ return null;
3855
+ }
3856
+ async function postViaWebhook({ url, blocks, text }) {
3857
+ const response = await fetch(url, {
3858
+ method: "POST",
3859
+ headers: { "Content-Type": "application/json" },
3860
+ body: JSON.stringify({ blocks, text })
3828
3861
  });
3829
- logger.debug(`Message blocks (${blocks.length} blocks)`);
3830
- if (dryRun) {
3831
- const preview = blocks.filter((b) => b.type === "header" || b.type === "section").map((b) => b.text?.text ?? "").filter(Boolean).join("\n\n");
3832
- logger.box(`[dry-run] Slack Post Preview (channel: ${channel})
3833
-
3834
- ${preview}`);
3835
- return;
3862
+ if (!response.ok) {
3863
+ const body = await response.text().catch(() => "");
3864
+ const hint = mapWebhookError(response.status, body);
3865
+ const detail = body ? ` - ${body}` : "";
3866
+ const hintLine = hint ? `
3867
+ \u2192 ${hint}` : "";
3868
+ throw new Error(`Slack webhook failed: ${response.status} ${response.statusText}${detail}${hintLine}`);
3836
3869
  }
3870
+ logger.success("Message posted successfully via Slack webhook!");
3871
+ return { ok: true, transport: "webhook" };
3872
+ }
3873
+ async function postViaWebApi({ token, channel, blocks, text }) {
3837
3874
  try {
3838
3875
  const { WebClient } = await import('@slack/web-api');
3839
3876
  const client = new WebClient(token);
3840
3877
  logger.debug(`Posting message to Slack channel: ${channel}`);
3841
- const result = await client.chat.postMessage({
3842
- channel,
3843
- blocks,
3844
- text: `${projectName} ${version} is out!`
3845
- // Fallback text for notifications
3846
- });
3878
+ const result = await client.chat.postMessage({ channel, blocks, text });
3847
3879
  logger.success(`Message posted successfully! Channel: ${result.channel}, Timestamp: ${result.ts}`);
3848
3880
  return result;
3849
3881
  } catch (error) {
@@ -3870,6 +3902,54 @@ ${preview}`);
3870
3902
  throw error;
3871
3903
  }
3872
3904
  }
3905
+ async function postReleaseToSlack({
3906
+ version,
3907
+ projectName,
3908
+ changelog,
3909
+ releaseUrl,
3910
+ changelogUrl,
3911
+ channel,
3912
+ token,
3913
+ webhookUrl,
3914
+ template,
3915
+ contributors,
3916
+ postMaxLength,
3917
+ dryRun = false
3918
+ }) {
3919
+ const useWebhook = Boolean(webhookUrl);
3920
+ if (!useWebhook && !token) {
3921
+ throw new Error("Slack: either webhookUrl or token must be provided");
3922
+ }
3923
+ if (!useWebhook && !channel) {
3924
+ throw new Error("Slack: channel is required when using token-based authentication");
3925
+ }
3926
+ logger.debug(`Slack transport: ${useWebhook ? "webhook" : "web-api"}`);
3927
+ logger.debug("Preparing Slack post...");
3928
+ const blocks = formatSlackMessage({
3929
+ template,
3930
+ projectName,
3931
+ version,
3932
+ changelog,
3933
+ releaseUrl,
3934
+ changelogUrl,
3935
+ contributors,
3936
+ postMaxLength
3937
+ });
3938
+ const fallbackText = `${projectName} ${version} is out!`;
3939
+ logger.debug(`Message blocks (${blocks.length} blocks)`);
3940
+ if (dryRun) {
3941
+ const preview = blocks.filter((b) => b.type === "header" || b.type === "section").map((b) => b.text?.text ?? "").filter(Boolean).join("\n\n");
3942
+ const target = useWebhook ? "webhook" : `channel: ${channel}`;
3943
+ logger.box(`[dry-run] Slack Post Preview (${target})
3944
+
3945
+ ${preview}`);
3946
+ return;
3947
+ }
3948
+ if (useWebhook) {
3949
+ return await postViaWebhook({ url: webhookUrl, blocks, text: fallbackText });
3950
+ }
3951
+ return await postViaWebApi({ token, channel, blocks, text: fallbackText });
3952
+ }
3873
3953
 
3874
3954
  function getTwitterCredentials({ socialCredentials, tokenCredentials }) {
3875
3955
  const apiKey = socialCredentials?.apiKey || tokenCredentials?.apiKey;
@@ -5180,27 +5260,37 @@ async function socialSafetyCheck({ config }) {
5180
5260
  }
5181
5261
  const slackConfig = config.social?.slack;
5182
5262
  if (slackConfig?.enabled) {
5263
+ const webhookUrl = getSlackWebhookUrl({ socialWebhookUrl: slackConfig.webhookUrl });
5183
5264
  const token = getSlackToken({
5184
5265
  socialCredentials: slackConfig.credentials,
5185
5266
  tokenCredential: config.tokens?.slack
5186
5267
  });
5187
- try {
5188
- await import('@slack/web-api');
5189
- } catch {
5190
- logger.fail("@slack/web-api is not installed, please install it");
5191
- throw new Error("@slack/web-api is not installed");
5192
- }
5193
- if (!token) {
5194
- logger.fail("Slack is enabled but credentials are missing.");
5195
- logger.log("Set the following environment variables or configure them in social.slack.credentials or tokens.slack:");
5196
- logger.log(" - SLACK_TOKEN or RELIZY_SLACK_TOKEN");
5268
+ if (webhookUrl) {
5269
+ if (slackConfig.channel) {
5270
+ logger.warn("social.slack.channel is ignored when webhookUrl is set (channel is baked into the webhook URL).");
5271
+ }
5272
+ if (token) {
5273
+ logger.warn("Slack token is ignored when webhookUrl is set (webhook takes priority).");
5274
+ }
5275
+ } else if (token) {
5276
+ try {
5277
+ await import('@slack/web-api');
5278
+ } catch {
5279
+ logger.fail("@slack/web-api is not installed, please install it");
5280
+ throw new Error("@slack/web-api is not installed");
5281
+ }
5282
+ if (!slackConfig.channel) {
5283
+ logger.fail("Slack is enabled but no channel is configured.");
5284
+ logger.log('Set the channel in social.slack.channel (e.g., "#releases" or "C1234567890") or switch to webhookUrl for a simpler setup.');
5285
+ throw new Error("Slack channel not found");
5286
+ }
5287
+ } else {
5288
+ logger.fail("Slack is enabled but no credentials are configured.");
5289
+ logger.log("Provide ONE of the following:");
5290
+ logger.log(" (a) social.slack.webhookUrl (or SLACK_WEBHOOK_URL / RELIZY_SLACK_WEBHOOK_URL env var) \u2014 simpler setup, channel baked in");
5291
+ logger.log(" (b) social.slack.credentials.token (or SLACK_TOKEN / RELIZY_SLACK_TOKEN env var) + social.slack.channel \u2014 requires bot invite");
5197
5292
  throw new Error("Slack credentials not found");
5198
5293
  }
5199
- if (!slackConfig.channel) {
5200
- logger.fail("Slack is enabled but no channel is configured.");
5201
- logger.log('Set the channel in social.slack.channel (e.g., "#releases" or "C1234567890")');
5202
- throw new Error("Slack channel not found");
5203
- }
5204
5294
  }
5205
5295
  if (isAISocialEnabled(config, "twitter") || isAISocialEnabled(config, "slack")) {
5206
5296
  await aiSafetyCheck({ config });
@@ -5281,7 +5371,8 @@ async function handleSlackPost({
5281
5371
  changelog,
5282
5372
  dryRun,
5283
5373
  newVersion,
5284
- tag
5374
+ tag,
5375
+ commits
5285
5376
  }) {
5286
5377
  const slackConfig = config.social?.slack;
5287
5378
  if (!slackConfig?.enabled) {
@@ -5290,22 +5381,23 @@ async function handleSlackPost({
5290
5381
  }
5291
5382
  logger.debug("Slack posting is enabled");
5292
5383
  try {
5384
+ const webhookUrl = getSlackWebhookUrl({ socialWebhookUrl: slackConfig.webhookUrl });
5293
5385
  const token = getSlackToken({
5294
5386
  socialCredentials: slackConfig.credentials,
5295
5387
  tokenCredential: config.tokens?.slack
5296
5388
  });
5297
- if (!token) {
5298
- logger.warn("Slack token not found. Set SLACK_TOKEN or RELIZY_SLACK_TOKEN environment variable or configure it in social.slack.credentials or tokens.slack.");
5389
+ if (!webhookUrl && !token) {
5390
+ logger.warn("Neither Slack webhookUrl nor token is configured. Set SLACK_WEBHOOK_URL / SLACK_TOKEN or configure social.slack.webhookUrl / credentials.token.");
5299
5391
  logger.info("Skipping Slack post");
5300
- return { success: false, error: "Slack token not found" };
5392
+ return { success: false, error: "Slack credentials not found" };
5301
5393
  }
5302
- logger.debug("Token found \u2713");
5303
- if (!slackConfig.channel) {
5304
- logger.warn("Slack channel not configured. Set it in social.slack.channel.");
5394
+ if (!webhookUrl && !slackConfig.channel) {
5395
+ logger.warn("Slack channel not configured (required in token mode). Set it in social.slack.channel.");
5305
5396
  logger.info("Skipping Slack post");
5306
5397
  return { success: false, error: "Slack channel not configured" };
5307
5398
  }
5308
- logger.debug(`Channel configured: ${slackConfig.channel}`);
5399
+ const slackMode = webhookUrl ? "webhook mode" : `token mode, channel: ${slackConfig.channel}`;
5400
+ logger.debug(`Slack: ${slackMode}`);
5309
5401
  logger.debug(`Preparing Slack message for release: ${tag} (${newVersion})`);
5310
5402
  const onlyStable = slackConfig.onlyStable ?? true;
5311
5403
  if (onlyStable && isPrerelease(newVersion)) {
@@ -5325,6 +5417,9 @@ async function handleSlackPost({
5325
5417
  logger.debug(`Changelog URL: ${changelogUrl || "none"}`);
5326
5418
  logger.debug(`Changelog generated (${changelog.length} chars)`);
5327
5419
  const template = slackConfig.template || config.templates.slackMessage;
5420
+ const shouldHideContributors = config.noAuthors === true || slackConfig.noAuthors === true;
5421
+ const contributors = shouldHideContributors ? [] : collectContributorNames({ commits, config });
5422
+ logger.debug(`Contributors: ${contributors.length}`);
5328
5423
  const response = await postReleaseToSlack({
5329
5424
  version: newVersion,
5330
5425
  projectName: config.projectName || rootPackageBase.name,
@@ -5332,8 +5427,11 @@ async function handleSlackPost({
5332
5427
  releaseUrl,
5333
5428
  changelogUrl,
5334
5429
  channel: slackConfig.channel,
5335
- token,
5430
+ token: token ?? void 0,
5431
+ webhookUrl: webhookUrl ?? void 0,
5336
5432
  template,
5433
+ contributors,
5434
+ postMaxLength: slackConfig.postMaxLength ?? 2500,
5337
5435
  dryRun
5338
5436
  });
5339
5437
  await executeHook("success:slack", config, dryRun);
@@ -5448,7 +5546,8 @@ ${twitterChangelog}`);
5448
5546
  changelog: slackChangelog,
5449
5547
  dryRun,
5450
5548
  newVersion,
5451
- tag: to
5549
+ tag: to,
5550
+ commits: rootPackage.commits
5452
5551
  });
5453
5552
  const results = [];
5454
5553
  if (config.social?.twitter?.enabled) {
@@ -5818,4 +5917,4 @@ Git provider: ${provider}`);
5818
5917
  }
5819
5918
  }
5820
5919
 
5821
- export { readPackageJson as $, getModifiedReleaseFilePatterns as A, createCommitAndTags as B, pushCommitAndTags as C, rollbackModifiedFiles as D, getFirstCommit as E, getCurrentGitBranch as F, getCurrentGitRef as G, getShortCommitSha as H, github as I, createGitlabRelease as J, gitlab as K, buildCompareLink as L, buildChangelogBody as M, buildContributors as N, generateMarkDown as O, parseChangelogMarkdown as P, detectPackageManager as Q, determinePublishTag as R, getPackagesToPublishInSelectiveMode as S, getPackagesToPublishInIndependentMode as T, getAuthCommand as U, publishPackage as V, findGitHubPR as W, findGitLabMR as X, detectPullRequest as Y, PR_COMMENT_MARKER as Z, postPrComment as _, buildCommentBody as a, getRootPackage as a0, readPackages as a1, getPackages as a2, getPackageCommits as a3, hasLernaJson as a4, getSlackToken as a5, formatChangelogForSlack as a6, formatSlackMessage as a7, postReleaseToSlack as a8, extractChangelogSummary as a9, extractVersionFromPackageTag as aA, isPrerelease as aB, isStableReleaseType as aC, isPrereleaseReleaseType as aD, isGraduating as aE, getPreid as aF, isChangedPreid as aG, getBumpedPackageIndependently as aH, confirmBump as aI, getBumpedIndependentPackages as aJ, shouldFilterPrereleaseTags as aK, extractVersionFromTag as aL, getCanaryVersion as aM, isTagVersionCompatibleWithCurrent as aN, getReleaseUrl as aa, getIndependentTag as ab, getLastStableTag as ac, getLastTag as ad, getLastRepoTag as ae, getLastPackageTag as af, NEW_PACKAGE_MARKER as ag, resolveTags as ah, getTwitterCredentials as ai, formatTweetMessage as aj, postReleaseToTwitter as ak, executeHook as al, isInCI as am, getCIName as an, executeFormatCmd as ao, executeBuildCmd as ap, isBumpedPackage as aq, filterOutPrivatePackages as ar, getPackagesOrBumpedPackages as as, isGraduatingToStableBetweenVersion as at, capReleaseTypeForZeroMajor as au, determineSemverChange as av, determineReleaseType as aw, writeVersion as ax, getPackageNewVersion as ay, updateLernaVersion as az, bump as b, changelog as c, providerReleaseSafetyCheck as d, providerRelease as e, publishSafetyCheck as f, publish as g, social as h, generateChangelog as i, getDefaultConfig as j, defineConfig as k, loadRelizyConfig as l, mergeTypes as m, getPackageDependencies as n, getDependentsOf as o, prComment as p, expandPackagesToBumpWithDependents as q, release as r, socialSafetyCheck as s, topologicalSort as t, getGitStatus as u, checkGitStatusIfDirty as v, writeChangelogToFile as w, fetchGitTags as x, detectGitProvider as y, parseGitRemoteUrl as z };
5920
+ export { postPrComment as $, getModifiedReleaseFilePatterns as A, createCommitAndTags as B, pushCommitAndTags as C, rollbackModifiedFiles as D, getFirstCommit as E, getCurrentGitBranch as F, getCurrentGitRef as G, getShortCommitSha as H, github as I, createGitlabRelease as J, gitlab as K, buildCompareLink as L, buildChangelogBody as M, collectContributorNames as N, buildContributors as O, generateMarkDown as P, parseChangelogMarkdown as Q, detectPackageManager as R, determinePublishTag as S, getPackagesToPublishInSelectiveMode as T, getPackagesToPublishInIndependentMode as U, getAuthCommand as V, publishPackage as W, findGitHubPR as X, findGitLabMR as Y, detectPullRequest as Z, PR_COMMENT_MARKER as _, buildCommentBody as a, readPackageJson as a0, getRootPackage as a1, readPackages as a2, getPackages as a3, getPackageCommits as a4, hasLernaJson as a5, getSlackToken as a6, getSlackWebhookUrl as a7, formatChangelogForSlack as a8, formatSlackMessage as a9, getPackageNewVersion as aA, updateLernaVersion as aB, extractVersionFromPackageTag as aC, isPrerelease as aD, isStableReleaseType as aE, isPrereleaseReleaseType as aF, isGraduating as aG, getPreid as aH, isChangedPreid as aI, getBumpedPackageIndependently as aJ, confirmBump as aK, getBumpedIndependentPackages as aL, shouldFilterPrereleaseTags as aM, extractVersionFromTag as aN, getCanaryVersion as aO, isTagVersionCompatibleWithCurrent as aP, postReleaseToSlack as aa, extractChangelogSummary as ab, getReleaseUrl as ac, getIndependentTag as ad, getLastStableTag as ae, getLastTag as af, getLastRepoTag as ag, getLastPackageTag as ah, NEW_PACKAGE_MARKER as ai, resolveTags as aj, getTwitterCredentials as ak, formatTweetMessage as al, postReleaseToTwitter as am, executeHook as an, isInCI as ao, getCIName as ap, executeFormatCmd as aq, executeBuildCmd as ar, isBumpedPackage as as, filterOutPrivatePackages as at, getPackagesOrBumpedPackages as au, isGraduatingToStableBetweenVersion as av, capReleaseTypeForZeroMajor as aw, determineSemverChange as ax, determineReleaseType as ay, writeVersion as az, bump as b, changelog as c, providerReleaseSafetyCheck as d, providerRelease as e, publishSafetyCheck as f, publish as g, social as h, generateChangelog as i, getDefaultConfig as j, defineConfig as k, loadRelizyConfig as l, mergeTypes as m, getPackageDependencies as n, getDependentsOf as o, prComment as p, expandPackagesToBumpWithDependents as q, release as r, socialSafetyCheck as s, topologicalSort as t, getGitStatus as u, checkGitStatusIfDirty as v, writeChangelogToFile as w, fetchGitTags as x, detectGitProvider as y, parseGitRemoteUrl as z };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "relizy",
3
3
  "type": "module",
4
- "version": "1.3.3",
4
+ "version": "1.4.0-beta.0",
5
5
  "description": "Changelogen adapter for monorepo management with unified and independent versioning",
6
6
  "author": "Louis Mazel <me@loicmazuel.com>",
7
7
  "license": "MIT",
@@ -71,7 +71,7 @@
71
71
  }
72
72
  },
73
73
  "dependencies": {
74
- "@inquirer/prompts": "^8.4.1",
74
+ "@inquirer/prompts": "^8.4.2",
75
75
  "@maz-ui/node": "4.6.1",
76
76
  "@maz-ui/utils": "^4.7.6",
77
77
  "c12": "^3.3.3",
@@ -88,23 +88,23 @@
88
88
  "@commitlint/config-conventional": "20.5.0",
89
89
  "@commitlint/cz-commitlint": "^20.5.1",
90
90
  "@commitlint/types": "^20.5.0",
91
- "@maz-ui/eslint-config": "^4.8.0",
92
- "@slack/web-api": "7.15.0",
91
+ "@maz-ui/eslint-config": "^4.9.1",
92
+ "@slack/web-api": "7.15.1",
93
93
  "@types/node": "^25.6.0",
94
94
  "@types/semver": "^7.7.1",
95
- "@vitest/coverage-v8": "^4.1.4",
95
+ "@vitest/coverage-v8": "^4.1.5",
96
96
  "@yoloship/claude-sdk": "0.1.0-beta.3",
97
97
  "cross-env": "10.1.0",
98
- "eslint": "^10.2.0",
98
+ "eslint": "^10.2.1",
99
99
  "husky": "9.1.7",
100
100
  "jiti": "2.6.1",
101
101
  "lint-staged": "^16.4.0",
102
- "memfs": "^4.57.1",
102
+ "memfs": "^4.57.2",
103
103
  "tsx": "^4.21.0",
104
104
  "twitter-api-v2": "^1.29.0",
105
105
  "typescript": "^5.9.3",
106
106
  "unbuild": "^3.6.1",
107
- "vitest": "^4.1.4"
107
+ "vitest": "^4.1.5"
108
108
  },
109
109
  "lint-staged": {
110
110
  "*.{js,jsx,ts,tsx,mjs,mts,cjs,md,yml,json}": [