├── .github
├── CODEOWNERS
├── dependabot.yml
└── workflows
│ └── build.yml
├── .gitignore
├── .scalafmt.conf
├── LICENSE
├── README.md
├── build.sbt
├── project
├── build.properties
└── plugins.sbt
└── src
└── main
├── resources
└── update
│ ├── gitbucket-page_1.1.sql
│ └── gitbucket-page_1.1.xml
├── scala
├── Plugin.scala
└── gitbucket
│ └── plugin
│ ├── model
│ ├── PageProfile.scala
│ └── Pages.scala
│ ├── pages
│ ├── PagesHook.scala
│ └── pages.scala
│ └── service
│ └── PagesService.scala
└── twirl
└── gitbucket
└── pages
└── options.scala.html
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @takezoe @xuwei-k
2 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "github-actions"
4 | directory: "/"
5 | schedule:
6 | interval: "weekly"
7 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: build
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 | strategy:
9 | matrix:
10 | java: [11]
11 | steps:
12 | - uses: actions/checkout@v4
13 | - name: Cache
14 | uses: actions/cache@v4
15 | env:
16 | cache-name: cache-sbt-libs
17 | with:
18 | path: |
19 | ~/.ivy2/cache
20 | ~/.sbt
21 | ~/.coursier
22 | key: build-${{ env.cache-name }}-${{ hashFiles('build.sbt') }}
23 | - name: Set up JDK
24 | uses: actions/setup-java@v4
25 | with:
26 | distribution: temurin
27 | java-version: ${{ matrix.java }}
28 | - uses: sbt/setup-sbt@v1
29 | - name: Run tests
30 | run: |
31 | git clone https://github.com/gitbucket/gitbucket.git
32 | cd gitbucket
33 | sbt publishLocal
34 | cd ../
35 | sbt scalafmtSbtCheck scalafmtCheckAll test
36 | - name: Assembly
37 | run: sbt assembly
38 | - name: Upload artifacts
39 | uses: actions/upload-artifact@v4
40 | with:
41 | name: gitbucket-pages-plugin-java${{ matrix.java }}-${{ github.sha }}
42 | path: ./target/scala-2.13/*.jar
43 |
44 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 | *.log
3 |
4 | # sbt specific
5 | dist/*
6 | target/
7 | lib_managed/
8 | src_managed/
9 | project/boot/
10 | project/plugins/project/
11 |
12 | # Scala-IDE specific
13 | .scala_dependencies
14 | .classpath
15 | .project
16 | .cache
17 | .settings
18 |
19 | # IntelliJ specific
20 | .idea/
21 | .idea_modules/
22 |
23 | # Ensime
24 | .ensime
25 | .ensime_cache/
26 |
27 | # Metals
28 | .bloop/
29 | .metals/
30 | .vscode/
31 | **/metals.sbt
32 | .bsp
33 |
--------------------------------------------------------------------------------
/.scalafmt.conf:
--------------------------------------------------------------------------------
1 | version = "3.9.7"
2 | project.git = true
3 |
4 | maxColumn = 120
5 |
6 | align.tokens = ["%", "%%", {code = "=>", owner = "Case"}]
7 | align.openParenCallSite = false
8 | align.openParenDefnSite = false
9 | continuationIndent.callSite = 2
10 | continuationIndent.defnSite = 2
11 | danglingParentheses.preset = true
12 | runner.dialect = scala213source3
13 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2015 Yan Su (tsu@yaroot.net)
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Gitbucket-Pages-Plugin [](https://gitter.im/gitbucket/gitbucket) [](https://github.com/gitbucket/gitbucket-pages-plugin/actions?query=workflow%3Abuild+branch%3Amaster)
3 |
4 | This plugin provides *Project Pages* functionality for
5 | [GitBucket](https://github.com/gitbucket/gitbucket) based repositories.
6 |
7 | ## User guide
8 |
9 | This plugin serves static files directly from one of the following
10 | places:
11 |
12 | - `gb-pages` branch (with fallback to `gh-pages` to be compatible with
13 | github, this is the default)
14 | - `master` branch
15 | - `docs` folder under `master` branch
16 |
17 | ### Quick start
18 |
19 | - create a directory or branch if necessary (eg. create an orphan branch called `gb-pages`: `git checkout --orphan gb-pages && git rm -f $(git ls-files)`)
20 | - create a static site under this branch. E.g. `echo '
hello, world
' > index.html` to create a simple file.
21 | - commit && push to gitbucket this orphan branch
22 | - open the browser and point to `/pages`
23 |
24 | **Note**: This plugin won't render markdown content. To render markdown content, use the GitBucket Wiki functionality, or use one of the many static site generators (e.g. [jekyll](http://jekyllrb.com/), [hugo](https://gohugo.io/))
25 |
26 | ## Installation
27 |
28 | **This plugin is bundled with newer version of GitBucket, for older
29 | version please follow the instruction below**
30 |
31 | ### Install manually
32 |
33 | - download from [releases](https://github.com/gitbucket/gitbucket-pages-plugin/releases)
34 | - copy the jar file to `/plugins/` (`GITBUCKET_HOME` defaults to `~/.gitbucket`)
35 | - enable it in plugin settings (you may need to restart gitbucket)
36 |
37 | ## Versions
38 |
39 | | pages version | gitbucket version |
40 | | :---: | :---: |
41 | | 1.10.0 | 4.36.0 |
42 | | 1.9.0 | 4.35.0 |
43 | | 1.8.0 | 4.32.0 |
44 | | 1.7.0 | 4.23.0 |
45 | | 1.6.0 | 4.19.0 |
46 | | 1.5.0 | 4.15.0 |
47 | | 1.3 | 4.14.1 |
48 | | 1.2 | 4.13 |
49 | | 1.1 | 4.11 |
50 | | 1.0 | 4.10 |
51 | | 0.9 | 4.9 |
52 | | 0.8 | 4.6 |
53 | | 0.7 | 4.3 ~ 4.6 |
54 | | 0.6 | 4.2.x |
55 | | 0.5 | 4.0, 4.1 |
56 | | 0.4 | 3.13 |
57 | | 0.3 | 3.12 |
58 | | 0.2 | 3.11 |
59 | | 0.1 | 3.9, 3.10 |
60 |
61 |
62 | ## Security (panic mode)
63 |
64 | To prevent XSS, one must use two different domains to host the pages and
65 | Gitbucket itself. Below is a working example of nginx configuration to achieve that.
66 |
67 | ```
68 | server {
69 | listen 80;
70 | server_name git.local;
71 |
72 | location ~ ^/([^/]+)/([^/]+)/pages/(.*)$ {
73 | rewrite ^/([^/]+)/([^/]+)/pages/(.*)$ http://doc.local/$1/$2/pages/$3 redirect;
74 | }
75 |
76 | location / {
77 | proxy_pass http://127.0.0.1:8080;
78 | }
79 | }
80 |
81 | server {
82 | listen 80;
83 | server_name doc.local;
84 |
85 | location ~ ^/([^/]+)/([^/]+)/pages/(.*)$ {
86 | proxy_pass http://127.0.0.1:8080;
87 | }
88 |
89 | location / {
90 | return 403;
91 | }
92 | }
93 | ```
94 |
95 | ## CI
96 |
97 | - build by [GitHub Actions](https://github.com/gitbucket/gitbucket-pages-plugin/actions)
98 |
--------------------------------------------------------------------------------
/build.sbt:
--------------------------------------------------------------------------------
1 | organization := "gitbucket"
2 | name := "gitbucket-pages-plugin"
3 | scalaVersion := "2.13.16"
4 | version := "1.10.0"
5 | gitbucketVersion := "4.42.1"
6 | scalacOptions := Seq("-unchecked", "-deprecation", "-encoding", "utf8", "-feature")
7 |
8 | scalafmtOnCompile := true
9 |
--------------------------------------------------------------------------------
/project/build.properties:
--------------------------------------------------------------------------------
1 | sbt.version=1.11.2
2 |
--------------------------------------------------------------------------------
/project/plugins.sbt:
--------------------------------------------------------------------------------
1 | addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.4")
2 | addSbtPlugin("io.github.gitbucket" % "sbt-gitbucket-plugin" % "1.6.0")
3 |
--------------------------------------------------------------------------------
/src/main/resources/update/gitbucket-page_1.1.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO PAGES
2 | (USER_NAME, REPOSITORY_NAME, SOURCE)
3 | SELECT
4 | A.USER_NAME
5 | , A.REPOSITORY_NAME
6 | , 'gh-pages'
7 | FROM
8 | REPOSITORY A;
9 |
--------------------------------------------------------------------------------
/src/main/resources/update/gitbucket-page_1.1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/main/scala/Plugin.scala:
--------------------------------------------------------------------------------
1 | import gitbucket.core.controller.Context
2 | import gitbucket.core.controller.ControllerBase
3 | import gitbucket.core.plugin.Link
4 | import gitbucket.core.service.RepositoryService.RepositoryInfo
5 | import gitbucket.plugin.pages.{PagesController, PagesHook}
6 | import io.github.gitbucket.solidbase.migration.{SqlMigration, LiquibaseMigration}
7 | import io.github.gitbucket.solidbase.model.Version
8 |
9 | class Plugin extends gitbucket.core.plugin.Plugin {
10 | override val pluginId = "pages"
11 | override val pluginName = "Pages Plugin"
12 | override val description = "Project pages for GitBucket"
13 | override val versions = List(
14 | new Version("0.1"),
15 | new Version("0.2"),
16 | new Version("0.3"),
17 | new Version("0.4"),
18 | new Version("0.5"),
19 | new Version("0.6"),
20 | new Version("0.7"),
21 | new Version("0.8"),
22 | new Version("0.9"),
23 | new Version("1.0"),
24 | new Version(
25 | "1.1",
26 | new LiquibaseMigration("update/gitbucket-page_1.1.xml"),
27 | new SqlMigration("update/gitbucket-page_1.1.sql")
28 | ),
29 | new Version("1.2"),
30 | new Version("1.3"),
31 | new Version("1.4.0"),
32 | new Version("1.5.0"),
33 | new Version("1.6.0"),
34 | new Version("1.7.0"),
35 | new Version("1.7.1"),
36 | new Version("1.8.0"),
37 | new Version("1.9.0"),
38 | new Version("1.10.0")
39 | )
40 |
41 | override val controllers: Seq[(String, ControllerBase)] = Seq("/*" -> new PagesController)
42 |
43 | override val repositorySettingTabs =
44 | Seq((repository: RepositoryInfo, context: Context) => Some(Link("pages", "Pages", s"settings/pages")))
45 |
46 | override val repositoryHooks = Seq(new PagesHook)
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/scala/gitbucket/plugin/model/PageProfile.scala:
--------------------------------------------------------------------------------
1 | package gitbucket.plugin.model
2 |
3 | import gitbucket.core.model._
4 |
5 | object Profile extends CoreProfile with PagesComponent
6 |
--------------------------------------------------------------------------------
/src/main/scala/gitbucket/plugin/model/Pages.scala:
--------------------------------------------------------------------------------
1 | package gitbucket.plugin.model
2 |
3 | trait PagesComponent { self: gitbucket.core.model.Profile =>
4 | import profile.api._
5 |
6 | implicit val psColumnType =
7 | MappedColumnType.base[PageSourceType, String](ps => ps.code, code => PageSourceType.valueOf(code))
8 |
9 | lazy val Pages = TableQuery[Pages]
10 |
11 | class Pages(tag: Tag) extends Table[Page](tag, "PAGES") {
12 | val userName = column[String]("USER_NAME")
13 | val repositoryName = column[String]("REPOSITORY_NAME")
14 | val source = column[PageSourceType]("SOURCE")
15 | def * = (userName, repositoryName, source).<>((Page.apply _).tupled, Page.unapply)
16 | }
17 | }
18 |
19 | abstract sealed case class PageSourceType(code: String)
20 |
21 | object PageSourceType {
22 | object NONE extends PageSourceType("none")
23 | object MASTER_DOCS extends PageSourceType("master /docs")
24 | object MASTER extends PageSourceType("master")
25 | object GH_PAGES extends PageSourceType("gh-pages")
26 |
27 | val values: Vector[PageSourceType] = Vector(NONE, MASTER_DOCS, MASTER, GH_PAGES)
28 |
29 | private val map: Map[String, PageSourceType] = values.map(enum => enum.code -> enum).toMap
30 |
31 | def apply(code: String): PageSourceType = map(code)
32 |
33 | def valueOf(code: String): PageSourceType = map(code)
34 | def valueOpt(code: String): Option[PageSourceType] = map.get(code)
35 | }
36 |
37 | case class Page(userName: String, repositoryName: String, source: PageSourceType)
38 |
--------------------------------------------------------------------------------
/src/main/scala/gitbucket/plugin/pages/PagesHook.scala:
--------------------------------------------------------------------------------
1 | package gitbucket.plugin.pages
2 |
3 | import gitbucket.core.plugin.RepositoryHook
4 | import gitbucket.plugin.model.PageSourceType
5 | import gitbucket.plugin.model.Profile.profile.blockingApi._
6 | import gitbucket.plugin.service.PagesService
7 |
8 | class PagesHook extends PagesHookBase with PagesService
9 |
10 | trait PagesHookBase extends RepositoryHook {
11 | self: PagesService =>
12 |
13 | override def created(owner: String, repository: String)(implicit session: Session): Unit =
14 | registerPageOptions(owner, repository, PageSourceType.GH_PAGES)
15 |
16 | override def deleted(owner: String, repository: String)(implicit session: Session): Unit =
17 | deletePageOptions(owner, repository)
18 |
19 | override def renamed(owner: String, oldRepository: String, newRepository: String)(implicit session: Session): Unit =
20 | renameRepository(owner, oldRepository, newRepository)
21 |
22 | override def transferred(oldOwner: String, newOwner: String, repository: String)(implicit session: Session): Unit =
23 | renameUserName(oldOwner, newOwner, repository)
24 |
25 | override def forked(owner: String, newOwner: String, repository: String)(implicit session: Session): Unit = {
26 | val source = getPageSource(owner, repository)
27 | registerPageOptions(newOwner, repository, source)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/scala/gitbucket/plugin/pages/pages.scala:
--------------------------------------------------------------------------------
1 | package gitbucket.plugin.pages
2 |
3 | import gitbucket.core.controller.ControllerBase
4 | import gitbucket.core.service.RepositoryService.RepositoryInfo
5 | import gitbucket.core.service.{AccountService, RepositoryService}
6 | import gitbucket.core.util.Implicits._
7 | import gitbucket.core.util.{Directory, JGitUtil, OwnerAuthenticator, ReferrerAuthenticator}
8 | import gitbucket.pages.html
9 | import gitbucket.plugin.model.PageSourceType
10 | import gitbucket.plugin.service.PagesService
11 | import org.scalatra.forms._
12 | import org.eclipse.jgit.api.Git
13 | import org.eclipse.jgit.lib.ObjectId
14 | import org.eclipse.jgit.revwalk.RevCommit
15 | import org.scalatra.i18n.Messages
16 |
17 | import javax.servlet.http.HttpServletRequest
18 | import scala.util.Using
19 | import scala.annotation.tailrec
20 | import scala.language.implicitConversions
21 |
22 | class PagesController
23 | extends PagesControllerBase
24 | with AccountService
25 | with OwnerAuthenticator
26 | with PagesService
27 | with RepositoryService
28 | with ReferrerAuthenticator
29 |
30 | trait PagesControllerBase extends ControllerBase {
31 | self: AccountService with RepositoryService with PagesService with ReferrerAuthenticator with OwnerAuthenticator =>
32 | import PagesControllerBase._
33 |
34 | val optionsForm: MappingValueType[OptionsForm] = mapping(
35 | "source" -> trim(label("Pages Source", text(required, pagesOption)))
36 | )(source => OptionsForm(PageSourceType.valueOf(source)))
37 |
38 | val PAGES_BRANCHES = List("gb-pages", "gh-pages")
39 |
40 | def endsWithSlash(): Boolean = request.getServletPath.endsWith("/")
41 |
42 | get("/:owner/:repository/pages/*")(referrersOnly { repository =>
43 | renderPage(repository, params("splat"))
44 | })
45 |
46 | get("/:owner/:repository/pages")(referrersOnly { repository =>
47 | if (endsWithSlash()) {
48 | renderPage(repository, "")
49 | } else {
50 | redirect(s"/${repository.owner}/${repository.name}/pages/")
51 | }
52 | })
53 |
54 | private def renderPage(repository: RepositoryInfo, path: String) = {
55 | val defaultBranch = repository.repository.defaultBranch
56 | Using.resource(Git.open(Directory.getRepositoryDir(repository.owner, repository.name))) { git =>
57 | getPageSource(repository.owner, repository.name) match {
58 | case PageSourceType.GH_PAGES =>
59 | renderFromBranch(repository, git, path, PAGES_BRANCHES.collectFirst(Function.unlift(resolveBranch(git, _))))
60 | case PageSourceType.MASTER =>
61 | renderFromBranch(repository, git, path, resolveBranch(git, defaultBranch))
62 | case PageSourceType.MASTER_DOCS =>
63 | renderFromBranch(repository, git, joinPath("docs", path), resolveBranch(git, defaultBranch))
64 | case PageSourceType.NONE =>
65 | NotFound()
66 | }
67 | }
68 | }
69 |
70 | get("/:owner/:repository/settings/pages")(ownerOnly { repository =>
71 | val source = getPageSource(repository.owner, repository.name)
72 | val defaultBranch = repository.repository.defaultBranch
73 | html.options(repository, source, defaultBranch, flash.get("info"))
74 | })
75 |
76 | post("/:owner/:repository/settings/pages", optionsForm)(ownerOnly { (form, repository) =>
77 | updatePageOptions(repository.owner, repository.name, form.source)
78 | flash.update("info", "Pages source saved")
79 | redirect(s"/${repository.owner}/${repository.name}/settings/pages")
80 | })
81 |
82 | def renderPageObject(git: Git, path: String, obj: ObjectId): Unit = {
83 | JGitUtil.getObjectLoaderFromId(git, obj) { loader =>
84 | contentType = guessContentType(path)
85 | response.setContentLength(loader.getSize.toInt)
86 | loader.copyTo(response.getOutputStream)
87 | }
88 | }
89 |
90 | def renderFromBranch(
91 | repository: RepositoryService.RepositoryInfo,
92 | git: Git,
93 | path: String,
94 | branchObject: Option[ObjectId]
95 | ): Any = {
96 | val pagePair = branchObject
97 | .map(JGitUtil.getRevCommitFromId(git, _))
98 | .flatMap(getPageObjectId(git, path, _))
99 |
100 | pagePair match {
101 | case Some((realPath, _)) if shouldRedirect(path, realPath) =>
102 | redirect(s"/${repository.owner}/${repository.name}/pages/$path/")
103 | case Some((realPath, pageObject)) =>
104 | renderPageObject(git, realPath, pageObject)
105 | case None =>
106 | NotFound()
107 | }
108 | }
109 |
110 | def resolveBranch(git: Git, name: String): Option[ObjectId] = Option(git.getRepository.resolve(name))
111 |
112 | // redirect [owner/repo/pages/path] -> [owner/repo/pages/path/]
113 | def shouldRedirect(path: String, path0: String): Boolean =
114 | !isRoot(path) && path0 != path && path0.startsWith(path) && !endsWithSlash()
115 |
116 | def getPageObjectId(git: Git, path: String, revCommit: RevCommit): Option[(String, ObjectId)] = {
117 | listProbablePages(path).collectFirst(Function.unlift(getPathObjectIdPair(git, _, revCommit)))
118 | }
119 |
120 | def listProbablePages(path: String): List[String] = {
121 | path :: List("index.html", "index.htm").map(joinPath(path, _))
122 | }
123 |
124 | def getPathObjectIdPair(git: Git, path: String, revCommit: RevCommit): Option[(String, ObjectId)] = {
125 | getPathObjectId(git, path, revCommit).map(path -> _)
126 | }
127 |
128 | def joinPath(base: String, suffix: String): String = {
129 | val sfx = suffix.stripPrefix("/")
130 | if (isRoot(base)) sfx
131 | else base.stripSuffix("/") + "/" + sfx
132 | }
133 |
134 | def isRoot(path: String): Boolean = path == ""
135 |
136 | def guessContentType(path: String): String = {
137 | Option(servletContext.getMimeType(path)).getOrElse("application/octet-stream")
138 | }
139 |
140 | }
141 |
142 | object PagesControllerBase {
143 | case class OptionsForm(source: PageSourceType)
144 |
145 | def pagesOption: Constraint = new Constraint() {
146 | override def validate(name: String, value: String, messages: Messages): Option[String] =
147 | PageSourceType.valueOpt(value) match {
148 | case Some(_) => None
149 | case None => Some("Pages source is invalid.")
150 | }
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/src/main/scala/gitbucket/plugin/service/PagesService.scala:
--------------------------------------------------------------------------------
1 | package gitbucket.plugin.service
2 |
3 | import gitbucket.plugin.model.{Page, PageSourceType}
4 | import gitbucket.plugin.model.Profile._
5 | import gitbucket.plugin.model.Profile.profile.blockingApi._
6 |
7 | trait PagesService {
8 |
9 | def getPageSource(userName: String, repositoryName: String)(implicit s: Session): PageSourceType =
10 | getPageOptions(userName, repositoryName).map(_.source).getOrElse(PageSourceType.GH_PAGES)
11 |
12 | def getPageOptions(userName: String, repositoryName: String)(implicit s: Session): Option[Page] =
13 | Pages.filter(t => (t.userName === userName.bind) && (t.repositoryName === repositoryName.bind)).firstOption
14 |
15 | def registerPageOptions(userName: String, repositoryName: String, source: PageSourceType)(implicit s: Session): Unit =
16 | Pages.insert(Page(userName, repositoryName, source))
17 |
18 | def updatePageOptions(userName: String, repositoryName: String, source: PageSourceType)(implicit s: Session): Unit =
19 | Pages
20 | .filter(t => (t.userName === userName.bind) && (t.repositoryName === repositoryName.bind))
21 | .map(t => t.source)
22 | .update(source)
23 |
24 | def renameRepository(userName: String, oldRepositoryName: String, newRepositoryName: String)(implicit
25 | s: Session
26 | ): Unit =
27 | Pages
28 | .filter(t => (t.userName === userName.bind) && (t.repositoryName === oldRepositoryName.bind))
29 | .map(t => t.repositoryName)
30 | .update(newRepositoryName)
31 |
32 | def renameUserName(oldUserName: String, newUserName: String, repositoryName: String)(implicit s: Session): Unit =
33 | Pages
34 | .filter(t => (t.userName === oldUserName.bind) && (t.repositoryName === repositoryName.bind))
35 | .map(t => t.userName)
36 | .update(newUserName)
37 |
38 | def deletePageOptions(userName: String, repositoryName: String)(implicit s: Session): Unit = {
39 | Pages.filter(t => (t.userName === userName.bind) && (t.repositoryName === repositoryName.bind)).delete
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/twirl/gitbucket/pages/options.scala.html:
--------------------------------------------------------------------------------
1 | @import gitbucket.plugin.model.PageSourceType
2 | @(repository: gitbucket.core.service.RepositoryService.RepositoryInfo,
3 | source: PageSourceType,
4 | defaultBranch: String,
5 | info: Option[Any])(implicit context: gitbucket.core.controller.Context)
6 | @import gitbucket.core.view.helpers
7 | @gitbucket.core.html.main("Pages", Some(repository)){
8 | @gitbucket.core.html.menu("settings", repository){
9 | @gitbucket.core.settings.html.menu("pages", repository){
10 | @gitbucket.core.helper.html.information(info)
11 |
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------