Skip to content

Commit

Permalink
feat: add contributors to git release body context (#1736)
Browse files Browse the repository at this point in the history
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
MarcoIeni and github-actions[bot] authored Oct 5, 2024
1 parent 6b8b7d0 commit f506b68
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 8 deletions.
49 changes: 45 additions & 4 deletions crates/release_plz_core/src/command/release.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ use crate::{
git::backend::GitClient,
pr_parser::{prs_from_text, Pr},
release_order::release_order,
GitBackend, PackagePath, Project, ReleaseMetadata, ReleaseMetadataBuilder, BRANCH_PREFIX,
CHANGELOG_FILENAME,
GitBackend, PackagePath, Project, ReleaseMetadata, ReleaseMetadataBuilder, Remote,
BRANCH_PREFIX, CHANGELOG_FILENAME,
};

#[derive(Debug)]
Expand Down Expand Up @@ -520,6 +520,7 @@ async fn release_package_if_needed(
git_tag: &git_tag,
release_name: &release_name,
changelog: &changelog,
prs: &prs,
};
for CargoRegistry { name, mut index } in registry_indexes {
let token = input.find_registry_token(name.as_deref())?;
Expand Down Expand Up @@ -613,6 +614,7 @@ struct ReleaseInfo<'a> {
git_tag: &'a str,
release_name: &'a str,
changelog: &'a str,
prs: &'a [Pr],
}

/// Return `true` if package was published, `false` otherwise.
Expand Down Expand Up @@ -663,8 +665,18 @@ async fn release_package(
repo.push(release_info.git_tag)?;
}

let contributors = get_contributors(release_info, git_client).await;

// TODO fill the rest
let remote = Remote {
owner: "".to_string(),
repo: "".to_string(),
link: "".to_string(),
contributors,
};
if input.is_git_release_enabled(&release_info.package.name) {
let release_body = release_body(input, release_info.package, release_info.changelog);
let release_body =
release_body(input, release_info.package, release_info.changelog, &remote);
let release_config = input
.get_package_config(&release_info.package.name)
.git_release;
Expand All @@ -688,6 +700,29 @@ async fn release_package(
}
}

async fn get_contributors(
release_info: &ReleaseInfo<'_>,
git_client: &GitClient,
) -> Vec<git_cliff_core::contributor::RemoteContributor> {
let prs_number = release_info
.prs
.iter()
.map(|pr| pr.number)
.collect::<Vec<_>>();
let contributors = git_client
.get_prs_info(&prs_number)
.await
.inspect_err(|e| tracing::warn!("failed to retrieve contributors: {e}"))
.unwrap_or(vec![])
.iter()
.map(|pr| git_cliff_core::contributor::RemoteContributor {
username: Some(pr.user.login.clone()),
..Default::default()
})
.collect::<Vec<_>>();
contributors
}

fn get_git_client(input: &ReleaseRequest) -> anyhow::Result<GitClient> {
let git_release = input
.git_release
Expand Down Expand Up @@ -766,7 +801,12 @@ fn run_cargo_publish(
}

/// Return an empty string if the changelog cannot be parsed.
fn release_body(req: &ReleaseRequest, package: &Package, changelog: &str) -> String {
fn release_body(
req: &ReleaseRequest,
package: &Package,
changelog: &str,
remote: &Remote,
) -> String {
let body_template = req
.get_package_config(&package.name)
.git_release
Expand All @@ -775,6 +815,7 @@ fn release_body(req: &ReleaseRequest, package: &Package, changelog: &str) -> Str
&package.name,
&package.version.to_string(),
changelog,
remote,
body_template.as_deref(),
)
}
Expand Down
50 changes: 48 additions & 2 deletions crates/release_plz_core/src/git/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ pub struct PrCommit {
pub author: Option<Author>,
}

#[derive(Deserialize)]
#[derive(Deserialize, Clone, Debug)]
pub struct Author {
login: String,
pub login: String,
}

#[derive(Serialize)]
Expand All @@ -82,6 +82,7 @@ pub struct CreateReleaseOption<'a> {

#[derive(Deserialize, Clone, Debug)]
pub struct GitPr {
pub user: Author,
pub number: u64,
pub html_url: Url,
pub head: Commit,
Expand Down Expand Up @@ -112,13 +113,17 @@ impl From<GitLabMr> for GitPr {
},
title: value.title,
body,
user: Author {
login: value.author.username,
},
}
}
}

