Skip to content

Commit cca1d21

Browse files
committed
ci: improve Spin CLI installation with manual download and code formatting
Replace the automated Spin CLI installation script with a manual download approach that provides better architecture detection, error handling, and version pinning. This ensures more reliable CI builds across different platforms. Additionally, apply consistent code formatting across Rust source files to improve code readability and maintainability. Changes include: - Better struct field formatting - Improved function parameter alignment - Consistent line breaking for long expressions
1 parent 93c52bb commit cca1d21

File tree

4 files changed

+188
-35
lines changed

4 files changed

+188
-35
lines changed

.github/workflows/ci.yml

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,35 @@ jobs:
172172

173173
- name: Install Spin CLI
174174
run: |
175-
# Pin Spin CLI version via env var
176-
curl -fsSL https://developer.fermyon.com/downloads/spin/install.sh | bash
175+
set -euo pipefail
176+
ver="${SPIN_VERSION:-2.7.0}"
177+
os="linux"
178+
arch="$(uname -m)"
179+
case "$arch" in
180+
x86_64) arch="amd64" ;;
181+
aarch64|arm64) arch="arm64" ;;
182+
*) echo "Unsupported arch: $arch" >&2; exit 1 ;;
183+
esac
184+
url="https://github.com/fermyon/spin/releases/download/v${ver}/spin-v${ver}-${os}-${arch}.tar.gz"
185+
echo "Downloading Spin from $url"
186+
mkdir -p "$HOME/.spin/bin"
187+
tmpdir="$(mktemp -d)"
188+
curl -fsSL "$url" -o "$tmpdir/spin.tgz"
189+
tar -xzf "$tmpdir/spin.tgz" -C "$tmpdir"
190+
# Find the spin binary and install it
191+
spincandidate="$(find "$tmpdir" -type f -name spin -perm -111 | head -n1 || true)"
192+
if [ -z "$spincandidate" ]; then
193+
# Some archives contain 'spin' without exec bit; try any matching file
194+
spincandidate="$(find "$tmpdir" -type f -name spin | head -n1 || true)"
195+
fi
196+
if [ -z "$spincandidate" ]; then
197+
echo "Failed to locate 'spin' in archive" >&2
198+
ls -R "$tmpdir" >&2 || true
199+
exit 1
200+
fi
201+
install -m 0755 "$spincandidate" "$HOME/.spin/bin/spin"
177202
echo "$HOME/.spin/bin" >> "$GITHUB_PATH"
203+
"$HOME/.spin/bin/spin" --version
178204
179205
- name: Verify Spin version
180206
run: |

apps/e2e-keel/src/lib.rs

Lines changed: 104 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
use anyhow::Result;
22
use serde::{Deserialize, Serialize};
3-
use spin_sdk::{http::{Method, Request, Response}, http_component, sqlite::{Connection, Value}};
3+
use spin_sdk::{
4+
http::{Method, Request, Response},
5+
http_component,
6+
sqlite::{Connection, Value},
7+
};
48
use urlencoding::decode;
59

610
#[derive(Serialize, Deserialize)]
@@ -22,7 +26,14 @@ fn handle_e2e(req: Request) -> Result<Response> {
2226
(m, "/test/users-add") if *m == Method::Get => users_add_via_query(req),
2327
(m, "/txn/commit") if *m == Method::Post || *m == Method::Get => txn_commit(),
2428
(m, "/txn/rollback") if *m == Method::Post || *m == Method::Get => txn_rollback(),
25-
_ => json(404, &ApiResponse::<()> { ok: false, data: None, error: Some("not found".into()) }),
29+
_ => json(
30+
404,
31+
&ApiResponse::<()> {
32+
ok: false,
33+
data: None,
34+
error: Some("not found".into()),
35+
},
36+
),
2637
}
2738
}
2839

