2
0

docs(detached-note): add comprehensive API reference and user guide
Some checks failed
Build and Release / Create Release (push) Successful in 0s
Build and Release / Unit Tests (push) Successful in 3m19s
Build and Release / Integration Tests (PostgreSQL) (push) Successful in 4m39s
Build and Release / Lint (push) Successful in 4m46s
Build and Release / Build Binary (linux/arm64) (push) Has been cancelled
Build and Release / Build Binaries (amd64, linux, linux-latest) (push) Has been cancelled
Build and Release / Build Binaries (amd64, windows, windows-latest) (push) Has been cancelled
Build and Release / Build Binaries (amd64, darwin, macos) (push) Has been cancelled
Build and Release / Build Binaries (arm64, darwin, macos) (push) Has been cancelled

Add API.md (3200+ lines) with complete REST API documentation covering authentication, repository management, issues, pull requests, organizations, package registry, Actions, and Vault APIs. Includes code examples and error handling.

Add GUIDE.md with user-focused documentation for getting started, repository operations, collaboration workflows, and CI/CD setup.

Implement documentation tab in repository view with automatic detection and rendering of API.md and GUIDE.md files alongside README. Add locale strings and template for doc tab navigation.
This commit is contained in:
2026-01-27 22:43:56 -05:00
parent 1c0c1b8b74
commit 8806fcecba
6 changed files with 4688 additions and 9 deletions

3226
API.md Normal file
View File

File diff suppressed because it is too large Load Diff

1343
GUIDE.md Normal file
View File

File diff suppressed because it is too large Load Diff

View File

@@ -1004,6 +1004,8 @@
"repo.readme": "README", "repo.readme": "README",
"repo.readme_helper": "Select a README file template.", "repo.readme_helper": "Select a README file template.",
"repo.readme_helper_desc": "This is the place where you can write a complete description for your project.", "repo.readme_helper_desc": "This is the place where you can write a complete description for your project.",
"repo.guide": "User Guide",
"repo.api_doc": "API",
"repo.auto_init": "Initialize Repository (Adds .gitignore, License and README)", "repo.auto_init": "Initialize Repository (Adds .gitignore, License and README)",
"repo.trust_model_helper": "Select trust model for signature verification. Possible options are:", "repo.trust_model_helper": "Select trust model for signature verification. Possible options are:",
"repo.trust_model_helper_collaborator": "Collaborator: Trust signatures by collaborators", "repo.trust_model_helper_collaborator": "Collaborator: Trust signatures by collaborators",

View File

