Add README.md, local dev mode & project visibility

This commit is contained in:
Luke Street
2025-07-07 23:13:29 -06:00
parent 137dba512a
commit 935a8e6868
37 changed files with 580 additions and 268 deletions
@@ -1,6 +1,6 @@
{
"db_name": "SQLite",
"query": "\n SELECT id AS \"id!\", owner, repo, name, short_name, default_category, default_version, platform, workflow_id, enable_pr_comments, header_image_id\n FROM projects\n WHERE owner = ? COLLATE NOCASE AND repo = ? COLLATE NOCASE\n ",
"query": "\n SELECT id AS \"id!\", owner, repo, name, short_name, default_category, default_version, platform, workflow_id, enable_pr_comments, header_image_id, enabled\n FROM projects\n WHERE owner = ? COLLATE NOCASE AND repo = ? COLLATE NOCASE\n ",
"describe": {
"columns": [
{
@@ -57,6 +57,11 @@
"name": "header_image_id",
"ordinal": 10,
"type_info": "Blob"
},
{
"name": "enabled",
"ordinal": 11,
"type_info": "Bool"
}
],
"parameters": {
@@ -73,8 +78,9 @@
true,
true,
false,
true
true,
false
]
},
"hash": "e679ddb4ba6c9a8e4e460b2654312956d174591989dec05c4cfe42eaedfebd21"
"hash": "415ca8dbe5fb5b2d573200257e96f2689efdbd0af3397ebdc9f4dec0a8709bd3"
}
@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "\n INSERT INTO projects (id, owner, repo, name, short_name, default_category, default_version, platform, workflow_id, enable_pr_comments, header_image_id, enabled, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 12
},
"nullable": []
},
"hash": "5bdd491e42bf700a271a5fc8431e2511d3f1668d07956ac60a1450ddd8901135"
}
@@ -1,12 +0,0 @@
{
"db_name": "SQLite",
"query": "\n INSERT INTO projects (id, owner, repo, name, short_name, default_category, default_version, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)\n ON CONFLICT (id) DO NOTHING\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 7
},
"nullable": []
},
"hash": "5de3235fb918d2e691289b998a5899e71f5f491f72864b134b4debe85bb57fa9"
}
@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "\n INSERT INTO projects (id, owner, repo, name, short_name, default_category, default_version, platform, workflow_id, enable_pr_comments, header_image_id, enabled, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)\n ON CONFLICT (id) DO NOTHING\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 12
},
"nullable": []
},
"hash": "c0ffba953513be9fccf5427dd818ef17184498e031c3f19aae4b27af4ab9fb0d"
}
@@ -1,6 +1,6 @@
{
"db_name": "SQLite",
"query": "\n SELECT owner, repo, name, short_name, default_category, default_version, platform, workflow_id, enable_pr_comments, header_image_id\n FROM projects\n WHERE id = ?\n ",
"query": "\n SELECT owner, repo, name, short_name, default_category, default_version, platform, workflow_id, enable_pr_comments, header_image_id, enabled\n FROM projects\n WHERE id = ?\n ",
"describe": {
"columns": [
{
@@ -52,6 +52,11 @@
"name": "header_image_id",
"ordinal": 9,
"type_info": "Blob"
},
{
"name": "enabled",
"ordinal": 10,
"type_info": "Bool"
}
],
"parameters": {
@@ -67,8 +72,9 @@
true,
true,
false,
true
true,
false
]
},
"hash": "36261e887badca80fc0c19ac0a368951387da8f8a42623be91ca2d251c745364"
"hash": "d66c20bc973f3199c05ca1e7f2e3b87cb3bf82646329034caeea9c48d9586823"
}
@@ -1,12 +0,0 @@
{
"db_name": "SQLite",
"query": "\n INSERT INTO projects (id, owner, repo, name, short_name, default_category, default_version, platform, workflow_id, enable_pr_comments, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 10
},
"nullable": []
},
"hash": "e9bddc3272d50fb0ca0c4375deecb6a8c6627de9d8e5f4a823c30cc52abe57d6"
}
@@ -1,12 +1,12 @@
{
"db_name": "SQLite",
"query": "\n UPDATE projects\n SET owner = ?, repo = ?, name = ?, short_name = ?, default_category = ?, default_version = ?, platform = ?, workflow_id = ?, enable_pr_comments = ?, header_image_id = ?, updated_at = CURRENT_TIMESTAMP\n WHERE id = ?\n ",
"query": "\n UPDATE projects\n SET owner = ?, repo = ?, name = ?, short_name = ?, default_category = ?, default_version = ?, platform = ?, workflow_id = ?, enable_pr_comments = ?, header_image_id = ?, enabled = ?, updated_at = CURRENT_TIMESTAMP\n WHERE id = ?\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 11
"Right": 12
},
"nullable": []
},
"hash": "c6e1281fcba9403a87315a09483b92c86d27bc26d6db402c0039026be5ade978"
"hash": "f7bf7260f20ecc8e216bfcf1c62d5c50ae1bb982ce29a63073f89a7723fc6f11"
}
@@ -1,6 +1,6 @@
{
"db_name": "SQLite",
"query": "\n SELECT\n projects.id AS \"project_id!\",\n owner AS \"owner!\",\n repo AS \"repo!\",\n name,\n short_name,\n default_category,\n default_version,\n platform,\n workflow_id,\n enable_pr_comments AS \"enable_pr_comments!\",\n header_image_id,\n git_commit,\n git_commit_message,\n MAX(timestamp) AS \"timestamp: time::OffsetDateTime\",\n JSON_GROUP_ARRAY(version ORDER BY version)\n FILTER (WHERE version IS NOT NULL) AS versions\n FROM projects LEFT JOIN reports ON (\n reports.project_id = projects.id\n AND reports.timestamp = (\n SELECT MAX(timestamp)\n FROM reports\n WHERE project_id = projects.id\n )\n )\n GROUP BY projects.id\n ORDER BY MAX(timestamp) DESC\n ",
"query": "\n SELECT\n projects.id AS \"project_id!\",\n owner AS \"owner!\",\n repo AS \"repo!\",\n name,\n short_name,\n default_category,\n default_version,\n platform,\n workflow_id,\n enable_pr_comments AS \"enable_pr_comments!\",\n header_image_id,\n enabled AS \"enabled!\",\n git_commit,\n git_commit_message,\n MAX(timestamp) AS \"timestamp: time::OffsetDateTime\",\n JSON_GROUP_ARRAY(version ORDER BY version)\n FILTER (WHERE version IS NOT NULL) AS versions\n FROM projects LEFT JOIN reports ON (\n reports.project_id = projects.id\n AND reports.timestamp = (\n SELECT MAX(timestamp)\n FROM reports\n WHERE project_id = projects.id\n )\n )\n GROUP BY projects.id\n ORDER BY MAX(timestamp) DESC\n ",
"describe": {
"columns": [
{
@@ -59,24 +59,29 @@
"type_info": "Blob"
},
{
"name": "git_commit",
"name": "enabled!",
"ordinal": 11,
"type_info": "Text"
"type_info": "Bool"
},
{
"name": "git_commit_message",
"name": "git_commit",
"ordinal": 12,
"type_info": "Text"
},
{
"name": "timestamp: time::OffsetDateTime",
"name": "git_commit_message",
"ordinal": 13,
"type_info": "Text"
},
{
"name": "versions",
"name": "timestamp: time::OffsetDateTime",
"ordinal": 14,
"type_info": "Text"
},
{
"name": "versions",
"ordinal": 15,
"type_info": "Text"
}
],
"parameters": {
@@ -97,8 +102,9 @@
true,
true,
true,
true,
true
]
},
"hash": "927b8e137db05ddd2996e9b2d04b80f8af3f6e2113654f3dd4a24ff5efb0855a"
"hash": "fc441fa93f0d46f6a0a541ae625154cc07efb5d4496d80d489f23a39f0e6b032"
}
Generated
+18 -3
View File
@@ -1208,6 +1208,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
dependencies = [
"crc32fast",
"libz-rs-sys",
"miniz_oxide",
]
@@ -2186,6 +2187,15 @@ dependencies = [
"glob",
]
[[package]]
name = "libz-rs-sys"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "172a788537a2221661b480fee8dc5f96c580eb34fa88764d3205dc356c7e4221"
dependencies = [
"zlib-rs",
]
[[package]]
name = "linux-raw-sys"
version = "0.9.4"
@@ -5676,18 +5686,23 @@ dependencies = [
[[package]]
name = "zip"
version = "2.6.1"
version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dcb24d0152526ae49b9b96c1dcf71850ca1e0b882e4e28ed898a93c41334744"
checksum = "95ab361742de920c5535880f89bbd611ee62002bf11341d16a5f057bb8ba6899"
dependencies = [
"arbitrary",
"crc32fast",
"crossbeam-utils",
"flate2",
"indexmap",
"memchr",
]
[[package]]
name = "zlib-rs"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "626bd9fa9734751fc50d6060752170984d7053f5a39061f524cda68023d4db8a"
[[package]]
name = "zstd"
version = "0.13.3"
+1
View File
@@ -13,6 +13,7 @@ members = [
[workspace.package]
version = "0.1.0"
edition = "2024"
rust-version = "1.88"
[workspace.dependencies]
anyhow = "1.0"
+60
View File
@@ -0,0 +1,60 @@
# [decomp.dev](https://decomp.dev)
Decompilation progress website & GitHub bot.
For more information, see the [wiki](https://wiki.decomp.dev/tools/decomp-dev).
## Backend Setup
1. Install Rust via [rustup](https://rustup.rs/):
```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```
2. Clone the repository:
```bash
git clone https://github.com/encounter/decomp.dev.git
cd decomp.dev
```
3. Copy `config.example.yml` to `config.yml`:
```bash
cp config.example.yml config.yml
```
4. [Create a new GitHub personal access token](https://github.com/settings/tokens/new?description=decomp.dev&scopes=workflow,write:discussion) with scopes `workflow`, `write:discussion`. Set it in `config.yml`:
```yaml
github:
token: ghp_abcd1234abcd1234abcd1234abcd1234abcd
```
5. Install [bacon](https://dystroy.org/bacon/):
```bash
cargo install --locked bacon
```
6. Run the backend with automatic rebuild on changes:
```bash
bacon
```
When modifying Rust code, it will take a few seconds to build and restart the server.
Once the server updates, the browser page will automatically reload.
## Frontend Setup
1. Install dependencies:
```bash
npm install
```
2. Start the frontend development server:
```bash
npm start
```
When the frontend development server is running, changes to files under `css/`, `js/` and `assets/` will live reload in the browser.
## Testing
When running both the backend and frontend, the site will be accessible at http://localhost:3000.
By default, `server.dev_mode` in `config.yml` is enabled, allowing any visitor to log in as a superuser without authentication.
To add projects to the site, visit http://localhost:3000/manage/new, using an existing project from [decomp.dev](https://decomp.dev/) as reference:
![New project page](/docs/manage_new.png)
+3 -3
View File
@@ -1,5 +1,8 @@
server:
port: 3000
# Enable development mode
# WARNING: Allows anyone to log in as a super admin
dev_mode: true
db:
url: sqlite:./db.sqlite
@@ -7,6 +10,3 @@ db:
github:
# Personal access token for public repo access
token: ghp_abcd1234abcd1234abcd1234abcd1234abcd
openai:
api_key: sk-proj-abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234
+50 -38
View File
@@ -6,7 +6,10 @@ use axum::{
response::{IntoResponse, Redirect, Response},
};
use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD};
use decomp_dev_core::{AppError, config::GitHubConfig};
use decomp_dev_core::{
AppError,
config::{Config, GitHubConfig},
};
use decomp_dev_github::graphql::{
CurrentUserResponse, RepositoryPermission, fetch_current_user, fetch_simple_current_user,
};
@@ -46,18 +49,25 @@ pub type Profile = Author;
#[derive(Clone, serde::Serialize, serde::Deserialize)]
pub struct CurrentUser {
pub oauth: StoredOAuth,
pub oauth: Option<StoredOAuth>,
pub data: CurrentUserResponse,
#[serde(skip, default)]
pub super_admin: bool,
}
impl CurrentUser {
pub fn client(&self) -> Result<Octocrab> {
Octocrab::builder()
.oauth(self.oauth.clone().into())
.build()
.context("Failed to create GitHub client")
pub fn client(&self, config: &GitHubConfig) -> Result<Octocrab> {
if let Some(oauth) = &self.oauth {
Octocrab::builder()
.oauth(oauth.clone().into())
.build()
.context("Failed to create GitHub client")
} else {
Octocrab::builder()
.personal_token(config.token.clone())
.build()
.context("Failed to create GitHub client")
}
}
pub fn permissions_for_repo(&self, id: u64) -> RepositoryPermission {
@@ -202,7 +212,7 @@ async fn fetch_access_token(config: &GitHubConfig, code: &str) -> Result<Current
} else {
tracing::info!("Logged in as @{} ({} repos)", data.login, data.repositories.len());
}
Ok(CurrentUser { oauth, data, super_admin })
Ok(CurrentUser { oauth: Some(oauth), data, super_admin })
}
async fn refresh_access_token(
@@ -229,12 +239,12 @@ async fn refresh_access_token(
let oauth = StoredOAuth::from(oauth);
let super_admin = config.super_admin_ids.contains(&prev_auth.data.id);
tracing::info!("Refreshed token for @{}", prev_auth.data.login);
Ok(CurrentUser { oauth, data: prev_auth.data.clone(), super_admin })
Ok(CurrentUser { oauth: Some(oauth), data: prev_auth.data.clone(), super_admin })
}
impl<S> FromRequestParts<S> for CurrentUser
where
GitHubConfig: FromRef<S>,
Config: FromRef<S>,
S: Send + Sync,
{
type Rejection = Response;
@@ -268,7 +278,7 @@ where
impl<S> OptionalFromRequestParts<S> for CurrentUser
where
GitHubConfig: FromRef<S>,
Config: FromRef<S>,
S: Send + Sync,
{
type Rejection = (StatusCode, &'static str);
@@ -278,7 +288,7 @@ where
state: &S,
) -> Result<Option<Self>, Self::Rejection> {
let session = Session::from_request_parts(parts, state).await?;
let config = GitHubConfig::from_ref(state);
let config = Config::from_ref(state);
let mut user = match session.get::<CurrentUser>(CURRENT_USER).await {
Ok(Some(user)) => user,
Ok(None) => return Ok(None),
@@ -289,7 +299,7 @@ where
};
// Refresh user data if the ID is 0
if user.data.id == 0 {
match user.client() {
match user.client(&config.github) {
Ok(client) => match fetch_simple_current_user(&client).await {
Ok(data) => {
user.data =
@@ -315,35 +325,37 @@ where
}
}
}
user.super_admin = config.super_admin_ids.contains(&user.data.id);
if let Some(expires_at) = user.oauth.expires_at {
if (UtcDateTime::now() + Duration::seconds(30)) > expires_at {
// Access token expired, attempt to refresh
if let Err(e) = session.remove_value(CURRENT_USER).await {
tracing::error!("Failed to remove user from session: {}", e);
};
if let Some(refresh_token) = &user.oauth.refresh_token {
if let Some(refresh_token_expires_at) = user.oauth.refresh_token_expires_at {
if UtcDateTime::now() >= refresh_token_expires_at {
// Refresh token expired
user.super_admin = (config.server.dev_mode && user.data.id == u64::MAX)
|| config.github.super_admin_ids.contains(&user.data.id);
if let Some(oauth) = &user.oauth
&& let Some(expires_at) = oauth.expires_at
&& (UtcDateTime::now() + Duration::seconds(30)) > expires_at
{
// Access token expired, attempt to refresh
if let Err(e) = session.remove_value(CURRENT_USER).await {
tracing::error!("Failed to remove user from session: {}", e);
};
if let Some(refresh_token) = &oauth.refresh_token {
if let Some(refresh_token_expires_at) = oauth.refresh_token_expires_at
&& UtcDateTime::now() >= refresh_token_expires_at
{
// Refresh token expired
return Ok(None);
}
let current_user =
match refresh_access_token(&config.github, refresh_token, &user).await {
Ok(current_user) => current_user,
Err(e) => {
tracing::error!("Failed to refresh access token: {:?}", e);
return Ok(None);
}
}
let current_user =
match refresh_access_token(&config, refresh_token, &user).await {
Ok(current_user) => current_user,
Err(e) => {
tracing::error!("Failed to refresh access token: {:?}", e);
return Ok(None);
}
};
if let Err(e) = session.insert(CURRENT_USER, current_user.clone()).await {
tracing::error!("Failed to insert user into session: {}", e);
}
return Ok(Some(current_user));
};
if let Err(e) = session.insert(CURRENT_USER, current_user.clone()).await {
tracing::error!("Failed to insert user into session: {}", e);
}
return Ok(None);
return Ok(Some(current_user));
}
return Ok(None);
}
Ok(Some(user))
}
+2 -2
View File
@@ -35,9 +35,9 @@ pub fn run(args: Args) -> Result<()> {
let comment = generate_comment(&previous_report, &current_report, None, None, None, changes);
if let Some(out_path) = &args.output {
std::fs::write(out_path.with_platform_encoding(), comment)
.with_context(|| format!("Failed to write output file '{}'", out_path))?;
.with_context(|| format!("Failed to write output file '{out_path}'"))?;
} else {
println!("{}", comment);
println!("{comment}");
}
Ok(())
}
+2
View File
@@ -11,6 +11,8 @@ pub struct Config {
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ServerConfig {
pub port: u16,
#[serde(default)]
pub dev_mode: bool,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
+1 -1
View File
@@ -25,7 +25,7 @@ impl IntoResponse for AppError {
Self::Status(status) => status.into_response(),
Self::Internal(err) => {
tracing::error!("{:?}", err);
(StatusCode::INTERNAL_SERVER_ERROR, format!("Something went wrong: {}", err))
(StatusCode::INTERNAL_SERVER_ERROR, format!("Something went wrong: {err}"))
.into_response()
}
}
+23 -1
View File
@@ -20,6 +20,7 @@ pub struct Project {
pub workflow_id: Option<String>,
pub enable_pr_comments: bool,
pub header_image_id: Option<ImageId>,
pub enabled: bool,
}
impl Default for Project {
@@ -36,12 +37,13 @@ impl Default for Project {
workflow_id: None,
enable_pr_comments: true,
header_image_id: None,
enabled: true,
}
}
}
impl Project {
pub fn name(&self) -> Cow<str> {
pub fn name(&self) -> Cow<'_, str> {
if let Some(name) = self.name.as_ref() {
Cow::Borrowed(name)
} else {
@@ -54,6 +56,8 @@ impl Project {
}
pub fn repo_url(&self) -> String { format!("https://github.com/{}/{}", self.owner, self.repo) }
pub fn default_category(&self) -> &str { self.default_category.as_deref().unwrap_or("all") }
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
@@ -225,3 +229,21 @@ impl FromStr for Platform {
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProjectVisibility {
Visible,
Hidden,
Disabled,
}
pub fn project_visibility(project: &Project, measures: Option<&Measures>) -> ProjectVisibility {
// Hide projects with less than 0.5% matched code or if the project is disabled
if !project.enabled {
ProjectVisibility::Disabled
} else if measures.is_none_or(|m| m.matched_code_percent < 0.5) {
ProjectVisibility::Hidden
} else {
ProjectVisibility::Visible
}
}
+2 -4
View File
@@ -31,10 +31,8 @@ impl UrlExt for Url {
pairs.append_pair(&k, &v);
}
}
if !updated {
if let Some(value) = value {
pairs.append_pair(key, value);
}
if !updated && let Some(value) = value {
pairs.append_pair(key, value);
}
drop(pairs);
if out.query() == Some("") {
+22 -8
View File
@@ -86,10 +86,11 @@ impl Database {
) -> Result<()> {
let mut tx = self.pool.begin().await?;
let project_id = project.id as i64;
let header_image_id = project.header_image_id.as_ref().map(|b| b.as_slice());
sqlx::query!(
r#"
INSERT INTO projects (id, owner, repo, name, short_name, default_category, default_version, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
INSERT INTO projects (id, owner, repo, name, short_name, default_category, default_version, platform, workflow_id, enable_pr_comments, header_image_id, enabled, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
ON CONFLICT (id) DO NOTHING
"#,
project_id,
@@ -99,6 +100,11 @@ impl Database {
project.short_name,
project.default_category,
project.default_version,
project.platform,
project.workflow_id,
project.enable_pr_comments,
header_image_id,
project.enabled,
)
.execute(&mut *tx)
.await?;
@@ -358,7 +364,7 @@ impl Database {
let mut conn = self.pool.acquire().await?;
let project = match sqlx::query!(
r#"
SELECT id AS "id!", owner, repo, name, short_name, default_category, default_version, platform, workflow_id, enable_pr_comments, header_image_id
SELECT id AS "id!", owner, repo, name, short_name, default_category, default_version, platform, workflow_id, enable_pr_comments, header_image_id, enabled
FROM projects
WHERE owner = ? COLLATE NOCASE AND repo = ? COLLATE NOCASE
"#,
@@ -380,6 +386,7 @@ impl Database {
workflow_id: row.workflow_id,
enable_pr_comments: row.enable_pr_comments,
header_image_id: row.header_image_id.and_then(|b| b.try_into().ok()),
enabled: row.enabled,
},
None => return Ok(None),
};
@@ -395,7 +402,7 @@ impl Database {
let project_id_db = project_id as i64;
let project = match sqlx::query!(
r#"
SELECT owner, repo, name, short_name, default_category, default_version, platform, workflow_id, enable_pr_comments, header_image_id
SELECT owner, repo, name, short_name, default_category, default_version, platform, workflow_id, enable_pr_comments, header_image_id, enabled
FROM projects
WHERE id = ?
"#,
@@ -416,6 +423,7 @@ impl Database {
workflow_id: row.workflow_id,
enable_pr_comments: row.enable_pr_comments,
header_image_id: row.header_image_id.and_then(|b| b.try_into().ok()),
enabled: row.enabled,
},
None => return Ok(None),
};
@@ -550,6 +558,7 @@ impl Database {
workflow_id,
enable_pr_comments AS "enable_pr_comments!",
header_image_id,
enabled AS "enabled!",
git_commit,
git_commit_message,
MAX(timestamp) AS "timestamp: time::OffsetDateTime",
@@ -583,6 +592,7 @@ impl Database {
workflow_id: row.workflow_id,
enable_pr_comments: row.enable_pr_comments,
header_image_id: row.header_image_id.and_then(|b| b.try_into().ok()),
enabled: row.enabled,
},
commit: match (row.git_commit, row.timestamp) {
(Some(sha), Some(timestamp)) => Some(Commit {
@@ -964,7 +974,7 @@ impl Database {
sqlx::query!(
r#"
UPDATE projects
SET owner = ?, repo = ?, name = ?, short_name = ?, default_category = ?, default_version = ?, platform = ?, workflow_id = ?, enable_pr_comments = ?, header_image_id = ?, updated_at = CURRENT_TIMESTAMP
SET owner = ?, repo = ?, name = ?, short_name = ?, default_category = ?, default_version = ?, platform = ?, workflow_id = ?, enable_pr_comments = ?, header_image_id = ?, enabled = ?, updated_at = CURRENT_TIMESTAMP
WHERE id = ?
"#,
project.owner,
@@ -977,6 +987,7 @@ impl Database {
project.workflow_id,
project.enable_pr_comments,
header_image_id,
project.enabled,
project_id,
)
.execute(&mut *conn)
@@ -987,10 +998,11 @@ impl Database {
pub async fn create_project(&self, project: &Project) -> Result<()> {
let mut conn = self.pool.acquire().await?;
let project_id = project.id as i64;
let header_image_id = project.header_image_id.as_ref().map(|b| b.as_slice());
sqlx::query!(
r#"
INSERT INTO projects (id, owner, repo, name, short_name, default_category, default_version, platform, workflow_id, enable_pr_comments, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
INSERT INTO projects (id, owner, repo, name, short_name, default_category, default_version, platform, workflow_id, enable_pr_comments, header_image_id, enabled, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
"#,
project_id,
project.owner,
@@ -1002,6 +1014,8 @@ impl Database {
project.platform,
project.workflow_id,
project.enable_pr_comments,
header_image_id,
project.enabled,
)
.execute(&mut *conn)
.await?;
@@ -1108,7 +1122,7 @@ thread_local! {
fn compress(data: &[u8]) -> Vec<u8> { COMPRESSOR.with_borrow_mut(|z| z.compress(data).unwrap()) }
fn decompress(data: &[u8]) -> Result<Cow<[u8]>> {
fn decompress(data: &[u8]) -> Result<Cow<'_, [u8]>> {
match zstd::zstd_safe::get_frame_content_size(data) {
Ok(Some(size)) => {
Ok(Cow::Owned(DECOMPRESSOR.with_borrow_mut(|z| z.decompress(data, size as usize))?))
+1 -1
View File
@@ -24,4 +24,4 @@ sha2 = "0.10"
time.workspace = true
tokio.workspace = true
tracing.workspace = true
zip = { version = "2.6", default-features = false, features = ["flate2", "deflate-flate2"] }
zip = { version = "4.2", default-features = false, features = ["deflate-flate2-zlib-rs"] }

Some files were not shown because too many files have changed in this diff Show More