blob: 99583315cd93f16adf44d04ef70bbc3a70d0adea [file] [log] [blame]
Mohammed Naser7f6414c2025-02-17 16:02:00 -05001use clap::Parser;
2use imagebumper::clients::ClientSet;
3use imagebumper::repository::Repository;
4use log::error;
5use log::{info, warn};
6use regex::Regex;
7use std::collections::HashMap;
8use std::path::{Path, PathBuf};
9use tokio::fs;
10use tokio::io::AsyncWriteExt;
11
12#[derive(Parser, Debug)]
13#[clap(author, version, about)]
14struct Args {
15 #[clap(short, long)]
16 branch: String,
17
18 #[clap(required = true)]
19 files: Vec<PathBuf>,
20}
21
22fn get_repo_map(clientset: &ClientSet) -> HashMap<&'static str, Repository> {
23 let mut map = HashMap::new();
24
25 map.insert(
26 "BARBICAN_GIT_REF",
27 Repository::from_url(clientset, "https://opendev.org/openstack/barbican.git").unwrap(),
28 );
29 map.insert(
30 "CINDER_GIT_REF",
31 Repository::from_url(clientset, "https://opendev.org/openstack/cinder.git").unwrap(),
32 );
33 map.insert(
34 "DESIGNATE_GIT_REF",
35 Repository::from_url(clientset, "https://opendev.org/openstack/designate.git").unwrap(),
36 );
37 map.insert(
38 "GLANCE_GIT_REF",
39 Repository::from_url(clientset, "https://opendev.org/openstack/glance.git").unwrap(),
40 );
41 map.insert(
42 "HEAT_GIT_REF",
43 Repository::from_url(clientset, "https://opendev.org/openstack/heat.git").unwrap(),
44 );
45 map.insert(
46 "HORIZON_GIT_REF",
47 Repository::from_url(clientset, "https://opendev.org/openstack/horizon.git").unwrap(),
48 );
49 map.insert(
50 "IRONIC_GIT_REF",
51 Repository::from_url(clientset, "https://opendev.org/openstack/ironic.git").unwrap(),
52 );
53 map.insert(
54 "KEYSTONE_GIT_REF",
55 Repository::from_url(clientset, "https://opendev.org/openstack/keystone.git").unwrap(),
56 );
57 map.insert(
58 "KUBERNETES_ENTRYPOINT_GIT_REF",
59 Repository::from_url(clientset, "https://opendev.org/airship/kubernetes-entrypoint").unwrap(),
60 );
61 map.insert(
62 "MAGNUM_GIT_REF",
63 Repository::from_url(clientset, "https://opendev.org/openstack/magnum.git").unwrap(),
64 );
65 map.insert(
66 "MANILA_GIT_REF",
67 Repository::from_url(clientset, "https://opendev.org/openstack/manila.git").unwrap(),
68 );
69 map.insert(
70 "NETOFFLOAD_GIT_REF",
71 Repository::from_url(clientset, "https://github.com/vexxhost/netoffload.git").unwrap(),
72 );
73 map.insert(
74 "NEUTRON_GIT_REF",
75 Repository::from_url(clientset, "https://opendev.org/openstack/neutron.git").unwrap(),
76 );
77 map.insert(
78 "NEUTRON_VPNAAS_GIT_REF",
79 Repository::from_url(clientset, "https://opendev.org/openstack/neutron-vpnaas.git").unwrap(),
80 );
81 map.insert(
82 "NETWORKING_BAREMETAL_GIT_REF",
83 Repository::from_url(clientset, "https://opendev.org/openstack/networking-baremetal.git").unwrap(),
84 );
85 map.insert(
86 "POLICY_SERVER_GIT_REF",
87 Repository::from_url(clientset, "https://github.com/vexxhost/neutron-policy-server.git").unwrap(),
88 );
89 map.insert(
90 "LOG_PASER_GIT_REF",
91 Repository::from_url(clientset, "https://github.com/vexxhost/neutron-ovn-network-logging-parser.git")
92 .unwrap(),
93 );
94 map.insert(
95 "NOVA_GIT_REF",
96 Repository::from_url(clientset, "https://opendev.org/openstack/nova.git").unwrap(),
97 );
98 map.insert(
99 "SCHEDULER_FILTERS_GIT_REF",
100 Repository::from_url(clientset, "https://github.com/vexxhost/nova-scheduler-filters.git").unwrap(),
101 );
102 map.insert(
103 "OCTAVIA_GIT_REF",
104 Repository::from_url(clientset, "https://opendev.org/openstack/octavia.git").unwrap(),
105 );
106 map.insert(
107 "REQUIREMENTS_GIT_REF",
108 Repository::from_url(clientset, "https://opendev.org/openstack/requirements.git").unwrap(),
109 );
110 map.insert(
111 "PLACEMENT_GIT_REF",
112 Repository::from_url(clientset, "https://opendev.org/openstack/placement.git").unwrap(),
113 );
114 map.insert(
115 "STAFFELN_GIT_REF",
116 Repository::from_url(clientset, "https://github.com/vexxhost/staffeln.git").unwrap(),
117 );
118 map.insert(
119 "TEMPEST_GIT_REF",
120 Repository::from_url(clientset, "https://opendev.org/openstack/tempest.git").unwrap(),
121 );
122
123 map
124}
125
126async fn update_dockerfile(clientset: &ClientSet, path: &Path, branch: &str) -> Result<(), Box<dyn std::error::Error>> {
127 let content = fs::read_to_string(path).await?;
128 let re = Regex::new(r"(ARG\s+(\w+_GIT_REF)=)(\S+)")?;
129 let mut new_content = content.clone();
130
131 for cap in re.captures_iter(&content) {
132 let arg_name = cap.get(2).unwrap().as_str();
133 if let Some(repo) = get_repo_map(clientset).get(arg_name) {
134 let new_git_ref = match repo.get_latest_commit(branch).await {
135 Ok(commit) => commit,
136 Err(e) => {
137 error!(arg = arg_name, error = e.to_string().as_str().trim(); "Failed to get latest commit");
138 continue;
139 }
140 };
141
142 new_content = new_content.replace(
143 &format!("{}{}", &cap[1], &cap[3]),
144 &format!("{}{}", &cap[1], new_git_ref),
145 );
146
147 info!(arg = arg_name, path = path.to_str(), ref = new_git_ref.as_str(); "Updated Dockerfile");
148 } else {
149 error!(arg = arg_name; "No repository URL found.");
150 }
151 }
152
153 if new_content != content {
154 let mut file = fs::File::create(path).await?;
155 file.write_all(new_content.as_bytes()).await?;
156 }
157 Ok(())
158}
159
160#[tokio::main]
161async fn main() -> Result<(), Box<dyn std::error::Error>> {
162 env_logger::init();
163 let args = Args::parse();
164
165 let clientset = ClientSet::new();
166
167 for file_path in args.files {
168 if file_path.is_file() {
169 update_dockerfile(&clientset, &file_path, &args.branch).await?;
170 } else {
171 warn!("{:?} is not a file, skipping", file_path);
172 }
173 }
174
175 Ok(())
176}