@@ -14,6 +14,7 @@ import (
"code.gitcaddy.com/server/v3/models/db" "code.gitcaddy.com/server/v3/models/db"
git_model "code.gitcaddy.com/server/v3/models/git" git_model "code.gitcaddy.com/server/v3/models/git"
"code.gitcaddy.com/server/v3/models/renderhelper"
repo_model "code.gitcaddy.com/server/v3/models/repo" repo_model "code.gitcaddy.com/server/v3/models/repo"
unit_model "code.gitcaddy.com/server/v3/models/unit" unit_model "code.gitcaddy.com/server/v3/models/unit"
user_model "code.gitcaddy.com/server/v3/models/user" user_model "code.gitcaddy.com/server/v3/models/user"
@@ -23,6 +24,7 @@ import (
"code.gitcaddy.com/server/v3/modules/httplib" "code.gitcaddy.com/server/v3/modules/httplib"
"code.gitcaddy.com/server/v3/modules/json" "code.gitcaddy.com/server/v3/modules/json"
"code.gitcaddy.com/server/v3/modules/log" "code.gitcaddy.com/server/v3/modules/log"
"code.gitcaddy.com/server/v3/modules/markup/markdown"
"code.gitcaddy.com/server/v3/modules/plugins" "code.gitcaddy.com/server/v3/modules/plugins"
repo_module "code.gitcaddy.com/server/v3/modules/repository" repo_module "code.gitcaddy.com/server/v3/modules/repository"
"code.gitcaddy.com/server/v3/modules/setting" "code.gitcaddy.com/server/v3/modules/setting"
@@ -259,6 +261,62 @@ func isGalleryImageFile(filename string) bool {
return false return false
} }
// prepareHomeDocTab loads a markdown doc file for a named tab on the repo home page.
// keyPrefix is used to namespace context data (e.g. "Guide" → "GuideTabExist", "GuideTabContent").
func prepareHomeDocTab(ctx *context.Context, filename, keyPrefix string) {
ctx.Data[keyPrefix+"TabExist"] = false
if ctx.Repo.Repository.IsEmpty {
return
}
commit := ctx.Repo.Commit
if commit == nil {
return
}
entry, err := commit.GetTreeEntryByPath(filename)
if err != nil || entry.IsDir() {
return
}
ctx.Data[keyPrefix+"TabExist"] = true
ctx.Data[keyPrefix+"TabFileName"] = filename
// Load content
content, err := entry.Blob().GetBlobContent(setting.UI.MaxDisplayFileSize)
if err != nil {
log.Error("prepareHomeDocTab(%s): GetBlobContent: %v", filename, err)
return
}
// Render markdown using the full markup pipeline
rctx := renderhelper.NewRenderContextRepoFile(ctx, ctx.Repo.Repository, renderhelper.RepoFileOptions{
CurrentRefPath: ctx.Repo.RefTypeNameSubURL(),
CurrentTreePath: ".",
}).WithMarkupType("markdown").WithRelativePath(filename)
rendered, err := markdown.RenderString(rctx, content)
if err != nil {
log.Error("prepareHomeDocTab(%s): RenderString: %v", filename, err)
ctx.Data[keyPrefix+"TabContent"] = content
ctx.Data[keyPrefix+"TabIsMarkdown"] = false
return
}
ctx.Data[keyPrefix+"TabContent"] = rendered
ctx.Data[keyPrefix+"TabIsMarkdown"] = true
}
// prepareHomeGuideTab loads GUIDE.md for the User Guide tab
func prepareHomeGuideTab(ctx *context.Context) {
prepareHomeDocTab(ctx, "GUIDE.md", "Guide")
}
// prepareHomeAPIDocTab loads API.md for the API tab
func prepareHomeAPIDocTab(ctx *context.Context) {
prepareHomeDocTab(ctx, "API.md", "APIDoc")
}
func prepareToRenderDirectory(ctx *context.Context) { func prepareToRenderDirectory(ctx *context.Context) {
entries := renderDirectoryFiles(ctx, 1*time.Second) entries := renderDirectoryFiles(ctx, 1*time.Second)
if ctx.Written() { if ctx.Written() {
@@ -594,6 +652,8 @@ func Home(ctx *context.Context) {
prepareUpstreamDivergingInfo, prepareUpstreamDivergingInfo,
prepareHomeSidebarLicenses, prepareHomeSidebarLicenses,
prepareHomeLicenseTab, prepareHomeLicenseTab,
prepareHomeGuideTab,
prepareHomeAPIDocTab,
prepareHomeGalleryTab, prepareHomeGalleryTab,
prepareHomeSidebarCitationFile(entry), prepareHomeSidebarCitationFile(entry),
prepareHomeSidebarLanguageStats, prepareHomeSidebarLanguageStats,

View File

@@ -130,43 +130,64 @@
{{template "repo/code/upstream_diverging_info" .}} {{template "repo/code/upstream_diverging_info" .}}
{{end}} {{end}}
{{template "repo/view_list" .}} {{template "repo/view_list" .}}
{{/* Tabs for Readme, License, Gallery - only shown at repo root */}} {{/* Tabs for Readme, Guide, API, License, Gallery - only shown at repo root */}}
{{if and $isTreePathRoot (or (and .ReadmeExist (or .IsMarkup .IsPlainText)) .LicenseTabExist .GalleryTabExist)}} {{$hasReadme := and .ReadmeExist (or .IsMarkup .IsPlainText)}}
{{if and $isTreePathRoot (or $hasReadme .GuideTabExist .APIDocTabExist .LicenseTabExist .GalleryTabExist)}}
<div class="ui top attached tabular menu" id="repo-home-tabs"> <div class="ui top attached tabular menu" id="repo-home-tabs">
{{if and .ReadmeExist (or .IsMarkup .IsPlainText)}} {{if $hasReadme}}
<a class="active item" data-tab="readme"> <a class="active item" data-tab="readme">
{{svg "octicon-book" 16}} {{ctx.Locale.Tr "repo.readme"}} {{svg "octicon-book" 16}} {{ctx.Locale.Tr "repo.readme"}}
</a> </a>
{{end}} {{end}}
{{if .GuideTabExist}}
<a class="{{if not $hasReadme}}active {{end}}item" data-tab="guide">
{{svg "octicon-mortar-board" 16}} {{ctx.Locale.Tr "repo.guide"}}
</a>
{{end}}
{{if .APIDocTabExist}}
<a class="{{if and (not $hasReadme) (not .GuideTabExist)}}active {{end}}item" data-tab="apidoc">
{{svg "octicon-plug" 16}} {{ctx.Locale.Tr "repo.api_doc"}}
</a>
{{end}}
{{if .LicenseTabExist}} {{if .LicenseTabExist}}
<a class="{{if not (and .ReadmeExist (or .IsMarkup .IsPlainText))}}active {{end}}item" data-tab="license"> <a class="{{if and (not $hasReadme) (not .GuideTabExist) (not .APIDocTabExist)}}active {{end}}item" data-tab="license">
{{svg "octicon-law" 16}} {{ctx.Locale.Tr "repo.license"}} {{svg "octicon-law" 16}} {{ctx.Locale.Tr "repo.license"}}
</a> </a>
{{end}} {{end}}
{{if .GalleryTabExist}} {{if .GalleryTabExist}}
<a class="{{if and (not (and .ReadmeExist (or .IsMarkup .IsPlainText))) (not .LicenseTabExist)}}active {{end}}item" data-tab="gallery"> <a class="{{if and (not $hasReadme) (not .GuideTabExist) (not .APIDocTabExist) (not .LicenseTabExist)}}active {{end}}item" data-tab="gallery">
{{svg "octicon-image" 16}} {{ctx.Locale.Tr "repo.gallery"}} {{svg "octicon-image" 16}} {{ctx.Locale.Tr "repo.gallery"}}
</a> </a>
{{end}} {{end}}
</div> </div>
<div class="ui bottom attached segment tw-p-0"> <div class="ui bottom attached segment tw-p-0">
{{if and .ReadmeExist (or .IsMarkup .IsPlainText)}} {{if $hasReadme}}
<div class="ui active tab" data-tab="readme"> <div class="ui active tab" data-tab="readme">
{{template "repo/view_file" .}} {{template "repo/view_file" .}}
</div> </div>
{{end}} {{end}}
{{if .GuideTabExist}}
<div class="ui {{if not $hasReadme}}active {{end}}tab" data-tab="guide">
{{template "repo/view_doc_tab" dict "ctxData" . "FileName" .GuideTabFileName "Content" .GuideTabContent "IsMarkdown" .GuideTabIsMarkdown "Icon" "octicon-mortar-board"}}
</div>
{{end}}
{{if .APIDocTabExist}}
<div class="ui {{if and (not $hasReadme) (not .GuideTabExist)}}active {{end}}tab" data-tab="apidoc">
{{template "repo/view_doc_tab" dict "ctxData" . "FileName" .APIDocTabFileName "Content" .APIDocTabContent "IsMarkdown" .APIDocTabIsMarkdown "Icon" "octicon-plug"}}
</div>
{{end}}
{{if .LicenseTabExist}} {{if .LicenseTabExist}}
<div class="ui {{if not (and .ReadmeExist (or .IsMarkup .IsPlainText))}}active {{end}}tab" data-tab="license"> <div class="ui {{if and (not $hasReadme) (not .GuideTabExist) (not .APIDocTabExist)}}active {{end}}tab" data-tab="license">
{{template "repo/view_license_tab" .}} {{template "repo/view_license_tab" .}}
</div> </div>
{{end}} {{end}}
{{if .GalleryTabExist}} {{if .GalleryTabExist}}
<div class="ui {{if and (not (and .ReadmeExist (or .IsMarkup .IsPlainText))) (not .LicenseTabExist)}}active {{end}}tab" data-tab="gallery"> <div class="ui {{if and (not $hasReadme) (not .GuideTabExist) (not .APIDocTabExist) (not .LicenseTabExist)}}active {{end}}tab" data-tab="gallery">
{{template "repo/view_gallery_tab" .}} {{template "repo/view_gallery_tab" .}}
</div> </div>
{{end}} {{end}}
</div> </div>
{{else if and .ReadmeExist (or .IsMarkup .IsPlainText)}} {{else if $hasReadme}}
{{/* Fallback: show README without tabs if it's the only content */}} {{/* Fallback: show README without tabs if it's the only content */}}
{{template "repo/view_file" .}} {{template "repo/view_file" .}}
{{end}} {{end}}

View File

@@ -0,0 +1,27 @@
<div class="file-view code-view">
<div class="file-header tw-flex tw-items-center tw-justify-between">
<div class="file-header-left tw-flex tw-items-center">
{{svg .Icon 18 "tw-mr-2"}}
<strong>{{.FileName}}</strong>
</div>
<div class="file-header-right">
<a class="ui basic tiny button" href="{{.ctxData.RepoLink}}/src/{{.ctxData.RefTypeNameSubURL}}/{{.FileName}}">
{{svg "octicon-file" 14}} {{ctx.Locale.Tr "repo.view_file"}}
</a>
<a class="ui basic tiny button" href="{{.ctxData.RepoLink}}/raw/{{.ctxData.RefTypeNameSubURL}}/{{.FileName}}">
{{svg "octicon-code" 14}} {{ctx.Locale.Tr "repo.file_raw"}}
</a>
</div>
</div>
<div class="file-body tw-p-4 tw-text-base">
{{if .IsMarkdown}}
<div class="markup markdown">
{{.Content}}
</div>
{{else}}
<div class="file-content plain-text">
<pre>{{.Content}}</pre>
</div>
{{end}}
</div>
</div>