Skip to content

automatically set release version#70

Merged
Panaetius merged 1 commit intomainfrom
automatic-release-version
Mar 5, 2026
Merged

automatically set release version#70
Panaetius merged 1 commit intomainfrom
automatic-release-version

Conversation

@Panaetius
Copy link
Member

No description provided.

@Panaetius Panaetius requested a review from a team as a code owner March 5, 2026 09:39
@github-actions
Copy link

github-actions bot commented Mar 5, 2026

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Login flow logic

The login flow now includes automatic selection and setting of the compute platform and CSCS account. Ensure this behavior is intentional and doesn't override user preferences when they are already set.

Ok(_) => {
    let mut config = match Config::new() {
        Ok(config) => config,
        Err(e) => {
            error_tx
                .send(format!(
                    "{:?}",
                    Err::<(), Report>(e).wrap_err("Couldn't create config object")
                ))
                .await
                .unwrap();
            return;
        }
    };
    let source = config.value_source("cscs.current_platform");
    if !source.1 && !source.2 {
        // don't override platform if it's already set
        if let Ok(available_platforms) = get_available_compute_platforms().await
            && !available_platforms.is_empty()
            && let Err(e) = config.set(
                "cscs.current_platform",
                available_platforms[0].to_string(),
                true,
            )
        {
            error_tx
                .send(format!(
                    "{:?}",
                    Err::<(), Report>(e).wrap_err("Couldn't set currnt platform")
                ))
                .await
                .unwrap();
            return;
        }
    }
    event_tx.send(UserEvent::Cscs(CscsEvent::LoggedIn)).await.unwrap()
}
Platform detection logic

The get_available_compute_platforms function iterates through all platforms and checks if the API client can list systems. This could be inefficient or cause issues if some platforms are inaccessible or slow to respond.

pub(crate) async fn get_available_compute_platforms() -> Result<Vec<ComputePlatform>> {
    match get_access_token().await {
        Ok(access_token) => {
            let mut platforms = Vec::new();
            for platform in ComputePlatform::iter() {
                let api_client = CscsApi::new(access_token.0.clone(), Some(platform.clone())).unwrap();
                if (api_client.list_systems().await).is_ok() {
                    platforms.push(platform);
                }
            }
            Ok(platforms)
        }
        Err(e) => Err(e),
    }
}
Version handling

The workflow now sets COMAN_RELEASE_VERSION from the GitHub release tag. Verify that the version stripping logic correctly handles all expected tag formats.

env:
  COMAN_RELEASE_VERSION: ${{ github.event.release.tag_name }}
strategy:
  matrix:
    platform:
      - os_name: Linux-x86_64
        os: ubuntu-latest
        target: x86_64-unknown-linux-musl
        bin: coman
        name: coman-x86_64-unknown-linux-musl.tar.gz
        cargo_command: cargo
        squash: true

      - os_name: Linux-aarch64
        os: ubuntu-24.04-arm
        target: aarch64-unknown-linux-musl
        bin: coman
        name: coman-aarch64-unknown-linux-musl.tar.gz
        cargo_command: cargo
        squash: true

      - os_name: Windows-x86_64
        os: windows-latest
        target: x86_64-pc-windows-msvc
        bin: coman.exe
        name: coman-x86_64-pc-windows-msvc.zip
        cargo_command: cargo
        squash: false

      - os_name: macOS-x86_64
        os: macOS-latest
        target: x86_64-apple-darwin
        bin: coman
        name: coman-x86_64-apple-darwin.tar.gz
        cargo_command: cargo
        squash: false

runs-on: ${{ matrix.platform.os }}
steps:
  - name: Checkout
    uses: actions/checkout@v5
  - name: Strip version leading v
    run: echo "COMAN_RELEASE_VERSION=${COMAN_RELEASE_VERSION##v}" >> $GITHUB_ENV
  - name: Install toolchain

@github-actions
Copy link

github-actions bot commented Mar 5, 2026

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Handle errors when fetching available platforms

