Unknwon лет назад: 8
Родитель
Сommit
e538ff2770

+ 1 - 1
README.md

@@ -5,7 +5,7 @@ Gogs - Go Git Service [![Build Status](https://travis-ci.org/gogits/gogs.svg?bra
 
 ![](public/img/gogs-large-resize.png)
 
-##### Current version: 0.7.29 Beta
+##### Current version: 0.7.30 Beta
 
 <table>
     <tr>

+ 4 - 4
cmd/web.go

@@ -421,7 +421,7 @@ func runWeb(ctx *cli.Context) {
 		m.Get("/action/:action", repo.Action)
 
 		m.Group("/issues", func() {
-			m.Combo("/new").Get(middleware.RepoRef(), repo.NewIssue).
+			m.Combo("/new", repo.MustEnableIssues).Get(middleware.RepoRef(), repo.NewIssue).
 				Post(bindIgnErr(auth.CreateIssueForm{}), repo.NewIssuePost)
 
 			m.Combo("/:index/comments").Post(bindIgnErr(auth.CreateCommentForm{}), repo.NewComment)
@@ -459,7 +459,7 @@ func runWeb(ctx *cli.Context) {
 			m.Post("/delete", repo.DeleteRelease)
 		}, reqRepoAdmin, middleware.RepoRef())
 
-		m.Combo("/compare/*").Get(repo.CompareAndPullRequest).
+		m.Combo("/compare/*", repo.MustEnablePulls).Get(repo.CompareAndPullRequest).
 			Post(bindIgnErr(auth.CreateIssueForm{}), repo.CompareAndPullRequestPost)
 	}, reqSignIn, middleware.RepoAssignment())
 
@@ -484,7 +484,7 @@ func runWeb(ctx *cli.Context) {
 				m.Combo("/:page/_edit").Get(repo.EditWiki).
 					Post(bindIgnErr(auth.NewWikiForm{}), repo.EditWikiPost)
 			}, reqSignIn, reqRepoPusher)
-		}, middleware.RepoRef())
+		}, repo.MustEnableWiki, middleware.RepoRef())
 
 		m.Get("/archive/*", repo.Download)
 
