-
Notifications
You must be signed in to change notification settings - Fork 20
/
git_push.rs
148 lines (131 loc) · 4.77 KB
/
git_push.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// get_push.rs
// Pushing a commit to a repo.
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;
// Get the latest commit on specified branch of the given repository
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)
}
// Create a new `GitChange` with the specified content
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: 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,
}
}
// Create a new `GitRefUpdate` with the specified base commit id and target branch
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<()> {
// Get authentication credential
let credential = utils::get_credential()?;
// Get ADO server configuration via environment variables
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");
// Create a git client
let git_client = git::ClientBuilder::new(credential).build();
// Get the latest commit id on the specified source branch from the specified repository
let base_commit_id = get_latest_commit_id(
&git_client,
&organization,
&repository_name,
&project,
&source_branch,
)
.await?;
println!("base_commit_id: {}", base_commit_id);
// Define the base commit id and the target branch
let ref_update = new_git_ref_update(base_commit_id, &target_branch);
// Define the change to be pushed.
// In this case, we are replacing the content of the specified file with the provided content.
let change = new_git_change_with_content(ChangeType::Edit, &filename, &file_content);
// Define the commits to be pushed.
// In this case, we are adding a single commit with the specified change.
let commits = vec![GitCommitRef {
comment: Some(String::from("This is a commit via the Azure DevOps API...")),
changes: vec![change],
..Default::default()
}];
// Define the push request.
// In this case, we are pushing the commit to a new branch.
let push_request = GitPush {
commits,
ref_updates: vec![ref_update],
..Default::default()
};
// Execute the push request.
let push_response = git_client
.pushes_client()
.create(&organization, push_request, &repository_name, &project)
.await?;
println!("Pushed commit.\npush_response: {:#?}", push_response);
Ok(())
}