The code does not handle the case where get_available_compute_platforms() returns an
error. This could lead to unexpected behavior when setting the default platform.
Consider propagating the error instead of silently continuing.

coman/src/app/model.rs [513-549]

                             Ok(_) => {
                                 let mut config = match Config::new() {
                                     Ok(config) => config,
                                     Err(e) => {
                                         error_tx
                                             .send(format!(
                                                 "{:?}",
                                                 Err::<(), Report>(e).wrap_err("Couldn't create config object")
                                             ))
                                             .await
                                             .unwrap();
                                         return;
                                     }
                                 };
                                 let source = config.value_source("cscs.current_platform");
                                 if !source.1 && !source.2 {
                                     // don't override platform if it's already set
                                     if let Ok(available_platforms) = get_available_compute_platforms().await
                                         && !available_platforms.is_empty()
-                                        && let Err(e) = config.set(
+                                    {
+                                        if let Err(e) = config.set(
                                             "cscs.current_platform",
                                             available_platforms[0].to_string(),
                                             true,
-                                        )
-                                    {
+                                        ) {
+                                            error_tx
+                                                .send(format!(
+                                                    "{:?}",
+                                                    Err::<(), Report>(e).wrap_err("Couldn't set current platform")
+                                                ))
+                                                .await
+                                                .unwrap();
+                                            return;
+                                        }
+                                    } else {
+                                        // Handle case where no platforms are available or error occurred
                                         error_tx
-                                            .send(format!(
-                                                "{:?}",
-                                                Err::<(), Report>(e).wrap_err("Couldn't set currnt platform")
-                                            ))
+                                            .send("No available compute platforms found".to_string())
                                             .await
                                             .unwrap();
                                         return;
                                     }
                                 }
                                 event_tx.send(UserEvent::Cscs(CscsEvent::LoggedIn)).await.unwrap()
                             }
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a potential issue where errors from get_available_compute_platforms() are not properly handled, which could lead to unexpected behavior. The improved code adds proper error handling and a fallback mechanism, enhancing robustness.

Medium
Improve error handling for platform selection

The code uses unwrap_or which can panic if get_available_compute_platforms() fails.
This should be handled more gracefully to prevent application crashes.

coman/src/cscs/cli.rs [49-54]

-    let available_platforms: Vec<_> = get_available_compute_platforms()
-            .await
-            .unwrap_or(<ComputePlatform as VariantArray>::VARIANTS.to_vec())
-            .iter()
-            .map(|c| c.to_string())
-            .collect();
+    let available_platforms: Vec<_> = match get_available_compute_platforms().await {
+        Ok(platforms) => platforms.iter().map(|c| c.to_string()).collect(),
+        Err(_) => <ComputePlatform as VariantArray>::VARIANTS.to_vec().iter().map(|c| c.to_string()).collect(),
+    };
Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies a potential panic due to unwrap_or usage. The improved code handles the error more gracefully, preventing application crashes. However, it's a medium impact improvement as the existing code would still work in most cases.

Low
General
Reintroduce automatic platform selection

The function cscs_login no longer sets the default compute platform automatically.
This may cause issues for users who expect automatic platform selection. Consider
re-introducing this logic or documenting the change.

coman/src/cscs/handlers.rs [84-92]

  pub(crate) async fn cscs_login(client_id: String, client_secret: String) -> Result<()> {
     let client_id_secret = Secret::new(client_id);
     store_secret(CLIENT_ID_SECRET_NAME, client_id_secret.clone()).await?;
     let client_secret_secret = Secret::new(client_secret);
     store_secret(CLIENT_SECRET_SECRET_NAME, client_secret_secret.clone()).await?;
     client_credentials_login(client_id_secret, client_secret_secret)
         .await
-        .map(|_| ())
+        .map(|_| ())?;
+    
+    // Set default compute platform if not already set
+    let mut config = Config::new()?;
+    let source = config.value_source("cscs.current_platform");
+    if !source.1 && !source.2 {
+        let available_platforms = get_available_compute_platforms().await?;
+        if !available_platforms.is_empty() {
+            config.set("cscs.current_platform", available_platforms[0].to_string(), true)?;
+        }
+    }
+    Ok(())
 }
Suggestion importance[1-10]: 7

__

Why: This suggestion points out a functional change where automatic platform selection was removed from cscs_login. While the suggestion provides a way to reintroduce this behavior, it's a moderate improvement since the core functionality remains intact but the UX might be affected.

Medium

[package]
name = "coman"
version = "0.8.9"
edition = "2024"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Version field was removed, ensure this is intentional and that versioning is handled elsewhere.

#ai-review-inline

env!("VERGEN_BUILD_DATE"),
")"
);
const VERSION_MESSAGE: &str = concat!(env!("CARGO_PKG_VERSION"), " (", env!("VERGEN_BUILD_DATE"), ")");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The VERSION_MESSAGE now omits the git describe information which might reduce debuggability.

