use anyhow::{Context, Result};
use azure_devops_rust_api::git;
use azure_devops_rust_api::git::models::{
change::ChangeType, item_content::ContentType, Change, GitChange, GitCommitRef, GitPush,
GitRefUpdate, ItemContent,
};
use serde_json::json;
use std::{env, vec};
mod utils;
async fn get_latest_commit_id(
client: &git::Client,
organization: &str,
repository_name: &str,
project: &str,
branch: &str,
) -> Result<String> {
let latest_commit = client
.commits_client()
.get_commits(organization, repository_name, project)
.search_criteria_item_version_version(branch)
.search_criteria_top(1)
.await?
.value;
let latest_commit_id = latest_commit
.first()
.context("No commits found")?
.commit_id
.as_ref()
.context("Missing commit_id")?
.to_string();
Ok(latest_commit_id)
}
fn new_git_change_with_content(
change_type: ChangeType,
filename: &str,
file_content: impl Into<String>,
) -> GitChange {
let file_content = file_content.into();
GitChange {
change: Change {
change_type,
item: Some(json!({
"path": filename
})),
new_content: Some(ItemContent {
content: file_content,
content_type: ContentType::RawText,
}),
source_server_item: None,
url: None,
},
change_id: None,
new_content_template: None,
original_path: None,
}
}
fn new_git_ref_update(base_commit_id: String, target_branch: &str) -> GitRefUpdate {
GitRefUpdate {
name: Some(format!("refs/heads/{target_branch}")),
old_object_id: Some(base_commit_id),
..Default::default()
}
}
#[tokio::main]
async fn main() -> Result<()> {
let credential = utils::get_credential()?;
let organization = env::var("ADO_ORGANIZATION").expect("Must define ADO_ORGANIZATION");
let repository_name = env::args()
.nth(1)
.expect("Usage: git_push <repository-name> <source-branch> <target-branch> <filename> <file-content>");
let source_branch = env::args()
.nth(2)
.expect("Usage: git_push <repository-name> <source-branch> <target-branch> <filename> <file-content>");
let target_branch = env::args()
.nth(3)
.expect("Usage: git_push <repository-name> <source-branch> <target-branch> <filename> <file-content>");
let filename = env::args()
.nth(4)
.expect("Usage: git_push <repository-name> <source-branch> <target-branch> <filename> <file-content>");
let file_content = env::args()
.nth(5)
.expect("Usage: git_push <repository-name> <source-branch> <target-branch> <filename> <file-content>");
let project = env::var("ADO_PROJECT").expect("Must define ADO_PROJECT");
let git_client = git::ClientBuilder::new(credential).build();
let base_commit_id = get_latest_commit_id(
&git_client,
&organization,
&repository_name,
&project,
&source_branch,
)
.await?;
println!("base_commit_id: {base_commit_id}");
let ref_update = new_git_ref_update(base_commit_id, &target_branch);
let change = new_git_change_with_content(ChangeType::Edit, &filename, &file_content);
let commits = vec![GitCommitRef {
comment: Some(String::from("This is a commit via the Azure DevOps API...")),
changes: vec![change],
..Default::default()
}];
let push_request = GitPush {
commits,
ref_updates: vec![ref_update],
..Default::default()
};
let push_response = git_client
.pushes_client()
.create(&organization, push_request, &repository_name, &project)
.await?;
println!("Pushed commit.\npush_response: {push_response:#?}");
Ok(())
}