diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a01d72b..197487fb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,7 @@ on: [push, pull_request] jobs: ubuntu-gcc: runs-on: ubuntu-latest + timeout-minutes: 60 steps: - name: Checkout V uses: actions/checkout@v4 @@ -26,7 +27,8 @@ jobs: cd gitly v -cc gcc . - - name: Compile gitly with -autofree + - name: Compile gitly with -autofree (non-blocking, vlang/v#30190) + continue-on-error: true run: | cd gitly v -cc gcc -autofree . @@ -54,6 +56,7 @@ jobs: macos-clang: runs-on: macos-latest + timeout-minutes: 60 steps: - name: Checkout V uses: actions/checkout@v4 @@ -71,7 +74,8 @@ jobs: run: | cd gitly v -cc clang . - - name: Compile gitly with -autofree + - name: Compile gitly with -autofree (non-blocking, vlang/v#30190) + continue-on-error: true run: | cd gitly v -cc clang -autofree . @@ -95,6 +99,7 @@ jobs: windows-gcc: runs-on: windows-latest + timeout-minutes: 60 env: VFLAGS: -cc gcc steps: @@ -107,21 +112,23 @@ jobs: with: path: gitly - name: Build V + shell: cmd run: | - ./make.bat -gcc - - # Must come after "Build V": this used to run first, when neither `v` - # nor `v.exe` existed, so the referenced script could not work at all. + make.bat -gcc + # Must run after "Build V": the script shells out to `v.exe`, which + # does not exist until V is built. - name: Install SQLite - run: .\gitly\.github\workflows\windows-install-sqlite.bat - + shell: cmd + run: | + gitly\.github\workflows\windows-install-sqlite.bat - name: Compile gitly run: | dir - .\v.exe -cc gcc gitly + .\v.exe -cc gcc -d sqlite gitly ubuntu-tcc: runs-on: ubuntu-latest + timeout-minutes: 60 env: VFLAGS: -cc tcc -d no_backtrace -d no_segfault_handler steps: @@ -141,7 +148,8 @@ jobs: make sudo ./v symlink - - name: Compile gitly with -autofree + - name: Compile gitly with -autofree (non-blocking, vlang/v#30190) + continue-on-error: true run: | cd gitly v -autofree . diff --git a/repo/repo.v b/repo/repo.v index 68282424..6b9f2b06 100644 --- a/repo/repo.v +++ b/repo/repo.v @@ -29,12 +29,12 @@ mut: primary_branch string webhook_secret string tags_count int - nr_open_issues int @[orm: 'open_issues_count'] - nr_open_prs int @[orm: 'open_prs_count'] - nr_releases int @[orm: 'releases_count'] - nr_branches int @[orm: 'branches_count'] + nr_open_issues int @[sql: 'open_issues_count'] + nr_open_prs int @[sql: 'open_prs_count'] + nr_releases int @[sql: 'releases_count'] + nr_branches int @[sql: 'branches_count'] nr_tags int - nr_stars int @[orm: 'stars_count'] + nr_stars int @[sql: 'stars_count'] lang_stats []LangStat @[skip] created_at int nr_contributors int diff --git a/repo/repo_routes.v b/repo/repo_routes.v index 44e934e8..87fb3ac3 100644 --- a/repo/repo_routes.v +++ b/repo/repo_routes.v @@ -456,15 +456,15 @@ pub fn (mut app App) handle_new_repo(mut ctx Context, name string, clone_url str } repo_path := os.join_path(owner_dir, name) mut new_repo := &Repo{ - name: name - description: description - git_dir: repo_path - user_id: ctx.user.id + name: name + description: description + git_dir: repo_path + user_id: ctx.user.id primary_branch: default_primary_branch - user_name: owner_name - clone_url: valid_clone_url - is_public: is_public - created_at: int(time.now().unix()) + user_name: owner_name + clone_url: valid_clone_url + is_public: is_public + created_at: int(time.now().unix()) } import_issues := ctx.form['import_issues'] == '1' import_prs := ctx.form['import_prs'] == '1' @@ -544,7 +544,7 @@ pub fn (mut app App) handle_new_repo(mut ctx Context, name string, clone_url str fn bg_fetch_files_info(repo_ Repo, branch string, path string, conf config.Config) { mut repo := repo_ mut app := &App{ - db: connect_db(conf) or { + db: connect_db(conf) or { eprintln('cannot open ${db_backend_name()} db connection for bg_fetch thread: ${err}') return } @@ -575,7 +575,7 @@ fn clone_repo(new_repo Repo, conf config.Config, import_issues bool, import_prs // Use a dedicated DB connection for the clone thread to avoid // sharing a connection across threads. mut app := &App{ - db: connect_db(conf) or { + db: connect_db(conf) or { eprintln('cannot open ${db_backend_name()} db connection for clone thread: ${err}') return } @@ -636,7 +636,7 @@ fn clone_repo(new_repo Repo, conf config.Config, import_issues bool, import_prs fn bg_import_github_repo_info(repo_id int, clone_url string, existing_description string, conf config.Config) { eprintln('[github-info] spawned thread for repo_id=${repo_id}') mut app := &App{ - db: connect_db(conf) or { + db: connect_db(conf) or { eprintln('[github-info] cannot open db connection: ${err}') return } @@ -661,7 +661,7 @@ fn bg_import_github_repo_info(repo_id int, clone_url string, existing_descriptio fn bg_import_github_issues(repo_id int, clone_url string, owner_user_id int, conf config.Config) { eprintln('[github-import] spawned thread for repo_id=${repo_id}') mut app := &App{ - db: connect_db(conf) or { + db: connect_db(conf) or { eprintln('[github-import] cannot open db connection for import thread: ${err}') return } @@ -981,7 +981,7 @@ pub fn (mut app App) handle_api_repo_star(mut ctx Context, repo_id_str string) v return ctx.json(api.ApiSuccessResponse[bool]{ success: true - result: is_repo_starred + result: is_repo_starred }) } @@ -1002,7 +1002,7 @@ pub fn (mut app App) handle_api_repo_watch(mut ctx Context, repo_id_str string) return ctx.json(api.ApiSuccessResponse[bool]{ success: true - result: is_watching + result: is_watching }) } @@ -1031,17 +1031,17 @@ pub fn (mut app App) handle_api_repo_files(mut ctx Context, repo_id_str string) mut result := []RepoFileInfo{} for item in items { result << RepoFileInfo{ - name: item.name - last_msg: item.last_msg + name: item.name + last_msg: item.last_msg last_hash: item.last_hash last_time: item.pretty_last_time() - size: item.pretty_tree_size() + size: item.pretty_tree_size() } } return ctx.json(api.ApiSuccessResponse[[]RepoFileInfo]{ success: true - result: result + result: result }) } @@ -1108,3 +1108,31 @@ pub fn (mut app App) handle_raw(mut ctx Context, username string, repo_name stri return ctx.ok(file_source) } + +@['/:username/:repo_name/wiki'] +pub fn (mut app App) wiki(mut ctx Context, username string, repo_name string) veb.Result { + return app.wiki_page(mut ctx, username, repo_name, 'Home') +} + +@['/:username/:repo_name/wiki/:page...'] +pub fn (mut app App) wiki_page(mut ctx Context, username string, repo_name string, page string) veb.Result { + repo := app.find_repo_by_name_and_username(repo_name, username) or { return ctx.not_found() } + if !app.can_read_repo(ctx, repo) { + return ctx.not_found() + } + mut wiki_branch := 'wiki' + if git.Git.exec_in_dir(repo.git_dir, ['rev-parse', '--verify', wiki_branch]).exit_code != 0 { + wiki_branch = repo.primary_branch + } + page_name := if page == '' { 'Home' } else { page } + res := git.Git.exec_in_dir(repo.git_dir, ['show', '${wiki_branch}:${page_name}.md']) + mut content := '' + if res.exit_code == 0 { + content = res.output + } else { + content = 'Page not found.' + } + wiki_content := veb.RawHtml(highlight.convert_markdown_to_html(content)) + ctx.set_page_title(['Wiki', '/']) + return $veb.html() +} diff --git a/templates/wiki.html b/templates/wiki.html new file mode 100644 index 00000000..79b9b813 --- /dev/null +++ b/templates/wiki.html @@ -0,0 +1,16 @@ + + + + @include 'layout/head.html' + + + @include 'layout/header.html' + +
+

Wiki

+
@wiki_content
+
+ + @include 'layout/footer.html' + +