Compare commits

...

139 Commits

Author SHA1 Message Date
Naoki Takezoe
d3268265cf Release GitBucket 4.42.1 (#3699) 2025-01-20 10:16:31 +09:00
Naoki Takezoe
5eaf59eebb Remove unnecessary setup code for SSL in LDAPUtil (#3697) 2025-01-20 09:41:33 +09:00
Scala Steward
d6d47aa977 Update scalafmt-core to 3.8.5 2025-01-20 07:19:49 +09:00
Naoki Takezoe
dc052e05ce Setup sbt explicitly in GitHub Actions (#3698) 2025-01-20 02:29:51 +09:00
Scala Steward
afb145ca7c Update sbt-scalafmt to 2.5.4 2025-01-17 07:26:49 +09:00
Scala Steward
a8beed33e0 Update scala3-library to 3.6.3 2025-01-16 20:00:10 +09:00
Scala Steward
488599dba5 Update postgresql to 42.7.5 2025-01-15 05:45:47 +09:00
Scala Steward
ef0d08a917 Update sbt-scoverage to 2.3.0 2025-01-14 07:42:48 +09:00
Scala Steward
9fa0d03c99 Update sbt-scalafmt to 2.5.3 2025-01-14 07:36:37 +09:00
kenji yoshida
15b6c5952b update build status badge in README 2025-01-11 16:06:43 +09:00
Scala Steward
cb75e9d312 Update oauth2-oidc-sdk to 11.21 2025-01-11 07:04:42 +09:00
Scala Steward
d542ee3528 Update scala-library to 2.13.16 2025-01-11 06:55:05 +09:00
Scala Steward
608a59cbfd Update oauth2-oidc-sdk to 11.20.2 2025-01-10 07:15:27 +09:00
Scala Steward
768e3a5c91 Update logback-classic to 1.5.16 2025-01-06 10:02:28 +09:00
Naoki Takezoe
f1fc794c0c Fix warnings in JGitUtil (#3683) 2025-01-05 14:35:50 +09:00
kenji yoshida
4cf924bee0 remove unused imports 2025-01-03 12:05:40 +09:00
kenji yoshida
8164efc720 remove unused import 2025-01-03 10:25:25 +09:00
Scala Steward
580a627d9d Update mockito-core to 5.15.2 2025-01-03 07:59:55 +09:00
Naoki Takezoe
1701916209 Update README and CHANGELOG for Java 17 requirement (#3679) 2025-01-02 02:17:06 +09:00
takezoe
811b2bff70 Update README.md and CHANGELOG.md 2024-12-30 05:52:06 +09:00
takezoe
9de9dd8940 Update README.md 2024-12-30 04:59:26 +09:00
Naoki Takezoe
572f83327f Release GitBucket 4.42.0 (#3678) 2024-12-30 04:56:10 +09:00
Naoki Takezoe
2afb37823b Increase max branch name length 100 -> 255 (#3676) 2024-12-30 04:36:24 +09:00
Naoki Takezoe
edc9720a88 Fix warnings in controllers (#3674) 2024-12-25 03:02:45 +09:00
Scala Steward
defc0fa041 Update sbt, sbt-dependency-tree, ... to 1.10.7 2024-12-23 12:51:33 +09:00
Naoki Takezoe
c14b3c5576 Fix warnings in ControllerBase (#3673) 2024-12-22 13:23:31 +09:00
Naoki Takezoe
10fc04cbc9 Return 400 error for invalid query string (#3672) 2024-12-22 12:48:39 +09:00
Scala Steward
67563a8805 Update logback-classic to 1.5.15 2024-12-22 07:13:09 +09:00
Naoki Takezoe
743bdab79b Fix wrong redirection when non-existent branch name is given as default branch (#3669) 2024-12-21 22:13:27 +09:00
Naoki Takezoe
a5a2e4732d Stabilize AccountServiceSpec (#3670) 2024-12-21 18:50:34 +09:00
Scala Steward
3a0cd5df62 Update scalatra-forms-javax, ... to 3.1.1 2024-12-21 14:43:49 +09:00
Naoki Takezoe
ad9a0afc9b Show branch errors when creating pull request (#3667) 2024-12-21 11:54:47 +09:00
Scala Steward
d2fc7a0642 Update logback-classic to 1.5.14 2024-12-20 13:44:08 +09:00
Naoki Takezoe
b1d4a18c9b Fix ref and ssh_url in WebHook payloads (#3656) 2024-12-19 15:19:42 +09:00
Scala Steward
fdfd8ec9b2 Update testcontainers-scala to 0.41.5 2024-12-19 13:31:22 +09:00
Scala Steward
396156c4e3 Update logback-classic to 1.5.13 2024-12-19 06:09:02 +09:00
Naoki Takezoe
8168580d60 Restore the original response of list-repository-tags API (#3662) 2024-12-16 00:27:56 +09:00
Naoki Takezoe
2abdd233e7 Apply user-defined CSS after plugins' JavaScript runs (#3661) 2024-12-15 12:30:07 +09:00
Naoki Takezoe
ef95ce99d2 Suppress Liquibase logs (#3660) 2024-12-14 14:49:38 +09:00
Scala Steward
3a6b2f6f4e Update sbt-pgp to 2.3.1 2024-12-11 07:09:14 +09:00
ziggystar
92304ac8c6 fix: make some methods call JGitUtil.getCommitLog with ObjectId instead of strings (#3653)
Co-authored-by: Thomas Geier <thomas.geier@solidat.de>
2024-12-10 08:25:38 +09:00
Scala Steward
a2242a3cb7 Update scala3-library to 3.6.2 2024-12-10 06:10:34 +09:00
ziggystar
64e8167fcb fix: calculate diffs between commits based on common ancestor; works for force push (#3647)
fixes #3476

Co-authored-by: Thomas Geier <thomas.geier@solidat.de>
2024-12-05 08:51:03 +09:00
Naoki Takezoe
06b93293a6 Update build.md about testing on Jetty from sbt (#3650) 2024-12-01 13:10:20 +09:00
Naoki Takezoe
3dcc0aee3c Use ContainerPlugin instead of JettyPlugin to run newer version of Jetty (#3649) 2024-12-01 12:49:14 +09:00
Scala Steward
c009a39dd7 Update sbt, sbt-dependency-tree, ... to 1.10.6 2024-12-01 07:45:38 +09:00
Scala Steward
b27e8ebb7e Update java-diff-utils to 4.15 2024-11-25 13:39:54 +09:00
Scala Steward
a690d43491 Update mysql, postgresql to 1.20.4 2024-11-21 06:36:53 +09:00
Scala Steward
86bfb68a0c Update commons-io to 2.18.0 2024-11-20 08:13:46 +09:00
Scala Steward
9469801d3d Update HikariCP to 6.2.1 2024-11-19 06:59:42 +09:00
Scala Steward
757a8399c1 Update HikariCP to 6.2.0 2024-11-17 15:49:50 +09:00
Scala Steward
ed00e613c3 Update json4s-jackson to 4.1.0-M8 2024-11-07 16:30:48 +09:00
Scala Steward
6e341116c1 Update HikariCP to 6.1.0 2024-11-06 13:54:48 +09:00
Scala Steward
9ccc2d0f97 Update sbt, sbt-dependency-tree, ... to 1.10.5 2024-11-04 09:16:17 +09:00
Scala Steward
72742306a0 Update sbt, sbt-dependency-tree, ... to 1.10.4 2024-10-30 09:50:35 +09:00
Scala Steward
47c6d61661 Update logback-classic to 1.5.12 2024-10-27 07:13:39 +09:00
Scala Steward
cfc444bcd2 Update sbt-license-report to 1.7.0 2024-10-24 05:24:38 +09:00
Scala Steward
a1f65258ea Update mysql, postgresql to 1.20.3 2024-10-23 10:22:47 +09:00
Scala Steward
5e3b97cf85 Update sbt, sbt-dependency-tree, ... to 1.10.3 2024-10-20 13:31:53 +09:00
kenji yoshida
209e1967d6 fail-fast: false 2024-10-20 13:23:32 +09:00
Scala Steward
4437a4e7a6 Update tika-core to 3.0.0 2024-10-20 09:31:44 +09:00
Scala Steward
e4d92bb494 Update scala3-library to 3.6.1 2024-10-19 19:27:45 +09:00
Scala Steward
d942c8f48a Update scala3-library to 3.6.0 2024-10-19 04:02:52 +09:00
Scala Steward
3a798e152f Update sbt-scoverage to 2.2.2 2024-10-19 04:02:29 +09:00
Scala Steward
91b862970f Update scala3-library to 3.5.2 2024-10-17 04:15:47 +09:00
Scala Steward
2d199e22e7 Update logback-classic to 1.5.11 2024-10-16 08:39:26 +09:00
Scala Steward
757da408d1 Update mockito-core to 5.14.2 2024-10-16 08:01:30 +09:00
Scala Steward
309d6e8b57 Update ec4j-core to 1.1.0 2024-10-13 07:55:33 +09:00
Scala Steward
ec0395a7f3 Update logback-classic to 1.5.10 2024-10-13 06:59:03 +09:00
Scala Steward
7cb4958ca0 Update oauth2-oidc-sdk to 11.20.1 2024-10-11 08:23:57 +09:00
Scala Steward
2d1c917a2c Update logback-classic to 1.5.9 2024-10-09 06:29:26 +09:00
Scala Steward
27dd5120dd Update sbt-assembly to 2.3.0 2024-10-07 12:21:35 +09:00
Scala Steward
9e0f8992c5 Update sbt-pgp to 2.3.0 2024-10-05 21:41:34 +09:00
Scala Steward
5f87a28da6 Update apache-sshd to 2.14.0 2024-10-03 08:07:53 +09:00
Scala Steward
25d5d5eee5 Update mysql, postgresql to 1.20.2 2024-10-01 12:31:19 +09:00
Scala Steward
ec9472b7cc Update mockito-core to 5.14.1 2024-10-01 06:58:02 +09:00
Scala Steward
b967fb93a7 Update oauth2-oidc-sdk to 11.20 2024-09-30 06:14:20 +09:00
Scala Steward
9d1bf3035b Update mockito-core to 5.14.0 2024-09-28 06:34:32 +09:00
Scala Steward
d6cedc2171 Update sbt-scoverage to 2.2.1 2024-09-26 06:39:12 +09:00
Scala Steward
8d8c78966a Update HikariCP to 6.0.0 2024-09-24 06:05:20 +09:00
Scala Steward
cbe1c1c9f6 Update ec4j-core to 1.0.0 2024-09-21 07:48:45 +09:00
Scala Steward
bf946960a7 Update scala-library to 2.13.15 2024-09-21 06:53:23 +09:00
Scala Steward
9677735542 Update github-api to 1.326 2024-09-19 09:30:09 +09:00
Scala Steward
e06c8fe5da Update scala3-library to 3.5.1 2024-09-19 09:27:27 +09:00
Scala Steward
d4ee6c9063 Update commons-io to 2.17.0 2024-09-19 09:26:32 +09:00
Scala Steward
1d0f079bd2 Update sbt, sbt-dependency-tree to 1.10.2 2024-09-16 20:05:08 +09:00
Scala Steward
7cc6972d83 Update github-api to 1.325 2024-09-14 06:52:27 +09:00
kenji yoshida
177da92b39 fix warning 2024-09-11 11:47:54 +09:00
Scala Steward
e1f433573b Update json4s-jackson to 4.1.0-M7 2024-09-10 08:08:14 +09:00
Scala Steward
cd958d7681 Update logback-classic to 1.5.8 2024-09-07 07:12:32 +09:00
Scala Steward
9c8e77f472 Update oauth2-oidc-sdk to 11.19.1 2024-09-06 10:46:21 +09:00
Scala Steward
bf7d3a8f0b Update sbt-scoverage to 2.2.0 2024-09-06 10:46:09 +09:00
Scala Steward
934e17666d Update jetty-http, jetty-io, jetty-security, ... to 10.0.24 2024-09-04 08:20:28 +09:00
Scala Steward
b20c4b3d7d Update oauth2-oidc-sdk to 11.19 2024-08-29 17:39:44 +09:00
Scala Steward
7c4e8b54d0 Update mockito-core to 5.13.0 2024-08-28 08:15:20 +09:00
Scala Steward
1e3794674b Update postgresql to 42.7.4 2024-08-23 10:01:12 +09:00
Scala Steward
5d5706451d Update sbt-scoverage to 2.1.1 2024-08-22 06:28:14 +09:00
Scala Steward
76e8d01846 Update oauth2-oidc-sdk to 11.18 2024-08-21 09:14:20 +09:00
Scala Steward
75e2883f61 Update jetty-http, jetty-io, jetty-security, ... to 10.0.23 2024-08-21 09:14:01 +09:00
Scala Steward
7e7cc1d4c7 Update commons-compress to 1.27.1 2024-08-21 06:25:57 +09:00
Scala Steward
d7623e8b7a Update github-api to 1.324 2024-08-19 19:45:55 +09:00
Scala Steward
7dd1470cd4 Update oauth2-oidc-sdk to 11.17 2024-08-19 06:15:01 +09:00
Scala Steward
9fb8d6fc66 Update oauth2-oidc-sdk to 11.16.1 2024-08-17 06:15:36 +09:00
Scala Steward
4f1869817c Update oauth2-oidc-sdk to 11.16 2024-08-16 07:07:35 +09:00
Scala Steward
6be269c388 Update logback-classic to 1.5.7 2024-08-16 06:32:52 +09:00
Scala Steward
af857853cb Update oauth2-oidc-sdk to 11.15 2024-08-14 07:45:41 +09:00
Scala Steward
1a664c2b6a Update scala3-library to 3.5.0 2024-08-13 06:17:59 +09:00
scala-steward-bot
1feb33fc19 Update commons-compress to 1.27.0 (#3574)
* Update commons-compress to 1.27.0

* Update build.sbt

---------

Co-authored-by: kenji yoshida <6b656e6a69@gmail.com>
2024-08-11 11:32:52 +09:00
Scala Steward
4fc1d9c3b6 Update oauth2-oidc-sdk to 11.14 2024-08-02 05:26:05 +09:00
Scala Steward
7eb77908d4 Update apache-sshd to 2.13.2 2024-08-01 05:58:36 +09:00
Scala Steward
54f9d01c42 Update mysql, postgresql to 1.20.1 2024-08-01 05:57:46 +09:00
Scala Steward
08154af7b1 Update scalafmt-core to 3.8.3 2024-07-27 07:57:11 +09:00
Scala Steward
e7ab376a34 Update mysql, postgresql to 1.20.0 2024-07-18 05:58:08 +09:00
Scala Steward
a680398c54 Update sbt, sbt-dependency-tree to 1.10.1 2024-07-08 08:49:28 +09:00
Scala Steward
6acf1e68ca Update jetty-http, jetty-io, jetty-security, ... to 10.0.22 2024-07-05 16:12:38 +09:00
Scala Steward
fc35e7b83d Update sbt-scoverage to 2.1.0 2024-07-04 02:31:10 +09:00
Scala Steward
1ae6fc7e9e Update github-api to 1.323 2024-07-02 06:12:05 +09:00
scala-steward-bot
884f63e6f4 Update scalatra-forms-javax, ... to 3.1.0 (#3545)
Co-authored-by: kenji yoshida <6b656e6a69@gmail.com>
2024-06-28 09:19:57 +09:00
Scala Steward
4d3e34af8b Update sbt-twirl, twirl-api to 2.0.7 2024-06-28 09:01:31 +09:00
Scala Steward
54426bb456 Update oauth2-oidc-sdk to 11.13 2024-06-26 13:23:20 +09:00
Scala Steward
c86b72bf6b Update oauth2-oidc-sdk to 11.12.1 2024-06-25 19:18:52 +09:00
Scala Steward
e6a5911a39 Update apache-sshd to 2.13.1 2024-06-25 07:08:53 +09:00
Scala Steward
6ea77fa73e Update github-api to 1.322 2024-06-21 19:09:21 +09:00
Scala Steward
32d0b94a7a Update apache-sshd to 2.13.0 2024-06-20 03:37:43 +09:00
scala-steward-bot
4f770adb35 Update sbt-twirl, twirl-api to 2.0.6 (#3553) 2024-06-17 21:32:10 +09:00
kenji yoshida
361f92a08d -Xsource:3-cross 2024-06-17 15:16:42 +09:00
xuwei-k
c2068f58e7 prepare Scala 3 2024-06-17 15:07:53 +09:00
kenji yoshida
67dd604469 Merge pull request #3549 from scala-steward-bot/update/scalafmt-core-3.8.2
Update scalafmt-core to 3.8.2
2024-06-17 11:23:22 +09:00
Scala Steward
d1a2c23cf3 Update json4s-jackson to 4.1.0-M6 2024-06-17 01:26:00 +09:00
Scala Steward
262500508c Add 'Reformat with scalafmt 3.8.2' to .git-blame-ignore-revs 2024-06-14 16:40:55 +00:00
Scala Steward
f1360f44c6 Reformat with scalafmt 3.8.2
Executed command: scalafmt --non-interactive
2024-06-14 16:40:55 +00:00
Scala Steward
1c818f890a Update scalafmt-core to 3.8.2 2024-06-14 16:40:45 +00:00
Scala Steward
16f146b660 Update testcontainers-scala to 0.41.4 2024-06-14 06:12:35 +09:00
Scala Steward
6166eaf0c7 Update org.eclipse.jgit.archive, ... to 6.10.0.202406032230-r 2024-06-13 09:43:42 +09:00
Scala Steward
ad4312cedb Update commons-net to 3.11.1 2024-06-11 05:46:46 +09:00
Scala Steward
15083a5aac Update commons-net to 3.11.0 2024-06-01 07:26:44 +09:00
Scala Steward
9ae420c553 Update commons-compress to 1.26.2 2024-05-25 05:08:23 +09:00
takezoe
4115ea4ab6 Update ChangeLog of 4.41.0 2024-05-18 17:26:23 +09:00
takezoe
024ac313ae Update ChangeLog of 4.41.0 2024-05-18 17:12:06 +09:00
69 changed files with 895 additions and 864 deletions

View File

@@ -1,2 +1,5 @@
# update scalafmt
3d5ca44d66c77a46770a65a895c9737c542690f6
# Scala Steward: Reformat with scalafmt 3.8.2
f1360f44c61f8e12666965c10e79f11cd75d6d30

View File

@@ -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

View File

@@ -1,4 +1,4 @@
version = "3.8.1"
version = "3.8.5"
project.git = true
maxColumn = 120

View File

@@ -1,12 +1,22 @@
# Changelog
All changes to the project will be documented in this file.
## 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

View File

@@ -1,4 +1,4 @@
GitBucket [![Gitter chat](https://badges.gitter.im/gitbucket/gitbucket.svg)](https://gitter.im/gitbucket/gitbucket) [![build](https://github.com/gitbucket/gitbucket/workflows/build/badge.svg?branch=master)](https://github.com/gitbucket/gitbucket/actions?query=workflow%3Abuild+branch%3Amaster) [![gitbucket Scala version support](https://index.scala-lang.org/gitbucket/gitbucket/gitbucket/latest-by-scala-version.svg)](https://index.scala-lang.org/gitbucket/gitbucket/gitbucket) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/gitbucket/gitbucket/blob/master/LICENSE)
GitBucket [![Gitter chat](https://badges.gitter.im/gitbucket/gitbucket.svg)](https://gitter.im/gitbucket/gitbucket) [![build](https://github.com/gitbucket/gitbucket/actions/workflows/build.yml/badge.svg)](https://github.com/gitbucket/gitbucket/actions/workflows/build.yml) [![gitbucket Scala version support](https://index.scala-lang.org/gitbucket/gitbucket/gitbucket/latest-by-scala-version.svg)](https://index.scala-lang.org/gitbucket/gitbucket/gitbucket) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](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,16 @@ 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.42.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.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
See the [change log](CHANGELOG.md) for all of the updates.

View File

@@ -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.42.1"
val ScalatraVersion = "3.1.1"
val JettyVersion = "10.0.24"
val JgitVersion = "6.10.0.202406032230-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.6.3"
// 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.18.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.14.0" exclude ("org.slf4j", "slf4j-jdk14") exclude (
"org.apache.sshd",
"sshd-mina"
) exclude ("org.apache.sshd", "sshd-netty"),
"org.apache.tika" % "tika-core" % "3.0.0",
"com.github.takezoe" %% "blocking-slick" % "0.0.14",
"com.novell.ldap" % "jldap" % "2009-10-07",
"com.h2database" % "h2" % "1.4.199",
"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.5",
"ch.qos.logback" % "logback-classic" % "1.5.16",
"com.zaxxer" % "HikariCP" % "6.2.1" 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.21",
"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.15.2" % "test",
"com.dimafeng" %% "testcontainers-scala" % "0.41.5" % "test",
"org.testcontainers" % "mysql" % "1.20.4" % "test",
"org.testcontainers" % "postgresql" % "1.20.4" % "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.0",
"org.kohsuke" % "github-api" % "1.326" % "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
@@ -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"

View File

@@ -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

View File

@@ -1 +1 @@
sbt.version=1.10.0
sbt.version=1.10.7

View File

@@ -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.7")
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.3.0")
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.0")
addDependencyTreePlugin

View 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>

View File

@@ -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,9 @@ 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")
) {
java.util.logging.Logger.getLogger("liquibase").setLevel(Level.SEVERE)
}

View File

@@ -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 {

View 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")
)
}

View File

@@ -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,
@@ -286,14 +273,13 @@ trait AccountControllerBase extends AccountManagementControllerBase {
isGroupManager(context.loginAccount, members)
)
}
}
} getOrElse NotFound()
}
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()
}

View File

@@ -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

View File

@@ -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()
@@ -189,7 +200,6 @@ abstract class ControllerBase
org.scalatra.InternalServerError(gitbucket.core.html.error("Internal Server Error", Some(e)))
}
}
}
override def url(
path: String,
@@ -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,7 +254,7 @@ 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 if walk.getPathString == path => Some(walk.getObjectId(0))
case true => _getPathObjectId(path, walk)
case false => None
}
@@ -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
}
}
}

View File

@@ -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(

View File

@@ -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

View File

@@ -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 {
@@ -199,6 +192,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 +232,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 {
@@ -250,7 +253,6 @@ trait IndexControllerBase extends ControllerBase {
}
)
)
)
})
/**

View File

@@ -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(
@@ -508,14 +503,13 @@ trait IssuesControllerBase extends ControllerBase {
}
)
)
)
})
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")

View File

@@ -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
}

View File

@@ -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())))

View File

@@ -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
}

View File

@@ -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")
}
})

View File

@@ -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)

View File

@@ -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()
})

View File

@@ -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.")

View File

@@ -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"
}
}

View File

@@ -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)

View File

@@ -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
}

View File

@@ -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])

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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(

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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))
)
}
})

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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) =>

View File

@@ -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

View File

@@ -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]]

View File

@@ -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,

View File

@@ -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) =

View File

@@ -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._

View File

@@ -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))
}

View File

@@ -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,

View File

@@ -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.

View File

@@ -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)

View File

@@ -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 =

View File

@@ -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(

View File

@@ -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))
}
}

View File

@@ -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)
}

View File

@@ -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)) }

View File

@@ -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,17 +554,19 @@ 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
if (objectId == null) {
None
} else {
val revCommit = revWalk.parseCommit(objectId)
Some(revCommit.getTree.name)
}
}
}
/**
* 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 =>
@@ -577,7 +581,6 @@ object JGitUtil {
ret.reverse
}
}
}
/**
* Returns the commit list of the specified branch.
@@ -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) => {
if (i.hasNext) {
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)
} 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 => {
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,7 +1078,7 @@ 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 if walk.getPathString == path => Some(walk.getObjectId(0))
case true => getPathObjectId(path, walk)
case false => None
}
@@ -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)
}
}

View File

@@ -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)
@@ -202,7 +172,6 @@ object LDAPUtil {
Left(error)
}
}
}
/**
* Search a specified user and returns userDN if exists.
@@ -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 {

View File

@@ -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>

View File

@@ -21,6 +21,7 @@
@import gitbucket.core.view.helpers
@gitbucket.core.html.main(s"Pull requests - ${repository.owner}/${repository.name}", Some(repository)){
@gitbucket.core.html.menu("pulls", repository){
<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...")) {
@@ -36,6 +37,7 @@
<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) =>
@@ -50,6 +52,7 @@
<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;">
@@ -59,7 +62,6 @@
</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">
<div class="row">
<div class="col-md-9">
<span class="error" id="error-title"></span>
@@ -113,9 +115,9 @@
)
</div>
</div>
</form>
</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>

View File

@@ -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")
}
}
}

View File

@@ -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)

View File

@@ -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

View File

@@ -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))
}
}