From aefc6910330a009fec654aece06c6dc411ad1679 Mon Sep 17 00:00:00 2001 From: realaravinth Date: Tue, 17 May 2022 01:04:44 +0530 Subject: [PATCH] feat: migrate gitea interfaces to use forge/gitea interfaces --- src/forge.rs | 46 ++++++ src/gitea.rs | 173 ----------------------- src/main.rs | 2 +- src/settings.rs | 78 ---------- src/spider.rs | 150 +++++--------------- tests/schema/gitea/git.batsense.net.json | 2 - 6 files changed, 82 insertions(+), 369 deletions(-) create mode 100644 src/forge.rs delete mode 100644 src/gitea.rs delete mode 100644 tests/schema/gitea/git.batsense.net.json diff --git a/src/forge.rs b/src/forge.rs new file mode 100644 index 0000000..5544071 --- /dev/null +++ b/src/forge.rs @@ -0,0 +1,46 @@ +/* + * ForgeFlux StarChart - A federated software forge spider + * Copyright © 2022 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use async_trait::async_trait; +use db_core::prelude::*; + +#[async_trait] +pub trait SCForge: std::marker::Send + std::marker::Sync + CloneSPForge { + async fn is_forge(&self) -> bool; + async fn get_repositories(&self, limit: usize, page: usize) -> Vec; +} + +/// Trait to clone SCForge +pub trait CloneSPForge { + /// clone DB + fn clone_db(&self) -> Box; +} + +impl CloneSPForge for T +where + T: SCForge + Clone + 'static, +{ + fn clone_db(&self) -> Box { + Box::new(self.clone()) + } +} + +impl Clone for Box { + fn clone(&self) -> Self { + (**self).clone_db() + } +} diff --git a/src/gitea.rs b/src/gitea.rs deleted file mode 100644 index 913ed35..0000000 --- a/src/gitea.rs +++ /dev/null @@ -1,173 +0,0 @@ -/* - * ForgeFlux StarChart - A federated software forge spider - * Copyright © 2usize22 Aravinth Manivannan - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -use std::collections::HashMap; - -use db_core::AddRepository; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct SearchResults { - pub ok: bool, - pub data: Vec, -} - -#[derive(Debug, Clone, PartialEq, Hash, Eq, Serialize, Deserialize)] -pub struct User { - pub id: usize, - pub login: String, - pub full_name: String, - pub email: String, - pub avatar_url: String, - pub language: String, - pub is_admin: bool, - pub last_login: String, - pub created: String, - pub restricted: bool, - pub active: bool, - pub prohibit_login: bool, - pub location: String, - pub website: String, - pub description: String, - pub visibility: String, - pub followers_count: usize, - pub following_count: usize, - pub starred_repos_count: usize, - pub username: String, -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Repository { - pub name: String, - pub full_name: String, - pub description: String, - pub empty: bool, - pub private: bool, - pub fork: bool, - pub template: bool, - pub parent: Option>, - pub mirror: bool, - pub size: usize, - pub html_url: String, - pub ssh_url: String, - pub clone_url: String, - pub original_url: String, - pub owner: User, - pub website: String, - pub stars_count: usize, - pub forks_count: usize, - pub watchers_count: usize, - pub open_issues_count: usize, - pub open_pr_counter: usize, - pub release_counter: usize, - pub default_branch: String, - pub archived: bool, - pub created_at: String, - pub updated_at: String, - pub internal_tracker: InternalIssueTracker, - pub has_issues: bool, - pub has_wiki: bool, - pub has_pull_requests: bool, - pub has_projects: bool, - pub ignore_whitespace_conflicts: bool, - pub allow_merge_commits: bool, - pub allow_rebase: bool, - pub allow_rebase_explicit: bool, - pub allow_squash_merge: bool, - pub default_merge_style: String, - pub avatar_url: String, - pub internal: bool, - pub mirror_interval: String, - pub mirror_updated: String, - pub repo_transfer: Option, -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct InternalIssueTracker { - pub enable_time_tracker: bool, - pub allow_only_contributors_to_track_time: bool, - pub enable_issue_dependencies: bool, -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct RepoTransfer { - pub doer: User, - pub recipient: User, - pub teams: Option, -} - -#[derive(Debug, Clone, PartialEq, Serialize, Hash, Deserialize)] -pub struct Organization { - pub avatar_url: String, - pub description: String, - pub full_name: String, - pub id: u64, - pub location: String, - pub repo_admin_change_team_access: bool, - pub username: String, - pub visibility: String, - pub website: String, -} - -#[derive(Debug, Clone, PartialEq, Serialize, Hash, Deserialize)] -#[serde(rename_all = "lowercase")] -pub enum Permission { - None, - Read, - Write, - Admin, - Owner, -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Team { - pub can_create_org_repo: bool, - pub description: String, - pub id: u64, - pub includes_all_repositories: bool, - pub name: String, - pub organization: Organization, - pub permission: Permission, - pub units: Vec, - pub units_map: HashMap, -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Topics { - pub topics: Vec, -} - -#[cfg(test)] -mod tests { - use super::*; - - use std::fs; - - #[test] - /// Tests if Gitea responses panic when deserialized with serde into structs defined in this - /// module/file. Since Go doesn't have abilities to describe nullable values, I(@realaravinth) - /// am forced to do this as I my knowledge about Gitea codebase is very limited. - fn schema_doesnt_panic() { - let files = ["./tests/schema/gitea/git.batsense.net.json"]; - for file in files.iter() { - let contents = fs::read_to_string(file).unwrap(); - for line in contents.lines() { - let _: SearchResults = serde_json::from_str(line).expect("Gitea schema paniced"); - } - } - } -} diff --git a/src/main.rs b/src/main.rs index a378895..1dd9950 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,7 +17,7 @@ */ pub mod data; pub mod db; -pub mod gitea; +pub mod forge; pub mod settings; pub mod spider; #[cfg(test)] diff --git a/src/settings.rs b/src/settings.rs index b17dc88..d72e18b 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -102,42 +102,6 @@ impl DBType { } } -#[derive(Debug, Clone, Deserialize)] -struct DatabaseBuilder { - pub port: u32, - pub hostname: String, - pub username: String, - pub password: String, - pub name: String, - pub database_type: DBType, -} - -impl DatabaseBuilder { - #[cfg(not(tarpaulin_include))] - fn extract_database_url(url: &Url) -> Self { - log::debug!("Databse name: {}", url.path()); - let mut path = url.path().split('/'); - path.next(); - let name = path.next().expect("no database name").to_string(); - - let database_type = DBType::from_url(url).unwrap(); - let port = if database_type == DBType::Sqlite { - 0 - } else { - url.port().expect("Enter database port").into() - }; - - DatabaseBuilder { - port, - hostname: url.host().expect("Enter database host").to_string(), - username: url.username().into(), - password: url.password().expect("Enter database password").into(), - name, - database_type: DBType::from_url(url).unwrap(), - } - } -} - #[derive(Debug, Clone, Deserialize)] pub struct Database { pub url: String, @@ -247,48 +211,6 @@ impl Settings { } } -//#[cfg(not(tarpaulin_include))] -//fn set_from_database_url(s: &mut Config, database_conf: &DatabaseBuilder) { -// s.set("database.username", database_conf.username.clone()) -// .expect("Couldn't set database username"); -// s.set("database.password", database_conf.password.clone()) -// .expect("Couldn't access database password"); -// s.set("database.hostname", database_conf.hostname.clone()) -// .expect("Couldn't access database hostname"); -// s.set("database.port", database_conf.port as i64) -// .expect("Couldn't access database port"); -// s.set("database.name", database_conf.name.clone()) -// .expect("Couldn't access database name"); -// s.set( -// "database.database_type", -// format!("{}", database_conf.database_type), -// ) -// .expect("Couldn't access database type"); -//} - -//#[cfg(not(tarpaulin_include))] -//fn set_database_url(s: &mut Config) { -// s.set( -// "database.url", -// format!( -// r"{}://{}:{}@{}:{}/{}", -// s.get::("database.database_type") -// .expect("Couldn't access database database_type"), -// s.get::("database.username") -// .expect("Couldn't access database username"), -// s.get::("database.password") -// .expect("Couldn't access database password"), -// s.get::("database.hostname") -// .expect("Couldn't access database hostname"), -// s.get::("database.port") -// .expect("Couldn't access database port"), -// s.get::("database.name") -// .expect("Couldn't access database name") -// ), -// ) -// .expect("Couldn't set databse url"); -//} - #[cfg(test)] mod tests { use super::*; diff --git a/src/spider.rs b/src/spider.rs index 3f3c399..d4ff12b 100644 --- a/src/spider.rs +++ b/src/spider.rs @@ -21,54 +21,32 @@ use tokio::time; use url::Url; use db_core::prelude::*; +use forge_core::prelude::*; +use gitea::Gitea; use crate::data::Data; use crate::db::BoxDB; -use crate::gitea::SearchResults; -use crate::gitea::Topics; - -const REPO_SEARCH_PATH: &str = "/api/v1/repos/search"; -const GITEA_NODEINFO: &str = "/api/v1/nodeinfo"; impl Data { - pub async fn crawl(&self, hostname: &str, db: &BoxDB) -> Vec { - fn empty_is_none(s: &str) -> Option<&str> { - if s.trim().is_empty() { - None - } else { - Some(s) - } - } - + pub async fn crawl(&self, instance_url: &str, db: &BoxDB) { + let gitea = Gitea::new(Url::parse(instance_url).unwrap(), self.client.clone()); let mut page = 1; - let instance_url = Url::parse(hostname).unwrap(); - let hostname = get_hostname(&instance_url); - if !db.forge_exists(&hostname).await.unwrap() { + let hostname = gitea.get_hostname(); + if !db.forge_exists(hostname).await.unwrap() { let msg = CreateForge { - hostname: &hostname, - forge_type: ForgeImplementation::Gitea, + hostname, + forge_type: gitea.forge_type(), }; db.create_forge_isntance(&msg).await.unwrap(); } - let mut url = instance_url.clone(); - url.set_path(REPO_SEARCH_PATH); - let mut repos = Vec::new(); loop { - let mut url = url.clone(); - url.set_query(Some(&format!( - "page={page}&limit={}", - self.settings.crawler.items_per_api_call - ))); - let res: SearchResults = self - .client - .get(url) - .send() - .await - .unwrap() - .json() - .await - .unwrap(); + let res = gitea + .crawl(self.settings.crawler.items_per_api_call, page) + .await; + if res.repos.is_empty() { + break; + } let sleep_fut = time::sleep(Duration::new( self.settings.crawler.wait_before_next_api_call, @@ -76,85 +54,26 @@ impl Data { )); let sleep_fut = tokio::spawn(sleep_fut); - for repo in res.data.iter() { + for (username, u) in res.users.iter() { if !db - .user_exists(&repo.owner.username, Some(&hostname)) + .user_exists(&username, Some(&gitea.get_hostname())) .await .unwrap() { - let mut profile_url = instance_url.clone(); - profile_url.set_path(&repo.owner.username); - let msg = AddUser { - hostname: &hostname, - username: &repo.owner.username, - html_link: profile_url.as_str(), - profile_photo: Some(&repo.owner.avatar_url), - }; + let msg = u.as_ref().into(); db.add_user(&msg).await.unwrap(); } + } - let mut url = instance_url.clone(); - url.set_path(&format!( - "/api/v1/repos/{}/{}/topics", - repo.owner.username, repo.name - )); - - let topics: Topics = self - .client - .get(url) - .send() - .await - .unwrap() - .json() - .await - .unwrap(); - - let add_repo_msg = AddRepository { - tags: Some(topics.topics), - name: &repo.name, - website: empty_is_none(&repo.website), - description: empty_is_none(&repo.description), - owner: &repo.owner.username, - html_link: &repo.html_url, - hostname: &hostname, - }; - - db.create_repository(&add_repo_msg).await.unwrap(); + for r in res.repos.iter() { + let msg = r.into(); + db.create_repository(&msg).await.unwrap(); } sleep_fut.await.unwrap(); - if res.data.is_empty() { - return repos; - } - repos.push(res); page += 1; } } - - /// purpose: interact with instance running on provided hostname and verify if the instance is a - /// Gitea instance. - /// - /// will get nodeinfo information, which contains an identifier to uniquely identify Gitea - pub async fn is_gitea(&self, hostname: &str) -> bool { - const GITEA_IDENTIFIER: &str = "gitea"; - let mut url = Url::parse(hostname).unwrap(); - url.set_path(GITEA_NODEINFO); - - let res: serde_json::Value = self - .client - .get(url) - .send() - .await - .unwrap() - .json() - .await - .unwrap(); - if let serde_json::Value::String(software) = &res["software"]["name"] { - software == GITEA_IDENTIFIER - } else { - false - } - } } #[cfg(test)] @@ -165,25 +84,26 @@ mod tests { use url::Url; pub const GITEA_HOST: &str = "http://localhost:8080"; - - #[actix_rt::test] - async fn is_gitea_works() { - let (_db, data) = sqlx_sqlite::get_data().await; - assert!(data.is_gitea(GITEA_HOST).await); - } + pub const GITEA_USERNAME: &str = "bot"; #[actix_rt::test] async fn crawl_gitea() { let (db, data) = sqlx_sqlite::get_data().await; let res = data.crawl(GITEA_HOST, &db).await; - let mut elements = 0; - let username = &res.get(0).unwrap().data.get(0).unwrap().owner.username; let hostname = get_hostname(&Url::parse(GITEA_HOST).unwrap()); assert!(db.forge_exists(&hostname).await.unwrap()); - assert!(db.user_exists(username, Some(&hostname)).await.unwrap()); - res.iter().for_each(|r| elements += r.data.len()); - - assert_eq!(res.len(), 5); - assert_eq!(elements, 100); + assert!(db + .user_exists(GITEA_USERNAME, Some(&hostname)) + .await + .unwrap()); + assert!(db.user_exists(GITEA_USERNAME, None).await.unwrap()); + for i in 0..100 { + let repo = format!("reopsitory_{i}"); + assert!(db + .repository_exists(&repo, GITEA_USERNAME, hostname.as_str()) + .await + .unwrap()) + } + assert!(db.forge_exists(&hostname).await.unwrap()); } } diff --git a/tests/schema/gitea/git.batsense.net.json b/tests/schema/gitea/git.batsense.net.json deleted file mode 100644 index f42b562..0000000 --- a/tests/schema/gitea/git.batsense.net.json +++ /dev/null @@ -1,2 +0,0 @@ -{"ok":true,"data":[{"id":5,"owner":{"id":1,"login":"realaravinth","full_name":"Aravinth Manivannan","email":"realaravinth@batsense.net","avatar_url":"https://git.batsense.net/avatars/bc11e95d9356ac4bdc035964be00ff0d","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-09-10T18:44:04+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"Internet","website":"https://batsense.net","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":2,"username":"realaravinth"},"name":"analysis-of-captcha-systems","full_name":"realaravinth/analysis-of-captcha-systems","description":"","empty":false,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":109,"html_url":"https://git.batsense.net/realaravinth/analysis-of-captcha-systems","ssh_url":"git@git.batsense.net:realaravinth/analysis-of-captcha-systems.git","clone_url":"https://git.batsense.net/realaravinth/analysis-of-captcha-systems.git","original_url":"","website":"","stars_count":0,"forks_count":0,"watchers_count":1,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2021-09-20T15:50:21+05:30","updated_at":"2021-09-21T18:06:09+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},{"id":32,"owner":{"id":1,"login":"realaravinth","full_name":"Aravinth Manivannan","email":"realaravinth@batsense.net","avatar_url":"https://git.batsense.net/avatars/bc11e95d9356ac4bdc035964be00ff0d","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-09-10T18:44:04+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"Internet","website":"https://batsense.net","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":2,"username":"realaravinth"},"name":"fediparty-wiki","full_name":"realaravinth/fediparty-wiki","description":"","empty":false,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":435,"html_url":"https://git.batsense.net/realaravinth/fediparty-wiki","ssh_url":"git@git.batsense.net:realaravinth/fediparty-wiki.git","clone_url":"https://git.batsense.net/realaravinth/fediparty-wiki.git","original_url":"","website":"","stars_count":0,"forks_count":0,"watchers_count":1,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2022-01-13T13:10:42+05:30","updated_at":"2022-01-13T13:11:24+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},{"id":26,"owner":{"id":1,"login":"realaravinth","full_name":"Aravinth Manivannan","email":"realaravinth@batsense.net","avatar_url":"https://git.batsense.net/avatars/bc11e95d9356ac4bdc035964be00ff0d","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-09-10T18:44:04+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"Internet","website":"https://batsense.net","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":2,"username":"realaravinth"},"name":"ff-spec","full_name":"realaravinth/ff-spec","description":"notes, spec and all things forged fed","empty":false,"private":false,"fork":false,"template":false,"parent":null,"mirror":true,"size":142,"html_url":"https://git.batsense.net/realaravinth/ff-spec","ssh_url":"git@git.batsense.net:realaravinth/ff-spec.git","clone_url":"https://git.batsense.net/realaravinth/ff-spec.git","original_url":"https://github.com/forgefedv2/spec","website":"","stars_count":0,"forks_count":0,"watchers_count":1,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2022-01-01T17:50:17+05:30","updated_at":"2022-01-19T18:38:20+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"8h0m0s","mirror_updated":"2022-04-02T15:42:42+05:30","repo_transfer":null},{"id":18,"owner":{"id":1,"login":"realaravinth","full_name":"Aravinth Manivannan","email":"realaravinth@batsense.net","avatar_url":"https://git.batsense.net/avatars/bc11e95d9356ac4bdc035964be00ff0d","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-09-10T18:44:04+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"Internet","website":"https://batsense.net","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":2,"username":"realaravinth"},"name":"fork-ex","full_name":"realaravinth/fork-ex","description":"","empty":true,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":80,"html_url":"https://git.batsense.net/realaravinth/fork-ex","ssh_url":"git@git.batsense.net:realaravinth/fork-ex.git","clone_url":"https://git.batsense.net/realaravinth/fork-ex.git","original_url":"","website":"","stars_count":0,"forks_count":0,"watchers_count":1,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2021-12-21T14:53:38+05:30","updated_at":"2021-12-21T14:53:38+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},{"id":22,"owner":{"id":1,"login":"realaravinth","full_name":"Aravinth Manivannan","email":"realaravinth@batsense.net","avatar_url":"https://git.batsense.net/avatars/bc11e95d9356ac4bdc035964be00ff0d","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-09-10T18:44:04+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"Internet","website":"https://batsense.net","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":2,"username":"realaravinth"},"name":"fork-ex2","full_name":"realaravinth/fork-ex2","description":"","empty":false,"private":false,"fork":true,"template":false,"parent":{"id":19,"owner":{"id":2,"login":"bot","full_name":"","email":"bot@batsense.net","avatar_url":"https://git.batsense.net/avatar/a4edc8a838d6e28ddc38ab12aeb9d9cd","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-09-29T15:18:42+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"bot"},"name":"fork-ex","full_name":"bot/fork-ex","description":"","empty":false,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":89,"html_url":"https://git.batsense.net/bot/fork-ex","ssh_url":"git@git.batsense.net:bot/fork-ex.git","clone_url":"https://git.batsense.net/bot/fork-ex.git","original_url":"","website":"","stars_count":0,"forks_count":1,"watchers_count":1,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2021-12-21T14:56:50+05:30","updated_at":"2021-12-21T14:56:53+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},"mirror":false,"size":89,"html_url":"https://git.batsense.net/realaravinth/fork-ex2","ssh_url":"git@git.batsense.net:realaravinth/fork-ex2.git","clone_url":"https://git.batsense.net/realaravinth/fork-ex2.git","original_url":"","website":"","stars_count":0,"forks_count":0,"watchers_count":1,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2021-12-22T16:58:46+05:30","updated_at":"2021-12-22T16:58:46+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},{"id":6,"owner":{"id":1,"login":"realaravinth","full_name":"Aravinth Manivannan","email":"realaravinth@batsense.net","avatar_url":"https://git.batsense.net/avatars/bc11e95d9356ac4bdc035964be00ff0d","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-09-10T18:44:04+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"Internet","website":"https://batsense.net","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":2,"username":"realaravinth"},"name":"git-sandbox","full_name":"realaravinth/git-sandbox","description":"","empty":false,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":103,"html_url":"https://git.batsense.net/realaravinth/git-sandbox","ssh_url":"git@git.batsense.net:realaravinth/git-sandbox.git","clone_url":"https://git.batsense.net/realaravinth/git-sandbox.git","original_url":"","website":"","stars_count":0,"forks_count":1,"watchers_count":1,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2021-09-29T13:09:42+05:30","updated_at":"2021-09-29T18:14:27+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},{"id":42,"owner":{"id":1,"login":"realaravinth","full_name":"Aravinth Manivannan","email":"realaravinth@batsense.net","avatar_url":"https://git.batsense.net/avatars/bc11e95d9356ac4bdc035964be00ff0d","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-09-10T18:44:04+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"Internet","website":"https://batsense.net","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":2,"username":"realaravinth"},"name":"hostea-organization","full_name":"realaravinth/hostea-organization","description":"Organization of the hostea project","empty":false,"private":false,"fork":true,"template":false,"parent":{"id":41,"owner":{"id":5,"login":"Hostea","full_name":"","email":"","avatar_url":"https://git.batsense.net/avatars/fbade9e36a3f36d3d676c1b808451dd7","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2022-03-14T23:24:35+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"https://pad.batsense.net/wiEY8U7pSpCuZLz7gZVJoQ?view#","description":"Managed Gitea Hosting\r\n\r\npreviously: Project Z and Gitea managed hosting","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"Hostea"},"name":"organization","full_name":"Hostea/organization","description":"Organization of the hostea project","empty":false,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":278,"html_url":"https://git.batsense.net/Hostea/organization","ssh_url":"git@git.batsense.net:Hostea/organization.git","clone_url":"https://git.batsense.net/Hostea/organization.git","original_url":"","website":"","stars_count":0,"forks_count":1,"watchers_count":2,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2022-03-22T16:55:57+05:30","updated_at":"2022-04-01T22:37:53+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},"mirror":false,"size":194,"html_url":"https://git.batsense.net/realaravinth/hostea-organization","ssh_url":"git@git.batsense.net:realaravinth/hostea-organization.git","clone_url":"https://git.batsense.net/realaravinth/hostea-organization.git","original_url":"","website":"","stars_count":0,"forks_count":0,"watchers_count":1,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2022-04-01T15:04:14+05:30","updated_at":"2022-04-01T15:04:14+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},{"id":35,"owner":{"id":5,"login":"Hostea","full_name":"","email":"","avatar_url":"https://git.batsense.net/avatars/fbade9e36a3f36d3d676c1b808451dd7","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2022-03-14T23:24:35+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"https://pad.batsense.net/wiEY8U7pSpCuZLz7gZVJoQ?view#","description":"Managed Gitea Hosting\r\n\r\npreviously: Project Z and Gitea managed hosting","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"Hostea"},"name":"july-mvp","full_name":"Hostea/july-mvp","description":"100% Free Software Managed Gitea Hosting MVP scheduled for July 2022","empty":false,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":148,"html_url":"https://git.batsense.net/Hostea/july-mvp","ssh_url":"git@git.batsense.net:Hostea/july-mvp.git","clone_url":"https://git.batsense.net/Hostea/july-mvp.git","original_url":"","website":"","stars_count":2,"forks_count":1,"watchers_count":2,"open_issues_count":28,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2022-03-14T23:31:53+05:30","updated_at":"2022-03-23T10:55:49+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},{"id":41,"owner":{"id":5,"login":"Hostea","full_name":"","email":"","avatar_url":"https://git.batsense.net/avatars/fbade9e36a3f36d3d676c1b808451dd7","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2022-03-14T23:24:35+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"https://pad.batsense.net/wiEY8U7pSpCuZLz7gZVJoQ?view#","description":"Managed Gitea Hosting\r\n\r\npreviously: Project Z and Gitea managed hosting","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"Hostea"},"name":"organization","full_name":"Hostea/organization","description":"Organization of the hostea project","empty":false,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":278,"html_url":"https://git.batsense.net/Hostea/organization","ssh_url":"git@git.batsense.net:Hostea/organization.git","clone_url":"https://git.batsense.net/Hostea/organization.git","original_url":"","website":"","stars_count":0,"forks_count":1,"watchers_count":2,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2022-03-22T16:55:57+05:30","updated_at":"2022-04-01T22:37:53+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},{"id":37,"owner":{"id":5,"login":"Hostea","full_name":"","email":"","avatar_url":"https://git.batsense.net/avatars/fbade9e36a3f36d3d676c1b808451dd7","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2022-03-14T23:24:35+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"https://pad.batsense.net/wiEY8U7pSpCuZLz7gZVJoQ?view#","description":"Managed Gitea Hosting\r\n\r\npreviously: Project Z and Gitea managed hosting","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"Hostea"},"name":"payments","full_name":"Hostea/payments","description":"","empty":false,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":148,"html_url":"https://git.batsense.net/Hostea/payments","ssh_url":"git@git.batsense.net:Hostea/payments.git","clone_url":"https://git.batsense.net/Hostea/payments.git","original_url":"","website":"","stars_count":1,"forks_count":0,"watchers_count":2,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2022-03-16T15:12:05+05:30","updated_at":"2022-03-19T20:54:23+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},{"id":34,"owner":{"id":1,"login":"realaravinth","full_name":"Aravinth Manivannan","email":"realaravinth@batsense.net","avatar_url":"https://git.batsense.net/avatars/bc11e95d9356ac4bdc035964be00ff0d","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-09-10T18:44:04+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"Internet","website":"https://batsense.net","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":2,"username":"realaravinth"},"name":"rust-async","full_name":"realaravinth/rust-async","description":"","empty":false,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":88,"html_url":"https://git.batsense.net/realaravinth/rust-async","ssh_url":"git@git.batsense.net:realaravinth/rust-async.git","clone_url":"https://git.batsense.net/realaravinth/rust-async.git","original_url":"","website":"","stars_count":0,"forks_count":0,"watchers_count":1,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2022-02-24T22:06:00+05:30","updated_at":"2022-02-24T23:04:57+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},{"id":15,"owner":{"id":1,"login":"realaravinth","full_name":"Aravinth Manivannan","email":"realaravinth@batsense.net","avatar_url":"https://git.batsense.net/avatars/bc11e95d9356ac4bdc035964be00ff0d","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-09-10T18:44:04+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"Internet","website":"https://batsense.net","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":2,"username":"realaravinth"},"name":"testing","full_name":"realaravinth/testing","description":"test-description","empty":false,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":93,"html_url":"https://git.batsense.net/realaravinth/testing","ssh_url":"git@git.batsense.net:realaravinth/testing.git","clone_url":"https://git.batsense.net/realaravinth/testing.git","original_url":"","website":"","stars_count":0,"forks_count":0,"watchers_count":1,"open_issues_count":0,"open_pr_counter":1,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2021-12-21T11:37:55+05:30","updated_at":"2022-03-19T18:41:16+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},{"id":10,"owner":{"id":1,"login":"realaravinth","full_name":"Aravinth Manivannan","email":"realaravinth@batsense.net","avatar_url":"https://git.batsense.net/avatars/bc11e95d9356ac4bdc035964be00ff0d","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-09-10T18:44:04+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"Internet","website":"https://batsense.net","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":2,"username":"realaravinth"},"name":"tmp","full_name":"realaravinth/tmp","description":"test repo","empty":false,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":417,"html_url":"https://git.batsense.net/realaravinth/tmp","ssh_url":"git@git.batsense.net:realaravinth/tmp.git","clone_url":"https://git.batsense.net/realaravinth/tmp.git","original_url":"","website":"","stars_count":0,"forks_count":1,"watchers_count":2,"open_issues_count":3,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2021-10-23T10:08:50+05:30","updated_at":"2021-11-28T14:30:49+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},{"id":13,"owner":{"id":1,"login":"realaravinth","full_name":"Aravinth Manivannan","email":"realaravinth@batsense.net","avatar_url":"https://git.batsense.net/avatars/bc11e95d9356ac4bdc035964be00ff0d","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-09-10T18:44:04+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"Internet","website":"https://batsense.net","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":2,"username":"realaravinth"},"name":"tmp22","full_name":"realaravinth/tmp22","description":"lib created","empty":false,"private":false,"fork":true,"template":false,"parent":{"id":11,"owner":{"id":2,"login":"bot","full_name":"","email":"bot@batsense.net","avatar_url":"https://git.batsense.net/avatar/a4edc8a838d6e28ddc38ab12aeb9d9cd","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-09-29T15:18:42+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"bot"},"name":"tmp2","full_name":"bot/tmp2","description":"https://git.batsense.net/bot/tmp2","empty":false,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":418,"html_url":"https://git.batsense.net/bot/tmp2","ssh_url":"git@git.batsense.net:bot/tmp2.git","clone_url":"https://git.batsense.net/bot/tmp2.git","original_url":"","website":"","stars_count":0,"forks_count":1,"watchers_count":1,"open_issues_count":3,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2021-10-23T16:56:59+05:30","updated_at":"2022-01-01T13:28:38+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},"mirror":false,"size":430,"html_url":"https://git.batsense.net/realaravinth/tmp22","ssh_url":"git@git.batsense.net:realaravinth/tmp22.git","clone_url":"https://git.batsense.net/realaravinth/tmp22.git","original_url":"","website":"","stars_count":0,"forks_count":0,"watchers_count":1,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2021-10-23T18:32:21+05:30","updated_at":"2021-10-23T18:32:21+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},{"id":38,"owner":{"id":5,"login":"Hostea","full_name":"","email":"","avatar_url":"https://git.batsense.net/avatars/fbade9e36a3f36d3d676c1b808451dd7","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2022-03-14T23:24:35+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"https://pad.batsense.net/wiEY8U7pSpCuZLz7gZVJoQ?view#","description":"Managed Gitea Hosting\r\n\r\npreviously: Project Z and Gitea managed hosting","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"Hostea"},"name":"user-research","full_name":"Hostea/user-research","description":"User Research https://jdittrich.github.io/userNeedResearchBook/","empty":true,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":80,"html_url":"https://git.batsense.net/Hostea/user-research","ssh_url":"git@git.batsense.net:Hostea/user-research.git","clone_url":"https://git.batsense.net/Hostea/user-research.git","original_url":"","website":"","stars_count":2,"forks_count":0,"watchers_count":2,"open_issues_count":6,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2022-03-19T12:46:53+05:30","updated_at":"2022-03-19T12:46:54+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":false,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null}]} -{"ok":true,"data":[]}