From fd5dfde2019ff6a352b259cab28592aafe878bb4 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Thu, 9 May 2024 18:51:47 +0200 Subject: [PATCH] fix(cli): add excludes to the codebase conf --- backend/src/ee.rs | 17 +- backend/substitute_ee_code.sh | 2 +- backend/windmill-api/src/ee.rs | 7 +- backend/windmill-api/src/job_helpers_ee.rs | 6 +- backend/windmill-api/src/oauth2_ee.rs | 200 +----------------- backend/windmill-api/src/oidc_ee.rs | 18 +- backend/windmill-api/src/saml_ee.rs | 26 +-- backend/windmill-api/src/scim_ee.rs | 24 +-- backend/windmill-api/src/stripe_ee.rs | 8 +- backend/windmill-audit/src/audit_ee.rs | 49 +---- backend/windmill-common/src/ee.rs | 29 +-- .../windmill-common/src/job_s3_helpers_ee.rs | 19 +- backend/windmill-common/src/stats_ee.rs | 36 +--- backend/windmill-git-sync/src/git_sync_ee.rs | 18 +- cli/conf.ts | 3 +- cli/main.ts | 7 +- cli/sync.ts | 25 ++- 17 files changed, 44 insertions(+), 450 deletions(-) mode change 100644 => 120000 backend/src/ee.rs mode change 100644 => 120000 backend/windmill-api/src/ee.rs mode change 100644 => 120000 backend/windmill-api/src/job_helpers_ee.rs mode change 100644 => 120000 backend/windmill-api/src/oauth2_ee.rs mode change 100644 => 120000 backend/windmill-api/src/oidc_ee.rs mode change 100644 => 120000 backend/windmill-api/src/saml_ee.rs mode change 100644 => 120000 backend/windmill-api/src/scim_ee.rs mode change 100644 => 120000 backend/windmill-api/src/stripe_ee.rs mode change 100644 => 120000 backend/windmill-audit/src/audit_ee.rs mode change 100644 => 120000 backend/windmill-common/src/ee.rs mode change 100644 => 120000 backend/windmill-common/src/job_s3_helpers_ee.rs mode change 100644 => 120000 backend/windmill-common/src/stats_ee.rs mode change 100644 => 120000 backend/windmill-git-sync/src/git_sync_ee.rs diff --git a/backend/src/ee.rs b/backend/src/ee.rs deleted file mode 100644 index ef944b984b..0000000000 --- a/backend/src/ee.rs +++ /dev/null @@ -1,16 +0,0 @@ -use anyhow::anyhow; -#[cfg(feature = "enterprise")] -use windmill_common::error::{Error, Result}; - -pub async fn set_license_key(_license_key: String) -> anyhow::Result<()> { - // Implementation is not open source - Err(anyhow!("License cannot be set in Windmill CE")) -} - -#[cfg(feature = "enterprise")] -pub async fn verify_license_key() -> Result<()> { - // Implementation is not open source - Err(Error::InternalErr( - "License always invalid in Windmill CE".to_string(), - )) -} diff --git a/backend/src/ee.rs b/backend/src/ee.rs new file mode 120000 index 0000000000..ca288038c6 --- /dev/null +++ b/backend/src/ee.rs @@ -0,0 +1 @@ +/git/windmill/../windmill-ee-private/src/ee.rs \ No newline at end of file diff --git a/backend/substitute_ee_code.sh b/backend/substitute_ee_code.sh index dab1c6d608..d7f98bf0fe 100755 --- a/backend/substitute_ee_code.sh +++ b/backend/substitute_ee_code.sh @@ -71,7 +71,7 @@ if [ "$REVERT" == "YES" ]; then ce_file="${ee_file/${EE_CODE_DIR}/.}" ce_file="${root_dirpath}/backend/${ce_file}" if [ "$REVERT_PREVIOUS" == "YES" ]; then - git checkout HEAD@{75} ${ce_file} || true + git checkout HEAD@{5} ${ce_file} || true else git restore --staged ${ce_file} || true git restore ${ce_file} || true diff --git a/backend/windmill-api/src/ee.rs b/backend/windmill-api/src/ee.rs deleted file mode 100644 index a9d170a3ac..0000000000 --- a/backend/windmill-api/src/ee.rs +++ /dev/null @@ -1,6 +0,0 @@ -use anyhow::anyhow; - -pub async fn validate_license_key(_license_key: String) -> anyhow::Result { - // Implementation is not open source - Err(anyhow!("License can't be validated in Windmill CE")) -} diff --git a/backend/windmill-api/src/ee.rs b/backend/windmill-api/src/ee.rs new file mode 120000 index 0000000000..0267c6e6fd --- /dev/null +++ b/backend/windmill-api/src/ee.rs @@ -0,0 +1 @@ +/git/windmill/../windmill-ee-private/windmill-api/src/ee.rs \ No newline at end of file diff --git a/backend/windmill-api/src/job_helpers_ee.rs b/backend/windmill-api/src/job_helpers_ee.rs deleted file mode 100644 index 61a946bb84..0000000000 --- a/backend/windmill-api/src/job_helpers_ee.rs +++ /dev/null @@ -1,5 +0,0 @@ -use axum::Router; - -pub fn workspaced_service() -> Router { - Router::new() -} diff --git a/backend/windmill-api/src/job_helpers_ee.rs b/backend/windmill-api/src/job_helpers_ee.rs new file mode 120000 index 0000000000..8cc4fbe8bf --- /dev/null +++ b/backend/windmill-api/src/job_helpers_ee.rs @@ -0,0 +1 @@ +/git/windmill/../windmill-ee-private/windmill-api/src/job_helpers_ee.rs \ No newline at end of file diff --git a/backend/windmill-api/src/oauth2_ee.rs b/backend/windmill-api/src/oauth2_ee.rs deleted file mode 100644 index caf9881c15..0000000000 --- a/backend/windmill-api/src/oauth2_ee.rs +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Author: Ruben Fiszel - * Copyright: Windmill Labs, Inc 2022 - * This file and its contents are licensed under the AGPLv3 License. - * Please see the included NOTICE for copyright information and - * LICENSE-AGPL for a copy of the license. - */ - -use std::{collections::HashMap, fmt::Debug}; - -use axum::{routing::get, Json, Router}; -use hmac::Mac; -use hyper::HeaderMap; - -use oauth2::{Client as OClient, *}; -use serde::{Deserialize, Serialize}; -use sqlx::{Postgres, Transaction}; -use windmill_common::more_serde::maybe_number_opt; - -use crate::OAUTH_CLIENTS; -use windmill_common::error; -use windmill_common::oauth2::*; - -use crate::db::DB; -use std::str; - -pub fn global_service() -> Router { - Router::new() - .route("/list_supabase", get(list_supabase)) - .route("/list_logins", get(list_logins)) - .route("/list_connects", get(list_connects)) -} - -pub fn workspaced_service() -> Router { - Router::new() -} - -#[derive(Serialize)] -#[serde(tag = "type")] -pub enum InstanceEvent { - UserAdded { email: String }, - // UserDeleted { email: String }, - // UserDeletedWorkspace { workspace: String, email: String }, - UserAddedWorkspace { workspace: String, email: String }, - UserInvitedWorkspace { workspace: String, email: String }, - UserJoinedWorkspace { workspace: String, email: String, username: String }, -} - -#[derive(Debug, Clone)] -pub struct ClientWithScopes { - _client: OClient, - scopes: Vec, - extra_params: Option>, - _extra_params_callback: Option>, - _allowed_domains: Option>, - _userinfo_url: Option, -} - -pub type BasicClientsMap = HashMap; - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct OAuthConfig { - auth_url: String, - token_url: String, - userinfo_url: Option, - scopes: Option>, - extra_params: Option>, - extra_params_callback: Option>, - req_body_auth: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct OAuthClient { - id: String, - secret: String, - allowed_domains: Option>, - connect_config: Option, - login_config: Option, -} - -#[derive(Debug)] -pub struct AllClients { - pub logins: BasicClientsMap, - pub connects: BasicClientsMap, - pub slack: Option, -} - -pub fn build_oauth_clients( - _base_url: &str, - _oauths_from_config: Option>, -) -> anyhow::Result { - // Implementation is not open source - return Ok(AllClients { - logins: HashMap::default(), - connects: HashMap::default(), - slack: None, - }); -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct TokenResponse { - access_token: AccessToken, - #[serde(deserialize_with = "maybe_number_opt")] - #[serde(default)] - expires_in: Option, - refresh_token: Option, - #[serde(deserialize_with = "helpers::deserialize_space_delimited_vec")] - #[serde(serialize_with = "helpers::serialize_space_delimited_vec")] - #[serde(default)] - scope: Option>, -} - -#[derive(Serialize)] -struct Logins { - oauth: Vec, - saml: Option, -} -async fn list_logins() -> error::JsonResult { - // Implementation is not open source - return Ok(Json(Logins { oauth: vec![], saml: None })); -} - -#[derive(Serialize)] -struct ScopesAndParams { - scopes: Vec, - extra_params: Option>, -} -async fn list_connects() -> error::JsonResult> { - Ok(Json( - (&OAUTH_CLIENTS.read().await.connects) - .into_iter() - .map(|(k, v)| { - ( - k.to_owned(), - ScopesAndParams { - scopes: v.scopes.clone(), - extra_params: v.extra_params.clone(), - }, - ) - }) - .collect::>(), - )) -} - -pub async fn _refresh_token<'c>( - _tx: Transaction<'c, Postgres>, - _path: &str, - _w_id: &str, - _id: i32, -) -> error::Result { - // Implementation is not open source - Err(error::Error::BadRequest( - "Not implemented in Windmill's Open Source repository".to_string(), - )) -} - -async fn list_supabase(_headers: HeaderMap) -> error::Result { - // Implementation is not open source - Err(error::Error::BadRequest( - "Not implemented in Windmill's Open Source repository".to_string(), - )) -} - -pub async fn check_nb_of_user(db: &DB) -> error::Result<()> { - let nb_users_sso = - sqlx::query_scalar!("SELECT COUNT(*) FROM password WHERE login_type != 'password'",) - .fetch_one(db) - .await?; - if nb_users_sso.unwrap_or(0) >= 10 { - return Err(error::Error::BadRequest( - "You have reached the maximum number of oauth users accounts (10) without an enterprise license" - .to_string(), - )); - } - - let nb_users = sqlx::query_scalar!("SELECT COUNT(*) FROM password",) - .fetch_one(db) - .await?; - if nb_users.unwrap_or(0) >= 50 { - return Err(error::Error::BadRequest( - "You have reached the maximum number of accounts (50) without an enterprise license" - .to_string(), - )); - } - return Ok(()); -} - -#[derive(Clone, Debug)] -pub struct SlackVerifier { - _mac: HmacSha256, -} - -impl SlackVerifier { - pub fn new>(secret: S) -> anyhow::Result { - HmacSha256::new_from_slice(secret.as_ref()) - .map(|mac| SlackVerifier { _mac: mac }) - .map_err(|_| anyhow::anyhow!("invalid secret")) - } -} diff --git a/backend/windmill-api/src/oauth2_ee.rs b/backend/windmill-api/src/oauth2_ee.rs new file mode 120000 index 0000000000..1ab1665454 --- /dev/null +++ b/backend/windmill-api/src/oauth2_ee.rs @@ -0,0 +1 @@ +/git/windmill/../windmill-ee-private/windmill-api/src/oauth2_ee.rs \ No newline at end of file diff --git a/backend/windmill-api/src/oidc_ee.rs b/backend/windmill-api/src/oidc_ee.rs deleted file mode 100644 index 248b990f54..0000000000 --- a/backend/windmill-api/src/oidc_ee.rs +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Author: Ruben Fiszel - * Copyright: Windmill Labs, Inc 2023 - * This file and its contents are licensed under the AGPLv3 License. - * Please see the included NOTICE for copyright information and - * LICENSE-AGPL for a copy of the license. - */ - -use axum::Router; - -pub fn global_service() -> Router { - Router::new() -} - -pub fn workspaced_service() -> Router { - Router::new() -} diff --git a/backend/windmill-api/src/oidc_ee.rs b/backend/windmill-api/src/oidc_ee.rs new file mode 120000 index 0000000000..1e902de563 --- /dev/null +++ b/backend/windmill-api/src/oidc_ee.rs @@ -0,0 +1 @@ +/git/windmill/../windmill-ee-private/windmill-api/src/oidc_ee.rs \ No newline at end of file diff --git a/backend/windmill-api/src/saml_ee.rs b/backend/windmill-api/src/saml_ee.rs deleted file mode 100644 index b3f1d4653c..0000000000 --- a/backend/windmill-api/src/saml_ee.rs +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Author: Ruben Fiszel - * Copyright: Windmill Labs, Inc 2023 - * This file and its contents are licensed under the AGPLv3 License. - * Please see the included NOTICE for copyright information and - * LICENSE-AGPL for a copy of the license. - */ -#![allow(non_snake_case)] - -use axum::{routing::post, Router}; - -pub struct ServiceProviderExt(); - -pub async fn build_sp_extension() -> anyhow::Result { - return Ok(ServiceProviderExt()); -} - -pub fn global_service() -> Router { - Router::new().route("/acs", post(acs)) -} - -pub async fn acs() -> String { - // Implementation is not open source as it is a Windmill Enterprise Edition feature - "SAML available only in enterprise version".to_string() -} diff --git a/backend/windmill-api/src/saml_ee.rs b/backend/windmill-api/src/saml_ee.rs new file mode 120000 index 0000000000..65286e3f12 --- /dev/null +++ b/backend/windmill-api/src/saml_ee.rs @@ -0,0 +1 @@ +/git/windmill/../windmill-ee-private/windmill-api/src/saml_ee.rs \ No newline at end of file diff --git a/backend/windmill-api/src/scim_ee.rs b/backend/windmill-api/src/scim_ee.rs deleted file mode 100644 index f11097f874..0000000000 --- a/backend/windmill-api/src/scim_ee.rs +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Author: Ruben Fiszel - * Copyright: Windmill Labs, Inc 2023 - * This file and its contents are licensed under the AGPLv3 License. - * Please see the included NOTICE for copyright information and - * LICENSE-AGPL for a copy of the license. - */ - -use axum::{middleware::Next, response::Response, routing::get, Router}; -use hyper::Request; - -pub fn global_service() -> Router { - Router::new().route("/ee", get(ee)) -} - -pub async fn ee() -> String { - return "Enterprise Edition".to_string(); -} - -pub async fn has_scim_token(_request: Request, _next: Next) -> Response { - //Not implemented in open-source version - todo!() -} diff --git a/backend/windmill-api/src/scim_ee.rs b/backend/windmill-api/src/scim_ee.rs new file mode 120000 index 0000000000..cd27dc4526 --- /dev/null +++ b/backend/windmill-api/src/scim_ee.rs @@ -0,0 +1 @@ +/git/windmill/../windmill-ee-private/windmill-api/src/scim_ee.rs \ No newline at end of file diff --git a/backend/windmill-api/src/stripe_ee.rs b/backend/windmill-api/src/stripe_ee.rs deleted file mode 100644 index 1aea2ecd2d..0000000000 --- a/backend/windmill-api/src/stripe_ee.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[cfg(feature = "stripe")] -use axum::Router; - -#[cfg(feature = "stripe")] -pub fn add_stripe_routes(router: Router) -> Router { - return router; -} diff --git a/backend/windmill-api/src/stripe_ee.rs b/backend/windmill-api/src/stripe_ee.rs new file mode 120000 index 0000000000..a6c7d1230e --- /dev/null +++ b/backend/windmill-api/src/stripe_ee.rs @@ -0,0 +1 @@ +/git/windmill/../windmill-ee-private/windmill-api/src/stripe_ee.rs \ No newline at end of file diff --git a/backend/windmill-audit/src/audit_ee.rs b/backend/windmill-audit/src/audit_ee.rs deleted file mode 100644 index 5bb52e7b3f..0000000000 --- a/backend/windmill-audit/src/audit_ee.rs +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Author: Ruben Fiszel - * Copyright: Windmill Labs, Inc 2022 - * This file and its contents are licensed under the AGPLv3 License. - * Please see the included NOTICE for copyright information and - * LICENSE-AGPL for a copy of the license. - */ -use std::collections::HashMap; - -use windmill_common::{ - error::{Error, Result}, - utils::Pagination, -}; - -use crate::{ActionKind, AuditLog, ListAuditLogQuery}; -use sqlx::{Postgres, Transaction}; - -#[tracing::instrument(level = "trace", skip_all)] -pub async fn audit_log<'c, E: sqlx::Executor<'c, Database = Postgres>>( - _db: E, - _username: &str, - mut _operation: &str, - _action_kind: ActionKind, - _w_id: &str, - mut _resource: Option<&str>, - _parameters: Option>, -) -> Result<()> { - // Implementation is not open source as Audit logs is a Windmill Enterprise Edition feature - Ok(()) -} - -pub async fn list_audit( - _tx: Transaction<'_, Postgres>, - _w_id: String, - _pagination: Pagination, - _lq: ListAuditLogQuery, -) -> Result> { - // Implementation is not open source as Audit logs is a Windmill Enterprise Edition feature - return Ok(vec![]); -} - -pub async fn get_audit(tx: Transaction<'_, Postgres>, _id: i32, _w_id: &str) -> Result { - // Implementation is not open source as Audit logs is a Windmill Enterprise Edition feature - tx.commit().await?; - Err(Error::NotFound( - "Audit log not not available in Windmill Community edition".to_string(), - )) -} diff --git a/backend/windmill-audit/src/audit_ee.rs b/backend/windmill-audit/src/audit_ee.rs new file mode 120000 index 0000000000..f8d4a81d03 --- /dev/null +++ b/backend/windmill-audit/src/audit_ee.rs @@ -0,0 +1 @@ +/git/windmill/../windmill-ee-private/windmill-audit/src/audit_ee.rs \ No newline at end of file diff --git a/backend/windmill-common/src/ee.rs b/backend/windmill-common/src/ee.rs deleted file mode 100644 index 51ad62a8a9..0000000000 --- a/backend/windmill-common/src/ee.rs +++ /dev/null @@ -1,28 +0,0 @@ -use crate::ee::LicensePlan::Community; -use serde::{Deserialize, Serialize}; -use std::sync::Arc; -use tokio::sync::RwLock; - -lazy_static::lazy_static! { - pub static ref LICENSE_KEY_VALID: Arc> = Arc::new(RwLock::new(true)); - pub static ref LICENSE_KEY_ID: Arc> = Arc::new(RwLock::new("".to_string())); - pub static ref LICENSE_KEY: Arc> = Arc::new(RwLock::new("".to_string())); -} - -pub enum LicensePlan { - Community, - Pro, - Enterprise, -} - -pub async fn get_license_plan() -> LicensePlan { - // Implementation is not open source - return Community; -} - -#[derive(Serialize, Deserialize)] -pub enum CriticalErrorChannel {} - -pub async fn trigger_critical_error_channels(_msg: String) { - // Implementation is not open source -} diff --git a/backend/windmill-common/src/ee.rs b/backend/windmill-common/src/ee.rs new file mode 120000 index 0000000000..3220066a5d --- /dev/null +++ b/backend/windmill-common/src/ee.rs @@ -0,0 +1 @@ +/git/windmill/../windmill-ee-private/windmill-common/src/ee.rs \ No newline at end of file diff --git a/backend/windmill-common/src/job_s3_helpers_ee.rs b/backend/windmill-common/src/job_s3_helpers_ee.rs deleted file mode 100644 index b00c00a583..0000000000 --- a/backend/windmill-common/src/job_s3_helpers_ee.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::future::Future; - -use crate::{ - error::Error, - s3_helpers::{ObjectStoreResource, StorageResourceType}, -}; - -pub async fn get_s3_resource_internal<'c, F, Fut>( - _resource_type: StorageResourceType, - _s3_resource_value_raw: serde_json::Value, - _gen_token: F, -) -> crate::error::Result -where - F: FnOnce(String) -> Fut, - Fut: Future> + Send + 'static, -{ - todo!() -} diff --git a/backend/windmill-common/src/job_s3_helpers_ee.rs b/backend/windmill-common/src/job_s3_helpers_ee.rs new file mode 120000 index 0000000000..6c8430be70 --- /dev/null +++ b/backend/windmill-common/src/job_s3_helpers_ee.rs @@ -0,0 +1 @@ +/git/windmill/../windmill-ee-private/windmill-common/src/job_s3_helpers_ee.rs \ No newline at end of file diff --git a/backend/windmill-common/src/stats_ee.rs b/backend/windmill-common/src/stats_ee.rs deleted file mode 100644 index 7fa3950276..0000000000 --- a/backend/windmill-common/src/stats_ee.rs +++ /dev/null @@ -1,35 +0,0 @@ -use crate::{error::Result, scripts::ScriptLang, utils::Mode, DB}; - -pub async fn get_disable_stats_setting(_db: &DB) -> bool { - // stats details are closed source - - false -} - -pub async fn schedule_stats( - _instance_name: String, - _mode: Mode, - _db: &DB, - _http_client: &reqwest::Client, - _is_enterprise: bool, -) -> () { - // stats details are closed source -} - -#[derive(Debug, sqlx::FromRow, serde::Serialize)] -struct JobsUsage { - language: Option, - total_duration: i64, - count: i64, -} - -pub async fn send_stats( - _instance_name: &String, - _mode: &Mode, - _http_client: &reqwest::Client, - _db: &DB, - _is_enterprise: bool, -) -> Result<()> { - // stats details are closed source - Ok(()) -} diff --git a/backend/windmill-common/src/stats_ee.rs b/backend/windmill-common/src/stats_ee.rs new file mode 120000 index 0000000000..d0ddc5bd1d --- /dev/null +++ b/backend/windmill-common/src/stats_ee.rs @@ -0,0 +1 @@ +/git/windmill/../windmill-ee-private/windmill-common/src/stats_ee.rs \ No newline at end of file diff --git a/backend/windmill-git-sync/src/git_sync_ee.rs b/backend/windmill-git-sync/src/git_sync_ee.rs deleted file mode 100644 index 4be2858c27..0000000000 --- a/backend/windmill-git-sync/src/git_sync_ee.rs +++ /dev/null @@ -1,17 +0,0 @@ -use windmill_common::error::Result; - -use crate::{DeployedObject, DB}; - -pub async fn handle_deployment_metadata<'c, R: rsmq_async::RsmqConnection + Send + Clone + 'c>( - _email: &str, - _created_by: &str, - _db: &DB, - _w_id: &str, - _obj: DeployedObject, - _deployment_message: Option, - _rsmq: Option, - _skip_db_insert: bool, -) -> Result<()> { - // Git sync is an enterprise feature and not part of the open-source version - return Ok(()); -} diff --git a/backend/windmill-git-sync/src/git_sync_ee.rs b/backend/windmill-git-sync/src/git_sync_ee.rs new file mode 120000 index 0000000000..0824f2c28c --- /dev/null +++ b/backend/windmill-git-sync/src/git_sync_ee.rs @@ -0,0 +1 @@ +/git/windmill/../windmill-ee-private/windmill-git-sync/src/git_sync_ee.rs \ No newline at end of file diff --git a/cli/conf.ts b/cli/conf.ts index a0c713481c..d21d9c6256 100644 --- a/cli/conf.ts +++ b/cli/conf.ts @@ -25,7 +25,8 @@ export interface SyncOptions { export interface Codebase { relative_path: string; - includes: string[]; + includes?: string[]; + excludes?: string[]; } export async function readConfigFile(): Promise { diff --git a/cli/main.ts b/cli/main.ts index 93f6001ae4..a5c9082d1e 100644 --- a/cli/main.ts +++ b/cli/main.ts @@ -68,7 +68,12 @@ let command: any = new Command() } await Deno.writeTextFile( "wmill.yaml", - yamlStringify({ defaultTs: "bun", includes: [], excludes: [] }) + yamlStringify({ + defaultTs: "bun", + includes: [], + excludes: [], + codebases: [], + }) ); log.info(colors.green("wmill.yaml created")); }) diff --git a/cli/sync.ts b/cli/sync.ts index 3dd677c355..3ab3d3531b 100644 --- a/cli/sync.ts +++ b/cli/sync.ts @@ -60,13 +60,32 @@ export function findCodebase( codebases: SyncCodebase[] ): SyncCodebase | undefined { for (const c of codebases) { + let included = false; + let excluded = false; + if (c.includes == undefined || c.includes == null) { + included = true; + } if (typeof c.includes == "string") { c.includes = [c.includes]; } - for (const r of c.includes) { - if (minimatch(path, r)) { - return c; + for (const r of c.includes ?? []) { + if (included) { + break; } + if (minimatch(path, r)) { + included = true; + } + } + if (typeof c.excludes == "string") { + c.excludes = [c.excludes]; + } + for (const r of c.excludes ?? []) { + if (minimatch(path, r)) { + excluded = true; + } + } + if (included && !excluded) { + return c; } } }