Suggested change
const VERSION_MESSAGE: &str = concat!(env!("CARGO_PKG_VERSION"), " (", env!("VERGEN_BUILD_DATE"), ")");
Consider re-adding the git describe info for better version tracking in production builds.

#ai-review-inline

release:
name: Release - ${{ matrix.platform.os_name }}
env:
COMAN_RELEASE_VERSION: ${{ github.event.release.tag_name }}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The environment variable COMAN_RELEASE_VERSION is set but may not be used elsewhere in the workflow.

#ai-review-inline

- name: Checkout
uses: actions/checkout@v5
- name: Strip version leading v
run: echo "COMAN_RELEASE_VERSION=${COMAN_RELEASE_VERSION##v}" >> $GITHUB_ENV
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The command to strip 'v' prefix might fail if tag_name is empty or malformed.

#ai-review-inline

// select cscs account
let source = config.value_source("cscs.account");
if !source.1
&& !source.2
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chained conditions with && can reduce readability; consider extracting into a helper function or variable.

#ai-review-inline

if !source.1 && !source.2 {
let available_platforms: Vec<_> = get_available_compute_platforms()
.await
.unwrap_or(<ComputePlatform as VariantArray>::VARIANTS.to_vec())
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using unwrap_or with a static list might hide errors; consider propagating the error instead.

#ai-review-inline

let mut config = Config::new()?;

let source = config.value_source("cscs.current_platform");
if !source.1 && !source.2 {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition '!source.1 && !source.2' may be unclear; consider using a more explicit check or adding a comment.

#ai-review-inline

// Returns tuple of bool saying whether a values is set in (default, global, project local) config
pub fn value_source(&self, key_path: &str) -> Result<(bool, bool, bool)> {
Ok((
pub fn value_source(&self, key_path: &str) -> (bool, bool, bool) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed return type from Result to tuple, which could hide errors in calling code if not handled properly.

Suggested change
pub fn value_source(&self, key_path: &str) -> (bool, bool, bool) {
Consider keeping Result for better error propagation unless there's a specific reason to change.

#ai-review-inline

use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};
use strum_macros::{EnumIter, EnumString, VariantNames};
use strum_macros::{EnumIter, EnumString, VariantArray, VariantNames};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added VariantArray derive macro which may increase memory usage for enums with many variants.

Suggested change
use strum_macros::{EnumIter, EnumString, VariantArray, VariantNames};
Ensure that adding VariantArray is intentional and doesn't impact performance negatively.

#ai-review-inline

}

#[derive(Clone, Debug, Serialize, Deserialize, Default, strum::Display, EnumString, VariantNames, EnumIter)]
#[derive(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The enum definition now includes VariantArray, which requires careful consideration of memory and compile-time costs.

Suggested change
#[derive(
Verify that this addition aligns with performance requirements of the application.

#ai-review-inline

use vergen_gix::{BuildBuilder, CargoBuilder, Emitter, GixBuilder};

fn main() -> Result<()> {
if let Ok(val) = std::env::var("COMAN_RELEASE_VERSION") {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding error handling for the environment variable parsing to avoid unexpected behavior if the variable is not a valid string.

Suggested change
if let Ok(val) = std::env::var("COMAN_RELEASE_VERSION") {
if let Ok(val) = std::env::var("COMAN_RELEASE_VERSION") {
println!("cargo:rustc-env=CARGO_PKG_VERSION={}", val);
} else {
eprintln!("Warning: COMAN_RELEASE_VERSION not set or invalid");
}

#ai-review-inline

if let Ok(val) = std::env::var("COMAN_RELEASE_VERSION") {
println!("cargo:rustc-env=CARGO_PKG_VERSION={}", val);
}
println!("cargo:rerun-if-env-changed=COMAN_RELEASE_VERSION");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rerun-if-env-changed instruction should be placed before any conditional logic to ensure proper dependency tracking.

Suggested change
println!("cargo:rerun-if-env-changed=COMAN_RELEASE_VERSION");
println!("cargo:rerun-if-env-changed=COMAN_RELEASE_VERSION");
if let Ok(val) = std::env::var("COMAN_RELEASE_VERSION") {
println!("cargo:rustc-env=CARGO_PKG_VERSION={}", val);
}

#ai-review-inline

tokio::spawn(async move {
match cscs_login(client_id, client_secret).await {
Ok(_) => event_tx.send(UserEvent::Cscs(CscsEvent::LoggedIn)).await.unwrap(),
Ok(_) => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider extracting the config setup and platform logic into a separate function for better readability and testability.

Suggested change
Ok(_) => {
let mut config = match Config::new() {
Ok(config) => config,
Err(e) => {
error_tx
.send(format!(
"{:#?}",
Err::<(), Report>(e).wrap_err("Couldn't create config object")
))
.await
.unwrap();
return;
}
};
let source = config.value_source("cscs.current_platform");
if !source.1 && !source.2 {
// don't override platform if it's already set
if let Ok(available_platforms) = get_available_compute_platforms().await
&& !available_platforms.is_empty()
&& let Err(e) = config.set(
"cscs.current_platform",
available_platforms[0].to_string(),
true,
)
{
error_tx
.send(format!(
"{:#?}",
Err::<(), Report>(e).wrap_err("Couldn't set currnt platform")
))
.await
.unwrap();
return;
}
}
event_tx.send(UserEvent::Cscs(CscsEvent::LoggedIn)).await.unwrap()

#ai-review-inline

if (api_client.list_systems().await).is_ok() {
config.set("cscs.current_platform", platform.to_string(), true)?;
break;
client_credentials_login(client_id_secret, client_secret_secret)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function now returns unit type () instead of the token, which may break callers expecting the token.

Suggested change
client_credentials_login(client_id_secret, client_secret_secret)
Consider returning the token or updating callers to handle the new signature.

#ai-review-inline

}
}
Ok(platforms)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning Ok(()) here may hide important context about whether the token was successfully retrieved.

Suggested change
}
Return the token or a meaningful result indicating success/failure.

#ai-review-inline

Ok(access_token) => {
let mut platforms = Vec::new();
for platform in ComputePlatform::iter() {
let api_client = CscsApi::new(access_token.0.clone(), Some(platform.clone())).unwrap();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using unwrap() can cause a panic if CscsApi::new fails; consider handling the error more gracefully.

Suggested change
let api_client = CscsApi::new(access_token.0.clone(), Some(platform.clone())).unwrap();
Replace `unwrap()` with proper error handling like `?` or a `match` expression.

#ai-review-inline

@Panaetius Panaetius force-pushed the automatic-release-version branch from a789037 to e41db2a Compare March 5, 2026 09:42
@Panaetius Panaetius force-pushed the automatic-release-version branch from e41db2a to b76e73a Compare March 5, 2026 09:47
@Panaetius Panaetius merged commit a94b8f6 into main Mar 5, 2026
2 checks passed
@Panaetius Panaetius deleted the automatic-release-version branch March 5, 2026 10:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant