-
Notifications
You must be signed in to change notification settings - Fork 31
Release/260408 #73
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
Release/260408 #73
Changes from all commits
6eb6ff9
04b7557
3694be7
1ac9d0b
ce64a3f
0d4340d
1ccb9ab
b2e5243
20a2d73
056ff81
4270ae7
6d8a69e
a72ce6d
ff3fbf6
d64114a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| name: UpgradeLink Upload | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| inputs: | ||
| tag: | ||
| description: "Release tag to upload (e.g. v1.2.3)" | ||
| required: true | ||
| type: string | ||
|
|
||
| jobs: | ||
| upgradelink-upload: | ||
| permissions: | ||
| contents: read | ||
| runs-on: ubuntu-22.04 | ||
| steps: | ||
| - name: Upload latest.json to UpgradeLink | ||
| uses: toolsetlink/upgradelink-action@3.0.2 | ||
| with: | ||
| access_key: ${{ secrets.UPGRADE_LINK_ACCESS_KEY }} | ||
| access_secret: ${{ secrets.UPGRADE_LINK_ACCESS_SECRET }} | ||
| config: | | ||
| { | ||
| "app_type": "tauri", | ||
| "request": { | ||
| "app_key": "${{ secrets.UPGRADE_LINK_TAURI_KEY }}", | ||
| "latest_json_url": "https://github.com/${{ github.repository }}/releases/download/${{ inputs.tag }}/latest.json" | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,6 +39,10 @@ case "${it_db}" in | |
| run_integration_test "mysql_command_integration" | ||
| run_integration_test "mysql_stateful_command_integration" | ||
| ;; | ||
| starrocks) | ||
| run_integration_test "starrocks_integration" | ||
| run_integration_test "starrocks_command_integration" | ||
| ;; | ||
|
Comment on lines
+42
to
+45
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add StarRocks to the Line 42 adds targeted StarRocks execution, but ✅ Proposed patch all)
+ run_integration_test "starrocks_integration"
+ run_integration_test "starrocks_command_integration"
run_integration_test "mysql_integration"
run_integration_test "mysql_command_integration"
run_integration_test "mysql_stateful_command_integration"Based on learnings: For new database driver additions, follow the step-by-step checklist in ADD_NEW_DB.md for exact file paths, line numbers, and implementation details; update 🤖 Prompt for AI Agents |
||
| mariadb) | ||
| run_integration_test "mariadb_integration" | ||
| run_integration_test "mariadb_command_integration" | ||
|
|
@@ -89,7 +93,7 @@ case "${it_db}" in | |
| run_integration_test "oracle_command_integration" | ||
| ;; | ||
| *) | ||
| echo "[error] Invalid IT_DB='${it_db}'. Expected one of: mysql|mariadb|postgres|clickhouse|mssql|duckdb|sqlite|oracle|all" | ||
| echo "[error] Invalid IT_DB='${it_db}'. Expected one of: mysql|starrocks|mariadb|postgres|clickhouse|mssql|duckdb|sqlite|oracle|all" | ||
| exit 1 | ||
| ;; | ||
| esac | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,7 +18,7 @@ crate-type = ["staticlib", "cdylib", "rlib"] | |
| tauri-build = { version = "2", features = [] } | ||
|
|
||
| [dependencies] | ||
| tauri = { version = "2", features = [] } | ||
| tauri = { version = "2", features = ["devtools"] } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "=== Check Rust/Tauri code paths for devtools usage and debug gating ==="
rg -n -C2 --type=rust --type=toml 'devtools|open_devtools|close_devtools|debug_toggle_devtools|cfg\(debug_assertions\)'
echo
echo "=== Check workflows/scripts for release builds enabling custom features ==="
rg -n -C2 'tauri build|cargo tauri build|--features'Repository: codeErrorSleep/dbpaw Length of output: 3369 🏁 Script executed: #!/bin/bash
# Check Cargo.toml for build profile overrides
echo "=== Check Cargo.toml for build profile configuration ==="
cat -n src-tauri/Cargo.toml | tail -30
echo
echo "=== Check if menu creation has any conditional guards ==="
rg -n -B5 -A5 'developer_menu' src-tauri/src/lib.rsRepository: codeErrorSleep/dbpaw Length of output: 2958 🏁 Script executed: #!/bin/bash
# Check for any release profile configuration in full Cargo.toml
echo "=== Full Cargo.toml to check for [profile.release] section ==="
wc -l src-tauri/Cargo.toml
cat -n src-tauri/Cargo.toml | grep -A10 '\[profile'Repository: codeErrorSleep/dbpaw Length of output: 150 🏁 Script executed: #!/bin/bash
# Show entire Cargo.toml
echo "=== Full Cargo.toml content ==="
cat -n src-tauri/Cargo.tomlRepository: codeErrorSleep/dbpaw Length of output: 2254 Disable Tauri The 🔧 Suggested approach [dependencies]
-tauri = { version = "2", features = ["devtools"] }
+tauri = { version = "2" }
+
+[features]
+default = []
+devtools = ["tauri/devtools"]Enable 🤖 Prompt for AI Agents |
||
| tauri-plugin-opener = "2" | ||
| tauri-plugin-dialog = "2" | ||
| tauri-plugin-fs = "2" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -267,7 +267,7 @@ pub async fn create_database_by_id( | |
| } | ||
|
|
||
| let exec_res = match driver.as_str() { | ||
| "mysql" | "mariadb" | "tidb" => { | ||
| driver if crate::db::drivers::is_mysql_family_driver(driver) => { | ||
| let sql = build_mysql_create_database_sql(&payload, &db_name)?; | ||
| super::execute_with_retry(&state, id, None, |driver| { | ||
| let sql_clone = sql.clone(); | ||
|
|
@@ -348,7 +348,7 @@ pub async fn create_database_by_id_direct( | |
| } | ||
|
|
||
| let exec_res = match driver.as_str() { | ||
| "mysql" | "mariadb" | "tidb" => { | ||
| driver if crate::db::drivers::is_mysql_family_driver(driver) => { | ||
| let sql = build_mysql_create_database_sql(&payload, &db_name)?; | ||
| super::execute_with_retry_from_app_state(state, id, None, |driver| { | ||
| let sql_clone = sql.clone(); | ||
|
|
@@ -419,6 +419,122 @@ pub async fn test_connection_ephemeral( | |
| }) | ||
| } | ||
|
|
||
| #[tauri::command] | ||
| pub async fn get_mysql_charsets_by_id( | ||
| state: State<'_, AppState>, | ||
| id: i64, | ||
| ) -> Result<Vec<String>, String> { | ||
| super::execute_with_retry(&state, id, None, |driver| async move { | ||
| let result = driver | ||
| .execute_query("SHOW CHARACTER SET".to_string()) | ||
| .await?; | ||
| let mut charsets: Vec<String> = result | ||
| .data | ||
| .iter() | ||
| .filter_map(|row| { | ||
| row.get("Charset") | ||
| .and_then(|v| v.as_str()) | ||
| .map(|s| s.to_string()) | ||
| }) | ||
| .collect(); | ||
| charsets.sort(); | ||
| Ok(charsets) | ||
| }) | ||
| .await | ||
| } | ||
|
|
||
| #[tauri::command] | ||
| pub async fn get_mysql_collations_by_id( | ||
| state: State<'_, AppState>, | ||
| id: i64, | ||
| charset: Option<String>, | ||
| ) -> Result<Vec<String>, String> { | ||
| let sql = match &charset { | ||
| Some(cs) if is_safe_option_token(cs) => { | ||
| format!("SHOW COLLATION WHERE Charset = '{}'", cs) | ||
| } | ||
| Some(cs) => { | ||
| return Err(format!("[VALIDATION_ERROR] Invalid charset: {}", cs)); | ||
| } | ||
| None => "SHOW COLLATION".to_string(), | ||
| }; | ||
| super::execute_with_retry(&state, id, None, |driver| { | ||
| let sql = sql.clone(); | ||
| async move { | ||
| let result = driver.execute_query(sql).await?; | ||
| let mut collations: Vec<String> = result | ||
| .data | ||
| .iter() | ||
| .filter_map(|row| { | ||
| row.get("Collation") | ||
| .and_then(|v| v.as_str()) | ||
| .map(|s| s.to_string()) | ||
| }) | ||
| .collect(); | ||
| collations.sort(); | ||
| Ok(collations) | ||
| } | ||
| }) | ||
| .await | ||
| } | ||
|
Comment on lines
+422
to
+479
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reject non-MySQL connections before running these queries. These handlers currently execute Also applies to: 481-536 🤖 Prompt for AI Agents |
||
|
|
||
| pub async fn get_mysql_charsets_by_id_direct( | ||
| state: &AppState, | ||
| id: i64, | ||
| ) -> Result<Vec<String>, String> { | ||
| super::execute_with_retry_from_app_state(state, id, None, |driver| async move { | ||
| let result = driver | ||
| .execute_query("SHOW CHARACTER SET".to_string()) | ||
| .await?; | ||
| let mut charsets: Vec<String> = result | ||
| .data | ||
| .iter() | ||
| .filter_map(|row| { | ||
| row.get("Charset") | ||
| .and_then(|v| v.as_str()) | ||
| .map(|s| s.to_string()) | ||
| }) | ||
| .collect(); | ||
| charsets.sort(); | ||
| Ok(charsets) | ||
| }) | ||
| .await | ||
| } | ||
|
|
||
| pub async fn get_mysql_collations_by_id_direct( | ||
| state: &AppState, | ||
| id: i64, | ||
| charset: Option<String>, | ||
| ) -> Result<Vec<String>, String> { | ||
| let sql = match &charset { | ||
| Some(cs) if is_safe_option_token(cs) => { | ||
| format!("SHOW COLLATION WHERE Charset = '{}'", cs) | ||
| } | ||
| Some(cs) => { | ||
| return Err(format!("[VALIDATION_ERROR] Invalid charset: {}", cs)); | ||
| } | ||
| None => "SHOW COLLATION".to_string(), | ||
| }; | ||
| super::execute_with_retry_from_app_state(state, id, None, |driver| { | ||
| let sql = sql.clone(); | ||
| async move { | ||
| let result = driver.execute_query(sql).await?; | ||
| let mut collations: Vec<String> = result | ||
| .data | ||
| .iter() | ||
| .filter_map(|row| { | ||
| row.get("Collation") | ||
| .and_then(|v| v.as_str()) | ||
| .map(|s| s.to_string()) | ||
| }) | ||
| .collect(); | ||
| collations.sort(); | ||
| Ok(collations) | ||
| } | ||
| }) | ||
| .await | ||
| } | ||
|
|
||
| #[tauri::command] | ||
| pub async fn get_connections(state: State<'_, AppState>) -> Result<Vec<Connection>, String> { | ||
| let local_db = { | ||
|
|
@@ -553,8 +669,8 @@ mod tests { | |
| validate_database_name, CreateDatabasePayload, | ||
| }; | ||
| use super::{ | ||
| normalize_create_database_error, normalize_option_token, quote_clickhouse_ident, | ||
| quote_mssql_ident, quote_mysql_ident, quote_pg_ident, | ||
| is_safe_option_token, normalize_create_database_error, normalize_option_token, | ||
| quote_clickhouse_ident, quote_mssql_ident, quote_mysql_ident, quote_pg_ident, | ||
| }; | ||
| use crate::connection_input::normalize_connection_form; | ||
| use crate::models::ConnectionForm; | ||
|
|
@@ -734,4 +850,52 @@ mod tests { | |
| .unwrap_err(); | ||
| assert!(err.contains("does not support charset option")); | ||
| } | ||
|
|
||
| #[test] | ||
| fn get_mysql_collations_charset_validation_rejects_unsafe_tokens() { | ||
| // Verify the validation logic used by get_mysql_collations_by_id/_direct. | ||
| // A charset with spaces or semicolons must be rejected. | ||
| assert!(!is_safe_option_token("utf8 mb4")); | ||
| assert!(!is_safe_option_token("utf8;drop")); | ||
| assert!(!is_safe_option_token("")); | ||
| } | ||
|
|
||
| #[test] | ||
| fn get_mysql_collations_charset_validation_accepts_valid_charsets() { | ||
| // All standard MySQL charset names must pass the token check. | ||
| let valid = [ | ||
| "utf8mb4", | ||
| "utf8", | ||
| "latin1", | ||
| "gbk", | ||
| "gb18030", | ||
| "ascii", | ||
| "binary", | ||
| "utf8mb4_0900_ai_ci", | ||
| ]; | ||
| for cs in valid { | ||
| assert!(is_safe_option_token(cs), "expected '{}' to be accepted", cs); | ||
| } | ||
| } | ||
|
|
||
| #[test] | ||
| fn mysql_create_database_sql_is_reusable_for_starrocks_connections() { | ||
| assert!(crate::db::drivers::is_mysql_family_driver("starrocks")); | ||
|
|
||
| let sql = build_mysql_create_database_sql( | ||
| &CreateDatabasePayload { | ||
| name: "analytics".to_string(), | ||
| if_not_exists: Some(true), | ||
| charset: None, | ||
| collation: None, | ||
| encoding: None, | ||
| lc_collate: None, | ||
| lc_ctype: None, | ||
| }, | ||
| "analytics", | ||
| ) | ||
| .unwrap(); | ||
|
|
||
| assert_eq!(sql, "CREATE DATABASE IF NOT EXISTS `analytics`"); | ||
| } | ||
| } | ||
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.
🧩 Analysis chain
🏁 Script executed:
Repository: codeErrorSleep/dbpaw
Length of output: 104
Pin third-party GitHub Action to an immutable commit SHA.
Using
@3.0.2is mutable and can be retargeted. For release workflows, pin to a full commit SHA instead.🔒 Suggested change
🤖 Prompt for AI Agents