Skip to content
Open
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
38 changes: 32 additions & 6 deletions src/services/Elastic.Documentation.Services/ChangelogService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -393,12 +393,38 @@ Cancel ctx
_ = _fileSystem.Directory.CreateDirectory(outputDir);
}

// Generate filename (timestamp-slug.yaml)
var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
var slug = string.IsNullOrWhiteSpace(input.Title)
? (prUrl != null ? $"pr-{prUrl.Replace("/", "-").Replace(":", "-")}" : "changelog")
: SanitizeFilename(input.Title);
var filename = $"{timestamp}-{slug}.yaml";
// Generate filename
string filename;
if (input.UsePrNumber && !string.IsNullOrWhiteSpace(prUrl))
{
// Use PR number as filename when --use-pr-number is specified
var prNumber = ExtractPrNumber(prUrl, input.Owner, input.Repo);
if (prNumber.HasValue)
{
filename = $"{prNumber.Value}.yaml";
}
else
{
// Fall back to timestamp-slug format if PR number extraction fails
collector.EmitWarning(string.Empty, $"Failed to extract PR number from '{prUrl}'. Falling back to timestamp-based filename.");
var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
var slug = string.IsNullOrWhiteSpace(input.Title)
? $"pr-{prUrl.Replace("/", "-").Replace(":", "-")}"
: SanitizeFilename(input.Title);
filename = $"{timestamp}-{slug}.yaml";
}
}
else
{
// Default: timestamp-slug.yaml
var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
var slug = string.IsNullOrWhiteSpace(input.Title)
? (string.IsNullOrWhiteSpace(prUrl)
? "changelog"
: $"pr-{prUrl.Replace("/", "-").Replace(":", "-")}")
: SanitizeFilename(input.Title);
filename = $"{timestamp}-{slug}.yaml";
}
var filePath = _fileSystem.Path.Combine(outputDir, filename);

// Write file
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,78 @@ public async Task CreateChangelog_WithPrOption_FetchesPrInfoAndDerivesTitle()
yamlContent.Should().Contain("pr: https://github.com/elastic/elasticsearch/pull/12345");
}

[Fact]
public async Task CreateChangelog_WithUsePrNumber_CreatesFileWithPrNumberAsFilename()
{
// Arrange
var mockGitHubService = A.Fake<IGitHubPrService>();
var prInfo = new GitHubPrInfo
{
Title = "Fix memory leak in search",
Labels = ["type:bug"]
};

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

// Create a config file with label mappings
// Note: ChangelogService uses real FileSystem, so we need to use the real file system
var fileSystem = new FileSystem();
var configDir = fileSystem.Path.Combine(fileSystem.Path.GetTempPath(), Guid.NewGuid().ToString());
fileSystem.Directory.CreateDirectory(configDir);
var configPath = fileSystem.Path.Combine(configDir, "changelog.yml");
var configContent = """
available_types:
- feature
- bug-fix
available_subtypes: []
available_lifecycles:
- preview
- beta
- ga
label_to_type:
"type:bug": bug-fix
""";
await fileSystem.File.WriteAllTextAsync(configPath, configContent, TestContext.Current.CancellationToken);

var service = new ChangelogService(_loggerFactory, _configurationContext, mockGitHubService);

var input = new ChangelogInput
{
Prs = ["https://github.com/elastic/elasticsearch/pull/140034"],
Products = [new ProductInfo { Product = "elasticsearch", Target = "9.2.0", Lifecycle = "ga" }],
Config = configPath,
Output = fileSystem.Path.Combine(fileSystem.Path.GetTempPath(), Guid.NewGuid().ToString()),
UsePrNumber = true
};

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

// Assert
result.Should().BeTrue();
_collector.Errors.Should().Be(0);

// Note: ChangelogService uses real FileSystem, so we need to check the actual file system
var outputDir = input.Output ?? Directory.GetCurrentDirectory();
if (!Directory.Exists(outputDir))
Directory.CreateDirectory(outputDir);
var files = Directory.GetFiles(outputDir, "*.yaml");
files.Should().HaveCount(1);

// Verify the filename is the PR number, not a timestamp-based name
var fileName = Path.GetFileName(files[0]);
fileName.Should().Be("140034.yaml", "the filename should be the PR number when UsePrNumber is true");

var yamlContent = await File.ReadAllTextAsync(files[0], TestContext.Current.CancellationToken);
yamlContent.Should().Contain("type: bug-fix");
yamlContent.Should().Contain("pr: https://github.com/elastic/elasticsearch/pull/140034");
}

[Fact]
public async Task CreateChangelog_WithPrOptionAndLabelMapping_MapsLabelsToType()
{
Expand Down
Loading