@@ -38,14 +49,27 @@ fn json<T: Serialize>(status: u16, val: &T) -> Result<Response> {
3849
fn setup() -> Result<Response> {
3950
let db = Connection::open_default()?;
4051
db.execute("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, email TEXT)", &[])?;
41-
db.execute("CREATE TABLE IF NOT EXISTS accounts (id INTEGER PRIMARY KEY AUTOINCREMENT, balance INTEGER)", &[])?;
52+
db.execute(
53+
"CREATE TABLE IF NOT EXISTS accounts (id INTEGER PRIMARY KEY AUTOINCREMENT, balance INTEGER)",
54+
&[],
55+
)?;
4256
db.execute("DELETE FROM users", &[])?;
4357
db.execute("DELETE FROM accounts", &[])?;
44-
json(200, &ApiResponse::<()> { ok: true, data: None, error: None })
58+
json(
59+
200,
60+
&ApiResponse::<()> {
61+
ok: true,
62+
data: None,
63+
error: None,
64+
},
65+
)
4566
}
4667

4768
#[derive(Deserialize)]
48-
struct NewUser { name: String, email: String }
69+
struct NewUser {
70+
name: String,
71+
email: String,
72+
}
4973

5074
fn create_user(req: Request) -> Result<Response> {
5175
let db = Connection::open_default()?;
@@ -55,11 +79,22 @@ fn create_user(req: Request) -> Result<Response> {
5579
"INSERT INTO users (name, email) VALUES (?, ?)",
5680
&[Value::Text(nu.name), Value::Text(nu.email)],
5781
)?;
58-
json(200, &ApiResponse::<()> { ok: true, data: None, error: None })
82+
json(
83+
200,
84+
&ApiResponse::<()> {
85+
ok: true,
86+
data: None,
87+
error: None,
88+
},
89+
)
5990
}
6091

6192
#[derive(Serialize)]
62-
struct UserOut { id: i64, name: String, email: String }
93+
struct UserOut {
94+
id: i64,
95+
name: String,
96+
email: String,
97+
}
6398

6499
fn list_users() -> Result<Response> {
65100
let db = Connection::open_default()?;
@@ -69,9 +104,20 @@ fn list_users() -> Result<Response> {
69104
let id: i64 = row.get(0).unwrap_or_default();
70105
let name: &str = row.get(1).unwrap_or("");
71106
let email: &str = row.get(2).unwrap_or("");
72-
users.push(UserOut { id, name: name.to_string(), email: email.to_string() });
107+
users.push(UserOut {
108+
id,
109+
name: name.to_string(),
110+
email: email.to_string(),
111+
});
73112
}
74-
json(200, &ApiResponse { ok: true, data: Some(users), error: None })
113+
json(
114+
200,
115+
&ApiResponse {
116+
ok: true,
117+
data: Some(users),
118+
error: None,
119+
},
120+
)
75121
}
76122

77123
fn users_add_via_query(req: Request) -> Result<Response> {
@@ -80,7 +126,7 @@ fn users_add_via_query(req: Request) -> Result<Response> {
80126
let mut name: Option<String> = None;
81127
let mut email: Option<String> = None;
82128
if let Some(idx) = qs.find('?') {
83-
let q = &qs[idx+1..];
129+
let q = &qs[idx + 1..];
84130
for pair in q.split('&') {
85131
let mut it = pair.splitn(2, '=');
86132
if let (Some(k), Some(v)) = (it.next(), it.next()) {
@@ -99,9 +145,23 @@ fn users_add_via_query(req: Request) -> Result<Response> {
99145
"INSERT INTO users (name, email) VALUES (?, ?)",
100146
&[Value::Text(n), Value::Text(e)],
101147
)?;
102-
json(200, &ApiResponse::<()> { ok: true, data: None, error: None })
148+
json(
149+
200,
150+
&ApiResponse::<()> {
151+
ok: true,
152+
data: None,
153+
error: None,
154+
},
155+
)
103156
}
104-
_ => json(400, &ApiResponse::<()> { ok: false, data: None, error: Some("missing name or email".into()) })
157+
_ => json(
158+
400,
159+
&ApiResponse::<()> {
160+
ok: false,
161+
data: None,
162+
error: Some("missing name or email".into()),
163+
},
164+
),
105165
}
106166
}
107167

@@ -110,25 +170,51 @@ fn txn_commit() -> Result<Response> {
110170
db.execute("DELETE FROM accounts", &[])?;
111171
db.execute("INSERT INTO accounts (balance) VALUES (100), (200)", &[])?;
112172
db.execute("BEGIN", &[])?;
113-
db.execute("UPDATE accounts SET balance = balance - 50 WHERE id = 1", &[])?;
114-
db.execute("UPDATE accounts SET balance = balance + 50 WHERE id = 2", &[])?;
173+
db.execute(
174+
"UPDATE accounts SET balance = balance - 50 WHERE id = 1",
175+
&[],
176+
)?;
177+
db.execute(
178+
"UPDATE accounts SET balance = balance + 50 WHERE id = 2",
179+
&[],
180+
)?;
115181
db.execute("COMMIT", &[])?;
116182
let qr = db.execute("SELECT balance FROM accounts ORDER BY id", &[])?;
117183
let b0: i64 = qr.rows.first().and_then(|r| r.get(0)).unwrap_or_default();
118184
let b1: i64 = qr.rows.get(1).and_then(|r| r.get(0)).unwrap_or_default();
119-
json(200, &ApiResponse { ok: true, data: Some(vec![b0, b1]), error: None })
185+
json(
186+
200,
187+
&ApiResponse {
188+
ok: true,
189+
data: Some(vec![b0, b1]),
190+
error: None,
191+
},
192+
)
120193
}
121194

122195
fn txn_rollback() -> Result<Response> {
123196
let db = Connection::open_default()?;
124197
db.execute("DELETE FROM accounts", &[])?;
125198
db.execute("INSERT INTO accounts (balance) VALUES (100), (200)", &[])?;
126199
db.execute("BEGIN", &[])?;
127-
db.execute("UPDATE accounts SET balance = balance - 50 WHERE id = 1", &[])?;
128-
db.execute("UPDATE accounts SET balance = balance + 50 WHERE id = 2", &[])?;
200+
db.execute(
201+
"UPDATE accounts SET balance = balance - 50 WHERE id = 1",
202+
&[],
203+
)?;
204+
db.execute(
205+
"UPDATE accounts SET balance = balance + 50 WHERE id = 2",
206+
&[],
207+
)?;
129208
db.execute("ROLLBACK", &[])?;
130209
let qr = db.execute("SELECT balance FROM accounts ORDER BY id", &[])?;
131210
let b0: i64 = qr.rows.first().and_then(|r| r.get(0)).unwrap_or_default();
132211
let b1: i64 = qr.rows.get(1).and_then(|r| r.get(0)).unwrap_or_default();
133-
json(200, &ApiResponse { ok: true, data: Some(vec![b0, b1]), error: None })
212+
json(
213+
200,
214+
&ApiResponse {
215+
ok: true,
216+
data: Some(vec![b0, b1]),
217+
error: None,
218+
},
219+
)
134220
}

components/infrastructure/kv-rocksdb/src/lib.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,20 @@ impl wit_kv::Guest for Adapter {
2323
Err(op_err("not implemented"))
2424
}
2525

26-
fn set_with_ttl(_key: String, _value: wit_kv::KvValue, _ttl_seconds: u32) -> Result<(), wit_kv::KvError> {
26+
fn set_with_ttl(
27+
_key: String,
28+
_value: wit_kv::KvValue,
29+
_ttl_seconds: u32,
30+
) -> Result<(), wit_kv::KvError> {
2731
Err(op_err("not implemented"))
2832
}
2933

30-
fn delete(_key: String) -> Result<bool, wit_kv::KvError> { Err(op_err("not implemented")) }
31-
fn exists(_key: String) -> Result<bool, wit_kv::KvError> { Err(op_err("not implemented")) }
34+
fn delete(_key: String) -> Result<bool, wit_kv::KvError> {
35+
Err(op_err("not implemented"))
36+
}
37+
fn exists(_key: String) -> Result<bool, wit_kv::KvError> {
38+
Err(op_err("not implemented"))
39+
}
3240

3341
fn increment(_key: String, _delta: i64) -> Result<i64, wit_kv::KvError> {
3442
Err(op_err("not implemented"))
@@ -38,10 +46,13 @@ impl wit_kv::Guest for Adapter {
3846
Err(op_err("not implemented"))
3947
}
4048

41-
fn scan(_pattern: String, _cursor: Option<String>, _limit: Option<u32>) -> Result<wit_kv::ScanResult, wit_kv::KvError> {
49+
fn scan(
50+
_pattern: String,
51+
_cursor: Option<String>,
52+
_limit: Option<u32>,
53+
) -> Result<wit_kv::ScanResult, wit_kv::KvError> {
4254
Err(op_err("not implemented"))
4355
}
4456
}
4557

4658
export!(Adapter);
47-

components/infrastructure/sql-spin-sqlite/src/lib.rs

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,10 @@ struct Adapter;
6464
impl wit_sql::Guest for Adapter {
6565
type Transaction = Transaction;
6666

67-
fn query(sql: String, params: Vec<wit_sql::SqlValue>) -> Result<wit_sql::QueryResult, wit_sql::SqlError> {
67+
fn query(
68+
sql: String,
69+
params: Vec<wit_sql::SqlValue>,
70+
) -> Result<wit_sql::QueryResult, wit_sql::SqlError> {
6871
exec_query(&sql, &params)
6972
}
7073

@@ -74,7 +77,8 @@ impl wit_sql::Guest for Adapter {
7477

7578
fn begin_transaction() -> Result<wit_sql::Transaction, wit_sql::SqlError> {
7679
let conn = Connection::open_default().map_err(|e| map_err(e, "connection"))?;
77-
conn.execute("BEGIN", &[]).map_err(|e| map_err(e, "transaction"))?;
80+
conn.execute("BEGIN", &[])
81+
.map_err(|e| map_err(e, "transaction"))?;
7882
Ok(wit_sql::Transaction::new(Transaction { conn }))
7983
}
8084
}
@@ -84,11 +88,19 @@ struct Transaction {
8488
}
8589

8690
impl wit_sql::GuestTransaction for Transaction {
87-
fn query(&self, sql: String, params: Vec<wit_sql::SqlValue>) -> Result<wit_sql::QueryResult, wit_sql::SqlError> {
91+
fn query(
92+
&self,
93+
sql: String,
94+
params: Vec<wit_sql::SqlValue>,
95+
) -> Result<wit_sql::QueryResult, wit_sql::SqlError> {
8896
exec_query_on(&self.conn, &sql, &params)
8997
}
9098

91-
fn execute(&self, sql: String, params: Vec<wit_sql::SqlValue>) -> Result<u64, wit_sql::SqlError> {
99+
fn execute(
100+
&self,
101+
sql: String,
102+
params: Vec<wit_sql::SqlValue>,
103+
) -> Result<u64, wit_sql::SqlError> {
92104
exec_execute_on(&self.conn, &sql, &params)
93105
}
94106

@@ -110,7 +122,10 @@ impl wit_sql::GuestTransaction for Transaction {
110122
// Export the component entry points
111123
export!(Adapter);
112124

113-
fn exec_query(sql: &str, params: &[wit_sql::SqlValue]) -> Result<wit_sql::QueryResult, wit_sql::SqlError> {
125+
fn exec_query(
126+
sql: &str,
127+
params: &[wit_sql::SqlValue],
128+
) -> Result<wit_sql::QueryResult, wit_sql::SqlError> {
114129
let conn = Connection::open_default().map_err(|e| map_err(e, "connection"))?;
115130
let values = values_from(params)?;
116131
let qr: SpinQueryResult = conn
@@ -120,15 +135,22 @@ fn exec_query(sql: &str, params: &[wit_sql::SqlValue]) -> Result<wit_sql::QueryR
120135
for row in &qr.rows {
121136
out_rows.push(row_to_wit(&qr.columns, &row.values));
122137
}
123-
Ok(wit_sql::QueryResult { rows: out_rows, rows_affected: 0 })
138+
Ok(wit_sql::QueryResult {
139+
rows: out_rows,
140+
rows_affected: 0,
141+
})
124142
}
125143

126144
fn exec_execute(sql: &str, params: &[wit_sql::SqlValue]) -> Result<u64, wit_sql::SqlError> {
127145
let conn = Connection::open_default().map_err(|e| map_err(e, "connection"))?;
128146
exec_execute_on(&conn, sql, params)
129147
}
130148

131-
fn exec_query_on(conn: &Connection, sql: &str, params: &[wit_sql::SqlValue]) -> Result<wit_sql::QueryResult, wit_sql::SqlError> {
149+
fn exec_query_on(
150+
conn: &Connection,
151+
sql: &str,
152+
params: &[wit_sql::SqlValue],
153+
) -> Result<wit_sql::QueryResult, wit_sql::SqlError> {
132154
let values = values_from(params)?;
133155
let qr: SpinQueryResult = conn
134156
.execute(sql, values.as_slice())
@@ -137,11 +159,19 @@ fn exec_query_on(conn: &Connection, sql: &str, params: &[wit_sql::SqlValue]) ->
137159
for row in &qr.rows {
138160
out_rows.push(row_to_wit(&qr.columns, &row.values));
139161
}
140-
Ok(wit_sql::QueryResult { rows: out_rows, rows_affected: 0 })
162+
Ok(wit_sql::QueryResult {
163+
rows: out_rows,
164+
rows_affected: 0,
165+
})
141166
}
142167

143-
fn exec_execute_on(conn: &Connection, sql: &str, params: &[wit_sql::SqlValue]) -> Result<u64, wit_sql::SqlError> {
168+
fn exec_execute_on(
169+
conn: &Connection,
170+
sql: &str,
171+
params: &[wit_sql::SqlValue],
172+
) -> Result<u64, wit_sql::SqlError> {
144173
let values = values_from(params)?;
145-
conn.execute(sql, values.as_slice()).map_err(|e| map_err(e, "query"))?;
174+
conn.execute(sql, values.as_slice())
175+
.map_err(|e| map_err(e, "query"))?;
146176
Ok(0)
147177
}

0 commit comments

Comments
 (0)