Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions docs/cli/release/changelog-add.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ docs-builder changelog add [options...] [-h|--help]

`--no-extract-release-notes`
: Optional: Turn off extraction of release notes from PR descriptions.
: By default, the extractor looks for content in various formats in the PR description:
: The extractor looks for content in various formats in the PR description:
: - `Release Notes: ...`
: - `Release-Notes: ...`
: - `release notes: ...`
Expand All @@ -36,6 +36,7 @@ docs-builder changelog add [options...] [-h|--help]
: - `## Release Note` (as a markdown header)
: Short release notes (≤120 characters, single line) are used as the changelog title (only if `--title` is not explicitly provided).
: Long release notes (>120 characters or multi-line) are used as the changelog description (only if `--description` is not explicitly provided).
: By default, the behavior is determined by the `extract.release_notes` changelog configuration setting.

`--feature-id <string?>`
: Optional: Feature flag ID
Expand All @@ -49,7 +50,7 @@ docs-builder changelog add [options...] [-h|--help]

`--issues <string[]?>`
: Optional: Issue URL(s) or number(s) (comma-separated), or a path to a newline-delimited file containing issue URLs or numbers. Can be specified multiple times.
: Each occurrence can be either comma-separated issues (e.g., `--issues "https://github.com/owner/repo/issues/123,456"`) or a file path (e.g., `--issues /path/to/file.txt`).
: Each occurrence can be either comma-separated issues (for example `--issues "https://github.com/owner/repo/issues/123,456"`) or a file path (for example `--issues /path/to/file.txt`).
: When specifying issues directly, provide comma-separated values.
: When specifying a file path, provide a single value that points to a newline-delimited file.
: If `--owner` and `--repo` are provided, issue numbers can be used instead of URLs.
Expand All @@ -60,7 +61,7 @@ docs-builder changelog add [options...] [-h|--help]
: Optional: Turn off extraction of linked references.
: When using `--prs`: turns off extraction of linked issues from the PR body (for example, "Fixes #123").
: When using `--issues`: turns off extraction of linked PRs from the issue body (for example, "Fixed by #123").
: By default, linked references are extracted in both cases.
: By default, the behavior is determined by the `extract.issues` changelog configuration setting.

`--output <string?>`
: Optional: Output directory for the changelog fragment. Defaults to current directory.
Expand All @@ -75,7 +76,7 @@ docs-builder changelog add [options...] [-h|--help]

`--prs <string[]?>`
: Optional: Pull request URLs or numbers (comma-separated), or a path to a newline-delimited file containing PR URLs or numbers. Can be specified multiple times.
: Each occurrence can be either comma-separated PRs (e.g., `--prs "https://github.com/owner/repo/pull/123,6789"`) or a file path (e.g., `--prs /path/to/file.txt`).
: Each occurrence can be either comma-separated PRs (for example `--prs "https://github.com/owner/repo/pull/123,6789"`) or a file path (for example `--prs /path/to/file.txt`).
: When specifying PRs directly, provide comma-separated values.
: When specifying a file path, provide a single value that points to a newline-delimited file.
: If `--owner` and `--repo` are provided, PR numbers can be used instead of URLs.
Expand All @@ -90,7 +91,7 @@ docs-builder changelog add [options...] [-h|--help]
`--strip-title-prefix`
: Optional: When used with `--prs`, remove square brackets and text within them from the beginning of PR titles, and also remove a colon if it follows the closing bracket.
: For example, if a PR title is `"[Attack discovery]: Improves Attack discovery hallucination detection"`, the changelog title will be `"Improves Attack discovery hallucination detection"`.
: Multiple square bracket prefixes are also supported (e.g., `"[Discover][ESQL] Fix filtering by multiline string fields"` becomes `"Fix filtering by multiline string fields"`).
: Multiple square bracket prefixes are also supported (for example `"[Discover][ESQL] Fix filtering by multiline string fields"` becomes `"Fix filtering by multiline string fields"`).
: This option applies only when the title is derived from the PR (when `--title` is not explicitly provided).

`--subtype <string?>`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,15 @@ public record CreateChangelogArguments
public bool UsePrNumber { get; init; }
public bool UseIssueNumber { get; init; }
public bool StripTitlePrefix { get; init; }
public bool ExtractReleaseNotes { get; init; }
public bool ExtractIssues { get; init; }
/// <summary>
/// Whether to extract release notes from PR/issue descriptions. null = use config default.
/// </summary>
public bool? ExtractReleaseNotes { get; init; }

/// <summary>
/// Whether to extract linked issues/PRs from PR/issue body. null = use config default.
/// </summary>
public bool? ExtractIssues { get; init; }
}

/// <summary>
Expand Down Expand Up @@ -122,9 +129,12 @@ public async Task<bool> CreateChangelog(IDiagnosticsCollector collector, CreateC
}
}

private static CreateChangelogArguments ApplyConfigDefaults(CreateChangelogArguments input, ChangelogConfiguration _) =>
// Config defaults are already handled by CLI layer, but this ensures service layer has proper defaults too
input;
private static CreateChangelogArguments ApplyConfigDefaults(CreateChangelogArguments input, ChangelogConfiguration config) =>
input with
{
ExtractReleaseNotes = input.ExtractReleaseNotes ?? config.Extract.ReleaseNotes,
ExtractIssues = input.ExtractIssues ?? config.Extract.Issues
};

