120 lines
3.9 KiB
Rust
120 lines
3.9 KiB
Rust
use std::collections::HashSet;
|
|
use std::fs::OpenOptions;
|
|
use std::io::prelude::*;
|
|
use std::io::BufReader;
|
|
use std::path::Path;
|
|
|
|
use reqwest::{Client, StatusCode};
|
|
use serde_json::{json, Value};
|
|
use tokio;
|
|
|
|
#[tokio::main]
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
let jira_base_url = "https://jira.someserver.com";
|
|
let username = "userName";
|
|
let password = "passWord! @#";
|
|
let project_key = "projectKey";
|
|
|
|
let client = Client::new();
|
|
|
|
// 1. Pull a project's component list
|
|
let url = format!("{}/rest/api/2/project/{}/components", jira_base_url, project_key);
|
|
let raw_data = client
|
|
.get(&url)
|
|
.basic_auth(username, Some(password))
|
|
.send()
|
|
.await?
|
|
.json::<Value>()
|
|
.await?;
|
|
|
|
// 2. Create a mapping of component ID, component name, and the assignee name
|
|
let component_data: Vec<Value> = raw_data
|
|
.as_array()
|
|
.unwrap()
|
|
.iter()
|
|
.map(|component| {
|
|
json!({
|
|
"id": component["id"],
|
|
"name": component["name"],
|
|
"assignee": component["assignee"]["name"]
|
|
})
|
|
})
|
|
.collect();
|
|
|
|
// 3. Show a comma-separated list of the usernames and ask which username we want to replace
|
|
let mut usernames: HashSet<String> = HashSet::new();
|
|
for component in &component_data {
|
|
usernames.insert(component["assignee"].as_str().unwrap().to_string());
|
|
}
|
|
println!("Usernames: {}", usernames.iter().cloned().collect::<Vec<String>>().join(", "));
|
|
let mut old_username = String::new();
|
|
println!("Enter the username you want to replace: ");
|
|
std::io::stdin().read_line(&mut old_username)?;
|
|
let old_username = old_username.trim();
|
|
|
|
// 4. Check if the entered username is in the list
|
|
if !usernames.contains(old_username) {
|
|
println!("Username not found in the list. Please select a name from the list.");
|
|
return Ok(());
|
|
}
|
|
|
|
// 5. Ask for the new username
|
|
let mut new_username = String::new();
|
|
println!("Enter the new username: ");
|
|
std::io::stdin().read_line(&mut new_username)?;
|
|
let new_username = new_username.trim();
|
|
|
|
// Create a folder for the source username and history.txt file
|
|
let history_folder = Path::new(old_username);
|
|
std::fs::create_dir_all(&history_folder)?;
|
|
|
|
let history_file_path = history_folder.join("history.txt");
|
|
let mut history_file = OpenOptions::new()
|
|
.write(true)
|
|
.append(true)
|
|
.create(true)
|
|
.open(&history_file_path)?;
|
|
|
|
// 6. Create a new mapping of the IDs and new assignees we will be changing
|
|
let components_to_update: Vec<&Value> = component_data
|
|
.iter()
|
|
.filter(|component| component["assignee"] == old_username)
|
|
.collect();
|
|
|
|
// 7. Push an update to the Jira Server API to update those component leads
|
|
for component in components_to_update {
|
|
let component_id = component["id"].as_str().unwrap();
|
|
let component_name = component["name"].as_str().unwrap();
|
|
|
|
let url = format!("{}/rest/api/2/component/{}", jira_base_url, component_id);
|
|
let post_data = json!({ "leadUserName": new_username });
|
|
|
|
let res = client
|
|
.put(&url)
|
|
.basic_auth(username, Some(password))
|
|
.json(&post_data)
|
|
.send()
|
|
.await?;
|
|
|
|
if res.status() == StatusCode::OK {
|
|
// Save the changed component ID and timestamp to the history file
|
|
let timestamp = chrono::Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
|
|
let history_entry = format!(
|
|
"Updated component {} ({}) with new assignee {} at {}\n",
|
|
component_name, component_id, new_username, timestamp
|
|
);
|
|
history_file.write_all(history_entry.as_bytes())?;
|
|
} else {
|
|
eprintln!(
|
|
"Failed to update component {} ({}), status code: {}",
|
|
component_name,
|
|
component_id,
|
|
res.status()
|
|
);
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|