@@ -492,7 +492,7 @@ func runWeb(ctx *cli.Context) {
 			m.Get("/commits", repo.ViewPullCommits)
 			m.Get("/files", repo.ViewPullFiles)
 			m.Post("/merge", reqRepoAdmin, repo.MergePullRequest)
-		})
+		}, repo.MustEnablePulls)
 
 		m.Group("", func() {
 			m.Get("/src/*", repo.Home)

+ 8 - 1
conf/locale/locale_en-US.ini

@@ -558,10 +558,17 @@ settings.collaboration = Collaboration
 settings.hooks = Webhooks
 settings.githooks = Git Hooks
 settings.basic_settings = Basic Settings
-settings.danger_zone = Danger Zone
 settings.site = Official Site
 settings.update_settings = Update Settings
 settings.change_reponame_prompt = This change will affect how links relate to the repository.
+settings.advanced_settings = Advanced Settings
+settings.wiki_desc = Enable wiki to allow people write documents
+settings.issues_desc = Enable builtin lightweight issue tracker 
+settings.use_external_issue_tracker = Use external issue tracker
+settings.tracker_url_format = External Issue Tracker URL Format
+settings.tracker_url_format_desc = You can use placeholder <code>{user} {repo} {index}</code> for user name, repository name and issue index.
+settings.pulls_desc = Enable pull requests to accept public contributions
+settings.danger_zone = Danger Zone
 settings.transfer = Transfer Ownership
 settings.transfer_desc = Transfer this repository to another user or to an organization in which you have admin rights.
 settings.new_owner_has_same_repo = The new owner already has a repository with same name. Please choose another name.

+ 0 - 1
docker/README.md

@@ -33,7 +33,6 @@ Directory `/var/gogs` keeps Git repositories and Gogs data:
         |-- conf
         |-- data
         |-- log
-        |-- templates
 
 ### Volume with data container
 

+ 1 - 1
gogs.go

@@ -17,7 +17,7 @@ import (
 	"github.com/gogits/gogs/modules/setting"
 )
 
-const APP_VER = "0.7.29.1204 Beta"
+const APP_VER = "0.7.30.1204 Beta"
 
 func init() {
 	runtime.GOMAXPROCS(runtime.NumCPU())

+ 22 - 0
models/repo.go

@@ -161,6 +161,14 @@ type Repository struct {
 	IsMirror bool
 	*Mirror  `xorm:"-"`
 
+	// Advanced settings
+	EnableWiki            bool `xorm:"NOT NULL DEFAULT true"`
+	EnableIssues          bool `xorm:"NOT NULL DEFAULT true"`
+	EnableExternalTracker bool
+	ExternalTrackerFormat string
+	ExternalMetas         map[string]string `xorm:"-"`
+	EnablePulls           bool              `xorm:"NOT NULL DEFAULT true"`
+
 	IsFork   bool `xorm:"NOT NULL DEFAULT false"`
 	ForkID   int64
 	BaseRepo *Repository `xorm:"-"`
@@ -214,6 +222,20 @@ func (repo *Repository) MustOwner() *User {
 	return repo.mustOwner(x)
 }
 
+// ComposeMetas composes a map of metas for rendering external issue tracker URL.
+func (repo *Repository) ComposeMetas() map[string]string {
+	if !repo.EnableExternalTracker {
+		return nil
+	} else if repo.ExternalMetas == nil {
+		repo.ExternalMetas = map[string]string{
+			"format": repo.ExternalTrackerFormat,
+			"user":   repo.MustOwner().Name,
+			"repo":   repo.Name,
+		}
+	}
+	return repo.ExternalMetas
+}
+
 // GetAssignees returns all users that have write access of repository.
 func (repo *Repository) GetAssignees() (_ []*User, err error) {
 	if err = repo.GetOwner(); err != nil {

+ 7 - 0
modules/auth/repo_form.go

@@ -87,6 +87,13 @@ type RepoSettingForm struct {
 	Branch      string
 	Interval    int
 	Private     bool
+
+	// Advanced settings
+	EnableWiki            bool
+	EnableIssues          bool
+	EnableExternalTracker bool
+	TrackerURLFormat      string
+	EnablePulls           bool
 }
 
 func (f *RepoSettingForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {

+ 67 - 62
modules/base/markdown.go

@@ -137,50 +137,6 @@ var (
 	sha1CurrentPattern = regexp.MustCompile(`\b[0-9a-f]{40}\b`)
 )
 
-func RenderSpecialLink(rawBytes []byte, urlPrefix string) []byte {
-	ms := MentionPattern.FindAll(rawBytes, -1)
-	for _, m := range ms {
-		m = bytes.TrimSpace(m)
-		rawBytes = bytes.Replace(rawBytes, m,
-			[]byte(fmt.Sprintf(`<a href="%s/%s">%s</a>`, setting.AppSubUrl, m[1:], m)), -1)
-	}
-
-	ms = commitPattern.FindAll(rawBytes, -1)
-	for _, m := range ms {
-		m = bytes.TrimSpace(m)
-		i := strings.Index(string(m), "commit/")
-		j := strings.Index(string(m), "#")
-		if j == -1 {
-			j = len(m)
-		}
-		rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(
-			` <code><a href="%s">%s</a></code>`, m, ShortSha(string(m[i+7:j])))), -1)
-	}
-	ms = issueFullPattern.FindAll(rawBytes, -1)
-	for _, m := range ms {
-		m = bytes.TrimSpace(m)
-		i := strings.Index(string(m), "issues/")
-		j := strings.Index(string(m), "#")
-		if j == -1 {
-			j = len(m)
-		}
-		rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(
-			` <a href="%s">#%s</a>`, m, ShortSha(string(m[i+7:j])))), -1)
-	}
-	rawBytes = RenderIssueIndexPattern(rawBytes, urlPrefix)
-	rawBytes = RenderSha1CurrentPattern(rawBytes, urlPrefix)
-	return rawBytes
-}
-
-func RenderSha1CurrentPattern(rawBytes []byte, urlPrefix string) []byte {
-	ms := sha1CurrentPattern.FindAll(rawBytes, -1)
-	for _, m := range ms {
-		rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(
-			`<a href="%s/commit/%s"><code>%s</code></a>`, urlPrefix, m, ShortSha(string(m)))), -1)
-	}
-	return rawBytes
-}
-
 func cutoutVerbosePrefix(prefix string) string {
 	count := 0
 	for i := 0; i < len(prefix); i++ {
@@ -194,7 +150,7 @@ func cutoutVerbosePrefix(prefix string) string {
 	return prefix
 }
 
-func RenderIssueIndexPattern(rawBytes []byte, urlPrefix string) []byte {
+func RenderIssueIndexPattern(rawBytes []byte, urlPrefix string, metas map[string]string) []byte {
 	urlPrefix = cutoutVerbosePrefix(urlPrefix)
 	ms := issueIndexPattern.FindAll(rawBytes, -1)
 	for _, m := range ms {
@@ -204,24 +160,45 @@ func RenderIssueIndexPattern(rawBytes []byte, urlPrefix string) []byte {
 			space = " "
 			m2 = m2[1:]
 		}
-		rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(`%s<a href="%s/issues/%s">%s</a>`,
-			space, urlPrefix, m2[1:], m2)), 1)
+		if metas == nil {
+			rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(`%s<a href="%s/issues/%s">%s</a>`,
+				space, urlPrefix, m2[1:], m2)), 1)
+		} else {
+			// Support for external issue tracker
+			metas["index"] = string(m2[1:])
+			rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(`%s<a href="%s">%s</a>`,
+				space, com.Expand(metas["format"], metas), m2)), 1)
+		}
+	}
+	return rawBytes
+}
+
+func RenderSpecialLink(rawBytes []byte, urlPrefix string, metas map[string]string) []byte {
+	ms := MentionPattern.FindAll(rawBytes, -1)
+	for _, m := range ms {
+		m = bytes.TrimSpace(m)
+		rawBytes = bytes.Replace(rawBytes, m,
+			[]byte(fmt.Sprintf(`<a href="%s/%s">%s</a>`, setting.AppSubUrl, m[1:], m)), -1)
+	}
+
+	rawBytes = RenderIssueIndexPattern(rawBytes, urlPrefix, metas)
+	rawBytes = RenderSha1CurrentPattern(rawBytes, urlPrefix)
+	return rawBytes
+}
+
+func RenderSha1CurrentPattern(rawBytes []byte, urlPrefix string) []byte {
+	ms := sha1CurrentPattern.FindAll(rawBytes, -1)
+	for _, m := range ms {
+		rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(
+			`<a href="%s/commit/%s"><code>%s</code></a>`, urlPrefix, m, ShortSha(string(m)))), -1)
 	}
 	return rawBytes
 }
 
 func RenderRawMarkdown(body []byte, urlPrefix string) []byte {
 	htmlFlags := 0
-	// htmlFlags |= blackfriday.HTML_USE_XHTML
-	// htmlFlags |= blackfriday.HTML_USE_SMARTYPANTS
-	// htmlFlags |= blackfriday.HTML_SMARTYPANTS_FRACTIONS
-	// htmlFlags |= blackfriday.HTML_SMARTYPANTS_LATEX_DASHES
-	// htmlFlags |= blackfriday.HTML_SKIP_HTML
 	htmlFlags |= blackfriday.HTML_SKIP_STYLE
-	// htmlFlags |= blackfriday.HTML_SKIP_SCRIPT
-	// htmlFlags |= blackfriday.HTML_GITHUB_BLOCKCODE
 	htmlFlags |= blackfriday.HTML_OMIT_CONTENTS
-	// htmlFlags |= blackfriday.HTML_COMPLETE_PAGE
 	renderer := &CustomRender{
 		Renderer:  blackfriday.HtmlRenderer(htmlFlags, "", ""),
 		urlPrefix: urlPrefix,
@@ -252,9 +229,36 @@ var (
 
 var noEndTags = []string{"img", "input", "br", "hr"}
 
+// PreProcessMarkdown renders full links of commits, issues and pulls to shorter version.
+func PreProcessMarkdown(rawHTML []byte, urlPrefix string) []byte {
+	ms := commitPattern.FindAll(rawHTML, -1)
+	for _, m := range ms {
+		m = bytes.TrimSpace(m)
+		i := strings.Index(string(m), "commit/")
+		j := strings.Index(string(m), "#")
+		if j == -1 {
+			j = len(m)
+		}
+		rawHTML = bytes.Replace(rawHTML, m, []byte(fmt.Sprintf(
+			` <code><a href="%s">%s</a></code>`, m, ShortSha(string(m[i+7:j])))), -1)
+	}
+	ms = issueFullPattern.FindAll(rawHTML, -1)
+	for _, m := range ms {
+		m = bytes.TrimSpace(m)
+		i := strings.Index(string(m), "issues/")
+		j := strings.Index(string(m), "#")
+		if j == -1 {
+			j = len(m)
+		}
+		rawHTML = bytes.Replace(rawHTML, m, []byte(fmt.Sprintf(
+			` <a href="%s">#%s</a>`, m, ShortSha(string(m[i+7:j])))), -1)
+	}
+	return rawHTML
+}
+
 // PostProcessMarkdown treats different types of HTML differently,
 // and only renders special links for plain text blocks.
-func PostProcessMarkdown(rawHtml []byte, urlPrefix string) []byte {
+func PostProcessMarkdown(rawHtml []byte, urlPrefix string, metas map[string]string) []byte {
 	startTags := make([]string, 0, 5)
 	var buf bytes.Buffer
 	tokenizer := html.NewTokenizer(bytes.NewReader(rawHtml))
@@ -264,7 +268,7 @@ OUTER_LOOP:
 		token := tokenizer.Token()
 		switch token.Type {
 		case html.TextToken:
-			buf.Write(RenderSpecialLink([]byte(token.String()), urlPrefix))
+			buf.Write(RenderSpecialLink([]byte(token.String()), urlPrefix, metas))
 
 		case html.StartTagToken:
 			buf.WriteString(token.String())
@@ -322,13 +326,14 @@ OUTER_LOOP:
 	return rawHtml
 }
 
-func RenderMarkdown(rawBytes []byte, urlPrefix string) []byte {
-	result := RenderRawMarkdown(rawBytes, urlPrefix)
-	result = PostProcessMarkdown(result, urlPrefix)
+func RenderMarkdown(rawBytes []byte, urlPrefix string, metas map[string]string) []byte {
+	result := PreProcessMarkdown(rawBytes, urlPrefix)
+	result = RenderRawMarkdown(result, urlPrefix)
+	result = PostProcessMarkdown(result, urlPrefix, metas)
 	result = Sanitizer.SanitizeBytes(result)
 	return result
 }
 
-func RenderMarkdownString(raw, urlPrefix string) string {
-	return string(RenderMarkdown([]byte(raw), urlPrefix))
+func RenderMarkdownString(raw, urlPrefix string, metas map[string]string) string {
+	return string(RenderMarkdown([]byte(raw), urlPrefix, metas))
 }

Разница между файлами не показана из-за своего большого размера
+ 2 - 2
modules/bindata/bindata.go


+ 2 - 2
modules/mailer/mail.go

@@ -125,7 +125,7 @@ func SendIssueNotifyMail(u, owner *models.User, repo *models.Repository, issue *
 
 	subject := fmt.Sprintf("[%s] %s (#%d)", repo.Name, issue.Name, issue.Index)
 	content := fmt.Sprintf("%s<br>-<br> <a href=\"%s%s/%s/issues/%d\">View it on Gogs</a>.",
-		base.RenderSpecialLink([]byte(issue.Content), owner.Name+"/"+repo.Name),
+		base.RenderSpecialLink([]byte(issue.Content), owner.Name+"/"+repo.Name, repo.ComposeMetas()),
 		setting.AppUrl, owner.Name, repo.Name, issue.Index)
 	msg := NewMessage(tos, subject, content)
 	msg.Info = fmt.Sprintf("Subject: %s, issue notify", subject)
@@ -148,7 +148,7 @@ func SendIssueMentionMail(r macaron.Render, u, owner *models.User,
 	data["IssueLink"] = fmt.Sprintf("%s/%s/issues/%d", owner.Name, repo.Name, issue.Index)
 	data["Subject"] = subject
 	data["ActUserName"] = u.DisplayName()
-	data["Content"] = string(base.RenderSpecialLink([]byte(issue.Content), owner.Name+"/"+repo.Name))
+	data["Content"] = string(base.RenderSpecialLink([]byte(issue.Content), owner.Name+"/"+repo.Name, repo.ComposeMetas()))
 
 	body, err := r.HTMLString(string(NOTIFY_MENTION), data)
 	if err != nil {

+ 1 - 0
modules/middleware/repo.go

@@ -165,6 +165,7 @@ func RepoAssignment(args ...bool) macaron.Handler {
 		ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner()
 		ctx.Data["IsRepositoryAdmin"] = ctx.Repo.IsAdmin()
 		ctx.Data["IsRepositoryPusher"] = ctx.Repo.IsPusher()
+		ctx.Data["CanPullRequest"] = ctx.Repo.IsAdmin() && repo.BaseRepo != nil && repo.BaseRepo.EnablePulls
 
 		ctx.Data["DisableSSH"] = setting.DisableSSH
 		ctx.Data["CloneLink"] = repo.CloneLink()

+ 2 - 2
modules/template/template.go

@@ -183,9 +183,9 @@ func ReplaceLeft(s, old, new string) string {
 }
 
 // RenderCommitMessage renders commit message with XSS-safe and special links.
-func RenderCommitMessage(msg, urlPrefix string) template.HTML {
+func RenderCommitMessage(msg, urlPrefix string, metas map[string]string) template.HTML {
 	cleanMsg := template.HTMLEscapeString(msg)
-	fullMessage := string(base.RenderIssueIndexPattern([]byte(cleanMsg), urlPrefix))
+	fullMessage := string(base.RenderIssueIndexPattern([]byte(cleanMsg), urlPrefix, metas))
 	msgLines := strings.Split(strings.TrimSpace(fullMessage), "\n")
 	for i := range msgLines {
 		msgLines[i] = ReplaceLeft(msgLines[i], " ", "&nbsp;")

+ 3 - 0
public/css/gogs.css

@@ -911,6 +911,9 @@ pre.raw {
 .ui .form .fake {
   display: none !important;
 }
+.ui .form .sub.field {
+  margin-left: 25px;
+}
 .ui .sha.label {
   font-family: Consolas, Menlo, Monaco, "Lucida Console", monospace;
   font-size: 13px;

+ 4 - 0
public/less/_base.less

@@ -217,6 +217,10 @@ pre {
 		.fake {
 			display: none !important;
 		}
+
+		.sub.field {
+			margin-left: 25px;
+		}
 	}
 
 	.sha.label {

+ 1 - 1
routers/api/v1/misc/markdown.go

@@ -25,7 +25,7 @@ func Markdown(ctx *middleware.Context, form api.MarkdownOption) {
 
 	switch form.Mode {
 	case "gfm":
-		ctx.Write(base.RenderMarkdown([]byte(form.Text), form.Context))
+		ctx.Write(base.RenderMarkdown([]byte(form.Text), form.Context, nil))
 	default:
 		ctx.Write(base.RenderRawMarkdown([]byte(form.Text), ""))
 	}

+ 28 - 5
routers/repo/issue.go

@@ -41,6 +41,18 @@ var (
 	ErrTooManyFiles      = errors.New("Maximum number of files to upload exceeded")
 )
 
+func MustEnableIssues(ctx *middleware.Context) {
+	if !ctx.Repo.Repository.EnableIssues {
+		ctx.Handle(404, "MustEnableIssues", nil)
+	}
+}
+
+func MustEnablePulls(ctx *middleware.Context) {
+	if !ctx.Repo.Repository.EnablePulls {
+		ctx.Handle(404, "MustEnablePulls", nil)
+	}
+}
+
 func RetrieveLabels(ctx *middleware.Context) {
 	labels, err := models.GetLabelsByRepoID(ctx.Repo.Repository.ID)
 	if err != nil {
@@ -60,7 +72,12 @@ func Issues(ctx *middleware.Context) {
 		ctx.Data["Title"] = ctx.Tr("repo.pulls")
 		ctx.Data["PageIsPullList"] = true
 		ctx.Data["HasForkedRepo"] = ctx.IsSigned && ctx.User.HasForkedRepo(ctx.Repo.Repository.ID)
+
 	} else {
+		MustEnableIssues(ctx)
+		if ctx.Written() {
+			return
+		}
 		ctx.Data["Title"] = ctx.Tr("repo.issues")
 		ctx.Data["PageIsIssueList"] = true
 	}
@@ -496,6 +513,10 @@ func ViewIssue(ctx *middleware.Context) {
 		ctx.Data["PageIsPullConversation"] = true
 		ctx.Data["HasForkedRepo"] = ctx.IsSigned && ctx.User.HasForkedRepo(ctx.Repo.Repository.ID)
 	} else {
+		MustEnableIssues(ctx)
+		if ctx.Written() {
+			return
+		}
 		ctx.Data["PageIsIssueList"] = true
 	}
 
@@ -503,7 +524,8 @@ func ViewIssue(ctx *middleware.Context) {
 		ctx.Handle(500, "GetPoster", err)
 		return
 	}
-	issue.RenderedContent = string(base.RenderMarkdown([]byte(issue.Content), ctx.Repo.RepoLink))
+	issue.RenderedContent = string(base.RenderMarkdown([]byte(issue.Content), ctx.Repo.RepoLink,
+		ctx.Repo.Repository.ComposeMetas()))
 
 	repo := ctx.Repo.Repository
 
@@ -570,7 +592,8 @@ func ViewIssue(ctx *middleware.Context) {
 	// Render comments.
 	for _, comment = range issue.Comments {
 		if comment.Type == models.COMMENT_TYPE_COMMENT {
-			comment.RenderedContent = string(base.RenderMarkdown([]byte(comment.Content), ctx.Repo.RepoLink))
+			comment.RenderedContent = string(base.RenderMarkdown([]byte(comment.Content), ctx.Repo.RepoLink,
+				ctx.Repo.Repository.ComposeMetas()))
 
 			// Check tag.
 			tag, ok = marked[comment.PosterID]
@@ -656,7 +679,7 @@ func UpdateIssueContent(ctx *middleware.Context) {
 	}
 
 	ctx.JSON(200, map[string]interface{}{
-		"content": string(base.RenderMarkdown([]byte(issue.Content), ctx.Query("context"))),
+		"content": string(base.RenderMarkdown([]byte(issue.Content), ctx.Query("context"), ctx.Repo.Repository.ComposeMetas())),
 	})
 }
 
@@ -893,7 +916,7 @@ func UpdateCommentContent(ctx *middleware.Context) {
 	}
 
 	ctx.JSON(200, map[string]interface{}{
-		"content": string(base.RenderMarkdown([]byte(comment.Content), ctx.Query("context"))),
+		"content": string(base.RenderMarkdown([]byte(comment.Content), ctx.Query("context"), ctx.Repo.Repository.ComposeMetas())),
 	})
 }
 
@@ -991,7 +1014,7 @@ func Milestones(ctx *middleware.Context) {
 		return
 	}
 	for _, m := range miles {
-		m.RenderedContent = string(base.RenderMarkdown([]byte(m.Content), ctx.Repo.RepoLink))
+		m.RenderedContent = string(base.RenderMarkdown([]byte(m.Content), ctx.Repo.RepoLink, ctx.Repo.Repository.ComposeMetas()))
 		m.CalOpenIssues()
 	}
 	ctx.Data["Milestones"] = miles

+ 2 - 2
routers/repo/release.go

@@ -69,7 +69,7 @@ func Releases(ctx *middleware.Context) {
 					rel.NumCommitsBehind = ctx.Repo.CommitsCount - rel.NumCommits
 				}
 
-				rel.Note = base.RenderMarkdownString(rel.Note, ctx.Repo.RepoLink)
+				rel.Note = base.RenderMarkdownString(rel.Note, ctx.Repo.RepoLink, ctx.Repo.Repository.ComposeMetas())
 				tags[i] = rel
 				rels[j] = nil // Mark as used.
 				break
@@ -129,7 +129,7 @@ func Releases(ctx *middleware.Context) {
 			rel.NumCommitsBehind = ctx.Repo.CommitsCount - rel.NumCommits
 		}
 
-		rel.Note = base.RenderMarkdownString(rel.Note, ctx.Repo.RepoLink)
+		rel.Note = base.RenderMarkdownString(rel.Note, ctx.Repo.RepoLink, ctx.Repo.Repository.ComposeMetas())
 		tags = append(tags, rel)
 	}
 	models.SortReleases(tags)

+ 19 - 2
routers/repo/setting.go

@@ -104,7 +104,7 @@ func SettingsPost(ctx *middleware.Context, form auth.RepoSettingForm) {
 			ctx.Handle(500, "UpdateRepository", err)
 			return
 		}
-		log.Trace("Repository updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
+		log.Trace("Repository basic settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
 
 		if isNameChanged {
 			if err := models.RenameRepoAction(ctx.User, oldRepoName, repo); err != nil {
@@ -123,7 +123,24 @@ func SettingsPost(ctx *middleware.Context, form auth.RepoSettingForm) {
 		}
 
 		ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
-		ctx.Redirect(fmt.Sprintf("%s/%s/%s/settings", setting.AppSubUrl, ctx.Repo.Owner.Name, repo.Name))
+		ctx.Redirect(ctx.Repo.RepoLink + "/settings")
+
+	case "advanced":
+		repo.EnableWiki = form.EnableWiki
+		repo.EnableIssues = form.EnableIssues
+		repo.EnableExternalTracker = form.EnableExternalTracker
+		repo.ExternalTrackerFormat = form.TrackerURLFormat
+		repo.EnablePulls = form.EnablePulls
+
+		if err := models.UpdateRepository(repo, false); err != nil {
+			ctx.Handle(500, "UpdateRepository", err)
+			return
+		}
+		log.Trace("Repository advanced settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
+
+		ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
+		ctx.Redirect(ctx.Repo.RepoLink + "/settings")
+
 	case "transfer":
 		if repo.Name != form.RepoName {
 			ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), SETTINGS_OPTIONS, nil)

+ 2 - 2
routers/repo/view.go

@@ -108,7 +108,7 @@ func Home(ctx *middleware.Context) {
 				readmeExist := base.IsMarkdownFile(blob.Name()) || base.IsReadmeFile(blob.Name())
 				ctx.Data["ReadmeExist"] = readmeExist
 				if readmeExist {
-					ctx.Data["FileContent"] = string(base.RenderMarkdown(buf, path.Dir(treeLink)))
+					ctx.Data["FileContent"] = string(base.RenderMarkdown(buf, path.Dir(treeLink), ctx.Repo.Repository.ComposeMetas()))
 				} else {
 					if err, content := template.ToUtf8WithErr(buf); err != nil {
 						if err != nil {
@@ -201,7 +201,7 @@ func Home(ctx *middleware.Context) {
 					buf = append(buf, d...)
 					switch {
 					case base.IsMarkdownFile(readmeFile.Name()):
-						buf = base.RenderMarkdown(buf, treeLink)
+						buf = base.RenderMarkdown(buf, treeLink, ctx.Repo.Repository.ComposeMetas())
 					default:
 						buf = bytes.Replace(buf, []byte("\n"), []byte(`<br>`), -1)
 					}

+ 7 - 1
routers/repo/wiki.go

@@ -24,6 +24,12 @@ const (
 	WIKI_PAGES base.TplName = "repo/wiki/pages"
 )
 
+func MustEnableWiki(ctx *middleware.Context) {
+	if !ctx.Repo.Repository.EnableWiki {
+		ctx.Handle(404, "MustEnableWiki", nil)
+	}
+}
+
 type PageMeta struct {
 	Name    string
 	URL     string
@@ -94,7 +100,7 @@ func renderWikiPage(ctx *middleware.Context, isViewPage bool) (*git.Repository,
 		return nil, ""
 	}
 	if isViewPage {
-		ctx.Data["content"] = string(base.RenderMarkdown(data, ctx.Repo.RepoLink))
+		ctx.Data["content"] = string(base.RenderMarkdown(data, ctx.Repo.RepoLink, ctx.Repo.Repository.ComposeMetas()))
 	} else {
 		ctx.Data["content"] = string(data)
 	}

+ 1 - 1
templates/.VERSION

@@ -1 +1 @@
-0.7.29.1204 Beta
+0.7.30.1204 Beta

+ 1 - 1
templates/repo/commits_table.tmpl

@@ -37,7 +37,7 @@
         </td>
         <td class="message collapsing">
           <a rel="nofollow" class="ui sha label" href="{{AppSubUrl}}/{{$.Username}}/{{$.Reponame}}/commit/{{.ID}}">{{ShortSha .ID.String}}</a>
-          {{RenderCommitMessage .Summary $.RepoLink}}   
+          {{RenderCommitMessage .Summary $.RepoLink $.Repository.ComposeMetas}}   
         </td>
         <td class="grey text right aligned">{{TimeSince .Author.When $.Lang}}</td>
       </tr>

+ 6 - 0
templates/repo/header.tmpl

@@ -51,21 +51,27 @@
     <a class="{{if .PageIsViewCode}}active{{end}} item" href="{{.RepoLink}}">
       <i class="icon octicon octicon-code"></i> {{.i18n.Tr "repo.code"}}
     </a>
+    {{if .Repository.EnableIssues}}
     <a class="{{if .PageIsIssueList}}active{{end}} item" href="{{.RepoLink}}/issues">
       <i class="icon octicon octicon-issue-opened"></i> {{.i18n.Tr "repo.issues"}} <span class="ui {{if not .Repository.NumOpenIssues}}gray{{else}}blue{{end}} small label">{{.Repository.NumOpenIssues}}</span>
     </a>
+    {{end}}
+    {{if .Repository.EnablePulls}}
     <a class="{{if .PageIsPullList}}active{{end}} item" href="{{.RepoLink}}/pulls">
       <i class="icon octicon octicon-git-pull-request"></i> {{.i18n.Tr "repo.pulls"}} <span class="ui {{if not .Repository.NumOpenPulls}}gray{{else}}blue{{end}} small label">{{.Repository.NumOpenPulls}}</span>
     </a>
+    {{end}}
     <a class="{{if .PageIsCommits}}active{{end}} item" href="{{.RepoLink}}/commits/{{EscapePound .BranchName}}">
       <i class="icon octicon octicon-history"></i> {{.i18n.Tr "repo.commits"}} <span class="ui {{if not .CommitsCount}}gray{{else}}blue{{end}} small label">{{.CommitsCount}}</span>
     </a>
     <a class="{{if .PageIsReleaseList}}active{{end}} item" href="{{.RepoLink}}/releases">
       <i class="icon octicon octicon-tag"></i> {{.i18n.Tr "repo.releases"}} <span class="ui {{if not .Repository.NumTags}}gray{{else}}blue{{end}} small label">{{.Repository.NumTags}}</span>
     </a>
+    {{if .Repository.EnableWiki}}
     <a class="{{if .PageIsWiki}}active{{end}} item" href="{{.RepoLink}}/wiki">
       <i class="icon octicon octicon-book"></i> {{.i18n.Tr "repo.wiki"}}
     </a>
+    {{end}}
     {{if .IsRepositoryAdmin}}
     <div class="right menu">
       <a class="{{if .PageIsSettings}}active{{end}} item" href="{{.RepoLink}}/settings">

+ 1 - 1
templates/repo/home.tmpl

@@ -7,7 +7,7 @@
       <a class="link" href="{{.Repository.Website}}">{{.Repository.Website}}</a>
     </p>
     <div class="ui secondary menu">
-      {{if and .IsRepositoryAdmin .Repository.BaseRepo}}
+      {{if .CanPullRequest}}
       <div class="fitted item">
         {{ $baseRepo := .Repository.BaseRepo}}
         <a href="{{AppSubUrl}}/{{$baseRepo.Owner.Name}}/{{$baseRepo.Name}}/compare/{{$.BaseDefaultBranch}}...{{$.Owner.Name}}:{{$.BranchName}}">

+ 56 - 2
templates/repo/settings/options.tmpl

@@ -26,7 +26,6 @@
 					    <input id="website" name="website" type="url" value="{{.Repository.Website}}">
 					  </div>
 
-					  <div class="ui divider"></div>
 					  {{if not .Repository.IsBare}}
 					  <div class="required inline field">
 					    <label>{{.i18n.Tr "repo.default_branch"}}</label>
@@ -57,13 +56,68 @@
 					    <input id="interval" name="interval" type="number" value="{{.MirrorInterval}}">
 					  </div>
 					  {{end}}
-
+					
+					  <div class="ui divider"></div>
 					  <div class="field">
 					     <button class="ui green button">{{$.i18n.Tr "repo.settings.update_settings"}}</button>
 					  </div>
 					</form>
         </div>
 
+        <h4 class="ui top attached header">
+				  {{.i18n.Tr "repo.settings.advanced_settings"}}
+        </h4>
+        <div class="ui attached segment">
+        	<form class="ui form" action="{{.Link}}" method="post">
+        		{{.CsrfTokenHtml}}
+      			<input type="hidden" name="action" value="advanced">
+
+	          <div class="inline field">
+	            <label>{{.i18n.Tr "repo.wiki"}}</label>
+	            <div class="ui checkbox">
+	              <input name="enable_wiki" type="checkbox" {{if .Repository.EnableWiki}}checked{{end}}>
+	              <label>{{.i18n.Tr "repo.settings.wiki_desc"}}</label>
+	            </div>
+	          </div>
+
+	        	<div class="ui divider"></div>
+
+	          <div class="inline field">
+	            <label>{{.i18n.Tr "repo.issues"}}</label>
+	            <div class="ui checkbox">
+	              <input name="enable_issues" type="checkbox" {{if .Repository.EnableIssues}}checked{{end}}>
+	              <label>{{.i18n.Tr "repo.settings.issues_desc"}}</label>
+	            </div>
+	          </div>
+	          <div class="inline field">
+	            <div class="ui checkbox">
+	              <input name="enable_external_tracker" type="checkbox" {{if .Repository.EnableExternalTracker}}checked{{end}}>
+	              <label>{{.i18n.Tr "repo.settings.use_external_issue_tracker"}}</label>
+	            </div>
+	          </div>
+	          <div class="field">
+					    <label for="tracker_url_format">{{.i18n.Tr "repo.settings.tracker_url_format"}}</label>
+					    <input id="tracker_url_format" name="tracker_url_format" value="{{.Repository.ExternalTrackerFormat}}" placeholder="e.g. https://github.com/{user}/{repo}/issues/{index}">
+					    <p class="help">{{.i18n.Tr "repo.settings.tracker_url_format_desc" | Str2html}}</p>
+	          </div>
+
+	        	<div class="ui divider"></div>
+
+	          <div class="inline field">
+	          	<label>{{.i18n.Tr "repo.pulls"}}</label>
+	            <div class="ui checkbox">
+	              <input name="enable_pulls" type="checkbox" {{if .Repository.EnablePulls}}checked{{end}}>
+	              <label>{{.i18n.Tr "repo.settings.pulls_desc"}}</label>
+	            </div>
+	          </div>
+					
+					  <div class="ui divider"></div>
+					  <div class="field">
+					     <button class="ui green button">{{$.i18n.Tr "repo.settings.update_settings"}}</button>
+					  </div>
+        	</form>
+        </div>
+
         <h4 class="ui top attached warning header">
           {{.i18n.Tr "repo.settings.danger_zone"}}
         </h4>