diff --git a/.gitignore b/.gitignore index dc256776..b395fd90 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,16 @@ .DS_Store -.idea/* +.idea/ *.iml +build/ target/* +*.*~ +.gradle +/bin/ +/target/ +target +.classpath +.project +.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 new file mode 100644 index 00000000..257d4981 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +language: java +sudo: required +services: + - docker +jdk: +- openjdk8 +install: +- ./mvnw -B -q -Pdocker-gitlab dependency:go-offline verify -DskipTests -Ddocker.skip +script: +- ./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 new file mode 100644 index 00000000..75b52484 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + 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/LICENCE b/NOTICE similarity index 87% rename from LICENCE rename to NOTICE index 66d98f5a..2977f0c9 100644 --- a/LICENCE +++ b/NOTICE @@ -1,4 +1,4 @@ -Copyright 2013 Timothy Olshansky +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. @@ -10,4 +10,4 @@ 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. \ No newline at end of file +limitations under the License. diff --git a/README.md b/README.md index e5e7fc4f..4dea5cbd 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ # Gitlab Java API Wrapper -A wrapper for the [Gitlab API](https://gitlab.org) written in Java. \ No newline at end of file +[![Maven Central](https://img.shields.io/maven-central/v/org.gitlab/java-gitlab-api.svg)](http://mvnrepository.com/artifact/org.gitlab/java-gitlab-api) +[![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 new file mode 100644 index 00000000..a245c85b --- /dev/null +++ b/build.gradle @@ -0,0 +1,64 @@ +buildscript { + tasks.withType(JavaCompile) { + options.encoding = "UTF-8" + } +} + +plugins { + id "java" + id "maven" + id "idea" + id "eclipse" +} + +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + +group = "org.gitlab" +version = "4.1.2-SNAPSHOT" + +repositories { + mavenLocal() + mavenCentral() +} + +dependencies { + 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 } + from "LICENSE" + from "NOTICE" +} + +install { + repositories.mavenInstaller { pom.artifactId = "java-gitlab-api" } +} + +task sourcesJar(type: Jar, dependsOn:classes) { + classifier = "sources" + from sourceSets.main.allSource + from "LICENSE" + from "NOTICE" +} + +artifacts { archives sourcesJar } + +test { + useJUnitPlatform { + includeEngines 'junit-jupiter' + includeEngines 'junit-vintage' + } +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..f6b961fd Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..430dfabc --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +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 diff --git a/gradlew b/gradlew new file mode 100755 index 00000000..cccdd3d5 --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# 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 () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +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 + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +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 + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +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` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +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" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 00000000..e95643d6 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +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 + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega 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 8cb26275..902f0424 100644 --- a/pom.xml +++ b/pom.xml @@ -1,79 +1,329 @@ - 4.0.0 + 4.0.0 - org.gitlab - java-gitlab-api - 1.1.3-SNAPSHOT + org.gitlab + java-gitlab-api + 4.1.2-SNAPSHOT - Gitlab Java API Wrapper - A Java wrapper for the Gitlab Git Hosting Server API + Gitlab Java API Wrapper + A Java wrapper for the Gitlab Git Hosting Server API - - org.sonatype.oss - oss-parent - 7 - + + org.sonatype.oss + oss-parent + 9 + - - - timols - Tim Olshansky - tim.olshansky@gmail.com - - + + + timols + Tim Olshansky + tim.olshansky@gmail.com + + + + + Adam Retter + adam.retter@googlemail.com + Evolved Binary Ltd + + + Cesar Aguilar + cesar@fuzzproductions.com + Fuzz Productions + + + Chris Luu + luu@fuzzproductions.com + Fuzz Productions + + + Oleg Shaburov + shaburov.o.a@gmail.com + + Automation QA + + +3 + + - - - The Apache Software License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt - repo - - + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + - - scm:git:ssh://github.com/timols/java-gitlab-api.git - scm:git:ssh://git@github.com/timols/java-gitlab-api.git - https://github.com/timols/java-gitlab-api - + + scm:git:ssh://github.com/timols/java-gitlab-api.git + scm:git:ssh://git@github.com/timols/java-gitlab-api.git + https://github.com/timols/java-gitlab-api + - - Github - https://github.com/timols/java-gitlab-api/issues - + + Github + https://github.com/timols/java-gitlab-api/issues + - - UTF-8 - + + 1.8 + 1.8 + UTF-8 + UTF-8 + 2.21.0 + + 180000 + 2.11.0 + 5.2.0 + - - - org.codehaus.jackson - jackson-core-asl - 1.9.9 - - - org.codehaus.jackson - jackson-mapper-asl - 1.9.9 - - - commons-io - commons-io - 1.4 - - - org.hamcrest - hamcrest-all - 1.3 - test - - - junit - junit - 4.11 - test - - + + + com.fasterxml.jackson.core + jackson-core + 2.5.3 + + + com.fasterxml.jackson.core + jackson-databind + 2.9.10.5 + + + commons-io + commons-io + 2.4 + + + + 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 + + + junit + junit + 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 + - \ No newline at end of file + + + + + + + + ./ + + LICENSE + NOTICE + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.5.1 + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + + org.apache.maven.plugins + maven-failsafe-plugin + ${maven-surefire-plugin.version} + + + default-integration-test + + integration-test + + + + ${docker.host.address} + ${gitlab.port} + + + + + default-verify + + verify + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.0.0 + + + attach-sources + verify + + jar-no-fork + + + + + + 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/AuthMethod.java b/src/main/java/org/gitlab/api/AuthMethod.java new file mode 100644 index 00000000..846ea126 --- /dev/null +++ b/src/main/java/org/gitlab/api/AuthMethod.java @@ -0,0 +1,5 @@ +package org.gitlab.api; + +public enum AuthMethod { + HEADER, URL_PARAMETER +} diff --git a/src/main/java/org/gitlab/api/GitlabAPI.java b/src/main/java/org/gitlab/api/GitlabAPI.java index 8838573e..c0c88fa7 100644 --- a/src/main/java/org/gitlab/api/GitlabAPI.java +++ b/src/main/java/org/gitlab/api/GitlabAPI.java @@ -1,67 +1,184 @@ package org.gitlab.api; -import org.codehaus.jackson.map.DeserializationConfig; -import org.codehaus.jackson.map.ObjectMapper; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; import org.gitlab.api.http.GitlabHTTPRequestor; -import org.gitlab.api.models.GitlabCommit; -import org.gitlab.api.models.GitlabMergeRequest; -import org.gitlab.api.models.GitlabNote; -import org.gitlab.api.models.GitlabProject; +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.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; import java.util.ArrayList; import java.util.Arrays; -import java.util.Iterator; +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 + * @author @timols (Tim O) */ +@SuppressWarnings({"unused", "WeakerAccess"}) public class GitlabAPI { - private final String _hostUrl; - private final String _apiToken; - private boolean _ignoreCertificateErrors = false; - private static final String API_NAMESPACE = "/api/v3"; - public static final ObjectMapper MAPPER = new ObjectMapper().configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false); - private GitlabAPI(String hostUrl, String apiToken) { - _hostUrl = hostUrl.endsWith("/") ? hostUrl.replaceAll("/$", "") : hostUrl; - _apiToken = apiToken; + 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 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 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, 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, (AuthMethod) null); + return api.dispatch().with("login", username).with("password", password) + .to(tailUrl, GitlabSession.class); } public static GitlabAPI connect(String hostUrl, String apiToken) { - return new GitlabAPI(hostUrl, apiToken); + return new GitlabAPI(hostUrl, apiToken, TokenType.PRIVATE_TOKEN, AuthMethod.HEADER); + } + + public static GitlabAPI connect(String hostUrl, String apiToken, TokenType tokenType) { + return new GitlabAPI(hostUrl, apiToken, tokenType, AuthMethod.HEADER); + } + + public static GitlabAPI connect(String hostUrl, String apiToken, TokenType tokenType, AuthMethod method) { + 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) { - _ignoreCertificateErrors = 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 getResponseReadTimeout(); + } + + /** + * @deprecated use this.setResponseReadTimeout(int readTimeout) method + */ + @Deprecated + public GitlabAPI setRequestTimeout(int readTimeout) { + setResponseReadTimeout(readTimeout); + return this; + } + + 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; } public GitlabHTTPRequestor retrieve() { - return new GitlabHTTPRequestor(this); + return new GitlabHTTPRequestor(this).authenticate(apiToken, tokenType, authMethod); } public GitlabHTTPRequestor dispatch() { - return new GitlabHTTPRequestor(this).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; + return ignoreCertificateErrors; } - public URL getAPIUrl(String tailAPIUrl) throws IOException { - if (_apiToken != null) { - tailAPIUrl = tailAPIUrl + (tailAPIUrl.indexOf('?') > 0 ? '&' : '?') + "private_token=" + _apiToken; - } + 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 { @@ -69,127 +186,4070 @@ public URL getUrl(String tailAPIUrl) throws IOException { tailAPIUrl = "/" + tailAPIUrl; } - return new URL(_hostUrl + tailAPIUrl); + return new URL(hostUrl + tailAPIUrl); } - public GitlabProject getProject(Integer projectId) throws IOException { - String tailUrl = GitlabProject.URL + "/" + projectId; - return retrieve().to(tailUrl, GitlabProject.class); + public String getHost() { + return hostUrl; } - public List getProjects() throws IOException { - String tailUrl = GitlabProject.URL; - return Arrays.asList(retrieve().to(tailUrl, GitlabProject[].class)); + 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 on gitlab api call error + */ + public List findUsers(String emailOrUsername) throws IOException { + List users = new ArrayList<>(); + if (emailOrUsername != null && !emailOrUsername.equals("")) { + String tailUrl = GitlabUser.URL + "?search=" + emailOrUsername; + GitlabUser[] response = retrieve().to(tailUrl, GitlabUser[].class); + users = Arrays.asList(response); + } + return users; + } + + /** + * Return API User + */ + public GitlabUser getUser() throws IOException { + String tailUrl = GitlabUser.USER_URL; + return retrieve().to(tailUrl, GitlabUser.class); + } + + public GitlabUser getUser(Integer userId) throws IOException { + String tailUrl = GitlabUser.URL + "/" + userId; + return retrieve().to(tailUrl, GitlabUser.class); + } + + public GitlabUser getUserViaSudo(String username) throws IOException { + String tailUrl = GitlabUser.USER_URL + "?" + PARAM_SUDO + "=" + username; + return retrieve().to(tailUrl, GitlabUser.class); + } + + /** + * Create a new User + * + * @param email User email + * @param password Password + * @param username User name + * @param fullName Full name + * @param skypeId Skype Id + * @param linkedIn LinkedIn + * @param twitter Twitter + * @param website_url Website URL + * @param projects_limit Projects limit + * @param extern_uid External User ID + * @param extern_provider_name External Provider Name + * @param bio Bio + * @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 + */ + public GitlabUser createUser(String email, String password, String username, + 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, + Boolean skip_confirmation, Boolean external) throws IOException { + + Query query = new Query() + .append("email", email) + .appendIf("skip_confirmation", skip_confirmation) + .appendIf("password", password) + .appendIf("username", username) + .appendIf("name", fullName) + .appendIf("skype", skypeId) + .appendIf("linkedin", linkedIn) + .appendIf("twitter", twitter) + .appendIf("website_url", website_url) + .appendIf("projects_limit", projects_limit) + .appendIf("extern_uid", extern_uid) + .appendIf("provider", extern_provider_name) + .appendIf("bio", bio) + .appendIf("admin", isAdmin) + .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); } - public List getAllProjects() throws IOException { - String tailUrl = GitlabProject.URL; - List results = new ArrayList(); - Iterator iterator = retrieve().asIterator(tailUrl, GitlabProject[].class); - while (iterator.hasNext()) { - GitlabProject[] projects = iterator.next(); + /** + * Update a user + * + * @param targetUserId User ID + * @param email User email + * @param password Password + * @param username User name + * @param fullName Full name + * @param skypeId Skype Id + * @param linkedIn LinkedIn + * @param twitter Twitter + * @param website_url Website URL + * @param projects_limit Projects limit + * @param extern_uid External User ID + * @param extern_provider_name External Provider Name + * @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 + */ + public GitlabUser updateUser(Integer targetUserId, + String email, String password, String username, + 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, Boolean external) throws IOException { - if (projects.length > 0) { - results.addAll(Arrays.asList(projects)); - } + Query query = new Query() + .append("email", email) + .appendIf("password", password) + .appendIf("username", username) + .appendIf("name", fullName) + .appendIf("skype", skypeId) + .appendIf("linkedin", linkedIn) + .appendIf("twitter", twitter) + .appendIf("website_url", website_url) + .appendIf("projects_limit", projects_limit) + .appendIf("extern_uid", extern_uid) + .appendIf("provider", extern_provider_name) + .appendIf("bio", bio) + .appendIf("admin", isAdmin) + .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); + } + + /** + * Block a user + * + * @param targetUserId The id of the Gitlab user + * @throws IOException on gitlab api call error + */ + public void blockUser(Integer targetUserId) throws IOException { + + String tailUrl = GitlabUser.USERS_URL + "/" + targetUserId + GitlabUser.BLOCK_URL; + + retrieve().method(POST).to(tailUrl, Void.class); + } + + /** + * Unblock a user + * + * @param targetUserId The id of the Gitlab user + * @throws IOException on gitlab api call error + */ + public void unblockUser(Integer targetUserId) throws IOException { + + String tailUrl = GitlabUser.USERS_URL + "/" + targetUserId + GitlabUser.UNBLOCK_URL; + + retrieve().method(POST).to(tailUrl, Void.class); + } + + /** + * Create a new ssh key for the user + * + * @param targetUserId The id of the Gitlab 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(Integer targetUserId, String title, String key) throws IOException { + + Query query = new Query() + .append("title", title) + .append("key", key); + + String tailUrl = GitlabUser.USERS_URL + "/" + targetUserId + GitlabSSHKey.KEYS_URL + query.toString(); + + 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 + * + * @param targetUserId The id of the Gitlab user + * @param targetKeyId The id of the Gitlab ssh key + * @throws IOException on gitlab api call error + */ + 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); + } + + + /** + * Gets all ssh keys for a user + * + * @param targetUserId The id of the GitLab User + * @return The list of user ssh keys + * @throws IOException on gitlab api call error + */ + public List getSSHKeys(Integer targetUserId) throws IOException { + String tailUrl = GitlabUser.USERS_URL + "/" + targetUserId + GitlabSSHKey.KEYS_URL; + return Arrays.asList(retrieve().to(tailUrl, GitlabSSHKey[].class)); + } + + /** + * Get key with user information by ID of an SSH key. + * + * @param keyId The ID of an SSH key + * @return The SSH key with user information + * @throws IOException on gitlab api call error + */ + public GitlabSSHKey getSSHKey(Integer keyId) throws IOException { + String tailUrl = GitlabSSHKey.KEYS_URL + "/" + keyId; + return retrieve().to(tailUrl, GitlabSSHKey.class); + } + + /** + * Delete a user + * + * @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); + } + + 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. Don't include the projects. + * + * @param path Path of the group + * @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 { + 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, new Pagination().withPerPage(Pagination.MAX_ITEMS_PER_PAGE)); + } + + public List getGroupsViaSudo(String username, Pagination pagination) throws IOException { + String tailUrl = GitlabGroup.URL; + + Query query = new Query() + .appendIf(PARAM_SUDO, username); + + if (pagination != null) { + query.mergeWith(pagination.asQuery()); } - return results; + return retrieve().getAll(tailUrl + query.toString(), GitlabGroup[].class); + } + /** + * Get all the projects for a group. + * + * @param group the target group + * @return a list of projects for the group + */ + public List getGroupProjects(GitlabGroup group) { + return getGroupProjects(group.getId()); } - public List getOpenMergeRequests(GitlabProject project) throws IOException { - List allMergeRequests = getAllMergeRequests(project); - List openMergeRequests = new ArrayList(); + /** + * Get all the projects for a group. + * + * @param groupId the target group's id. + * @return a list of projects for the group + */ + public List getGroupProjects(Integer groupId) { + String tailUrl = GitlabGroup.URL + "/" + groupId + GitlabProject.URL + PARAM_MAX_ITEMS_PER_PAGE; + return retrieve().getAll(tailUrl, GitlabProject[].class); + } + + /** + * Gets all members of a Group + * + * @param group The GitLab Group + * @return The Group Members + */ + public List getGroupMembers(GitlabGroup group) { + return getGroupMembers(group.getId()); + } + + /** + * Gets all members of a Group + * + * @param groupId The id of the GitLab Group + * @return The Group Members + */ + public List getGroupMembers(Integer groupId) { + String tailUrl = GitlabGroup.URL + "/" + groupId + GitlabGroupMember.URL + PARAM_MAX_ITEMS_PER_PAGE; + return retrieve().getAll(tailUrl, GitlabGroupMember[].class); + } + + /** + * Creates a Group + * + * @param name The name of the group. The + * name will also be used as the path + * of the group. + * @return The GitLab Group + * @throws IOException on gitlab api call error + */ + public GitlabGroup createGroup(String name) throws IOException { + return createGroup(name, name); + } + + /** + * Creates a Group + * + * @param name The name of the group + * @param path The path for the group + * @return The GitLab Group + * @throws IOException on gitlab api call error + */ + public GitlabGroup createGroup(String name, String path) throws IOException { + return createGroup(name, path, null, null, null); + } + + /** + * Creates a 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 + */ + public GitlabGroup createGroupViaSudo(String name, String path, GitlabUser sudoUser) throws IOException { + return createGroup(name, path, null, null, sudoUser); + } + + /** + * 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 + * @return The GitLab Group + * @throws IOException on gitlab api call error + */ + public GitlabGroup createGroup(String name, String path, String ldapCn, GitlabAccessLevel ldapAccess) throws IOException { + return createGroup(name, path, ldapCn, ldapAccess, null); + } + + + /** + * 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(); - for (GitlabMergeRequest mergeRequest : allMergeRequests) { - if (mergeRequest.isMerged() || mergeRequest.isClosed()) { - continue; - } - openMergeRequests.add(mergeRequest); + return dispatch().to(tailUrl, GitlabGroup.class); + } + + /** + * 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 + * @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(); + + 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. + * + * @param group the GitlabGroup + * @param user the GitlabUser + * @param accessLevel the GitlabAccessLevel + * @return the GitlabGroupMember + * @throws IOException on gitlab api call error + */ + public GitlabGroupMember addGroupMember(GitlabGroup group, GitlabUser user, GitlabAccessLevel accessLevel) throws IOException { + return addGroupMember(group.getId(), user.getId(), accessLevel); + } + + /** + * Add a group member. + * + * @param groupId the group id + * @param userId the user id + * @param accessLevel the GitlabAccessLevel + * @return the GitlabGroupMember + * @throws IOException on gitlab api call error + */ + public GitlabGroupMember addGroupMember(Integer groupId, Integer userId, GitlabAccessLevel accessLevel) throws IOException { + Query query = new Query() + .appendIf("id", groupId) + .appendIf("user_id", userId) + .appendIf("access_level", accessLevel); + String tailUrl = GitlabGroup.URL + "/" + groupId + GitlabProjectMember.URL + query.toString(); + return dispatch().to(tailUrl, GitlabGroupMember.class); + } + + /** + * Delete a group member. + * + * @param group the GitlabGroup + * @param user the GitlabUser + * @throws IOException on gitlab api call error + */ + public void deleteGroupMember(GitlabGroup group, GitlabUser user) throws IOException { + deleteGroupMember(group.getId(), user.getId()); + } + + /** + * Delete a group member. + * + * @param groupId the group id + * @param userId the user id + * @throws IOException on gitlab api call error + */ + public void deleteGroupMember(Integer groupId, Integer userId) throws IOException { + String tailUrl = GitlabGroup.URL + "/" + groupId + "/" + GitlabGroupMember.URL + "/" + userId; + retrieve().method(DELETE).to(tailUrl, Void.class); + } + + /** + * Delete a group. + * + * @param groupId the group id + * @throws IOException on gitlab api call error + */ + public void deleteGroup(Integer groupId) throws IOException { + String tailUrl = GitlabGroup.URL + "/" + groupId; + 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 + */ + 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 openMergeRequests; + return Arrays.asList(retrieve().method(GET).to(tailUrl.toString(), GitlabProject[].class)); } - public List getMergeRequests(Integer projectId) throws IOException { - String tailUrl = GitlabProject.URL + "/" + projectId + GitlabMergeRequest.URL; - return fetchMergeRequests(tailUrl); + /** + * Get a list of projects owned by the authenticated user. + * + * @return A list of gitlab projects + * @throws IOException on gitlab api call error + */ + public List getOwnedProjects() throws IOException { + 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); } - public List getMergeRequests(GitlabProject project) throws IOException { - String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabMergeRequest.URL; - return fetchMergeRequests(tailUrl); + /** + * Get a list of projects that the authenticated user is a member of. + * + * @return A list of gitlab projects + * @throws IOException on gitlab api call error + */ + 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); } - public List getAllMergeRequests(GitlabProject project) throws IOException { - String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabMergeRequest.URL; - List results = new ArrayList(); - Iterator iterator = retrieve().asIterator(tailUrl, GitlabMergeRequest[].class); + /** + * Get a list of projects starred by the authenticated user. + * + * @return A list of gitlab projects + * @throws IOException on gitlab api call error + */ + 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. + * + * @return A list of gitlab projects + * @throws IOException on gitlab api call error + */ + 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 + * + * @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 getProjectsViaSudoWithPagination(GitlabUser user, int page, int perPage) throws IOException { + Pagination pagination = new Pagination() + .withPage(page) + .withPerPage(perPage); + return getProjectsViaSudoWithPagination(user, pagination); + } - while (iterator.hasNext()) { - GitlabMergeRequest[] requests = iterator.next(); + /** + * Get a list of projects of with Pagination. + * + * @param user Gitlab User to invoke sudo with + * @param pagination + * @return A list of gitlab projects + * @throws IOException Gitlab API call error + */ + public List getProjectsViaSudoWithPagination(GitlabUser user, Pagination pagination) throws IOException { + StringBuilder tailUrl = new StringBuilder(GitlabProject.URL); - if (requests.length > 0) { - results.addAll(Arrays.asList(requests)); - } + Query query = new Query() + .appendIf(PARAM_SUDO, user.getId()); + + if (pagination != null) { + query.mergeWith(pagination.asQuery()); } - return results; + tailUrl.append(query.toString()); + return Arrays.asList(retrieve().method(GET).to(tailUrl.toString(), GitlabProject[].class)); } - public GitlabMergeRequest getMergeRequest(GitlabProject project, Integer mergeRequestId) throws IOException { - String tailUrl = GitlabProject.URL + "/" + project.getId() + "/merge_request/" + mergeRequestId; - return retrieve().to(tailUrl, GitlabMergeRequest.class); + /** + * 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. + * + * @return A list of gitlab namespace + */ + public List getNamespaces() { + String tailUrl = GitlabNamespace.URL + PARAM_MAX_ITEMS_PER_PAGE; + return retrieve().getAll(tailUrl, GitlabNamespace[].class); } - public List getNotes(GitlabMergeRequest mergeRequest) throws IOException { - String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + - GitlabMergeRequest.URL + "/" + mergeRequest.getId() + - GitlabNote.URL; + /** + * Uploads a file to a project + * + * @param project + * @param file + * @return + * @throws IOException on gitlab api call error + */ + 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); + } - GitlabNote[] notes = retrieve().to(tailUrl, GitlabNote[].class); - return Arrays.asList(notes); + /** + * 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()); } - public List getAllNotes(GitlabMergeRequest mergeRequest) throws IOException { - String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + - GitlabMergeRequest.URL + "/" + mergeRequest.getId() + - GitlabNote.URL; + /** + * 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); + } - List results = new ArrayList(); - Iterator iterator = retrieve().asIterator(tailUrl, GitlabNote[].class); - while (iterator.hasNext()) { - GitlabNote[] projects = iterator.next(); + /** + * 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()); - if (projects.length > 0) { - results.addAll(Arrays.asList(projects)); - } + GitlabNamespace namespace = project.getNamespace(); + if (namespace != null) { + query.appendIf("namespace_id", namespace.getId()); } - return results; + String tailUrl = GitlabProject.URL + query.toString(); + + return dispatch().to(tailUrl, GitlabProject.class); } - public List getCommits(GitlabMergeRequest mergeRequest) throws IOException { - String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + - "/repository" + GitlabCommit.URL + "?ref_name=" + mergeRequest.getSourceBranch(); + /** + * Creates a private Project + * + * @param name The name of the project + * @return The GitLab Project + * @throws IOException on gitlab api call error + */ + public GitlabProject createProject(String name) throws IOException { + return createProject(name, null, null, null, null, null, null, null, null, null, null); + } - GitlabCommit[] commits = retrieve().to(tailUrl, GitlabCommit[].class); - return Arrays.asList(commits); + /** + * 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); } - public GitlabNote createNote(GitlabMergeRequest mergeRequest, String body) throws IOException { - String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + - GitlabMergeRequest.URL + "/" + mergeRequest.getId() + GitlabNote.URL; + /** + * 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); + } - return dispatch().with("body", body).to(tailUrl, GitlabNote.class); + /** + * 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 + * + * @param name The name of the project + * @param namespaceId The Namespace for the new project, otherwise null indicates to use the GitLab default (user) + * @param description A description for the project, null otherwise + * @param issuesEnabled Whether Issues should be enabled, otherwise null indicates to use GitLab default + * @param wallEnabled Whether The Wall should be enabled, otherwise null indicates to use GitLab default + * @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 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, String visibility, String importUrl) throws IOException { + Query query = new Query() + .append("name", name) + .appendIf("namespace_id", namespaceId) + .appendIf("description", description) + .appendIf("issues_enabled", issuesEnabled) + .appendIf("wall_enabled", wallEnabled) + .appendIf("merge_requests_enabled", mergeRequestsEnabled) + .appendIf("wiki_enabled", wikiEnabled) + .appendIf("snippets_enabled", snippetsEnabled) + .appendIf("visibility", visibility) + .appendIf("import_url", importUrl); + + String tailUrl = GitlabProject.URL + query.toString(); + + return dispatch().to(tailUrl, GitlabProject.class); + } + + /** + * Creates a Project for a specific User + * + * @param userId The id of the user to create the project for + * @param name The name of the project + * @return The GitLab Project + * @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); } - private List fetchMergeRequests(String tailUrl) throws IOException { - GitlabMergeRequest[] mergeRequests = retrieve().to(tailUrl, GitlabMergeRequest[].class); - return Arrays.asList(mergeRequests); + /** + * Creates a Project for a specific User + * + * @param userId The id of the user to create the project for + * @param name The name of the project + * @param description A description for the project, null otherwise + * @param defaultBranch The default branch for the project, otherwise null indicates to use GitLab default (master) + * @param issuesEnabled Whether Issues should be enabled, otherwise null indicates to use GitLab default + * @param wallEnabled Whether The Wall should be enabled, otherwise null indicates to use GitLab default + * @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 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, String visibility, String importUrl) throws IOException { + Query query = new Query() + .append("name", name) + .appendIf("description", description) + .appendIf("default_branch", defaultBranch) + .appendIf("issues_enabled", issuesEnabled) + .appendIf("wall_enabled", wallEnabled) + .appendIf("merge_requests_enabled", mergeRequestsEnabled) + .appendIf("wiki_enabled", wikiEnabled) + .appendIf("snippets_enabled", snippetsEnabled) + .appendIf("visibility", visibility) + .appendIf("import_url", importUrl); + + String tailUrl = GitlabProject.URL + "/user/" + userId + query.toString(); + + 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 + * + * @param projectId The id of the project to update + * @param name The name of the project + * @param description A description for the project, null otherwise + * @param defaultBranch The branch displayed in the Gitlab UI when a user navigates to the project + * @param issuesEnabled Whether Issues should be enabled, otherwise null indicates to use GitLab default + * @param wallEnabled Whether The Wall should be enabled, otherwise null indicates to use GitLab default + * @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 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, + Boolean issuesEnabled, + Boolean wallEnabled, + Boolean mergeRequestsEnabled, + Boolean wikiEnabled, + Boolean snippetsEnabled, + String visibility) + throws IOException { + Query query = new Query() + .appendIf("name", name) + .appendIf("description", description) + .appendIf("default_branch", defaultBranch) + .appendIf("issues_enabled", issuesEnabled) + .appendIf("wall_enabled", wallEnabled) + .appendIf("merge_requests_enabled", mergeRequestsEnabled) + .appendIf("wiki_enabled", wikiEnabled) + .appendIf("snippets_enabled", snippetsEnabled) + .appendIf("visibility", visibility); + + String tailUrl = GitlabProject.URL + "/" + projectId + query.toString(); + + return retrieve().method(PUT).to(tailUrl, GitlabProject.class); + } + + /** + * Delete a Project. + * + * @param projectId The id of the project to delete + * @throws IOException on gitlab api call error + */ + public void deleteProject(Serializable projectId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId); + retrieve().method(DELETE).to(tailUrl, null); + } + + public List getOpenMergeRequests(Serializable projectId) throws IOException { + 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 { + 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 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(Serializable projectId) { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabMergeRequest.URL + PARAM_MAX_ITEMS_PER_PAGE; + return retrieve().getAll(tailUrl, GitlabMergeRequest[].class); + } + + 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 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 { + 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 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 mergeRequestIid) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + + GitlabMergeRequest.URL + "/" + mergeRequestIid + "/changes"; + return retrieve().to(tailUrl, GitlabMergeRequest.class); + } + + 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 + * + * @param projectId + * @param sourceBranch + * @param targetBranch + * @param assigneeId + * @param title + * @return GitlabMergeRequest + * @throws IOException on gitlab api call error + */ + public GitlabMergeRequest createMergeRequest(Serializable projectId, String sourceBranch, String targetBranch, + Integer assigneeId, String title) throws IOException { + + Query query = new Query() + .appendIf("target_branch", targetBranch) + .appendIf("source_branch", sourceBranch) + .appendIf("assignee_id", assigneeId) + .appendIf("title", title); + + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabMergeRequest.URL + query.toString(); + + return dispatch().to(tailUrl, GitlabMergeRequest.class); + } + + + /** + * 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); + } + + /** + * 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 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 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() + .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 + "/" + mergeRequest.getProjectId() + + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + + GitlabDiscussion.URL + query.toString(); + + return dispatch().to(tailUrl, GitlabDiscussion.class); + } + + /** + * 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 + */ + 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'!"); + } + } + + /** + * Resolve or unresolve a whole discussion of a merge request. + * + * @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 GitlabDiscussion resolveDiscussion(GitlabMergeRequest mergeRequest, + int discussionId, boolean resolved) throws IOException { + String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + + GitlabDiscussion.URL + "/" + discussionId; + return retrieve().method(PUT) + .with("resolved", resolved) + .to(tailUrl, GitlabDiscussion.class); + } + + /** + * 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.getIid() + + GitlabDiscussion.URL + "/" + discussionId + + GitlabNote.URL; + return dispatch().with("body", body).to(tailUrl, GitlabNote.class); + } + + /** + * 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.getIid() + + GitlabDiscussion.URL + "/" + discussionId + + GitlabNote.URL + "/" + noteId; + return retrieve().method(PUT) + .with("body", body) + .with("resolved", resolved) + .to(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 + // GET /projects/:id/repository/commits/:sha + public GitlabCommit getCommit(Serializable projectId, String commitHash) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + "/repository/commits/" + commitHash; + return retrieve().to(tailUrl, GitlabCommit.class); + } + + public List getCommits(GitlabMergeRequest mergeRequest) throws IOException { + return getCommits(mergeRequest, new Pagination()); + } + + public List getCommits(GitlabMergeRequest mergeRequest, Pagination pagination) throws IOException { + Integer projectId = mergeRequest.getSourceProjectId(); + if (projectId == null) { + projectId = mergeRequest.getProjectId(); + } + + 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); + } + + public List getLastCommits(Serializable projectId) throws IOException { + return getCommits(projectId, null, null); + } + + public List getLastCommits(Serializable projectId, String branchOrTag) throws IOException { + return getCommits(projectId, null, branchOrTag); + } + + 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()); + } + + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + + "/repository" + GitlabCommit.URL + query; + final GitlabCommit[] commits = retrieve().to(tailUrl, GitlabCommit[].class); + return Arrays.asList(commits); + } + + // gets all commits for a project + public List getAllCommits(Serializable projectId) throws IOException { + return getAllCommits(projectId, null, null); + } + + // gets all commits for a project + public List getAllCommits(Serializable projectId, String branchOrTag) throws IOException { + return getAllCommits(projectId, null, branchOrTag); + } + + public List getAllCommits(Serializable projectId, Pagination pagination, + String branchOrTag) throws IOException { + final Query query = new Query(); + if (branchOrTag != null) { + query.append("ref_name", branchOrTag); + } + + if (pagination != null) { + query.mergeWith(pagination.asQuery()); + } + + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + + "/repository" + GitlabCommit.URL + query; + return retrieve().getAll(tailUrl, GitlabCommit[].class); + } + + // List commit diffs for a project ID and commit hash + // GET /projects/:id/repository/commits/:sha/diff + public List getCommitDiffs(Serializable projectId, String commitHash) throws IOException { + return getCommitDiffs(projectId, commitHash, new Pagination()); + } + + public List getCommitDiffs(Serializable projectId, String commitHash, + Pagination pagination) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + "/repository/commits/" + commitHash + + GitlabCommitDiff.URL + pagination; + GitlabCommitDiff[] diffs = retrieve().to(tailUrl, GitlabCommitDiff[].class); + return Arrays.asList(diffs); + } + + + // List commit diffs for a project ID and two commit hashes + // GET /projects/:id/repository/compare + public GitlabCommitComparison compareCommits(Serializable projectId, String commitHash1, String commitHash2) throws IOException { + return compareCommits(projectId, commitHash1, commitHash2, new Pagination()); + } + + // List commit diffs for a project ID and two commit hashes + // GET /projects/:id/repository/compare + public GitlabCommitComparison compareCommits(Serializable projectId, String commitHash1, String commitHash2, Pagination pagination) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabCommitComparison.URL; + Query query = new Query() + .append("from", commitHash1) + .append("to", commitHash2); + query.mergeWith(pagination.asQuery()); + return retrieve().to(tailUrl + query, GitlabCommitComparison.class); + } + + // 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.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 { + 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); + } + + // Submit new commit statuses for a project ID and commit hash + // GET /projects/:id/statuses/:sha + public GitlabCommitStatus createCommitStatus(GitlabProject project, String commitHash, String state, String ref, + String name, String targetUrl, String description) throws IOException { + 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) + .with("name", name) + .with("target_url", targetUrl) + .with("description", description) + .to(tailUrl, GitlabCommitStatus.class); + } + + /** + * Get raw file content + * + * @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 { + return getRawFileContent(project.getId(), sha, filepath); + } + + /** + * Get raw file content + * + * @param projectId 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(Serializable projectId, String sha, String filepath) throws IOException { + Query query = new Query() + .append("ref", sha); + + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + "/repository/files/" + sanitizePath(filepath) + "/raw" + query.toString(); + return retrieve().to(tailUrl, byte[].class); + } + + /** + * Get the raw file contents for a blob by blob SHA. + * + * @param project The Project + * @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/blobs/" + sha + "/raw"; + return retrieve().to(tailUrl, byte[].class); + } + + /** + * Get an archive of the repository + * + * @param project The Project + * @throws IOException on gitlab api call error + */ + public byte[] getFileArchive(GitlabProject project) throws IOException { + String tailUrl = GitlabProject.URL + "/" + project.getId() + "/repository/archive"; + return retrieve().to(tailUrl, byte[].class); + } + + /** + * 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 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, boolean recursive) throws IOException { + Query query = new Pagination().withPerPage(Pagination.MAX_ITEMS_PER_PAGE).asQuery() + .appendIf("path", path) + .appendIf("ref", ref) + .appendIf("recursive", recursive); + + String tailUrl = GitlabProject.URL + "/" + project.getId() + "/repository" + GitlabRepositoryTree.URL + query.toString(); + 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 + * @return the Gitlab Note + * @throws IOException on gitlab api call error + */ + public GitlabNote updateNote(GitlabMergeRequest mergeRequest, Integer noteId, String body) throws IOException { + Query query = new Query() + .appendIf("body", body); + + String tailUrl = GitlabProject.URL + "/" + mergeRequest.getProjectId() + + GitlabMergeRequest.URL + "/" + mergeRequest.getIid() + GitlabNote.URL + "/" + noteId + query.toString(); + + 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.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 + * @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.getIid() + GitlabNote.URL + "/" + noteToDelete.getId(); + retrieve().method(DELETE).to(tailUrl, GitlabNote.class); + } + + 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) { + 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 + * + * + * @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 + * @throws IOException on gitlab api call error + */ + public void createBranch(GitlabProject project, String branchName, String ref) throws IOException { + createBranch(project.getId(), branchName, ref); + } + + /** + * Create Branch. + * + * 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 + * @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", branchName).with("ref", ref).to(tailUrl, Void.class); + } + + /** + * Delete Branch. + * + * @param projectId The id of the project + * @param branchName The name of the branch to delete + * @throws IOException on gitlab api call error + */ + public void deleteBranch(Serializable projectId, String branchName) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabBranch.URL + '/' + sanitizePath(branchName); + retrieve().method(DELETE).to(tailUrl, Void.class); + } + + 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 { + 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 + '/' + 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; + return retrieve().getAll(tailUrl, GitlabProjectHook[].class); + } + + public List getProjectHooks(GitlabProject project) throws IOException { + String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabProjectHook.URL; + return retrieve().getAll(tailUrl, GitlabProjectHook[].class); + } + + public GitlabProjectHook getProjectHook(GitlabProject project, String hookId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabProjectHook.URL + "/" + hookId; + return retrieve().to(tailUrl, GitlabProjectHook.class); + } + + public GitlabProjectHook addProjectHook(GitlabProject project, String url) throws IOException { + Query query = new Query() + .append("url", url); + + String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabProjectHook.URL + query.toString(); + return dispatch().to(tailUrl, GitlabProjectHook.class); + } + + 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() + .with("url", url) + .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 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); + } + + 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); + } + + 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); + } + + 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, 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); + } + + public GitlabIssue getIssue(Serializable projectId, Integer issueId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabIssue.URL + "/" + issueId; + return retrieve().to(tailUrl, GitlabIssue.class); + } + + 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(); + applyIssue(requestor, projectId, assigneeId, milestoneId, labels, description, title); + + 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(); + requestor.with("to_project_id", toProjectId); + return requestor.to(tailUrl, GitlabIssue.class); + } + + 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); + applyIssue(requestor, projectId, assigneeId, milestoneId, labels, description, title); + + if (action != GitlabIssue.Action.LEAVE) { + requestor.with("state_event", action.toString().toLowerCase()); + } + + return requestor.to(tailUrl, GitlabIssue.class); + } + + private void applyIssue(GitlabHTTPRequestor requestor, int projectId, + int assigneeId, Integer milestoneId, String labels, String description, + String title) { + + requestor.with("title", title) + .with("description", description) + .with("labels", labels) + .with("milestone_id", milestoneId); + + if (assigneeId != 0) { + 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.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.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 + "/" + 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.getIid(), message); + } + + /** + * Delete an Issue Note + * + * @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 + "/" + 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 + * @throws IOException on gitlab api call error + */ + 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 on gitlab api call error + */ + public List getLabels(Serializable projectId) + throws IOException { + 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 on gitlab api call error + */ + public List getLabels(GitlabProject project) + throws IOException { + return getLabels(project.getId()); + } + + /** + * 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). + * @return The newly created label. + * @throws IOException on gitlab api call error + */ + public GitlabLabel createLabel( + Serializable projectId, + String name, + String color) throws IOException { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabLabel.URL; + return dispatch().with("name", name) + .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. + * @return The newly created label. + */ + public GitlabLabel createLabel(Serializable projectId, GitlabLabel label) + throws IOException { + String name = label.getName(); + String color = label.getColor(); + return createLabel(projectId, name, color); + } + + /** + * 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 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 + "/" + + sanitizeProjectId(projectId) + + GitlabLabel.URL + + query.toString(); + 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 on gitlab api call error + */ + public void deleteLabel(Serializable projectId, GitlabLabel label) + throws IOException { + deleteLabel(projectId, label.getName()); + } + + /** + * 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. + * @return The updated, deserialized label. + * @throws IOException on gitlab api call error + */ + public GitlabLabel updateLabel(Serializable projectId, + String name, + String newName, + String newColor) throws IOException { + 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); + } + if (newColor != null) { + requestor = requestor.with("color", newColor); + } + return requestor.to(tailUrl, GitlabLabel.class); + } + + public List getMilestones(GitlabProject project) throws IOException { + return getProjectMilestones(String.valueOf(project.getId())); + } + + public List getMilestones(GitlabGroup group) throws IOException { + return getGroupMilestones(String.valueOf(group.getId())); + } + + 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 description The description of the milestone. (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 on gitlab api call error + */ + public GitlabMilestone createMilestone( + Serializable projectId, + String title, + String description, + 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) { + 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 on gitlab api call error + */ + public GitlabMilestone createMilestone( + Serializable projectId, + GitlabMilestone milestone) throws IOException { + String title = milestone.getTitle(); + String description = milestone.getDescription(); + Date dateDue = milestone.getDueDate(); + Date dateStart = milestone.getStartDate(); + return createMilestone(projectId, title, description, dateDue, dateStart); + } + + /** + * Updates an existing project milestone. + * + * @param projectId The ID of the project. + * @param milestoneId The ID of the milestone. + * @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 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 on gitlab api call error + */ + public GitlabMilestone updateMilestone( + Serializable projectId, + int milestoneId, + String title, + String description, + Date dueDate, + Date startDate, + String stateEvent) throws IOException { + String tailUrl = GitlabProject.URL + "/" + + sanitizeProjectId(projectId) + + GitlabMilestone.URL + "/" + + milestoneId; + GitlabHTTPRequestor requestor = retrieve().method(PUT); + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + if (title != null) { + requestor.with("title", title); + } + if (description != null) { + requestor = requestor.with("description", description); + } + if (dueDate != null) { + 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); + } + return requestor.to(tailUrl, GitlabMilestone.class); + } + + /** + * Updates an existing project 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 on gitlab api call error + */ + public GitlabMilestone updateMilestone( + Serializable projectId, + GitlabMilestone edited, + String stateEvent) throws IOException { + return updateMilestone(projectId, + edited.getId(), + edited.getTitle(), + edited.getDescription(), + edited.getDueDate(), + edited.getStartDate(), + stateEvent); + } + + /** + * Updates an existing project milestone. + * + * @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 on gitlab api call error + */ + public GitlabMilestone updateMilestone( + GitlabMilestone edited, + String stateEvent) + throws IOException { + return updateMilestone(edited.getProjectId(), edited, stateEvent); + } + + /** + * Add a project member. + * + * @param project the GitlabProject + * @param user the GitlabUser + * @param accessLevel the GitlabAccessLevel + * @return the GitlabProjectMember + * @throws IOException on gitlab api call error + */ + public GitlabProjectMember addProjectMember(GitlabProject project, GitlabUser user, GitlabAccessLevel accessLevel) throws IOException { + return addProjectMember(project.getId(), user.getId(), accessLevel); + } + + /** + * Add a project member. + * + * @param projectId the project id + * @param userId the user id + * @param accessLevel the GitlabAccessLevel + * @return the GitlabProjectMember + * @throws IOException on gitlab api call error + */ + public GitlabProjectMember addProjectMember(Integer projectId, Integer userId, GitlabAccessLevel accessLevel) throws IOException { + Query query = new Query() + .appendIf("id", projectId) + .appendIf("user_id", userId) + .appendIf("access_level", accessLevel); + String tailUrl = GitlabProject.URL + "/" + projectId + GitlabProjectMember.URL + query.toString(); + return dispatch().to(tailUrl, GitlabProjectMember.class); + } + + /** + * Delete a project team member. + * + * @param project the GitlabProject + * @param user the GitlabUser + * @throws IOException on gitlab api call error + */ + public void deleteProjectMember(GitlabProject project, GitlabUser user) throws IOException { + deleteProjectMember(project.getId(), user.getId()); + } + + /** + * Delete a project team member. + * + * @param projectId the project id + * @param userId the user id + * @throws IOException on gitlab api call error + */ + public void deleteProjectMember(Integer projectId, Integer userId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + projectId + "/" + GitlabProjectMember.URL + "/" + userId; + 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()); + } + + public List getProjectMembers(GitlabProject project, Pagination pagination) throws IOException { + return getProjectMembers(project.getId(), pagination); + } + + public List getProjectMembers(Serializable projectId) throws IOException { + return getProjectMembers(projectId, new Pagination()); + } + + public List getProjectMembers(Serializable projectId, Pagination pagination) throws IOException { + 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 + * @throws IOException on gitlab api call error + */ + public List getNamespaceMembers(GitlabNamespace namespace) throws IOException { + return getNamespaceMembers(namespace.getId()); + } + + /** + * 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 + * @throws IOException on gitlab api call error + */ + public List getNamespaceMembers(Integer namespaceId) throws IOException { + String tailUrl = GitlabGroup.URL + "/" + namespaceId + GitlabProjectMember.URL; + return Arrays.asList(retrieve().to(tailUrl, GitlabProjectMember[].class)); + } + + /** + * Transfer a project to the given namespace + * + * @param namespaceId Namespace ID + * @param projectId Project ID + * @throws IOException on gitlab api call error + */ + public void transfer(Integer namespaceId, Integer projectId) throws IOException { + 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 + * @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("can_push", Boolean.toString(canPush)); + + 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 + * @throws IOException on gitlab api call error + */ + public void deleteDeployKey(Integer targetProjectId, Integer targetKeyId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + targetProjectId + GitlabSSHKey.DEPLOY_KEYS_URL + "/" + targetKeyId; + retrieve().method(DELETE).to(tailUrl, Void.class); + } + + /** + * Gets all deploy keys for a project + * + * @param targetProjectId The id of the Gitlab project + * @return The list of project deploy keys + * @throws IOException on gitlab api call error + */ + public List getDeployKeys(Integer targetProjectId) throws IOException { + String tailUrl = GitlabProject.URL + "/" + targetProjectId + GitlabSSHKey.DEPLOY_KEYS_URL; + return Arrays.asList(retrieve().to(tailUrl, GitlabSSHKey[].class)); + } + + public GitlabSession getCurrentSession() throws IOException { + String tailUrl = "/user"; + return retrieve().to(tailUrl, GitlabSession.class); + } + + /** + * Get list of system hooks + * + * @return The system hooks list + * @throws IOException on gitlab api call error + */ + public List getSystemHooks() throws IOException { + String tailUrl = GitlabSystemHook.URL; + return Arrays.asList(retrieve().to(tailUrl, GitlabSystemHook[].class)); + } + + /** + * Add new system hook hook + * + * @param url System hook url + * @throws IOException on gitlab api call error + */ + public GitlabSystemHook addSystemHook(String url) throws IOException { + String tailUrl = GitlabSystemHook.URL; + return dispatch().with("url", url).to(tailUrl, GitlabSystemHook.class); + } + + /** + * Test system hook + * + * @throws IOException on gitlab api call error + */ + public void testSystemHook(Integer hookId) throws IOException { + String tailUrl = GitlabSystemHook.URL + "/" + hookId; + retrieve().to(tailUrl, Void.class); + } + + /** + * Delete system hook + * + * @throws IOException on gitlab api call error + */ + public GitlabSystemHook deleteSystemHook(Integer hookId) throws IOException { + String tailUrl = GitlabSystemHook.URL + "/" + hookId; + return retrieve().method(DELETE).to(tailUrl, GitlabSystemHook.class); + } + + private String sanitizeProjectId(Serializable projectId) { + 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(id), "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException((e)); + } + } + + private String sanitizePath(String branch) { + try { + return URLEncoder.encode(branch, "UTF-8").replaceAll("\\+", "%20"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException((e)); + } + } + + /** + * 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 + * @throws IOException on gitlab api call error + * @see http://doc.gitlab.com/ce/api/commits.html#post-comment-to-commit + */ + 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(); + + 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 + * @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; + + return Arrays.asList(retrieve().to(tailUrl, CommitComment[].class)); + } + + /** + * Get a list of tags in specific project + * + * @param projectId + * @return + */ + public List getTags(Serializable projectId) { + String tailUrl = GitlabProject.URL + "/" + sanitizeProjectId(projectId) + GitlabTag.URL + PARAM_MAX_ITEMS_PER_PAGE; + return retrieve().getAll(tailUrl, GitlabTag[].class); + } + + /** + * Get a list of tags in specific project + * + * @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 GitlabTag getTag(GitlabProject project, String tagName) throws IOException { + String tailUrl = GitlabProject.URL + "/" + project.getId() + GitlabTag.URL + "/" + tagName; + return retrieve().to(tailUrl, GitlabTag.class); + } + + /** + * Create tag in specific project + * + * @param projectId + * @param tagName + * @param ref + * @param message + * @param releaseDescription + * @return + * @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); + } + + /** + * Create tag in specific project + * + * @param project + * @param tagName + * @param ref + * @param message + * @param releaseDescription + * @return + * @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); + } + + /** + * Delete tag in specific project + * + * @param projectId + * @param tagName + * @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); + } + + /** + * Delete tag in specific project + * + * @param project + * @param tagName + * @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); + } + + /** + * Get all awards for a merge request + * + * @param mergeRequest + */ + 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); + } + + /** + * 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.getIid() + GitlabAward.URL + "/" + awardId; + + return retrieve().to(tailUrl, GitlabAward.class); + } + + /** + * 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.getIid() + GitlabAward.URL + query.toString(); + + return dispatch().to(tailUrl, GitlabAward.class); + } + + /** + * 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.getIid() + GitlabAward.URL + "/" + award.getId(); + + retrieve().method(DELETE).to(tailUrl, Void.class); + } + + /** + * Get all awards for an issue + * + * @param issue + */ + 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); + } + + /** + * Get a specific award for an issue + * + * @param issue + * @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; + + return retrieve().to(tailUrl, GitlabAward.class); + } + + /** + * 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); + } + + /** + * Delete an award for an issue + * + * @param issue + * @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); + } + + /** + * Get all awards for an issue note + * + * @param issue + * @param noteId + */ + 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); + } + + /** + * Get a specific award for an issue note + * + * @param issue + * @param noteId + * @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; + + return retrieve().to(tailUrl, GitlabAward.class); + } + + /** + * Create an award for an issue note + * + * @param issue + * @param noteId + * @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); + } + + /** + * Delete an award for an issue note + * + * @param issue + * @param noteId + * @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); + } + + /** + * Gets build variables associated with a project. + * + * @param projectId The ID of the project. + * @return A non-null list of variables. + * @throws IOException on gitlab api call error + */ + public List getBuildVariables(Integer projectId) + throws IOException { + String tailUrl = GitlabProject.URL + "/" + projectId + GitlabBuildVariable.URL; + GitlabBuildVariable[] variables = retrieve().to(tailUrl, GitlabBuildVariable[].class); + return Arrays.asList(variables); + } + + /** + * Gets build variables associated with a project. + * + * @param project The project associated with variables. + * @return A non-null list of variables. + * @throws IOException on gitlab api call error + */ + public List getBuildVariables(GitlabProject project) + throws IOException { + return getBuildVariables(project.getId()); + } + + /** + * Gets build variable associated with a project and key. + * + * @param projectId The ID of the project. + * @param key The key of the variable. + * @return A variable. + * @throws IOException on gitlab api call error + */ + public GitlabBuildVariable getBuildVariable(Integer projectId, String key) + throws IOException { + String tailUrl = GitlabProject.URL + "/" + + projectId + + 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 on gitlab api call error + */ + public GitlabBuildVariable getBuildVariable(GitlabProject project, String key) + throws IOException { + return getBuildVariable(project.getId(), 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 + * @return The newly created variable. + * @throws IOException on gitlab api call error + */ + public GitlabBuildVariable createBuildVariable( + Integer projectId, + String key, + String value) throws IOException { + String tailUrl = GitlabProject.URL + "/" + projectId + GitlabBuildVariable.URL; + return dispatch().with("key", key) + .with("value", value) + .to(tailUrl, GitlabBuildVariable.class); + } + + /** + * Creates a new variable. + * + * @param projectId The ID of the project containing the variable. + * @param variable The variable to create. + * @return The newly created variable. + */ + public GitlabBuildVariable createBuildVariable(Integer projectId, GitlabBuildVariable variable) + throws IOException { + String key = variable.getKey(); + String value = variable.getValue(); + return createBuildVariable(projectId, key, value); + } + + /** + * 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 on gitlab api call error + */ + public void deleteBuildVariable(Integer projectId, String key) + throws IOException { + String tailUrl = GitlabProject.URL + "/" + + projectId + + GitlabBuildVariable.URL + "/" + + key; + 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 on gitlab api call error + */ + public void deleteBuildVariable(Integer projectId, GitlabBuildVariable variable) + throws IOException { + deleteBuildVariable(projectId, variable.getKey()); + } + + /** + * 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. + * @return The updated, deserialized variable. + * @throws IOException on gitlab api call error + */ + public GitlabBuildVariable updateBuildVariable(Integer projectId, + String key, + String newValue) throws IOException { + String tailUrl = GitlabProject.URL + "/" + + projectId + + GitlabBuildVariable.URL + "/" + + key; + GitlabHTTPRequestor requestor = retrieve().method(PUT); + if (newValue != null) { + requestor = requestor.with("value", newValue); + } + return requestor.to(tailUrl, GitlabBuildVariable.class); + } + + /** + * Returns the list of build triggers for a project. + * + * @param project the project + * @return list of build triggers + * @throws IllegalStateException if jobs are not enabled for the project + */ + 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("Jobs are not enabled for " + project.getNameWithNamespace()); + } else { + 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/GitlabAPIException.java b/src/main/java/org/gitlab/api/GitlabAPIException.java new file mode 100644 index 00000000..05b3fddc --- /dev/null +++ b/src/main/java/org/gitlab/api/GitlabAPIException.java @@ -0,0 +1,20 @@ +package org.gitlab.api; + +import java.io.IOException; + +/** + * Gitlab API Exception + */ +public class GitlabAPIException extends IOException { + + private int responseCode; + + public GitlabAPIException(String message, Integer responseCode, Throwable cause) { + super(message, cause); + this.responseCode = responseCode; + } + + public int getResponseCode() { + return responseCode; + } +} diff --git a/src/main/java/org/gitlab/api/Pagination.java b/src/main/java/org/gitlab/api/Pagination.java new file mode 100644 index 00000000..20be0d27 --- /dev/null +++ b/src/main/java/org/gitlab/api/Pagination.java @@ -0,0 +1,44 @@ +package org.gitlab.api; + +import org.gitlab.api.http.Query; +import org.gitlab.api.query.PaginationQuery; + +/** + * @deprecated Use {@link PaginationQuery#PARAM_PAGE} instead. + */ +@Deprecated +public class Pagination extends PaginationQuery { + + /** + * @deprecated Use {@link PaginationQuery#PARAM_PAGE} instead. + */ + @Deprecated + public static final String PARAM_PAGE = PaginationQuery.PARAM_PAGE; + + /** + @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 Pagination withPerPage(int perPage) { + setPerPage(perPage); + return this; + } + + public Query asQuery() { + return this; + } + +} diff --git a/src/main/java/org/gitlab/api/TokenType.java b/src/main/java/org/gitlab/api/TokenType.java new file mode 100644 index 00000000..572ca1d7 --- /dev/null +++ b/src/main/java/org/gitlab/api/TokenType.java @@ -0,0 +1,35 @@ +package org.gitlab.api; + +public enum TokenType { + PRIVATE_TOKEN("private_token", "PRIVATE-TOKEN", "%s"), + ACCESS_TOKEN("access_token", "Authorization", "Bearer %s"); + + private final String tokenParamName; + private final String tokenHeaderName; + private final String tokenHeaderFormat; + + /** + * Constructor + * + * @param tokenParamName The url parameter name when using AuthMethod.URL_PARAMETER + * @param tokenHeaderName The header name when using AuthMethod.HEADER + * @param tokenHeaderFormat The header format for String.format when using AuthMethod.HEADER + */ + TokenType(String tokenParamName, String tokenHeaderName, String tokenHeaderFormat) { + this.tokenParamName = tokenParamName; + this.tokenHeaderName = tokenHeaderName; + this.tokenHeaderFormat = tokenHeaderFormat; + } + + public String getTokenParamName() { + return tokenParamName; + } + + public String getTokenHeaderName() { + return tokenHeaderName; + } + + public String getTokenHeaderFormat() { + return tokenHeaderFormat; + } +} diff --git a/src/main/java/org/gitlab/api/http/GitlabHTTPRequestor.java b/src/main/java/org/gitlab/api/http/GitlabHTTPRequestor.java index 8baf3638..ebe80573 100644 --- a/src/main/java/org/gitlab/api/http/GitlabHTTPRequestor.java +++ b/src/main/java/org/gitlab/api/http/GitlabHTTPRequestor.java @@ -1,91 +1,113 @@ package org.gitlab.api.http; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLHandshakeException; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; +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.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.ProtocolException; -import java.net.URL; +import java.net.*; import java.util.*; import java.util.regex.Matcher; 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 * - * @author @timols + * @author @timols (Tim O) */ public class GitlabHTTPRequestor { - private final GitlabAPI _root; - private String _method = "GET"; // Default to GET requests - private Map _data = new HashMap(); + private static final Pattern PAGE_PATTERN = Pattern.compile("([&|?])page=(\\d+)"); - private enum METHOD { - GET, PUT, POST, PATCH, DELETE, HEAD, OPTIONS, TRACE; + private final GitlabAPI root; - 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()); + private Method method = GET; // Default to GET requests + private Map data = new HashMap<>(); + private Map attachments = new HashMap<>(); - if (i != methods.length - 1) { - builder.append(", "); - } - } - return builder.toString(); - } - } + private String apiToken; + private TokenType tokenType; + private AuthMethod authMethod; public GitlabHTTPRequestor(GitlabAPI root) { - _root = root; + this.root = root; } /** - * Sets the HTTP Request method for the request. - * + * Sets authentication data for the request. * Has a fluent api for method chaining. * - * @param method The HTTP method - * @return this + * @param token The token value + * @param type The type of the token + * @param method The authentication method + * @return this */ - public GitlabHTTPRequestor method(String method) { - try { - _method = METHOD.valueOf(method).toString(); - } catch (IllegalArgumentException e) { - throw new IllegalArgumentException("Invalid HTTP Method: " + method + ". Must be one of " + METHOD.prettyValues()); - } + public GitlabHTTPRequestor authenticate(String token, TokenType type, AuthMethod method) { + this.apiToken = token; + this.tokenType = type; + this.authMethod = method; + return this; + } + /** + * Sets the HTTP Request method for the request. + * Has a fluent api for method chaining. + * + * @param method The HTTP method + * @return this + */ + public GitlabHTTPRequestor method(Method method) { + this.method = method; return this; } /** * Sets the HTTP Form Post parameters for the request - * * Has a fluent api for method chaining * - * @param key - * @param value - * @return this + * @param key Form parameter Key + * @param value Form parameter Value + * @return this */ public GitlabHTTPRequestor with(String key, Object value) { if (value != null && key != null) { - _data.put(key, value); + data.put(key, 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; } @@ -101,155 +123,234 @@ public T to(String tailAPIUrl, Class type) throws IOException { /** * Opens the HTTP(S) connection, submits any data and parses the response. * Will throw an error - * @param tailAPIUrl The url to open a connection to (after the host and namespace) - * @param type The type of the response to be deserialized from - * @param instance The instance to update from the response * - * @return An object of type T - * @throws java.io.IOException + * @param The return type of the method + * @param tailAPIUrl The url to open a connection to (after the host and namespace) + * @param type The type of the response to be deserialized from + * @param instance The instance to update from the response + * @return An object of type T + * @throws java.io.IOException on gitlab api error */ public T to(String tailAPIUrl, Class type, T instance) throws IOException { - HttpURLConnection connection = setupConnection(_root.getAPIUrl(tailAPIUrl)); + HttpURLConnection connection = null; + try { + connection = setupConnection(root.getAPIUrl(tailAPIUrl)); + if (hasAttachments()) { + submitAttachments(connection); + } else if (hasOutput()) { + submitData(connection); + } 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); + } - if (hasOutput()) { - submitData(connection); - } + try { + return parse(connection, type, instance); + } catch (IOException e) { + handleAPIError(e, connection); + } - try { - return parse(connection, type, instance); - } catch (IOException e) { - handleAPIError(e, connection); + return null; + } finally { + if (connection != null) { + connection.disconnect(); + } } - - return null; } + public List getAll(final String tailUrl, final Class type) { + List results = new ArrayList<>(); + Iterator iterator = asIterator(tailUrl, type); + + while (iterator.hasNext()) { + T[] requests = iterator.next(); + + if (requests.length > 0) { + results.addAll(Arrays.asList(requests)); + } + } + return results; + } 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()) { + if (!data.isEmpty()) { throw new IllegalStateException(); } return new Iterator() { - T _next; - URL _url; + T next; + URL url; { try { - _url = _root.getAPIUrl(tailApiUrl); + url = root.getAPIUrl(tailApiUrl); } catch (IOException e) { - throw new Error(e); + throw new UncheckedIOException(e); } } @Override public boolean hasNext() { fetch(); - if (_next.getClass().isArray()) { - Object[] arr = (Object[]) _next; + if (next != null && next.getClass().isArray()) { + Object[] arr = (Object[]) next; return arr.length != 0; } else { - return _next != null; + return next != null; } } @Override public T next() { fetch(); - T record = _next; + T record = next; if (record == null) { throw new NoSuchElementException(); } - _next = null; + next = null; return record; } + @Override public void remove() { throw new UnsupportedOperationException(); } private void fetch() { - if (_next != null) { + if (next != null) { return; } - if (_url == null) { + if (url == null) { return; } try { - HttpURLConnection connection = setupConnection(_url); + HttpURLConnection connection = setupConnection(url); try { - _next = parse(connection, type, null); - assert _next != null; - findNextUrl(connection); + next = parse(connection, type, null); + assert next != null; + findNextUrl(); } catch (IOException e) { handleAPIError(e, connection); } } catch (IOException e) { - throw new Error(e); + throw new UncheckedIOException(e); } } - private void findNextUrl(HttpURLConnection connection) throws MalformedURLException { - String url = _url.toString(); + private void findNextUrl() throws MalformedURLException { + String url = this.url.toString(); - _url = null; + this.url = null; /* Increment the page number for the url if a "page" property exists, * otherwise, add the page property and increment it. * The Gitlab API is not a compliant hypermedia REST api, so we use * a naive implementation. */ - Pattern pattern = Pattern.compile("([&|?])page=(\\d+)"); - Matcher matcher = pattern.matcher(url); + Matcher matcher = PAGE_PATTERN.matcher(url); if (matcher.find()) { Integer page = Integer.parseInt(matcher.group(2)) + 1; - _url = new URL(matcher.replaceAll(matcher.group(1) + "page=" + page)); + this.url = new URL(matcher.replaceAll(matcher.group(1) + "page=" + page)); } 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 - _url = new URL(url + "&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); + 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 { - if (_root.isIgnoreCertificateErrors()) { + if (root.isIgnoreCertificateErrors()) { ignoreCertificateErrors(); } - HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + if (apiToken != null && authMethod == AuthMethod.URL_PARAMETER) { + String urlWithAuth = url.toString(); + urlWithAuth = urlWithAuth + (urlWithAuth.indexOf('?') > 0 ? '&' : '?') + + tokenType.getTokenParamName() + "=" + apiToken; + url = new URL(urlWithAuth); + } + + 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.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; } @@ -257,18 +358,24 @@ private HttpURLConnection setupConnection(URL url) throws IOException { private T parse(HttpURLConnection connection, Class type, T instance) throws IOException { InputStreamReader reader = null; try { + if (byte[].class == type) { + 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"); + throw new SSLException("You can disable certificate checking by setting ignoreCertificateErrors " + + "on GitlabHTTPRequestor.", e); } finally { IOUtils.closeQuietly(reader); } @@ -287,17 +394,19 @@ 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 FileNotFoundException || // pass through 404 Not Found to allow the caller to handle it intelligently + e instanceof SocketTimeoutException || + e instanceof ConnectException) { + throw e; } InputStream es = wrapStream(connection, connection.getErrorStream()); try { + String error = null; if (es != null) { - throw (IOException) new IOException(IOUtils.toString(es, "UTF-8")).initCause(e); - } else { - throw e; + error = IOUtils.toString(es, "UTF-8"); } + throw new GitlabAPIException(error, connection.getResponseCode(), e); } finally { IOUtils.closeQuietly(es); } @@ -305,25 +414,32 @@ private void handleAPIError(IOException e, HttpURLConnection connection) throws private void ignoreCertificateErrors() { TrustManager[] trustAllCerts = new TrustManager[]{ - new X509TrustManager() { - public java.security.cert.X509Certificate[] getAcceptedIssuers() { - return null; - } - public void checkClientTrusted( - java.security.cert.X509Certificate[] certs, String authType) { - } - public void checkServerTrusted( - java.security.cert.X509Certificate[] certs, String authType) { + new X509TrustManager() { + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return null; + } + + @Override + public void checkClientTrusted( + java.security.cert.X509Certificate[] certs, String authType) { + } + + @Override + public void checkServerTrusted( + java.security.cert.X509Certificate[] certs, String authType) { + } } - } }; + // Added per https://github.com/timols/java-gitlab-api/issues/44 + HostnameVerifier nullVerifier = (hostname, session) -> true; try { SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); - } catch (Exception e) { - // Ignore it - } + // Added per https://github.com/timols/java-gitlab-api/issues/44 + HttpsURLConnection.setDefaultHostnameVerifier(nullVerifier); + } 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 new file mode 100644 index 00000000..ad8db9a0 --- /dev/null +++ b/src/main/java/org/gitlab/api/http/Query.java @@ -0,0 +1,102 @@ +package org.gitlab.api.http; + +import org.gitlab.api.models.GitlabAccessLevel; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.List; + +/** + * Models the Query + * aspect of a URL + */ +public class Query { + + private class Tuple { + T1 _1; + T2 _2; + + public Tuple(T1 _1, T2 _2) { + this._1 = _1; + this._2 = _2; + } + } + + /** + * The type of params is: + * Tuple> + */ + private final List>> params = new ArrayList>>(); + + /** + * Appends a parameter to the query + * + * @param name Parameter name + * @param value Parameter value + * @return this + * @throws java.io.UnsupportedEncodingException If the provided value cannot be URL Encoded + */ + public Query append(final String name, final String value) throws UnsupportedEncodingException { + params.add(new Tuple>(name, new Tuple(value, URLEncoder.encode(value, "UTF-8")))); + 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 T 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 GitlabAccessLevel value) throws UnsupportedEncodingException { + if (value != null) { + append(name, Integer.toString(value.accessValue)); + } + return this; + } + + public boolean mergeWith(Query query) { + return params.addAll(query.params); + } + + /** + * Returns a Query suitable for appending + * to a URI + */ + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + + for (final Tuple> param : params) { + if (builder.length() == 0) { + builder.append('?'); + } else { + builder.append('&'); + } + builder.append(param._1); + builder.append('='); + builder.append(param._2._2); + } + + return builder.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 new file mode 100644 index 00000000..dd40c0b8 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/CommitComment.java @@ -0,0 +1,69 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Date; + +public class CommitComment { + + public static final String URL = "/comments"; + + private GitlabUser author; + private String note; + private String path; + private String line; + + @JsonProperty("line_type") + private String lineType; + + @JsonProperty("created_at") + private Date createdAt; + + public GitlabUser getAuthor() { + return author; + } + + public void setAuthor(GitlabUser author) { + this.author = author; + } + + public String getNote() { + return note; + } + + public void setNote(String note) { + this.note = note; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public String getLine() { + return line; + } + + public void setLine(String line) { + this.line = line; + } + + public String getLineType() { + return lineType; + } + + 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/GitlabAbstractMember.java b/src/main/java/org/gitlab/api/models/GitlabAbstractMember.java new file mode 100644 index 00000000..e79a9157 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabAbstractMember.java @@ -0,0 +1,20 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public abstract class GitlabAbstractMember extends GitlabUser { + + public static final String URL = "/members"; + + @JsonProperty("access_level") + private int accessLevel; + + public GitlabAccessLevel getAccessLevel() { + return GitlabAccessLevel.fromAccessValue(accessLevel); + } + + public void setAccessLevel(GitlabAccessLevel accessLevel) { + this.accessLevel = accessLevel.accessValue; + } + +} diff --git a/src/main/java/org/gitlab/api/models/GitlabAccessLevel.java b/src/main/java/org/gitlab/api/models/GitlabAccessLevel.java new file mode 100644 index 00000000..1b88f7c7 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabAccessLevel.java @@ -0,0 +1,28 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonCreator; + +public enum GitlabAccessLevel { + Guest(10), + Reporter(20), + Developer(30), + Master(40), + Owner(50); + + public final int accessValue; + + GitlabAccessLevel(int accessValue) { + this.accessValue = accessValue; + } + + // http://fasterxml.github.io/jackson-annotations/javadoc/2.2.0/index.html?com/fasterxml/jackson/annotation/JsonCreator.html + @JsonCreator + public static GitlabAccessLevel fromAccessValue(final int accessValue) throws IllegalArgumentException { + for (final GitlabAccessLevel gitlabAccessLevel : GitlabAccessLevel.values()) { + if (gitlabAccessLevel.accessValue == accessValue) { + return gitlabAccessLevel; + } + } + throw new IllegalArgumentException("No GitLab Access Level enum constant with access value: " + accessValue); + } +} 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/GitlabAward.java b/src/main/java/org/gitlab/api/models/GitlabAward.java new file mode 100644 index 00000000..06122f03 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabAward.java @@ -0,0 +1,92 @@ +package org.gitlab.api.models; + +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class GitlabAward { + + public static final String THUMBSUP = "thumbsup"; + + public static final String THUMBSDOWN = "thumbsdown"; + + public static final String ISSUE = "Issue"; + + public static final String NOTE = "Note"; + + public static final String URL = "/award_emoji"; + + private Integer id; + + private String name; + + private GitlabUser user; + + @JsonProperty("created_at") + private Date createdAt; + + @JsonProperty("updated_at") + private Date updatedAt; + + @JsonProperty("awardable_id") + private Integer awardableId; + + @JsonProperty("awardable_type") + private String awardableType; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setBody(String body) { + this.name = body; + } + + public GitlabUser getUser() { + return user; + } + + public void setUser(GitlabUser user) { + this.user = user; + } + + 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 Integer getAwardableId() { + return awardableId; + } + + public void setAwardableId(Integer awardableId) { + this.awardableId = awardableId; + } + + public String getAwardableType() { + return awardableType; + } + + public void setAwardableType(String awardableType) { + this.awardableType = awardableType; + } +} 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 new file mode 100644 index 00000000..eaebc3e3 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabBranch.java @@ -0,0 +1,40 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class GitlabBranch { + public final static String URL = "/repository/branches"; + + @JsonProperty("name") + private String name; + + @JsonProperty("commit") + private GitlabBranchCommit commit; + + @JsonProperty("protected") + private boolean branchProtected; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public GitlabBranchCommit getCommit() { + return commit; + } + + public void setCommit(GitlabBranchCommit commit) { + this.commit = commit; + } + + public boolean isProtected() { + return branchProtected; + } + + public void setProtected(boolean isProtected) { + this.branchProtected = isProtected; + } +} diff --git a/src/main/java/org/gitlab/api/models/GitlabBranchCommit.java b/src/main/java/org/gitlab/api/models/GitlabBranchCommit.java new file mode 100644 index 00000000..4f753fc6 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabBranchCommit.java @@ -0,0 +1,77 @@ +package org.gitlab.api.models; + +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class GitlabBranchCommit { + public static String URL = "/users"; + + private String id; + private String tree; + private String message; + private GitlabUser author; + private GitlabUser committer; + + @JsonProperty("authored_date") + private Date authoredDate; + + @JsonProperty("committed_date") + private Date committedDate; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getTree() { + return tree; + } + + public void setTree(String tree) { + this.tree = tree; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public GitlabUser getAuthor() { + return author; + } + + public void setAuthor(GitlabUser author) { + this.author = author; + } + + public GitlabUser getCommitter() { + return committer; + } + + public void setCommitter(GitlabUser committer) { + this.committer = committer; + } + + public Date getAuthoredDate() { + return authoredDate; + } + + public void setAuthoredDate(Date authoredDate) { + this.authoredDate = authoredDate; + } + + public Date getCommittedDate() { + return committedDate; + } + + public void setCommittedDate(Date committedDate) { + this.committedDate = committedDate; + } +} diff --git a/src/main/java/org/gitlab/api/models/GitlabBuildVariable.java b/src/main/java/org/gitlab/api/models/GitlabBuildVariable.java new file mode 100644 index 00000000..e26b9601 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabBuildVariable.java @@ -0,0 +1,64 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * @author Vitezslav Zak + */ +public class GitlabBuildVariable { + public final static String URL = "/variables"; + + 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") + private String key; + + @JsonProperty("value") + private String value; + + @JsonProperty("variable_type") + private VariableType variableType; + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getValue() { + return value; + } + + 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 6db13cc9..f99bc32f 100644 --- a/src/main/java/org/gitlab/api/models/GitlabCommit.java +++ b/src/main/java/org/gitlab/api/models/GitlabCommit.java @@ -1,72 +1,145 @@ package org.gitlab.api.models; +import com.fasterxml.jackson.annotation.JsonProperty; + import java.util.Date; -import org.codehaus.jackson.annotate.JsonProperty; +import java.util.List; public class GitlabCommit { public final static String URL = "/commits"; - private String _id; - private String _title; + private String id; + private String title; + private String message; @JsonProperty("short_id") - private String _shortId; + private String shortId; @JsonProperty("author_name") - private String _authorName; + private String authorName; @JsonProperty("author_email") - private String _authorEmail; + private String authorEmail; @JsonProperty("created_at") - private Date _createdAt; + private Date createdAt; + + @JsonProperty("committed_date") + private Date committedDate; + + @JsonProperty("authored_date") + private Date authoredDate; + + @JsonProperty("parent_ids") + private List parentIds; + + @JsonProperty("last_pipeline") + private GitlabPipeline lastPipeline; public String getId() { - return _id; + return id; } public void setId(String id) { - _id = id; + this.id = id; } public String getShortId() { - return _shortId; + return shortId; } public void setShortId(String shortId) { - _shortId = shortId; + this.shortId = shortId; } public String getTitle() { - return _title; + return title; } public void setTitle(String title) { - _title = title; + this.title = title; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; } public String getAuthorName() { - return _authorName; + return authorName; } public void setAuthorName(String authorName) { - _authorName = authorName; + this.authorName = authorName; } public String getAuthorEmail() { - return _authorEmail; + return authorEmail; } public void setAuthorEmail(String authorEmail) { - _authorEmail = authorEmail; + this.authorEmail = authorEmail; } public Date getCreatedAt() { - return _createdAt; + return createdAt; } public void setCreatedAt(Date createdAt) { - _createdAt = createdAt; + this.createdAt = createdAt; + } + + public List getParentIds() { + return parentIds; + } + + 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 + // this prevents us from having to do clever workarounds for + // https://gitlab.com/gitlab-org/gitlab-ce/issues/759 + try { + GitlabCommit commitObj = (GitlabCommit) obj; + return (this.getId().compareTo(commitObj.getId()) == 0); + } catch (ClassCastException e) { + 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/GitlabCommitComparison.java b/src/main/java/org/gitlab/api/models/GitlabCommitComparison.java new file mode 100644 index 00000000..a1658861 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabCommitComparison.java @@ -0,0 +1,60 @@ +package org.gitlab.api.models; + + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +public class GitlabCommitComparison { + public final static String URL = "/repository/compare"; + @JsonProperty("commit") + private GitlabCommit commit; + @JsonProperty("commits") + private List commits; + @JsonProperty("diffs") + private List diffs; + @JsonProperty("compare_same_ref") + private Boolean compareSameRef; + @JsonProperty("compare_timeout") + private Boolean compareTimeout; + + public GitlabCommit getCommit() { + return commit; + } + + public void setCommit(GitlabCommit commit) { + this.commit = commit; + } + + public List getCommits() { + return commits; + } + + public void setCommits(List commits) { + this.commits = commits; + } + + public List getDiffs() { + return diffs; + } + + public void setDiffs(List diffs) { + this.diffs = diffs; + } + + public Boolean getCompareSameRef() { + return compareSameRef; + } + + public void setCompareSameRef(Boolean compareSameRef) { + this.compareSameRef = compareSameRef; + } + + public Boolean getCompareTimeout() { + return compareTimeout; + } + + public void setCompareTimeout(Boolean compareTimeout) { + this.compareTimeout = compareTimeout; + } +} diff --git a/src/main/java/org/gitlab/api/models/GitlabCommitDiff.java b/src/main/java/org/gitlab/api/models/GitlabCommitDiff.java new file mode 100644 index 00000000..e55d24c6 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabCommitDiff.java @@ -0,0 +1,96 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class GitlabCommitDiff { + + public final static String URL = "/diff"; + + @JsonProperty("diff") + private String diff; + + @JsonProperty("new_path") + private String newPath; + + @JsonProperty("old_path") + private String oldPath; + + @JsonProperty("a_mode") + private String aMode; + + @JsonProperty("b_mode") + private String bMode; + + @JsonProperty("new_file") + private boolean newFile; + + @JsonProperty("renamed_file") + private boolean renamedFile; + + @JsonProperty("deleted_file") + private boolean deletedFile; + + public String getDiff() { + return diff; + } + + public void setDiff(String diff) { + this.diff = diff; + } + + public String getNewPath() { + return newPath; + } + + public void setNewPath(String newPath) { + this.newPath = newPath; + } + + public String getOldPath() { + return oldPath; + } + + public void setOldPath(String oldPath) { + this.oldPath = oldPath; + } + + public String getAMode() { + return aMode; + } + + public void setAMode(String aMode) { + this.aMode = aMode; + } + + public String getBMode() { + return bMode; + } + + public void setBMode(String bMode) { + this.bMode = bMode; + } + + public boolean getNewFile() { + return newFile; + } + + public void setNewFile(boolean newFile) { + this.newFile = newFile; + } + + public boolean getRenamedFile() { + return renamedFile; + } + + public void setRenamedFile(boolean renamedFile) { + this.renamedFile = renamedFile; + } + + public boolean getDeletedFile() { + return deletedFile; + } + + public void setDeletedFile(boolean deletedFile) { + this.deletedFile = deletedFile; + } +} diff --git a/src/main/java/org/gitlab/api/models/GitlabCommitStatus.java b/src/main/java/org/gitlab/api/models/GitlabCommitStatus.java new file mode 100644 index 00000000..1505246d --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabCommitStatus.java @@ -0,0 +1,136 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Date; + +public class GitlabCommitStatus { + + public final static String URL = "/statuses"; + + private String id; + private String sha; + private String ref; + private String status; + private String name; + private String description; + private GitlabUser author; + + @JsonProperty("target_url") + private String targetUrl; + + @JsonProperty("created_at") + private Date createdAt; + + @JsonProperty("started_at") + private Date startedAt; + + @JsonProperty("finished_at") + private Date finishedAt; + + public String getId() { + return id; + } + + public void setId(String 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 getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public GitlabUser getAuthor() { + return author; + } + + public void setAuthor(GitlabUser author) { + this.author = author; + } + + public String getTargetUrl() { + return targetUrl; + } + + public void setTargetUrl(String targetUrl) { + this.targetUrl = targetUrl; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public Date getStartedAt() { + return startedAt; + } + + public void setStartedAt(Date startedAt) { + this.startedAt = startedAt; + } + + public Date getFinishedAt() { + return finishedAt; + } + + public void setFinishedAt(Date finishedAt) { + this.finishedAt = finishedAt; + } + + @Override + public boolean equals(Object obj) { + // we say that two commit objects are equal iff they have the same ID + // this prevents us from having to do clever workarounds for + // https://gitlab.com/gitlab-org/gitlab-ce/issues/759 + try { + GitlabCommitStatus commitObj = (GitlabCommitStatus) obj; + return (this.getId().compareTo(commitObj.getId()) == 0); + } catch (ClassCastException e) { + 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 new file mode 100644 index 00000000..1003cc52 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabGroup.java @@ -0,0 +1,206 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +public class GitlabGroup { + + public static final String URL = "/groups"; + + 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; + + @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; + } + + public void setName(String name) { + this.name = name; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public String getLdapCn() { + return ldapCn; + } + + 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; + } + return GitlabAccessLevel.fromAccessValue(ldapAccess); + } + + public void setLdapAccess(GitlabAccessLevel ldapGitlabAccessLevel) { + if (ldapGitlabAccessLevel != null) { + 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/GitlabGroupMember.java b/src/main/java/org/gitlab/api/models/GitlabGroupMember.java new file mode 100644 index 00000000..52a87d3c --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabGroupMember.java @@ -0,0 +1,4 @@ +package org.gitlab.api.models; + +public class GitlabGroupMember extends GitlabAbstractMember { +} diff --git a/src/main/java/org/gitlab/api/models/GitlabIssue.java b/src/main/java/org/gitlab/api/models/GitlabIssue.java new file mode 100644 index 00000000..046fe609 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabIssue.java @@ -0,0 +1,233 @@ +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 { + LEAVE, CLOSE, REOPEN + } + + public static final String STATE_CLOSED = "closed"; + public static final String STATE_OPENED = "opened"; + + public static final String URL = "/issues"; + + private int id; + private int iid; + + @JsonProperty("project_id") + private int projectId; + + private String title; + private String description; + 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") + private Date updatedAt; + + @JsonProperty("created_at") + private Date createdAt; + + @JsonProperty("closed_at") + private Date closedAt; + + @JsonProperty("web_url") + private String webUrl; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getIid() { + return iid; + } + + public void setIid(int iid) { + this.iid = iid; + } + + public int getProjectId() { + return projectId; + } + + public void setProjectId(int 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 description) { + this.description = description; + } + + public String[] getLabels() { + return labels; + } + + public void setLabels(String[] labels) { + this.labels = labels; + } + + public GitlabMilestone getMilestone() { + return milestone; + } + + 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; + } + + public void setAssignee(GitlabUser assignee) { + this.assignee = assignee; + } + + public GitlabUser getAuthor() { + return author; + } + + 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; + } + + 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; + } + +} 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/GitlabJob.java b/src/main/java/org/gitlab/api/models/GitlabJob.java new file mode 100644 index 00000000..4027c544 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabJob.java @@ -0,0 +1,140 @@ +package org.gitlab.api.models; + + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class GitlabJob { + + public final static String URL = "/jobs"; + + private GitlabCommit commit; + private Float coverage; + @JsonProperty("created_at") + private String createdAt; + @JsonProperty("download_url") + private String downloadUrl; + @JsonProperty("finished_at") + private String finishedAt; + private Integer id; + private String name; + private String ref; + private GitlabRunner runner; + private String stage; + @JsonProperty("started_at") + private String startedAt; + private String status; + private Boolean tag; + private GitlabUser user; + + public GitlabUser getUser() { + return user; + } + + public void setUser(GitlabUser user) { + this.user = user; + } + + public Boolean getTag() { + return tag; + } + + public void setTag(Boolean tag) { + this.tag = tag; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getStartedAt() { + return startedAt; + } + + public void setStartedAt(String startedAt) { + this.startedAt = startedAt; + } + + public String getStage() { + return stage; + } + + public void setStage(String stage) { + this.stage = stage; + } + + public GitlabRunner getRunner() { + return runner; + } + + public void setRunner(GitlabRunner runner) { + this.runner = runner; + } + + public String getRef() { + return ref; + } + + public void setRef(String ref) { + this.ref = ref; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getFinishedAt() { + return finishedAt; + } + + public void setFinishedAt(String finishedAt) { + this.finishedAt = finishedAt; + } + + public String getDownloadUrl() { + return downloadUrl; + } + + public void setDownloadUrl(String downloadUrl) { + this.downloadUrl = downloadUrl; + } + + public String getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(String createdAt) { + this.createdAt = createdAt; + } + + public Float getCoverage() { + return coverage; + } + + public void setCoverage(Float coverage) { + this.coverage = coverage; + } + + public GitlabCommit getCommit() { + return commit; + } + + public void setCommit(GitlabCommit commit) { + this.commit = commit; + } +} diff --git a/src/main/java/org/gitlab/api/models/GitlabLabel.java b/src/main/java/org/gitlab/api/models/GitlabLabel.java new file mode 100644 index 00000000..571539ab --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabLabel.java @@ -0,0 +1,45 @@ +package org.gitlab.api.models; + +/** + * Models a Gitlab label. + */ +public class GitlabLabel { + + public static final String URL = "/labels"; + + private String name; + private String color; + + /** + * Gets the name (text) of a label. + * @return + */ + public String getName() { + return name; + } + + /** + * Sets the name (text) of a label. + * @param name + */ + public void setName(String name) { + this.name = name; + } + + /** + * Gets the color of a label as six digit HTML hex value. + * @return + */ + public String getColor() { + return color; + } + + /** + * Sets the color of a label. + * @param color A six digit HTML hex value including number sign (eg #ff0000) + */ + public void setColor(String color) { + this.color = color; + } + +} diff --git a/src/main/java/org/gitlab/api/models/GitlabMergeRequest.java b/src/main/java/org/gitlab/api/models/GitlabMergeRequest.java index f9f6dc0d..11d037e5 100644 --- a/src/main/java/org/gitlab/api/models/GitlabMergeRequest.java +++ b/src/main/java/org/gitlab/api/models/GitlabMergeRequest.java @@ -1,108 +1,425 @@ package org.gitlab.api.models; -import org.codehaus.jackson.annotate.JsonProperty; +import java.util.Date; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; 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; + private String title; + private String state; + private String description; + private boolean closed; + private boolean merged; + private GitlabUser author; + private GitlabUser assignee; + private GitlabMilestone milestone; + + private String[] labels; + + private List changes; + + private Integer upvotes; - private Integer _id; - private String _title; - private String _state; - private boolean _closed; - private boolean _merged; - private GitlabUser _author; - private GitlabUser _assignee; + private Integer downvotes; + + @JsonProperty("updated_at") + private Date updatedAt; + + @JsonProperty("created_at") + private Date createdAt; @JsonProperty("target_branch") - private String _targetBranch; + private String targetBranch; @JsonProperty("source_branch") - private String _sourceBranch; + private String sourceBranch; @JsonProperty("project_id") - private Integer _projectId; + private Integer projectId; + + @JsonProperty("source_project_id") + private Integer sourceProjectId; + + @JsonProperty("target_project_id") + private Integer targetProjectId; + + @JsonProperty("milestone_id") + private Integer milestoneId; + + @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; + return id; } public void setId(Integer id) { - _id = id; + this.id = id; + } + + @Deprecated + public Integer getMilestoneId() { + return milestoneId; + } + + @Deprecated + public void setMilestoneId(Integer id) { + milestoneId = id; + } + + public Integer getIid() { + return iid; + } + + public void setIid(Integer iid) { + this.iid = iid; } public String getTargetBranch() { - return _targetBranch; + return targetBranch; } public void setTargetBranch(String targetBranch) { - _targetBranch = targetBranch; + this.targetBranch = targetBranch; } public String getSourceBranch() { - return _sourceBranch; + return sourceBranch; } public void setSourceBranch(String sourceBranch) { - _sourceBranch = sourceBranch; + this.sourceBranch = sourceBranch; } public Integer getProjectId() { - return _projectId; + return projectId; } public void setProjectId(Integer projectId) { - _projectId = projectId; + this.projectId = projectId; + } + + public Integer getSourceProjectId() { + return sourceProjectId; + } + + public void setSourceProjectId(Integer sourceProjectId) { + this.sourceProjectId = sourceProjectId; } public String getTitle() { - return _title; + return title; } public void setTitle(String title) { - _title = title; + this.title = title; } + public String getDescription() { + return description; + } + + public void setDescription(String d) { + description = d; + } + + @Deprecated public boolean isClosed() { - return _closed; + return closed; } + @Deprecated public void setClosed(boolean closed) { - _closed = closed; + this.closed = closed; } + @Deprecated public boolean isMerged() { - return _merged; + return merged; } + @Deprecated public void setMerged(boolean merged) { - _merged = merged; + this.merged = merged; } public GitlabUser getAuthor() { - return _author; + return author; } public void setAuthor(GitlabUser author) { - _author = author; + this.author = author; } public GitlabUser getAssignee() { - return _assignee; + return assignee; } public void setAssignee(GitlabUser assignee) { - _assignee = assignee; + this.assignee = assignee; } public String getState() { - return _state; + return state; } public void setState(String state) { - _state = state; - if(state != null) { - _closed = state.equals("closed"); - _merged = state.equals("merged"); + this.state = state; + if (state != null) { + closed = state.equals("closed"); + merged = state.equals("merged"); } } + + public GitlabMilestone getMilestone() { + return milestone; + } + + public void setMilestone(GitlabMilestone milestone) { + this.milestone = milestone; + } + + public String[] getLabels() { + return labels; + } + + public void setLabels(String[] labels) { + this.labels = labels; + } + + public Integer getUpvotes() { + return upvotes; + } + + public void setUpvotes(int upvotes) { + this.upvotes = upvotes; + } + + public Integer getDownvotes() { + return downvotes; + } + + public void setDownvotes(int downvotes) { + this.downvotes = downvotes; + } + + public Integer getTargetProjectId() { + return targetProjectId; + } + + public void setTargetProjectId(Integer targetProjectId) { + this.targetProjectId = targetProjectId; + } + + 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 List getChanges() { + return changes; + } + + public void setChanges(List changes) { + this.changes = changes; + } + + 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 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 new file mode 100644 index 00000000..5f533e6e --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabMilestone.java @@ -0,0 +1,127 @@ +package org.gitlab.api.models; + +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class GitlabMilestone { + + public static final String URL = "/milestones"; + + private int id; + + private int iid; + + @JsonProperty("project_id") + private int projectId; + + @JsonProperty("group_id") + private int groupId; + + private String title; + + private String description; + + @JsonProperty("due_date") + private Date dueDate; + + @JsonProperty("start_date") + private Date startDate; + + private String state; + + @JsonProperty("updated_date") + private Date updatedDate; + + @JsonProperty("created_date") + private Date createdDate; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getIid() { + return iid; + } + + public void setIid(int iid) { + this.iid = iid; + } + + public int getProjectId() { + return projectId; + } + + 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; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Date getDueDate() { + return dueDate; + } + + 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; + } + + public void setState(String state) { + this.state = state; + } + + public Date getUpdatedDate() { + return updatedDate; + } + + public void setUpdatedDate(Date updatedDate) { + this.updatedDate = updatedDate; + } + + public Date getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(Date createdDate) { + this.createdDate = createdDate; + } + +} diff --git a/src/main/java/org/gitlab/api/models/GitlabNamespace.java b/src/main/java/org/gitlab/api/models/GitlabNamespace.java index 6f40a1d9..0173f86b 100644 --- a/src/main/java/org/gitlab/api/models/GitlabNamespace.java +++ b/src/main/java/org/gitlab/api/models/GitlabNamespace.java @@ -1,77 +1,111 @@ package org.gitlab.api.models; import java.util.Date; -import org.codehaus.jackson.annotate.JsonProperty; + +import com.fasterxml.jackson.annotation.JsonProperty; public class GitlabNamespace { + public static final String URL = "/namespaces"; + + private Integer id; + private String name; + private String path; + private String kind; + private String plan; + + @JsonProperty("full_path") + private String fullPath; - private Integer _id; - private String _name; - private String _path; - private String _description; + @JsonProperty("parent_id") + private String parentId; - @JsonProperty("created_at") - private Date _createdAt; + @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; + return id; } public void setId(Integer id) { - _id = id; + this.id = id; } - public Date getCreatedAt() { - return _createdAt; + public String getName() { + return name; } - public void setCreatedAt(Date createdAt) { - _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) { - _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) { - _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) { - _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) { - _path = path; + public void setFullPath(String fullPath) { + this.fullPath = fullPath; } - public String getDescription() { - return _description; + public String getParentId() { + return parentId; + } + + public void setParentId(String parentId) { + this.parentId = parentId; + } + + public Integer getMembersCountWithDescendants() { + return membersCountWithDescendants; + } + + 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) { - _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/GitlabNote.java b/src/main/java/org/gitlab/api/models/GitlabNote.java index 52778444..39eda597 100644 --- a/src/main/java/org/gitlab/api/models/GitlabNote.java +++ b/src/main/java/org/gitlab/api/models/GitlabNote.java @@ -1,57 +1,85 @@ package org.gitlab.api.models; import java.util.Date; -import org.codehaus.jackson.annotate.JsonProperty; + +import com.fasterxml.jackson.annotation.JsonProperty; public class GitlabNote { public static final String URL = "/notes"; - private Integer _id; - private String _body; - private String _attachment; - private GitlabUser _author; + private Integer id; + private String body; + private String attachment; + private GitlabUser author; + private boolean system; + private boolean upvote; + private boolean downvote; @JsonProperty("created_at") - private Date _createdAt; + private Date createdAt; public Integer getId() { - return _id; + return id; } public void setId(Integer id) { - _id = id; + this.id = id; } public String getBody() { - return _body; + return body; } public void setBody(String body) { - _body = body; + this.body = body; } public GitlabUser getAuthor() { - return _author; + return author; } public void setAuthor(GitlabUser author) { - _author = author; + this.author = author; } public Date getCreatedAt() { - return _createdAt; + return createdAt; } public void setCreatedAt(Date createdAt) { - _createdAt = createdAt; + this.createdAt = createdAt; } public String getAttachment() { - return _attachment; + return attachment; } public void setAttachment(String attachment) { - _attachment = attachment; + this.attachment = attachment; + } + + public boolean isSystem() { + return system; + } + + public void setSystem(boolean system) { + this.system = system; + } + + public boolean isUpvote() { + return upvote; + } + + public void setUpvote(boolean upvote) { + this.upvote = upvote; + } + + public boolean isDownvote() { + return downvote; + } + + public void setDownvote(boolean downvote) { + this.downvote = downvote; } } diff --git a/src/main/java/org/gitlab/api/models/GitlabPermission.java b/src/main/java/org/gitlab/api/models/GitlabPermission.java new file mode 100644 index 00000000..86fd6f03 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabPermission.java @@ -0,0 +1,20 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class GitlabPermission { + + @JsonProperty("project_access") + private GitlabProjectAccessLevel projectAccess; + + @JsonProperty("group_access") + private GitlabProjectAccessLevel groupAccess; + + public GitlabProjectAccessLevel getProjectAccess() { + return projectAccess; + } + + public GitlabProjectAccessLevel getProjectGroupAccess() { + return groupAccess; + } +} 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 46061fd6..a245d23b 100644 --- a/src/main/java/org/gitlab/api/models/GitlabProject.java +++ b/src/main/java/org/gitlab/api/models/GitlabProject.java @@ -1,152 +1,511 @@ package org.gitlab.api.models; import java.util.Date; -import org.codehaus.jackson.annotate.JsonProperty; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; public class GitlabProject { public static final String URL = "/projects"; - private Integer _id; - private String _name; - private String _description; + private Integer id; + private String name; + + @JsonProperty("name_with_namespace") + private String nameWithNamespace; + + private String description; @JsonProperty("default_branch") - private String _defaultBranch; + private String defaultBranch; - private GitlabUser _owner; - private boolean _public; - private String _path; + private GitlabUser owner; + private Boolean publicProject; + private String path; + + @JsonProperty("visibility") + private String visibility; @JsonProperty("path_with_namespace") - private String _pathWithNamespace; + 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; @JsonProperty("wall_enabled") - private boolean _wallEnabled; + private Boolean wallEnabled; @JsonProperty("wiki_enabled") - private boolean _wikiEnabled; + private Boolean wikiEnabled; + + @JsonProperty("jobs_enabled") + private Boolean jobsEnabled; + + @JsonProperty("shared_runners_enabled") + private Boolean sharedRunnersEnabled; + + @JsonProperty("public_jobs") + private Boolean publicJobs; + + @JsonProperty("runners_token") + private String runnersToken; @JsonProperty("created_at") - private Date _createdAt; + private Date createdAt; + + @JsonProperty("ssh_url_to_repo") + private String sshUrl; + + @JsonProperty("web_url") + private String webUrl; + + @JsonProperty("http_url_to_repo") + private String httpUrl; + + @JsonProperty("last_activity_at") + private Date lastActivityAt; + + @JsonProperty("archived") + private Boolean archived; + + private GitlabNamespace namespace; + + @JsonProperty("permissions") + private GitlabPermission permissions; + + @JsonProperty("avatar_url") + private String avatarUrl; + + @JsonProperty("creator_id") + private Integer creatorId; + + @JsonProperty("star_count") + private Integer starCount; + + @JsonProperty("forks_count") + private Integer forksCount; - private GitlabNamespace _namespace; + @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; + return id; } public void setId(Integer id) { - _id = id; + this.id = id; } public String getName() { - return _name; + return name; } public void setName(String name) { - _name = name; + this.name = name; + } + + public String getNameWithNamespace() { + return nameWithNamespace; + } + + public void setNameWithNamespace(String nameWithNamespace) { + this.nameWithNamespace = nameWithNamespace; } public String getDescription() { - return _description; + return description; } public void setDescription(String description) { - _description = description; + this.description = description; } public String getDefaultBranch() { - return _defaultBranch; + return defaultBranch; } public void setDefaultBranch(String defaultBranch) { - _defaultBranch = defaultBranch; + this.defaultBranch = defaultBranch; + } + + public String getVisibility() { + return visibility; + } + + public void setVisibility(String visibility) { + this.visibility = visibility; } public GitlabUser getOwner() { - return _owner; + return owner; } public void setOwner(GitlabUser owner) { - _owner = owner; + this.owner = owner; } public String getPath() { - return _path; + return path; } public void setPath(String path) { - _path = path; + this.path = path; } public String getPathWithNamespace() { - return _pathWithNamespace; + return pathWithNamespace; } public void setPathWithNamespace(String pathWithNamespace) { - _pathWithNamespace = pathWithNamespace; + this.pathWithNamespace = pathWithNamespace; + } + + public Boolean isIssuesEnabled() { + return issuesEnabled; + } + + public void setIssuesEnabled(Boolean issuesEnabled) { + this.issuesEnabled = issuesEnabled; + } + + public Boolean isMergeRequestsEnabled() { + return mergeRequestsEnabled; + } + + public void setMergeRequestsEnabled(Boolean mergeRequestsEnabled) { + this.mergeRequestsEnabled = mergeRequestsEnabled; + } + + public Boolean isSnippetsEnabled() { + return snippetsEnabled; + } + + public void setSnippetsEnabled(Boolean snippetsEnabled) { + this.snippetsEnabled = snippetsEnabled; + } + + public Boolean isWallEnabled() { + return wallEnabled; + } + + public void setWallEnabled(Boolean wallEnabled) { + this.wallEnabled = wallEnabled; + } + + public Boolean isWikiEnabled() { + return wikiEnabled; + } + + public void setWikiEnabled(Boolean wikiEnabled) { + this.wikiEnabled = wikiEnabled; + } + + public Boolean isJobsEnabled() { + return jobsEnabled; + } + + public void setJobsEnabled(Boolean jobsEnabled) { + this.jobsEnabled = jobsEnabled; + } + + public Boolean isRequestAccessEnabled() { + return requestAccessEnabled; + } + + public void setRequestAccessEnabled(Boolean requestAccessEnabled) { + this.requestAccessEnabled = requestAccessEnabled; + } + + public Boolean isLfsEnabled() { + return lfsEnabled; + } + + public void setLfsEnabled(Boolean lfsEnabled) { + this.lfsEnabled = lfsEnabled; + } + + public Boolean isSharedRunnersEnabled() { + return sharedRunnersEnabled; } - public boolean isIssuesEnabled() { - return _issuesEnabled; + public void setSharedRunnersEnabled(Boolean sharedRunnersEnabled) { + this.sharedRunnersEnabled = sharedRunnersEnabled; } - public void setIssuesEnabled(boolean issuesEnabled) { - _issuesEnabled = issuesEnabled; + public Boolean getOnlyAllowMergeIfPipelineSucceeds() { + return onlyAllowMergeIfPipelineSucceeds; } - public boolean isMergeRequestsEnabled() { - return _mergeRequestsEnabled; + public void setOnlyAllowMergeIfPipelineSucceeds(Boolean onlyAllowMergeIfPipelineSucceeds) { + this.onlyAllowMergeIfPipelineSucceeds = onlyAllowMergeIfPipelineSucceeds; } - public void setMergeRequestsEnabled(boolean mergeRequestsEnabled) { - _mergeRequestsEnabled = mergeRequestsEnabled; + public Boolean getOnlyAllowMergeIfAllDiscussionsAreResolved() { + return onlyAllowMergeIfAllDiscussionsAreResolved; } - public boolean isWallEnabled() { - return _wallEnabled; + public void setOnlyAllowMergeIfAllDiscussionsAreResolved(Boolean onlyAllowMergeIfAllDiscussionsAreResolved) { + this.onlyAllowMergeIfAllDiscussionsAreResolved = onlyAllowMergeIfAllDiscussionsAreResolved; } - public void setWallEnabled(boolean wallEnabled) { - _wallEnabled = wallEnabled; + public Boolean isContainerRegistryEnabled() { + return containerRegistryEnabled; } - public boolean isWikiEnabled() { - return _wikiEnabled; + public void setContainerRegistryEnabled(Boolean containerRegistryEnabled) { + this.containerRegistryEnabled = containerRegistryEnabled; } - public void setWikiEnabled(boolean wikiEnabled) { - _wikiEnabled = wikiEnabled; + public Boolean hasPublicJobs() { + return publicJobs; + } + + public void setPublicJobs(Boolean publicJobs) { + this.publicJobs = publicJobs; + } + + public String getRunnersToken() { + return runnersToken; + } + + public void setRunnersToken(String runnersToken) { + this.runnersToken = runnersToken; } public Date getCreatedAt() { - return _createdAt; + return createdAt; } public void setCreatedAt(Date createdAt) { - _createdAt = createdAt; + this.createdAt = createdAt; + } + + public String getSshUrl() { + return sshUrl; + } + + public void setSshUrl(String sshUrl) { + this.sshUrl = sshUrl; + } + + public String getWebUrl() { + return webUrl; + } + + public void setWebUrl(String webUrl) { + this.webUrl = webUrl; + } + + public String getHttpUrl() { + return httpUrl; + } + + public void setHttpUrl(String httpUrl) { + this.httpUrl = httpUrl; } public GitlabNamespace getNamespace() { - return _namespace; + return namespace; } public void setNamespace(GitlabNamespace namespace) { - _namespace = namespace; + this.namespace = namespace; + } + + public Boolean isPublic() { + return publicProject; + } + + public void setPublic(Boolean aPublic) { + publicProject = aPublic; + } + + public Boolean isArchived() { + return archived; + } + + public void setArchived(Boolean archived) { + this.archived = archived; + } + + public Date getLastActivityAt() { + return lastActivityAt; + } + + public void setLastActivityAt(Date lastActivityAt) { + this.lastActivityAt = lastActivityAt; + } + + public GitlabPermission getPermissions() { + return permissions; + } + + public void setPermissions(GitlabPermission permissions) { + this.permissions = permissions; + } + + public String getAvatarUrl() { + return avatarUrl; + } + + public void setAvatarUrl(String avatarUrl) { + this.avatarUrl = avatarUrl; + } + + public Integer getCreatorId() { + return creatorId; } - public boolean isPublic() { - return _public; + public void setCreatorId(Integer creatorId) { + this.creatorId = creatorId; + } + + public Integer getStarCount() { + return starCount; + } + + public void setStarCount(Integer starCount) { + this.starCount = starCount; + } + + public Integer getForksCount() { + return forksCount; + } + + public void setForksCount(Integer forksCount) { + this.forksCount = forksCount; + } + + public List getTagList() { + return tagList; + } + + 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; + } } - public void setPublic(boolean aPublic) { - _public = aPublic; + @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/GitlabProjectAccessLevel.java b/src/main/java/org/gitlab/api/models/GitlabProjectAccessLevel.java new file mode 100644 index 00000000..09cbc256 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabProjectAccessLevel.java @@ -0,0 +1,32 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class GitlabProjectAccessLevel { + + @JsonProperty("access_level") + private int accessLevel; + + @JsonProperty("notification_level") + private int notificationLevel; + + + public GitlabAccessLevel getAccessLevel() { + return GitlabAccessLevel.fromAccessValue(accessLevel); + } + + public void setAccessLevel(GitlabAccessLevel accessLevel) { + this.accessLevel = accessLevel.accessValue; + } + + + public int getNoficationLevel() { + return notificationLevel; + } + + public void setNotificationLevel(int notificationLevel) { + this.notificationLevel = notificationLevel; + } + + +} diff --git a/src/main/java/org/gitlab/api/models/GitlabProjectHook.java b/src/main/java/org/gitlab/api/models/GitlabProjectHook.java new file mode 100644 index 00000000..34326f4c --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabProjectHook.java @@ -0,0 +1,134 @@ +package org.gitlab.api.models; + +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class GitlabProjectHook { + + public final static String URL = "/hooks"; + + private String id; + private String url; + + @JsonProperty("project_id") + private Integer projectId; + + @JsonProperty("push_events") + private boolean pushEvents; + + @JsonProperty("issues_events") + private boolean issueEvents; + + @JsonProperty("merge_requests_events") + private boolean mergeRequestsEvents; + + @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; + } + + public void setId(String id) { + this.id = id; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public Integer getProjectId() { + return projectId; + } + + public void setProjectId(Integer projectId) { + this.projectId = projectId; + } + + public boolean getPushEvents() { + return pushEvents; + } + + public void setPushEvents(boolean pushEvents) { + this.pushEvents = pushEvents; + } + + public boolean getIssueEvents() { + return issueEvents; + } + + public void setIssueEvents(boolean issueEvents) { + this.issueEvents = issueEvents; + } + + public boolean isMergeRequestsEvents() { + return mergeRequestsEvents; + } + + 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; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public boolean isSslVerificationEnabled() { + return sslVerificationEnabled; + } + + 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/GitlabProjectMember.java b/src/main/java/org/gitlab/api/models/GitlabProjectMember.java new file mode 100644 index 00000000..27226172 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabProjectMember.java @@ -0,0 +1,4 @@ +package org.gitlab.api.models; + +public class GitlabProjectMember extends GitlabAbstractMember { +} 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/GitlabRelease.java b/src/main/java/org/gitlab/api/models/GitlabRelease.java new file mode 100644 index 00000000..301e9b56 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabRelease.java @@ -0,0 +1,28 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class GitlabRelease { + + @JsonProperty("tag_name") + private String tagName; + + @JsonProperty("description") + private String description; + + public String getTagName() { + return tagName; + } + + public void setTagName(String tagName) { + this.tagName = tagName; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} 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 new file mode 100644 index 00000000..02784d78 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabRepositoryTree.java @@ -0,0 +1,51 @@ +package org.gitlab.api.models; + +public class GitlabRepositoryTree { + public static String URL = "/tree"; + + private String name; + private String type; + private String mode; + private String id; + private String path; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getMode() { + return mode; + } + + public void setMode(String mode) { + this.mode = mode; + } + + public String getId() { + return id; + } + + 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 new file mode 100644 index 00000000..d03d0561 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabRunner.java @@ -0,0 +1,184 @@ +package org.gitlab.api.models; + + +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 this.id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getDescription() { + return this.description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Boolean getActive() { + return this.active; + } + + public void setActive(Boolean active) { + this.active = active; + } + + public Boolean getShared() { + return this.isShared; + } + + public void setShared(Boolean shared) { + this.isShared = shared; + } + + public String getName() { + 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 new file mode 100644 index 00000000..f9e29e6e --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabSSHKey.java @@ -0,0 +1,44 @@ +package org.gitlab.api.models; + + +public class GitlabSSHKey { + public static String KEYS_URL = "/keys"; + public static String DEPLOY_KEYS_URL = "/deploy_keys"; + + private Integer _id; + private String _title; + private String _key; + private GitlabUser _user; + + public Integer getId() { + return _id; + } + + public void setId(Integer id) { + _id = id; + } + + public String getTitle() { + return _title; + } + + public void setTitle(String title) { + _title = title; + } + + public String getKey() { + return _key; + } + + public void setKey(String key) { + _key = key; + } + + public GitlabUser getUser() { + return _user; + } + + public void setUser(GitlabUser user) { + _user = user; + } +} 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/GitlabSession.java b/src/main/java/org/gitlab/api/models/GitlabSession.java new file mode 100644 index 00000000..dabab850 --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabSession.java @@ -0,0 +1,22 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class GitlabSession extends GitlabUser { + + public static final String URL = "/session"; + + @JsonProperty("private_token") + private String privateToken; + + @Override + public String getPrivateToken() { + return privateToken; + } + + @Override + public void setPrivateToken(String privateToken) { + this.privateToken = privateToken; + } + +} 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/GitlabSystemHook.java b/src/main/java/org/gitlab/api/models/GitlabSystemHook.java new file mode 100644 index 00000000..c7d543ec --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabSystemHook.java @@ -0,0 +1,40 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Date; + +public class GitlabSystemHook { + + public final static String URL = "/hooks"; + + private Integer id; + private String url; + + @JsonProperty("created_at") + private Date createdAt; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } +} diff --git a/src/main/java/org/gitlab/api/models/GitlabTag.java b/src/main/java/org/gitlab/api/models/GitlabTag.java new file mode 100644 index 00000000..c0ec8cbb --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabTag.java @@ -0,0 +1,52 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class GitlabTag { + + public final static String URL = "/repository/tags"; + + @JsonProperty("commit") + private GitlabCommit commit; + + @JsonProperty("release") + private GitlabRelease release; + + @JsonProperty("name") + private String name; + + @JsonProperty("message") + private String message; + + public GitlabCommit getCommit() { + return commit; + } + + public void setCommit(GitlabCommit commit) { + this.commit = commit; + } + + public GitlabRelease getRelease() { + return release; + } + + public void setRelease(GitlabRelease release) { + this.release = release; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/src/main/java/org/gitlab/api/models/GitlabTrigger.java b/src/main/java/org/gitlab/api/models/GitlabTrigger.java new file mode 100644 index 00000000..cef9a44b --- /dev/null +++ b/src/main/java/org/gitlab/api/models/GitlabTrigger.java @@ -0,0 +1,75 @@ +package org.gitlab.api.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Date; + +/** + * [ + * { + * "token": "7dfb8f45432193abcd54123456090f", + * "created_at": "2016-07-08T12:33:25.151Z", + * "updated_at": "2016-07-08T12:33:25.151Z", + * "deleted_at": null, + * "last_used": "2016-09-04T23:00:01.681Z" + * } + * ] + */ +public class GitlabTrigger { + + public static final String URL = "/triggers"; + + private String token; + + @JsonProperty("created_at") + private Date createdAt; + + @JsonProperty("updated_at") + private Date updatedAt; + + @JsonProperty("deleted_at") + private Date deletedAt; + + @JsonProperty("last_used") + private Date lastUsed; + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + 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 Date getDeletedAt() { + return deletedAt; + } + + public void setDeletedAt(Date deletedAt) { + this.deletedAt = deletedAt; + } + + public Date getLastUsed() { + return lastUsed; + } + + public void setLastUsed(Date lastUsed) { + this.lastUsed = lastUsed; + } +} 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 352f5578..9f6cff5f 100644 --- a/src/main/java/org/gitlab/api/models/GitlabUser.java +++ b/src/main/java/org/gitlab/api/models/GitlabUser.java @@ -1,10 +1,19 @@ package org.gitlab.api.models; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + import java.util.Date; -import org.codehaus.jackson.annotate.JsonProperty; +import java.util.List; +@JsonIgnoreProperties(ignoreUnknown = true) public class GitlabUser { + public static String URL = "/users"; + public static String USERS_URL = "/users"; + public static String USER_URL = "/user"; // for sudo based ops + public static String BLOCK_URL = "/block"; + public static String UNBLOCK_URL = "/unblock"; private Integer _id; private String _username; @@ -15,7 +24,20 @@ 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; + + @JsonProperty("color_scheme_id") + private Integer _colorSchemeId; + + @JsonProperty("provider") + private String _externProviderName; + + @JsonProperty("website_url") + private String _websiteUrl; @JsonProperty("created_at") private Date _createdAt; @@ -24,7 +46,7 @@ public class GitlabUser { private String _bio; @JsonProperty("dark_scheme") - private boolean _darkScheme; + private Boolean _darkScheme; @JsonProperty("theme_id") private Integer _themeId; @@ -33,166 +55,272 @@ 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; + + @JsonProperty("last_sign_in_at") + private Date _lastSignInAt; + + @JsonProperty("current_sign_in_at") + private Date _currentSignInAt; + + @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 this._externProviderName; } - public boolean isAdmin() { - return _isAdmin; + public void setExternProviderName(String externProviderName) { + this._externProviderName = externProviderName; + } + + public String getWebsiteUrl() { + return this._websiteUrl; + } + + public void setWebsiteUrl(String websiteUrl) { + this._websiteUrl = websiteUrl; + } + + 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() { + return _avatarUrl; + } + + public void setAvatarUrl(String avatarUrl) { + this._avatarUrl = avatarUrl; + } + + public Integer getColorSchemeId() { + return _colorSchemeId; + } + + public void setColorSchemeId(Integer colorSchemeId) { + this._colorSchemeId = colorSchemeId; + } + + public String getPrivateToken() { + return this._privateToken; + } + + public void setPrivateToken(String privateToken) { + this._privateToken = privateToken; + } + + public Date getLastSignInAt() { + return this._lastSignInAt; + } + + public void setLastSignInAt(Date lastSignInAt) { + this._lastSignInAt = lastSignInAt; + } + + public Date getCurrentSignInAt() { + return this._currentSignInAt; + } + + public void setCurrentSignInAt(Date currentSignInAt) { + this._currentSignInAt = currentSignInAt; + } + + public Integer getProjectsLimit() { + 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 6753a906..00000000 --- a/src/test/java/org/gitlab/api/GitlabAPITest.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.gitlab.api; - -import org.junit.Before; -import org.junit.Test; - -import java.io.IOException; -import java.net.URL; - -import static org.junit.Assert.assertEquals; - -public class GitlabAPITest { - - GitlabAPI _api; - - @Before - public void setup() { - _api = GitlabAPI.connect("http://localhost", "token"); - } - - @Test - public void testConnect() throws IOException { - assertEquals(GitlabAPI.class, _api.getClass()); - } - - @Test - public void testGetAPIUrl() throws IOException { - URL expected = new URL("http://localhost/api/v3/?private_token=token"); - assertEquals(expected, _api.getAPIUrl("")); - } - - @Test - public void testGetUrl() throws IOException { - URL expected = new URL("http://localhost/"); - assertEquals(expected, _api.getUrl("")); - } -} 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 new file mode 100644 index 00000000..e08db9b2 --- /dev/null +++ b/src/test/java/org/gitlab/api/PaginationTest.java @@ -0,0 +1,69 @@ +package org.gitlab.api; + +import org.gitlab.api.http.Query; +import org.junit.Test; + +import java.io.UnsupportedEncodingException; + +import static org.junit.Assert.assertEquals; + +public class PaginationTest { + @Test + public void emptyPagination() { + Pagination pagination = new Pagination(); + + final Query expectedQuery = new Query(); + assertEquals(expectedQuery.toString(), pagination.toString()); + assertEquals(expectedQuery.toString(), pagination.asQuery().toString()); + } + + @Test + public void pageOnlyPagination() throws UnsupportedEncodingException { + Pagination pagination = new Pagination(); + pagination.setPage(1); + + final Query expectedQuery = new Query() + .append(Pagination.PARAM_PAGE, "1"); + + assertEquals(expectedQuery.toString(), pagination.toString()); + assertEquals(expectedQuery.toString(), pagination.asQuery().toString()); + } + + @Test + public void perPageOnlyPagination() throws UnsupportedEncodingException { + Pagination pagination = new Pagination(); + pagination.setPerPage(50); + + final Query expectedQuery = new Query() + .append(Pagination.PARAM_PER_PAGE, "50"); + + assertEquals(expectedQuery.toString(), pagination.toString()); + assertEquals(expectedQuery.toString(), pagination.asQuery().toString()); + } + + @Test(expected = IllegalArgumentException.class) + public void perPageException() { + Pagination pagination = new Pagination(); + pagination.setPerPage(Pagination.MAX_ITEMS_PER_PAGE + 1); + } + + @Test + public void complexPagination() throws UnsupportedEncodingException { + Pagination pagination = new Pagination(); + pagination.setPage(1); + pagination.setPerPage(50); + + final Query expectedQuery = new Query() + .append(Pagination.PARAM_PAGE, "1") + .append(Pagination.PARAM_PER_PAGE, "50"); + + 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 a88832a7..9db94bac 100644 --- a/src/test/java/org/gitlab/api/http/GitlabHTTPRequestorTest.java +++ b/src/test/java/org/gitlab/api/http/GitlabHTTPRequestorTest.java @@ -1,20 +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.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/http/QueryTest.java b/src/test/java/org/gitlab/api/http/QueryTest.java new file mode 100644 index 00000000..6d0432ac --- /dev/null +++ b/src/test/java/org/gitlab/api/http/QueryTest.java @@ -0,0 +1,94 @@ +package org.gitlab.api.http; + +import org.junit.Test; + +import java.io.UnsupportedEncodingException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class QueryTest { + + @Test + public void mutableStyle_append() throws UnsupportedEncodingException { + Query query = new Query(); + + query.append("p1", "v1"); + query.append("p2", "v2"); + + assertEquals("?p1=v1&p2=v2", query.toString()); + } + + @Test + public void fluentStyle_append() throws UnsupportedEncodingException { + Query query = new Query() + .append("p1", "v1") + .append("p2", "v2"); + + assertEquals("?p1=v1&p2=v2", query.toString()); + } + + @Test + public void mixedStyle_append() throws UnsupportedEncodingException { + Query query = new Query() + .append("p1", "v1"); + + + query.append("p2", "v2"); + + query = query.append("p3", "v3"); + + assertEquals("?p1=v1&p2=v2&p3=v3", query.toString()); + } + + @Test + public void conditionalAppend_notNull() throws UnsupportedEncodingException { + Query query = new Query() + .appendIf("p1", "v1") + .appendIf("p2", "v2"); + + assertEquals("?p1=v1&p2=v2", query.toString()); + } + + @Test + public void conditionalAppend_null() throws UnsupportedEncodingException { + Query query = new Query() + .appendIf("p1", (String) null); + + assertEquals("", query.toString()); + } + + @Test + public void conditionalAppend_null_notNull() throws UnsupportedEncodingException { + Query query = new Query() + .appendIf("p1", (String) null) + .appendIf("p2", "v2"); + + assertEquals("?p2=v2", query.toString()); + } + + @Test + public void append_encodes_values() throws UnsupportedEncodingException { + Query query = new Query() + .append("p1", "v 1") + .append("p2", "v 2"); + + assertEquals("?p1=v+1&p2=v+2", query.toString()); + } + + @Test + public void merge() throws UnsupportedEncodingException{ + Query sourceQuery= new Query() + .append("p1", "v1") + .append("p2", "v2"); + + Query targetQuery = new Query() + .append("p3", "v3") + .append("p2", "v22"); + + boolean mergeResult = targetQuery.mergeWith(sourceQuery); + + assertTrue(mergeResult); + assertEquals("?p3=v3&p2=v22&p1=v1&p2=v2", targetQuery.toString()); + } +} diff --git a/src/test/java/org/gitlab/api/models/GitlabGroupTest.java b/src/test/java/org/gitlab/api/models/GitlabGroupTest.java new file mode 100644 index 00000000..884a70ae --- /dev/null +++ b/src/test/java/org/gitlab/api/models/GitlabGroupTest.java @@ -0,0 +1,24 @@ +package org.gitlab.api.models; + +import org.junit.Test; + +import static org.junit.Assert.assertNull; + +/** + * Tests for {@link GitlabGroup} + */ +public class GitlabGroupTest { + + @Test + public void setLdapAccessHandlesNull() { + GitlabGroup group = new GitlabGroup(); + group.setLdapAccess(null); + } + + @Test + public void getLdapAccessHandlesNull() { + GitlabGroup group = new GitlabGroup(); + group.setLdapAccess(null); + assertNull( group.getLdapAccess() ); + } +} 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 + + + + + + + + + + + +