/// <summary>
/// Infers products from configuration defaults or git repository name.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public async Task<IssueProcessingResult> ProcessIssueAsync(
{
var derived = new DerivedPrFields();

if (input.ExtractReleaseNotes)
if (input.ExtractReleaseNotes ?? false)
{
var (releaseNoteTitle, releaseNoteDescription) = ReleaseNotesExtractor.ExtractReleaseNotes(issueInfo.Body);

Expand Down Expand Up @@ -176,7 +176,7 @@ public async Task<IssueProcessingResult> ProcessIssueAsync(
: [issueUrl];

// Extract linked PRs from issue body
if (input.ExtractIssues && issueInfo.LinkedPrs.Count > 0)
if ((input.ExtractIssues ?? false) && issueInfo.LinkedPrs.Count > 0)
{
derived.Prs = issueInfo.LinkedPrs.ToArray();
logger.LogInformation("Extracted {Count} linked PRs from issue body: {Prs}",
Expand Down
4 changes: 2 additions & 2 deletions src/services/Elastic.Changelog/Creation/PrInfoProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public async Task<PrProcessingResult> ProcessPrAsync(
var derived = new DerivedPrFields();

// Extract release notes from PR body if requested
if (input.ExtractReleaseNotes)
if (input.ExtractReleaseNotes ?? false)
{
var (releaseNoteTitle, releaseNoteDescription) = ReleaseNotesExtractor.ExtractReleaseNotes(prInfo.Body);

Expand Down Expand Up @@ -181,7 +181,7 @@ public async Task<PrProcessingResult> ProcessPrAsync(
logger.LogDebug("Using explicitly provided highlight value, ignoring PR labels");

// Extract linked issues from PR body if config enabled and issues not provided
if (input.ExtractIssues && (input.Issues == null || input.Issues.Length == 0))
if ((input.ExtractIssues ?? false) && (input.Issues == null || input.Issues.Length == 0))
{
if (prInfo.LinkedIssues.Count > 0)
{
Expand Down
9 changes: 5 additions & 4 deletions src/tooling/docs-builder/Commands/ChangelogCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,9 @@ public async Task<int> Create(
parsedPrs = allPrs.ToArray();
}

var shouldExtractReleaseNotes = !noExtractReleaseNotes;
var shouldExtractIssues = !noExtractIssues;
// null = use config default; explicit false when --no-extract-* passed
var extractReleaseNotes = noExtractReleaseNotes ? false : (bool?)null;
var extractIssues = noExtractIssues ? false : (bool?)null;

// Parse issues: handle both comma-separated values and file paths (mirrors PR parsing)
string[]? parsedIssues = null;
Expand Down Expand Up @@ -378,8 +379,8 @@ public async Task<int> Create(
UsePrNumber = usePrNumber,
UseIssueNumber = useIssueNumber,
StripTitlePrefix = stripTitlePrefix,
ExtractReleaseNotes = shouldExtractReleaseNotes,
ExtractIssues = shouldExtractIssues
ExtractReleaseNotes = extractReleaseNotes,
ExtractIssues = extractIssues
};

serviceInvoker.AddCommand(service, input,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -404,4 +404,69 @@ public async Task CreateChangelog_WithExtractReleaseNotes_ExplicitDescription_Ta
yamlContent.Should().Contain("description: Custom description");
yamlContent.Should().NotContain(longReleaseNote);
}

[Fact]
public async Task CreateChangelog_WhenExtractNotSpecifiedByCli_UsesConfigExtractReleaseNotes()
{
// When CLI does not pass --no-extract-release-notes, config extract.release_notes applies.
// Config has release_notes: false, so PR title is used instead of extracted release note.

var prInfo = new GitHubPrInfo
{
Title = "Implement new aggregation API",
Body = "## Summary\n\nThis PR adds a new feature.\n\nRelease Notes: Adds support for new aggregation types",
Labels = ["type:feature"]
};

A.CallTo(() => MockGitHubService.FetchPrInfoAsync(
"https://github.com/elastic/elasticsearch/pull/12345",
null,
null,
A<CancellationToken>._))
.Returns(prInfo);

// language=yaml
var configContent =
"""
extract:
release_notes: false
pivot:
types:
feature: "type:feature"
bug-fix:
breaking-change:
lifecycles:
- preview
- beta
- ga
""";
var configPath = await CreateConfigDirectory(configContent);

var service = CreateService();

var input = new CreateChangelogArguments
{
Prs = ["https://github.com/elastic/elasticsearch/pull/12345"],
Products = [new ProductArgument { Product = "elasticsearch", Target = "9.2.0", Lifecycle = "ga" }],
Config = configPath,
Output = CreateOutputDirectory(),
ExtractReleaseNotes = null // CLI did not specify; config default applies
};

// Act
var result = await service.CreateChangelog(Collector, input, TestContext.Current.CancellationToken);

// Assert - config says don't extract, so PR title is used
result.Should().BeTrue();
Collector.Errors.Should().Be(0);

var outputDir = input.Output ?? FileSystem.Directory.GetCurrentDirectory();
FileSystem.Directory.CreateDirectory(outputDir);
var files = FileSystem.Directory.GetFiles(outputDir, "*.yaml");
files.Should().HaveCount(1);

var yamlContent = await FileSystem.File.ReadAllTextAsync(files[0], TestContext.Current.CancellationToken);
yamlContent.Should().Contain("title: Implement new aggregation API");
yamlContent.Should().NotContain("Adds support for new aggregation types");
}
}
Loading