1use std::collections::HashMap;
2
3use next_version::{NextVersion as NextVersionTrait, VersionUpdater};
4use semver::Version;
5use serde::{Deserialize, Serialize};
6use serde_json::value::Value;
7
8use crate::commit::{Commit, Range, commits_to_conventional_commits};
9use crate::config::{Bump, BumpType};
10use crate::error::Result;
11use crate::statistics::Statistics;
12#[cfg(feature = "remote")]
13use crate::{
14 contributor::RemoteContributor,
15 remote::{RemoteCommit, RemotePullRequest, RemoteReleaseMetadata},
16};
17
18#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
20#[serde(rename_all(serialize = "camelCase"))]
21pub struct Release<'a> {
22 pub version: Option<String>,
24 pub message: Option<String>,
26 #[serde(deserialize_with = "commits_to_conventional_commits")]
28 pub commits: Vec<Commit<'a>>,
29 #[serde(rename = "commit_id")]
31 pub commit_id: Option<String>,
32 pub timestamp: Option<i64>,
34 pub previous: Option<Box<Release<'a>>>,
36 pub repository: Option<String>,
38 #[serde(rename = "commit_range")]
40 pub commit_range: Option<Range>,
41 #[serde(rename = "submodule_commits")]
45 pub submodule_commits: HashMap<String, Vec<Commit<'a>>>,
46 pub statistics: Option<Statistics>,
48 pub extra: Option<Value>,
50 #[serde(rename = "bump_type")]
52 pub bump_type: Option<BumpType>,
53 #[cfg(feature = "github")]
55 pub github: RemoteReleaseMetadata,
56 #[cfg(feature = "gitlab")]
58 pub gitlab: RemoteReleaseMetadata,
59 #[cfg(feature = "gitea")]
61 pub gitea: RemoteReleaseMetadata,
62 #[cfg(feature = "bitbucket")]
64 pub bitbucket: RemoteReleaseMetadata,
65 #[cfg(feature = "azure_devops")]
67 #[serde(rename = "azure_devops")]
68 pub azure_devops: RemoteReleaseMetadata,
69}
70
71#[cfg(feature = "github")]
72crate::update_release_metadata!(github, update_github_metadata);
73
74#[cfg(feature = "gitlab")]
75crate::update_release_metadata!(gitlab, update_gitlab_metadata);
76
77#[cfg(feature = "gitea")]
78crate::update_release_metadata!(gitea, update_gitea_metadata);
79
80#[cfg(feature = "bitbucket")]
81crate::update_release_metadata!(bitbucket, update_bitbucket_metadata);
82
83#[cfg(feature = "azure_devops")]
84crate::update_release_metadata!(azure_devops, update_azure_devops_metadata);
85
86impl Release<'_> {
87 #[cfg_attr(
92 feature = "tracing",
93 tracing::instrument(
94 skip_all,
95 fields(
96 version = self.version.as_deref().unwrap_or("unreleased"),
97 commits = self.commits.len()
98 )
99 )
100 )]
101 pub fn calculate_next_version(&self) -> Result<NextVersion> {
102 crate::set_progress_message!("Calculating the next version from commits");
103 self.calculate_next_version_with_config(&Bump::default())
104 }
105
106 #[must_use]
112 pub fn with_statistics(mut self) -> Self {
113 self.statistics = Some((&self).into());
114 self
115 }
116
117 pub(super) fn calculate_next_version_with_config(&self, config: &Bump) -> Result<NextVersion> {
122 self.calculate_next_version_from_commits(config, true)
123 }
124
125 #[cfg_attr(
133 feature = "tracing",
134 tracing::instrument(
135 skip_all,
136 fields(
137 version = self.version.as_deref().unwrap_or("unreleased"),
138 commits = self.commits.len()
139 )
140 )
141 )]
142 pub(super) fn calculate_next_version_from_commits(
143 &self,
144 config: &Bump,
145 conventional_commits: bool,
146 ) -> Result<NextVersion> {
147 crate::set_progress_message!(
148 "Calculating the next version from commits with custom bump rules"
149 );
150 match self
151 .previous
152 .as_ref()
153 .and_then(|release| release.version.clone())
154 {
155 Some(version) => {
156 let mut semver = Version::parse(&version);
157 let mut prefix = None;
158 if semver.is_err() && version.split('.').count() >= 2 {
159 let mut found_numeric = false;
160 for (i, c) in version.char_indices() {
161 if c.is_numeric() && !found_numeric {
162 found_numeric = true;
163 let version_prefix = version[..i].to_string();
164 let remaining = version[i..].to_string();
165 let version = Version::parse(&remaining);
166 if version.is_ok() {
167 semver = version;
168 prefix = Some(version_prefix);
169 break;
170 }
171 } else if !c.is_numeric() && found_numeric {
172 found_numeric = false;
173 }
174 }
175 }
176 let mut next_version = VersionUpdater::new()
177 .with_features_always_increment_minor(
178 config.features_always_bump_minor.unwrap_or(true),
179 )
180 .with_breaking_always_increment_major(
181 config.breaking_always_bump_major.unwrap_or(true),
182 );
183 if let Some(custom_major_increment_regex) = &config.custom_major_increment_regex {
184 next_version = next_version
185 .with_custom_major_increment_regex(custom_major_increment_regex)?;
186 }
187 if let Some(custom_minor_increment_regex) = &config.custom_minor_increment_regex {
188 next_version = next_version
189 .with_custom_minor_increment_regex(custom_minor_increment_regex)?;
190 }
191 if let Some(no_increment_regex) = &config.no_increment_regex {
192 next_version = next_version.with_no_increment_regex(no_increment_regex)?;
193 }
194 let old_semver = semver?;
195 let (next_version, determined_bump_type) =
196 if let Some(bump_type) = &config.bump_type {
197 let v = match bump_type {
198 BumpType::Major => old_semver.increment_major().to_string(),
199 BumpType::Minor => old_semver.increment_minor().to_string(),
200 BumpType::Patch => old_semver.increment_patch().to_string(),
201 };
202 (v, Some(*bump_type))
203 } else {
204 let new_semver = next_version.increment(
205 &old_semver,
206 self.commits
207 .iter()
208 .map(|commit| {
209 let message = commit.raw_message().trim_end();
210 if conventional_commits {
216 message.to_string()
217 } else {
218 message.lines().next().unwrap_or_default().to_string()
219 }
220 })
221 .collect::<Vec<String>>(),
222 );
223 let bump_type = determine_bump_type(&old_semver, &new_semver);
224 (new_semver.to_string(), bump_type)
225 };
226 let version = if let Some(prefix) = prefix {
227 format!("{prefix}{next_version}")
228 } else {
229 next_version
230 };
231 Ok(NextVersion {
232 version,
233 bump_type: determined_bump_type,
234 })
235 }
236 None => Ok(NextVersion {
237 version: config.get_initial_tag(),
238 bump_type: None,
239 }),
240 }
241 }
242}
243
244#[derive(Debug, Clone, PartialEq)]
246pub struct NextVersion {
247 pub version: String,
249 pub bump_type: Option<BumpType>,
251}
252
253fn determine_bump_type(old: &Version, new: &Version) -> Option<BumpType> {
255 if new.major != old.major {
256 Some(BumpType::Major)
257 } else if new.minor != old.minor {
258 Some(BumpType::Minor)
259 } else if new.patch != old.patch {
260 Some(BumpType::Patch)
261 } else {
262 None
263 }
264}
265
266#[derive(Serialize)]
268pub struct Releases<'a> {
269 pub releases: &'a Vec<Release<'a>>,
271}
272
273impl Releases<'_> {
274 pub fn as_json(&self) -> Result<String> {
276 Ok(serde_json::to_string(self.releases)?)
277 }
278}
279
280#[cfg(test)]
281mod test {
282 use pretty_assertions::assert_eq;
283
284 use super::*;
285 #[test]
286 fn bump_version() -> Result<()> {
287 fn build_release<'a>(version: &str, commits: &'a [&str]) -> Release<'a> {
288 Release {
289 version: None,
290 message: None,
291 extra: None,
292 commits: commits
293 .iter()
294 .map(|v| Commit::from((*v).to_string()))
295 .collect(),
296 commit_range: None,
297 commit_id: None,
298 timestamp: None,
299 previous: Some(Box::new(Release {
300 version: Some(String::from(version)),
301 ..Default::default()
302 })),
303 repository: Some(String::from("/root/repo")),
304 submodule_commits: HashMap::new(),
305 statistics: None,
306 bump_type: None,
307 #[cfg(feature = "github")]
308 github: crate::remote::RemoteReleaseMetadata {
309 contributors: vec![],
310 },
311 #[cfg(feature = "gitlab")]
312 gitlab: crate::remote::RemoteReleaseMetadata {
313 contributors: vec![],
314 },
315 #[cfg(feature = "gitea")]
316 gitea: crate::remote::RemoteReleaseMetadata {
317 contributors: vec![],
318 },
319 #[cfg(feature = "bitbucket")]
320 bitbucket: crate::remote::RemoteReleaseMetadata {
321 contributors: vec![],
322 },
323 #[cfg(feature = "azure_devops")]
324 azure_devops: crate::remote::RemoteReleaseMetadata {
325 contributors: vec![],
326 },
327 }
328 }
329
330 let test_shared = [
331 ("1.0.0", "1.1.0", vec!["feat: add xyz", "fix: fix xyz"]),
332 ("1.0.0", "1.0.1", vec!["fix: add xyz", "fix: aaaaaa"]),
333 ("1.0.0", "2.0.0", vec!["feat!: add xyz", "feat: zzz"]),
334 ("1.0.0", "2.0.0", vec!["feat!: add xyz\n", "feat: zzz\n"]),
335 ("2.0.0", "2.0.1", vec!["fix: something"]),
336 ("foo/1.0.0", "foo/1.1.0", vec![
337 "feat: add xyz",
338 "fix: fix xyz",
339 ]),
340 ("bar/1.0.0", "bar/2.0.0", vec![
341 "fix: add xyz",
342 "fix!: aaaaaa",
343 ]),
344 ("zzz-123/test/1.0.0", "zzz-123/test/1.0.1", vec![
345 "fix: aaaaaa",
346 ]),
347 ("v100.0.0", "v101.0.0", vec!["feat!: something"]),
348 ("v1.0.0-alpha.1", "v1.0.0-alpha.2", vec!["fix: minor"]),
349 ("testing/v1.0.0-beta.1", "testing/v1.0.0-beta.2", vec![
350 "feat: nice",
351 ]),
352 ("tauri-v1.5.4", "tauri-v1.6.0", vec!["feat: something"]),
353 (
354 "rocket/rocket-v4.0.0-rc.1",
355 "rocket/rocket-v4.0.0-rc.2",
356 vec!["chore!: wow"],
357 ),
358 (
359 "aaa#/@#$@9384!#%^#@#@!#!239432413-idk-9999.2200.5932-alpha.419",
360 "aaa#/@#$@9384!#%^#@#@!#!239432413-idk-9999.2200.5932-alpha.420",
361 vec!["feat: damn this is working"],
362 ),
363 ];
364
365 for (version, expected_version, commits) in test_shared.iter().chain(
366 [
367 ("0.0.1", "0.0.2", vec!["fix: fix xyz"]),
368 ("0.0.1", "0.1.0", vec!["feat: add xyz", "fix: fix xyz"]),
369 ("0.0.1", "1.0.0", vec!["feat!: add xyz", "feat: zzz"]),
370 ("0.1.0", "0.1.1", vec!["fix: fix xyz"]),
371 ("0.1.0", "0.2.0", vec!["feat: add xyz", "fix: fix xyz"]),
372 ("0.1.0", "1.0.0", vec!["feat!: add xyz", "feat: zzz"]),
373 ]
374 .iter(),
375 ) {
376 let release = build_release(version, commits);
377 let next_version = release.calculate_next_version()?.version;
378 assert_eq!(expected_version, &next_version);
379 let next_version = release
380 .calculate_next_version_with_config(&Bump::default())?
381 .version;
382 assert_eq!(expected_version, &next_version);
383 }
384
385 for (version, expected_version, commits) in test_shared.iter().chain(
386 [
387 ("0.0.1", "0.0.2", vec!["fix: fix xyz"]),
388 ("0.0.1", "0.0.2", vec!["feat: add xyz", "fix: fix xyz"]),
389 ("0.0.1", "0.0.2", vec!["feat!: add xyz", "feat: zzz"]),
390 ("0.1.0", "0.1.1", vec!["fix: fix xyz"]),
391 ("0.1.0", "0.1.1", vec!["feat: add xyz", "fix: fix xyz"]),
392 ("0.1.0", "0.2.0", vec!["feat!: add xyz", "feat: zzz"]),
393 ]
394 .iter(),
395 ) {
396 let release = build_release(version, commits);
397 let next_version = release
398 .calculate_next_version_with_config(&Bump {
399 features_always_bump_minor: Some(false),
400 breaking_always_bump_major: Some(false),
401 initial_tag: None,
402 custom_major_increment_regex: None,
403 custom_minor_increment_regex: None,
404 no_increment_regex: None,
405 bump_type: None,
406 })?
407 .version;
408 assert_eq!(expected_version, &next_version);
409 }
410
411 for (version, expected_version, commits) in test_shared.iter().chain(
412 [
413 ("0.0.1", "0.0.2", vec!["fix: fix xyz"]),
414 ("0.0.1", "0.1.0", vec!["feat: add xyz", "fix: fix xyz"]),
415 ("0.0.1", "0.1.0", vec!["feat!: add xyz", "feat: zzz"]),
416 ("0.1.0", "0.1.1", vec!["fix: fix xyz"]),
417 ("0.1.0", "0.2.0", vec!["feat: add xyz", "fix: fix xyz"]),
418 ("0.1.0", "0.2.0", vec!["feat!: add xyz", "feat: zzz"]),
419 ]
420 .iter(),
421 ) {
422 let release = build_release(version, commits);
423 let next_version = release
424 .calculate_next_version_with_config(&Bump {
425 features_always_bump_minor: Some(true),
426 breaking_always_bump_major: Some(false),
427 initial_tag: None,
428 custom_major_increment_regex: None,
429 custom_minor_increment_regex: None,
430 no_increment_regex: None,
431 bump_type: None,
432 })?
433 .version;
434 assert_eq!(expected_version, &next_version);
435 }
436
437 for (version, expected_version, commits) in test_shared.iter().chain(
438 [
439 ("0.0.1", "0.0.2", vec!["fix: fix xyz"]),
440 ("0.0.1", "0.0.2", vec!["feat: add xyz", "fix: fix xyz"]),
441 ("0.0.1", "1.0.0", vec!["feat!: add xyz", "feat: zzz"]),
442 ("0.1.0", "0.1.1", vec!["fix: fix xyz"]),
443 ("0.1.0", "0.1.1", vec!["feat: add xyz", "fix: fix xyz"]),
444 ("0.1.0", "1.0.0", vec!["feat!: add xyz", "feat: zzz"]),
445 ]
446 .iter(),
447 ) {
448 let release = build_release(version, commits);
449 let next_version = release
450 .calculate_next_version_with_config(&Bump {
451 features_always_bump_minor: Some(false),
452 breaking_always_bump_major: Some(true),
453 initial_tag: None,
454 custom_major_increment_regex: None,
455 custom_minor_increment_regex: None,
456 no_increment_regex: None,
457 bump_type: None,
458 })?
459 .version;
460 assert_eq!(expected_version, &next_version);
461 }
462
463 let empty_release = Release {
464 previous: Some(Box::new(Release {
465 version: None,
466 ..Default::default()
467 })),
468 ..Default::default()
469 };
470 let result = empty_release.calculate_next_version()?;
471 assert_eq!("0.1.0", result.version);
472 assert_eq!(None, result.bump_type);
473 for (features_always_bump_minor, breaking_always_bump_major) in
474 [(true, true), (true, false), (false, true), (false, false)]
475 {
476 let result = empty_release.calculate_next_version_with_config(&Bump {
477 features_always_bump_minor: Some(features_always_bump_minor),
478 breaking_always_bump_major: Some(breaking_always_bump_major),
479 initial_tag: None,
480 custom_major_increment_regex: None,
481 custom_minor_increment_regex: None,
482 no_increment_regex: None,
483 bump_type: None,
484 })?;
485 assert_eq!("0.1.0", result.version);
486 assert_eq!(None, result.bump_type);
487 }
488 Ok(())
489 }
490
491 #[test]
492 fn no_increment_regex_skips_matching_commit_types() -> Result<()> {
493 fn build_release<'a>(version: &str, commits: &'a [&str]) -> Release<'a> {
494 Release {
495 version: None,
496 commits: commits
497 .iter()
498 .map(|v| Commit::from((*v).to_string()))
499 .collect(),
500 previous: Some(Box::new(Release {
501 version: Some(String::from(version)),
502 ..Default::default()
503 })),
504 ..Default::default()
505 }
506 }
507
508 let release = build_release("1.0.0", &["chore: should not release"]);
509 let result = release.calculate_next_version_with_config(&Bump {
510 no_increment_regex: Some(String::from("^chore$")),
511 ..Default::default()
512 })?;
513 assert_eq!("1.0.0", result.version);
514 assert_eq!(None, result.bump_type);
515
516 let release = build_release("1.0.0", &[
517 "docs: update readme",
518 "feat: add a user-facing feature",
519 ]);
520 let result = release.calculate_next_version_with_config(&Bump {
521 no_increment_regex: Some(String::from("^docs$")),
522 ..Default::default()
523 })?;
524 assert_eq!("1.1.0", result.version);
525 assert_eq!(Some(BumpType::Minor), result.bump_type);
526
527 let release = Release {
528 version: None,
529 commits: vec![
530 Commit {
531 message: String::from("test"),
532 raw_message: Some(String::from("ci: test")),
533 ..Default::default()
534 }
535 .into_conventional()?,
536 ],
537 previous: Some(Box::new(Release {
538 version: Some(String::from("1.0.0")),
539 ..Default::default()
540 })),
541 ..Default::default()
542 };
543 let result = release.calculate_next_version_with_config(&Bump {
544 no_increment_regex: Some(String::from("^ci$")),
545 ..Default::default()
546 })?;
547 assert_eq!("1.0.0", result.version);
548 assert_eq!(None, result.bump_type);
549
550 Ok(())
551 }
552
553 #[test]
554 fn custom_increment_regex_matches_subject_only_when_non_conventional() -> Result<()> {
555 fn build_release<'a>(version: &str, commits: &'a [&str]) -> Release<'a> {
556 Release {
557 version: None,
558 commits: commits
559 .iter()
560 .map(|v| Commit::from((*v).to_string()))
561 .collect(),
562 previous: Some(Box::new(Release {
563 version: Some(String::from(version)),
564 ..Default::default()
565 })),
566 ..Default::default()
567 }
568 }
569
570 let bump = Bump {
571 custom_major_increment_regex: Some(String::from("breaking")),
572 custom_minor_increment_regex: Some(String::from("feat")),
573 ..Default::default()
574 };
575
576 let release = build_release("1.0.0", &[
581 "fix a bug\n\nThe body mentions breaking and feat as plain words."
582 ]);
583 let result = release.calculate_next_version_from_commits(&bump, false)?;
584 assert_eq!("1.0.1", result.version);
585 assert_eq!(Some(BumpType::Patch), result.bump_type);
586
587 let release = build_release("1.0.0", &["breaking: remove v1 endpoints\n\nBody text."]);
589 let result = release.calculate_next_version_from_commits(&bump, false)?;
590 assert_eq!("2.0.0", result.version);
591 assert_eq!(Some(BumpType::Major), result.bump_type);
592
593 let release = build_release("1.0.0", &["feat: add a thing\n\nBody text."]);
594 let result = release.calculate_next_version_from_commits(&bump, false)?;
595 assert_eq!("1.1.0", result.version);
596 assert_eq!(Some(BumpType::Minor), result.bump_type);
597
598 Ok(())
599 }
600
601 #[test]
602 fn no_increment_regex_uses_subject_only_when_non_conventional() -> Result<()> {
603 fn build_release<'a>(version: &str, commits: &'a [&str]) -> Release<'a> {
604 Release {
605 version: None,
606 commits: commits
607 .iter()
608 .map(|v| Commit::from((*v).to_string()))
609 .collect(),
610 previous: Some(Box::new(Release {
611 version: Some(String::from(version)),
612 ..Default::default()
613 })),
614 ..Default::default()
615 }
616 }
617
618 let release = build_release("1.0.0", &[
623 "fix a bug\n\nThis is a chore cleanup and must not skip the bump."
624 ]);
625 let result = release.calculate_next_version_from_commits(
626 &Bump {
627 no_increment_regex: Some(String::from("chore")),
628 ..Default::default()
629 },
630 false,
631 )?;
632 assert_eq!("1.0.1", result.version);
633 assert_eq!(Some(BumpType::Patch), result.bump_type);
634
635 let release = build_release("1.0.0", &["chore cleanup\n\nBody text."]);
637 let result = release.calculate_next_version_from_commits(
638 &Bump {
639 no_increment_regex: Some(String::from("chore")),
640 ..Default::default()
641 },
642 false,
643 )?;
644 assert_eq!("1.0.0", result.version);
645 assert_eq!(None, result.bump_type);
646
647 Ok(())
648 }
649
650 #[test]
651 fn bump_version_type() -> Result<()> {
652 fn build_release<'a>(version: &str, commits: &'a [&str]) -> Release<'a> {
653 Release {
654 version: None,
655 commits: commits
656 .iter()
657 .map(|v| Commit::from((*v).to_string()))
658 .collect(),
659 previous: Some(Box::new(Release {
660 version: Some(String::from(version)),
661 ..Default::default()
662 })),
663 ..Default::default()
664 }
665 }
666
667 let release = build_release("1.0.0", &["fix: something"]);
668 let result = release.calculate_next_version()?;
669 assert_eq!(Some(BumpType::Patch), result.bump_type);
670
671 let release = build_release("1.0.0", &["feat: add xyz"]);
672 let result = release.calculate_next_version()?;
673 assert_eq!(Some(BumpType::Minor), result.bump_type);
674
675 let release = build_release("1.0.0", &["feat!: breaking change"]);
676 let result = release.calculate_next_version()?;
677 assert_eq!(Some(BumpType::Major), result.bump_type);
678
679 let release = build_release("1.0.0", &["fix: something"]);
680 let result = release.calculate_next_version_with_config(&Bump {
681 bump_type: Some(BumpType::Minor),
682 ..Default::default()
683 })?;
684 assert_eq!("1.1.0", result.version);
685 assert_eq!(Some(BumpType::Minor), result.bump_type);
686
687 let release = Release {
688 previous: Some(Box::new(Release {
689 version: None,
690 ..Default::default()
691 })),
692 ..Default::default()
693 };
694 let result = release.calculate_next_version()?;
695 assert_eq!(None, result.bump_type);
696
697 Ok(())
698 }
699
700 #[test]
701 fn with_statistics() {
702 let release = Release {
703 commits: vec![],
704 timestamp: Some(1_649_373_910),
705 previous: Some(Box::new(Release {
706 timestamp: Some(1_649_201_110),
707 ..Default::default()
708 })),
709 repository: Some(String::from("/root/repo")),
710 ..Default::default()
711 };
712
713 assert!(release.statistics.is_none());
714 let release = release.with_statistics();
715 assert!(release.statistics.is_some());
716 }
717
718 #[cfg(feature = "github")]
719 #[test]
720 fn update_github_metadata() -> Result<()> {
721 use crate::remote::github::{
722 GitHubCommit, GitHubCommitAuthor, GitHubCommitDetails, GitHubCommitDetailsAuthor,
723 GitHubPullRequest, PullRequestLabel,
724 };
725
726 let mut release = Release {
727 version: None,
728 message: None,
729 extra: None,
730 commits: vec![
731 Commit::from(String::from(
732 "1d244937ee6ceb8e0314a4a201ba93a7a61f2071 add github integration",
733 )),
734 Commit::from(String::from(
735 "21f6aa587fcb772de13f2fde0e92697c51f84162 fix github integration",
736 )),
737 Commit::from(String::from(
738 "35d8c6b6329ecbcf131d7df02f93c3bbc5ba5973 update metadata",
739 )),
740 Commit::from(String::from(
741 "4d3ffe4753b923f4d7807c490e650e6624a12074 do some stuff",
742 )),
743 Commit::from(String::from(
744 "5a55e92e5a62dc5bf9872ffb2566959fad98bd05 alright",
745 )),
746 Commit::from(String::from(
747 "6c34967147560ea09658776d4901709139b4ad66 should be fine",
748 )),
749 ],
750 commit_range: None,
751 commit_id: None,
752 timestamp: None,
753 previous: Some(Box::new(Release {
754 version: Some(String::from("1.0.0")),
755 ..Default::default()
756 })),
757 repository: Some(String::from("/root/repo")),
758 submodule_commits: HashMap::new(),
759 statistics: None,
760 bump_type: None,
761 github: RemoteReleaseMetadata {
762 contributors: vec![],
763 },
764 #[cfg(feature = "gitlab")]
765 gitlab: RemoteReleaseMetadata {
766 contributors: vec![],
767 },
768 #[cfg(feature = "gitea")]
769 gitea: RemoteReleaseMetadata {
770 contributors: vec![],
771 },
772 #[cfg(feature = "bitbucket")]
773 bitbucket: RemoteReleaseMetadata {
774 contributors: vec![],
775 },
776 #[cfg(feature = "azure_devops")]
777 azure_devops: RemoteReleaseMetadata {
778 contributors: vec![],
779 },
780 };
781 release.update_github_metadata(
782 vec![
783 GitHubCommit {
784 sha: String::from("1d244937ee6ceb8e0314a4a201ba93a7a61f2071"),
785 author: Some(GitHubCommitAuthor {
786 login: Some(String::from("orhun")),
787 }),
788 commit: Some(GitHubCommitDetails {
789 author: GitHubCommitDetailsAuthor {
790 date: String::from("2021-07-18T15:14:39+03:00"),
791 },
792 }),
793 },
794 GitHubCommit {
795 sha: String::from("21f6aa587fcb772de13f2fde0e92697c51f84162"),
796 author: Some(GitHubCommitAuthor {
797 login: Some(String::from("orhun")),
798 }),
799 commit: Some(GitHubCommitDetails {
800 author: GitHubCommitDetailsAuthor {
801 date: String::from("2021-07-18T15:12:19+03:00"),
802 },
803 }),
804 },
805 GitHubCommit {
806 sha: String::from("35d8c6b6329ecbcf131d7df02f93c3bbc5ba5973"),
807 author: Some(GitHubCommitAuthor {
808 login: Some(String::from("nuhro")),
809 }),
810 commit: Some(GitHubCommitDetails {
811 author: GitHubCommitDetailsAuthor {
812 date: String::from("2021-07-18T15:07:23+03:00"),
813 },
814 }),
815 },
816 GitHubCommit {
817 sha: String::from("4d3ffe4753b923f4d7807c490e650e6624a12074"),
818 author: Some(GitHubCommitAuthor {
819 login: Some(String::from("awesome_contributor")),
820 }),
821 commit: Some(GitHubCommitDetails {
822 author: GitHubCommitDetailsAuthor {
823 date: String::from("2021-07-18T15:05:10+03:00"),
824 },
825 }),
826 },
827 GitHubCommit {
828 sha: String::from("5a55e92e5a62dc5bf9872ffb2566959fad98bd05"),
829 author: Some(GitHubCommitAuthor {
830 login: Some(String::from("orhun")),
831 }),
832 commit: Some(GitHubCommitDetails {
833 author: GitHubCommitDetailsAuthor {
834 date: String::from("2021-07-18T15:03:30+03:00"),
835 },
836 }),
837 },
838 GitHubCommit {
839 sha: String::from("6c34967147560ea09658776d4901709139b4ad66"),
840 author: Some(GitHubCommitAuthor {
841 login: Some(String::from("someone")),
842 }),
843 commit: Some(GitHubCommitDetails {
844 author: GitHubCommitDetailsAuthor {
845 date: String::from("2021-07-18T15:00:38+03:00"),
846 },
847 }),
848 },
849 GitHubCommit {
850 sha: String::from("0c34967147560e809658776d4901709139b4ad68"),
851 author: Some(GitHubCommitAuthor {
852 login: Some(String::from("idk")),
853 }),
854 commit: Some(GitHubCommitDetails {
855 author: GitHubCommitDetailsAuthor {
856 date: String::from("2021-07-18T15:00:38+03:00"),
857 },
858 }),
859 },
860 GitHubCommit {
861 sha: String::from("kk34967147560e809658776d4901709139b4ad68"),
862 author: None,
863 commit: None,
864 },
865 GitHubCommit {
866 sha: String::new(),
867 author: None,
868 commit: None,
869 },
870 ]
871 .into_iter()
872 .map(|v| Box::new(v) as Box<dyn RemoteCommit>)
873 .collect(),
874 vec![
875 GitHubPullRequest {
876 user: Some(GitHubCommitAuthor {
877 login: Some(String::from("author-1")),
878 }),
879 title: Some(String::from("1")),
880 number: 42,
881 merge_commit_sha: Some(String::from(
882 "1d244937ee6ceb8e0314a4a201ba93a7a61f2071",
883 )),
884 labels: vec![PullRequestLabel {
885 name: String::from("rust"),
886 }],
887 },
888 GitHubPullRequest {
889 user: Some(GitHubCommitAuthor {
890 login: Some(String::from("author-2")),
891 }),
892 title: Some(String::from("2")),
893 number: 66,
894 merge_commit_sha: Some(String::from(
895 "21f6aa587fcb772de13f2fde0e92697c51f84162",
896 )),
897 labels: vec![PullRequestLabel {
898 name: String::from("rust"),
899 }],
900 },
901 GitHubPullRequest {
902 user: Some(GitHubCommitAuthor {
903 login: Some(String::from("author-3")),
904 }),
905 title: Some(String::from("3")),
906 number: 53,
907 merge_commit_sha: Some(String::from(
908 "35d8c6b6329ecbcf131d7df02f93c3bbc5ba5973",
909 )),
910 labels: vec![PullRequestLabel {
911 name: String::from("deps"),
912 }],
913 },
914 GitHubPullRequest {
915 user: Some(GitHubCommitAuthor {
916 login: Some(String::from("author-4")),
917 }),
918 title: Some(String::from("4")),
919 number: 1_000,
920 merge_commit_sha: Some(String::from(
921 "4d3ffe4753b923f4d7807c490e650e6624a12074",
922 )),
923 labels: vec![PullRequestLabel {
924 name: String::from("deps"),
925 }],
926 },
927 GitHubPullRequest {
928 user: Some(GitHubCommitAuthor {
929 login: Some(String::from("author-5")),
930 }),
931 title: Some(String::from("5")),
932 number: 999_999,
933 merge_commit_sha: Some(String::from(
934 "5a55e92e5a62dc5bf9872ffb2566959fad98bd05",
935 )),
936 labels: vec![PullRequestLabel {
937 name: String::from("github"),
938 }],
939 },
940 ]
941 .into_iter()
942 .map(|v| Box::new(v) as Box<dyn RemotePullRequest>)
943 .collect(),
944 )?;
945 #[allow(deprecated)]
946 let expected_commits = vec![
947 Commit {
948 id: String::from("1d244937ee6ceb8e0314a4a201ba93a7a61f2071"),
949 message: String::from("add github integration"),
950 github: RemoteContributor {
951 username: Some(String::from("orhun")),
952 pr_author: Some(String::from("author-1")),
953 pr_title: Some(String::from("1")),
954 pr_number: Some(42),
955 pr_numbers: vec![],
956 pr_labels: vec![String::from("rust")],
957 is_first_time: false,
958 },
959 remote: Some(RemoteContributor {
960 username: Some(String::from("orhun")),
961 pr_author: Some(String::from("author-1")),
962 pr_title: Some(String::from("1")),
963 pr_number: Some(42),
964 pr_numbers: vec![],
965 pr_labels: vec![String::from("rust")],
966 is_first_time: false,
967 }),
968 ..Default::default()
969 },
970 Commit {
971 id: String::from("21f6aa587fcb772de13f2fde0e92697c51f84162"),
972 message: String::from("fix github integration"),
973 github: RemoteContributor {
974 username: Some(String::from("orhun")),
975 pr_author: Some(String::from("author-2")),
976 pr_title: Some(String::from("2")),
977 pr_number: Some(66),
978 pr_numbers: vec![],
979 pr_labels: vec![String::from("rust")],
980 is_first_time: false,
981 },
982 remote: Some(RemoteContributor {
983 username: Some(String::from("orhun")),
984 pr_author: Some(String::from("author-2")),
985 pr_title: Some(String::from("2")),
986 pr_number: Some(66),
987 pr_numbers: vec![],
988 pr_labels: vec![String::from("rust")],
989 is_first_time: false,
990 }),
991 ..Default::default()
992 },
993 Commit {
994 id: String::from("35d8c6b6329ecbcf131d7df02f93c3bbc5ba5973"),
995 message: String::from("update metadata"),
996 github: RemoteContributor {
997 username: Some(String::from("nuhro")),
998 pr_author: Some(String::from("author-3")),
999 pr_title: Some(String::from("3")),
1000 pr_number: Some(53),
1001 pr_numbers: vec![],
1002 pr_labels: vec![String::from("deps")],
1003 is_first_time: false,
1004 },
1005 remote: Some(RemoteContributor {
1006 username: Some(String::from("nuhro")),
1007 pr_author: Some(String::from("author-3")),
1008 pr_title: Some(String::from("3")),
1009 pr_number: Some(53),
1010 pr_numbers: vec![],
1011 pr_labels: vec![String::from("deps")],
1012 is_first_time: false,
1013 }),
1014 ..Default::default()
1015 },
1016 Commit {
1017 id: String::from("4d3ffe4753b923f4d7807c490e650e6624a12074"),
1018 message: String::from("do some stuff"),
1019 github: RemoteContributor {
1020 username: Some(String::from("awesome_contributor")),
1021 pr_author: Some(String::from("author-4")),
1022 pr_title: Some(String::from("4")),
1023 pr_number: Some(1_000),
1024 pr_numbers: vec![],
1025 pr_labels: vec![String::from("deps")],
1026 is_first_time: false,
1027 },
1028 remote: Some(RemoteContributor {
1029 username: Some(String::from("awesome_contributor")),
1030 pr_author: Some(String::from("author-4")),
1031 pr_title: Some(String::from("4")),
1032 pr_number: Some(1_000),
1033 pr_numbers: vec![],
1034 pr_labels: vec![String::from("deps")],
1035 is_first_time: false,
1036 }),
1037 ..Default::default()
1038 },
1039 Commit {
1040 id: String::from("5a55e92e5a62dc5bf9872ffb2566959fad98bd05"),
1041 message: String::from("alright"),
1042 github: RemoteContributor {
1043 username: Some(String::from("orhun")),
1044 pr_author: Some(String::from("author-5")),
1045 pr_title: Some(String::from("5")),
1046 pr_number: Some(999_999),
1047 pr_numbers: vec![],
1048 pr_labels: vec![String::from("github")],
1049 is_first_time: false,
1050 },
1051 remote: Some(RemoteContributor {
1052 username: Some(String::from("orhun")),
1053 pr_author: Some(String::from("author-5")),
1054 pr_title: Some(String::from("5")),
1055 pr_number: Some(999_999),
1056 pr_numbers: vec![],
1057 pr_labels: vec![String::from("github")],
1058 is_first_time: false,
1059 }),
1060 ..Default::default()
1061 },
1062 Commit {
1063 id: String::from("6c34967147560ea09658776d4901709139b4ad66"),
1064 message: String::from("should be fine"),
1065 github: RemoteContributor {
1066 username: Some(String::from("someone")),
1067 pr_author: None,
1068 pr_title: None,
1069 pr_number: None,
1070 pr_numbers: vec![],
1071 pr_labels: vec![],
1072 is_first_time: false,
1073 },
1074 remote: Some(RemoteContributor {
1075 username: Some(String::from("someone")),
1076 pr_author: None,
1077 pr_title: None,
1078 pr_number: None,
1079 pr_numbers: vec![],
1080 pr_labels: vec![],
1081 is_first_time: false,
1082 }),
1083 ..Default::default()
1084 },
1085 ];
1086 assert_eq!(expected_commits, release.commits);
1087
1088 release.github.contributors.sort_by_key(|a| a.pr_number);
1089
1090 let expected_metadata = RemoteReleaseMetadata {
1091 contributors: vec![
1092 RemoteContributor {
1093 username: Some(String::from("someone")),
1094 pr_author: None,
1095 pr_title: None,
1096 pr_number: None,
1097 pr_numbers: vec![],
1098 pr_labels: vec![],
1099 is_first_time: true,
1100 },
1101 RemoteContributor {
1102 username: Some(String::from("orhun")),
1103 pr_author: None,
1104 pr_title: Some(String::from("1")),
1105 pr_number: Some(42),
1106 pr_numbers: vec![42, 66, 999_999],
1107 pr_labels: vec![String::from("rust")],
1108 is_first_time: true,
1109 },
1110 RemoteContributor {
1111 username: Some(String::from("nuhro")),
1112 pr_author: None,
1113 pr_title: Some(String::from("3")),
1114 pr_number: Some(53),
1115 pr_numbers: vec![53],
1116 pr_labels: vec![String::from("deps")],
1117 is_first_time: true,
1118 },
1119 RemoteContributor {
1120 username: Some(String::from("awesome_contributor")),
1121 pr_author: None,
1122 pr_title: Some(String::from("4")),
1123 pr_number: Some(1_000),
1124 pr_numbers: vec![1_000],
1125 pr_labels: vec![String::from("deps")],
1126 is_first_time: true,
1127 },
1128 ],
1129 };
1130 assert_eq!(expected_metadata, release.github);
1131
1132 Ok(())
1133 }
1134
1135 #[cfg(feature = "gitlab")]
1136 #[test]
1137 fn update_gitlab_metadata() -> Result<()> {
1138 use crate::remote::gitlab::{GitLabCommit, GitLabMergeRequest, GitLabUser};
1139
1140 let mut release = Release {
1141 version: None,
1142 message: None,
1143 extra: None,
1144 commits: vec![
1145 Commit::from(String::from(
1146 "1d244937ee6ceb8e0314a4a201ba93a7a61f2071 add github integration",
1147 )),
1148 Commit::from(String::from(
1149 "21f6aa587fcb772de13f2fde0e92697c51f84162 fix github integration",
1150 )),
1151 Commit::from(String::from(
1152 "35d8c6b6329ecbcf131d7df02f93c3bbc5ba5973 update metadata",
1153 )),
1154 Commit::from(String::from(
1155 "4d3ffe4753b923f4d7807c490e650e6624a12074 do some stuff",
1156 )),
1157 Commit::from(String::from(
1158 "5a55e92e5a62dc5bf9872ffb2566959fad98bd05 alright",
1159 )),
1160 Commit::from(String::from(
1161 "6c34967147560ea09658776d4901709139b4ad66 should be fine",
1162 )),
1163 ],
1164 commit_range: None,
1165 commit_id: None,
1166 timestamp: None,
1167 previous: Some(Box::new(Release {
1168 version: Some(String::from("1.0.0")),
1169 ..Default::default()
1170 })),
1171 repository: Some(String::from("/root/repo")),
1172 submodule_commits: HashMap::new(),
1173 statistics: None,
1174 bump_type: None,
1175 #[cfg(feature = "github")]
1176 github: RemoteReleaseMetadata {
1177 contributors: vec![],
1178 },
1179 #[cfg(feature = "gitlab")]
1180 gitlab: RemoteReleaseMetadata {
1181 contributors: vec![],
1182 },
1183 #[cfg(feature = "gitea")]
1184 gitea: RemoteReleaseMetadata {
1185 contributors: vec![],
1186 },
1187 #[cfg(feature = "bitbucket")]
1188 bitbucket: RemoteReleaseMetadata {
1189 contributors: vec![],
1190 },
1191 #[cfg(feature = "azure_devops")]
1192 azure_devops: RemoteReleaseMetadata {
1193 contributors: vec![],
1194 },
1195 };
1196 release.update_gitlab_metadata(
1197 vec![
1198 GitLabCommit {
1199 id: Some(String::from("1d244937ee6ceb8e0314a4a201ba93a7a61f2071")),
1200 author_name: Some(String::from("orhun")),
1201 short_id: Some(String::new()),
1202 title: Some(String::new()),
1203 author_email: Some(String::new()),
1204 authored_date: Some(String::new()),
1205 committer_name: Some(String::new()),
1206 committer_email: Some(String::new()),
1207 committed_date: Some(String::new()),
1208 created_at: Some(String::new()),
1209 message: Some(String::new()),
1210 parent_ids: vec![],
1211 web_url: Some(String::new()),
1212 },
1213 GitLabCommit {
1214 id: Some(String::from("21f6aa587fcb772de13f2fde0e92697c51f84162")),
1215 author_name: Some(String::from("orhun")),
1216 short_id: Some(String::new()),
1217 title: Some(String::new()),
1218 author_email: Some(String::new()),
1219 authored_date: Some(String::new()),
1220 committer_name: Some(String::new()),
1221 committer_email: Some(String::new()),
1222 committed_date: Some(String::new()),
1223 created_at: Some(String::new()),
1224 message: Some(String::new()),
1225 parent_ids: vec![],
1226 web_url: Some(String::new()),
1227 },
1228 GitLabCommit {
1229 id: Some(String::from("35d8c6b6329ecbcf131d7df02f93c3bbc5ba5973")),
1230 author_name: Some(String::from("nuhro")),
1231 short_id: Some(String::new()),
1232 title: Some(String::new()),
1233 author_email: Some(String::new()),
1234 authored_date: Some(String::new()),
1235 committer_name: Some(String::new()),
1236 committer_email: Some(String::new()),
1237 committed_date: Some(String::new()),
1238 created_at: Some(String::new()),
1239 message: Some(String::new()),
1240 parent_ids: vec![],
1241 web_url: Some(String::new()),
1242 },
1243 GitLabCommit {
1244 id: Some(String::from("4d3ffe4753b923f4d7807c490e650e6624a12074")),
1245 author_name: Some(String::from("awesome_contributor")),
1246 short_id: Some(String::new()),
1247 title: Some(String::new()),
1248 author_email: Some(String::new()),
1249 authored_date: Some(String::new()),
1250 committer_name: Some(String::new()),
1251 committer_email: Some(String::new()),
1252 committed_date: Some(String::new()),
1253 created_at: Some(String::new()),
1254 message: Some(String::new()),
1255 parent_ids: vec![],
1256 web_url: Some(String::new()),
1257 },
1258 GitLabCommit {
1259 id: Some(String::from("5a55e92e5a62dc5bf9872ffb2566959fad98bd05")),
1260 author_name: Some(String::from("orhun")),
1261 short_id: Some(String::new()),
1262 title: Some(String::new()),
1263 author_email: Some(String::new()),
1264 authored_date: Some(String::new()),
1265 committer_name: Some(String::new()),
1266 committer_email: Some(String::new()),
1267 committed_date: Some(String::new()),
1268 created_at: Some(String::new()),
1269 message: Some(String::new()),
1270 parent_ids: vec![],
1271 web_url: Some(String::new()),
1272 },
1273 GitLabCommit {
1274 id: Some(String::from("6c34967147560ea09658776d4901709139b4ad66")),
1275 author_name: Some(String::from("someone")),
1276 short_id: Some(String::new()),
1277 title: Some(String::new()),
1278 author_email: Some(String::new()),
1279 authored_date: Some(String::new()),
1280 committer_name: Some(String::new()),
1281 committer_email: Some(String::new()),
1282 committed_date: Some(String::new()),
1283 created_at: Some(String::new()),
1284 message: Some(String::new()),
1285 parent_ids: vec![],
1286 web_url: Some(String::new()),
1287 },
1288 GitLabCommit {
1289 id: Some(String::from("0c34967147560e809658776d4901709139b4ad68")),
1290 author_name: Some(String::from("idk")),
1291 short_id: Some(String::new()),
1292 title: Some(String::new()),
1293 author_email: Some(String::new()),
1294 authored_date: Some(String::new()),
1295 committer_name: Some(String::new()),
1296 committer_email: Some(String::new()),
1297 committed_date: Some(String::new()),
1298 created_at: Some(String::new()),
1299 message: Some(String::new()),
1300 parent_ids: vec![],
1301 web_url: Some(String::new()),
1302 },
1303 GitLabCommit {
1304 id: Some(String::from("kk34967147560e809658776d4901709139b4ad68")),
1305 author_name: Some(String::from("orhun")),
1306 short_id: Some(String::new()),
1307 title: Some(String::new()),
1308 author_email: Some(String::new()),
1309 authored_date: Some(String::new()),
1310 committer_name: Some(String::new()),
1311 committer_email: Some(String::new()),
1312 committed_date: Some(String::new()),
1313 created_at: Some(String::new()),
1314 message: Some(String::new()),
1315 parent_ids: vec![],
1316 web_url: Some(String::new()),
1317 },
1318 ]
1319 .into_iter()
1320 .map(|v| Box::new(v) as Box<dyn RemoteCommit>)
1321 .collect(),
1322 vec![Box::new(GitLabMergeRequest {
1323 title: Some(String::from("1")),
1324 merge_commit_sha: Some(String::from("1d244937ee6ceb8e0314a4a201ba93a7a61f2071")),
1325 id: Some(1),
1326 iid: Some(1),
1327 project_id: Some(1),
1328 description: Some(String::new()),
1329 state: Some(String::new()),
1330 created_at: Some(String::new()),
1331 author: Some(GitLabUser {
1332 id: Some(1),
1333 name: Some(String::from("42")),
1334 username: Some(String::from("author-1")),
1335 state: Some(String::from("42")),
1336 avatar_url: None,
1337 web_url: Some(String::from("42")),
1338 }),
1339 sha: Some(String::from("1d244937ee6ceb8e0314a4a201ba93a7a61f2071")),
1340 web_url: Some(String::new()),
1341 squash_commit_sha: None,
1342 labels: vec![String::from("rust")],
1343 })],
1344 )?;
1345 #[allow(deprecated)]
1346 let expected_commits = vec![
1347 Commit {
1348 id: String::from("1d244937ee6ceb8e0314a4a201ba93a7a61f2071"),
1349 message: String::from("add github integration"),
1350 gitlab: RemoteContributor {
1351 username: Some(String::from("orhun")),
1352 pr_author: Some(String::from("author-1")),
1353 pr_title: Some(String::from("1")),
1354 pr_number: Some(1),
1355 pr_numbers: vec![],
1356 pr_labels: vec![String::from("rust")],
1357 is_first_time: false,
1358 },
1359 remote: Some(RemoteContributor {
1360 username: Some(String::from("orhun")),
1361 pr_author: Some(String::from("author-1")),
1362 pr_title: Some(String::from("1")),
1363 pr_number: Some(1),
1364 pr_numbers: vec![],
1365 pr_labels: vec![String::from("rust")],
1366 is_first_time: false,
1367 }),
1368 ..Default::default()
1369 },
1370 Commit {
1371 id: String::from("21f6aa587fcb772de13f2fde0e92697c51f84162"),
1372 message: String::from("fix github integration"),
1373 gitlab: RemoteContributor {
1374 username: Some(String::from("orhun")),
1375 pr_author: None,
1376 pr_title: None,
1377 pr_number: None,
1378 pr_numbers: vec![],
1379 pr_labels: vec![],
1380 is_first_time: false,
1381 },
1382 remote: Some(RemoteContributor {
1383 username: Some(String::from("orhun")),
1384 pr_author: None,
1385 pr_title: None,
1386 pr_number: None,
1387 pr_numbers: vec![],
1388 pr_labels: vec![],
1389 is_first_time: false,
1390 }),
1391 ..Default::default()
1392 },
1393 Commit {
1394 id: String::from("35d8c6b6329ecbcf131d7df02f93c3bbc5ba5973"),
1395 message: String::from("update metadata"),
1396 gitlab: RemoteContributor {
1397 username: Some(String::from("nuhro")),
1398 pr_author: None,
1399 pr_title: None,
1400 pr_number: None,
1401 pr_numbers: vec![],
1402 pr_labels: vec![],
1403 is_first_time: false,
1404 },
1405 remote: Some(RemoteContributor {
1406 username: Some(String::from("nuhro")),
1407 pr_author: None,
1408 pr_title: None,
1409 pr_number: None,
1410 pr_numbers: vec![],
1411 pr_labels: vec![],
1412 is_first_time: false,
1413 }),
1414 ..Default::default()
1415 },
1416 Commit {
1417 id: String::from("4d3ffe4753b923f4d7807c490e650e6624a12074"),
1418 message: String::from("do some stuff"),
1419 gitlab: RemoteContributor {
1420 username: Some(String::from("awesome_contributor")),
1421 pr_author: None,
1422 pr_title: None,
1423 pr_number: None,
1424 pr_numbers: vec![],
1425 pr_labels: vec![],
1426 is_first_time: false,
1427 },
1428 remote: Some(RemoteContributor {
1429 username: Some(String::from("awesome_contributor")),
1430 pr_author: None,
1431 pr_title: None,
1432 pr_number: None,
1433 pr_numbers: vec![],
1434 pr_labels: vec![],
1435 is_first_time: false,
1436 }),
1437 ..Default::default()
1438 },
1439 Commit {
1440 id: String::from("5a55e92e5a62dc5bf9872ffb2566959fad98bd05"),
1441 message: String::from("alright"),
1442 gitlab: RemoteContributor {
1443 username: Some(String::from("orhun")),
1444 pr_author: None,
1445 pr_title: None,
1446 pr_number: None,
1447 pr_numbers: vec![],
1448 pr_labels: vec![],
1449 is_first_time: false,
1450 },
1451 remote: Some(RemoteContributor {
1452 username: Some(String::from("orhun")),
1453 pr_author: None,
1454 pr_title: None,
1455 pr_number: None,
1456 pr_numbers: vec![],
1457 pr_labels: vec![],
1458 is_first_time: false,
1459 }),
1460 ..Default::default()
1461 },
1462 Commit {
1463 id: String::from("6c34967147560ea09658776d4901709139b4ad66"),
1464 message: String::from("should be fine"),
1465 gitlab: RemoteContributor {
1466 username: Some(String::from("someone")),
1467 pr_author: None,
1468 pr_title: None,
1469 pr_number: None,
1470 pr_numbers: vec![],
1471 pr_labels: vec![],
1472 is_first_time: false,
1473 },
1474 remote: Some(RemoteContributor {
1475 username: Some(String::from("someone")),
1476 pr_author: None,
1477 pr_title: None,
1478 pr_number: None,
1479 pr_numbers: vec![],
1480 pr_labels: vec![],
1481 is_first_time: false,
1482 }),
1483 ..Default::default()
1484 },
1485 ];
1486 assert_eq!(expected_commits, release.commits);
1487
1488 release.github.contributors.sort_by_key(|a| a.pr_number);
1489
1490 let expected_metadata = RemoteReleaseMetadata {
1491 contributors: vec![
1492 RemoteContributor {
1493 username: Some(String::from("orhun")),
1494 pr_author: None,
1495 pr_title: Some(String::from("1")),
1496 pr_number: Some(1),
1497 pr_numbers: vec![1],
1498 pr_labels: vec![String::from("rust")],
1499 is_first_time: false,
1500 },
1501 RemoteContributor {
1502 username: Some(String::from("nuhro")),
1503 pr_author: None,
1504 pr_title: None,
1505 pr_number: None,
1506 pr_numbers: vec![],
1507 pr_labels: vec![],
1508 is_first_time: true,
1509 },
1510 RemoteContributor {
1511 username: Some(String::from("awesome_contributor")),
1512 pr_author: None,
1513 pr_title: None,
1514 pr_number: None,
1515 pr_numbers: vec![],
1516 pr_labels: vec![],
1517 is_first_time: true,
1518 },
1519 RemoteContributor {
1520 username: Some(String::from("someone")),
1521 pr_author: None,
1522 pr_title: None,
1523 pr_number: None,
1524 pr_numbers: vec![],
1525 pr_labels: vec![],
1526 is_first_time: true,
1527 },
1528 ],
1529 };
1530 assert_eq!(expected_metadata, release.gitlab);
1531
1532 Ok(())
1533 }
1534
1535 #[cfg(feature = "gitea")]
1536 #[test]
1537 fn update_gitea_metadata() -> Result<()> {
1538 use crate::remote::gitea::{
1539 GiteaCommit, GiteaCommitAuthor, GiteaPullRequest, PullRequestLabel,
1540 };
1541
1542 let mut release = Release {
1543 version: None,
1544 message: None,
1545 extra: None,
1546 commits: vec![
1547 Commit::from(String::from(
1548 "1d244937ee6ceb8e0314a4a201ba93a7a61f2071 add github integration",
1549 )),
1550 Commit::from(String::from(
1551 "21f6aa587fcb772de13f2fde0e92697c51f84162 fix github integration",
1552 )),
1553 Commit::from(String::from(
1554 "35d8c6b6329ecbcf131d7df02f93c3bbc5ba5973 update metadata",
1555 )),
1556 Commit::from(String::from(
1557 "4d3ffe4753b923f4d7807c490e650e6624a12074 do some stuff",
1558 )),
1559 Commit::from(String::from(
1560 "5a55e92e5a62dc5bf9872ffb2566959fad98bd05 alright",
1561 )),
1562 Commit::from(String::from(
1563 "6c34967147560ea09658776d4901709139b4ad66 should be fine",
1564 )),
1565 ],
1566 commit_range: None,
1567 commit_id: None,
1568 timestamp: None,
1569 previous: Some(Box::new(Release {
1570 version: Some(String::from("1.0.0")),
1571 ..Default::default()
1572 })),
1573 repository: Some(String::from("/root/repo")),
1574 submodule_commits: HashMap::new(),
1575 statistics: None,
1576 bump_type: None,
1577 #[cfg(feature = "github")]
1578 github: RemoteReleaseMetadata {
1579 contributors: vec![],
1580 },
1581 #[cfg(feature = "gitlab")]
1582 gitlab: RemoteReleaseMetadata {
1583 contributors: vec![],
1584 },
1585 #[cfg(feature = "gitea")]
1586 gitea: RemoteReleaseMetadata {
1587 contributors: vec![],
1588 },
1589 #[cfg(feature = "bitbucket")]
1590 bitbucket: RemoteReleaseMetadata {
1591 contributors: vec![],
1592 },
1593 #[cfg(feature = "azure_devops")]
1594 azure_devops: RemoteReleaseMetadata {
1595 contributors: vec![],
1596 },
1597 };
1598 release.update_gitea_metadata(
1599 vec![
1600 GiteaCommit {
1601 sha: String::from("1d244937ee6ceb8e0314a4a201ba93a7a61f2071"),
1602 author: Some(GiteaCommitAuthor {
1603 login: Some(String::from("orhun")),
1604 }),
1605 created: String::from("2021-07-18T15:14:39+03:00"),
1606 },
1607 GiteaCommit {
1608 sha: String::from("21f6aa587fcb772de13f2fde0e92697c51f84162"),
1609 author: Some(GiteaCommitAuthor {
1610 login: Some(String::from("orhun")),
1611 }),
1612 created: String::from("2021-07-18T15:12:19+03:00"),
1613 },
1614 GiteaCommit {
1615 sha: String::from("35d8c6b6329ecbcf131d7df02f93c3bbc5ba5973"),
1616 author: Some(GiteaCommitAuthor {
1617 login: Some(String::from("nuhro")),
1618 }),
1619 created: String::from("2021-07-18T15:07:23+03:00"),
1620 },
1621 GiteaCommit {
1622 sha: String::from("4d3ffe4753b923f4d7807c490e650e6624a12074"),
1623 author: Some(GiteaCommitAuthor {
1624 login: Some(String::from("awesome_contributor")),
1625 }),
1626 created: String::from("2021-07-18T15:05:10+03:00"),
1627 },
1628 GiteaCommit {
1629 sha: String::from("5a55e92e5a62dc5bf9872ffb2566959fad98bd05"),
1630 author: Some(GiteaCommitAuthor {
1631 login: Some(String::from("orhun")),
1632 }),
1633 created: String::from("2021-07-18T15:03:30+03:00"),
1634 },
1635 GiteaCommit {
1636 sha: String::from("6c34967147560ea09658776d4901709139b4ad66"),
1637 author: Some(GiteaCommitAuthor {
1638 login: Some(String::from("someone")),
1639 }),
1640 created: String::from("2021-07-18T15:00:38+03:00"),
1641 },
1642 GiteaCommit {
1643 sha: String::from("0c34967147560e809658776d4901709139b4ad68"),
1644 author: Some(GiteaCommitAuthor {
1645 login: Some(String::from("idk")),
1646 }),
1647 created: String::from("2021-07-18T15:00:38+03:00"),
1648 },
1649 GiteaCommit {
1650 sha: String::from("kk34967147560e809658776d4901709139b4ad68"),
1651 author: None,
1652 created: String::new(),
1653 },
1654 GiteaCommit {
1655 sha: String::new(),
1656 author: None,
1657 created: String::new(),
1658 },
1659 ]
1660 .into_iter()
1661 .map(|v| Box::new(v) as Box<dyn RemoteCommit>)
1662 .collect(),
1663 vec![
1664 GiteaPullRequest {
1665 user: Some(GiteaCommitAuthor {
1666 login: Some(String::from("author-1")),
1667 }),
1668 title: Some(String::from("1")),
1669 number: 42,
1670 merge_commit_sha: Some(String::from(
1671 "1d244937ee6ceb8e0314a4a201ba93a7a61f2071",
1672 )),
1673 labels: vec![PullRequestLabel {
1674 name: String::from("rust"),
1675 }],
1676 },
1677 GiteaPullRequest {
1678 user: Some(GiteaCommitAuthor {
1679 login: Some(String::from("author-2")),
1680 }),
1681 title: Some(String::from("2")),
1682 number: 66,
1683 merge_commit_sha: Some(String::from(
1684 "21f6aa587fcb772de13f2fde0e92697c51f84162",
1685 )),
1686 labels: vec![PullRequestLabel {
1687 name: String::from("rust"),
1688 }],
1689 },
1690 GiteaPullRequest {
1691 user: Some(GiteaCommitAuthor {
1692 login: Some(String::from("author-3")),
1693 }),
1694 title: Some(String::from("3")),
1695 number: 53,
1696 merge_commit_sha: Some(String::from(
1697 "35d8c6b6329ecbcf131d7df02f93c3bbc5ba5973",
1698 )),
1699 labels: vec![PullRequestLabel {
1700 name: String::from("deps"),
1701 }],
1702 },
1703 GiteaPullRequest {
1704 user: Some(GiteaCommitAuthor {
1705 login: Some(String::from("author-4")),
1706 }),
1707 title: Some(String::from("4")),
1708 number: 1_000,
1709 merge_commit_sha: Some(String::from(
1710 "4d3ffe4753b923f4d7807c490e650e6624a12074",
1711 )),
1712 labels: vec![PullRequestLabel {
1713 name: String::from("deps"),
1714 }],
1715 },
1716 GiteaPullRequest {
1717 user: Some(GiteaCommitAuthor {
1718 login: Some(String::from("author-5")),
1719 }),
1720 title: Some(String::from("5")),
1721 number: 999_999,
1722 merge_commit_sha: Some(String::from(
1723 "5a55e92e5a62dc5bf9872ffb2566959fad98bd05",
1724 )),
1725 labels: vec![PullRequestLabel {
1726 name: String::from("github"),
1727 }],
1728 },
1729 ]
1730 .into_iter()
1731 .map(|v| Box::new(v) as Box<dyn RemotePullRequest>)
1732 .collect(),
1733 )?;
1734 #[allow(deprecated)]
1735 let expected_commits = vec![
1736 Commit {
1737 id: String::from("1d244937ee6ceb8e0314a4a201ba93a7a61f2071"),
1738 message: String::from("add github integration"),
1739 gitea: RemoteContributor {
1740 username: Some(String::from("orhun")),
1741 pr_author: Some(String::from("author-1")),
1742 pr_title: Some(String::from("1")),
1743 pr_number: Some(42),
1744 pr_numbers: vec![],
1745 pr_labels: vec![String::from("rust")],
1746 is_first_time: false,
1747 },
1748 remote: Some(RemoteContributor {
1749 username: Some(String::from("orhun")),
1750 pr_author: Some(String::from("author-1")),
1751 pr_title: Some(String::from("1")),
1752 pr_number: Some(42),
1753 pr_numbers: vec![],
1754 pr_labels: vec![String::from("rust")],
1755 is_first_time: false,
1756 }),
1757 ..Default::default()
1758 },
1759 Commit {
1760 id: String::from("21f6aa587fcb772de13f2fde0e92697c51f84162"),
1761 message: String::from("fix github integration"),
1762 gitea: RemoteContributor {
1763 username: Some(String::from("orhun")),
1764 pr_author: Some(String::from("author-2")),
1765 pr_title: Some(String::from("2")),
1766 pr_number: Some(66),
1767 pr_numbers: vec![],
1768 pr_labels: vec![String::from("rust")],
1769 is_first_time: false,
1770 },
1771 remote: Some(RemoteContributor {
1772 username: Some(String::from("orhun")),
1773 pr_author: Some(String::from("author-2")),
1774 pr_title: Some(String::from("2")),
1775 pr_number: Some(66),
1776 pr_numbers: vec![],
1777 pr_labels: vec![String::from("rust")],
1778 is_first_time: false,
1779 }),
1780 ..Default::default()
1781 },
1782 Commit {
1783 id: String::from("35d8c6b6329ecbcf131d7df02f93c3bbc5ba5973"),
1784 message: String::from("update metadata"),
1785 gitea: RemoteContributor {
1786 username: Some(String::from("nuhro")),
1787 pr_author: Some(String::from("author-3")),
1788 pr_title: Some(String::from("3")),
1789 pr_number: Some(53),
1790 pr_numbers: vec![],
1791 pr_labels: vec![String::from("deps")],
1792 is_first_time: false,
1793 },
1794 remote: Some(RemoteContributor {
1795 username: Some(String::from("nuhro")),
1796 pr_author: Some(String::from("author-3")),
1797 pr_title: Some(String::from("3")),
1798 pr_number: Some(53),
1799 pr_numbers: vec![],
1800 pr_labels: vec![String::from("deps")],
1801 is_first_time: false,
1802 }),
1803 ..Default::default()
1804 },
1805 Commit {
1806 id: String::from("4d3ffe4753b923f4d7807c490e650e6624a12074"),
1807 message: String::from("do some stuff"),
1808 gitea: RemoteContributor {
1809 username: Some(String::from("awesome_contributor")),
1810 pr_author: Some(String::from("author-4")),
1811 pr_title: Some(String::from("4")),
1812 pr_number: Some(1_000),
1813 pr_numbers: vec![],
1814 pr_labels: vec![String::from("deps")],
1815 is_first_time: false,
1816 },
1817 remote: Some(RemoteContributor {
1818 username: Some(String::from("awesome_contributor")),
1819 pr_author: Some(String::from("author-4")),
1820 pr_title: Some(String::from("4")),
1821 pr_number: Some(1_000),
1822 pr_numbers: vec![],
1823 pr_labels: vec![String::from("deps")],
1824 is_first_time: false,
1825 }),
1826 ..Default::default()
1827 },
1828 Commit {
1829 id: String::from("5a55e92e5a62dc5bf9872ffb2566959fad98bd05"),
1830 message: String::from("alright"),
1831 gitea: RemoteContributor {
1832 username: Some(String::from("orhun")),
1833 pr_author: Some(String::from("author-5")),
1834 pr_title: Some(String::from("5")),
1835 pr_number: Some(999_999),
1836 pr_numbers: vec![],
1837 pr_labels: vec![String::from("github")],
1838 is_first_time: false,
1839 },
1840 remote: Some(RemoteContributor {
1841 username: Some(String::from("orhun")),
1842 pr_author: Some(String::from("author-5")),
1843 pr_title: Some(String::from("5")),
1844 pr_number: Some(999_999),
1845 pr_numbers: vec![],
1846 pr_labels: vec![String::from("github")],
1847 is_first_time: false,
1848 }),
1849 ..Default::default()
1850 },
1851 Commit {
1852 id: String::from("6c34967147560ea09658776d4901709139b4ad66"),
1853 message: String::from("should be fine"),
1854 gitea: RemoteContributor {
1855 username: Some(String::from("someone")),
1856 pr_author: None,
1857 pr_title: None,
1858 pr_number: None,
1859 pr_numbers: vec![],
1860 pr_labels: vec![],
1861 is_first_time: false,
1862 },
1863 remote: Some(RemoteContributor {
1864 username: Some(String::from("someone")),
1865 pr_author: None,
1866 pr_title: None,
1867 pr_number: None,
1868 pr_numbers: vec![],
1869 pr_labels: vec![],
1870 is_first_time: false,
1871 }),
1872 ..Default::default()
1873 },
1874 ];
1875 assert_eq!(expected_commits, release.commits);
1876
1877 release.gitea.contributors.sort_by_key(|a| a.pr_number);
1878
1879 let expected_metadata = RemoteReleaseMetadata {
1880 contributors: vec![
1881 RemoteContributor {
1882 username: Some(String::from("someone")),
1883 pr_author: None,
1884 pr_title: None,
1885 pr_number: None,
1886 pr_numbers: vec![],
1887 pr_labels: vec![],
1888 is_first_time: true,
1889 },
1890 RemoteContributor {
1891 username: Some(String::from("orhun")),
1892 pr_author: None,
1893 pr_title: Some(String::from("1")),
1894 pr_number: Some(42),
1895 pr_numbers: vec![42, 66, 999_999],
1896 pr_labels: vec![String::from("rust")],
1897 is_first_time: true,
1898 },
1899 RemoteContributor {
1900 username: Some(String::from("nuhro")),
1901 pr_author: None,
1902 pr_title: Some(String::from("3")),
1903 pr_number: Some(53),
1904 pr_numbers: vec![53],
1905 pr_labels: vec![String::from("deps")],
1906 is_first_time: true,
1907 },
1908 RemoteContributor {
1909 username: Some(String::from("awesome_contributor")),
1910 pr_author: None,
1911 pr_title: Some(String::from("4")),
1912 pr_number: Some(1_000),
1913 pr_numbers: vec![1_000],
1914 pr_labels: vec![String::from("deps")],
1915 is_first_time: true,
1916 },
1917 ],
1918 };
1919 assert_eq!(expected_metadata, release.gitea);
1920
1921 Ok(())
1922 }
1923
1924 #[cfg(feature = "bitbucket")]
1925 #[test]
1926 fn update_bitbucket_metadata() -> Result<()> {
1927 use crate::remote::bitbucket::{
1928 BitbucketCommit, BitbucketCommitAuthor, BitbucketPullRequest,
1929 BitbucketPullRequestMergeCommit,
1930 };
1931
1932 let mut release = Release {
1933 version: None,
1934 message: None,
1935 extra: None,
1936 commits: vec![
1937 Commit::from(String::from(
1938 "1d244937ee6ceb8e0314a4a201ba93a7a61f2071 add bitbucket integration",
1939 )),
1940 Commit::from(String::from(
1941 "21f6aa587fcb772de13f2fde0e92697c51f84162 fix bitbucket integration",
1942 )),
1943 Commit::from(String::from(
1944 "35d8c6b6329ecbcf131d7df02f93c3bbc5ba5973 update metadata",
1945 )),
1946 Commit::from(String::from(
1947 "4d3ffe4753b923f4d7807c490e650e6624a12074 do some stuff",
1948 )),
1949 Commit::from(String::from(
1950 "5a55e92e5a62dc5bf9872ffb2566959fad98bd05 alright",
1951 )),
1952 Commit::from(String::from(
1953 "6c34967147560ea09658776d4901709139b4ad66 should be fine",
1954 )),
1955 ],
1956 commit_range: None,
1957 commit_id: None,
1958 timestamp: None,
1959 previous: Some(Box::new(Release {
1960 version: Some(String::from("1.0.0")),
1961 ..Default::default()
1962 })),
1963 repository: Some(String::from("/root/repo")),
1964 submodule_commits: HashMap::new(),
1965 statistics: None,
1966 bump_type: None,
1967 #[cfg(feature = "github")]
1968 github: RemoteReleaseMetadata {
1969 contributors: vec![],
1970 },
1971 #[cfg(feature = "gitlab")]
1972 gitlab: RemoteReleaseMetadata {
1973 contributors: vec![],
1974 },
1975 #[cfg(feature = "gitea")]
1976 gitea: RemoteReleaseMetadata {
1977 contributors: vec![],
1978 },
1979 #[cfg(feature = "bitbucket")]
1980 bitbucket: RemoteReleaseMetadata {
1981 contributors: vec![],
1982 },
1983 #[cfg(feature = "azure_devops")]
1984 azure_devops: RemoteReleaseMetadata {
1985 contributors: vec![],
1986 },
1987 };
1988 release.update_bitbucket_metadata(
1989 vec![
1990 BitbucketCommit {
1991 hash: String::from("1d244937ee6ceb8e0314a4a201ba93a7a61f2071"),
1992 author: Some(BitbucketCommitAuthor {
1993 login: Some(String::from("orhun")),
1994 nickname: None,
1995 }),
1996 date: String::from("2021-07-18T15:14:39+03:00"),
1997 },
1998 BitbucketCommit {
1999 hash: String::from("21f6aa587fcb772de13f2fde0e92697c51f84162"),
2000 author: Some(BitbucketCommitAuthor {
2001 login: Some(String::from("orhun")),
2002 nickname: None,
2003 }),
2004 date: String::from("2021-07-18T15:12:19+03:00"),
2005 },
2006 BitbucketCommit {
2007 hash: String::from("35d8c6b6329ecbcf131d7df02f93c3bbc5ba5973"),
2008 author: Some(BitbucketCommitAuthor {
2009 login: Some(String::from("nuhro")),
2010 nickname: None,
2011 }),
2012 date: String::from("2021-07-18T15:07:23+03:00"),
2013 },
2014 BitbucketCommit {
2015 hash: String::from("4d3ffe4753b923f4d7807c490e650e6624a12074"),
2016 author: Some(BitbucketCommitAuthor {
2017 login: Some(String::from("awesome_contributor")),
2018 nickname: None,
2019 }),
2020 date: String::from("2021-07-18T15:05:10+03:00"),
2021 },
2022 BitbucketCommit {
2023 hash: String::from("5a55e92e5a62dc5bf9872ffb2566959fad98bd05"),
2024 author: Some(BitbucketCommitAuthor {
2025 login: Some(String::from("orhun")),
2026 nickname: None,
2027 }),
2028 date: String::from("2021-07-18T15:03:30+03:00"),
2029 },
2030 BitbucketCommit {
2031 hash: String::from("6c34967147560ea09658776d4901709139b4ad66"),
2032 author: Some(BitbucketCommitAuthor {
2033 login: Some(String::from("someone")),
2034 nickname: None,
2035 }),
2036 date: String::from("2021-07-18T15:00:38+03:00"),
2037 },
2038 BitbucketCommit {
2039 hash: String::from("0c34967147560e809658776d4901709139b4ad68"),
2040 author: Some(BitbucketCommitAuthor {
2041 login: Some(String::from("idk")),
2042 nickname: None,
2043 }),
2044 date: String::from("2021-07-18T15:00:01+03:00"),
2045 },
2046 BitbucketCommit {
2047 hash: String::from("kk34967147560e809658776d4901709139b4ad68"),
2048 author: Some(BitbucketCommitAuthor {
2049 login: Some(String::from("orhun")),
2050 nickname: None,
2051 }),
2052 date: String::from("2021-07-14T21:25:24+03:00"),
2053 },
2054 ]
2055 .into_iter()
2056 .map(|v| Box::new(v) as Box<dyn RemoteCommit>)
2057 .collect(),
2058 vec![Box::new(BitbucketPullRequest {
2059 id: 1,
2060 title: Some(String::from("1")),
2061 author: BitbucketCommitAuthor {
2062 login: Some(String::from("42")),
2063 nickname: Some(String::from("author-1")),
2064 },
2065 merge_commit: BitbucketPullRequestMergeCommit {
2066 hash: String::from("1d244937ee6c"),
2068 },
2069 })],
2070 )?;
2071 #[allow(deprecated)]
2072 let expected_commits = vec![
2073 Commit {
2074 id: String::from("1d244937ee6ceb8e0314a4a201ba93a7a61f2071"),
2075 message: String::from("add bitbucket integration"),
2076 bitbucket: RemoteContributor {
2077 username: Some(String::from("orhun")),
2078 pr_author: Some(String::from("author-1")),
2079 pr_title: Some(String::from("1")),
2080 pr_number: Some(1),
2081 pr_numbers: vec![],
2082 pr_labels: vec![],
2083 is_first_time: false,
2084 },
2085 remote: Some(RemoteContributor {
2086 username: Some(String::from("orhun")),
2087 pr_author: Some(String::from("author-1")),
2088 pr_title: Some(String::from("1")),
2089 pr_number: Some(1),
2090 pr_numbers: vec![],
2091 pr_labels: vec![],
2092 is_first_time: false,
2093 }),
2094 ..Default::default()
2095 },
2096 Commit {
2097 id: String::from("21f6aa587fcb772de13f2fde0e92697c51f84162"),
2098 message: String::from("fix bitbucket integration"),
2099 bitbucket: RemoteContributor {
2100 username: Some(String::from("orhun")),
2101 pr_author: None,
2102 pr_title: None,
2103 pr_number: None,
2104 pr_numbers: vec![],
2105 pr_labels: vec![],
2106 is_first_time: false,
2107 },
2108 remote: Some(RemoteContributor {
2109 username: Some(String::from("orhun")),
2110 pr_author: None,
2111 pr_title: None,
2112 pr_number: None,
2113 pr_numbers: vec![],
2114 pr_labels: vec![],
2115 is_first_time: false,
2116 }),
2117 ..Default::default()
2118 },
2119 Commit {
2120 id: String::from("35d8c6b6329ecbcf131d7df02f93c3bbc5ba5973"),
2121 message: String::from("update metadata"),
2122 bitbucket: RemoteContributor {
2123 username: Some(String::from("nuhro")),
2124 pr_author: None,
2125 pr_title: None,
2126 pr_number: None,
2127 pr_numbers: vec![],
2128 pr_labels: vec![],
2129 is_first_time: false,
2130 },
2131 remote: Some(RemoteContributor {
2132 username: Some(String::from("nuhro")),
2133 pr_author: None,
2134 pr_title: None,
2135 pr_number: None,
2136 pr_numbers: vec![],
2137 pr_labels: vec![],
2138 is_first_time: false,
2139 }),
2140 ..Default::default()
2141 },
2142 Commit {
2143 id: String::from("4d3ffe4753b923f4d7807c490e650e6624a12074"),
2144 message: String::from("do some stuff"),
2145 bitbucket: RemoteContributor {
2146 username: Some(String::from("awesome_contributor")),
2147 pr_author: None,
2148 pr_title: None,
2149 pr_number: None,
2150 pr_numbers: vec![],
2151 pr_labels: vec![],
2152 is_first_time: false,
2153 },
2154 remote: Some(RemoteContributor {
2155 username: Some(String::from("awesome_contributor")),
2156 pr_author: None,
2157 pr_title: None,
2158 pr_number: None,
2159 pr_numbers: vec![],
2160 pr_labels: vec![],
2161 is_first_time: false,
2162 }),
2163 ..Default::default()
2164 },
2165 Commit {
2166 id: String::from("5a55e92e5a62dc5bf9872ffb2566959fad98bd05"),
2167 message: String::from("alright"),
2168 bitbucket: RemoteContributor {
2169 username: Some(String::from("orhun")),
2170 pr_author: None,
2171 pr_title: None,
2172 pr_number: None,
2173 pr_numbers: vec![],
2174 pr_labels: vec![],
2175 is_first_time: false,
2176 },
2177 remote: Some(RemoteContributor {
2178 username: Some(String::from("orhun")),
2179 pr_author: None,
2180 pr_title: None,
2181 pr_number: None,
2182 pr_numbers: vec![],
2183 pr_labels: vec![],
2184 is_first_time: false,
2185 }),
2186 ..Default::default()
2187 },
2188 Commit {
2189 id: String::from("6c34967147560ea09658776d4901709139b4ad66"),
2190 message: String::from("should be fine"),
2191 bitbucket: RemoteContributor {
2192 username: Some(String::from("someone")),
2193 pr_author: None,
2194 pr_title: None,
2195 pr_number: None,
2196 pr_numbers: vec![],
2197 pr_labels: vec![],
2198 is_first_time: false,
2199 },
2200 remote: Some(RemoteContributor {
2201 username: Some(String::from("someone")),
2202 pr_author: None,
2203 pr_title: None,
2204 pr_number: None,
2205 pr_numbers: vec![],
2206 pr_labels: vec![],
2207 is_first_time: false,
2208 }),
2209 ..Default::default()
2210 },
2211 ];
2212 assert_eq!(expected_commits, release.commits);
2213
2214 release.bitbucket.contributors.sort_by_key(|a| a.pr_number);
2215
2216 let expected_metadata = RemoteReleaseMetadata {
2217 contributors: vec![
2218 RemoteContributor {
2219 username: Some(String::from("nuhro")),
2220 pr_author: None,
2221 pr_title: None,
2222 pr_number: None,
2223 pr_numbers: vec![],
2224 pr_labels: vec![],
2225 is_first_time: true,
2226 },
2227 RemoteContributor {
2228 username: Some(String::from("awesome_contributor")),
2229 pr_author: None,
2230 pr_title: None,
2231 pr_number: None,
2232 pr_numbers: vec![],
2233 pr_labels: vec![],
2234 is_first_time: true,
2235 },
2236 RemoteContributor {
2237 username: Some(String::from("someone")),
2238 pr_author: None,
2239 pr_title: None,
2240 pr_number: None,
2241 pr_numbers: vec![],
2242 pr_labels: vec![],
2243 is_first_time: true,
2244 },
2245 RemoteContributor {
2246 username: Some(String::from("orhun")),
2247 pr_author: None,
2248 pr_title: Some(String::from("1")),
2249 pr_number: Some(1),
2250 pr_numbers: vec![1],
2251 pr_labels: vec![],
2252 is_first_time: false,
2253 },
2254 ],
2255 };
2256 assert_eq!(expected_metadata, release.bitbucket);
2257
2258 Ok(())
2259 }
2260
2261 #[cfg(feature = "azure_devops")]
2262 #[test]
2263 fn update_azure_devops_metadata() -> Result<()> {
2264 use crate::remote::azure_devops::{
2265 AzureDevOpsCommit, AzureDevOpsCommitAuthor, AzureDevOpsCommitRef,
2266 AzureDevOpsPullRequest, AzureDevOpsUser,
2267 };
2268
2269 let mut release = Release {
2270 version: None,
2271 message: None,
2272 extra: None,
2273 commits: vec![
2274 Commit::from(String::from(
2275 "1d244937ee6ceb8e0314a4a201ba93a7a61f2071 add azure devops integration",
2276 )),
2277 Commit::from(String::from(
2278 "21f6aa587fcb772de13f2fde0e92697c51f84162 fix azure devops integration",
2279 )),
2280 Commit::from(String::from(
2281 "35d8c6b6329ecbcf131d7df02f93c3bbc5ba5973 update metadata",
2282 )),
2283 Commit::from(String::from(
2284 "4d3ffe4753b923f4d7807c490e650e6624a12074 do some stuff",
2285 )),
2286 Commit::from(String::from(
2287 "5a55e92e5a62dc5bf9872ffb2566959fad98bd05 alright",
2288 )),
2289 Commit::from(String::from(
2290 "6c34967147560ea09658776d4901709139b4ad66 should be fine",
2291 )),
2292 ],
2293 commit_range: None,
2294 commit_id: None,
2295 timestamp: None,
2296 previous: Some(Box::new(Release {
2297 version: Some(String::from("1.0.0")),
2298 ..Default::default()
2299 })),
2300 repository: Some(String::from("/root/repo")),
2301 submodule_commits: HashMap::new(),
2302 statistics: None,
2303 bump_type: None,
2304 #[cfg(feature = "github")]
2305 github: RemoteReleaseMetadata {
2306 contributors: vec![],
2307 },
2308 #[cfg(feature = "gitlab")]
2309 gitlab: RemoteReleaseMetadata {
2310 contributors: vec![],
2311 },
2312 #[cfg(feature = "gitea")]
2313 gitea: RemoteReleaseMetadata {
2314 contributors: vec![],
2315 },
2316 #[cfg(feature = "bitbucket")]
2317 bitbucket: RemoteReleaseMetadata {
2318 contributors: vec![],
2319 },
2320 #[cfg(feature = "azure_devops")]
2321 azure_devops: RemoteReleaseMetadata {
2322 contributors: vec![],
2323 },
2324 };
2325 release.update_azure_devops_metadata(
2326 vec![
2327 AzureDevOpsCommit {
2328 commit_id: String::from("1d244937ee6ceb8e0314a4a201ba93a7a61f2071"),
2329 author: Some(AzureDevOpsCommitAuthor {
2330 name: Some(String::from("orhun")),
2331 email: Some(String::from("orhun@example.com")),
2332 date: Some(String::from("2021-07-18T15:14:39+03:00")),
2333 }),
2334 committer: None,
2335 },
2336 AzureDevOpsCommit {
2337 commit_id: String::from("21f6aa587fcb772de13f2fde0e92697c51f84162"),
2338 author: Some(AzureDevOpsCommitAuthor {
2339 name: Some(String::from("orhun")),
2340 email: Some(String::from("orhun@example.com")),
2341 date: Some(String::from("2021-07-18T15:12:19+03:00")),
2342 }),
2343 committer: None,
2344 },
2345 AzureDevOpsCommit {
2346 commit_id: String::from("35d8c6b6329ecbcf131d7df02f93c3bbc5ba5973"),
2347 author: Some(AzureDevOpsCommitAuthor {
2348 name: Some(String::from("nuhro")),
2349 email: Some(String::from("nuhro@example.com")),
2350 date: Some(String::from("2021-07-18T15:07:23+03:00")),
2351 }),
2352 committer: None,
2353 },
2354 AzureDevOpsCommit {
2355 commit_id: String::from("4d3ffe4753b923f4d7807c490e650e6624a12074"),
2356 author: Some(AzureDevOpsCommitAuthor {
2357 name: Some(String::from("awesome_contributor")),
2358 email: Some(String::from("awesome@example.com")),
2359 date: Some(String::from("2021-07-18T15:05:10+03:00")),
2360 }),
2361 committer: None,
2362 },
2363 AzureDevOpsCommit {
2364 commit_id: String::from("5a55e92e5a62dc5bf9872ffb2566959fad98bd05"),
2365 author: Some(AzureDevOpsCommitAuthor {
2366 name: Some(String::from("orhun")),
2367 email: Some(String::from("orhun@example.com")),
2368 date: Some(String::from("2021-07-18T15:03:30+03:00")),
2369 }),
2370 committer: None,
2371 },
2372 AzureDevOpsCommit {
2373 commit_id: String::from("6c34967147560ea09658776d4901709139b4ad66"),
2374 author: Some(AzureDevOpsCommitAuthor {
2375 name: Some(String::from("someone")),
2376 email: Some(String::from("someone@example.com")),
2377 date: Some(String::from("2021-07-18T15:00:38+03:00")),
2378 }),
2379 committer: None,
2380 },
2381 AzureDevOpsCommit {
2382 commit_id: String::from("0c34967147560e809658776d4901709139b4ad68"),
2383 author: Some(AzureDevOpsCommitAuthor {
2384 name: Some(String::from("idk")),
2385 email: Some(String::from("idk@example.com")),
2386 date: Some(String::from("2021-07-18T15:00:01+03:00")),
2387 }),
2388 committer: None,
2389 },
2390 AzureDevOpsCommit {
2391 commit_id: String::from("kk34967147560e809658776d4901709139b4ad68"),
2392 author: Some(AzureDevOpsCommitAuthor {
2393 name: Some(String::from("orhun")),
2394 email: Some(String::from("orhun@example.com")),
2395 date: Some(String::from("2021-07-14T21:25:24+03:00")),
2396 }),
2397 committer: None,
2398 },
2399 ]
2400 .into_iter()
2401 .map(|v| Box::new(v) as Box<dyn RemoteCommit>)
2402 .collect(),
2403 vec![Box::new(AzureDevOpsPullRequest {
2404 pull_request_id: 42,
2405 title: Some(String::from("1")),
2406 status: String::from("completed"),
2407 created_by: Some(AzureDevOpsUser {
2408 display_name: Some(String::from("author-1")),
2409 unique_name: None,
2410 }),
2411 last_merge_commit: Some(AzureDevOpsCommitRef {
2412 commit_id: Some(String::from("1d244937ee6ceb8e0314a4a201ba93a7a61f2071")),
2413 }),
2414 labels: vec![],
2415 })],
2416 )?;
2417 #[allow(deprecated)]
2418 let expected_commits = vec![
2419 Commit {
2420 id: String::from("1d244937ee6ceb8e0314a4a201ba93a7a61f2071"),
2421 message: String::from("add azure devops integration"),
2422 azure_devops: RemoteContributor {
2423 username: Some(String::from("orhun")),
2424 pr_author: Some(String::from("author-1")),
2425 pr_title: Some(String::from("1")),
2426 pr_number: Some(42),
2427 pr_numbers: vec![],
2428 pr_labels: vec![],
2429 is_first_time: false,
2430 },
2431 remote: Some(RemoteContributor {
2432 username: Some(String::from("orhun")),
2433 pr_author: Some(String::from("author-1")),
2434 pr_title: Some(String::from("1")),
2435 pr_number: Some(42),
2436 pr_numbers: vec![],
2437 pr_labels: vec![],
2438 is_first_time: false,
2439 }),
2440 ..Default::default()
2441 },
2442 Commit {
2443 id: String::from("21f6aa587fcb772de13f2fde0e92697c51f84162"),
2444 message: String::from("fix azure devops integration"),
2445 azure_devops: RemoteContributor {
2446 username: Some(String::from("orhun")),
2447 pr_author: None,
2448 pr_title: None,
2449 pr_number: None,
2450 pr_numbers: vec![],
2451 pr_labels: vec![],
2452 is_first_time: false,
2453 },
2454 remote: Some(RemoteContributor {
2455 username: Some(String::from("orhun")),
2456 pr_author: None,
2457 pr_title: None,
2458 pr_number: None,
2459 pr_numbers: vec![],
2460 pr_labels: vec![],
2461 is_first_time: false,
2462 }),
2463 ..Default::default()
2464 },
2465 Commit {
2466 id: String::from("35d8c6b6329ecbcf131d7df02f93c3bbc5ba5973"),
2467 message: String::from("update metadata"),
2468 azure_devops: RemoteContributor {
2469 username: Some(String::from("nuhro")),
2470 pr_author: None,
2471 pr_title: None,
2472 pr_number: None,
2473 pr_numbers: vec![],
2474 pr_labels: vec![],
2475 is_first_time: false,
2476 },
2477 remote: Some(RemoteContributor {
2478 username: Some(String::from("nuhro")),
2479 pr_author: None,
2480 pr_title: None,
2481 pr_number: None,
2482 pr_numbers: vec![],
2483 pr_labels: vec![],
2484 is_first_time: false,
2485 }),
2486 ..Default::default()
2487 },
2488 Commit {
2489 id: String::from("4d3ffe4753b923f4d7807c490e650e6624a12074"),
2490 message: String::from("do some stuff"),
2491 azure_devops: RemoteContributor {
2492 username: Some(String::from("awesome_contributor")),
2493 pr_author: None,
2494 pr_title: None,
2495 pr_number: None,
2496 pr_numbers: vec![],
2497 pr_labels: vec![],
2498 is_first_time: false,
2499 },
2500 remote: Some(RemoteContributor {
2501 username: Some(String::from("awesome_contributor")),
2502 pr_author: None,
2503 pr_title: None,
2504 pr_number: None,
2505 pr_numbers: vec![],
2506 pr_labels: vec![],
2507 is_first_time: false,
2508 }),
2509 ..Default::default()
2510 },
2511 Commit {
2512 id: String::from("5a55e92e5a62dc5bf9872ffb2566959fad98bd05"),
2513 message: String::from("alright"),
2514 azure_devops: RemoteContributor {
2515 username: Some(String::from("orhun")),
2516 pr_author: None,
2517 pr_title: None,
2518 pr_number: None,
2519 pr_numbers: vec![],
2520 pr_labels: vec![],
2521 is_first_time: false,
2522 },
2523 remote: Some(RemoteContributor {
2524 username: Some(String::from("orhun")),
2525 pr_author: None,
2526 pr_title: None,
2527 pr_number: None,
2528 pr_numbers: vec![],
2529 pr_labels: vec![],
2530 is_first_time: false,
2531 }),
2532 ..Default::default()
2533 },
2534 Commit {
2535 id: String::from("6c34967147560ea09658776d4901709139b4ad66"),
2536 message: String::from("should be fine"),
2537 azure_devops: RemoteContributor {
2538 username: Some(String::from("someone")),
2539 pr_author: None,
2540 pr_title: None,
2541 pr_number: None,
2542 pr_numbers: vec![],
2543 pr_labels: vec![],
2544 is_first_time: false,
2545 },
2546 remote: Some(RemoteContributor {
2547 username: Some(String::from("someone")),
2548 pr_author: None,
2549 pr_title: None,
2550 pr_number: None,
2551 pr_numbers: vec![],
2552 pr_labels: vec![],
2553 is_first_time: false,
2554 }),
2555 ..Default::default()
2556 },
2557 ];
2558 assert_eq!(expected_commits, release.commits);
2559
2560 release
2561 .azure_devops
2562 .contributors
2563 .sort_by_key(|a| a.pr_number);
2564
2565 let expected_metadata = RemoteReleaseMetadata {
2566 contributors: vec![
2567 RemoteContributor {
2568 username: Some(String::from("nuhro")),
2569 pr_author: None,
2570 pr_title: None,
2571 pr_number: None,
2572 pr_numbers: vec![],
2573 pr_labels: vec![],
2574 is_first_time: true,
2575 },
2576 RemoteContributor {
2577 username: Some(String::from("awesome_contributor")),
2578 pr_author: None,
2579 pr_title: None,
2580 pr_number: None,
2581 pr_numbers: vec![],
2582 pr_labels: vec![],
2583 is_first_time: true,
2584 },
2585 RemoteContributor {
2586 username: Some(String::from("someone")),
2587 pr_author: None,
2588 pr_title: None,
2589 pr_number: None,
2590 pr_numbers: vec![],
2591 pr_labels: vec![],
2592 is_first_time: true,
2593 },
2594 RemoteContributor {
2595 username: Some(String::from("orhun")),
2596 pr_author: None,
2597 pr_title: Some(String::from("1")),
2598 pr_number: Some(42),
2599 pr_numbers: vec![42],
2600 pr_labels: vec![],
2601 is_first_time: false,
2602 },
2603 ],
2604 };
2605 assert_eq!(expected_metadata, release.azure_devops);
2606
2607 Ok(())
2608 }
2609}