1use rustic_git::{Repository, Result, TagOptions, TagType};
13use std::env;
14use std::fs;
15
16fn main() -> Result<()> {
17 println!("Rustic Git - Tag Operations Example\n");
18
19 let repo_path = env::temp_dir().join("rustic_git_tag_example");
21
22 if repo_path.exists() {
24 fs::remove_dir_all(&repo_path).expect("Failed to clean up previous example");
25 }
26
27 println!("Initializing repository at: {}", repo_path.display());
28
29 let repo = Repository::init(&repo_path, false)?;
31 repo.config()
32 .set_user("Tag Demo User", "tags@example.com")?;
33
34 println!("\nCreating initial commits...");
36
37 fs::write(
39 repo_path.join("README.md"),
40 "# Tag Demo Project\n\nDemonstrating Git tag operations.\n",
41 )?;
42 repo.add(&["README.md"])?;
43 let first_commit_hash = repo.commit("Initial commit: Add README")?;
44 println!("Created commit: {}", first_commit_hash.short());
45
46 fs::create_dir_all(repo_path.join("src"))?;
48 fs::write(
49 repo_path.join("src/main.rs"),
50 "fn main() {\n println!(\"Hello, tags!\");\n}\n",
51 )?;
52 repo.add(&["src/main.rs"])?;
53 let second_commit_hash = repo.commit("Add main.rs with hello world")?;
54 println!("Created commit: {}", second_commit_hash.short());
55
56 fs::write(
58 repo_path.join("src/lib.rs"),
59 "//! Tag demo library\n\npub fn greet(name: &str) -> String {\n format!(\"Hello, {}!\", name)\n}\n",
60 )?;
61 repo.add(&["src/lib.rs"])?;
62 let third_commit_hash = repo.commit("Add library with greet function")?;
63 println!("Created commit: {}", third_commit_hash.short());
64
65 println!("\n=== Creating Tags ===");
67
68 println!("\n1. Creating lightweight tags:");
70
71 let v0_1_0 = repo.create_tag("v0.1.0", Some(&first_commit_hash))?;
72 println!(
73 "Created lightweight tag: {} -> {} ({})",
74 v0_1_0.name,
75 v0_1_0.hash.short(),
76 v0_1_0.tag_type
77 );
78
79 let v0_2_0 = repo.create_tag("v0.2.0", Some(&second_commit_hash))?;
80 println!(
81 "Created lightweight tag: {} -> {} ({})",
82 v0_2_0.name,
83 v0_2_0.hash.short(),
84 v0_2_0.tag_type
85 );
86
87 println!("\n2. Creating annotated tags:");
89
90 let options =
91 TagOptions::new().with_message("First stable release with basic functionality".to_string());
92 let v1_0_0 = repo.create_tag_with_options("v1.0.0", Some(&third_commit_hash), options)?;
93 println!(
94 "Created annotated tag: {} -> {} ({})",
95 v1_0_0.name,
96 v1_0_0.hash.short(),
97 v1_0_0.tag_type
98 );
99 if let Some(message) = &v1_0_0.message {
100 println!(" Message: {}", message);
101 }
102
103 let latest_options = TagOptions::new().with_message("Latest development version".to_string());
105 let latest_tag = repo.create_tag_with_options("latest", None, latest_options)?;
106 println!(
107 "Created annotated tag on HEAD: {} -> {} ({})",
108 latest_tag.name,
109 latest_tag.hash.short(),
110 latest_tag.tag_type
111 );
112
113 println!("\n3. Creating feature and release candidate tags:");
115
116 let feature_options = TagOptions::new().with_message("Feature branch snapshot".to_string());
117 repo.create_tag_with_options("feature/demo", None, feature_options)?;
118
119 let rc_options = TagOptions::new().with_message("Release candidate for v1.1.0".to_string());
120 repo.create_tag_with_options("v1.1.0-rc1", None, rc_options)?;
121
122 repo.create_tag("v0.3.0", None)?;
124 repo.create_tag("v0.9.0", None)?;
125
126 println!("\n=== Tag Listing and Filtering ===");
128
129 let tags = repo.tags()?;
130 println!("\nAll tags ({} total):", tags.len());
131 for tag in tags.iter() {
132 let type_marker = match tag.tag_type {
133 TagType::Lightweight => "L",
134 TagType::Annotated => "A",
135 };
136 println!(" [{}] {} -> {}", type_marker, tag.name, tag.hash.short());
137 if let Some(message) = &tag.message {
138 println!(" Message: {}", message.lines().next().unwrap_or(""));
139 }
140 }
141
142 println!("\nLightweight tags ({} total):", tags.lightweight_count());
144 for tag in tags.lightweight() {
145 println!(" {} -> {}", tag.name, tag.hash.short());
146 }
147
148 println!("\nAnnotated tags ({} total):", tags.annotated_count());
149 for tag in tags.annotated() {
150 println!(" {} -> {}", tag.name, tag.hash.short());
151 if let Some(message) = &tag.message {
152 println!(" Message: {}", message.lines().next().unwrap_or(""));
153 }
154 }
155
156 println!("\n=== Tag Searching ===");
158
159 if let Some(tag) = tags.find("v1.0.0") {
161 println!("\nFound tag 'v1.0.0':");
162 println!(" Type: {}", tag.tag_type);
163 println!(" Hash: {}", tag.hash.short());
164 if let Some(message) = &tag.message {
165 println!(" Message: {}", message);
166 }
167 }
168
169 let version_tags: Vec<_> = tags.find_containing("v").collect();
171 println!(
172 "\nVersion tags (containing 'v'): {} found",
173 version_tags.len()
174 );
175 for tag in &version_tags {
176 println!(" {}", tag.name);
177 }
178
179 let rc_tags: Vec<_> = tags.find_containing("rc").collect();
181 println!("\nRelease candidate tags: {} found", rc_tags.len());
182 for tag in &rc_tags {
183 println!(" {}", tag.name);
184 }
185
186 let tags_for_third_commit: Vec<_> = tags.for_commit(&third_commit_hash).collect();
188 println!(
189 "\nTags pointing to commit {}: {} found",
190 third_commit_hash.short(),
191 tags_for_third_commit.len()
192 );
193 for tag in &tags_for_third_commit {
194 println!(" {}", tag.name);
195 }
196
197 println!("\n=== Tag Details ===");
199
200 let detailed_tag = repo.show_tag("v1.0.0")?;
201 println!("\nDetailed information for 'v1.0.0':");
202 println!(" Name: {}", detailed_tag.name);
203 println!(" Type: {}", detailed_tag.tag_type);
204 println!(" Commit: {}", detailed_tag.hash);
205 println!(" Short hash: {}", detailed_tag.hash.short());
206
207 if let Some(message) = &detailed_tag.message {
208 println!(" Message: {}", message);
209 }
210
211 if let Some(tagger) = &detailed_tag.tagger {
212 println!(" Tagger: {}", tagger);
213 println!(
214 " Tagged at: {}",
215 tagger.timestamp.format("%Y-%m-%d %H:%M:%S UTC")
216 );
217 }
218
219 if let Some(timestamp) = &detailed_tag.timestamp {
220 println!(" Timestamp: {}", timestamp.format("%Y-%m-%d %H:%M:%S UTC"));
221 }
222
223 println!("\n=== Tag Operations ===");
225
226 println!("\n1. Testing tag overwrite:");
228
229 match repo.create_tag("latest", None) {
231 Ok(_) => println!(" ERROR: Should have failed to create existing tag"),
232 Err(e) => println!(" Expected error creating existing tag: {}", e),
233 }
234
235 let force_options = TagOptions::new()
237 .with_force()
238 .with_message("Forcefully updated latest tag".to_string());
239
240 match repo.create_tag_with_options("latest", None, force_options) {
241 Ok(tag) => println!(" Successfully force-created tag: {}", tag.name),
242 Err(e) => println!(" Error force-creating tag: {}", e),
243 }
244
245 println!("\n2. Testing tag deletion:");
247
248 repo.create_tag("temp-tag", None)?;
250 println!(" Created temporary tag: temp-tag");
251
252 let tags_before = repo.tags()?;
254 let temp_exists_before = tags_before.find("temp-tag").is_some();
255 println!(" Temp tag exists before deletion: {}", temp_exists_before);
256
257 repo.delete_tag("temp-tag")?;
259 println!(" Deleted temp-tag");
260
261 let tags_after = repo.tags()?;
263 let temp_exists_after = tags_after.find("temp-tag").is_some();
264 println!(" Temp tag exists after deletion: {}", temp_exists_after);
265
266 println!("\n=== Summary ===");
268 let final_tags = repo.tags()?;
269 println!("\nFinal repository state:");
270 println!(" Total tags: {}", final_tags.len());
271 println!(" Lightweight tags: {}", final_tags.lightweight_count());
272 println!(" Annotated tags: {}", final_tags.annotated_count());
273
274 println!("\nTag creation options demonstrated:");
275 println!(" ✓ Lightweight tags (simple references)");
276 println!(" ✓ Annotated tags (with messages and metadata)");
277 println!(" ✓ Tags on specific commits");
278 println!(" ✓ Tags on current HEAD");
279 println!(" ✓ Force tag creation/overwrite");
280
281 println!("\nTag listing and filtering demonstrated:");
282 println!(" ✓ List all tags");
283 println!(" ✓ Filter by tag type (lightweight/annotated)");
284 println!(" ✓ Search by name patterns");
285 println!(" ✓ Find tags by commit hash");
286 println!(" ✓ Show detailed tag information");
287
288 println!("\nTag management demonstrated:");
289 println!(" ✓ Tag creation with options");
290 println!(" ✓ Tag deletion");
291 println!(" ✓ Error handling for duplicate tags");
292
293 println!("\nCleaning up example repository...");
295 fs::remove_dir_all(&repo_path)?;
296 println!("Tag operations example completed successfully!");
297
298 Ok(())
299}