diff --git a/.gitignore b/.gitignore index 7a3b81b9..b395fd90 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ .DS_Store -.idea/* +.idea/ *.iml build/ target/* @@ -13,3 +13,4 @@ target .settings *.ipr *.iws +out/ diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar new file mode 100755 index 00000000..9cc84ea9 Binary files /dev/null and b/.mvn/wrapper/maven-wrapper.jar differ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100755 index 00000000..56bb0164 --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1 @@ +distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.0/apache-maven-3.5.0-bin.zip \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 4332fd0b..257d4981 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,10 @@ language: java -sudo: false +sudo: required +services: + - docker jdk: -- oraclejdk7 +- openjdk8 install: -- ./gradlew assemble +- ./mvnw -B -q -Pdocker-gitlab dependency:go-offline verify -DskipTests -Ddocker.skip script: -- ./gradlew check -before_deploy: -- ./gradlew deployZip +- ./mvnw -B -V -Pdocker-gitlab verify diff --git a/CHANGES.txt b/CHANGES.txt new file mode 100644 index 00000000..f8749726 --- /dev/null +++ b/CHANGES.txt @@ -0,0 +1,2 @@ +Current +Fixed: GITHUB-297: The "connectTimeout" parameter is not configurable. \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..5b8d6f70 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,9 @@ +# How to contribute + + +* The integration tests need a running Docker infrastructure. +* To execute these, run `mvn -Pdocker-gitlab clean verify`. This will spawn + a new gitlab instance (`pull` needs some time and starting `gitlab-ce` may take up to 3 minutes). +* To run integration tests in your IDE, you need to execute `mvn -Pdocker-gitlab,docker-ide docker:start`. +* Once you are done, you may stop gitlab by executing `mvn -Pdocker-gitlab,docker-ide docker:stop`. +* For more information about the API, take a look at the [documentation](https://gitlab.com/help/api/README.md). \ No newline at end of file diff --git a/LICENSE b/LICENSE index 2977f0c9..75b52484 100644 --- a/LICENSE +++ b/LICENSE @@ -1,13 +1,202 @@ -Copyright 2013-2014 Timothy Olshansky - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/NOTICE b/NOTICE new file mode 100644 index 00000000..2977f0c9 --- /dev/null +++ b/NOTICE @@ -0,0 +1,13 @@ +Copyright 2013-2014 Timothy Olshansky + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/README.md b/README.md index 7a64ec5e..4dea5cbd 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # Gitlab Java API Wrapper [![Maven Central](https://img.shields.io/maven-central/v/org.gitlab/java-gitlab-api.svg)](http://mvnrepository.com/artifact/org.gitlab/java-gitlab-api) - -A wrapper for the [Gitlab API](https://gitlab.org) written in Java. +[![Build Status](https://travis-ci.org/timols/java-gitlab-api.svg?branch=master)](https://travis-ci.org/timols/java-gitlab-api) +A wrapper for the [Gitlab API](https://docs.gitlab.com/ee/api/) written in Java. [Documentation](https://timols.github.io/java-gitlab-api) is available in the form of [Javadocs](https://timols.github.io/java-gitlab-api) +The major version indicates the API version of gitlab. diff --git a/build.gradle b/build.gradle index a0d3a58d..a245c85b 100644 --- a/build.gradle +++ b/build.gradle @@ -1,21 +1,21 @@ buildscript { - tasks.withType(JavaCompile) { - options.encoding = 'UTF-8' - } + tasks.withType(JavaCompile) { + options.encoding = "UTF-8" + } } -apply plugin: 'java' -apply plugin: 'maven' - -// IDE plugins -apply plugin: 'idea' -apply plugin: 'eclipse' +plugins { + id "java" + id "maven" + id "idea" + id "eclipse" +} -sourceCompatibility = 1.7 -targetCompatibility = 1.7 +sourceCompatibility = 1.8 +targetCompatibility = 1.8 -group = 'org.gitlab' -version = '1.2.7-SNAPSHOT' +group = "org.gitlab" +version = "4.1.2-SNAPSHOT" repositories { mavenLocal() @@ -23,27 +23,42 @@ repositories { } dependencies { - compile(group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.5.3') - compile(group: 'commons-io', name: 'commons-io', version: '2.4') - testCompile(group: 'org.hamcrest', name: 'hamcrest-all', version: '1.3') - testCompile(group: 'junit', name: 'junit', version: '4.12') + compile(group: "org.slf4j", name: "slf4j-api", version: "1.8.0-beta2") + compile(group: "commons-io", name: "commons-io", version: "2.4") + compile(group: "com.fasterxml.jackson.core", name: "jackson-databind", version: "2.5.+") + compile(group: "com.fasterxml.jackson.datatype", name: "jackson-datatype-jsr310", version: "2.5.1") + testCompile(group: "org.apache.logging.log4j", name: "log4j-api", version: "2.11.0") + testCompile(group: "org.apache.logging.log4j", name: "log4j-slf4j-impl", version: "2.11.0") + testCompile(group: "org.hamcrest", name: "hamcrest-all", version: "1.3") + testCompile(group: "org.mockito", name: "mockito-core", version: "2.18.3") + testCompile(group: "org.junit.jupiter", name: "junit-jupiter-api", version: "5.2.0") + testCompile(group: "junit", name: "junit", version: "4.12") + testRuntime(group: "org.junit.jupiter", name: "junit-jupiter-engine", version: "5.2.0") + testRuntime(group: "org.junit.vintage", name: "junit-vintage-engine", version: "5.2.0") } jar { - manifest { attributes 'Gradle-Version': gradle.gradleVersion } + manifest { attributes "Gradle-Version": gradle.gradleVersion } + from "LICENSE" + from "NOTICE" } install { - repositories.mavenInstaller { pom.artifactId = 'java-gitlab-api' } + repositories.mavenInstaller { pom.artifactId = "java-gitlab-api" } } task sourcesJar(type: Jar, dependsOn:classes) { - classifier = 'sources' - from sourceSets.main.allSource + classifier = "sources" + from sourceSets.main.allSource + from "LICENSE" + from "NOTICE" } artifacts { archives sourcesJar } -task wrapper(type: Wrapper) { - gradleVersion = '2.4' +test { + useJUnitPlatform { + includeEngines 'junit-jupiter' + includeEngines 'junit-vintage' + } } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index b5166dad..f6b961fd 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c1c608ef..430dfabc 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Wed May 13 23:55:44 CEST 2015 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-bin.zip diff --git a/gradlew b/gradlew index 91a7e269..cccdd3d5 100755 --- a/gradlew +++ b/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh ############################################################################## ## @@ -6,20 +6,38 @@ ## ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -30,6 +48,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,31 +59,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -90,7 +89,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -114,6 +113,7 @@ fi if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` @@ -154,11 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index aec99730..e95643d6 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -8,14 +8,14 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -46,10 +46,9 @@ echo location of your Java installation. goto fail :init -@rem Get command-line arguments, handling Windowz variants +@rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. @@ -60,11 +59,6 @@ set _SKIP=2 if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ :execute @rem Setup the command line diff --git a/mvnw b/mvnw new file mode 100755 index 00000000..5bf251c0 --- /dev/null +++ b/mvnw @@ -0,0 +1,225 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Migwn, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" + # TODO classpath? +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +echo $MAVEN_PROJECTBASEDIR +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100755 index 00000000..019bd74d --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,143 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" + +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml index 4081b7a7..902f0424 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.gitlab java-gitlab-api - 1.2.8-SNAPSHOT + 4.1.2-SNAPSHOT Gitlab Java API Wrapper A Java wrapper for the Gitlab Git Hosting Server API @@ -38,6 +38,14 @@ luu@fuzzproductions.com Fuzz Productions + + Oleg Shaburov + shaburov.o.a@gmail.com + + Automation QA + + +3 + @@ -60,8 +68,15 @@ + 1.8 + 1.8 UTF-8 UTF-8 + 2.21.0 + + 180000 + 2.11.0 + 5.2.0 @@ -73,17 +88,30 @@ com.fasterxml.jackson.core jackson-databind - 2.5.3 + 2.9.10.5 commons-io commons-io 2.4 + - org.hamcrest - hamcrest-all - 1.3 + org.slf4j + slf4j-api + 1.8.0-beta2 + + + + org.junit.jupiter + junit-jupiter-api + ${junit.jupiter.version} + test + + + org.junit.jupiter + junit-jupiter-engine + ${junit.jupiter.version} test @@ -92,34 +120,85 @@ 4.12 test + + org.junit.vintage + junit-vintage-engine + ${junit.jupiter.version} + test + + + org.hamcrest + hamcrest-all + 1.3 + test + + + org.mockito + mockito-core + 2.10.0 + test + + + + org.apache.logging.log4j + log4j-api + ${log4j.version} + test + + + org.apache.logging.log4j + log4j-slf4j-impl + ${log4j.version} + test + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + 2.5.1 + + + + + + + ./ + + LICENSE + NOTICE + + + org.apache.maven.plugins maven-compiler-plugin 2.5.1 - - 1.6 - 1.6 - org.apache.maven.plugins maven-surefire-plugin - 2.17 + ${maven-surefire-plugin.version} org.apache.maven.plugins maven-failsafe-plugin - 2.17 + ${maven-surefire-plugin.version} default-integration-test integration-test + + + ${docker.host.address} + ${gitlab.port} + + default-verify @@ -132,7 +211,7 @@ org.apache.maven.plugins maven-source-plugin - 2.4 + 3.0.0 attach-sources @@ -143,6 +222,108 @@ + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + verify + + sign + + + + --pinentry-mode + loopback + + + + + + + + docker-ide + + 127.0.0.1 + 18080 + + + + docker-gitlab + + + + io.fabric8 + docker-maven-plugin + 0.23.0 + + + default-start + + start + + + + default-stop + + stop + + + + + + + gitlab/gitlab-ce:latest + gitlab + + + gitlab.port:80 + + + + + ${user.dir}/src/test/resources/gitlab.rb:/etc/gitlab/gitlab.rb + + + + + + http://${docker.host.address}:${gitlab.port}/api/v4/version + GET + 401 + + + + + + + + + + + + + doclint-java8-disable + + [1.8,) + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.0.0-M1 + + -Xdoclint:none + + + + + + diff --git a/src/main/java/org/gitlab/api/GitlabAPI.java b/src/main/java/org/gitlab/api/GitlabAPI.java index 6fede1e6..c0c88fa7 100644 --- a/src/main/java/org/gitlab/api/GitlabAPI.java +++ b/src/main/java/org/gitlab/api/GitlabAPI.java @@ -5,11 +5,17 @@ import org.gitlab.api.http.GitlabHTTPRequestor; import org.gitlab.api.http.Query; import org.gitlab.api.models.*; +import org.gitlab.api.query.PaginationQuery; +import org.gitlab.api.query.PipelinesQuery; +import org.gitlab.api.query.ProjectsQuery; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import java.io.FileNotFoundException; +import java.io.File; import java.io.IOException; import java.io.Serializable; import java.io.UnsupportedEncodingException; +import java.net.Proxy; import java.net.URL; import java.net.URLEncoder; import java.text.SimpleDateFormat; @@ -17,39 +23,56 @@ import java.util.Arrays; import java.util.Date; import java.util.List; +import java.util.Collection; +import static org.gitlab.api.http.Method.*; /** * Gitlab API Wrapper class * * @author @timols (Tim O) */ -@SuppressWarnings("unused") +@SuppressWarnings({"unused", "WeakerAccess"}) public class GitlabAPI { + private static final Logger LOG = LoggerFactory.getLogger(GitlabAPI.class); + public static final ObjectMapper MAPPER = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - private static final String API_NAMESPACE = "/api/v3"; + + private static final String DEFAULT_API_NAMESPACE = "/api/v4"; private static final String PARAM_SUDO = "sudo"; + private static final String PARAM_WITH_PROJECTS = "with_projects"; + private static final String PARAM_MAX_ITEMS_PER_PAGE = new Pagination().withPerPage(Pagination.MAX_ITEMS_PER_PAGE).toString(); private final String hostUrl; private final String apiToken; private final TokenType tokenType; private AuthMethod authMethod; + private final String apiNamespace; private boolean ignoreCertificateErrors = false; - private int requestTimeout = 0; + private Proxy proxy; + private int defaultTimeout = 0; + private int readTimeout = defaultTimeout; + private int connectionTimeout = defaultTimeout; + private String userAgent = GitlabAPI.class.getCanonicalName() + "/" + System.getProperty("java.version"); - private GitlabAPI(String hostUrl, String apiToken, TokenType tokenType, AuthMethod method) { + private GitlabAPI(String hostUrl, String apiToken, TokenType tokenType, AuthMethod method, String apiNamespace) { this.hostUrl = hostUrl.endsWith("/") ? hostUrl.replaceAll("/$", "") : hostUrl; this.apiToken = apiToken; this.tokenType = tokenType; this.authMethod = method; + this.apiNamespace = apiNamespace; + } + + private GitlabAPI(String hostUrl, String apiToken, TokenType tokenType, AuthMethod method) { + this(hostUrl, apiToken, tokenType, method, DEFAULT_API_NAMESPACE); } public static GitlabSession connect(String hostUrl, String username, String password) throws IOException { String tailUrl = GitlabSession.URL; - GitlabAPI api = connect(hostUrl, null, null, null); + GitlabAPI api = connect(hostUrl, null, null, (AuthMethod) null); return api.dispatch().with("login", username).with("password", password) .to(tailUrl, GitlabSession.class); } @@ -66,17 +89,68 @@ public static GitlabAPI connect(String hostUrl, String apiToken, TokenType token return new GitlabAPI(hostUrl, apiToken, tokenType, method); } + public static GitlabAPI connect(String hostUrl, String apiToken, TokenType tokenType, String apiNamespace) { + return new GitlabAPI(hostUrl, apiToken, tokenType, AuthMethod.HEADER, apiNamespace); + } + + public static GitlabAPI connect(String hostUrl, String apiToken, TokenType tokenType, AuthMethod method, String apiNamespace) { + return new GitlabAPI(hostUrl, apiToken, tokenType, method, apiNamespace); + } + public GitlabAPI ignoreCertificateErrors(boolean ignoreCertificateErrors) { this.ignoreCertificateErrors = ignoreCertificateErrors; return this; } + public GitlabAPI proxy(Proxy proxy) { + this.proxy = proxy; + return this; + } + + public int getResponseReadTimeout() { + return readTimeout; + } + + /** + * @deprecated use this.getResponseReadTimeout() method + */ + @Deprecated public int getRequestTimeout() { - return requestTimeout; + return getResponseReadTimeout(); + } + + /** + * @deprecated use this.setResponseReadTimeout(int readTimeout) method + */ + @Deprecated + public GitlabAPI setRequestTimeout(int readTimeout) { + setResponseReadTimeout(readTimeout); + return this; } - public GitlabAPI setRequestTimeout(int requestTimeout) { - this.requestTimeout = requestTimeout; + public GitlabAPI setResponseReadTimeout(int readTimeout) { + if (readTimeout < 0) { + LOG.warn("The value of the \"Response Read Timeout\" parameter can not be negative. " + + "The default value [{}] will be used.", defaultTimeout); + this.readTimeout = defaultTimeout; + } else { + this.readTimeout = readTimeout; + } + return this; + } + + public int getConnectionTimeout() { + return connectionTimeout; + } + + public GitlabAPI setConnectionTimeout(int connectionTimeout) { + if (connectionTimeout < 0) { + LOG.warn("The value of the \"Connection Timeout\" parameter can not be negative. " + + "The default value [{}] will be used.", defaultTimeout); + this.connectionTimeout = defaultTimeout; + } else { + this.connectionTimeout = connectionTimeout; + } return this; } @@ -85,18 +159,26 @@ public GitlabHTTPRequestor retrieve() { } public GitlabHTTPRequestor dispatch() { - return new GitlabHTTPRequestor(this).authenticate(apiToken, tokenType, authMethod).method("POST"); + return new GitlabHTTPRequestor(this).authenticate(apiToken, tokenType, authMethod).method(POST); + } + + public GitlabHTTPRequestor put() { + return new GitlabHTTPRequestor(this).authenticate(apiToken, tokenType, authMethod).method(PUT); } public boolean isIgnoreCertificateErrors() { return ignoreCertificateErrors; } + public Proxy getProxy() { + return proxy; + } + public URL getAPIUrl(String tailAPIUrl) throws IOException { if (!tailAPIUrl.startsWith("/")) { tailAPIUrl = "/" + tailAPIUrl; } - return new URL(hostUrl + API_NAMESPACE + tailAPIUrl); + return new URL(hostUrl + apiNamespace + tailAPIUrl); } public URL getUrl(String tailAPIUrl) throws IOException { @@ -107,20 +189,25 @@ public URL getUrl(String tailAPIUrl) throws IOException { return new URL(hostUrl + tailAPIUrl); } - public List getUsers() throws IOException { - String tailUrl = GitlabUser.URL; + public String getHost() { + return hostUrl; + } + + public List getUsers() { + String tailUrl = GitlabUser.URL + PARAM_MAX_ITEMS_PER_PAGE; return retrieve().getAll(tailUrl, GitlabUser[].class); } /** * Finds users by email address or username. + * * @param emailOrUsername Some portion of the email address or username * @return A non-null List of GitlabUser instances. If the search term is - * null or empty a List with zero GitlabUsers is returned. - * @throws IOException + * null or empty a List with zero GitlabUsers is returned. + * @throws IOException on gitlab api call error */ public List findUsers(String emailOrUsername) throws IOException { - List users = new ArrayList(); + List users = new ArrayList<>(); if (emailOrUsername != null && !emailOrUsername.equals("")) { String tailUrl = GitlabUser.URL + "?search=" + emailOrUsername; GitlabUser[] response = retrieve().to(tailUrl, GitlabUser[].class); @@ -165,6 +252,7 @@ public GitlabUser getUserViaSudo(String username) throws IOException { * @param isAdmin Is Admin * @param can_create_group Can Create Group * @param skip_confirmation Skip Confirmation + * @param external External * @return A GitlabUser * @throws IOException on gitlab api call error * @see http://doc.gitlab.com/ce/api/users.html @@ -174,11 +262,11 @@ public GitlabUser createUser(String email, String password, String username, String twitter, String website_url, Integer projects_limit, String extern_uid, String extern_provider_name, String bio, Boolean isAdmin, Boolean can_create_group, - Boolean skip_confirmation) throws IOException { + Boolean skip_confirmation, Boolean external) throws IOException { Query query = new Query() .append("email", email) - .appendIf("confirm", skip_confirmation == null ? null : !skip_confirmation) + .appendIf("skip_confirmation", skip_confirmation) .appendIf("password", password) .appendIf("username", username) .appendIf("name", fullName) @@ -191,13 +279,26 @@ public GitlabUser createUser(String email, String password, String username, .appendIf("provider", extern_provider_name) .appendIf("bio", bio) .appendIf("admin", isAdmin) - .appendIf("can_create_group", can_create_group); + .appendIf("can_create_group", can_create_group) + .appendIf("external", external); String tailUrl = GitlabUser.USERS_URL + query.toString(); return dispatch().to(tailUrl, GitlabUser.class); } + /** + * Create a new user. This may succeed only if the requester is an administrator. + * + * @param request An object that represents the parameters for the request. + * @return {@link GitlabUser} + * @throws IOException on gitlab api call error + */ + public GitlabUser createUser(CreateUserRequest request) throws IOException { + String tailUrl = GitlabUser.USERS_URL + request.toQuery().toString(); + return dispatch().to(tailUrl, GitlabUser.class); + } + /** * Update a user @@ -217,6 +318,7 @@ public GitlabUser createUser(String email, String password, String username, * @param bio Bio * @param isAdmin Is Admin * @param can_create_group Can Create Group + * @param external External * @return The Updated User * @throws IOException on gitlab api call error */ @@ -225,7 +327,7 @@ public GitlabUser updateUser(Integer targetUserId, String fullName, String skypeId, String linkedIn, String twitter, String website_url, Integer projects_limit, String extern_uid, String extern_provider_name, - String bio, Boolean isAdmin, Boolean can_create_group) throws IOException { + String bio, Boolean isAdmin, Boolean can_create_group, Boolean external) throws IOException { Query query = new Query() .append("email", email) @@ -241,11 +343,12 @@ public GitlabUser updateUser(Integer targetUserId, .appendIf("provider", extern_provider_name) .appendIf("bio", bio) .appendIf("admin", isAdmin) - .appendIf("can_create_group", can_create_group); + .appendIf("can_create_group", can_create_group) + .appendIf("external", external); String tailUrl = GitlabUser.USERS_URL + "/" + targetUserId + query.toString(); - return retrieve().method("PUT").to(tailUrl, GitlabUser.class); + return retrieve().method(PUT).to(tailUrl, GitlabUser.class); } /** @@ -258,7 +361,7 @@ public void blockUser(Integer targetUserId) throws IOException { String tailUrl = GitlabUser.USERS_URL + "/" + targetUserId + GitlabUser.BLOCK_URL; - retrieve().method("PUT").to(tailUrl, Void.class); + retrieve().method(POST).to(tailUrl, Void.class); } /** @@ -271,7 +374,7 @@ public void unblockUser(Integer targetUserId) throws IOException { String tailUrl = GitlabUser.USERS_URL + "/" + targetUserId + GitlabUser.UNBLOCK_URL; - retrieve().method("PUT").to(tailUrl, Void.class); + retrieve().method(POST).to(tailUrl, Void.class); } /** @@ -294,6 +397,25 @@ public GitlabSSHKey createSSHKey(Integer targetUserId, String title, String key) return dispatch().to(tailUrl, GitlabSSHKey.class); } + /** + * Create a new ssh key for the authenticated user. + * + * @param title The title of the ssh key + * @param key The public key + * @return The new GitlabSSHKey + * @throws IOException on gitlab api call error + */ + public GitlabSSHKey createSSHKey(String title, String key) throws IOException { + + Query query = new Query() + .append("title", title) + .append("key", key); + + String tailUrl = GitlabUser.USER_URL + GitlabSSHKey.KEYS_URL + query.toString(); + + return dispatch().to(tailUrl, GitlabSSHKey.class); + } + /** * Delete user's ssh key * @@ -303,7 +425,7 @@ public GitlabSSHKey createSSHKey(Integer targetUserId, String title, String key) */ public void deleteSSHKey(Integer targetUserId, Integer targetKeyId) throws IOException { String tailUrl = GitlabUser.USERS_URL + "/" + targetUserId + GitlabSSHKey.KEYS_URL + "/" + targetKeyId; - retrieve().method("DELETE").to(tailUrl, Void.class); + retrieve().method(DELETE).to(tailUrl, Void.class); } @@ -334,32 +456,65 @@ public GitlabSSHKey getSSHKey(Integer keyId) throws IOException { /** * Delete a user * - * @param targetUserId The target User ID + * @param targetUserId The target User ID * @throws IOException on gitlab api call error */ public void deleteUser(Integer targetUserId) throws IOException { String tailUrl = GitlabUser.USERS_URL + "/" + targetUserId; - retrieve().method("DELETE").to(tailUrl, Void.class); + retrieve().method(DELETE).to(tailUrl, Void.class); } public GitlabGroup getGroup(Integer groupId) throws IOException { return getGroup(groupId.toString()); } + public GitlabGroup getGroupWithoutProjects(Integer groupId) throws IOException { + return getGroupWithoutProjects(groupId.toString()); + } + /** - * Get a group by path + * Get a group by path. Don't include the projects. * * @param path Path of the group - * @return - * @throws IOException + * @return {@link GitlabGroup} object + * + * @throws IOException on gitlab api call error + */ + public GitlabGroup getGroupWithoutProjects(String path) throws IOException { + return getGroup(path, false); + } + + /** + * Get a group by path, including its projects. + * + * @param path Path of the group + * @return {@link GitlabGroup} object + * + * @throws IOException on gitlab api call error */ public GitlabGroup getGroup(String path) throws IOException { - String tailUrl = GitlabGroup.URL + "/" + path; - return retrieve().to(tailUrl, GitlabGroup.class); + return getGroup(path, true); + } + + /** + * Get a group by path + * + * @param path Path of the group + * @param withProjects If true, include the projects + * @return {@link GitlabGroup} object + * + * @throws IOException on gitlab api call error + */ + public GitlabGroup getGroup(String path, boolean withProjects) throws IOException { + String tailUrl = GitlabGroup.URL + "/" + URLEncoder.encode(path, "UTF-8"); + Query query = new Query() + .append(PARAM_WITH_PROJECTS, "" + withProjects); + + return retrieve().to(tailUrl + query.toString(), GitlabGroup.class); } public List getGroups() throws IOException { - return getGroupsViaSudo(null, null); + return getGroupsViaSudo(null, new Pagination().withPerPage(Pagination.MAX_ITEMS_PER_PAGE)); } public List getGroupsViaSudo(String username, Pagination pagination) throws IOException { @@ -380,9 +535,8 @@ public List getGroupsViaSudo(String username, Pagination pagination * * @param group the target group * @return a list of projects for the group - * @throws IOException */ - public List getGroupProjects(GitlabGroup group) throws IOException { + public List getGroupProjects(GitlabGroup group) { return getGroupProjects(group.getId()); } @@ -391,11 +545,10 @@ public List getGroupProjects(GitlabGroup group) throws IOExceptio * * @param groupId the target group's id. * @return a list of projects for the group - * @throws IOException */ - public List getGroupProjects(Integer groupId) throws IOException { - String tailUrl = GitlabGroup.URL + "/" + groupId + GitlabProject.URL; - return Arrays.asList(retrieve().to(tailUrl, GitlabProject[].class)); + public List getGroupProjects(Integer groupId) { + String tailUrl = GitlabGroup.URL + "/" + groupId + GitlabProject.URL + PARAM_MAX_ITEMS_PER_PAGE; + return retrieve().getAll(tailUrl, GitlabProject[].class); } /** @@ -403,9 +556,8 @@ public List getGroupProjects(Integer groupId) throws IOException * * @param group The GitLab Group * @return The Group Members - * @throws IOException on gitlab api call error */ - public List getGroupMembers(GitlabGroup group) throws IOException { + public List getGroupMembers(GitlabGroup group) { return getGroupMembers(group.getId()); } @@ -414,11 +566,10 @@ public List getGroupMembers(GitlabGroup group) throws IOExcep * * @param groupId The id of the GitLab Group * @return The Group Members - * @throws IOException on gitlab api call error */ - public List getGroupMembers(Integer groupId) throws IOException { - String tailUrl = GitlabGroup.URL + "/" + groupId + GitlabGroupMember.URL; - return Arrays.asList(retrieve().to(tailUrl, GitlabGroupMember[].class)); + public List getGroupMembers(Integer groupId) { + String tailUrl = GitlabGroup.URL + "/" + groupId + GitlabGroupMember.URL + PARAM_MAX_ITEMS_PER_PAGE; + return retrieve().getAll(tailUrl, GitlabGroupMember[].class); } /** @@ -449,8 +600,8 @@ public GitlabGroup createGroup(String name, String path) throws IOException { /** * Creates a Group * - * @param name The name of the group - * @param path The path for the group + * @param name The name of the group + * @param path The path for the group * @param sudoUser The user to create the group on behalf of * @return The GitLab Group * @throws IOException on gitlab api call error @@ -466,7 +617,6 @@ public GitlabGroup createGroupViaSudo(String name, String path, GitlabUser sudoU * @param path The path for the group * @param ldapCn LDAP Group Name to sync with, null otherwise * @param ldapAccess Access level for LDAP group members, null otherwise - * * @return The GitLab Group * @throws IOException on gitlab api call error */ @@ -475,6 +625,23 @@ public GitlabGroup createGroup(String name, String path, String ldapCn, GitlabAc } + /** + * Creates a Group + * + * @param request An object that represents the parameters for the request. + * @param sudoUser The user for whom we're creating the group + * @return The GitLab Group + * @throws IOException on gitlab api call error + */ + public GitlabGroup createGroup(CreateGroupRequest request, GitlabUser sudoUser) throws IOException { + Query query = request.toQuery(); + query.appendIf(PARAM_SUDO, sudoUser != null ? sudoUser.getId() : null); + + String tailUrl = GitlabGroup.URL + query.toString(); + + return dispatch().to(tailUrl, GitlabGroup.class); + } + /** * Creates a Group * @@ -482,18 +649,64 @@ public GitlabGroup createGroup(String name, String path, String ldapCn, GitlabAc * @param path The path for the group * @param ldapCn LDAP Group Name to sync with, null otherwise * @param ldapAccess Access level for LDAP group members, null otherwise - * @param sudoUser The user to create the group on behalf of - * + * @param sudoUser The user to create the group on behalf of * @return The GitLab Group * @throws IOException on gitlab api call error */ public GitlabGroup createGroup(String name, String path, String ldapCn, GitlabAccessLevel ldapAccess, GitlabUser sudoUser) throws IOException { + return createGroup(name, path, ldapCn, ldapAccess, sudoUser, null); + } + + /** + * Creates a Group + * + * @param name The name of the group + * @param path The path for the group + * @param ldapCn LDAP Group Name to sync with, null otherwise + * @param ldapAccess Access level for LDAP group members, null otherwise + * @param sudoUser The user to create the group on behalf of + * @param parentId The id of a parent group; the new group will be its subgroup + * @return The GitLab Group + * @throws IOException on gitlab api call error + */ + public GitlabGroup createGroup(String name, String path, String ldapCn, GitlabAccessLevel ldapAccess, GitlabUser sudoUser, Integer parentId) throws IOException { Query query = new Query() .append("name", name) .append("path", path) .appendIf("ldap_cn", ldapCn) .appendIf("ldap_access", ldapAccess) + .appendIf(PARAM_SUDO, sudoUser != null ? sudoUser.getId() : null) + .appendIf("parent_id", parentId); + + String tailUrl = GitlabGroup.URL + query.toString(); + + return dispatch().to(tailUrl, GitlabGroup.class); + } + + /** + * Creates a Group + * + * @param group The gitlab Group object + * @param sudoUser The user to create the group on behalf of + * + * @return The GitLab Group + * @throws IOException on gitlab api call error + */ + public GitlabGroup createGroup(GitlabGroup group, GitlabUser sudoUser) throws IOException { + + Query query = new Query() + .append("name", group.getName()) + .append("path", group.getPath()) + .appendIf("description", group.getDescription()) + .appendIf("membership_lock", group.getMembershipLock()) + .appendIf("share_with_group_lock", group.getShareWithGroupLock()) + .appendIf("visibility", group.getVisibility().toString()) + .appendIf("lfs_enabled", group.isLfsEnabled()) + .appendIf("request_access_enabled", group.isRequestAccessEnabled()) + .appendIf("shared_runners_minutes_limit", group.getSharedRunnersMinutesLimit()) + .appendIf("ldap_cn", group.getLdapCn()) + .appendIf("ldap_access", group.getLdapAccess()) .appendIf(PARAM_SUDO, sudoUser != null ? sudoUser.getId() : null); String tailUrl = GitlabGroup.URL + query.toString(); @@ -501,6 +714,35 @@ public GitlabGroup createGroup(String name, String path, String ldapCn, GitlabAc return dispatch().to(tailUrl, GitlabGroup.class); } + /** + * Updates a Group + * + * @param group the group object + * @param sudoUser The user to create the group on behalf of + * @return The GitLab Group + * @throws IOException on gitlab api call error + */ + public GitlabGroup updateGroup(GitlabGroup group, GitlabUser sudoUser) throws IOException { + + Query query = new Query() + .appendIf("name", group.getName()) + .appendIf("path", group.getPath()) + .appendIf("description", group.getDescription()) + .appendIf("membership_lock", group.getMembershipLock()) + .appendIf("share_with_group_lock", group.getShareWithGroupLock()) + .appendIf("visibility", group.getVisibility().toString()) + .appendIf("lfs_enabled", group.isLfsEnabled()) + .appendIf("request_access_enabled", group.isRequestAccessEnabled()) + .appendIf("shared_runners_minutes_limit", group.getSharedRunnersMinutesLimit()) + .appendIf("ldap_cn", group.getLdapCn()) + .appendIf("ldap_access", group.getLdapAccess()) + .appendIf(PARAM_SUDO, sudoUser != null ? sudoUser.getId() : null); + + String tailUrl = GitlabGroup.URL + "/" + group.getId() + query.toString(); + + return retrieve().method(PUT).to(tailUrl, GitlabGroup.class); + } + /** * Add a group member. * @@ -552,7 +794,7 @@ public void deleteGroupMember(GitlabGroup group, GitlabUser user) throws IOExcep */ public void deleteGroupMember(Integer groupId, Integer userId) throws IOException { String tailUrl = GitlabGroup.URL + "/" + groupId + "/" + GitlabGroupMember.URL + "/" + userId; - retrieve().method("DELETE").to(tailUrl, Void.class); + retrieve().method(DELETE).to(tailUrl, Void.class); } /** @@ -563,128 +805,521 @@ public void deleteGroupMember(Integer groupId, Integer userId) throws IOExceptio */ public void deleteGroup(Integer groupId) throws IOException { String tailUrl = GitlabGroup.URL + "/" + groupId; - retrieve().method("DELETE").to(tailUrl, Void.class); + retrieve().method(DELETE).to(tailUrl, Void.class); + } + + /** + * Get's all projects in Gitlab, requires sudo user + * + * @return A list of gitlab projects + */ + public List getAllProjects() { + String tailUrl = GitlabProject.URL; + return retrieve().getAll(tailUrl, GitlabProject[].class); } + /** + * Get Project by project Id + * + * @param projectId - gitlab project Id + * @return {@link GitlabProject} + * @throws IOException on gitlab api call error + */ public GitlabProject getProject(Serializable projectId) throws IOException { String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId); return retrieve().to(tailUrl, GitlabProject.class); } /** + * use namespace & project name to get project + */ + public GitlabProject getProject(String namespace, String projectName) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeGroupId(namespace) + "%2F" + sanitizeProjectId(projectName); + return retrieve().to(tailUrl, GitlabProject.class); + } + + /* + * use project id to get Project JSON + */ + public String getProjectJson(Serializable projectId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId); + return retrieve().to(tailUrl, String.class); + } + + /* + * use namespace & project name to get project + */ + public String getProjectJson(String namespace, String projectName) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeGroupId(namespace) + "%2F" + sanitizeProjectId(projectName); + return retrieve().to(tailUrl, String.class); + } + + /** + * Get a list of projects accessible by the authenticated user. + * + * @return A list of gitlab projects + */ + public List getProjects() { + String tailUrl = GitlabProject.URL + PARAM_MAX_ITEMS_PER_PAGE; + return retrieve().getAll(tailUrl, GitlabProject[].class); + } + + /** + * Get a list of projects of size perPage accessible by the authenticated user. * + * @param page page offset. + * @param perPage number elements to get after page offset. + * @return A list of gitlab projects + * @throws IOException on Gitlab API call error + */ + public List getProjectsWithPagination(int page, int perPage) throws IOException { + Pagination pagination = new Pagination() + .withPage(page) + .withPerPage(perPage); + return getProjectsWithPagination(pagination); + } + + /** * Get a list of projects accessible by the authenticated user. * * @return A list of gitlab projects - * @throws IOException */ - public List getProjects() throws IOException { - String tailUrl = GitlabProject.URL; + public List getProjects(ProjectsQuery projectsQuery) { + String tailUrl = GitlabProject.URL + projectsQuery; return retrieve().getAll(tailUrl, GitlabProject[].class); } /** + * Get a list of projects by pagination accessible by the authenticated user. * + * @param pagination + * @return + * @throws IOException on gitlab api call error + */ + public List getProjectsWithPagination(Pagination pagination) throws IOException { + StringBuilder tailUrl = new StringBuilder(GitlabProject.URL); + + if (pagination != null) { + Query query = pagination.asQuery(); + tailUrl.append(query.toString()); + } + + return Arrays.asList(retrieve().method(GET).to(tailUrl.toString(), GitlabProject[].class)); + } + + /** * Get a list of projects owned by the authenticated user. * * @return A list of gitlab projects - * @throws IOException + * @throws IOException on gitlab api call error */ public List getOwnedProjects() throws IOException { - String tailUrl = GitlabProject.URL + "/owned"; + Query query = new Query().append("owned", "true"); + query.mergeWith(new Pagination().withPerPage(Pagination.MAX_ITEMS_PER_PAGE).asQuery()); + String tailUrl = GitlabProject.URL + query.toString(); return retrieve().getAll(tailUrl, GitlabProject[].class); } /** - * - * Get a list of projects accessible by the authenticated user. + * Get a list of projects that the authenticated user is a member of. * * @return A list of gitlab projects - * @throws IOException + * @throws IOException on gitlab api call error */ - public List getProjectsViaSudo(GitlabUser user) throws IOException { - Query query = new Query() - .appendIf(PARAM_SUDO, user.getId()); + public List getMembershipProjects() throws IOException { + Query query = new Query().append("membership", "true"); + query.mergeWith(new Pagination().withPerPage(Pagination.MAX_ITEMS_PER_PAGE).asQuery()); String tailUrl = GitlabProject.URL + query.toString(); return retrieve().getAll(tailUrl, GitlabProject[].class); } /** - * - * Get's all projects in Gitlab, requires sudo user + * Get a list of projects starred by the authenticated user. * * @return A list of gitlab projects - * @throws IOException + * @throws IOException on gitlab api call error */ - public List getAllProjects() throws IOException { - String tailUrl = GitlabProject.URL + "/all"; + public List getStarredProjects() throws IOException { + Query query = new Query().append("starred", "true"); + query.mergeWith(new Pagination().withPerPage(Pagination.MAX_ITEMS_PER_PAGE).asQuery()); + String tailUrl = GitlabProject.URL + query.toString(); return retrieve().getAll(tailUrl, GitlabProject[].class); } /** + * Get a list of projects accessible by the authenticated user. * - * Gets a list of a project's builds in Gitlab - * - * @param project the project - * @return A list of project builds - * @throws IOException + * @return A list of gitlab projects + * @throws IOException on gitlab api call error */ - public List getProjectBuilds(GitlabProject project) throws IOException { - return getProjectBuilds(project.getId()); + public List getProjectsViaSudo(GitlabUser user) throws IOException { + Query query = new Query() + .appendIf(PARAM_SUDO, user.getId()); + query.mergeWith(new Pagination().withPerPage(Pagination.MAX_ITEMS_PER_PAGE).asQuery()); + String tailUrl = GitlabProject.URL + query.toString(); + return retrieve().getAll(tailUrl, GitlabProject[].class); } /** + * Get a list of projects of perPage elements accessible by the authenticated user given page offset * - * Gets a list of a project's builds in Gitlab - * - * @param projectId the project id - * @return A list of project builds - * @throws IOException + * @param user Gitlab User to invoke sudo with + * @param page Page offset + * @param perPage Number of elements to get after page offset + * @return A list of gitlab projects + * @throws IOException Gitlab API call error */ - public List getProjectBuilds(Integer projectId) throws IOException { - String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabBuild.URL; - return retrieve().getAll(tailUrl, GitlabBuild[].class); + public List getProjectsViaSudoWithPagination(GitlabUser user, int page, int perPage) throws IOException { + Pagination pagination = new Pagination() + .withPage(page) + .withPerPage(perPage); + return getProjectsViaSudoWithPagination(user, pagination); } /** + * Get a list of projects of with Pagination. * - * Gets a build for a project - * - * @param projectId the project id - * @param buildId the build id - * @return A list of project builds - * @throws IOException + * @param user Gitlab User to invoke sudo with + * @param pagination + * @return A list of gitlab projects + * @throws IOException Gitlab API call error */ - public GitlabBuild getProjectBuild(Integer projectId, Integer buildId) throws IOException { - String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabBuild.URL + "/" + buildId; - return retrieve().to(tailUrl, GitlabBuild.class); + public List getProjectsViaSudoWithPagination(GitlabUser user, Pagination pagination) throws IOException { + StringBuilder tailUrl = new StringBuilder(GitlabProject.URL); + + Query query = new Query() + .appendIf(PARAM_SUDO, user.getId()); + + if (pagination != null) { + query.mergeWith(pagination.asQuery()); + } + + tailUrl.append(query.toString()); + return Arrays.asList(retrieve().method(GET).to(tailUrl.toString(), GitlabProject[].class)); } /** - * Get build artifacts of a project build + * Get a list of the namespaces of the authenticated user. + * If the user is an administrator, a list of all namespaces in the GitLab instance is shown. * - * @param project The Project - * @param build The build - * @throws IOException on gitlab api call error + * @return A list of gitlab namespace */ - public byte[] getBuildArtifact(GitlabProject project, GitlabBuild build) throws IOException { - return getBuildArtifact(project.getId(), build.getId()); + public List getNamespaces() { + String tailUrl = GitlabNamespace.URL + PARAM_MAX_ITEMS_PER_PAGE; + return retrieve().getAll(tailUrl, GitlabNamespace[].class); } /** - * Get build artifacts of a project build + * Uploads a file to a project * - * @param projectId The Project's Id - * @param buildId The build's Id + * @param project + * @param file + * @return * @throws IOException on gitlab api call error */ - public byte[] getBuildArtifact(Integer projectId, Integer buildId) throws IOException { - String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabBuild.URL + "/" + buildId + "/artifacts"; - return retrieve().to(tailUrl, byte[].class); + public GitlabUpload uploadFile(GitlabProject project, File file) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(project.getId()) + GitlabUpload.URL; + return dispatch().withAttachment("file", file).to(tailUrl, GitlabUpload.class); } /** - * Creates a private Project + * Get a project's pipeline + * + * @param project the project + * @param pipeline the pipeline + * @return The project pipeline + */ + public GitlabPipeline getProjectPipeline(GitlabProject project, GitlabPipeline pipeline) throws IOException { + return getProjectPipeline(project.getId(), pipeline.getId()); + } + + /** + * Get a project's pipeline + * + * @param projectId the project id + * @param pipelineId the pipeline id + * @return The project pipeline + */ + public GitlabPipeline getProjectPipeline(Integer projectId, Integer pipelineId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabPipeline.URL + "/" + sanitizeId(pipelineId, "pipelineId"); + return retrieve().to(tailUrl, GitlabPipeline.class); + } + + /** + * Get a list of a project's pipelines in Gitlab + * + * @param project the project + * @return A list of project pipelines + */ + public List getProjectPipelines(GitlabProject project) { + return getProjectPipelines(project.getId()); + } + + /** + * Get a list of a project's pipelines in Gitlab + * + * @param projectId the project id + * @return A list of project pipelines + */ + public List getProjectPipelines(Integer projectId) { + return getProjectPipelines(projectId, new PipelinesQuery().withPerPage(PaginationQuery.MAX_ITEMS_PER_PAGE)); + } + + /** + * Get a list of a project's pipelines in Gitlab + * + * @param project the project + * @return A list of project pipelines + */ + public List getProjectPipelines(GitlabProject project, PipelinesQuery pipelinesQuery) { + return getProjectPipelines(project.getId(), pipelinesQuery); + } + + /** + * Get a list of a project's pipelines in Gitlab + * + * @param projectId the project id + * @return A list of project pipelines + */ + public List getProjectPipelines(Integer projectId, PipelinesQuery pipelinesQuery) { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabPipeline.URL + pipelinesQuery; + return retrieve().getAll(tailUrl, GitlabPipeline[].class); + } + + /** + * Gets a list of a project's jobs in Gitlab + * + * @param project the project + * @return A list of project jobs + */ + public List getProjectJobs(GitlabProject project) { + return getProjectJobs(project.getId()); + } + + /** + * Gets a list of a project's jobs in Gitlab + * + * @param projectId the project id + * @return A list of project jobs + */ + public List getProjectJobs(Integer projectId) { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabJob.URL + PARAM_MAX_ITEMS_PER_PAGE; + return retrieve().getAll(tailUrl, GitlabJob[].class); + } + + + /** + * Run pipeline for selected project and branch + * @param project project + * @param ref branch + * @param variables pipeline variables + * @return Created pipeline + * @throws IOException + */ + public GitlabPipeline runPipeline(GitlabProject project, String ref, List variables) throws IOException { + return runPipeline(project.getId(), ref, variables); + } + + + /** + * Run pipeline for selected project and branch + * @param projectId project's id + * @param ref branch + * @param variables pipeline variables + * @return Created pipeline + * @throws IOException + */ + public GitlabPipeline runPipeline(Integer projectId, String ref, List variables) throws IOException { + Query query = new Query().appendIf("ref", ref); + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabPipeline.CREATE_URL + query.toString(); + return dispatch().with("variables", variables).to(tailUrl, GitlabPipeline.class); + } + + /** + * Gets a list of project's jobs of the given pipeline in Gitlab + * + * @param project the project + * @param pipelineId + * @return A list of project jobs + */ + public List getPipelineJobs(GitlabProject project, Integer pipelineId) { + return getPipelineJobs(project.getId(), pipelineId); + } + + /** + * Gets a list of project's jobs of the given pipeline in Gitlab + * + * @param projectId + * @param pipelineId + * @return A list of project jobs + */ + public List getPipelineJobs(Integer projectId, Integer pipelineId) { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabPipeline.URL + "/" + sanitizeId(pipelineId, "PipelineID") + GitlabJob.URL + PARAM_MAX_ITEMS_PER_PAGE; + return retrieve().getAll(tailUrl, GitlabJob[].class); + } + + + /** + * Cancel a single job of a project + * + * @param projectId + * @param jobId + * @return + * @throws IOException on gitlab api call error + */ + public GitlabJob cancelJob(Integer projectId, Integer jobId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabJob.URL + "/" + sanitizeId(jobId, "JobID") + "/cancel"; + return dispatch().to(tailUrl, GitlabJob.class); + } + + /** + * Retry a single job of a project + * + * @param projectId + * @param jobId + * @return + * @throws IOException on gitlab api call error + */ + public GitlabJob retryJob(Integer projectId, Integer jobId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabJob.URL + "/" + sanitizeId(jobId, "JobID") + "/retry"; + return dispatch().to(tailUrl, GitlabJob.class); + } + + /** + * Erase a single job of a project (remove job artifacts and a job trace) + * + * @param projectId + * @param jobId + * @return + * @throws IOException on gitlab api call error + */ + public GitlabJob eraseJob(Integer projectId, Integer jobId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabJob.URL + "/" + sanitizeId(jobId, "JobID") + "/erase"; + return dispatch().to(tailUrl, GitlabJob.class); + } + + + /** + * Triggers a manual action to start a job. + * + * @param projectId + * @param jobId + * @return + * @throws IOException on gitlab api call error + */ + public GitlabJob playJob(Integer projectId, Integer jobId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabJob.URL + "/" + sanitizeId(jobId, "JobID") + "/play"; + return dispatch().to(tailUrl, GitlabJob.class); + } + + + /** + * Gets a build for a project + * + * @param projectId the project id + * @param jobId the build id + * @return A list of project jobs + * @throws IOException on gitlab api call error + */ + public GitlabJob getProjectJob(Integer projectId, Integer jobId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabJob.URL + "/" + jobId; + return retrieve().to(tailUrl, GitlabJob.class); + } + + /** + * Get build artifacts of a project build + * + * @param project The Project + * @param job The build + * @throws IOException on gitlab api call error + */ + public byte[] getJobArtifact(GitlabProject project, GitlabJob job) throws IOException { + return getJobArtifact(project.getId(), job.getId()); + } + + /** + * Get build artifacts of a project build + * + * @param projectId The Project's Id + * @param jobId The build's Id + * @throws IOException on gitlab api call error + */ + public byte[] getJobArtifact(Integer projectId, Integer jobId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabJob.URL + "/" + jobId + "/artifacts"; + return retrieve().to(tailUrl, byte[].class); + } + + /** + * Get build trace of a project build + * + * @param project The Project + * @param job The build + * @throws IOException on gitlab api call error + */ + public byte[] getJobTrace(GitlabProject project, GitlabJob job) throws IOException { + return getJobArtifact(project.getId(), job.getId()); + } + + /** + * Get build trace of a project build + * + * @param projectId The Project's Id + * @param jobId The build's Id + * @throws IOException on gitlab api call error + */ + public byte[] getJobTrace(Integer projectId, Integer jobId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabJob.URL + "/" + jobId + "/trace"; + return retrieve().to(tailUrl, byte[].class); + } + + /** + * Creates a Project + * + * @param project The project to create + * @return The GitLab Project + * @throws IOException on gitlab api call error + */ + public GitlabProject createProject(GitlabProject project) throws IOException { + Query query = new Query() + .appendIf("name", project.getName()) + .appendIf("path", project.getPath()) + .appendIf("default_branch", project.getDefaultBranch()) + .appendIf("description", project.getDescription()) + .appendIf("issues_enabled", project.isIssuesEnabled()) + .appendIf("merge_requests_enabled", project.isMergeRequestsEnabled()) + .appendIf("jobs_enabled", project.isJobsEnabled()) + .appendIf("wiki_enabled", project.isWikiEnabled()) + .appendIf("snippets_enabled", project.isSnippetsEnabled()) + + .appendIf("container_registry_enabled", project.isContainerRegistryEnabled()) + .appendIf("shared_runners_enabled", project.isSharedRunnersEnabled()) + + .appendIf("visibility", project.getVisibility()) + .appendIf("public_jobs", project.hasPublicJobs()) + .appendIf("import_url", project.getImportUrl()) + + .appendIf("only_allow_merge_if_pipeline_succeeds", project.getOnlyAllowMergeIfPipelineSucceeds()) + .appendIf("only_allow_merge_if_all_discussions_are_resolved", project.getOnlyAllowMergeIfAllDiscussionsAreResolved()) + .appendIf("lfs_enabled", project.isLfsEnabled()) + .appendIf("request_access_enabled", project.isRequestAccessEnabled()) + .appendIf("repository_storage", project.getRepositoryStorage()) + .appendIf("approvals_before_merge", project.getApprovalsBeforeMerge()) + .appendIf("printing_merge_request_link_enabled", project.isPrintingMergeRequestLinkEnabled()) + .appendIf("initialize_with_readme",project.isInitializeWithReadme()); + + GitlabNamespace namespace = project.getNamespace(); + if (namespace != null) { + query.appendIf("namespace_id", namespace.getId()); + } + + + String tailUrl = GitlabProject.URL + query.toString(); + + return dispatch().to(tailUrl, GitlabProject.class); + } + + /** + * Creates a private Project * * @param name The name of the project * @return The GitLab Project @@ -694,6 +1329,45 @@ public GitlabProject createProject(String name) throws IOException { return createProject(name, null, null, null, null, null, null, null, null, null, null); } + /** + * Creates a group Project + * + * @param name The name of the project + * @param group The group for which the project should be crated + * @return The GitLab Project + * @throws IOException on gitlab api call error + */ + public GitlabProject createProjectForGroup(String name, GitlabGroup group) throws IOException { + return createProjectForGroup(name, group, null); + } + + /** + * Creates a group Project + * + * @param name The name of the project + * @param group The group for which the project should be crated + * @param description The project description + * @return The GitLab Project + * @throws IOException on gitlab api call error + */ + public GitlabProject createProjectForGroup(String name, GitlabGroup group, String description) throws IOException { + return createProjectForGroup(name, group, description, null); + } + + /** + * Creates a group Project + * + * @param name The name of the project + * @param group The group for which the project should be crated + * @param description The project description + * @param visibility The project visibility level (private: 0, internal: 10, public: 20) + * @return The GitLab Project + * @throws IOException on gitlab api call error + */ + public GitlabProject createProjectForGroup(String name, GitlabGroup group, String description, String visibility) throws IOException { + return createProject(name, group.getId(), description, null, null, null, null, null, null, visibility, null); + } + /** * Creates a Project * @@ -705,14 +1379,13 @@ public GitlabProject createProject(String name) throws IOException { * @param mergeRequestsEnabled Whether Merge Requests should be enabled, otherwise null indicates to use GitLab default * @param wikiEnabled Whether a Wiki should be enabled, otherwise null indicates to use GitLab default * @param snippetsEnabled Whether Snippets should be enabled, otherwise null indicates to use GitLab default - * @param publik Whether the project is public or private, if true same as setting visibilityLevel = 20, otherwise null indicates to use GitLab default - * @param visibilityLevel The visibility level of the project, otherwise null indicates to use GitLab default + * @param visibility The visibility level of the project, otherwise null indicates to use GitLab default * @param importUrl The Import URL for the project, otherwise null * @return the Gitlab Project * @throws IOException on gitlab api call error */ @Deprecated - public GitlabProject createProject(String name, Integer namespaceId, String description, Boolean issuesEnabled, Boolean wallEnabled, Boolean mergeRequestsEnabled, Boolean wikiEnabled, Boolean snippetsEnabled, Boolean publik, Integer visibilityLevel, String importUrl) throws IOException { + public GitlabProject createProject(String name, Integer namespaceId, String description, Boolean issuesEnabled, Boolean wallEnabled, Boolean mergeRequestsEnabled, Boolean wikiEnabled, Boolean snippetsEnabled, Boolean publik, String visibility, String importUrl) throws IOException { Query query = new Query() .append("name", name) .appendIf("namespace_id", namespaceId) @@ -722,8 +1395,7 @@ public GitlabProject createProject(String name, Integer namespaceId, String desc .appendIf("merge_requests_enabled", mergeRequestsEnabled) .appendIf("wiki_enabled", wikiEnabled) .appendIf("snippets_enabled", snippetsEnabled) - .appendIf("public", publik) - .appendIf("visibility_level", visibilityLevel) + .appendIf("visibility", visibility) .appendIf("import_url", importUrl); String tailUrl = GitlabProject.URL + query.toString(); @@ -740,7 +1412,7 @@ public GitlabProject createProject(String name, Integer namespaceId, String desc * @throws IOException on gitlab api call error */ public GitlabProject createUserProject(Integer userId, String name) throws IOException { - return createUserProject(userId, name, null, null, null, null, null, null, null, null, null, null); + return createUserProject(userId, name, null, null, null, null, null, null, null, null, null); } /** @@ -755,14 +1427,13 @@ public GitlabProject createUserProject(Integer userId, String name) throws IOExc * @param mergeRequestsEnabled Whether Merge Requests should be enabled, otherwise null indicates to use GitLab default * @param wikiEnabled Whether a Wiki should be enabled, otherwise null indicates to use GitLab default * @param snippetsEnabled Whether Snippets should be enabled, otherwise null indicates to use GitLab default - * @param publik Whether the project is public or private, if true same as setting visibilityLevel = 20, otherwise null indicates to use GitLab default - * @param visibilityLevel The visibility level of the project, otherwise null indicates to use GitLab default + * @param visibility The visibility level of the project, otherwise null indicates to use GitLab default * @param importUrl The Import URL for the project, otherwise null * @return The GitLab Project * @throws IOException on gitlab api call error */ @Deprecated - public GitlabProject createUserProject(Integer userId, String name, String description, String defaultBranch, Boolean issuesEnabled, Boolean wallEnabled, Boolean mergeRequestsEnabled, Boolean wikiEnabled, Boolean snippetsEnabled, Boolean publik, Integer visibilityLevel, String importUrl) throws IOException { + public GitlabProject createUserProject(Integer userId, String name, String description, String defaultBranch, Boolean issuesEnabled, Boolean wallEnabled, Boolean mergeRequestsEnabled, Boolean wikiEnabled, Boolean snippetsEnabled, String visibility, String importUrl) throws IOException { Query query = new Query() .append("name", name) .appendIf("description", description) @@ -772,8 +1443,7 @@ public GitlabProject createUserProject(Integer userId, String name, String descr .appendIf("merge_requests_enabled", mergeRequestsEnabled) .appendIf("wiki_enabled", wikiEnabled) .appendIf("snippets_enabled", snippetsEnabled) - .appendIf("public", publik) - .appendIf("visibility_level", visibilityLevel) + .appendIf("visibility", visibility) .appendIf("import_url", importUrl); String tailUrl = GitlabProject.URL + "/user/" + userId + query.toString(); @@ -781,6 +1451,43 @@ public GitlabProject createUserProject(Integer userId, String name, String descr return dispatch().to(tailUrl, GitlabProject.class); } + /** + * @param namespace The namespace of the fork + * @param projectId ProjectId of the project forked + * @param path The path that will be assigned to the resultant project after forking. (Optional) + * @param name The name that will be assigned to the resultant project after forking. (Optional) + * @return The new Gitlab Project + * @throws IOException on gitlab api call error + */ + public GitlabProject createFork(String namespace, Integer projectId, String path, String name) throws IOException { + Query query = new Query() + .appendIf("namespace", namespace) + .appendIf("path", path) + .appendIf("name", name); + String tailUrl = GitlabProject.URL + "/" + projectId + "/fork" + query.toString(); + return dispatch().to(tailUrl, GitlabProject.class); + } + + /** + * @param namespace The namespace of the fork + * @param projectId ProjectId of the project forked + * @return The new Gitlab Project + * @throws IOException on gitlab api call error + */ + public GitlabProject createFork(String namespace, Integer projectId) throws IOException { + return createFork(namespace, projectId, null, null); + } + + /** + * @param namespace The namespace of the fork + * @param gitlabProject The project forked + * @return The new Gitlab Project + * @throws IOException on gitlab api call error + */ + public GitlabProject createFork(String namespace, GitlabProject gitlabProject) throws IOException { + return createFork(namespace, gitlabProject.getId()); + } + /** * Updates a Project * @@ -793,26 +1500,23 @@ public GitlabProject createUserProject(Integer userId, String name, String descr * @param mergeRequestsEnabled Whether Merge Requests should be enabled, otherwise null indicates to use GitLab default * @param wikiEnabled Whether a Wiki should be enabled, otherwise null indicates to use GitLab default * @param snippetsEnabled Whether Snippets should be enabled, otherwise null indicates to use GitLab default - * @param publik Whether the project is public or private, if true same as setting visibilityLevel = 20, otherwise null indicates to use GitLab default - * @param visibilityLevel The visibility level of the project, otherwise null indicates to use GitLab default + * @param visibility The visibility level of the project, otherwise null indicates to use GitLab default * @return the Gitlab Project * @throws IOException on gitlab api call error */ @Deprecated public GitlabProject updateProject( Integer projectId, - String name, - String description, - String defaultBranch, + String name, + String description, + String defaultBranch, Boolean issuesEnabled, Boolean wallEnabled, Boolean mergeRequestsEnabled, Boolean wikiEnabled, Boolean snippetsEnabled, - Boolean publik, - Integer visibilityLevel) - throws IOException - { + String visibility) + throws IOException { Query query = new Query() .appendIf("name", name) .appendIf("description", description) @@ -822,12 +1526,11 @@ public GitlabProject updateProject( .appendIf("merge_requests_enabled", mergeRequestsEnabled) .appendIf("wiki_enabled", wikiEnabled) .appendIf("snippets_enabled", snippetsEnabled) - .appendIf("public", publik) - .appendIf("visibility_level", visibilityLevel); + .appendIf("visibility", visibility); String tailUrl = GitlabProject.URL + "/" + projectId + query.toString(); - return retrieve().method("PUT").to(tailUrl, GitlabProject.class); + return retrieve().method(PUT).to(tailUrl, GitlabProject.class); } /** @@ -838,71 +1541,202 @@ public GitlabProject updateProject( */ public void deleteProject(Serializable projectId) throws IOException { String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId); - retrieve().method("DELETE").to(tailUrl, null); + retrieve().method(DELETE).to(tailUrl, null); } public List getOpenMergeRequests(Serializable projectId) throws IOException { - String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabMergeRequest.URL + "?state=opened"; - return retrieve().getAll(tailUrl, GitlabMergeRequest[].class); + return getMergeRequestsWithStatus(projectId, GitlabMergeRequest.STATUS_OPENED); + } + + public List getOpenMergeRequests(Serializable projectId, Pagination pagination) throws IOException { + return getMergeRequestsWithStatus(projectId, GitlabMergeRequest.STATUS_OPENED, pagination); } public List getOpenMergeRequests(GitlabProject project) throws IOException { - String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabMergeRequest.URL + "?state=opened"; + return getMergeRequestsWithStatus(project, GitlabMergeRequest.STATUS_OPENED); + } + + public List getOpenMergeRequests(GitlabProject project, Pagination pagination) throws IOException { + return getMergeRequestsWithStatus(project, GitlabMergeRequest.STATUS_OPENED, pagination); + } + + public List getMergedMergeRequests(Serializable projectId) throws IOException { + return getMergeRequestsWithStatus(projectId, GitlabMergeRequest.STATUS_MERGED); + } + + public List getMergedMergeRequests(Serializable projectId, Pagination pagination) throws IOException { + return getMergeRequestsWithStatus(projectId, GitlabMergeRequest.STATUS_MERGED, pagination); + } + + public List getMergedMergeRequests(GitlabProject project) throws IOException { + return getMergeRequestsWithStatus(project, GitlabMergeRequest.STATUS_MERGED); + } + + public List getMergedMergeRequests(GitlabProject project, Pagination pagination) throws IOException { + return getMergeRequestsWithStatus(project, GitlabMergeRequest.STATUS_MERGED, pagination); + } + + public List getClosedMergeRequests(Serializable projectId) throws IOException { + return getMergeRequestsWithStatus(projectId, GitlabMergeRequest.STATUS_CLOSED); + } + + public List getClosedMergeRequests(Serializable projectId, Pagination pagination) throws IOException { + return getMergeRequestsWithStatus(projectId, GitlabMergeRequest.STATUS_CLOSED, pagination); + } + + public List getClosedMergeRequests(GitlabProject project) throws IOException { + return getMergeRequestsWithStatus(project, GitlabMergeRequest.STATUS_CLOSED); + } + + public List getClosedMergeRequests(GitlabProject project, Pagination pagination) throws IOException { + return getMergeRequestsWithStatus(project, GitlabMergeRequest.STATUS_CLOSED, pagination); + } + + public List getMergeRequestsWithStatus(Serializable projectId, String status) throws IOException { + return getMergeRequestsWithStatus(projectId, status, new Pagination().withPerPage(Pagination.MAX_ITEMS_PER_PAGE)); + } + + public List getMergeRequestsWithStatus(Serializable projectId, String state, Pagination pagination) throws IOException { + Query query = pagination.asQuery(); + query.append("state", state); + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabMergeRequest.URL + query; return retrieve().getAll(tailUrl, GitlabMergeRequest[].class); } - public List getMergeRequests(Serializable projectId) throws IOException { - String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabMergeRequest.URL; + public List getMergeRequestsWithStatus(GitlabProject project, String status) throws IOException { + return getMergeRequestsWithStatus(project, status, new Pagination().withPerPage(Pagination.MAX_ITEMS_PER_PAGE)); + } + + public List getMergeRequestsWithStatus(GitlabProject project, String state, Pagination pagination) throws IOException { + Query query = pagination.asQuery(); + query.append("state", state); + String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabMergeRequest.URL + query; return retrieve().getAll(tailUrl, GitlabMergeRequest[].class); } - public List getMergeRequests(GitlabProject project) throws IOException { - String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabMergeRequest.URL; + public List getMergeRequests(Serializable projectId) { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabMergeRequest.URL + PARAM_MAX_ITEMS_PER_PAGE; return retrieve().getAll(tailUrl, GitlabMergeRequest[].class); } - public List getAllMergeRequests(GitlabProject project) throws IOException { + public List getMergeRequests(Serializable projectId, Pagination pagination) { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabMergeRequest.URL + pagination.toString(); + return retrieve().getAll(tailUrl, GitlabMergeRequest[].class); + } + + public List getMergeRequests(GitlabProject project) { + String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabMergeRequest.URL + PARAM_MAX_ITEMS_PER_PAGE; + return retrieve().getAll(tailUrl, GitlabMergeRequest[].class); + } + + public List getMergeRequests(GitlabProject project, Pagination pagination) { + String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabMergeRequest.URL + pagination.toString(); + return retrieve().getAll(tailUrl, GitlabMergeRequest[].class); + } + + public List getAllMergeRequests(GitlabProject project) { String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabMergeRequest.URL; return retrieve().getAll(tailUrl, GitlabMergeRequest[].class); } + /** + * Get information about the approvals present and required for a merge request + * EE only. + */ + public GitlabMergeRequestApprovals getMergeRequestApprovals(GitlabMergeRequest mr) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(mr.getProjectId()) + + GitlabMergeRequest.URL + "/" + mr.getIid() + GitlabMergeRequestApprovals.URL; + return retrieve().to(tailUrl, GitlabMergeRequestApprovals.class); + } + + /** + * Set the number of required approvers. + * + * EE only. + */ + public GitlabMergeRequestApprovals setMergeRequestApprovals(GitlabMergeRequest mr, int count) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(mr.getProjectId()) + + GitlabMergeRequest.URL + "/" + mr.getIid() + GitlabMergeRequestApprovals.URL; + return dispatch() + .with("approvals_required", count) + .to(tailUrl, GitlabMergeRequestApprovals.class); + } + + /** + * Set the list of approvers. Important: Approvers and groups not + * in the request will be removed + * + * EE only. + */ + public GitlabMergeRequestApprovals setMergeRequestApprovers(GitlabMergeRequest mr, + Collection userApproverIds, + Collection groupApproverIds) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(mr.getProjectId()) + + GitlabMergeRequest.URL + "/" + mr.getIid() + GitlabMergeRequestApprovals.APPROVERS_URL; + return put() + .with("approver_ids", userApproverIds) + .with("approver_group_ids", groupApproverIds) + .to(tailUrl, GitlabMergeRequestApprovals.class); + } + + /** + * Cherry picks a commit. + * + * @param projectId The id of the project + * @param sha The sha of the commit + * @param targetBranchName The branch on which the commit must be cherry-picked + * @return the commit of the cherry-pick. + * @throws IOException on gitlab api call error + */ + public GitlabCommit cherryPick(Serializable projectId, String sha, String targetBranchName) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + "/repository/commits/" + sha + "/cherry_pick"; + return retrieve().with("branch", targetBranchName).to(tailUrl, GitlabCommit.class); + } + + public GitlabCommit cherryPick(GitlabProject project, String sha, String targetBranchName) throws IOException { + String tailUrl = GitlabProject.URL + "/" + project.getId() + "/repository/commits/" + sha + "/cherry_pick"; + return dispatch().with("branch", targetBranchName).to(tailUrl, GitlabCommit.class); + } + /** * Return Merge Request. * * @param projectId The id of the project - * @param mergeRequestIid The iid of the merge request + * @param mergeRequestIid The internal id of the merge request * @return the Gitlab Merge Request * @throws IOException on gitlab api call error */ public GitlabMergeRequest getMergeRequestByIid(Serializable projectId, Integer mergeRequestIid) throws IOException { - Query query = new Query() - .append("iid", mergeRequestIid.toString()); - String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabMergeRequest.URL + query.toString(); - List ls = retrieve().getAll(tailUrl, GitlabMergeRequest[].class); - if (ls.size() == 0) { - throw new FileNotFoundException(); - } - return ls.get(0); + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabMergeRequest.URL + "/" + mergeRequestIid; + return retrieve().to(tailUrl, GitlabMergeRequest.class); } /** * Return a Merge Request including its changes. * * @param projectId The id of the project - * @param mergeRequestId The id of the merge request + * @param mergeRequestIid The internal id of the merge request * @return the Gitlab Merge Request * @throws IOException on gitlab api call error */ - public GitlabMergeRequest getMergeRequestChanges(Serializable projectId, Integer mergeRequestId) throws IOException { - String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + "/merge_request/" + mergeRequestId + "/changes"; + public GitlabMergeRequest getMergeRequestChanges(Serializable projectId, + Integer mergeRequestIid) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + + GitlabMergeRequest.URL + "/" + mergeRequestIid + "/changes"; return retrieve().to(tailUrl, GitlabMergeRequest.class); } - public GitlabMergeRequest getMergeRequest(GitlabProject project, Integer mergeRequestId) throws IOException { - String tailUrl = GitlabProject.URL + "/" + project.getId() + "/merge_request/" + mergeRequestId; + public GitlabMergeRequest getMergeRequest(Serializable projectId, + Integer mergeRequestIid) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + + GitlabMergeRequest.URL + "/" + mergeRequestIid; return retrieve().to(tailUrl, GitlabMergeRequest.class); } + public GitlabMergeRequest getMergeRequest(GitlabProject project, + Integer mergeRequestIid) throws IOException { + return getMergeRequest(project.getId(), mergeRequestIid); + } /** * Create a new MergeRequest @@ -930,85 +1764,348 @@ public GitlabMergeRequest createMergeRequest(Serializable projectId, String sour } + /** + * Updates a Merge Request + * + * @param projectId The id of the project + * @param mergeRequestIid The internal id of the merge request to update + * @param targetBranch The target branch of the merge request, otherwise null to leave it untouched + * @param assigneeId The id of the assignee, otherwise null to leave it untouched + * @param title The title of the merge request, otherwise null to leave it untouched + * @param description The description of the merge request, otherwise null to leave it untouched + * @param stateEvent The state (close|reopen|merge) of the merge request, otherwise null to leave it untouched + * @param labels A comma separated list of labels, otherwise null to leave it untouched + * @return the Merge Request + * @throws IOException on gitlab api call error + */ + public GitlabMergeRequest updateMergeRequest(Serializable projectId, Integer mergeRequestIid, String targetBranch, + Integer assigneeId, String title, String description, String stateEvent, + String labels) throws IOException { + Query query = new Query() + .appendIf("target_branch", targetBranch) + .appendIf("assignee_id", assigneeId) + .appendIf("title", title) + .appendIf("description", description) + .appendIf("state_event", stateEvent) + .appendIf("labels", labels); + + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + + GitlabMergeRequest.URL + "/" + mergeRequestIid + query.toString(); + + return retrieve().method(PUT).to(tailUrl, GitlabMergeRequest.class); + } + + /** + * @param project The Project + * @param mergeRequestIid Merge Request internal ID + * @param mergeCommitMessage optional merge commit message. Null if not set + * @return new merge request status + * @throws IOException on gitlab api call error + */ + public GitlabMergeRequest acceptMergeRequest(GitlabProject project, Integer mergeRequestIid, String mergeCommitMessage) throws IOException { + return acceptMergeRequest(project.getId(), mergeRequestIid, mergeCommitMessage); + } + + public GitlabMergeRequest acceptMergeRequest(Serializable projectId, Integer mergeRequestIid, String mergeCommitMessage) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + + GitlabMergeRequest.URL + "/" + mergeRequestIid + "/merge"; + GitlabHTTPRequestor requestor = retrieve().method(PUT); + requestor.with("id", projectId); + requestor.with("merge_request_iid", mergeRequestIid); + if (mergeCommitMessage != null) + requestor.with("merge_commit_message", mergeCommitMessage); + return requestor.to(tailUrl, GitlabMergeRequest.class); + } + + /** + * Get a Note from a Merge Request. + * + * @param mergeRequest The merge request + * @param noteId The id of the note + * @return the Gitlab Note + * @throws IOException on gitlab api call error + */ + public GitlabNote getNote(GitlabMergeRequest mergeRequest, + Integer noteId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + + GitlabNote.URL + "/" + noteId; + + return retrieve().to(tailUrl, GitlabNote.class); + } + + public List getNotes(GitlabMergeRequest mergeRequest) throws IOException { + String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + + GitlabNote.URL; + + GitlabNote[] notes = retrieve().to(tailUrl, GitlabNote[].class); + return Arrays.asList(notes); + } + + public List getAllNotes(GitlabMergeRequest mergeRequest) { + String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + + GitlabNote.URL + PARAM_MAX_ITEMS_PER_PAGE; + + return retrieve().getAll(tailUrl, GitlabNote[].class); + } + + /** + * Get a discussion by id from a merge request. + * https://docs.gitlab.com/ce/api/discussions.html#get-single-merge-request-discussion + * + * @param mergeRequest to fetch the discussion from. + * @param discussionId The id of the discussion. + * + * @return The GitLab discussion identified by the given id. + * @throws IOException on a GitLab api call error + */ + public GitlabDiscussion getDiscussion(GitlabMergeRequest mergeRequest, + int discussionId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + + GitlabDiscussion.URL + "/" + discussionId; + return retrieve().to(tailUrl, GitlabDiscussion.class); + } + + /** + * Get the discussions from a merge request. + * https://docs.gitlab.com/ce/api/discussions.html#list-project-merge-request-discussions + * + * @param mergeRequest to fetch the discussions from. + * + * @return The discussions contained in the given merge request. + * @throws IOException on a GitLab api call error + */ + public List getDiscussions(GitlabMergeRequest mergeRequest) throws IOException { + String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + + GitlabDiscussion.URL; + + GitlabDiscussion[] discussions = retrieve().to(tailUrl, GitlabDiscussion[].class); + return Arrays.asList(discussions); + } + + /** + * Create a discussion just with the required arguments. + * + * @param mergeRequest The merge request where the discussion is created. + * @param body The content of a discussion. + * @param positionBaseSha The base commit SHA in the source branch. + * @param positionStartSha The SHA referencing the commit in the target branch. + * @param positionHeadSha The SHA referencing the HEAD of this merge request. + * + * @return The created discussion object. + * @throws IOException on a GitLab api call error + */ + public GitlabDiscussion createDiscussion(GitlabMergeRequest mergeRequest, + String body, String positionBaseSha, String positionStartSha, + String positionHeadSha) throws IOException { + return createTextDiscussion(mergeRequest, body, null, + positionBaseSha, positionStartSha, positionHeadSha, + null, null, null, null); + } + + /** + * Create a new discussion with position type text on the given merge request. + * https://docs.gitlab.com/ce/api/discussions.html#create-new-merge-request-discussion + * + * @param mergeRequest The merge request where the discussion is created. + * @param body The content of a discussion. + * @param position The position when creating a diff note. (hash) + * @param positionBaseSha The base commit SHA in the source branch. + * @param positionStartSha The SHA referencing the commit in the target branch. + * @param positionHeadSha The SHA referencing the HEAD of this merge request. + * @param positionNewPath The file path after the change. + * @param positionNewLine The Line number after change + * @param positionOldPath The file path before the change. + * @param positionOldLine The Line number before change. + * + * @return The created discussion object. + * @throws IOException on a GitLab api call error + */ + public GitlabDiscussion createTextDiscussion(GitlabMergeRequest mergeRequest, + String body, String position, String positionBaseSha, String positionStartSha, + String positionHeadSha, String positionNewPath, Integer positionNewLine, + String positionOldPath, Integer positionOldLine) throws IOException { + checkRequiredCreateDiscussionArguments(body, positionBaseSha, positionStartSha, positionHeadSha); + Query query = new Query() + .append("body", body) + .appendIf("position", position) + .append("position[base_sha]", positionBaseSha) + .append("position[start_sha]", positionStartSha) + .append("position[head_sha]", positionHeadSha) + .append("position[position_type]", "text") + .appendIf("position[new_path]", positionNewPath) + .appendIf("position[new_line]", positionNewLine) + .appendIf("position[old_path]", positionOldPath) + .appendIf("position[old_line]", positionOldLine); + + String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + + GitlabDiscussion.URL + query.toString(); + + return dispatch().to(tailUrl, GitlabDiscussion.class); + } /** - * Updates a Merge Request + * Create a new discussion with position type image on the given merge request. + * https://docs.gitlab.com/ce/api/discussions.html#create-new-merge-request-discussion * - * @param projectId The id of the project - * @param mergeRequestId The id of the merge request to update - * @param targetBranch The target branch of the merge request, otherwise null to leave it untouched - * @param assigneeId The id of the assignee, otherwise null to leave it untouched - * @param title The title of the merge request, otherwise null to leave it untouched - * @param description The description of the merge request, otherwise null to leave it untouched - * @param stateEvent The state (close|reopen|merge) of the merge request, otherwise null to leave it untouched - * @param labels A comma separated list of labels, otherwise null to leave it untouched - * @return the Merge Request - * @throws IOException on gitlab api call error + * @param mergeRequest The merge request where the discussion is created. + * @param body The content of a discussion. + * @param position The position when creating a diff note. (hash) + * @param positionBaseSha The base commit SHA in the source branch. + * @param positionStartSha The SHA referencing the commit in the target branch. + * @param positionHeadSha The SHA referencing the HEAD of this merge request. + * @param positionNewPath The file path after the change. + * @param positionOldPath The file path before the change. + * @param positionWidth The width of the image. + * @param positionHeight The height of the image. + * @param positionX The X coordinate. + * @param positionY The Y coordinate. + * + * @return The created discussion object. + * @throws IOException on a GitLab api call error */ - public GitlabMergeRequest updateMergeRequest(Serializable projectId, Integer mergeRequestId, String targetBranch, - Integer assigneeId, String title, String description, String stateEvent, - String labels) throws IOException { + public GitlabDiscussion createImageDiscussion( + GitlabMergeRequest mergeRequest, String body, String position, + String positionBaseSha, String positionStartSha, + String positionHeadSha, String positionNewPath, String positionOldPath, + Integer positionWidth, Integer positionHeight, Integer positionX, + Integer positionY + ) throws IOException { + checkRequiredCreateDiscussionArguments(body, positionBaseSha, positionStartSha, positionHeadSha); Query query = new Query() - .appendIf("target_branch", targetBranch) - .appendIf("assignee_id", assigneeId) - .appendIf("title", title) - .appendIf("description", description) - .appendIf("state_event", stateEvent) - .appendIf("labels", labels); + .append("body", body) + .appendIf("position", position) + .append("position[base_sha]", positionBaseSha) + .append("position[start_sha]", positionStartSha) + .append("position[head_sha]", positionHeadSha) + .append("position[position_type]", "image") + .appendIf("position[new_path]", positionNewPath) + .appendIf("position[old_path]", positionOldPath) + .appendIf("position[width]", positionWidth) + .appendIf("position[height]", positionHeight) + .appendIf("position[x]", positionX) + .appendIf("position[y]", positionY); - String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + "/merge_request/" + mergeRequestId + query.toString(); + String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + + GitlabDiscussion.URL + query.toString(); - return retrieve().method("PUT").to(tailUrl, GitlabMergeRequest.class); + return dispatch().to(tailUrl, GitlabDiscussion.class); } /** - * @param project The Project - * @param mergeRequestId Merge Request ID - * @param mergeCommitMessage optional merge commit message. Null if not set - * @return new merge request status - * @throws IOException on gitlab api call error + * Check if the required arguments to create a discussion are present and + * contain values. + * + * @param body The content of a discussion. + * @param positionBaseSha The base commit SHA in the source branch. + * @param positionStartSha The SHA referencing commit in target branch + * @param positionHeadSha The SHA referencing HEAD of this merge request */ - public GitlabMergeRequest acceptMergeRequest(GitlabProject project, Integer mergeRequestId, String mergeCommitMessage) throws IOException { - String tailUrl = GitlabProject.URL + "/" + project.getId() + "/merge_request/" + mergeRequestId + "/merge"; - GitlabHTTPRequestor requestor = retrieve().method("PUT"); - requestor.with("id", project.getId()); - requestor.with("merge_request_id", mergeRequestId); - if (mergeCommitMessage != null) - requestor.with("merge_commit_message", mergeCommitMessage); - return requestor.to(tailUrl, GitlabMergeRequest.class); + private void checkRequiredCreateDiscussionArguments(String body, + String positionBaseSha, String positionStartSha, String positionHeadSha) { + if (body == null || body.isEmpty()) { + throw new IllegalArgumentException("Missing required argument 'body'!"); + } else if (positionBaseSha == null || positionBaseSha.isEmpty()) { + throw new IllegalArgumentException("Missing required argument 'positionBaseSha'!"); + } else if (positionStartSha == null || positionStartSha.isEmpty()) { + throw new IllegalArgumentException("Missing required argument 'positionStartSha'!"); + } else if (positionHeadSha == null || positionHeadSha.isEmpty()) { + throw new IllegalArgumentException("Missing required argument 'positionHeadSha'!"); + } } /** - * Get a Note from a Merge Request. + * Resolve or unresolve a whole discussion of a merge request. * - * @param mergeRequest The merge request - * @param noteId The id of the note - * @return the Gitlab Note - * @throws IOException on gitlab api call error + * @param mergeRequest The merge request of the discussion. + * @param discussionId The id of the discussion to resolve. + * @param resolved Resolve or unresolve the note. + * + * @return The discussion object. + * @throws IOException on a GitLab api call error */ - public GitlabNote getNote(GitlabMergeRequest mergeRequest, Integer noteId) throws IOException { + public GitlabDiscussion resolveDiscussion(GitlabMergeRequest mergeRequest, + int discussionId, boolean resolved) throws IOException { String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + - GitlabMergeRequest.URL + "/" + mergeRequest.getId() + - GitlabNote.URL + "/" + noteId; - - return retrieve().to(tailUrl, GitlabNote.class); + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + + GitlabDiscussion.URL + "/" + discussionId; + return retrieve().method(PUT) + .with("resolved", resolved) + .to(tailUrl, GitlabDiscussion.class); } - public List getNotes(GitlabMergeRequest mergeRequest) throws IOException { + /** + * Add a note to existing merge request discussion. + * + * @param mergeRequest The merge request of the discussion. + * @param discussionId The id of the discussion to add a note to. + * @param body The content of the discussion. + * + * @return The added note object. + * @throws IOException on a GitLab api call error + */ + public GitlabNote addDiscussionNote(GitlabMergeRequest mergeRequest, + int discussionId, String body) throws IOException { String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + - GitlabMergeRequest.URL + "/" + mergeRequest.getId() + + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + + GitlabDiscussion.URL + "/" + discussionId + GitlabNote.URL; - - GitlabNote[] notes = retrieve().to(tailUrl, GitlabNote[].class); - return Arrays.asList(notes); + return dispatch().with("body", body).to(tailUrl, GitlabNote.class); } - public List getAllNotes(GitlabMergeRequest mergeRequest) throws IOException { + /** + * Modify or resolve an existing discussion note of the given merge request. + * + * @param mergeRequest The merge request of the discussion. + * @param discussionId The id of the discussion to modify. + * @param noteId The id of the discussion note. + * @param body The content of the discussion. + * @param resolved Resolve or unresolve the note. + * + * @return The modified note object. + * @throws IOException on a GitLab api call error + */ + public GitlabNote modifyDiscussionNote(GitlabMergeRequest mergeRequest, int discussionId, + int noteId, String body, Boolean resolved) throws IOException { + boolean bodyHasValue = false; + if (body != null && !body.isEmpty()) { + bodyHasValue = true; + } + if ((!bodyHasValue && resolved == null) || (bodyHasValue && resolved != null)) { + throw new IllegalArgumentException("Exactly one of body or resolved must be set!"); + } String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + - GitlabMergeRequest.URL + "/" + mergeRequest.getId() + - GitlabNote.URL; + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + + GitlabDiscussion.URL + "/" + discussionId + + GitlabNote.URL + "/" + noteId; + return retrieve().method(PUT) + .with("body", body) + .with("resolved", resolved) + .to(tailUrl, GitlabNote.class); + } - return retrieve().getAll(tailUrl, GitlabNote[].class); + /** + * Delete a discussion note of a merge request. + * + * @param mergeRequest The merge request of the discussion. + * @param discussionId The id of the discussion to resolve. + * @param noteId The id of a discussion note. + * + * @return The deleted note object. + * @throws IOException on a GitLab api call error + */ + public void deleteDiscussionNote(GitlabMergeRequest mergeRequest, int discussionId, int noteId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + + GitlabDiscussion.URL + "/" + discussionId + + GitlabNote.URL + "/" + noteId; + retrieve().method(DELETE).to(tailUrl, Void.class); } // Get a specific commit identified by the commit hash or name of a branch or tag @@ -1018,17 +2115,6 @@ public GitlabCommit getCommit(Serializable projectId, String commitHash) throws return retrieve().to(tailUrl, GitlabCommit.class); } - - public List getCommitBuilds(GitlabProject projectId, String commitHash) throws IOException { - return getCommitBuilds(projectId.getId(), commitHash); - } - - public List getCommitBuilds(Serializable projectId, String commitHash) throws IOException { - String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + "/repository/commits/" + commitHash + GitlabBuild.URL; - return retrieve().getAll(tailUrl, GitlabBuild[].class); - } - - public List getCommits(GitlabMergeRequest mergeRequest) throws IOException { return getCommits(mergeRequest, new Pagination()); } @@ -1039,13 +2125,9 @@ public List getCommits(GitlabMergeRequest mergeRequest, Pagination projectId = mergeRequest.getProjectId(); } - Query query = new Query() - .append("ref_name", mergeRequest.getSourceBranch()); - - query.mergeWith(pagination.asQuery()); - - String tailUrl = GitlabProject.URL + "/" + projectId + - "/repository" + GitlabCommit.URL + query.toString(); + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + + GitlabCommit.URL + pagination.toString(); GitlabCommit[] commits = retrieve().to(tailUrl, GitlabCommit[].class); return Arrays.asList(commits); @@ -1061,11 +2143,18 @@ public List getLastCommits(Serializable projectId, String branchOr public List getCommits(Serializable projectId, Pagination pagination, String branchOrTag) throws IOException { + return getCommits(projectId, pagination, branchOrTag, null); + } + + public List getCommits(Serializable projectId, Pagination pagination, + String branchOrTag, String path) throws IOException { final Query query = new Query(); if (branchOrTag != null) { query.append("ref_name", branchOrTag); } - + if (path != null) { + query.append("path", path); + } if (pagination != null) { query.mergeWith(pagination.asQuery()); } @@ -1137,12 +2226,21 @@ public GitlabCommitComparison compareCommits(Serializable projectId, String comm // List commit statuses for a project ID and commit hash // GET /projects/:id/repository/commits/:sha/statuses public List getCommitStatuses(GitlabProject project, String commitHash) throws IOException { - return getCommitStatuses(project, commitHash, new Pagination()); + return getCommitStatuses(project.getId(), commitHash, new Pagination()); + } + + public List getCommitStatuses(Serializable projectId, String commitHash) throws IOException { + return getCommitStatuses(projectId, commitHash, new Pagination()); } public List getCommitStatuses(GitlabProject project, String commitHash, Pagination pagination) throws IOException { - String tailUrl = GitlabProject.URL + "/" + project.getId() + "/repository" + GitlabCommit.URL + "/" + + return getCommitStatuses(project.getId(), commitHash, pagination); + } + + public List getCommitStatuses(Serializable projectId, String commitHash, + Pagination pagination) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + "/repository" + GitlabCommit.URL + "/" + commitHash + GitlabCommitStatus.URL + pagination; GitlabCommitStatus[] statuses = retrieve().to(tailUrl, GitlabCommitStatus[].class); return Arrays.asList(statuses); @@ -1152,7 +2250,12 @@ public List getCommitStatuses(GitlabProject project, String // GET /projects/:id/statuses/:sha public GitlabCommitStatus createCommitStatus(GitlabProject project, String commitHash, String state, String ref, String name, String targetUrl, String description) throws IOException { - String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabCommitStatus.URL + "/" + commitHash; + return createCommitStatus(project.getId(), commitHash, state, ref, name, targetUrl, description); + } + + public GitlabCommitStatus createCommitStatus(Serializable projectId, String commitHash, String state, String ref, + String name, String targetUrl, String description) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabCommitStatus.URL + "/" + commitHash; return dispatch() .with("state", state) .with("ref", ref) @@ -1165,9 +2268,9 @@ public GitlabCommitStatus createCommitStatus(GitlabProject project, String commi /** * Get raw file content * - * @param project The Project - * @param sha The commit or branch name - * @param filepath The path of the file + * @param project The Project + * @param sha The commit or branch name + * @param filepath The path of the file * @throws IOException on gitlab api call error */ public byte[] getRawFileContent(GitlabProject project, String sha, String filepath) throws IOException { @@ -1178,15 +2281,15 @@ public byte[] getRawFileContent(GitlabProject project, String sha, String filepa * Get raw file content * * @param projectId The Project - * @param sha The commit or branch name - * @param filepath The path of the file + * @param sha The commit or branch name + * @param filepath The path of the file * @throws IOException on gitlab api call error */ - public byte[] getRawFileContent(Integer projectId, String sha, String filepath) throws IOException { + public byte[] getRawFileContent(Serializable projectId, String sha, String filepath) throws IOException { Query query = new Query() - .append("filepath", filepath); + .append("ref", sha); - String tailUrl = GitlabProject.URL + "/" + projectId + "/repository/blobs/" + sha + query.toString(); + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + "/repository/files/" + sanitizePath(filepath) + "/raw" + query.toString(); return retrieve().to(tailUrl, byte[].class); } @@ -1194,11 +2297,11 @@ public byte[] getRawFileContent(Integer projectId, String sha, String filepath) * Get the raw file contents for a blob by blob SHA. * * @param project The Project - * @param sha The commit or branch name + * @param sha The commit or branch name * @throws IOException on gitlab api call error */ public byte[] getRawBlobContent(GitlabProject project, String sha) throws IOException { - String tailUrl = GitlabProject.URL + "/" + project.getId() + "/repository/raw_blobs/" + sha; + String tailUrl = GitlabProject.URL + "/" + project.getId() + "/repository/blobs/" + sha + "/raw"; return retrieve().to(tailUrl, byte[].class); } @@ -1217,26 +2320,95 @@ public byte[] getFileArchive(GitlabProject project) throws IOException { * Get an archive of the repository * * @param project The Project - * @param path The path inside the repository. Used to get content of subdirectories (optional) - * @param ref_name The name of a repository branch or tag or if not given the default branch (optional) + * @param path The path inside the repository. Used to get content of subdirectories (optional) + * @param ref The name of a repository branch or tag or if not given the default branch (optional) * @throws IOException on gitlab api call error */ - public List getRepositoryTree(GitlabProject project, String path, String ref_name) throws IOException { - Query query = new Query() + public List getRepositoryTree(GitlabProject project, String path, String ref, boolean recursive) throws IOException { + Query query = new Pagination().withPerPage(Pagination.MAX_ITEMS_PER_PAGE).asQuery() .appendIf("path", path) - .appendIf("ref_name", ref_name); + .appendIf("ref", ref) + .appendIf("recursive", recursive); String tailUrl = GitlabProject.URL + "/" + project.getId() + "/repository" + GitlabRepositoryTree.URL + query.toString(); - GitlabRepositoryTree[] tree = retrieve().to(tailUrl, GitlabRepositoryTree[].class); - return Arrays.asList(tree); - } + return retrieve().getAll(tailUrl, GitlabRepositoryTree[].class); + } + + public GitlabRepositoryFile getRepositoryFile(GitlabProject project, String path, String ref) throws IOException { + Query query = new Query() + .append("ref", ref); + + String tailUrl = GitlabProject.URL + "/" + project.getId() + "/repository/files/" + sanitizePath(path) + query.toString(); + return retrieve().to(tailUrl, GitlabRepositoryFile.class); + } + + /** + * Creates a new file in the repository + * + * @param project The Project + * @param path The file path inside the repository + * @param branchName The name of a repository branch + * @param commitMsg The commit message + * @param content The base64 encoded content of the file + * @throws IOException on gitlab api call error + */ + public GitlabSimpleRepositoryFile createRepositoryFile(GitlabProject project, String path, String branchName, String commitMsg, String content) throws IOException { + String tailUrl = GitlabProject.URL + "/" + project.getId() + "/repository/files/" + sanitizePath(path); + GitlabHTTPRequestor requestor = dispatch(); + + return requestor + .with("branch", branchName) + .with("encoding", "base64") + .with("commit_message", commitMsg) + .with("content", content) + .to(tailUrl, GitlabSimpleRepositoryFile.class); + } + + /** + * Updates the content of an existing file in the repository + * + * @param project The Project + * @param path The file path inside the repository + * @param branchName The name of a repository branch + * @param commitMsg The commit message + * @param content The base64 encoded content of the file + * @throws IOException on gitlab api call error + */ + public GitlabSimpleRepositoryFile updateRepositoryFile(GitlabProject project, String path, String branchName, String commitMsg, String content) throws IOException { + String tailUrl = GitlabProject.URL + "/" + project.getId() + "/repository/files/" + sanitizePath(path); + GitlabHTTPRequestor requestor = retrieve().method(PUT); + + return requestor + .with("branch", branchName) + .with("encoding", "base64") + .with("commit_message", commitMsg) + .with("content", content) + .to(tailUrl, GitlabSimpleRepositoryFile.class); + } + + /** + * Deletes an existing file in the repository + * + * @param project The Project + * @param path The file path inside the repository + * @param branchName The name of a repository branch + * @param commitMsg The commit message + * @throws IOException on gitlab api call error + */ + public void deleteRepositoryFile(GitlabProject project, String path, String branchName, String commitMsg) throws IOException { + Query query = new Query() + .append("branch", branchName) + .append("commit_message", commitMsg); + String tailUrl = GitlabProject.URL + "/" + project.getId() + "/repository/files/" + sanitizePath(path) + query.toString(); + retrieve().method(DELETE).to(tailUrl, Void.class); + } /** * Update a Merge Request Note * - * @param mergeRequest The merge request - * @param noteId The id of the note - * @param body The content of the note + * @param mergeRequest The merge request + * @param noteId The id of the note + * @param body The content of the note * @return the Gitlab Note * @throws IOException on gitlab api call error */ @@ -1245,52 +2417,50 @@ public GitlabNote updateNote(GitlabMergeRequest mergeRequest, Integer noteId, St .appendIf("body", body); String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + - GitlabMergeRequest.URL + "/" + mergeRequest.getId() + GitlabNote.URL + "/" + noteId + query.toString(); + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + GitlabNote.URL + "/" + noteId + query.toString(); - return retrieve().method("PUT").to(tailUrl, GitlabNote.class); + return retrieve().method(PUT).to(tailUrl, GitlabNote.class); } public GitlabNote createNote(GitlabMergeRequest mergeRequest, String body) throws IOException { String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + - GitlabMergeRequest.URL + "/" + mergeRequest.getId() + GitlabNote.URL; + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + GitlabNote.URL; return dispatch().with("body", body).to(tailUrl, GitlabNote.class); } - + /** * Delete a Merge Request Note * - * @param mergeRequest The merge request - * @param noteToDelete The note to delete + * @param mergeRequest The merge request + * @param noteToDelete The note to delete * @throws IOException on gitlab api call error */ public void deleteNote(GitlabMergeRequest mergeRequest, GitlabNote noteToDelete) throws IOException { - String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + GitlabMergeRequest.URL + "/" - + mergeRequest.getId() + GitlabNote.URL + "/" + noteToDelete.getId(); - retrieve().method("DELETE").to(tailUrl, GitlabNote.class); - } + String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + GitlabMergeRequest.URL + "/" + + mergeRequest.getIid() + GitlabNote.URL + "/" + noteToDelete.getId(); + retrieve().method(DELETE).to(tailUrl, GitlabNote.class); + } - public List getBranches(Serializable projectId) throws IOException { - String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabBranch.URL; - GitlabBranch[] branches = retrieve().to(tailUrl, GitlabBranch[].class); - return Arrays.asList(branches); + public List getBranches(Serializable projectId) { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabBranch.URL + PARAM_MAX_ITEMS_PER_PAGE; + return retrieve().getAll(tailUrl, GitlabBranch[].class); } - public List getBranches(GitlabProject project) throws IOException { - String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabBranch.URL; - GitlabBranch[] branches = retrieve().to(tailUrl, GitlabBranch[].class); - return Arrays.asList(branches); + public List getBranches(GitlabProject project) { + String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabBranch.URL + PARAM_MAX_ITEMS_PER_PAGE; + return retrieve().getAll(tailUrl, GitlabBranch[].class); } /** * Create Branch. * - * Create Repository Branch Documentation + * Create Repository Branch Documentation * * - * @param project The gitlab project + * @param project The gitlab project * @param branchName The name of the branch to create - * @param ref The branch name or commit SHA to create branch from + * @param ref The branch name or commit SHA to create branch from * @throws IOException on gitlab api call error */ public void createBranch(GitlabProject project, String branchName, String ref) throws IOException { @@ -1300,18 +2470,17 @@ public void createBranch(GitlabProject project, String branchName, String ref) t /** * Create Branch. * - * Create Repository Branch Documentation + * Create Repository Branch Documentation * * - * * @param projectId The id of the project * @param branchName The name of the branch to create - * @param ref The branch name or commit SHA to create branch from + * @param ref The branch name or commit SHA to create branch from * @throws IOException on gitlab api call error */ public void createBranch(Serializable projectId, String branchName, String ref) throws IOException { String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabBranch.URL; - dispatch().with("branch_name", branchName).with("ref", ref).to(tailUrl, Void.class); + dispatch().with("branch", branchName).with("ref", ref).to(tailUrl, Void.class); } /** @@ -1322,35 +2491,44 @@ public void createBranch(Serializable projectId, String branchName, String ref) * @throws IOException on gitlab api call error */ public void deleteBranch(Serializable projectId, String branchName) throws IOException { - String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabBranch.URL + sanitizeBranch(branchName); - retrieve().method("DELETE").to(tailUrl, Void.class); + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabBranch.URL + '/' + sanitizePath(branchName); + retrieve().method(DELETE).to(tailUrl, Void.class); } - public GitlabBranch getBranch(GitlabProject project, String branchName) throws IOException { - String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabBranch.URL + sanitizeBranch(branchName); + public GitlabBranch getBranch(Serializable projectId, String branchName) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabBranch.URL + '/' + sanitizePath(branchName); return retrieve().to(tailUrl, GitlabBranch.class); } + public GitlabBranch getBranch(GitlabProject project, String branchName) throws IOException { + return getBranch(project.getId(), branchName); + } + public void protectBranch(GitlabProject project, String branchName) throws IOException { - String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabBranch.URL + sanitizeBranch(branchName) + "/protect"; - retrieve().method("PUT").to(tailUrl, Void.class); + protectBranchWithDeveloperOptions(project, branchName, false, false); + } + + public void protectBranchWithDeveloperOptions(GitlabProject project, String branchName, boolean developers_can_push, boolean developers_can_merge) throws IOException { + String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabBranch.URL + '/' + sanitizePath(branchName) + "/protect"; + final Query query = new Query() + .append("developers_can_push", Boolean.toString(developers_can_push)) + .append("developers_can_merge", Boolean.toString(developers_can_merge)); + retrieve().method(PUT).to(tailUrl + query.toString(), Void.class); } public void unprotectBranch(GitlabProject project, String branchName) throws IOException { - String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabBranch.URL + sanitizeBranch(branchName) + "/unprotect"; - retrieve().method("PUT").to(tailUrl, Void.class); + String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabBranch.URL + '/' + sanitizePath(branchName) + "/unprotect"; + retrieve().method(PUT).to(tailUrl, Void.class); } public List getProjectHooks(Serializable projectId) throws IOException { String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabProjectHook.URL; - GitlabProjectHook[] hooks = retrieve().to(tailUrl, GitlabProjectHook[].class); - return Arrays.asList(hooks); + return retrieve().getAll(tailUrl, GitlabProjectHook[].class); } public List getProjectHooks(GitlabProject project) throws IOException { String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabProjectHook.URL; - GitlabProjectHook[] hooks = retrieve().to(tailUrl, GitlabProjectHook[].class); - return Arrays.asList(hooks); + return retrieve().getAll(tailUrl, GitlabProjectHook[].class); } public GitlabProjectHook getProjectHook(GitlabProject project, String hookId) throws IOException { @@ -1366,7 +2544,15 @@ public GitlabProjectHook addProjectHook(GitlabProject project, String url) throw return dispatch().to(tailUrl, GitlabProjectHook.class); } - public GitlabProjectHook addProjectHook(Serializable projectId, String url, boolean pushEvents, boolean issuesEvents, boolean mergeRequestEvents, boolean tagPushEvents, boolean sslVerification) throws IOException { + public GitlabProjectHook addProjectHook(GitlabProject project, String url, String token) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(project.getId()) + GitlabProjectHook.URL; + return dispatch() + .with("url", url) + .with("token", token) + .to(tailUrl, GitlabProjectHook.class); + } + + public GitlabProjectHook addProjectHook(Serializable projectId, String url, boolean pushEvents, boolean issuesEvents, boolean mergeRequestEvents, boolean noteEvents, boolean tagPushEvents, boolean sslVerification, boolean jobEvents, boolean pipelineEvents, boolean wikiPageEvents, String token) throws IOException { String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabProjectHook.URL; return dispatch() @@ -1374,31 +2560,79 @@ public GitlabProjectHook addProjectHook(Serializable projectId, String url, bool .with("push_events", pushEvents ? "true" : "false") .with("issues_events", issuesEvents ? "true" : "false") .with("merge_requests_events", mergeRequestEvents ? "true" : "false") + .with("note_events", noteEvents ? "true" : "false") .with("tag_push_events", tagPushEvents ? "true" : "false") .with("enable_ssl_verification", sslVerification ? "true" : "false") + .with("job_events", jobEvents ? "true" : "false") + .with("pipeline_events", pipelineEvents ? "true" : "false") + .with("wiki_page_events", wikiPageEvents ? "true" : "false") + .with("token", token) .to(tailUrl, GitlabProjectHook.class); } - public GitlabProjectHook editProjectHook(GitlabProject project, String hookId, String url) throws IOException { - Query query = new Query() - .append("url", url); + public GitlabProjectHook addProjectHook(Serializable projectId, String url, GitlabProjectHook hook, String token) throws IOException { + return this.addProjectHook(projectId, url, hook.getPushEvents(), hook.getIssueEvents(), hook.isMergeRequestsEvents(), + hook.isNoteEvents(), hook.isTagPushEvents(), hook.isSslVerificationEnabled(), hook.isJobEvents(), + hook.isPipelineEvents(), hook.isWikiPageEvents(), token); + } + public GitlabProjectHook editProjectHook(GitlabProject project, String hookId, String url, + boolean pushEvents, boolean issuesEvents, boolean mergeRequestEvents, boolean noteEvents, + boolean tagPushEvents, boolean sslVerification, boolean jobEvents, boolean pipelineEvents, + boolean wikiPageEvents, String token) throws IOException { + Query query = new Query(); + query.append("url", url); + query.append("push_events", String.valueOf(pushEvents)); + query.append("issues_events", String.valueOf(issuesEvents)); + query.append("merge_request_events", String.valueOf(mergeRequestEvents)); + query.append("note_events", String.valueOf(noteEvents)); + query.append("tag_push_events", String.valueOf(tagPushEvents)); + query.append("enable_ssl_verification", String.valueOf(sslVerification)); + query.append("job_events", String.valueOf(jobEvents)); + query.append("pipeline_events", String.valueOf(pipelineEvents)); + query.append("wiki_page_events", String.valueOf(wikiPageEvents)); + query.append("token", token); String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabProjectHook.URL + "/" + hookId + query.toString(); - return retrieve().method("PUT").to(tailUrl, GitlabProjectHook.class); + return retrieve().method(PUT).to(tailUrl, GitlabProjectHook.class); + } + + public GitlabProjectHook editProjectHook(GitlabProject project, GitlabProjectHook projectHook, String token) throws IOException { + return editProjectHook(project, projectHook.getId(), projectHook.getUrl(), projectHook.getPushEvents(), + projectHook.getIssueEvents(), projectHook.isMergeRequestsEvents(), projectHook.isNoteEvents(), + projectHook.isTagPushEvents(), projectHook.isSslVerificationEnabled(), projectHook.isJobEvents(), + projectHook.isWikiPageEvents(), projectHook.isPipelineEvents(), token); } public void deleteProjectHook(GitlabProjectHook hook) throws IOException { String tailUrl = GitlabProject.URL + "/" + hook.getProjectId() + GitlabProjectHook.URL + "/" + hook.getId(); - retrieve().method("DELETE").to(tailUrl, Void.class); + retrieve().method(DELETE).to(tailUrl, Void.class); } public void deleteProjectHook(GitlabProject project, String hookId) throws IOException { String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabProjectHook.URL + "/" + hookId; - retrieve().method("DELETE").to(tailUrl, Void.class); + retrieve().method(DELETE).to(tailUrl, Void.class); + } + + public List getIssues(GitlabProject project) { + return getIssues(project.getId()); + } + + public List getIssues(Serializable projectId) { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabIssue.URL + PARAM_MAX_ITEMS_PER_PAGE; + return retrieve().getAll(tailUrl, GitlabIssue[].class); } - public List getIssues(GitlabProject project) throws IOException { - String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabIssue.URL; + public List getIssues(GitlabProject project, GitlabMilestone milestone) { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(project.getId()) + + GitlabMilestone.URL + "/" + sanitizeMilestoneId(milestone.getId()) + + GitlabIssue.URL + PARAM_MAX_ITEMS_PER_PAGE; + return retrieve().getAll(tailUrl, GitlabIssue[].class); + } + + public List getIssues(GitlabGroup group, GitlabMilestone milestone) { + String tailUrl = GitlabGroup.URL + "/" + sanitizeGroupId(group.getId()) + + GitlabMilestone.URL + "/" + sanitizeMilestoneId(milestone.getId()) + + GitlabIssue.URL + PARAM_MAX_ITEMS_PER_PAGE; return retrieve().getAll(tailUrl, GitlabIssue[].class); } @@ -1407,7 +2641,12 @@ public GitlabIssue getIssue(Serializable projectId, Integer issueId) throws IOEx return retrieve().to(tailUrl, GitlabIssue.class); } - public GitlabIssue createIssue(int projectId, int assigneeId, int milestoneId, String labels, + public GitlabIssueTimeStats getIssueTimeStats(Serializable projectId, Integer issueId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabIssue.URL + "/" + issueId + GitlabIssueTimeStats.URL; + return retrieve().to(tailUrl, GitlabIssueTimeStats.class); + } + + public GitlabIssue createIssue(int projectId, int assigneeId, Integer milestoneId, String labels, String description, String title) throws IOException { String tailUrl = GitlabProject.URL + "/" + projectId + GitlabIssue.URL; GitlabHTTPRequestor requestor = dispatch(); @@ -1415,7 +2654,7 @@ public GitlabIssue createIssue(int projectId, int assigneeId, int milestoneId, S return requestor.to(tailUrl, GitlabIssue.class); } - + public GitlabIssue moveIssue(Integer projectId, Integer issueId, Integer toProjectId) throws IOException { String tailUrl = GitlabProject.URL + "/" + projectId + GitlabIssue.URL + "/" + issueId + "/move"; GitlabHTTPRequestor requestor = dispatch(); @@ -1426,7 +2665,7 @@ public GitlabIssue moveIssue(Integer projectId, Integer issueId, Integer toProje public GitlabIssue editIssue(int projectId, int issueId, int assigneeId, int milestoneId, String labels, String description, String title, GitlabIssue.Action action) throws IOException { String tailUrl = GitlabProject.URL + "/" + projectId + GitlabIssue.URL + "/" + issueId; - GitlabHTTPRequestor requestor = retrieve().method("PUT"); + GitlabHTTPRequestor requestor = retrieve().method(PUT); applyIssue(requestor, projectId, assigneeId, milestoneId, labels, description, title); if (action != GitlabIssue.Action.LEAVE) { @@ -1437,7 +2676,7 @@ public GitlabIssue editIssue(int projectId, int issueId, int assigneeId, int mil } private void applyIssue(GitlabHTTPRequestor requestor, int projectId, - int assigneeId, int milestoneId, String labels, String description, + int assigneeId, Integer milestoneId, String labels, String description, String title) { requestor.with("title", title) @@ -1449,73 +2688,232 @@ private void applyIssue(GitlabHTTPRequestor requestor, int projectId, requestor.with("assignee_id", assigneeId == -1 ? 0 : assigneeId); } } - + public GitlabNote getNote(GitlabIssue issue, Integer noteId) throws IOException { String tailUrl = GitlabProject.URL + "/" + issue.getProjectId() + - GitlabIssue.URL + "/" + issue.getId() + + GitlabIssue.URL + "/" + issue.getIid() + GitlabNote.URL + "/" + noteId; return retrieve().to(tailUrl, GitlabNote.class); } public List getNotes(GitlabIssue issue) throws IOException { String tailUrl = GitlabProject.URL + "/" + issue.getProjectId() + GitlabIssue.URL + "/" - + issue.getId() + GitlabNote.URL; + + issue.getIid() + GitlabNote.URL; return Arrays.asList(retrieve().to(tailUrl, GitlabNote[].class)); } public GitlabNote createNote(Serializable projectId, Integer issueId, String message) throws IOException { - String tailUrl = GitlabProject.URL + "/" + projectId + GitlabIssue.URL + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabIssue.URL + "/" + issueId + GitlabNote.URL; return dispatch().with("body", message).to(tailUrl, GitlabNote.class); } public GitlabNote createNote(GitlabIssue issue, String message) throws IOException { - return createNote(String.valueOf(issue.getProjectId()), issue.getId(), message); + return createNote(String.valueOf(issue.getProjectId()), issue.getIid(), message); } /** * Delete an Issue Note * - * @param projectId The project id - * @param issueId The issue id - * @param noteToDelete The note to delete + * @param projectId The project id + * @param issueId The issue id + * @param noteToDelete The note to delete * @throws IOException on gitlab api call error */ - public void deleteNote(Serializable projectId, Integer issueId, GitlabNote noteToDelete) throws IOException { - String tailUrl = GitlabProject.URL + "/" + projectId + GitlabIssue.URL + "/" - + issueId + GitlabNote.URL + "/" + noteToDelete.getId(); - retrieve().method("DELETE").to(tailUrl, GitlabNote.class); - } + public void deleteNote(Serializable projectId, Integer issueId, GitlabNote noteToDelete) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + + GitlabIssue.URL + "/" + issueId + GitlabNote.URL + + "/" + noteToDelete.getId(); + retrieve().method(DELETE).to(tailUrl, GitlabNote.class); + } - /** + /** * Delete an Issue Note * - * @param issue The issue - * @param noteToDelete The note to delete + * @param issue The issue + * @param noteToDelete The note to delete * @throws IOException on gitlab api call error */ - public void deleteNote(GitlabIssue issue, GitlabNote noteToDelete) throws IOException { - deleteNote(String.valueOf(issue.getProjectId()), issue.getId(), noteToDelete); - } + public void deleteNote(GitlabIssue issue, GitlabNote noteToDelete) throws IOException { + deleteNote(String.valueOf(issue.getProjectId()), issue.getId(), noteToDelete); + } + + /** + * Get project badges + * + * @param projectId The id of the project for which the badges should be retrieved + * @return The list of badges + * + * @throws IOException on GitLab API call error + */ + public List getProjectBadges(Serializable projectId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabBadge.URL; + return Arrays.asList(retrieve().to(tailUrl, GitlabBadge[].class)); + } + + /** + * Get project badge + * + * @param projectId The id of the project for which the badge should be retrieved + * @param badgeId The id of the badge that should be retrieved + * @return The badge with a given id + * + * @throws IOException on GitLab API call error + */ + public GitlabBadge getProjectBadge(Serializable projectId, Integer badgeId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabBadge.URL + + "/" + badgeId; + return retrieve().to(tailUrl, GitlabBadge.class); + } + + /** + * Add project badge + * + * @param projectId The id of the project for which the badge should be added + * @param linkUrl The URL that the badge should link to + * @param imageUrl The URL to the badge image + * @return The created badge + * + * @throws IOException on GitLab API call error + */ + public GitlabBadge addProjectBadge(Serializable projectId, String linkUrl, String imageUrl) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabBadge.URL; + return dispatch().with("link_url", linkUrl) + .with("image_url", imageUrl) + .to(tailUrl, GitlabBadge.class); + } + + /** + * Edit project badge + * + * @param projectId The id of the project for which the badge should be edited + * @param badgeId The id of the badge that should be edited + * @param linkUrl The URL that the badge should link to + * @param imageUrl The URL to the badge image + * @return The updated badge + * + * @throws IOException on GitLab API call error + */ + public GitlabBadge editProjectBadge(Serializable projectId, Integer badgeId, String linkUrl, String imageUrl) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabBadge.URL + + "/" + badgeId; + GitlabHTTPRequestor requestor = retrieve().method(PUT); + requestor.with("link_url", linkUrl) + .with("image_url", imageUrl); + return requestor.to(tailUrl, GitlabBadge.class); + } + + /** + * Delete project badge + * + * @param projectId The id of the project for which the badge should be deleted + * @param badgeId The id of the badge that should be deleted + * @throws IOException on GitLab API call error + */ + public void deleteProjectBadge(Serializable projectId, Integer badgeId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabBadge.URL + + "/" + badgeId; + retrieve().method(DELETE).to(tailUrl, Void.class); + } + + /** + * Get project badges + * + * @param groupId The id of the group for which the badges should be retrieved + * @return The list of badges + * + * @throws IOException on GitLab API call error + */ + public List getGroupBadges(Integer groupId) throws IOException { + String tailUrl = GitlabGroup.URL + "/" + groupId + GitlabBadge.URL; + return Arrays.asList(retrieve().to(tailUrl, GitlabBadge[].class)); + } + + /** + * Get group badge + * + * @param groupId The id of the group for which the badge should be retrieved + * @param badgeId The id of the badge that should be retrieved + * @return The badge with a given id + * + * @throws IOException on GitLab API call error + */ + public GitlabBadge getGroupBadge(Integer groupId, Integer badgeId) throws IOException { + String tailUrl = GitlabGroup.URL + "/" + groupId + GitlabBadge.URL + + "/" + badgeId; + return retrieve().to(tailUrl, GitlabBadge.class); + } + + /** + * Add group badge + * + * @param groupId The id of the group for which the badge should be added + * @param linkUrl The URL that the badge should link to + * @param imageUrl The URL to the badge image + * @return The created badge + * + * @throws IOException on GitLab API call error + */ + public GitlabBadge addGroupBadge(Integer groupId, String linkUrl, String imageUrl) throws IOException { + String tailUrl = GitlabGroup.URL + "/" + groupId + GitlabBadge.URL; + return dispatch().with("link_url", linkUrl) + .with("image_url", imageUrl) + .to(tailUrl, GitlabBadge.class); + } + + /** + * Edit group badge + * + * @param groupId The id of the group for which the badge should be edited + * @param badgeId The id of the badge that should be edited + * @param linkUrl The URL that the badge should link to + * @param imageUrl The URL to the badge image + * @return The updated badge + * + * @throws IOException on GitLab API call error + */ + public GitlabBadge editGroupBadge(Integer groupId, Integer badgeId, String linkUrl, String imageUrl) throws IOException { + String tailUrl = GitlabGroup.URL + "/" + groupId + GitlabBadge.URL + + "/" + badgeId; + GitlabHTTPRequestor requestor = retrieve().method(PUT); + requestor.with("link_url", linkUrl) + .with("image_url", imageUrl); + return requestor.to(tailUrl, GitlabBadge.class); + } + + /** + * Delete group badge + * + * @param groupId The id of the group for which the badge should be deleted + * @param badgeId The id of the badge that should be deleted + * @throws IOException on GitLab API call error + */ + public void deleteGroupBadge(Integer groupId, Integer badgeId) throws IOException { + String tailUrl = GitlabGroup.URL + "/" + groupId + GitlabBadge.URL + + "/" + badgeId; + retrieve().method(DELETE).to(tailUrl, Void.class); + } /** * Gets labels associated with a project. + * * @param projectId The ID of the project. * @return A non-null list of labels. - * @throws IOException + * @throws IOException on gitlab api call error */ public List getLabels(Serializable projectId) throws IOException { - String tailUrl = GitlabProject.URL + "/" + projectId + GitlabLabel.URL; + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabLabel.URL; GitlabLabel[] labels = retrieve().to(tailUrl, GitlabLabel[].class); return Arrays.asList(labels); } /** * Gets labels associated with a project. + * * @param project The project associated with labels. * @return A non-null list of labels. - * @throws IOException + * @throws IOException on gitlab api call error */ public List getLabels(GitlabProject project) throws IOException { @@ -1524,26 +2922,28 @@ public List getLabels(GitlabProject project) /** * Creates a new label. + * * @param projectId The ID of the project containing the new label. - * @param name The name of the label. - * @param color The color of the label (eg #ff0000). + * @param name The name of the label. + * @param color The color of the label (eg #ff0000). * @return The newly created label. - * @throws IOException + * @throws IOException on gitlab api call error */ public GitlabLabel createLabel( Serializable projectId, String name, String color) throws IOException { - String tailUrl = GitlabProject.URL + "/" + projectId + GitlabLabel.URL; + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabLabel.URL; return dispatch().with("name", name) - .with("color", color) - .to(tailUrl, GitlabLabel.class); + .with("color", color) + .to(tailUrl, GitlabLabel.class); } /** * Creates a new label. + * * @param projectId The ID of the project containing the label. - * @param label The label to create. + * @param label The label to create. * @return The newly created label. */ public GitlabLabel createLabel(Serializable projectId, GitlabLabel label) @@ -1555,26 +2955,28 @@ public GitlabLabel createLabel(Serializable projectId, GitlabLabel label) /** * Deletes an existing label. + * * @param projectId The ID of the project containing the label. - * @param name The name of the label to delete. - * @throws IOException + * @param name The name of the label to delete. + * @throws IOException on gitlab api call error */ public void deleteLabel(Serializable projectId, String name) throws IOException { Query query = new Query(); query.append("name", name); String tailUrl = GitlabProject.URL + "/" + - projectId + + sanitizeProjectId(projectId) + GitlabLabel.URL + query.toString(); - retrieve().method("DELETE").to(tailUrl, Void.class); + retrieve().method(DELETE).to(tailUrl, Void.class); } /** * Deletes an existing label. + * * @param projectId The ID of the project containing the label. - * @param label The label to delete. - * @throws IOException + * @param label The label to delete. + * @throws IOException on gitlab api call error */ public void deleteLabel(Serializable projectId, GitlabLabel label) throws IOException { @@ -1583,19 +2985,20 @@ public void deleteLabel(Serializable projectId, GitlabLabel label) /** * Updates an existing label. + * * @param projectId The ID of the project containing the label. - * @param name The name of the label to update. - * @param newName The updated name. - * @param newColor The updated color. + * @param name The name of the label to update. + * @param newName The updated name. + * @param newColor The updated color. * @return The updated, deserialized label. - * @throws IOException + * @throws IOException on gitlab api call error */ public GitlabLabel updateLabel(Serializable projectId, String name, String newName, String newColor) throws IOException { - String tailUrl = GitlabProject.URL + "/" + projectId + GitlabLabel.URL; - GitlabHTTPRequestor requestor = retrieve().method("PUT"); + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabLabel.URL; + GitlabHTTPRequestor requestor = retrieve().method(PUT); requestor.with("name", name); if (newName != null) { requestor.with("new_name", newName); @@ -1607,47 +3010,62 @@ public GitlabLabel updateLabel(Serializable projectId, } public List getMilestones(GitlabProject project) throws IOException { - return getMilestones(String.valueOf(project.getId())); + return getProjectMilestones(String.valueOf(project.getId())); + } + + public List getMilestones(GitlabGroup group) throws IOException { + return getGroupMilestones(String.valueOf(group.getId())); } - public List getMilestones(Serializable projectId) throws IOException { + public List getProjectMilestones(Serializable projectId) throws IOException { String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabMilestone.URL; return Arrays.asList(retrieve().to(tailUrl, GitlabMilestone[].class)); } + public List getGroupMilestones(Serializable groupId) throws IOException { + String tailUrl = GitlabGroup.URL + "/" + sanitizeGroupId(groupId) + GitlabMilestone.URL; + return Arrays.asList(retrieve().to(tailUrl, GitlabMilestone[].class)); + } + /** * Cretaes a new project milestone. - * @param projectId The ID of the project. - * @param title The title of the milestone. + * + * @param projectId The ID of the project. + * @param title The title of the milestone. * @param description The description of the milestone. (Optional) - * @param dueDate The date the milestone is due. (Optional) + * @param dueDate The date the milestone is due. (Optional) + * @param startDate The start date of the milestone. (Optional) * @return The newly created, de-serialized milestone. - * @throws IOException + * @throws IOException on gitlab api call error */ public GitlabMilestone createMilestone( Serializable projectId, String title, String description, - Date dueDate) throws IOException { - String tailUrl = GitlabProject.URL + "/" + projectId + GitlabMilestone.URL; + Date dueDate, + Date startDate) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabMilestone.URL; GitlabHTTPRequestor requestor = dispatch().with("title", title); + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); if (description != null) { requestor = requestor.with("description", description); } if (dueDate != null) { - SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); - String formatted = formatter.format(dueDate); - requestor = requestor.with("due_date", formatted); + requestor = requestor.with("due_date", formatter.format(dueDate)); + } + if (startDate != null) { + requestor = requestor.with("start_date", formatter.format(startDate)); } return requestor.to(tailUrl, GitlabMilestone.class); } /** * Creates a new project milestone. + * * @param projectId The ID of the project. * @param milestone The milestone to create. * @return The newly created, de-serialized milestone. - * @throws IOException + * @throws IOException on gitlab api call error */ public GitlabMilestone createMilestone( Serializable projectId, @@ -1655,20 +3073,23 @@ public GitlabMilestone createMilestone( String title = milestone.getTitle(); String description = milestone.getDescription(); Date dateDue = milestone.getDueDate(); - return createMilestone(projectId, title, description, dateDue); + Date dateStart = milestone.getStartDate(); + return createMilestone(projectId, title, description, dateDue, dateStart); } /** * Updates an existing project milestone. - * @param projectId The ID of the project. + * + * @param projectId The ID of the project. * @param milestoneId The ID of the milestone. - * @param title The title of the milestone. (Optional) + * @param title The title of the milestone. (Optional) * @param description The description of the milestone. (Optional) - * @param dueDate The date the milestone is due. (Optional) - * @param stateEvent A value used to update the state of the milestone. - * (Optional) (activate | close) + * @param dueDate The date the milestone is due. (Optional) + * @param startDate The start date of the milestone. (Optional) + * @param stateEvent A value used to update the state of the milestone. + * (Optional) (activate | close) * @return The updated, de-serialized milestone. - * @throws IOException + * @throws IOException on gitlab api call error */ public GitlabMilestone updateMilestone( Serializable projectId, @@ -1676,12 +3097,14 @@ public GitlabMilestone updateMilestone( String title, String description, Date dueDate, + Date startDate, String stateEvent) throws IOException { String tailUrl = GitlabProject.URL + "/" + - projectId + + sanitizeProjectId(projectId) + GitlabMilestone.URL + "/" + milestoneId; - GitlabHTTPRequestor requestor = retrieve().method("PUT"); + GitlabHTTPRequestor requestor = retrieve().method(PUT); + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); if (title != null) { requestor.with("title", title); } @@ -1689,9 +3112,10 @@ public GitlabMilestone updateMilestone( requestor = requestor.with("description", description); } if (dueDate != null) { - SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); - String formatted = formatter.format(dueDate); - requestor = requestor.with("due_date", formatted); + requestor = requestor.with("due_date", formatter.format(dueDate)); + } + if (startDate != null) { + requestor = requestor.with("start_date", formatter.format(startDate)); } if (stateEvent != null) { requestor.with("state_event", stateEvent); @@ -1701,12 +3125,13 @@ public GitlabMilestone updateMilestone( /** * Updates an existing project milestone. - * @param projectId The ID of the project. - * @param edited The already edited milestone. + * + * @param projectId The ID of the project. + * @param edited The already edited milestone. * @param stateEvent A value used to update the state of the milestone. * (Optional) (activate | close) * @return The updated, de-serialized milestone. - * @throws IOException + * @throws IOException on gitlab api call error */ public GitlabMilestone updateMilestone( Serializable projectId, @@ -1717,16 +3142,18 @@ public GitlabMilestone updateMilestone( edited.getTitle(), edited.getDescription(), edited.getDueDate(), + edited.getStartDate(), stateEvent); } /** * Updates an existing project milestone. - * @param edited The already edited milestone. - * @return The updated, de-serialized milestone. + * + * @param edited The already edited milestone. * @param stateEvent A value used to update the state of the milestone. * (Optional) (activate | close) - * @throws IOException + * @return The updated, de-serialized milestone. + * @throws IOException on gitlab api call error */ public GitlabMilestone updateMilestone( GitlabMilestone edited, @@ -1786,9 +3213,41 @@ public void deleteProjectMember(GitlabProject project, GitlabUser user) throws I */ public void deleteProjectMember(Integer projectId, Integer userId) throws IOException { String tailUrl = GitlabProject.URL + "/" + projectId + "/" + GitlabProjectMember.URL + "/" + userId; - retrieve().method("DELETE").to(tailUrl, Void.class); + retrieve().method(DELETE).to(tailUrl, Void.class); + } + + /** + * Updates a project member. + * + * @param projectId the project id + * @param userId the user id + * @param accessLevel the updated access level for the specified user + * @return GitLabProjectMember with updated access level on success + * @throws IOException on Gitlab API call error + */ + public GitlabProjectMember updateProjectMember(Integer projectId, Integer userId, GitlabAccessLevel accessLevel) throws IOException { + return updateProjectMember(projectId, userId, accessLevel, null); + } + + /** + * Updates a project member. + * + * @param projectId the project id + * @param userId the user id + * @param accessLevel the updated access level for the specified user + * @param expiresAt the date at which the user's membership expires at in the form YEAR-MONTH-DAY + * @return GitLabProjectMember with updated access level on success + * @throws IOException on Gitlab API call error + */ + public GitlabProjectMember updateProjectMember(Integer projectId, Integer userId, GitlabAccessLevel accessLevel, String expiresAt) throws IOException { + Query query = new Query() + .appendIf("access_level", accessLevel) + .appendIf("expires_at", expiresAt); + String tailUrl = GitlabProject.URL + "/" + projectId + GitlabProjectMember.URL + "/" + userId + query.toString(); + return retrieve().method(PUT).to(tailUrl, GitlabProjectMember.class); } + public List getProjectMembers(GitlabProject project) throws IOException { return getProjectMembers(project.getId()); } @@ -1798,19 +3257,19 @@ public List getProjectMembers(GitlabProject project, Pagina } public List getProjectMembers(Serializable projectId) throws IOException { - return getProjectMembers(projectId, new Pagination()); + return getProjectMembers(projectId, new Pagination()); } public List getProjectMembers(Serializable projectId, Pagination pagination) throws IOException { - String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabProjectMember.URL + pagination.asQuery(); + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabProjectMember.URL + pagination.asQuery(); return Arrays.asList(retrieve().to(tailUrl, GitlabProjectMember[].class)); } - + /** * This will fail, if the given namespace is a user and not a group * * @param namespace The namespace - * @return A list of Gitlab Project members + * @return A list of Gitlab Project members * @throws IOException on gitlab api call error */ public List getNamespaceMembers(GitlabNamespace namespace) throws IOException { @@ -1821,11 +3280,11 @@ public List getNamespaceMembers(GitlabNamespace namespace) * This will fail, if the given namespace is a user and not a group * * @param namespaceId Namespace ID - * @return A list of Gitlab Project members + * @return A list of Gitlab Project members * @throws IOException on gitlab api call error */ public List getNamespaceMembers(Integer namespaceId) throws IOException { - String tailUrl = GitlabNamespace.URL + "/" + namespaceId + GitlabProjectMember.URL; + String tailUrl = GitlabGroup.URL + "/" + namespaceId + GitlabProjectMember.URL; return Arrays.asList(retrieve().to(tailUrl, GitlabProjectMember[].class)); } @@ -1837,39 +3296,59 @@ public List getNamespaceMembers(Integer namespaceId) throws * @throws IOException on gitlab api call error */ public void transfer(Integer namespaceId, Integer projectId) throws IOException { - String tailUrl = GitlabNamespace.URL + "/" + namespaceId + GitlabProject.URL + "/" + projectId; - dispatch().to(tailUrl, Void.class); + Query query = new Query().append("namespace", String.valueOf(namespaceId)); + String tailUrl = GitlabProject.URL + "/" + projectId + "/transfer" + query.toString(); + retrieve().method(PUT).to(tailUrl, Void.class); } /** * Create a new deploy key for the project * * @param targetProjectId The id of the Gitlab project - * @param title The title of the ssh key - * @param key The public key + * @param title The title of the ssh key + * @param key The public key * @return The new GitlabSSHKey * @throws IOException on gitlab api call error */ public GitlabSSHKey createDeployKey(Integer targetProjectId, String title, String key) throws IOException { + return createDeployKey(targetProjectId, title, key, false); + } + + /** + * Create a new deploy key for the project which can push. + * + * @param targetProjectId The id of the Gitlab project + * @param title The title of the ssh key + * @param key The public key + * @return The new GitlabSSHKey + * @throws IOException on gitlab api call error + */ + public GitlabSSHKey createPushDeployKey(Integer targetProjectId, String title, String key) throws IOException { + return createDeployKey(targetProjectId, title, key, true); + } + + private GitlabSSHKey createDeployKey(Integer targetProjectId, String title, String key, boolean canPush) throws IOException { Query query = new Query() .append("title", title) - .append("key", key); + .append("key", key) + .append("can_push", Boolean.toString(canPush)); - String tailUrl = GitlabProject.URL + "/" + targetProjectId + GitlabSSHKey.KEYS_URL + query.toString(); + String tailUrl = GitlabProject.URL + "/" + targetProjectId + GitlabSSHKey.DEPLOY_KEYS_URL + query.toString(); return dispatch().to(tailUrl, GitlabSSHKey.class); } + /** * Delete a deploy key for a project * * @param targetProjectId The id of the Gitlab project - * @param targetKeyId The id of the Gitlab ssh key + * @param targetKeyId The id of the Gitlab ssh key * @throws IOException on gitlab api call error */ public void deleteDeployKey(Integer targetProjectId, Integer targetKeyId) throws IOException { - String tailUrl = GitlabProject.URL + "/" + targetProjectId + GitlabSSHKey.KEYS_URL + "/" + targetKeyId; - retrieve().method("DELETE").to(tailUrl, Void.class); + String tailUrl = GitlabProject.URL + "/" + targetProjectId + GitlabSSHKey.DEPLOY_KEYS_URL + "/" + targetKeyId; + retrieve().method(DELETE).to(tailUrl, Void.class); } /** @@ -1880,7 +3359,7 @@ public void deleteDeployKey(Integer targetProjectId, Integer targetKeyId) throws * @throws IOException on gitlab api call error */ public List getDeployKeys(Integer targetProjectId) throws IOException { - String tailUrl = GitlabProject.URL + "/" + targetProjectId + GitlabSSHKey.KEYS_URL; + String tailUrl = GitlabProject.URL + "/" + targetProjectId + GitlabSSHKey.DEPLOY_KEYS_URL; return Arrays.asList(retrieve().to(tailUrl, GitlabSSHKey[].class)); } @@ -1928,24 +3407,36 @@ public void testSystemHook(Integer hookId) throws IOException { */ public GitlabSystemHook deleteSystemHook(Integer hookId) throws IOException { String tailUrl = GitlabSystemHook.URL + "/" + hookId; - return retrieve().method("DELETE").to(tailUrl, GitlabSystemHook.class); + return retrieve().method(DELETE).to(tailUrl, GitlabSystemHook.class); } private String sanitizeProjectId(Serializable projectId) { - if (!(projectId instanceof String) && !(projectId instanceof Number)) { - throw new IllegalArgumentException("projectId needs to be of type String or Number"); + return sanitizeId(projectId, "projectId"); + } + + private String sanitizeGroupId(Serializable groupId) { + return sanitizeId(groupId, "groupId"); + } + + private String sanitizeMilestoneId(Serializable milestoneId) { + return sanitizeId(milestoneId, "milestoneId"); + } + + private String sanitizeId(Serializable id, String parameterName) { + if (!(id instanceof String) && !(id instanceof Number)) { + throw new IllegalArgumentException(parameterName + " needs to be of type String or Number"); } try { - return URLEncoder.encode(String.valueOf(projectId), "UTF-8"); + return URLEncoder.encode(String.valueOf(id), "UTF-8"); } catch (UnsupportedEncodingException e) { throw new RuntimeException((e)); } } - private String sanitizeBranch(String branch){ + private String sanitizePath(String branch) { try { - return URLEncoder.encode(branch, "UTF-8"); + return URLEncoder.encode(branch, "UTF-8").replaceAll("\\+", "%20"); } catch (UnsupportedEncodingException e) { throw new RuntimeException((e)); } @@ -1954,45 +3445,45 @@ private String sanitizeBranch(String branch){ /** * Post comment to commit * - * @param projectId (required) - The ID of a project - * @param sha (required) - The name of a repository branch or tag or if not given the default branch - * @param note (required) - Text of comment - * @param path (optional) - The file path - * @param line (optional) - The line number - * @param line_type (optional) - The line type (new or old) - * @return A CommitComment + * @param projectId (required) - The ID of a project + * @param sha (required) - The name of a repository branch or tag or if not given the default branch + * @param note (required) - Text of comment + * @param path (optional) - The file path + * @param line (optional) - The line number + * @param line_type (optional) - The line type (new or old) + * @return A CommitComment * @throws IOException on gitlab api call error * @see http://doc.gitlab.com/ce/api/commits.html#post-comment-to-commit */ - public CommitComment createCommitComment(Integer projectId, String sha, String note, - String path, String line, String line_type) throws IOException { + public CommitComment createCommitComment(Serializable projectId, String sha, String note, + String path, String line, String line_type) throws IOException { - Query query = new Query() - .append("id", projectId.toString()) - .appendIf("sha", sha) - .appendIf("note", note) - .appendIf("path", path) - .appendIf("line", line) - .appendIf("line_type", line_type); - String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + "/repository/commits/" + sha + CommitComment.URL + query.toString(); + Query query = new Query() + .append("id", projectId.toString()) + .appendIf("sha", sha) + .appendIf("note", note) + .appendIf("path", path) + .appendIf("line", line) + .appendIf("line_type", line_type); + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + "/repository/commits/" + sha + CommitComment.URL + query.toString(); - return dispatch().to(tailUrl, CommitComment.class); + return dispatch().to(tailUrl, CommitComment.class); } /** * Get the comments of a commit * - * @param projectId (required) - The ID of a project - * @param sha (required) - The name of a repository branch or tag or if not given the default branch - * @return A CommitComment + * @param projectId (required) - The ID of a project + * @param sha (required) - The name of a repository branch or tag or if not given the default branch + * @return A CommitComment * @throws IOException on gitlab api call error * @see http://doc.gitlab.com/ce/api/commits.html#post-comment-to-commit */ public List getCommitComments(Integer projectId, String sha) throws IOException { - String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + "/repository/commits/" + sha + CommitComment.URL; + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + "/repository/commits/" + sha + CommitComment.URL; - return Arrays.asList(retrieve().to(tailUrl, CommitComment[].class)); + return Arrays.asList(retrieve().to(tailUrl, CommitComment[].class)); } /** @@ -2000,12 +3491,10 @@ public List getCommitComments(Integer projectId, String sha) thro * * @param projectId * @return - * @throws IOException on gitlab api call error */ - public List getTags(Serializable projectId) throws IOException { - String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabTag.URL; - GitlabTag[] tags = retrieve().to(tailUrl, GitlabTag[].class); - return Arrays.asList(tags); + public List getTags(Serializable projectId) { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabTag.URL + PARAM_MAX_ITEMS_PER_PAGE; + return retrieve().getAll(tailUrl, GitlabTag[].class); } /** @@ -2013,12 +3502,23 @@ public List getTags(Serializable projectId) throws IOException { * * @param project * @return + */ + public List getTags(GitlabProject project) { + String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabTag.URL + PARAM_MAX_ITEMS_PER_PAGE; + return retrieve().getAll(tailUrl, GitlabTag[].class); + } + + /** + * Get a single repository tag in a specific project + * + * @param project (required) The ID or URL-encoded path of the project + * @param tagName (required) The name of the tag + * @return the found git tag object * @throws IOException on gitlab api call error */ - public List getTags(GitlabProject project) throws IOException { - String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabTag.URL; - GitlabTag[] tags = retrieve().to(tailUrl, GitlabTag[].class); - return Arrays.asList(tags); + public GitlabTag getTag(GitlabProject project, String tagName) throws IOException { + String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabTag.URL + "/" + tagName; + return retrieve().to(tailUrl, GitlabTag.class); } /** @@ -2033,13 +3533,13 @@ public List getTags(GitlabProject project) throws IOException { * @throws IOException on gitlab api call error */ public GitlabTag addTag(Serializable projectId, String tagName, String ref, String message, String releaseDescription) throws IOException { - String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabTag.URL; - return dispatch() - .with("tag_name", tagName ) - .with("ref", ref) - .with("message", message) - .with("release_description", releaseDescription) - .to(tailUrl, GitlabTag.class); + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabTag.URL; + return dispatch() + .with("tag_name", tagName) + .with("ref", ref) + .with("message", message) + .with("release_description", releaseDescription) + .to(tailUrl, GitlabTag.class); } /** @@ -2054,13 +3554,13 @@ public GitlabTag addTag(Serializable projectId, String tagName, String ref, Stri * @throws IOException on gitlab api call error */ public GitlabTag addTag(GitlabProject project, String tagName, String ref, String message, String releaseDescription) throws IOException { - String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabTag.URL; - return dispatch() - .with("tag_name", tagName ) - .with("ref", ref) - .with("message", message) - .with("release_description", releaseDescription) - .to(tailUrl, GitlabTag.class); + String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabTag.URL; + return dispatch() + .with("tag_name", tagName) + .with("ref", ref) + .with("message", message) + .with("release_description", releaseDescription) + .to(tailUrl, GitlabTag.class); } /** @@ -2071,8 +3571,8 @@ public GitlabTag addTag(GitlabProject project, String tagName, String ref, Strin * @throws IOException on gitlab api call error */ public void deleteTag(Serializable projectId, String tagName) throws IOException { - String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabTag.URL + "/" + tagName; - retrieve().method("DELETE").to(tailUrl, Void.class); + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabTag.URL + "/" + tagName; + retrieve().method(DELETE).to(tailUrl, Void.class); } /** @@ -2083,78 +3583,76 @@ public void deleteTag(Serializable projectId, String tagName) throws IOException * @throws IOException on gitlab api call error */ public void deleteTag(GitlabProject project, String tagName) throws IOException { - String tailUrl = GitlabProject.URL + "/" + project + GitlabTag.URL + "/" + tagName; - retrieve().method("DELETE").to(tailUrl, Void.class); + String tailUrl = GitlabProject.URL + "/" + project + GitlabTag.URL + "/" + tagName; + retrieve().method(DELETE).to(tailUrl, Void.class); } /** * Get all awards for a merge request * * @param mergeRequest - * @throws IOException on gitlab api call error */ - public List getAllAwards(GitlabMergeRequest mergeRequest) throws IOException { - String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + GitlabMergeRequest.URL + "/" - + mergeRequest.getId() + GitlabAward.URL; + public List getAllAwards(GitlabMergeRequest mergeRequest) { + String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + GitlabMergeRequest.URL + "/" + + mergeRequest.getIid() + GitlabAward.URL + PARAM_MAX_ITEMS_PER_PAGE; - return retrieve().getAll(tailUrl, GitlabAward[].class); - } + return retrieve().getAll(tailUrl, GitlabAward[].class); + } /** - * Get a specific award for a merge request + * Get a specific award for a merge request * * @param mergeRequest * @param awardId * @throws IOException on gitlab api call error */ - public GitlabAward getAward(GitlabMergeRequest mergeRequest, Integer awardId) throws IOException { - String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + GitlabMergeRequest.URL + "/" - + mergeRequest.getId() + GitlabAward.URL + "/" + awardId; + public GitlabAward getAward(GitlabMergeRequest mergeRequest, Integer awardId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + GitlabMergeRequest.URL + "/" + + mergeRequest.getIid() + GitlabAward.URL + "/" + awardId; - return retrieve().to(tailUrl, GitlabAward.class); - } + return retrieve().to(tailUrl, GitlabAward.class); + } /** - * Create an award for a merge request + * Create an award for a merge request * * @param mergeRequest * @param awardName * @throws IOException on gitlab api call error */ - public GitlabAward createAward(GitlabMergeRequest mergeRequest, String awardName) throws IOException { - Query query = new Query().append("name", awardName); - String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + GitlabMergeRequest.URL + "/" - + mergeRequest.getId() + GitlabAward.URL + query.toString(); - - return dispatch().to(tailUrl, GitlabAward.class); - } + public GitlabAward createAward(GitlabMergeRequest mergeRequest, String awardName) throws IOException { + Query query = new Query().append("name", awardName); + String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + GitlabMergeRequest.URL + "/" + + mergeRequest.getIid() + GitlabAward.URL + query.toString(); + + return dispatch().to(tailUrl, GitlabAward.class); + } /** - * Delete an award for a merge request + * Delete an award for a merge request * * @param mergeRequest * @param award * @throws IOException on gitlab api call error */ - public void deleteAward(GitlabMergeRequest mergeRequest, GitlabAward award) throws IOException { - String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + GitlabMergeRequest.URL + "/" - + mergeRequest.getId() + GitlabAward.URL + "/" + award.getId(); - - retrieve().method("DELETE").to(tailUrl, Void.class); - } + public void deleteAward(GitlabMergeRequest mergeRequest, GitlabAward award) throws IOException { + String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + GitlabMergeRequest.URL + "/" + + mergeRequest.getIid() + GitlabAward.URL + "/" + award.getId(); + + retrieve().method(DELETE).to(tailUrl, Void.class); + } /** * Get all awards for an issue * * @param issue - * @throws IOException on gitlab api call error */ - public List getAllAwards(GitlabIssue issue) throws IOException { - String tailUrl = GitlabProject.URL + "/" + issue.getProjectId() + GitlabIssue.URL + "/" + issue.getId() - + GitlabAward.URL; + public List getAllAwards(GitlabIssue issue) { + String tailUrl = GitlabProject.URL + "/" + issue.getProjectId() + GitlabIssue.URL + "/" + issue.getId() + + GitlabAward.URL + PARAM_MAX_ITEMS_PER_PAGE; - return retrieve().getAll(tailUrl, GitlabAward[].class); - } + return retrieve().getAll(tailUrl, GitlabAward[].class); + } /** * Get a specific award for an issue @@ -2163,27 +3661,27 @@ public List getAllAwards(GitlabIssue issue) throws IOException { * @param awardId * @throws IOException on gitlab api call error */ - public GitlabAward getAward(GitlabIssue issue, Integer awardId) throws IOException { - String tailUrl = GitlabProject.URL + "/" + issue.getProjectId() + GitlabIssue.URL + "/" + issue.getId() - + GitlabAward.URL + "/" + awardId; + public GitlabAward getAward(GitlabIssue issue, Integer awardId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + issue.getProjectId() + GitlabIssue.URL + "/" + issue.getId() + + GitlabAward.URL + "/" + awardId; - return retrieve().to(tailUrl, GitlabAward.class); - } + return retrieve().to(tailUrl, GitlabAward.class); + } /** - * Create an award for an issue + * Create an award for an issue * * @param issue * @param awardName * @throws IOException on gitlab api call error */ - public GitlabAward createAward(GitlabIssue issue, String awardName) throws IOException { - Query query = new Query().append("name", awardName); - String tailUrl = GitlabProject.URL + "/" + issue.getProjectId() + GitlabIssue.URL + "/" + issue.getId() - + GitlabAward.URL + query.toString(); - - return dispatch().to(tailUrl, GitlabAward.class); - } + public GitlabAward createAward(GitlabIssue issue, String awardName) throws IOException { + Query query = new Query().append("name", awardName); + String tailUrl = GitlabProject.URL + "/" + issue.getProjectId() + GitlabIssue.URL + "/" + issue.getId() + + GitlabAward.URL + query.toString(); + + return dispatch().to(tailUrl, GitlabAward.class); + } /** * Delete an award for an issue @@ -2192,25 +3690,24 @@ public GitlabAward createAward(GitlabIssue issue, String awardName) throws IOExc * @param award * @throws IOException on gitlab api call error */ - public void deleteAward(GitlabIssue issue, GitlabAward award) throws IOException { - String tailUrl = GitlabProject.URL + "/" + issue.getProjectId() + GitlabIssue.URL + "/" + issue.getId() - + GitlabAward.URL + "/" + award.getId(); - retrieve().method("DELETE").to(tailUrl, Void.class); - } + public void deleteAward(GitlabIssue issue, GitlabAward award) throws IOException { + String tailUrl = GitlabProject.URL + "/" + issue.getProjectId() + GitlabIssue.URL + "/" + issue.getId() + + GitlabAward.URL + "/" + award.getId(); + retrieve().method(DELETE).to(tailUrl, Void.class); + } - /** + /** * Get all awards for an issue note * * @param issue * @param noteId - * @throws IOException on gitlab api call error */ - public List getAllAwards(GitlabIssue issue, Integer noteId) throws IOException { - String tailUrl = GitlabProject.URL + "/" + issue.getProjectId() + GitlabIssue.URL + "/" + issue.getId() - + GitlabNote.URL + noteId + GitlabAward.URL; + public List getAllAwards(GitlabIssue issue, Integer noteId) { + String tailUrl = GitlabProject.URL + "/" + issue.getProjectId() + GitlabIssue.URL + "/" + issue.getId() + + GitlabNote.URL + noteId + GitlabAward.URL + PARAM_MAX_ITEMS_PER_PAGE; - return retrieve().getAll(tailUrl, GitlabAward[].class); - } + return retrieve().getAll(tailUrl, GitlabAward[].class); + } /** * Get a specific award for an issue note @@ -2220,12 +3717,12 @@ public List getAllAwards(GitlabIssue issue, Integer noteId) throws * @param awardId * @throws IOException on gitlab api call error */ - public GitlabAward getAward(GitlabIssue issue, Integer noteId, Integer awardId) throws IOException { - String tailUrl = GitlabProject.URL + "/" + issue.getProjectId() + GitlabIssue.URL + "/" + issue.getId() - + GitlabNote.URL + noteId + GitlabAward.URL + "/" + awardId; + public GitlabAward getAward(GitlabIssue issue, Integer noteId, Integer awardId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + issue.getProjectId() + GitlabIssue.URL + "/" + issue.getId() + + GitlabNote.URL + noteId + GitlabAward.URL + "/" + awardId; - return retrieve().to(tailUrl, GitlabAward.class); - } + return retrieve().to(tailUrl, GitlabAward.class); + } /** * Create an award for an issue note @@ -2235,15 +3732,15 @@ public GitlabAward getAward(GitlabIssue issue, Integer noteId, Integer awardId) * @param awardName * @throws IOException on gitlab api call error */ - public GitlabAward createAward(GitlabIssue issue, Integer noteId, String awardName) throws IOException { - Query query = new Query().append("name", awardName); - String tailUrl = GitlabProject.URL + "/" + issue.getProjectId() + GitlabIssue.URL + "/" + issue.getId() - + GitlabNote.URL + noteId + GitlabAward.URL + query.toString(); - - return dispatch().to(tailUrl, GitlabAward.class); - } + public GitlabAward createAward(GitlabIssue issue, Integer noteId, String awardName) throws IOException { + Query query = new Query().append("name", awardName); + String tailUrl = GitlabProject.URL + "/" + issue.getProjectId() + GitlabIssue.URL + "/" + issue.getId() + + GitlabNote.URL + noteId + GitlabAward.URL + query.toString(); - /** + return dispatch().to(tailUrl, GitlabAward.class); + } + + /** * Delete an award for an issue note * * @param issue @@ -2251,17 +3748,18 @@ public GitlabAward createAward(GitlabIssue issue, Integer noteId, String awardNa * @param award * @throws IOException on gitlab api call error */ - public void deleteAward(GitlabIssue issue, Integer noteId, GitlabAward award) throws IOException { - String tailUrl = GitlabProject.URL + "/" + issue.getProjectId() + GitlabIssue.URL + "/" + issue.getId() - + GitlabNote.URL + noteId + GitlabAward.URL + "/" + award.getId(); - retrieve().method("DELETE").to(tailUrl, Void.class); - } + public void deleteAward(GitlabIssue issue, Integer noteId, GitlabAward award) throws IOException { + String tailUrl = GitlabProject.URL + "/" + issue.getProjectId() + GitlabIssue.URL + "/" + issue.getId() + + GitlabNote.URL + noteId + GitlabAward.URL + "/" + award.getId(); + retrieve().method(DELETE).to(tailUrl, Void.class); + } /** * Gets build variables associated with a project. + * * @param projectId The ID of the project. * @return A non-null list of variables. - * @throws IOException + * @throws IOException on gitlab api call error */ public List getBuildVariables(Integer projectId) throws IOException { @@ -2272,9 +3770,10 @@ public List getBuildVariables(Integer projectId) /** * Gets build variables associated with a project. + * * @param project The project associated with variables. * @return A non-null list of variables. - * @throws IOException + * @throws IOException on gitlab api call error */ public List getBuildVariables(GitlabProject project) throws IOException { @@ -2283,25 +3782,27 @@ public List getBuildVariables(GitlabProject project) /** * Gets build variable associated with a project and key. + * * @param projectId The ID of the project. - * @param key The key of the variable. + * @param key The key of the variable. * @return A variable. - * @throws IOException + * @throws IOException on gitlab api call error */ public GitlabBuildVariable getBuildVariable(Integer projectId, String key) throws IOException { String tailUrl = GitlabProject.URL + "/" + projectId + - GitlabBuildVariable.URL + + GitlabBuildVariable.URL + "/" + key; return retrieve().to(tailUrl, GitlabBuildVariable.class); } /** * Gets build variable associated with a project and key. + * * @param project The project associated with the variable. * @return A variable. - * @throws IOException + * @throws IOException on gitlab api call error */ public GitlabBuildVariable getBuildVariable(GitlabProject project, String key) throws IOException { @@ -2310,11 +3811,12 @@ public GitlabBuildVariable getBuildVariable(GitlabProject project, String key) /** * Creates a new build variable. + * * @param projectId The ID of the project containing the new variable. - * @param key The key of the variable. - * @param value The value of the variable + * @param key The key of the variable. + * @param value The value of the variable * @return The newly created variable. - * @throws IOException + * @throws IOException on gitlab api call error */ public GitlabBuildVariable createBuildVariable( Integer projectId, @@ -2328,8 +3830,9 @@ public GitlabBuildVariable createBuildVariable( /** * Creates a new variable. + * * @param projectId The ID of the project containing the variable. - * @param variable The variable to create. + * @param variable The variable to create. * @return The newly created variable. */ public GitlabBuildVariable createBuildVariable(Integer projectId, GitlabBuildVariable variable) @@ -2341,24 +3844,26 @@ public GitlabBuildVariable createBuildVariable(Integer projectId, GitlabBuildVar /** * Deletes an existing variable. + * * @param projectId The ID of the project containing the variable. - * @param key The key of the variable to delete. - * @throws IOException + * @param key The key of the variable to delete. + * @throws IOException on gitlab api call error */ public void deleteBuildVariable(Integer projectId, String key) throws IOException { String tailUrl = GitlabProject.URL + "/" + projectId + - GitlabBuildVariable.URL + + GitlabBuildVariable.URL + "/" + key; - retrieve().method("DELETE").to(tailUrl, Void.class); + retrieve().method(DELETE).to(tailUrl, Void.class); } /** * Deletes an existing variable. + * * @param projectId The ID of the project containing the variable. - * @param variable The variable to delete. - * @throws IOException + * @param variable The variable to delete. + * @throws IOException on gitlab api call error */ public void deleteBuildVariable(Integer projectId, GitlabBuildVariable variable) throws IOException { @@ -2367,20 +3872,21 @@ public void deleteBuildVariable(Integer projectId, GitlabBuildVariable variable) /** * Updates an existing variable. + * * @param projectId The ID of the project containing the variable. - * @param key The key of the variable to update. - * @param newValue The updated value. + * @param key The key of the variable to update. + * @param newValue The updated value. * @return The updated, deserialized variable. - * @throws IOException + * @throws IOException on gitlab api call error */ public GitlabBuildVariable updateBuildVariable(Integer projectId, - String key, - String newValue) throws IOException { + String key, + String newValue) throws IOException { String tailUrl = GitlabProject.URL + "/" + projectId + - GitlabBuildVariable.URL + + GitlabBuildVariable.URL + "/" + key; - GitlabHTTPRequestor requestor = retrieve().method("PUT"); + GitlabHTTPRequestor requestor = retrieve().method(PUT); if (newValue != null) { requestor = requestor.with("value", newValue); } @@ -2392,16 +3898,358 @@ public GitlabBuildVariable updateBuildVariable(Integer projectId, * * @param project the project * @return list of build triggers - * @throws IllegalStateException if builds are not enabled for the project - * @throws IOException + * @throws IllegalStateException if jobs are not enabled for the project */ - public List getBuildTriggers(GitlabProject project) throws IOException { - if (!project.isBuildsEnabled()) { - // if the project has not allowed builds, you will only get a 403 forbidden message which is + public List getPipelineTriggers(GitlabProject project) { + if (!project.isJobsEnabled()) { + // if the project has not allowed jobs, you will only get a 403 forbidden message which is // not helpful. - throw new IllegalStateException("Builds are not enabled for " + project.getNameWithNamespace() ); + throw new IllegalStateException("Jobs are not enabled for " + project.getNameWithNamespace()); } else { - return retrieve().getAll(GitlabProject.URL + "/" + project.getId() + GitlabTrigger.URL, GitlabTrigger[].class); + return retrieve().getAll(GitlabProject.URL + "/" + project.getId() + GitlabTrigger.URL + PARAM_MAX_ITEMS_PER_PAGE, GitlabTrigger[].class); + } + } + + /** + * Gets email-on-push service setup for a projectId. + * + * @param projectId The ID of the project containing the variable. + * @throws IOException on gitlab api call error + */ + public GitlabServiceEmailOnPush getEmailsOnPush(Integer projectId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + projectId + GitlabServiceEmailOnPush.URL; + return retrieve().to(tailUrl, GitlabServiceEmailOnPush.class); + } + + /** + * Update recipients for email-on-push service for a projectId. + * + * @param projectId The ID of the project containing the variable. + * @param emailAddress The emailaddress of the recipent who is going to receive push notification. + * @return + * @throws IOException on gitlab api call error + */ + public boolean updateEmailsOnPush(Integer projectId, String emailAddress) throws IOException { + GitlabServiceEmailOnPush emailOnPush = this.getEmailsOnPush(projectId); + GitlabEmailonPushProperties properties = emailOnPush.getProperties(); + String appendedRecipients = properties.getRecipients(); + if (appendedRecipients != "") { + if (appendedRecipients.contains(emailAddress)) + return true; + appendedRecipients = appendedRecipients + " " + emailAddress; + } else + appendedRecipients = emailAddress; + + Query query = new Query() + .appendIf("active", true) + .appendIf("recipients", appendedRecipients); + + String tailUrl = GitlabProject.URL + "/" + projectId + GitlabServiceEmailOnPush.URL + query.toString(); + return retrieve().method(PUT).to(tailUrl, Boolean.class); + } + + /** + * Get JIRA service settings for a project. + * https://docs.gitlab.com/ce/api/services.html#get-jira-service-settings + * + * @param projectId The ID of the project containing the variable. + * @return + * @throws IOException on gitlab api call error + */ + public GitlabServiceJira getJiraService(Integer projectId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + projectId + GitlabServiceJira.URL; + return retrieve().to(tailUrl, GitlabServiceJira.class); + } + + /** + * Remove all previously JIRA settings from a project. + * https://docs.gitlab.com/ce/api/services.html#delete-jira-service + * + * @param projectId The ID of the project containing the variable. + * @return + * @throws IOException on gitlab api call error + */ + public boolean deleteJiraService(Integer projectId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + projectId + GitlabServiceJira.URL; + return retrieve().method(DELETE).to(tailUrl, Boolean.class); + } + + /** + * Set JIRA service for a project. + * https://docs.gitlab.com/ce/api/services.html#create-edit-jira-service + * + * @param projectId The ID of the project containing the variable. + * @param jiraPropties + * @return + * @throws IOException on gitlab api call error + */ + public boolean createOrEditJiraService(Integer projectId, GitlabJiraProperties jiraPropties) throws IOException { + + Query query = new Query() + .appendIf("url", jiraPropties.getUrl()) + .appendIf("project_key", jiraPropties.getProjectKey()); + + if (!jiraPropties.getUsername().isEmpty()) { + query.appendIf("username", jiraPropties.getUsername()); + } + + if (!jiraPropties.getPassword().isEmpty()) { + query.appendIf("password", jiraPropties.getPassword()); + } + + if (jiraPropties.getIssueTransitionId() != null) { + query.appendIf("jira_issue_transition_id", jiraPropties.getIssueTransitionId()); + } + + + String tailUrl = GitlabProject.URL + "/" + projectId + GitlabServiceJira.URL + query.toString(); + return retrieve().method(PUT).to(tailUrl, Boolean.class); + + } + + /** + * Get a list of projects accessible by the authenticated user by search. + * + * @return A list of gitlab projects + * @throws IOException on gitlab api call error + */ + public List searchProjects(String search) throws IOException { + Query query = new Query() + .append("search", search); + String tailUrl = GitlabProject.URL + query.toString(); + GitlabProject[] response = retrieve().to(tailUrl, GitlabProject[].class); + return Arrays.asList(response); + } + + /** + * Share a project with a group. + * + * @param accessLevel The permissions level to grant the group. + * @param group The group to share with. + * @param project The project to be shared. + * @param expiration Share expiration date in ISO 8601 format: 2016-09-26 or {@code null}. + * @throws IOException on gitlab api call error + */ + public void shareProjectWithGroup(GitlabAccessLevel accessLevel, String expiration, GitlabGroup group, GitlabProject project) throws IOException { + Query query = new Query() + .append("group_id", group.getId().toString()) + .append("group_access", String.valueOf(accessLevel.accessValue)) + .appendIf("expires_at", expiration); + + String tailUrl = GitlabProject.URL + "/" + project.getId() + "/share" + query.toString(); + dispatch().to(tailUrl, Void.class); + } + + /** + * Delete a shared project link within a group. + * + * @param group The group. + * @param project The project. + * @throws IOException on gitlab api call error + */ + public void deleteSharedProjectGroupLink(GitlabGroup group, GitlabProject project) throws IOException { + deleteSharedProjectGroupLink(group.getId(), project.getId()); + } + + /** + * Delete a shared project link within a group. + * + * @param groupId The group id number. + * @param projectId The project id number. + * @throws IOException on gitlab api call error + */ + public void deleteSharedProjectGroupLink(int groupId, int projectId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + projectId + "/share/" + groupId; + retrieve().method(DELETE).to(tailUrl, Void.class); + } + + /** + * Set the User-Agent header for the requests. + * + * @param userAgent + */ + public void setUserAgent(String userAgent) { + this.userAgent = userAgent; + } + + public String getUserAgent() { + return userAgent; + } + + public GitlabVersion getVersion() throws IOException { + return retrieve().to("version", GitlabVersion.class); + } + + /** + * Returns a List of all GitlabRunners. + * + * @return List of GitlabRunners + * @throws IOException on gitlab api call error + */ + public List getRunners() throws IOException { + return getRunnersWithPagination(GitlabRunner.RunnerScope.ALL, null); + } + + /** + * Returns a List of GitlabRunners. + * + * @param scope Can be null. Defines type of Runner to retrieve. + * @return List of GitLabRunners + * @throws IOException on Gitlab API call error + */ + public List getRunners(GitlabRunner.RunnerScope scope) throws IOException { + return getRunnersWithPagination(scope, null); + } + + /** + * Returns a list of runners with perPage elements on the page number specified. + * + * @param scope Can be null. Defines type of Runner to retrieve. + * @param page Page to get perPage number of Runners from. + * @param perPage Number of elements to get per page. + * @return List of GitlabRunners + * @throws IOException on Gitlab API call error + */ + public List getRunnersWithPagination(GitlabRunner.RunnerScope scope, int page, int perPage) throws IOException { + Pagination pagination = new Pagination() + .withPage(page) + .withPerPage(perPage); + return getRunnersWithPagination(scope, pagination); + } + + /** + * Returns a list of runners with perPage elements on the page number specified. + * + * @param scope Can be null. Defines type of Runner to retrieve. + * @param pagination Can be null. Pagination to query by. + * @return List of GitlabRunners + * @throws IOException on Gitlab API call error + */ + public List getRunnersWithPagination(GitlabRunner.RunnerScope scope, Pagination pagination) throws IOException { + StringBuilder tailUrl = new StringBuilder(GitlabRunner.URL).append("/all"); + Query query = new Query() + .appendIf("scope", scope.getScope()); + + if (pagination != null) { + query.mergeWith(pagination.asQuery()); + } + + tailUrl.append(query.toString()); + return Arrays.asList(retrieve().method(GET).to(tailUrl.toString(), GitlabRunner[].class)); + } + + /** + * Get details information of the runner with the specified id. + * + * @param id Runner id. + * @return Extensive GitlabRunner Details. + * @throws IOException on gitlab api call error + */ + public GitlabRunner getRunnerDetail(int id) throws IOException { + String tailUrl = String.format("%s/%d", GitlabRunner.URL, id); + return retrieve().to(tailUrl, GitlabRunner.class); + } + + /** + * Get events for a project. + * + * @param action If not null, include only events of a particular action type + * @param targetType If not null, include only events of a particular target type + * @param before If not null, include only events created before a particular date. + * @param after If not null, include only events created before a + * particular date. + * @param sortOrder If null, uses the server's default, which is "desc" + */ + public List getEvents(GitlabProject project, + GitlabEvent.ActionType action, + GitlabEvent.TargetType targetType, + GitlabDate before, + GitlabDate after, + SortOrder sortOrder) + throws IOException { + return getEvents(project, action, targetType, before, + after, sortOrder, new Pagination()); + } + + /** + * Get events for a project. + * + * @param action If not null, include only events of a particular action type + * @param targetType If not null, include only events of a particular target type + * @param before If not null, include only events created before a particular date. + * @param after If not null, include only events created before a + * particular date. + * @param sortOrder If null, uses the server's default, which is "desc" + */ + public List getEvents(GitlabProject project, + GitlabEvent.ActionType action, + GitlabEvent.TargetType targetType, + GitlabDate before, + GitlabDate after, + SortOrder sortOrder, + Pagination pagination) + throws IOException { + return getProjectEvents(project.getId(), action, targetType, before, + after, sortOrder, pagination); + } + + /** + * Get events for a project. + * + * @param action If not null, include only events of a particular action type + * @param targetType If not null, include only events of a particular target type + * @param before If not null, include only events created before a particular date. + * @param after If not null, include only events created before a + * particular date. + * @param sort If null, uses the server's default, which is "desc" + */ + public List getProjectEvents(Serializable projectId, + GitlabEvent.ActionType action, + GitlabEvent.TargetType targetType, + GitlabDate before, + GitlabDate after, + SortOrder sort) + throws IOException { + return getProjectEvents(projectId, action, targetType, before, + after, sort, new Pagination()); + } + + /** + * Get events for a project. + * + * @param action If not null, include only events of a particular action type + * @param targetType If not null, include only events of a particular target type + * @param before If not null, include only events created before a particular date. + * @param after If not null, include only events created before a + * particular date. + * @param sort If null, uses the server's default, which is "desc" + */ + public List getProjectEvents(Serializable projectId, + GitlabEvent.ActionType action, + GitlabEvent.TargetType targetType, + GitlabDate before, + GitlabDate after, + SortOrder sort, + Pagination pagination) + throws IOException { + + final Query query = new Query(); + query.appendIf("action", action); + query.appendIf("target_type", targetType); + query.appendIf("before", before); + query.appendIf("after", after); + query.appendIf("sort", sort); + + if (pagination != null) { + query.mergeWith(pagination.asQuery()); } + + StringBuilder tailUrl = new StringBuilder(GitlabProject.URL) + .append("/") + .append(sanitizeProjectId(projectId)) + .append(GitlabEvent.URL) + .append(query.toString()); + + return Arrays.asList(retrieve().method(GET).to(tailUrl.toString(), GitlabEvent[].class)); } } diff --git a/src/main/java/org/gitlab/api/Pagination.java b/src/main/java/org/gitlab/api/Pagination.java index af2e3c4e..20be0d27 100644 --- a/src/main/java/org/gitlab/api/Pagination.java +++ b/src/main/java/org/gitlab/api/Pagination.java @@ -1,38 +1,44 @@ package org.gitlab.api; import org.gitlab.api.http.Query; +import org.gitlab.api.query.PaginationQuery; -import java.io.UnsupportedEncodingException; +/** + * @deprecated Use {@link PaginationQuery#PARAM_PAGE} instead. + */ +@Deprecated +public class Pagination extends PaginationQuery { -public class Pagination { - public static final String PARAM_PAGE = "page"; - public static final String PARAM_PER_PAGE = "per_page"; - public static final int MAX_ITEMS_PER_PAGE = 100; - private final Query paginationQuery = new Query(); + /** + * @deprecated Use {@link PaginationQuery#PARAM_PAGE} instead. + */ + @Deprecated + public static final String PARAM_PAGE = PaginationQuery.PARAM_PAGE; - public void setPage(int page) { - try { - paginationQuery.append(PARAM_PAGE, String.valueOf(page)); - } catch (UnsupportedEncodingException ignored) { - } + /** + @deprecated Use {@link PaginationQuery#PARAM_PER_PAGE} instead. + */ + @Deprecated + public static final String PARAM_PER_PAGE = PaginationQuery.PARAM_PER_PAGE; + + /** + @deprecated Use {@link PaginationQuery#MAX_ITEMS_PER_PAGE} instead. + */ + @Deprecated + public static final int MAX_ITEMS_PER_PAGE = PaginationQuery.MAX_ITEMS_PER_PAGE; + + public Pagination withPage(int page) { + setPage(page); + return this; } - public void setPerPage(int perPage) { - if (perPage > MAX_ITEMS_PER_PAGE) { - throw new IllegalArgumentException("Max value for perPage is " + MAX_ITEMS_PER_PAGE); - } - try { - paginationQuery.append(PARAM_PER_PAGE, String.valueOf(perPage)); - } catch (UnsupportedEncodingException ignored) { - } + public Pagination withPerPage(int perPage) { + setPerPage(perPage); + return this; } public Query asQuery() { - return paginationQuery; + return this; } - @Override - public String toString() { - return paginationQuery.toString(); - } } diff --git a/src/main/java/org/gitlab/api/http/GitlabHTTPRequestor.java b/src/main/java/org/gitlab/api/http/GitlabHTTPRequestor.java index 18822390..ebe80573 100644 --- a/src/main/java/org/gitlab/api/http/GitlabHTTPRequestor.java +++ b/src/main/java/org/gitlab/api/http/GitlabHTTPRequestor.java @@ -1,17 +1,16 @@ package org.gitlab.api.http; -import org.apache.commons.io.IOUtils; -import org.gitlab.api.AuthMethod; -import org.gitlab.api.GitlabAPI; -import org.gitlab.api.GitlabAPIException; -import org.gitlab.api.TokenType; -import org.gitlab.api.models.GitlabCommit; - -import javax.net.ssl.*; +import java.io.File; import java.io.FileNotFoundException; +import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.Reader; +import java.io.UncheckedIOException; import java.lang.reflect.Field; import java.net.*; import java.util.*; @@ -19,6 +18,18 @@ import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; +import javax.net.ssl.*; + +import org.apache.commons.io.IOUtils; +import org.gitlab.api.AuthMethod; +import org.gitlab.api.GitlabAPI; +import org.gitlab.api.GitlabAPIException; +import org.gitlab.api.TokenType; + +import static org.gitlab.api.http.Method.GET; +import static org.gitlab.api.http.Method.POST; +import static org.gitlab.api.http.Method.PUT; + /** * Gitlab HTTP Requestor * Responsible for handling HTTP requests to the Gitlab API @@ -31,31 +42,14 @@ public class GitlabHTTPRequestor { private final GitlabAPI root; - private String method = "GET"; // Default to GET requests - private Map data = new HashMap(); + private Method method = GET; // Default to GET requests + private Map data = new HashMap<>(); + private Map attachments = new HashMap<>(); private String apiToken; private TokenType tokenType; private AuthMethod authMethod; - private enum METHOD { - GET, PUT, POST, PATCH, DELETE, HEAD, OPTIONS, TRACE; - - public static String prettyValues() { - METHOD[] methods = METHOD.values(); - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < methods.length; i++) { - METHOD method = methods[i]; - builder.append(method.toString()); - - if (i != methods.length - 1) { - builder.append(", "); - } - } - return builder.toString(); - } - } - public GitlabHTTPRequestor(GitlabAPI root) { this.root = root; } @@ -83,13 +77,8 @@ public GitlabHTTPRequestor authenticate(String token, TokenType type, AuthMethod * @param method The HTTP method * @return this */ - public GitlabHTTPRequestor method(String method) { - try { - this.method = METHOD.valueOf(method).toString(); - } catch (IllegalArgumentException e) { - throw new IllegalArgumentException("Invalid HTTP Method: " + method + ". Must be one of " + METHOD.prettyValues()); - } - + public GitlabHTTPRequestor method(Method method) { + this.method = method; return this; } @@ -107,6 +96,21 @@ public GitlabHTTPRequestor with(String key, Object value) { } return this; } + + /** + * Sets the HTTP Form Post parameters for the request + * Has a fluent api for method chaining + * + * @param key Form parameter Key + * @param file File data + * @return this + */ + public GitlabHTTPRequestor withAttachment(String key, File file) { + if (file != null && key != null) { + attachments.put(key, file); + } + return this; + } public T to(String tailAPIUrl, T instance) throws IOException { return to(tailAPIUrl, null, instance); @@ -131,10 +135,11 @@ public T to(String tailAPIUrl, Class type, T instance) throws IOException HttpURLConnection connection = null; try { connection = setupConnection(root.getAPIUrl(tailAPIUrl)); - - if (hasOutput()) { + if (hasAttachments()) { + submitAttachments(connection); + } else if (hasOutput()) { submitData(connection); - } else if ("PUT".equals(method)) { + } else if (PUT.equals(method)) { // PUT requires Content-Length: 0 even when there is no body (eg: API for protecting a branch) connection.setDoOutput(true); connection.setFixedLengthStreamingMode(0); @@ -155,7 +160,7 @@ public T to(String tailAPIUrl, Class type, T instance) throws IOException } public List getAll(final String tailUrl, final Class type) { - List results = new ArrayList(); + List results = new ArrayList<>(); Iterator iterator = asIterator(tailUrl, type); while (iterator.hasNext()) { @@ -169,7 +174,7 @@ public List getAll(final String tailUrl, final Class type) { } public Iterator asIterator(final String tailApiUrl, final Class type) { - method("GET"); // Ensure we only use iterators for GET requests + method(GET); // Ensure we only use iterators for GET requests // Ensure that we don't submit any data and alert the user if (!data.isEmpty()) { @@ -184,7 +189,7 @@ public Iterator asIterator(final String tailApiUrl, final Class type) try { url = root.getAPIUrl(tailApiUrl); } catch (IOException e) { - throw new Error(e); + throw new UncheckedIOException(e); } } @@ -236,7 +241,7 @@ private void fetch() { handleAPIError(e, connection); } } catch (IOException e) { - throw new Error(e); + throw new UncheckedIOException(e); } } @@ -255,29 +260,60 @@ private void findNextUrl() throws MalformedURLException { Integer page = Integer.parseInt(matcher.group(2)) + 1; this.url = new URL(matcher.replaceAll(matcher.group(1) + "page=" + page)); } else { - if (GitlabCommit[].class == type) { - // there is a bug in the Gitlab CE API - // (https://gitlab.com/gitlab-org/gitlab-ce/issues/759) - // that starts pagination with page=0 for commits - this.url = new URL(url + (url.indexOf('?') > 0 ? '&' : '?') + "page=1"); - } else { - // Since the page query was not present, its safe to assume that we just - // currently used the first page, so we can default to page 2 - this.url = new URL(url + (url.indexOf('?') > 0 ? '&' : '?') + "&page=2"); - } + // Since the page query was not present, its safe to assume that we just + // currently used the first page, so we can default to page 2 + this.url = new URL(url + (url.indexOf('?') > 0 ? '&' : '?') + "page=2"); } } }; } + private void submitAttachments(HttpURLConnection connection) throws IOException { + String boundary = Long.toHexString(System.currentTimeMillis()); // Just generate some unique random value. + connection.setDoOutput(true); + connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); + String charset = "UTF-8"; + String CRLF = "\r\n"; // Line separator required by multipart/form-data. + OutputStream output = connection.getOutputStream(); + try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, charset), true)) { + for (Map.Entry paramEntry : data.entrySet()) { + String paramName = paramEntry.getKey(); + String param = GitlabAPI.MAPPER.writeValueAsString(paramEntry.getValue()); + writer.append("--").append(boundary).append(CRLF); + writer.append("Content-Disposition: form-data; name=\"").append(paramName).append("\"").append(CRLF); + writer.append("Content-Type: text/plain; charset=").append(charset).append(CRLF); + writer.append(CRLF).append(param).append(CRLF).flush(); + } + for (Map.Entry attachMentEntry : attachments.entrySet()) { + File binaryFile = attachMentEntry.getValue(); + writer.append("--").append(boundary).append(CRLF); + writer.append("Content-Disposition: form-data; name=\"").append(attachMentEntry.getKey()) + .append("\"; filename=\"").append(binaryFile.getName()).append("\"").append(CRLF); + writer.append("Content-Type: ").append(URLConnection.guessContentTypeFromName(binaryFile.getName())).append(CRLF); + writer.append("Content-Transfer-Encoding: binary").append(CRLF); + writer.append(CRLF).flush(); + try (Reader fileReader = new FileReader(binaryFile)) { + IOUtils.copy(fileReader, output); + } + output.flush(); // Important before continuing with writer! + writer.append(CRLF).flush(); // CRLF is important! It indicates end of boundary. + } + writer.append("--").append(boundary).append("--").append(CRLF).flush(); + } + } + private void submitData(HttpURLConnection connection) throws IOException { connection.setDoOutput(true); connection.setRequestProperty("Content-Type", "application/json"); GitlabAPI.MAPPER.writeValue(connection.getOutputStream(), data); } + private boolean hasAttachments() { + return !attachments.isEmpty(); + } + private boolean hasOutput() { - return method.equals("POST") || method.equals("PUT") && !data.isEmpty(); + return method.equals(POST) || method.equals(PUT) && !data.isEmpty(); } private HttpURLConnection setupConnection(URL url) throws IOException { @@ -287,33 +323,34 @@ private HttpURLConnection setupConnection(URL url) throws IOException { if (apiToken != null && authMethod == AuthMethod.URL_PARAMETER) { String urlWithAuth = url.toString(); - urlWithAuth = urlWithAuth + (urlWithAuth.indexOf('?') > 0 ? '&' : '?') + tokenType.getTokenParamName() + "=" + apiToken; + urlWithAuth = urlWithAuth + (urlWithAuth.indexOf('?') > 0 ? '&' : '?') + + tokenType.getTokenParamName() + "=" + apiToken; url = new URL(urlWithAuth); } - HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + HttpURLConnection connection = root.getProxy() != null ? + (HttpURLConnection) url.openConnection(root.getProxy()) : (HttpURLConnection) url.openConnection(); if (apiToken != null && authMethod == AuthMethod.HEADER) { - connection.setRequestProperty(tokenType.getTokenHeaderName(), String.format(tokenType.getTokenHeaderFormat(), apiToken)); + connection.setRequestProperty(tokenType.getTokenHeaderName(), + String.format(tokenType.getTokenHeaderFormat(), apiToken)); } - final int requestTimeout = root.getRequestTimeout(); - if (requestTimeout > 0) { - connection.setReadTimeout(requestTimeout); - } + connection.setReadTimeout(root.getResponseReadTimeout()); + connection.setConnectTimeout(root.getConnectionTimeout()); try { - connection.setRequestMethod(method); + connection.setRequestMethod(method.name()); } catch (ProtocolException e) { // Hack in case the API uses a non-standard HTTP verb try { Field methodField = connection.getClass().getDeclaredField("method"); methodField.setAccessible(true); - methodField.set(connection, method); + methodField.set(connection, method.name()); } catch (Exception x) { - throw (IOException) new IOException("Failed to set the custom verb").initCause(x); + throw new IOException("Failed to set the custom verb", x); } } - + connection.setRequestProperty("User-Agent", root.getUserAgent()); connection.setRequestProperty("Accept-Encoding", "gzip"); return connection; } @@ -325,16 +362,20 @@ private T parse(HttpURLConnection connection, Class type, T instance) thr return type.cast(IOUtils.toByteArray(wrapStream(connection, connection.getInputStream()))); } reader = new InputStreamReader(wrapStream(connection, connection.getInputStream()), "UTF-8"); - String data = IOUtils.toString(reader); - if (type != null) { - return GitlabAPI.MAPPER.readValue(data, type); + String json = IOUtils.toString(reader); + if (type != null && type == String.class) { + return type.cast(json); + } + if (type != null && type != Void.class) { + return GitlabAPI.MAPPER.readValue(json, type); } else if (instance != null) { - return GitlabAPI.MAPPER.readerForUpdating(instance).readValue(data); + return GitlabAPI.MAPPER.readerForUpdating(instance).readValue(json); } else { return null; } } catch (SSLHandshakeException e) { - throw new SSLHandshakeException("You can disable certificate checking by setting ignoreCertificateErrors on GitlabHTTPRequestor. SSL Error: " + e.getMessage()); + throw new SSLException("You can disable certificate checking by setting ignoreCertificateErrors " + + "on GitlabHTTPRequestor.", e); } finally { IOUtils.closeQuietly(reader); } @@ -353,10 +394,9 @@ private InputStream wrapStream(HttpURLConnection connection, InputStream inputSt } private void handleAPIError(IOException e, HttpURLConnection connection) throws IOException { - if (e instanceof FileNotFoundException) { - throw e; // pass through 404 Not Found to allow the caller to handle it intelligently - } - if (e instanceof SocketTimeoutException && root.getRequestTimeout() > 0) { + if (e instanceof FileNotFoundException || // pass through 404 Not Found to allow the caller to handle it intelligently + e instanceof SocketTimeoutException || + e instanceof ConnectException) { throw e; } @@ -392,12 +432,7 @@ public void checkServerTrusted( } }; // Added per https://github.com/timols/java-gitlab-api/issues/44 - HostnameVerifier nullVerifier = new HostnameVerifier() { - @Override - public boolean verify(String hostname, SSLSession session) { - return true; - } - }; + HostnameVerifier nullVerifier = (hostname, session) -> true; try { SSLContext sc = SSLContext.getInstance("SSL"); @@ -405,8 +440,6 @@ public boolean verify(String hostname, SSLSession session) { HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); // Added per https://github.com/timols/java-gitlab-api/issues/44 HttpsURLConnection.setDefaultHostnameVerifier(nullVerifier); - } catch (Exception e) { - // Ignore it - } + } catch (Exception ignore) {} } } diff --git a/src/main/java/org/gitlab/api/http/Method.java b/src/main/java/org/gitlab/api/http/Method.java new file mode 100644 index 00000000..02655e7e --- /dev/null +++ b/src/main/java/org/gitlab/api/http/Method.java @@ -0,0 +1,11 @@ +package org.gitlab.api.http; + +/** + * Created by Oleg Shaburov on 03.05.2018 + * shaburov.o.a@gmail.com + */ +public enum Method { + + GET, PUT, POST, PATCH, DELETE, HEAD, OPTIONS, TRACE; + +} diff --git a/src/main/java/org/gitlab/api/http/Query.java b/src/main/java/org/gitlab/api/http/Query.java index 521c493c..ad8db9a0 100644 --- a/src/main/java/org/gitlab/api/http/Query.java +++ b/src/main/java/org/gitlab/api/http/Query.java @@ -51,39 +51,7 @@ public Query append(final String name, final String value) throws UnsupportedEnc * @return this * @throws java.io.UnsupportedEncodingException If the provided value cannot be URL Encoded */ - public Query appendIf(final String name, final String value) throws UnsupportedEncodingException { - if (value != null) { - append(name, value); - } - return this; - } - - /** - * Conditionally append a parameter to the query - * if the value of the parameter is not null - * - * @param name Parameter name - * @param value Parameter value - * @return this - * @throws java.io.UnsupportedEncodingException If the provided value cannot be URL Encoded - */ - public Query appendIf(final String name, final Integer value) throws UnsupportedEncodingException { - if (value != null) { - append(name, value.toString()); - } - return this; - } - - /** - * Conditionally append a parameter to the query - * if the value of the parameter is not null - * - * @param name Parameter name - * @param value Parameter value - * @return this - * @throws java.io.UnsupportedEncodingException If the provided value cannot be URL Encoded - */ - public Query appendIf(final String name, final Boolean value) throws UnsupportedEncodingException { + public Query appendIf(final String name, final T value) throws UnsupportedEncodingException { if (value != null) { append(name, value.toString()); } diff --git a/src/main/java/org/gitlab/api/jackson/InstantDeserializer.java b/src/main/java/org/gitlab/api/jackson/InstantDeserializer.java new file mode 100644 index 00000000..5663826a --- /dev/null +++ b/src/main/java/org/gitlab/api/jackson/InstantDeserializer.java @@ -0,0 +1,80 @@ +package org.gitlab.api.jackson; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; + +import java.io.IOException; +import java.time.Instant; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.DateTimeParseException; +import java.time.format.FormatStyle; +import java.util.Locale; +import java.util.Objects; +import java.util.stream.Stream; + +/** + * A spezialized {@link Instant} deserializer that can parse different formats. + */ +public class InstantDeserializer extends StdDeserializer { + + private static final DateTimeFormatter LOCAL_DATE_TIME_FORMATTER_WITH_SPACE_SEPARATOR = new DateTimeFormatterBuilder() + .parseCaseInsensitive() + .append(DateTimeFormatter.ISO_LOCAL_DATE) + .appendLiteral(' ') + .append(DateTimeFormatter.ISO_LOCAL_TIME) + .toFormatter(Locale.getDefault(Locale.Category.FORMAT)); + + public InstantDeserializer() { + super(Instant.class); + } + + @Override + public Instant deserialize(JsonParser parser, DeserializationContext context) throws IOException { + if (JsonToken.VALUE_NULL.equals(parser.getCurrentToken())) { + return null; + } + + final String text = parser.getText(); + + if (null == text || text.trim().isEmpty()) { + return null; + } + + return getFormatters() + .map(formatter -> { + try { + return formatter.parse(text, Instant::from); + } catch (DateTimeParseException e) { + return null; + } + }) + .filter(Objects::nonNull) + .findFirst() + .orElseThrow(() -> new JsonParseException("Unable to parse instant \"" + text + "\"", parser.getCurrentLocation())); + } + + private static Stream getFormatters() { + return Stream.of( + // English (Standard) Formats + DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG, FormatStyle.LONG).withLocale(Locale.ENGLISH), + DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.LONG).withLocale(Locale.ENGLISH), + DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT, FormatStyle.LONG).withLocale(Locale.ENGLISH), + DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG, FormatStyle.MEDIUM).withLocale(Locale.ENGLISH), + DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.MEDIUM).withLocale(Locale.ENGLISH), + DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT, FormatStyle.MEDIUM).withLocale(Locale.ENGLISH), + DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG, FormatStyle.SHORT).withLocale(Locale.ENGLISH), + DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.SHORT).withLocale(Locale.ENGLISH), + DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT, FormatStyle.SHORT).withLocale(Locale.ENGLISH), + + // ISO Formats + LOCAL_DATE_TIME_FORMATTER_WITH_SPACE_SEPARATOR, + DateTimeFormatter.ISO_LOCAL_DATE_TIME, + DateTimeFormatter.ISO_DATE_TIME + ); + } + +} diff --git a/src/main/java/org/gitlab/api/models/CommitComment.java b/src/main/java/org/gitlab/api/models/CommitComment.java index eeb67d79..dd40c0b8 100644 --- a/src/main/java/org/gitlab/api/models/CommitComment.java +++ b/src/main/java/org/gitlab/api/models/CommitComment.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Date; + public class CommitComment { public static final String URL = "/comments"; @@ -14,6 +16,9 @@ public class CommitComment { @JsonProperty("line_type") private String lineType; + @JsonProperty("created_at") + private Date createdAt; + public GitlabUser getAuthor() { return author; } @@ -53,4 +58,12 @@ public String getLineType() { public void setLineType(String lineType) { this.lineType = lineType; } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } } diff --git a/src/main/java/org/gitlab/api/models/CreateGroupRequest.java b/src/main/java/org/gitlab/api/models/CreateGroupRequest.java new file mode 100644 index 00000000..baf5554c --- /dev/null +++ b/src/main/java/org/gitlab/api/models/CreateGroupRequest.java @@ -0,0 +1,139 @@ +package org.gitlab.api.models; + +import java.io.UnsupportedEncodingException; +import org.gitlab.api.http.Query; + +/** + * The model for custom group-creation requests. + * + */ +public class CreateGroupRequest { + + public CreateGroupRequest(String name) { + this(name, name); + } + + public CreateGroupRequest(String name, String path) { + this.name = name; + this.path = path; + } + + private String name; + private String path; + private String ldapCn; + private String description; + private Boolean membershipLock; + private Boolean shareWithGroupLock; + private GitlabVisibility visibility; + private Boolean lfsEnabled; + private Boolean requestAccessEnabled; + private Integer parentId; + + /** + * Generates query representing this request's properties. + * @return {@link Query} + * @throws UnsupportedEncodingException + */ + public Query toQuery() throws UnsupportedEncodingException{ + return new Query() + .append("name", name) + .append("path", path) + .appendIf("ldap_cn", ldapCn) + .appendIf("description", description) + .appendIf("membershipLock", membershipLock) + .appendIf("share_with_group_lock", shareWithGroupLock) + .appendIf("visibility", visibility != null ? visibility.toString() : null) + .appendIf("lfs_enabled", lfsEnabled) + .appendIf("request_access_enabled", requestAccessEnabled) + .appendIf("parent_id", parentId); + } + + public String getName() { + return name; + } + + public CreateGroupRequest setName(String name) { + this.name = name; + return this; + } + public String getPath() { + return path; + } + + public CreateGroupRequest setPath(String path) { + this.path = path; + return this; + } + + public String getLdapCn() { + return ldapCn; + } + + public CreateGroupRequest setLdapCn(String ldapCn) { + this.ldapCn = ldapCn; + return this; + } + + public String getDescription() { + return description; + } + + public CreateGroupRequest setDescription(String description) { + this.description = description; + return this; + } + + public Boolean getMembershipLock() { + return membershipLock; + } + + public CreateGroupRequest setMembershipLock(Boolean membershipLock) { + this.membershipLock = membershipLock; + return this; + } + + public Boolean getShareWithGroupLock() { + return shareWithGroupLock; + } + + public CreateGroupRequest setShareWithGroupLock(Boolean shareWithGroupLock) { + this.shareWithGroupLock = shareWithGroupLock; + return this; + } + + public GitlabVisibility getVisibility() { + return visibility; + } + + public CreateGroupRequest setVisibility(GitlabVisibility visibility) { + this.visibility = visibility; + return this; + } + + public Boolean getLfsEnabled() { + return lfsEnabled; + } + + public CreateGroupRequest setLfsEnabled(Boolean lfsEnabled) { + this.lfsEnabled = lfsEnabled; + return this; + } + + public Boolean getRequestAccessEnabled() { + return requestAccessEnabled; + } + + public CreateGroupRequest setRequestAccessEnabled(Boolean requestAccessEnabled) { + this.requestAccessEnabled = requestAccessEnabled; + return this; + } + + public Integer getParentId() { + return parentId; + } + + public CreateGroupRequest setParentId(Integer parentId) { + this.parentId = parentId; + return this; + } +} \ No newline at end of file diff --git a/src/main/java/org/gitlab/api/models/CreateUserRequest.java b/src/main/java/org/gitlab/api/models/CreateUserRequest.java new file mode 100644 index 00000000..0880e029 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/CreateUserRequest.java @@ -0,0 +1,258 @@ +package org.gitlab.api.models; + +import java.io.UnsupportedEncodingException; +import org.gitlab.api.http.Query; + +/** + * Model for customized creater-user requests. + * + */ +public class CreateUserRequest { + + private String email; + private String password; + private Boolean resetPassword; + private String username; + private String name; + private String skype; + private String linkedin; + private String twitter; + private String websiteUrl; + private String organization; + private Integer projectsLimit; + private String externUid; + private String provider; + private String bio; + private String location; + private Boolean admin; + private Boolean canCreateGroup; + private Boolean skipConfirmation; + private Boolean external; + private String avatar; + + /** + * The only constructor. The constructor demands the required fields for the request. + * + * @param name The user's name. + * @param username The user's display name. + * @param email The user's email. + */ + public CreateUserRequest(String name, String username, String email){ + this.name = name; + this.username = username; + this.email = email; + } + + /** + * Generates a query based on this request's properties. + * @return {@link Query} + * @throws UnsupportedEncodingException + */ + public Query toQuery() throws UnsupportedEncodingException{ + return new Query() + .appendIf("email", email) + .appendIf("password", password) + .appendIf("reset_password", resetPassword) + .appendIf("username", username) + .appendIf("name", name) + .appendIf("skype", skype) + .appendIf("linkedin", linkedin) + .appendIf("twitter", twitter) + .appendIf("website_url", websiteUrl) + .appendIf("organization", organization) + .appendIf("projects_limit", projectsLimit) + .appendIf("extern_uid", externUid) + .appendIf("provider", provider) + .appendIf("bio", bio) + .appendIf("location", location) + .appendIf("admin", admin) + .appendIf("can_create_group", canCreateGroup) + .appendIf("skip_confirmation", skipConfirmation) + .appendIf("external", external) + .appendIf("avatar", avatar); + + } + + public String getEmail() { + return email; + } + + public CreateUserRequest setEmail(String email) { + this.email = email; + return this; + } + + public String getPassword() { + return password; + } + + public CreateUserRequest setPassword(String password) { + this.password = password; + return this; + } + + public Boolean getResetPassword() { + return resetPassword; + } + + public CreateUserRequest setResetPassword(Boolean resetPassword) { + this.resetPassword = resetPassword; + return this; + } + + public String getUsername() { + return username; + } + + public CreateUserRequest setUsername(String username) { + this.username = username; + return this; + } + + public String getName() { + return name; + } + + public CreateUserRequest setName(String name) { + this.name = name; + return this; + } + + public String getSkype() { + return skype; + } + + public CreateUserRequest setSkype(String skype) { + this.skype = skype; + return this; + } + + public String getLinkedin() { + return linkedin; + } + + public CreateUserRequest setLinkedin(String linkedin) { + this.linkedin = linkedin; + return this; + } + + public String getTwitter() { + return twitter; + } + + public CreateUserRequest setTwitter(String twitter) { + this.twitter = twitter; + return this; + } + + public String getWebsiteUrl() { + return websiteUrl; + } + + public CreateUserRequest setWebsiteUrl(String websiteUrl) { + this.websiteUrl = websiteUrl; + return this; + } + + public String getOrganization() { + return organization; + } + + public CreateUserRequest setOrganization(String organization) { + this.organization = organization; + return this; + } + + public Integer getProjectsLimit() { + return projectsLimit; + } + + public CreateUserRequest setProjectsLimit(Integer projectsLimit) { + this.projectsLimit = projectsLimit; + return this; + } + + public String getExternUid() { + return externUid; + } + + public CreateUserRequest setExternUid(String externUid) { + this.externUid = externUid; + return this; + } + + public String getProvider() { + return provider; + } + + public CreateUserRequest setProvider(String provider) { + this.provider = provider; + return this; + } + + public String getBio() { + return bio; + } + + public CreateUserRequest setBio(String bio) { + this.bio = bio; + return this; + } + + public String getLocation() { + return location; + } + + public CreateUserRequest setLocation(String location) { + this.location = location; + return this; + } + + public Boolean getAdmin() { + return admin; + } + + public CreateUserRequest setAdmin(Boolean admin) { + this.admin = admin; + return this; + } + + public Boolean getCanCreateGroup() { + return canCreateGroup; + } + + public CreateUserRequest setCanCreateGroup(Boolean canCreateGroup) { + this.canCreateGroup = canCreateGroup; + return this; + } + + public Boolean getSkipConfirmation() { + return skipConfirmation; + } + + public CreateUserRequest setSkipConfirmation(Boolean skipConfirmation) { + this.skipConfirmation = skipConfirmation; + return this; + } + + public Boolean getExternal() { + return external; + } + + public CreateUserRequest setExternal(Boolean external) { + this.external = external; + return this; + } + + public String getAvatar() { + return avatar; + } + + public CreateUserRequest setAvatar(String avatar) { + this.avatar = avatar; + return this; + } + + + +} diff --git a/src/main/java/org/gitlab/api/models/GitlabApprovedBy.java b/src/main/java/org/gitlab/api/models/GitlabApprovedBy.java new file mode 100644 index 00000000..1c5f8937 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabApprovedBy.java @@ -0,0 +1,19 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Incomprehensibly, Gitlab packages "approved_by" in a wrapper which contains a user + * and nothing else. + */ +public class GitlabApprovedBy { + private GitlabUser user; + + public GitlabUser getUser() { + return user; + } + + public void setUser(GitlabUser user) { + this.user = user; + } +} diff --git a/src/main/java/org/gitlab/api/models/GitlabBadge.java b/src/main/java/org/gitlab/api/models/GitlabBadge.java new file mode 100644 index 00000000..7de3f1a6 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabBadge.java @@ -0,0 +1,70 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * @author Olga Maciaszek-Sharma + */ +public class GitlabBadge { + + public static final String URL = "/badges"; + + private Integer id; + @JsonProperty("link_url") + private String linkUrl; + @JsonProperty("image_url") + private String imageUrl; + @JsonProperty("rendered_link_url") + private String renderedLinkUrl; + @JsonProperty("rendered_image_url") + private String renderedImageUrl; + private String kind; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getLinkUrl() { + return linkUrl; + } + + public void setLinkUrl(String linkUrl) { + this.linkUrl = linkUrl; + } + + public String getImageUrl() { + return imageUrl; + } + + public void setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + } + + public String getRenderedLinkUrl() { + return renderedLinkUrl; + } + + public void setRenderedLinkUrl(String renderedLinkUrl) { + this.renderedLinkUrl = renderedLinkUrl; + } + + public String getRenderedImageUrl() { + return renderedImageUrl; + } + + public void setRenderedImageUrl(String renderedImageUrl) { + this.renderedImageUrl = renderedImageUrl; + } + + public String getKind() { + return kind; + } + + public void setKind(String kind) { + this.kind = kind; + } +} diff --git a/src/main/java/org/gitlab/api/models/GitlabBranch.java b/src/main/java/org/gitlab/api/models/GitlabBranch.java index 15302a71..eaebc3e3 100644 --- a/src/main/java/org/gitlab/api/models/GitlabBranch.java +++ b/src/main/java/org/gitlab/api/models/GitlabBranch.java @@ -3,7 +3,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; public class GitlabBranch { - public final static String URL = "/repository/branches/"; + public final static String URL = "/repository/branches"; @JsonProperty("name") private String name; diff --git a/src/main/java/org/gitlab/api/models/GitlabBuildVariable.java b/src/main/java/org/gitlab/api/models/GitlabBuildVariable.java index 605499de..e26b9601 100644 --- a/src/main/java/org/gitlab/api/models/GitlabBuildVariable.java +++ b/src/main/java/org/gitlab/api/models/GitlabBuildVariable.java @@ -6,7 +6,7 @@ * @author Vitezslav Zak */ public class GitlabBuildVariable { - public final static String URL = "/variables/"; + public final static String URL = "/variables"; public GitlabBuildVariable() { } @@ -14,6 +14,13 @@ public GitlabBuildVariable() { public GitlabBuildVariable(String key, String value) { this.key = key; this.value = value; + this.variableType = VariableType.env_var; + } + + public GitlabBuildVariable(String key, String value, VariableType variableType) { + this.key = key; + this.value = value; + this.variableType = variableType; } @JsonProperty("key") @@ -22,6 +29,9 @@ public GitlabBuildVariable(String key, String value) { @JsonProperty("value") private String value; + @JsonProperty("variable_type") + private VariableType variableType; + public String getKey() { return key; } @@ -37,4 +47,18 @@ public String getValue() { public void setValue(String value) { this.value = value; } + + public VariableType getVariableType() { + return variableType; + } + + public void setVariableType(VariableType variableType) { + this.variableType = variableType; + } + + public enum VariableType { + env_var, + file + } + } diff --git a/src/main/java/org/gitlab/api/models/GitlabCommit.java b/src/main/java/org/gitlab/api/models/GitlabCommit.java index f731ca73..f99bc32f 100644 --- a/src/main/java/org/gitlab/api/models/GitlabCommit.java +++ b/src/main/java/org/gitlab/api/models/GitlabCommit.java @@ -1,10 +1,10 @@ package org.gitlab.api.models; +import com.fasterxml.jackson.annotation.JsonProperty; + import java.util.Date; import java.util.List; -import com.fasterxml.jackson.annotation.JsonProperty; - public class GitlabCommit { public final static String URL = "/commits"; @@ -34,6 +34,9 @@ public class GitlabCommit { @JsonProperty("parent_ids") private List parentIds; + @JsonProperty("last_pipeline") + private GitlabPipeline lastPipeline; + public String getId() { return id; } @@ -98,6 +101,22 @@ public void setParentIds(List parentIds) { this.parentIds = parentIds; } + public Date getCommittedDate() { + return committedDate; + } + + public void setCommittedDate(Date committedDate) { + this.committedDate = committedDate; + } + + public Date getAuthoredDate() { + return authoredDate; + } + + public void setAuthoredDate(Date authoredDate) { + this.authoredDate = authoredDate; + } + @Override public boolean equals(Object obj) { // we say that two commit objects are equal iff they have the same ID @@ -110,4 +129,17 @@ public boolean equals(Object obj) { return false; } } + + @Override + public int hashCode() { + return this.getId().hashCode(); + } + + public GitlabPipeline getLastPipeline() { + return lastPipeline; + } + + public void setLastPipeline(GitlabPipeline lastPipeline) { + this.lastPipeline = lastPipeline; + } } diff --git a/src/main/java/org/gitlab/api/models/GitlabCommitStatus.java b/src/main/java/org/gitlab/api/models/GitlabCommitStatus.java index 3eb726c9..1505246d 100644 --- a/src/main/java/org/gitlab/api/models/GitlabCommitStatus.java +++ b/src/main/java/org/gitlab/api/models/GitlabCommitStatus.java @@ -128,4 +128,9 @@ public boolean equals(Object obj) { return false; } } + + @Override + public int hashCode() { + return this.getId().hashCode(); + } } diff --git a/src/main/java/org/gitlab/api/models/GitlabDate.java b/src/main/java/org/gitlab/api/models/GitlabDate.java new file mode 100644 index 00000000..43b2e845 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabDate.java @@ -0,0 +1,55 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Date; +import java.util.List; + +/** + * A date, with no time or timezone. This is, given the lack of + * timezone, an object whose meaning is somewhat ill-defined, but we + * must use the API that the hexarchs^W^W Gitlab gives us. We're + * going to make this immutable, because that's less error-prone. And + * we won't provide a constructor from Date, because Date is an + * instant in time rather than a calendar period. + */ +public final class GitlabDate { + private int year; + private int month; + private int day; + + /** + * @param month and day are 1-based. + */ + public GitlabDate(int year, int month, int day) { + this.year = year; + this.month = month; + this.day = day; + } + + public int getYear() { + return year; + } + + public int getMonth() { + return month; + } + public int getDay() { + return day; + } + + public String toString() { + // Gitlab requires this specific format + return String.format("%04d-%02d-%02d", year, month, day); + } + + public int hashCode() { + return this.year * 31 * 12 + this.month * 31 + this.day; + } + + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + GitlabDate that = (GitlabDate) o; + return this.year == that.year && this.month == that.month && this.day == that.day; + } +} diff --git a/src/main/java/org/gitlab/api/models/GitlabDiscussion.java b/src/main/java/org/gitlab/api/models/GitlabDiscussion.java new file mode 100644 index 00000000..5b4b6887 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabDiscussion.java @@ -0,0 +1,71 @@ +package org.gitlab.api.models; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * A class representing a GitLab discussion. A discussion is a collection of + * notes. + * + * @author Patrizio Bonzani + */ +public class GitlabDiscussion { + + public static final String URL = "/discussions"; + + /** + * The ID of a discussion. + */ + private String id; + + /** + * The notes contained in this discussion. + */ + private List notes = new ArrayList(); + + @JsonProperty("individual_note") + private boolean individualNote; + + @SuppressWarnings("unused") + private GitlabDiscussion() {} + + public GitlabDiscussion(String id) { + this.id = id; + } + + /** + * Get the id of this discussion. + * + * @return The id of the discussion. + */ + public String getId() { + return id; + } + + /** + * Get the notes of this discussion. + * + * @return The notes contained in this discussion. + */ + public List getNotes() { + return Collections.unmodifiableList(notes); + } + + /** + * Add a note to the discussion. + * + * @param note The note to add to the discussion. + * @return true (as specified by {@link Collection#add}) + */ + public boolean addNote(GitlabNote note) { + return notes.add(note); + } + + public boolean isIndividualNote() { + return individualNote; + } +} diff --git a/src/main/java/org/gitlab/api/models/GitlabEmailonPushProperties.java b/src/main/java/org/gitlab/api/models/GitlabEmailonPushProperties.java new file mode 100644 index 00000000..92606286 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabEmailonPushProperties.java @@ -0,0 +1,33 @@ +package org.gitlab.api.models; + +public class GitlabEmailonPushProperties { + + private Integer disable_diffs; + private String recipients; + private Integer send_from_committer_email; + + public Integer getDisableDiffs() { + return disable_diffs; + } + + public void setDisableDiffs(Integer disable_diffs) { + this.disable_diffs = disable_diffs; + } + + public String getRecipients() { + return recipients; + } + + public void setRecipients(String recipients) { + this.recipients = recipients; + } + + public Integer getSendFromCommitterEmail() { + return send_from_committer_email; + } + + public void setSendFromCommitterEmail(Integer send_from_committer_email) { + this.send_from_committer_email = send_from_committer_email; + } +} + diff --git a/src/main/java/org/gitlab/api/models/GitlabEvent.java b/src/main/java/org/gitlab/api/models/GitlabEvent.java new file mode 100644 index 00000000..640a8f66 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabEvent.java @@ -0,0 +1,185 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Date; +import java.util.List; + +public class GitlabEvent { + + public final static String URL = "/events"; + + private String title; + + @JsonProperty("project_id") + private String projectId; + + @JsonProperty("action_name") + private String actionName; + + // nullable + @JsonProperty("target_id") + private Integer targetId; + + // nullable + @JsonProperty("target_iid") + private Integer targetIid; + + @JsonProperty("target_type") + private TargetType targetType; + + // It's not clear if this is nullable + @JsonProperty("author_id") + private Integer authorId; + + // nullable + @JsonProperty("target_title") + private String targetTitle; + + @JsonProperty("created_at") + private Date createdAt; + + // see above re "author" + private GitlabUser author; + + // see above re "author" + @JsonProperty("author_username") + private String authorUsername; + + @JsonProperty("push_data") + private GitlabPushData pushData; + + public String getTitle() { + return title; + } + + public String getProjectId() { + return projectId; + } + + /** + * It would be reasonable to expect that this matches up with + * ActionType, below, but it doesn't. The action type "pushed" is + * spelled "pushed to" in action_name (but it's spelled "pushed" + * in GitlabPushData). + */ + public String getActionName() { + return actionName; + } + + public Integer getTargetId() { + return targetId; + } + + public Integer getTargetIid() { + return targetIid; + } + + public TargetType getTargetType() { + return targetType; + } + + /** See() {@link #getAuthor()} for note */ + public Integer getAuthorId() { + return authorId; + } + + public String getTargetTitle() { + return targetTitle; + } + + public Date getCreatedAt() { + return createdAt; + } + + /** + * For many events, this seem to have nothing to do with any + * "author", but is in fact the user who performed the action. + * e.g. a push's "author" is not necessarily the author or + * committer of any commit, but the user doing the pushing. + */ + public GitlabUser getAuthor() { + return author; + } + + /** See {@link #getAuthor()} for note */ + public String getAuthorUsername() { + return authorUsername; + } + + public GitlabPushData getPushData() { + return pushData; + } + + public void setTitle(String title) { + this.title = title; + } + + public void setProjectId(String projectId) { + this.projectId = projectId; + } + + public void setActionName(String actionName) { + this.actionName = actionName; + } + + public void setTargetId(Integer targetId) { + this.targetId = targetId; + } + + public void setTargetIid(Integer targetIid) { + this.targetIid = targetIid; + } + + public void setTargetType(TargetType targetType) { + this.targetType = targetType; + } + + public void setAuthorId(Integer authorId) { + this.authorId = authorId; + } + + public void setTargetTitle(String targetTitle) { + this.targetTitle = targetTitle; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public void setAuthor(GitlabUser author) { + this.author = author; + } + + public void setAuthorUsername(String authorUsername) { + this.authorUsername = authorUsername; + } + + public void setPushData(GitlabPushData pushData) { + this.pushData = pushData; + } + + public enum ActionType { + created, + updated, + closed, + reopened, + pushed, + commented, + merged, + joined, + left, + destroyed, + expired + } + + public enum TargetType { + issue, + milestone, + merge_request, + note, + project, + snippet, + user + } +} diff --git a/src/main/java/org/gitlab/api/models/GitlabGroup.java b/src/main/java/org/gitlab/api/models/GitlabGroup.java index 84a242b3..1003cc52 100644 --- a/src/main/java/org/gitlab/api/models/GitlabGroup.java +++ b/src/main/java/org/gitlab/api/models/GitlabGroup.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; + public class GitlabGroup { public static final String URL = "/groups"; @@ -9,6 +11,28 @@ public class GitlabGroup { private Integer id; private String name; private String path; + private String description; + + @JsonProperty("membership_lock") + private Boolean membershipLock; + + @JsonProperty("share_with_group_lock") + private Boolean shareWithGroupLock; + + @JsonProperty("visibility") + private GitlabVisibility visibility; + + @JsonProperty("lfs_enabled") + private Boolean lfsEnabled; + + @JsonProperty("request_access_enabled") + private Boolean requestAccessEnabled; + + @JsonProperty("shared_runners_minutes_limit") + private Integer sharedRunnersMinutesLimit; + + @JsonProperty("avatar_url") + private String avatarUrl; @JsonProperty("ldap_cn") private String ldapCn; @@ -16,14 +40,85 @@ public class GitlabGroup { @JsonProperty("ldap_access") private Integer ldapAccess; + @JsonProperty("shared_projects") + private List sharedProjects; + + @JsonProperty("web_url") + private String webUrl; + + @JsonProperty("parent_id") + private Integer parentId; + + @JsonProperty("full_name") + private String fullName; + + @JsonProperty("full_path") + private String fullPath; + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Boolean isLfsEnabled() { + return lfsEnabled; + } + + public void setLfsEnabled(Boolean lfsEnabled) { + this.lfsEnabled = lfsEnabled; + } + + public String getAvatarUrl() { + return avatarUrl; + } + + public void setAvatarUrl(String avatarUrl) { + this.avatarUrl = avatarUrl; + } + + public String getFullName() { + return fullName; + } + + public void setFullName(String fullName) { + this.fullName = fullName; + } + + public String getFullPath() { + return fullPath; + } + + public void setFullPath(String fullPath) { + this.fullPath = fullPath; + } + + public Boolean isRequestAccessEnabled() { + return requestAccessEnabled; + } + + public void setRequestAccessEnabled(Boolean requestAccessEnabled) { + this.requestAccessEnabled = requestAccessEnabled; + } + public Integer getId() { return id; } + public Integer getParentId() { + return parentId; + } + public void setId(Integer id) { this.id = id; } + public void setParentId(Integer parentId) { + this.parentId = parentId; + } + public String getName() { return name; } @@ -48,6 +143,38 @@ public void setLdapCn(String ldapCn) { this.ldapCn = ldapCn; } + public Boolean getMembershipLock() { + return membershipLock; + } + + public void setMembershipLock(Boolean membershipLock) { + this.membershipLock = membershipLock; + } + + public Boolean getShareWithGroupLock() { + return shareWithGroupLock; + } + + public void setShareWithGroupLock(Boolean shareWithGroupLock) { + this.shareWithGroupLock = shareWithGroupLock; + } + + public GitlabVisibility getVisibility() { + return visibility; + } + + public void setVisibility(GitlabVisibility visibility) { + this.visibility = visibility; + } + + public Integer getSharedRunnersMinutesLimit() { + return sharedRunnersMinutesLimit; + } + + public void setSharedRunnersMinutesLimit(Integer sharedRunnersMinutesLimit) { + this.sharedRunnersMinutesLimit = sharedRunnersMinutesLimit; + } + public GitlabAccessLevel getLdapAccess() { if (ldapAccess == null) { return null; @@ -60,4 +187,20 @@ public void setLdapAccess(GitlabAccessLevel ldapGitlabAccessLevel) { this.ldapAccess = ldapGitlabAccessLevel.accessValue; } } + + public List getSharedProjects() { + return sharedProjects; + } + + public void setSharedProjects(List sharedProjects) { + this.sharedProjects = sharedProjects; + } + + public String getWebUrl() { + return webUrl; + } + + public void setWebUrl(String webUrl) { + this.webUrl = webUrl; + } } diff --git a/src/main/java/org/gitlab/api/models/GitlabIssue.java b/src/main/java/org/gitlab/api/models/GitlabIssue.java index 3d7f8cef..046fe609 100644 --- a/src/main/java/org/gitlab/api/models/GitlabIssue.java +++ b/src/main/java/org/gitlab/api/models/GitlabIssue.java @@ -1,9 +1,15 @@ package org.gitlab.api.models; +import java.time.LocalDate; import java.util.Date; +import java.util.List; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; +@JsonIgnoreProperties(ignoreUnknown = true) public class GitlabIssue { public enum Action { @@ -26,9 +32,31 @@ public enum Action { private String[] labels; private GitlabMilestone milestone; + private List assignees; private GitlabUser assignee; private GitlabUser author; + @JsonProperty("user_notes_count") + private Integer userNotesCount; + + @JsonProperty("upvotes") + private Integer upVotes; + + @JsonProperty("downvotes") + private Integer downVotes; + + @JsonDeserialize(using = LocalDateDeserializer.class) + @JsonProperty("due_date") + private LocalDate dueDate; + + private Boolean confidential; + + @JsonProperty("discussion_locked") + private Boolean discussionLocked; + + @JsonProperty("time_stats") + private GitlabIssueTimeStats timeStats; + private String state; @JsonProperty("updated_at") @@ -37,6 +65,12 @@ public enum Action { @JsonProperty("created_at") private Date createdAt; + @JsonProperty("closed_at") + private Date closedAt; + + @JsonProperty("web_url") + private String webUrl; + public int getId() { return id; } @@ -93,6 +127,13 @@ public void setMilestone(GitlabMilestone milestone) { this.milestone = milestone; } + public List getAssignees() { + return assignees; + } + + public void setAssignees(List assignees) { + this.assignees = assignees; + } public GitlabUser getAssignee() { return assignee; } @@ -109,6 +150,62 @@ public void setAuthor(GitlabUser author) { this.author = author; } + public Integer getUserNotesCount() { + return userNotesCount; + } + + public void setUserNotesCount(Integer userNotesCount) { + this.userNotesCount = userNotesCount; + } + + public Integer getUpVotes() { + return upVotes; + } + + public void setUpVotes(Integer upVotes) { + this.upVotes = upVotes; + } + + public Integer getDownVotes() { + return downVotes; + } + + public void setDownVotes(Integer downVotes) { + this.downVotes = downVotes; + } + + public LocalDate getDueDate() { + return dueDate; + } + + public void setDueDate(LocalDate dueDate) { + this.dueDate = dueDate; + } + + public Boolean getConfidential() { + return confidential; + } + + public void setConfidential(Boolean confidential) { + this.confidential = confidential; + } + + public Boolean getDiscussionLocked() { + return discussionLocked; + } + + public void setDiscussionLocked(Boolean discussionLocked) { + this.discussionLocked = discussionLocked; + } + + public GitlabIssueTimeStats getTimeStats() { + return timeStats; + } + + public void setTimeStats(GitlabIssueTimeStats timeStats) { + this.timeStats = timeStats; + } + public String getState() { return state; } diff --git a/src/main/java/org/gitlab/api/models/GitlabIssueTimeStats.java b/src/main/java/org/gitlab/api/models/GitlabIssueTimeStats.java new file mode 100644 index 00000000..3f57e156 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabIssueTimeStats.java @@ -0,0 +1,40 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class GitlabIssueTimeStats { + + public static final String URL = "/time_stats"; + + @JsonProperty("time_estimate") + private long timeEstimate = 0; + + @JsonProperty("total_time_spent") + private long totalTimeSpent = 0; + + @JsonProperty("human_time_estimate") + private String humanTimeEstimate; + + @JsonProperty("human_total_time_spent") + private String humanTotalTimeSpent; + + public static String getURL() { + return URL; + } + + public long getTimeEstimate() { + return timeEstimate; + } + + public long getTotalTimeSpent() { + return totalTimeSpent; + } + + public String getHumanTimeEstimate() { + return humanTimeEstimate; + } + + public String getHumanTotalTimeSpent() { + return humanTotalTimeSpent; + } +} diff --git a/src/main/java/org/gitlab/api/models/GitlabJiraProperties.java b/src/main/java/org/gitlab/api/models/GitlabJiraProperties.java new file mode 100644 index 00000000..1702acf5 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabJiraProperties.java @@ -0,0 +1,48 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class GitlabJiraProperties { + + private String url; + + @JsonProperty("project_key") + private String projectKey; + + private String username; + private String password; + + @JsonProperty("jira_issue_transition_id") + private Integer issueTransitionId; + + public String getUrl() { + return url; + } + public void setUrl(String url) { + this.url = url; + } + public String getProjectKey() { + return projectKey; + } + public void setProjectKey(String projectKey) { + this.projectKey = projectKey; + } + public String getUsername() { + return username; + } + public void setUsername(String username) { + this.username = username; + } + public String getPassword() { + return password; + } + public void setPassword(String password) { + this.password = password; + } + public Integer getIssueTransitionId() { + return issueTransitionId; + } + public void setIssueTransitionId(Integer issueTransitionId) { + this.issueTransitionId = issueTransitionId; + } +} diff --git a/src/main/java/org/gitlab/api/models/GitlabBuild.java b/src/main/java/org/gitlab/api/models/GitlabJob.java similarity index 97% rename from src/main/java/org/gitlab/api/models/GitlabBuild.java rename to src/main/java/org/gitlab/api/models/GitlabJob.java index d1805138..4027c544 100644 --- a/src/main/java/org/gitlab/api/models/GitlabBuild.java +++ b/src/main/java/org/gitlab/api/models/GitlabJob.java @@ -3,9 +3,9 @@ import com.fasterxml.jackson.annotation.JsonProperty; -public class GitlabBuild { +public class GitlabJob { - public final static String URL = "/builds"; + public final static String URL = "/jobs"; private GitlabCommit commit; private Float coverage; diff --git a/src/main/java/org/gitlab/api/models/GitlabMergeRequest.java b/src/main/java/org/gitlab/api/models/GitlabMergeRequest.java index 40df1ccf..11d037e5 100644 --- a/src/main/java/org/gitlab/api/models/GitlabMergeRequest.java +++ b/src/main/java/org/gitlab/api/models/GitlabMergeRequest.java @@ -7,6 +7,9 @@ public class GitlabMergeRequest { public static final String URL = "/merge_requests"; + public static final String STATUS_OPENED = "opened"; + public static final String STATUS_MERGED = "merged"; + public static final String STATUS_CLOSED = "closed"; private Integer id; private Integer iid; @@ -20,10 +23,18 @@ public class GitlabMergeRequest { private GitlabMilestone milestone; private String[] labels; + private List changes; - private int upvotes; - private int downvotes; + private Integer upvotes; + + private Integer downvotes; + + @JsonProperty("updated_at") + private Date updatedAt; + + @JsonProperty("created_at") + private Date createdAt; @JsonProperty("target_branch") private String targetBranch; @@ -43,16 +54,65 @@ public class GitlabMergeRequest { @JsonProperty("milestone_id") private Integer milestoneId; - @JsonProperty("updated_at") - private Date updatedAt; - - @JsonProperty("created_at") - private Date createdAt; + @JsonProperty("work_in_progress") + private Boolean workInProgress; + @JsonProperty("merge_when_pipeline_succeeds") + private Boolean mergeWhenPipelineSucceeds; @JsonProperty("merge_status") private String mergeStatus; + @JsonProperty("sha") + private String sha; + + @JsonProperty("merge_commit_sha") + private String mergeCommitSHA; + + @JsonProperty("user_notes_count") + private Integer userNotesCount; + + @JsonProperty("discussion_locked") + private Boolean discussionLocked; + + @JsonProperty("should_remove_source_branch") + private Boolean shouldRemoveSourceBranch; + + @JsonProperty("force_remove_source_branch") + private Boolean forceRemoveSourceBranch; + + @JsonProperty("web_url") + private String webUrl; + + private Boolean squash; + + @JsonProperty("changes_count") + private String changesCount; + + @JsonProperty("merged_by") + private GitlabUser mergedBy; + + @JsonProperty("merged_at") + private Date mergedAt; + + @JsonProperty("closed_by") + private GitlabUser closedBy; + + @JsonProperty("closed_at") + private Date closedAt; + + @JsonProperty("latest_build_started_at") + private Date latestBuildStartedAt; + + @JsonProperty("latest_build_finished_at") + private Date latestBuildFinishedAt; + + @JsonProperty("first_deployed_to_production_at") + private Date firstDeployedToProductionAt; + + @JsonProperty("diff_refs") + private DiffRefs diffRefs; + public Integer getId() { return id; } @@ -191,7 +251,7 @@ public void setLabels(String[] labels) { this.labels = labels; } - public int getUpvotes() { + public Integer getUpvotes() { return upvotes; } @@ -199,7 +259,7 @@ public void setUpvotes(int upvotes) { this.upvotes = upvotes; } - public int getDownvotes() { + public Integer getDownvotes() { return downvotes; } @@ -239,7 +299,127 @@ public void setChanges(List changes) { this.changes = changes; } - public String getMergeStatus() { return mergeStatus; } + public String getMergeCommitSHA() { + return mergeCommitSHA; + } + + public void setMergeCommitSHA(String mergeCommitSHA) { + this.mergeCommitSHA = mergeCommitSHA; + } + + public String getMergeStatus() { + return mergeStatus; + } + + public void setMergeStatus(String mergeStatus) { + this.mergeStatus = mergeStatus; + } + + public String getWebUrl() { + return webUrl; + } + + public void setWebUrl(String webUrl) { + this.webUrl = webUrl; + } + + public String getSha() { + return sha; + } + + public void setSha(String sha) { + this.sha = sha; + } + + public Boolean isWorkInProgress() { + return workInProgress; + } + + + public Boolean isMergeWhenPipelineSucceeds() { + return mergeWhenPipelineSucceeds; + } + + public Integer getUserNotesCount() { + return userNotesCount; + } + + public Boolean isDiscussionLocked() { + return discussionLocked; + } + + public Boolean isShouldRemoveSourceBranch() { + return shouldRemoveSourceBranch; + } + + public Boolean isForceRemoveSourceBranch() { + return forceRemoveSourceBranch; + } + + public Boolean isSquash() { + return squash; + } - public void setMergeStatus(String mergeStatus) { this.mergeStatus = mergeStatus; } + public String getChangesCount() { + return changesCount; + } + + public GitlabUser getMergedBy() { + return mergedBy; + } + + public Date getMergedAt() { + return mergedAt; + } + + public GitlabUser getClosedBy() { + return closedBy; + } + + public Date getClosedAt() { + return closedAt; + } + + public Date getLatestBuildStartedAt() { + return latestBuildStartedAt; + } + + public Date getLatestBuildFinishedAt() { + return latestBuildFinishedAt; + } + + public Date getFirstDeployedToProductionAt() { + return firstDeployedToProductionAt; + } + + public String getBaseSha() { + return diffRefs == null ? null : diffRefs.baseSha; + } + + public String getHeadSha() { + return diffRefs == null ? null : diffRefs.headSha; + } + + public String getStartSha() { + return diffRefs == null ? null : diffRefs.startSha; + } + + /** + * Class representing the diff_refs json object, which is just a collection + * of sha references of the merge request. It is currently not provided by + * GitLab when fetching multiple merge requests. + * + * @author Patrizio Bonzani + */ + private static class DiffRefs { + + @JsonProperty("base_sha") + private String baseSha; + + @JsonProperty("head_sha") + private String headSha; + + @JsonProperty("start_sha") + private String startSha; + } } diff --git a/src/main/java/org/gitlab/api/models/GitlabMergeRequestApprovals.java b/src/main/java/org/gitlab/api/models/GitlabMergeRequestApprovals.java new file mode 100644 index 00000000..81c6c991 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabMergeRequestApprovals.java @@ -0,0 +1,168 @@ +package org.gitlab.api.models; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class GitlabMergeRequestApprovals { + public static final String URL = "/approvals"; + public static final String APPROVERS_URL = "/approvers"; + + private Integer id; + private Integer iid; + @JsonProperty("project_id") + private Integer projectId; + private String title; + private String description; + private String state; + + @JsonProperty("updated_at") + private Date updatedAt; + + @JsonProperty("created_at") + private Date createdAt; + + @JsonProperty("merge_status") + private String mergeStatus; + + @JsonProperty("approvals_required") + private Integer approvalsRequired; + + @JsonProperty("approvals_left") + private Integer approvalsLeft; + + @JsonProperty("approved_by") + private List approvedBy; + + @JsonProperty("suggested_approvers") + private List suggestedApprovers; + + private List approvers; + + @JsonProperty("approver_groups") + private List approverGroups; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getIid() { + return iid; + } + + public void setIid(Integer iid) { + this.iid = iid; + } + + public Integer getProjectId() { + return projectId; + } + + public void setProjectId(Integer projectId) { + this.projectId = projectId; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String d) { + description = d; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public Date getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public String getMergeStatus() { + return mergeStatus; + } + + public void setMergeStatus(String mergeStatus) { + this.mergeStatus = mergeStatus; + } + + public Integer getApprovalsRequired() { + return approvalsRequired; + } + + public void setApprovalsRequired(Integer approvalsRequired) { + this.approvalsRequired = approvalsRequired; + } + + public Integer getApprovalsLeft() { + return approvalsLeft; + } + + public void setApprovalsLeft(Integer approvalsLeft) { + this.approvalsLeft = approvalsLeft; + } + + public List getApprovedBy() { + return approvedBy; + } + + public void setApprovedBy(List approvedBy) { + this.approvedBy = approvedBy; + } + + public List getSuggestedApprovers() { + return suggestedApprovers; + } + + public void setSuggestedApprovers(List suggestedApprovers) { + this.suggestedApprovers = suggestedApprovers; + } + + public List getApprovers() { + return approvers; + } + + public void setApprovers(List approvers) { + this.approvers = approvers; + } + + public List getApproverGroups() { + return approverGroups; + } + + public void setApproverGroups(List approverGroups) { + this.approverGroups = approverGroups; + } + +} diff --git a/src/main/java/org/gitlab/api/models/GitlabMilestone.java b/src/main/java/org/gitlab/api/models/GitlabMilestone.java index de91ffd4..5f533e6e 100644 --- a/src/main/java/org/gitlab/api/models/GitlabMilestone.java +++ b/src/main/java/org/gitlab/api/models/GitlabMilestone.java @@ -15,6 +15,9 @@ public class GitlabMilestone { @JsonProperty("project_id") private int projectId; + @JsonProperty("group_id") + private int groupId; + private String title; private String description; @@ -22,6 +25,9 @@ public class GitlabMilestone { @JsonProperty("due_date") private Date dueDate; + @JsonProperty("start_date") + private Date startDate; + private String state; @JsonProperty("updated_date") @@ -54,6 +60,14 @@ public void setProjectId(int projectId) { this.projectId = projectId; } + public int getGroupId() { + return groupId; + } + + public void setGroupId(int groupId) { + this.groupId = groupId; + } + public String getTitle() { return title; } @@ -78,6 +92,14 @@ public void setDueDate(Date dueDate) { this.dueDate = dueDate; } + public Date getStartDate() { + return startDate; + } + + public void setStartDate(Date startDate) { + this.startDate = startDate; + } + public String getState() { return state; } diff --git a/src/main/java/org/gitlab/api/models/GitlabNamespace.java b/src/main/java/org/gitlab/api/models/GitlabNamespace.java index 5de74269..0173f86b 100644 --- a/src/main/java/org/gitlab/api/models/GitlabNamespace.java +++ b/src/main/java/org/gitlab/api/models/GitlabNamespace.java @@ -5,21 +5,24 @@ import com.fasterxml.jackson.annotation.JsonProperty; public class GitlabNamespace { - public static final String URL = "/groups"; + public static final String URL = "/namespaces"; private Integer id; private String name; private String path; - private String description; + private String kind; + private String plan; - @JsonProperty("created_at") - private Date createdAt; + @JsonProperty("full_path") + private String fullPath; + + @JsonProperty("parent_id") + private String parentId; + + @JsonProperty("members_count_with_descendants") + private Integer membersCountWithDescendants; - @JsonProperty("updated_at") - private Date updatedAt; - @JsonProperty("owner_id") - private Integer ownerId; public Integer getId() { return id; @@ -29,51 +32,80 @@ public void setId(Integer id) { this.id = id; } - public Date getCreatedAt() { - return createdAt; + public String getName() { + return name; } - public void setCreatedAt(Date createdAt) { - this.createdAt = createdAt; + public void setName(String name) { + this.name = name; } - public Date getUpdatedAt() { - return updatedAt; + public String getPath() { + return path; } - public void setUpdatedAt(Date updatedAt) { - this.updatedAt = updatedAt; + public void setPath(String path) { + this.path = path; } - public Integer getOwnerId() { - return ownerId; + public String getKind() { + return kind; } - public void setOwnerId(Integer ownerId) { - this.ownerId = ownerId; + public void setKind(String kind) { + this.kind = kind; } - public String getName() { - return name; + public String getPlan() { + return plan; } - public void setName(String name) { - this.name = name; + public void setPlan(String plan) { + this.plan = plan; } - public String getPath() { - return path; + public String getFullPath() { + return fullPath; } - public void setPath(String path) { - this.path = path; + public void setFullPath(String fullPath) { + this.fullPath = fullPath; + } + + public String getParentId() { + return parentId; + } + + public void setParentId(String parentId) { + this.parentId = parentId; + } + + public Integer getMembersCountWithDescendants() { + return membersCountWithDescendants; } - public String getDescription() { - return description; + public void setMembersCountWithDescendants(Integer membersCountWithDescendants) { + this.membersCountWithDescendants = membersCountWithDescendants; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + GitlabNamespace that = (GitlabNamespace) o; + + if (id != null || that.id != null) { + return id != null && id.equals(that.id); + } else { + return name != null ? name.equals(that.name) : that.name == null; + } } - public void setDescription(String description) { - this.description = description; + @Override + public int hashCode() { + int result = id != null ? id.hashCode() : 0; + result = 31 * result + (name != null ? name.hashCode() : 0); + return result; } } diff --git a/src/main/java/org/gitlab/api/models/GitlabPipeline.java b/src/main/java/org/gitlab/api/models/GitlabPipeline.java new file mode 100644 index 00000000..c2f55b95 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabPipeline.java @@ -0,0 +1,303 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import org.gitlab.api.jackson.InstantDeserializer; + +import java.time.Instant; + +public class GitlabPipeline { + public static final String URL = "/pipelines"; + + public static final String CREATE_URL = "/pipeline"; + + + @JsonProperty("id") + private Integer id; + + @JsonProperty("sha") + private String sha; + + @JsonProperty("ref") + private String ref; + + @JsonProperty("status") + private String status; + + @JsonProperty("web_url") + private String webUrl; + + @JsonProperty("before_sha") + private String beforeSha; + + @JsonProperty("tag") + private boolean tag; + + @JsonProperty("yaml_errors") + private String yamlErrors; + + @JsonProperty("user") + private GitlabUser user; + + @JsonProperty("created_at") + @JsonDeserialize(using = InstantDeserializer.class) + private Instant createdAt; + + @JsonProperty("updated_at") + @JsonDeserialize(using = InstantDeserializer.class) + private Instant updatedAt; + + @JsonProperty("started_at") + @JsonDeserialize(using = InstantDeserializer.class) + private Instant startedAt; + + @JsonProperty("finished_at") + @JsonDeserialize(using = InstantDeserializer.class) + private Instant finishedAt; + + @JsonProperty("committed_at") + @JsonDeserialize(using = InstantDeserializer.class) + private Instant committedAt; + + @JsonProperty("duration") + private int duration; + + @JsonProperty("coverage") + private String coverage; + + @JsonProperty("detailed_status") + private DetailedStatus detailedStatus; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getSha() { + return sha; + } + + public void setSha(String sha) { + this.sha = sha; + } + + public String getRef() { + return ref; + } + + public void setRef(String ref) { + this.ref = ref; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getWebUrl() { + return webUrl; + } + + public void setWebUrl(String webUrl) { + this.webUrl = webUrl; + } + + public String getBeforeSha() { + return beforeSha; + } + + public void setBeforeSha(String beforeSha) { + this.beforeSha = beforeSha; + } + + public boolean isTag() { + return tag; + } + + public void setTag(boolean tag) { + this.tag = tag; + } + + public String getYamlErrors() { + return yamlErrors; + } + + public void setYamlErrors(String yamlErrors) { + this.yamlErrors = yamlErrors; + } + + public GitlabUser getUser() { + return user; + } + + public void setUser(GitlabUser user) { + this.user = user; + } + + public Instant getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Instant createdAt) { + this.createdAt = createdAt; + } + + public Instant getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Instant updatedAt) { + this.updatedAt = updatedAt; + } + + public Instant getStartedAt() { + return startedAt; + } + + public void setStartedAt(Instant startedAt) { + this.startedAt = startedAt; + } + + public Instant getFinishedAt() { + return finishedAt; + } + + public void setFinishedAt(Instant finishedAt) { + this.finishedAt = finishedAt; + } + + public Instant getCommittedAt() { + return committedAt; + } + + public void setCommittedAt(Instant committedAt) { + this.committedAt = committedAt; + } + + public int getDuration() { + return duration; + } + + public void setDuration(int duration) { + this.duration = duration; + } + + public String getCoverage() { + return coverage; + } + + public void setCoverage(String coverage) { + this.coverage = coverage; + } + + public DetailedStatus getDetailedStatus() { + return detailedStatus; + } + + public void setDetailedStatus(DetailedStatus detailedStatus) { + this.detailedStatus = detailedStatus; + } + + public static class DetailedStatus { + + private String icon; + + private String text; + + private String label; + + private String group; + + private String tooltip; + + @JsonProperty("has_details") + private String hasDetails; + + @JsonProperty("details_path") + private String detailsPath; + + private String illustration; + + private String favicon; + + public String getIcon() { + return icon; + } + + public void setIcon(String icon) { + this.icon = icon; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getGroup() { + return group; + } + + public void setGroup(String group) { + this.group = group; + } + + public String getTooltip() { + return tooltip; + } + + public void setTooltip(String tooltip) { + this.tooltip = tooltip; + } + + public String getHasDetails() { + return hasDetails; + } + + public void setHasDetails(String hasDetails) { + this.hasDetails = hasDetails; + } + + public String getDetailsPath() { + return detailsPath; + } + + public void setDetailsPath(String detailsPath) { + this.detailsPath = detailsPath; + } + + public String getIllustration() { + return illustration; + } + + public void setIllustration(String illustration) { + this.illustration = illustration; + } + + public String getFavicon() { + return favicon; + } + + public void setFavicon(String favicon) { + this.favicon = favicon; + } + + } + +} diff --git a/src/main/java/org/gitlab/api/models/GitlabProject.java b/src/main/java/org/gitlab/api/models/GitlabProject.java index 7a2dc50f..a245d23b 100644 --- a/src/main/java/org/gitlab/api/models/GitlabProject.java +++ b/src/main/java/org/gitlab/api/models/GitlabProject.java @@ -21,38 +21,38 @@ public class GitlabProject { private String defaultBranch; private GitlabUser owner; - private boolean publicProject; + private Boolean publicProject; private String path; - @JsonProperty("visibility_level") - private Integer visibilityLevel; + @JsonProperty("visibility") + private String visibility; @JsonProperty("path_with_namespace") private String pathWithNamespace; @JsonProperty("issues_enabled") - private boolean issuesEnabled; + private Boolean issuesEnabled; @JsonProperty("merge_requests_enabled") - private boolean mergeRequestsEnabled; + private Boolean mergeRequestsEnabled; @JsonProperty("snippets_enabled") - private boolean snippetsEnabled; + private Boolean snippetsEnabled; @JsonProperty("wall_enabled") - private boolean wallEnabled; + private Boolean wallEnabled; @JsonProperty("wiki_enabled") - private boolean wikiEnabled; + private Boolean wikiEnabled; - @JsonProperty("builds_enabled") - private boolean buildsEnabled; + @JsonProperty("jobs_enabled") + private Boolean jobsEnabled; @JsonProperty("shared_runners_enabled") - private boolean sharedRunnersEnabled; + private Boolean sharedRunnersEnabled; - @JsonProperty("public_builds") - private boolean publicBuilds; + @JsonProperty("public_jobs") + private Boolean publicJobs; @JsonProperty("runners_token") private String runnersToken; @@ -73,7 +73,7 @@ public class GitlabProject { private Date lastActivityAt; @JsonProperty("archived") - private boolean archived; + private Boolean archived; private GitlabNamespace namespace; @@ -95,6 +95,45 @@ public class GitlabProject { @JsonProperty("tag_list") private List tagList; + @JsonProperty("shared_with_groups") + private List sharedWithGroups; + + @JsonProperty("container_registry_enabled") + private Boolean containerRegistryEnabled; + + @JsonProperty("only_allow_merge_if_pipeline_succeeds") + private Boolean onlyAllowMergeIfPipelineSucceeds; + + @JsonProperty("only_allow_merge_if_all_discussions_are_resolved") + private Boolean onlyAllowMergeIfAllDiscussionsAreResolved; + + @JsonProperty("lfs_enabled") + private Boolean lfsEnabled; + + @JsonProperty("request_access_enabled") + private Boolean requestAccessEnabled; + + @JsonProperty("repository_storage") + private String repositoryStorage; + + @JsonProperty("approvals_before_merge") + private Integer approvalsBeforeMerge; + + @JsonProperty("import_url") + private String importUrl; + + @JsonProperty("forked_from_project") + private GitlabProject forkedFrom; + + @JsonProperty("printing_merge_request_link_enabled") + private Boolean printingMergeRequestLinkEnabled; + + @JsonProperty("import_status") + private String importStatus; + + @JsonProperty("initialize_with_readme") + private Boolean initializeWithReadme; + public Integer getId() { return id; } @@ -135,12 +174,12 @@ public void setDefaultBranch(String defaultBranch) { this.defaultBranch = defaultBranch; } - public Integer getVisibilityLevel() { - return visibilityLevel; + public String getVisibility() { + return visibility; } - public void setVisibilityLevel(Integer visibilityLevel) { - this.visibilityLevel = visibilityLevel; + public void setVisibility(String visibility) { + this.visibility = visibility; } public GitlabUser getOwner() { @@ -167,68 +206,108 @@ public void setPathWithNamespace(String pathWithNamespace) { this.pathWithNamespace = pathWithNamespace; } - public boolean isIssuesEnabled() { + public Boolean isIssuesEnabled() { return issuesEnabled; } - public void setIssuesEnabled(boolean issuesEnabled) { + public void setIssuesEnabled(Boolean issuesEnabled) { this.issuesEnabled = issuesEnabled; } - public boolean isMergeRequestsEnabled() { + public Boolean isMergeRequestsEnabled() { return mergeRequestsEnabled; } - public void setMergeRequestsEnabled(boolean mergeRequestsEnabled) { + public void setMergeRequestsEnabled(Boolean mergeRequestsEnabled) { this.mergeRequestsEnabled = mergeRequestsEnabled; } - public boolean isSnippetsEnabled() { + public Boolean isSnippetsEnabled() { return snippetsEnabled; } - public void setSnippetsEnabled(boolean snippetsEnabled) { + public void setSnippetsEnabled(Boolean snippetsEnabled) { this.snippetsEnabled = snippetsEnabled; } - public boolean isWallEnabled() { + public Boolean isWallEnabled() { return wallEnabled; } - public void setWallEnabled(boolean wallEnabled) { + public void setWallEnabled(Boolean wallEnabled) { this.wallEnabled = wallEnabled; } - public boolean isWikiEnabled() { + public Boolean isWikiEnabled() { return wikiEnabled; } - public void setWikiEnabled(boolean wikiEnabled) { + public void setWikiEnabled(Boolean wikiEnabled) { this.wikiEnabled = wikiEnabled; } - public boolean isBuildsEnabled() { - return buildsEnabled; + public Boolean isJobsEnabled() { + return jobsEnabled; + } + + public void setJobsEnabled(Boolean jobsEnabled) { + this.jobsEnabled = jobsEnabled; + } + + public Boolean isRequestAccessEnabled() { + return requestAccessEnabled; } - public void setBuildsEnabled(boolean buildsEnabled) { - this.buildsEnabled = buildsEnabled; + public void setRequestAccessEnabled(Boolean requestAccessEnabled) { + this.requestAccessEnabled = requestAccessEnabled; } - public boolean isSharedRunnersEnabled() { + public Boolean isLfsEnabled() { + return lfsEnabled; + } + + public void setLfsEnabled(Boolean lfsEnabled) { + this.lfsEnabled = lfsEnabled; + } + + public Boolean isSharedRunnersEnabled() { return sharedRunnersEnabled; } - public void setSharedRunnersEnabled(boolean sharedRunnersEnabled) { + public void setSharedRunnersEnabled(Boolean sharedRunnersEnabled) { this.sharedRunnersEnabled = sharedRunnersEnabled; } - public boolean hasPublicBuilds() { - return publicBuilds; + public Boolean getOnlyAllowMergeIfPipelineSucceeds() { + return onlyAllowMergeIfPipelineSucceeds; } - public void setPublicBuilds(boolean publicBuilds) { - this.publicBuilds = publicBuilds; + public void setOnlyAllowMergeIfPipelineSucceeds(Boolean onlyAllowMergeIfPipelineSucceeds) { + this.onlyAllowMergeIfPipelineSucceeds = onlyAllowMergeIfPipelineSucceeds; + } + + public Boolean getOnlyAllowMergeIfAllDiscussionsAreResolved() { + return onlyAllowMergeIfAllDiscussionsAreResolved; + } + + public void setOnlyAllowMergeIfAllDiscussionsAreResolved(Boolean onlyAllowMergeIfAllDiscussionsAreResolved) { + this.onlyAllowMergeIfAllDiscussionsAreResolved = onlyAllowMergeIfAllDiscussionsAreResolved; + } + + public Boolean isContainerRegistryEnabled() { + return containerRegistryEnabled; + } + + public void setContainerRegistryEnabled(Boolean containerRegistryEnabled) { + this.containerRegistryEnabled = containerRegistryEnabled; + } + + public Boolean hasPublicJobs() { + return publicJobs; + } + + public void setPublicJobs(Boolean publicJobs) { + this.publicJobs = publicJobs; } public String getRunnersToken() { @@ -279,19 +358,19 @@ public void setNamespace(GitlabNamespace namespace) { this.namespace = namespace; } - public boolean isPublic() { + public Boolean isPublic() { return publicProject; } - public void setPublic(boolean aPublic) { + public void setPublic(Boolean aPublic) { publicProject = aPublic; } - public boolean isArchived() { + public Boolean isArchived() { return archived; } - public void setArchived(boolean archived) { + public void setArchived(Boolean archived) { this.archived = archived; } @@ -350,4 +429,83 @@ public List getTagList() { public void setTagList(List tagList) { this.tagList = tagList; } + + public List getSharedWithGroups() { + return sharedWithGroups; + } + + public void setSharedWithGroups(List sharedWithGroups) { + this.sharedWithGroups = sharedWithGroups; + } + + public String getRepositoryStorage() { + return repositoryStorage; + } + + public void setRepositoryStorage(String repositoryStorage) { + this.repositoryStorage = repositoryStorage; + } + + public Integer getApprovalsBeforeMerge() { + return approvalsBeforeMerge; + } + + public void setApprovalsBeforeMerge(Integer approvalsBeforeMerge) { + this.approvalsBeforeMerge = approvalsBeforeMerge; + } + + public String getImportUrl() { + return importUrl; + } + + public void setImportUrl(String importUrl) { + this.importUrl = importUrl; + } + + public GitlabProject getForkedFrom() { + return forkedFrom; + } + + public void setForkedFrom(GitlabProject forkedFrom) { + this.forkedFrom = forkedFrom; + } + + public Boolean isPrintingMergeRequestLinkEnabled() { + return printingMergeRequestLinkEnabled; + } + + public void setPrintingMergeRequestLinkEnabled(Boolean printingMergeRequestLinkEnabled) { + this.printingMergeRequestLinkEnabled = printingMergeRequestLinkEnabled; + } + + public Boolean isInitializeWithReadme() { + return initializeWithReadme; + } + + public void setInitializeWithReadme(Boolean initializeWithReadme) { + this.initializeWithReadme = initializeWithReadme; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + GitlabProject that = (GitlabProject) o; + + if (id != null || that.id != null) { + return id != null && id.equals(that.id); + } else { + if (name != null ? !name.equals(that.name) : that.name != null) return false; + return namespace != null ? namespace.equals(that.namespace) : that.namespace == null; + } + } + + @Override + public int hashCode() { + int result = id != null ? id.hashCode() : 0; + result = 31 * result + (name != null ? name.hashCode() : 0); + result = 31 * result + (namespace != null ? namespace.hashCode() : 0); + return result; + } } diff --git a/src/main/java/org/gitlab/api/models/GitlabProjectHook.java b/src/main/java/org/gitlab/api/models/GitlabProjectHook.java index 32f63ed4..34326f4c 100644 --- a/src/main/java/org/gitlab/api/models/GitlabProjectHook.java +++ b/src/main/java/org/gitlab/api/models/GitlabProjectHook.java @@ -25,13 +25,25 @@ public class GitlabProjectHook { @JsonProperty("tag_push_events") private boolean tagPushEvents; - + @JsonProperty("created_at") private Date createdAt; @JsonProperty("enable_ssl_verification") private boolean sslVerificationEnabled; + @JsonProperty("note_events") + private boolean noteEvents; + + @JsonProperty("job_events") + private boolean jobEvents; + + @JsonProperty("pipeline_events") + private boolean pipelineEvents; + + @JsonProperty("wiki_page_events") + private boolean wikiPageEvents; + public String getId() { return id; } @@ -80,15 +92,14 @@ public void setMergeRequestsEvents(boolean mergeRequestsEvents) { this.mergeRequestsEvents = mergeRequestsEvents; } - public boolean isTagPushEvents() { return tagPushEvents; } - + public void setTagPushEvents(boolean tagPushEvents) { this.tagPushEvents = tagPushEvents; } - + public Date getCreatedAt() { return createdAt; } @@ -105,4 +116,19 @@ public void setSslVerificationEnabled(boolean sslVerificationEnabled) { this.sslVerificationEnabled = sslVerificationEnabled; } + public boolean isNoteEvents() { return noteEvents; } + + public void setNoteEvents(boolean noteEvents) { this.noteEvents = noteEvents; } + + public boolean isJobEvents() { return jobEvents; } + + public void setJobEvents(boolean jobEvents) { this.jobEvents = jobEvents; } + + public boolean isPipelineEvents() { return pipelineEvents; } + + public void setPipelineEvents(boolean pipelineEvents) { this.pipelineEvents = pipelineEvents; } + + public boolean isWikiPageEvents() { return wikiPageEvents; } + + public void setWikiPageEvents(boolean wikiPageEvents) { this.wikiPageEvents = wikiPageEvents; } } diff --git a/src/main/java/org/gitlab/api/models/GitlabProjectSharedGroup.java b/src/main/java/org/gitlab/api/models/GitlabProjectSharedGroup.java new file mode 100644 index 00000000..46de51eb --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabProjectSharedGroup.java @@ -0,0 +1,38 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class GitlabProjectSharedGroup { + @JsonProperty("group_id") + private int groupId; + + @JsonProperty("group_name") + private String groupName; + + @JsonProperty("group_access_level") + private int groupAccessLevel; + + public int getGroupId() { + return groupId; + } + + public void setGroupId(int groupId) { + this.groupId = groupId; + } + + public String getGroupName() { + return groupName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } + + public GitlabAccessLevel getAccessLevel() { + return GitlabAccessLevel.fromAccessValue(groupAccessLevel); + } + + public void setAccessLevel(GitlabAccessLevel accessLevel) { + this.groupAccessLevel = accessLevel.accessValue; + } +} diff --git a/src/main/java/org/gitlab/api/models/GitlabPushData.java b/src/main/java/org/gitlab/api/models/GitlabPushData.java new file mode 100644 index 00000000..95f8f4d7 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabPushData.java @@ -0,0 +1,85 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Date; +import java.util.List; + +public class GitlabPushData { + + @JsonProperty("commit_count") + private int commitCount; + + @JsonProperty("action") + private GitlabEvent.ActionType action; + + @JsonProperty("ref_type") + private String refType; + + @JsonProperty("commit_from") + private String commitFrom; + + @JsonProperty("commit_to") + private String commitTo; + + private String ref; + + @JsonProperty("commit_title") + private String commitTitle; + + public int getCommitCount() { + return commitCount; + } + + public GitlabEvent.ActionType getAction() { + return action; + } + + public String getRefType() { + return refType; + } + + public String getCommitFrom() { + return commitFrom; + } + + public String getCommitTo() { + return commitTo; + } + + public String getRef() { + return ref; + } + + public String getCommitTitle() { + return commitTitle; + } + + public void setCommitCount(int commitCount) { + this.commitCount = commitCount; + } + + public void setAction(GitlabEvent.ActionType action) { + this.action = action; + } + + public void setRefType(String refType) { + this.refType = refType; + } + + public void setCommitFrom(String commitFrom) { + this.commitFrom = commitFrom; + } + + public void setCommitTo(String commitTo) { + this.commitTo = commitTo; + } + + public void setRef(String ref) { + this.ref = ref; + } + + public void setCommitTitle(String commitTitle) { + this.commitTitle = commitTitle; + } +} diff --git a/src/main/java/org/gitlab/api/models/GitlabRepositoryFile.java b/src/main/java/org/gitlab/api/models/GitlabRepositoryFile.java new file mode 100644 index 00000000..38086333 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabRepositoryFile.java @@ -0,0 +1,103 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * @author Kohsuke Kawaguchi + */ +public class GitlabRepositoryFile { + /* + "ref" : "master", + "blob_id" : "17cab971a4202e8342effbb358ebe07c2de8fcc0", + "commit_id" : "e8e073d98a6f15f8018e3359bf7bce3a6a144227", + "encoding" : "base64", + "size" : 21, + "content" : "VGhpcyBpcyBzdXBlciB3aWRnZXQK", + "file_path" : "README.md", + "file_name" : "README.md", + "last_commit_id" : "c0ad9bcdc43bc7f4050c58c699ff44cb8b916cdb" + */ + + private String ref; + + @JsonProperty("blob_id") + private String blobId; + + @JsonProperty("commit_id") + private String commitId; + + @JsonProperty("last_commit_id") + private String lastCommitId; + + @JsonProperty("file_path") + private String filePath; + + @JsonProperty("file_name") + private String fileName; + + private String encoding, content; + + public String getRef() { + return ref; + } + + public void setRef(String ref) { + this.ref = ref; + } + + public String getBlobId() { + return blobId; + } + + public void setBlobId(String blobId) { + this.blobId = blobId; + } + + public String getCommitId() { + return commitId; + } + + public void setCommitId(String commitId) { + this.commitId = commitId; + } + + public String getLastCommitId() { + return lastCommitId; + } + + public void setLastCommitId(String lastCommitId) { + this.lastCommitId = lastCommitId; + } + + public String getFilePath() { + return filePath; + } + + public void setFilePath(String filePath) { + this.filePath = filePath; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public String getEncoding() { + return encoding; + } + + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } +} diff --git a/src/main/java/org/gitlab/api/models/GitlabRepositoryTree.java b/src/main/java/org/gitlab/api/models/GitlabRepositoryTree.java index f9a1c3fe..02784d78 100644 --- a/src/main/java/org/gitlab/api/models/GitlabRepositoryTree.java +++ b/src/main/java/org/gitlab/api/models/GitlabRepositoryTree.java @@ -7,6 +7,7 @@ public class GitlabRepositoryTree { private String type; private String mode; private String id; + private String path; public String getName() { return name; @@ -40,4 +41,11 @@ public void setId(String id) { this.id = id; } + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } } diff --git a/src/main/java/org/gitlab/api/models/GitlabRunner.java b/src/main/java/org/gitlab/api/models/GitlabRunner.java index 85dfe1ab..d03d0561 100644 --- a/src/main/java/org/gitlab/api/models/GitlabRunner.java +++ b/src/main/java/org/gitlab/api/models/GitlabRunner.java @@ -3,17 +3,66 @@ import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Date; +import java.util.List; + public class GitlabRunner { + public static final String URL = "/runners"; + + public enum RunnerScope { + SPECIFIC("specific"), + SHARED("shared"), + ACTIVE("active"), + PAUSED("paused"), + ONLINE("online"), + ALL(null); + + private final String scope; + + RunnerScope(String scope) { + this.scope = scope; + } + + public String getScope() { + return this.scope; + } + } + @JsonProperty("id") private Integer id; + @JsonProperty("description") private String description; + @JsonProperty("active") private Boolean active; @JsonProperty("is_shared") private Boolean isShared; + @JsonProperty("name") private String name; + @JsonProperty("version") + private String version; + @JsonProperty("revision") + private String revision; + @JsonProperty("contacted_at") + private Date contactedAt; + @JsonProperty("tag_list") + private List tagList; + @JsonProperty("run_untagged") + private Boolean runUntagged; + @JsonProperty("locked") + private Boolean locked; + @JsonProperty("platform") + private String platform; + @JsonProperty("architecture") + private String architecture; + @JsonProperty("projects") + private List projects; + @JsonProperty("online") + private Boolean online; + @JsonProperty("status") + private String status; public Integer getId() { - return id; + return this.id; } public void setId(Integer id) { @@ -21,7 +70,7 @@ public void setId(Integer id) { } public String getDescription() { - return description; + return this.description; } public void setDescription(String description) { @@ -29,7 +78,7 @@ public void setDescription(String description) { } public Boolean getActive() { - return active; + return this.active; } public void setActive(Boolean active) { @@ -37,18 +86,99 @@ public void setActive(Boolean active) { } public Boolean getShared() { - return isShared; + return this.isShared; } public void setShared(Boolean shared) { - isShared = shared; + this.isShared = shared; } public String getName() { - return name; + return this.name; } public void setName(String name) { this.name = name; } + + public String getVersion() { + return this.version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getRevision() { + return this.revision; + } + + public void setRevision(String revision) { + this.revision = revision; + } + + public Date getContactedAt() { + return this.contactedAt; + } + + public void setContactedAt(Date contactedAt) { + this.contactedAt = contactedAt; + } + + public List getTagList() { + return this.tagList; + } + + public void setTagList(List tagList) { + this.tagList = tagList; + } + + public Boolean isRunUntagged() { + return this.runUntagged; + } + + public void setRunUntagged(boolean runUntagged) { + this.runUntagged = runUntagged; + } + + public Boolean isLocked() { + return this.locked; + } + + public void setLocked(boolean locked) { + this.locked = locked; + } + + + public String getPlatform() { + return this.platform; + } + + public void setPlatform(String platform) { + this.platform = platform; + } + + public String getArchitecture() { + return this.architecture; + } + + public void setArchitecture(String architecture) { + this.architecture = architecture; + } + + public Boolean getOnline() { + return this.online; + } + + public void setOnline(boolean online) { + this.online = online; + } + + public String getStatus() { + return this.status; + } + + public void setStatus(String status) { + this.status = status; + } } diff --git a/src/main/java/org/gitlab/api/models/GitlabSSHKey.java b/src/main/java/org/gitlab/api/models/GitlabSSHKey.java index 4635ae5a..f9e29e6e 100644 --- a/src/main/java/org/gitlab/api/models/GitlabSSHKey.java +++ b/src/main/java/org/gitlab/api/models/GitlabSSHKey.java @@ -3,6 +3,7 @@ public class GitlabSSHKey { public static String KEYS_URL = "/keys"; + public static String DEPLOY_KEYS_URL = "/deploy_keys"; private Integer _id; private String _title; diff --git a/src/main/java/org/gitlab/api/models/GitlabServiceEmailOnPush.java b/src/main/java/org/gitlab/api/models/GitlabServiceEmailOnPush.java new file mode 100644 index 00000000..ca6a1ce8 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabServiceEmailOnPush.java @@ -0,0 +1,123 @@ +package org.gitlab.api.models; + +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class GitlabServiceEmailOnPush { + + public static final String URL = "/services/emails-on-push/"; + + private Integer id; + private String title; + + @JsonProperty("created_at") + private Date createdAt; + + @JsonProperty("updated_at") + private Date updatedAt; + + private boolean active; + private boolean push_events; + private boolean issues_events; + private boolean merge_requests_events; + private boolean tag_push_events; + private boolean note_events; + private boolean build_events; + private GitlabEmailonPushProperties properties; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public Date getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + + public boolean isActive() { + return active; + } + + public void setActive(boolean active) { + this.active = active; + } + + public boolean isPushEvents() { + return push_events; + } + + public void setPushEvents(boolean push_events) { + this.push_events = push_events; + } + + public boolean isIssuesEvents() { + return issues_events; + } + + public void setIssuesEvents(boolean issues_events) { + this.issues_events = issues_events; + } + + public boolean isMergeRequestsEvents() { + return merge_requests_events; + } + + public void setMergeRequestsEvents(boolean merge_requests_events) { + this.merge_requests_events = merge_requests_events; + } + + public boolean isTagPushEvents() { + return tag_push_events; + } + + public void setTagPushEvents(boolean tag_push_events) { + this.tag_push_events = tag_push_events; + } + + public boolean isNoteEvents() { + return note_events; + } + + public void setNoteEvents(boolean note_events) { + this.note_events = note_events; + } + + public boolean isBuildEvents() { + return build_events; + } + + public void setBuildEvents(boolean build_events) { + this.build_events = build_events; + } + + public GitlabEmailonPushProperties getProperties() { + return properties; + } + + public void setProperties(GitlabEmailonPushProperties properties) { + this.properties = properties; + } +} diff --git a/src/main/java/org/gitlab/api/models/GitlabServiceJira.java b/src/main/java/org/gitlab/api/models/GitlabServiceJira.java new file mode 100644 index 00000000..159fa239 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabServiceJira.java @@ -0,0 +1,124 @@ +package org.gitlab.api.models; + +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class GitlabServiceJira { + + public static final String URL = "/services/jira/"; + + private Integer id; + private String title; + + @JsonProperty("created_at") + private Date createdAt; + + @JsonProperty("updated_at") + private Date updatedAt; + + private boolean active; + private boolean push_events; + private boolean issues_events; + private boolean merge_requests_events; + private boolean tag_push_events; + private boolean note_events; + private boolean build_events; + private GitlabJiraProperties properties; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public Date getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + + public boolean isActive() { + return active; + } + + public void setActive(boolean active) { + this.active = active; + } + + public boolean isPushEvents() { + return push_events; + } + + public void setPushEvents(boolean push_events) { + this.push_events = push_events; + } + + public boolean isIssuesEvents() { + return issues_events; + } + + public void setIssuesEvents(boolean issues_events) { + this.issues_events = issues_events; + } + + public boolean isMergeRequestsEvents() { + return merge_requests_events; + } + + public void setMergeRequestsEvents(boolean merge_requests_events) { + this.merge_requests_events = merge_requests_events; + } + + public boolean isTagPushEvents() { + return tag_push_events; + } + + public void setTagPushEvents(boolean tag_push_events) { + this.tag_push_events = tag_push_events; + } + + public boolean isNoteEvents() { + return note_events; + } + + public void setNoteEvents(boolean note_events) { + this.note_events = note_events; + } + + public boolean isBuildEvents() { + return build_events; + } + + public void setBuildEvents(boolean build_events) { + this.build_events = build_events; + } + + public GitlabJiraProperties getProperties() { + return properties; + } + public void setProperties(GitlabJiraProperties properties) { + this.properties = properties; + } + +} diff --git a/src/main/java/org/gitlab/api/models/GitlabSimpleRepositoryFile.java b/src/main/java/org/gitlab/api/models/GitlabSimpleRepositoryFile.java new file mode 100644 index 00000000..f1075922 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabSimpleRepositoryFile.java @@ -0,0 +1,32 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class GitlabSimpleRepositoryFile { + /* + "file_name": "app/project.rb", + "branch_name": "master" + */ + + @JsonProperty("file_path") + private String filePath; + + @JsonProperty("branch") + private String branchName; + + public String getFilePath() { + return filePath; + } + + public void setFilePath(String filePath) { + this.filePath = filePath; + } + + public String getBranchName() { + return branchName; + } + + public void setBranchName(String branchName) { + this.branchName = branchName; + } +} diff --git a/src/main/java/org/gitlab/api/models/GitlabTag.java b/src/main/java/org/gitlab/api/models/GitlabTag.java index 4ed51596..c0ec8cbb 100644 --- a/src/main/java/org/gitlab/api/models/GitlabTag.java +++ b/src/main/java/org/gitlab/api/models/GitlabTag.java @@ -7,7 +7,7 @@ public class GitlabTag { public final static String URL = "/repository/tags"; @JsonProperty("commit") - private GitlabBranchCommit commit; + private GitlabCommit commit; @JsonProperty("release") private GitlabRelease release; @@ -18,11 +18,11 @@ public class GitlabTag { @JsonProperty("message") private String message; - public GitlabBranchCommit getCommit() { + public GitlabCommit getCommit() { return commit; } - public void setCommit(GitlabBranchCommit commit) { + public void setCommit(GitlabCommit commit) { this.commit = commit; } diff --git a/src/main/java/org/gitlab/api/models/GitlabUpload.java b/src/main/java/org/gitlab/api/models/GitlabUpload.java new file mode 100644 index 00000000..407d2033 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabUpload.java @@ -0,0 +1,35 @@ +package org.gitlab.api.models; + +public class GitlabUpload { + + public final static String URL = "/uploads"; + + private String alt; + private String url; + private String markdown; + + public String getAlt() { + return alt; + } + + public void setAlt(String alt) { + this.alt = alt; + } + + public String getMarkdown() { + return markdown; + } + + public void setMarkdown(String markdown) { + this.markdown = markdown; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + +} diff --git a/src/main/java/org/gitlab/api/models/GitlabUser.java b/src/main/java/org/gitlab/api/models/GitlabUser.java index e0b613cc..9f6cff5f 100644 --- a/src/main/java/org/gitlab/api/models/GitlabUser.java +++ b/src/main/java/org/gitlab/api/models/GitlabUser.java @@ -1,9 +1,12 @@ package org.gitlab.api.models; -import java.util.Date; - +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Date; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) public class GitlabUser { public static String URL = "/users"; @@ -21,7 +24,8 @@ public class GitlabUser { private String _twitter; private String _provider; private String _state; - private boolean _blocked; + private Boolean _blocked; + private List _identities; @JsonProperty("private_token") private String _privateToken; @@ -42,7 +46,7 @@ public class GitlabUser { private String _bio; @JsonProperty("dark_scheme") - private boolean _darkScheme; + private Boolean _darkScheme; @JsonProperty("theme_id") private Integer _themeId; @@ -51,16 +55,19 @@ public class GitlabUser { private String _externUid; @JsonProperty("is_admin") - private boolean _isAdmin; + private Boolean _isAdmin; @JsonProperty("can_create_group") - private boolean _canCreateGroup; + private Boolean _canCreateGroup; @JsonProperty("can_create_project") - private boolean _canCreateProject; + private Boolean _canCreateProject; @JsonProperty("can_create_team") - private boolean _canCreateTeam; + private Boolean _canCreateTeam; + + @JsonProperty("external") + private boolean _external; @JsonProperty("avatar_url") private String _avatarUrl; @@ -74,172 +81,183 @@ public class GitlabUser { @JsonProperty("projects_limit") private Integer _projectsLimit; + @JsonProperty("last_activity_on") + private Date _lastActivityOn; + public Integer getId() { - return _id; + return this._id; } public void setId(Integer id) { - _id = id; + this._id = id; } public String getUsername() { - return _username; + return this._username; } public void setUsername(String userName) { - _username = userName; + this._username = userName; } public String getEmail() { - return _email; + return this._email; } public void setEmail(String email) { - _email = email; + this._email = email; } public String getName() { - return _name; + return this._name; } public void setName(String name) { - _name = name; + this._name = name; } - public boolean isBlocked() { - return _blocked; + public Boolean isBlocked() { + return this._blocked; } - public void setBlocked(boolean blocked) { - _blocked = blocked; + public void setBlocked(Boolean blocked) { + this._blocked = blocked; } public Date getCreatedAt() { - return _createdAt; + return this._createdAt; } public void setCreatedAt(Date createdAt) { - _createdAt = createdAt; + this._createdAt = createdAt; } public String getBio() { - return _bio; + return this._bio; } public void setBio(String bio) { - _bio = bio; + this._bio = bio; } public String getSkype() { - return _skype; + return this._skype; } public void setSkype(String skype) { - _skype = skype; + this._skype = skype; } public String getLinkedin() { - return _linkedin; + return this._linkedin; } public void setLinkedin(String linkedin) { - _linkedin = linkedin; + this._linkedin = linkedin; } public String getTwitter() { - return _twitter; + return this._twitter; } public void setTwitter(String twitter) { - _twitter = twitter; + this._twitter = twitter; } - public boolean isDarkScheme() { - return _darkScheme; + public Boolean isDarkScheme() { + return this._darkScheme; } public void setDarkScheme(boolean darkScheme) { - _darkScheme = darkScheme; + this._darkScheme = darkScheme; } public Integer getThemeId() { - return _themeId; + return this._themeId; } public void setThemeId(Integer themeId) { - _themeId = themeId; + this._themeId = themeId; } public String getExternUid() { - return _externUid; + return this._externUid; } public void setExternUid(String externUid) { - _externUid = externUid; + this._externUid = externUid; } public String getProvider() { - return _provider; + return this._provider; } public void setProvider(String provider) { - _provider = provider; + this._provider = provider; } public String getState() { - return _state; + return this._state; } public void setState(String state) { - _state = state; + this._state = state; } public String getExternProviderName() { - return _externProviderName; + return this._externProviderName; } public void setExternProviderName(String externProviderName) { - _externProviderName = externProviderName; + this._externProviderName = externProviderName; } public String getWebsiteUrl() { - return _websiteUrl; + return this._websiteUrl; } public void setWebsiteUrl(String websiteUrl) { - _websiteUrl = websiteUrl; + this._websiteUrl = websiteUrl; } - public boolean isAdmin() { - return _isAdmin; + public Boolean isAdmin() { + return this._isAdmin; } public void setAdmin(boolean admin) { - _isAdmin = admin; + this._isAdmin = admin; } - public boolean isCanCreateGroup() { - return _canCreateGroup; + public Boolean isCanCreateGroup() { + return this._canCreateGroup; } public void setCanCreateGroup(boolean canCreateGroup) { - _canCreateGroup = canCreateGroup; + this._canCreateGroup = canCreateGroup; } - public boolean isCanCreateProject() { - return _canCreateProject; + public Boolean isCanCreateProject() { + return this._canCreateProject; } public void setCanCreateProject(boolean canCreateProject) { - _canCreateProject = canCreateProject; + this._canCreateProject = canCreateProject; } - public boolean isCanCreateTeam() { - return _canCreateTeam; + public Boolean isCanCreateTeam() { + return this._canCreateTeam; } public void setCanCreateTeam(boolean canCreateTeam) { - _canCreateTeam = canCreateTeam; + this._canCreateTeam = canCreateTeam; + } + + public boolean isExternal() { + return _external; + } + + public void setExternal(boolean external) { + _external = external; } public String getAvatarUrl() { @@ -259,7 +277,7 @@ public void setColorSchemeId(Integer colorSchemeId) { } public String getPrivateToken() { - return _privateToken; + return this._privateToken; } public void setPrivateToken(String privateToken) { @@ -267,26 +285,42 @@ public void setPrivateToken(String privateToken) { } public Date getLastSignInAt() { - return _lastSignInAt; + return this._lastSignInAt; } public void setLastSignInAt(Date lastSignInAt) { - _lastSignInAt = lastSignInAt; + this._lastSignInAt = lastSignInAt; } public Date getCurrentSignInAt() { - return _currentSignInAt; + return this._currentSignInAt; } public void setCurrentSignInAt(Date currentSignInAt) { - _currentSignInAt = currentSignInAt; + this._currentSignInAt = currentSignInAt; } public Integer getProjectsLimit() { - return _projectsLimit; + return this._projectsLimit; } public void setProjectsLimit(Integer projectsLimit) { this._projectsLimit = projectsLimit; } + + public List getIdentities() { + return this._identities; + } + + public void setIdentities(List identities) { + this._identities = identities; + } + + public Date getLastActivityOn() { + return this._lastActivityOn; + } + + public void setLastActivityOn(Date _lastActivityOn) { + this._lastActivityOn = _lastActivityOn; + } } diff --git a/src/main/java/org/gitlab/api/models/GitlabUserIdentity.java b/src/main/java/org/gitlab/api/models/GitlabUserIdentity.java new file mode 100644 index 00000000..94171842 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabUserIdentity.java @@ -0,0 +1,28 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class GitlabUserIdentity { + + @JsonProperty("provider") + private String _provider; + + @JsonProperty("extern_uid") + private String _externUid; + + public String getProvider() { + return _provider; + } + + public void setProvider(String provider) { + this._provider = provider; + } + + public String getExternUid() { + return _externUid; + } + + public void setExternUuid(String externUid) { + this._externUid = externUid; + } +} diff --git a/src/main/java/org/gitlab/api/models/GitlabVersion.java b/src/main/java/org/gitlab/api/models/GitlabVersion.java new file mode 100644 index 00000000..976f3703 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabVersion.java @@ -0,0 +1,13 @@ +package org.gitlab.api.models; + +public class GitlabVersion { + private String version,revision; + + public String getVersion() { + return version; + } + + public String getRevision() { + return revision; + } +} diff --git a/src/main/java/org/gitlab/api/models/GitlabVisibility.java b/src/main/java/org/gitlab/api/models/GitlabVisibility.java new file mode 100644 index 00000000..fa209336 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabVisibility.java @@ -0,0 +1,20 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Enum for the privacy settings supported by GitLab API v4. + */ +public enum GitlabVisibility { + PRIVATE, INTERNAL, PUBLIC; + + /** + * Returns lower-case of {@link #name()}. Lower-case is required for requests + * that accept a visiblity parameter. + */ + @Override + @JsonValue + public String toString() { + return name().toLowerCase(); + } +} \ No newline at end of file diff --git a/src/main/java/org/gitlab/api/models/SortOrder.java b/src/main/java/org/gitlab/api/models/SortOrder.java new file mode 100644 index 00000000..a181791f --- /dev/null +++ b/src/main/java/org/gitlab/api/models/SortOrder.java @@ -0,0 +1,12 @@ +package org.gitlab.api.models; + +public enum SortOrder { + ASC, DESC; + + public static final SortOrder DEFAULT = DESC; + + @Override + public String toString() { + return name().toLowerCase(); + } +} diff --git a/src/main/java/org/gitlab/api/query/PaginationQuery.java b/src/main/java/org/gitlab/api/query/PaginationQuery.java new file mode 100644 index 00000000..7996ec3f --- /dev/null +++ b/src/main/java/org/gitlab/api/query/PaginationQuery.java @@ -0,0 +1,40 @@ +package org.gitlab.api.query; + +import org.gitlab.api.http.Query; + +import java.io.UnsupportedEncodingException; + +public class PaginationQuery extends Query { + + public static final String PARAM_PAGE = "page"; + public static final String PARAM_PER_PAGE = "per_page"; + public static final int MAX_ITEMS_PER_PAGE = 100; + + public void setPage(int page) { + try { + append(PARAM_PAGE, String.valueOf(page)); + } catch (UnsupportedEncodingException ignored) { + } + } + + public void setPerPage(int perPage) { + if (perPage > MAX_ITEMS_PER_PAGE) { + throw new IllegalArgumentException("Max value for perPage is " + MAX_ITEMS_PER_PAGE); + } + try { + append(PARAM_PER_PAGE, String.valueOf(perPage)); + } catch (UnsupportedEncodingException ignored) { + } + } + + public PaginationQuery withPage(int page) { + setPage(page); + return this; + } + + public PaginationQuery withPerPage(int perPage) { + setPerPage(perPage); + return this; + } + +} diff --git a/src/main/java/org/gitlab/api/query/PipelinesQuery.java b/src/main/java/org/gitlab/api/query/PipelinesQuery.java new file mode 100644 index 00000000..5c919e2c --- /dev/null +++ b/src/main/java/org/gitlab/api/query/PipelinesQuery.java @@ -0,0 +1,100 @@ +package org.gitlab.api.query; + +import java.io.UnsupportedEncodingException; + +public class PipelinesQuery extends PaginationQuery { + + public void setScope(String scope) throws UnsupportedEncodingException { + appendIf("scope", scope); + } + + public PipelinesQuery withScope(String scope) throws UnsupportedEncodingException { + this.setScope(scope); + return this; + } + + public void setStatus(String status) throws UnsupportedEncodingException { + appendIf("status", status); + } + + public PipelinesQuery withStatus(String status) throws UnsupportedEncodingException { + this.setStatus(status); + return this; + } + + public void setRef(String ref) throws UnsupportedEncodingException { + appendIf("ref", ref); + } + + public PipelinesQuery withRef(String ref) throws UnsupportedEncodingException { + this.setRef(ref); + return this; + } + + public void setSha(String sha) throws UnsupportedEncodingException { + appendIf("sha", sha); + } + + public PipelinesQuery withSha(String sha) throws UnsupportedEncodingException { + this.setSha(sha); + return this; + } + + public void setYamlErrors(Boolean yamlErrors) throws UnsupportedEncodingException { + appendIf("yaml_errors", yamlErrors); + } + + public PipelinesQuery withYamlErrors(Boolean yamlErrors) throws UnsupportedEncodingException { + this.setYamlErrors(yamlErrors); + return this; + } + + public void setName(String name) throws UnsupportedEncodingException { + appendIf("name", name); + } + + public PipelinesQuery withName(String name) throws UnsupportedEncodingException { + this.setName(name); + return this; + } + + public void setUsername(String username) throws UnsupportedEncodingException { + appendIf("username", username); + } + + public PipelinesQuery withUsername(String username) throws UnsupportedEncodingException { + this.setUsername(username); + return this; + } + + public void setOrderBy(String orderBy) throws UnsupportedEncodingException { + appendIf("order_by", orderBy); + } + + public PipelinesQuery withOrderBy(String orderBy) throws UnsupportedEncodingException { + this.setOrderBy(orderBy); + return this; + } + + public void setSort(String sort) throws UnsupportedEncodingException { + appendIf("sort", sort); + } + + public PipelinesQuery withSort(String sort) throws UnsupportedEncodingException { + this.setSort(sort); + return this; + } + + @Override + public PipelinesQuery withPage(int page) { + super.withPage(page); + return this; + } + + @Override + public PipelinesQuery withPerPage(int perPage) { + super.withPerPage(perPage); + return this; + } + +} diff --git a/src/main/java/org/gitlab/api/query/ProjectsQuery.java b/src/main/java/org/gitlab/api/query/ProjectsQuery.java new file mode 100644 index 00000000..02fd4142 --- /dev/null +++ b/src/main/java/org/gitlab/api/query/ProjectsQuery.java @@ -0,0 +1,192 @@ +package org.gitlab.api.query; + +import org.gitlab.api.models.GitlabAccessLevel; + +import java.io.UnsupportedEncodingException; + +public class ProjectsQuery extends PaginationQuery { + + public static final String PARAM_ARCHIVED = "archived"; + public static final String PARAM_VISIBILITY = "visibility"; + public static final String PARAM_ORDER_BY = "order_by"; + public static final String PARAM_SORT = "sort"; + public static final String PARAM_SEARCH = "search"; + public static final String PARAM_SIMPLE = "simple"; + public static final String PARAM_OWNED = "owned"; + public static final String PARAM_MEMBERSHIP = "membership"; + public static final String PARAM_STARRED = "starred"; + public static final String PARAM_STATISTICS = "statistics"; + public static final String PARAM_WITH_CUSTOM_ATTRIBUTES = "with_custom_attributes"; + public static final String PARAM_WITH_ISSUES_ENABLED = "with_issues_enabled"; + public static final String PARAM_WITH_MERGE_REQUESTS_ENABLED = "with_merge_requests_enabled"; + public static final String PARAM_WITH_PROGRAMMING_LANGUAGE = "with_programming_language"; + public static final String PARAM_WIKI_CHECKSUM_FAILED = "wiki_checksum_failed"; + public static final String PARAM_REPOSITORY_CHECKSUM_FAILED = "repository_checksum_failed"; + public static final String PARAM_MIN_ACCESS_LEVEL = "min_access_level"; + + public void setArchived(Boolean archived) throws UnsupportedEncodingException { + appendIf(PARAM_ARCHIVED, archived); + } + + public ProjectsQuery withArchived(Boolean archived) throws UnsupportedEncodingException { + setArchived(archived); + return this; + } + + public void setVisibility(String visibility) throws UnsupportedEncodingException { + appendIf(PARAM_VISIBILITY, visibility); + } + + public ProjectsQuery withVisibility(String visibility) throws UnsupportedEncodingException { + setVisibility(visibility); + return this; + } + + public void setOrderBy(String orderBy) throws UnsupportedEncodingException { + appendIf(PARAM_ORDER_BY, orderBy); + } + + public ProjectsQuery withOrderBy(String orderBy) throws UnsupportedEncodingException { + setOrderBy(orderBy); + return this; + } + + public void setSort(String sort) throws UnsupportedEncodingException { + appendIf(PARAM_SORT, sort); + } + + public ProjectsQuery withSort(String sort) throws UnsupportedEncodingException { + setSort(sort); + return this; + } + + public void setSearch(String search) throws UnsupportedEncodingException { + appendIf(PARAM_SEARCH, search); + } + + public ProjectsQuery withSearch(String search) throws UnsupportedEncodingException { + setSearch(search); + return this; + } + + public void setSimple(Boolean simple) throws UnsupportedEncodingException { + appendIf(PARAM_SIMPLE, simple); + } + + public ProjectsQuery withSimple(Boolean simple) throws UnsupportedEncodingException { + setSimple(simple); + return this; + } + + public void setOwned(Boolean owned) throws UnsupportedEncodingException { + appendIf(PARAM_OWNED, owned); + } + + public ProjectsQuery withOwned(Boolean owned) throws UnsupportedEncodingException { + setOwned(owned); + return this; + } + + public void setMembership(Boolean membership) throws UnsupportedEncodingException { + appendIf(PARAM_MEMBERSHIP, membership); + } + + public ProjectsQuery withMembership(Boolean membership) throws UnsupportedEncodingException { + setMembership(membership); + return this; + } + + public void setStarred(Boolean starred) throws UnsupportedEncodingException { + appendIf(PARAM_STARRED, starred); + } + + public ProjectsQuery withStarred(Boolean starred) throws UnsupportedEncodingException { + setStarred(starred); + return this; + } + + public void setStatistics(Boolean statistics) throws UnsupportedEncodingException { + appendIf(PARAM_STATISTICS, statistics); + } + + public ProjectsQuery withStatistics(Boolean statistics) throws UnsupportedEncodingException { + setStatistics(statistics); + return this; + } + + public void setWithCustomAttributes(Boolean withCustomAttributes) throws UnsupportedEncodingException { + appendIf(PARAM_WITH_CUSTOM_ATTRIBUTES, withCustomAttributes); + } + + public ProjectsQuery withWithCustomAttributes(Boolean withCustomAttributes) throws UnsupportedEncodingException { + setWithCustomAttributes(withCustomAttributes); + return this; + } + + public void setWithIssuesEnabled(Boolean withIssuesEnabled) throws UnsupportedEncodingException { + appendIf(PARAM_WITH_ISSUES_ENABLED, withIssuesEnabled); + } + + public ProjectsQuery withWithIssuesEnabled(Boolean withIssuesEnabled) throws UnsupportedEncodingException { + setWithIssuesEnabled(withIssuesEnabled); + return this; + } + + public void setWithMergeRequestsEnabled(Boolean withMergeRequestsEnabled) throws UnsupportedEncodingException { + appendIf(PARAM_WITH_MERGE_REQUESTS_ENABLED, withMergeRequestsEnabled); + } + + public ProjectsQuery withWithMergeRequestsEnabled(Boolean withMergeRequestsEnabled) throws UnsupportedEncodingException { + setWithMergeRequestsEnabled(withMergeRequestsEnabled); + return this; + } + + public void setWithProgrammingLanguage(String withProgrammingLanguage) throws UnsupportedEncodingException { + appendIf(PARAM_WITH_PROGRAMMING_LANGUAGE, withProgrammingLanguage); + } + + public ProjectsQuery withWithProgrammingLanguage(String withProgrammingLanguage) throws UnsupportedEncodingException { + setWithProgrammingLanguage(withProgrammingLanguage); + return this; + } + + public void setWikiChecksumFailed(Boolean wikiChecksumFailed) throws UnsupportedEncodingException { + appendIf(PARAM_WIKI_CHECKSUM_FAILED, wikiChecksumFailed); + } + + public ProjectsQuery withWikiChecksumFailed(Boolean wikiChecksumFailed) throws UnsupportedEncodingException { + setWikiChecksumFailed(wikiChecksumFailed); + return this; + } + + public void setRepositoryChecksumFailed(Boolean repositoryChecksumFailed) throws UnsupportedEncodingException { + appendIf(PARAM_REPOSITORY_CHECKSUM_FAILED, repositoryChecksumFailed); + } + + public ProjectsQuery withRepositoryChecksumFailed(Boolean repositoryChecksumFailed) throws UnsupportedEncodingException { + setRepositoryChecksumFailed(repositoryChecksumFailed); + return this; + } + + public void setMinAccessLevel(GitlabAccessLevel minAccessLevel) throws UnsupportedEncodingException { + appendIf(PARAM_MIN_ACCESS_LEVEL, minAccessLevel); + } + + public ProjectsQuery withMinAccessLevel(GitlabAccessLevel minAccessLevel) throws UnsupportedEncodingException { + setMinAccessLevel(minAccessLevel); + return this; + } + + @Override + public ProjectsQuery withPage(int page) { + super.withPage(page); + return this; + } + + @Override + public ProjectsQuery withPerPage(int perPage) { + super.withPerPage(perPage); + return this; + } + +} diff --git a/src/test/java/org/gitlab/api/APIForIntegrationTestingHolder.java b/src/test/java/org/gitlab/api/APIForIntegrationTestingHolder.java new file mode 100644 index 00000000..a2ac1a2a --- /dev/null +++ b/src/test/java/org/gitlab/api/APIForIntegrationTestingHolder.java @@ -0,0 +1,43 @@ +package org.gitlab.api; + + +import org.gitlab.api.models.GitlabSession; +import org.junit.AssumptionViolatedException; + +import java.io.IOException; + +/** + * Token holder for integration tests. + *
    + *
  • By throwing an {@link AssumptionViolatedException} when the host is not reachable, + * provoke skipping of tests.
  • + *
  • GitLab is strict about creating too much sessions for username/password. + * If you create too many sessions, you will receive HTTP/429 (Retry Later).
  • + *
+ */ +public class APIForIntegrationTestingHolder { + + private static final String TEST_URL = "http://" + System.getProperty("docker.host.address", "localhost") + ":" + System.getProperty("gitlab.port", "18080"); + + public static APIForIntegrationTestingHolder INSTANCE = new APIForIntegrationTestingHolder(); + + private Object api; + + private APIForIntegrationTestingHolder(){ + final GitlabSession session; + try { + session = GitlabAPI.connect(TEST_URL, "root", "password"); + String privateToken = session.getPrivateToken(); + api = GitlabAPI.connect(TEST_URL, privateToken); + } catch (IOException e) { + api = e; + } + } + + public GitlabAPI getApi() { + if (api instanceof IOException) { + throw new AssumptionViolatedException("GITLAB not running on '" + TEST_URL + "', skipping...", (IOException)api); + } + return (GitlabAPI)api; + } +} diff --git a/src/test/java/org/gitlab/api/GitlabAPIIT.java b/src/test/java/org/gitlab/api/GitlabAPIIT.java new file mode 100644 index 00000000..f8d2fc62 --- /dev/null +++ b/src/test/java/org/gitlab/api/GitlabAPIIT.java @@ -0,0 +1,280 @@ +package org.gitlab.api; + +import org.gitlab.api.models.*; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.FileNotFoundException; +import java.net.URL; +import java.util.List; +import java.util.UUID; + +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.*; + +public class GitlabAPIIT { + + private static GitlabAPI api; + + private static final String TEST_URL = "http://" + System.getProperty("docker.host.address", "localhost") + + ":" + System.getProperty("gitlab.port", "18080"); + + @BeforeClass + public static void getApi() { + api = APIForIntegrationTestingHolder.INSTANCE.getApi(); + } + + @Test + public void checkInvalidCredentials() throws Exception { + try { + api.dispatch().with("login", "INVALID").with("password", createRandomString()) + .to("session", GitlabUser.class); + } catch (GitlabAPIException e) { + final String message = e.getMessage(); + if (!message.equals("{\"message\":\"401 Unauthorized\"}")) { + throw new AssertionError("Expected an unauthorized message", e); + } else if(e.getResponseCode() != 401) { + throw new AssertionError("Expected 401 code", e); + } + } + } + + @Test + public void testAllProjects() { + assertThat(api.getAllProjects(), is(notNullValue())); + } + + @Test + public void testGetAPIUrl() throws Exception { + URL expected = new URL(TEST_URL + "/api/v4/"); + assertEquals(expected, api.getAPIUrl("")); + } + + @Test + public void testGetUrl() throws Exception { + URL expected = new URL(TEST_URL); + assertEquals(expected + "/", api.getUrl("").toString()); + } + + @Test + public void testCreateUpdateDeleteVariable() throws Exception { + String key = randVal("key"); + String value = randVal("value"); + String newValue = randVal("new_value"); + String projectName = randVal("project"); + + GitlabProject project = api.createProject(projectName); + assertNotNull(project); + + GitlabBuildVariable variable = api.createBuildVariable(project.getId(), key, value); + assertNotNull(variable); + + GitlabBuildVariable refetched = api.getBuildVariable(project.getId(), key); + + assertNotNull(refetched); + + assertEquals(refetched.getKey(), variable.getKey()); + assertEquals(refetched.getValue(), variable.getValue()); + + api.updateBuildVariable(project.getId(), key, newValue); + + GitlabBuildVariable postUpdate = api.getBuildVariable(project.getId(), key); + + assertNotNull(postUpdate); + assertEquals(postUpdate.getKey(), variable.getKey()); + assertNotEquals(postUpdate.getValue(), variable.getValue()); + assertEquals(postUpdate.getValue(), newValue); + + api.deleteBuildVariable(project.getId(), key); + + // expect a 404, but we have no access to it + try { + GitlabBuildVariable shouldNotExist = api.getBuildVariable(project.getId(), key); + assertNull(shouldNotExist); + } catch (FileNotFoundException thisIsSoOddForAnRESTApiClient) { + assertTrue(true); // expected + } + api.deleteProject(project.getId()); + } + + @Test + public void testCreateUpdateDeleteUser() throws Exception { + String password = randVal("$%password"); + GitlabUser gitUser = api.createUser(randVal("testEmail@gitlabapitest.com"), + password, + randVal("userName"), + randVal("fullName"), + randVal("skypeId"), + randVal("linkedin"), + randVal("twitter"), + "http://" + randVal("url.com"), + 10, + randVal("externuid"), + randVal("externprovidername"), + randVal("bio"), + false, + false, + true, + false); + assertNotNull(gitUser); + + GitlabUser refetched = api.getUserViaSudo(gitUser.getUsername()); + + assertNotNull(refetched); + assertEquals(refetched.getUsername(), gitUser.getUsername()); + + api.updateUser(gitUser.getId(), gitUser.getEmail(), password, gitUser.getUsername(), + gitUser.getName(), "newSkypeId", gitUser.getLinkedin(), + gitUser.getTwitter(), gitUser.getWebsiteUrl(), + 10 /* project limit does not come back on GET */, + gitUser.getExternUid(), gitUser.getExternProviderName(), + gitUser.getBio(), gitUser.isAdmin(), gitUser.isCanCreateGroup(), gitUser.isExternal()); + + GitlabUser postUpdate = api.getUserViaSudo(gitUser.getUsername()); + + assertNotNull(postUpdate); + assertEquals(postUpdate.getSkype(), "newSkypeId"); + + // block + api.blockUser(refetched.getId()); + api.unblockUser(refetched.getId()); + + api.deleteUser(postUpdate.getId()); + // This is odd, but it seems the user is deleted asynchronously... + Thread.sleep(1000); + // expect a 404, but we have no access to it + try { + GitlabUser shouldNotExist = api.getUser(postUpdate.getId()); + assertNull(shouldNotExist); + } catch (FileNotFoundException thisIsSoOddForAnRESTApiClient) { + assertTrue(true); // expected + } + } + + @Test + public void testGetGroupByPath() throws Exception { + // Given + String name = "groupName"; + String path = "groupPath"; + + GitlabGroup originalGroup = api.createGroup(name, path); + + // When + GitlabGroup group = api.getGroup(path); + + // Then: + assertNotNull(group); + assertEquals(originalGroup.getId(), group.getId()); + assertEquals(originalGroup.getName(), group.getName()); + assertEquals(originalGroup.getPath(), group.getPath()); + + // Cleanup + api.deleteGroup(group.getId()); + } + + @Test + public void testCreateAndUpdateGroup() throws Exception { + // Given + GitlabGroup originalGroup = new GitlabGroup(); + originalGroup.setDescription("test description"); + originalGroup.setName("groupNameTest"); + originalGroup.setPath("groupPathTest"); + originalGroup.setVisibility(GitlabVisibility.INTERNAL); + + GitlabGroup newGroup = api.createGroup(originalGroup, null); + assertNotNull(newGroup); + assertEquals(originalGroup.getId(), newGroup.getId()); + assertEquals(originalGroup.getName(), newGroup.getName()); + assertEquals(originalGroup.getPath(), newGroup.getPath()); + assertEquals(originalGroup.getDescription(), newGroup.getDescription()); + assertEquals(originalGroup.getVisibility(), newGroup.getVisibility()); + + GitlabGroup groupToUpdate = new GitlabGroup(); + groupToUpdate.setId(newGroup.getId()); + groupToUpdate.setVisibility(GitlabVisibility.PRIVATE); + + // When + GitlabGroup updatedGroup = api.updateGroup(newGroup, null); + + // Then: + assertNotNull(updatedGroup); + assertEquals(groupToUpdate.getVisibility(), updatedGroup.getVisibility()); + + // Cleanup + api.deleteGroup(updatedGroup.getId()); + } + + @Test + public void testGetMembershipProjects() throws Exception { + assertThat(api.getMembershipProjects(), not(nullValue())); + } + + @Test + public void checkGetOwnedProjects() throws Exception { + assertThat(api.getOwnedProjects(), not(nullValue())); + } + + @Test + public void checkSearchProjects() throws Exception { + final List searchedProjects = api.searchProjects("foo"); + assertThat(searchedProjects, not(nullValue())); + assertThat(searchedProjects.isEmpty(), is(true)); + } + + /** + * There is at least one namespace for the user + */ + @Test + public void testGetNamespace() { + final List gitlabNamespaces = api.getNamespaces(); + assertThat(gitlabNamespaces, not(nullValue())); + assertThat(gitlabNamespaces.isEmpty(), is(false)); + } + + @Test + public void testCreateDeleteFork() throws Exception { + String projectName = randVal("Fork-me"); + String password = randVal("$%password"); + GitlabUser gitUser = api.createUser(randVal("testEmail@gitlabapitest.com"), + password, + randVal("userName"), + randVal("fullName"), + randVal("skypeId"), + randVal("linkedin"), + randVal("twitter"), + "http://" + randVal("url.com"), + 10, + randVal("externuid"), + randVal("externprovidername"), + randVal("bio"), + false, + false, + false, + false); + + String namespace = api.getNamespaces().get(0).getPath(); + + GitlabProject project = api.createUserProject(gitUser.getId(), projectName); + GitlabProject fork = api.createFork(namespace, project); + + assertNotNull(fork); + assertEquals(project.getId(), fork.getForkedFrom().getId()); + assertEquals(project.getNamespace(), namespace); + + api.deleteProject(project.getId()); + api.deleteProject(fork.getId()); + api.deleteUser(gitUser.getId()); + } + + private String randVal(String postfix) { + return createRandomString() + "_" + postfix; + } + + private static String createRandomString() { + return UUID.randomUUID().toString().replace("-", "").substring(0, 8); + } +} diff --git a/src/test/java/org/gitlab/api/GitlabAPITest.java b/src/test/java/org/gitlab/api/GitlabAPITest.java deleted file mode 100644 index 7287d670..00000000 --- a/src/test/java/org/gitlab/api/GitlabAPITest.java +++ /dev/null @@ -1,194 +0,0 @@ -package org.gitlab.api; - -import org.gitlab.api.models.GitlabBuildVariable; -import org.gitlab.api.models.GitlabProject; -import org.gitlab.api.models.GitlabGroup; -import org.gitlab.api.models.GitlabUser; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.net.ConnectException; -import java.net.URL; -import java.util.UUID; - -import static org.junit.Assert.*; -import static org.junit.Assume.assumeNoException; - -@Ignore -public class GitlabAPITest { - - GitlabAPI api; - - private static final String TEST_URL = System.getProperty("TEST_URL", "http://localhost"); - private static final String TEST_TOKEN = System.getProperty("TEST_TOKEN", "y0E5b9761b7y4qk"); - - String rand = UUID.randomUUID().toString().replace("-", "").substring(0, 8); - - - @Before - public void setup() throws IOException { - api = GitlabAPI.connect(TEST_URL, TEST_TOKEN); - try { - api.dispatch().with("login", "INVALID").with("password", rand).to("session", GitlabUser.class); - } catch (ConnectException e) { - assumeNoException("GITLAB not running on '" + TEST_URL + "', skipping...", e); - } catch (GitlabAPIException e) { - final String message = e.getMessage(); - if (!message.equals("{\"message\":\"401 Unauthorized\"}")) { - throw new AssertionError("Expected an unauthorized message", e); - } else if(e.getResponseCode() != 401) { - throw new AssertionError("Expected 401 code", e); - } - } - } - - @Test - public void testAllProjects() throws IOException { - api.getAllProjects(); - } - - @Test - public void testConnect() throws IOException { - assertEquals(GitlabAPI.class, api.getClass()); - } - - @Test - public void testGetAPIUrl() throws IOException { - URL expected = new URL(TEST_URL + "/api/v3/"); - assertEquals(expected, api.getAPIUrl("")); - } - - @Test - public void testGetUrl() throws IOException { - URL expected = new URL(TEST_URL); - assertEquals(expected + "/", api.getUrl("").toString()); - } - - @Test - public void testCreateUpdateDeleteVariable() throws IOException { - String key = randVal("key"); - String value = randVal("value"); - String newValue = randVal("new_value"); - String projectName = randVal("project"); - - GitlabProject project = api.createProject(projectName); - assertNotNull(project); - - GitlabBuildVariable variable = api.createBuildVariable(project.getId(), key, value); - assertNotNull(variable); - - GitlabBuildVariable refetched = api.getBuildVariable(project.getId(), key); - - assertNotNull(refetched); - - assertEquals(refetched.getKey(), variable.getKey()); - assertEquals(refetched.getValue(), variable.getValue()); - - api.updateBuildVariable(project.getId(), key, newValue); - - - GitlabBuildVariable postUpdate = api.getBuildVariable(project.getId(), key); - - - assertNotNull(postUpdate); - assertEquals(postUpdate.getKey(), variable.getKey()); - assertNotEquals(postUpdate.getValue(), variable.getValue()); - assertEquals(postUpdate.getValue(), newValue); - - - api.deleteBuildVariable(project.getId(), key); - - // expect a 404, but we have no access to it - try { - GitlabBuildVariable shouldNotExist = api.getBuildVariable(project.getId(), key); - assertNull(shouldNotExist); - } catch (FileNotFoundException thisIsSoOddForAnRESTApiClient) { - assertTrue(true); // expected - } - - api.deleteProject(project.getId()); - } - - @Test - public void testCreateUpdateDeleteUser() throws IOException { - - String password = randVal("$%password"); - - - GitlabUser gitUser = api.createUser(randVal("testEmail@gitlabapitest.com"), - password, - randVal("userName"), - randVal("fullName"), - randVal("skypeId"), - randVal("linledin"), - randVal("twitter"), - "http://" + randVal("url.com"), - 10, - randVal("externuid"), - randVal("externprovidername"), - randVal("bio"), - false, - false, - false); - assertNotNull(gitUser); - - GitlabUser refetched = api.getUserViaSudo(gitUser.getUsername()); - - assertNotNull(refetched); - - assertEquals(refetched.getUsername(), gitUser.getUsername()); - - api.updateUser(gitUser.getId(), gitUser.getEmail(), password, gitUser.getUsername(), - gitUser.getName(), "newSkypeId", gitUser.getLinkedin(), gitUser.getTwitter(), gitUser.getWebsiteUrl(), - 10 /* project limit does not come back on GET */, gitUser.getExternUid(), gitUser.getExternProviderName(), - gitUser.getBio(), gitUser.isAdmin(), gitUser.isCanCreateGroup()); - - - GitlabUser postUpdate = api.getUserViaSudo(gitUser.getUsername()); - - - assertNotNull(postUpdate); - assertEquals(postUpdate.getSkype(), "newSkypeId"); - - - api.deleteUser(postUpdate.getId()); - - // expect a 404, but we have no access to it - try { - GitlabUser shouldNotExist = api.getUser(postUpdate.getId()); - assertNull(shouldNotExist); - } catch (FileNotFoundException thisIsSoOddForAnRESTApiClient) { - assertTrue(true); // expected - } - - - } - - @Test - public void testGetGroupByPath() throws IOException { - // Given - String name = "groupName"; - String path = "groupPath"; - - GitlabGroup originalGroup = api.createGroup(name, path); - - // When - GitlabGroup group = api.getGroup(path); - - // Then: - assertNotNull(group); - assertEquals(originalGroup.getId(), group.getId()); - assertEquals(originalGroup.getName(), group.getName()); - assertEquals(originalGroup.getPath(), group.getPath()); - - // Cleanup - api.deleteGroup(group.getId()); - } - - private String randVal(String postfix) { - return rand + "_" + postfix; - } -} diff --git a/src/test/java/org/gitlab/api/GitlabAPIUT.java b/src/test/java/org/gitlab/api/GitlabAPIUT.java new file mode 100644 index 00000000..dd5cec6e --- /dev/null +++ b/src/test/java/org/gitlab/api/GitlabAPIUT.java @@ -0,0 +1,94 @@ +package org.gitlab.api; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.net.NoRouteToHostException; +import java.net.ServerSocket; +import java.net.SocketTimeoutException; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * Created by Oleg Shaburov on 03.05.2018 + * shaburov.o.a@gmail.com + */ +@SuppressWarnings("WeakerAccess") +public class GitlabAPIUT { + + //@Test + @DisplayName(value = "Check non-routable connection with connection timeout error") + public void unitTest_20180503175711() { + GitlabAPI api = GitlabAPI.connect("http://172.16.0.0:80", "test"); + api.setConnectionTimeout(100); + Throwable exception = assertThrows(NoRouteToHostException.class, api::getVersion); + assertThat(exception.getMessage(), is("No route to host")); + } + + @Test + @DisplayName(value = "Check default value is 0 for connection timeout") + public void unitTest_20180503185536() { + GitlabAPI api = GitlabAPI.connect("http://test.api", "test"); + assertThat(api.getConnectionTimeout(), is(0)); + } + + @Test + @DisplayName(value = "Check set/get methods for connection timeout parameter") + public void unitTest_20180503185632() { + GitlabAPI api = GitlabAPI.connect("http://test.api", "test"); + api.setConnectionTimeout(123); + assertThat(api.getConnectionTimeout(), is(123)); + } + + @Test + @DisplayName(value = "Check ignore negative value for connection timeout parameter") + public void unitTest_20180503185750() { + GitlabAPI api = GitlabAPI.connect("http://test.api", "test"); + api.setConnectionTimeout(-123); + assertThat(api.getConnectionTimeout(), is(0)); + } + + @Test + @DisplayName(value = "Check connection with read timeout error") + public void unitTest_20180503191159() throws IOException { + ServerSocket socket = null; + try { + socket = new ServerSocket(15896); + GitlabAPI api = GitlabAPI.connect("http://localhost:15896", "test"); + api.setResponseReadTimeout(100); + Throwable exception = assertThrows(SocketTimeoutException.class, api::getVersion); + assertThat(exception.getMessage(), is("Read timed out")); + } finally { + if (socket != null) { + socket.close(); + } + } + } + + @Test + @DisplayName(value = "Check default value is 0 for request timeout parameter") + public void unitTest_20180503191716() { + GitlabAPI api = GitlabAPI.connect("http://test.api", "test"); + assertThat(api.getResponseReadTimeout(), is(0)); + } + + @Test + @DisplayName(value = "Check set/get methods for request timeout parameter") + public void unitTest_20180503191945() { + GitlabAPI api = GitlabAPI.connect("http://test.api", "test"); + api.setResponseReadTimeout(123); + assertThat(api.getResponseReadTimeout(), is(123)); + } + + @Test + @DisplayName(value = "Check ignore negative value for request timeout parameter") + public void unitTest_20180503192141() { + GitlabAPI api = GitlabAPI.connect("http://test.api", "test"); + api.setResponseReadTimeout(-123); + assertThat(api.getResponseReadTimeout(), is(0)); + } + +} diff --git a/src/test/java/org/gitlab/api/GitlabJson.java b/src/test/java/org/gitlab/api/GitlabJson.java new file mode 100644 index 00000000..a18f0adb --- /dev/null +++ b/src/test/java/org/gitlab/api/GitlabJson.java @@ -0,0 +1,44 @@ +package org.gitlab.api; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.util.List; +import java.util.Random; + +import org.gitlab.api.models.GitlabProject; +import org.junit.BeforeClass; +import org.junit.Test; + +public class GitlabJson { + + static GitlabAPI api; + + @BeforeClass + public static void getApi() { + api = APIForIntegrationTestingHolder.INSTANCE.getApi(); + } + + @Test + public void getProjectJson () throws IOException { + List projects = api.getProjects(); + int randomProjectNumber = getRandomProject(projects); + if (randomProjectNumber != 0) { + String p = api.getProjectJson(randomProjectNumber); + assertTrue("The JSON is 0 length",p.length() > 0); + assertTrue("Project JSON does not contain 'id'.",p.indexOf("id") > 0); + assertTrue("Project JSON does not contain 'default_branch'.",p.indexOf("default_branch") > 0); + } else { + fail("No projects are defined in the gitlab instance, or something failed."); + } + } + + private int getRandomProject (List projects) { + if (projects.size() > 0) { + Random rand = new Random(); + return projects.get(rand.nextInt(projects.size())).getId(); + } else + return 0; + } +} diff --git a/src/test/java/org/gitlab/api/GitlabUploadIT.java b/src/test/java/org/gitlab/api/GitlabUploadIT.java new file mode 100644 index 00000000..31524b66 --- /dev/null +++ b/src/test/java/org/gitlab/api/GitlabUploadIT.java @@ -0,0 +1,52 @@ +package org.gitlab.api; + +import org.apache.commons.io.IOUtils; +import org.gitlab.api.models.GitlabProject; +import org.gitlab.api.models.GitlabUpload; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.*; + +public class GitlabUploadIT { + + static GitlabAPI api; + + @BeforeClass + public static void getApi() { + api = APIForIntegrationTestingHolder.INSTANCE.getApi(); + } + + + @Test + public void testUploadToProject() throws Exception { + GitlabProject project; + try { + project = api.getProject("root", "project"); + } catch (FileNotFoundException e) { + project = api.createUserProject(api.getUser().getId(), "project"); + } + String content = "test file content"; + File tempFile = createTempFile(content); + try { + GitlabUpload upload = api.uploadFile(project, tempFile); + Assert.assertNotNull(upload.getUrl()); + } finally { + tempFile.delete(); + } + } + + private File createTempFile(String content) throws IOException { + File tempFile = File.createTempFile("upload-", ".txt"); + InputStream is = new ByteArrayInputStream(content.getBytes()); + OutputStream os = new FileOutputStream(tempFile); + try { + IOUtils.copy(is, os); + } finally { + is.close(); + os.close(); + } + return tempFile; + } +} diff --git a/src/test/java/org/gitlab/api/InstantDeserializerTest.java b/src/test/java/org/gitlab/api/InstantDeserializerTest.java new file mode 100644 index 00000000..727554db --- /dev/null +++ b/src/test/java/org/gitlab/api/InstantDeserializerTest.java @@ -0,0 +1,34 @@ +package org.gitlab.api; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.gitlab.api.jackson.InstantDeserializer; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.time.*; +import java.util.concurrent.TimeUnit; + +import static org.junit.jupiter.api.Assertions.*; + +class InstantDeserializerTest { + + @Test + void deserialize() throws IOException { + final ObjectMapper objectMapper = new ObjectMapper(); + + final InstantDeserializer deserializer = new InstantDeserializer(); + final JsonParser parser = objectMapper.treeAsTokens(objectMapper.readTree("\"2016-08-11T11:28:34.085Z\"")); + parser.nextToken(); + final Instant instant = deserializer.deserialize(parser, objectMapper.getDeserializationContext()); + + assertEquals(Instant.from( + ZonedDateTime.of( + LocalDate.of(2016, 8, 11), + LocalTime.of(11, 28, 34, (int) TimeUnit.MILLISECONDS.toNanos(85)), + ZoneOffset.UTC + ) + ), instant); + } + +} \ No newline at end of file diff --git a/src/test/java/org/gitlab/api/PaginationTest.java b/src/test/java/org/gitlab/api/PaginationTest.java index ce8c2839..e08db9b2 100644 --- a/src/test/java/org/gitlab/api/PaginationTest.java +++ b/src/test/java/org/gitlab/api/PaginationTest.java @@ -60,4 +60,10 @@ public void complexPagination() throws UnsupportedEncodingException { assertEquals(expectedQuery.toString(), pagination.toString()); assertEquals(expectedQuery.toString(), pagination.asQuery().toString()); } + + @Test + public void maxItemsPerPage() throws Exception { + Pagination pagination = new Pagination().withPerPage(Pagination.MAX_ITEMS_PER_PAGE); + assertEquals(String.format("?%s=%d", Pagination.PARAM_PER_PAGE, Pagination.MAX_ITEMS_PER_PAGE), pagination.toString()); + } } diff --git a/src/test/java/org/gitlab/api/TestUtils.java b/src/test/java/org/gitlab/api/TestUtils.java new file mode 100644 index 00000000..71bbe027 --- /dev/null +++ b/src/test/java/org/gitlab/api/TestUtils.java @@ -0,0 +1,18 @@ +package org.gitlab.api; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.stream.Collectors; + +public class TestUtils { + public static String readDataFromResource(String path) throws IOException { + InputStream inputStream = TestUtils.class.getClassLoader().getResourceAsStream(path); + assert inputStream != null; + try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { + return reader.lines().collect(Collectors.joining("\n")); + } + } + +} diff --git a/src/test/java/org/gitlab/api/http/GitlabHTTPRequestorTest.java b/src/test/java/org/gitlab/api/http/GitlabHTTPRequestorTest.java index 6c95e1c5..9db94bac 100644 --- a/src/test/java/org/gitlab/api/http/GitlabHTTPRequestorTest.java +++ b/src/test/java/org/gitlab/api/http/GitlabHTTPRequestorTest.java @@ -1,21 +1,114 @@ package org.gitlab.api.http; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import org.gitlab.api.GitlabAPI; -import org.gitlab.api.TokenType; -import org.junit.Test; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import java.lang.reflect.Method; +import java.net.HttpURLConnection; +import java.net.URL; +@SuppressWarnings({"WeakerAccess", "ConstantConditions"}) public class GitlabHTTPRequestorTest { @Test - public void testSettingInvalidHTTPMethod() { - GitlabHTTPRequestor http = new GitlabHTTPRequestor(GitlabAPI.connect("localhost", "api")); + @DisplayName(value = "Expected success, calling the \"setupConnection\" method if the connection timeout = 0") + public void unitTest_20180503194340() throws Exception { + GitlabAPI api = mock(GitlabAPI.class); + when(api.getConnectionTimeout()).thenReturn(0); + GitlabHTTPRequestor http = new GitlabHTTPRequestor(api); + URL url = new URL("http://test.url"); + Method method = GitlabHTTPRequestor.class.getDeclaredMethod("setupConnection", URL.class); + method.setAccessible(true); + HttpURLConnection connection = (HttpURLConnection) method.invoke(http, url); + assertThat(connection.getConnectTimeout(), is(0)); + } + + @Test + @DisplayName(value = "Expected success, calling the \"setupConnection\" method if the connection timeout > 0") + public void unitTest_20180503194559() throws Exception { + GitlabAPI api = mock(GitlabAPI.class); + when(api.getConnectionTimeout()).thenReturn(456); + GitlabHTTPRequestor http = new GitlabHTTPRequestor(api); + URL url = new URL("http://test.url"); + Method method = GitlabHTTPRequestor.class.getDeclaredMethod("setupConnection", URL.class); + method.setAccessible(true); + HttpURLConnection connection = (HttpURLConnection) method.invoke(http, url); + assertThat(connection.getConnectTimeout(), is(456)); + } + + @Test + @DisplayName(value = "An error is expected, calling the \"setupConnection\" method if the connection timeout < 0") + public void unitTest_20180503194643() throws Exception { + GitlabAPI api = mock(GitlabAPI.class); + when(api.getConnectionTimeout()).thenReturn(-555); + GitlabHTTPRequestor http = new GitlabHTTPRequestor(api); + URL url = new URL("http://test.url"); + Method method = GitlabHTTPRequestor.class.getDeclaredMethod("setupConnection", URL.class); + method.setAccessible(true); + Throwable throwable = null; + try { + method.invoke(http, url); + } catch (Exception e) { + throwable = e.getCause(); + } + assertThat(throwable, not(nullValue())); + assertThat(throwable, is(instanceOf(IllegalArgumentException.class))); + assertThat(throwable.getMessage(), is("timeouts can't be negative")); + } + + @Test + @DisplayName(value = "Expected success, calling the \"setupConnection\" method if the read timeout = 0") + public void unitTest_20180503202458() throws Exception { + GitlabAPI api = mock(GitlabAPI.class); + when(api.getResponseReadTimeout()).thenReturn(0); + GitlabHTTPRequestor http = new GitlabHTTPRequestor(api); + URL url = new URL("http://test.url"); + Method method = GitlabHTTPRequestor.class.getDeclaredMethod("setupConnection", URL.class); + method.setAccessible(true); + HttpURLConnection connection = (HttpURLConnection) method.invoke(http, url); + assertThat(connection.getReadTimeout(), is(0)); + } + + @Test + @DisplayName(value = "Expected success, calling the \"setupConnection\" method if the read timeout > 0") + public void unitTest_20180503203531() throws Exception { + GitlabAPI api = mock(GitlabAPI.class); + when(api.getResponseReadTimeout()).thenReturn(555); + GitlabHTTPRequestor http = new GitlabHTTPRequestor(api); + URL url = new URL("http://test.url"); + Method method = GitlabHTTPRequestor.class.getDeclaredMethod("setupConnection", URL.class); + method.setAccessible(true); + HttpURLConnection connection = (HttpURLConnection) method.invoke(http, url); + assertThat(connection.getReadTimeout(), is(555)); + } + + @Test + @DisplayName(value = "An error is expected, calling the \"setupConnection\" method if the read timeout < 0") + public void unitTest_20180503203635() throws Exception { + GitlabAPI api = mock(GitlabAPI.class); + when(api.getResponseReadTimeout()).thenReturn(-555); + GitlabHTTPRequestor http = new GitlabHTTPRequestor(api); + URL url = new URL("http://test.url"); + Method method = GitlabHTTPRequestor.class.getDeclaredMethod("setupConnection", URL.class); + method.setAccessible(true); + Throwable throwable = null; try { - http.method("WRONG METHOD"); + method.invoke(http, url); } catch (Exception e) { - assertEquals("Invalid HTTP Method: WRONG METHOD. Must be one of GET, PUT, POST, PATCH, DELETE, HEAD, OPTIONS, TRACE", e.getMessage()); + throwable = e.getCause(); } + assertThat(throwable, not(nullValue())); + assertThat(throwable, is(instanceOf(IllegalArgumentException.class))); + assertThat(throwable.getMessage(), is("timeouts can't be negative")); } } diff --git a/src/test/java/org/gitlab/api/models/GitlabIssueDeserializationTest.java b/src/test/java/org/gitlab/api/models/GitlabIssueDeserializationTest.java new file mode 100644 index 00000000..52802671 --- /dev/null +++ b/src/test/java/org/gitlab/api/models/GitlabIssueDeserializationTest.java @@ -0,0 +1,17 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.gitlab.api.TestUtils; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +class GitlabIssueDeserializationTest { + @Test + void deserializationTest() { + ObjectMapper objectMapper = new ObjectMapper(); + Assertions.assertDoesNotThrow(() -> objectMapper.readValue( + TestUtils.readDataFromResource("IssueExample.json"), GitlabIssue.class)); + } +} diff --git a/src/test/resources/IssueExample.json b/src/test/resources/IssueExample.json new file mode 100644 index 00000000..66936686 --- /dev/null +++ b/src/test/resources/IssueExample.json @@ -0,0 +1,44 @@ +{ + "id":231, + "iid":2456, + "project_id":871, + "title":"Data Feed Dghrythfh00", + "description":"# Bountyrdhfy.", + "state":"opened", + "created_at":"2019-06-06T21:54:50.241Z", + "updated_at":"2019-06-08T17:22:59.613Z", + "closed_at":null, + "closed_by":null, + "labels":[ + "bounty::available", + "status::untouched" + ], + "milestone":null, + "assignees":[ + + ], + "author":{ + "id":1325, + "name":"jlsfldgs", + "username":"jlsfldgsd", + "state":"active", + "avatar_url":"https://assets.gitlab-static.net/uploads/-/system/user/avatar/139453452225/avatar.png", + "web_url":"https://gitlab.com/jlsfldgsd" + }, + "assignee":null, + "user_notes_count":4, + "merge_requests_count":0, + "upvotes":0, + "downvotes":0, + "due_date":"2019-06-29", + "confidential":false, + "discussion_locked":null, + "web_url":"https://gitlab.com/3456457", + "time_stats":{ + "time_estimate":0, + "total_time_spent":0, + "human_time_estimate":null, + "human_total_time_spent":null + }, + "weight":null +} \ No newline at end of file diff --git a/src/test/resources/gitlab.rb b/src/test/resources/gitlab.rb new file mode 100644 index 00000000..c47fdb49 --- /dev/null +++ b/src/test/resources/gitlab.rb @@ -0,0 +1,2 @@ +gitlab_rails['initial_root_password'] = "password" +gitlab_rails['lfs_enabled'] = false diff --git a/src/test/resources/log4j2.xml b/src/test/resources/log4j2.xml new file mode 100644 index 00000000..57f3d206 --- /dev/null +++ b/src/test/resources/log4j2.xml @@ -0,0 +1,16 @@ + + + + %d{HH:mm:ss.SSS} [%-5p] [%25.25C] - %m%n + + + + + + + + + + + +