mirror of
https://github.com/gitbucket/gitbucket.git
synced 2026-05-08 22:47:16 +02:00
Compare commits
55 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f16cc117a9 | ||
|
|
af66f8f746 | ||
|
|
d9cc57e8e0 | ||
|
|
72b6dad3a2 | ||
|
|
18f396b4a2 | ||
|
|
9f3fde8de2 | ||
|
|
dfd6f80b63 | ||
|
|
119d91210c | ||
|
|
75ef30ee03 | ||
|
|
d1cf9dd600 | ||
|
|
9c9fea908c | ||
|
|
1145c4d0f6 | ||
|
|
d847fc6e0f | ||
|
|
bb9585f7a6 | ||
|
|
e91411fa45 | ||
|
|
adbc065a6f | ||
|
|
862283b729 | ||
|
|
217df7012c | ||
|
|
e672d41e77 | ||
|
|
d975700bd4 | ||
|
|
f65e41561a | ||
|
|
dab4f33ed9 | ||
|
|
5ff45ef5ae | ||
|
|
af7c622647 | ||
|
|
f7027e57df | ||
|
|
6a4719469d | ||
|
|
6ebc865ba5 | ||
|
|
0c1e8b932b | ||
|
|
fda67a32e2 | ||
|
|
14d7e9ee90 | ||
|
|
b7b7322cce | ||
|
|
5eb44398d0 | ||
|
|
be7bb255c3 | ||
|
|
cb9522d416 | ||
|
|
d80afb473b | ||
|
|
607d85c661 | ||
|
|
a5fab3bc96 | ||
|
|
eb403ada58 | ||
|
|
911c102f39 | ||
|
|
bf23e854f8 | ||
|
|
52427c0a1e | ||
|
|
d8e5ac585c | ||
|
|
2fbeef73b0 | ||
|
|
15e39572dd | ||
|
|
9eac4f42c5 | ||
|
|
01d18bb5c3 | ||
|
|
00258e9125 | ||
|
|
046b337337 | ||
|
|
46cc7b6fd3 | ||
|
|
59344b4f05 | ||
|
|
c4d8af02b2 | ||
|
|
a10bc3687a | ||
|
|
b0d21dee42 | ||
|
|
13ea0e7507 | ||
|
|
d66fdaede5 |
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
blank_issues_enabled: false
|
||||
@@ -1,7 +1,5 @@
|
||||
name: Bug report
|
||||
description: Report a problem with GitBucket
|
||||
title: "[Bug] "
|
||||
labels: [bug]
|
||||
name: Report issue
|
||||
description: Report a problem or feature request with GitBucket
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
@@ -10,6 +8,7 @@ body:
|
||||
- Read the [contribution guidelines](https://github.com/gitbucket/gitbucket/blob/master/.github/CONTRIBUTING.md)
|
||||
- Searched for similar existing issues
|
||||
- Read the documentation and [wiki](https://github.com/gitbucket/gitbucket/wiki)
|
||||
- You can use [Gitter chat room](https://gitter.im/gitbucket/gitbucket) instead of GitHub Issues for casual discussion or inquiry
|
||||
|
||||
- type: checkboxes
|
||||
id: prerequisites
|
||||
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
matrix:
|
||||
java: [17, 21]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- name: Cache
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
~/.cache/coursier/v1
|
||||
key: build-${{ env.cache-name }}-${{ hashFiles('build.sbt') }}
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v4
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
java-version: ${{ matrix.java }}
|
||||
distribution: adopt
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
version = "3.9.8"
|
||||
version = "3.9.10"
|
||||
project.git = true
|
||||
|
||||
maxColumn = 120
|
||||
|
||||
14
CHANGELOG.md
14
CHANGELOG.md
@@ -1,13 +1,17 @@
|
||||
# Changelog
|
||||
All changes to the project will be documented in this file.
|
||||
|
||||
## 4.44.0 - 23 Sep 2025
|
||||
- Enhanced branch protection which supports rejecting users fo push, etc.
|
||||
- Improve logging for initialization errors
|
||||
|
||||
## 4.43.0 - 29 Jun 2025
|
||||
- Upgrade H2 database from 1.x to 2.x
|
||||
|
||||
Note that upgrading from h2 1.x to 2.x requires data file migration: https://www.h2database.com/html/migration-to-v2.html
|
||||
|
||||
It can't be done automatically using GitBucket's auto migration mechanism because it relies on database itself. So, users who use h2 will have to dump and recreate their database manually with the following steps:
|
||||
```
|
||||
```bash
|
||||
# Export database using the current version of H2
|
||||
$ curl -O https://repo1.maven.org/maven2/com/h2database/h2/1.4.199/h2-1.4.199.jar
|
||||
$ java -cp h2-1.4.199.jar org.h2.tools.Script -url "jdbc:h2:~/.gitbucket/data" -user sa -password sa -script dump.sql
|
||||
@@ -17,6 +21,14 @@ $ curl -O https://repo1.maven.org/maven2/com/h2database/h2/2.3.232/h2-2.3.232.ja
|
||||
$ java -cp h2-2.3.232.jar org.h2.tools.RunScript -url "jdbc:h2:~/.gitbucket/data" -user sa -password sa -script dump.sql
|
||||
```
|
||||
|
||||
In addition, if `~/.gitbucket/database.conf` has the following configuration, remove `;MVCC=true` from `url`.
|
||||
```
|
||||
db {
|
||||
url = "jdbc:h2:${DatabaseHome};MVCC=true" // => "jdbc:h2:${DatabaseHome}"
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
## 4.42.1 - 20 Jan 2025
|
||||
- Fix LDAP issue with SSL
|
||||
|
||||
|
||||
21
README.md
21
README.md
@@ -56,18 +56,19 @@ Support
|
||||
--------
|
||||
|
||||
- If you have any questions about GitBucket, see [Wiki](https://github.com/gitbucket/gitbucket/wiki) and check issues whether there is a same question or request in the past.
|
||||
- If you can't find same question and report, send it to our [Gitter room](https://gitter.im/gitbucket/gitbucket) before raising an issue.
|
||||
- If you can't find same question and report, send it to our [Gitter chat 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.43.x
|
||||
What's New in 4.44.x
|
||||
-------------
|
||||
## 4.43.0 - 29 Jun 2025
|
||||
- Upgrade H2 database from 1.x to 2.x
|
||||
## 4.44.0 - 23 Sep 2025
|
||||
- Enhanced branch protection which supports rejecting users fo push, etc.
|
||||
- Improve logging for initialization errors
|
||||
|
||||
Note that upgrading from h2 1.x to 2.x requires data file migration: https://www.h2database.com/html/migration-to-v2.html
|
||||
Note that you have to migrate h2 database file if you will upgrade GitBucket from 4.42 or before to 4.43 or later and you are using the default h2 database because h2 1.x and h2.x don't have compatibility: https://www.h2database.com/html/migration-to-v2.html
|
||||
|
||||
It can't be done automatically using GitBucket's auto migration mechanism because it relies on database itself. So, users who use h2 will have to dump and recreate their database manually with the following steps:
|
||||
```
|
||||
```bash
|
||||
# Export database using the current version of H2
|
||||
$ curl -O https://repo1.maven.org/maven2/com/h2database/h2/1.4.199/h2-1.4.199.jar
|
||||
$ java -cp h2-1.4.199.jar org.h2.tools.Script -url "jdbc:h2:~/.gitbucket/data" -user sa -password sa -script dump.sql
|
||||
@@ -77,4 +78,12 @@ $ curl -O https://repo1.maven.org/maven2/com/h2database/h2/2.3.232/h2-2.3.232.ja
|
||||
$ java -cp h2-2.3.232.jar org.h2.tools.RunScript -url "jdbc:h2:~/.gitbucket/data" -user sa -password sa -script dump.sql
|
||||
```
|
||||
|
||||
In addition, if `~/.gitbucket/database.conf` has the following configuration, remove `;MVCC=true` from `url`.
|
||||
```
|
||||
db {
|
||||
url = "jdbc:h2:${DatabaseHome};MVCC=true" // => "jdbc:h2:${DatabaseHome}"
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
See the [change log](CHANGELOG.md) for all the past updates.
|
||||
|
||||
35
build.sbt
35
build.sbt
@@ -2,9 +2,9 @@ import com.jsuereth.sbtpgp.PgpKeys._
|
||||
|
||||
val Organization = "io.github.gitbucket"
|
||||
val Name = "gitbucket"
|
||||
val GitBucketVersion = "4.43.0"
|
||||
val GitBucketVersion = "4.44.0"
|
||||
val ScalatraVersion = "3.1.2"
|
||||
val JettyVersion = "10.0.25"
|
||||
val JettyVersion = "10.0.26"
|
||||
val JgitVersion = "6.10.1.202505221210-r"
|
||||
|
||||
lazy val root = (project in file("."))
|
||||
@@ -16,7 +16,7 @@ name := Name
|
||||
version := GitBucketVersion
|
||||
scalaVersion := "2.13.16"
|
||||
|
||||
crossScalaVersions += "3.7.1"
|
||||
crossScalaVersions += "3.7.3"
|
||||
|
||||
// scalafmtOnCompile := true
|
||||
|
||||
@@ -29,45 +29,46 @@ libraryDependencies ++= Seq(
|
||||
"org.scalatra" %% "scalatra-json-javax" % ScalatraVersion,
|
||||
"org.scalatra" %% "scalatra-forms-javax" % ScalatraVersion,
|
||||
"org.json4s" %% "json4s-jackson" % "4.1.0-M8",
|
||||
"commons-io" % "commons-io" % "2.19.0",
|
||||
"commons-io" % "commons-io" % "2.20.0",
|
||||
"io.github.gitbucket" % "solidbase" % "1.1.0",
|
||||
"io.github.gitbucket" % "markedj" % "1.0.20",
|
||||
"org.tukaani" % "xz" % "1.10",
|
||||
"org.apache.commons" % "commons-compress" % "1.27.1",
|
||||
"org.apache.commons" % "commons-compress" % "1.28.0",
|
||||
"org.apache.commons" % "commons-email" % "1.6.0",
|
||||
"commons-net" % "commons-net" % "3.11.1",
|
||||
"commons-net" % "commons-net" % "3.12.0",
|
||||
"org.apache.httpcomponents" % "httpclient" % "4.5.14",
|
||||
"org.apache.sshd" % "apache-sshd" % "2.15.0" exclude ("org.slf4j", "slf4j-jdk14") exclude (
|
||||
"org.apache.sshd" % "apache-sshd" % "2.16.0" exclude ("org.slf4j", "slf4j-jdk14") exclude (
|
||||
"org.apache.sshd",
|
||||
"sshd-mina"
|
||||
) exclude ("org.apache.sshd", "sshd-netty"),
|
||||
"org.apache.tika" % "tika-core" % "3.2.0",
|
||||
) exclude ("org.apache.sshd", "sshd-netty")
|
||||
exclude ("org.apache.sshd", "sshd-spring-sftp"),
|
||||
"org.apache.tika" % "tika-core" % "3.2.3",
|
||||
"com.github.takezoe" %% "blocking-slick" % "0.0.14",
|
||||
"com.novell.ldap" % "jldap" % "2009-10-07",
|
||||
"com.h2database" % "h2" % "2.3.232",
|
||||
"org.mariadb.jdbc" % "mariadb-java-client" % "2.7.12",
|
||||
"org.postgresql" % "postgresql" % "42.7.7",
|
||||
"org.postgresql" % "postgresql" % "42.7.8",
|
||||
"ch.qos.logback" % "logback-classic" % "1.5.18",
|
||||
"com.zaxxer" % "HikariCP" % "6.3.0" exclude ("org.slf4j", "slf4j-api"),
|
||||
"com.typesafe" % "config" % "1.4.3",
|
||||
"com.zaxxer" % "HikariCP" % "7.0.2" exclude ("org.slf4j", "slf4j-api"),
|
||||
"com.typesafe" % "config" % "1.4.5",
|
||||
"fr.brouillard.oss.security.xhub" % "xhub4j-core" % "1.1.0",
|
||||
"io.github.java-diff-utils" % "java-diff-utils" % "4.15",
|
||||
"io.github.java-diff-utils" % "java-diff-utils" % "4.16",
|
||||
"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.26",
|
||||
"com.nimbusds" % "oauth2-oidc-sdk" % "11.29.1",
|
||||
"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.18.0" % "test",
|
||||
"org.mockito" % "mockito-core" % "5.20.0" % "test",
|
||||
"com.dimafeng" %% "testcontainers-scala" % "0.43.0" % "test",
|
||||
"org.testcontainers" % "mysql" % "1.21.3" % "test",
|
||||
"org.testcontainers" % "postgresql" % "1.21.3" % "test",
|
||||
"net.i2p.crypto" % "eddsa" % "0.3.0",
|
||||
"is.tagomor.woothee" % "woothee-java" % "1.11.0",
|
||||
"org.ec4j.core" % "ec4j-core" % "1.1.1",
|
||||
"org.kohsuke" % "github-api" % "1.327" % "test"
|
||||
"org.kohsuke" % "github-api" % "1.330" % "test"
|
||||
)
|
||||
|
||||
// Compiler settings
|
||||
@@ -191,7 +192,7 @@ executableKey := {
|
||||
|
||||
// zip it up
|
||||
IO delete (temp / "META-INF" / "MANIFEST.MF")
|
||||
val contentMappings = (temp.allPaths --- PathFinder(temp)).get pair { file =>
|
||||
val contentMappings = (temp.allPaths --- PathFinder(temp)).get() pair { file =>
|
||||
IO.relativizeFile(temp, file)
|
||||
}
|
||||
val manifest = new JarManifest
|
||||
|
||||
@@ -38,15 +38,26 @@ Generate release files
|
||||
|
||||
For plug-in development, we have to publish the GitBucket jar file to the Maven central repository before release GitBucket itself.
|
||||
|
||||
First, hit following command to publish artifacts to the sonatype OSS repository:
|
||||
First, start the sbt shell:
|
||||
|
||||
```bash
|
||||
$ sbt publishSigned
|
||||
```
|
||||
|
||||
Then logged-in to https://oss.sonatype.org/, close and release the repository.
|
||||
Next, upload artifacts to Sonatype's Central Portal with the following command:
|
||||
|
||||
You need to wait up to a day until [gitbucket-notification-plugin](https://plugins.gitbucket-community.org/) which is default bundled plugin is built for new version of GitBucket.
|
||||
```bash
|
||||
$ sbt sonaUpload
|
||||
```
|
||||
|
||||
Then logged-in to https://central.sonatype.com/ and publish the deployment.
|
||||
|
||||
You need to wait up to a day until default bundled plugins:
|
||||
|
||||
- https://github.com/gitbucket/gitbucket-notifications-plugin
|
||||
- https://github.com/gitbucket/gitbucket-gist-plugin
|
||||
- https://github.com/gitbucket/gitbucket-pages-plugin
|
||||
- https://github.com/gitbucket/gitbucket-emoji-plugin
|
||||
|
||||
### Make release war file
|
||||
|
||||
@@ -55,5 +66,4 @@ Run `sbt executable`. The release war file and fingerprint are generated into `t
|
||||
```bash
|
||||
$ sbt executable
|
||||
```
|
||||
|
||||
Create new release from the corresponded tag on GitHub, then upload generated jar file and fingerprints to the release.
|
||||
|
||||
@@ -1 +1 @@
|
||||
sbt.version=1.11.2
|
||||
sbt.version=1.11.6
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
scalacOptions ++= Seq("-unchecked", "-deprecation", "-feature")
|
||||
|
||||
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.4")
|
||||
addSbtPlugin("org.playframework.twirl" % "sbt-twirl" % "2.0.8")
|
||||
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.5")
|
||||
addSbtPlugin("org.playframework.twirl" % "sbt-twirl" % "2.0.9")
|
||||
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.3.1")
|
||||
addSbtPlugin("org.scalatra.sbt" % "sbt-scalatra" % "1.0.4")
|
||||
addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.3.1")
|
||||
addSbtPlugin("com.github.sbt" % "sbt-license-report" % "1.7.0")
|
||||
addSbtPlugin("com.github.sbt" % "sbt-license-report" % "1.8.0")
|
||||
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.3.1")
|
||||
|
||||
addDependencyTreePlugin
|
||||
|
||||
32
src/main/resources/update/gitbucket-core_4.44.xml
Normal file
32
src/main/resources/update/gitbucket-core_4.44.xml
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<changeSet>
|
||||
<!--================================================================================================-->
|
||||
<!-- PROTECTED_BRANCH -->
|
||||
<!--================================================================================================-->
|
||||
<addColumn tableName="PROTECTED_BRANCH">
|
||||
<column name="REQUIRED_STATUS_CHECK" type="boolean" nullable="false" defaultValue="false"/>
|
||||
<column name="RESTRICTIONS" type="boolean" nullable="false" defaultValue="false"/>
|
||||
</addColumn>
|
||||
|
||||
<sql>
|
||||
UPDATE PROTECTED_BRANCH SET REQUIRED_STATUS_CHECK = TRUE
|
||||
WHERE EXISTS (SELECT * FROM PROTECTED_BRANCH_REQUIRE_CONTEXT
|
||||
WHERE PROTECTED_BRANCH.USER_NAME = PROTECTED_BRANCH_REQUIRE_CONTEXT.USER_NAME
|
||||
AND PROTECTED_BRANCH.REPOSITORY_NAME = PROTECTED_BRANCH_REQUIRE_CONTEXT.REPOSITORY_NAME
|
||||
AND PROTECTED_BRANCH.BRANCH = PROTECTED_BRANCH_REQUIRE_CONTEXT.BRANCH)
|
||||
</sql>
|
||||
|
||||
<!--================================================================================================-->
|
||||
<!-- PROTECTED_BRANCH_RESTRICTIONS_USER -->
|
||||
<!--================================================================================================-->
|
||||
<createTable tableName="PROTECTED_BRANCH_RESTRICTION">
|
||||
<column name="USER_NAME" type="varchar(100)" nullable="false"/>
|
||||
<column name="REPOSITORY_NAME" type="varchar(100)" nullable="false"/>
|
||||
<column name="BRANCH" type="varchar(100)" nullable="false"/>
|
||||
<column name="ALLOWED_USER" type="varchar(255)" nullable="false"/>
|
||||
</createTable>
|
||||
|
||||
<addPrimaryKey constraintName="IDX_PROTECTED_BRANCH_RESTRICTION_PK" tableName="PROTECTED_BRANCH_RESTRICTION" columnNames="USER_NAME, REPOSITORY_NAME, BRANCH, ALLOWED_USER"/>
|
||||
<addForeignKeyConstraint constraintName="IDX_PROTECTED_BRANCH_RESTRICTION_FK0" baseTableName="PROTECTED_BRANCH_RESTRICTION" baseColumnNames="USER_NAME, REPOSITORY_NAME, BRANCH" referencedTableName="PROTECTED_BRANCH" referencedColumnNames="USER_NAME, REPOSITORY_NAME, BRANCH" onDelete="CASCADE" onUpdate="CASCADE"/>
|
||||
<addForeignKeyConstraint constraintName="IDX_PROTECTED_BRANCH_RESTRICTION_FK1" baseTableName="PROTECTED_BRANCH_RESTRICTION" baseColumnNames="ALLOWED_USER" referencedTableName="ACCOUNT" referencedColumnNames="USER_NAME"/>
|
||||
</changeSet>
|
||||
@@ -120,7 +120,8 @@ object GitBucketCoreModule
|
||||
new Version("4.41.0"),
|
||||
new Version("4.42.0", new LiquibaseMigration("update/gitbucket-core_4.42.xml")),
|
||||
new Version("4.42.1"),
|
||||
new Version("4.43.0")
|
||||
new Version("4.43.0"),
|
||||
new Version("4.44.0", new LiquibaseMigration("update/gitbucket-core_4.44.xml"))
|
||||
) {
|
||||
java.util.logging.Logger.getLogger("liquibase").setLevel(Level.SEVERE)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import gitbucket.core.util.RepositoryName
|
||||
* https://developer.github.com/v3/repos/#get-branch
|
||||
* https://developer.github.com/v3/repos/#enabling-and-disabling-branch-protection
|
||||
*/
|
||||
case class ApiBranch(name: String, commit: ApiBranchCommit, protection: ApiBranchProtection)(
|
||||
case class ApiBranch(name: String, commit: ApiBranchCommit, protection: ApiBranchProtectionResponse)(
|
||||
repositoryName: RepositoryName
|
||||
) extends FieldSerializable {
|
||||
val _links =
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package gitbucket.core.api
|
||||
|
||||
/** https://developer.github.com/v3/repos/#enabling-and-disabling-branch-protection */
|
||||
case class ApiBranchProtectionRequest(
|
||||
enabled: Boolean,
|
||||
required_status_checks: Option[ApiBranchProtectionRequest.Status],
|
||||
restrictions: Option[ApiBranchProtectionRequest.Restrictions],
|
||||
enforce_admins: Option[Boolean]
|
||||
)
|
||||
|
||||
object ApiBranchProtectionRequest {
|
||||
|
||||
/** form for enabling-and-disabling-branch-protection */
|
||||
case class EnablingAndDisabling(protection: ApiBranchProtectionRequest)
|
||||
|
||||
case class Status(
|
||||
contexts: Seq[String]
|
||||
)
|
||||
|
||||
case class Restrictions(users: Seq[String])
|
||||
}
|
||||
@@ -4,55 +4,68 @@ import gitbucket.core.service.ProtectedBranchService
|
||||
import org.json4s._
|
||||
|
||||
/** https://developer.github.com/v3/repos/#enabling-and-disabling-branch-protection */
|
||||
case class ApiBranchProtection(
|
||||
case class ApiBranchProtectionResponse(
|
||||
url: Option[ApiPath], // for output
|
||||
enabled: Boolean,
|
||||
required_status_checks: Option[ApiBranchProtection.Status]
|
||||
required_status_checks: Option[ApiBranchProtectionResponse.Status],
|
||||
restrictions: Option[ApiBranchProtectionResponse.Restrictions],
|
||||
enforce_admins: Option[ApiBranchProtectionResponse.EnforceAdmins]
|
||||
) {
|
||||
def status: ApiBranchProtection.Status = required_status_checks.getOrElse(ApiBranchProtection.statusNone)
|
||||
def status: ApiBranchProtectionResponse.Status =
|
||||
required_status_checks.getOrElse(ApiBranchProtectionResponse.statusNone)
|
||||
}
|
||||
|
||||
object ApiBranchProtection {
|
||||
object ApiBranchProtectionResponse {
|
||||
|
||||
/** form for enabling-and-disabling-branch-protection */
|
||||
case class EnablingAndDisabling(protection: ApiBranchProtection)
|
||||
case class EnforceAdmins(enabled: Boolean)
|
||||
|
||||
def apply(info: ProtectedBranchService.ProtectedBranchInfo): ApiBranchProtection =
|
||||
ApiBranchProtection(
|
||||
// /** form for enabling-and-disabling-branch-protection */
|
||||
// case class EnablingAndDisabling(protection: ApiBranchProtectionResponse)
|
||||
|
||||
def apply(info: ProtectedBranchService.ProtectedBranchInfo): ApiBranchProtectionResponse =
|
||||
ApiBranchProtectionResponse(
|
||||
url = Some(
|
||||
ApiPath(
|
||||
s"/api/v3/repos/${info.owner}/${info.repository}/branches/${info.branch}/protection"
|
||||
)
|
||||
),
|
||||
enabled = info.enabled,
|
||||
required_status_checks = Some(
|
||||
required_status_checks = info.contexts.map { contexts =>
|
||||
Status(
|
||||
Some(
|
||||
ApiPath(
|
||||
s"/api/v3/repos/${info.owner}/${info.repository}/branches/${info.branch}/protection/required_status_checks"
|
||||
)
|
||||
),
|
||||
EnforcementLevel(info.enabled && info.contexts.nonEmpty, info.includeAdministrators),
|
||||
info.contexts,
|
||||
EnforcementLevel(info.enabled && info.contexts.nonEmpty, info.enforceAdmins),
|
||||
contexts,
|
||||
Some(
|
||||
ApiPath(
|
||||
s"/api/v3/repos/${info.owner}/${info.repository}/branches/${info.branch}/protection/required_status_checks/contexts"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
},
|
||||
restrictions = info.restrictionsUsers.map { restrictionsUsers =>
|
||||
Restrictions(restrictionsUsers)
|
||||
},
|
||||
enforce_admins = if (info.enabled) Some(EnforceAdmins(info.enforceAdmins)) else None
|
||||
)
|
||||
val statusNone = Status(None, Off, Seq.empty, None)
|
||||
|
||||
val statusNone: Status = Status(None, Off, Seq.empty, None)
|
||||
|
||||
case class Status(
|
||||
url: Option[ApiPath], // for output
|
||||
enforcement_level: EnforcementLevel,
|
||||
contexts: Seq[String],
|
||||
contexts_url: Option[ApiPath] // for output
|
||||
)
|
||||
|
||||
sealed class EnforcementLevel(val name: String)
|
||||
case object Off extends EnforcementLevel("off")
|
||||
case object NonAdmins extends EnforcementLevel("non_admins")
|
||||
case object Everyone extends EnforcementLevel("everyone")
|
||||
|
||||
object EnforcementLevel {
|
||||
def apply(enabled: Boolean, includeAdministrators: Boolean): EnforcementLevel =
|
||||
if (enabled) {
|
||||
@@ -66,6 +79,8 @@ object ApiBranchProtection {
|
||||
}
|
||||
}
|
||||
|
||||
case class Restrictions(users: Seq[String])
|
||||
|
||||
implicit val enforcementLevelSerializer: CustomSerializer[EnforcementLevel] =
|
||||
new CustomSerializer[EnforcementLevel](format =>
|
||||
(
|
||||
@@ -44,7 +44,7 @@ object JsonFormat {
|
||||
FieldSerializer[ApiCommits.File]() +
|
||||
FieldSerializer[ApiRelease]() +
|
||||
FieldSerializer[ApiReleaseAsset]() +
|
||||
ApiBranchProtection.enforcementLevelSerializer
|
||||
ApiBranchProtectionResponse.enforcementLevelSerializer
|
||||
|
||||
def apiPathSerializer(c: Context) =
|
||||
new CustomSerializer[ApiPath](_ =>
|
||||
|
||||
@@ -261,11 +261,22 @@ trait IndexControllerBase extends ControllerBase {
|
||||
|
||||
/**
|
||||
* JSON API for checking user or group existence.
|
||||
*
|
||||
* Returns a single string which is any of "group", "user" or "".
|
||||
* Additionally, check whether the user is writable to the repository
|
||||
* if "owner" and "repository" are given,
|
||||
*/
|
||||
post("/_user/existence")(usersOnly {
|
||||
getAccountByUserNameIgnoreCase(params("userName")).map { account =>
|
||||
if (account.isGroupAccount) "group" else "user"
|
||||
if (!account.isGroupAccount && params.get("repository").isDefined && params.get("owner").isDefined) {
|
||||
getRepository(params("owner"), params("repository"))
|
||||
.collect {
|
||||
case repository if isWritable(repository.repository, Some(account)) => "user"
|
||||
}
|
||||
.getOrElse("")
|
||||
} else {
|
||||
if (account.isGroupAccount) "group" else "user"
|
||||
}
|
||||
} getOrElse ""
|
||||
})
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ trait PreProcessControllerBase extends ControllerBase {
|
||||
if (
|
||||
!context.currentPath.startsWith("/assets") && !context.currentPath.startsWith("/signin") &&
|
||||
!context.currentPath.startsWith("/register") && !context.currentPath.endsWith("/info/refs") &&
|
||||
!context.currentPath.startsWith("/plugin-assets") &&
|
||||
!context.currentPath.startsWith("/plugin-assets") && !context.currentPath.equals("/user.css") &&
|
||||
!PluginRegistry().getAnonymousAccessiblePaths().exists { path =>
|
||||
context.currentPath.startsWith(path)
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
||||
if (!repository.branchList.contains(branch)) {
|
||||
redirect(s"/${repository.owner}/${repository.name}/settings/branches")
|
||||
} else {
|
||||
val protection = ApiBranchProtection(getProtectedBranchInfo(repository.owner, repository.name, branch))
|
||||
val protection = ApiBranchProtectionResponse(getProtectedBranchInfo(repository.owner, repository.name, branch))
|
||||
val lastWeeks = getRecentStatusContexts(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
|
||||
@@ -1076,14 +1076,9 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
redirect(s"${repository.owner}/${repository.name}/releases")
|
||||
})
|
||||
|
||||
get("/:owner/:repository/archive/:name")(referrersOnly { repository =>
|
||||
val name = params("name")
|
||||
archiveRepository(name, repository, "")
|
||||
})
|
||||
|
||||
get("/:owner/:repository/archive/*/:name")(referrersOnly { repository =>
|
||||
val name = params("name")
|
||||
val path = multiParams("splat").head
|
||||
get("/:owner/:repository/archive/*")(referrersOnly { repository =>
|
||||
val name = multiParams("splat").mkString("/")
|
||||
val path = params.get("path").getOrElse("")
|
||||
archiveRepository(name, repository, path)
|
||||
})
|
||||
|
||||
|
||||
@@ -306,7 +306,8 @@ trait WikiControllerBase extends ControllerBase {
|
||||
|
||||
get("/:owner/:repository/wiki/_history")(referrersOnly { repository =>
|
||||
Using.resource(Git.open(getWikiRepositoryDir(repository.owner, repository.name))) { git =>
|
||||
JGitUtil.getCommitLog(git, "master") match {
|
||||
val branch = getWikiBranch(repository.owner, repository.name)
|
||||
JGitUtil.getCommitLog(git, branch) match {
|
||||
case Right((logs, hasNext)) => html.history(None, logs, repository, isEditable(repository))
|
||||
case Left(_) => NotFound()
|
||||
}
|
||||
@@ -316,7 +317,8 @@ trait WikiControllerBase extends ControllerBase {
|
||||
get("/:owner/:repository/wiki/_blob/*")(referrersOnly { repository =>
|
||||
val path = multiParams("splat").head
|
||||
Using.resource(Git.open(getWikiRepositoryDir(repository.owner, repository.name))) { git =>
|
||||
val revCommit = JGitUtil.getRevCommitFromId(git, git.getRepository.resolve("master"))
|
||||
val branch = getWikiBranch(repository.owner, repository.name)
|
||||
val revCommit = JGitUtil.getRevCommitFromId(git, git.getRepository.resolve(branch))
|
||||
|
||||
getPathObjectId(git, path, revCommit).map { objectId =>
|
||||
responseRawFile(git, objectId, path, repository)
|
||||
|
||||
@@ -5,7 +5,7 @@ import gitbucket.core.service.{AccountService, ProtectedBranchService, Repositor
|
||||
import gitbucket.core.util.*
|
||||
import gitbucket.core.util.Directory.*
|
||||
import gitbucket.core.util.Implicits.*
|
||||
import gitbucket.core.util.JGitUtil.getBranchesNoMergeInfo
|
||||
import gitbucket.core.util.JGitUtil.{getBranchesNoMergeInfo, processTree}
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.scalatra.NoContent
|
||||
|
||||
@@ -43,7 +43,9 @@ trait ApiRepositoryBranchControllerBase extends ControllerBase {
|
||||
} yield {
|
||||
val protection = getProtectedBranchInfo(repository.owner, repository.name, branch)
|
||||
JsonFormat(
|
||||
ApiBranch(branch, ApiBranchCommit(br.commitId), ApiBranchProtection(protection))(RepositoryName(repository))
|
||||
ApiBranch(branch, ApiBranchCommit(br.commitId), ApiBranchProtectionResponse(protection))(
|
||||
RepositoryName(repository)
|
||||
)
|
||||
)
|
||||
}) getOrElse NotFound()
|
||||
}
|
||||
@@ -58,7 +60,7 @@ trait ApiRepositoryBranchControllerBase extends ControllerBase {
|
||||
if (repository.branchList.contains(branch)) {
|
||||
val protection = getProtectedBranchInfo(repository.owner, repository.name, branch)
|
||||
JsonFormat(
|
||||
ApiBranchProtection(protection)
|
||||
ApiBranchProtectionResponse(protection)
|
||||
)
|
||||
} else { NotFound() }
|
||||
})
|
||||
@@ -138,7 +140,7 @@ trait ApiRepositoryBranchControllerBase extends ControllerBase {
|
||||
if (repository.branchList.contains(branch)) {
|
||||
val protection = getProtectedBranchInfo(repository.owner, repository.name, branch)
|
||||
JsonFormat(
|
||||
ApiBranchProtection(protection).required_status_checks
|
||||
ApiBranchProtectionResponse(protection).required_status_checks
|
||||
)
|
||||
} else { NotFound() }
|
||||
})
|
||||
@@ -262,7 +264,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)
|
||||
protection <- extractFromJsonBody[ApiBranchProtection.EnablingAndDisabling].map(_.protection)
|
||||
protection <- extractFromJsonBody[ApiBranchProtectionRequest.EnablingAndDisabling].map(_.protection)
|
||||
br <- getBranchesNoMergeInfo(git).find(_.name == branch)
|
||||
} yield {
|
||||
if (protection.enabled) {
|
||||
@@ -270,13 +272,17 @@ trait ApiRepositoryBranchControllerBase extends ControllerBase {
|
||||
repository.owner,
|
||||
repository.name,
|
||||
branch,
|
||||
protection.status.enforcement_level == ApiBranchProtection.Everyone,
|
||||
protection.status.contexts
|
||||
protection.enforce_admins.getOrElse(false),
|
||||
protection.required_status_checks.isDefined,
|
||||
protection.required_status_checks.map(_.contexts).getOrElse(Nil),
|
||||
protection.restrictions.isDefined,
|
||||
protection.restrictions.map(_.users).getOrElse(Nil)
|
||||
)
|
||||
} else {
|
||||
disableBranchProtection(repository.owner, repository.name, branch)
|
||||
}
|
||||
JsonFormat(ApiBranch(branch, ApiBranchCommit(br.commitId), protection)(RepositoryName(repository)))
|
||||
val response = ApiBranchProtectionResponse(getProtectedBranchInfo(repository.owner, repository.name, branch))
|
||||
JsonFormat(ApiBranch(branch, ApiBranchCommit(br.commitId), response)(RepositoryName(repository)))
|
||||
}) getOrElse NotFound()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -142,10 +142,11 @@ trait ApiRepositoryContentsControllerBase extends ControllerBase {
|
||||
val revCommit = JGitUtil.getRevCommitFromId(git, git.getRepository.resolve(branch))
|
||||
revCommit.name
|
||||
}
|
||||
val paths = multiParams("splat").head.split("/")
|
||||
val fullPath = multiParams("splat").head
|
||||
val paths = fullPath.split("/")
|
||||
val path = paths.take(paths.size - 1).toList.mkString("/")
|
||||
Using.resource(Git.open(getRepositoryDir(params("owner"), params("repository")))) { git =>
|
||||
val fileInfo = getFileInfo(git, commit, path, false)
|
||||
val fileInfo = getFileInfo(git, commit, fullPath, ignoreCase = false)
|
||||
|
||||
fileInfo match {
|
||||
case Some(f) if !data.sha.contains(f.id.getName) =>
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
package gitbucket.core.model
|
||||
|
||||
trait ProtectedBranchComponent extends TemplateComponent { self: Profile =>
|
||||
import profile.api._
|
||||
import self._
|
||||
import profile.api.*
|
||||
|
||||
lazy val ProtectedBranches = TableQuery[ProtectedBranches]
|
||||
class ProtectedBranches(tag: Tag) extends Table[ProtectedBranch](tag, "PROTECTED_BRANCH") with BranchTemplate {
|
||||
val statusCheckAdmin = column[Boolean]("STATUS_CHECK_ADMIN")
|
||||
def * = (userName, repositoryName, branch, statusCheckAdmin).mapTo[ProtectedBranch]
|
||||
def byPrimaryKey(userName: String, repositoryName: String, branch: String) =
|
||||
val statusCheckAdmin = column[Boolean]("STATUS_CHECK_ADMIN") // enforceAdmins
|
||||
val requiredStatusCheck = column[Boolean]("REQUIRED_STATUS_CHECK")
|
||||
val restrictions = column[Boolean]("RESTRICTIONS")
|
||||
def * =
|
||||
(userName, repositoryName, branch, statusCheckAdmin, requiredStatusCheck, restrictions).mapTo[ProtectedBranch]
|
||||
def byPrimaryKey(userName: String, repositoryName: String, branch: String): Rep[Boolean] =
|
||||
byBranch(userName, repositoryName, branch)
|
||||
def byPrimaryKey(userName: Rep[String], repositoryName: Rep[String], branch: Rep[String]) =
|
||||
def byPrimaryKey(userName: Rep[String], repositoryName: Rep[String], branch: Rep[String]): Rep[Boolean] =
|
||||
byBranch(userName, repositoryName, branch)
|
||||
}
|
||||
|
||||
@@ -22,8 +24,27 @@ trait ProtectedBranchComponent extends TemplateComponent { self: Profile =>
|
||||
def * =
|
||||
(userName, repositoryName, branch, context).mapTo[ProtectedBranchContext]
|
||||
}
|
||||
|
||||
lazy val ProtectedBranchRestrictions = TableQuery[ProtectedBranchRestrictions]
|
||||
class ProtectedBranchRestrictions(tag: Tag)
|
||||
extends Table[ProtectedBranchRestriction](tag, "PROTECTED_BRANCH_RESTRICTION")
|
||||
with BranchTemplate {
|
||||
val allowedUser = column[String]("ALLOWED_USER")
|
||||
def * = (userName, repositoryName, branch, allowedUser).mapTo[ProtectedBranchRestriction]
|
||||
def byPrimaryKey(userName: String, repositoryName: String, branch: String, allowedUser: String): Rep[Boolean] =
|
||||
this.userName === userName.bind && this.repositoryName === repositoryName.bind && this.branch === branch.bind && this.allowedUser === allowedUser.bind
|
||||
}
|
||||
}
|
||||
|
||||
case class ProtectedBranch(userName: String, repositoryName: String, branch: String, statusCheckAdmin: Boolean)
|
||||
case class ProtectedBranch(
|
||||
userName: String,
|
||||
repositoryName: String,
|
||||
branch: String,
|
||||
enforceAdmins: Boolean,
|
||||
requiredStatusCheck: Boolean,
|
||||
restrictions: Boolean
|
||||
)
|
||||
|
||||
case class ProtectedBranchContext(userName: String, repositoryName: String, branch: String, context: String)
|
||||
|
||||
case class ProtectedBranchRestriction(userName: String, repositoryName: String, branch: String, allowedUser: String)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package gitbucket.core.service
|
||||
|
||||
import gitbucket.core.model.{Session => _, _}
|
||||
import gitbucket.core.plugin.ReceiveHook
|
||||
import gitbucket.core.model.Profile._
|
||||
import gitbucket.core.model.Profile.profile.blockingApi._
|
||||
import gitbucket.core.model.Profile.*
|
||||
import gitbucket.core.model.Profile.profile.blockingApi.*
|
||||
import gitbucket.core.model.{CommitState, ProtectedBranch, ProtectedBranchContext, ProtectedBranchRestriction, Role}
|
||||
import gitbucket.core.util.SyntaxSugars.*
|
||||
import org.eclipse.jgit.transport.{ReceiveCommand, ReceivePack}
|
||||
|
||||
trait ProtectedBranchService {
|
||||
@@ -13,17 +14,27 @@ trait ProtectedBranchService {
|
||||
): Option[ProtectedBranchInfo] =
|
||||
ProtectedBranches
|
||||
.joinLeft(ProtectedBranchContexts)
|
||||
.on { case (pb, c) => pb.byBranch(c.userName, c.repositoryName, c.branch) }
|
||||
.map { case (pb, c) => pb -> c.map(_.context) }
|
||||
.on { case pb ~ c => pb.byBranch(c.userName, c.repositoryName, c.branch) }
|
||||
.joinLeft(ProtectedBranchRestrictions)
|
||||
.on { case pb ~ c ~ r => pb.byBranch(r.userName, r.repositoryName, r.branch) }
|
||||
.map { case pb ~ c ~ r => pb -> (c.map(_.context), r.map(_.allowedUser)) }
|
||||
.filter(_._1.byPrimaryKey(owner, repository, branch))
|
||||
.list
|
||||
.groupBy(_._1)
|
||||
.headOption
|
||||
.map { p =>
|
||||
p._1 -> p._2.flatMap(_._2)
|
||||
.map { (p: (ProtectedBranch, List[(ProtectedBranch, (Option[String], Option[String]))])) =>
|
||||
p._1 -> (p._2.flatMap(_._2._1), p._2.flatMap(_._2._2))
|
||||
}
|
||||
.map { case (t1, contexts) =>
|
||||
new ProtectedBranchInfo(t1.userName, t1.repositoryName, t1.branch, true, contexts, t1.statusCheckAdmin)
|
||||
.map { case (t1, (contexts, users)) =>
|
||||
new ProtectedBranchInfo(
|
||||
t1.userName,
|
||||
t1.repositoryName,
|
||||
t1.branch,
|
||||
true,
|
||||
if (t1.requiredStatusCheck) Some(contexts) else None,
|
||||
t1.enforceAdmins,
|
||||
if (t1.restrictions) Some(users) else None
|
||||
)
|
||||
}
|
||||
|
||||
def getProtectedBranchInfo(owner: String, repository: String, branch: String)(implicit
|
||||
@@ -40,19 +51,32 @@ trait ProtectedBranchService {
|
||||
owner: String,
|
||||
repository: String,
|
||||
branch: String,
|
||||
includeAdministrators: Boolean,
|
||||
contexts: Seq[String]
|
||||
enforceAdmins: Boolean,
|
||||
requiredStatusCheck: Boolean,
|
||||
contexts: Seq[String],
|
||||
restrictions: Boolean,
|
||||
restrictionsUsers: Seq[String]
|
||||
)(implicit session: Session): Unit = {
|
||||
disableBranchProtection(owner, repository, branch)
|
||||
ProtectedBranches.insert(new ProtectedBranch(owner, repository, branch, includeAdministrators && contexts.nonEmpty))
|
||||
contexts.map { context =>
|
||||
ProtectedBranchContexts.insert(new ProtectedBranchContext(owner, repository, branch, context))
|
||||
ProtectedBranches.insert(
|
||||
ProtectedBranch(owner, repository, branch, enforceAdmins, requiredStatusCheck, restrictions)
|
||||
)
|
||||
|
||||
if (restrictions) {
|
||||
restrictionsUsers.foreach { user =>
|
||||
ProtectedBranchRestrictions.insert(ProtectedBranchRestriction(owner, repository, branch, user))
|
||||
}
|
||||
}
|
||||
|
||||
if (requiredStatusCheck) {
|
||||
contexts.foreach { context =>
|
||||
ProtectedBranchContexts.insert(ProtectedBranchContext(owner, repository, branch, context))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def disableBranchProtection(owner: String, repository: String, branch: String)(implicit session: Session): Unit =
|
||||
ProtectedBranches.filter(_.byPrimaryKey(owner, repository, branch)).delete
|
||||
|
||||
}
|
||||
|
||||
object ProtectedBranchService {
|
||||
@@ -101,6 +125,7 @@ object ProtectedBranchService {
|
||||
)
|
||||
}
|
||||
} else {
|
||||
println("-> else")
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -117,12 +142,16 @@ object ProtectedBranchService {
|
||||
* When enabled, commits must first be pushed to another branch,
|
||||
* then merged or pushed directly to test after status checks have passed.
|
||||
*/
|
||||
contexts: Seq[String],
|
||||
contexts: Option[Seq[String]],
|
||||
/**
|
||||
* Include administrators
|
||||
* Enforce required status checks for repository administrators.
|
||||
*/
|
||||
includeAdministrators: Boolean
|
||||
enforceAdmins: Boolean,
|
||||
/**
|
||||
* Users who can push to the branch.
|
||||
*/
|
||||
restrictionsUsers: Option[Seq[String]]
|
||||
) extends AccountService
|
||||
with RepositoryService
|
||||
with CommitStatusService {
|
||||
@@ -148,42 +177,66 @@ object ProtectedBranchService {
|
||||
session: Session
|
||||
): Option[String] = {
|
||||
if (enabled) {
|
||||
command.getType() match {
|
||||
command.getType match {
|
||||
case ReceiveCommand.Type.UPDATE_NONFASTFORWARD if isAllowNonFastForwards =>
|
||||
Some("Cannot force-push to a protected branch")
|
||||
case ReceiveCommand.Type.UPDATE | ReceiveCommand.Type.UPDATE_NONFASTFORWARD if !isPushAllowed(pusher) =>
|
||||
Some("You do not have permission to push to this branch")
|
||||
case ReceiveCommand.Type.UPDATE | ReceiveCommand.Type.UPDATE_NONFASTFORWARD if needStatusCheck(pusher) =>
|
||||
unSuccessedContexts(command.getNewId.name) match {
|
||||
case s if s.sizeIs == 1 => Some(s"""Required status check "${s.toSeq(0)}" is expected""")
|
||||
case s if s.sizeIs >= 1 => Some(s"${s.size} of ${contexts.size} required status checks are expected")
|
||||
case _ => None
|
||||
case s if s.sizeIs == 1 => Some(s"""Required status check "${s.head}" is expected""")
|
||||
case s if s.sizeIs >= 1 =>
|
||||
Some(s"${s.size} of ${contexts.map(_.size).getOrElse(0)} required status checks are expected")
|
||||
case _ => None
|
||||
}
|
||||
case ReceiveCommand.Type.DELETE =>
|
||||
Some("Cannot delete a protected branch")
|
||||
Some("You do not have permission to push to this branch")
|
||||
case _ => None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
def unSuccessedContexts(sha1: String)(implicit session: Session): Set[String] =
|
||||
if (contexts.isEmpty) {
|
||||
Set.empty
|
||||
} else {
|
||||
contexts.toSet -- getCommitStatuses(owner, repository, sha1)
|
||||
.filter(_.state == CommitState.SUCCESS)
|
||||
.map(_.context)
|
||||
.toSet
|
||||
|
||||
def unSuccessedContexts(sha1: String)(implicit session: Session): Set[String] = {
|
||||
contexts match {
|
||||
case None => Set.empty
|
||||
case Some(x) if x.isEmpty => Set.empty
|
||||
case Some(x) =>
|
||||
x.toSet -- getCommitStatuses(owner, repository, sha1)
|
||||
.filter(_.state == CommitState.SUCCESS)
|
||||
.map(_.context)
|
||||
.toSet
|
||||
}
|
||||
}
|
||||
|
||||
def needStatusCheck(pusher: String)(implicit session: Session): Boolean = pusher match {
|
||||
case _ if !enabled => false
|
||||
case _ if contexts.isEmpty => false
|
||||
case _ if includeAdministrators => true
|
||||
case p if isAdministrator(p) => false
|
||||
case _ => true
|
||||
case _ if !enabled => false
|
||||
case _ if contexts.isEmpty => false
|
||||
case _ if enforceAdmins => true
|
||||
case p if isAdministrator(p) => false
|
||||
case _ => true
|
||||
}
|
||||
|
||||
def isPushAllowed(pusher: String)(implicit session: Session): Boolean = pusher match {
|
||||
case _ if !enabled || restrictionsUsers.isEmpty => true
|
||||
case _ if restrictionsUsers.get.contains(pusher) => true
|
||||
case p if isAdministrator(p) && enforceAdmins => false
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
object ProtectedBranchInfo {
|
||||
def disabled(owner: String, repository: String, branch: String): ProtectedBranchInfo =
|
||||
ProtectedBranchInfo(owner, repository, branch, false, Nil, false)
|
||||
def disabled(owner: String, repository: String, branch: String): ProtectedBranchInfo = {
|
||||
ProtectedBranchInfo(
|
||||
owner,
|
||||
repository,
|
||||
branch,
|
||||
enabled = false,
|
||||
contexts = None,
|
||||
enforceAdmins = false,
|
||||
restrictionsUsers = None
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -653,18 +653,18 @@ object PullRequestService {
|
||||
commitIdTo: String
|
||||
) {
|
||||
|
||||
val hasConflict = conflictMessage.isDefined
|
||||
val hasConflict: Boolean = conflictMessage.isDefined
|
||||
val statuses: List[CommitStatus] =
|
||||
commitStatuses ++ (branchProtection.contexts.toSet -- commitStatuses.map(_.context).toSet)
|
||||
commitStatuses ++ (branchProtection.contexts.getOrElse(Nil).toSet -- commitStatuses.map(_.context).toSet)
|
||||
.map(CommitStatus.pending(branchProtection.owner, branchProtection.repository, _))
|
||||
val hasRequiredStatusProblem = needStatusCheck && branchProtection.contexts.exists(context =>
|
||||
statuses.find(_.context == context).map(_.state) != Some(CommitState.SUCCESS)
|
||||
)
|
||||
val hasProblem = hasRequiredStatusProblem || hasConflict || (statuses.nonEmpty && CommitState.combine(
|
||||
val hasRequiredStatusProblem: Boolean = needStatusCheck && branchProtection.contexts
|
||||
.getOrElse(Nil)
|
||||
.exists(context => !statuses.find(_.context == context).map(_.state).contains(CommitState.SUCCESS))
|
||||
val hasProblem: Boolean = hasRequiredStatusProblem || hasConflict || (statuses.nonEmpty && CommitState.combine(
|
||||
statuses.map(_.state).toSet
|
||||
) != CommitState.SUCCESS)
|
||||
val canUpdate = branchIsOutOfDate && !hasConflict
|
||||
val canMerge = hasMergePermission && !hasConflict && !hasRequiredStatusProblem
|
||||
val canUpdate: Boolean = branchIsOutOfDate && !hasConflict
|
||||
val canMerge: Boolean = hasMergePermission && !hasConflict && !hasRequiredStatusProblem
|
||||
lazy val commitStateSummary: (CommitState, String) = {
|
||||
val stateMap = statuses.groupBy(_.state)
|
||||
val state = CommitState.combine(stateMap.keySet)
|
||||
@@ -672,8 +672,8 @@ object PullRequestService {
|
||||
state -> summary
|
||||
}
|
||||
lazy val statusesAndRequired: List[(CommitStatus, Boolean)] = statuses.map { s =>
|
||||
s -> branchProtection.contexts.contains(s.context)
|
||||
s -> branchProtection.contexts.getOrElse(Nil).contains(s.context)
|
||||
}
|
||||
lazy val isAllSuccess = commitStateSummary._1 == CommitState.SUCCESS
|
||||
lazy val isAllSuccess: Boolean = commitStateSummary._1 == CommitState.SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package gitbucket.core.service
|
||||
import gitbucket.core.api.JsonFormat
|
||||
import gitbucket.core.model.{Account, WebHook}
|
||||
import gitbucket.core.model.Profile.profile.blockingApi._
|
||||
import gitbucket.core.model.Profile.profile.blockingApi.*
|
||||
import gitbucket.core.model.activity.{CloseIssueInfo, PushInfo}
|
||||
import gitbucket.core.plugin.PluginRegistry
|
||||
import gitbucket.core.service.SystemSettingsService.SystemSettings
|
||||
@@ -11,14 +11,14 @@ import gitbucket.core.util.JGitUtil.CommitInfo
|
||||
import gitbucket.core.util.{JGitUtil, LockUtil}
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.eclipse.jgit.dircache.{DirCache, DirCacheBuilder}
|
||||
import org.eclipse.jgit.lib._
|
||||
import org.eclipse.jgit.lib.*
|
||||
import org.eclipse.jgit.transport.{ReceiveCommand, ReceivePack}
|
||||
|
||||
import scala.util.Using
|
||||
|
||||
trait RepositoryCommitFileService {
|
||||
self: AccountService & ActivityService & IssuesService & PullRequestService & WebHookPullRequestService &
|
||||
RepositoryService =>
|
||||
RepositoryService & ProtectedBranchService =>
|
||||
|
||||
/**
|
||||
* Create multiple files by callback function.
|
||||
@@ -92,10 +92,10 @@ trait RepositoryCommitFileService {
|
||||
)(implicit s: Session, c: JsonFormat.Context): Either[String, (ObjectId, Option[ObjectId])] = {
|
||||
|
||||
val newPath = newFileName.map { newFileName =>
|
||||
if (path.length == 0) newFileName else s"${path}/${newFileName}"
|
||||
if (path.isEmpty) newFileName else s"${path}/${newFileName}"
|
||||
}
|
||||
val oldPath = oldFileName.map { oldFileName =>
|
||||
if (path.length == 0) oldFileName else s"${path}/${oldFileName}"
|
||||
if (path.isEmpty) oldFileName else s"${path}/${oldFileName}"
|
||||
}
|
||||
|
||||
_createFiles(repository, branch, message, pusherAccount, committerName, committerMailAddress, settings) {
|
||||
@@ -139,7 +139,6 @@ trait RepositoryCommitFileService {
|
||||
)(
|
||||
f: (Git, ObjectId, DirCacheBuilder, ObjectInserter) => R
|
||||
)(implicit s: Session, c: JsonFormat.Context): Either[String, (ObjectId, R)] = {
|
||||
|
||||
LockUtil.lock(s"${repository.owner}/${repository.name}") {
|
||||
Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
|
||||
val builder = DirCache.newInCore.builder()
|
||||
@@ -168,7 +167,14 @@ trait RepositoryCommitFileService {
|
||||
|
||||
// call pre-commit hook
|
||||
val error = PluginRegistry().getReceiveHooks.flatMap { hook =>
|
||||
hook.preReceive(repository.owner, repository.name, receivePack, receiveCommand, pusherAccount.userName, false)
|
||||
hook.preReceive(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
receivePack,
|
||||
receiveCommand,
|
||||
pusherAccount.userName,
|
||||
mergePullRequest = false
|
||||
)
|
||||
}.headOption
|
||||
|
||||
error match {
|
||||
@@ -194,7 +200,8 @@ trait RepositoryCommitFileService {
|
||||
// record activity
|
||||
updateLastActivityDate(repository.owner, repository.name)
|
||||
val commitInfo = new CommitInfo(JGitUtil.getRevCommitFromId(git, commitId))
|
||||
val pushInfo = PushInfo(repository.owner, repository.name, pusherAccount.userName, branch, List(commitInfo))
|
||||
val pushInfo =
|
||||
PushInfo(repository.owner, repository.name, pusherAccount.userName, branch, List(commitInfo))
|
||||
recordActivity(pushInfo)
|
||||
|
||||
// create issue comment by commit message
|
||||
@@ -221,7 +228,14 @@ trait RepositoryCommitFileService {
|
||||
|
||||
// call post-commit hook
|
||||
PluginRegistry().getReceiveHooks.foreach { hook =>
|
||||
hook.postReceive(repository.owner, repository.name, receivePack, receiveCommand, committerName, false)
|
||||
hook.postReceive(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
receivePack,
|
||||
receiveCommand,
|
||||
committerName,
|
||||
mergePullRequest = false
|
||||
)
|
||||
}
|
||||
|
||||
val commit = new JGitUtil.CommitInfo(JGitUtil.getRevCommitFromId(git, commitId))
|
||||
|
||||
@@ -654,11 +654,11 @@ trait RepositoryService {
|
||||
|
||||
def hasOwnerRole(owner: String, repository: String, loginAccount: Option[Account])(implicit s: Session): Boolean = {
|
||||
loginAccount match {
|
||||
case Some(a) if (a.isAdmin) => true
|
||||
case Some(a) if (a.userName == owner) => true
|
||||
case Some(a) if (getGroupMembers(owner).exists(_.userName == a.userName)) => true
|
||||
case Some(a) if (getCollaboratorUserNames(owner, repository, Seq(Role.ADMIN)).contains(a.userName)) => true
|
||||
case _ => false
|
||||
case Some(a) if a.isAdmin => true
|
||||
case Some(a) if a.userName == owner => true
|
||||
case Some(a) if getGroupMembers(owner).exists(_.userName == a.userName) => true
|
||||
case Some(a) if getCollaboratorUserNames(owner, repository, Seq(Role.ADMIN)).contains(a.userName) => true
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -666,11 +666,11 @@ trait RepositoryService {
|
||||
s: Session
|
||||
): Boolean = {
|
||||
loginAccount match {
|
||||
case Some(a) if (a.isAdmin) => true
|
||||
case Some(a) if (a.userName == owner) => true
|
||||
case Some(a) if (getGroupMembers(owner).exists(_.userName == a.userName)) => true
|
||||
case Some(a) if a.isAdmin => true
|
||||
case Some(a) if a.userName == owner => true
|
||||
case Some(a) if getGroupMembers(owner).exists(_.userName == a.userName) => true
|
||||
case Some(a)
|
||||
if (getCollaboratorUserNames(owner, repository, Seq(Role.ADMIN, Role.DEVELOPER)).contains(a.userName)) =>
|
||||
if getCollaboratorUserNames(owner, repository, Seq(Role.ADMIN, Role.DEVELOPER)).contains(a.userName) =>
|
||||
true
|
||||
case _ => false
|
||||
}
|
||||
@@ -678,12 +678,12 @@ trait RepositoryService {
|
||||
|
||||
def hasGuestRole(owner: String, repository: String, loginAccount: Option[Account])(implicit s: Session): Boolean = {
|
||||
loginAccount match {
|
||||
case Some(a) if (a.isAdmin) => true
|
||||
case Some(a) if (a.userName == owner) => true
|
||||
case Some(a) if (getGroupMembers(owner).exists(_.userName == a.userName)) => true
|
||||
case Some(a) if a.isAdmin => true
|
||||
case Some(a) if a.userName == owner => true
|
||||
case Some(a) if getGroupMembers(owner).exists(_.userName == a.userName) => true
|
||||
case Some(a)
|
||||
if (getCollaboratorUserNames(owner, repository, Seq(Role.ADMIN, Role.DEVELOPER, Role.GUEST))
|
||||
.contains(a.userName)) =>
|
||||
if getCollaboratorUserNames(owner, repository, Seq(Role.ADMIN, Role.DEVELOPER, Role.GUEST))
|
||||
.contains(a.userName) =>
|
||||
true
|
||||
case _ => false
|
||||
}
|
||||
@@ -694,17 +694,29 @@ trait RepositoryService {
|
||||
true
|
||||
} else {
|
||||
loginAccount match {
|
||||
case Some(x) if (x.isAdmin) => true
|
||||
case Some(x) if (repository.userName == x.userName) => true
|
||||
case Some(x) if (getGroupMembers(repository.userName).exists(_.userName == x.userName)) => true
|
||||
case Some(x)
|
||||
if (getCollaboratorUserNames(repository.userName, repository.repositoryName).contains(x.userName)) =>
|
||||
case Some(x) if x.isAdmin => true
|
||||
case Some(x) if repository.userName == x.userName => true
|
||||
case Some(x) if getGroupMembers(repository.userName).exists(_.userName == x.userName) => true
|
||||
case Some(x) if getCollaboratorUserNames(repository.userName, repository.repositoryName).contains(x.userName) =>
|
||||
true
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def isWritable(repository: Repository, loginAccount: Option[Account])(implicit s: Session): Boolean = {
|
||||
loginAccount match {
|
||||
case Some(x) if x.isAdmin => true
|
||||
case Some(x) if repository.userName == x.userName => true
|
||||
case Some(x) if getGroupMembers(repository.userName).exists(_.userName == x.userName) => true
|
||||
case Some(x)
|
||||
if getCollaboratorUserNames(repository.userName, repository.repositoryName, Seq(Role.ADMIN, Role.DEVELOPER))
|
||||
.contains(x.userName) =>
|
||||
true
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
private def getForkedCount(userName: String, repositoryName: String)(implicit s: Session): Int =
|
||||
Query(Repositories.filter { t =>
|
||||
(t.originUserName === userName.bind) && (t.originRepositoryName === repositoryName.bind)
|
||||
|
||||
@@ -9,11 +9,11 @@ import gitbucket.core.api.JsonFormat.Context
|
||||
import gitbucket.core.model.WebHook
|
||||
import gitbucket.core.plugin.{GitRepositoryRouting, PluginRegistry}
|
||||
import gitbucket.core.service.IssuesService.IssueSearchCondition
|
||||
import gitbucket.core.service.WebHookService._
|
||||
import gitbucket.core.service._
|
||||
import gitbucket.core.util.Implicits._
|
||||
import gitbucket.core.util._
|
||||
import gitbucket.core.model.Profile.profile.blockingApi._
|
||||
import gitbucket.core.service.WebHookService.*
|
||||
import gitbucket.core.service.*
|
||||
import gitbucket.core.util.Implicits.*
|
||||
import gitbucket.core.util.*
|
||||
import gitbucket.core.model.Profile.profile.blockingApi.*
|
||||
import gitbucket.core.model.activity.{
|
||||
BaseActivityInfo,
|
||||
CloseIssueInfo,
|
||||
@@ -33,9 +33,9 @@ import gitbucket.core.servlet.Database
|
||||
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.eclipse.jgit.http.server.GitServlet
|
||||
import org.eclipse.jgit.lib._
|
||||
import org.eclipse.jgit.transport._
|
||||
import org.eclipse.jgit.transport.resolver._
|
||||
import org.eclipse.jgit.lib.*
|
||||
import org.eclipse.jgit.transport.*
|
||||
import org.eclipse.jgit.transport.resolver.*
|
||||
import org.slf4j.LoggerFactory
|
||||
import javax.servlet.ServletConfig
|
||||
import javax.servlet.http.{HttpServletRequest, HttpServletResponse}
|
||||
@@ -43,7 +43,7 @@ import org.eclipse.jgit.diff.DiffEntry.ChangeType
|
||||
import org.eclipse.jgit.internal.storage.file.FileRepository
|
||||
import org.json4s.Formats
|
||||
import org.json4s.convertToJsonInput
|
||||
import org.json4s.jackson.Serialization._
|
||||
import org.json4s.jackson.Serialization.*
|
||||
|
||||
/**
|
||||
* Provides Git repository via HTTP.
|
||||
@@ -117,7 +117,7 @@ class GitRepositoryServlet extends GitServlet with SystemSettingsService {
|
||||
GitLfs.BatchResponseObject(
|
||||
requestObject.oid,
|
||||
requestObject.size,
|
||||
true,
|
||||
authenticated = true,
|
||||
GitLfs.Actions(
|
||||
upload = Some(
|
||||
GitLfs.Action(
|
||||
@@ -138,7 +138,7 @@ class GitRepositoryServlet extends GitServlet with SystemSettingsService {
|
||||
GitLfs.BatchResponseObject(
|
||||
requestObject.oid,
|
||||
requestObject.size,
|
||||
true,
|
||||
authenticated = true,
|
||||
GitLfs.Actions(
|
||||
download = Some(
|
||||
GitLfs.Action(
|
||||
@@ -223,7 +223,7 @@ class GitBucketReceivePackFactory extends ReceivePackFactory[HttpServletRequest]
|
||||
}
|
||||
}
|
||||
|
||||
import scala.jdk.CollectionConverters._
|
||||
import scala.jdk.CollectionConverters.*
|
||||
|
||||
class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl: String, sshUrl: Option[String])
|
||||
extends PostReceiveHook
|
||||
@@ -242,6 +242,7 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl:
|
||||
with WebHookPullRequestReviewCommentService
|
||||
with CommitsService
|
||||
with SystemSettingsService
|
||||
with ProtectedBranchService
|
||||
with RequestCache {
|
||||
|
||||
private val logger = LoggerFactory.getLogger(classOf[CommitLogHook])
|
||||
@@ -253,7 +254,7 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl:
|
||||
commands.asScala.foreach { command =>
|
||||
// call pre-commit hook
|
||||
PluginRegistry().getReceiveHooks
|
||||
.flatMap(_.preReceive(owner, repository, receivePack, command, pusher, false))
|
||||
.flatMap(_.preReceive(owner, repository, receivePack, command, pusher, mergePullRequest = false))
|
||||
.headOption
|
||||
.foreach { error =>
|
||||
command.setResult(ReceiveCommand.Result.REJECTED_OTHER_REASON, error)
|
||||
@@ -428,8 +429,8 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl:
|
||||
repositoryInfo,
|
||||
newCommits,
|
||||
ownerAccount,
|
||||
newId = command.getNewId(),
|
||||
oldId = command.getOldId()
|
||||
newId = command.getNewId,
|
||||
oldId = command.getOldId
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -453,7 +454,7 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl:
|
||||
|
||||
// call post-commit hook
|
||||
PluginRegistry().getReceiveHooks
|
||||
.foreach(_.postReceive(owner, repository, receivePack, command, pusher, false))
|
||||
.foreach(_.postReceive(owner, repository, receivePack, command, pusher, mergePullRequest = false))
|
||||
}
|
||||
}
|
||||
// update repository last modified time.
|
||||
|
||||
@@ -6,9 +6,9 @@ import gitbucket.core.GitBucketCoreModule
|
||||
import gitbucket.core.plugin.PluginRegistry
|
||||
import gitbucket.core.service.SystemSettingsService
|
||||
import gitbucket.core.util.DatabaseConfig
|
||||
import gitbucket.core.util.Directory._
|
||||
import gitbucket.core.util.JDBCUtil._
|
||||
import gitbucket.core.model.Profile.profile.blockingApi._
|
||||
import gitbucket.core.util.Directory.*
|
||||
import gitbucket.core.util.JDBCUtil.*
|
||||
import gitbucket.core.model.Profile.profile.blockingApi.*
|
||||
// Imported names have higher precedence than names, defined in other files.
|
||||
// If Database is not bound by explicit import, then "Database" refers to the Database introduced by the wildcard import above.
|
||||
import gitbucket.core.servlet.Database
|
||||
@@ -20,7 +20,7 @@ import javax.servlet.{ServletContextEvent, ServletContextListener}
|
||||
import org.apache.commons.io.{FileUtils, IOUtils}
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
import scala.jdk.CollectionConverters._
|
||||
import scala.jdk.CollectionConverters.*
|
||||
import scala.util.Using
|
||||
|
||||
/**
|
||||
@@ -50,51 +50,57 @@ class InitializeListener extends ServletContextListener with SystemSettingsServi
|
||||
// )
|
||||
|
||||
override def contextInitialized(event: ServletContextEvent): Unit = {
|
||||
val dataDir = event.getServletContext.getInitParameter("gitbucket.home")
|
||||
if (dataDir != null) {
|
||||
System.setProperty("gitbucket.home", dataDir)
|
||||
}
|
||||
org.h2.Driver.load()
|
||||
try {
|
||||
val dataDir = event.getServletContext.getInitParameter("gitbucket.home")
|
||||
if (dataDir != null) {
|
||||
System.setProperty("gitbucket.home", dataDir)
|
||||
}
|
||||
org.h2.Driver.load()
|
||||
|
||||
Database() withTransaction { session =>
|
||||
val conn = session.conn
|
||||
val manager = new JDBCVersionManager(conn)
|
||||
Database() withTransaction { session =>
|
||||
val conn = session.conn
|
||||
val manager = new JDBCVersionManager(conn)
|
||||
|
||||
// Check version
|
||||
checkVersion(manager, conn)
|
||||
// Check version
|
||||
checkVersion(manager, conn)
|
||||
|
||||
// Run normal migration
|
||||
logger.info("Start schema update")
|
||||
new Solidbase()
|
||||
.migrate(conn, Thread.currentThread.getContextClassLoader, DatabaseConfig.liquiDriver, GitBucketCoreModule)
|
||||
// Run normal migration
|
||||
logger.info("Start schema update")
|
||||
new Solidbase()
|
||||
.migrate(conn, Thread.currentThread.getContextClassLoader, DatabaseConfig.liquiDriver, GitBucketCoreModule)
|
||||
|
||||
// Rescue code for users who updated from 3.14 to 4.0.0
|
||||
// https://github.com/gitbucket/gitbucket/issues/1227
|
||||
val currentVersion = manager.getCurrentVersion(GitBucketCoreModule.getModuleId)
|
||||
val databaseVersion = if (currentVersion == "4.0") {
|
||||
manager.updateVersion(GitBucketCoreModule.getModuleId, "4.0.0")
|
||||
"4.0.0"
|
||||
} else currentVersion
|
||||
// Rescue code for users who updated from 3.14 to 4.0.0
|
||||
// https://github.com/gitbucket/gitbucket/issues/1227
|
||||
val currentVersion = manager.getCurrentVersion(GitBucketCoreModule.getModuleId)
|
||||
val databaseVersion = if (currentVersion == "4.0") {
|
||||
manager.updateVersion(GitBucketCoreModule.getModuleId, "4.0.0")
|
||||
"4.0.0"
|
||||
} else currentVersion
|
||||
|
||||
val gitbucketVersion = GitBucketCoreModule.getVersions.asScala.last.getVersion
|
||||
if (databaseVersion != gitbucketVersion) {
|
||||
throw new IllegalStateException(
|
||||
s"Initialization failed. GitBucket version is ${gitbucketVersion}, but database version is ${databaseVersion}."
|
||||
)
|
||||
val gitbucketVersion = GitBucketCoreModule.getVersions.asScala.last.getVersion
|
||||
if (databaseVersion != gitbucketVersion) {
|
||||
throw new IllegalStateException(
|
||||
s"Initialization failed. GitBucket version is ${gitbucketVersion}, but database version is ${databaseVersion}."
|
||||
)
|
||||
}
|
||||
|
||||
// Install bundled plugins
|
||||
extractBundledPlugins()
|
||||
|
||||
// Load plugins
|
||||
logger.info("Initialize plugins")
|
||||
PluginRegistry.initialize(event.getServletContext, loadSystemSettings(), conn)
|
||||
}
|
||||
|
||||
// Install bundled plugins
|
||||
extractBundledPlugins()
|
||||
|
||||
// Load plugins
|
||||
logger.info("Initialize plugins")
|
||||
PluginRegistry.initialize(event.getServletContext, loadSystemSettings(), conn)
|
||||
// // Start Quartz scheduler
|
||||
// val scheduler = QuartzSchedulerExtension(system)
|
||||
//
|
||||
// scheduler.schedule("Daily", system.actorOf(Props[DeleteOldActivityActor]), "DeleteOldActivity")
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
logger.error(e.getMessage, e)
|
||||
throw e
|
||||
}
|
||||
|
||||
// // Start Quartz scheduler
|
||||
// val scheduler = QuartzSchedulerExtension(system)
|
||||
//
|
||||
// scheduler.schedule("Daily", system.actorOf(Props[DeleteOldActivityActor]), "DeleteOldActivity")
|
||||
}
|
||||
|
||||
private def checkVersion(manager: JDBCVersionManager, conn: java.sql.Connection): Unit = {
|
||||
@@ -141,7 +147,7 @@ class InitializeListener extends ServletContextListener with SystemSettingsServi
|
||||
Using.resource(cl.getResourceAsStream("bundle-plugins.txt")) { pluginsFile =>
|
||||
if (pluginsFile != null) {
|
||||
val plugins = IOUtils.readLines(pluginsFile, "UTF-8")
|
||||
val gitbucketVersion = GitBucketCoreModule.getVersions.asScala.last.getVersion
|
||||
// val gitbucketVersion = GitBucketCoreModule.getVersions.asScala.last.getVersion
|
||||
|
||||
plugins.asScala.foreach { plugin =>
|
||||
plugin.trim.split(":") match {
|
||||
|
||||
@@ -15,9 +15,9 @@ trait OneselfAuthenticator { self: ControllerBase =>
|
||||
|
||||
private def authenticate(action: => Any) = {
|
||||
context.loginAccount match {
|
||||
case Some(x) if (x.isAdmin) => action
|
||||
case Some(x) if (request.paths(0) == x.userName) => action
|
||||
case _ => Unauthorized()
|
||||
case Some(x) if x.isAdmin => action
|
||||
case Some(x) if request.paths(0) == x.userName => action
|
||||
case _ => Unauthorized()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ trait OneselfAuthenticator { self: ControllerBase =>
|
||||
* Allows only the repository owner and administrators.
|
||||
*/
|
||||
trait OwnerAuthenticator { self: ControllerBase & RepositoryService & AccountService =>
|
||||
protected def ownerOnly(action: (RepositoryInfo) => Any) = { authenticate(action) }
|
||||
protected def ownerOnly(action: RepositoryInfo => Any) = { authenticate(action) }
|
||||
protected def ownerOnly[T](action: (T, RepositoryInfo) => Any) = (form: T) => { authenticate(action(form, _)) }
|
||||
|
||||
private def authenticate(action: (RepositoryInfo) => Any) = {
|
||||
@@ -34,14 +34,14 @@ trait OwnerAuthenticator { self: ControllerBase & RepositoryService & AccountSer
|
||||
val repoName = params("repository")
|
||||
getRepository(userName, repoName).map { repository =>
|
||||
context.loginAccount match {
|
||||
case Some(x) if (x.isAdmin) => action(repository)
|
||||
case Some(x) if (repository.owner == x.userName) => action(repository)
|
||||
case Some(x) if x.isAdmin => action(repository)
|
||||
case Some(x) if repository.owner == x.userName => action(repository)
|
||||
// TODO Repository management is allowed for only group managers?
|
||||
case Some(x) if (getGroupMembers(repository.owner).exists { m =>
|
||||
case Some(x) if getGroupMembers(repository.owner).exists { m =>
|
||||
m.userName == x.userName && m.isManager
|
||||
}) =>
|
||||
} =>
|
||||
action(repository)
|
||||
case Some(x) if (getCollaboratorUserNames(userName, repoName, Seq(Role.ADMIN)).contains(x.userName)) =>
|
||||
case Some(x) if getCollaboratorUserNames(userName, repoName, Seq(Role.ADMIN)).contains(x.userName) =>
|
||||
action(repository)
|
||||
case _ => Unauthorized()
|
||||
}
|
||||
@@ -83,10 +83,10 @@ trait AdminAuthenticator { self: ControllerBase =>
|
||||
* Allows only guests and signed in users who can access the repository.
|
||||
*/
|
||||
trait ReferrerAuthenticator { self: ControllerBase & RepositoryService & AccountService =>
|
||||
protected def referrersOnly(action: (RepositoryInfo) => Any) = { authenticate(action) }
|
||||
protected def referrersOnly(action: RepositoryInfo => Any) = { authenticate(action) }
|
||||
protected def referrersOnly[T](action: (T, RepositoryInfo) => Any) = (form: T) => { authenticate(action(form, _)) }
|
||||
|
||||
private def authenticate(action: (RepositoryInfo) => Any) = {
|
||||
private def authenticate(action: RepositoryInfo => Any) = {
|
||||
val userName = params("owner")
|
||||
val repoName = params("repository")
|
||||
getRepository(userName, repoName).map { repository =>
|
||||
@@ -103,12 +103,12 @@ trait ReferrerAuthenticator { self: ControllerBase & RepositoryService & Account
|
||||
* Allows only signed in users who have read permission for the repository.
|
||||
*/
|
||||
trait ReadableUsersAuthenticator { self: ControllerBase & RepositoryService & AccountService =>
|
||||
protected def readableUsersOnly(action: (RepositoryInfo) => Any) = { authenticate(action) }
|
||||
protected def readableUsersOnly(action: RepositoryInfo => Any) = { authenticate(action) }
|
||||
protected def readableUsersOnly[T](action: (T, RepositoryInfo) => Any) = (form: T) => {
|
||||
authenticate(action(form, _))
|
||||
}
|
||||
|
||||
private def authenticate(action: (RepositoryInfo) => Any) = {
|
||||
private def authenticate(action: RepositoryInfo => Any) = {
|
||||
val userName = params("owner")
|
||||
val repoName = params("repository")
|
||||
getRepository(userName, repoName).map { repository =>
|
||||
@@ -125,24 +125,19 @@ trait ReadableUsersAuthenticator { self: ControllerBase & RepositoryService & Ac
|
||||
* Allows only signed in users who have write permission for the repository.
|
||||
*/
|
||||
trait WritableUsersAuthenticator { self: ControllerBase & RepositoryService & AccountService =>
|
||||
protected def writableUsersOnly(action: (RepositoryInfo) => Any) = { authenticate(action) }
|
||||
protected def writableUsersOnly(action: RepositoryInfo => Any) = { authenticate(action) }
|
||||
protected def writableUsersOnly[T](action: (T, RepositoryInfo) => Any) = (form: T) => {
|
||||
authenticate(action(form, _))
|
||||
}
|
||||
|
||||
private def authenticate(action: (RepositoryInfo) => Any) = {
|
||||
private def authenticate(action: RepositoryInfo => Any) = {
|
||||
val userName = params("owner")
|
||||
val repoName = params("repository")
|
||||
getRepository(userName, repoName).map { repository =>
|
||||
context.loginAccount match {
|
||||
case Some(x) if (x.isAdmin) => action(repository)
|
||||
case Some(x) if (userName == x.userName) => action(repository)
|
||||
case Some(x) if (getGroupMembers(repository.owner).exists(_.userName == x.userName)) => action(repository)
|
||||
case Some(x)
|
||||
if (getCollaboratorUserNames(userName, repoName, Seq(Role.ADMIN, Role.DEVELOPER))
|
||||
.contains(x.userName)) =>
|
||||
action(repository)
|
||||
case _ => Unauthorized()
|
||||
if (isWritable(repository.repository, context.loginAccount)) {
|
||||
action(repository)
|
||||
} else {
|
||||
Unauthorized()
|
||||
}
|
||||
} getOrElse NotFound()
|
||||
}
|
||||
@@ -159,9 +154,9 @@ trait GroupManagerAuthenticator { self: ControllerBase & AccountService =>
|
||||
context.loginAccount match {
|
||||
case Some(x) if x.isAdmin => action
|
||||
case Some(x) if x.userName == request.paths(0) => action
|
||||
case Some(x) if (getGroupMembers(request.paths(0)).exists { member =>
|
||||
case Some(x) if getGroupMembers(request.paths(0)).exists { member =>
|
||||
member.userName == x.userName && member.isManager
|
||||
}) =>
|
||||
} =>
|
||||
action
|
||||
case _ => Unauthorized()
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
});
|
||||
|
||||
function updateBranchControlList(active) {
|
||||
if (active == 'branches') {
|
||||
if (active === 'branches') {
|
||||
$('li#branch-control-tab-branches').addClass('active');
|
||||
$('li#branch-control-tab-tags').removeClass('active');
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
} else {
|
||||
$('#branch-control-input').attr('placeholder', 'Find branch ...');
|
||||
}
|
||||
} else if (active == 'tags') {
|
||||
} else if (active === 'tags') {
|
||||
$('li#branch-control-tab-branches').removeClass('active');
|
||||
$('li#branch-control-tab-tags').addClass('active');
|
||||
|
||||
|
||||
@@ -40,7 +40,10 @@
|
||||
<div id="branchCtrlWrapper" style="display:inline;">
|
||||
@gitbucket.core.helper.html.branchcontrol(branch, repository, hasWritePermission){
|
||||
@repository.branchList.map { x =>
|
||||
<li><a href="@helpers.url(repository)/blob/@helpers.encodeRefName((x :: pathList).mkString("/"))">@gitbucket.core.helper.html.checkicon(x == branch) @x</a></li>
|
||||
<li class="branch-control-item-branch"><a href="@helpers.url(repository)/blob/@helpers.encodeRefName((x :: pathList).mkString("/"))">@gitbucket.core.helper.html.checkicon(x == branch) @x</a></li>
|
||||
}
|
||||
@repository.tags.map { x =>
|
||||
<li class="branch-control-item-tag"><a href="@helpers.url(repository)/blob/@helpers.encodeRefName((x.name :: pathList).mkString("/"))">@gitbucket.core.helper.html.checkicon(x.name == branch) @x.name</a></li>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,10 @@
|
||||
@if(pathList.isEmpty){
|
||||
@gitbucket.core.helper.html.branchcontrol(branch, repository, hasWritePermission){
|
||||
@repository.branchList.map { x =>
|
||||
<li><a href="@helpers.url(repository)/commits/@helpers.encodeRefName(x)">@gitbucket.core.helper.html.checkicon(x == branch) @x</a></li>
|
||||
<li class="branch-control-item-branch"><a href="@helpers.url(repository)/commits/@helpers.encodeRefName(x)">@gitbucket.core.helper.html.checkicon(x == branch) @x</a></li>
|
||||
}
|
||||
@repository.tags.map { x =>
|
||||
<li class="branch-control-item-tag"><a href="@helpers.url(repository)/commits/@helpers.encodeRefName(x.name)">@gitbucket.core.helper.html.checkicon(x.name == branch) @x.name</a></li>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
<div class="head" style="height: 24px;">
|
||||
<div class="pull-right">
|
||||
<div class="btn-group">
|
||||
<a href="@{helpers.url(repository)}/archive@if(pathList.length > 0){/@pathList.map(helpers.urlEncode).mkString("/")}/@{helpers.urlEncode(branch)}.zip" class="btn btn-sm btn-default pc"><i class="octicon octicon-cloud-download"></i> Download ZIP</a>
|
||||
<a href="@{helpers.url(repository)}/archive/@{helpers.urlEncode(branch)}.zip@if(pathList.nonEmpty){?path=@helpers.urlEncode(pathList.mkString("/"))}" class="btn btn-sm btn-default pc"><i class="octicon octicon-cloud-download"></i> Download ZIP</a>
|
||||
<a href="@helpers.url(repository)/find/@helpers.encodeRefName(branch)" class="btn btn-sm btn-default" data-hotkey="t" title="Search files"><i class="octicon octicon-search" aria-label="Search files"></i></a>
|
||||
<a href="@helpers.url(repository)/commits/@helpers.encodeRefName((branch :: pathList).mkString("/"))" class="btn btn-sm btn-default"><i class="octicon octicon-history"></i> @if(commitCount > 10000){10000+} else {@commitCount} @helpers.plural(commitCount, "commit")</a>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@(repository: gitbucket.core.service.RepositoryService.RepositoryInfo,
|
||||
branch: String,
|
||||
protection: gitbucket.core.api.ApiBranchProtection,
|
||||
protection: gitbucket.core.api.ApiBranchProtectionResponse,
|
||||
knownContexts: Seq[String],
|
||||
info: Option[Any])(implicit context: gitbucket.core.controller.Context)
|
||||
@import gitbucket.core.view.helpers
|
||||
@@ -22,9 +22,44 @@
|
||||
</label>
|
||||
<p class="help-block">Disables force-pushes to this branch and prevents it from being deleted.</p>
|
||||
</div>
|
||||
|
||||
<!--====================================================================-->
|
||||
<!-- Enforce administrators -->
|
||||
<!--====================================================================-->
|
||||
<div class="checkbox js-enabled" style="display:none">
|
||||
<label>
|
||||
<input type="checkbox" name="has_required_statuses" onclick="update()" @check(protection.status.enforcement_level.name!="off") @if(knownContexts.isEmpty){disabled }>
|
||||
<input type="checkbox" name="enforce_for_admins" onclick="update()" @check(protection.enforce_admins.exists(_.enabled))>
|
||||
<span class="strong">Include administrators</span>
|
||||
</label>
|
||||
<p class="help-block">Enforce restrictions even for repository administrators.</p>
|
||||
</div>
|
||||
|
||||
<!--====================================================================-->
|
||||
<!-- Push restrictions -->
|
||||
<!--====================================================================-->
|
||||
<div class="checkbox js-enabled" style="display:none">
|
||||
<label>
|
||||
<input type="checkbox" name="restrictions" onclick="update()" @check(protection.restrictions.isDefined)>
|
||||
<span class="strong">Restrict users for push</span>
|
||||
</label>
|
||||
<p class="help-block">Restrict users who can push to this branch</p>
|
||||
<div class="js-restrictions_enabled" style="display: none;">
|
||||
<ul id="restrictions-user-list">
|
||||
</ul>
|
||||
@gitbucket.core.helper.html.account("userName-restrictions-user", 200, true, false)
|
||||
<input type="button" class="btn btn-default add-restrictions-user" value="Add"/>
|
||||
<div>
|
||||
<span class="error" id="error-restrictions-user"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--====================================================================-->
|
||||
<!-- Status check -->
|
||||
<!--====================================================================-->
|
||||
<div class="checkbox js-enabled" style="display:none">
|
||||
<label>
|
||||
<input type="checkbox" name="has_required_statuses" onclick="update()" @check(protection.required_status_checks.isDefined) @if(knownContexts.isEmpty){disabled }>
|
||||
<span class="strong">Require status checks to pass before merging</span>
|
||||
</label>
|
||||
<p class="help-block">When enabled, commits must first be pushed to another branch, then merged or pushed directly to <b>@branch</b> after status checks have passed.</p>
|
||||
@@ -48,14 +83,6 @@
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="enforce_for_admins" onclick="update()" @check(protection.status.enforcement_level.name=="everyone")>
|
||||
<span class="strong">Include administrators</span>
|
||||
</label>
|
||||
<p class="help-block">Enforce required status checks for repository administrators.</p>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@@ -68,59 +95,114 @@
|
||||
}
|
||||
<script>
|
||||
function getValue(){
|
||||
var v = {}, contexts=[];
|
||||
const v = {}, contexts = [];
|
||||
let restrictions = undefined;
|
||||
$("input[type=checkbox]:checked").each(function(){
|
||||
if(this.name === 'contexts'){
|
||||
if(this.name === 'contexts') {
|
||||
contexts.push(this.value);
|
||||
} else if (this.name === 'restrictions') {
|
||||
restrictions = $('#restrictions-user-list li').map(function(i, e){
|
||||
return $(e).data('name');
|
||||
}).get();
|
||||
} else {
|
||||
v[this.name] = true;
|
||||
}
|
||||
});
|
||||
|
||||
if(v.enabled){
|
||||
return {
|
||||
enabled: true,
|
||||
required_status_checks: {
|
||||
enforcement_level: v.has_required_statuses ? ((v.enforce_for_admins ? 'everyone' : 'non_admins')) : 'off',
|
||||
contexts: v.has_required_statuses ? contexts : []
|
||||
}
|
||||
};
|
||||
enforce_admins: v.enforce_for_admins,
|
||||
required_status_checks: v.has_required_statuses ? { contexts: contexts } : undefined,
|
||||
restrictions: restrictions ? { users: restrictions } : undefined
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
enabled: false,
|
||||
required_status_checks: {
|
||||
enforcement_level: "off",
|
||||
contexts: []
|
||||
}
|
||||
enabled: false
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function updateView(protection){
|
||||
$('.js-enabled').toggle(protection.enabled);
|
||||
$('.js-has_required_statuses').toggle(protection.required_status_checks.enforcement_level != 'off');
|
||||
$('.js-submit-btn').attr('disabled',protection.required_status_checks.enforcement_level != 'off' && protection.required_status_checks.contexts.length == 0);
|
||||
$('.js-restrictions_enabled').toggle(protection.restrictions !== undefined);
|
||||
$('.js-has_required_statuses').toggle(protection.required_status_checks !== undefined);
|
||||
}
|
||||
|
||||
function update(){
|
||||
var protection = getValue();
|
||||
const protection = getValue();
|
||||
updateView(protection);
|
||||
}
|
||||
$(update);
|
||||
|
||||
function submitForm(e){
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
var protection = getValue();
|
||||
const protection = getValue();
|
||||
$.ajax({
|
||||
method:'PATCH',
|
||||
url:'@context.path/api/v3/repos/@repository.owner/@repository.name/branches/@helpers.urlEncode(branch)',
|
||||
method: 'PATCH',
|
||||
url: '@context.path/api/v3/repos/@repository.owner/@repository.name/branches/@helpers.urlEncode(branch)',
|
||||
contentType: 'application/json',
|
||||
dataType: 'json',
|
||||
data:JSON.stringify({protection:protection}),
|
||||
success:function(r){
|
||||
data: JSON.stringify({protection: protection}),
|
||||
success: function(r){
|
||||
$('#saved-info').show();
|
||||
},
|
||||
error:function(err){
|
||||
error: function(err){
|
||||
console.log(err);
|
||||
alert('update error');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function addUserToListHTML(userName, id){
|
||||
$(id).append($('<li>').data('name', userName)
|
||||
.append(' ')
|
||||
.append(userName)
|
||||
.append($('<a href="#" onclick="$(this).parent().remove();" class="remove">(remove)</a>')));
|
||||
}
|
||||
|
||||
$(function() {
|
||||
// Initialize
|
||||
update();
|
||||
|
||||
@protection.restrictions.map(_.users).map { users =>
|
||||
@users.map { user =>
|
||||
addUserToListHTML('@user', '#restrictions-user-list');
|
||||
}
|
||||
}
|
||||
|
||||
$('.add-restrictions-user').click(function(){
|
||||
$('#error-restrictions-user').text('');
|
||||
const userName = $('#userName-restrictions-user').val();
|
||||
|
||||
// check empty
|
||||
if($.trim(userName) === ''){
|
||||
return false;
|
||||
}
|
||||
|
||||
// check duplication
|
||||
const exists = $('#restrictions-user-list li').filter(function(){
|
||||
return $(this).data('name') === userName;
|
||||
}).length > 0;
|
||||
if(exists){
|
||||
$('#error-restrictions-user').text('User has been already added.');
|
||||
return false;
|
||||
}
|
||||
|
||||
// check existence
|
||||
$.post('@context.path/_user/existence', {
|
||||
'userName': userName,
|
||||
'owner': '@repository.owner',
|
||||
'repository': '@repository.name'
|
||||
},
|
||||
function(data, status){
|
||||
if(data !== ''){
|
||||
addUserToListHTML(userName, '#restrictions-user-list');
|
||||
$('#userName-restrictions-user').val('');
|
||||
} else {
|
||||
$('#error-restrictions-user').text("User does not exist or isn't writable to this repository.");
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -183,14 +183,14 @@ class ApiIntegrationTest extends AnyFunSuite {
|
||||
.branch("main")
|
||||
.content("create")
|
||||
.message("Create content")
|
||||
.path("README.md")
|
||||
.path("test.txt")
|
||||
.commit()
|
||||
|
||||
assert(createResult.getContent.isFile == true)
|
||||
assert(createResult.getContent.isFile)
|
||||
assert(IOUtils.toString(createResult.getContent.read(), "UTF-8") == "create")
|
||||
|
||||
val content1 = repo.getFileContent("README.md")
|
||||
assert(content1.isFile == true)
|
||||
val content1 = repo.getFileContent("test.txt")
|
||||
assert(content1.isFile)
|
||||
assert(IOUtils.toString(content1.read(), "UTF-8") == "create")
|
||||
assert(content1.getSha == createResult.getContent.getSha)
|
||||
|
||||
@@ -200,14 +200,14 @@ class ApiIntegrationTest extends AnyFunSuite {
|
||||
.branch("main")
|
||||
.content("update")
|
||||
.message("Update content")
|
||||
.path("README.md")
|
||||
.path("test.txt")
|
||||
.sha(content1.getSha)
|
||||
.commit()
|
||||
|
||||
assert(updateResult.getContent.isFile == true)
|
||||
assert(updateResult.getContent.isFile)
|
||||
assert(IOUtils.toString(updateResult.getContent.read(), "UTF-8") == "update")
|
||||
|
||||
val content2 = repo.getFileContent("README.md")
|
||||
val content2 = repo.getFileContent("test.txt")
|
||||
assert(content2.isFile == true)
|
||||
assert(IOUtils.toString(content2.read(), "UTF-8") == "update")
|
||||
assert(content2.getSha == updateResult.getContent.getSha)
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package gitbucket.core.api
|
||||
|
||||
import java.util.{Calendar, Date, TimeZone}
|
||||
import gitbucket.core.api.ApiBranchProtectionResponse.Restrictions
|
||||
|
||||
import gitbucket.core.model._
|
||||
import java.util.{Calendar, Date, TimeZone}
|
||||
import gitbucket.core.model.*
|
||||
import gitbucket.core.plugin.PluginInfo
|
||||
import gitbucket.core.service.ProtectedBranchService.ProtectedBranchInfo
|
||||
import gitbucket.core.service.RepositoryService.RepositoryInfo
|
||||
@@ -15,7 +16,7 @@ object ApiSpecModels {
|
||||
|
||||
implicit val context: JsonFormat.Context = JsonFormat.Context("http://gitbucket.exmple.com", None)
|
||||
|
||||
val date1 = {
|
||||
val date1: Date = {
|
||||
val d = Calendar.getInstance(TimeZone.getTimeZone("UTC"))
|
||||
d.set(2011, 3, 14, 16, 0, 49)
|
||||
d.getTime
|
||||
@@ -29,7 +30,7 @@ object ApiSpecModels {
|
||||
|
||||
// Models
|
||||
|
||||
val account = Account(
|
||||
val account: Account = Account(
|
||||
userName = "octocat",
|
||||
fullName = "octocat",
|
||||
mailAddress = "octocat@example.com",
|
||||
@@ -45,10 +46,10 @@ object ApiSpecModels {
|
||||
description = None
|
||||
)
|
||||
|
||||
val sha1 = "6dcb09b5b57875f334f61aebed695e2e4193db5e"
|
||||
val repo1Name = RepositoryName("octocat/Hello-World")
|
||||
val sha1: String = "6dcb09b5b57875f334f61aebed695e2e4193db5e"
|
||||
val repo1Name: RepositoryName = RepositoryName("octocat/Hello-World")
|
||||
|
||||
val repository = Repository(
|
||||
val repository: Repository = Repository(
|
||||
userName = repo1Name.owner,
|
||||
repositoryName = repo1Name.name,
|
||||
isPrivate = false,
|
||||
@@ -73,7 +74,7 @@ object ApiSpecModels {
|
||||
)
|
||||
)
|
||||
|
||||
val repositoryInfo = RepositoryInfo(
|
||||
val repositoryInfo: RepositoryInfo = RepositoryInfo(
|
||||
owner = repo1Name.owner,
|
||||
name = repo1Name.name,
|
||||
repository = repository,
|
||||
@@ -101,7 +102,7 @@ object ApiSpecModels {
|
||||
managers = Seq("myboss")
|
||||
)
|
||||
|
||||
val label = Label(
|
||||
val label: Label = Label(
|
||||
userName = repo1Name.owner,
|
||||
repositoryName = repo1Name.name,
|
||||
labelId = 10,
|
||||
@@ -109,7 +110,7 @@ object ApiSpecModels {
|
||||
color = "f29513"
|
||||
)
|
||||
|
||||
val issue = Issue(
|
||||
val issue: Issue = Issue(
|
||||
userName = repo1Name.owner,
|
||||
repositoryName = repo1Name.name,
|
||||
issueId = 1347,
|
||||
@@ -124,14 +125,14 @@ object ApiSpecModels {
|
||||
isPullRequest = false
|
||||
)
|
||||
|
||||
val issuePR = issue.copy(
|
||||
val issuePR: Issue = issue.copy(
|
||||
title = "new-feature",
|
||||
content = Some("Please pull these awesome changes"),
|
||||
closed = true,
|
||||
isPullRequest = true
|
||||
)
|
||||
|
||||
val issueComment = IssueComment(
|
||||
val issueComment: IssueComment = IssueComment(
|
||||
userName = repo1Name.owner,
|
||||
repositoryName = repo1Name.name,
|
||||
issueId = issue.issueId,
|
||||
@@ -143,7 +144,7 @@ object ApiSpecModels {
|
||||
updatedDate = date1
|
||||
)
|
||||
|
||||
val pullRequest = PullRequest(
|
||||
val pullRequest: PullRequest = PullRequest(
|
||||
userName = repo1Name.owner,
|
||||
repositoryName = repo1Name.name,
|
||||
issueId = issuePR.issueId,
|
||||
@@ -156,7 +157,7 @@ object ApiSpecModels {
|
||||
isDraft = true
|
||||
)
|
||||
|
||||
val commitComment = CommitComment(
|
||||
val commitComment: CommitComment = CommitComment(
|
||||
userName = repo1Name.owner,
|
||||
repositoryName = repo1Name.name,
|
||||
commitId = sha1,
|
||||
@@ -174,7 +175,7 @@ object ApiSpecModels {
|
||||
originalNewLine = None
|
||||
)
|
||||
|
||||
val commitStatus = CommitStatus(
|
||||
val commitStatus: CommitStatus = CommitStatus(
|
||||
commitStatusId = 1,
|
||||
userName = repo1Name.owner,
|
||||
repositoryName = repo1Name.name,
|
||||
@@ -188,7 +189,7 @@ object ApiSpecModels {
|
||||
updatedDate = date1
|
||||
)
|
||||
|
||||
val milestone = Milestone(
|
||||
val milestone: Milestone = Milestone(
|
||||
userName = repo1Name.owner,
|
||||
repositoryName = repo1Name.name,
|
||||
milestoneId = 1,
|
||||
@@ -200,28 +201,28 @@ object ApiSpecModels {
|
||||
|
||||
// APIs
|
||||
|
||||
val apiUser = ApiUser(account)
|
||||
val apiUser: ApiUser = ApiUser(account)
|
||||
|
||||
val apiRepository = ApiRepository(
|
||||
val apiRepository: ApiRepository = ApiRepository(
|
||||
repository = repository,
|
||||
owner = apiUser,
|
||||
forkedCount = repositoryInfo.forkedCount,
|
||||
watchers = 0
|
||||
)
|
||||
|
||||
val apiLabel = ApiLabel(
|
||||
val apiLabel: ApiLabel = ApiLabel(
|
||||
label = label,
|
||||
repositoryName = repo1Name
|
||||
)
|
||||
|
||||
val apiMilestone = ApiMilestone(
|
||||
val apiMilestone: ApiMilestone = ApiMilestone(
|
||||
repository = repository,
|
||||
milestone = milestone,
|
||||
open_issue_count = 1,
|
||||
closed_issue_count = 1
|
||||
)
|
||||
|
||||
val apiIssue = ApiIssue(
|
||||
val apiIssue: ApiIssue = ApiIssue(
|
||||
issue = issue,
|
||||
repositoryName = repo1Name,
|
||||
user = apiUser,
|
||||
@@ -230,7 +231,7 @@ object ApiSpecModels {
|
||||
milestone = Some(apiMilestone)
|
||||
)
|
||||
|
||||
val apiNotAssignedIssue = ApiIssue(
|
||||
val apiNotAssignedIssue: ApiIssue = ApiIssue(
|
||||
issue = issue,
|
||||
repositoryName = repo1Name,
|
||||
user = apiUser,
|
||||
@@ -239,7 +240,7 @@ object ApiSpecModels {
|
||||
milestone = Some(apiMilestone)
|
||||
)
|
||||
|
||||
val apiIssuePR = ApiIssue(
|
||||
val apiIssuePR: ApiIssue = ApiIssue(
|
||||
issue = issuePR,
|
||||
repositoryName = repo1Name,
|
||||
user = apiUser,
|
||||
@@ -248,7 +249,7 @@ object ApiSpecModels {
|
||||
milestone = Some(apiMilestone)
|
||||
)
|
||||
|
||||
val apiComment = ApiComment(
|
||||
val apiComment: ApiComment = ApiComment(
|
||||
comment = issueComment,
|
||||
repositoryName = repo1Name,
|
||||
issueId = issueComment.issueId,
|
||||
@@ -256,7 +257,7 @@ object ApiSpecModels {
|
||||
isPullRequest = false
|
||||
)
|
||||
|
||||
val apiCommentPR = ApiComment(
|
||||
val apiCommentPR: ApiComment = ApiComment(
|
||||
comment = issueComment,
|
||||
repositoryName = repo1Name,
|
||||
issueId = issueComment.issueId,
|
||||
@@ -264,7 +265,7 @@ object ApiSpecModels {
|
||||
isPullRequest = true
|
||||
)
|
||||
|
||||
val apiPullRequest = ApiPullRequest(
|
||||
val apiPullRequest: ApiPullRequest = ApiPullRequest(
|
||||
issue = issuePR,
|
||||
pullRequest = pullRequest,
|
||||
headRepo = apiRepository,
|
||||
@@ -275,15 +276,14 @@ object ApiSpecModels {
|
||||
mergedComment = Some((issueComment, account))
|
||||
)
|
||||
|
||||
// https://developer.github.com/v3/activity/events/types/#pullrequestreviewcommentevent
|
||||
val apiPullRequestReviewComment = ApiPullRequestReviewComment(
|
||||
val apiPullRequestReviewComment: ApiPullRequestReviewComment = ApiPullRequestReviewComment(
|
||||
comment = commitComment,
|
||||
commentedUser = apiUser,
|
||||
repositoryName = repo1Name,
|
||||
issueId = commitComment.issueId.get
|
||||
)
|
||||
|
||||
val commitInfo = (id: String) =>
|
||||
val commitInfo: String => CommitInfo = (id: String) =>
|
||||
CommitInfo(
|
||||
id = id,
|
||||
shortMessage = "short message",
|
||||
@@ -299,12 +299,12 @@ object ApiSpecModels {
|
||||
None
|
||||
)
|
||||
|
||||
val apiCommitListItem = ApiCommitListItem(
|
||||
val apiCommitListItem: ApiCommitListItem = ApiCommitListItem(
|
||||
commit = commitInfo(sha1),
|
||||
repositoryName = repo1Name
|
||||
)
|
||||
|
||||
val apiCommit = {
|
||||
val apiCommit: ApiCommit = {
|
||||
val commit = commitInfo(sha1)
|
||||
ApiCommit(
|
||||
id = commit.id,
|
||||
@@ -318,7 +318,7 @@ object ApiSpecModels {
|
||||
)(repo1Name)
|
||||
}
|
||||
|
||||
val apiCommits = ApiCommits(
|
||||
val apiCommits: ApiCommits = ApiCommits(
|
||||
repositoryName = repo1Name,
|
||||
commitInfo = commitInfo(sha1),
|
||||
diffs = Seq(
|
||||
@@ -348,42 +348,45 @@ object ApiSpecModels {
|
||||
commentCount = 2
|
||||
)
|
||||
|
||||
val apiCommitStatus = ApiCommitStatus(
|
||||
val apiCommitStatus: ApiCommitStatus = ApiCommitStatus(
|
||||
status = commitStatus,
|
||||
creator = apiUser
|
||||
)
|
||||
|
||||
val apiCombinedCommitStatus = ApiCombinedCommitStatus(
|
||||
val apiCombinedCommitStatus: ApiCombinedCommitStatus = ApiCombinedCommitStatus(
|
||||
sha = sha1,
|
||||
statuses = Iterable((commitStatus, account)),
|
||||
repository = apiRepository
|
||||
)
|
||||
|
||||
val apiBranchProtectionOutput = ApiBranchProtection(
|
||||
val apiBranchProtectionOutput: ApiBranchProtectionResponse = ApiBranchProtectionResponse(
|
||||
info = ProtectedBranchInfo(
|
||||
owner = repo1Name.owner,
|
||||
repository = repo1Name.name,
|
||||
branch = "main",
|
||||
enabled = true,
|
||||
contexts = Seq("continuous-integration/travis-ci"),
|
||||
includeAdministrators = true
|
||||
contexts = Some(Seq("continuous-integration/travis-ci")),
|
||||
enforceAdmins = true,
|
||||
restrictionsUsers = Some(Seq("admin"))
|
||||
)
|
||||
)
|
||||
|
||||
val apiBranchProtectionInput = new ApiBranchProtection(
|
||||
val apiBranchProtectionInput: ApiBranchProtectionResponse = new ApiBranchProtectionResponse(
|
||||
url = None,
|
||||
enabled = true,
|
||||
required_status_checks = Some(
|
||||
ApiBranchProtection.Status(
|
||||
ApiBranchProtectionResponse.Status(
|
||||
url = None,
|
||||
enforcement_level = ApiBranchProtection.Everyone,
|
||||
enforcement_level = ApiBranchProtectionResponse.Everyone,
|
||||
contexts = Seq("continuous-integration/travis-ci"),
|
||||
contexts_url = None
|
||||
)
|
||||
)
|
||||
),
|
||||
restrictions = Some(Restrictions(users = Seq("admin"))),
|
||||
enforce_admins = None
|
||||
)
|
||||
|
||||
val apiBranch = ApiBranch(
|
||||
val apiBranch: ApiBranch = ApiBranch(
|
||||
name = "main",
|
||||
commit = ApiBranchCommit(sha1),
|
||||
protection = apiBranchProtectionOutput
|
||||
@@ -391,12 +394,12 @@ object ApiSpecModels {
|
||||
repositoryName = repo1Name
|
||||
)
|
||||
|
||||
val apiBranchForList = ApiBranchForList(
|
||||
val apiBranchForList: ApiBranchForList = ApiBranchForList(
|
||||
name = "main",
|
||||
commit = ApiBranchCommit(sha1)
|
||||
)
|
||||
|
||||
val apiContents = ApiContents(
|
||||
val apiContents: ApiContents = ApiContents(
|
||||
fileInfo = FileInfo(
|
||||
id = ObjectId.fromString(sha1),
|
||||
isDirectory = false,
|
||||
@@ -413,14 +416,14 @@ object ApiSpecModels {
|
||||
content = Some("README".getBytes("UTF-8"))
|
||||
)
|
||||
|
||||
val apiEndPoint = ApiEndPoint()
|
||||
val apiEndPoint: ApiEndPoint = ApiEndPoint()
|
||||
|
||||
val apiError = ApiError(
|
||||
val apiError: ApiError = ApiError(
|
||||
message = "A repository with this name already exists on this account",
|
||||
documentation_url = Some("https://developer.github.com/v3/repos/#create")
|
||||
)
|
||||
|
||||
val apiGroup = ApiGroup(
|
||||
val apiGroup: ApiGroup = ApiGroup(
|
||||
account.copy(
|
||||
isAdmin = true,
|
||||
isGroupAccount = true,
|
||||
@@ -428,7 +431,7 @@ object ApiSpecModels {
|
||||
)
|
||||
)
|
||||
|
||||
val apiPlugin = ApiPlugin(
|
||||
val apiPlugin: ApiPlugin = ApiPlugin(
|
||||
plugin = PluginInfo(
|
||||
pluginId = "gist",
|
||||
pluginName = "Gist Plugin",
|
||||
@@ -441,12 +444,12 @@ object ApiSpecModels {
|
||||
)
|
||||
)
|
||||
|
||||
val apiPusher = ApiPusher(account)
|
||||
val apiPusher: ApiPusher = ApiPusher(account)
|
||||
|
||||
// have both urls as https, as the expected samples are using https
|
||||
val gitHubContext = JsonFormat.Context("https://api.github.com", Some("https://api.github.com"))
|
||||
val gitHubContext: JsonFormat.Context = JsonFormat.Context("https://api.github.com", Some("https://api.github.com"))
|
||||
|
||||
val apiRefHeadsMaster = ApiRef(
|
||||
val apiRefHeadsMaster: ApiRef = ApiRef(
|
||||
ref = "refs/heads/main",
|
||||
url = ApiPath("/repos/gitbucket/gitbucket/git/refs/heads/main"),
|
||||
node_id = "MDM6UmVmOTM1MDc0NjpyZWZzL2hlYWRzL21hc3Rlcg==",
|
||||
@@ -457,7 +460,7 @@ object ApiSpecModels {
|
||||
)
|
||||
)
|
||||
|
||||
val apiRefTag = ApiRef(
|
||||
val apiRefTag: ApiRef = ApiRef(
|
||||
ref = "refs/tags/1.0",
|
||||
url = ApiPath("/repos/gitbucket/gitbucket/git/refs/tags/1.0"),
|
||||
node_id = "MDM6UmVmOTM1MDc0NjpyZWZzL3RhZ3MvMS4w",
|
||||
@@ -468,9 +471,9 @@ object ApiSpecModels {
|
||||
)
|
||||
)
|
||||
|
||||
val assetFileName = "010203040a0b0c0d"
|
||||
val assetFileName: String = "010203040a0b0c0d"
|
||||
|
||||
val apiReleaseAsset = ApiReleaseAsset(
|
||||
val apiReleaseAsset: ApiReleaseAsset = ApiReleaseAsset(
|
||||
name = "release.zip",
|
||||
size = 100
|
||||
)(
|
||||
@@ -479,7 +482,7 @@ object ApiSpecModels {
|
||||
repositoryName = repo1Name
|
||||
)
|
||||
|
||||
val apiRelease = ApiRelease(
|
||||
val apiRelease: ApiRelease = ApiRelease(
|
||||
name = "release1",
|
||||
tag_name = "tag1",
|
||||
body = Some("content"),
|
||||
@@ -489,7 +492,7 @@ object ApiSpecModels {
|
||||
|
||||
// JSON String for APIs
|
||||
|
||||
val jsonUser = """{
|
||||
val jsonUser: String = """{
|
||||
|"login":"octocat",
|
||||
|"email":"octocat@example.com",
|
||||
|"type":"User",
|
||||
@@ -501,7 +504,7 @@ object ApiSpecModels {
|
||||
|"avatar_url":"http://gitbucket.exmple.com/octocat/_avatar"
|
||||
|}""".stripMargin
|
||||
|
||||
val jsonRepository = s"""{
|
||||
val jsonRepository: String = s"""{
|
||||
|"name":"Hello-World",
|
||||
|"full_name":"octocat/Hello-World",
|
||||
|"description":"This your first repo!",
|
||||
@@ -519,10 +522,10 @@ object ApiSpecModels {
|
||||
|"html_url":"http://gitbucket.exmple.com/octocat/Hello-World"
|
||||
|}""".stripMargin
|
||||
|
||||
val jsonLabel =
|
||||
val jsonLabel: String =
|
||||
"""{"name":"bug","color":"f29513","url":"http://gitbucket.exmple.com/api/v3/repos/octocat/Hello-World/labels/bug"}"""
|
||||
|
||||
val jsonMilestone = """{
|
||||
val jsonMilestone: String = """{
|
||||
|"url":"http://gitbucket.exmple.com/api/v3/repos/octocat/Hello-World/milestones/1",
|
||||
|"html_url":"http://gitbucket.exmple.com/octocat/Hello-World/milestone/1",
|
||||
|"id":1,
|
||||
@@ -535,7 +538,7 @@ object ApiSpecModels {
|
||||
|"due_on":"2011-04-14T16:00:49Z"
|
||||
|}""".stripMargin
|
||||
|
||||
val jsonIssue = s"""{
|
||||
val jsonIssue: String = s"""{
|
||||
|"number":1347,
|
||||
|"title":"Found a bug",
|
||||
|"user":$jsonUser,
|
||||
@@ -552,7 +555,7 @@ object ApiSpecModels {
|
||||
|"html_url":"http://gitbucket.exmple.com/octocat/Hello-World/issues/1347"
|
||||
|}""".stripMargin
|
||||
|
||||
val jsonNotAssignedIssue = s"""{
|
||||
val jsonNotAssignedIssue: String = s"""{
|
||||
|"number":1347,
|
||||
|"title":"Found a bug",
|
||||
|"user":$jsonUser,
|
||||
@@ -568,7 +571,7 @@ object ApiSpecModels {
|
||||
|"html_url":"http://gitbucket.exmple.com/octocat/Hello-World/issues/1347"
|
||||
|}""".stripMargin
|
||||
|
||||
val jsonIssuePR = s"""{
|
||||
val jsonIssuePR: String = s"""{
|
||||
|"number":1347,
|
||||
|"title":"new-feature",
|
||||
|"user":$jsonUser,
|
||||
@@ -588,7 +591,7 @@ object ApiSpecModels {
|
||||
|"html_url":"http://gitbucket.exmple.com/octocat/Hello-World/pull/1347"}
|
||||
|}""".stripMargin
|
||||
|
||||
val jsonPullRequest = s"""{
|
||||
val jsonPullRequest: String = s"""{
|
||||
|"number":1347,
|
||||
|"state":"closed",
|
||||
|"updated_at":"2011-04-14T16:00:49Z",
|
||||
@@ -615,7 +618,7 @@ object ApiSpecModels {
|
||||
|"statuses_url":"http://gitbucket.exmple.com/api/v3/repos/octocat/Hello-World/statuses/6dcb09b5b57875f334f61aebed695e2e4193db5e"
|
||||
|}""".stripMargin
|
||||
|
||||
val jsonPullRequestReviewComment = s"""{
|
||||
val jsonPullRequestReviewComment: String = s"""{
|
||||
|"id":29724692,
|
||||
|"path":"README.md",
|
||||
|"commit_id":"6dcb09b5b57875f334f61aebed695e2e4193db5e",
|
||||
@@ -632,7 +635,7 @@ object ApiSpecModels {
|
||||
|"pull_request":{"href":"http://gitbucket.exmple.com/api/v3/repos/octocat/Hello-World/pulls/1347"}}
|
||||
|}""".stripMargin
|
||||
|
||||
val jsonComment = s"""{
|
||||
val jsonComment: String = s"""{
|
||||
|"id":1,
|
||||
|"user":$jsonUser,
|
||||
|"body":"Me too",
|
||||
@@ -641,7 +644,7 @@ object ApiSpecModels {
|
||||
|"html_url":"http://gitbucket.exmple.com/octocat/Hello-World/issues/1347#comment-1"
|
||||
|}""".stripMargin
|
||||
|
||||
val jsonCommentPR = s"""{
|
||||
val jsonCommentPR: String = s"""{
|
||||
|"id":1,
|
||||
|"user":$jsonUser,
|
||||
|"body":"Me too",
|
||||
@@ -650,7 +653,7 @@ object ApiSpecModels {
|
||||
|"html_url":"http://gitbucket.exmple.com/octocat/Hello-World/pull/1347#comment-1"
|
||||
|}""".stripMargin
|
||||
|
||||
val jsonCommitListItem = s"""{
|
||||
val jsonCommitListItem: String = s"""{
|
||||
|"sha":"6dcb09b5b57875f334f61aebed695e2e4193db5e",
|
||||
|"commit":{
|
||||
|"message":"full message",
|
||||
@@ -664,7 +667,7 @@ object ApiSpecModels {
|
||||
|"url":"http://gitbucket.exmple.com/api/v3/repos/octocat/Hello-World/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e"
|
||||
|}""".stripMargin
|
||||
|
||||
val jsonCommit = (id: String) => s"""{
|
||||
val jsonCommit: String => String = (id: String) => s"""{
|
||||
|"id":"$id",
|
||||
|"message":"full message",
|
||||
|"timestamp":"2011-04-14T16:00:49Z",
|
||||
@@ -677,7 +680,7 @@ object ApiSpecModels {
|
||||
|"html_url":"http://gitbucket.exmple.com/octocat/Hello-World/commit/$id"
|
||||
|}""".stripMargin
|
||||
|
||||
val jsonCommits = s"""{
|
||||
val jsonCommits: String = s"""{
|
||||
|"url":"http://gitbucket.exmple.com/api/v3/repos/octocat/Hello-World/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e",
|
||||
|"sha":"6dcb09b5b57875f334f61aebed695e2e4193db5e",
|
||||
|"html_url":"http://gitbucket.exmple.com/octocat/Hello-World/commit/6dcb09b5b57875f334f61aebed695e2e4193db5e",
|
||||
@@ -707,7 +710,7 @@ object ApiSpecModels {
|
||||
|"patch":"@@ -1 +1,2 @@\\n-body1\\n\\\\ No newline at end of file\\n+body1\\n+body2\\n\\\\ No newline at end of file"}]
|
||||
|}""".stripMargin
|
||||
|
||||
val jsonCommitStatus = s"""{
|
||||
val jsonCommitStatus: String = s"""{
|
||||
|"created_at":"2011-04-14T16:00:49Z",
|
||||
|"updated_at":"2011-04-14T16:00:49Z",
|
||||
|"state":"success",
|
||||
@@ -719,7 +722,7 @@ object ApiSpecModels {
|
||||
|"url":"http://gitbucket.exmple.com/api/v3/repos/octocat/Hello-World/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e/statuses"
|
||||
|}""".stripMargin
|
||||
|
||||
val jsonCombinedCommitStatus = s"""{
|
||||
val jsonCombinedCommitStatus: String = s"""{
|
||||
|"state":"success",
|
||||
|"sha":"6dcb09b5b57875f334f61aebed695e2e4193db5e",
|
||||
|"total_count":1,
|
||||
@@ -728,7 +731,7 @@ object ApiSpecModels {
|
||||
|"url":"http://gitbucket.exmple.com/api/v3/repos/octocat/Hello-World/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e/status"
|
||||
|}""".stripMargin
|
||||
|
||||
val jsonBranchProtectionOutput =
|
||||
val jsonBranchProtectionOutput: String =
|
||||
"""{
|
||||
|"url":"http://gitbucket.exmple.com/api/v3/repos/octocat/Hello-World/branches/main/protection",
|
||||
|"enabled":true,
|
||||
@@ -736,15 +739,25 @@ object ApiSpecModels {
|
||||
|"url":"http://gitbucket.exmple.com/api/v3/repos/octocat/Hello-World/branches/main/protection/required_status_checks",
|
||||
|"enforcement_level":"everyone",
|
||||
|"contexts":["continuous-integration/travis-ci"],
|
||||
|"contexts_url":"http://gitbucket.exmple.com/api/v3/repos/octocat/Hello-World/branches/main/protection/required_status_checks/contexts"}
|
||||
|"contexts_url":"http://gitbucket.exmple.com/api/v3/repos/octocat/Hello-World/branches/main/protection/required_status_checks/contexts"
|
||||
|},
|
||||
|"restrictions":{
|
||||
|"users":["admin"]
|
||||
|},
|
||||
|"enforce_admins":{
|
||||
|"enabled":true
|
||||
|}
|
||||
|}""".stripMargin
|
||||
|
||||
val jsonBranchProtectionInput =
|
||||
val jsonBranchProtectionInput: String =
|
||||
"""{
|
||||
|"enabled":true,
|
||||
|"required_status_checks":{
|
||||
|"enforcement_level":"everyone",
|
||||
|"contexts":["continuous-integration/travis-ci"]
|
||||
|},
|
||||
|"restrictions":{
|
||||
|"users":["admin"]
|
||||
|}
|
||||
|}""".stripMargin
|
||||
|
||||
@@ -757,9 +770,9 @@ object ApiSpecModels {
|
||||
|"html":"http://gitbucket.exmple.com/octocat/Hello-World/tree/main"}
|
||||
|}""".stripMargin
|
||||
|
||||
val jsonBranchForList = """{"name":"main","commit":{"sha":"6dcb09b5b57875f334f61aebed695e2e4193db5e"}}"""
|
||||
val jsonBranchForList: String = """{"name":"main","commit":{"sha":"6dcb09b5b57875f334f61aebed695e2e4193db5e"}}"""
|
||||
|
||||
val jsonContents =
|
||||
val jsonContents: String =
|
||||
"""{
|
||||
|"type":"file",
|
||||
|"name":"README.md",
|
||||
@@ -770,14 +783,14 @@ object ApiSpecModels {
|
||||
|"download_url":"http://gitbucket.exmple.com/api/v3/repos/octocat/Hello-World/raw/6dcb09b5b57875f334f61aebed695e2e4193db5e/doc/README.md"
|
||||
|}""".stripMargin
|
||||
|
||||
val jsonEndPoint = """{"rate_limit_url":"http://gitbucket.exmple.com/api/v3/rate_limit"}"""
|
||||
val jsonEndPoint: String = """{"rate_limit_url":"http://gitbucket.exmple.com/api/v3/rate_limit"}"""
|
||||
|
||||
val jsonError = """{
|
||||
val jsonError: String = """{
|
||||
|"message":"A repository with this name already exists on this account",
|
||||
|"documentation_url":"https://developer.github.com/v3/repos/#create"
|
||||
|}""".stripMargin
|
||||
|
||||
val jsonGroup = """{
|
||||
val jsonGroup: String = """{
|
||||
|"login":"octocat",
|
||||
|"description":"Admin group",
|
||||
|"created_at":"2011-04-14T16:00:49Z",
|
||||
@@ -787,7 +800,7 @@ object ApiSpecModels {
|
||||
|"avatar_url":"http://gitbucket.exmple.com/octocat/_avatar"
|
||||
|}""".stripMargin
|
||||
|
||||
val jsonPlugin = """{
|
||||
val jsonPlugin: String = """{
|
||||
|"id":"gist",
|
||||
|"name":"Gist Plugin",
|
||||
|"version":"4.16.0",
|
||||
@@ -795,12 +808,12 @@ object ApiSpecModels {
|
||||
|"jarFileName":"gitbucket-gist-plugin-gitbucket_4.30.0-SNAPSHOT-4.17.0.jar"
|
||||
|}""".stripMargin
|
||||
|
||||
val jsonPusher = """{"name":"octocat","email":"octocat@example.com"}"""
|
||||
val jsonPusher: String = """{"name":"octocat","email":"octocat@example.com"}"""
|
||||
|
||||
// I checked all refs in gitbucket repo, and there appears to be only type "commit" and type "tag"
|
||||
val jsonRef = """{"ref":"refs/heads/featureA","object":{"sha":"6dcb09b5b57875f334f61aebed695e2e4193db5e"}}"""
|
||||
val jsonRef: String = """{"ref":"refs/heads/featureA","object":{"sha":"6dcb09b5b57875f334f61aebed695e2e4193db5e"}}"""
|
||||
|
||||
val jsonRefHeadsMain =
|
||||
val jsonRefHeadsMain: String =
|
||||
"""{
|
||||
|"ref": "refs/heads/main",
|
||||
|"node_id": "MDM6UmVmOTM1MDc0NjpyZWZzL2hlYWRzL21hc3Rlcg==",
|
||||
@@ -812,7 +825,7 @@ object ApiSpecModels {
|
||||
|}
|
||||
|}""".stripMargin
|
||||
|
||||
val jsonRefTag =
|
||||
val jsonRefTag: String =
|
||||
"""{
|
||||
|"ref": "refs/tags/1.0",
|
||||
|"node_id": "MDM6UmVmOTM1MDc0NjpyZWZzL3RhZ3MvMS4w",
|
||||
@@ -824,7 +837,7 @@ object ApiSpecModels {
|
||||
|}
|
||||
|}""".stripMargin
|
||||
|
||||
val jsonReleaseAsset =
|
||||
val jsonReleaseAsset: String =
|
||||
s"""{
|
||||
|"name":"release.zip",
|
||||
|"size":100,
|
||||
@@ -833,7 +846,7 @@ object ApiSpecModels {
|
||||
|"browser_download_url":"http://gitbucket.exmple.com/octocat/Hello-World/releases/tag1/assets/${assetFileName}"
|
||||
|}""".stripMargin
|
||||
|
||||
val jsonRelease =
|
||||
val jsonRelease: String =
|
||||
s"""{
|
||||
|"name":"release1",
|
||||
|"tag_name":"tag1",
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
package gitbucket.core.api
|
||||
|
||||
import org.json4s.Formats
|
||||
import org.json4s.{Formats, JValue, jvalue2extractable}
|
||||
import org.json4s.jackson.JsonMethods
|
||||
import org.json4s.jvalue2extractable
|
||||
import org.scalatest.Assertion
|
||||
import org.scalatest.funsuite.AnyFunSuite
|
||||
|
||||
class JsonFormatSpec extends AnyFunSuite {
|
||||
import ApiSpecModels._
|
||||
import ApiSpecModels.*
|
||||
implicit val format: Formats = JsonFormat.jsonFormats
|
||||
|
||||
private def expected(json: String) = json.replaceAll("\n", "")
|
||||
def normalizeJson(json: String) = {
|
||||
def normalizeJson(json: String): JValue = {
|
||||
org.json4s.jackson.parseJson(json)
|
||||
}
|
||||
def assertEqualJson(actual: String, expected: String) = {
|
||||
def assertEqualJson(actual: String, expected: String): Assertion = {
|
||||
assert(normalizeJson(actual) == normalizeJson(expected))
|
||||
}
|
||||
|
||||
@@ -57,7 +57,9 @@ class JsonFormatSpec extends AnyFunSuite {
|
||||
assert(JsonFormat(apiBranchProtectionOutput) == expected(jsonBranchProtectionOutput))
|
||||
}
|
||||
test("deserialize apiBranchProtection") {
|
||||
assert(JsonMethods.parse(jsonBranchProtectionInput).extract[ApiBranchProtection] == apiBranchProtectionInput)
|
||||
assert(
|
||||
JsonMethods.parse(jsonBranchProtectionInput).extract[ApiBranchProtectionResponse] == apiBranchProtectionInput
|
||||
)
|
||||
}
|
||||
test("apiBranch") {
|
||||
assert(JsonFormat(apiBranch) == expected(jsonBranch))
|
||||
|
||||
@@ -29,26 +29,28 @@ class ProtectedBranchServiceSpec
|
||||
it("should enable and update and disable") {
|
||||
withTestDB { implicit session =>
|
||||
generateNewUserWithDBRepository("user1", "repo1")
|
||||
enableBranchProtection("user1", "repo1", "branch", false, Nil)
|
||||
enableBranchProtection("user1", "repo1", "branch", false, false, Nil, false, Nil)
|
||||
assert(
|
||||
getProtectedBranchInfo("user1", "repo1", "branch") == ProtectedBranchInfo(
|
||||
"user1",
|
||||
"repo1",
|
||||
"branch",
|
||||
true,
|
||||
Nil,
|
||||
false
|
||||
None,
|
||||
false,
|
||||
None
|
||||
)
|
||||
)
|
||||
enableBranchProtection("user1", "repo1", "branch", true, Seq("hoge", "huge"))
|
||||
enableBranchProtection("user1", "repo1", "branch", true, true, Seq("hoge", "huge"), false, Nil)
|
||||
assert(
|
||||
getProtectedBranchInfo("user1", "repo1", "branch") == ProtectedBranchInfo(
|
||||
"user1",
|
||||
"repo1",
|
||||
"branch",
|
||||
true,
|
||||
Seq("hoge", "huge"),
|
||||
true
|
||||
enabled = true,
|
||||
contexts = Some(Seq("hoge", "huge")),
|
||||
enforceAdmins = true,
|
||||
restrictionsUsers = None
|
||||
)
|
||||
)
|
||||
disableBranchProtection("user1", "repo1", "branch")
|
||||
@@ -57,21 +59,21 @@ class ProtectedBranchServiceSpec
|
||||
)
|
||||
}
|
||||
}
|
||||
it("should empty contexts is no-include-administrators") {
|
||||
it("should empty contexts is include-administrators") {
|
||||
withTestDB { implicit session =>
|
||||
generateNewUserWithDBRepository("user1", "repo1")
|
||||
enableBranchProtection("user1", "repo1", "branch", false, Nil)
|
||||
assert(getProtectedBranchInfo("user1", "repo1", "branch").includeAdministrators == false)
|
||||
enableBranchProtection("user1", "repo1", "branch", true, Nil)
|
||||
assert(getProtectedBranchInfo("user1", "repo1", "branch").includeAdministrators == false)
|
||||
enableBranchProtection("user1", "repo1", "branch", false, false, Nil, false, Nil)
|
||||
assert(!getProtectedBranchInfo("user1", "repo1", "branch").enforceAdmins)
|
||||
enableBranchProtection("user1", "repo1", "branch", true, false, Nil, false, Nil)
|
||||
assert(getProtectedBranchInfo("user1", "repo1", "branch").enforceAdmins)
|
||||
}
|
||||
}
|
||||
it("getProtectedBranchList") {
|
||||
withTestDB { implicit session =>
|
||||
generateNewUserWithDBRepository("user1", "repo1")
|
||||
enableBranchProtection("user1", "repo1", "branch", false, Nil)
|
||||
enableBranchProtection("user1", "repo1", "branch2", false, Seq("fuga"))
|
||||
enableBranchProtection("user1", "repo1", "branch3", true, Seq("hoge"))
|
||||
enableBranchProtection("user1", "repo1", "branch", false, false, Nil, false, Nil)
|
||||
enableBranchProtection("user1", "repo1", "branch2", false, false, Seq("fuga"), false, Nil)
|
||||
enableBranchProtection("user1", "repo1", "branch3", true, false, Seq("hoge"), false, Nil)
|
||||
assert(getProtectedBranchList("user1", "repo1").toSet == Set("branch", "branch2", "branch3"))
|
||||
}
|
||||
}
|
||||
@@ -87,12 +89,12 @@ class ProtectedBranchServiceSpec
|
||||
ReceiveCommand.Type.UPDATE_NONFASTFORWARD
|
||||
)
|
||||
generateNewUserWithDBRepository("user1", "repo1")
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user1", false) == None)
|
||||
enableBranchProtection("user1", "repo1", "branch", false, Nil)
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user1", false).isEmpty)
|
||||
enableBranchProtection("user1", "repo1", "branch", false, false, Nil, false, Nil)
|
||||
assert(
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user1", false) == Some(
|
||||
"Cannot force-push to a protected branch"
|
||||
)
|
||||
receiveHook
|
||||
.preReceive("user1", "repo1", rp, rc, "user1", false)
|
||||
.contains("Cannot force-push to a protected branch")
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -109,12 +111,12 @@ class ProtectedBranchServiceSpec
|
||||
ReceiveCommand.Type.UPDATE_NONFASTFORWARD
|
||||
)
|
||||
generateNewUserWithDBRepository("user1", "repo1")
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user2", false) == None)
|
||||
enableBranchProtection("user1", "repo1", "branch", false, Nil)
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user2", false).isEmpty)
|
||||
enableBranchProtection("user1", "repo1", "branch", false, false, Nil, false, Nil)
|
||||
assert(
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user2", false) == Some(
|
||||
"Cannot force-push to a protected branch"
|
||||
)
|
||||
receiveHook
|
||||
.preReceive("user1", "repo1", rp, rc, "user2", false)
|
||||
.contains("Cannot force-push to a protected branch")
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -131,33 +133,33 @@ class ProtectedBranchServiceSpec
|
||||
ReceiveCommand.Type.UPDATE
|
||||
)
|
||||
val user1 = generateNewUserWithDBRepository("user1", "repo1")
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user2", false) == None)
|
||||
enableBranchProtection("user1", "repo1", "branch", false, Seq("must"))
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user2", false).isEmpty)
|
||||
enableBranchProtection("user1", "repo1", "branch", false, true, Seq("must"), false, Nil)
|
||||
assert(
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user2", false) == Some(
|
||||
"Required status check \"must\" is expected"
|
||||
)
|
||||
receiveHook
|
||||
.preReceive("user1", "repo1", rp, rc, "user2", false)
|
||||
.contains("Required status check \"must\" is expected")
|
||||
)
|
||||
enableBranchProtection("user1", "repo1", "branch", false, Seq("must", "must2"))
|
||||
enableBranchProtection("user1", "repo1", "branch", false, true, Seq("must", "must2"), false, Nil)
|
||||
assert(
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user2", false) == Some(
|
||||
"2 of 2 required status checks are expected"
|
||||
)
|
||||
receiveHook
|
||||
.preReceive("user1", "repo1", rp, rc, "user2", false)
|
||||
.contains("2 of 2 required status checks are expected")
|
||||
)
|
||||
createCommitStatus("user1", "repo1", sha2, "context", CommitState.SUCCESS, None, None, now, user1)
|
||||
assert(
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user2", false) == Some(
|
||||
"2 of 2 required status checks are expected"
|
||||
)
|
||||
receiveHook
|
||||
.preReceive("user1", "repo1", rp, rc, "user2", false)
|
||||
.contains("2 of 2 required status checks are expected")
|
||||
)
|
||||
createCommitStatus("user1", "repo1", sha2, "must", CommitState.SUCCESS, None, None, now, user1)
|
||||
assert(
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user2", false) == Some(
|
||||
"Required status check \"must2\" is expected"
|
||||
)
|
||||
receiveHook
|
||||
.preReceive("user1", "repo1", rp, rc, "user2", false)
|
||||
.contains("Required status check \"must2\" is expected")
|
||||
)
|
||||
createCommitStatus("user1", "repo1", sha2, "must2", CommitState.SUCCESS, None, None, now, user1)
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user2", false) == None)
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user2", false).isEmpty)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -173,37 +175,60 @@ class ProtectedBranchServiceSpec
|
||||
ReceiveCommand.Type.UPDATE
|
||||
)
|
||||
val user1 = generateNewUserWithDBRepository("user1", "repo1")
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user1", false) == None)
|
||||
enableBranchProtection("user1", "repo1", "branch", false, Seq("must"))
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user1", false) == None)
|
||||
enableBranchProtection("user1", "repo1", "branch", true, Seq("must"))
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user1", false).isEmpty)
|
||||
enableBranchProtection("user1", "repo1", "branch", false, true, Seq("must"), false, Nil)
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user1", false).isEmpty)
|
||||
enableBranchProtection("user1", "repo1", "branch", true, true, Seq("must"), false, Nil)
|
||||
assert(
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user1", false) == Some(
|
||||
"Required status check \"must\" is expected"
|
||||
)
|
||||
receiveHook
|
||||
.preReceive("user1", "repo1", rp, rc, "user1", false)
|
||||
.contains("Required status check \"must\" is expected")
|
||||
)
|
||||
enableBranchProtection("user1", "repo1", "branch", false, Seq("must", "must2"))
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user1", false) == None)
|
||||
enableBranchProtection("user1", "repo1", "branch", true, Seq("must", "must2"))
|
||||
enableBranchProtection("user1", "repo1", "branch", false, true, Seq("must", "must2"), false, Nil)
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user1", false).isEmpty)
|
||||
enableBranchProtection("user1", "repo1", "branch", true, true, Seq("must", "must2"), false, Nil)
|
||||
assert(
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user1", false) == Some(
|
||||
"2 of 2 required status checks are expected"
|
||||
)
|
||||
receiveHook
|
||||
.preReceive("user1", "repo1", rp, rc, "user1", false)
|
||||
.contains("2 of 2 required status checks are expected")
|
||||
)
|
||||
createCommitStatus("user1", "repo1", sha2, "context", CommitState.SUCCESS, None, None, now, user1)
|
||||
assert(
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user1", false) == Some(
|
||||
"2 of 2 required status checks are expected"
|
||||
)
|
||||
receiveHook
|
||||
.preReceive("user1", "repo1", rp, rc, "user1", false)
|
||||
.contains("2 of 2 required status checks are expected")
|
||||
)
|
||||
createCommitStatus("user1", "repo1", sha2, "must", CommitState.SUCCESS, None, None, now, user1)
|
||||
assert(
|
||||
receiveHook.preReceive("user1", "repo1", rp, rc, "user1", false) == Some(
|
||||
"Required status check \"must2\" is expected"
|
||||
)
|
||||
receiveHook
|
||||
.preReceive("user1", "repo1", rp, rc, "user1", false)
|
||||
.contains("Required status check \"must2\" is expected")
|
||||
)
|
||||
createCommitStatus("user1", "repo1", sha2, "must2", CommitState.SUCCESS, None, None, now, user1)
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user1", false) == None)
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user1", false).isEmpty)
|
||||
}
|
||||
}
|
||||
}
|
||||
it("should restrict push to allowed users only") {
|
||||
withTestDB { implicit session =>
|
||||
withTestRepository { git =>
|
||||
val rp = new ReceivePack(git.getRepository)
|
||||
rp.setAllowNonFastForwards(true)
|
||||
val rc = new ReceiveCommand(
|
||||
ObjectId.fromString(sha),
|
||||
ObjectId.fromString(sha2),
|
||||
"refs/heads/branch",
|
||||
ReceiveCommand.Type.UPDATE
|
||||
)
|
||||
generateNewUserWithDBRepository("user1", "repo1")
|
||||
generateNewAccount("user2")
|
||||
enableBranchProtection("user1", "repo1", "branch", false, false, Nil, true, Seq("user2"))
|
||||
assert(receiveHook.preReceive("user1", "repo1", rp, rc, "user2", false).isEmpty)
|
||||
assert(
|
||||
receiveHook
|
||||
.preReceive("user1", "repo1", rp, rc, "user3", false)
|
||||
.contains("You do not have permission to push to this branch")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -212,29 +237,53 @@ class ProtectedBranchServiceSpec
|
||||
it("administrator is owner") {
|
||||
withTestDB { implicit session =>
|
||||
generateNewUserWithDBRepository("user1", "repo1")
|
||||
val x = ProtectedBranchInfo("user1", "repo1", "branch", true, Nil, false)
|
||||
assert(x.isAdministrator("user1") == true)
|
||||
assert(x.isAdministrator("user2") == false)
|
||||
val x = ProtectedBranchInfo(
|
||||
"user1",
|
||||
"repo1",
|
||||
"branch",
|
||||
enabled = true,
|
||||
contexts = Some(Nil),
|
||||
enforceAdmins = false,
|
||||
restrictionsUsers = None
|
||||
)
|
||||
assert(x.isAdministrator("user1"))
|
||||
assert(!x.isAdministrator("user2"))
|
||||
}
|
||||
}
|
||||
it("administrator is manager") {
|
||||
withTestDB { implicit session =>
|
||||
val x = ProtectedBranchInfo("grp1", "repo1", "branch", true, Nil, false)
|
||||
val x = ProtectedBranchInfo(
|
||||
"grp1",
|
||||
"repo1",
|
||||
"branch",
|
||||
enabled = true,
|
||||
contexts = Some(Nil),
|
||||
enforceAdmins = false,
|
||||
restrictionsUsers = None
|
||||
)
|
||||
x.createGroup("grp1", None, None)
|
||||
generateNewAccount("user1")
|
||||
generateNewAccount("user2")
|
||||
generateNewAccount("user3")
|
||||
|
||||
x.updateGroupMembers("grp1", List("user1" -> true, "user2" -> false))
|
||||
assert(x.isAdministrator("user1") == true)
|
||||
assert(x.isAdministrator("user2") == false)
|
||||
assert(x.isAdministrator("user3") == false)
|
||||
assert(x.isAdministrator("user1"))
|
||||
assert(!x.isAdministrator("user2"))
|
||||
assert(!x.isAdministrator("user3"))
|
||||
}
|
||||
}
|
||||
it("unSuccessedContexts") {
|
||||
withTestDB { implicit session =>
|
||||
val user1 = generateNewUserWithDBRepository("user1", "repo1")
|
||||
val x = ProtectedBranchInfo("user1", "repo1", "branch", true, List("must"), false)
|
||||
val x = ProtectedBranchInfo(
|
||||
"user1",
|
||||
"repo1",
|
||||
"branch",
|
||||
enabled = true,
|
||||
contexts = Some(List("must")),
|
||||
enforceAdmins = false,
|
||||
restrictionsUsers = None
|
||||
)
|
||||
assert(x.unSuccessedContexts(sha) == Set("must"))
|
||||
createCommitStatus("user1", "repo1", sha, "context", CommitState.SUCCESS, None, None, now, user1)
|
||||
assert(x.unSuccessedContexts(sha) == Set("must"))
|
||||
@@ -251,7 +300,15 @@ class ProtectedBranchServiceSpec
|
||||
it("unSuccessedContexts when empty") {
|
||||
withTestDB { implicit session =>
|
||||
val user1 = generateNewUserWithDBRepository("user1", "repo1")
|
||||
val x = ProtectedBranchInfo("user1", "repo1", "branch", true, Nil, false)
|
||||
val x = ProtectedBranchInfo(
|
||||
"user1",
|
||||
"repo1",
|
||||
"branch",
|
||||
enabled = true,
|
||||
contexts = Some(Nil),
|
||||
enforceAdmins = false,
|
||||
restrictionsUsers = None
|
||||
)
|
||||
val sha = "0c77148632618b59b6f70004e3084002be2b8804"
|
||||
assert(x.unSuccessedContexts(sha) == Set())
|
||||
createCommitStatus("user1", "repo1", sha, "context", CommitState.SUCCESS, None, None, now, user1)
|
||||
@@ -261,23 +318,63 @@ class ProtectedBranchServiceSpec
|
||||
it("if disabled, needStatusCheck is false") {
|
||||
withTestDB { implicit session =>
|
||||
assert(
|
||||
ProtectedBranchInfo("user1", "repo1", "branch", false, Seq("must"), true).needStatusCheck("user1") == false
|
||||
!ProtectedBranchInfo(
|
||||
"user1",
|
||||
"repo1",
|
||||
"branch",
|
||||
enabled = false,
|
||||
contexts = Some(Seq("must")),
|
||||
enforceAdmins = true,
|
||||
restrictionsUsers = None
|
||||
).needStatusCheck("user1")
|
||||
)
|
||||
}
|
||||
}
|
||||
it("needStatusCheck includeAdministrators") {
|
||||
withTestDB { implicit session =>
|
||||
assert(
|
||||
ProtectedBranchInfo("user1", "repo1", "branch", true, Seq("must"), false).needStatusCheck("user2") == true
|
||||
ProtectedBranchInfo(
|
||||
"user1",
|
||||
"repo1",
|
||||
"branch",
|
||||
enabled = true,
|
||||
contexts = Some(Seq("must")),
|
||||
enforceAdmins = false,
|
||||
restrictionsUsers = None
|
||||
).needStatusCheck("user2")
|
||||
)
|
||||
assert(
|
||||
ProtectedBranchInfo("user1", "repo1", "branch", true, Seq("must"), false).needStatusCheck("user1") == false
|
||||
!ProtectedBranchInfo(
|
||||
"user1",
|
||||
"repo1",
|
||||
"branch",
|
||||
enabled = true,
|
||||
contexts = Some(Seq("must")),
|
||||
enforceAdmins = false,
|
||||
restrictionsUsers = None
|
||||
).needStatusCheck("user1")
|
||||
)
|
||||
assert(
|
||||
ProtectedBranchInfo("user1", "repo1", "branch", true, Seq("must"), true).needStatusCheck("user2") == true
|
||||
ProtectedBranchInfo(
|
||||
"user1",
|
||||
"repo1",
|
||||
"branch",
|
||||
enabled = true,
|
||||
contexts = Some(Seq("must")),
|
||||
enforceAdmins = true,
|
||||
restrictionsUsers = None
|
||||
).needStatusCheck("user2")
|
||||
)
|
||||
assert(
|
||||
ProtectedBranchInfo("user1", "repo1", "branch", true, Seq("must"), true).needStatusCheck("user1") == true
|
||||
ProtectedBranchInfo(
|
||||
"user1",
|
||||
"repo1",
|
||||
"branch",
|
||||
enabled = true,
|
||||
contexts = Some(Seq("must")),
|
||||
enforceAdmins = true,
|
||||
restrictionsUsers = None
|
||||
).needStatusCheck("user1")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ class RepositoryServiceSpec extends AnyFunSuite with ServiceSpecBase with Reposi
|
||||
now = new java.util.Date
|
||||
)
|
||||
|
||||
service.enableBranchProtection("root", "repo", "branch", true, Seq("must1", "must2"))
|
||||
service.enableBranchProtection("root", "repo", "branch", true, true, Seq("must1", "must2"), false, Nil)
|
||||
|
||||
val orgPbi = service.getProtectedBranchInfo("root", "repo", "branch")
|
||||
val org = service.getCommitStatus("root", "repo", id).get
|
||||
|
||||
Reference in New Issue
Block a user