Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions models/repo/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ type Repository struct {
OriginalURL string `xorm:"VARCHAR(2048)"`
DefaultBranch string
DefaultWikiBranch string
DefaultWikiFormat string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use RepoUnit to store the per repository configuration.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright I'll make the changes needed still getting familiar with the codebase apologies.


NumWatches int
NumStars int
Expand Down
3 changes: 3 additions & 0 deletions modules/setting/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ var (
DisableMigrations bool
DisableStars bool `ini:"DISABLE_STARS"`
DefaultBranch string
DefaultWikiFormat string
AllowAdoptionOfUnadoptedRepositories bool
AllowDeleteOfUnadoptedRepositories bool
DisableDownloadSourceArchives bool
Expand Down Expand Up @@ -172,6 +173,7 @@ var (
DisableMigrations: false,
DisableStars: false,
DefaultBranch: "main",
DefaultWikiFormat: "markdown",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need a global configuration?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be useful to have it for cases where you want every repo globally to support both or either upon creation while still leaving the repo owners the freedom to change it.

AllowForkWithoutMaximumLimit: true,
StreamArchives: true,

Expand Down Expand Up @@ -284,6 +286,7 @@ func loadRepositoryFrom(rootCfg ConfigProvider) {
Repository.GoGetCloneURLProtocol = sec.Key("GO_GET_CLONE_URL_PROTOCOL").MustString("https")
Repository.MaxCreationLimit = sec.Key("MAX_CREATION_LIMIT").MustInt(-1)
Repository.DefaultBranch = sec.Key("DEFAULT_BRANCH").MustString(Repository.DefaultBranch)
Repository.DefaultWikiFormat = sec.Key("WIKI_FORMAT").MustString(Repository.DefaultWikiFormat)
RepoRootPath = sec.Key("ROOT").MustString(filepath.Join(AppDataPath, "gitea-repositories"))
if !filepath.IsAbs(RepoRootPath) {
RepoRootPath = filepath.Join(AppWorkPath, RepoRootPath)
Expand Down
4 changes: 4 additions & 0 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2223,6 +2223,10 @@ settings.advanced_settings = Advanced Settings
settings.wiki_desc = Enable Repository Wiki
settings.use_internal_wiki = Use Built-In Wiki
settings.default_wiki_branch_name = Default Wiki Branch Name
settings.default_wiki_format = Default Wiki Format
settings.default_wiki_format.markdown = Markdown
settings.default_wiki_format.org = Org-mode
settings.default_wiki_format.both = Both
settings.failed_to_change_default_wiki_branch = Failed to change the default wiki branch.
settings.use_external_wiki = Use External Wiki
settings.external_wiki_url = External Wiki URL
Expand Down
3 changes: 2 additions & 1 deletion routers/api/v1/repo/wiki.go
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,8 @@ func wikiContentsByEntry(ctx *context.APIContext, entry *git.TreeEntry) string {
// wikiContentsByName returns the contents of a wiki page, along with a boolean
// indicating whether the page exists. Writes to ctx if an error occurs.
func wikiContentsByName(ctx *context.APIContext, commit *git.Commit, wikiName wiki_service.WebPath, isSidebarOrFooter bool) (string, string) {
gitFilename := wiki_service.WebPathToGitPath(wikiName)
repoDefaultWikiFormat := ctx.Repo.Repository.DefaultWikiFormat
gitFilename := wiki_service.WebPathToGitPath(wikiName, repoDefaultWikiFormat)
entry, err := findEntryForFile(commit, gitFilename)
if err != nil {
if git.IsErrNotExist(err) {
Expand Down
12 changes: 12 additions & 0 deletions routers/web/repo/setting/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,18 @@ func handleSettingsPostAdvanced(ctx *context.Context) {
}
}

// Update DefaultWikiFormat if wiki is enabled
if form.EnableWiki && !form.EnableExternalWiki {
defaultWikiFormat := form.DefaultWikiFormat
if defaultWikiFormat == "" {
defaultWikiFormat = setting.Repository.DefaultWikiFormat
}
if repo.DefaultWikiFormat != defaultWikiFormat {
repo.DefaultWikiFormat = defaultWikiFormat
repoChanged = true
}
}

if form.EnableIssues && form.EnableExternalTracker && !unit_model.TypeExternalTracker.UnitGlobalDisabled() {
if !validation.IsValidExternalURL(form.ExternalTrackerURL) {
ctx.Flash.Error(ctx.Tr("repo.settings.external_tracker_url_error"))
Expand Down
201 changes: 168 additions & 33 deletions routers/web/repo/wiki.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,21 +146,68 @@ func wikiContentsByEntry(ctx *context.Context, entry *git.TreeEntry) []byte {
// The last return value indicates whether the file should be returned as a raw file
func wikiEntryByName(ctx *context.Context, commit *git.Commit, wikiName wiki_service.WebPath) (*git.TreeEntry, string, bool, bool) {
isRaw := false
gitFilename := wiki_service.WebPathToGitPath(wikiName)
repoDefaultWikiFormat := ctx.Repo.Repository.DefaultWikiFormat
gitFilename := wiki_service.WebPathToGitPath(wikiName, repoDefaultWikiFormat)
entry, err := findEntryForFile(commit, gitFilename)
if err != nil && !git.IsErrNotExist(err) {
ctx.ServerError("findEntryForFile", err)
return nil, "", false, false
}
if entry == nil {
// check if the file without ".md" suffix exists
gitFilename := strings.TrimSuffix(gitFilename, ".md")
entry, err = findEntryForFile(commit, gitFilename)
if err != nil && !git.IsErrNotExist(err) {
ctx.ServerError("findEntryForFile", err)
return nil, "", false, false
// Get default wiki format from repository, using global setting as fallback
defaultWikiFormat := ctx.Repo.Repository.DefaultWikiFormat
if defaultWikiFormat == "" {
defaultWikiFormat = setting.Repository.DefaultWikiFormat
}

// Check if gitFilename already has .md or .org extension and extract base filename
baseFilename, hasMdSuffix := strings.CutSuffix(gitFilename, ".md")
var hasOrgSuffix bool
if !hasMdSuffix {
baseFilename, hasOrgSuffix = strings.CutSuffix(gitFilename, ".org")
if !hasOrgSuffix {
baseFilename = gitFilename
}
}

// Try alternative formats based on DefaultWikiFormat setting
if defaultWikiFormat == "markdown" || defaultWikiFormat == "both" {
if !hasMdSuffix && !hasOrgSuffix {
entry, err = findEntryForFile(commit, baseFilename+".md")
if err != nil && !git.IsErrNotExist(err) {
ctx.ServerError("findEntryForFile", err)
return nil, "", false, false
}
if entry != nil {
gitFilename = baseFilename + ".md"
}
}
}

if entry == nil && (defaultWikiFormat == "org" || defaultWikiFormat == "both") {
if !hasMdSuffix && !hasOrgSuffix {
entry, err = findEntryForFile(commit, baseFilename+".org")
if err != nil && !git.IsErrNotExist(err) {
ctx.ServerError("findEntryForFile", err)
return nil, "", false, false
}
if entry != nil {
gitFilename = baseFilename + ".org"
}
}
}

if entry == nil {
entry, err = findEntryForFile(commit, baseFilename)
if err != nil && !git.IsErrNotExist(err) {
ctx.ServerError("findEntryForFile", err)
return nil, "", false, false
}
if entry != nil {
gitFilename = baseFilename
isRaw = true
}
}
isRaw = true
}
if entry == nil {
return nil, "", true, false
Expand Down Expand Up @@ -193,12 +240,31 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
ctx.ServerError("ListEntries", err)
return nil, nil
}

// Get default wiki format from repository, using global setting as fallback
defaultWikiFormat := ctx.Repo.Repository.DefaultWikiFormat
if defaultWikiFormat == "" {
defaultWikiFormat = setting.Repository.DefaultWikiFormat
}

pages := make([]PageMeta, 0, len(entries))
for _, entry := range entries {
if !entry.IsRegular() {
continue
}
wikiName, err := wiki_service.GitPathToWebPath(entry.Name())
entryName := entry.Name()

// Filter by DefaultWikiFormat
hasMdSuffix := strings.HasSuffix(entryName, ".md")
hasOrgSuffix := strings.HasSuffix(entryName, ".org")
if defaultWikiFormat == "markdown" && hasOrgSuffix {
continue
}
if defaultWikiFormat == "org" && hasMdSuffix {
continue
}

wikiName, err := wiki_service.GitPathToWebPath(entryName)
if err != nil {
if repo_model.IsErrWikiInvalidFileName(err) {
continue
Expand All @@ -212,7 +278,7 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
pages = append(pages, PageMeta{
Name: displayName,
SubURL: wiki_service.WebPathToURLPath(wikiName),
GitEntryName: entry.Name(),
GitEntryName: entryName,
})
}
ctx.Data["Pages"] = pages
Expand Down Expand Up @@ -252,7 +318,7 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {

rctx := renderhelper.NewRenderContextRepoWiki(ctx, ctx.Repo.Repository)

renderFn := func(data []byte) (escaped *charset.EscapeStatus, output template.HTML, err error) {
renderFn := func(data []byte, filename string) (escaped *charset.EscapeStatus, output template.HTML, err error) {
buf := &strings.Builder{}
markupRd, markupWr := io.Pipe()
defer markupWr.Close()
Expand All @@ -265,13 +331,21 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
close(done)
}()

err = markdown.Render(rctx, bytes.NewReader(data), markupWr)
// Detect markup type from filename and use the appropriate renderer
// (.md -> markdown, .org -> orgmode)
markupType := markup.DetectMarkupTypeByFileName(filename)
if markupType == "" {
// Default to markdown if detection fails
markupType = markdown.MarkupName
}
fileRctx := rctx.WithMarkupType(markupType).WithRelativePath(filename)
err = markup.Render(fileRctx, bytes.NewReader(data), markupWr)
_ = markupWr.CloseWithError(err)
<-done
return escaped, output, err
}

ctx.Data["EscapeStatus"], ctx.Data["WikiContentHTML"], err = renderFn(data)
ctx.Data["EscapeStatus"], ctx.Data["WikiContentHTML"], err = renderFn(data, pageFilename)
if err != nil {
ctx.ServerError("Render", err)
return nil, nil
Expand All @@ -286,26 +360,38 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
}

if !isSideBar {
sidebarContent, _, _, _ := wikiContentsByName(ctx, commit, "_Sidebar")
sidebarContent, sidebarEntry, sidebarFilename, _ := wikiContentsByName(ctx, commit, "_Sidebar")
if ctx.Written() {
return nil, nil
}
ctx.Data["WikiSidebarEscapeStatus"], ctx.Data["WikiSidebarHTML"], err = renderFn(sidebarContent)
if err != nil {
ctx.ServerError("Render", err)
return nil, nil
if sidebarEntry != nil && sidebarContent != nil {
// Use the git filename returned by wikiContentsByName, which correctly handles .org files
if sidebarFilename == "" {
sidebarFilename = sidebarEntry.Name()
}
ctx.Data["WikiSidebarEscapeStatus"], ctx.Data["WikiSidebarHTML"], err = renderFn(sidebarContent, sidebarFilename)
if err != nil {
ctx.ServerError("Render", err)
return nil, nil
}
}
}

if !isFooter {
footerContent, _, _, _ := wikiContentsByName(ctx, commit, "_Footer")
footerContent, footerEntry, footerFilename, _ := wikiContentsByName(ctx, commit, "_Footer")
if ctx.Written() {
return nil, nil
}
ctx.Data["WikiFooterEscapeStatus"], ctx.Data["WikiFooterHTML"], err = renderFn(footerContent)
if err != nil {
ctx.ServerError("Render", err)
return nil, nil
if footerEntry != nil && footerContent != nil {
// Use git filename here too to handle .org files correctly
if footerFilename == "" {
footerFilename = footerEntry.Name()
}
ctx.Data["WikiFooterEscapeStatus"], ctx.Data["WikiFooterHTML"], err = renderFn(footerContent, footerFilename)
if err != nil {
ctx.ServerError("Render", err)
return nil, nil
}
}
}

Expand Down Expand Up @@ -492,7 +578,9 @@ func Wiki(ctx *context.Context) {
}

wikiPath := entry.Name()
if markup.DetectMarkupTypeByFileName(wikiPath) != markdown.MarkupName {
detectedMarkupType := markup.DetectMarkupTypeByFileName(wikiPath)
if detectedMarkupType == "" {
// Only show warning if no renderer was found for this file type
ext := strings.ToUpper(filepath.Ext(wikiPath))
ctx.Data["FormatWarning"] = ext + " rendering is not supported at the moment. Rendered as Markdown."
}
Expand Down Expand Up @@ -575,12 +663,30 @@ func WikiPages(ctx *context.Context) {
return
}

// Get default wiki format from repository, using global setting as fallback
defaultWikiFormat := ctx.Repo.Repository.DefaultWikiFormat
if defaultWikiFormat == "" {
defaultWikiFormat = setting.Repository.DefaultWikiFormat
}

pages := make([]PageMeta, 0, len(entries))
for _, entry := range entries {
if !entry.Entry.IsRegular() {
continue
}
wikiName, err := wiki_service.GitPathToWebPath(entry.Entry.Name())
entryName := entry.Entry.Name()

// Filter by DefaultWikiFormat
hasMdSuffix := strings.HasSuffix(entryName, ".md")
hasOrgSuffix := strings.HasSuffix(entryName, ".org")
if defaultWikiFormat == "markdown" && hasOrgSuffix {
continue
}
if defaultWikiFormat == "org" && hasMdSuffix {
continue
}

wikiName, err := wiki_service.GitPathToWebPath(entryName)
if err != nil {
if repo_model.IsErrWikiInvalidFileName(err) {
continue
Expand All @@ -592,7 +698,7 @@ func WikiPages(ctx *context.Context) {
pages = append(pages, PageMeta{
Name: displayName,
SubURL: wiki_service.WebPathToURLPath(wikiName),
GitEntryName: entry.Entry.Name(),
GitEntryName: entryName,
UpdatedUnix: timeutil.TimeStamp(entry.Commit.Author.When.Unix()),
})
}
Expand All @@ -614,7 +720,8 @@ func WikiRaw(ctx *context.Context) {
}

providedWebPath := wiki_service.WebPathFromRequest(ctx.PathParamRaw("*"))
providedGitPath := wiki_service.WebPathToGitPath(providedWebPath)
repoDefaultWikiFormat := ctx.Repo.Repository.DefaultWikiFormat
providedGitPath := wiki_service.WebPathToGitPath(providedWebPath, repoDefaultWikiFormat)
var entry *git.TreeEntry
if commit != nil {
// Try to find a file with that name
Expand All @@ -625,12 +732,40 @@ func WikiRaw(ctx *context.Context) {
}

if entry == nil {
// Try to find a wiki page with that name
providedGitPath = strings.TrimSuffix(providedGitPath, ".md")
entry, err = findEntryForFile(commit, providedGitPath)
if err != nil && !git.IsErrNotExist(err) {
ctx.ServerError("findFile", err)
return
// Get default wiki format from repository, using global setting as fallback
defaultWikiFormat := ctx.Repo.Repository.DefaultWikiFormat
if defaultWikiFormat == "" {
defaultWikiFormat = setting.Repository.DefaultWikiFormat
}

// Try to find a wiki page with that name based on DefaultWikiFormat
basePath, _ := strings.CutSuffix(providedGitPath, ".md")
if basePath == providedGitPath {
basePath, _ = strings.CutSuffix(providedGitPath, ".org")
}

if defaultWikiFormat == "markdown" || defaultWikiFormat == "both" {
entry, err = findEntryForFile(commit, basePath+".md")
if err != nil && !git.IsErrNotExist(err) {
ctx.ServerError("findFile", err)
return
}
}

if entry == nil && (defaultWikiFormat == "org" || defaultWikiFormat == "both") {
entry, err = findEntryForFile(commit, basePath+".org")
if err != nil && !git.IsErrNotExist(err) {
ctx.ServerError("findFile", err)
return
}
}

if entry == nil {
entry, err = findEntryForFile(commit, basePath)
if err != nil && !git.IsErrNotExist(err) {
ctx.ServerError("findFile", err)
return
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion routers/web/repo/wiki_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func wikiEntry(t *testing.T, repo *repo_model.Repository, wikiName wiki_service.
entries, err := commit.ListEntries()
assert.NoError(t, err)
for _, entry := range entries {
if entry.Name() == wiki_service.WebPathToGitPath(wikiName) {
if entry.Name() == wiki_service.WebPathToGitPath(wikiName, repo.DefaultWikiFormat) {
return entry
}
}
Expand Down
1 change: 1 addition & 0 deletions services/forms/repo_form.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ type RepoSettingForm struct {
// Advanced settings
EnableCode bool

DefaultWikiFormat string
EnableWiki bool
EnableExternalWiki bool
DefaultWikiBranch string
Expand Down
Loading