-
Notifications
You must be signed in to change notification settings - Fork 1.9k
chore(ci): move changelog fragment validation to vdev/Rust #23702
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
pront
wants to merge
22
commits into
master
Choose a base branch
from
pront-convert-changelog-fragments-to-rust
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
c37dbdc
chore(ci): move changelog fragment validation to vdev/Rust
pront 3c43893
update workflow
pront 12f5731
ran cargo fmt
pront 8dd8ed4
rmv bash script
pront 8a0c41e
replace mentions of old script
pront 1317af5
teaks
pront 1d7a0ca
Merge branch 'master' into pront-convert-changelog-fragments-to-rust
pront 1590128
Merge branch 'master' into pront-convert-changelog-fragments-to-rust
pront 1e4a6f9
bininstall vdev
pront dad225a
test - add invalid changelog fragment
pront 06ff6a7
test - add valid fragment
pront ce641d0
test - remove invalid fragment
pront b171295
rmv trailing spaces
pront 8b7320b
Revert "test - add valid fragment"
pront 0331086
add to REQUIRES_RUSTUP
pront 4cfe8ba
Merge branch 'master' into pront-convert-changelog-fragments-to-rust
pront 9c08727
Add pull_request trigger to debug changes
thomasqueirozb d4c2b0a
Checkout prepare.sh
thomasqueirozb 3f26fe1
Add SHOULD_RUN == 'true' to prepare step
thomasqueirozb 044a445
REVERT ME - checkout prepare.sh from branch
thomasqueirozb 4a160e0
Checkout release-flags.sh from master
thomasqueirozb f917ff1
Checkout binstall from master
thomasqueirozb File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -49,6 +49,7 @@ Modules: | |
wasm-pack | ||
markdownlint | ||
datadog-ci | ||
vdev | ||
|
||
If a module requires rust then rustup will be automatically installed. | ||
By default, all modules are installed. To install only a subset: | ||
|
@@ -77,7 +78,7 @@ contains_module() { | |
# Always ensure git safe.directory is set | ||
git config --global --add safe.directory "$(pwd)" | ||
|
||
REQUIRES_RUSTUP=(dd-rust-license-tool cargo-deb cross cargo-nextest cargo-deny cargo-msrv wasm-pack) | ||
REQUIRES_RUSTUP=(dd-rust-license-tool cargo-deb cross cargo-nextest cargo-deny cargo-msrv wasm-pack vdev) | ||
|
||
REQUIRES_BINSTALL=("${REQUIRES_RUSTUP[@]}") | ||
unset -v 'REQUIRES_BINSTALL[0]' # remove dd-rust-license-tool | ||
|
@@ -169,3 +170,9 @@ if contains_module datadog-ci; then | |
sudo npm install -g @datadog/[email protected] | ||
fi | ||
fi | ||
|
||
pront marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if contains_module vdev; then | ||
if [[ "$(vdev --version 2>/dev/null)" != "vdev 0.1.0" ]]; then | ||
rustup run stable cargo "${install[@]}" vdev --version 0.1.0 --force --locked | ||
fi | ||
fi |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
use crate::git::added_files_against_merge_base; | ||
use crate::path_utils::get_changelog_dir; | ||
use anyhow::{anyhow, Context, Result}; | ||
use std::ffi::OsStr; | ||
use std::path::{Path, PathBuf}; | ||
|
||
const FRAGMENT_TYPES: &[&str] = &[ | ||
"breaking", | ||
"security", | ||
"deprecation", | ||
"feature", | ||
"enhancement", | ||
"fix", | ||
]; | ||
|
||
const DEFAULT_MAX_FRAGMENTS: usize = 1000; | ||
|
||
/// Validate changelog fragments added in this branch/PR. | ||
#[derive(clap::Args, Debug)] | ||
#[command()] | ||
pub struct Cli { | ||
/// Changelog directory (defaults to `changelog.d`) | ||
#[arg(long)] | ||
changelog_dir: Option<PathBuf>, | ||
|
||
/// Merge base to diff against (defaults to `origin/master`) | ||
#[arg(long)] | ||
merge_base: Option<String>, | ||
|
||
/// Max fragments threshold (defaults to `1000`) | ||
#[arg(long)] | ||
max_fragments: Option<usize>, | ||
} | ||
|
||
impl Cli { | ||
pub fn exec(&self) -> Result<()> { | ||
let changelog_dir = self | ||
.changelog_dir.clone().unwrap_or_else(get_changelog_dir); | ||
|
||
if !changelog_dir.is_dir() { | ||
error!( | ||
"No ./{} found. This tool must be invoked from the root of the repo.", | ||
changelog_dir.display() | ||
); | ||
std::process::exit(1); | ||
} | ||
|
||
let merge_base = self | ||
.merge_base.clone() | ||
.unwrap_or_else(|| "origin/master".to_string()); | ||
|
||
let max_fragments: usize = self | ||
.max_fragments | ||
.unwrap_or(DEFAULT_MAX_FRAGMENTS); | ||
|
||
let fragments = added_files_against_merge_base(&merge_base, &changelog_dir) | ||
.context("failed to collect added changelog fragments")?; | ||
|
||
if fragments.is_empty() { | ||
info!("No changelog fragments detected"); | ||
info!("If no changes necessitate user-facing explanations, add the GH label 'no-changelog'"); | ||
info!("Otherwise, add changelog fragments to {}/", changelog_dir.display()); | ||
info!("For details, see '{}/README.md'", changelog_dir.display()); | ||
std::process::exit(1); | ||
} | ||
|
||
if fragments.len() > max_fragments { | ||
error!("Too many changelog fragments ({} > {max_fragments}).", fragments.len()); | ||
std::process::exit(1); | ||
} | ||
|
||
for path in fragments { | ||
if let Some(name) = path.file_name().and_then(OsStr::to_str) { | ||
if name == "README.md" { | ||
continue; | ||
} | ||
info!("Validating `{name}`"); | ||
validate_fragment_filename(name)?; | ||
validate_fragment_contents(&changelog_dir.join(name), name)?; | ||
} else { | ||
return Err(anyhow!("unexpected path (no filename): {}", path.display())); | ||
} | ||
} | ||
|
||
info!("changelog additions are valid."); | ||
Ok(()) | ||
} | ||
} | ||
|
||
fn validate_fragment_filename(filename: &str) -> Result<()> { | ||
// Expected: <unique_name>.<fragment_type>.md | ||
let parts: Vec<&str> = filename.split('.').collect(); | ||
if parts.len() != 3 { | ||
return Err(anyhow!( | ||
"invalid fragment filename: {filename} - wrong number of period delimiters. \ | ||
expected '<unique_name>.<fragment_type>.md'", | ||
)); | ||
} | ||
|
||
let fragment_type = parts[1]; | ||
if !FRAGMENT_TYPES.contains(&fragment_type) { | ||
return Err(anyhow!( | ||
"invalid fragment filename: {filename} - fragment type must be one of: {})", | ||
FRAGMENT_TYPES.join("|"), | ||
)); | ||
} | ||
|
||
if parts[2] != "md" { | ||
return Err(anyhow!( | ||
"invalid fragment filename: {filename} - extension must be markdown (.md)", | ||
)); | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
fn validate_fragment_contents(path: &Path, filename: &str) -> Result<()> { | ||
let content = std::fs::read_to_string(path).with_context(|| { | ||
format!("failed to read fragment file: {}", path.to_string_lossy()) | ||
})?; | ||
|
||
// Use last non-empty line to avoid false negatives due to trailing newline(s). | ||
let last_line = content.lines().rev().find(|l| !l.trim().is_empty()).unwrap_or(""); | ||
|
||
if !last_line.starts_with("authors:") { | ||
return Err(anyhow!("last line must start with 'authors: ' and include at least one name. ({filename})")); | ||
} | ||
|
||
// Split on the first colon, take the remainder as names | ||
let names = last_line.split_once(':').map_or("", |(_, rest)| rest.trim()); | ||
|
||
if names.is_empty() { | ||
return Err(anyhow!( | ||
"author line is empty. ({})", | ||
filename | ||
)); | ||
} | ||
|
||
if names.contains('@') { | ||
return Err(anyhow!("author should not be prefixed with @")); | ||
} | ||
|
||
if names.contains(',') { | ||
return Err(anyhow!("authors should be space delimited, not comma delimited.")); | ||
} | ||
|
||
Ok(()) | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reminder: this change needs to be reverted before merging