-
Notifications
You must be signed in to change notification settings - Fork 4
✨ Add versioning to election event configs #1855
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
c80dd3b
Add versoning to election event.
omri81 62d280f
cargo fmt
omri81 15919f7
Merge branch 'main' into feat/meta-6333A/main
xalsina-sequent 97fedcd
Added formatting to exported json. Fixed version check.
xalsina-sequent 1c91616
Added version as a sequent-core util
xalsina-sequent 87bb57f
Merge branch 'main' into feat/meta-6333A/main
BelSequent 256ab80
Format
BelSequent ec93d41
Merge remote-tracking branch 'origin/main' into feat/meta-6333A/main
BelSequent e5b5614
Remove not needed build feature
BelSequent File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,176 @@ | ||
| // SPDX-FileCopyrightText: 2025 Sequent Tech Inc <legal@sequentech.io> | ||
| // | ||
| // SPDX-License-Identifier: AGPL-3.0-only | ||
|
|
||
| use anyhow::{anyhow, Result}; | ||
| use tracing::{info, instrument}; | ||
|
|
||
| pub const DEV_APP_VERSION: &str = "dev"; | ||
| pub const ENV_VAR_APP_VERSION: &str = "APP_VERSION"; | ||
| pub const ENV_VAR_APP_HASH: &str = "APP_HASH"; | ||
|
|
||
| pub fn check_version_compatibility( | ||
| imported_version: &str, | ||
| current_version: &str, | ||
| ) -> Result<()> { | ||
| info!( | ||
| "Checking version compatibility - Current: {}, Imported: {}", | ||
| current_version, imported_version | ||
| ); | ||
|
|
||
| // If current version is DEV_APP_VERSION, allow any import | ||
| if current_version == DEV_APP_VERSION { | ||
| info!("Current version is 'dev', allowing import"); | ||
| return Ok(()); | ||
| } | ||
|
|
||
| if imported_version == DEV_APP_VERSION { | ||
| info!("Imported version is 'dev' while system is not in dev mode, rejecting import"); | ||
| return Err(anyhow!("Imported version is 'dev', which is not compatible with current version {}. Please use a different version.", current_version)); | ||
| } | ||
|
|
||
| let current_major_parsed = extract_major(¤t_version) | ||
| .ok_or_else(|| anyhow!("Could not parse current version"))?; | ||
| let imported_major_parsed = extract_major(imported_version) | ||
| .ok_or_else(|| anyhow!("Could not parse imported version"))?; | ||
|
|
||
| if current_major_parsed < imported_major_parsed { | ||
| return Err(anyhow!( | ||
| "Version mismatch: Imported version {} is not compatible with current version {}. Please upgrade your system.", | ||
| imported_version, | ||
| current_version | ||
| )); | ||
| } | ||
| Ok(()) | ||
| } | ||
|
|
||
| fn extract_major(input: &str) -> Option<u64> { | ||
| // Trim optional 'v' or 'V' prefix | ||
| let trimmed = input.trim_start_matches(|c| c == 'v' || c == 'V'); | ||
|
|
||
| // We take characters from the start as long as they are digits. | ||
| // This stops at the first dot '.', hyphen '-', or any non-digit. | ||
| let major_str: String = | ||
| trimmed.chars().take_while(|c| c.is_ascii_digit()).collect(); | ||
|
|
||
| // Parse the result into a u64 | ||
| // If the string was empty (e.g., input was "invalid"), this returns None. | ||
| major_str.parse::<u64>().ok() | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
|
|
||
| // ========================================== | ||
| // Public API Tests: check_version_compatibility | ||
| // ========================================== | ||
|
|
||
| #[test] | ||
| fn test_current_version_is_dev() { | ||
| // If current system is DEV_APP_VERSION, it should accept anything | ||
| assert!(check_version_compatibility("1.0.0", DEV_APP_VERSION).is_ok()); | ||
| assert!( | ||
| check_version_compatibility("99.99.99", DEV_APP_VERSION).is_ok() | ||
| ); | ||
| assert!( | ||
| check_version_compatibility(DEV_APP_VERSION, DEV_APP_VERSION) | ||
| .is_ok() | ||
| ); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_imported_version_is_dev_rejected() { | ||
| // If importing DEV_APP_VERSION into a non-dev system, it must fail | ||
| let result = check_version_compatibility(DEV_APP_VERSION, "1.0.0"); | ||
| assert!(result.is_err()); | ||
| assert_eq!( | ||
| result.unwrap_err().to_string(), | ||
| "Imported version is 'dev', which is not compatible with current version 1.0.0. Please use a different version." | ||
| ); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_exact_match_versions() { | ||
| assert!(check_version_compatibility("1.0.0", "1.0.0").is_ok()); | ||
| assert!(check_version_compatibility("2.5.1", "2.5.1").is_ok()); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_backward_compatibility() { | ||
| // Importing an OLDER version into a NEWER system should be OK | ||
| // Imported: 1, Current: 2 | ||
| assert!(check_version_compatibility("1.0.0", "2.0.0").is_ok()); | ||
|
|
||
| // Imported: 10, Current: 11 | ||
| assert!(check_version_compatibility("10.5.5", "11.0.0").is_ok()); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_forward_compatibility_rejection() { | ||
| // Importing a NEWER version into an OLDER system should FAIL | ||
| // Imported: 2, Current: 1 | ||
| let result = check_version_compatibility("2.0.0", "1.0.0"); | ||
| assert!(result.is_err()); | ||
| assert!(result.unwrap_err().to_string().contains("not compatible")); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_parsing_failures() { | ||
| // Invalid current version | ||
| let res_current = check_version_compatibility("1.0.0", "invalid_ver"); | ||
| assert!(res_current.is_err()); | ||
| assert!(res_current | ||
| .unwrap_err() | ||
| .to_string() | ||
| .contains("Could not parse current version")); | ||
|
|
||
| // Invalid imported version | ||
| let res_imported = check_version_compatibility("invalid_ver", "1.0.0"); | ||
| assert!(res_imported.is_err()); | ||
| assert!(res_imported | ||
| .unwrap_err() | ||
| .to_string() | ||
| .contains("Could not parse imported version")); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_version_prefixes() { | ||
| // Handling 'v' or 'V' prefixes | ||
| // Imported v1 (1) into Current 1 -> OK | ||
| assert!(check_version_compatibility("v1.0.0", "1.0.0").is_ok()); | ||
|
|
||
| // Imported V2 (2) into Current v1 (1) -> Error | ||
| assert!(check_version_compatibility("V2.0.0", "v1.0.0").is_err()); | ||
| } | ||
|
|
||
| // ========================================== | ||
| // Internal Helper Tests: extract_major | ||
| // ========================================== | ||
|
|
||
| #[test] | ||
| fn test_extract_major_logic() { | ||
| // Standard semver | ||
| assert_eq!(extract_major("1.2.3"), Some(1)); | ||
| assert_eq!(extract_major("10.0.0"), Some(10)); | ||
| assert_eq!(extract_major("0.5.9"), Some(0)); | ||
|
|
||
| // With prefixes | ||
| assert_eq!(extract_major("v1.2.3"), Some(1)); | ||
| assert_eq!(extract_major("V2.0.0"), Some(2)); | ||
|
|
||
| // With suffixes (alpha, beta, rc) | ||
| assert_eq!(extract_major("1.0.0-alpha"), Some(1)); | ||
| assert_eq!(extract_major("3.0.0-rc1"), Some(3)); | ||
| assert_eq!(extract_major("v4-beta"), Some(4)); | ||
|
|
||
| // Edge cases | ||
| assert_eq!(extract_major("2"), Some(2)); // Just a number | ||
| assert_eq!(extract_major("not_a_number"), None); | ||
| assert_eq!(extract_major(""), None); | ||
| assert_eq!(extract_major("v"), None); | ||
|
|
||
| // Ensure it stops at non-digits | ||
| assert_eq!(extract_major("5startswithnumber"), Some(5)); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could make older election events import fails if version is not present. We could either add a default value to version or make the parameter optional for backwards compatibilit.