/// Merge request.
#[derive(Deserialize, Clone, Debug)]
pub struct GitLabMr {
pub author: GitLabAuthor,
pub iid: u64,
pub web_url: Url,
pub sha: String,
Expand All @@ -127,13 +132,21 @@ pub struct GitLabMr {
pub description: String,
}

#[derive(Deserialize, Clone, Debug)]
pub struct GitLabAuthor {
pub username: String,
}

impl From<GitPr> for GitLabMr {
fn from(value: GitPr) -> Self {
let description = match value.body {
Some(d) => d,
None => "".to_string(),
};
GitLabMr {
author: GitLabAuthor {
username: value.user.login,
},
iid: value.number,
web_url: value.html_url,
sha: value.head.sha,
Expand Down Expand Up @@ -415,6 +428,18 @@ impl GitClient {
}
}

async fn pr_from_response(&self, resp: Response) -> anyhow::Result<GitPr> {
match self.backend {
BackendType::Github | BackendType::Gitea => {
resp.json().await.context("failed to parse pr")
}
BackendType::Gitlab => {
let gitlab_mr: GitLabMr = resp.json().await.context("failed to parse gitlab mr")?;
Ok(gitlab_mr.into())
}
}
}

#[instrument(skip(self))]
pub async fn close_pr(&self, pr_number: u64) -> anyhow::Result<()> {
debug!("closing pr #{pr_number}");
Expand Down Expand Up @@ -595,6 +620,27 @@ impl GitClient {
Ok(prs)
}

pub async fn get_pr_info(&self, pr_number: u64) -> anyhow::Result<GitPr> {
let response = self
.client
.get(format!("{}/{}", self.pulls_url(), pr_number))
.send()
.await?
.successful_status()
.await?;

self.pr_from_response(response).await
}

pub async fn get_prs_info(&self, pr_numbers: &[u64]) -> anyhow::Result<Vec<GitPr>> {
let mut prs = vec![];
for pr_number in pr_numbers {
let pr = self.get_pr_info(*pr_number).await?;
prs.push(pr);
}
Ok(prs)
}

pub async fn get_remote_commit(&self, commit: &str) -> Result<RemoteCommit, anyhow::Error> {
let api_path = self.commits_api_path(commit);
let github_commit: GitHubCommit = self
Expand Down
2 changes: 1 addition & 1 deletion crates/release_plz_core/src/pr_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use url::Url;
#[derive(Debug, PartialEq, Serialize)]
pub struct Pr {
html_url: Url,
number: u64,
pub number: u64,
}

/// Parse PRs from text, e.g. a changelog entry.
Expand Down
13 changes: 12 additions & 1 deletion crates/release_plz_core/src/tera.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use crate::Remote;

pub const PACKAGE_VAR: &str = "package";
pub const VERSION_VAR: &str = "version";
pub const CHANGELOG_VAR: &str = "changelog";
pub const REMOTE_VAR: &str = "remote";

pub fn tera_var(var_name: &str) -> String {
format!("{{{{ {var_name} }}}}")
Expand All @@ -10,11 +13,13 @@ pub fn release_body_from_template(
package_name: &str,
version: &str,
changelog: &str,
remote: &Remote,
body_template: Option<&str>,
) -> String {
let mut tera = tera::Tera::default();
let mut context = tera_context(package_name, version);
context.insert(CHANGELOG_VAR, changelog);
context.insert(REMOTE_VAR, remote);

let default_body_template = tera_var(CHANGELOG_VAR);
let body_template = body_template.unwrap_or(&default_body_template);
Expand Down Expand Up @@ -47,7 +52,13 @@ mod tests {
use super::*;
#[test]
fn default_body_template_is_rendered() {
let body = release_body_from_template("my_package", "0.1.0", "my changes", None);
let remote = Remote {
owner: "owner".to_string(),
repo: "repo".to_string(),
link: "link".to_string(),
contributors: vec![],
};
let body = release_body_from_template("my_package", "0.1.0", "my changes", &remote, None);
assert_eq!(body, "my changes");
}
}
21 changes: 21 additions & 0 deletions website/docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,27 @@ In `git_release_body`, you can use the following variables:
- `{{ changelog }}`: the changelog body of the new release.
- `{{ package }}`: the name of the package.
- `{{ version }}`: the new version of the package.
- `{{ release.contributors }}`: array of contributors.
I.e. the username of the authors of the PRs present in the changelog.
This means that your commit messages should contain the PR number, e.g. `(#123)`
or `([#1421](https://github.com/me/proj/pull/1421))`.

:::tip
To list the contributors at the end of the release you can do the following:

```toml
git_release_body = """
{{ changelog }}
{% if remote.contributors %}
### Contributors
{% for contributor in remote.contributors %}
* @{{ contributor.username }}
{% endfor %}
{% endif %}
"""
```

:::

#### The `git_release_type` field

Expand Down

0 comments on commit f506b68

Please sign in to comment.