mirror of
https://github.com/gitbucket/gitbucket.git
synced 2026-05-08 11:57:37 +02:00
Compare commits
211 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d6217d89eb | ||
|
|
c99ff1cf0f | ||
|
|
001b9ae2ae | ||
|
|
f63493f1c0 | ||
|
|
c9095722f8 | ||
|
|
b9d2efa582 | ||
|
|
9c2e09020a | ||
|
|
1ffcf8c1e9 | ||
|
|
0124091840 | ||
|
|
2a28a7b35b | ||
|
|
2a68ffc8dc | ||
|
|
6b47c49cdd | ||
|
|
b634967776 | ||
|
|
172bed760d | ||
|
|
1b7eb69083 | ||
|
|
185c01db99 | ||
|
|
ab548d8c25 | ||
|
|
983975620b | ||
|
|
b512b08256 | ||
|
|
a54fb4960f | ||
|
|
93de53d717 | ||
|
|
f262c0a9eb | ||
|
|
e5d15569df | ||
|
|
369b08eae3 | ||
|
|
8e6fcb022b | ||
|
|
456b1f6571 | ||
|
|
6e459ad225 | ||
|
|
cece4c1c7d | ||
|
|
42e7a9fa9f | ||
|
|
f9510aba8e | ||
|
|
8a7d719025 | ||
|
|
1293a21450 | ||
|
|
65dd597ab7 | ||
|
|
e145b5151e | ||
|
|
b9684c277b | ||
|
|
4accb77533 | ||
|
|
9eef961025 | ||
|
|
546b40cdd1 | ||
|
|
274a08c14c | ||
|
|
eed4b51189 | ||
|
|
5c2f84367b | ||
|
|
d5b625e43f | ||
|
|
27f9e3dec9 | ||
|
|
00ef4db9a7 | ||
|
|
bf4f814389 | ||
|
|
23e45afd7f | ||
|
|
bfb02eef62 | ||
|
|
c129aae73a | ||
|
|
a955856cef | ||
|
|
a43a3fa55c | ||
|
|
a6254ab955 | ||
|
|
b505c3dc12 | ||
|
|
9d69b9e980 | ||
|
|
44b2320644 | ||
|
|
8fb9643ea5 | ||
|
|
10ea988298 | ||
|
|
7896945519 | ||
|
|
210342d2bc | ||
|
|
fdacea858b | ||
|
|
6825028d37 | ||
|
|
2089882d41 | ||
|
|
8e1d938155 | ||
|
|
39eb4cef04 | ||
|
|
d4e3adafa6 | ||
|
|
a7b8326499 | ||
|
|
249f8738d3 | ||
|
|
fefe6ef74f | ||
|
|
9ca6cd1d90 | ||
|
|
bff7b7c460 | ||
|
|
cfff79758b | ||
|
|
ded8ceb2c6 | ||
|
|
c502ebfc16 | ||
|
|
d3268265cf | ||
|
|
5eaf59eebb | ||
|
|
d6d47aa977 | ||
|
|
dc052e05ce | ||
|
|
afb145ca7c | ||
|
|
a8beed33e0 | ||
|
|
488599dba5 | ||
|
|
ef0d08a917 | ||
|
|
9fa0d03c99 | ||
|
|
15b6c5952b | ||
|
|
cb75e9d312 | ||
|
|
d542ee3528 | ||
|
|
608a59cbfd | ||
|
|
768e3a5c91 | ||
|
|
f1fc794c0c | ||
|
|
4cf924bee0 | ||
|
|
8164efc720 | ||
|
|
580a627d9d | ||
|
|
1701916209 | ||
|
|
811b2bff70 | ||
|
|
9de9dd8940 | ||
|
|
572f83327f | ||
|
|
2afb37823b | ||
|
|
edc9720a88 | ||
|
|
defc0fa041 | ||
|
|
c14b3c5576 | ||
|
|
10fc04cbc9 | ||
|
|
67563a8805 | ||
|
|
743bdab79b | ||
|
|
a5a2e4732d | ||
|
|
3a0cd5df62 | ||
|
|
ad9a0afc9b | ||
|
|
d2fc7a0642 | ||
|
|
b1d4a18c9b | ||
|
|
fdfd8ec9b2 | ||
|
|
396156c4e3 | ||
|
|
8168580d60 | ||
|
|
2abdd233e7 | ||
|
|
ef95ce99d2 | ||
|
|
3a6b2f6f4e | ||
|
|
92304ac8c6 | ||
|
|
a2242a3cb7 | ||
|
|
64e8167fcb | ||
|
|
06b93293a6 | ||
|
|
3dcc0aee3c | ||
|
|
c009a39dd7 | ||
|
|
b27e8ebb7e | ||
|
|
a690d43491 | ||
|
|
86bfb68a0c | ||
|
|
9469801d3d | ||
|
|
757a8399c1 | ||
|
|
ed00e613c3 | ||
|
|
6e341116c1 | ||
|
|
9ccc2d0f97 | ||
|
|
72742306a0 | ||
|
|
47c6d61661 | ||
|
|
cfc444bcd2 | ||
|
|
a1f65258ea | ||
|
|
5e3b97cf85 | ||
|
|
209e1967d6 | ||
|
|
4437a4e7a6 | ||
|
|
e4d92bb494 | ||
|
|
d942c8f48a | ||
|
|
3a798e152f | ||
|
|
91b862970f | ||
|
|
2d199e22e7 | ||
|
|
757da408d1 | ||
|
|
309d6e8b57 | ||
|
|
ec0395a7f3 | ||
|
|
7cb4958ca0 | ||
|
|
2d1c917a2c | ||
|
|
27dd5120dd | ||
|
|
9e0f8992c5 | ||
|
|
5f87a28da6 | ||
|
|
25d5d5eee5 | ||
|
|
ec9472b7cc | ||
|
|
b967fb93a7 | ||
|
|
9d1bf3035b | ||
|
|
d6cedc2171 | ||
|
|
8d8c78966a | ||
|
|
cbe1c1c9f6 | ||
|
|
bf946960a7 | ||
|
|
9677735542 | ||
|
|
e06c8fe5da | ||
|
|
d4ee6c9063 | ||
|
|
1d0f079bd2 | ||
|
|
7cc6972d83 | ||
|
|
177da92b39 | ||
|
|
e1f433573b | ||
|
|
cd958d7681 | ||
|
|
9c8e77f472 | ||
|
|
bf7d3a8f0b | ||
|
|
934e17666d | ||
|
|
b20c4b3d7d | ||
|
|
7c4e8b54d0 | ||
|
|
1e3794674b | ||
|
|
5d5706451d | ||
|
|
76e8d01846 | ||
|
|
75e2883f61 | ||
|
|
7e7cc1d4c7 | ||
|
|
d7623e8b7a | ||
|
|
7dd1470cd4 | ||
|
|
9fb8d6fc66 | ||
|
|
4f1869817c | ||
|
|
6be269c388 | ||
|
|
af857853cb | ||
|
|
1a664c2b6a | ||
|
|
1feb33fc19 | ||
|
|
4fc1d9c3b6 | ||
|
|
7eb77908d4 | ||
|
|
54f9d01c42 | ||
|
|
08154af7b1 | ||
|
|
e7ab376a34 | ||
|
|
a680398c54 | ||
|
|
6acf1e68ca | ||
|
|
fc35e7b83d | ||
|
|
1ae6fc7e9e | ||
|
|
884f63e6f4 | ||
|
|
4d3e34af8b | ||
|
|
54426bb456 | ||
|
|
c86b72bf6b | ||
|
|
e6a5911a39 | ||
|
|
6ea77fa73e | ||
|
|
32d0b94a7a | ||
|
|
4f770adb35 | ||
|
|
361f92a08d | ||
|
|
c2068f58e7 | ||
|
|
67dd604469 | ||
|
|
d1a2c23cf3 | ||
|
|
262500508c | ||
|
|
f1360f44c6 | ||
|
|
1c818f890a | ||
|
|
16f146b660 | ||
|
|
6166eaf0c7 | ||
|
|
ad4312cedb | ||
|
|
15083a5aac | ||
|
|
9ae420c553 | ||
|
|
4115ea4ab6 | ||
|
|
024ac313ae |
@@ -1,2 +1,8 @@
|
||||
# update scalafmt
|
||||
3d5ca44d66c77a46770a65a895c9737c542690f6
|
||||
|
||||
# Scala Steward: Reformat with scalafmt 3.8.2
|
||||
f1360f44c61f8e12666965c10e79f11cd75d6d30
|
||||
|
||||
# Scala Steward: Reformat with scalafmt 3.9.7
|
||||
a54fb4960ff0762738f4895cdc29bf2715a57f87
|
||||
|
||||
22
.github/ISSUE_TEMPLATE.md
vendored
22
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,22 +0,0 @@
|
||||
### Before submitting an issue to GitBucket I have first:
|
||||
|
||||
- [ ] read the [contribution guidelines](https://github.com/gitbucket/gitbucket/blob/master/.github/CONTRIBUTING.md)
|
||||
- [ ] searched for similar already existing issue
|
||||
- [ ] read the documentation and [wiki](https://github.com/gitbucket/gitbucket/wiki)
|
||||
|
||||
<!--
|
||||
|
||||
*(if you have performed all the above, remove the paragraph and continue describing the issue with template below)*
|
||||
|
||||
-->
|
||||
|
||||
## Issue
|
||||
**Impacted version**: xxxx
|
||||
|
||||
**Deployment mode**: *explain here how you use GitBucket : standalone app, under webcontainer (which one), with an http frontend (nginx, httpd, ...)*
|
||||
|
||||
**Problem description**:
|
||||
- *be as explicit as you can*
|
||||
- *describe the problem and its symptoms*
|
||||
- *explain how to reproduce*
|
||||
- *attach whatever information that can help understanding the context (screen capture, log files)*
|
||||
42
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
42
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
name: Bug report
|
||||
description: Report a problem with GitBucket
|
||||
title: "[Bug] "
|
||||
labels: [bug]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
### Before submitting an issue to GitBucket, please ensure you have:
|
||||
- Read the [contribution guidelines](https://github.com/gitbucket/gitbucket/blob/master/.github/CONTRIBUTING.md)
|
||||
- Searched for similar existing issues
|
||||
- Read the documentation and [wiki](https://github.com/gitbucket/gitbucket/wiki)
|
||||
|
||||
- type: checkboxes
|
||||
id: prerequisites
|
||||
attributes:
|
||||
label: Prerequisites
|
||||
options:
|
||||
- label: I have read the contribution guidelines
|
||||
- label: I have searched for similar issues
|
||||
- label: I have read the documentation and wiki
|
||||
|
||||
- type: input
|
||||
id: impacted_version
|
||||
attributes:
|
||||
label: Impacted version
|
||||
description: Which version of GitBucket is affected?
|
||||
placeholder: e.g. 4.37.0
|
||||
|
||||
- type: input
|
||||
id: deployment_mode
|
||||
attributes:
|
||||
label: Deployment mode
|
||||
description: How do you use GitBucket? (standalone app, under webcontainer, with an HTTP frontend, etc.)
|
||||
placeholder: e.g. Standalone app, Tomcat, nginx
|
||||
|
||||
- type: textarea
|
||||
id: problem_description
|
||||
attributes:
|
||||
label: Problem description
|
||||
description: Be as explicit as you can. Describe the problem, its symptoms, how to reproduce, and attach any relevant information (screenshots, logs, etc.)
|
||||
placeholder: Describe the problem and how to reproduce it
|
||||
5
.github/workflows/build.yml
vendored
5
.github/workflows/build.yml
vendored
@@ -7,8 +7,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
java: [11, 21]
|
||||
java: [17, 21]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Cache
|
||||
@@ -26,6 +27,8 @@ jobs:
|
||||
with:
|
||||
java-version: ${{ matrix.java }}
|
||||
distribution: adopt
|
||||
- name: Setup sbt launcher
|
||||
uses: sbt/setup-sbt@v1
|
||||
- name: Run tests
|
||||
run: sbt scalafmtSbtCheck scalafmtCheckAll test
|
||||
- name: Scala 3
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
version = "3.8.1"
|
||||
version = "3.9.8"
|
||||
project.git = true
|
||||
|
||||
maxColumn = 120
|
||||
|
||||
32
CHANGELOG.md
32
CHANGELOG.md
@@ -1,12 +1,38 @@
|
||||
# Changelog
|
||||
All changes to the project will be documented in this file.
|
||||
|
||||
## 4.43.0 - 29 Jun 2025
|
||||
- Upgrade H2 database from 1.x to 2.x
|
||||
|
||||
Note that upgrading from h2 1.x to 2.x requires data file migration: https://www.h2database.com/html/migration-to-v2.html
|
||||
|
||||
It can't be done automatically using GitBucket's auto migration mechanism because it relies on database itself. So, users who use h2 will have to dump and recreate their database manually with the following steps:
|
||||
```
|
||||
# Export database using the current version of H2
|
||||
$ curl -O https://repo1.maven.org/maven2/com/h2database/h2/1.4.199/h2-1.4.199.jar
|
||||
$ java -cp h2-1.4.199.jar org.h2.tools.Script -url "jdbc:h2:~/.gitbucket/data" -user sa -password sa -script dump.sql
|
||||
|
||||
# Recreate database using the new version of H2
|
||||
$ curl -O https://repo1.maven.org/maven2/com/h2database/h2/2.3.232/h2-2.3.232.jar
|
||||
$ java -cp h2-2.3.232.jar org.h2.tools.RunScript -url "jdbc:h2:~/.gitbucket/data" -user sa -password sa -script dump.sql
|
||||
```
|
||||
|
||||
## 4.42.1 - 20 Jan 2025
|
||||
- Fix LDAP issue with SSL
|
||||
|
||||
## 4.42.0 - 30 Dec 2024
|
||||
- Increase max branch name length 100 -> 255
|
||||
- Fix some GitHub incompatible Web APIs
|
||||
- Apply user-defined CSS after all plugins
|
||||
- Improve performance of listing commit logs
|
||||
- Drop Java 11 support. Java 17 is now required
|
||||
|
||||
## 4.41.0 - 18 May 2024
|
||||
- Simplify pull request UI
|
||||
- Keyword search for issues and pull requests
|
||||
- New settings for max files and lines limit in showing diff
|
||||
- Adjust the default branch automatically when cloning external repository
|
||||
- Fix layout of branch selector
|
||||
- Integrate keyword search with filtering in the search box
|
||||
- Make max files and lines limit in showing diff configurable
|
||||
- Adjust the default branch automatically when cloning external repo
|
||||
- Performance improvement for listing branches
|
||||
- Upgrade internal libraries
|
||||
|
||||
|
||||
31
README.md
31
README.md
@@ -1,4 +1,4 @@
|
||||
GitBucket [](https://gitter.im/gitbucket/gitbucket) [](https://github.com/gitbucket/gitbucket/actions?query=workflow%3Abuild+branch%3Amaster) [](https://index.scala-lang.org/gitbucket/gitbucket/gitbucket) [](https://github.com/gitbucket/gitbucket/blob/master/LICENSE)
|
||||
GitBucket [](https://gitter.im/gitbucket/gitbucket) [](https://github.com/gitbucket/gitbucket/actions/workflows/build.yml) [](https://index.scala-lang.org/gitbucket/gitbucket/gitbucket) [](https://github.com/gitbucket/gitbucket/blob/master/LICENSE)
|
||||
=========
|
||||
|
||||
GitBucket is a Git web platform powered by Scala offering:
|
||||
@@ -24,7 +24,7 @@ The current version of GitBucket provides many features such as:
|
||||
|
||||
Installation
|
||||
--------
|
||||
GitBucket requires **Java 11**. You have to install it, if it is not already installed.
|
||||
GitBucket requires **Java 17**. You have to install it, if it is not already installed.
|
||||
|
||||
1. Download the latest **gitbucket.war** from [the releases page](https://github.com/gitbucket/gitbucket/releases) and run it by `java -jar gitbucket.war`.
|
||||
2. Go to `http://[hostname]:8080/` and log in with ID: **root** / Pass: **root**.
|
||||
@@ -59,15 +59,22 @@ Support
|
||||
- If you can't find same question and report, send it to our [Gitter room](https://gitter.im/gitbucket/gitbucket) before raising an issue.
|
||||
- The highest priority of GitBucket is the ease of installation and API compatibility with GitHub, so your feature request might be rejected if they go against those principles.
|
||||
|
||||
What's New in 4.41.x
|
||||
What's New in 4.43.x
|
||||
-------------
|
||||
## 4.41.0 - 18 May 2024
|
||||
- Simplify pull request UI
|
||||
- Fix layout of branch selector
|
||||
- Integrate keyword search with filtering in the search box
|
||||
- Make max files and lines limit in showing diff configurable
|
||||
- Adjust the default branch automatically when cloning external repo
|
||||
- Performance improvement for listing branches
|
||||
- Upgrade internal libraries
|
||||
## 4.43.0 - 29 Jun 2025
|
||||
- Upgrade H2 database from 1.x to 2.x
|
||||
|
||||
See the [change log](CHANGELOG.md) for all of the updates.
|
||||
Note that upgrading from h2 1.x to 2.x requires data file migration: https://www.h2database.com/html/migration-to-v2.html
|
||||
|
||||
It can't be done automatically using GitBucket's auto migration mechanism because it relies on database itself. So, users who use h2 will have to dump and recreate their database manually with the following steps:
|
||||
```
|
||||
# Export database using the current version of H2
|
||||
$ curl -O https://repo1.maven.org/maven2/com/h2database/h2/1.4.199/h2-1.4.199.jar
|
||||
$ java -cp h2-1.4.199.jar org.h2.tools.Script -url "jdbc:h2:~/.gitbucket/data" -user sa -password sa -script dump.sql
|
||||
|
||||
# Recreate database using the new version of H2
|
||||
$ curl -O https://repo1.maven.org/maven2/com/h2database/h2/2.3.232/h2-2.3.232.jar
|
||||
$ java -cp h2-2.3.232.jar org.h2.tools.RunScript -url "jdbc:h2:~/.gitbucket/data" -user sa -password sa -script dump.sql
|
||||
```
|
||||
|
||||
See the [change log](CHANGELOG.md) for all the past updates.
|
||||
|
||||
76
build.sbt
76
build.sbt
@@ -1,23 +1,22 @@
|
||||
import sbtlicensereport.license.{DepModuleInfo, LicenseInfo}
|
||||
import com.jsuereth.sbtpgp.PgpKeys._
|
||||
|
||||
val Organization = "io.github.gitbucket"
|
||||
val Name = "gitbucket"
|
||||
val GitBucketVersion = "4.41.0"
|
||||
val ScalatraVersion = "3.0.0"
|
||||
val JettyVersion = "10.0.21"
|
||||
val JgitVersion = "6.9.0.202403050737-r"
|
||||
val GitBucketVersion = "4.43.0"
|
||||
val ScalatraVersion = "3.1.2"
|
||||
val JettyVersion = "10.0.25"
|
||||
val JgitVersion = "6.10.1.202505221210-r"
|
||||
|
||||
lazy val root = (project in file("."))
|
||||
.enablePlugins(SbtTwirl, ScalatraPlugin)
|
||||
.enablePlugins(SbtTwirl, ContainerPlugin)
|
||||
|
||||
sourcesInBase := false
|
||||
organization := Organization
|
||||
name := Name
|
||||
version := GitBucketVersion
|
||||
scalaVersion := "2.13.14"
|
||||
scalaVersion := "2.13.16"
|
||||
|
||||
crossScalaVersions += "3.4.2"
|
||||
crossScalaVersions += "3.7.1"
|
||||
|
||||
// scalafmtOnCompile := true
|
||||
|
||||
@@ -29,42 +28,46 @@ libraryDependencies ++= Seq(
|
||||
"org.scalatra" %% "scalatra-javax" % ScalatraVersion,
|
||||
"org.scalatra" %% "scalatra-json-javax" % ScalatraVersion,
|
||||
"org.scalatra" %% "scalatra-forms-javax" % ScalatraVersion,
|
||||
"org.json4s" %% "json4s-jackson" % "4.1.0-M5",
|
||||
"commons-io" % "commons-io" % "2.16.1",
|
||||
"org.json4s" %% "json4s-jackson" % "4.1.0-M8",
|
||||
"commons-io" % "commons-io" % "2.19.0",
|
||||
"io.github.gitbucket" % "solidbase" % "1.1.0",
|
||||
"io.github.gitbucket" % "markedj" % "1.0.20",
|
||||
"org.apache.commons" % "commons-compress" % "1.26.1",
|
||||
"org.tukaani" % "xz" % "1.10",
|
||||
"org.apache.commons" % "commons-compress" % "1.27.1",
|
||||
"org.apache.commons" % "commons-email" % "1.6.0",
|
||||
"commons-net" % "commons-net" % "3.10.0",
|
||||
"commons-net" % "commons-net" % "3.11.1",
|
||||
"org.apache.httpcomponents" % "httpclient" % "4.5.14",
|
||||
"org.apache.sshd" % "apache-sshd" % "2.12.1" exclude ("org.slf4j", "slf4j-jdk14") exclude ("org.apache.sshd", "sshd-mina") exclude ("org.apache.sshd", "sshd-netty"),
|
||||
"org.apache.tika" % "tika-core" % "2.9.2",
|
||||
"org.apache.sshd" % "apache-sshd" % "2.15.0" exclude ("org.slf4j", "slf4j-jdk14") exclude (
|
||||
"org.apache.sshd",
|
||||
"sshd-mina"
|
||||
) exclude ("org.apache.sshd", "sshd-netty"),
|
||||
"org.apache.tika" % "tika-core" % "3.2.0",
|
||||
"com.github.takezoe" %% "blocking-slick" % "0.0.14",
|
||||
"com.novell.ldap" % "jldap" % "2009-10-07",
|
||||
"com.h2database" % "h2" % "1.4.199",
|
||||
"com.h2database" % "h2" % "2.3.232",
|
||||
"org.mariadb.jdbc" % "mariadb-java-client" % "2.7.12",
|
||||
"org.postgresql" % "postgresql" % "42.7.3",
|
||||
"ch.qos.logback" % "logback-classic" % "1.5.6",
|
||||
"com.zaxxer" % "HikariCP" % "5.1.0" exclude ("org.slf4j", "slf4j-api"),
|
||||
"org.postgresql" % "postgresql" % "42.7.7",
|
||||
"ch.qos.logback" % "logback-classic" % "1.5.18",
|
||||
"com.zaxxer" % "HikariCP" % "6.3.0" exclude ("org.slf4j", "slf4j-api"),
|
||||
"com.typesafe" % "config" % "1.4.3",
|
||||
"fr.brouillard.oss.security.xhub" % "xhub4j-core" % "1.1.0",
|
||||
"io.github.java-diff-utils" % "java-diff-utils" % "4.12",
|
||||
"io.github.java-diff-utils" % "java-diff-utils" % "4.15",
|
||||
"org.cache2k" % "cache2k-all" % "1.6.0.Final",
|
||||
"net.coobird" % "thumbnailator" % "0.4.20",
|
||||
"com.github.zafarkhaja" % "java-semver" % "0.10.2",
|
||||
"com.nimbusds" % "oauth2-oidc-sdk" % "11.12",
|
||||
"com.nimbusds" % "oauth2-oidc-sdk" % "11.26",
|
||||
"org.eclipse.jetty" % "jetty-webapp" % JettyVersion % "provided",
|
||||
"javax.servlet" % "javax.servlet-api" % "3.1.0" % "provided",
|
||||
"junit" % "junit" % "4.13.2" % "test",
|
||||
"org.scalatra" %% "scalatra-scalatest-javax" % ScalatraVersion % "test",
|
||||
"org.mockito" % "mockito-core" % "5.12.0" % "test",
|
||||
"com.dimafeng" %% "testcontainers-scala" % "0.41.3" % "test",
|
||||
"org.testcontainers" % "mysql" % "1.19.8" % "test",
|
||||
"org.testcontainers" % "postgresql" % "1.19.8" % "test",
|
||||
"org.mockito" % "mockito-core" % "5.18.0" % "test",
|
||||
"com.dimafeng" %% "testcontainers-scala" % "0.43.0" % "test",
|
||||
"org.testcontainers" % "mysql" % "1.21.3" % "test",
|
||||
"org.testcontainers" % "postgresql" % "1.21.3" % "test",
|
||||
"net.i2p.crypto" % "eddsa" % "0.3.0",
|
||||
"is.tagomor.woothee" % "woothee-java" % "1.11.0",
|
||||
"org.ec4j.core" % "ec4j-core" % "0.3.0",
|
||||
"org.kohsuke" % "github-api" % "1.321" % "test"
|
||||
"org.ec4j.core" % "ec4j-core" % "1.1.1",
|
||||
"org.kohsuke" % "github-api" % "1.327" % "test"
|
||||
)
|
||||
|
||||
// Compiler settings
|
||||
@@ -79,13 +82,13 @@ scalacOptions := Seq(
|
||||
scalacOptions ++= {
|
||||
scalaBinaryVersion.value match {
|
||||
case "2.13" =>
|
||||
Seq("-Xsource:3")
|
||||
Seq("-Xsource:3-cross")
|
||||
case _ =>
|
||||
Nil
|
||||
}
|
||||
}
|
||||
compile / javacOptions ++= Seq("-target", "11", "-source", "11")
|
||||
Jetty / javaOptions += "-Dlogback.configurationFile=/logback-dev.xml"
|
||||
Container / javaOptions += "-Dlogback.configurationFile=/logback-dev.xml"
|
||||
|
||||
// Test settings
|
||||
//testOptions in Test += Tests.Argument("-l", "ExternalDBTest")
|
||||
@@ -152,8 +155,11 @@ executableKey := {
|
||||
// include jetty classes
|
||||
val jettyJars = Keys.update.value select configurationFilter(name = ExecutableConfig.name)
|
||||
jettyJars foreach { jar =>
|
||||
IO unzip (jar, temp, (name: String) =>
|
||||
(name startsWith "javax/") || (name startsWith "org/") || (name startsWith "META-INF/services/"))
|
||||
IO unzip (
|
||||
jar,
|
||||
temp,
|
||||
(name: String) => (name startsWith "javax/") || (name startsWith "org/") || (name startsWith "META-INF/services/")
|
||||
)
|
||||
}
|
||||
|
||||
// include original war file
|
||||
@@ -209,9 +215,9 @@ executableKey := {
|
||||
outputFile
|
||||
}
|
||||
publishTo := {
|
||||
val nexus = "https://oss.sonatype.org/"
|
||||
if (version.value.trim.endsWith("SNAPSHOT")) Some("snapshots" at nexus + "content/repositories/snapshots")
|
||||
else Some("releases" at nexus + "service/local/staging/deploy/maven2")
|
||||
val centralSnapshots = "https://central.sonatype.com/repository/maven-snapshots/"
|
||||
if (isSnapshot.value) Some("central-snapshots" at centralSnapshots)
|
||||
else localStaging.value
|
||||
}
|
||||
publishMavenStyle := true
|
||||
pomIncludeRepository := { _ =>
|
||||
@@ -277,10 +283,12 @@ Test / testOptions ++= {
|
||||
}
|
||||
}
|
||||
|
||||
Jetty / javaOptions ++= Seq(
|
||||
Container / javaOptions ++= Seq(
|
||||
"-Dlogback.configurationFile=/logback-dev.xml",
|
||||
"-Xdebug",
|
||||
"-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000",
|
||||
"-Dorg.eclipse.jetty.annotations.AnnotationParser.LEVEL=OFF",
|
||||
// "-Ddev-features=keep-session"
|
||||
)
|
||||
Container / containerLibs := Seq(("org.eclipse.jetty" % "jetty-runner" % JettyVersion).intransitive())
|
||||
Container / containerMain := "org.eclipse.jetty.runner.Runner"
|
||||
|
||||
@@ -13,7 +13,7 @@ Run for Development
|
||||
If you want to test GitBucket, type the following command in the root directory of the source tree.
|
||||
|
||||
```shell
|
||||
$ sbt ~jetty:start
|
||||
$ sbt ~container:start
|
||||
```
|
||||
|
||||
Then access `http://localhost:8080/` in your browser. The default administrator account is `root` and password is `root`.
|
||||
@@ -24,11 +24,11 @@ You can modify the logging configuration by editing `src/main/resources/logback-
|
||||
Note that HttpSession is cleared when auto-reloading happened.
|
||||
This is a bit annoying when developing features that requires sign-in.
|
||||
You can keep HttpSession even if GitBucket is restarted by enabling this configuration in `build.sbt`:
|
||||
https://github.com/gitbucket/gitbucket/blob/d5c083b70f7f3748d080166252e9a3dcaf579648/build.sbt#L292
|
||||
https://github.com/gitbucket/gitbucket/blob/3dcc0aee3c4413b05be7c03476626cb202674afc/build.sbt#L292
|
||||
|
||||
Or by launching GitBucket with the following command:
|
||||
```shell
|
||||
sbt '; set Jetty/javaOptions += "-Ddev-features=keep-session" ; ~jetty:start'
|
||||
sbt '; set Container/javaOptions += "-Ddev-features=keep-session" ; ~container:start'
|
||||
```
|
||||
|
||||
Note that this feature serializes HttpSession on the local disk and assigns all requests to the same session
|
||||
|
||||
@@ -12,7 +12,7 @@ javaOptions in Jetty ++= Seq(
|
||||
Run GitBucket:
|
||||
|
||||
```shell
|
||||
$ sbt ~jetty:start
|
||||
$ sbt ~container:start
|
||||
```
|
||||
|
||||
In IntelliJ, create remote debug configuration as follows. Make sure port number is same as above configuration.
|
||||
|
||||
@@ -1 +1 @@
|
||||
sbt.version=1.10.0
|
||||
sbt.version=1.11.2
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
scalacOptions ++= Seq("-unchecked", "-deprecation", "-feature")
|
||||
|
||||
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.2")
|
||||
addSbtPlugin("org.playframework.twirl" % "sbt-twirl" % "2.0.5")
|
||||
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.2.0")
|
||||
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.4")
|
||||
addSbtPlugin("org.playframework.twirl" % "sbt-twirl" % "2.0.8")
|
||||
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.3.1")
|
||||
addSbtPlugin("org.scalatra.sbt" % "sbt-scalatra" % "1.0.4")
|
||||
addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.2.1")
|
||||
addSbtPlugin("com.github.sbt" % "sbt-license-report" % "1.6.1")
|
||||
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.12")
|
||||
addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.3.1")
|
||||
addSbtPlugin("com.github.sbt" % "sbt-license-report" % "1.7.0")
|
||||
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.3.1")
|
||||
|
||||
addDependencyTreePlugin
|
||||
|
||||
20
src/main/resources/update/gitbucket-core_4.42.xml
Normal file
20
src/main/resources/update/gitbucket-core_4.42.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<changeSet>
|
||||
<dropForeignKeyConstraint constraintName="IDX_PROTECTED_BRANCH_REQUIRE_CONTEXT_FK0" baseTableName="PROTECTED_BRANCH_REQUIRE_CONTEXT"/>
|
||||
<dropPrimaryKey constraintName="IDX_PROTECTED_BRANCH_REQUIRE_CONTEXT_PK" tableName="PROTECTED_BRANCH_REQUIRE_CONTEXT"/>
|
||||
|
||||
<dropForeignKeyConstraint constraintName="IDX_PROTECTED_BRANCH_FK0" baseTableName="PROTECTED_BRANCH"/>
|
||||
<dropPrimaryKey constraintName="IDX_PROTECTED_BRANCH_PK" tableName="PROTECTED_BRANCH"/>
|
||||
|
||||
<modifyDataType columnName="DEFAULT_BRANCH" newDataType="varchar(255)" tableName="REPOSITORY"/>
|
||||
<modifyDataType columnName="BRANCH" newDataType="varchar(255)" tableName="PULL_REQUEST"/>
|
||||
<modifyDataType columnName="REQUEST_BRANCH" newDataType="varchar(255)" tableName="PULL_REQUEST"/>
|
||||
<modifyDataType columnName="BRANCH" newDataType="varchar(255)" tableName="PROTECTED_BRANCH"/>
|
||||
<modifyDataType columnName="BRANCH" newDataType="varchar(255)" tableName="PROTECTED_BRANCH_REQUIRE_CONTEXT"/>
|
||||
|
||||
<addPrimaryKey constraintName="IDX_PROTECTED_BRANCH_PK" tableName="PROTECTED_BRANCH" columnNames="USER_NAME, REPOSITORY_NAME, BRANCH"/>
|
||||
<addForeignKeyConstraint constraintName="IDX_PROTECTED_BRANCH_FK0" baseTableName="PROTECTED_BRANCH" baseColumnNames="USER_NAME, REPOSITORY_NAME" referencedTableName="REPOSITORY" referencedColumnNames="USER_NAME, REPOSITORY_NAME" onDelete="CASCADE" onUpdate="CASCADE"/>
|
||||
|
||||
<addPrimaryKey constraintName="IDX_PROTECTED_BRANCH_REQUIRE_CONTEXT_PK" tableName="PROTECTED_BRANCH_REQUIRE_CONTEXT" columnNames="USER_NAME, REPOSITORY_NAME, BRANCH, CONTEXT"/>
|
||||
<addForeignKeyConstraint constraintName="IDX_PROTECTED_BRANCH_REQUIRE_CONTEXT_FK0" baseTableName="PROTECTED_BRANCH_REQUIRE_CONTEXT" baseColumnNames="USER_NAME, REPOSITORY_NAME, BRANCH" referencedTableName="PROTECTED_BRANCH" referencedColumnNames="USER_NAME, REPOSITORY_NAME, BRANCH" onDelete="CASCADE" onUpdate="CASCADE"/>
|
||||
</changeSet>
|
||||
@@ -4,7 +4,6 @@ import java.io.FileOutputStream
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.sql.Connection
|
||||
import java.util.UUID
|
||||
|
||||
import gitbucket.core.model.Activity
|
||||
import gitbucket.core.util.Directory.ActivityLog
|
||||
import gitbucket.core.util.JDBCUtil
|
||||
@@ -15,6 +14,7 @@ import org.json4s.{Formats, NoTypeHints}
|
||||
import org.json4s.jackson.Serialization
|
||||
import org.json4s.jackson.Serialization.write
|
||||
|
||||
import java.util.logging.Level
|
||||
import scala.util.Using
|
||||
|
||||
object GitBucketCoreModule
|
||||
@@ -117,5 +117,10 @@ object GitBucketCoreModule
|
||||
new Version("4.38.4"),
|
||||
new Version("4.39.0", new LiquibaseMigration("update/gitbucket-core_4.39.xml")),
|
||||
new Version("4.40.0"),
|
||||
new Version("4.41.0")
|
||||
)
|
||||
new Version("4.41.0"),
|
||||
new Version("4.42.0", new LiquibaseMigration("update/gitbucket-core_4.42.xml")),
|
||||
new Version("4.42.1"),
|
||||
new Version("4.43.0")
|
||||
) {
|
||||
java.util.logging.Logger.getLogger("liquibase").setLevel(Level.SEVERE)
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ case class ApiRepository(
|
||||
val url = ApiPath(s"/api/v3/repos/${full_name}")
|
||||
val clone_url = ApiPath(s"/git/${full_name}.git")
|
||||
val html_url = ApiPath(s"/${full_name}")
|
||||
val ssh_url = Some(SshPath(""))
|
||||
val ssh_url = Some(SshPath(s"/${full_name}.git"))
|
||||
}
|
||||
|
||||
object ApiRepository {
|
||||
|
||||
29
src/main/scala/gitbucket/core/api/ApiTag.scala
Normal file
29
src/main/scala/gitbucket/core/api/ApiTag.scala
Normal file
@@ -0,0 +1,29 @@
|
||||
package gitbucket.core.api
|
||||
|
||||
import gitbucket.core.util.RepositoryName
|
||||
|
||||
case class ApiTagCommit(
|
||||
sha: String,
|
||||
url: ApiPath
|
||||
)
|
||||
|
||||
case class ApiTag(
|
||||
name: String,
|
||||
commit: ApiTagCommit,
|
||||
zipball_url: ApiPath,
|
||||
tarball_url: ApiPath
|
||||
)
|
||||
|
||||
object ApiTag {
|
||||
def apply(
|
||||
tagName: String,
|
||||
repositoryName: RepositoryName,
|
||||
commitId: String
|
||||
): ApiTag =
|
||||
ApiTag(
|
||||
name = tagName,
|
||||
commit = ApiTagCommit(sha = commitId, url = ApiPath(s"/${repositoryName.fullName}/commits/${commitId}")),
|
||||
zipball_url = ApiPath(s"/${repositoryName.fullName}/archive/${tagName}.zip"),
|
||||
tarball_url = ApiPath(s"/${repositoryName.fullName}/archive/${tagName}.tar.gz")
|
||||
)
|
||||
}
|
||||
@@ -38,23 +38,11 @@ class AccountController
|
||||
with RequestCache
|
||||
|
||||
trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
self: AccountService
|
||||
with RepositoryService
|
||||
with ActivityService
|
||||
with WikiService
|
||||
with LabelsService
|
||||
with SshKeyService
|
||||
with GpgKeyService
|
||||
with OneselfAuthenticator
|
||||
with UsersAuthenticator
|
||||
with GroupManagerAuthenticator
|
||||
with ReadableUsersAuthenticator
|
||||
with AccessTokenService
|
||||
with WebHookService
|
||||
with PrioritiesService
|
||||
with RepositoryCreationService =>
|
||||
self: AccountService & RepositoryService & ActivityService & WikiService & LabelsService & SshKeyService &
|
||||
GpgKeyService & OneselfAuthenticator & UsersAuthenticator & GroupManagerAuthenticator & ReadableUsersAuthenticator &
|
||||
AccessTokenService & WebHookService & PrioritiesService & RepositoryCreationService =>
|
||||
|
||||
case class AccountNewForm(
|
||||
private case class AccountNewForm(
|
||||
userName: String,
|
||||
password: String,
|
||||
fullName: String,
|
||||
@@ -65,7 +53,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
fileId: Option[String]
|
||||
)
|
||||
|
||||
case class AccountEditForm(
|
||||
private case class AccountEditForm(
|
||||
password: Option[String],
|
||||
fullName: String,
|
||||
mailAddress: String,
|
||||
@@ -76,15 +64,15 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
clearImage: Boolean
|
||||
)
|
||||
|
||||
case class SshKeyForm(title: String, publicKey: String)
|
||||
private case class SshKeyForm(title: String, publicKey: String)
|
||||
|
||||
case class GpgKeyForm(title: String, publicKey: String)
|
||||
private case class GpgKeyForm(title: String, publicKey: String)
|
||||
|
||||
case class PersonalTokenForm(note: String)
|
||||
private case class PersonalTokenForm(note: String)
|
||||
|
||||
case class SyntaxHighlighterThemeForm(theme: String)
|
||||
private case class SyntaxHighlighterThemeForm(theme: String)
|
||||
|
||||
val newForm = mapping(
|
||||
private val newForm = mapping(
|
||||
"userName" -> trim(label("User name", text(required, maxlength(100), identifier, uniqueUserName, reservedNames))),
|
||||
"password" -> trim(label("Password", text(required, maxlength(40)))),
|
||||
"fullName" -> trim(label("Full Name", text(required, maxlength(100)))),
|
||||
@@ -97,7 +85,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
"fileId" -> trim(label("File ID", optional(text())))
|
||||
)(AccountNewForm.apply)
|
||||
|
||||
val editForm = mapping(
|
||||
private val editForm = mapping(
|
||||
"password" -> trim(label("Password", optional(text(maxlength(40))))),
|
||||
"fullName" -> trim(label("Full Name", text(required, maxlength(100)))),
|
||||
"mailAddress" -> trim(label("Mail Address", text(required, maxlength(100), uniqueMailAddress("userName")))),
|
||||
@@ -110,41 +98,41 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
"clearImage" -> trim(label("Clear image", boolean()))
|
||||
)(AccountEditForm.apply)
|
||||
|
||||
val sshKeyForm = mapping(
|
||||
private val sshKeyForm = mapping(
|
||||
"title" -> trim(label("Title", text(required, maxlength(100)))),
|
||||
"publicKey" -> trim2(label("Key", text(required, validPublicKey)))
|
||||
)(SshKeyForm.apply)
|
||||
|
||||
val gpgKeyForm = mapping(
|
||||
private val gpgKeyForm = mapping(
|
||||
"title" -> trim(label("Title", text(required, maxlength(100)))),
|
||||
"publicKey" -> label("Key", text(required, validGpgPublicKey))
|
||||
)(GpgKeyForm.apply)
|
||||
|
||||
val personalTokenForm = mapping(
|
||||
private val personalTokenForm = mapping(
|
||||
"note" -> trim(label("Token", text(required, maxlength(100))))
|
||||
)(PersonalTokenForm.apply)
|
||||
|
||||
val syntaxHighlighterThemeForm = mapping(
|
||||
private val syntaxHighlighterThemeForm = mapping(
|
||||
"highlighterTheme" -> trim(label("Theme", text(required)))
|
||||
)(SyntaxHighlighterThemeForm.apply)
|
||||
|
||||
val resetPasswordEmailForm = mapping(
|
||||
private val resetPasswordEmailForm = mapping(
|
||||
"mailAddress" -> trim(label("Email", text(required)))
|
||||
)(ResetPasswordEmailForm.apply)
|
||||
|
||||
val resetPasswordForm = mapping(
|
||||
private val resetPasswordForm = mapping(
|
||||
"token" -> trim(label("Token", text(required))),
|
||||
"password" -> trim(label("Password", text(required, maxlength(40))))
|
||||
)(ResetPasswordForm.apply)
|
||||
|
||||
case class NewGroupForm(
|
||||
private case class NewGroupForm(
|
||||
groupName: String,
|
||||
description: Option[String],
|
||||
url: Option[String],
|
||||
fileId: Option[String],
|
||||
members: String
|
||||
)
|
||||
case class EditGroupForm(
|
||||
private case class EditGroupForm(
|
||||
groupName: String,
|
||||
description: Option[String],
|
||||
url: Option[String],
|
||||
@@ -152,15 +140,15 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
members: String,
|
||||
clearImage: Boolean
|
||||
)
|
||||
case class ResetPasswordEmailForm(
|
||||
private case class ResetPasswordEmailForm(
|
||||
mailAddress: String
|
||||
)
|
||||
case class ResetPasswordForm(
|
||||
private case class ResetPasswordForm(
|
||||
token: String,
|
||||
password: String
|
||||
)
|
||||
|
||||
val newGroupForm = mapping(
|
||||
private val newGroupForm = mapping(
|
||||
"groupName" -> trim(label("Group name", text(required, maxlength(100), identifier, uniqueUserName, reservedNames))),
|
||||
"description" -> trim(label("Group description", optional(text()))),
|
||||
"url" -> trim(label("URL", optional(text(maxlength(200))))),
|
||||
@@ -168,7 +156,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
"members" -> trim(label("Members", text(required, members)))
|
||||
)(NewGroupForm.apply)
|
||||
|
||||
val editGroupForm = mapping(
|
||||
private val editGroupForm = mapping(
|
||||
"groupName" -> trim(label("Group name", text(required, maxlength(100), identifier))),
|
||||
"description" -> trim(label("Group description", optional(text()))),
|
||||
"url" -> trim(label("URL", optional(text(maxlength(200))))),
|
||||
@@ -177,7 +165,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
"clearImage" -> trim(label("Clear image", boolean()))
|
||||
)(EditGroupForm.apply)
|
||||
|
||||
case class RepositoryCreationForm(
|
||||
private case class RepositoryCreationForm(
|
||||
owner: String,
|
||||
name: String,
|
||||
description: Option[String],
|
||||
@@ -186,7 +174,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
sourceUrl: Option[String]
|
||||
)
|
||||
|
||||
val newRepositoryForm = mapping(
|
||||
private val newRepositoryForm = mapping(
|
||||
"owner" -> trim(label("Owner", text(required, maxlength(100), identifier, existsAccount))),
|
||||
"name" -> trim(label("Repository name", text(required, maxlength(100), repository, uniqueRepository))),
|
||||
"description" -> trim(label("Description", optional(text()))),
|
||||
@@ -195,21 +183,21 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
"sourceUrl" -> trim(label("Source URL", optionalRequired(_.value("initOption") == "COPY", text())))
|
||||
)(RepositoryCreationForm.apply)
|
||||
|
||||
case class AccountForm(accountName: String)
|
||||
private case class AccountForm(accountName: String)
|
||||
|
||||
val accountForm = mapping(
|
||||
private val accountForm = mapping(
|
||||
"account" -> trim(label("Group/User name", text(required, validAccountName)))
|
||||
)(AccountForm.apply)
|
||||
|
||||
// for account web hook url addition.
|
||||
case class AccountWebHookForm(
|
||||
private case class AccountWebHookForm(
|
||||
url: String,
|
||||
events: Set[WebHook.Event],
|
||||
ctype: WebHookContentType,
|
||||
token: Option[String]
|
||||
)
|
||||
|
||||
def accountWebHookForm(update: Boolean) =
|
||||
private def accountWebHookForm(update: Boolean) =
|
||||
mapping(
|
||||
"url" -> trim(label("url", text(required, accountWebHook(update)))),
|
||||
"events" -> accountWebhookEvents,
|
||||
@@ -265,7 +253,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
)
|
||||
|
||||
// Members
|
||||
case "members" if (account.isGroupAccount) => {
|
||||
case "members" if account.isGroupAccount =>
|
||||
val members = getGroupMembers(account.userName)
|
||||
gitbucket.core.account.html.members(
|
||||
account,
|
||||
@@ -273,10 +261,9 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
extraMailAddresses,
|
||||
isGroupManager(context.loginAccount, members)
|
||||
)
|
||||
}
|
||||
|
||||
// Repositories
|
||||
case _ => {
|
||||
case _ =>
|
||||
val members = getGroupMembers(account.userName)
|
||||
gitbucket.core.account.html.repositories(
|
||||
account,
|
||||
@@ -285,7 +272,6 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
extraMailAddresses,
|
||||
isGroupManager(context.loginAccount, members)
|
||||
)
|
||||
}
|
||||
}
|
||||
} getOrElse NotFound()
|
||||
}
|
||||
@@ -293,7 +279,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
get("/:userName.atom") {
|
||||
val userName = params("userName")
|
||||
contentType = "application/atom+xml; type=feed"
|
||||
helper.xml.feed(getActivitiesByUser(userName, true))
|
||||
helper.xml.feed(getActivitiesByUser(userName, publicOnly = true))
|
||||
}
|
||||
|
||||
get("/:userName.keys") {
|
||||
@@ -352,7 +338,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
updateImage(userName, form.fileId, form.clearImage)
|
||||
updateAccountExtraMailAddresses(userName, form.extraMailAddresses.filter(_ != ""))
|
||||
flash.update("info", "Account information has been updated.")
|
||||
redirect(s"/${userName}/_edit")
|
||||
redirect(s"/$userName/_edit")
|
||||
|
||||
} getOrElse NotFound()
|
||||
})
|
||||
@@ -360,10 +346,10 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
get("/:userName/_delete")(oneselfOnly {
|
||||
val userName = params("userName")
|
||||
|
||||
getAccountByUserName(userName, true).map { account =>
|
||||
getAccountByUserName(userName, includeRemoved = true).map { account =>
|
||||
if (isLastAdministrator(account)) {
|
||||
flash.update("error", "Account can't be removed because this is last one administrator.")
|
||||
redirect(s"/${userName}/_edit")
|
||||
redirect(s"/$userName/_edit")
|
||||
} else {
|
||||
// // Remove repositories
|
||||
// getRepositoryNamesOfUser(userName).foreach { repositoryName =>
|
||||
@@ -373,7 +359,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
// FileUtils.deleteDirectory(getTemporaryDir(userName, repositoryName))
|
||||
// }
|
||||
suspendAccount(account)
|
||||
session.invalidate
|
||||
session.invalidate()
|
||||
redirect("/")
|
||||
}
|
||||
} getOrElse NotFound()
|
||||
@@ -389,14 +375,14 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
post("/:userName/_ssh", sshKeyForm)(oneselfOnly { form =>
|
||||
val userName = params("userName")
|
||||
addPublicKey(userName, form.title, form.publicKey)
|
||||
redirect(s"/${userName}/_ssh")
|
||||
redirect(s"/$userName/_ssh")
|
||||
})
|
||||
|
||||
get("/:userName/_ssh/delete/:id")(oneselfOnly {
|
||||
val userName = params("userName")
|
||||
val sshKeyId = params("id").toInt
|
||||
deletePublicKey(userName, sshKeyId)
|
||||
redirect(s"/${userName}/_ssh")
|
||||
redirect(s"/$userName/_ssh")
|
||||
})
|
||||
|
||||
get("/:userName/_gpg")(oneselfOnly {
|
||||
@@ -410,14 +396,14 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
post("/:userName/_gpg", gpgKeyForm)(oneselfOnly { form =>
|
||||
val userName = params("userName")
|
||||
addGpgPublicKey(userName, form.title, form.publicKey)
|
||||
redirect(s"/${userName}/_gpg")
|
||||
redirect(s"/$userName/_gpg")
|
||||
})
|
||||
|
||||
get("/:userName/_gpg/delete/:id")(oneselfOnly {
|
||||
val userName = params("userName")
|
||||
val keyId = params("id").toInt
|
||||
deleteGpgPublicKey(userName, keyId)
|
||||
redirect(s"/${userName}/_gpg")
|
||||
redirect(s"/$userName/_gpg")
|
||||
})
|
||||
|
||||
get("/:userName/_application")(oneselfOnly {
|
||||
@@ -425,13 +411,12 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
getAccountByUserName(userName).map { x =>
|
||||
var tokens = getAccessTokens(x.userName)
|
||||
val generatedToken = flash.get("generatedToken") match {
|
||||
case Some((tokenId: Int, token: String)) => {
|
||||
case Some((tokenId: Int, token: String)) =>
|
||||
val gt = tokens.find(_.accessTokenId == tokenId)
|
||||
gt.map { t =>
|
||||
tokens = tokens.filterNot(_ == t)
|
||||
(t, token)
|
||||
}
|
||||
}
|
||||
case _ => None
|
||||
}
|
||||
html.application(x, tokens, generatedToken)
|
||||
@@ -440,18 +425,18 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
|
||||
post("/:userName/_personalToken", personalTokenForm)(oneselfOnly { form =>
|
||||
val userName = params("userName")
|
||||
getAccountByUserName(userName).foreach { x =>
|
||||
getAccountByUserName(userName).foreach { _ =>
|
||||
val (tokenId, token) = generateAccessToken(userName, form.note)
|
||||
flash.update("generatedToken", (tokenId, token))
|
||||
}
|
||||
redirect(s"/${userName}/_application")
|
||||
redirect(s"/$userName/_application")
|
||||
})
|
||||
|
||||
get("/:userName/_personalToken/delete/:id")(oneselfOnly {
|
||||
val userName = params("userName")
|
||||
val tokenId = params("id").toInt
|
||||
deleteAccessToken(userName, tokenId)
|
||||
redirect(s"/${userName}/_application")
|
||||
redirect(s"/$userName/_application")
|
||||
})
|
||||
|
||||
/**
|
||||
@@ -474,7 +459,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
post("/:userName/_preferences/highlighter", syntaxHighlighterThemeForm)(oneselfOnly { form =>
|
||||
val userName = params("userName")
|
||||
addOrUpdateAccountPreference(userName, form.theme)
|
||||
redirect(s"/${userName}/_preferences")
|
||||
redirect(s"/$userName/_preferences")
|
||||
})
|
||||
|
||||
get("/:userName/_hooks")(managersOnly {
|
||||
@@ -491,7 +476,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
val userName = params("userName")
|
||||
getAccountByUserName(userName).map { account =>
|
||||
val webhook = AccountWebHook(userName, "", WebHookContentType.FORM, None)
|
||||
html.edithook(webhook, Set(WebHook.Push), account, true)
|
||||
html.edithook(webhook, Set(WebHook.Push), account, create = true)
|
||||
} getOrElse NotFound()
|
||||
})
|
||||
|
||||
@@ -502,7 +487,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
val userName = params("userName")
|
||||
addAccountWebHook(userName, form.url, form.events, form.ctype, form.token)
|
||||
flash.update("info", s"Webhook ${form.url} created")
|
||||
redirect(s"/${userName}/_hooks")
|
||||
redirect(s"/$userName/_hooks")
|
||||
})
|
||||
|
||||
/**
|
||||
@@ -512,7 +497,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
val userName = params("userName")
|
||||
deleteAccountWebHook(userName, params("url"))
|
||||
flash.update("info", s"Webhook ${params("url")} deleted")
|
||||
redirect(s"/${userName}/_hooks")
|
||||
redirect(s"/$userName/_hooks")
|
||||
})
|
||||
|
||||
/**
|
||||
@@ -522,7 +507,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
val userName = params("userName")
|
||||
getAccountByUserName(userName).flatMap { account =>
|
||||
getAccountWebHook(userName, params("url")).map { case (webhook, events) =>
|
||||
html.edithook(webhook, events, account, false)
|
||||
html.edithook(webhook, events, account, create = false)
|
||||
}
|
||||
} getOrElse NotFound()
|
||||
})
|
||||
@@ -534,7 +519,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
val userName = params("userName")
|
||||
updateAccountWebHook(userName, form.url, form.events, form.ctype, form.token)
|
||||
flash.update("info", s"webhook ${form.url} updated")
|
||||
redirect(s"/${userName}/_hooks")
|
||||
redirect(s"/$userName/_hooks")
|
||||
})
|
||||
|
||||
/**
|
||||
@@ -542,8 +527,8 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
*/
|
||||
ajaxPost("/:userName/_hooks/test")(managersOnly {
|
||||
// TODO Is it possible to merge with [[RepositorySettingsController.ajaxPost]]?
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent._
|
||||
import scala.concurrent.duration.*
|
||||
import scala.concurrent.*
|
||||
import scala.util.control.NonFatal
|
||||
import org.apache.http.util.EntityUtils
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
@@ -567,10 +552,10 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
callWebHook(WebHook.Push, List(dummyWebHookInfo), dummyPayload, context.settings).head
|
||||
|
||||
val toErrorMap: PartialFunction[Throwable, Map[String, String]] = {
|
||||
case e: java.net.UnknownHostException => Map("error" -> ("Unknown host " + e.getMessage))
|
||||
case e: java.lang.IllegalArgumentException => Map("error" -> ("invalid url"))
|
||||
case e: org.apache.http.client.ClientProtocolException => Map("error" -> ("invalid url"))
|
||||
case NonFatal(e) => Map("error" -> (s"${e.getClass} ${e.getMessage}"))
|
||||
case e: java.net.UnknownHostException => Map("error" -> s"Unknown host ${e.getMessage}")
|
||||
case _: java.lang.IllegalArgumentException => Map("error" -> "invalid url")
|
||||
case _: org.apache.http.client.ClientProtocolException => Map("error" -> "invalid url")
|
||||
case NonFatal(e) => Map("error" -> s"${e.getClass} ${e.getMessage}")
|
||||
}
|
||||
|
||||
contentType = formats("json")
|
||||
@@ -592,9 +577,9 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
resFuture
|
||||
.map(res =>
|
||||
Map(
|
||||
"status" -> res.getStatusLine(),
|
||||
"body" -> EntityUtils.toString(res.getEntity()),
|
||||
"headers" -> _headers(res.getAllHeaders())
|
||||
"status" -> res.getStatusLine,
|
||||
"body" -> EntityUtils.toString(res.getEntity),
|
||||
"headers" -> _headers(res.getAllHeaders)
|
||||
)
|
||||
)
|
||||
.recover(toErrorMap),
|
||||
@@ -621,11 +606,11 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
pbkdf2_sha256(form.password),
|
||||
form.fullName,
|
||||
form.mailAddress,
|
||||
false,
|
||||
isAdmin = false,
|
||||
form.description,
|
||||
form.url
|
||||
)
|
||||
updateImage(form.userName, form.fileId, false)
|
||||
updateImage(form.userName, form.fileId, clearImage = false)
|
||||
updateAccountExtraMailAddresses(form.userName, form.extraMailAddresses.filter(_ != ""))
|
||||
redirect("/signin")
|
||||
} else NotFound()
|
||||
@@ -650,7 +635,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
|You requested to reset the password for your GitBucket account.
|
||||
|If you are not sure about the request, you can ignore this email.
|
||||
|Otherwise, click the following link to set the new password:
|
||||
|${context.baseUrl}/reset/form/${token}
|
||||
|${context.baseUrl}/reset/form/$token
|
||||
|""".stripMargin
|
||||
)
|
||||
}
|
||||
@@ -690,7 +675,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
|
||||
get("/groups/new")(usersOnly {
|
||||
context.withLoginAccount { loginAccount =>
|
||||
html.creategroup(List(GroupMember("", loginAccount.userName, true)))
|
||||
html.creategroup(List(GroupMember("", loginAccount.userName, isManager = true)))
|
||||
}
|
||||
})
|
||||
|
||||
@@ -707,13 +692,13 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
}
|
||||
.toList
|
||||
)
|
||||
updateImage(form.groupName, form.fileId, false)
|
||||
updateImage(form.groupName, form.fileId, clearImage = false)
|
||||
redirect(s"/${form.groupName}")
|
||||
})
|
||||
|
||||
get("/:groupName/_editgroup")(managersOnly {
|
||||
val groupName = params("groupName")
|
||||
getAccountByUserName(groupName, true).map { account =>
|
||||
getAccountByUserName(groupName, includeRemoved = true).map { account =>
|
||||
html.editgroup(account, getGroupMembers(groupName), flash.get("info"))
|
||||
} getOrElse NotFound()
|
||||
})
|
||||
@@ -723,8 +708,8 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
// Remove from GROUP_MEMBER
|
||||
updateGroupMembers(groupName, Nil)
|
||||
// Disable group
|
||||
getAccountByUserName(groupName, false).foreach { account =>
|
||||
updateGroup(groupName, account.description, account.url, true)
|
||||
getAccountByUserName(groupName, includeRemoved = false).foreach { account =>
|
||||
updateGroup(groupName, account.description, account.url, removed = true)
|
||||
}
|
||||
// // Remove repositories
|
||||
// getRepositoryNamesOfUser(groupName).foreach { repositoryName =>
|
||||
@@ -747,8 +732,8 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
}
|
||||
.toList
|
||||
|
||||
getAccountByUserName(groupName, true).map { account =>
|
||||
updateGroup(groupName, form.description, form.url, false)
|
||||
getAccountByUserName(groupName, includeRemoved = true).map { _ =>
|
||||
updateGroup(groupName, form.description, form.url, removed = false)
|
||||
|
||||
// Update GROUP_MEMBER
|
||||
updateGroupMembers(form.groupName, members)
|
||||
@@ -763,7 +748,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
updateImage(form.groupName, form.fileId, form.clearImage)
|
||||
|
||||
flash.update("info", "Account information has been updated.")
|
||||
redirect(s"/${groupName}/_editgroup")
|
||||
redirect(s"/$groupName/_editgroup")
|
||||
|
||||
} getOrElse NotFound()
|
||||
})
|
||||
@@ -831,7 +816,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
repository,
|
||||
(groups zip managerPermissions).sortBy(_._1)
|
||||
)
|
||||
case _ => redirect(s"/${loginUserName}")
|
||||
case _ => redirect(s"/$loginUserName")
|
||||
}
|
||||
} else BadRequest()
|
||||
}
|
||||
@@ -847,7 +832,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
|
||||
if (getRepository(accountName, repository.name).isDefined) {
|
||||
// redirect to the repository if repository already exists
|
||||
redirect(s"/${accountName}/${repository.name}")
|
||||
redirect(s"/$accountName/${repository.name}")
|
||||
} else if (!canCreateRepository(accountName, loginAccount)) {
|
||||
// Permission error
|
||||
Forbidden()
|
||||
@@ -855,7 +840,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
// fork repository asynchronously
|
||||
forkRepository(accountName, repository, loginUserName)
|
||||
// redirect to the repository
|
||||
redirect(s"/${accountName}/${repository.name}")
|
||||
redirect(s"/$accountName/${repository.name}")
|
||||
}
|
||||
} else Forbidden()
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package gitbucket.core.controller
|
||||
|
||||
import gitbucket.core.api._
|
||||
import gitbucket.core.controller.api._
|
||||
import gitbucket.core.service._
|
||||
import gitbucket.core.util.Implicits._
|
||||
import gitbucket.core.util._
|
||||
import gitbucket.core.api.*
|
||||
import gitbucket.core.controller.api.*
|
||||
import gitbucket.core.service.*
|
||||
import gitbucket.core.util.Implicits.*
|
||||
import gitbucket.core.util.*
|
||||
import gitbucket.core.plugin.PluginRegistry
|
||||
|
||||
class ApiController
|
||||
|
||||
@@ -4,15 +4,15 @@ import java.io.{File, FileInputStream, FileOutputStream}
|
||||
import gitbucket.core.api.{ApiError, JsonFormat}
|
||||
import gitbucket.core.model.Account
|
||||
import gitbucket.core.service.{AccountService, RepositoryService, SystemSettingsService}
|
||||
import gitbucket.core.util.SyntaxSugars._
|
||||
import gitbucket.core.util.Directory._
|
||||
import gitbucket.core.util.Implicits._
|
||||
import gitbucket.core.util._
|
||||
import org.json4s._
|
||||
import org.scalatra._
|
||||
import org.scalatra.i18n._
|
||||
import org.scalatra.json._
|
||||
import org.scalatra.forms._
|
||||
import gitbucket.core.util.SyntaxSugars.*
|
||||
import gitbucket.core.util.Directory.*
|
||||
import gitbucket.core.util.Implicits.*
|
||||
import gitbucket.core.util.*
|
||||
import org.json4s.*
|
||||
import org.scalatra.{MultiParams, *}
|
||||
import org.scalatra.i18n.*
|
||||
import org.scalatra.json.*
|
||||
import org.scalatra.forms.*
|
||||
|
||||
import javax.servlet.http.{HttpServletRequest, HttpServletResponse}
|
||||
import javax.servlet.{FilterChain, ServletRequest, ServletResponse}
|
||||
@@ -24,7 +24,7 @@ import net.coobird.thumbnailator.Thumbnails
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.eclipse.jgit.lib.ObjectId
|
||||
import org.eclipse.jgit.revwalk.RevCommit
|
||||
import org.eclipse.jgit.treewalk._
|
||||
import org.eclipse.jgit.treewalk.*
|
||||
import org.apache.commons.io.IOUtils
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.json4s.Formats
|
||||
@@ -48,11 +48,21 @@ abstract class ControllerBase
|
||||
|
||||
implicit val jsonFormats: Formats = gitbucket.core.api.JsonFormat.jsonFormats
|
||||
|
||||
private case class HttpException(status: Int) extends RuntimeException
|
||||
|
||||
before("/api/v3/*") {
|
||||
contentType = formats("json")
|
||||
request.setAttribute(Keys.Request.APIv3, true)
|
||||
}
|
||||
|
||||
override def multiParams(implicit request: HttpServletRequest): MultiParams = {
|
||||
try {
|
||||
super.multiParams
|
||||
} catch {
|
||||
case _: Exception => throw HttpException(400)
|
||||
}
|
||||
}
|
||||
|
||||
override def requestPath(uri: String, idx: Int): String = {
|
||||
val path = super.requestPath(uri, idx)
|
||||
if (path != "/" && path.endsWith("/")) {
|
||||
@@ -86,11 +96,10 @@ abstract class ControllerBase
|
||||
*/
|
||||
implicit def context: Context = {
|
||||
contextCache.get match {
|
||||
case null => {
|
||||
case null =>
|
||||
val context = Context(loadSystemSettings(), LoginAccount, request)
|
||||
contextCache.set(context)
|
||||
context
|
||||
}
|
||||
case context => context
|
||||
}
|
||||
}
|
||||
@@ -130,7 +139,7 @@ abstract class ControllerBase
|
||||
action(form)
|
||||
}
|
||||
|
||||
protected def NotFound() =
|
||||
protected def NotFound(): ActionResult =
|
||||
if (request.hasAttribute(Keys.Request.Ajax)) {
|
||||
org.scalatra.NotFound()
|
||||
} else if (request.hasAttribute(Keys.Request.APIv3)) {
|
||||
@@ -150,7 +159,7 @@ abstract class ControllerBase
|
||||
}
|
||||
}
|
||||
|
||||
protected def Unauthorized()(implicit context: Context) =
|
||||
protected def Unauthorized()(implicit context: Context): ActionResult =
|
||||
if (request.hasAttribute(Keys.Request.Ajax)) {
|
||||
org.scalatra.Unauthorized()
|
||||
} else if (request.hasAttribute(Keys.Request.APIv3)) {
|
||||
@@ -178,7 +187,9 @@ abstract class ControllerBase
|
||||
}
|
||||
|
||||
error {
|
||||
case e => {
|
||||
case e: HttpException =>
|
||||
ActionResult(e.status, (), Map.empty)
|
||||
case e =>
|
||||
logger.error(s"Catch unhandled error in request: ${request}", e)
|
||||
if (request.hasAttribute(Keys.Request.Ajax)) {
|
||||
org.scalatra.InternalServerError()
|
||||
@@ -188,7 +199,6 @@ abstract class ControllerBase
|
||||
} else {
|
||||
org.scalatra.InternalServerError(gitbucket.core.html.error("Internal Server Error", Some(e)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override def url(
|
||||
@@ -200,7 +210,7 @@ abstract class ControllerBase
|
||||
withSessionId: Boolean = true
|
||||
)(implicit request: HttpServletRequest, response: HttpServletResponse): String =
|
||||
if (path.startsWith("http")) path
|
||||
else baseUrl + super.url(path, params, false, false, false)
|
||||
else baseUrl + super.url(path, params, includeContextPath = false, includeServletPath = false, absolutize = false)
|
||||
|
||||
/**
|
||||
* Extends scalatra-form's trim rule to eliminate CR and LF.
|
||||
@@ -244,9 +254,9 @@ abstract class ControllerBase
|
||||
protected def getPathObjectId(git: Git, path: String, revCommit: RevCommit): Option[ObjectId] = {
|
||||
@scala.annotation.tailrec
|
||||
def _getPathObjectId(path: String, walk: TreeWalk): Option[ObjectId] = walk.next match {
|
||||
case true if (walk.getPathString == path) => Some(walk.getObjectId(0))
|
||||
case true => _getPathObjectId(path, walk)
|
||||
case false => None
|
||||
case true if walk.getPathString == path => Some(walk.getObjectId(0))
|
||||
case true => _getPathObjectId(path, walk)
|
||||
case false => None
|
||||
}
|
||||
|
||||
Using.resource(new TreeWalk(git.getRepository)) { treeWalk =>
|
||||
@@ -338,18 +348,18 @@ case class Context(
|
||||
loginAccount: Option[Account],
|
||||
request: HttpServletRequest
|
||||
) {
|
||||
val path = settings.baseUrl.getOrElse(request.getContextPath)
|
||||
val currentPath = request.getRequestURI.substring(request.getContextPath.length)
|
||||
val baseUrl = settings.baseUrl(request)
|
||||
val host = new java.net.URL(baseUrl).getHost
|
||||
val platform = request.getHeader("User-Agent") match {
|
||||
val path: String = settings.baseUrl.getOrElse(request.getContextPath)
|
||||
val currentPath: String = request.getRequestURI.substring(request.getContextPath.length)
|
||||
val baseUrl: String = settings.baseUrl(request)
|
||||
val host: String = new java.net.URL(baseUrl).getHost
|
||||
val platform: String = request.getHeader("User-Agent") match {
|
||||
case null => null
|
||||
case agent if agent.contains("Mac") => "mac"
|
||||
case agent if agent.contains("Linux") => "linux"
|
||||
case agent if agent.contains("Win") => "windows"
|
||||
case _ => null
|
||||
}
|
||||
val sidebarCollapse = request.getSession.getAttribute("sidebar-collapse") != null
|
||||
val sidebarCollapse: Boolean = request.getSession.getAttribute("sidebar-collapse") != null
|
||||
|
||||
def withLoginAccount(f: Account => Any): Any = {
|
||||
loginAccount match {
|
||||
@@ -430,9 +440,9 @@ trait AccountManagementControllerBase extends ControllerBase {
|
||||
) {
|
||||
Some("These mail addresses are duplicated.")
|
||||
} else {
|
||||
getAccountByMailAddress(value, true)
|
||||
getAccountByMailAddress(value, includeRemoved = true)
|
||||
.collect {
|
||||
case x if paramName.isEmpty || Some(x.userName) != params.optionValue(paramName) =>
|
||||
case x if paramName.isEmpty || !params.optionValue(paramName).contains(x.userName) =>
|
||||
"Mail address is already registered."
|
||||
}
|
||||
}
|
||||
@@ -448,22 +458,22 @@ trait AccountManagementControllerBase extends ControllerBase {
|
||||
): Option[String] = {
|
||||
val extraMailAddresses = params.view.filterKeys(k => k.startsWith("extraMailAddresses"))
|
||||
if (
|
||||
Some(value) == params.optionValue("mailAddress") || extraMailAddresses.count { case (k, v) =>
|
||||
params.optionValue("mailAddress").contains(value) || extraMailAddresses.count { case (k, v) =>
|
||||
v.contains(value)
|
||||
} > 1
|
||||
) {
|
||||
Some("These mail addresses are duplicated.")
|
||||
} else {
|
||||
getAccountByMailAddress(value, true)
|
||||
getAccountByMailAddress(value, includeRemoved = true)
|
||||
.collect {
|
||||
case x if paramName.isEmpty || Some(x.userName) != params.optionValue(paramName) =>
|
||||
case x if paramName.isEmpty || !params.optionValue(paramName).contains(x.userName) =>
|
||||
"Mail address is already registered."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val allReservedNames = Set(
|
||||
private val allReservedNames = Set(
|
||||
"git",
|
||||
"admin",
|
||||
"upload",
|
||||
@@ -482,10 +492,9 @@ trait AccountManagementControllerBase extends ControllerBase {
|
||||
protected def reservedNames: Constraint = new Constraint() {
|
||||
override def validate(name: String, value: String, messages: Messages): Option[String] =
|
||||
if (allReservedNames.contains(value.toLowerCase)) {
|
||||
Some(s"${value} is reserved")
|
||||
Some(s"$value is reserved")
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@ package gitbucket.core.controller
|
||||
|
||||
import gitbucket.core.dashboard.html
|
||||
import gitbucket.core.model.Account
|
||||
import gitbucket.core.service._
|
||||
import gitbucket.core.util.{Keys, UsersAuthenticator}
|
||||
import gitbucket.core.util.Implicits._
|
||||
import gitbucket.core.service.IssuesService._
|
||||
import gitbucket.core.service.ActivityService._
|
||||
import gitbucket.core.service.*
|
||||
import gitbucket.core.util.UsersAuthenticator
|
||||
import gitbucket.core.util.Implicits.*
|
||||
import gitbucket.core.service.IssuesService.*
|
||||
import gitbucket.core.service.ActivityService.*
|
||||
|
||||
class DashboardController
|
||||
extends DashboardControllerBase
|
||||
@@ -28,12 +28,8 @@ class DashboardController
|
||||
with RequestCache
|
||||
|
||||
trait DashboardControllerBase extends ControllerBase {
|
||||
self: IssuesService
|
||||
with PullRequestService
|
||||
with RepositoryService
|
||||
with AccountService
|
||||
with CommitStatusService
|
||||
with UsersAuthenticator =>
|
||||
self: IssuesService & PullRequestService & RepositoryService & AccountService & CommitStatusService &
|
||||
UsersAuthenticator =>
|
||||
|
||||
get("/dashboard/repos")(usersOnly {
|
||||
context.withLoginAccount { loginAccount =>
|
||||
@@ -95,7 +91,7 @@ trait DashboardControllerBase extends ControllerBase {
|
||||
}
|
||||
})
|
||||
|
||||
private def getOrCreateCondition(key: String, filter: String, userName: String) = {
|
||||
private def getOrCreateCondition(filter: String, userName: String) = {
|
||||
val condition = IssueSearchCondition(request)
|
||||
|
||||
filter match {
|
||||
@@ -106,11 +102,11 @@ trait DashboardControllerBase extends ControllerBase {
|
||||
}
|
||||
|
||||
private def searchIssues(loginAccount: Account, filter: String) = {
|
||||
import IssuesService._
|
||||
import IssuesService.*
|
||||
|
||||
val userName = loginAccount.userName
|
||||
val condition = getOrCreateCondition(Keys.Session.DashboardIssues, filter, userName)
|
||||
val userRepos = getUserRepositories(userName, true).map(repo => repo.owner -> repo.name)
|
||||
val condition = getOrCreateCondition(filter, userName)
|
||||
val userRepos = getUserRepositories(userName, withoutPhysicalInfo = true).map(repo => repo.owner -> repo.name)
|
||||
val page = IssueSearchCondition.page(request)
|
||||
val issues = searchIssue(condition, IssueSearchOption.Issues, (page - 1) * IssueLimit, IssueLimit, userRepos*)
|
||||
|
||||
@@ -137,11 +133,11 @@ trait DashboardControllerBase extends ControllerBase {
|
||||
}
|
||||
|
||||
private def searchPullRequests(loginAccount: Account, filter: String) = {
|
||||
import IssuesService._
|
||||
import PullRequestService._
|
||||
import IssuesService.*
|
||||
import PullRequestService.*
|
||||
|
||||
val userName = loginAccount.userName
|
||||
val condition = getOrCreateCondition(Keys.Session.DashboardPulls, filter, userName)
|
||||
val condition = getOrCreateCondition(filter, userName)
|
||||
val allRepos = getAllRepositories(userName)
|
||||
val page = IssueSearchCondition.page(request)
|
||||
val issues = searchIssue(
|
||||
|
||||
@@ -84,7 +84,7 @@ class FileUploadController
|
||||
execute(
|
||||
{ (file, fileId) =>
|
||||
val fileName = file.getName
|
||||
LockUtil.lock(s"${owner}/${repository}/wiki") {
|
||||
LockUtil.lock(s"$owner/$repository/wiki") {
|
||||
Using.resource(Git.open(Directory.getWikiRepositoryDir(owner, repository))) { git =>
|
||||
val builder = DirCache.newInCore.builder()
|
||||
val inserter = git.getRepository.newObjectInserter()
|
||||
@@ -108,7 +108,7 @@ class FileUploadController
|
||||
)
|
||||
builder.finish()
|
||||
|
||||
val newHeadId = JGitUtil.createNewCommit(
|
||||
JGitUtil.createNewCommit(
|
||||
git,
|
||||
inserter,
|
||||
headId,
|
||||
@@ -116,7 +116,7 @@ class FileUploadController
|
||||
Constants.HEAD,
|
||||
loginAccount.fullName,
|
||||
loginAccount.mailAddress,
|
||||
s"Uploaded ${fileName}"
|
||||
s"Uploaded $fileName"
|
||||
)
|
||||
|
||||
fileName
|
||||
@@ -151,7 +151,7 @@ class FileUploadController
|
||||
}
|
||||
|
||||
post("/import") {
|
||||
import JDBCUtil._
|
||||
import JDBCUtil.*
|
||||
setMultipartConfig()
|
||||
session.get(Keys.Session.LoginAccount).collect {
|
||||
case loginAccount: Account if loginAccount.isAdmin =>
|
||||
@@ -168,13 +168,13 @@ class FileUploadController
|
||||
private def setMultipartConfig(): Unit = {
|
||||
val settings = loadSystemSettings()
|
||||
val config = MultipartConfig(maxFileSize = Some(settings.upload.maxFileSize))
|
||||
config.apply(request.getServletContext())
|
||||
config.apply(request.getServletContext)
|
||||
}
|
||||
|
||||
private def setMultipartConfigForLargeFile(): Unit = {
|
||||
val settings = loadSystemSettings()
|
||||
val config = MultipartConfig(maxFileSize = Some(settings.upload.largeMaxFileSize))
|
||||
config.apply(request.getServletContext())
|
||||
config.apply(request.getServletContext)
|
||||
}
|
||||
|
||||
private def onlyWikiEditable(owner: String, repository: String, loginAccount: Account)(action: => Any): Any = {
|
||||
@@ -191,7 +191,7 @@ class FileUploadController
|
||||
}
|
||||
}
|
||||
|
||||
private def execute(f: (FileItem, String) => Unit, mimeTypeChecker: (String) => Boolean) =
|
||||
private def execute(f: (FileItem, String) => Unit, mimeTypeChecker: String => Boolean) =
|
||||
fileParams.get("file") match {
|
||||
case Some(file) if mimeTypeChecker(file.name) =>
|
||||
val fileId = FileUtil.generateFileId
|
||||
|
||||
@@ -7,14 +7,14 @@ import com.nimbusds.oauth2.sdk.id.State
|
||||
import com.nimbusds.openid.connect.sdk.Nonce
|
||||
import gitbucket.core.helper.xml
|
||||
import gitbucket.core.model.Account
|
||||
import gitbucket.core.service._
|
||||
import gitbucket.core.util.Implicits._
|
||||
import gitbucket.core.util._
|
||||
import gitbucket.core.view.helpers._
|
||||
import gitbucket.core.service.*
|
||||
import gitbucket.core.util.Implicits.*
|
||||
import gitbucket.core.util.*
|
||||
import gitbucket.core.view.helpers.*
|
||||
import org.scalatra.Ok
|
||||
import org.scalatra.forms._
|
||||
import org.scalatra.forms.*
|
||||
|
||||
import gitbucket.core.service.ActivityService._
|
||||
import gitbucket.core.service.ActivityService.*
|
||||
|
||||
class IndexController
|
||||
extends IndexControllerBase
|
||||
@@ -34,19 +34,12 @@ class IndexController
|
||||
with RequestCache
|
||||
|
||||
trait IndexControllerBase extends ControllerBase {
|
||||
self: RepositoryService
|
||||
with ActivityService
|
||||
with AccountService
|
||||
with RepositorySearchService
|
||||
with UsersAuthenticator
|
||||
with ReferrerAuthenticator
|
||||
with AccessTokenService
|
||||
with AccountFederationService
|
||||
with OpenIDConnectService =>
|
||||
self: RepositoryService & ActivityService & AccountService & RepositorySearchService & UsersAuthenticator &
|
||||
ReferrerAuthenticator & AccessTokenService & AccountFederationService & OpenIDConnectService =>
|
||||
|
||||
case class SignInForm(userName: String, password: String, hash: Option[String])
|
||||
private case class SignInForm(userName: String, password: String, hash: Option[String])
|
||||
|
||||
val signinForm = mapping(
|
||||
private val signinForm = mapping(
|
||||
"userName" -> trim(label("Username", text(required))),
|
||||
"password" -> trim(label("Password", text(required))),
|
||||
"hash" -> trim(optional(text()))
|
||||
@@ -60,13 +53,13 @@ trait IndexControllerBase extends ControllerBase {
|
||||
//
|
||||
// case class SearchForm(query: String, owner: String, repository: String)
|
||||
|
||||
case class OidcAuthContext(state: State, nonce: Nonce, redirectBackURI: String)
|
||||
case class OidcSessionContext(token: JWT)
|
||||
private case class OidcAuthContext(state: State, nonce: Nonce, redirectBackURI: String)
|
||||
private case class OidcSessionContext(token: JWT)
|
||||
|
||||
get("/") {
|
||||
context.loginAccount
|
||||
.map { account =>
|
||||
val visibleOwnerSet: Set[String] = Set(account.userName) ++ getGroupsByUserName(account.userName)
|
||||
// val visibleOwnerSet: Set[String] = Set(account.userName) ++ getGroupsByUserName(account.userName)
|
||||
if (!isNewsFeedEnabled) {
|
||||
redirect("/dashboard/repos")
|
||||
} else {
|
||||
@@ -100,9 +93,13 @@ trait IndexControllerBase extends ControllerBase {
|
||||
}
|
||||
|
||||
get("/signin") {
|
||||
val redirect = params.get("redirect")
|
||||
if (redirect.isDefined && redirect.get.startsWith("/")) {
|
||||
flash.update(Keys.Flash.Redirect, redirect.get)
|
||||
if (context.loginAccount.nonEmpty) {
|
||||
redirect("/")
|
||||
}
|
||||
params.get("redirect").foreach { redirect =>
|
||||
if (redirect.startsWith("/")) {
|
||||
flash.update(Keys.Flash.Redirect, redirect)
|
||||
}
|
||||
}
|
||||
gitbucket.core.html.signin(flash.get("userName"), flash.get("password"), flash.get("error"))
|
||||
}
|
||||
@@ -199,6 +196,16 @@ trait IndexControllerBase extends ControllerBase {
|
||||
Ok()
|
||||
}
|
||||
|
||||
get("/user.css") {
|
||||
context.settings.userDefinedCss match {
|
||||
case Some(css) =>
|
||||
contentType = "text/css"
|
||||
css
|
||||
case None =>
|
||||
NotFound()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set account information into HttpSession and redirect.
|
||||
*/
|
||||
@@ -229,7 +236,7 @@ trait IndexControllerBase extends ControllerBase {
|
||||
val group = params("group").toBoolean
|
||||
org.json4s.jackson.Serialization.write(
|
||||
Map(
|
||||
"options" -> (
|
||||
"options" ->
|
||||
getAllUsers(includeRemoved = false)
|
||||
.withFilter { t =>
|
||||
(user, group) match {
|
||||
@@ -248,7 +255,6 @@ trait IndexControllerBase extends ControllerBase {
|
||||
"value" -> t.userName
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
@@ -2,13 +2,13 @@ package gitbucket.core.controller
|
||||
|
||||
import gitbucket.core.issues.html
|
||||
import gitbucket.core.model.{Account, CustomFieldBehavior}
|
||||
import gitbucket.core.service.IssuesService._
|
||||
import gitbucket.core.service._
|
||||
import gitbucket.core.util.Implicits._
|
||||
import gitbucket.core.util._
|
||||
import gitbucket.core.service.IssuesService.*
|
||||
import gitbucket.core.service.*
|
||||
import gitbucket.core.util.Implicits.*
|
||||
import gitbucket.core.util.*
|
||||
import gitbucket.core.view
|
||||
import gitbucket.core.view.Markdown
|
||||
import org.scalatra.forms._
|
||||
import org.scalatra.forms.*
|
||||
import org.scalatra.{BadRequest, Ok}
|
||||
|
||||
class IssuesController
|
||||
@@ -34,23 +34,12 @@ class IssuesController
|
||||
with RequestCache
|
||||
|
||||
trait IssuesControllerBase extends ControllerBase {
|
||||
self: IssuesService
|
||||
with RepositoryService
|
||||
with AccountService
|
||||
with LabelsService
|
||||
with MilestonesService
|
||||
with ActivityService
|
||||
with HandleCommentService
|
||||
with IssueCreationService
|
||||
with CustomFieldsService
|
||||
with ReadableUsersAuthenticator
|
||||
with ReferrerAuthenticator
|
||||
with WritableUsersAuthenticator
|
||||
with PullRequestService
|
||||
with WebHookIssueCommentService
|
||||
with PrioritiesService =>
|
||||
self: IssuesService & RepositoryService & AccountService & LabelsService & MilestonesService & ActivityService &
|
||||
HandleCommentService & IssueCreationService & CustomFieldsService & ReadableUsersAuthenticator &
|
||||
ReferrerAuthenticator & WritableUsersAuthenticator & PullRequestService & WebHookIssueCommentService &
|
||||
PrioritiesService =>
|
||||
|
||||
case class IssueCreateForm(
|
||||
private case class IssueCreateForm(
|
||||
title: String,
|
||||
content: Option[String],
|
||||
assigneeUserNames: Option[String],
|
||||
@@ -58,10 +47,10 @@ trait IssuesControllerBase extends ControllerBase {
|
||||
priorityId: Option[Int],
|
||||
labelNames: Option[String]
|
||||
)
|
||||
case class CommentForm(issueId: Int, content: String)
|
||||
case class IssueStateForm(issueId: Int, content: Option[String])
|
||||
private case class CommentForm(issueId: Int, content: String)
|
||||
private case class IssueStateForm(issueId: Int, content: Option[String])
|
||||
|
||||
val issueCreateForm = mapping(
|
||||
private val issueCreateForm = mapping(
|
||||
"title" -> trim(label("Title", text(required))),
|
||||
"content" -> trim(optional(text())),
|
||||
"assigneeUserNames" -> trim(optional(text())),
|
||||
@@ -70,19 +59,19 @@ trait IssuesControllerBase extends ControllerBase {
|
||||
"labelNames" -> trim(optional(text()))
|
||||
)(IssueCreateForm.apply)
|
||||
|
||||
val issueTitleEditForm = mapping(
|
||||
private val issueTitleEditForm = mapping(
|
||||
"title" -> trim(label("Title", text(required)))
|
||||
)(x => x)
|
||||
val issueEditForm = mapping(
|
||||
private val issueEditForm = mapping(
|
||||
"content" -> trim(optional(text()))
|
||||
)(x => x)
|
||||
|
||||
val commentForm = mapping(
|
||||
private val commentForm = mapping(
|
||||
"issueId" -> label("Issue Id", number()),
|
||||
"content" -> trim(label("Comment", text(required)))
|
||||
)(CommentForm.apply)
|
||||
|
||||
val issueStateForm = mapping(
|
||||
private val issueStateForm = mapping(
|
||||
"issueId" -> label("Issue Id", number()),
|
||||
"content" -> trim(optional(text()))
|
||||
)(IssueStateForm.apply)
|
||||
@@ -109,7 +98,7 @@ trait IssuesControllerBase extends ControllerBase {
|
||||
val issueId = params("id")
|
||||
getIssue(repository.owner, repository.name, issueId) map { issue =>
|
||||
if (issue.isPullRequest) {
|
||||
redirect(s"/${repository.owner}/${repository.name}/pull/${issueId}")
|
||||
redirect(s"/${repository.owner}/${repository.name}/pull/$issueId")
|
||||
} else {
|
||||
html.issue(
|
||||
issue,
|
||||
@@ -230,7 +219,7 @@ trait IssuesControllerBase extends ControllerBase {
|
||||
.filter(_ => isEditableContent(issue.userName, issue.repositoryName, issue.openedUserName, loginAccount))
|
||||
handleComment(issue, Some(form.content), repository, actionOpt) map { case (issue, id) =>
|
||||
redirect(
|
||||
s"/${repository.owner}/${repository.name}/${if (issue.isPullRequest) "pull" else "issues"}/${form.issueId}#comment-${id}"
|
||||
s"/${repository.owner}/${repository.name}/${if (issue.isPullRequest) "pull" else "issues"}/${form.issueId}#comment-$id"
|
||||
)
|
||||
}
|
||||
} getOrElse NotFound()
|
||||
@@ -246,7 +235,7 @@ trait IssuesControllerBase extends ControllerBase {
|
||||
.filter(_ => isEditableContent(issue.userName, issue.repositoryName, issue.openedUserName, loginAccount))
|
||||
handleComment(issue, form.content, repository, actionOpt) map { case (issue, id) =>
|
||||
redirect(
|
||||
s"/${repository.owner}/${repository.name}/${if (issue.isPullRequest) "pull" else "issues"}/${form.issueId}#comment-${id}"
|
||||
s"/${repository.owner}/${repository.name}/${if (issue.isPullRequest) "pull" else "issues"}/${form.issueId}#comment-$id"
|
||||
)
|
||||
}
|
||||
} getOrElse NotFound()
|
||||
@@ -341,30 +330,36 @@ trait IssuesControllerBase extends ControllerBase {
|
||||
|
||||
ajaxPost("/:owner/:repository/issues/:id/label/new")(writableUsersOnly { repository =>
|
||||
val issueId = params("id").toInt
|
||||
registerIssueLabel(repository.owner, repository.name, issueId, params("labelId").toInt, true)
|
||||
registerIssueLabel(repository.owner, repository.name, issueId, params("labelId").toInt, insertComment = true)
|
||||
html.labellist(getIssueLabels(repository.owner, repository.name, issueId))
|
||||
})
|
||||
|
||||
ajaxPost("/:owner/:repository/issues/:id/label/delete")(writableUsersOnly { repository =>
|
||||
val issueId = params("id").toInt
|
||||
deleteIssueLabel(repository.owner, repository.name, issueId, params("labelId").toInt, true)
|
||||
deleteIssueLabel(repository.owner, repository.name, issueId, params("labelId").toInt, insertComment = true)
|
||||
html.labellist(getIssueLabels(repository.owner, repository.name, issueId))
|
||||
})
|
||||
|
||||
ajaxPost("/:owner/:repository/issues/:id/assignee/new")(writableUsersOnly { repository =>
|
||||
val issueId = params("id").toInt
|
||||
registerIssueAssignee(repository.owner, repository.name, issueId, params("assigneeUserName"), true)
|
||||
registerIssueAssignee(repository.owner, repository.name, issueId, params("assigneeUserName"), insertComment = true)
|
||||
Ok()
|
||||
})
|
||||
|
||||
ajaxPost("/:owner/:repository/issues/:id/assignee/delete")(writableUsersOnly { repository =>
|
||||
val issueId = params("id").toInt
|
||||
deleteIssueAssignee(repository.owner, repository.name, issueId, params("assigneeUserName"), true)
|
||||
deleteIssueAssignee(repository.owner, repository.name, issueId, params("assigneeUserName"), insertComment = true)
|
||||
Ok()
|
||||
})
|
||||
|
||||
ajaxPost("/:owner/:repository/issues/:id/milestone")(writableUsersOnly { repository =>
|
||||
updateMilestoneId(repository.owner, repository.name, params("id").toInt, milestoneId("milestoneId"), true)
|
||||
updateMilestoneId(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
params("id").toInt,
|
||||
milestoneId("milestoneId"),
|
||||
insertComment = true
|
||||
)
|
||||
milestoneId("milestoneId").map { milestoneId =>
|
||||
getMilestonesWithIssueCount(repository.owner, repository.name)
|
||||
.find(_._1.milestoneId == milestoneId)
|
||||
@@ -376,7 +371,7 @@ trait IssuesControllerBase extends ControllerBase {
|
||||
|
||||
ajaxPost("/:owner/:repository/issues/:id/priority")(writableUsersOnly { repository =>
|
||||
val priority = priorityId("priorityId")
|
||||
updatePriorityId(repository.owner, repository.name, params("id").toInt, priority, true)
|
||||
updatePriorityId(repository.owner, repository.name, params("id").toInt, priority, insertComment = true)
|
||||
Ok("updated")
|
||||
})
|
||||
|
||||
@@ -438,7 +433,7 @@ trait IssuesControllerBase extends ControllerBase {
|
||||
params("value").toIntOpt.map { labelId =>
|
||||
executeBatch(repository) { issueId =>
|
||||
getIssueLabel(repository.owner, repository.name, issueId, labelId) getOrElse {
|
||||
registerIssueLabel(repository.owner, repository.name, issueId, labelId, true)
|
||||
registerIssueLabel(repository.owner, repository.name, issueId, labelId, insertComment = true)
|
||||
if (params("uri").nonEmpty) {
|
||||
redirect(params("uri"))
|
||||
}
|
||||
@@ -453,9 +448,9 @@ trait IssuesControllerBase extends ControllerBase {
|
||||
// updateAssignedUserName(repository.owner, repository.name, _, value, true)
|
||||
value match {
|
||||
case Some(assignedUserName) =>
|
||||
registerIssueAssignee(repository.owner, repository.name, _, assignedUserName, true)
|
||||
registerIssueAssignee(repository.owner, repository.name, _, assignedUserName, insertComment = true)
|
||||
case None =>
|
||||
deleteAllIssueAssignees(repository.owner, repository.name, _, true)
|
||||
deleteAllIssueAssignees(repository.owner, repository.name, _, insertComment = true)
|
||||
}
|
||||
}
|
||||
if (params("uri").nonEmpty) {
|
||||
@@ -466,20 +461,20 @@ trait IssuesControllerBase extends ControllerBase {
|
||||
post("/:owner/:repository/issues/batchedit/milestone")(writableUsersOnly { repository =>
|
||||
val value = milestoneId("value")
|
||||
executeBatch(repository) {
|
||||
updateMilestoneId(repository.owner, repository.name, _, value, true)
|
||||
updateMilestoneId(repository.owner, repository.name, _, value, insertComment = true)
|
||||
}
|
||||
})
|
||||
|
||||
post("/:owner/:repository/issues/batchedit/priority")(writableUsersOnly { repository =>
|
||||
val value = priorityId("value")
|
||||
executeBatch(repository) {
|
||||
updatePriorityId(repository.owner, repository.name, _, value, true)
|
||||
updatePriorityId(repository.owner, repository.name, _, value, insertComment = true)
|
||||
}
|
||||
})
|
||||
|
||||
get("/:owner/:repository/_attached/:file")(referrersOnly { repository =>
|
||||
(Directory.getAttachedDir(repository.owner, repository.name) match {
|
||||
case dir if (dir.exists && dir.isDirectory) =>
|
||||
case dir if dir.exists && dir.isDirectory =>
|
||||
dir.listFiles.find(_.getName.startsWith(params("file") + ".")).map { file =>
|
||||
response.setHeader("Content-Disposition", f"""inline; filename=${file.getName}""")
|
||||
RawData(FileUtil.getSafeMimeType(file.getName), file)
|
||||
@@ -495,7 +490,7 @@ trait IssuesControllerBase extends ControllerBase {
|
||||
contentType = formats("json")
|
||||
org.json4s.jackson.Serialization.write(
|
||||
Map(
|
||||
"options" -> (
|
||||
"options" ->
|
||||
getOpenIssues(repository.owner, repository.name)
|
||||
.map { t =>
|
||||
Map(
|
||||
@@ -506,16 +501,15 @@ trait IssuesControllerBase extends ControllerBase {
|
||||
"value" -> t.issueId.toString
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
val assignedUserName = (key: String) => params.get(key) filter (_.trim != "")
|
||||
val milestoneId: String => Option[Int] = (key: String) => params.get(key).flatMap(_.toIntOpt)
|
||||
val priorityId: String => Option[Int] = (key: String) => params.get(key).flatMap(_.toIntOpt)
|
||||
private val assignedUserName = (key: String) => params.get(key) filter (_.trim != "")
|
||||
private val milestoneId: String => Option[Int] = (key: String) => params.get(key).flatMap(_.toIntOpt)
|
||||
private val priorityId: String => Option[Int] = (key: String) => params.get(key).flatMap(_.toIntOpt)
|
||||
|
||||
private def executeBatch(repository: RepositoryService.RepositoryInfo)(execute: Int => Unit) = {
|
||||
private def executeBatch(repository: RepositoryService.RepositoryInfo)(execute: Int => Unit): Unit = {
|
||||
params("checked").split(',') map (_.toInt) foreach execute
|
||||
params("from") match {
|
||||
case "issues" => redirect(s"/${repository.owner}/${repository.name}/issues")
|
||||
|
||||
@@ -10,9 +10,9 @@ import gitbucket.core.service.{
|
||||
PrioritiesService
|
||||
}
|
||||
import gitbucket.core.util.{ReferrerAuthenticator, WritableUsersAuthenticator}
|
||||
import gitbucket.core.util.Implicits._
|
||||
import gitbucket.core.util.SyntaxSugars._
|
||||
import org.scalatra.forms._
|
||||
import gitbucket.core.util.Implicits.*
|
||||
import gitbucket.core.util.SyntaxSugars.*
|
||||
import org.scalatra.forms.*
|
||||
import org.scalatra.i18n.Messages
|
||||
import org.scalatra.Ok
|
||||
|
||||
@@ -28,15 +28,11 @@ class LabelsController
|
||||
with WritableUsersAuthenticator
|
||||
|
||||
trait LabelsControllerBase extends ControllerBase {
|
||||
self: LabelsService
|
||||
with IssuesService
|
||||
with RepositoryService
|
||||
with ReferrerAuthenticator
|
||||
with WritableUsersAuthenticator =>
|
||||
self: LabelsService & IssuesService & RepositoryService & ReferrerAuthenticator & WritableUsersAuthenticator =>
|
||||
|
||||
case class LabelForm(labelName: String, color: String)
|
||||
private case class LabelForm(labelName: String, color: String)
|
||||
|
||||
val labelForm = mapping(
|
||||
private val labelForm = mapping(
|
||||
"labelName" -> trim(label("Label name", text(required, labelName, uniqueLabelName, maxlength(100)))),
|
||||
"labelColor" -> trim(label("Color", text(required, color)))
|
||||
)(LabelForm.apply)
|
||||
@@ -93,9 +89,9 @@ trait LabelsControllerBase extends ControllerBase {
|
||||
private def labelName: Constraint = new Constraint() {
|
||||
override def validate(name: String, value: String, messages: Messages): Option[String] =
|
||||
if (value.contains(',')) {
|
||||
Some(s"${name} contains invalid character.")
|
||||
Some(s"$name contains invalid character.")
|
||||
} else if (value.startsWith("_") || value.startsWith("-")) {
|
||||
Some(s"${name} starts with invalid character.")
|
||||
Some(s"$name starts with invalid character.")
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
@@ -9,11 +9,11 @@ import gitbucket.core.service.{
|
||||
MilestonesService,
|
||||
RepositoryService
|
||||
}
|
||||
import gitbucket.core.util.Implicits._
|
||||
import gitbucket.core.util.Implicits.*
|
||||
import gitbucket.core.util.{ReferrerAuthenticator, WritableUsersAuthenticator}
|
||||
import gitbucket.core.util.SyntaxSugars._
|
||||
import gitbucket.core.util.SyntaxSugars.*
|
||||
import gitbucket.core.view.helpers.{getAssignableUserNames, getLabels, getPriorities, searchIssue}
|
||||
import org.scalatra.forms._
|
||||
import org.scalatra.forms.*
|
||||
import org.scalatra.i18n.Messages
|
||||
|
||||
class MilestonesController
|
||||
@@ -26,15 +26,12 @@ class MilestonesController
|
||||
with WritableUsersAuthenticator
|
||||
|
||||
trait MilestonesControllerBase extends ControllerBase {
|
||||
self: MilestonesService
|
||||
with RepositoryService
|
||||
with CommitStatusService
|
||||
with ReferrerAuthenticator
|
||||
with WritableUsersAuthenticator =>
|
||||
self: MilestonesService & RepositoryService & CommitStatusService & ReferrerAuthenticator &
|
||||
WritableUsersAuthenticator =>
|
||||
|
||||
case class MilestoneForm(title: String, description: Option[String], dueDate: Option[java.util.Date])
|
||||
private case class MilestoneForm(title: String, description: Option[String], dueDate: Option[java.util.Date])
|
||||
|
||||
val milestoneForm = mapping(
|
||||
private val milestoneForm = mapping(
|
||||
"title" -> trim(label("Title", text(required, maxlength(100), uniqueMilestone))),
|
||||
"description" -> trim(label("Description", optional(text()))),
|
||||
"dueDate" -> trim(label("Due Date", optional(date())))
|
||||
|
||||
@@ -28,15 +28,11 @@ class PrioritiesController
|
||||
with WritableUsersAuthenticator
|
||||
|
||||
trait PrioritiesControllerBase extends ControllerBase {
|
||||
self: PrioritiesService
|
||||
with IssuesService
|
||||
with RepositoryService
|
||||
with ReferrerAuthenticator
|
||||
with WritableUsersAuthenticator =>
|
||||
self: PrioritiesService & IssuesService & RepositoryService & ReferrerAuthenticator & WritableUsersAuthenticator =>
|
||||
|
||||
case class PriorityForm(priorityName: String, description: Option[String], color: String)
|
||||
private case class PriorityForm(priorityName: String, description: Option[String], color: String)
|
||||
|
||||
val priorityForm = mapping(
|
||||
private val priorityForm = mapping(
|
||||
"priorityName" -> trim(label("Priority name", text(required, priorityName, uniquePriorityName, maxlength(100)))),
|
||||
"description" -> trim(label("Description", optional(text(maxlength(255))))),
|
||||
"priorityColor" -> trim(label("Color", text(required, color)))
|
||||
@@ -90,7 +86,7 @@ trait PrioritiesControllerBase extends ControllerBase {
|
||||
)
|
||||
})
|
||||
|
||||
ajaxPost("/:owner/:repository/issues/priorities/reorder")(writableUsersOnly { (repository) =>
|
||||
ajaxPost("/:owner/:repository/issues/priorities/reorder")(writableUsersOnly { repository =>
|
||||
reorderPriorities(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
@@ -104,7 +100,7 @@ trait PrioritiesControllerBase extends ControllerBase {
|
||||
Ok()
|
||||
})
|
||||
|
||||
ajaxPost("/:owner/:repository/issues/priorities/default")(writableUsersOnly { (repository) =>
|
||||
ajaxPost("/:owner/:repository/issues/priorities/default")(writableUsersOnly { repository =>
|
||||
setDefaultPriority(repository.owner, repository.name, priorityId("priorityId"))
|
||||
Ok()
|
||||
})
|
||||
@@ -122,9 +118,9 @@ trait PrioritiesControllerBase extends ControllerBase {
|
||||
private def priorityName: Constraint = new Constraint() {
|
||||
override def validate(name: String, value: String, messages: Messages): Option[String] =
|
||||
if (value.contains(',')) {
|
||||
Some(s"${name} contains invalid character.")
|
||||
Some(s"$name contains invalid character.")
|
||||
} else if (value.startsWith("_") || value.startsWith("-")) {
|
||||
Some(s"${name} starts with invalid character.")
|
||||
Some(s"$name starts with invalid character.")
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
@@ -4,14 +4,14 @@ import gitbucket.core.model.activity.DeleteBranchInfo
|
||||
import gitbucket.core.pulls.html
|
||||
import gitbucket.core.service.CommitStatusService
|
||||
import gitbucket.core.service.MergeService
|
||||
import gitbucket.core.service.IssuesService._
|
||||
import gitbucket.core.service.PullRequestService._
|
||||
import gitbucket.core.service.IssuesService.*
|
||||
import gitbucket.core.service.PullRequestService.*
|
||||
import gitbucket.core.service.RepositoryService.RepositoryInfo
|
||||
import gitbucket.core.service._
|
||||
import gitbucket.core.util.Directory._
|
||||
import gitbucket.core.util.Implicits._
|
||||
import gitbucket.core.util._
|
||||
import org.scalatra.forms._
|
||||
import gitbucket.core.service.*
|
||||
import gitbucket.core.util.Directory.*
|
||||
import gitbucket.core.util.Implicits.*
|
||||
import gitbucket.core.util.*
|
||||
import org.scalatra.forms.*
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.scalatra.BadRequest
|
||||
|
||||
@@ -40,32 +40,19 @@ class PullRequestsController
|
||||
with RequestCache
|
||||
|
||||
trait PullRequestsControllerBase extends ControllerBase {
|
||||
self: RepositoryService
|
||||
with AccountService
|
||||
with IssuesService
|
||||
with MilestonesService
|
||||
with LabelsService
|
||||
with CustomFieldsService
|
||||
with CommitsService
|
||||
with ActivityService
|
||||
with PullRequestService
|
||||
with WebHookPullRequestService
|
||||
with ReadableUsersAuthenticator
|
||||
with ReferrerAuthenticator
|
||||
with WritableUsersAuthenticator
|
||||
with CommitStatusService
|
||||
with MergeService
|
||||
with ProtectedBranchService
|
||||
with PrioritiesService =>
|
||||
self: RepositoryService & AccountService & IssuesService & MilestonesService & LabelsService & CustomFieldsService &
|
||||
CommitsService & ActivityService & PullRequestService & WebHookPullRequestService & ReadableUsersAuthenticator &
|
||||
ReferrerAuthenticator & WritableUsersAuthenticator & CommitStatusService & MergeService & ProtectedBranchService &
|
||||
PrioritiesService =>
|
||||
|
||||
val pullRequestForm = mapping(
|
||||
private val pullRequestForm = mapping(
|
||||
"title" -> trim(label("Title", text(required))),
|
||||
"content" -> trim(label("Content", optional(text()))),
|
||||
"targetUserName" -> trim(text(required, maxlength(100))),
|
||||
"targetBranch" -> trim(text(required, maxlength(100))),
|
||||
"targetBranch" -> trim(text(required, maxlength(255))),
|
||||
"requestUserName" -> trim(text(required, maxlength(100))),
|
||||
"requestRepositoryName" -> trim(text(required, maxlength(100))),
|
||||
"requestBranch" -> trim(text(required, maxlength(100))),
|
||||
"requestBranch" -> trim(text(required, maxlength(255))),
|
||||
"commitIdFrom" -> trim(text(required, maxlength(40))),
|
||||
"commitIdTo" -> trim(text(required, maxlength(40))),
|
||||
"isDraft" -> trim(boolean(required)),
|
||||
@@ -75,13 +62,13 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
"labelNames" -> trim(optional(text()))
|
||||
)(PullRequestForm.apply)
|
||||
|
||||
val mergeForm = mapping(
|
||||
private val mergeForm = mapping(
|
||||
"message" -> trim(label("Message", text(required))),
|
||||
"strategy" -> trim(label("Strategy", text(required))),
|
||||
"isDraft" -> trim(boolean(required))
|
||||
)(MergeForm.apply)
|
||||
|
||||
case class PullRequestForm(
|
||||
private case class PullRequestForm(
|
||||
title: String,
|
||||
content: Option[String],
|
||||
targetUserName: String,
|
||||
@@ -98,7 +85,7 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
labelNames: Option[String]
|
||||
)
|
||||
|
||||
case class MergeForm(message: String, strategy: String, isDraft: Boolean)
|
||||
private case class MergeForm(message: String, strategy: String, isDraft: Boolean)
|
||||
|
||||
get("/:owner/:repository/pulls")(referrersOnly { repository =>
|
||||
val q = request.getParameter("q")
|
||||
@@ -263,7 +250,7 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
(for {
|
||||
issueId <- params("id").toIntOpt
|
||||
loginAccount <- context.loginAccount
|
||||
(issue, pullreq) <- getPullRequest(baseRepository.owner, baseRepository.name, issueId)
|
||||
case (issue, pullreq) <- getPullRequest(baseRepository.owner, baseRepository.name, issueId)
|
||||
owner = pullreq.requestUserName
|
||||
name = pullreq.requestRepositoryName
|
||||
if hasDeveloperRole(owner, name, context.loginAccount)
|
||||
@@ -301,7 +288,7 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
(for {
|
||||
issueId <- params("id").toIntOpt
|
||||
loginAccount <- context.loginAccount
|
||||
(issue, pullreq) <- getPullRequest(baseRepository.owner, baseRepository.name, issueId)
|
||||
case (issue, pullreq) <- getPullRequest(baseRepository.owner, baseRepository.name, issueId)
|
||||
repository <- getRepository(pullreq.requestUserName, pullreq.requestRepositoryName)
|
||||
remoteRepository <- getRepository(pullreq.userName, pullreq.repositoryName)
|
||||
owner = pullreq.requestUserName
|
||||
@@ -312,7 +299,7 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
if (branchProtection.needStatusCheck(loginAccount.userName)) {
|
||||
flash.update("error", s"branch ${pullreq.requestBranch} is protected need status check.")
|
||||
} else {
|
||||
LockUtil.lock(s"${owner}/${name}") {
|
||||
LockUtil.lock(s"$owner/$name") {
|
||||
val alias =
|
||||
if (
|
||||
pullreq.repositoryName == pullreq.requestRepositoryName && pullreq.userName == pullreq.requestUserName
|
||||
@@ -321,27 +308,27 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
} else {
|
||||
s"${pullreq.userName}:${pullreq.branch}"
|
||||
}
|
||||
val existIds = Using
|
||||
.resource(Git.open(Directory.getRepositoryDir(owner, name))) { git =>
|
||||
JGitUtil.getAllCommitIds(git)
|
||||
}
|
||||
.toSet
|
||||
// val existIds = Using
|
||||
// .resource(Git.open(Directory.getRepositoryDir(owner, name))) { git =>
|
||||
// JGitUtil.getAllCommitIds(git)
|
||||
// }
|
||||
// .toSet
|
||||
pullRemote(
|
||||
repository,
|
||||
pullreq.requestBranch,
|
||||
remoteRepository,
|
||||
pullreq.branch,
|
||||
loginAccount,
|
||||
s"Merge branch '${alias}' into ${pullreq.requestBranch}",
|
||||
s"Merge branch '$alias' into ${pullreq.requestBranch}",
|
||||
Some(pullreq),
|
||||
context.settings
|
||||
) match {
|
||||
case None => // conflict
|
||||
flash.update("error", s"Can't automatic merging branch '${alias}' into ${pullreq.requestBranch}.")
|
||||
flash.update("error", s"Can't automatic merging branch '$alias' into ${pullreq.requestBranch}.")
|
||||
case Some(oldId) =>
|
||||
// update pull request
|
||||
updatePullRequests(owner, name, pullreq.requestBranch, loginAccount, "synchronize", context.settings)
|
||||
flash.update("info", s"Merge branch '${alias}' into ${pullreq.requestBranch}")
|
||||
flash.update("info", s"Merge branch '$alias' into ${pullreq.requestBranch}")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -353,7 +340,7 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
post("/:owner/:repository/pull/:id/update_draft")(readableUsersOnly { baseRepository =>
|
||||
(for {
|
||||
issueId <- params("id").toIntOpt
|
||||
(_, pullreq) <- getPullRequest(baseRepository.owner, baseRepository.name, issueId)
|
||||
case (_, pullreq) <- getPullRequest(baseRepository.owner, baseRepository.name, issueId)
|
||||
owner = pullreq.requestUserName
|
||||
name = pullreq.requestRepositoryName
|
||||
if hasDeveloperRole(owner, name, context.loginAccount)
|
||||
@@ -374,7 +361,7 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
form.isDraft,
|
||||
context.settings
|
||||
) match {
|
||||
case Right(objectId) => redirect(s"/${repository.owner}/${repository.name}/pull/${issueId}")
|
||||
case Right(objectId) => redirect(s"/${repository.owner}/${repository.name}/pull/$issueId")
|
||||
case Left(message) => Some(BadRequest(message))
|
||||
}
|
||||
} getOrElse NotFound()
|
||||
@@ -396,7 +383,7 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
.getOrElse(JGitUtil.getDefaultBranch(oldGit, originRepository).get._2)
|
||||
|
||||
redirect(
|
||||
s"/${forkedRepository.owner}/${forkedRepository.name}/compare/${originUserName}:${oldBranch}...${newBranch}"
|
||||
s"/${forkedRepository.owner}/${forkedRepository.name}/compare/$originUserName:$oldBranch...$newBranch"
|
||||
)
|
||||
}
|
||||
} getOrElse NotFound()
|
||||
@@ -404,7 +391,7 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
Using.resource(Git.open(getRepositoryDir(forkedRepository.owner, forkedRepository.name))) { git =>
|
||||
JGitUtil.getDefaultBranch(git, forkedRepository).map { case (_, defaultBranch) =>
|
||||
redirect(
|
||||
s"/${forkedRepository.owner}/${forkedRepository.name}/compare/${defaultBranch}...${headBranch.getOrElse(defaultBranch)}"
|
||||
s"/${forkedRepository.owner}/${forkedRepository.name}/compare/$defaultBranch...${headBranch.getOrElse(defaultBranch)}"
|
||||
)
|
||||
} getOrElse {
|
||||
redirect(s"/${forkedRepository.owner}/${forkedRepository.name}")
|
||||
@@ -426,7 +413,7 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
getForkedRepositories(forkedRepository.owner, forkedRepository.name)
|
||||
.find(_.userName == originOwner)
|
||||
.map(_.repositoryName)
|
||||
} else if (Some(originOwner) == forkedRepository.repository.originUserName) {
|
||||
} else if (forkedRepository.repository.originUserName.contains(originOwner)) {
|
||||
// Original repository
|
||||
forkedRepository.repository.originRepositoryName
|
||||
} else {
|
||||
@@ -487,7 +474,9 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
(repository.userName, repository.repositoryName, repository.defaultBranch)
|
||||
},
|
||||
commits.flatten
|
||||
.flatMap(commit => getCommitComments(forkedRepository.owner, forkedRepository.name, commit.id, false))
|
||||
.flatMap(commit =>
|
||||
getCommitComments(forkedRepository.owner, forkedRepository.name, commit.id, includePullRequest = false)
|
||||
)
|
||||
.toList,
|
||||
originId,
|
||||
forkedId,
|
||||
@@ -508,8 +497,8 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
case (oldId, newId) =>
|
||||
redirect(
|
||||
s"/${forkedRepository.owner}/${forkedRepository.name}/compare/" +
|
||||
s"${originOwner}:${oldId.map(_ => originId).getOrElse(originRepository.repository.defaultBranch)}..." +
|
||||
s"${forkedOwner}:${newId.map(_ => forkedId).getOrElse(forkedRepository.repository.defaultBranch)}"
|
||||
s"$originOwner:${oldId.map(_ => originId).getOrElse(originRepository.repository.defaultBranch)}..." +
|
||||
s"$forkedOwner:${newId.map(_ => forkedId).getOrElse(forkedRepository.repository.defaultBranch)}"
|
||||
)
|
||||
|
||||
}
|
||||
@@ -569,7 +558,7 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
val (originOwner, tmpOriginBranch) = parseCompareIdentifier(origin, forkedRepository.owner)
|
||||
val (forkedOwner, tmpForkedBranch) = parseCompareIdentifier(forked, forkedRepository.owner)
|
||||
|
||||
(for (
|
||||
(for {
|
||||
originRepositoryName <-
|
||||
if (originOwner == forkedOwner) {
|
||||
Some(forkedRepository.name)
|
||||
@@ -579,9 +568,9 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
.find(_.userName == originOwner)
|
||||
.map(_.repositoryName)
|
||||
}
|
||||
};
|
||||
}
|
||||
originRepository <- getRepository(originOwner, originRepositoryName)
|
||||
) yield {
|
||||
} yield {
|
||||
Using.resources(
|
||||
Git.open(getRepositoryDir(originRepository.owner, originRepository.name)),
|
||||
Git.open(getRepositoryDir(forkedRepository.owner, forkedRepository.name))
|
||||
@@ -650,7 +639,7 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
}
|
||||
}
|
||||
|
||||
redirect(s"/${repository.owner}/${repository.name}/pull/${issueId}")
|
||||
redirect(s"/${repository.owner}/${repository.name}/pull/$issueId")
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -11,10 +11,10 @@ import gitbucket.core.service.{
|
||||
RepositoryService,
|
||||
RequestCache
|
||||
}
|
||||
import gitbucket.core.util._
|
||||
import gitbucket.core.util.Directory._
|
||||
import gitbucket.core.util.Implicits._
|
||||
import org.scalatra.forms._
|
||||
import gitbucket.core.util.*
|
||||
import gitbucket.core.util.Directory.*
|
||||
import gitbucket.core.util.Implicits.*
|
||||
import org.scalatra.forms.*
|
||||
import gitbucket.core.releases.html
|
||||
import org.apache.commons.io.FileUtils
|
||||
import org.eclipse.jgit.api.Git
|
||||
@@ -33,20 +33,15 @@ class ReleaseController
|
||||
with RequestCache
|
||||
|
||||
trait ReleaseControllerBase extends ControllerBase {
|
||||
self: RepositoryService
|
||||
with AccountService
|
||||
with ReleaseService
|
||||
with ReadableUsersAuthenticator
|
||||
with ReferrerAuthenticator
|
||||
with WritableUsersAuthenticator
|
||||
with ActivityService =>
|
||||
self: RepositoryService & AccountService & ReleaseService & ReadableUsersAuthenticator & ReferrerAuthenticator &
|
||||
WritableUsersAuthenticator & ActivityService =>
|
||||
|
||||
case class ReleaseForm(
|
||||
private case class ReleaseForm(
|
||||
name: String,
|
||||
content: Option[String]
|
||||
)
|
||||
|
||||
val releaseForm = mapping(
|
||||
private val releaseForm = mapping(
|
||||
"name" -> trim(text(required)),
|
||||
"content" -> trim(optional(text()))
|
||||
)(ReleaseForm.apply)
|
||||
@@ -130,16 +125,15 @@ trait ReleaseControllerBase extends ControllerBase {
|
||||
val releaseInfo = ReleaseInfo(repository.owner, repository.name, loginAccount.userName, form.name, tagName)
|
||||
recordActivity(releaseInfo)
|
||||
|
||||
redirect(s"/${repository.owner}/${repository.name}/releases/${tagName}")
|
||||
redirect(s"/${repository.owner}/${repository.name}/releases/$tagName")
|
||||
}
|
||||
})
|
||||
|
||||
get("/:owner/:repository/changelog/*...*")(writableUsersOnly { repository =>
|
||||
val Seq(previousTag, currentTag) = multiParams("splat")
|
||||
val previousTagId = repository.tags.collectFirst { case x if x.name == previousTag => x.commitId }.getOrElse("")
|
||||
|
||||
val commitLog = Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
|
||||
val commits = JGitUtil.getCommitLog(git, previousTagId, currentTag).reverse
|
||||
val Seq(previousTag, currentTag) = multiParams("splat")
|
||||
|
||||
val commits = JGitUtil.getCommitLog(git, previousTag, currentTag).reverse
|
||||
commits
|
||||
.map { commit =>
|
||||
s"- ${commit.shortMessage} ${commit.id}"
|
||||
@@ -205,7 +199,7 @@ trait ReleaseControllerBase extends ControllerBase {
|
||||
}
|
||||
}
|
||||
|
||||
redirect(s"/${release.userName}/${release.repositoryName}/releases/${tagName}")
|
||||
redirect(s"/${release.userName}/${release.repositoryName}/releases/$tagName")
|
||||
}
|
||||
.getOrElse(NotFound())
|
||||
}
|
||||
@@ -223,7 +217,7 @@ trait ReleaseControllerBase extends ControllerBase {
|
||||
})
|
||||
|
||||
private def fetchReleases(repository: RepositoryService.RepositoryInfo, page: Int) = {
|
||||
import gitbucket.core.service.ReleaseService._
|
||||
import gitbucket.core.service.ReleaseService.*
|
||||
|
||||
val (offset, limit) = ((page - 1) * ReleaseLimit, ReleaseLimit)
|
||||
val tagsToDisplay = repository.tags.reverse.slice(offset, offset + limit)
|
||||
|
||||
@@ -4,16 +4,16 @@ import java.time.{LocalDateTime, ZoneOffset}
|
||||
import java.util.Date
|
||||
import gitbucket.core.settings.html
|
||||
import gitbucket.core.model.{RepositoryWebHook, WebHook}
|
||||
import gitbucket.core.service._
|
||||
import gitbucket.core.service.WebHookService._
|
||||
import gitbucket.core.util._
|
||||
import gitbucket.core.util.JGitUtil._
|
||||
import gitbucket.core.util.SyntaxSugars._
|
||||
import gitbucket.core.util.Implicits._
|
||||
import gitbucket.core.util.Directory._
|
||||
import gitbucket.core.service.*
|
||||
import gitbucket.core.service.WebHookService.*
|
||||
import gitbucket.core.util.*
|
||||
import gitbucket.core.util.JGitUtil.*
|
||||
import gitbucket.core.util.SyntaxSugars.*
|
||||
import gitbucket.core.util.Implicits.*
|
||||
import gitbucket.core.util.Directory.*
|
||||
import gitbucket.core.model.WebHookContentType
|
||||
import gitbucket.core.model.activity.RenameRepositoryInfo
|
||||
import org.scalatra.forms._
|
||||
import org.scalatra.forms.*
|
||||
import org.scalatra.i18n.Messages
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.eclipse.jgit.lib.Constants
|
||||
@@ -37,19 +37,11 @@ class RepositorySettingsController
|
||||
with RequestCache
|
||||
|
||||
trait RepositorySettingsControllerBase extends ControllerBase {
|
||||
self: RepositoryService
|
||||
with AccountService
|
||||
with WebHookService
|
||||
with ProtectedBranchService
|
||||
with CommitStatusService
|
||||
with DeployKeyService
|
||||
with CustomFieldsService
|
||||
with ActivityService
|
||||
with OwnerAuthenticator
|
||||
with UsersAuthenticator =>
|
||||
self: RepositoryService & AccountService & WebHookService & ProtectedBranchService & CommitStatusService &
|
||||
DeployKeyService & CustomFieldsService & ActivityService & OwnerAuthenticator & UsersAuthenticator =>
|
||||
|
||||
// for repository options
|
||||
case class OptionsForm(
|
||||
private case class OptionsForm(
|
||||
description: Option[String],
|
||||
isPrivate: Boolean,
|
||||
issuesOption: String,
|
||||
@@ -62,7 +54,7 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
||||
safeMode: Boolean
|
||||
)
|
||||
|
||||
val optionsForm = mapping(
|
||||
private val optionsForm = mapping(
|
||||
"description" -> trim(label("Description", optional(text()))),
|
||||
"isPrivate" -> trim(label("Repository Type", boolean())),
|
||||
"issuesOption" -> trim(label("Issues Option", text(required, featureOption))),
|
||||
@@ -80,25 +72,30 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
||||
}
|
||||
|
||||
// for default branch
|
||||
case class DefaultBranchForm(defaultBranch: String)
|
||||
private case class DefaultBranchForm(defaultBranch: String)
|
||||
|
||||
val defaultBranchForm = mapping(
|
||||
private val defaultBranchForm = mapping(
|
||||
"defaultBranch" -> trim(label("Default Branch", text(required, maxlength(100))))
|
||||
)(DefaultBranchForm.apply)
|
||||
|
||||
// for deploy key
|
||||
case class DeployKeyForm(title: String, publicKey: String, allowWrite: Boolean)
|
||||
private case class DeployKeyForm(title: String, publicKey: String, allowWrite: Boolean)
|
||||
|
||||
val deployKeyForm = mapping(
|
||||
private val deployKeyForm = mapping(
|
||||
"title" -> trim(label("Title", text(required, maxlength(100)))),
|
||||
"publicKey" -> trim2(label("Key", text(required))), // TODO duplication check in the repository?
|
||||
"allowWrite" -> trim(label("Key", boolean()))
|
||||
)(DeployKeyForm.apply)
|
||||
|
||||
// for web hook url addition
|
||||
case class WebHookForm(url: String, events: Set[WebHook.Event], ctype: WebHookContentType, token: Option[String])
|
||||
private case class WebHookForm(
|
||||
url: String,
|
||||
events: Set[WebHook.Event],
|
||||
ctype: WebHookContentType,
|
||||
token: Option[String]
|
||||
)
|
||||
|
||||
def webHookForm(update: Boolean) =
|
||||
private def webHookForm(update: Boolean) =
|
||||
mapping(
|
||||
"url" -> trim(label("url", text(required, webHook(update)))),
|
||||
"events" -> webhookEvents,
|
||||
@@ -107,23 +104,23 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
||||
)((url, events, ctype, token) => WebHookForm(url, events, WebHookContentType.valueOf(ctype), token))
|
||||
|
||||
// for rename repository
|
||||
case class RenameRepositoryForm(repositoryName: String)
|
||||
private case class RenameRepositoryForm(repositoryName: String)
|
||||
|
||||
val renameForm = mapping(
|
||||
private val renameForm = mapping(
|
||||
"repositoryName" -> trim(
|
||||
label("New repository name", text(required, maxlength(100), repository, renameRepositoryName))
|
||||
)
|
||||
)(RenameRepositoryForm.apply)
|
||||
|
||||
// for transfer ownership
|
||||
case class TransferOwnerShipForm(newOwner: String)
|
||||
private case class TransferOwnerShipForm(newOwner: String)
|
||||
|
||||
val transferForm = mapping(
|
||||
private val transferForm = mapping(
|
||||
"newOwner" -> trim(label("New owner", text(required, transferUser)))
|
||||
)(TransferOwnerShipForm.apply)
|
||||
|
||||
// for custom field
|
||||
case class CustomFieldForm(
|
||||
private case class CustomFieldForm(
|
||||
fieldName: String,
|
||||
fieldType: String,
|
||||
constraints: Option[String],
|
||||
@@ -131,7 +128,7 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
||||
enableForPullRequests: Boolean
|
||||
)
|
||||
|
||||
val customFieldForm = mapping(
|
||||
private val customFieldForm = mapping(
|
||||
"fieldName" -> trim(label("Field name", text(required, maxlength(100)))),
|
||||
"fieldType" -> trim(label("Field type", text(required))),
|
||||
"constraints" -> trim(label("Constraints", optional(text()))),
|
||||
@@ -186,7 +183,7 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
||||
/** Update default branch */
|
||||
post("/:owner/:repository/settings/update_default_branch", defaultBranchForm)(ownerOnly { (form, repository) =>
|
||||
if (!repository.branchList.contains(form.defaultBranch)) {
|
||||
redirect(s"/${repository.owner}/${repository.name}/settings/options")
|
||||
redirect(s"/${repository.owner}/${repository.name}/settings/branches")
|
||||
} else {
|
||||
saveRepositoryDefaultBranch(repository.owner, repository.name, form.defaultBranch)
|
||||
// Change repository HEAD
|
||||
@@ -200,7 +197,7 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
||||
|
||||
/** Branch protection for branch */
|
||||
get("/:owner/:repository/settings/branches/*")(ownerOnly { repository =>
|
||||
import gitbucket.core.api._
|
||||
import gitbucket.core.api.*
|
||||
val branch = params("splat")
|
||||
|
||||
if (!repository.branchList.contains(branch)) {
|
||||
@@ -256,7 +253,7 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
||||
ctype = WebHookContentType.FORM,
|
||||
token = None
|
||||
)
|
||||
html.edithook(webhook, Set(WebHook.Push), repository, true)
|
||||
html.edithook(webhook, Set(WebHook.Push), repository, create = true)
|
||||
})
|
||||
|
||||
/**
|
||||
@@ -287,9 +284,9 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
||||
}
|
||||
|
||||
Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent._
|
||||
import scala.jdk.CollectionConverters._
|
||||
import scala.concurrent.duration.*
|
||||
import scala.concurrent.*
|
||||
import scala.jdk.CollectionConverters.*
|
||||
import scala.util.control.NonFatal
|
||||
import org.apache.http.util.EntityUtils
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
@@ -335,10 +332,10 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
||||
callWebHook(WebHook.Push, List(dummyWebHookInfo), dummyPayload, context.settings).head
|
||||
|
||||
val toErrorMap: PartialFunction[Throwable, Map[String, String]] = {
|
||||
case e: java.net.UnknownHostException => Map("error" -> ("Unknown host " + e.getMessage))
|
||||
case e: java.lang.IllegalArgumentException => Map("error" -> ("invalid url"))
|
||||
case e: org.apache.http.client.ClientProtocolException => Map("error" -> ("invalid url"))
|
||||
case NonFatal(e) => Map("error" -> (s"${e.getClass} ${e.getMessage}"))
|
||||
case e: java.net.UnknownHostException => Map("error" -> s"Unknown host ${e.getMessage}")
|
||||
case _: java.lang.IllegalArgumentException => Map("error" -> "invalid url")
|
||||
case _: org.apache.http.client.ClientProtocolException => Map("error" -> "invalid url")
|
||||
case NonFatal(e) => Map("error" -> s"${e.getClass} ${e.getMessage}")
|
||||
}
|
||||
|
||||
contentType = formats("json")
|
||||
@@ -361,8 +358,8 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
||||
.map(res =>
|
||||
Map(
|
||||
"status" -> res.getStatusLine.getStatusCode,
|
||||
"body" -> EntityUtils.toString(res.getEntity()),
|
||||
"headers" -> _headers(res.getAllHeaders())
|
||||
"body" -> EntityUtils.toString(res.getEntity),
|
||||
"headers" -> _headers(res.getAllHeaders)
|
||||
)
|
||||
)
|
||||
.recover(toErrorMap),
|
||||
@@ -378,7 +375,7 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
||||
*/
|
||||
get("/:owner/:repository/settings/hooks/edit")(ownerOnly { repository =>
|
||||
getWebHook(repository.owner, repository.name, params("url")).map { case (webhook, events) =>
|
||||
html.edithook(webhook, events, repository, false)
|
||||
html.edithook(webhook, events, repository, create = false)
|
||||
} getOrElse NotFound()
|
||||
})
|
||||
|
||||
@@ -631,7 +628,7 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
||||
new Constraint() {
|
||||
override def validate(name: String, value: String, messages: Messages): Option[String] =
|
||||
getAccountByUserName(value) match {
|
||||
case None => Some("User does not exist.")
|
||||
case None => Some("User does not exist.")
|
||||
case Some(x) =>
|
||||
if (x.userName == params("owner")) {
|
||||
Some("This is current repository owner.")
|
||||
|
||||
@@ -6,12 +6,12 @@ import javax.servlet.http.{HttpServletRequest, HttpServletResponse}
|
||||
import gitbucket.core.repo.html
|
||||
import gitbucket.core.helper
|
||||
import gitbucket.core.model.activity.DeleteBranchInfo
|
||||
import gitbucket.core.service._
|
||||
import gitbucket.core.service.*
|
||||
import gitbucket.core.service.RepositoryCommitFileService.CommitFile
|
||||
import gitbucket.core.util._
|
||||
import gitbucket.core.util.StringUtil._
|
||||
import gitbucket.core.util.Implicits._
|
||||
import gitbucket.core.util.Directory._
|
||||
import gitbucket.core.util.*
|
||||
import gitbucket.core.util.StringUtil.*
|
||||
import gitbucket.core.util.Implicits.*
|
||||
import gitbucket.core.util.Directory.*
|
||||
import gitbucket.core.model.{Account, WebHook}
|
||||
import gitbucket.core.service.RepositoryService.RepositoryInfo
|
||||
import gitbucket.core.service.WebHookService.{WebHookCreatePayload, WebHookPushPayload}
|
||||
@@ -25,11 +25,11 @@ import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream
|
||||
import org.apache.commons.compress.compressors.xz.XZCompressorOutputStream
|
||||
import org.apache.commons.compress.utils.IOUtils
|
||||
import org.apache.commons.io.FileUtils
|
||||
import org.scalatra.forms._
|
||||
import org.scalatra.forms.*
|
||||
import org.eclipse.jgit.api.{ArchiveCommand, Git}
|
||||
import org.eclipse.jgit.archive.{TgzFormat, ZipFormat}
|
||||
import org.eclipse.jgit.errors.MissingObjectException
|
||||
import org.eclipse.jgit.lib._
|
||||
import org.eclipse.jgit.lib.*
|
||||
import org.eclipse.jgit.treewalk.{TreeWalk, WorkingTreeOptions}
|
||||
import org.eclipse.jgit.treewalk.TreeWalk.OperationType
|
||||
import org.eclipse.jgit.treewalk.filter.PathFilter
|
||||
@@ -65,26 +65,15 @@ class RepositoryViewerController
|
||||
* The repository viewer.
|
||||
*/
|
||||
trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
self: RepositoryService
|
||||
with RepositoryCommitFileService
|
||||
with AccountService
|
||||
with ActivityService
|
||||
with IssuesService
|
||||
with WebHookService
|
||||
with CommitsService
|
||||
with ReadableUsersAuthenticator
|
||||
with ReferrerAuthenticator
|
||||
with WritableUsersAuthenticator
|
||||
with PullRequestService
|
||||
with CommitStatusService
|
||||
with WebHookPullRequestService
|
||||
with WebHookPullRequestReviewCommentService
|
||||
with ProtectedBranchService =>
|
||||
self: RepositoryService & RepositoryCommitFileService & AccountService & ActivityService & IssuesService &
|
||||
WebHookService & CommitsService & ReadableUsersAuthenticator & ReferrerAuthenticator & WritableUsersAuthenticator &
|
||||
PullRequestService & CommitStatusService & WebHookPullRequestService & WebHookPullRequestReviewCommentService &
|
||||
ProtectedBranchService =>
|
||||
|
||||
ArchiveCommand.registerFormat("zip", new ZipFormat)
|
||||
ArchiveCommand.registerFormat("tar.gz", new TgzFormat)
|
||||
|
||||
case class UploadForm(
|
||||
private case class UploadForm(
|
||||
branch: String,
|
||||
path: String,
|
||||
uploadFiles: String,
|
||||
@@ -93,7 +82,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
newBranch: Boolean
|
||||
)
|
||||
|
||||
case class EditorForm(
|
||||
private case class EditorForm(
|
||||
branch: String,
|
||||
path: String,
|
||||
content: String,
|
||||
@@ -106,7 +95,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
newBranch: Boolean
|
||||
)
|
||||
|
||||
case class DeleteForm(
|
||||
private case class DeleteForm(
|
||||
branch: String,
|
||||
path: String,
|
||||
message: Option[String],
|
||||
@@ -115,7 +104,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
newBranch: Boolean
|
||||
)
|
||||
|
||||
case class CommentForm(
|
||||
private case class CommentForm(
|
||||
fileName: Option[String],
|
||||
oldLineNumber: Option[Int],
|
||||
newLineNumber: Option[Int],
|
||||
@@ -124,13 +113,13 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
diff: Option[String]
|
||||
)
|
||||
|
||||
case class TagForm(
|
||||
private case class TagForm(
|
||||
commitId: String,
|
||||
tagName: String,
|
||||
message: Option[String]
|
||||
)
|
||||
|
||||
val uploadForm = mapping(
|
||||
private val uploadForm = mapping(
|
||||
"branch" -> trim(label("Branch", text(required))),
|
||||
"path" -> trim(label("Path", text())),
|
||||
"uploadFiles" -> trim(label("Upload files", text(required))),
|
||||
@@ -139,7 +128,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
"newBranch" -> trim(label("New Branch", boolean()))
|
||||
)(UploadForm.apply)
|
||||
|
||||
val editorForm = mapping(
|
||||
private val editorForm = mapping(
|
||||
"branch" -> trim(label("Branch", text(required))),
|
||||
"path" -> trim(label("Path", text())),
|
||||
"content" -> trim(label("Content", text(required))),
|
||||
@@ -152,7 +141,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
"newBranch" -> trim(label("New Branch", boolean()))
|
||||
)(EditorForm.apply)
|
||||
|
||||
val deleteForm = mapping(
|
||||
private val deleteForm = mapping(
|
||||
"branch" -> trim(label("Branch", text(required))),
|
||||
"path" -> trim(label("Path", text())),
|
||||
"message" -> trim(label("Message", optional(text()))),
|
||||
@@ -161,7 +150,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
"newBranch" -> trim(label("New Branch", boolean()))
|
||||
)(DeleteForm.apply)
|
||||
|
||||
val commentForm = mapping(
|
||||
private val commentForm = mapping(
|
||||
"fileName" -> trim(label("Filename", optional(text()))),
|
||||
"oldLineNumber" -> trim(label("Old line number", optional(number()))),
|
||||
"newLineNumber" -> trim(label("New line number", optional(number()))),
|
||||
@@ -170,7 +159,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
"diff" -> optional(text())
|
||||
)(CommentForm.apply)
|
||||
|
||||
val tagForm = mapping(
|
||||
private val tagForm = mapping(
|
||||
"commitId" -> trim(label("Commit id", text(required))),
|
||||
"tagName" -> trim(label("Tag name", text(required))),
|
||||
"message" -> trim(label("Message", optional(text())))
|
||||
@@ -296,7 +285,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
html.editor(
|
||||
branch = branch,
|
||||
repository = repository,
|
||||
pathList = if (path.length == 0) Nil else path.split("/").toList,
|
||||
pathList = if (path.isEmpty) Nil else path.split("/").toList,
|
||||
fileName = None,
|
||||
content = JGitUtil.ContentInfo("text", None, None, Some("UTF-8")),
|
||||
protectedBranch = protectedBranch,
|
||||
@@ -316,7 +305,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
html.upload(
|
||||
branch,
|
||||
repository,
|
||||
if (path.length == 0) Nil else path.split("/").toList,
|
||||
if (path.isEmpty) Nil else path.split("/").toList,
|
||||
protectedBranch,
|
||||
revCommit.name
|
||||
)
|
||||
@@ -364,7 +353,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
.toSeq
|
||||
|
||||
val newFiles = files.map { file =>
|
||||
file.copy(name = if (form.path.length == 0) file.name else s"${form.path}/${file.name}")
|
||||
file.copy(name = if (form.path.isEmpty) file.name else s"${form.path}/${file.name}")
|
||||
}
|
||||
|
||||
if (form.newBranch) {
|
||||
@@ -381,13 +370,13 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
form.message,
|
||||
loginAccount
|
||||
)
|
||||
redirect(s"/${repository.owner}/${repository.name}/pull/${issueId}")
|
||||
redirect(s"/${repository.owner}/${repository.name}/pull/$issueId")
|
||||
case Left(error) => Forbidden(gitbucket.core.html.error(error))
|
||||
}
|
||||
} else {
|
||||
_commit(form.branch, newFiles, loginAccount) match {
|
||||
case Right(_) =>
|
||||
if (form.path.length == 0) {
|
||||
if (form.path.isEmpty) {
|
||||
redirect(s"/${repository.owner}/${repository.name}/tree/${encodeRefName(form.branch)}")
|
||||
} else {
|
||||
redirect(
|
||||
@@ -482,13 +471,13 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
form.message,
|
||||
loginAccount
|
||||
)
|
||||
redirect(s"/${repository.owner}/${repository.name}/pull/${issueId}")
|
||||
redirect(s"/${repository.owner}/${repository.name}/pull/$issueId")
|
||||
case Left(error) => Forbidden(gitbucket.core.html.error(error))
|
||||
}
|
||||
} else {
|
||||
_commit(form.branch, loginAccount) match {
|
||||
case Right(_) =>
|
||||
if (form.path.length == 0) {
|
||||
if (form.path.isEmpty) {
|
||||
redirect(
|
||||
s"/${repository.owner}/${repository.name}/blob/${encodeRefName(form.branch)}/${urlEncode(form.newFileName)}"
|
||||
)
|
||||
@@ -539,13 +528,13 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
form.message,
|
||||
loginAccount
|
||||
)
|
||||
redirect(s"/${repository.owner}/${repository.name}/pull/${issueId}")
|
||||
redirect(s"/${repository.owner}/${repository.name}/pull/$issueId")
|
||||
case Left(error) => Forbidden(gitbucket.core.html.error(error))
|
||||
}
|
||||
} else {
|
||||
_commit(form.branch, loginAccount) match {
|
||||
case Right(_) =>
|
||||
if (form.path.length == 0) {
|
||||
if (form.path.isEmpty) {
|
||||
redirect(
|
||||
s"/${repository.owner}/${repository.name}/blob/${encodeRefName(form.branch)}/${urlEncode(form.newFileName)}"
|
||||
)
|
||||
@@ -592,7 +581,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
form.message,
|
||||
loginAccount
|
||||
)
|
||||
redirect(s"/${repository.owner}/${repository.name}/pull/${issueId}")
|
||||
redirect(s"/${repository.owner}/${repository.name}/pull/$issueId")
|
||||
case Left(error) => Forbidden(gitbucket.core.html.error(error))
|
||||
}
|
||||
} else {
|
||||
@@ -640,7 +629,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
sender,
|
||||
repository,
|
||||
owner,
|
||||
ref = newBranchName,
|
||||
ref = s"refs/heads/$newBranchName",
|
||||
refType = "branch"
|
||||
)
|
||||
}
|
||||
@@ -697,7 +686,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
/**
|
||||
* Displays the file content of the specified branch or commit.
|
||||
*/
|
||||
val blobRoute = get("/:owner/:repository/blob/*")(referrersOnly { repository =>
|
||||
private val blobRoute = get("/:owner/:repository/blob/*")(referrersOnly { repository =>
|
||||
val (id, path) = repository.splitPath(multiParams("splat").head)
|
||||
val raw = params.get("raw").getOrElse("false").toBoolean
|
||||
val highlighterTheme = getSyntaxHighlighterTheme()
|
||||
@@ -803,7 +792,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
JGitUtil.getBranchesOfCommit(git, revCommit.getName),
|
||||
JGitUtil.getTagsOfCommit(git, revCommit.getName),
|
||||
getCommitStatusWithSummary(repository.owner, repository.name, revCommit.getName),
|
||||
getCommitComments(repository.owner, repository.name, id, true),
|
||||
getCommitComments(repository.owner, repository.name, id, includePullRequest = true),
|
||||
repository,
|
||||
diffs,
|
||||
oldCommitId,
|
||||
@@ -813,7 +802,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
)
|
||||
}
|
||||
} catch {
|
||||
case e: MissingObjectException => NotFound()
|
||||
case _: MissingObjectException => NotFound()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -825,7 +814,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
diff
|
||||
}
|
||||
} catch {
|
||||
case e: MissingObjectException => NotFound()
|
||||
case _: MissingObjectException => NotFound()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -838,7 +827,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
diff
|
||||
}
|
||||
} catch {
|
||||
case e: MissingObjectException => NotFound()
|
||||
case _: MissingObjectException => NotFound()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -857,7 +846,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
form.issueId
|
||||
)
|
||||
|
||||
redirect(s"/${repository.owner}/${repository.name}/commit/${id}")
|
||||
redirect(s"/${repository.owner}/${repository.name}/commit/$id")
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1017,7 +1006,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
case Right(message) =>
|
||||
flash.update("info", message)
|
||||
val settings = loadSystemSettings()
|
||||
val newCommitId = git.getRepository.resolve(s"refs/heads/${newBranchName}")
|
||||
val newCommitId = git.getRepository.resolve(s"refs/heads/$newBranchName")
|
||||
val oldCommitId = ObjectId.fromString("0" * 40)
|
||||
// call push webhook
|
||||
callWebHookOf(repository.owner, repository.name, WebHook.Push, settings) {
|
||||
@@ -1028,7 +1017,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
WebHookPushPayload(
|
||||
git,
|
||||
pusherAccount,
|
||||
newBranchName,
|
||||
s"refs/heads/$newBranchName",
|
||||
repository,
|
||||
List(),
|
||||
ownerAccount,
|
||||
@@ -1047,7 +1036,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
sender,
|
||||
repository,
|
||||
owner,
|
||||
ref = newBranchName,
|
||||
ref = s"refs/heads/$newBranchName",
|
||||
refType = "branch"
|
||||
)
|
||||
}
|
||||
@@ -1057,7 +1046,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
)
|
||||
case Left(message) =>
|
||||
flash.update("error", message)
|
||||
redirect(s"/${repository.owner}/${repository.name}/tree/${fromBranchName}")
|
||||
redirect(s"/${repository.owner}/${repository.name}/tree/$fromBranchName")
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -1143,9 +1132,9 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
}
|
||||
})
|
||||
|
||||
case class UploadFiles(branch: String, path: String, fileIds: Map[String, String], message: String) {
|
||||
lazy val isValid: Boolean = fileIds.nonEmpty
|
||||
}
|
||||
// case class UploadFiles(branch: String, path: String, fileIds: Map[String, String], message: String) {
|
||||
// lazy val isValid: Boolean = fileIds.nonEmpty
|
||||
// }
|
||||
|
||||
/**
|
||||
* Provides HTML of the file list.
|
||||
@@ -1185,7 +1174,11 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
val path = (file.name :: parentPath.reverse).reverse
|
||||
path -> StringUtil.convertFromByteArray(
|
||||
JGitUtil
|
||||
.getContentFromId(Git.open(getRepositoryDir(repository.owner, repository.name)), file.id, true)
|
||||
.getContentFromId(
|
||||
Git.open(getRepositoryDir(repository.owner, repository.name)),
|
||||
file.id,
|
||||
fetchLargeFile = true
|
||||
)
|
||||
.get
|
||||
)
|
||||
}
|
||||
@@ -1226,7 +1219,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
val oid = git.getRepository.resolve(revision)
|
||||
val commit = JGitUtil.getRevCommitFromId(git, oid)
|
||||
val date = commit.getCommitterIdent.getWhen
|
||||
val sha1 = oid.getName()
|
||||
val sha1 = oid.getName
|
||||
val repositorySuffix = (if (sha1.startsWith(revision)) sha1 else revision).replace('/', '-')
|
||||
val pathSuffix = if (path.isEmpty) "" else s"-${path.replace('/', '-')}"
|
||||
val baseName = repository.name + "-" + repositorySuffix + pathSuffix
|
||||
@@ -1234,7 +1227,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
Using.resource(new TreeWalk(git.getRepository)) { treeWalk =>
|
||||
treeWalk.addTree(commit.getTree)
|
||||
treeWalk.setRecursive(true)
|
||||
if (!path.isEmpty) {
|
||||
if (path.nonEmpty) {
|
||||
treeWalk.setFilter(PathFilter.create(path))
|
||||
}
|
||||
if (treeWalk != null) {
|
||||
@@ -1278,7 +1271,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
}
|
||||
|
||||
val suffix =
|
||||
path.split("/").lastOption.collect { case x if x.length > 0 => "-" + x.replace('/', '_') }.getOrElse("")
|
||||
path.split("/").lastOption.collect { case x if x.nonEmpty => "-" + x.replace('/', '_') }.getOrElse("")
|
||||
val zipRe = """(.+)\.zip$""".r
|
||||
val tarRe = """(.+)\.tar\.(gz|bz2|xz)$""".r
|
||||
|
||||
@@ -1286,7 +1279,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
case zipRe(revision) =>
|
||||
response.setHeader(
|
||||
"Content-Disposition",
|
||||
s"attachment; filename=${repository.name}-${revision}${suffix}.zip"
|
||||
s"attachment; filename=${repository.name}-$revision$suffix.zip"
|
||||
)
|
||||
contentType = "application/octet-stream"
|
||||
response.setBufferSize(1024 * 1024)
|
||||
@@ -1303,7 +1296,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
case tarRe(revision, compressor) =>
|
||||
response.setHeader(
|
||||
"Content-Disposition",
|
||||
s"attachment; filename=${repository.name}-${revision}${suffix}.tar.${compressor}"
|
||||
s"attachment; filename=${repository.name}-$revision$suffix.tar.$compressor"
|
||||
)
|
||||
contentType = "application/octet-stream"
|
||||
response.setBufferSize(1024 * 1024)
|
||||
@@ -1341,9 +1334,9 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
val repository = params("repository")
|
||||
val branch = params("branch")
|
||||
|
||||
LockUtil.lock(s"${owner}/${repository}") {
|
||||
LockUtil.lock(s"$owner/$repository") {
|
||||
Using.resource(Git.open(getRepositoryDir(owner, repository))) { git =>
|
||||
val headName = s"refs/heads/${branch}"
|
||||
val headName = s"refs/heads/$branch"
|
||||
val headTip = git.getRepository.resolve(headName)
|
||||
if (headTip.getName != value) {
|
||||
Some("Someone pushed new commits before you. Please reload this page and re-apply your changes.")
|
||||
|
||||
@@ -3,17 +3,17 @@ package gitbucket.core.controller
|
||||
import java.io.FileInputStream
|
||||
import gitbucket.core.admin.html
|
||||
import gitbucket.core.plugin.PluginRegistry
|
||||
import gitbucket.core.service.SystemSettingsService._
|
||||
import gitbucket.core.service.SystemSettingsService.*
|
||||
import gitbucket.core.service.{AccountService, RepositoryService}
|
||||
import gitbucket.core.ssh.SshServer
|
||||
import gitbucket.core.util.Implicits._
|
||||
import gitbucket.core.util.StringUtil._
|
||||
import gitbucket.core.util.Implicits.*
|
||||
import gitbucket.core.util.StringUtil.*
|
||||
import gitbucket.core.util.{AdminAuthenticator, Mailer}
|
||||
import org.apache.commons.io.IOUtils
|
||||
import org.apache.commons.mail.EmailException
|
||||
import org.json4s.jackson.Serialization
|
||||
import org.scalatra._
|
||||
import org.scalatra.forms._
|
||||
import org.scalatra.*
|
||||
import org.scalatra.forms.*
|
||||
import org.scalatra.i18n.Messages
|
||||
|
||||
import scala.collection.mutable.ListBuffer
|
||||
@@ -29,7 +29,7 @@ case class Table(name: String, columns: Seq[Column])
|
||||
case class Column(name: String, primaryKey: Boolean)
|
||||
|
||||
trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
self: AccountService with RepositoryService with AdminAuthenticator =>
|
||||
self: AccountService & RepositoryService & AdminAuthenticator =>
|
||||
|
||||
private val form = mapping(
|
||||
"baseUrl" -> trim(label("Base URL", optional(text()))),
|
||||
@@ -151,11 +151,11 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
"testAddress" -> trim(label("", text(required)))
|
||||
)(SendMailForm.apply)
|
||||
|
||||
case class SendMailForm(smtp: Smtp, testAddress: String)
|
||||
private case class SendMailForm(smtp: Smtp, testAddress: String)
|
||||
|
||||
case class DataExportForm(tableNames: List[String])
|
||||
// case class DataExportForm(tableNames: List[String])
|
||||
|
||||
case class NewUserForm(
|
||||
private case class NewUserForm(
|
||||
userName: String,
|
||||
password: String,
|
||||
fullName: String,
|
||||
@@ -167,7 +167,7 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
fileId: Option[String]
|
||||
)
|
||||
|
||||
case class EditUserForm(
|
||||
private case class EditUserForm(
|
||||
userName: String,
|
||||
password: Option[String],
|
||||
fullName: String,
|
||||
@@ -181,7 +181,7 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
isRemoved: Boolean
|
||||
)
|
||||
|
||||
case class NewGroupForm(
|
||||
private case class NewGroupForm(
|
||||
groupName: String,
|
||||
description: Option[String],
|
||||
url: Option[String],
|
||||
@@ -189,7 +189,7 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
members: String
|
||||
)
|
||||
|
||||
case class EditGroupForm(
|
||||
private case class EditGroupForm(
|
||||
groupName: String,
|
||||
description: Option[String],
|
||||
url: Option[String],
|
||||
@@ -199,7 +199,7 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
isRemoved: Boolean
|
||||
)
|
||||
|
||||
val newUserForm = mapping(
|
||||
private val newUserForm = mapping(
|
||||
"userName" -> trim(label("Username", text(required, maxlength(100), identifier, uniqueUserName, reservedNames))),
|
||||
"password" -> trim(label("Password", text(required, maxlength(40)))),
|
||||
"fullName" -> trim(label("Full Name", text(required, maxlength(100)))),
|
||||
@@ -213,7 +213,7 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
"fileId" -> trim(label("File ID", optional(text())))
|
||||
)(NewUserForm.apply)
|
||||
|
||||
val editUserForm = mapping(
|
||||
private val editUserForm = mapping(
|
||||
"userName" -> trim(label("Username", text(required, maxlength(100), identifier))),
|
||||
"password" -> trim(label("Password", optional(text(maxlength(40))))),
|
||||
"fullName" -> trim(label("Full Name", text(required, maxlength(100)))),
|
||||
@@ -229,7 +229,7 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
"removed" -> trim(label("Disable", boolean(disableByNotYourself("userName"))))
|
||||
)(EditUserForm.apply)
|
||||
|
||||
val newGroupForm = mapping(
|
||||
private val newGroupForm = mapping(
|
||||
"groupName" -> trim(label("Group name", text(required, maxlength(100), identifier, uniqueUserName, reservedNames))),
|
||||
"description" -> trim(label("Group description", optional(text()))),
|
||||
"url" -> trim(label("URL", optional(text(maxlength(200))))),
|
||||
@@ -237,7 +237,7 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
"members" -> trim(label("Members", text(required, members)))
|
||||
)(NewGroupForm.apply)
|
||||
|
||||
val editGroupForm = mapping(
|
||||
private val editGroupForm = mapping(
|
||||
"groupName" -> trim(label("Group name", text(required, maxlength(100), identifier))),
|
||||
"description" -> trim(label("Group description", optional(text()))),
|
||||
"url" -> trim(label("URL", optional(text(maxlength(200))))),
|
||||
@@ -363,7 +363,7 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
})
|
||||
|
||||
post("/admin/plugins/_reload")(adminOnly {
|
||||
PluginRegistry.reload(request.getServletContext(), loadSystemSettings(), request2Session(request).conn)
|
||||
PluginRegistry.reload(request.getServletContext, loadSystemSettings(), request2Session(request).conn)
|
||||
flash.update("info", "All plugins were reloaded.")
|
||||
redirect("/admin/plugins")
|
||||
})
|
||||
@@ -385,7 +385,7 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
val includeGroups = params.get("includeGroups").exists(_.toBoolean)
|
||||
val users = getAllUsers(includeRemoved, includeGroups)
|
||||
val members = users.collect {
|
||||
case account if (account.isGroupAccount) =>
|
||||
case account if account.isGroupAccount =>
|
||||
account.userName -> getGroupMembers(account.userName).map(_.userName)
|
||||
}.toMap
|
||||
|
||||
@@ -406,7 +406,7 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
form.description,
|
||||
form.url
|
||||
)
|
||||
updateImage(form.userName, form.fileId, false)
|
||||
updateImage(form.userName, form.fileId, clearImage = false)
|
||||
updateAccountExtraMailAddresses(form.userName, form.extraMailAddresses.filter(_ != ""))
|
||||
redirect("/admin/users")
|
||||
})
|
||||
@@ -414,12 +414,12 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
get("/admin/users/:userName/_edituser")(adminOnly {
|
||||
val userName = params("userName")
|
||||
val extraMails = getAccountExtraMailAddresses(userName)
|
||||
html.user(getAccountByUserName(userName, true), extraMails, flash.get("error"))
|
||||
html.user(getAccountByUserName(userName, includeRemoved = true), extraMails, flash.get("error"))
|
||||
})
|
||||
|
||||
post("/admin/users/:name/_edituser", editUserForm)(adminOnly { form =>
|
||||
val userName = params("userName")
|
||||
getAccountByUserName(userName, true).map { account =>
|
||||
getAccountByUserName(userName, includeRemoved = true).map { account =>
|
||||
if (account.isAdmin && (form.isRemoved || !form.isAdmin) && isLastAdministrator(account)) {
|
||||
flash.update("error", "Account can't be turned off because this is last one administrator.")
|
||||
redirect(s"/admin/users/${userName}/_edituser")
|
||||
@@ -476,13 +476,13 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
}
|
||||
.toList
|
||||
)
|
||||
updateImage(form.groupName, form.fileId, false)
|
||||
updateImage(form.groupName, form.fileId, clearImage = false)
|
||||
redirect("/admin/users")
|
||||
})
|
||||
|
||||
get("/admin/users/:groupName/_editgroup")(adminOnly {
|
||||
val groupName = params("groupName")
|
||||
html.usergroup(getAccountByUserName(groupName, true), getGroupMembers(groupName))
|
||||
html.usergroup(getAccountByUserName(groupName, includeRemoved = true), getGroupMembers(groupName))
|
||||
})
|
||||
|
||||
post("/admin/users/:groupName/_editgroup", editGroupForm)(adminOnly { form =>
|
||||
@@ -496,7 +496,7 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
}
|
||||
.toList
|
||||
|
||||
getAccountByUserName(groupName, true).map { account =>
|
||||
getAccountByUserName(groupName, includeRemoved = true).map { account =>
|
||||
updateGroup(groupName, form.description, form.url, form.isRemoved)
|
||||
|
||||
if (form.isRemoved) {
|
||||
@@ -528,13 +528,13 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
})
|
||||
|
||||
get("/admin/data")(adminOnly {
|
||||
import gitbucket.core.util.JDBCUtil._
|
||||
import gitbucket.core.util.JDBCUtil.*
|
||||
val session = request2Session(request)
|
||||
html.data(session.conn.allTableNames())
|
||||
})
|
||||
|
||||
post("/admin/export")(adminOnly {
|
||||
import gitbucket.core.util.JDBCUtil._
|
||||
import gitbucket.core.util.JDBCUtil.*
|
||||
val file = request2Session(request).conn.exportAsSQL(request.getParameterValues("tableNames").toSeq)
|
||||
|
||||
contentType = "application/octet-stream"
|
||||
@@ -577,7 +577,7 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
for {
|
||||
userName <- params.get(paramName)
|
||||
loginAccount <- context.loginAccount
|
||||
if userName == loginAccount.userName && params.get("removed") == Some("true")
|
||||
if userName == loginAccount.userName && params.get("removed").contains("true")
|
||||
} yield "You can't disable your account yourself"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
package gitbucket.core.controller
|
||||
|
||||
import org.json4s.{JField, JObject, JString}
|
||||
import org.scalatra._
|
||||
import org.scalatra.json._
|
||||
import org.scalatra.forms._
|
||||
import org.scalatra.*
|
||||
import org.scalatra.json.*
|
||||
import org.scalatra.forms.*
|
||||
import org.scalatra.i18n.I18nSupport
|
||||
import org.scalatra.servlet.ServletBase
|
||||
|
||||
/**
|
||||
* Extends scalatra-forms to support the client-side validation and Ajax requests as well.
|
||||
*/
|
||||
trait ValidationSupport extends FormSupport { self: ServletBase with JacksonJsonSupport with I18nSupport =>
|
||||
trait ValidationSupport extends FormSupport { self: ServletBase & JacksonJsonSupport & I18nSupport =>
|
||||
|
||||
def get[T](path: String, form: ValueType[T])(action: T => Any): Route = {
|
||||
registerValidate(path, form)
|
||||
|
||||
@@ -5,13 +5,13 @@ import gitbucket.core.model.activity.{CreateWikiPageInfo, DeleteWikiInfo, EditWi
|
||||
import gitbucket.core.service.RepositoryService.RepositoryInfo
|
||||
import gitbucket.core.service.WebHookService.WebHookGollumPayload
|
||||
import gitbucket.core.wiki.html
|
||||
import gitbucket.core.service._
|
||||
import gitbucket.core.util._
|
||||
import gitbucket.core.util.StringUtil._
|
||||
import gitbucket.core.util.SyntaxSugars._
|
||||
import gitbucket.core.util.Implicits._
|
||||
import gitbucket.core.util.Directory._
|
||||
import org.scalatra.forms._
|
||||
import gitbucket.core.service.*
|
||||
import gitbucket.core.util.*
|
||||
import gitbucket.core.util.StringUtil.*
|
||||
import gitbucket.core.util.SyntaxSugars.*
|
||||
import gitbucket.core.util.Implicits.*
|
||||
import gitbucket.core.util.Directory.*
|
||||
import org.scalatra.forms.*
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.scalatra.i18n.Messages
|
||||
|
||||
@@ -29,15 +29,10 @@ class WikiController
|
||||
with RequestCache
|
||||
|
||||
trait WikiControllerBase extends ControllerBase {
|
||||
self: WikiService
|
||||
with RepositoryService
|
||||
with AccountService
|
||||
with ActivityService
|
||||
with WebHookService
|
||||
with ReadableUsersAuthenticator
|
||||
with ReferrerAuthenticator =>
|
||||
self: WikiService & RepositoryService & AccountService & ActivityService & WebHookService &
|
||||
ReadableUsersAuthenticator & ReferrerAuthenticator =>
|
||||
|
||||
case class WikiPageEditForm(
|
||||
private case class WikiPageEditForm(
|
||||
pageName: String,
|
||||
content: String,
|
||||
message: Option[String],
|
||||
@@ -45,7 +40,7 @@ trait WikiControllerBase extends ControllerBase {
|
||||
id: String
|
||||
)
|
||||
|
||||
val newForm = mapping(
|
||||
private val newForm = mapping(
|
||||
"pageName" -> trim(label("Page name", text(required, maxlength(40), pageName, unique))),
|
||||
"content" -> trim(label("Content", text(required, conflictForNew))),
|
||||
"message" -> trim(label("Message", optional(text()))),
|
||||
@@ -53,7 +48,7 @@ trait WikiControllerBase extends ControllerBase {
|
||||
"id" -> trim(label("Latest commit id", text()))
|
||||
)(WikiPageEditForm.apply)
|
||||
|
||||
val editForm = mapping(
|
||||
private val editForm = mapping(
|
||||
"pageName" -> trim(label("Page name", text(required, maxlength(40), pageName))),
|
||||
"content" -> trim(label("Content", text(required, conflictForEdit))),
|
||||
"message" -> trim(label("Message", optional(text()))),
|
||||
@@ -175,7 +170,7 @@ trait WikiControllerBase extends ControllerBase {
|
||||
} else {
|
||||
flash.update("info", "This patch was not able to be reversed.")
|
||||
redirect(
|
||||
s"/${repository.owner}/${repository.name}/wiki/${StringUtil.urlEncode(pageName)}/_compare/${from}...${to}"
|
||||
s"/${repository.owner}/${repository.name}/wiki/${StringUtil.urlEncode(pageName)}/_compare/$from...$to"
|
||||
)
|
||||
}
|
||||
} else Unauthorized()
|
||||
@@ -192,7 +187,7 @@ trait WikiControllerBase extends ControllerBase {
|
||||
redirect(s"/${repository.owner}/${repository.name}/wiki")
|
||||
} else {
|
||||
flash.update("info", "This patch was not able to be reversed.")
|
||||
redirect(s"/${repository.owner}/${repository.name}/wiki/_compare/${from}...${to}")
|
||||
redirect(s"/${repository.owner}/${repository.name}/wiki/_compare/$from...$to")
|
||||
}
|
||||
} else Unauthorized()
|
||||
}
|
||||
@@ -288,7 +283,7 @@ trait WikiControllerBase extends ControllerBase {
|
||||
pageName,
|
||||
loginAccount.fullName,
|
||||
loginAccount.mailAddress,
|
||||
s"Destroyed ${pageName}"
|
||||
s"Destroyed $pageName"
|
||||
)
|
||||
val deleteWikiInfo = DeleteWikiInfo(
|
||||
repository.owner,
|
||||
@@ -349,9 +344,9 @@ trait WikiControllerBase extends ControllerBase {
|
||||
private def pageName: Constraint = new Constraint() {
|
||||
override def validate(name: String, value: String, messages: Messages): Option[String] =
|
||||
if (value.exists("\\/:*?\"<>|".contains(_))) {
|
||||
Some(s"${name} contains invalid character.")
|
||||
Some(s"$name contains invalid character.")
|
||||
} else if (notReservedPageName(value) && (value.startsWith("_") || value.startsWith("-"))) {
|
||||
Some(s"${name} starts with invalid character.")
|
||||
Some(s"$name starts with invalid character.")
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import scala.jdk.CollectionConverters._
|
||||
import scala.util.Using
|
||||
|
||||
trait ApiGitReferenceControllerBase extends ControllerBase {
|
||||
self: ReferrerAuthenticator with WritableUsersAuthenticator =>
|
||||
self: ReferrerAuthenticator & WritableUsersAuthenticator =>
|
||||
|
||||
private val logger = LoggerFactory.getLogger(classOf[ApiGitReferenceControllerBase])
|
||||
|
||||
@@ -138,7 +138,7 @@ trait ApiGitReferenceControllerBase extends ControllerBase {
|
||||
|
||||
val name = RepositoryName(repository)
|
||||
val result = JsonFormat(revstr match {
|
||||
case "tags" => repository.tags.map(ApiRef.fromTag(name, _))
|
||||
case "tags" => repository.tags.map(ApiRef.fromTag(name, _))
|
||||
case x if x.startsWith("tags/") =>
|
||||
val tagName = x.substring("tags/".length)
|
||||
repository.tags.find(_.name == tagName) match {
|
||||
|
||||
@@ -7,13 +7,8 @@ import gitbucket.core.util.{ReadableUsersAuthenticator, ReferrerAuthenticator, R
|
||||
import org.scalatra.ActionResult
|
||||
|
||||
trait ApiIssueCommentControllerBase extends ControllerBase {
|
||||
self: AccountService
|
||||
with IssuesService
|
||||
with RepositoryService
|
||||
with HandleCommentService
|
||||
with MilestonesService
|
||||
with ReadableUsersAuthenticator
|
||||
with ReferrerAuthenticator =>
|
||||
self: AccountService & IssuesService & RepositoryService & HandleCommentService & MilestonesService &
|
||||
ReadableUsersAuthenticator & ReferrerAuthenticator =>
|
||||
/*
|
||||
* i. List issue comments for a repository
|
||||
* https://docs.github.com/en/rest/reference/issues#list-issue-comments-for-a-repository
|
||||
|
||||
@@ -9,12 +9,8 @@ import gitbucket.core.util.{ReadableUsersAuthenticator, ReferrerAuthenticator, R
|
||||
import gitbucket.core.util.Implicits._
|
||||
|
||||
trait ApiIssueControllerBase extends ControllerBase {
|
||||
self: AccountService
|
||||
with IssuesService
|
||||
with IssueCreationService
|
||||
with MilestonesService
|
||||
with ReadableUsersAuthenticator
|
||||
with ReferrerAuthenticator =>
|
||||
self: AccountService & IssuesService & IssueCreationService & MilestonesService & ReadableUsersAuthenticator &
|
||||
ReferrerAuthenticator =>
|
||||
/*
|
||||
* i. List issues
|
||||
* https://developer.github.com/v3/issues/#list-issues
|
||||
|
||||
@@ -7,11 +7,7 @@ import gitbucket.core.util._
|
||||
import org.scalatra.{Created, NoContent, UnprocessableEntity}
|
||||
|
||||
trait ApiIssueLabelControllerBase extends ControllerBase {
|
||||
self: AccountService
|
||||
with IssuesService
|
||||
with LabelsService
|
||||
with ReferrerAuthenticator
|
||||
with WritableUsersAuthenticator =>
|
||||
self: AccountService & IssuesService & LabelsService & ReferrerAuthenticator & WritableUsersAuthenticator =>
|
||||
|
||||
/*
|
||||
* i. List all labels for this repository
|
||||
|
||||
@@ -7,7 +7,7 @@ import gitbucket.core.util.Implicits._
|
||||
import org.scalatra.NoContent
|
||||
|
||||
trait ApiIssueMilestoneControllerBase extends ControllerBase {
|
||||
self: MilestonesService with WritableUsersAuthenticator with ReferrerAuthenticator =>
|
||||
self: MilestonesService & WritableUsersAuthenticator & ReferrerAuthenticator =>
|
||||
|
||||
/*
|
||||
* i. List milestones
|
||||
@@ -29,7 +29,7 @@ trait ApiIssueMilestoneControllerBase extends ControllerBase {
|
||||
)
|
||||
}).reverse
|
||||
state match {
|
||||
case "all" => JsonFormat(apiMilestones)
|
||||
case "all" => JsonFormat(apiMilestones)
|
||||
case "open" | "closed" =>
|
||||
JsonFormat(
|
||||
apiMilestones.filter(p => p.state == state)
|
||||
|
||||
@@ -6,7 +6,7 @@ import gitbucket.core.util.Implicits._
|
||||
import gitbucket.core.util.{AdminAuthenticator, UsersAuthenticator}
|
||||
|
||||
trait ApiOrganizationControllerBase extends ControllerBase {
|
||||
self: RepositoryService with AccountService with AdminAuthenticator with UsersAuthenticator =>
|
||||
self: RepositoryService & AccountService & AdminAuthenticator & UsersAuthenticator =>
|
||||
|
||||
/*
|
||||
* i. List your organizations
|
||||
|
||||
@@ -16,14 +16,8 @@ import scala.util.Using
|
||||
import scala.jdk.CollectionConverters._
|
||||
|
||||
trait ApiPullRequestControllerBase extends ControllerBase {
|
||||
self: AccountService
|
||||
with IssuesService
|
||||
with PullRequestService
|
||||
with RepositoryService
|
||||
with MergeService
|
||||
with ReferrerAuthenticator
|
||||
with ReadableUsersAuthenticator
|
||||
with WritableUsersAuthenticator =>
|
||||
self: AccountService & IssuesService & PullRequestService & RepositoryService & MergeService & ReferrerAuthenticator &
|
||||
ReadableUsersAuthenticator & WritableUsersAuthenticator =>
|
||||
|
||||
/*
|
||||
* i. Link Relations
|
||||
|
||||
@@ -11,7 +11,7 @@ import org.apache.commons.io.FileUtils
|
||||
import org.scalatra.NoContent
|
||||
|
||||
trait ApiReleaseControllerBase extends ControllerBase {
|
||||
self: AccountService with ReleaseService with ReferrerAuthenticator with WritableUsersAuthenticator =>
|
||||
self: AccountService & ReleaseService & ReferrerAuthenticator & WritableUsersAuthenticator =>
|
||||
|
||||
/**
|
||||
* i. List releases for a repository
|
||||
|
||||
@@ -12,15 +12,8 @@ import org.scalatra.NoContent
|
||||
import scala.util.Using
|
||||
|
||||
trait ApiRepositoryBranchControllerBase extends ControllerBase {
|
||||
self: RepositoryService
|
||||
with AccountService
|
||||
with OwnerAuthenticator
|
||||
with UsersAuthenticator
|
||||
with GroupManagerAuthenticator
|
||||
with ProtectedBranchService
|
||||
with ReferrerAuthenticator
|
||||
with ReadableUsersAuthenticator
|
||||
with WritableUsersAuthenticator =>
|
||||
self: RepositoryService & AccountService & OwnerAuthenticator & UsersAuthenticator & GroupManagerAuthenticator &
|
||||
ProtectedBranchService & ReferrerAuthenticator & ReadableUsersAuthenticator & WritableUsersAuthenticator =>
|
||||
|
||||
/**
|
||||
* i. List branches
|
||||
@@ -30,10 +23,7 @@ trait ApiRepositoryBranchControllerBase extends ControllerBase {
|
||||
Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
|
||||
JsonFormat(
|
||||
JGitUtil
|
||||
.getBranchesNoMergeInfo(
|
||||
git = git,
|
||||
defaultBranch = repository.repository.defaultBranch
|
||||
)
|
||||
.getBranchesNoMergeInfo(git)
|
||||
.map { br =>
|
||||
ApiBranchForList(br.name, ApiBranchCommit(br.commitId))
|
||||
}
|
||||
@@ -49,10 +39,7 @@ trait ApiRepositoryBranchControllerBase extends ControllerBase {
|
||||
Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
|
||||
(for {
|
||||
branch <- params.get("splat") if repository.branchList.contains(branch)
|
||||
br <- getBranchesNoMergeInfo(
|
||||
git,
|
||||
repository.repository.defaultBranch
|
||||
).find(_.name == branch)
|
||||
br <- getBranchesNoMergeInfo(git).find(_.name == branch)
|
||||
} yield {
|
||||
val protection = getProtectedBranchInfo(repository.owner, repository.name, branch)
|
||||
JsonFormat(
|
||||
@@ -276,10 +263,7 @@ trait ApiRepositoryBranchControllerBase extends ControllerBase {
|
||||
(for {
|
||||
branch <- params.get("splat") if repository.branchList.contains(branch)
|
||||
protection <- extractFromJsonBody[ApiBranchProtection.EnablingAndDisabling].map(_.protection)
|
||||
br <- getBranchesNoMergeInfo(
|
||||
git,
|
||||
repository.repository.defaultBranch
|
||||
).find(_.name == branch)
|
||||
br <- getBranchesNoMergeInfo(git).find(_.name == branch)
|
||||
} yield {
|
||||
if (protection.enabled) {
|
||||
enableBranchProtection(
|
||||
|
||||
@@ -7,7 +7,7 @@ import gitbucket.core.util.{OwnerAuthenticator, ReferrerAuthenticator}
|
||||
import org.scalatra.NoContent
|
||||
|
||||
trait ApiRepositoryCollaboratorControllerBase extends ControllerBase {
|
||||
self: RepositoryService with AccountService with ReferrerAuthenticator with OwnerAuthenticator =>
|
||||
self: RepositoryService & AccountService & ReferrerAuthenticator & OwnerAuthenticator =>
|
||||
|
||||
/*
|
||||
* i. List repository collaborators
|
||||
|
||||
@@ -21,7 +21,7 @@ import scala.math.min
|
||||
import scala.util.Using
|
||||
|
||||
trait ApiRepositoryCommitControllerBase extends ControllerBase {
|
||||
self: AccountService with CommitsService with ProtectedBranchService with ReferrerAuthenticator =>
|
||||
self: AccountService & CommitsService & ProtectedBranchService & ReferrerAuthenticator =>
|
||||
/*
|
||||
* i. List commits on a repository
|
||||
* https://developer.github.com/v3/repos/commits/#list-commits-on-a-repository
|
||||
@@ -159,7 +159,7 @@ trait ApiRepositoryCommitControllerBase extends ControllerBase {
|
||||
Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
|
||||
val apiBranchForCommits = for {
|
||||
branch <- getBranchesOfCommit(git, sha)
|
||||
br <- getBranchesNoMergeInfo(git, branch).find(_.name == branch)
|
||||
br <- getBranchesNoMergeInfo(git).find(_.name == branch)
|
||||
} yield {
|
||||
val protection = getProtectedBranchInfo(repository.owner, repository.name, branch)
|
||||
ApiBranchForHeadCommit(branch, ApiBranchCommit(br.commitId), protection.enabled)
|
||||
|
||||
@@ -12,7 +12,7 @@ import org.eclipse.jgit.api.Git
|
||||
import scala.util.Using
|
||||
|
||||
trait ApiRepositoryContentsControllerBase extends ControllerBase {
|
||||
self: ReferrerAuthenticator with WritableUsersAuthenticator with RepositoryCommitFileService =>
|
||||
self: ReferrerAuthenticator & WritableUsersAuthenticator & RepositoryCommitFileService =>
|
||||
|
||||
/**
|
||||
* i. Get a repository README
|
||||
|
||||
@@ -15,16 +15,9 @@ import scala.concurrent.duration.Duration
|
||||
import scala.util.Using
|
||||
|
||||
trait ApiRepositoryControllerBase extends ControllerBase {
|
||||
self: RepositoryService
|
||||
with ApiGitReferenceControllerBase
|
||||
with RepositoryCreationService
|
||||
with AccountService
|
||||
with OwnerAuthenticator
|
||||
with UsersAuthenticator
|
||||
with GroupManagerAuthenticator
|
||||
with ReferrerAuthenticator
|
||||
with ReadableUsersAuthenticator
|
||||
with WritableUsersAuthenticator =>
|
||||
self: RepositoryService & ApiGitReferenceControllerBase & RepositoryCreationService & AccountService &
|
||||
OwnerAuthenticator & UsersAuthenticator & GroupManagerAuthenticator & ReferrerAuthenticator &
|
||||
ReadableUsersAuthenticator & WritableUsersAuthenticator =>
|
||||
|
||||
/**
|
||||
* i. List your repositories
|
||||
@@ -189,7 +182,7 @@ trait ApiRepositoryControllerBase extends ControllerBase {
|
||||
get("/api/v3/repos/:owner/:repository/tags")(referrersOnly { repository =>
|
||||
Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
|
||||
JsonFormat(
|
||||
self.getRef("tags", repository)
|
||||
repository.tags.map(tagInfo => ApiTag(tagInfo.name, RepositoryName(repository), tagInfo.commitId))
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -7,7 +7,7 @@ import gitbucket.core.util.Implicits._
|
||||
import gitbucket.core.util.{JGitUtil, ReferrerAuthenticator, WritableUsersAuthenticator}
|
||||
|
||||
trait ApiRepositoryStatusControllerBase extends ControllerBase {
|
||||
self: AccountService with CommitStatusService with ReferrerAuthenticator with WritableUsersAuthenticator =>
|
||||
self: AccountService & CommitStatusService & ReferrerAuthenticator & WritableUsersAuthenticator =>
|
||||
|
||||
/*
|
||||
* i. Create a status
|
||||
|
||||
@@ -8,7 +8,7 @@ import gitbucket.core.util.Implicits._
|
||||
import org.scalatra.NoContent
|
||||
|
||||
trait ApiRepositoryWebhookControllerBase extends ControllerBase {
|
||||
self: RepositoryService with WebHookService with ReferrerAuthenticator with WritableUsersAuthenticator =>
|
||||
self: RepositoryService & WebHookService & ReferrerAuthenticator & WritableUsersAuthenticator =>
|
||||
|
||||
/*
|
||||
* i. List repository webhooks
|
||||
|
||||
@@ -8,7 +8,7 @@ import gitbucket.core.util.StringUtil._
|
||||
import org.scalatra.NoContent
|
||||
|
||||
trait ApiUserControllerBase extends ControllerBase {
|
||||
self: RepositoryService with AccountService with AdminAuthenticator with UsersAuthenticator =>
|
||||
self: RepositoryService & AccountService & AdminAuthenticator & UsersAuthenticator =>
|
||||
|
||||
/**
|
||||
* i. Get a single user
|
||||
|
||||
@@ -67,7 +67,7 @@ trait RepositoryComponent extends TemplateComponent { self: Profile =>
|
||||
repository._10,
|
||||
repository._11,
|
||||
repository._12,
|
||||
RepositoryOptions.tupled.apply(options)
|
||||
RepositoryOptions.apply.tupled.apply(options)
|
||||
)
|
||||
},
|
||||
{ (r: Repository) =>
|
||||
|
||||
@@ -59,7 +59,7 @@ trait AccountFederationService {
|
||||
.orElse(extractSafeStringForUserName(mailAddress)) match {
|
||||
case Some(safeUserName) =>
|
||||
getAccountByUserName(safeUserName, includeRemoved = true) match {
|
||||
case None => Some(safeUserName)
|
||||
case None => Some(safeUserName)
|
||||
case Some(_) =>
|
||||
logger.info(
|
||||
s"User ($safeUserName) already exists. preferredUserName=$preferredUserName, mailAddress=$mailAddress"
|
||||
|
||||
@@ -46,7 +46,7 @@ trait AccountService {
|
||||
case account if !account.isGroupAccount =>
|
||||
account.password match {
|
||||
case pbkdf2re(iter, salt, hash) if (pbkdf2_sha256(iter.toInt, salt, password) == hash) => Some(account)
|
||||
case p if p == sha1(password) =>
|
||||
case p if p == sha1(password) =>
|
||||
updateAccount(account.copy(password = pbkdf2_sha256(password)))
|
||||
Some(account)
|
||||
case _ => None
|
||||
|
||||
@@ -16,7 +16,7 @@ import gitbucket.core.util.{FileUtil, StringUtil}
|
||||
import org.apache.commons.io.FileUtils
|
||||
|
||||
trait CommitsService {
|
||||
self: ActivityService with PullRequestService with WebHookPullRequestReviewCommentService =>
|
||||
self: ActivityService & PullRequestService & WebHookPullRequestReviewCommentService =>
|
||||
|
||||
def getCommitComments(owner: String, repository: String, commitId: String, includePullRequest: Boolean)(implicit
|
||||
s: Session
|
||||
|
||||
@@ -16,12 +16,8 @@ import gitbucket.core.service.RepositoryService.RepositoryInfo
|
||||
import gitbucket.core.util.Implicits._
|
||||
|
||||
trait HandleCommentService {
|
||||
self: RepositoryService
|
||||
with IssuesService
|
||||
with ActivityService
|
||||
with WebHookService
|
||||
with WebHookIssueCommentService
|
||||
with WebHookPullRequestService =>
|
||||
self: RepositoryService & IssuesService & ActivityService & WebHookService & WebHookIssueCommentService &
|
||||
WebHookPullRequestService =>
|
||||
|
||||
/**
|
||||
* @see [[https://github.com/gitbucket/gitbucket/wiki/CommentAction]]
|
||||
@@ -66,7 +62,7 @@ trait HandleCommentService {
|
||||
.getOrElse(None -> None)
|
||||
|
||||
val commentId = (content, action) match {
|
||||
case (None, None) => None
|
||||
case (None, None) => None
|
||||
case (None, Some(action)) =>
|
||||
Some(createComment(owner, name, userName, issue.issueId, action.capitalize, action))
|
||||
case (Some(content), _) =>
|
||||
|
||||
@@ -10,7 +10,7 @@ import gitbucket.core.util.Implicits._
|
||||
|
||||
trait IssueCreationService {
|
||||
|
||||
self: RepositoryService with WebHookIssueCommentService with LabelsService with IssuesService with ActivityService =>
|
||||
self: RepositoryService & WebHookIssueCommentService & LabelsService & IssuesService & ActivityService =>
|
||||
|
||||
def createIssue(
|
||||
repository: RepositoryInfo,
|
||||
|
||||
@@ -26,7 +26,7 @@ import gitbucket.core.plugin.PluginRegistry
|
||||
import scala.jdk.CollectionConverters._
|
||||
|
||||
trait IssuesService {
|
||||
self: AccountService with RepositoryService with LabelsService with PrioritiesService with MilestonesService =>
|
||||
self: AccountService & RepositoryService & LabelsService & PrioritiesService & MilestonesService =>
|
||||
import IssuesService._
|
||||
|
||||
def getIssue(owner: String, repository: String, issueId: String)(implicit s: Session) =
|
||||
|
||||
@@ -23,13 +23,8 @@ import scala.jdk.CollectionConverters._
|
||||
import scala.util.Using
|
||||
|
||||
trait MergeService {
|
||||
self: AccountService
|
||||
with ActivityService
|
||||
with IssuesService
|
||||
with RepositoryService
|
||||
with PullRequestService
|
||||
with WebHookPullRequestService
|
||||
with WebHookService =>
|
||||
self: AccountService & ActivityService & IssuesService & RepositoryService & PullRequestService &
|
||||
WebHookPullRequestService & WebHookService =>
|
||||
|
||||
import MergeService._
|
||||
|
||||
|
||||
@@ -25,13 +25,8 @@ import scala.jdk.CollectionConverters.*
|
||||
import scala.util.Using
|
||||
|
||||
trait PullRequestService {
|
||||
self: IssuesService
|
||||
with CommitsService
|
||||
with WebHookService
|
||||
with WebHookPullRequestService
|
||||
with RepositoryService
|
||||
with MergeService
|
||||
with ActivityService =>
|
||||
self: IssuesService & CommitsService & WebHookService & WebHookPullRequestService & RepositoryService & MergeService &
|
||||
ActivityService =>
|
||||
import PullRequestService.*
|
||||
|
||||
def getPullRequest(owner: String, repository: String, issueId: Int)(implicit
|
||||
@@ -318,7 +313,7 @@ trait PullRequestService {
|
||||
base.foreach { _base =>
|
||||
if (pr.branch != _base) {
|
||||
Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
|
||||
getBranchesNoMergeInfo(git, repository.repository.defaultBranch)
|
||||
getBranchesNoMergeInfo(git)
|
||||
.find(_.name == _base)
|
||||
.foreach(br => updateBaseBranch(repository.owner, repository.name, issueId, br.name, br.commitId))
|
||||
}
|
||||
@@ -432,7 +427,7 @@ trait PullRequestService {
|
||||
case Some(patch) =>
|
||||
file -> comments.foreach { case (commentId, lineNumber) =>
|
||||
lineNumber match {
|
||||
case Left(oldLine) => updateCommitCommentPosition(commentId, newCommitId, Some(oldLine), None)
|
||||
case Left(oldLine) => updateCommitCommentPosition(commentId, newCommitId, Some(oldLine), None)
|
||||
case Right(newLine) =>
|
||||
var counter = newLine
|
||||
patch.getDeltas.asScala.filter(_.getSource.getPosition < newLine).foreach { delta =>
|
||||
|
||||
@@ -8,7 +8,7 @@ import gitbucket.core.model.Profile.dateColumnType
|
||||
import gitbucket.core.util.JGitUtil
|
||||
|
||||
trait ReleaseService {
|
||||
self: AccountService with RepositoryService =>
|
||||
self: AccountService & RepositoryService =>
|
||||
|
||||
def createReleaseAsset(
|
||||
owner: String,
|
||||
|
||||
@@ -17,12 +17,8 @@ import org.eclipse.jgit.transport.{ReceiveCommand, ReceivePack}
|
||||
import scala.util.Using
|
||||
|
||||
trait RepositoryCommitFileService {
|
||||
self: AccountService
|
||||
with ActivityService
|
||||
with IssuesService
|
||||
with PullRequestService
|
||||
with WebHookPullRequestService
|
||||
with RepositoryService =>
|
||||
self: AccountService & ActivityService & IssuesService & PullRequestService & WebHookPullRequestService &
|
||||
RepositoryService =>
|
||||
|
||||
/**
|
||||
* Create multiple files by callback function.
|
||||
|
||||
@@ -46,12 +46,7 @@ object RepositoryCreationService {
|
||||
}
|
||||
|
||||
trait RepositoryCreationService {
|
||||
self: AccountService
|
||||
with RepositoryService
|
||||
with LabelsService
|
||||
with WikiService
|
||||
with ActivityService
|
||||
with PrioritiesService =>
|
||||
self: AccountService & RepositoryService & LabelsService & WikiService & ActivityService & PrioritiesService =>
|
||||
|
||||
def canCreateRepository(repositoryOwner: String, loginAccount: Account)(implicit session: Session): Boolean = {
|
||||
repositoryOwner == loginAccount.userName || getGroupsByUserName(loginAccount.userName)
|
||||
|
||||
@@ -373,7 +373,7 @@ object SystemSettingsService {
|
||||
if (isDefaultPort) {
|
||||
s"${genericUser}@${host}"
|
||||
} else {
|
||||
s"${genericUser}@${host}:${port}"
|
||||
s"ssh://${genericUser}@${host}:${port}"
|
||||
}
|
||||
|
||||
def getUrl(owner: String, name: String): String =
|
||||
|
||||
@@ -367,7 +367,7 @@ trait WebHookService {
|
||||
}
|
||||
|
||||
trait WebHookPullRequestService extends WebHookService {
|
||||
self: AccountService with RepositoryService with PullRequestService with IssuesService =>
|
||||
self: AccountService & RepositoryService & PullRequestService & IssuesService =>
|
||||
|
||||
import WebHookService._
|
||||
// https://developer.github.com/v3/activity/events/types/#issuesevent
|
||||
@@ -513,7 +513,7 @@ trait WebHookPullRequestService extends WebHookService {
|
||||
}
|
||||
|
||||
trait WebHookPullRequestReviewCommentService extends WebHookService {
|
||||
self: AccountService with RepositoryService with PullRequestService with IssuesService with CommitsService =>
|
||||
self: AccountService & RepositoryService & PullRequestService & IssuesService & CommitsService =>
|
||||
def callPullRequestReviewCommentWebHook(
|
||||
action: String,
|
||||
comment: CommitComment,
|
||||
@@ -561,7 +561,7 @@ trait WebHookPullRequestReviewCommentService extends WebHookService {
|
||||
}
|
||||
|
||||
trait WebHookIssueCommentService extends WebHookPullRequestService {
|
||||
self: AccountService with RepositoryService with PullRequestService with IssuesService =>
|
||||
self: AccountService & RepositoryService & PullRequestService & IssuesService =>
|
||||
|
||||
import WebHookService._
|
||||
def callIssueCommentWebHook(
|
||||
|
||||
@@ -25,8 +25,8 @@ class ApiAuthenticationFilter extends Filter with AccessTokenService with Accoun
|
||||
val response = res.asInstanceOf[HttpServletResponse]
|
||||
Option(request.getHeader("Authorization"))
|
||||
.map {
|
||||
case auth if auth.toLowerCase().startsWith("token ") =>
|
||||
AccessTokenService.getAccountByAccessToken(auth.substring(6).trim).toRight(())
|
||||
case auth if auth.toLowerCase().startsWith("token ") || auth.toLowerCase().startsWith("bearer ") =>
|
||||
AccessTokenService.getAccountByAccessToken(auth.substring(auth.indexOf(" ") + 1).trim).toRight(())
|
||||
case auth if auth.startsWith("Basic ") => doBasicAuth(auth, loadSystemSettings(), request).toRight(())
|
||||
case _ => Left(())
|
||||
}
|
||||
@@ -42,7 +42,7 @@ class ApiAuthenticationFilter extends Filter with AccessTokenService with Accoun
|
||||
updateLastLoginDate(account.userName)
|
||||
}
|
||||
chain.doFilter(req, res)
|
||||
case None => chain.doFilter(req, res)
|
||||
case None => chain.doFilter(req, res)
|
||||
case Some(Left(_)) => {
|
||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED)
|
||||
response.setContentType("application/json; charset=utf-8")
|
||||
|
||||
@@ -204,7 +204,7 @@ class GitBucketReceivePackFactory extends ReceivePackFactory[HttpServletRequest]
|
||||
|
||||
val settings = loadSystemSettings()
|
||||
val baseUrl = settings.baseUrl(request)
|
||||
val sshUrl = settings.sshUrl(owner, repository)
|
||||
val sshUrl = settings.sshUrl
|
||||
|
||||
if (!repository.endsWith(".wiki")) {
|
||||
val hook = new CommitLogHook(owner, repository, pusher, baseUrl, sshUrl)
|
||||
@@ -296,7 +296,7 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl:
|
||||
} else {
|
||||
command.getType match {
|
||||
case ReceiveCommand.Type.DELETE => Nil
|
||||
case _ => JGitUtil.getCommitLog(git, command.getOldId.name, command.getNewId.name)
|
||||
case _ => JGitUtil.getCommitLog(git, command.getOldId, command.getNewId)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -492,7 +492,7 @@ class WikiCommitHook(owner: String, repository: String, pusher: String, baseUrl:
|
||||
} else {
|
||||
command.getType match {
|
||||
case ReceiveCommand.Type.DELETE => None
|
||||
case _ => Some((command.getOldId.getName, command.getNewId.name))
|
||||
case _ => Some((command.getOldId, command.getNewId))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -543,7 +543,7 @@ class WikiCommitHook(owner: String, repository: String, pusher: String, baseUrl:
|
||||
case ChangeType.ADD | ChangeType.RENAME => "created"
|
||||
case ChangeType.MODIFY => "edited"
|
||||
case ChangeType.DELETE => "deleted"
|
||||
case other =>
|
||||
case other =>
|
||||
logger.error(s"Unsupported Wiki action: $other")
|
||||
"unsupported action"
|
||||
}
|
||||
@@ -560,7 +560,7 @@ class WikiCommitHook(owner: String, repository: String, pusher: String, baseUrl:
|
||||
case "created" => Some(CreateWikiPageInfo(owner, repo, commit.committerName, pageName))
|
||||
case "edited" => Some(EditWikiPageInfo(owner, repo, commit.committerName, pageName, commit.id))
|
||||
case "deleted" => Some(DeleteWikiInfo(owner, repo, commit.committerName, pageName))
|
||||
case other =>
|
||||
case other =>
|
||||
logger.info(s"Attempted to build wiki record for unsupported action: $other")
|
||||
None
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ abstract class GitCommand extends Command with ServerSessionAware {
|
||||
}
|
||||
|
||||
abstract class DefaultGitCommand(val owner: String, val repoName: String) extends GitCommand {
|
||||
self: RepositoryService with AccountService with DeployKeyService =>
|
||||
self: RepositoryService & AccountService & DeployKeyService =>
|
||||
|
||||
protected def userName(authType: AuthType): String = {
|
||||
authType match {
|
||||
@@ -183,7 +183,7 @@ class DefaultGitReceivePack(owner: String, repoName: String, baseUrl: String, ss
|
||||
val receive = new ReceivePack(repository)
|
||||
if (!repoName.endsWith(".wiki")) {
|
||||
val hook =
|
||||
new CommitLogHook(owner, repoName, userName(authType), baseUrl, Some(sshAddress.getUrl(owner, repoName)))
|
||||
new CommitLogHook(owner, repoName, userName(authType), baseUrl, Some(sshAddress.getUrl))
|
||||
receive.setPreReceiveHook(hook)
|
||||
receive.setPostReceiveHook(hook)
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ trait OneselfAuthenticator { self: ControllerBase =>
|
||||
/**
|
||||
* Allows only the repository owner and administrators.
|
||||
*/
|
||||
trait OwnerAuthenticator { self: ControllerBase with RepositoryService with AccountService =>
|
||||
trait OwnerAuthenticator { self: ControllerBase & RepositoryService & AccountService =>
|
||||
protected def ownerOnly(action: (RepositoryInfo) => Any) = { authenticate(action) }
|
||||
protected def ownerOnly[T](action: (T, RepositoryInfo) => Any) = (form: T) => { authenticate(action(form, _)) }
|
||||
|
||||
@@ -82,7 +82,7 @@ trait AdminAuthenticator { self: ControllerBase =>
|
||||
/**
|
||||
* Allows only guests and signed in users who can access the repository.
|
||||
*/
|
||||
trait ReferrerAuthenticator { self: ControllerBase with RepositoryService with AccountService =>
|
||||
trait ReferrerAuthenticator { self: ControllerBase & RepositoryService & AccountService =>
|
||||
protected def referrersOnly(action: (RepositoryInfo) => Any) = { authenticate(action) }
|
||||
protected def referrersOnly[T](action: (T, RepositoryInfo) => Any) = (form: T) => { authenticate(action(form, _)) }
|
||||
|
||||
@@ -102,7 +102,7 @@ trait ReferrerAuthenticator { self: ControllerBase with RepositoryService with A
|
||||
/**
|
||||
* Allows only signed in users who have read permission for the repository.
|
||||
*/
|
||||
trait ReadableUsersAuthenticator { self: ControllerBase with RepositoryService with AccountService =>
|
||||
trait ReadableUsersAuthenticator { self: ControllerBase & RepositoryService & AccountService =>
|
||||
protected def readableUsersOnly(action: (RepositoryInfo) => Any) = { authenticate(action) }
|
||||
protected def readableUsersOnly[T](action: (T, RepositoryInfo) => Any) = (form: T) => {
|
||||
authenticate(action(form, _))
|
||||
@@ -124,7 +124,7 @@ trait ReadableUsersAuthenticator { self: ControllerBase with RepositoryService w
|
||||
/**
|
||||
* Allows only signed in users who have write permission for the repository.
|
||||
*/
|
||||
trait WritableUsersAuthenticator { self: ControllerBase with RepositoryService with AccountService =>
|
||||
trait WritableUsersAuthenticator { self: ControllerBase & RepositoryService & AccountService =>
|
||||
protected def writableUsersOnly(action: (RepositoryInfo) => Any) = { authenticate(action) }
|
||||
protected def writableUsersOnly[T](action: (T, RepositoryInfo) => Any) = (form: T) => {
|
||||
authenticate(action(form, _))
|
||||
@@ -151,7 +151,7 @@ trait WritableUsersAuthenticator { self: ControllerBase with RepositoryService w
|
||||
/**
|
||||
* Allows only the group managers.
|
||||
*/
|
||||
trait GroupManagerAuthenticator { self: ControllerBase with AccountService =>
|
||||
trait GroupManagerAuthenticator { self: ControllerBase & AccountService =>
|
||||
protected def managersOnly(action: => Any) = { authenticate(action) }
|
||||
protected def managersOnly[T](action: T => Any) = (form: T) => { authenticate(action(form)) }
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ object DatabaseConfig {
|
||||
FileUtils.write(
|
||||
file,
|
||||
"""db {
|
||||
| url = "jdbc:h2:${DatabaseHome};MVCC=true"
|
||||
| url = "jdbc:h2:${DatabaseHome}"
|
||||
| user = "sa"
|
||||
| password = "sa"
|
||||
|# connectionTimeout = 30000
|
||||
|
||||
@@ -10,7 +10,7 @@ object Directory {
|
||||
val GitBucketHome = (System.getProperty("gitbucket.home") match {
|
||||
// -Dgitbucket.home=<path>
|
||||
case path if (path != null) => new File(path)
|
||||
case _ =>
|
||||
case _ =>
|
||||
scala.util.Properties.envOrNone("GITBUCKET_HOME") match {
|
||||
// environment variable GITBUCKET_HOME
|
||||
case Some(env) => new File(env)
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
package gitbucket.core.util
|
||||
|
||||
import java.io._
|
||||
import java.io.*
|
||||
import gitbucket.core.service.RepositoryService
|
||||
import org.eclipse.jgit.api.Git
|
||||
import Directory._
|
||||
import StringUtil._
|
||||
import Directory.*
|
||||
import StringUtil.*
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.jdk.CollectionConverters._
|
||||
import scala.jdk.CollectionConverters.*
|
||||
import scala.util.Using
|
||||
import org.eclipse.jgit.lib._
|
||||
import org.eclipse.jgit.revwalk._
|
||||
import org.eclipse.jgit.revwalk.filter._
|
||||
import org.eclipse.jgit.treewalk._
|
||||
import org.eclipse.jgit.treewalk.filter._
|
||||
import org.eclipse.jgit.lib.*
|
||||
import org.eclipse.jgit.revwalk.*
|
||||
import org.eclipse.jgit.revwalk.filter.*
|
||||
import org.eclipse.jgit.treewalk.*
|
||||
import org.eclipse.jgit.treewalk.filter.*
|
||||
import org.eclipse.jgit.diff.DiffEntry.ChangeType
|
||||
import org.eclipse.jgit.errors.{ConfigInvalidException, IncorrectObjectTypeException, MissingObjectException}
|
||||
import org.eclipse.jgit.transport.RefSpec
|
||||
@@ -21,7 +21,7 @@ import org.eclipse.jgit.transport.RefSpec
|
||||
import java.util.Date
|
||||
import java.util.concurrent.TimeUnit
|
||||
import org.cache2k.{Cache, Cache2kBuilder}
|
||||
import org.eclipse.jgit.api.errors._
|
||||
import org.eclipse.jgit.api.errors.*
|
||||
import org.eclipse.jgit.diff.{DiffEntry, DiffFormatter, RawTextComparator}
|
||||
import org.eclipse.jgit.dircache.DirCacheEntry
|
||||
import org.eclipse.jgit.util.io.DisabledOutputStream
|
||||
@@ -39,7 +39,7 @@ object JGitUtil {
|
||||
private implicit val objectDatabaseReleasable: Releasable[ObjectDatabase] =
|
||||
_.close()
|
||||
|
||||
private def isCacheEnabled(): Boolean =
|
||||
private def isCacheEnabled: Boolean =
|
||||
!ConfigUtil.getConfigValue[Boolean]("gitbucket.disableCache").getOrElse(false)
|
||||
|
||||
/**
|
||||
@@ -90,8 +90,6 @@ object JGitUtil {
|
||||
|
||||
/**
|
||||
* The verified gpg sign data.
|
||||
* @param signedUser
|
||||
* @param signedKeyId
|
||||
*/
|
||||
case class GpgVerifyInfo(signedUser: String, signedKeyId: String)
|
||||
|
||||
@@ -127,7 +125,7 @@ object JGitUtil {
|
||||
|
||||
os.write('\n')
|
||||
|
||||
if (!rev.getFullMessage.isEmpty) {
|
||||
if (rev.getFullMessage.nonEmpty) {
|
||||
w.write(rev.getFullMessage)
|
||||
w.flush()
|
||||
}
|
||||
@@ -168,7 +166,7 @@ object JGitUtil {
|
||||
rev.getName,
|
||||
rev.getShortMessage,
|
||||
rev.getFullMessage,
|
||||
rev.getParents().map(_.name).toList,
|
||||
rev.getParents.map(_.name).toList,
|
||||
rev.getAuthorIdent.getWhen,
|
||||
rev.getAuthorIdent.getName,
|
||||
rev.getAuthorIdent.getEmailAddress,
|
||||
@@ -181,9 +179,9 @@ object JGitUtil {
|
||||
None
|
||||
)
|
||||
|
||||
val summary = getSummaryMessage(fullMessage, shortMessage)
|
||||
val summary: String = getSummaryMessage(fullMessage, shortMessage)
|
||||
|
||||
val description = {
|
||||
val description: Option[String] = {
|
||||
val i = fullMessage.trim.indexOf('\n')
|
||||
if (i >= 0) {
|
||||
Some(fullMessage.trim.substring(i).trim)
|
||||
@@ -290,11 +288,11 @@ object JGitUtil {
|
||||
case r: RevTag => revWalk.parseCommit(r.getObject)
|
||||
case _ => revWalk.parseCommit(objectId)
|
||||
}
|
||||
revWalk.dispose
|
||||
revWalk.dispose()
|
||||
revCommit
|
||||
}
|
||||
|
||||
private val cache: Cache[String, Int] = if (isCacheEnabled()) {
|
||||
private val cache: Cache[String, Int] = if (isCacheEnabled) {
|
||||
Cache2kBuilder
|
||||
.of(classOf[String], classOf[Int])
|
||||
.name("commit-count")
|
||||
@@ -303,7 +301,7 @@ object JGitUtil {
|
||||
.build()
|
||||
} else null
|
||||
|
||||
private val objectCommitCache: Cache[ObjectId, RevCommit] = if (isCacheEnabled()) {
|
||||
private val objectCommitCache: Cache[ObjectId, RevCommit] = if (isCacheEnabled) {
|
||||
Cache2kBuilder
|
||||
.of(classOf[ObjectId], classOf[RevCommit])
|
||||
.name("object-commit")
|
||||
@@ -312,7 +310,7 @@ object JGitUtil {
|
||||
} else null
|
||||
|
||||
def removeCache(git: Git): Unit = {
|
||||
if (isCacheEnabled()) {
|
||||
if (isCacheEnabled) {
|
||||
val dir = git.getRepository.getDirectory
|
||||
val keyPrefix = dir.getAbsolutePath + "@"
|
||||
|
||||
@@ -331,7 +329,7 @@ object JGitUtil {
|
||||
def getCommitCount(git: Git, branch: String, max: Int = 10001): Int = {
|
||||
val dir = git.getRepository.getDirectory
|
||||
|
||||
if (isCacheEnabled()) {
|
||||
if (isCacheEnabled) {
|
||||
val key = dir.getAbsolutePath + "@" + branch
|
||||
val entry = cache.getEntry(key)
|
||||
|
||||
@@ -387,7 +385,7 @@ object JGitUtil {
|
||||
)
|
||||
} catch {
|
||||
// not initialized
|
||||
case e: NoHeadException => RepositoryInfo(owner, repository, Nil, Nil)
|
||||
case _: NoHeadException => RepositoryInfo(owner, repository, Nil, Nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -424,7 +422,7 @@ object JGitUtil {
|
||||
} else {
|
||||
val treeWalk = TreeWalk.forPath(git.getRepository, path, rev.getTree)
|
||||
if (treeWalk != null) {
|
||||
treeWalk.enterSubtree
|
||||
treeWalk.enterSubtree()
|
||||
Using.resource(treeWalk)(f)
|
||||
}
|
||||
}
|
||||
@@ -435,7 +433,7 @@ object JGitUtil {
|
||||
): (ObjectId, FileMode, String, String, Option[String], Option[RevCommit]) =
|
||||
tuple match {
|
||||
case (oid, FileMode.TREE, name, path, _, commit) =>
|
||||
(Using.resource(new TreeWalk(git.getRepository)) { walk =>
|
||||
Using.resource(new TreeWalk(git.getRepository)) { walk =>
|
||||
walk.addTree(oid)
|
||||
// single tree child, or None
|
||||
if (walk.next() && walk.getFileMode(0) == FileMode.TREE) {
|
||||
@@ -452,7 +450,7 @@ object JGitUtil {
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) match {
|
||||
} match {
|
||||
case Some(child) => simplifyPath(child)
|
||||
case _ => tuple
|
||||
}
|
||||
@@ -468,7 +466,7 @@ object JGitUtil {
|
||||
(id, mode, name, path, opt, None)
|
||||
} else if (commitCount < 10000) {
|
||||
(id, mode, name, path, opt, Some(getCommit(path)))
|
||||
} else if (isCacheEnabled()) {
|
||||
} else if (isCacheEnabled) {
|
||||
// Use in-memory cache if the commit count is too big.
|
||||
val cached = objectCommitCache.getEntry(id)
|
||||
if (cached == null) {
|
||||
@@ -502,9 +500,13 @@ object JGitUtil {
|
||||
val linkUrl = if (treeWalk.getFileMode(0) == FileMode.GITLINK) {
|
||||
getSubmodules(git, revCommit.getTree, baseUrl).find(_.path == treeWalk.getPathString).map(_.viewerUrl)
|
||||
} else None
|
||||
fileList +:= (treeWalk.getObjectId(0), treeWalk.getFileMode(
|
||||
0
|
||||
), treeWalk.getNameString, treeWalk.getPathString, linkUrl)
|
||||
fileList +:= (
|
||||
treeWalk.getObjectId(0),
|
||||
treeWalk.getFileMode(0),
|
||||
treeWalk.getNameString,
|
||||
treeWalk.getPathString,
|
||||
linkUrl
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -552,9 +554,12 @@ object JGitUtil {
|
||||
def getTreeId(git: Git, revision: String): Option[String] = {
|
||||
Using.resource(new RevWalk(git.getRepository)) { revWalk =>
|
||||
val objectId = git.getRepository.resolve(revision)
|
||||
if (objectId == null) return None
|
||||
val revCommit = revWalk.parseCommit(objectId)
|
||||
Some(revCommit.getTree.name)
|
||||
if (objectId == null) {
|
||||
None
|
||||
} else {
|
||||
val revCommit = revWalk.parseCommit(objectId)
|
||||
Some(revCommit.getTree.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -562,20 +567,18 @@ object JGitUtil {
|
||||
* get all file list by tree object id.
|
||||
*/
|
||||
def getAllFileListByTreeId(git: Git, treeId: String): List[String] = {
|
||||
Using.resource(new RevWalk(git.getRepository)) { revWalk =>
|
||||
val objectId = git.getRepository.resolve(treeId + "^{tree}")
|
||||
if (objectId == null) return Nil
|
||||
Using.resource(new TreeWalk(git.getRepository)) { treeWalk =>
|
||||
treeWalk.addTree(objectId)
|
||||
treeWalk.setRecursive(true)
|
||||
var ret: List[String] = Nil
|
||||
if (treeWalk != null) {
|
||||
while (treeWalk.next()) {
|
||||
ret +:= treeWalk.getPathString
|
||||
}
|
||||
val objectId = git.getRepository.resolve(treeId + "^{tree}")
|
||||
if (objectId == null) return Nil
|
||||
Using.resource(new TreeWalk(git.getRepository)) { treeWalk =>
|
||||
treeWalk.addTree(objectId)
|
||||
treeWalk.setRecursive(true)
|
||||
var ret: List[String] = Nil
|
||||
if (treeWalk != null) {
|
||||
while (treeWalk.next()) {
|
||||
ret +:= treeWalk.getPathString
|
||||
}
|
||||
ret.reverse
|
||||
}
|
||||
ret.reverse
|
||||
}
|
||||
}
|
||||
|
||||
@@ -604,22 +607,21 @@ object JGitUtil {
|
||||
count: Int,
|
||||
logs: List[CommitInfo]
|
||||
): (List[CommitInfo], Boolean) =
|
||||
i.hasNext match {
|
||||
case true if (limit <= 0 || logs.size < limit) => {
|
||||
val commit = i.next
|
||||
getCommitLog(
|
||||
i,
|
||||
count + 1,
|
||||
if (limit <= 0 || (fixedPage - 1) * limit <= count) logs :+ new CommitInfo(commit) else logs
|
||||
)
|
||||
}
|
||||
case _ => (logs, i.hasNext)
|
||||
if (i.hasNext) {
|
||||
val commit = i.next
|
||||
getCommitLog(
|
||||
i,
|
||||
count + 1,
|
||||
if (limit <= 0 || (fixedPage - 1) * limit <= count) logs :+ new CommitInfo(commit) else logs
|
||||
)
|
||||
} else {
|
||||
(logs, i.hasNext)
|
||||
}
|
||||
|
||||
Using.resource(new RevWalk(git.getRepository)) { revWalk =>
|
||||
val objectId = git.getRepository.resolve(revision)
|
||||
if (objectId == null) {
|
||||
Left(s"${revision} can't be resolved.")
|
||||
Left(s"$revision can't be resolved.")
|
||||
} else {
|
||||
revWalk.markStart(revWalk.parseCommit(objectId))
|
||||
if (path.nonEmpty) {
|
||||
@@ -635,16 +637,15 @@ object JGitUtil {
|
||||
): List[CommitInfo] = {
|
||||
@scala.annotation.tailrec
|
||||
def getCommitLog(i: java.util.Iterator[RevCommit], logs: List[CommitInfo]): List[CommitInfo] =
|
||||
i.hasNext match {
|
||||
case true => {
|
||||
val revCommit = i.next
|
||||
if (endCondition(revCommit)) {
|
||||
if (includesLastCommit) logs :+ new CommitInfo(revCommit) else logs
|
||||
} else {
|
||||
getCommitLog(i, logs :+ new CommitInfo(revCommit))
|
||||
}
|
||||
if (i.hasNext) {
|
||||
val revCommit = i.next
|
||||
if (endCondition(revCommit)) {
|
||||
if (includesLastCommit) logs :+ new CommitInfo(revCommit) else logs
|
||||
} else {
|
||||
getCommitLog(i, logs :+ new CommitInfo(revCommit))
|
||||
}
|
||||
case false => logs
|
||||
} else {
|
||||
logs
|
||||
}
|
||||
|
||||
Using.resource(new RevWalk(git.getRepository)) { revWalk =>
|
||||
@@ -653,17 +654,62 @@ object JGitUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the commit list between two revisions.
|
||||
* `to` and `from` must be valid revision strings.
|
||||
*
|
||||
* @see [[org.eclipse.jgit.lib.Repository#resolve]]
|
||||
* @param git the Git object
|
||||
* @param from Must refer to a valid commit object.
|
||||
* @param to Must refer to a valid commit object.
|
||||
* @return The commits before 'to', that are not already present in the tree of 'from'.
|
||||
*/
|
||||
def getCommitLog(git: Git, from: String, to: String): List[CommitInfo] = {
|
||||
def resolveString(name: String): ObjectId = {
|
||||
val objectId = git.getRepository.resolve(name)
|
||||
git.getRepository.open(objectId).getType match {
|
||||
case Constants.OBJ_COMMIT => objectId
|
||||
case Constants.OBJ_TAG =>
|
||||
val ref = git.getRepository.getRefDatabase.findRef(name)
|
||||
git.getRepository.getRefDatabase.peel(ref).getPeeledObjectId
|
||||
case _ => ObjectId.zeroId()
|
||||
}
|
||||
}
|
||||
|
||||
getCommitLog(git, resolveString(from), resolveString(to))
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the commit list between two revisions.
|
||||
*
|
||||
* @param git the Git object
|
||||
* @param from the from revision
|
||||
* @param to the to revision
|
||||
* @return the commit list
|
||||
* @param from Must refer to a valid commit object.
|
||||
* @param to Must refer to a valid commit object.
|
||||
* @return The commits before 'to', that are not already present in the tree of 'from'.
|
||||
*/
|
||||
// TODO swap parameters 'from' and 'to'!?
|
||||
def getCommitLog(git: Git, from: String, to: String): List[CommitInfo] =
|
||||
getCommitLogs(git, to)(_.getName == from)
|
||||
def getCommitLog(git: Git, from: ObjectId, to: ObjectId): List[CommitInfo] =
|
||||
Option(from)
|
||||
.filter(f => f != ObjectId.zeroId)
|
||||
// find the common ancestor of the two commits
|
||||
.flatMap(f =>
|
||||
git
|
||||
.log()
|
||||
.add(f)
|
||||
.add(to)
|
||||
.setRevFilter(RevFilter.MERGE_BASE)
|
||||
.call()
|
||||
.asScala
|
||||
.headOption
|
||||
)
|
||||
.fold(
|
||||
git.log() // no stop condition when merge base with 'from' is not found
|
||||
)(f => git.log().not(f)) // we have a stop condition (start commit)
|
||||
.add(to)
|
||||
.call()
|
||||
.asScala
|
||||
.map(new CommitInfo(_))
|
||||
.toList
|
||||
.reverse
|
||||
|
||||
/**
|
||||
* Returns the latest RevCommit of the specified path.
|
||||
@@ -821,7 +867,7 @@ object JGitUtil {
|
||||
|
||||
private def getTextContent(git: Git, objectId: ObjectId): Option[String] = {
|
||||
JGitUtil
|
||||
.getContentFromId(git, objectId, false)
|
||||
.getContentFromId(git, objectId, fetchLargeFile = false)
|
||||
.filter(FileUtil.isText)
|
||||
.map(convertFromByteArray)
|
||||
}
|
||||
@@ -846,10 +892,7 @@ object JGitUtil {
|
||||
.getRefsByPrefix(Constants.R_HEADS)
|
||||
.asScala
|
||||
.filter { e =>
|
||||
(revWalk.isMergedInto(
|
||||
commit,
|
||||
revWalk.parseCommit(e.getObjectId)
|
||||
))
|
||||
revWalk.isMergedInto(commit, revWalk.parseCommit(e.getObjectId))
|
||||
}
|
||||
.map { e =>
|
||||
e.getName.substring(Constants.R_HEADS.length)
|
||||
@@ -888,10 +931,7 @@ object JGitUtil {
|
||||
.getRefsByPrefix(Constants.R_TAGS)
|
||||
.asScala
|
||||
.filter { e =>
|
||||
(revWalk.isMergedInto(
|
||||
commit,
|
||||
revWalk.parseCommit(e.getObjectId)
|
||||
))
|
||||
revWalk.isMergedInto(commit, revWalk.parseCommit(e.getObjectId))
|
||||
}
|
||||
.map { e =>
|
||||
e.getName.substring(Constants.R_TAGS.length)
|
||||
@@ -918,7 +958,7 @@ object JGitUtil {
|
||||
private def setReceivePack(repository: org.eclipse.jgit.lib.Repository): Unit = {
|
||||
val config = repository.getConfig
|
||||
config.setBoolean("http", null, "receivepack", true)
|
||||
config.save
|
||||
config.save()
|
||||
}
|
||||
|
||||
def getDefaultBranch(
|
||||
@@ -935,7 +975,7 @@ object JGitUtil {
|
||||
}.find(_._1 != null)
|
||||
}
|
||||
|
||||
def createTag(git: Git, name: String, message: Option[String], commitId: String) = {
|
||||
def createTag(git: Git, name: String, message: Option[String], commitId: String): Either[String, String] = {
|
||||
try {
|
||||
val objectId: ObjectId = git.getRepository.resolve(commitId)
|
||||
Using.resource(new RevWalk(git.getRepository)) { walk =>
|
||||
@@ -954,7 +994,7 @@ object JGitUtil {
|
||||
}
|
||||
}
|
||||
|
||||
def createBranch(git: Git, fromBranch: String, newBranch: String) = {
|
||||
def createBranch(git: Git, fromBranch: String, newBranch: String): Either[String, String] = {
|
||||
try {
|
||||
git.branchCreate().setStartPoint(fromBranch).setName(newBranch).call()
|
||||
Right("Branch created.")
|
||||
@@ -1009,19 +1049,18 @@ object JGitUtil {
|
||||
*/
|
||||
def getSubmodules(git: Git, tree: RevTree, baseUrl: Option[String]): List[SubmoduleInfo] = {
|
||||
val repository = git.getRepository
|
||||
getContentFromPath(git, tree, ".gitmodules", true).map { bytes =>
|
||||
getContentFromPath(git, tree, ".gitmodules", fetchLargeFile = true).map { bytes =>
|
||||
(try {
|
||||
val config = new BlobBasedConfig(repository.getConfig(), bytes)
|
||||
val config = new BlobBasedConfig(repository.getConfig, bytes)
|
||||
config.getSubsections("submodule").asScala.map { module =>
|
||||
val path = config.getString("submodule", module, "path")
|
||||
val url = config.getString("submodule", module, "url")
|
||||
SubmoduleInfo(module, path, url, StringUtil.getRepositoryViewerUrl(url, baseUrl))
|
||||
}
|
||||
} catch {
|
||||
case e: ConfigInvalidException => {
|
||||
logger.error("Failed to load .gitmodules file for " + repository.getDirectory(), e)
|
||||
case e: ConfigInvalidException =>
|
||||
logger.error("Failed to load .gitmodules file for " + repository.getDirectory, e)
|
||||
Nil
|
||||
}
|
||||
}).toList
|
||||
} getOrElse Nil
|
||||
}
|
||||
@@ -1039,9 +1078,9 @@ object JGitUtil {
|
||||
@scala.annotation.tailrec
|
||||
def getPathObjectId(path: String, walk: TreeWalk): Option[ObjectId] =
|
||||
walk.next match {
|
||||
case true if (walk.getPathString == path) => Some(walk.getObjectId(0))
|
||||
case true => getPathObjectId(path, walk)
|
||||
case false => None
|
||||
case true if walk.getPathString == path => Some(walk.getObjectId(0))
|
||||
case true => getPathObjectId(path, walk)
|
||||
case false => None
|
||||
}
|
||||
|
||||
Using.resource(new TreeWalk(git.getRepository)) { treeWalk =>
|
||||
@@ -1094,7 +1133,7 @@ object JGitUtil {
|
||||
val isLfs = isLfsPointer(loader)
|
||||
val large = FileUtil.isLarge(loader.getSize)
|
||||
val viewer = if (FileUtil.isImage(path, safeMode)) "image" else if (large) "large" else "other"
|
||||
val bytes = if (viewer == "other") JGitUtil.getContentFromId(git, objectId, false) else None
|
||||
val bytes = if (viewer == "other") JGitUtil.getContentFromId(git, objectId, fetchLargeFile = false) else None
|
||||
val size = Some(getContentSize(loader))
|
||||
|
||||
if (viewer == "other") {
|
||||
@@ -1129,7 +1168,7 @@ object JGitUtil {
|
||||
try {
|
||||
Using.resource(git.getRepository.getObjectDatabase) { db =>
|
||||
val loader = db.open(id)
|
||||
if (loader.isLarge || (fetchLargeFile == false && FileUtil.isLarge(loader.getSize))) {
|
||||
if (loader.isLarge || (!fetchLargeFile && FileUtil.isLarge(loader.getSize))) {
|
||||
None
|
||||
} else {
|
||||
Some(loader.getBytes)
|
||||
@@ -1199,7 +1238,7 @@ object JGitUtil {
|
||||
requestBranch: String
|
||||
): String = {
|
||||
val existIds = getAllCommitIds(oldGit)
|
||||
getCommitLogs(newGit, requestBranch, true) { commit =>
|
||||
getCommitLogs(newGit, requestBranch, includesLastCommit = true) { commit =>
|
||||
existIds.contains(commit.name) && getBranchesOfCommit(oldGit, commit.getName).contains(branch)
|
||||
}.head.id
|
||||
}
|
||||
@@ -1223,10 +1262,10 @@ object JGitUtil {
|
||||
) { (oldGit, newGit) =>
|
||||
oldGit.fetch
|
||||
.setRemote(Directory.getRepositoryDir(requestUserName, requestRepositoryName).toURI.toString)
|
||||
.setRefSpecs(new RefSpec(s"refs/heads/${requestBranch}:refs/pull/${issueId}/head").setForceUpdate(true))
|
||||
.setRefSpecs(new RefSpec(s"refs/heads/$requestBranch:refs/pull/$issueId/head").setForceUpdate(true))
|
||||
.call
|
||||
|
||||
val commitIdTo = oldGit.getRepository.resolve(s"refs/pull/${issueId}/head").getName
|
||||
val commitIdTo = oldGit.getRepository.resolve(s"refs/pull/$issueId/head").getName
|
||||
val commitIdFrom = getForkedCommitId(
|
||||
oldGit,
|
||||
newGit,
|
||||
@@ -1252,9 +1291,8 @@ object JGitUtil {
|
||||
git.log.add(startCommit).addPath(path).setMaxCount(1).call.iterator.next
|
||||
}
|
||||
|
||||
def getBranchesNoMergeInfo(git: Git, defaultBranch: String): Seq[BranchInfoSimple] = {
|
||||
def getBranchesNoMergeInfo(git: Git): Seq[BranchInfoSimple] = {
|
||||
val repo = git.getRepository
|
||||
val defaultObject = repo.resolve(defaultBranch)
|
||||
|
||||
git.branchList.call.asScala.map { ref =>
|
||||
val walk = new RevWalk(repo)
|
||||
@@ -1318,7 +1356,7 @@ object JGitUtil {
|
||||
val blame = blamer.call()
|
||||
var blameMap = Map[String, JGitUtil.BlameInfo]()
|
||||
var idLine = List[(String, Int)]()
|
||||
0.until(blame.getResultContents().size()).foreach { i =>
|
||||
0.until(blame.getResultContents.size()).foreach { i =>
|
||||
val c = blame.getSourceCommit(i)
|
||||
if (!blameMap.contains(c.name)) {
|
||||
blameMap += c.name -> JGitUtil.BlameInfo(
|
||||
@@ -1355,7 +1393,7 @@ object JGitUtil {
|
||||
*/
|
||||
def getShaByRef(owner: String, name: String, revstr: String): Option[String] = {
|
||||
Using.resource(Git.open(getRepositoryDir(owner, name))) { git =>
|
||||
Option(git.getRepository.resolve(revstr)).map(ObjectId.toString(_))
|
||||
Option(git.getRepository.resolve(revstr)).map(ObjectId.toString)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,7 @@ package gitbucket.core.util
|
||||
import gitbucket.core.model.Account
|
||||
import gitbucket.core.service.SystemSettingsService
|
||||
import gitbucket.core.service.SystemSettingsService.Ldap
|
||||
import com.novell.ldap._
|
||||
import java.security.{Provider, Security}
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import com.novell.ldap.*
|
||||
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
@@ -19,8 +17,7 @@ object LDAPUtil {
|
||||
private val LDAP_VERSION: Int = LDAPConnection.LDAP_V3
|
||||
private val LDAP_DUMMY_MAL = "@ldap-devnull"
|
||||
|
||||
private val logger = LoggerFactory.getLogger(getClass().getName())
|
||||
private val provider = new AtomicReference[Provider](null)
|
||||
private val logger = LoggerFactory.getLogger(getClass.getName)
|
||||
|
||||
/**
|
||||
* Returns true if mail address ends with "@ldap-devnull"
|
||||
@@ -119,34 +116,10 @@ object LDAPUtil {
|
||||
private def getUserNameFromMailAddress(userName: String): String = {
|
||||
(userName.indexOf('@') match {
|
||||
case i if i >= 0 => userName.substring(0, i)
|
||||
case i => userName
|
||||
case _ => userName
|
||||
}).replaceAll("[^a-zA-Z0-9\\-_.]", "").replaceAll("^[_\\-]", "")
|
||||
}
|
||||
|
||||
private def getSslProvider(): Provider = {
|
||||
import scala.language.existentials
|
||||
|
||||
val cachedInstance = provider.get()
|
||||
if (cachedInstance == null) {
|
||||
val cls =
|
||||
try {
|
||||
Class.forName("com.sun.net.ssl.internal.ssl.Provider")
|
||||
} catch {
|
||||
case e: ClassNotFoundException =>
|
||||
Class.forName("com.ibm.jsse.IBMJSSEProvider")
|
||||
case e: Throwable => throw e
|
||||
}
|
||||
val newInstance = cls
|
||||
.getDeclaredConstructor()
|
||||
.newInstance()
|
||||
.asInstanceOf[Provider]
|
||||
provider.compareAndSet(null, newInstance)
|
||||
newInstance
|
||||
} else {
|
||||
cachedInstance
|
||||
}
|
||||
}
|
||||
|
||||
private def bind[A](
|
||||
host: String,
|
||||
port: Int,
|
||||
@@ -158,9 +131,6 @@ object LDAPUtil {
|
||||
error: String
|
||||
)(f: LDAPConnection => Either[String, A]): Either[String, A] = {
|
||||
if (tls || ssl) {
|
||||
// Dynamically set Sun as the security provider
|
||||
Security.addProvider(getSslProvider())
|
||||
|
||||
if (keystore.compareTo("") != 0) {
|
||||
// Dynamically set the property that JSSE uses to identify
|
||||
// the keystore that holds trusted root certificates
|
||||
@@ -191,7 +161,7 @@ object LDAPUtil {
|
||||
f(conn)
|
||||
|
||||
} catch {
|
||||
case e: Exception => {
|
||||
case e: Exception =>
|
||||
// Provide more information if something goes wrong
|
||||
logger.info("" + e)
|
||||
|
||||
@@ -200,7 +170,6 @@ object LDAPUtil {
|
||||
}
|
||||
// Returns an error message
|
||||
Left(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,7 +191,7 @@ object LDAPUtil {
|
||||
entries :+ (try {
|
||||
Option(results.next)
|
||||
} catch {
|
||||
case ex: LDAPReferralException => None // NOTE(tanacasino): Referral follow is off. so ignores it.(for AD)
|
||||
case _: LDAPReferralException => None // NOTE(tanacasino): Referral follow is off. so ignores it.(for AD)
|
||||
})
|
||||
)
|
||||
} else {
|
||||
|
||||
@@ -53,8 +53,8 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache
|
||||
def datetimeAgoRecentOnly(date: Date): String = {
|
||||
val duration = new Date().getTime - date.getTime
|
||||
timeUnits.find(tuple => duration / tuple._1 > 0) match {
|
||||
case Some((_, "month")) => s"on ${new SimpleDateFormat("d MMM", Locale.ENGLISH).format(date)}"
|
||||
case Some((_, "year")) => s"on ${new SimpleDateFormat("d MMM yyyy", Locale.ENGLISH).format(date)}"
|
||||
case Some((_, "month")) => s"on ${new SimpleDateFormat("d MMM", Locale.ENGLISH).format(date)}"
|
||||
case Some((_, "year")) => s"on ${new SimpleDateFormat("d MMM yyyy", Locale.ENGLISH).format(date)}"
|
||||
case Some((unitValue, unitString)) =>
|
||||
val value = duration / unitValue
|
||||
s"${value} ${unitString}${if (value > 1) "s" else ""} ago"
|
||||
|
||||
@@ -159,5 +159,10 @@
|
||||
@Html(script)
|
||||
</script>
|
||||
}
|
||||
@if(context.settings.userDefinedCss.isDefined) {
|
||||
<script>
|
||||
$('head').append($('<link rel="stylesheet" type="text/css" href="@context.baseUrl/user.css">'))
|
||||
</script>
|
||||
}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -21,45 +21,47 @@
|
||||
@import gitbucket.core.view.helpers
|
||||
@gitbucket.core.html.main(s"Pull requests - ${repository.owner}/${repository.name}", Some(repository)){
|
||||
@gitbucket.core.html.menu("pulls", repository){
|
||||
<div class="pullreq-info">
|
||||
<div id="compare-edit">
|
||||
@gitbucket.core.helper.html.dropdown(originRepository.owner + "/" + originRepository.name, "base fork", filter=("origin_repo", "Find Repository...")) {
|
||||
@members.map { case (owner, name, defaultBranch) =>
|
||||
<li><a href="#" class="origin-owner" data-owner="@owner" data-name="@name" data-default-branch="@defaultBranch">@gitbucket.core.helper.html.checkicon(owner == originRepository.owner) @owner/@name</a></li>
|
||||
<form method="POST" action="@context.path/@originRepository.owner/@originRepository.name/pulls/new" validate="true">
|
||||
<div class="pullreq-info">
|
||||
<div id="compare-edit">
|
||||
@gitbucket.core.helper.html.dropdown(originRepository.owner + "/" + originRepository.name, "base fork", filter=("origin_repo", "Find Repository...")) {
|
||||
@members.map { case (owner, name, defaultBranch) =>
|
||||
<li><a href="#" class="origin-owner" data-owner="@owner" data-name="@name" data-default-branch="@defaultBranch">@gitbucket.core.helper.html.checkicon(owner == originRepository.owner) @owner/@name</a></li>
|
||||
}
|
||||
}
|
||||
}
|
||||
@gitbucket.core.helper.html.dropdown(originId, "base", filter=("origin_branch", "Find Branch...")) {
|
||||
@if(!originRepository.branchList.contains(originId)){
|
||||
<li><a href="#" class="origin-branch" data-branch="@helpers.encodeRefName(originId)">@gitbucket.core.helper.html.checkicon(true) @originId</a></li>
|
||||
@gitbucket.core.helper.html.dropdown(originId, "base", filter=("origin_branch", "Find Branch...")) {
|
||||
@if(!originRepository.branchList.contains(originId)){
|
||||
<li><a href="#" class="origin-branch" data-branch="@helpers.encodeRefName(originId)">@gitbucket.core.helper.html.checkicon(true) @originId</a></li>
|
||||
}
|
||||
@originRepository.branchList.map { branch =>
|
||||
<li><a href="#" class="origin-branch" data-branch="@helpers.encodeRefName(branch)">@gitbucket.core.helper.html.checkicon(branch == originId) @branch</a></li>
|
||||
}
|
||||
}
|
||||
@originRepository.branchList.map { branch =>
|
||||
<li><a href="#" class="origin-branch" data-branch="@helpers.encodeRefName(branch)">@gitbucket.core.helper.html.checkicon(branch == originId) @branch</a></li>
|
||||
<span class="error" id="error-targetBranch"></span>
|
||||
...
|
||||
@gitbucket.core.helper.html.dropdown(forkedRepository.owner + "/" + forkedRepository.name, "head fork", filter=("forked_repo", "Find Repository...")) {
|
||||
@members.map { case (owner, name, defaultBranch) =>
|
||||
<li><a href="#" class="forked-owner" data-owner="@owner" data-name="@name" data-default-branch="@defaultBranch">@gitbucket.core.helper.html.checkicon(owner == forkedRepository.owner) @owner/@name</a></li>
|
||||
}
|
||||
}
|
||||
}
|
||||
...
|
||||
@gitbucket.core.helper.html.dropdown(forkedRepository.owner + "/" + forkedRepository.name, "head fork", filter=("forked_repo", "Find Repository...")) {
|
||||
@members.map { case (owner, name, defaultBranch) =>
|
||||
<li><a href="#" class="forked-owner" data-owner="@owner" data-name="@name" data-default-branch="@defaultBranch">@gitbucket.core.helper.html.checkicon(owner == forkedRepository.owner) @owner/@name</a></li>
|
||||
}
|
||||
}
|
||||
@gitbucket.core.helper.html.dropdown(forkedId, "compare", filter=("forked_branch", "Find Branch...")) {
|
||||
@if(!forkedRepository.branchList.contains(forkedId)){
|
||||
<li><a href="#" class="origin-branch" data-branch="@helpers.encodeRefName(forkedId)">@gitbucket.core.helper.html.checkicon(true) @forkedId</a></li>
|
||||
}
|
||||
@forkedRepository.branchList.map { branch =>
|
||||
<li><a href="#" class="forked-branch" data-branch="@helpers.encodeRefName(branch)">@gitbucket.core.helper.html.checkicon(branch == forkedId) @branch</a></li>
|
||||
@gitbucket.core.helper.html.dropdown(forkedId, "compare", filter=("forked_branch", "Find Branch...")) {
|
||||
@if(!forkedRepository.branchList.contains(forkedId)){
|
||||
<li><a href="#" class="origin-branch" data-branch="@helpers.encodeRefName(forkedId)">@gitbucket.core.helper.html.checkicon(true) @forkedId</a></li>
|
||||
}
|
||||
@forkedRepository.branchList.map { branch =>
|
||||
<li><a href="#" class="forked-branch" data-branch="@helpers.encodeRefName(branch)">@gitbucket.core.helper.html.checkicon(branch == forkedId) @branch</a></li>
|
||||
}
|
||||
}
|
||||
<span class="error" id="error-requestBranch"></span>
|
||||
</div>
|
||||
@if(originRepository.branchList.contains(originId) && forkedRepository.branchList.contains(forkedId)){
|
||||
<div class="check-conflict" style="display: none;">
|
||||
<img src="@helpers.assets("/common/images/indicator.gif")"/> Checking...
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@if(originRepository.branchList.contains(originId) && forkedRepository.branchList.contains(forkedId)){
|
||||
<div class="check-conflict" style="display: none;">
|
||||
<img src="@helpers.assets("/common/images/indicator.gif")"/> Checking...
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@if(commits.nonEmpty && context.loginAccount.isDefined && originRepository.branchList.contains(originId) && forkedRepository.branchList.contains(forkedId)){
|
||||
<div id="pull-request-form" style="margin-bottom: 20px;">
|
||||
<form method="POST" action="@context.path/@originRepository.owner/@originRepository.name/pulls/new" validate="true">
|
||||
@if(commits.nonEmpty && context.loginAccount.isDefined && originRepository.branchList.contains(originId) && forkedRepository.branchList.contains(forkedId)){
|
||||
<div id="pull-request-form" style="margin-bottom: 20px;">
|
||||
<div class="row">
|
||||
<div class="col-md-9">
|
||||
<span class="error" id="error-title"></span>
|
||||
@@ -113,9 +115,9 @@
|
||||
)
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</form>
|
||||
@if(commits.isEmpty){
|
||||
<div class="panel panel-default" style="padding: 20px; background-color: #eee; text-align: center;">
|
||||
<h4>There isn't anything to compare.</h4>
|
||||
|
||||
@@ -37,8 +37,8 @@
|
||||
</div>
|
||||
}
|
||||
@if(isManageableForkedRepository && issue.closed && merged &&
|
||||
forkedRepository.map(r => (r.branchList.contains(pullreq.requestBranch) && r.repository.defaultBranch != pullreq.requestBranch)).getOrElse(false)){
|
||||
<div class="issue-comment-box" style="background-color: #d0eeff;">
|
||||
forkedRepository.exists(r => r.branchList.contains(pullreq.requestBranch) && r.repository.defaultBranch != pullreq.requestBranch)){
|
||||
<div class="issue-comment-box" style="background-color: #d0eeff; margin-bottom: 20px;">
|
||||
<div class="box-content" style="border: 1px solid #87a8c9; padding: 10px;">
|
||||
<a href="@helpers.url(repository)/pull/@issue.issueId/delete_branch" class="btn btn-info pull-right delete-branch" data-name="@pullreq.requestBranch">Delete branch</a>
|
||||
<div>
|
||||
|
||||
@@ -158,11 +158,15 @@ class ApiIntegrationTest extends AnyFunSuite {
|
||||
// get tag v1.0
|
||||
{
|
||||
Using.resource(Git.open(new File(server.getDirectory(), "repositories/root/create_status_test"))) { git =>
|
||||
git.tag().setName("v1.0").call()
|
||||
git.tag().setName("v1.0").call().getPeeledObjectId
|
||||
}
|
||||
val ref = repo.getRef("tags/v1.0")
|
||||
assert(ref.getRef == "refs/tags/v1.0")
|
||||
assert(ref.getUrl.toString == "http://localhost:19999/api/v3/repos/root/create_status_test/git/refs/tags/v1.0")
|
||||
|
||||
val tags = repo.listTags().toList
|
||||
assert(tags.size() == 1)
|
||||
assert(tags.get(0).getName == "v1.0")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package gitbucket.core.service
|
||||
|
||||
import gitbucket.core.model._
|
||||
import gitbucket.core.model.*
|
||||
import org.scalatest.funsuite.AnyFunSuite
|
||||
import gitbucket.core.model.Profile._
|
||||
import gitbucket.core.model.Profile.profile.blockingApi._
|
||||
import gitbucket.core.model.Profile.*
|
||||
import gitbucket.core.model.Profile.profile.blockingApi.*
|
||||
|
||||
class AccessTokenServiceSpec extends AnyFunSuite with ServiceSpecBase {
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ class AccountServiceSpec extends AnyFunSuite with ServiceSpecBase {
|
||||
assert(user().lastLoginDate.isEmpty)
|
||||
|
||||
val date1 = new Date
|
||||
Thread.sleep(1000)
|
||||
AccountService.updateLastLoginDate(root)
|
||||
assert(user().lastLoginDate.get.compareTo(date1) > 0)
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package gitbucket.core.service
|
||||
|
||||
import gitbucket.core.model._
|
||||
import gitbucket.core.model.Profile._
|
||||
import gitbucket.core.model.Profile.profile.blockingApi._
|
||||
import gitbucket.core.model.*
|
||||
import gitbucket.core.model.Profile.*
|
||||
import gitbucket.core.model.Profile.profile.blockingApi.*
|
||||
import gitbucket.core.model.Session
|
||||
import org.scalatest.funsuite.AnyFunSuite
|
||||
|
||||
class CommitStatusServiceSpec
|
||||
@@ -12,7 +13,7 @@ class CommitStatusServiceSpec
|
||||
with RepositoryService
|
||||
with AccountService {
|
||||
val now = new java.util.Date()
|
||||
val fixture1 = CommitStatus(
|
||||
val fixture1: CommitStatus = CommitStatus(
|
||||
userName = "root",
|
||||
repositoryName = "repo",
|
||||
commitId = "0e97b8f59f7cdd709418bb59de53f741fd1c1bd7",
|
||||
@@ -24,8 +25,9 @@ class CommitStatusServiceSpec
|
||||
updatedDate = now,
|
||||
registeredDate = now
|
||||
)
|
||||
def findById(id: Int)(implicit s: Session) = CommitStatuses.filter(_.byPrimaryKey(id)).firstOption
|
||||
def generateFixture1(tester: Account)(implicit s: Session) =
|
||||
def findById(id: Int)(implicit s: Session): Option[CommitStatus] =
|
||||
CommitStatuses.filter(_.byPrimaryKey(id)).firstOption
|
||||
def generateFixture1(tester: Account)(implicit s: Session): Int =
|
||||
createCommitStatus(
|
||||
userName = fixture1.userName,
|
||||
repositoryName = fixture1.repositoryName,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package gitbucket.core.service
|
||||
|
||||
import gitbucket.core.model._
|
||||
import gitbucket.core.model.*
|
||||
import org.scalatest.funspec.AnyFunSpec
|
||||
|
||||
class LabelsServiceSpec extends AnyFunSpec with ServiceSpecBase {
|
||||
|
||||
@@ -1,31 +1,32 @@
|
||||
package gitbucket.core.service
|
||||
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.eclipse.jgit.revwalk._
|
||||
import org.eclipse.jgit.revwalk.*
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler
|
||||
import org.scalatest.funspec.AnyFunSpec
|
||||
|
||||
import java.io.File
|
||||
import java.util.Date
|
||||
import java.net.InetSocketAddress
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
||||
import javax.servlet.http.{HttpServletRequest, HttpServletResponse}
|
||||
|
||||
import scala.util.Using
|
||||
import scala.jdk.CollectionConverters._
|
||||
import scala.jdk.CollectionConverters.*
|
||||
import gitbucket.core.controller.Context
|
||||
import gitbucket.core.plugin.ReceiveHook
|
||||
import gitbucket.core.util.Directory._
|
||||
import gitbucket.core.util.GitSpecUtil._
|
||||
import gitbucket.core.util.Directory.*
|
||||
import gitbucket.core.util.GitSpecUtil.*
|
||||
import gitbucket.core.service.RepositoryService.RepositoryInfo
|
||||
import gitbucket.core.model._
|
||||
import gitbucket.core.model.Profile._
|
||||
import gitbucket.core.model.Profile.profile.blockingApi._
|
||||
import gitbucket.core.model.*
|
||||
import gitbucket.core.model.Profile.*
|
||||
import gitbucket.core.model.Profile.profile.blockingApi.*
|
||||
import gitbucket.core.model.Session
|
||||
import org.eclipse.jetty.webapp.WebAppContext
|
||||
import org.eclipse.jetty.server.{Request, Server}
|
||||
import org.json4s.jackson.JsonMethods._
|
||||
import org.json4s.jvalue2monadic
|
||||
import MergeServiceSpec._
|
||||
import org.json4s.jackson.JsonMethods.*
|
||||
import org.json4s.{Formats, jvalue2monadic}
|
||||
import MergeServiceSpec.*
|
||||
import org.eclipse.jgit.lib.ObjectId
|
||||
import org.json4s.JsonAST.{JArray, JString}
|
||||
|
||||
class MergeServiceSpec extends AnyFunSpec with ServiceSpecBase {
|
||||
@@ -54,7 +55,7 @@ class MergeServiceSpec extends AnyFunSpec with ServiceSpecBase {
|
||||
}
|
||||
dir
|
||||
}
|
||||
def createConfrict(git: Git) = {
|
||||
def createConfrict(git: Git): ObjectId = {
|
||||
createFile(git, s"refs/heads/${branch}", "test.txt", "hoge2")
|
||||
createFile(git, s"refs/pull/${issueId}/head", "test.txt", "hoge4")
|
||||
}
|
||||
@@ -141,14 +142,14 @@ class MergeServiceSpec extends AnyFunSpec with ServiceSpecBase {
|
||||
}
|
||||
describe("mergePullRequest") {
|
||||
it("can merge") {
|
||||
implicit val jsonFormats = gitbucket.core.api.JsonFormat.jsonFormats
|
||||
import gitbucket.core.util.Implicits._
|
||||
implicit val jsonFormats: Formats = gitbucket.core.api.JsonFormat.jsonFormats
|
||||
import gitbucket.core.util.Implicits.*
|
||||
|
||||
withTestDB { implicit session =>
|
||||
generateNewUserWithDBRepository("user1", "repo8")
|
||||
initRepository("user1", "repo8")
|
||||
|
||||
implicit val context = Context(
|
||||
implicit val context: Context = Context(
|
||||
createSystemSettings(),
|
||||
Some(createAccount("dummy2", "dummy2-fullname", "dummy2@example.com")),
|
||||
request
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package gitbucket.core.service
|
||||
|
||||
import gitbucket.core.util.GitSpecUtil._
|
||||
import gitbucket.core.util.GitSpecUtil.*
|
||||
import org.eclipse.jgit.transport.{ReceivePack, ReceiveCommand}
|
||||
import org.eclipse.jgit.lib.ObjectId
|
||||
import gitbucket.core.model.CommitState
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package gitbucket.core.service
|
||||
|
||||
import gitbucket.core.model._
|
||||
import gitbucket.core.model.*
|
||||
import org.scalatest.funspec.AnyFunSpec
|
||||
|
||||
class PullRequestServiceSpec
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package gitbucket.core.service
|
||||
|
||||
import gitbucket.core.model._
|
||||
import gitbucket.core.model.*
|
||||
import org.scalatest.funsuite.AnyFunSuite
|
||||
|
||||
class RepositoryServiceSpec extends AnyFunSuite with ServiceSpecBase with RepositoryService with AccountService {
|
||||
|
||||
@@ -5,8 +5,9 @@ import gitbucket.core.util.{DatabaseConfig, Directory, FileUtil, JGitUtil}
|
||||
import io.github.gitbucket.solidbase.Solidbase
|
||||
import liquibase.database.core.H2Database
|
||||
import liquibase.database.jvm.JdbcConnection
|
||||
import gitbucket.core.model._
|
||||
import gitbucket.core.model.Profile.profile.blockingApi._
|
||||
import gitbucket.core.model.*
|
||||
import gitbucket.core.model.Profile.profile.blockingApi.*
|
||||
import gitbucket.core.model.Session
|
||||
import org.apache.commons.io.FileUtils
|
||||
|
||||
import java.sql.DriverManager
|
||||
@@ -21,21 +22,21 @@ import gitbucket.core.service.SystemSettingsService.{
|
||||
}
|
||||
|
||||
import javax.servlet.http.{HttpServletRequest, HttpSession}
|
||||
import org.mockito.Mockito._
|
||||
import org.mockito.Mockito.*
|
||||
|
||||
import scala.util.Random
|
||||
import scala.util.Using
|
||||
|
||||
trait ServiceSpecBase {
|
||||
|
||||
val request = mock(classOf[HttpServletRequest])
|
||||
val session = mock(classOf[HttpSession])
|
||||
val request: HttpServletRequest = mock(classOf[HttpServletRequest])
|
||||
val session: HttpSession = mock(classOf[HttpSession])
|
||||
when(request.getRequestURL).thenReturn(new StringBuffer("http://localhost:8080/path.html"))
|
||||
when(request.getRequestURI).thenReturn("/path.html")
|
||||
when(request.getContextPath).thenReturn("")
|
||||
when(request.getSession).thenReturn(session)
|
||||
|
||||
def createSystemSettings() =
|
||||
def createSystemSettings(): SystemSettings =
|
||||
SystemSettings(
|
||||
baseUrl = None,
|
||||
information = None,
|
||||
|
||||
@@ -90,7 +90,7 @@ class SystemSettingsServiceSpec extends AnyWordSpecLike with Matchers {
|
||||
"getUrl" which {
|
||||
"returns the port number when not using port 22" in new MockContext {
|
||||
override val port = 8022
|
||||
sshAddress.getUrl shouldBe "git@code.these.solutions:8022"
|
||||
sshAddress.getUrl shouldBe "ssh://git@code.these.solutions:8022"
|
||||
}
|
||||
"leaves off the port number when using port 22" in new MockContext {
|
||||
override val port = 22
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package gitbucket.core.service
|
||||
|
||||
import gitbucket.core.api.JsonFormat
|
||||
import gitbucket.core.service.WebHookService._
|
||||
import gitbucket.core.service.WebHookService.*
|
||||
import org.scalatest.Assertion
|
||||
import org.scalatest.funsuite.AnyFunSuite
|
||||
|
||||
class WebHookJsonFormatSpec extends AnyFunSuite {
|
||||
import gitbucket.core.api.ApiSpecModels._
|
||||
import gitbucket.core.api.ApiSpecModels.*
|
||||
|
||||
private def assert(payload: WebHookPayload, expected: String): Assertion = {
|
||||
val json = JsonFormat(payload)
|
||||
@@ -34,7 +34,7 @@ class WebHookJsonFormatSpec extends AnyFunSuite {
|
||||
}
|
||||
|
||||
test("WebHookPushPayload") {
|
||||
import gitbucket.core.util.GitSpecUtil._
|
||||
import gitbucket.core.util.GitSpecUtil.*
|
||||
import org.eclipse.jgit.lib.{Constants, ObjectId}
|
||||
|
||||
withTestRepository { git =>
|
||||
|
||||
@@ -13,10 +13,10 @@ class JGitUtilSpec extends AnyFunSuite {
|
||||
|
||||
test("isEmpty") {
|
||||
withTestRepository { git =>
|
||||
assert(JGitUtil.isEmpty(git) == true)
|
||||
assert(JGitUtil.isEmpty(git))
|
||||
|
||||
createFile(git, Constants.HEAD, "README.md", "body1", message = "commit1")
|
||||
assert(JGitUtil.isEmpty(git) == false)
|
||||
assert(!JGitUtil.isEmpty(git))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,13 +31,13 @@ class JGitUtilSpec extends AnyFunSuite {
|
||||
createFile(git, Constants.HEAD, "README.md", "body1\nbody2", message = "commit1")
|
||||
|
||||
// latest commit
|
||||
val diff1 = JGitUtil.getDiffs(git, None, "main", false, true)
|
||||
val diff1 = JGitUtil.getDiffs(git, None, "main", fetchContent = false, makePatch = true)
|
||||
assert(diff1.size == 1)
|
||||
assert(diff1(0).changeType == ChangeType.MODIFY)
|
||||
assert(diff1(0).oldPath == "README.md")
|
||||
assert(diff1(0).newPath == "README.md")
|
||||
assert(diff1(0).tooLarge == false)
|
||||
assert(diff1(0).patch == Some("""@@ -1 +1,2 @@
|
||||
assert(!diff1(0).tooLarge)
|
||||
assert(diff1(0).patch.contains("""@@ -1 +1,2 @@
|
||||
|-body1
|
||||
|\ No newline at end of file
|
||||
|+body1
|
||||
@@ -45,13 +45,13 @@ class JGitUtilSpec extends AnyFunSuite {
|
||||
|\ No newline at end of file""".stripMargin))
|
||||
|
||||
// from specified commit
|
||||
val diff2 = JGitUtil.getDiffs(git, Some(commit.getName), "main", false, true)
|
||||
val diff2 = JGitUtil.getDiffs(git, Some(commit.getName), "main", fetchContent = false, makePatch = true)
|
||||
assert(diff2.size == 2)
|
||||
assert(diff2(0).changeType == ChangeType.ADD)
|
||||
assert(diff2(0).oldPath == "/dev/null")
|
||||
assert(diff2(0).newPath == "LICENSE")
|
||||
assert(diff2(0).tooLarge == false)
|
||||
assert(diff2(0).patch == Some("""+++ b/LICENSE
|
||||
assert(!diff2(0).tooLarge)
|
||||
assert(diff2(0).patch.contains("""+++ b/LICENSE
|
||||
|@@ -0,0 +1 @@
|
||||
|+Apache License
|
||||
|\ No newline at end of file""".stripMargin))
|
||||
@@ -59,8 +59,8 @@ class JGitUtilSpec extends AnyFunSuite {
|
||||
assert(diff2(1).changeType == ChangeType.MODIFY)
|
||||
assert(diff2(1).oldPath == "README.md")
|
||||
assert(diff2(1).newPath == "README.md")
|
||||
assert(diff2(1).tooLarge == false)
|
||||
assert(diff2(1).patch == Some("""@@ -1 +1,2 @@
|
||||
assert(!diff2(1).tooLarge)
|
||||
assert(diff2(1).patch.contains("""@@ -1 +1,2 @@
|
||||
|-body1
|
||||
|\ No newline at end of file
|
||||
|+body1
|
||||
@@ -119,6 +119,62 @@ class JGitUtilSpec extends AnyFunSuite {
|
||||
}
|
||||
}
|
||||
|
||||
test("getCommitLog") {
|
||||
withTestRepository { git =>
|
||||
/** repo looks like this
|
||||
* commit1 -> commit2 -> commit3 [main]
|
||||
* \-> commit4 [branch1]
|
||||
* */
|
||||
val root = git.getRepository.resolve("main")
|
||||
|
||||
createFile(git, Constants.HEAD, "README.md", "body1", message = "commit1")
|
||||
val commit1 = git.getRepository.resolve("main")
|
||||
|
||||
createFile(git, Constants.HEAD, "LICENSE", "Apache License", message = "commit2")
|
||||
val commit2 = git.getRepository.resolve("main")
|
||||
// also make a tag
|
||||
JGitUtil.createTag(git, "t1", None, commit2.getName)
|
||||
|
||||
createFile(git, Constants.HEAD, "README.md", "body1\nbody2", message = "commit3")
|
||||
val commit3 = git.getRepository.resolve("main")
|
||||
|
||||
// create branch
|
||||
JGitUtil.createBranch(git, "main", "branch1")
|
||||
createFile(git, "branch1", "README.md", "body2", message = "commit4")
|
||||
val commit4 = git.getRepository.resolve("branch1")
|
||||
|
||||
// compare results for empty → commit3
|
||||
assert(
|
||||
JGitUtil.getCommitLogs(git, commit3.getName, includesLastCommit = true)(_ => false) == JGitUtil.getCommitLog(
|
||||
git,
|
||||
root,
|
||||
commit3
|
||||
)
|
||||
)
|
||||
// compare results for commit1 → commit3
|
||||
assert(
|
||||
JGitUtil.getCommitLogs(git, commit3.getName, includesLastCommit = true)(
|
||||
_.getName != commit3.getName
|
||||
) == JGitUtil.getCommitLog(git, commit1, commit3)
|
||||
)
|
||||
|
||||
// compare results for empty → commit4
|
||||
assert(
|
||||
JGitUtil.getCommitLogs(git, commit4.getName, includesLastCommit = true)(_ => false) == JGitUtil.getCommitLog(
|
||||
git,
|
||||
root,
|
||||
commit4
|
||||
)
|
||||
)
|
||||
|
||||
// check with names
|
||||
assert(JGitUtil.getCommitLog(git, "main", "branch1").size == 1)
|
||||
|
||||
// tag names must work, too
|
||||
assertResult(JGitUtil.getCommitLog(git, "t1", "main").length)(1)
|
||||
}
|
||||
}
|
||||
|
||||
test("createBranch, branchesOfCommit and getBranches") {
|
||||
withTestRepository { git =>
|
||||
createFile(git, Constants.HEAD, "README.md", "body1", message = "commit1")
|
||||
@@ -154,7 +210,7 @@ class JGitUtilSpec extends AnyFunSuite {
|
||||
JGitUtil.createBranch(git, "main", "test2")
|
||||
|
||||
// getBranches
|
||||
val branches = JGitUtil.getBranches(git, "main", true)
|
||||
val branches = JGitUtil.getBranches(git, "main", origin = true)
|
||||
assert(branches.size == 3)
|
||||
|
||||
assert(branches(0).name == "main")
|
||||
@@ -183,8 +239,8 @@ class JGitUtilSpec extends AnyFunSuite {
|
||||
JGitUtil.createBranch(git, "main", "test2")
|
||||
|
||||
// getBranches
|
||||
val branchesNMI = JGitUtil.getBranchesNoMergeInfo(git, "main")
|
||||
val branches = JGitUtil.getBranches(git, "main", true)
|
||||
val branchesNMI = JGitUtil.getBranchesNoMergeInfo(git)
|
||||
val branches = JGitUtil.getBranches(git, "main", origin = true)
|
||||
|
||||
assert(
|
||||
branches.map(bi =>
|
||||
@@ -257,14 +313,14 @@ class JGitUtilSpec extends AnyFunSuite {
|
||||
val objectId = git.getRepository.resolve("main")
|
||||
val commit = JGitUtil.getRevCommitFromId(git, objectId)
|
||||
|
||||
val content1 = JGitUtil.getContentFromPath(git, commit.getTree, "README.md", true)
|
||||
assert(content1.map(x => new String(x, "UTF-8")) == Some("body1"))
|
||||
val content1 = JGitUtil.getContentFromPath(git, commit.getTree, "README.md", fetchLargeFile = true)
|
||||
assert(content1.map(x => new String(x, "UTF-8")).contains("body1"))
|
||||
|
||||
val content2 = JGitUtil.getContentFromPath(git, commit.getTree, "LARGE_FILE", false)
|
||||
val content2 = JGitUtil.getContentFromPath(git, commit.getTree, "LARGE_FILE", fetchLargeFile = false)
|
||||
assert(content2.isEmpty)
|
||||
|
||||
val content3 = JGitUtil.getContentFromPath(git, commit.getTree, "LARGE_FILE", true)
|
||||
assert(content3.map(x => new String(x, "UTF-8")) == Some("body1" * 1000000))
|
||||
val content3 = JGitUtil.getContentFromPath(git, commit.getTree, "LARGE_FILE", fetchLargeFile = true)
|
||||
assert(content3.map(x => new String(x, "UTF-8")).contains("body1" * 1000000))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user