Merge branch 'stable-2.11'
* stable-2.11:
Update 2.11.1 release notes
PatchListCacheImpl: Catch LargeObjectException
Update commons-validator to 1.4.1
Change-Id: I34f81ad8a0276d127b925422d6d97ac3c7b9bea4
diff --git a/.buckconfig b/.buckconfig
index e4a19f1..e3d0ffc 100644
--- a/.buckconfig
+++ b/.buckconfig
@@ -9,6 +9,7 @@
docs = //Documentation:searchfree
firefox = //:firefox
gerrit = //:gerrit
+ headless = //:headless
release = //:release
safari = //:safari
soyc = //gerrit-gwtui:ui_soyc
diff --git a/.buckversion b/.buckversion
index 9c09744..46408a5 100644
--- a/.buckversion
+++ b/.buckversion
@@ -1 +1 @@
-79d36de9f5284f6e833cca81867d6088a25685fb
+8204fddf60b25a3c2090f3ef0742fca5d466d562
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..1f149cf
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,11 @@
+# http://EditorConfig.org
+
+# top-most EditorConfig file
+root = true
+
+[*]
+end_of_line = lf
+insert_final_newline = true
+charset = utf-8
+indent_style = space
+indent_size = 2
diff --git a/.gitignore b/.gitignore
index c30cee6..f2cb839 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,3 +21,4 @@
/gwt-unitCache
*.swp
*.asc
+/bin/
diff --git a/.mailmap b/.mailmap
index 75aea08..c8e2f82 100644
--- a/.mailmap
+++ b/.mailmap
@@ -1,21 +1,43 @@
-Adrian Görler <adrian.goerler@sap.com> Adrian Goerler <adrian.goerler@sap.com>
-Alex Ryazantsev <alex.ryazantsev@gmail.com> alex <alex.ryazantsev@gmail.com>
-Alex Ryazantsev <alex.ryazantsev@gmail.com> alex.ryazantsev <alex.ryazantsev@gmail.com>
-Carlos Eduardo Baldacin <carloseduardo.baldacin@sonyericsson.com> carloseduardo.baldacin <carloseduardo.baldacin@sonyericsson.com>
-Deniz Türkoglu <deniz@spotify.com> Deniz Turkoglu <deniz@spotify.com>
-Deniz Türkoglu <deniz@spotify.com> Deniz Türkoglu <deniz@spotify.com>
-Edwin Kempin <edwin.kempin@sap.com> Edwin Kempin <edwin.kempin@gmail.com>
-Hugo Arès <hugo.ares@ericsson.com> Hugo Ares <hugo.ares@ericsson.com>
-Jason Huntley <jhuntley@houghtonassociates.com> jhuntley <jhuntley@houghtonassociates.com>
-Johan Björk <jbjoerk@gmail.com> Johan Bjork <phb@spotify.com>
+Adrian Görler <adrian.goerler@sap.com> Adrian Goerler <adrian.goerler@sap.com>
+Ahaan Ugale <ahaanugale@gmail.com> <augale@codeaurora.org>
+Alex Blewitt <alex.blewitt@gmail.com> <alex.blewitt@gs.com>
+Alex Ryazantsev <alex.ryazantsev@gmail.com> alex <alex.ryazantsev@gmail.com>
+Alex Ryazantsev <alex.ryazantsev@gmail.com> alex.ryazantsev <alex.ryazantsev@gmail.com>
+Brad Larson <bklarson@gmail.com> <brad.larson@garmin.com>
+Bruce Zu <bruce.zu@sonymobile.com> <bruce.zu@sonyericsson.com>
+Carlos Eduardo Baldacin <carloseduardo.baldacin@sonyericsson.com> carloseduardo.baldacin <carloseduardo.baldacin@sonyericsson.com>
+David Ostrovsky <david@ostrovsky.org> <d.ostrovsky@gmx.de>
+Deniz Türkoglu <deniz@spotify.com> Deniz Türkoglu <deniz@spotify.com>
+Deniz Türkoglu <deniz@spotify.com> Deniz Turkoglu <deniz@spotify.com>
+Edwin Kempin <edwin.kempin@sap.com> Edwin Kempin <edwin.kempin@gmail.com>
+Eryk Szymanski <eryksz@gmail.com> <eryksz@google.com>
+Fredrik Luthander <fredrik.luthander@sonymobile.com> <fredrik@gandaraj.com>
+Fredrik Luthander <fredrik.luthander@sonymobile.com> <fredrik.luthander@sonyericsson.com>
+Gustaf Lundh <gustaf.lundh@sonymobile.com> <gustaf.lundh@sonyericsson.com>
+Hugo Arès <hugo.ares@ericsson.com> Hugo Ares <hugo.ares@ericsson.com>
+Jason Huntley <jhuntley@houghtonassociates.com> jhuntley <jhuntley@houghtonassociates.com>
+Jiří Engelthaler <EngyCZ@gmail.com> <engycz@gmail.com>
+Joe Onorato <onoratoj@gmail.com> <joeo@android.com>
+Johan Björk <jbjoerk@gmail.com> Johan Bjork <phb@spotify.com>
Lincoln Oliveira Campos Do Nascimento <lincoln.oliveiracamposdonascimento@sonyericsson.com> lincoln <lincoln.oliveiracamposdonascimento@sonyericsson.com>
-Mônica Dionísio <monica.dionisio@sonyericsson.com> monica.dionisio <monica.dionisio@sonyericsson.com>
-Peter Jönsson <peter.joensson@gmail.com> Peter Jönsson <peter.joensson@gmail.com>
-Rafael Rabelo Silva <rafael.rabelosilva@sonyericsson.com> rafael.rabelosilva <rafael.rabelosilva@sonyericsson.com>
-Saša Živkov <sasa.zivkov@sap.com> Sasa Zivkov <sasa.zivkov@sap.com>
-Saša Živkov <sasa.zivkov@sap.com> Saša Živkov <zivkov@gmail.com>
-Shawn Pearce <sop@google.com> Shawn O. Pearce <sop@google.com>
-Tomas Westling <thomas.westling@sonyericsson.com> thomas.westling <thomas.westling@sonyericsson.com>
-Ulrik Sjölin <ulrik.sjolin@sonyericsson.com> Ulrik Sjolin <ulrik.sjolin@gmail.com>
-Ulrik Sjölin <ulrik.sjolin@sonyericsson.com> Ulrik Sjolin <ulrik.sjolin@sonyericsson.com>
-Ulrik Sjölin <ulrik.sjolin@sonyericsson.com> Ulrik Sjölin <ulrik.sjolin@sonyericsson.com>
+Luca Milanesio <luca.milanesio@gmail.com> <luca@gitent-scm.com>
+Magnus Bäck <baeck@google.com> <magnus.back@sonyericsson.com>
+Mark Derricutt <mark.derricutt@smxemail.com> <mark@talios.com>
+Martin Fick <mfick@codeaurora.org> <mogulguy10@gmail.com>
+Martin Fick <mfick@codeaurora.org> <mogulguy@yahoo.com>
+Michael Zhou <moz@google.com> <zhoumotongxue008@gmail.com>
+Mônica Dionísio <monica.dionisio@sonyericsson.com> monica.dionisio <monica.dionisio@sonyericsson.com>
+Nasser Grainawi <nasser@grainawi.org> <nasser@codeaurora.org>
+Nasser Grainawi <nasser@grainawi.org> <nasserg@quicinc.com>
+Peter Jönsson <peter.joensson@gmail.com> Peter Jönsson <peter.joensson@gmail.com>
+Rafael Rabelo Silva <rafael.rabelosilva@sonyericsson.com> rafael.rabelosilva <rafael.rabelosilva@sonyericsson.com>
+Richard Möhn <richard.moehn@posteo.de> <richard.moehn@fu-berlin.de>
+Saša Živkov <sasa.zivkov@sap.com> Sasa Zivkov <sasa.zivkov@sap.com>
+Saša Živkov <sasa.zivkov@sap.com> Saša Živkov <zivkov@gmail.com>
+Shawn Pearce <sop@google.com> Shawn O. Pearce <sop@google.com>
+Tomas Westling <thomas.westling@sonyericsson.com> thomas.westling <thomas.westling@sonyericsson.com>
+Ulrik Sjölin <ulrik.sjolin@sonyericsson.com> <ulrik.sjolin@gmail.com>
+Ulrik Sjölin <ulrik.sjolin@sonyericsson.com> Ulrik Sjolin <ulrik.sjolin@gmail.com>
+Ulrik Sjölin <ulrik.sjolin@sonyericsson.com> Ulrik Sjölin <ulrik.sjolin@sonyericsson.com>
+Ulrik Sjölin <ulrik.sjolin@sonyericsson.com> Ulrik Sjolin <ulrik.sjolin@sonyericsson.com>
+Zalán Blénessy <zalanb@axis.com> Zalan Blenessy <zalanb@axis.com>
diff --git a/.settings/edu.umd.cs.findbugs.core.prefs b/.settings/edu.umd.cs.findbugs.core.prefs
new file mode 100644
index 0000000..4dfcf2d
--- /dev/null
+++ b/.settings/edu.umd.cs.findbugs.core.prefs
@@ -0,0 +1,143 @@
+#FindBugs User Preferences
+#Fri Mar 20 17:07:10 JST 2015
+cloud_id=edu.umd.cs.findbugs.cloud.doNothingCloud
+detectorAppendingToAnObjectOutputStream=AppendingToAnObjectOutputStream|true
+detectorAtomicityProblem=AtomicityProblem|true
+detectorBadAppletConstructor=BadAppletConstructor|false
+detectorBadResultSetAccess=BadResultSetAccess|true
+detectorBadSyntaxForRegularExpression=BadSyntaxForRegularExpression|true
+detectorBadUseOfReturnValue=BadUseOfReturnValue|true
+detectorBadlyOverriddenAdapter=BadlyOverriddenAdapter|true
+detectorBooleanReturnNull=BooleanReturnNull|true
+detectorCallToUnsupportedMethod=CallToUnsupportedMethod|false
+detectorCheckExpectedWarnings=CheckExpectedWarnings|false
+detectorCheckImmutableAnnotation=CheckImmutableAnnotation|true
+detectorCheckRelaxingNullnessAnnotation=CheckRelaxingNullnessAnnotation|true
+detectorCheckTypeQualifiers=CheckTypeQualifiers|true
+detectorCloneIdiom=CloneIdiom|true
+detectorComparatorIdiom=ComparatorIdiom|true
+detectorConfusedInheritance=ConfusedInheritance|true
+detectorConfusionBetweenInheritedAndOuterMethod=ConfusionBetweenInheritedAndOuterMethod|true
+detectorCovariantArrayAssignment=CovariantArrayAssignment|false
+detectorCrossSiteScripting=CrossSiteScripting|true
+detectorDefaultEncodingDetector=DefaultEncodingDetector|true
+detectorDoInsideDoPrivileged=DoInsideDoPrivileged|true
+detectorDontCatchIllegalMonitorStateException=DontCatchIllegalMonitorStateException|true
+detectorDontIgnoreResultOfPutIfAbsent=DontIgnoreResultOfPutIfAbsent|true
+detectorDontUseEnum=DontUseEnum|true
+detectorDroppedException=DroppedException|true
+detectorDumbMethodInvocations=DumbMethodInvocations|true
+detectorDumbMethods=DumbMethods|true
+detectorDuplicateBranches=DuplicateBranches|true
+detectorEmptyZipFileEntry=EmptyZipFileEntry|false
+detectorEqualsOperandShouldHaveClassCompatibleWithThis=EqualsOperandShouldHaveClassCompatibleWithThis|true
+detectorExplicitSerialization=ExplicitSerialization|true
+detectorFinalizerNullsFields=FinalizerNullsFields|true
+detectorFindBadCast2=FindBadCast2|true
+detectorFindBadForLoop=FindBadForLoop|true
+detectorFindCircularDependencies=FindCircularDependencies|false
+detectorFindComparatorProblems=FindComparatorProblems|true
+detectorFindDeadLocalStores=FindDeadLocalStores|true
+detectorFindDoubleCheck=FindDoubleCheck|true
+detectorFindEmptySynchronizedBlock=FindEmptySynchronizedBlock|true
+detectorFindFieldSelfAssignment=FindFieldSelfAssignment|true
+detectorFindFinalizeInvocations=FindFinalizeInvocations|true
+detectorFindFloatEquality=FindFloatEquality|true
+detectorFindHEmismatch=FindHEmismatch|true
+detectorFindInconsistentSync2=FindInconsistentSync2|true
+detectorFindJSR166LockMonitorenter=FindJSR166LockMonitorenter|true
+detectorFindLocalSelfAssignment2=FindLocalSelfAssignment2|true
+detectorFindMaskedFields=FindMaskedFields|true
+detectorFindMismatchedWaitOrNotify=FindMismatchedWaitOrNotify|true
+detectorFindNakedNotify=FindNakedNotify|true
+detectorFindNonShortCircuit=FindNonShortCircuit|true
+detectorFindNullDeref=FindNullDeref|true
+detectorFindNullDerefsInvolvingNonShortCircuitEvaluation=FindNullDerefsInvolvingNonShortCircuitEvaluation|true
+detectorFindOpenStream=FindOpenStream|true
+detectorFindPuzzlers=FindPuzzlers|true
+detectorFindRefComparison=FindRefComparison|true
+detectorFindReturnRef=FindReturnRef|true
+detectorFindRoughConstants=FindRoughConstants|true
+detectorFindRunInvocations=FindRunInvocations|true
+detectorFindSelfComparison=FindSelfComparison|true
+detectorFindSelfComparison2=FindSelfComparison2|true
+detectorFindSleepWithLockHeld=FindSleepWithLockHeld|true
+detectorFindSpinLoop=FindSpinLoop|true
+detectorFindSqlInjection=FindSqlInjection|true
+detectorFindTwoLockWait=FindTwoLockWait|true
+detectorFindUncalledPrivateMethods=FindUncalledPrivateMethods|true
+detectorFindUnconditionalWait=FindUnconditionalWait|true
+detectorFindUninitializedGet=FindUninitializedGet|true
+detectorFindUnrelatedTypesInGenericContainer=FindUnrelatedTypesInGenericContainer|true
+detectorFindUnreleasedLock=FindUnreleasedLock|true
+detectorFindUnsatisfiedObligation=FindUnsatisfiedObligation|true
+detectorFindUnsyncGet=FindUnsyncGet|true
+detectorFindUseOfNonSerializableValue=FindUseOfNonSerializableValue|true
+detectorFindUselessControlFlow=FindUselessControlFlow|true
+detectorFindUselessObjects=FindUselessObjects|true
+detectorFormatStringChecker=FormatStringChecker|true
+detectorHugeSharedStringConstants=HugeSharedStringConstants|true
+detectorIDivResultCastToDouble=IDivResultCastToDouble|true
+detectorIncompatMask=IncompatMask|true
+detectorInconsistentAnnotations=InconsistentAnnotations|true
+detectorInefficientIndexOf=InefficientIndexOf|true
+detectorInefficientInitializationInsideLoop=InefficientInitializationInsideLoop|false
+detectorInefficientMemberAccess=InefficientMemberAccess|false
+detectorInefficientToArray=InefficientToArray|true
+detectorInfiniteLoop=InfiniteLoop|true
+detectorInfiniteRecursiveLoop=InfiniteRecursiveLoop|true
+detectorInheritanceUnsafeGetResource=InheritanceUnsafeGetResource|true
+detectorInitializationChain=InitializationChain|true
+detectorInitializeNonnullFieldsInConstructor=InitializeNonnullFieldsInConstructor|true
+detectorInstantiateStaticClass=InstantiateStaticClass|true
+detectorIntCast2LongAsInstant=IntCast2LongAsInstant|true
+detectorInvalidJUnitTest=InvalidJUnitTest|true
+detectorIteratorIdioms=IteratorIdioms|true
+detectorLazyInit=LazyInit|true
+detectorLoadOfKnownNullValue=LoadOfKnownNullValue|true
+detectorLostLoggerDueToWeakReference=LostLoggerDueToWeakReference|true
+detectorMethodReturnCheck=MethodReturnCheck|true
+detectorMultithreadedInstanceAccess=MultithreadedInstanceAccess|true
+detectorMutableEnum=MutableEnum|true
+detectorMutableLock=MutableLock|true
+detectorMutableStaticFields=MutableStaticFields|true
+detectorNaming=Naming|true
+detectorNoteUnconditionalParamDerefs=NoteUnconditionalParamDerefs|true
+detectorNumberConstructor=NumberConstructor|true
+detectorOptionalReturnNull=OptionalReturnNull|true
+detectorOverridingEqualsNotSymmetrical=OverridingEqualsNotSymmetrical|true
+detectorPreferZeroLengthArrays=PreferZeroLengthArrays|true
+detectorPublicSemaphores=PublicSemaphores|false
+detectorQuestionableBooleanAssignment=QuestionableBooleanAssignment|true
+detectorReadOfInstanceFieldInMethodInvokedByConstructorInSuperclass=ReadOfInstanceFieldInMethodInvokedByConstructorInSuperclass|true
+detectorReadReturnShouldBeChecked=ReadReturnShouldBeChecked|true
+detectorRedundantConditions=RedundantConditions|true
+detectorRedundantInterfaces=RedundantInterfaces|true
+detectorRepeatedConditionals=RepeatedConditionals|true
+detectorRuntimeExceptionCapture=RuntimeExceptionCapture|true
+detectorSerializableIdiom=SerializableIdiom|true
+detectorStartInConstructor=StartInConstructor|true
+detectorStaticCalendarDetector=StaticCalendarDetector|true
+detectorStringConcatenation=StringConcatenation|true
+detectorSuperfluousInstanceOf=SuperfluousInstanceOf|true
+detectorSuspiciousThreadInterrupted=SuspiciousThreadInterrupted|true
+detectorSwitchFallthrough=SwitchFallthrough|true
+detectorSynchronizationOnSharedBuiltinConstant=SynchronizationOnSharedBuiltinConstant|true
+detectorSynchronizeAndNullCheckField=SynchronizeAndNullCheckField|true
+detectorSynchronizeOnClassLiteralNotGetClass=SynchronizeOnClassLiteralNotGetClass|true
+detectorSynchronizingOnContentsOfFieldToProtectField=SynchronizingOnContentsOfFieldToProtectField|true
+detectorURLProblems=URLProblems|true
+detectorUncallableMethodOfAnonymousClass=UncallableMethodOfAnonymousClass|true
+detectorUnnecessaryMath=UnnecessaryMath|true
+detectorUnreadFields=UnreadFields|true
+detectorUselessSubclassMethod=UselessSubclassMethod|false
+detectorVarArgsProblems=VarArgsProblems|true
+detectorVolatileUsage=VolatileUsage|true
+detectorWaitInLoop=WaitInLoop|true
+detectorWrongMapIterator=WrongMapIterator|true
+detectorXMLFactoryBypass=XMLFactoryBypass|true
+detector_threshold=2
+effort=default
+filter_settings=Medium|BAD_PRACTICE,CORRECTNESS,EXPERIMENTAL,MALICIOUS_CODE,MT_CORRECTNESS,PERFORMANCE,SECURITY,STYLE|false|12
+filter_settings_neg=NOISE,I18N|
+run_at_full_build=false
diff --git a/.settings/org.eclipse.jdt.ui.prefs b/.settings/org.eclipse.jdt.ui.prefs
index d4218a5..7397758 100644
--- a/.settings/org.eclipse.jdt.ui.prefs
+++ b/.settings/org.eclipse.jdt.ui.prefs
@@ -1,10 +1,9 @@
-#Wed Jul 29 11:31:38 PDT 2009
eclipse.preferences.version=1
editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
formatter_profile=_Google Format
formatter_settings_version=11
org.eclipse.jdt.ui.ignorelowercasenames=true
-org.eclipse.jdt.ui.importorder=com.google;com;junit;net;org;java;javax;
+org.eclipse.jdt.ui.importorder=\#;com.google;com;dk;eu;junit;net;org;java;javax;
org.eclipse.jdt.ui.ondemandthreshold=99
org.eclipse.jdt.ui.staticondemandthreshold=99
org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates/>
diff --git a/BUCK b/BUCK
index 2cd3fa8..02ee883 100644
--- a/BUCK
+++ b/BUCK
@@ -1,6 +1,7 @@
include_defs('//tools/build.defs')
gerrit_war(name = 'gerrit')
+gerrit_war(name = 'headless', ui = None)
gerrit_war(name = 'chrome', ui = 'ui_chrome')
gerrit_war(name = 'firefox', ui = 'ui_firefox')
gerrit_war(name = 'safari', ui = 'ui_safari')
diff --git a/Documentation/Makefile b/Documentation/Makefile
deleted file mode 100644
index aed9e90..0000000
--- a/Documentation/Makefile
+++ /dev/null
@@ -1,50 +0,0 @@
-# Copyright (C) 2009 The Android Open Source Project
-#
-# 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.
-
-ASCIIDOC ?= asciidoc
-ASCIIDOC_EXTRA ?=
-ASCIIDOC_VER ?= 8.6.3
-
-all: html
-
-clean:
- rm -f *.html
-
-ASCIIDOC_EXE := $(shell which $(ASCIIDOC))
-ifeq ($(wildcard $(ASCIIDOC_EXE)),)
- $(error $(ASCIIDOC) must be available)
-else
- ASCIIDOC_OK := $(shell expr `asciidoc --version | cut -f2 -d' '` \>= $(ASCIIDOC_VER))
- ifeq ($(ASCIIDOC_OK),0)
- $(error $(ASCIIDOC) version $(ASCIIDOC_VER) or higher is required)
- endif
-endif
-
-DOC_HTML := $(patsubst %.txt,%.html,$(wildcard *.txt))
-REVISION := $(shell git describe HEAD | sed s/^v//)
-
-html: $(DOC_HTML)
-
-$(DOC_HTML): %.html : %.txt
- @echo "FORMAT $@"
- @rm -f $@+ $@
- @$(ASCIIDOC) -a toc \
- -a data-uri \
- -a 'revision=$(REVISION)' \
- -a 'newline=\n' \
- -b xhtml11 \
- -f asciidoc.conf \
- $(ASCIIDOC_EXTRA) \
- -o $@+ $<
- @mv $@+ $@
diff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf
deleted file mode 100644
index 2fe6213..0000000
--- a/Documentation/asciidoc.conf
+++ /dev/null
@@ -1,29 +0,0 @@
-[attributes]
-asterisk=*
-plus=+
-caret=^
-startsb=[
-endsb=]
-tilde=~
-
-[specialsections]
-GERRIT=gerrituplink
-
-[gerrituplink]
-<hr style="
- height: 2px;
- color: silver;
- margin-top: 1.2em;
- margin-bottom: 0.5em;
-">
-
-[macros]
-(?u)^(?P<name>get)::(?P<target>\S*?)$=#
-
-[get-blockmacro]
-<a id="{target}" onmousedown="javascript:
- var i = document.URL.lastIndexOf('/Documentation/');
- var url = document.URL.substring(0, i) + '{target}';
- document.getElementById('{target}').href = url;">
- GET {target} HTTP/1.0
-</a>
diff --git a/Documentation/cmd-gc.txt b/Documentation/cmd-gc.txt
index a890f1b..b7388a1 100644
--- a/Documentation/cmd-gc.txt
+++ b/Documentation/cmd-gc.txt
@@ -8,6 +8,7 @@
'ssh' -p <port> <host> 'gerrit gc'
[--all]
[--show-progress]
+ [--aggressive]
<NAME> ...
--
@@ -44,6 +45,9 @@
--show-progress::
If specified progress information is shown.
+--aggressive::
+ If an aggressive garbage collection should be done.
+
== EXAMPLES
Run the Git garbage collection for the projects 'myProject' and
diff --git a/Documentation/cmd-index.txt b/Documentation/cmd-index.txt
index 7c664ac..f3bff7d 100644
--- a/Documentation/cmd-index.txt
+++ b/Documentation/cmd-index.txt
@@ -75,6 +75,9 @@
link:cmd-review.html[gerrit review]::
Verify, approve and/or submit a patch set from the command line.
+link:cmd-set-head.html[gerrit set-head]::
+ Change the HEAD reference of a project.
+
link:cmd-set-reviewers.html[gerrit set-reviewers]::
Add or remove reviewers on a change.
diff --git a/Documentation/cmd-set-head.txt b/Documentation/cmd-set-head.txt
new file mode 100644
index 0000000..d74caaa
--- /dev/null
+++ b/Documentation/cmd-set-head.txt
@@ -0,0 +1,45 @@
+= gerrit set-head
+
+== NAME
+gerrit set-head - Change a project's HEAD.
+
+== SYNOPSIS
+--
+'ssh' -p <port> <host> 'gerrit set-head' <NAME>
+ --new-head <REF>
+--
+
+== DESCRIPTION
+Modifies a given project's HEAD reference.
+
+The command is argument-safe, that is, if no argument is given the
+previous settings are kept intact.
+
+== ACCESS
+Caller must be an owner of the given project.
+
+== SCRIPTING
+This command is intended to be used in scripts.
+
+== OPTIONS
+<NAME>::
+ Required; name of the project to change the HEAD. If name ends
+ with `.git` the suffix will be automatically removed.
+
+--new-head::
+ Required; name of the ref that should be set as new HEAD. The
+ 'refs/heads/' prefix can be omitted.
+
+== EXAMPLES
+Change HEAD of project `example` to `stable-2.11` branch:
+
+====
+ $ ssh -p 29418 review.example.com gerrit set-head example --new-head stable-2.11
+====
+
+GERRIT
+------
+Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-stream-events.txt b/Documentation/cmd-stream-events.txt
index c754f35..dcdbb07 100644
--- a/Documentation/cmd-stream-events.txt
+++ b/Documentation/cmd-stream-events.txt
@@ -153,6 +153,19 @@
eventCreatedOn:: Time in seconds since the UNIX epoch when this event was
created.
+=== Project Created
+
+Sent when a new project has been created.
+
+type:: "project-created"
+
+projectName:: The created project name
+
+projectHead:: The created project head name
+
+eventCreatedOn:: Time in seconds since the UNIX epoch when this event was
+created.
+
=== Merge Failed
Sent when a change has failed to be merged into the git repository.
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index fdb9d18..95b6717 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -871,6 +871,30 @@
+
Default is "Submit patch set ${patchSet} into ${branch}".
+[[change.submitWholeTopic]]change.submitWholeTopic::
++
+Determines if the submit button submits the whole topic instead of
+just the current change.
++
+Default is false.
+
+[[change.submitTopicLabel]]change.submitTopicLabel::
++
+If `change.submitWholeTopic` is set and a change has a topic,
+the label name for the submit button is given here instead of
+the configuration `change.submitLabel`.
++
+Defaults to "Submit whole topic"
+
+[[change.submitTopicTooltip]]change.submitTopicTooltip::
++
+If `change.submitWholeTopic` is configuerd to true and a change has a
+topic, this configuration determines the tooltip for the submit button
+instead of `change.submitTooltip`. The variable `${topicSize}` is available
+for the number of changes to be submitted.
++
+Defaults to "Submit all ${topicSize} changes within the topic".
+
[[change.replyLabel]]change.replyLabel::
+
Label name for the reply button. In the user interface an ellipsis (…)
@@ -1188,7 +1212,7 @@
[[core.useRecursiveMerge]]core.useRecursiveMerge::
+
Use JGit's recursive merger for three-way merges. This only affects
-projects configured to automatically resolve conflicts.
+projects that allow content merges.
+
As explained in this
link:http://codicesoftware.blogspot.com/2011/09/merge-recursive-strategy.html[
@@ -1428,7 +1452,7 @@
[[download.archive]]download.archive::
+
Specifies which archive formats, if any, should be offered on the change
-screen:
+screen and supported for `git-upload-archive` operation:
+
----
[download]
@@ -1436,11 +1460,17 @@
archive = tbz2
archive = tgz
archive = txz
+ archive = zip
----
If `download.archive` is not specified defaults to all archive
commands. Set to `off` or empty string to disable.
+Zip is not supported because it may be interpreted by a Java plugin as a
+valid JAR file, whose code would have access to cookies on the domain.
+For this reason `zip` format is always excluded from formats offered
+through the `Download` drop down or accessible in the REST API.
+
[[gc]]
=== Section gc
@@ -1448,6 +1478,15 @@
to run periodically. It will be triggered and executed sequentially for all
projects.
+[[gc.aggressive]]gc.aggressive::
++
+Determines if scheduled garbage collections and garbage collections triggered
+through Web-UI should run in aggressive mode or not. Aggressive garbage
+collections are more expensive but may lead to significantly smaller
+repositories.
++
+Valid values are "true" and "false," default is "false".
+
[[gc.startTime]]gc.startTime::
+
Start time to define the first execution of the git garbage collection.
@@ -1800,6 +1839,11 @@
Optional filename for the hashtags changed hook, if not specified then
`hashtags-changed` will be used.
+[[hooks.projectCreatedHook]]hooks.projectCreatedHook::
++
+Optional filename for the project created hook, if not specified then
+`project-created` will be used.
+
[[hooks.mergeFailedHook]]hooks.mergeFailedHook::
+
Optional filename for the merge failed hook, if not specified then
@@ -2156,6 +2200,36 @@
CPUs as returned by the JVM (unless
link:#changeMerge.threadPoolSize[changeMerge.threadPoolSize] is set).
+[[index.onlineUpgrade]]index.onlineUpgrade::
++
+Whether to upgrade to new index schema versions while the server is
+running. This is recommended as it prevents additional downtime during
+Gerrit version upgrades (avoiding the need for an offline reindex step
+using Reindex), but can add additional server load during the upgrade.
++
+If set to false, there is no way to upgrade the index schema to take
+advantage of new search features without restarting the server.
++
+Defaults to true.
+
+[[index.maxLimit]]index.maxLimit::
++
+Maximum limit to allow for search queries. Requesting results above this
+limit will truncate the list (but will still set `_more_changes` on
+result lists). Set to 0 for no limit.
++
+Defaults to no limit.
+
+[[index.maxPages]]index.maxPages::
++
+Maximum number of pages of search results to allow, as index
+implementations may have to scan through large numbers of skipped
+results when searching with an offset. Requesting results starting past
+this threshold times the requested limit will result in an error. Set to
+0 for no limit.
++
+Defaults to no limit.
+
==== Lucene configuration
Open and closed changes are indexed in separate indexes named
@@ -2581,6 +2655,22 @@
javaOptions = -Dcom.sun.jndi.ldap.connect.pool.timeout=300000
----
+[[log]]
+=== Section log
+
+[[log.jsonLogging]]log.jsonLogging::
++
+If set to true, enables error logging in JSON format (file name: "logs/error_log.json").
++
+Defaults to false.
+
+[[log.textLogging]]log.textLogging::
++
+If set to true, enables error logging in regular plain text format. Can only be disabled
+if `jsonLogging` is enabled.
++
+Defaults to true.
+
[[mimetype]]
=== Section mimetype
@@ -2657,6 +2747,13 @@
and SSH. If set to true Administrators can install new plugins
remotely, or disable existing plugins. Defaults to false.
+[[plugins.jsLoadTimeout]]plugins.jsLoadTimeout::
++
+Set the timeout value for loading JavaScript plugins in Gerrit UI.
+Values can be specified using standard time unit abbreviations ('ms',
+'sec', 'min', etc.).
++
+Default is 5 seconds. Negative values will be converted to 0.
[[receive]]
=== Section receive
@@ -2788,9 +2885,22 @@
ownerGroup = Registered Users
----
-[NOTE]
-Currently only the repository name `*` is supported.
-This is a wildcard designating all repositories.
+The only matching patterns supported are exact match or wildcard matching which
+can be specified by ending the name with a `*`. If a project matches more than one
+repository configuration, then the configuration from the more precise match
+will be used. In the following example, the default submit type for a project
+named `project/plugins/a` would be `CHERRY_PICK`.
+
+----
+[repository "project/*"]
+ defaultSubmitType = MERGE_IF_NECESSARY
+[repository "project/plugins/*"]
+ defaultSubmitType = CHERRY_PICK
+----
+
+[NOTE] All properties are used from the matching repository configuration. In
+the previous example, all properties will be used from `project/plugins/\*`
+section and no properties will be inherited nor overridden from `project/*`.
[[repository.name.defaultSubmitType]]repository.<name>.defaultSubmitType::
+
diff --git a/Documentation/config-hooks.txt b/Documentation/config-hooks.txt
index ce908b9..3068cc5 100644
--- a/Documentation/config-hooks.txt
+++ b/Documentation/config-hooks.txt
@@ -110,6 +110,14 @@
ref-updated --oldrev <old rev> --newrev <new rev> --refname <ref name> --project <project name> --submitter <submitter>
====
+=== project-created
+
+Called whenever a project has been created.
+
+====
+ project-created --project <project name> --head <head name>
+====
+
=== reviewer-added
Called whenever a reviewer is added to a change.
diff --git a/Documentation/config-labels.txt b/Documentation/config-labels.txt
index ce49d31..a40c5f3 100644
--- a/Documentation/config-labels.txt
+++ b/Documentation/config-labels.txt
@@ -243,7 +243,7 @@
This is the case if the change was rebased onto a different parent.
This can be used to enable sticky approvals, reducing turn-around for
trivial rebases prior to submitting a change.
-It is recommended to enable this for the Code-Review label.
+For the pre-installed Code-Review label this is enabled by default.
Defaults to false.
[[label_copyAllScoresIfNoCodeChange]]
@@ -255,7 +255,8 @@
the commit message is different. This can be used to enable sticky
approvals on labels that only depend on the code, reducing turn-around
if only the commit message is changed prior to submitting a change.
-It is recommended to enable this for the Verified label if enabled.
+For the Verified label that is installed by the link:pgm-init.html[init]
+site program this is enabled by default.
Defaults to false.
[[label_copyAllScoresIfNoChange]]
diff --git a/Documentation/config-plugins.txt b/Documentation/config-plugins.txt
index 608a3ac..3887ff3 100644
--- a/Documentation/config-plugins.txt
+++ b/Documentation/config-plugins.txt
@@ -386,6 +386,17 @@
link:https://gerrit.googlesource.com/plugins/motd/+doc/master/src/main/resources/Documentation/config.md[
Configuration]
+[[oauth-authentication-provider]]
+=== OAuth authentication provider
+This plugin enables Gerrit to use OAuth2 protocol for authentication.
+Two different OAuth providers are supported:
+
+* GitHub
+* Google
+
+https://github.com/davido/gerrit-oauth-provider[Project] |
+https://github.com/davido/gerrit-oauth-provider/wiki/Getting-Started[Configuration]
+
[[project-download-commands]]
=== project-download-commands
diff --git a/Documentation/config-reverseproxy.txt b/Documentation/config-reverseproxy.txt
index 7f30b14..c3dd12e 100644
--- a/Documentation/config-reverseproxy.txt
+++ b/Documentation/config-reverseproxy.txt
@@ -48,6 +48,8 @@
<Proxy *>
Order deny,allow
Allow from all
+ # Use following line instead of the previous two on Apache >= 2.4
+ # Require all granted
</Proxy>
AllowEncodedSlashes On
diff --git a/Documentation/dev-buck.txt b/Documentation/dev-buck.txt
index 2eb478c..89cd849 100644
--- a/Documentation/dev-buck.txt
+++ b/Documentation/dev-buck.txt
@@ -7,7 +7,7 @@
There is currently no binary distribution of Buck, so it has to be manually
built and installed. Apache Ant is required. Currently only Linux and Mac
-OS are supported. Buck requires Python version 2.7 to be installed.
+OS are supported.
Clone the git and build it:
@@ -50,6 +50,10 @@
script from `./scripts/buck_completion.bash` in the buck project. Refer
to the script's header comments for installation instructions.
+== Prerequisites
+
+Buck requires Python version 2.7 to be installed. The Maven download toolchain
+requires `curl` to be installed.
[[eclipse]]
== Eclipse Integration
@@ -116,6 +120,20 @@
----
+=== Headless Mode
+
+To build Gerrit in headless mode, i.e. without the GWT Web UI:
+
+----
+ buck build headless
+----
+
+The output executable WAR will be placed in:
+
+----
+ buck-out/gen/headless.war
+----
+
=== Extension and Plugin API JAR Files
To build the extension, plugin and GWT API JAR files:
@@ -593,14 +611,14 @@
needs to be repeated, the unit test cache for that test must be removed first:
----
- rm -rf buck-out/bin/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/.AddRemoveGroupMembersIT/
+ rm -rf buck-out/bin/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/group/.AddRemoveGroupMembersIT/
----
After clearing the cache, the test can be run again:
----
- buck test //gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group:AddRemoveGroupMembersIT
- TESTING //gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group:AddRemoveGroupMembersIT
+ buck test //gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/group:AddRemoveGroupMembersIT
+ TESTING //gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/group:AddRemoveGroupMembersIT
PASS 14,9s 8 Passed 0 Failed com.google.gerrit.acceptance.rest.group.AddRemoveGroupMembersIT
TESTS PASSED
----
diff --git a/Documentation/dev-contributing.txt b/Documentation/dev-contributing.txt
index 72d7ddf..b717f4e 100644
--- a/Documentation/dev-contributing.txt
+++ b/Documentation/dev-contributing.txt
@@ -334,6 +334,8 @@
plugins that have a dependency on GWT.
* Update the GWT version in the archetype metadata in the
`gerrit-plugin-gwt-archetype`.
+* Update the version of `gwt-maven-plugin` in the example pom.xml file in
+link:dev-plugins.html[dev-plugins].
* Update to the same GWT version in the `gwtjsonrpc` project, and release a
new version.
diff --git a/Documentation/dev-plugins.txt b/Documentation/dev-plugins.txt
index f9b66cb..9bb0007 100644
--- a/Documentation/dev-plugins.txt
+++ b/Documentation/dev-plugins.txt
@@ -36,7 +36,7 @@
----
mvn archetype:generate -DarchetypeGroupId=com.google.gerrit \
-DarchetypeArtifactId=gerrit-plugin-archetype \
- -DarchetypeVersion=2.10 \
+ -DarchetypeVersion=2.12-SNAPSHOT \
-DgroupId=com.googlesource.gerrit.plugins.testplugin \
-DartifactId=testplugin
----
@@ -404,6 +404,10 @@
+
Publication of usage data
+* `com.google.gerrit.extensions.events.GarbageCollectorListener`:
++
+Garbage collection ran on a project
+
[[stream-events]]
== Sending Events to the Events Stream
@@ -1519,7 +1523,7 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
- <version>2.5.1</version>
+ <version>2.7.0</version>
<configuration>
<module>com.googlesource.gerrit.plugins.myplugin.HelloPlugin</module>
<disableClassMetadata>true</disableClassMetadata>
@@ -1717,17 +1721,18 @@
[[data-directory]]
== Data Directory
-Plugins can request a data directory with a `@PluginData` File
-dependency. A data directory will be created automatically by the
-server in `$site_path/data/$plugin_name` and passed to the plugin.
+Plugins can request a data directory with a `@PluginData` Path (or File,
+deprecated) dependency. A data directory will be created automatically
+by the server in `$site_path/data/$plugin_name` and passed to the
+plugin.
Plugins can use this to store any data they want.
[source,java]
----
@Inject
-MyType(@PluginData java.io.File myDir) {
- new FileInputStream(new File(myDir, "my.config"));
+MyType(@PluginData java.nio.file.Path myDir) {
+ this.in = Files.newInputStream(myDir.resolve("my.config"));
}
----
diff --git a/Documentation/dev-readme.txt b/Documentation/dev-readme.txt
index bcf4a588..b64973a 100644
--- a/Documentation/dev-readme.txt
+++ b/Documentation/dev-readme.txt
@@ -56,6 +56,17 @@
Eclipse integration and then open it as Eclipse project in IDEA.
You need the Eclipse plugin activated in IntelliJ IDEA.
+Once you start compiling using both buck and your Gerrit project in
+IDEA, you will likely need to mark the below directories as generated
+sources roots. You can do so using the IDEA "Project" view. In the
+context menu of each one of these, use "Mark Directory As" to mark
+them as "Generated Sources Root":
+
+----
+ __auto_value_tests_gen__
+ __httpd_gen__
+ __server_gen__
+----
== Mac OS X
diff --git a/Documentation/dev-release-deploy-config.txt b/Documentation/dev-release-deploy-config.txt
index f3397a4..b2c5358 100644
--- a/Documentation/dev-release-deploy-config.txt
+++ b/Documentation/dev-release-deploy-config.txt
@@ -10,12 +10,11 @@
To be able to publish artifacts to Maven Central some preparations must
be done:
-* Create a Sonatype account as described in the
-link:https://docs.sonatype.org/display/Repository/Sonatype+OSS+Maven+Repository+Usage+Guide#SonatypeOSSMavenRepositoryUsageGuide-2.Signup[
-Sonatype OSS Maven Repository Usage Guide].
+* Create an account on
+link:https://issues.sonatype.org/secure/Signup!default.jspa[Sonatype's Jira].
+
Sonatype is the company that runs Maven Central and you need a Sonatype
-account for uploading artifacts to Maven Central.
+account to be able to upload artifacts to Maven Central.
* Configure your Sonatype user and password in `~/.m2/settings.xml`:
+
@@ -75,7 +74,7 @@
Gerrit Subproject Artifacts are stored on
link:https://developers.google.com/storage/[Google Cloud Storage].
-Via the link:https://code.google.com/apis/console/?noredirect[API Console] the
+Via the link:https://console.developers.google.com/project/164060093628[Developers Console] the
Gerrit maintainers have access to the `Gerrit Code Review` project.
This projects host several buckets for storing Gerrit artifacts:
@@ -90,13 +89,14 @@
To upload artifacts to a bucket the user must authenticate with a
username and password. The username and password need to be retrieved
-from the link:https://code.google.com/apis/console/?noredirect[API Console]:
+from the link:https://console.developers.google.com/project/164060093628[
+Google Developers Console]:
-* Go to the `Gerrit Code Review` project
-* In the menu on the left select `Google Cloud Storage` >
-`Interoperable Access`
-* Use the `Access Key` as username
-* Click under `Secret` on the `Show` button to find the password
+* In the menu on the left select `Storage` -> `Cloud Storage` >
+> `Storage access`
+* Select the `Interoperability` tab
+* If no keys are listed under `Interoperable storage access keys`, select "Create a new key"
+* Use the `Access Key` as username, and `Secret` as the password
To make the username and password known to Maven, they must be
configured in the `~/.m2/settings.xml` file.
diff --git a/Documentation/dev-release.txt b/Documentation/dev-release.txt
index 3d3104c..1b3e98f 100644
--- a/Documentation/dev-release.txt
+++ b/Documentation/dev-release.txt
@@ -157,7 +157,8 @@
* Build the Gerrit WAR and API JARs
+
----
- buck build release
+ buck clean
+ buck build --no-cache release
buck build api_install
----
@@ -352,9 +353,7 @@
* Upload the html files manually via web browser to the
link:https://console.developers.google.com/project/164060093628/storage/gerrit-documentation/[
-gerrit-documentation] storage bucket. The `gerrit-documentation`
-storage bucket is accessible via the
-link:https://cloud.google.com/console[Google Developers Console].
+gerrit-documentation] storage bucket.
[[update-links]]
==== Update Google Code project links
diff --git a/Documentation/intro-project-owner.txt b/Documentation/intro-project-owner.txt
index f5d5277..eb3c4fb 100644
--- a/Documentation/intro-project-owner.txt
+++ b/Documentation/intro-project-owner.txt
@@ -238,7 +238,7 @@
=== Submit Type
An important decision for a project is the choice of the submit type
-and the content merge setting (aka `Automatically resolve conflicts`).
+and the content merge setting (see the `Allow content merges` option).
The link:project-configuration.html#submit_type[submit type] is the method
Gerrit uses to submit a change to the project. The submit type defines
what Gerrit should do on submit of a change if the destination branch
diff --git a/Documentation/intro-user.txt b/Documentation/intro-user.txt
index 4677307..4584841 100644
--- a/Documentation/intro-user.txt
+++ b/Documentation/intro-user.txt
@@ -29,6 +29,9 @@
* link:http://eclipse.org/mylyn/[Mylyn Gerrit Connector]: Gerrit
integration with Mylyn
+* link:https://github.com/uwolfer/gerrit-intellij-plugin[Gerrit
+ IntelliJ Plugin]: Gerrit integration with the
+ link:http://www.jetbrains.com/idea/[IntelliJ Platform]
* link:https://play.google.com/store/apps/details?id=com.jbirdvegas.mgerrit[
mGerrit]: Android client for Gerrit
* link:https://github.com/stackforge/gertty[Gertty]: Console-based
diff --git a/Documentation/json.txt b/Documentation/json.txt
index feef1a1..8ccd03b 100644
--- a/Documentation/json.txt
+++ b/Documentation/json.txt
@@ -156,7 +156,7 @@
newRev:: The new value the ref was updated to.
-refName:: Ref name within project.
+refName:: Full ref name within project.
project:: Project path in Gerrit.
diff --git a/Documentation/man/.gitignore b/Documentation/man/.gitignore
deleted file mode 100644
index 7993a55..0000000
--- a/Documentation/man/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-gerrit*
diff --git a/Documentation/man/Makefile b/Documentation/man/Makefile
deleted file mode 100644
index 945f215..0000000
--- a/Documentation/man/Makefile
+++ /dev/null
@@ -1,64 +0,0 @@
-# Copyright (C) 2013 The Android Open Source Project
-#
-# 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.
-
-A2X ?= a2x
-
-all: man
-
-clean:
- @rm -f gerrit-*
-
-CMD_CORE_SSH_CMD := \
-cmd-ban-commit.txt \
-cmd-create-account.txt \
-cmd-create-group.txt \
-cmd-create-project.txt \
-cmd-flush-caches.txt \
-cmd-gc.txt \
-cmd-gsql.txt \
-cmd-ls-groups.txt \
-cmd-ls-projects.txt \
-cmd-ls-user-refs.txt \
-cmd-query.txt \
-cmd-rename-group.txt \
-cmd-review.txt \
-cmd-set-account.txt \
-cmd-set-members.txt \
-cmd-set-project-parent.txt \
-cmd-set-project.txt \
-cmd-set-reviewers.txt \
-cmd-show-caches.txt \
-cmd-show-connections.txt \
-cmd-show-queue.txt \
-cmd-stream-events.txt \
-cmd-test-submit-rule.txt \
-cmd-version.txt
-
-GERRIT_CORE_SSH_CMD := $(patsubst cmd-%,gerrit-%,$(CMD_CORE_SSH_CMD))
-DOC_MAN := $(patsubst %.txt,%.1,$(GERRIT_CORE_SSH_CMD))
-
-man: $(GERRIT_CORE_SSH_CMD) $(DOC_MAN)
-
-$(GERRIT_CORE_SSH_CMD) : gerrit-%.txt : ../cmd-%.txt
- @cp $< $@
-
-$(DOC_MAN) : %.1 : %.txt
- @echo "creating man page for $@ ..."
- @rm -f $@
- @$(eval TITLE := $(join $(basename $<),\(1\)))
- @$(eval SEPERATOR := $(shell echo $(TITLE) | sed 's/./=/g'))
- @sed -i -re '1s/^.*$//$(TITLE)/' $<
- @sed -i -re '2s/^=.*/$(SEPERATOR)/' $<
- @sed -i -re '6s/^gerrit\s+(\w)/gerrit-\1/' $<
- @$(A2X) --doctype manpage --format manpage $<
diff --git a/Documentation/project-configuration.txt b/Documentation/project-configuration.txt
index 1cecabf..6d7c6d0 100644
--- a/Documentation/project-configuration.txt
+++ b/Documentation/project-configuration.txt
@@ -114,7 +114,7 @@
the same file has also been changed on the other side of the merge.
[[content_merge]]
-If `Automatically resolve conflicts` is enabled, Gerrit will try
+If `Allow content merges` is enabled, Gerrit will try
to do a content merge when a path conflict occurs.
[[project-state]]
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index 1b9a705..138f85f 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -310,6 +310,13 @@
* `CHECK`: include potential problems with the change.
--
+[[commit-footers]]
+--
+* `COMMIT_FOOTERS`: include the full commit message with
+ Gerrit-specific commit footers in the
+ link:#revision-info[RevisionInfo].
+--
+
.Request
----
GET /changes/?q=97&o=CURRENT_REVISION&o=CURRENT_COMMIT&o=CURRENT_FILES&o=DOWNLOAD_COMMANDS HTTP/1.0
@@ -1146,6 +1153,109 @@
HTTP/1.1 204 No Content
----
+[[list-change-comments]]
+=== List Change Comments
+--
+'GET /changes/link:#change-id[\{change-id\}]/comments'
+--
+
+Lists the published comments of all revisions of the change.
+
+Returns a map of file paths to lists of link:#comment-info[CommentInfo]
+entries. The entries in the map are sorted by file path, and the
+comments for each path are sorted by patch set number. Each comment has
+the `patch_set` and `author` fields set.
+
+.Request
+----
+ GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/comments HTTP/1.0
+----
+
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Disposition: attachment
+ Content-Type: application/json; charset=UTF-8
+
+ )]}'
+ {
+ "gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java": [
+ {
+ "patch_set": 1,
+ "id": "TvcXrmjM",
+ "line": 23,
+ "message": "[nit] trailing whitespace",
+ "updated": "2013-02-26 15:40:43.986000000"
+ "author": {
+ "_account_id": 1000096,
+ "name": "John Doe",
+ "email": "john.doe@example.com"
+ }
+ },
+ {
+ "patch_set": 2,
+ "id": "TveXwFiA",
+ "line": 49,
+ "in_reply_to": "TfYX-Iuo",
+ "message": "Done",
+ "updated": "2013-02-26 15:40:45.328000000"
+ "author": {
+ "_account_id": 1000097,
+ "name": "Jane Roe",
+ "email": "jane.roe@example.com"
+ }
+ }
+ ]
+ }
+----
+
+[[list-change-drafts]]
+=== List Change Drafts
+--
+'GET /changes/link:#change-id[\{change-id\}]/drafts'
+--
+
+Lists the draft comments of all revisions of the change that belong to
+the calling user.
+
+Returns a map of file paths to lists of link:#comment-info[CommentInfo]
+entries. The entries in the map are sorted by file path, and the
+comments for each path are sorted by patch set number. Each comment has
+the `patch_set` field set, and no `author`.
+
+.Request
+----
+ GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/drafts HTTP/1.0
+----
+
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Disposition: attachment
+ Content-Type: application/json; charset=UTF-8
+
+ )]}'
+ {
+ "gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java": [
+ {
+ "patch_set": 1,
+ "id": "TvcXrmjM",
+ "line": 23,
+ "message": "[nit] trailing whitespace",
+ "updated": "2013-02-26 15:40:43.986000000"
+ },
+ {
+ "patch_set": 2,
+ "id": "TveXwFiA",
+ "line": 49,
+ "in_reply_to": "TfYX-Iuo",
+ "message": "Done",
+ "updated": "2013-02-26 15:40:45.328000000"
+ }
+ ]
+ }
+----
+
[[check-change]]
=== Check change
--
@@ -2586,7 +2696,7 @@
----
[[list-drafts]]
-=== List Drafts
+=== List Revision Drafts
--
'GET /changes/link:#change-id[\{change-id\}]/revisions/link:#revision-id[\{revision-id\}]/drafts/'
--
@@ -2594,9 +2704,8 @@
Lists the draft comments of a revision that belong to the calling
user.
-As result a map is returned that maps the file path to a list of
-link:#comment-info[CommentInfo] entries. The entries in the map are
-sorted by file path.
+Returns a map of file paths to lists of link:#comment-info[CommentInfo]
+entries. The entries in the map are sorted by file path.
.Request
----
@@ -2765,7 +2874,7 @@
----
[[list-comments]]
-=== List Comments
+=== List Revision Comments
--
'GET /changes/link:#change-id[\{change-id\}]/revisions/link:#revision-id[\{revision-id\}]/comments/'
--
@@ -3494,6 +3603,9 @@
[options="header",cols="1,^1,5"]
|===========================
|Field Name ||Description
+|`patch_set` |optional|
+The patch set number for the comment; only set in contexts where +
+comments may be returned for multiple patch sets.
|`id` ||The URL encoded UUID of the comment.
|`path` |optional|
The path of the file for which the inline comment was done. +
@@ -4013,7 +4125,9 @@
Draft handling that defines how draft comments are handled that are
already in the database but that were not also described in this
input. +
-Allowed values are `DELETE`, `PUBLISH` and `KEEP`. +
+Allowed values are `DELETE`, `PUBLISH`, `PUBLISH_ALL_REVISIONS` and
+`KEEP`. All values except `PUBLISH_ALL_REVISIONS` operate only on drafts
+for a single revision. +
If not set, the default is `DELETE`.
|`notify` |optional|
Notify handling that defines to whom email notifications should be sent
@@ -4108,6 +4222,12 @@
|`reviewed` |optional|
Indicates whether the caller is authenticated and has commented on the
current revision. Only set if link:#reviewed[REVIEWED] option is requested.
+|`messageWithFooter` |optional|
+If the link:#commit-footers[COMMIT_FOOTERS] option is requested and
+this is the current patch set, contains the full commit message with
+Gerrit-specific commit footers, as if this revision were submitted
+using the link:project-configuration.html#cherry_pick[Cherry Pick]
+submit type.
|===========================
[[rule-input]]
diff --git a/Documentation/rest-api-config.txt b/Documentation/rest-api-config.txt
index 0ee6966..a8bbbfa 100644
--- a/Documentation/rest-api-config.txt
+++ b/Documentation/rest-api-config.txt
@@ -30,6 +30,84 @@
"2.7"
----
+[[get-info]]
+=== Get Server Info
+--
+'GET /config/server/info'
+--
+
+Returns the information about the Gerrit server configuration.
+
+.Request
+----
+ GET /config/server/info HTTP/1.0
+----
+
+As result a link:#server-info[ServerInfo] entity is returned.
+
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Type: application/json; charset=UTF-8
+
+ )]}'
+ {
+ "auth": {
+ "auth_type": "LDAP",
+ "editable_account_fields": [
+ "FULL_NAME",
+ "REGISTER_NEW_EMAIL"
+ ]
+ },
+ "download": {
+ "schemes": [
+ "anonymous http": {
+ "url": "http://gerrithost:8080/${project}",
+ "commands": {
+ "Checkout": "git fetch http://gerrithost:8080/${project} ${ref} \u0026\u0026 git checkout FETCH_HEAD",
+ "Format Patch": "git fetch http://gerrithost:8080/${project} ${ref} \u0026\u0026 git format-patch -1 --stdout FETCH_HEAD",
+ "Pull": "git pull http://gerrithost:8080/${project} ${ref}",
+ "Cherry Pick": "git fetch http://gerrithost:8080/${project} ${ref} \u0026\u0026 git cherry-pick FETCH_HEAD"
+ }
+ },
+ "http": {
+ "url": "http://jdoe@gerrithost:8080/${project}",
+ "is_auth_required": true,
+ "is_auth_supported": true,
+ "commands": {
+ "Checkout": "git fetch http://jdoe@gerrithost:8080/${project} ${ref} \u0026\u0026 git checkout FETCH_HEAD",
+ "Format Patch": "git fetch http://jdoe@gerrithost:8080/${project} ${ref} \u0026\u0026 git format-patch -1 --stdout FETCH_HEAD",
+ "Pull": "git pull http://jdoe@gerrithost:8080/${project} ${ref}",
+ "Cherry Pick": "git fetch http://jdoe@gerrithost:8080/${project} ${ref} \u0026\u0026 git cherry-pick FETCH_HEAD"
+ }
+ },
+ "ssh": {
+ "url": "ssh://jdoe@gerrithost:29418/${project}",
+ "is_auth_required": true,
+ "is_auth_supported": true,
+ "commands": {
+ "Checkout": "git fetch ssh://jdoe@gerrithost:29418/${project} ${ref} \u0026\u0026 git checkout FETCH_HEAD",
+ "Format Patch": "git fetch ssh://jdoe@gerrithost:29418/${project} ${ref} \u0026\u0026 git format-patch -1 --stdout FETCH_HEAD",
+ "Pull": "git pull ssh://jdoe@gerrithost:29418/${project} ${ref}",
+ "Cherry Pick": "git fetch ssh://jdoe@gerrithost:29418/${project} ${ref} \u0026\u0026 git cherry-pick FETCH_HEAD"
+ }
+ }
+ ],
+ "archives": [
+ "tgz",
+ "tar",
+ "tbz2",
+ "txz"
+ ]
+ },
+ "gerrit": {
+ "all_projects": "All-Projects",
+ "all_users": "All-Users"
+ }
+ }
+----
+
+
[[list-caches]]
=== List Caches
--
@@ -822,6 +900,27 @@
[[json-entities]]
== JSON Entities
+[[auth-info]]
+=== AuthInfo
+The `AuthInfo` entity contains information about the authentication
+configuration of the Gerrit server.
+
+[options="header",cols="1,^1,5"]
+|==========================================
+|Field Name ||Description
+|`type` ||
+The link:config-gerrit.html#auth.type[authentication type] that is
+configured on the server. Can be `OPENID`, `OPENID_SSO`, `OAUTH`,
+`HTTP`, `HTTP_LDAP`, `CLIENT_SSL_CERT_LDAP`, `LDAP`, `LDAP_BIND`,
+`CUSTOM_EXTENSION` or `DEVELOPMENT_BECOME_ANY_ACCOUNT`.
+|`use_contributor_agreements` |not set if `false`|
+Whether link:config-gerrit.html#auth.contributorAgreements[contributor
+agreements] are required.
+|`editable_account_fields` ||
+List of account fields that are editable. Possible values are
+`FULL_NAME`, `USER_NAME` and `REGISTER_NEW_EMAIL`.
+|==========================================
+
[[cache-info]]
=== CacheInfo
The `CacheInfo` entity contains information about a cache.
@@ -878,6 +977,59 @@
|`name` |capability name
|=================================
+[[contact-store-info]]
+=== ContactStoreInfo
+The `ContactStoreInfo` entity contains information about the contact
+store.
+
+[options="header",cols="1,6"]
+|=======================
+|Field Name |Description
+|`url` |
+The link:config-gerrit.html#contactstore.url[URL of the contact store].
+|=======================
+
+[[download-info]]
+=== DownloadInfo
+The `DownloadInfo` entity contains information about supported download
+options.
+
+[options="header",cols="1,6"]
+|=======================
+|Field Name |Description
+|`schemes` |
+The supported download schemes as a map which maps the scheme name to a
+of link:#download-scheme-info[DownloadSchemeInfo] entity.
+|`archives` |
+List of supported archive formats. Possible values are `tgz`, `tar`,
+`tbz2` and `txz`.
+|=======================
+
+[[download-scheme-info]]
+=== DownloadSchemeInfo
+The `DownloadSchemeInfo` entity contains information about a supported
+download scheme and its commands.
+
+[options="header",cols="1,^1,5"]
+|=================================
+|Field Name ||Description
+|`url` ||
+The URL of the download scheme, where '${project}' is used as
+placeholder for the project name.
+|`is_auth_required` |not set if `false`|
+Whether this download scheme requires authentication.
+|`is_auth_supported` |not set if `false`|
+Whether this download scheme supports authentication.
+|`commands` ||
+Download commands as a map which maps the command name to the download
+command. In the download command '${project}' is used as
+placeholder for the project name, and '${ref}' is used as
+placeholder for the (change) ref.
+
+Empty, if accessed anonymously and the download scheme requires
+authentication.
+|=================================
+
[[entries-info]]
=== EntriesInfo
The `EntriesInfo` entity contains information about the entries in a
@@ -896,6 +1048,21 @@
`g`: gigabytes). Only set for disk caches.
|==================================
+[[gerrit-info]]
+=== GerritInfo
+The `GerritInfo` entity contains information about Gerrit
+configuration from the link:config-gerrit.html#gerrit[gerrit] section.
+
+[options="header",cols="1,6"]
+|================================
+|Field Name |Description
+|`all_projects_name` |
+Name of the link:config-gerrit.html#gerrit.allProjects[root project].
+|`all_users_name` |
+Name of the link:config-gerrit.html#gerrit.allUsers[project in which
+meta data of all users is stored].
+|================================
+
[[hit-ration-info]]
=== HitRatioInfo
The `HitRatioInfo` entity contains information about the hit ratio of a
@@ -958,6 +1125,30 @@
The number of open files.
|============================
+[[server-info]]
+=== ServerInfo
+The `ServerInfo` entity contains information about the configuration of
+the Gerrit server.
+
+[options="header",cols="1,^1,5"]
+|=======================================
+|Field Name ||Description
+|`auth` ||
+Information about the authentication configuration as
+link:#auth-info[AuthInfo] entity.
+|`contact_store` |optional|
+Information about the contact store configuration as
+link:#contact-store-info[ContactStoreInfo] entity.
+|`download` ||
+Information about the configured download options as
+link:#download-info[DownloadInfo] entity.
+information about Gerrit
+|`gerrit` ||
+Information about the configuration from the
+link:config-gerrit.html#gerrit[gerrit] section as link:#gerrit-info[
+GerritInfo] entity.
+|=======================================
+
[[summary-info]]
=== SummaryInfo
The `SummaryInfo` entity contains information about the current state
diff --git a/Documentation/rest-api-projects.txt b/Documentation/rest-api-projects.txt
index a909ab4..a25c7bb 100644
--- a/Documentation/rest-api-projects.txt
+++ b/Documentation/rest-api-projects.txt
@@ -2116,6 +2116,8 @@
|Field Name ||Description
|`show_progress` |`false` if not set|
Whether progress information should be shown.
+|`aggressive` |`false` if not set|
+Whether an aggressive garbage collection should be done.
|=============================
[[head-input]]
diff --git a/Documentation/user-inline-edit.txt b/Documentation/user-inline-edit.txt
index 5ad6b39..a89d0db 100644
--- a/Documentation/user-inline-edit.txt
+++ b/Documentation/user-inline-edit.txt
@@ -44,10 +44,9 @@
While in edit mode, it is possible to add new files to the change by clicking
the 'Add...' button at the top of the file list.
-Files can be removed from the change, or restored, by clicking the icon to the
-left of the file name. Reverting a file in the change is also supported and is
-achieved in two steps: remove file from the change and restore the file in the
-change.
+File changes can be reverted or files can be removed from the change or
+deleted files can be restored, by clicking the icons to the left of the file
+name.
To switch from edit mode back to review mode, click the 'Done Editing' button.
diff --git a/Documentation/user-named-queries.txt b/Documentation/user-named-queries.txt
new file mode 100644
index 0000000..0ddbbef
--- /dev/null
+++ b/Documentation/user-named-queries.txt
@@ -0,0 +1,32 @@
+= Gerrit Code Review - Named Queries
+
+[[user-named-queries]]
+== User Named Queries
+It is possible to define named queries on a user level. To do
+this, define the named queries in the `queries` file of
+the user's account ref in the `All-Users` project. The user's
+account ref is based on the user's account id which is an
+integer. The account refs are sharded by the last two digits
+(`+nn+`) in the refname, leading to refs of the format
+`+refs/users/nn/accountid+`. The user's queries file is a
+2 column tab delimited file. The left column represents the
+name of the query, and the right column represents the query
+expression represented by the name.
+
+Example queries file:
+
+----
+# Name Query
+#
+selfapproved owner:self label:code-review+2,user=self
+blocked label:code-review-2 OR label:verified-1
+# Note below how to reference your own named queries in other named queries
+ready label:code-review+2 label:verified+1 -query:blocked status:open
+----
+
+GERRIT
+------
+Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/user-search.txt b/Documentation/user-search.txt
index 3de45d2..ca29e44 100644
--- a/Documentation/user-search.txt
+++ b/Documentation/user-search.txt
@@ -99,6 +99,12 @@
+
Changes originally submitted by a user in 'GROUP'.
+[[query]]
+query:'NAME'::
++
+Changes which match the current user's query named 'NAME'
+(see link:user-named-queries.html[Named Queries]).
+
[[reviewer]]
reviewer:'USER', r:'USER'::
+
@@ -327,6 +333,19 @@
Valid relations are >=, >, <=, <, or no relation, which will match if the
number of lines is exactly equal.
+[[commentby]]
+commentby:'USER'::
++
+Changes containing a top-level or inline comment by 'USER'. The special
+case of `commentby:self` will find changes where the caller has
+commented.
+
+[[from]]
+from:'USER'::
++
+Changes containing a top-level or inline comment by 'USER', or owned by
+'USER'. Equivalent to `(owner:USER OR commentby:USER)`.
+
== Argument Quoting
diff --git a/ReleaseNotes/ReleaseNotes-2.12.txt b/ReleaseNotes/ReleaseNotes-2.12.txt
new file mode 100644
index 0000000..dfdcd37
--- /dev/null
+++ b/ReleaseNotes/ReleaseNotes-2.12.txt
@@ -0,0 +1,41 @@
+Release notes for Gerrit 2.12
+=============================
+
+
+Gerrit 2.12 is now available:
+
+link:https://gerrit-releases.storage.googleapis.com/gerrit-2.12.war[
+https://gerrit-releases.storage.googleapis.com/gerrit-2.12.war]
+
+Important Notes
+---------------
+
+
+*WARNING:* Upgrading to 2.12.x requires the server be first upgraded to 2.8 (or
+2.9) and then to 2.12.x. If you are upgrading from 2.8.x or later, you may ignore
+this warning and upgrade directly to 2.12.x.
+
+*WARNING:* When upgrading from version 2.8.4 or older with a site that uses
+Bouncy Castle Crypto, new versions of the libraries will be downloaded. The old
+libraries should be manually removed from site's `lib` folder to prevent the
+startup failure described in
+link:https://code.google.com/p/gerrit/issues/detail?id=3084[Issue 3084].
+
+
+Release Highlights
+------------------
+
+* TODO
+
+
+New Features
+------------
+
+* TODO
+
+
+Upgrades
+--------
+
+* Upgrade gson to 2.3.1
+
diff --git a/VERSION b/VERSION
index 9791ceb..83d3d2a 100644
--- a/VERSION
+++ b/VERSION
@@ -2,4 +2,4 @@
# Used by :api_install and :api_deploy targets
# when talking to the destination repository.
#
-GERRIT_VERSION = '2.11.1'
+GERRIT_VERSION = '2.12-SNAPSHOT'
diff --git a/gerrit-acceptance-tests/BUCK b/gerrit-acceptance-tests/BUCK
index c7bea4e..b6a7b29 100644
--- a/gerrit-acceptance-tests/BUCK
+++ b/gerrit-acceptance-tests/BUCK
@@ -28,12 +28,14 @@
'//lib:servlet-api-3_1',
'//lib:truth',
+ '//lib/auto:auto-value',
'//lib/httpcomponents:httpclient',
'//lib/httpcomponents:httpcore',
'//lib/log:impl_log4j',
'//lib/log:log4j',
'//lib/guice:guice',
'//lib/guice:guice-assistedinject',
+ '//lib/guice:guice-servlet',
'//lib/jgit:jgit',
'//lib/jgit:junit',
'//lib/mina:sshd',
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
index ff61899..0b40891 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
@@ -14,32 +14,36 @@
package com.google.gerrit.acceptance;
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.GitUtil.cloneProject;
-import static com.google.gerrit.acceptance.GitUtil.createProject;
import static com.google.gerrit.acceptance.GitUtil.initSsh;
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
import static com.google.gerrit.server.project.Util.block;
-import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
+import com.google.common.base.Strings;
+import com.google.common.collect.Sets;
import com.google.common.primitives.Chars;
import com.google.gerrit.acceptance.AcceptanceTestRequestScope.Context;
import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.Permission;
import com.google.gerrit.common.data.PermissionRule;
import com.google.gerrit.extensions.api.GerritApi;
+import com.google.gerrit.extensions.api.changes.ReviewInput;
import com.google.gerrit.extensions.api.changes.RevisionApi;
+import com.google.gerrit.extensions.api.projects.ProjectInput;
import com.google.gerrit.extensions.client.ListChangesOption;
+import com.google.gerrit.extensions.common.ActionInfo;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.EditInfo;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.AnonymousUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.OutputFormat;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.config.AllProjectsName;
+import com.google.gerrit.server.config.CanonicalWebUrl;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MetaDataUpdate;
@@ -56,12 +60,16 @@
import com.google.inject.Provider;
import com.google.inject.util.Providers;
-import org.apache.http.HttpStatus;
import org.eclipse.jgit.api.Git;
-import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
+import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
+import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.Transport;
+import org.junit.AfterClass;
import org.junit.Rule;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
@@ -69,16 +77,23 @@
import org.junit.runners.model.Statement;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.EnumSet;
import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
@RunWith(ConfigSuite.class)
public abstract class AbstractDaemonTest {
+ private static GerritServer commonServer;
+
@ConfigSuite.Parameter
public Config baseConfig;
+ @ConfigSuite.Name
+ private String configName;
+
@Inject
protected AllProjectsName allProjects;
@@ -92,7 +107,7 @@
protected GerritApi gApi;
@Inject
- private AcceptanceTestRequestScope atrScope;
+ protected AcceptanceTestRequestScope atrScope;
@Inject
private IdentifiedUser.GenericFactory identifiedUserFactory;
@@ -119,9 +134,20 @@
protected Provider<InternalChangeQuery> queryProvider;
@Inject
- protected @GerritServerConfig Config cfg;
+ @CanonicalWebUrl
+ protected Provider<String> canonicalWebUrl;
- protected Git git;
+ @Inject
+ @GerritServerConfig
+ protected Config cfg;
+
+ @Inject
+ private InProcessProtocol inProcessProtocol;
+
+ @Inject
+ private Provider<AnonymousUser> anonymousUser;
+
+ protected TestRepository<InMemoryRepository> testRepo;
protected GerritServer server;
protected TestAccount admin;
protected TestAccount user;
@@ -131,6 +157,9 @@
protected ReviewDb db;
protected Project.NameKey project;
+ private String resourcePrefix;
+ private List<Repository> toClose;
+
@Rule
public TestRule testRunner = new TestRule() {
@Override
@@ -138,30 +167,24 @@
return new Statement() {
@Override
public void evaluate() throws Throwable {
- boolean mem = description.getAnnotation(UseLocalDisk.class) == null;
- boolean enableHttpd = description.getAnnotation(NoHttpd.class) == null
- && description.getTestClass().getAnnotation(NoHttpd.class) == null;
- beforeTest(config(description), mem, enableHttpd);
- base.evaluate();
- afterTest();
+ beforeTest(description);
+ try {
+ base.evaluate();
+ } finally {
+ afterTest();
+ }
}
};
}
};
- private Config config(Description description) {
- GerritConfigs cfgs = description.getAnnotation(GerritConfigs.class);
- GerritConfig cfg = description.getAnnotation(GerritConfig.class);
- if (cfgs != null && cfg != null) {
- throw new IllegalStateException("Use either @GerritConfigs or @GerritConfig not both");
+ @AfterClass
+ public static void stopCommonServer() throws Exception {
+ if (commonServer != null) {
+ commonServer.stop();
+ commonServer = null;
}
- if (cfgs != null) {
- return ConfigAnnotationParser.parse(baseConfig, cfgs);
- } else if (cfg != null) {
- return ConfigAnnotationParser.parse(baseConfig, cfg);
- } else {
- return baseConfig;
- }
+ TempFileUtil.cleanup();
}
protected static Config submitWholeTopicEnabledConfig() {
@@ -184,9 +207,24 @@
return cfg.getBoolean("change", null, "submitWholeTopic", false);
}
- private void beforeTest(Config cfg, boolean memory, boolean enableHttpd) throws Exception {
- server = startServer(cfg, memory, enableHttpd);
+ private void beforeTest(Description description) throws Exception {
+ GerritServer.Description classDesc =
+ GerritServer.Description.forTestClass(description, configName);
+ GerritServer.Description methodDesc =
+ GerritServer.Description.forTestMethod(description, configName);
+
+ if (classDesc.equals(methodDesc)) {
+ if (commonServer == null) {
+ commonServer = GerritServer.start(classDesc, baseConfig);
+ }
+ server = commonServer;
+ } else {
+ server = GerritServer.start(methodDesc, baseConfig);
+ }
+
server.getTestInjector().injectMembers(this);
+ Transport.register(inProcessProtocol);
+ toClose = Collections.synchronizedList(new ArrayList<Repository>());
admin = accounts.admin();
user = accounts.user();
adminSession = new RestSession(server, admin);
@@ -196,56 +234,167 @@
Context ctx = newRequestContext(admin);
atrScope.set(ctx);
sshSession = ctx.getSession();
- project = new Project.NameKey("p");
- createProject(sshSession, project.get());
- git = cloneProject(sshSession.getUrl() + "/" + project.get());
+ sshSession.open();
+ resourcePrefix = UNSAFE_PROJECT_NAME.matcher(
+ description.getClassName() + "_"
+ + description.getMethodName() + "_").replaceAll("");
+
+ project = createProject(projectInput(description));
+ testRepo = cloneProject(project, getCloneAsAccount(description));
}
- protected GerritServer startServer(Config cfg, boolean memory,
- boolean enableHttpd) throws Exception {
- return GerritServer.start(cfg, memory, enableHttpd);
+ private TestAccount getCloneAsAccount(Description description) {
+ TestProjectInput ann = description.getAnnotation(TestProjectInput.class);
+ return accounts.get(ann != null ? ann.cloneAs() : "admin");
+ }
+
+ private ProjectInput projectInput(Description description) {
+ ProjectInput in = new ProjectInput();
+ TestProjectInput ann = description.getAnnotation(TestProjectInput.class);
+ in.name = name("project");
+ if (ann != null) {
+ in.parent = Strings.emptyToNull(ann.parent());
+ in.description = Strings.emptyToNull(ann.description());
+ in.createEmptyCommit = ann.createEmptyCommit();
+ in.submitType = ann.submitType();
+ in.useContentMerge = ann.useContributorAgreements();
+ in.useSignedOffBy = ann.useSignedOffBy();
+ in.useContentMerge = ann.useContentMerge();
+ } else {
+ // Defaults should match TestProjectConfig, omitting nullable values.
+ in.createEmptyCommit = true;
+ }
+ updateProjectInput(in);
+ return in;
+ }
+
+ private static final Pattern UNSAFE_PROJECT_NAME =
+ Pattern.compile("[^a-zA-Z0-9._/-]+");
+
+ protected Git git() {
+ return testRepo.git();
+ }
+
+ protected InMemoryRepository repo() {
+ return testRepo.getRepository();
+ }
+
+ /**
+ * Return a resource name scoped to this test method.
+ * <p>
+ * Test methods in a single class by default share a running server. For any
+ * resource name you require to be unique to a test method, wrap it in a call
+ * to this method.
+ *
+ * @param name resource name (group, project, topic, etc.)
+ * @return name prefixed by a string unique to this test method.
+ */
+ protected String name(String name) {
+ return resourcePrefix + name;
+ }
+
+ protected Project.NameKey createProject(String nameSuffix)
+ throws RestApiException {
+ return createProject(nameSuffix, null);
+ }
+
+ protected Project.NameKey createProject(String nameSuffix,
+ Project.NameKey parent) throws RestApiException {
+ // Default for createEmptyCommit should match TestProjectConfig.
+ return createProject(nameSuffix, parent, true);
+ }
+
+ protected Project.NameKey createProject(String nameSuffix,
+ Project.NameKey parent, boolean createEmptyCommit)
+ throws RestApiException {
+ ProjectInput in = new ProjectInput();
+ in.name = name(nameSuffix);
+ in.parent = parent != null ? parent.get() : null;
+ in.createEmptyCommit = createEmptyCommit;
+ return createProject(in);
+ }
+
+ private Project.NameKey createProject(ProjectInput in)
+ throws RestApiException {
+ gApi.projects().create(in);
+ return new Project.NameKey(in.name);
+ }
+
+ /**
+ * Modify a project input before creating the initial test project.
+ *
+ * @param in input; may be modified in place.
+ */
+ protected void updateProjectInput(ProjectInput in) {
+ // Default implementation does nothing.
+ }
+
+ protected TestRepository<InMemoryRepository> cloneProject(Project.NameKey p)
+ throws Exception {
+ return cloneProject(p, admin);
+ }
+
+ protected TestRepository<InMemoryRepository> cloneProject(Project.NameKey p,
+ TestAccount testAccount) throws Exception {
+ InProcessProtocol.Context ctx = new InProcessProtocol.Context(
+ reviewDbProvider, identifiedUserFactory, testAccount.getId(), p);
+ Repository repo = repoManager.openRepository(p);
+ toClose.add(repo);
+ return GitUtil.cloneProject(
+ p, inProcessProtocol.register(ctx, repo).toString());
}
private void afterTest() throws Exception {
+ Transport.unregister(inProcessProtocol);
+ for (Repository repo : toClose) {
+ repo.close();
+ }
db.close();
sshSession.close();
- server.stop();
- TempFileUtil.cleanup();
+ if (server != commonServer) {
+ server.stop();
+ }
}
- protected PushOneCommit.Result createChange() throws GitAPIException,
- IOException {
- PushOneCommit push = pushFactory.create(db, admin.getIdent());
- return push.to(git, "refs/for/master");
+ protected TestRepository<?>.CommitBuilder commitBuilder() throws Exception {
+ return testRepo.branch("HEAD").commit().insertChangeId();
+ }
+
+ protected TestRepository<?>.CommitBuilder amendBuilder() throws Exception {
+ ObjectId head = repo().getRef("HEAD").getObjectId();
+ TestRepository<?>.CommitBuilder b = testRepo.amendRef("HEAD");
+ Optional<String> id = GitUtil.getChangeId(testRepo, head);
+ // TestRepository behaves like "git commit --amend -m foo", which does not
+ // preserve an existing Change-Id. Tests probably want this.
+ if (id.isPresent()) {
+ b.insertChangeId(id.get().substring(1));
+ } else {
+ b.insertChangeId();
+ }
+ return b;
+ }
+
+ protected PushOneCommit.Result createChange() throws Exception {
+ PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo);
+ PushOneCommit.Result result = push.to("refs/for/master");
+ result.assertOkStatus();
+ return result;
}
private static final List<Character> RANDOM =
Chars.asList(new char[]{'a','b','c','d','e','f','g','h'});
protected PushOneCommit.Result amendChange(String changeId)
- throws GitAPIException, IOException {
+ throws Exception {
return amendChange(changeId, "refs/for/master");
}
protected PushOneCommit.Result amendChange(String changeId, String ref)
- throws GitAPIException, IOException {
+ throws Exception {
Collections.shuffle(RANDOM);
PushOneCommit push =
- pushFactory.create(db, admin.getIdent(), PushOneCommit.SUBJECT,
+ pushFactory.create(db, admin.getIdent(), testRepo, PushOneCommit.SUBJECT,
PushOneCommit.FILE_NAME, new String(Chars.toArray(RANDOM)), changeId);
- return push.to(git, ref);
- }
-
- protected ChangeInfo getChange(String changeId, ListChangesOption... options)
- throws IOException {
- return getChange(adminSession, changeId, options);
- }
-
- protected ChangeInfo getChange(RestSession session, String changeId,
- ListChangesOption... options) throws IOException {
- String q = options.length > 0 ? "?o=" + Joiner.on("&o=").join(options) : "";
- RestResponse r = session.get("/changes/" + changeId + q);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- return newGson().fromJson(r.getReader(), ChangeInfo.class);
+ return push.to(ref);
}
protected ChangeInfo info(String id)
@@ -265,9 +414,8 @@
protected ChangeInfo get(String id, ListChangesOption... options)
throws RestApiException {
- EnumSet<ListChangesOption> s = EnumSet.noneOf(ListChangesOption.class);
- s.addAll(Arrays.asList(options));
- return gApi.changes().id(id).get(s);
+ return gApi.changes().id(id).get(
+ Sets.newEnumSet(Arrays.asList(options), ListChangesOption.class));
}
protected List<ChangeInfo> query(String q) throws RestApiException {
@@ -283,6 +431,10 @@
return atrScope.set(newRequestContext(account));
}
+ protected Context setApiUserAnonymous() {
+ return atrScope.newContext(reviewDbProvider, null, anonymousUser.get());
+ }
+
protected static Gson newGson() {
return OutputFormat.JSON_COMPACT.newGson();
}
@@ -300,10 +452,31 @@
saveProjectConfig(project, cfg);
}
- protected void allowGlobalCapability(String capabilityName,
- AccountGroup.UUID id) throws Exception {
+ protected void allowGlobalCapabilities(AccountGroup.UUID id,
+ String... capabilityNames) throws Exception {
+ allowGlobalCapabilities(id, Arrays.asList(capabilityNames));
+ }
+
+ protected void allowGlobalCapabilities(AccountGroup.UUID id,
+ Iterable<String> capabilityNames) throws Exception {
ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig();
- Util.allow(cfg, capabilityName, id);
+ for (String capabilityName : capabilityNames) {
+ Util.allow(cfg, capabilityName, id);
+ }
+ saveProjectConfig(allProjects, cfg);
+ }
+
+ protected void removeGlobalCapabilities(AccountGroup.UUID id,
+ String... capabilityNames) throws Exception {
+ removeGlobalCapabilities(id, Arrays.asList(capabilityNames));
+ }
+
+ protected void removeGlobalCapabilities(AccountGroup.UUID id,
+ Iterable<String> capabilityNames) throws Exception {
+ ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig();
+ for (String capabilityName : capabilityNames) {
+ Util.remove(cfg, capabilityName, id);
+ }
saveProjectConfig(allProjects, cfg);
}
@@ -352,9 +525,22 @@
saveProjectConfig(project, cfg);
}
- protected PushOneCommit.Result pushTo(String ref) throws GitAPIException,
- IOException {
- PushOneCommit push = pushFactory.create(db, admin.getIdent());
- return push.to(git, ref);
+ protected PushOneCommit.Result pushTo(String ref) throws Exception {
+ PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo);
+ return push.to(ref);
+ }
+
+ protected void approve(String id) throws Exception {
+ gApi.changes()
+ .id(id)
+ .revision("current")
+ .review(ReviewInput.approve());
+ }
+
+ protected Map<String, ActionInfo> getActions(String id) throws Exception {
+ return gApi.changes()
+ .id(id)
+ .revision(1)
+ .actions();
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AcceptanceTestRequestScope.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AcceptanceTestRequestScope.java
index 2a578c2..0ff4709 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AcceptanceTestRequestScope.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AcceptanceTestRequestScope.java
@@ -41,7 +41,7 @@
private static final Key<RequestScopedReviewDbProvider> DB_KEY =
Key.get(RequestScopedReviewDbProvider.class);
- public class Context implements RequestContext {
+ public static class Context implements RequestContext {
private final RequestCleanup cleanup = new RequestCleanup();
private final Map<Key<?>, Object> map = Maps.newHashMap();
private final SchemaFactory<ReviewDb> schemaFactory;
@@ -162,6 +162,21 @@
return old;
}
+ public Context disableDb() {
+ Context old = current.get();
+ SchemaFactory<ReviewDb> sf = new SchemaFactory<ReviewDb>() {
+ @Override
+ public ReviewDb open() {
+ return new DisabledReviewDb();
+ }
+ };
+ Context ctx = new Context(sf, old.session, old.user, old.created);
+
+ current.set(ctx);
+ local.setContext(ctx);
+ return old;
+ }
+
/** Returns exactly one instance per command executed. */
static final Scope REQUEST = new Scope() {
@Override
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AccountCreator.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AccountCreator.java
index a376332..f247463 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AccountCreator.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AccountCreator.java
@@ -14,6 +14,8 @@
package com.google.gerrit.acceptance;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountExternalId;
@@ -28,6 +30,7 @@
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.SchemaFactory;
import com.google.inject.Inject;
+import com.google.inject.Singleton;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
@@ -36,8 +39,12 @@
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+@Singleton
public class AccountCreator {
+ private final Map<String, TestAccount> accounts;
private SchemaFactory<ReviewDb> reviewDbProvider;
private GroupCache groupCache;
@@ -49,6 +56,7 @@
AccountCreator(SchemaFactory<ReviewDb> schema, GroupCache groupCache,
SshKeyCache sshKeyCache, AccountCache accountCache,
AccountByEmailCache byEmailCache) {
+ accounts = new HashMap<>();
reviewDbProvider = schema;
this.groupCache = groupCache;
this.sshKeyCache = sshKeyCache;
@@ -56,9 +64,13 @@
this.byEmailCache = byEmailCache;
}
- public TestAccount create(String username, String email, String fullName,
- String... groups)
+ public synchronized TestAccount create(String username, String email,
+ String fullName, String... groups)
throws OrmException, UnsupportedEncodingException, JSchException {
+ TestAccount account = accounts.get(username);
+ if (account != null) {
+ return account;
+ }
ReviewDb db = reviewDbProvider.open();
try {
Account.Id id = new Account.Id(db.nextAccountId());
@@ -99,7 +111,10 @@
accountCache.evictByUsername(username);
byEmailCache.evict(email);
- return new TestAccount(id, username, email, fullName, sshKey, httpPass);
+ account =
+ new TestAccount(id, username, email, fullName, sshKey, httpPass);
+ accounts.put(username, account);
+ return account;
} finally {
db.close();
}
@@ -137,6 +152,12 @@
return create("user2", "user2@example.com", "User2");
}
+ public TestAccount get(String username) {
+ return checkNotNull(
+ accounts.get(username),
+ "No TestAccount created for %s", username);
+ }
+
private AccountExternalId.Key getEmailKey(String email) {
return new AccountExternalId.Key(AccountExternalId.SCHEME_MAILTO, email);
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ConfigAnnotationParser.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ConfigAnnotationParser.java
index 07d0f50..b07ed30 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ConfigAnnotationParser.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ConfigAnnotationParser.java
@@ -15,11 +15,13 @@
package com.google.gerrit.acceptance;
import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import org.eclipse.jgit.lib.Config;
import java.util.ArrayList;
+import java.util.Arrays;
class ConfigAnnotationParser {
private static Splitter splitter = Splitter.on(".").trimResults();
@@ -45,9 +47,19 @@
private static void parseAnnotation(Config cfg, GerritConfig c) {
ArrayList<String> l = Lists.newArrayList(splitter.split(c.name()));
if (l.size() == 2) {
- cfg.setString(l.get(0), null, l.get(1), c.value());
+ if (!Strings.isNullOrEmpty(c.value())) {
+ cfg.setString(l.get(0), null, l.get(1), c.value());
+ } else {
+ String[] values = c.values();
+ cfg.setStringList(l.get(0), null, l.get(1), Arrays.asList(values));
+ }
} else if (l.size() == 3) {
- cfg.setString(l.get(0), l.get(1), l.get(2), c.value());
+ if (!Strings.isNullOrEmpty(c.value())) {
+ cfg.setString(l.get(0), l.get(1), l.get(2), c.value());
+ } else {
+ cfg.setStringList(l.get(0), l.get(1), l.get(2),
+ Arrays.asList(c.value()));
+ }
} else {
throw new IllegalArgumentException(
"GerritConfig.name must be of the format"
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/DisabledReviewDb.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/DisabledReviewDb.java
new file mode 100644
index 0000000..44d3d7f
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/DisabledReviewDb.java
@@ -0,0 +1,206 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.acceptance;
+
+import com.google.gerrit.reviewdb.server.AccountAccess;
+import com.google.gerrit.reviewdb.server.AccountDiffPreferenceAccess;
+import com.google.gerrit.reviewdb.server.AccountExternalIdAccess;
+import com.google.gerrit.reviewdb.server.AccountGroupAccess;
+import com.google.gerrit.reviewdb.server.AccountGroupByIdAccess;
+import com.google.gerrit.reviewdb.server.AccountGroupByIdAudAccess;
+import com.google.gerrit.reviewdb.server.AccountGroupMemberAccess;
+import com.google.gerrit.reviewdb.server.AccountGroupMemberAuditAccess;
+import com.google.gerrit.reviewdb.server.AccountGroupNameAccess;
+import com.google.gerrit.reviewdb.server.AccountPatchReviewAccess;
+import com.google.gerrit.reviewdb.server.AccountProjectWatchAccess;
+import com.google.gerrit.reviewdb.server.AccountSshKeyAccess;
+import com.google.gerrit.reviewdb.server.ChangeAccess;
+import com.google.gerrit.reviewdb.server.ChangeMessageAccess;
+import com.google.gerrit.reviewdb.server.PatchLineCommentAccess;
+import com.google.gerrit.reviewdb.server.PatchSetAccess;
+import com.google.gerrit.reviewdb.server.PatchSetAncestorAccess;
+import com.google.gerrit.reviewdb.server.PatchSetApprovalAccess;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.reviewdb.server.SchemaVersionAccess;
+import com.google.gerrit.reviewdb.server.StarredChangeAccess;
+import com.google.gerrit.reviewdb.server.SubmoduleSubscriptionAccess;
+import com.google.gerrit.reviewdb.server.SystemConfigAccess;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.StatementExecutor;
+
+/** ReviewDb that is disabled for testing. */
+class DisabledReviewDb implements ReviewDb {
+ private static final String MESSAGE = "ReviewDb is disabled for this test";
+
+ @Override
+ public void close() {
+ // Do nothing.
+ }
+
+ @Override
+ public void commit() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public void rollback() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public void updateSchema(StatementExecutor e) {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public void pruneSchema(StatementExecutor e) {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public Access<?, ?>[] allRelations() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public SchemaVersionAccess schemaVersion() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public SystemConfigAccess systemConfig() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public AccountAccess accounts() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public AccountExternalIdAccess accountExternalIds() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public AccountSshKeyAccess accountSshKeys() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public AccountGroupAccess accountGroups() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public AccountGroupNameAccess accountGroupNames() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public AccountGroupMemberAccess accountGroupMembers() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public AccountGroupMemberAuditAccess accountGroupMembersAudit() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public AccountDiffPreferenceAccess accountDiffPreferences() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public StarredChangeAccess starredChanges() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public AccountProjectWatchAccess accountProjectWatches() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public AccountPatchReviewAccess accountPatchReviews() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public ChangeAccess changes() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public PatchSetApprovalAccess patchSetApprovals() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public ChangeMessageAccess changeMessages() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public PatchSetAccess patchSets() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public PatchSetAncestorAccess patchSetAncestors() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public PatchLineCommentAccess patchComments() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public SubmoduleSubscriptionAccess submoduleSubscriptions() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public AccountGroupByIdAccess accountGroupById() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public AccountGroupByIdAudAccess accountGroupByIdAud() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public int nextAccountId() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public int nextAccountGroupId() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public int nextChangeId() {
+ throw new AssertionError(MESSAGE);
+ }
+
+ @Override
+ public int nextChangeMessageId() {
+ throw new AssertionError(MESSAGE);
+ }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritConfig.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritConfig.java
index 5cb1229..4b956a2 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritConfig.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritConfig.java
@@ -24,5 +24,6 @@
@Retention(RUNTIME)
public @interface GerritConfig {
String name();
- String value();
+ String value() default "";
+ String[] values() default "";
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritServer.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritServer.java
index 3be8195..a721221 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritServer.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritServer.java
@@ -14,15 +14,22 @@
package com.google.gerrit.acceptance;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
+import com.google.gerrit.common.Nullable;
import com.google.gerrit.lucene.LuceneIndexModule;
import com.google.gerrit.pgm.Daemon;
import com.google.gerrit.pgm.Init;
import com.google.gerrit.server.config.FactoryModule;
import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.git.AsyncReceiveCommits;
+import com.google.gerrit.server.git.SubmoduleOp;
import com.google.gerrit.server.index.ChangeSchemas;
+import com.google.gerrit.server.ssh.NoSshModule;
import com.google.gerrit.server.util.SocketUtil;
import com.google.gerrit.server.util.SystemLog;
+import com.google.gerrit.testutil.FakeEmailSender;
import com.google.gerrit.testutil.TempFileUtil;
import com.google.inject.Injector;
import com.google.inject.Key;
@@ -47,10 +54,55 @@
import java.util.concurrent.TimeUnit;
public class GerritServer {
+ @AutoValue
+ abstract static class Description {
+ static Description forTestClass(org.junit.runner.Description testDesc,
+ String configName) {
+ return new AutoValue_GerritServer_Description(
+ configName,
+ true, // @UseLocalDisk is only valid on methods.
+ testDesc.getTestClass().getAnnotation(NoHttpd.class) == null,
+ null, // @GerritConfig is only valid on methods.
+ null); // @GerritConfigs is only valid on methods.
+
+ }
+
+ static Description forTestMethod(org.junit.runner.Description testDesc,
+ String configName) {
+ return new AutoValue_GerritServer_Description(
+ configName,
+ testDesc.getAnnotation(UseLocalDisk.class) == null,
+ testDesc.getAnnotation(NoHttpd.class) == null
+ && testDesc.getTestClass().getAnnotation(NoHttpd.class) == null,
+ testDesc.getAnnotation(GerritConfig.class),
+ testDesc.getAnnotation(GerritConfigs.class));
+ }
+
+ @Nullable abstract String configName();
+ abstract boolean memory();
+ abstract boolean httpd();
+ @Nullable abstract GerritConfig config();
+ @Nullable abstract GerritConfigs configs();
+
+ private Config buildConfig(Config baseConfig) {
+ if (configs() != null && config() != null) {
+ throw new IllegalStateException(
+ "Use either @GerritConfigs or @GerritConfig not both");
+ }
+ if (configs() != null) {
+ return ConfigAnnotationParser.parse(baseConfig, configs());
+ } else if (config() != null) {
+ return ConfigAnnotationParser.parse(baseConfig, config());
+ } else {
+ return baseConfig;
+ }
+ }
+ }
/** Returns fully started Gerrit server */
- static GerritServer start(Config cfg, boolean memory, boolean enableHttpd)
+ static GerritServer start(Description desc, Config baseConfig)
throws Exception {
+ Config cfg = desc.buildConfig(baseConfig);
Logger.getLogger("com.google.gerrit").setLevel(Level.DEBUG);
final CyclicBarrier serverStarted = new CyclicBarrier(2);
final Daemon daemon = new Daemon(new Runnable() {
@@ -65,10 +117,11 @@
}
}
});
+ daemon.setEmailModuleForTesting(new FakeEmailSender.Module());
final File site;
ExecutorService daemonService = null;
- if (memory) {
+ if (desc.memory()) {
site = null;
mergeTestConfig(cfg);
// Set the log4j configuration to an invalid one to prevent system logs
@@ -78,10 +131,9 @@
cfg.setBoolean("sshd", null, "requestLog", false);
cfg.setBoolean("index", "lucene", "testInmemory", true);
cfg.setString("gitweb", null, "cgi", "");
- daemon.setEnableHttpd(enableHttpd);
+ daemon.setEnableHttpd(desc.httpd());
daemon.setLuceneModule(new LuceneIndexModule(
- ChangeSchemas.getLatest().getVersion(),
- Runtime.getRuntime().availableProcessors(), null));
+ ChangeSchemas.getLatest().getVersion(), 0, null));
daemon.setDatabaseForTesting(ImmutableList.<Module>of(
new InMemoryTestingDatabaseModule(cfg)));
daemon.start();
@@ -105,7 +157,7 @@
}
Injector i = createTestInjector(daemon);
- return new GerritServer(i, daemon, daemonService);
+ return new GerritServer(desc, i, daemon, daemonService);
}
private static File initSite(Config base) throws Exception {
@@ -138,9 +190,15 @@
cfg.setBoolean("sshd", null, "testUseInsecureRandom", true);
cfg.setString("cache", null, "directory", null);
cfg.setString("gerrit", null, "basePath", "git");
- cfg.setBoolean("sendemail", null, "enable", false);
+ cfg.setBoolean("sendemail", null, "enable", true);
+ cfg.setInt("sendemail", null, "threadPoolSize", 0);
cfg.setInt("cache", "projects", "checkFrequency", 0);
cfg.setInt("plugins", null, "checkFrequency", 0);
+
+ cfg.setInt("sshd", null, "threads", 1);
+ cfg.setInt("sshd", null, "commandStartThreads", 1);
+ cfg.setInt("receive", null, "threadPoolSize", 1);
+ cfg.setInt("index", null, "threads", 1);
}
private static Injector createTestInjector(Daemon daemon) throws Exception {
@@ -150,6 +208,10 @@
protected void configure() {
bind(AccountCreator.class);
factory(PushOneCommit.Factory.class);
+ factory(SubmoduleOp.Factory.class);
+ install(InProcessProtocol.module());
+ install(new NoSshModule());
+ install(new AsyncReceiveCommits.Module());
}
};
return sysInjector.createChildInjector(module);
@@ -167,6 +229,8 @@
return InetAddress.getLoopbackAddress();
}
+ private final Description desc;
+
private Daemon daemon;
private ExecutorService daemonService;
private Injector testInjector;
@@ -174,8 +238,9 @@
private InetSocketAddress sshdAddress;
private InetSocketAddress httpAddress;
- private GerritServer(Injector testInjector, Daemon daemon,
+ private GerritServer(Description desc, Injector testInjector, Daemon daemon,
ExecutorService daemonService) {
+ this.desc = desc;
this.testInjector = testInjector;
this.daemon = daemon;
this.daemonService = daemonService;
@@ -207,6 +272,10 @@
return testInjector;
}
+ Description getDescription() {
+ return desc;
+ }
+
void stop() throws Exception {
daemon.getLifecycleManager().stop();
if (daemonService != null) {
@@ -216,4 +285,9 @@
}
RepositoryCache.clear();
}
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this).addValue(desc).toString();
+ }
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GitUtil.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GitUtil.java
index dee36ef..e8f8925 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GitUtil.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GitUtil.java
@@ -14,46 +14,43 @@
package com.google.gerrit.acceptance;
-import static com.google.common.base.Preconditions.checkState;
-
+import com.google.common.base.Optional;
import com.google.common.collect.Iterables;
+import com.google.common.primitives.Ints;
import com.google.gerrit.common.FooterConstants;
import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.testutil.TempFileUtil;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
-import org.eclipse.jgit.api.AddCommand;
-import org.eclipse.jgit.api.CheckoutCommand;
-import org.eclipse.jgit.api.CloneCommand;
-import org.eclipse.jgit.api.CommitCommand;
import org.eclipse.jgit.api.FetchCommand;
-import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.PushCommand;
import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
+import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.transport.FetchResult;
import org.eclipse.jgit.transport.JschConfigSessionFactory;
import org.eclipse.jgit.transport.OpenSshConfig.Host;
import org.eclipse.jgit.transport.PushResult;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.SshSessionFactory;
-import org.eclipse.jgit.util.ChangeIdUtil;
import org.eclipse.jgit.util.FS;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
public class GitUtil {
+ private static final AtomicInteger testRepoCount = new AtomicInteger();
+ private static final int TEST_REPO_WINDOW_DAYS = 2;
public static void initSsh(final TestAccount a) {
final Properties config = new Properties();
@@ -77,131 +74,75 @@
});
}
- public static void createProject(SshSession s, String name)
- throws JSchException, IOException {
- createProject(s, name, null);
+ /**
+ * Create a new {@link TestRepository} with a distinct commit clock.
+ * <p>
+ * It is very easy for tests to create commits with identical subjects and
+ * trees; if such commits also have identical authors/committers, then the
+ * computed Change-Id is identical as well. Tests may generally assume that
+ * Change-Ids are unique, so to ensure this, we provision TestRepository
+ * instances with non-overlapping commit clock times.
+ * <p>
+ * Space test repos 1 day apart, which allows for about 86k ticks per repo
+ * before overlapping, and about 8k instances per process before hitting
+ * JGit's year 2038 limit.
+ *
+ * @param repo repository to wrap.
+ * @return wrapped test repository with distinct commit time space.
+ */
+ public static <R extends Repository> TestRepository<R> newTestRepository(
+ R repo) throws IOException {
+ TestRepository<R> tr = new TestRepository<>(repo);
+ tr.tick(Ints.checkedCast(TimeUnit.SECONDS.convert(
+ testRepoCount.getAndIncrement() * TEST_REPO_WINDOW_DAYS,
+ TimeUnit.DAYS)));
+ return tr;
}
- public static void createProject(SshSession s, String name, Project.NameKey parent)
- throws JSchException, IOException {
- createProject(s, name, parent, true);
- }
-
- public static void createProject(SshSession s, String name,
- Project.NameKey parent, boolean emptyCommit)
- throws JSchException, IOException {
- StringBuilder b = new StringBuilder();
- b.append("gerrit create-project");
- if (emptyCommit) {
- b.append(" --empty-commit");
+ public static TestRepository<InMemoryRepository> cloneProject(
+ Project.NameKey project, String uri) throws Exception {
+ DfsRepositoryDescription desc =
+ new DfsRepositoryDescription("clone of " + project.get());
+ InMemoryRepository dest = new InMemoryRepository.Builder()
+ .setRepositoryDescription(desc)
+ // SshTransport depends on a real FS to read ~/.ssh/config, but
+ // InMemoryRepository by default uses a null FS.
+ // TODO(dborowitz): Remove when we no longer depend on SSH.
+ .setFS(FS.detect())
+ .build();
+ Config cfg = dest.getConfig();
+ cfg.setString("remote", "origin", "url", uri);
+ cfg.setString("remote", "origin", "fetch",
+ "+refs/heads/*:refs/remotes/origin/*");
+ TestRepository<InMemoryRepository> testRepo = newTestRepository(dest);
+ FetchResult result = testRepo.git().fetch().setRemote("origin").call();
+ String originMaster = "refs/remotes/origin/master";
+ if (result.getTrackingRefUpdate(originMaster) != null) {
+ testRepo.reset(originMaster);
}
- b.append(" --name \"");
- b.append(name);
- b.append("\"");
- if (parent != null) {
- b.append(" --parent \"");
- b.append(parent.get());
- b.append("\"");
- }
- s.exec(b.toString());
- if (s.hasError()) {
- throw new IllegalStateException(
- "gerrit create-project returned error: " + s.getError());
- }
+ return testRepo;
}
- public static Git cloneProject(String url) throws GitAPIException, IOException {
- return cloneProject(url, true);
+ public static TestRepository<InMemoryRepository> cloneProject(
+ Project.NameKey project, SshSession sshSession) throws Exception {
+ return cloneProject(project, sshSession.getUrl() + "/" + project.get());
}
- public static Git cloneProject(String url, boolean checkout) throws GitAPIException, IOException {
- final File gitDir = TempFileUtil.createTempDirectory();
- final CloneCommand cloneCmd = Git.cloneRepository();
- cloneCmd.setURI(url);
- cloneCmd.setDirectory(gitDir);
- cloneCmd.setNoCheckout(!checkout);
- return cloneCmd.call();
- }
-
- public static void add(Git git, String path, String content)
- throws GitAPIException, IOException {
- File f = new File(git.getRepository().getDirectory().getParentFile(), path);
- File p = f.getParentFile();
- if (!p.exists() && !p.mkdirs()) {
- throw new IOException("failed to create dir: " + p.getAbsolutePath());
- }
- FileOutputStream s = new FileOutputStream(f);
- BufferedWriter out = new BufferedWriter(
- new OutputStreamWriter(s, StandardCharsets.UTF_8));
- try {
- out.write(content);
- } finally {
- out.close();
- }
-
- final AddCommand addCmd = git.add();
- addCmd.addFilepattern(path);
- addCmd.call();
- }
-
- public static void rm(Git gApi, String path)
+ public static void fetch(TestRepository<?> testRepo, String spec)
throws GitAPIException {
- gApi.rm()
- .addFilepattern(path)
- .call();
- }
-
- public static Commit createCommit(Git git, PersonIdent i, String msg)
- throws GitAPIException {
- return createCommit(git, i, msg, null);
- }
-
- public static Commit amendCommit(Git git, PersonIdent i, String msg, String changeId)
- throws GitAPIException {
- msg = ChangeIdUtil.insertId(msg, ObjectId.fromString(changeId.substring(1)));
- return createCommit(git, i, msg, changeId);
- }
-
- private static Commit createCommit(Git git, PersonIdent i, String msg,
- String changeId) throws GitAPIException {
-
- final CommitCommand commitCmd = git.commit();
- commitCmd.setAmend(changeId != null);
- commitCmd.setAuthor(i);
- commitCmd.setCommitter(i);
- commitCmd.setMessage(msg);
- commitCmd.setInsertChangeId(changeId == null);
-
- RevCommit c = commitCmd.call();
-
- List<String> ids = c.getFooterLines(FooterConstants.CHANGE_ID);
- checkState(ids.size() >= 1,
- "No Change-Id found in new commit:\n%s", c.getFullMessage());
- changeId = ids.get(ids.size() - 1);
-
- return new Commit(c, changeId);
- }
-
- public static void fetch(Git git, String spec) throws GitAPIException {
- FetchCommand fetch = git.fetch();
+ FetchCommand fetch = testRepo.git().fetch();
fetch.setRefSpecs(new RefSpec(spec));
fetch.call();
}
- public static void checkout(Git git, String name) throws GitAPIException {
- CheckoutCommand checkout = git.checkout();
- checkout.setName(name);
- checkout.call();
+ public static PushResult pushHead(TestRepository<?> testRepo, String ref,
+ boolean pushTags) throws GitAPIException {
+ return pushHead(testRepo, ref, pushTags, false);
}
- public static PushResult pushHead(Git git, String ref, boolean pushTags)
- throws GitAPIException {
- return pushHead(git, ref, pushTags, false);
- }
-
- public static PushResult pushHead(Git git, String ref, boolean pushTags,
- boolean force) throws GitAPIException {
- PushCommand pushCmd = git.push();
+ public static PushResult pushHead(TestRepository<?> testRepo, String ref,
+ boolean pushTags, boolean force) throws GitAPIException {
+ PushCommand pushCmd = testRepo.git().push();
pushCmd.setForce(force);
pushCmd.setRefSpecs(new RefSpec("HEAD:" + ref));
if (pushTags) {
@@ -211,21 +152,14 @@
return Iterables.getOnlyElement(r);
}
- public static class Commit {
- private final RevCommit commit;
- private final String changeId;
-
- Commit(RevCommit commit, String changeId) {
- this.commit = commit;
- this.changeId = changeId;
+ public static Optional<String> getChangeId(TestRepository<?> tr, ObjectId id)
+ throws IOException {
+ RevCommit c = tr.getRevWalk().parseCommit(id);
+ tr.getRevWalk().parseBody(c);
+ List<String> ids = c.getFooterLines(FooterConstants.CHANGE_ID);
+ if (ids.isEmpty()) {
+ return Optional.absent();
}
-
- public RevCommit getCommit() {
- return commit;
- }
-
- public String getChangeId() {
- return changeId;
- }
+ return Optional.of(ids.get(ids.size() - 1));
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java
index 8548b5c..8f4c2d4 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java
@@ -43,7 +43,8 @@
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.eclipse.jgit.lib.Config;
-import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
class InMemoryTestingDatabaseModule extends LifecycleModule {
private final Config cfg;
@@ -58,9 +59,10 @@
.annotatedWith(GerritServerConfig.class)
.toInstance(cfg);
- bind(File.class)
+ // TODO(dborowitz): Use jimfs.
+ bind(Path.class)
.annotatedWith(SitePath.class)
- .toInstance(new File("UNIT_TEST_GERRIT_SITE"));
+ .toInstance(Paths.get("UNIT_TEST_GERRIT_SITE"));
bind(GitRepositoryManager.class)
.toInstance(new InMemoryRepositoryManager());
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/InProcessProtocol.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/InProcessProtocol.java
new file mode 100644
index 0000000..c02b9e5
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/InProcessProtocol.java
@@ -0,0 +1,352 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.acceptance;
+
+import com.google.common.collect.Lists;
+import com.google.gerrit.acceptance.InProcessProtocol.Context;
+import com.google.gerrit.common.data.Capable;
+import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.AccessPath;
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.RemotePeer;
+import com.google.gerrit.server.RequestCleanup;
+import com.google.gerrit.server.config.GerritRequestModule;
+import com.google.gerrit.server.config.RequestScopedReviewDbProvider;
+import com.google.gerrit.server.git.AsyncReceiveCommits;
+import com.google.gerrit.server.git.ChangeCache;
+import com.google.gerrit.server.git.ReceiveCommits;
+import com.google.gerrit.server.git.ReceivePackInitializer;
+import com.google.gerrit.server.git.TagCache;
+import com.google.gerrit.server.git.TransferConfig;
+import com.google.gerrit.server.git.VisibleRefFilter;
+import com.google.gerrit.server.git.validators.UploadValidators;
+import com.google.gerrit.server.project.NoSuchProjectException;
+import com.google.gerrit.server.project.ProjectControl;
+import com.google.gerrit.server.util.RequestContext;
+import com.google.gerrit.server.util.RequestScopePropagator;
+import com.google.gerrit.server.util.ThreadLocalRequestContext;
+import com.google.gerrit.server.util.ThreadLocalRequestScopePropagator;
+import com.google.gwtorm.server.SchemaFactory;
+import com.google.inject.AbstractModule;
+import com.google.inject.Inject;
+import com.google.inject.Key;
+import com.google.inject.Module;
+import com.google.inject.OutOfScopeException;
+import com.google.inject.Provider;
+import com.google.inject.Provides;
+import com.google.inject.Scope;
+import com.google.inject.servlet.RequestScoped;
+import com.google.inject.util.Providers;
+
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.PostReceiveHook;
+import org.eclipse.jgit.transport.PostReceiveHookChain;
+import org.eclipse.jgit.transport.PreUploadHook;
+import org.eclipse.jgit.transport.PreUploadHookChain;
+import org.eclipse.jgit.transport.ReceivePack;
+import org.eclipse.jgit.transport.TestProtocol;
+import org.eclipse.jgit.transport.UploadPack;
+import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
+import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
+import org.eclipse.jgit.transport.resolver.UploadPackFactory;
+
+import java.io.IOException;
+import java.net.SocketAddress;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+class InProcessProtocol extends TestProtocol<Context> {
+ static Module module() {
+ return new AbstractModule() {
+ @Override
+ public void configure() {
+ install(new GerritRequestModule());
+ bind(RequestScopePropagator.class).to(Propagator.class);
+ bindScope(RequestScoped.class, InProcessProtocol.REQUEST);
+ }
+
+ @Provides
+ @RemotePeer
+ SocketAddress getSocketAddress() {
+ // TODO(dborowitz): Could potentially fake this with thread ID or
+ // something.
+ throw new OutOfScopeException("No remote peer in acceptance tests");
+ }
+ };
+ }
+
+ private static final Scope REQUEST = new Scope() {
+ @Override
+ public <T> Provider<T> scope(final Key<T> key, final Provider<T> creator) {
+ return new Provider<T>() {
+ @Override
+ public T get() {
+ Context ctx = current.get();
+ if (ctx == null) {
+ throw new OutOfScopeException("Not in TestProtocol scope");
+ }
+ return ctx.get(key, creator);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s[%s]", creator, REQUEST);
+ }
+ };
+ }
+
+ @Override
+ public String toString() {
+ return "InProcessProtocol.REQUEST";
+ }
+ };
+
+ private static class Propagator
+ extends ThreadLocalRequestScopePropagator<Context> {
+ @Inject
+ Propagator(ThreadLocalRequestContext local,
+ Provider<RequestScopedReviewDbProvider> dbProviderProvider) {
+ super(REQUEST, current, local, dbProviderProvider);
+ }
+
+ @Override
+ protected Context continuingContext(Context ctx) {
+ return ctx.newContinuingContext();
+ }
+ }
+
+ private static final ThreadLocal<Context> current = new ThreadLocal<>();
+
+ // TODO(dborowitz): Merge this with AcceptanceTestRequestScope.
+ /**
+ * Multi-purpose session/context object.
+ * <p>
+ * Confusingly, Gerrit has two ideas of what a "context" object is:
+ * one for Guice {@link RequestScoped}, and one for its own simplified
+ * version of request scoping using {@link ThreadLocalRequestContext}.
+ * This class provides both, in essence just delegating the {@code
+ * ThreadLocalRequestContext} scoping to the Guice scoping mechanism.
+ * <p>
+ * It is also used as the session type for {@code UploadPackFactory} and
+ * {@code ReceivePackFactory}, since, after all, it encapsulates all the
+ * information about a single request.
+ */
+ static class Context implements RequestContext {
+ private static final Key<RequestScopedReviewDbProvider> DB_KEY =
+ Key.get(RequestScopedReviewDbProvider.class);
+ private static final Key<RequestCleanup> RC_KEY =
+ Key.get(RequestCleanup.class);
+ private static final Key<CurrentUser> USER_KEY = Key.get(CurrentUser.class);
+
+ private final SchemaFactory<ReviewDb> schemaFactory;
+ private final IdentifiedUser.GenericFactory userFactory;
+ private final Account.Id accountId;
+ private final Project.NameKey project;
+ private final RequestCleanup cleanup;
+ private final Map<Key<?>, Object> map;
+
+ Context(SchemaFactory<ReviewDb> schemaFactory,
+ IdentifiedUser.GenericFactory userFactory,
+ Account.Id accountId,
+ Project.NameKey project) {
+ this.schemaFactory = schemaFactory;
+ this.userFactory = userFactory;
+ this.accountId = accountId;
+ this.project = project;
+ map = new HashMap<>();
+ cleanup = new RequestCleanup();
+ map.put(DB_KEY,
+ new RequestScopedReviewDbProvider(
+ schemaFactory, Providers.of(cleanup)));
+ map.put(RC_KEY, cleanup);
+
+ IdentifiedUser user = userFactory.create(accountId);
+ user.setAccessPath(AccessPath.GIT);
+ map.put(USER_KEY, user);
+ }
+
+ private Context newContinuingContext() {
+ return new Context(schemaFactory, userFactory, accountId, project);
+ }
+
+ @Override
+ public CurrentUser getCurrentUser() {
+ return get(USER_KEY, null);
+ }
+
+ @Override
+ public Provider<ReviewDb> getReviewDbProvider() {
+ return get(DB_KEY, null);
+ }
+
+ private synchronized <T> T get(Key<T> key, Provider<T> creator) {
+ @SuppressWarnings("unchecked")
+ T t = (T) map.get(key);
+ if (t == null) {
+ t = creator.get();
+ map.put(key, t);
+ }
+ return t;
+ }
+ }
+
+ private static class Upload implements UploadPackFactory<Context> {
+ private final Provider<ReviewDb> dbProvider;
+ private final Provider<CurrentUser> userProvider;
+ private final TagCache tagCache;
+ private final ChangeCache changeCache;
+ private final ProjectControl.GenericFactory projectControlFactory;
+ private final TransferConfig transferConfig;
+ private final DynamicSet<PreUploadHook> preUploadHooks;
+ private final UploadValidators.Factory uploadValidatorsFactory;
+ private final ThreadLocalRequestContext threadContext;
+
+ @Inject
+ Upload(
+ Provider<ReviewDb> dbProvider,
+ Provider<CurrentUser> userProvider,
+ TagCache tagCache,
+ ChangeCache changeCache,
+ ProjectControl.GenericFactory projectControlFactory,
+ TransferConfig transferConfig,
+ DynamicSet<PreUploadHook> preUploadHooks,
+ UploadValidators.Factory uploadValidatorsFactory,
+ ThreadLocalRequestContext threadContext) {
+ this.dbProvider = dbProvider;
+ this.userProvider = userProvider;
+ this.tagCache = tagCache;
+ this.changeCache = changeCache;
+ this.projectControlFactory = projectControlFactory;
+ this.transferConfig = transferConfig;
+ this.preUploadHooks = preUploadHooks;
+ this.uploadValidatorsFactory = uploadValidatorsFactory;
+ this.threadContext = threadContext;
+ }
+
+ @Override
+ public UploadPack create(Context req, final Repository repo)
+ throws ServiceNotAuthorizedException {
+ // Set the request context, but don't bother unsetting, since we don't
+ // have an easy way to run code when this instance is done being used.
+ // Each operation is run in its own thread, so we don't need to recover
+ // its original context anyway.
+ threadContext.setContext(req);
+ current.set(req);
+ try {
+ ProjectControl ctl = projectControlFactory.controlFor(
+ req.project, userProvider.get());
+ if (!ctl.canRunUploadPack()) {
+ throw new ServiceNotAuthorizedException();
+ }
+
+ UploadPack up = new UploadPack(repo);
+ up.setPackConfig(transferConfig.getPackConfig());
+ up.setTimeout(transferConfig.getTimeout());
+
+ if (!ctl.allRefsAreVisible()) {
+ up.setAdvertiseRefsHook(new VisibleRefFilter(
+ tagCache, changeCache, repo, ctl, dbProvider.get(), true));
+ }
+ List<PreUploadHook> hooks = Lists.newArrayList(preUploadHooks);
+ hooks.add(uploadValidatorsFactory.create(
+ ctl.getProject(), repo, "localhost-test"));
+ up.setPreUploadHook(PreUploadHookChain.newChain(hooks));
+ return up;
+ } catch (NoSuchProjectException | IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private static class Receive implements ReceivePackFactory<Context> {
+ private final Provider<CurrentUser> userProvider;
+ private final ProjectControl.GenericFactory projectControlFactory;
+ private final AsyncReceiveCommits.Factory factory;
+ private final TransferConfig config;
+ private final DynamicSet<ReceivePackInitializer> receivePackInitializers;
+ private final DynamicSet<PostReceiveHook> postReceiveHooks;
+ private final ThreadLocalRequestContext threadContext;
+
+ @Inject
+ Receive(
+ Provider<CurrentUser> userProvider,
+ ProjectControl.GenericFactory projectControlFactory,
+ AsyncReceiveCommits.Factory factory,
+ TransferConfig config,
+ DynamicSet<ReceivePackInitializer> receivePackInitializers,
+ DynamicSet<PostReceiveHook> postReceiveHooks,
+ ThreadLocalRequestContext threadContext) {
+ this.userProvider = userProvider;
+ this.projectControlFactory = projectControlFactory;
+ this.factory = factory;
+ this.config = config;
+ this.receivePackInitializers = receivePackInitializers;
+ this.postReceiveHooks = postReceiveHooks;
+ this.threadContext = threadContext;
+ }
+
+ @Override
+ public ReceivePack create(final Context req, Repository db)
+ throws ServiceNotAuthorizedException {
+ // Set the request context, but don't bother unsetting, since we don't
+ // have an easy way to run code when this instance is done being used.
+ // Each operation is run in its own thread, so we don't need to recover
+ // its original context anyway.
+ threadContext.setContext(req);
+ current.set(req);
+ try {
+ ProjectControl ctl =
+ projectControlFactory.controlFor(req.project, userProvider.get());
+ if (!ctl.canRunReceivePack()) {
+ throw new ServiceNotAuthorizedException();
+ }
+
+ ReceiveCommits rc = factory.create(ctl, db).getReceiveCommits();
+ ReceivePack rp = rc.getReceivePack();
+
+ Capable r = rc.canUpload();
+ if (r != Capable.OK) {
+ throw new ServiceNotAuthorizedException();
+ }
+
+ IdentifiedUser user = (IdentifiedUser) ctl.getCurrentUser();
+ rp.setRefLogIdent(user.newRefLogIdent());
+ rp.setTimeout(config.getTimeout());
+ rp.setMaxObjectSizeLimit(config.getMaxObjectSizeLimit());
+
+ for (ReceivePackInitializer initializer : receivePackInitializers) {
+ initializer.init(ctl.getProject().getNameKey(), rp);
+ }
+
+ rp.setPostReceiveHook(PostReceiveHookChain.newChain(
+ Lists.newArrayList(postReceiveHooks)));
+ return rp;
+ } catch (NoSuchProjectException | IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ @Inject
+ InProcessProtocol(Upload uploadPackFactory,
+ Receive receivePackFactory) {
+ super(uploadPackFactory, receivePackFactory);
+ }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java
index 6cd8031..f2c51e1 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java
@@ -15,17 +15,11 @@
package com.google.gerrit.acceptance;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.GitUtil.add;
-import static com.google.gerrit.acceptance.GitUtil.amendCommit;
-import static com.google.gerrit.acceptance.GitUtil.createCommit;
import static com.google.gerrit.acceptance.GitUtil.pushHead;
-import com.google.common.base.Function;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
-import com.google.gerrit.acceptance.GitUtil.Commit;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Change;
@@ -40,12 +34,8 @@
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
-import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.TagCommand;
-import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
-import org.eclipse.jgit.api.errors.GitAPIException;
-import org.eclipse.jgit.api.errors.InvalidTagNameException;
-import org.eclipse.jgit.api.errors.NoHeadException;
+import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.revwalk.RevCommit;
@@ -53,10 +43,6 @@
import org.eclipse.jgit.transport.RemoteRefUpdate;
import org.eclipse.jgit.transport.RemoteRefUpdate.Status;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Set;
-
public class PushOneCommit {
public static final String SUBJECT = "test commit";
public static final String FILE_NAME = "a.txt";
@@ -65,11 +51,13 @@
public interface Factory {
PushOneCommit create(
ReviewDb db,
- PersonIdent i);
+ PersonIdent i,
+ TestRepository<?> testRepo);
PushOneCommit create(
ReviewDb db,
PersonIdent i,
+ TestRepository<?> testRepo,
@Assisted("subject") String subject,
@Assisted("fileName") String fileName,
@Assisted("content") String content);
@@ -77,6 +65,7 @@
PushOneCommit create(
ReviewDb db,
PersonIdent i,
+ TestRepository<?> testRepo,
@Assisted("subject") String subject,
@Assisted("fileName") String fileName,
@Assisted("content") String content,
@@ -106,7 +95,7 @@
private final ApprovalsUtil approvalsUtil;
private final Provider<InternalChangeQuery> queryProvider;
private final ReviewDb db;
- private final PersonIdent i;
+ private final TestRepository<?> testRepo;
private final String subject;
private final String fileName;
@@ -115,14 +104,17 @@
private Tag tag;
private boolean force;
+ private final TestRepository<?>.CommitBuilder commitBuilder;
+
@AssistedInject
PushOneCommit(ChangeNotes.Factory notesFactory,
ApprovalsUtil approvalsUtil,
Provider<InternalChangeQuery> queryProvider,
@Assisted ReviewDb db,
- @Assisted PersonIdent i) {
+ @Assisted PersonIdent i,
+ @Assisted TestRepository<?> testRepo) throws Exception {
this(notesFactory, approvalsUtil, queryProvider,
- db, i, SUBJECT, FILE_NAME, FILE_CONTENT);
+ db, i, testRepo, SUBJECT, FILE_NAME, FILE_CONTENT);
}
@AssistedInject
@@ -131,11 +123,12 @@
Provider<InternalChangeQuery> queryProvider,
@Assisted ReviewDb db,
@Assisted PersonIdent i,
+ @Assisted TestRepository<?> testRepo,
@Assisted("subject") String subject,
@Assisted("fileName") String fileName,
- @Assisted("content") String content) {
+ @Assisted("content") String content) throws Exception {
this(notesFactory, approvalsUtil, queryProvider,
- db, i, subject, fileName, content, null);
+ db, i, testRepo, subject, fileName, content, null);
}
@AssistedInject
@@ -144,42 +137,48 @@
Provider<InternalChangeQuery> queryProvider,
@Assisted ReviewDb db,
@Assisted PersonIdent i,
+ @Assisted TestRepository<?> testRepo,
@Assisted("subject") String subject,
@Assisted("fileName") String fileName,
@Assisted("content") String content,
- @Nullable @Assisted("changeId") String changeId) {
+ @Nullable @Assisted("changeId") String changeId) throws Exception {
this.db = db;
+ this.testRepo = testRepo;
this.notesFactory = notesFactory;
this.approvalsUtil = approvalsUtil;
this.queryProvider = queryProvider;
- this.i = i;
this.subject = subject;
this.fileName = fileName;
this.content = content;
this.changeId = changeId;
- }
-
- public Result to(Git git, String ref) throws GitAPIException, IOException {
- add(git, fileName, content);
- return execute(git, ref);
- }
-
- public Result rm(Git git, String ref) throws GitAPIException {
- GitUtil.rm(git, fileName);
- return execute(git, ref);
- }
-
- private Result execute(Git git, String ref) throws GitAPIException,
- ConcurrentRefUpdateException, InvalidTagNameException, NoHeadException {
- Commit c;
if (changeId != null) {
- c = amendCommit(git, i, subject, changeId);
+ commitBuilder = testRepo.amendRef("HEAD")
+ .insertChangeId(changeId.substring(1));
} else {
- c = createCommit(git, i, subject);
- changeId = c.getChangeId();
+ commitBuilder = testRepo.branch("HEAD").commit().insertChangeId();
+ }
+ commitBuilder.message(subject)
+ .author(i)
+ .committer(new PersonIdent(i, testRepo.getClock()));
+ }
+
+ public Result to(String ref) throws Exception {
+ commitBuilder.add(fileName, content);
+ return execute(ref);
+ }
+
+ public Result rm(String ref) throws Exception {
+ commitBuilder.rm(fileName);
+ return execute(ref);
+ }
+
+ private Result execute(String ref) throws Exception {
+ RevCommit c = commitBuilder.create();
+ if (changeId == null) {
+ changeId = GitUtil.getChangeId(testRepo, c).get();
}
if (tag != null) {
- TagCommand tagCommand = git.tag().setName(tag.name);
+ TagCommand tagCommand = testRepo.git().tag().setName(tag.name);
if (tag instanceof AnnotatedTag) {
AnnotatedTag annotatedTag = (AnnotatedTag)tag;
tagCommand.setAnnotated(true)
@@ -190,7 +189,8 @@
}
tagCommand.call();
}
- return new Result(ref, pushHead(git, ref, tag != null, force), c, subject);
+ return new Result(ref, pushHead(testRepo, ref, tag != null, force), c,
+ subject);
}
public void setTag(final Tag tag) {
@@ -204,10 +204,10 @@
public class Result {
private final String ref;
private final PushResult result;
- private final Commit commit;
+ private final RevCommit commit;
private final String resSubj;
- private Result(String ref, PushResult resSubj, Commit commit,
+ private Result(String ref, PushResult resSubj, RevCommit commit,
String subject) {
this.ref = ref;
this.result = resSubj;
@@ -217,7 +217,7 @@
public ChangeData getChange() throws OrmException {
return Iterables.getOnlyElement(
- queryProvider.get().byKeyPrefix(commit.getChangeId()));
+ queryProvider.get().byKeyPrefix(changeId));
}
public PatchSet getPatchSet() throws OrmException {
@@ -229,47 +229,33 @@
}
public String getChangeId() {
- return commit.getChangeId();
+ return changeId;
}
public ObjectId getCommitId() {
- return commit.getCommit().getId();
+ return commit;
}
public RevCommit getCommit() {
- return commit.getCommit();
+ return commit;
}
public void assertChange(Change.Status expectedStatus,
String expectedTopic, TestAccount... expectedReviewers)
throws OrmException {
Change c = getChange().change();
- assertThat(resSubj).isEqualTo(c.getSubject());
- assertThat(expectedStatus).isEqualTo(c.getStatus());
- assertThat(expectedTopic).isEqualTo(Strings.emptyToNull(c.getTopic()));
+ assertThat(c.getSubject()).isEqualTo(resSubj);
+ assertThat(c.getStatus()).isEqualTo(expectedStatus);
+ assertThat(Strings.emptyToNull(c.getTopic())).isEqualTo(expectedTopic);
assertReviewers(c, expectedReviewers);
}
private void assertReviewers(Change c, TestAccount... expectedReviewers)
throws OrmException {
- Set<Account.Id> expectedReviewerIds =
- Sets.newHashSet(Lists.transform(Arrays.asList(expectedReviewers),
- new Function<TestAccount, Account.Id>() {
- @Override
- public Account.Id apply(TestAccount a) {
- return a.id;
- }
- }));
-
- for (Account.Id accountId
- : approvalsUtil.getReviewers(db, notesFactory.create(c)).values()) {
- assertThat(expectedReviewerIds.remove(accountId))
- .named("unexpected reviewer " + accountId)
- .isTrue();
- }
- assertThat((Iterable<?>)expectedReviewerIds)
- .named("missing reviewers: " + expectedReviewerIds)
- .isEmpty();
+ Iterable<Account.Id> actualIds =
+ approvalsUtil.getReviewers(db, notesFactory.create(c)).values();
+ assertThat(actualIds).containsExactlyElementsIn(
+ Sets.newHashSet(TestAccount.ids(expectedReviewers)));
}
public void assertOkStatus() {
@@ -282,10 +268,10 @@
private void assertStatus(Status expectedStatus, String expectedMessage) {
RemoteRefUpdate refUpdate = result.getRemoteUpdate(ref);
- assertThat(expectedStatus)
+ assertThat(refUpdate.getStatus())
.named(message(refUpdate))
- .isEqualTo(refUpdate.getStatus());
- assertThat(expectedMessage).isEqualTo(refUpdate.getMessage());
+ .isEqualTo(expectedStatus);
+ assertThat(refUpdate.getMessage()).isEqualTo(expectedMessage);
}
public void assertMessage(String expectedMessage) {
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/RestSession.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/RestSession.java
index bf6f928..e06d31f 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/RestSession.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/RestSession.java
@@ -65,7 +65,20 @@
}
public RestResponse put(String endPoint, Object content) throws IOException {
+ return putWithHeader(endPoint, null, content);
+ }
+
+ public RestResponse putWithHeader(String endPoint, Header header)
+ throws IOException {
+ return putWithHeader(endPoint, header, null);
+ }
+
+ public RestResponse putWithHeader(String endPoint, Header header,
+ Object content) throws IOException {
HttpPut put = new HttpPut(url + "/a" + endPoint);
+ if (header != null) {
+ put.addHeader(header);
+ }
if (content != null) {
put.addHeader(new BasicHeader("Content-Type", "application/json"));
put.setEntity(new StringEntity(
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/SshSession.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/SshSession.java
index 701b337..794f832 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/SshSession.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/SshSession.java
@@ -42,11 +42,12 @@
}
@SuppressWarnings("resource")
- public String exec(String command) throws JSchException, IOException {
+ public String exec(String command, InputStream opt) throws JSchException,
+ IOException {
ChannelExec channel = (ChannelExec) getSession().openChannel("exec");
try {
channel.setCommand(command);
- channel.setInputStream(null);
+ channel.setInputStream(opt);
InputStream in = channel.getInputStream();
channel.connect();
@@ -60,6 +61,20 @@
}
}
+ public InputStream exec2(String command, InputStream opt) throws JSchException,
+ IOException {
+ ChannelExec channel = (ChannelExec) getSession().openChannel("exec");
+ channel.setCommand(command);
+ channel.setInputStream(opt);
+ InputStream in = channel.getInputStream();
+ channel.connect();
+ return in;
+ }
+
+ public String exec(String command) throws JSchException, IOException {
+ return exec(command, null);
+ }
+
public boolean hasError() {
return error != null;
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/TestAccount.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/TestAccount.java
index bd5f19f..e7b5834 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/TestAccount.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/TestAccount.java
@@ -14,6 +14,8 @@
package com.google.gerrit.acceptance;
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
import com.google.gerrit.reviewdb.client.Account;
import com.jcraft.jsch.KeyPair;
@@ -21,9 +23,38 @@
import org.eclipse.jgit.lib.PersonIdent;
import java.io.ByteArrayOutputStream;
-
+import java.util.Arrays;
public class TestAccount {
+ public static FluentIterable<Account.Id> ids(
+ Iterable<TestAccount> accounts) {
+ return FluentIterable.from(accounts)
+ .transform(new Function<TestAccount, Account.Id>() {
+ @Override
+ public Account.Id apply(TestAccount in) {
+ return in.id;
+ }
+ });
+ }
+
+ public static FluentIterable<Account.Id> ids(TestAccount... accounts) {
+ return ids(Arrays.asList(accounts));
+ }
+
+ public static FluentIterable<String> names(Iterable<TestAccount> accounts) {
+ return FluentIterable.from(accounts)
+ .transform(new Function<TestAccount, String>() {
+ @Override
+ public String apply(TestAccount in) {
+ return in.fullName;
+ }
+ });
+ }
+
+ public static FluentIterable<String> names(TestAccount... accounts) {
+ return names(Arrays.asList(accounts));
+ }
+
public final Account.Id id;
public final String username;
public final String email;
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/TestProjectInput.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/TestProjectInput.java
new file mode 100644
index 0000000..4ad37e2
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/TestProjectInput.java
@@ -0,0 +1,49 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.acceptance;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.google.gerrit.extensions.client.InheritableBoolean;
+import com.google.gerrit.extensions.client.SubmitType;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+@Target({METHOD})
+@Retention(RUNTIME)
+public @interface TestProjectInput {
+ // Fields from ProjectInput for creating the project.
+
+ String parent() default "";
+ boolean createEmptyCommit() default true;
+ String description() default "";
+
+ // These may be null in a ProjectInput, but annotations do not allow null
+ // default values. Thus these defaults should match ProjectConfig.
+ SubmitType submitType() default SubmitType.MERGE_IF_NECESSARY;
+ InheritableBoolean useContributorAgreements()
+ default InheritableBoolean.INHERIT;
+ InheritableBoolean useSignedOffBy() default InheritableBoolean.INHERIT;
+ InheritableBoolean useContentMerge() default InheritableBoolean.INHERIT;
+ InheritableBoolean requireChangeId() default InheritableBoolean.INHERIT;
+
+
+ // Fields specific to acceptance test behavior.
+
+ /** Username to use for initial clone, passed to {@link AccountCreator}. */
+ String cloneAs() default "admin";
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java
index 8945a22d..aaf6192 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java
@@ -22,6 +22,8 @@
import org.junit.Test;
+import java.util.List;
+
public class AccountIT extends AbstractDaemonTest {
@Test
@@ -49,14 +51,31 @@
@Test
public void starUnstarChange() throws Exception {
PushOneCommit.Result r = createChange();
- String triplet = "p~master~" + r.getChangeId();
+ String triplet = project.get() + "~master~" + r.getChangeId();
gApi.accounts()
.self()
.starChange(triplet);
- assertThat(getChange(triplet).starred).isTrue();
+ assertThat(info(triplet).starred).isTrue();
gApi.accounts()
.self()
.unstarChange(triplet);
- assertThat(getChange(triplet).starred).isNull();
+ assertThat(info(triplet).starred).isNull();
+ }
+
+ @Test
+ public void suggestAccounts() throws Exception {
+ String adminUsername = "admin";
+ List<AccountInfo> result = gApi.accounts()
+ .suggestAccounts().withQuery(adminUsername).get();
+ assertThat(result).hasSize(1);
+ assertThat(result.get(0).username).isEqualTo(adminUsername);
+
+ List<AccountInfo> resultShortcutApi = gApi.accounts()
+ .suggestAccounts(adminUsername).get();
+ assertThat(resultShortcutApi).hasSize(result.size());
+
+ List<AccountInfo> emptyResult = gApi.accounts()
+ .suggestAccounts("unknown").get();
+ assertThat(emptyResult).isEmpty();
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
index c13187f..9a58702 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -15,6 +15,11 @@
package com.google.gerrit.acceptance.api.change;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.acceptance.PushOneCommit.FILE_NAME;
+import static com.google.gerrit.acceptance.PushOneCommit.SUBJECT;
+import static com.google.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS;
+import static com.google.gerrit.server.project.Util.category;
+import static com.google.gerrit.server.project.Util.value;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
@@ -22,6 +27,8 @@
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.acceptance.PushOneCommit;
+import com.google.gerrit.common.data.LabelType;
+import com.google.gerrit.common.data.Permission;
import com.google.gerrit.extensions.api.changes.AddReviewerInput;
import com.google.gerrit.extensions.api.changes.RebaseInput;
import com.google.gerrit.extensions.api.changes.ReviewInput;
@@ -33,11 +40,17 @@
import com.google.gerrit.extensions.common.RevisionInfo;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.server.git.ProjectConfig;
+import com.google.gerrit.server.group.SystemGroupBackend;
+import com.google.gerrit.server.project.Util;
import org.eclipse.jgit.lib.Constants;
import org.junit.Test;
+import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
@@ -48,19 +61,19 @@
@Test
public void get() throws Exception {
PushOneCommit.Result r = createChange();
- String triplet = "p~master~" + r.getChangeId();
+ String triplet = project.get() + "~master~" + r.getChangeId();
ChangeInfo c = info(triplet);
assertThat(c.id).isEqualTo(triplet);
- assertThat(c.project).isEqualTo("p");
+ assertThat(c.project).isEqualTo(project.get());
assertThat(c.branch).isEqualTo("master");
assertThat(c.status).isEqualTo(ChangeStatus.NEW);
assertThat(c.subject).isEqualTo("test commit");
assertThat(c.mergeable).isTrue();
assertThat(c.changeId).isEqualTo(r.getChangeId());
assertThat(c.created).isEqualTo(c.updated);
- assertThat(c._number).is(1);
+ assertThat(c._number).isEqualTo(r.getChange().getId().get());
- assertThat(c.owner._accountId).is(admin.getId().get());
+ assertThat(c.owner._accountId).isEqualTo(admin.getId().get());
assertThat(c.owner.name).isNull();
assertThat(c.owner.email).isNull();
assertThat(c.owner.username).isNull();
@@ -126,7 +139,7 @@
.revision(r3.getCommit().name())
.rebase(ri);
PatchSet ps3 = r3.getPatchSet();
- assertThat(ps3.getId().get()).is(2);
+ assertThat(ps3.getId().get()).isEqualTo(2);
// rebase r2 onto r3 (referenced by ref)
ri.base = ps3.getId().toRefName();
@@ -135,7 +148,7 @@
.revision(r2.getCommit().name())
.rebase(ri);
PatchSet ps2 = r2.getPatchSet();
- assertThat(ps2.getId().get()).is(2);
+ assertThat(ps2.getId().get()).isEqualTo(2);
// rebase r1 onto r2 (referenced by commit)
ri.base = ps2.getRevision().get();
@@ -144,7 +157,7 @@
.revision(r1.getCommit().name())
.rebase(ri);
PatchSet ps1 = r1.getPatchSet();
- assertThat(ps1.getId().get()).is(2);
+ assertThat(ps1.getId().get()).isEqualTo(2);
// rebase r1 onto r3 (referenced by change number)
ri.base = String.valueOf(r3.getChange().getId().get());
@@ -152,7 +165,7 @@
.id(r1.getChangeId())
.revision(ps1.getRevision().get())
.rebase(ri);
- assertThat(r1.getPatchSetId().get()).is(3);
+ assertThat(r1.getPatchSetId().get()).isEqualTo(3);
}
@Test(expected = ResourceConflictException.class)
@@ -188,7 +201,7 @@
.id(r.getChangeId())
.addReviewer(in);
- assertThat((Iterable<?>)getReviewers(r.getChangeId()))
+ assertThat(getReviewers(r.getChangeId()))
.containsExactlyElementsIn(ImmutableSet.of(user.id));
}
@@ -204,7 +217,7 @@
.revision(r.getCommit().name())
.submit();
- assertThat((Iterable<?>)getReviewers(r.getChangeId()))
+ assertThat(getReviewers(r.getChangeId()))
.containsExactlyElementsIn(ImmutableSet.of(admin.getId()));
AddReviewerInput in = new AddReviewerInput();
@@ -212,7 +225,7 @@
gApi.changes()
.id(r.getChangeId())
.addReviewer(in);
- assertThat((Iterable<?>)getReviewers(r.getChangeId()))
+ assertThat(getReviewers(r.getChangeId()))
.containsExactlyElementsIn(ImmutableSet.of(admin.getId(), user.id));
}
@@ -233,38 +246,35 @@
@Test
public void queryChangesNoQuery() throws Exception {
- PushOneCommit.Result r1 = createChange();
- PushOneCommit.Result r2 = createChange();
+ PushOneCommit.Result r = createChange();
List<ChangeInfo> results = gApi.changes().query().get();
- assertThat(results).hasSize(2);
- assertThat(results.get(0).changeId).isEqualTo(r2.getChangeId());
- assertThat(results.get(1).changeId).isEqualTo(r1.getChangeId());
+ assertThat(results.size()).isAtLeast(1);
+ List<Integer> ids = new ArrayList<>(results.size());
+ for (int i = 0; i < results.size(); i++) {
+ ChangeInfo info = results.get(i);
+ if (i == 0) {
+ assertThat(info._number).isEqualTo(r.getChange().getId().get());
+ }
+ assertThat(Change.Status.forChangeStatus(info.status).isOpen()).isTrue();
+ ids.add(info._number);
+ }
+ assertThat(ids).contains(r.getChange().getId().get());
}
@Test
public void queryChangesNoResults() throws Exception {
createChange();
- List<ChangeInfo> results = query("status:open");
- assertThat(results).hasSize(1);
- results = query("status:closed");
- assertThat(results).isEmpty();
+ assertThat(query("message:test")).isNotEmpty();
+ assertThat(query("message:{" + getClass().getName() + "fhqwhgads}"))
+ .isEmpty();
}
@Test
- public void queryChangesOneTerm() throws Exception {
- PushOneCommit.Result r1 = createChange();
- PushOneCommit.Result r2 = createChange();
- List<ChangeInfo> results = query("status:open");
- assertThat(results).hasSize(2);
- assertThat(results.get(0).changeId).isEqualTo(r2.getChangeId());
- assertThat(results.get(1).changeId).isEqualTo(r1.getChangeId());
- }
-
- @Test
- public void queryChangesMultipleTerms() throws Exception {
+ public void queryChanges() throws Exception {
PushOneCommit.Result r1 = createChange();
createChange();
- List<ChangeInfo> results = query("status:open " + r1.getChangeId());
+ List<ChangeInfo> results =
+ query("project:{" + project.get() + "} " + r1.getChangeId());
assertThat(Iterables.getOnlyElement(results).changeId)
.isEqualTo(r1.getChangeId());
}
@@ -283,7 +293,8 @@
public void queryChangesStart() throws Exception {
PushOneCommit.Result r1 = createChange();
createChange();
- List<ChangeInfo> results = gApi.changes().query().withStart(1).get();
+ List<ChangeInfo> results = gApi.changes()
+ .query("project:{" + project.get() + "}").withStart(1).get();
assertThat(Iterables.getOnlyElement(results).changeId)
.isEqualTo(r1.getChangeId());
}
@@ -293,7 +304,7 @@
PushOneCommit.Result r = createChange();
ChangeInfo result = Iterables.getOnlyElement(query(r.getChangeId()));
assertThat(result.labels).isNull();
- assertThat((Iterable<?>)result.messages).isNull();
+ assertThat(result.messages).isNull();
assertThat(result.revisions).isNull();
assertThat(result.actions).isNull();
}
@@ -307,13 +318,13 @@
.get());
assertThat(Iterables.getOnlyElement(result.labels.keySet()))
.isEqualTo("Code-Review");
- assertThat((Iterable<?>)result.messages).hasSize(1);
+ assertThat(result.messages).hasSize(1);
assertThat(result.actions).isNotEmpty();
RevisionInfo rev = Iterables.getOnlyElement(result.revisions.values());
assertThat(rev._number).isEqualTo(r.getPatchSetId().get());
assertThat(rev.created).isNotNull();
- assertThat(rev.uploader._accountId).is(admin.getId().get());
+ assertThat(rev.uploader._accountId).isEqualTo(admin.getId().get());
assertThat(rev.ref).isEqualTo(r.getPatchSetId().toRefName());
assertThat(rev.actions).isNotEmpty();
}
@@ -321,7 +332,8 @@
@Test
public void queryChangesOwnerWithDifferentUsers() throws Exception {
PushOneCommit.Result r = createChange();
- assertThat(Iterables.getOnlyElement(query("owner:self")).changeId)
+ assertThat(Iterables.getOnlyElement(
+ query("project:{" + project.get() + "} owner:self")).changeId)
.isEqualTo(r.getChangeId());
setApiUser(user);
assertThat(query("owner:self")).isEmpty();
@@ -375,4 +387,86 @@
.get(EnumSet.of(ListChangesOption.CHECK))
.problems).isEmpty();
}
+
+ @Test
+ public void commitFooters() throws Exception {
+ LabelType verified = category("Verified",
+ value(1, "Failed"), value(0, "No score"), value(-1, "Passes"));
+ LabelType custom1 = category("Custom1",
+ value(1, "Positive"), value(0, "No score"), value(-1, "Negative"));
+ LabelType custom2 = category("Custom2",
+ value(1, "Positive"), value(0, "No score"), value(-1, "Negative"));
+ ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
+ cfg.getLabelSections().put(verified.getName(), verified);
+ cfg.getLabelSections().put(custom1.getName(), verified);
+ cfg.getLabelSections().put(custom2.getName(), verified);
+ String heads = "refs/heads/*";
+ AccountGroup.UUID anon =
+ SystemGroupBackend.getGroup(ANONYMOUS_USERS).getUUID();
+ Util.allow(cfg, Permission.forLabel("Verified"), -1, 1, anon, heads);
+ Util.allow(cfg, Permission.forLabel("Custom1"), -1, 1, anon, heads);
+ Util.allow(cfg, Permission.forLabel("Custom2"), -1, 1, anon, heads);
+ saveProjectConfig(project, cfg);
+
+ PushOneCommit.Result r1 = createChange();
+ r1.assertOkStatus();
+ PushOneCommit.Result r2 = pushFactory.create(
+ db, admin.getIdent(), testRepo, SUBJECT, FILE_NAME, "new content",
+ r1.getChangeId())
+ .to("refs/for/master");
+ r2.assertOkStatus();
+
+ ReviewInput in = new ReviewInput();
+ in.label("Code-Review", 1);
+ in.label("Verified", 1);
+ in.label("Custom1", -1);
+ in.label("Custom2", 1);
+ gApi.changes().id(r2.getChangeId()).current().review(in);
+
+ EnumSet<ListChangesOption> options = EnumSet.of(
+ ListChangesOption.ALL_REVISIONS, ListChangesOption.COMMIT_FOOTERS);
+ ChangeInfo actual = gApi.changes().id(r2.getChangeId()).get(options);
+ assertThat(actual.revisions).hasSize(2);
+
+ // No footers except on latest patch set.
+ assertThat(actual.revisions.get(r1.getCommit().getName()).commitWithFooters)
+ .isNull();
+
+ String expected = SUBJECT + "\n"
+ + "\n"
+ + "Change-Id: " + r2.getChangeId() + "\n"
+ + "Reviewed-on: "
+ + canonicalWebUrl.get() + r2.getChange().getId() + "\n"
+ + "Reviewed-by: Administrator <admin@example.com>\n"
+ + "Custom2: Administrator <admin@example.com>\n"
+ + "Tested-by: Administrator <admin@example.com>\n";
+ assertThat(actual.revisions.get(r2.getCommit().getName()).commitWithFooters)
+ .isEqualTo(expected);
+ }
+
+ @Test
+ public void defaultSearchDoesNotTouchDatabase() throws Exception {
+ PushOneCommit.Result r1 = createChange();
+ gApi.changes()
+ .id(r1.getChangeId())
+ .revision(r1.getCommit().name())
+ .review(ReviewInput.approve());
+ gApi.changes()
+ .id(r1.getChangeId())
+ .revision(r1.getCommit().name())
+ .submit();
+
+ createChange();
+
+ setApiUserAnonymous(); // Identified user may async get stars from DB.
+ atrScope.disableDb();
+ assertThat(gApi.changes().query()
+ .withQuery(
+ "project:{" + project.get() + "} (status:open OR status:closed)")
+ // Options should match defaults in ChangeTable.
+ .withOption(ListChangesOption.LABELS)
+ .withOption(ListChangesOption.DETAILED_ACCOUNTS)
+ .get())
+ .hasSize(2);
+ }
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/group/BUCK
similarity index 100%
rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/BUCK
rename to gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/group/BUCK
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/GroupAssert.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/group/GroupAssert.java
similarity index 94%
rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/GroupAssert.java
rename to gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/group/GroupAssert.java
index 97503f4..c3c2224 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/GroupAssert.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/group/GroupAssert.java
@@ -12,14 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.acceptance.rest.group;
+package com.google.gerrit.acceptance.api.group;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assert_;
+import com.google.gerrit.extensions.common.GroupInfo;
import com.google.gerrit.extensions.restapi.Url;
import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gerrit.server.group.GroupJson.GroupInfo;
import java.util.Set;
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/group/GroupsIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/group/GroupsIT.java
new file mode 100644
index 0000000..8ed4165
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/group/GroupsIT.java
@@ -0,0 +1,497 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.acceptance.api.group;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.acceptance.api.group.GroupAssert.assertGroupInfo;
+import static com.google.gerrit.acceptance.rest.account.AccountAssert.assertAccountInfos;
+
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Ordering;
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.NoHttpd;
+import com.google.gerrit.acceptance.TestAccount;
+import com.google.gerrit.common.Nullable;
+import com.google.gerrit.extensions.api.groups.GroupInput;
+import com.google.gerrit.extensions.common.AccountInfo;
+import com.google.gerrit.extensions.common.GroupInfo;
+import com.google.gerrit.extensions.common.GroupOptionsInfo;
+import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.ResourceConflictException;
+import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
+import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
+import com.google.gerrit.extensions.restapi.Url;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.server.group.SystemGroupBackend;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+@NoHttpd
+public class GroupsIT extends AbstractDaemonTest {
+ @Test
+ public void addToNonExistingGroup_NotFound() throws Exception {
+ try {
+ gApi.groups().id("non-existing").addMembers("admin");
+ } catch (ResourceNotFoundException expected) {
+ // Expected.
+ }
+ }
+
+ @Test
+ public void removeFromNonExistingGroup_NotFound() throws Exception {
+ try {
+ gApi.groups().id("non-existing").removeMembers("admin");
+ } catch (ResourceNotFoundException expected) {
+ // Expected.
+ }
+ }
+
+ @Test
+ public void addRemoveMember() throws Exception {
+ String g = createGroup("users");
+ gApi.groups().id(g).addMembers("user");
+ assertMembers(g, user);
+
+ gApi.groups().id(g).removeMembers("user");
+ assertNoMembers(g);
+ }
+
+ @Test
+ public void addExistingMember_OK() throws Exception {
+ String g = "Administrators";
+ assertMembers(g, admin);
+ gApi.groups().id("Administrators").addMembers("admin");
+ assertMembers(g, admin);
+ }
+
+ @Test
+ public void addMultipleMembers() throws Exception {
+ String g = createGroup("users");
+ TestAccount u1 = accounts.create("u1", "u1@example.com", "Full Name 1");
+ TestAccount u2 = accounts.create("u2", "u2@example.com", "Full Name 2");
+ gApi.groups().id(g).addMembers(u1.username, u2.username);
+ assertMembers(g, u1, u2);
+ }
+
+ @Test
+ public void includeRemoveGroup() throws Exception {
+ String p = createGroup("parent");
+ String g = createGroup("newGroup");
+ gApi.groups().id(p).addGroups(g);
+ assertIncludes(p, g);
+
+ gApi.groups().id(p).removeGroups(g);
+ assertNoIncludes(p);
+ }
+
+ @Test
+ public void includeExistingGroup_OK() throws Exception {
+ String p = createGroup("parent");
+ String g = createGroup("newGroup");
+ gApi.groups().id(p).addGroups(g);
+ assertIncludes(p, g);
+ gApi.groups().id(p).addGroups(g);
+ assertIncludes(p, g);
+ }
+
+ @Test
+ public void addMultipleIncludes() throws Exception {
+ String p = createGroup("parent");
+ String g1 = createGroup("newGroup1");
+ String g2 = createGroup("newGroup2");
+ List<String> groups = Lists.newLinkedList();
+ groups.add(g1);
+ groups.add(g2);
+ gApi.groups().id(p).addGroups(g1, g2);
+ assertIncludes(p, g1, g2);
+ }
+
+ @Test
+ public void testCreateGroup() throws Exception {
+ String newGroupName = name("newGroup");
+ GroupInfo g = gApi.groups().create(newGroupName).get();
+ assertGroupInfo(getFromCache(newGroupName), g);
+ }
+
+ @Test
+ public void testCreateGroupWithProperties() throws Exception {
+ GroupInput in = new GroupInput();
+ in.name = name("newGroup");
+ in.description = "Test description";
+ in.visibleToAll = true;
+ in.ownerId = getFromCache("Administrators").getGroupUUID().get();
+ GroupInfo g = gApi.groups().create(in).detail();
+ assertThat(g.description).isEqualTo(in.description);
+ assertThat(g.options.visibleToAll).isEqualTo(in.visibleToAll);
+ assertThat(g.ownerId).isEqualTo(in.ownerId);
+ }
+
+ @Test
+ public void testCreateGroupWithoutCapability_Forbidden() throws Exception {
+ setApiUser(user);
+ try {
+ gApi.groups().create(name("newGroup"));
+ } catch (AuthException expected) {
+ // Expected.
+ }
+ }
+
+ @Test
+ public void testCreateGroupWhenGroupAlreadyExists_Conflict()
+ throws Exception {
+ try {
+ gApi.groups().create("Administrators");
+ } catch (ResourceConflictException expected) {
+ // Expected.
+ }
+ }
+ @Test
+ public void testGetGroup() throws Exception {
+ AccountGroup adminGroup = groupCache.get(new AccountGroup.NameKey("Administrators"));
+ testGetGroup(adminGroup.getGroupUUID().get(), adminGroup);
+ testGetGroup(adminGroup.getName(), adminGroup);
+ testGetGroup(adminGroup.getId().get(), adminGroup);
+ }
+
+ private void testGetGroup(Object id, AccountGroup expectedGroup)
+ throws Exception {
+ GroupInfo group = gApi.groups().id(id.toString()).get();
+ assertGroupInfo(expectedGroup, group);
+ }
+
+ @Test
+ public void testGroupName() throws Exception {
+ String name = name("group");
+ gApi.groups().create(name);
+
+ // get name
+ assertThat(gApi.groups().id(name).name()).isEqualTo(name);
+
+ // set name with name conflict
+ String other = name("other");
+ gApi.groups().create(other);
+ try {
+ gApi.groups().id(name).name(other);
+ } catch (ResourceConflictException expected) {
+ // Expected.
+ }
+
+ // set name to same name
+ gApi.groups().id(name).name(name);
+ assertThat(gApi.groups().id(name).name()).isEqualTo(name);
+
+ // rename
+ String newName = name("newName");
+ gApi.groups().id(name).name(newName);
+ assertThat(getFromCache(newName)).isNotNull();
+ assertThat(gApi.groups().id(newName).name()).isEqualTo(newName);
+
+ assertThat(getFromCache(name)).isNull();
+ try {
+ gApi.groups().id(name).get();
+ } catch (ResourceNotFoundException expected) {
+ // Expceted.
+ }
+ }
+
+ @Test
+ public void testGroupDescription() throws Exception {
+ String name = name("group");
+ gApi.groups().create(name);
+
+ // get description
+ assertThat(gApi.groups().id(name).description()).isEmpty();
+
+ // set description
+ String desc = "New description for the group.";
+ gApi.groups().id(name).description(desc);
+ assertThat(gApi.groups().id(name).description()).isEqualTo(desc);
+
+ // set description to null
+ gApi.groups().id(name).description(null);
+ assertThat(gApi.groups().id(name).description()).isEmpty();
+
+ // set description to empty string
+ gApi.groups().id(name).description("");
+ assertThat(gApi.groups().id(name).description()).isEmpty();
+ }
+
+ @Test
+ public void testGroupOptions() throws Exception {
+ String name = name("group");
+ gApi.groups().create(name);
+
+ // get options
+ assertThat(gApi.groups().id(name).options().visibleToAll).isNull();
+
+ // set options
+ GroupOptionsInfo options = new GroupOptionsInfo();
+ options.visibleToAll = true;
+ gApi.groups().id(name).options(options);
+ assertThat(gApi.groups().id(name).options().visibleToAll).isTrue();
+ }
+
+ @Test
+ public void testGroupOwner() throws Exception {
+ String name = name("group");
+ GroupInfo info = gApi.groups().create(name).get();
+ String adminUUID = getFromCache("Administrators").getGroupUUID().get();
+ String registeredUUID = SystemGroupBackend.REGISTERED_USERS.get();
+
+ // get owner
+ assertThat(Url.decode(gApi.groups().id(name).owner().id))
+ .isEqualTo(info.id);
+
+ // set owner by name
+ gApi.groups().id(name).owner("Registered Users");
+ assertThat(Url.decode(gApi.groups().id(name).owner().id))
+ .isEqualTo(registeredUUID);
+
+ // set owner by UUID
+ gApi.groups().id(name).owner(adminUUID);
+ assertThat(Url.decode(gApi.groups().id(name).owner().id))
+ .isEqualTo(adminUUID);
+
+ // set non existing owner
+ try {
+ gApi.groups().id(name).owner("Non-Existing Group");
+ } catch (UnprocessableEntityException expected) {
+ // Expected.
+ }
+ }
+
+ @Test
+ public void listNonExistingGroupIncludes_NotFound() throws Exception {
+ try {
+ gApi.groups().id("non-existing").includedGroups();
+ } catch (ResourceNotFoundException expected) {
+ // Expected.
+ }
+ }
+
+ @Test
+ public void listEmptyGroupIncludes() throws Exception {
+ String gx = createGroup("gx");
+ assertThat(gApi.groups().id(gx).includedGroups()).isEmpty();
+ }
+
+ @Test
+ public void includeNonExistingGroup() throws Exception {
+ String gx = createGroup("gx");
+ try {
+ gApi.groups().id(gx).addGroups("non-existing");
+ } catch (UnprocessableEntityException expecetd) {
+ // Expected.
+ }
+ }
+
+ @Test
+ public void listNonEmptyGroupIncludes() throws Exception {
+ String gx = createGroup("gx");
+ String gy = createGroup("gy");
+ String gz = createGroup("gz");
+ gApi.groups().id(gx).addGroups(gy);
+ gApi.groups().id(gx).addGroups(gz);
+ assertIncludes(gApi.groups().id(gx).includedGroups(), gy, gz);
+ }
+
+ @Test
+ public void listOneIncludeMember() throws Exception {
+ String gx = createGroup("gx");
+ String gy = createGroup("gy");
+ gApi.groups().id(gx).addGroups(gy);
+ assertIncludes(gApi.groups().id(gx).includedGroups(), gy);
+ }
+
+ @Test
+ public void listNonExistingGroupMembers_NotFound() throws Exception {
+ try {
+ gApi.groups().id("non-existing").members();
+ } catch (ResourceNotFoundException expected) {
+ // Expected.
+ }
+ }
+
+ @Test
+ public void listEmptyGroupMembers() throws Exception {
+ String group = createGroup("empty");
+ assertThat(gApi.groups().id(group).members()).isEmpty();
+ }
+
+ @Test
+ public void listNonEmptyGroupMembers() throws Exception {
+ String group = createGroup("group");
+ String user1 = createAccount("user1", group);
+ String user2 = createAccount("user2", group);
+ assertMembers(gApi.groups().id(group).members(), user1, user2);
+ }
+
+ @Test
+ public void listOneGroupMember() throws Exception {
+ String group = createGroup("group");
+ String user = createAccount("user1", group);
+ assertMembers(gApi.groups().id(group).members(), user);
+ }
+
+ @Test
+ public void listGroupMembersRecursively() throws Exception {
+ String gx = createGroup("gx");
+ String ux = createAccount("ux", gx);
+
+ String gy = createGroup("gy");
+ String uy = createAccount("uy", gy);
+
+ String gz = createGroup("gz");
+ String uz = createAccount("uz", gz);
+
+ gApi.groups().id(gx).addGroups(gy);
+ gApi.groups().id(gy).addGroups(gz);
+ assertMembers(gApi.groups().id(gx).members(), ux);
+ assertMembers(gApi.groups().id(gx).members(true), ux, uy, uz);
+ }
+
+ @Test
+ public void defaultGroupsCreated() throws Exception {
+ Iterable<String> names = gApi.groups().list().getAsMap().keySet();
+ assertThat(names).containsAllOf("Administrators", "Non-Interactive Users")
+ .inOrder();
+ }
+
+ @Test
+ public void testListAllGroups() throws Exception {
+ List<String> expectedGroups = FluentIterable
+ .from(groupCache.all())
+ .transform(new Function<AccountGroup, String>() {
+ @Override
+ public String apply(AccountGroup group) {
+ return group.getName();
+ }
+ }).toSortedList(Ordering.natural());
+ assertThat(expectedGroups.size()).isAtLeast(2);
+ assertThat(gApi.groups().list().getAsMap().keySet())
+ .containsExactlyElementsIn(expectedGroups).inOrder();
+ }
+
+ @Test
+ public void testOnlyVisibleGroupsReturned() throws Exception {
+ String newGroupName = name("newGroup");
+ GroupInput in = new GroupInput();
+ in.name = newGroupName;
+ in.description = "a hidden group";
+ in.visibleToAll = false;
+ in.ownerId = getFromCache("Administrators").getGroupUUID().get();
+ gApi.groups().create(in);
+
+ setApiUser(user);
+ assertThat(gApi.groups().list().getAsMap())
+ .doesNotContainKey(newGroupName);
+
+ setApiUser(admin);
+ gApi.groups().id(newGroupName).addMembers(user.username);
+
+ setApiUser(user);
+ assertThat(gApi.groups().list().getAsMap()).containsKey(newGroupName);
+ }
+
+ @Test
+ public void testAllGroupInfoFieldsSetCorrectly() throws Exception {
+ AccountGroup adminGroup = getFromCache("Administrators");
+ Map<String, GroupInfo> groups =
+ gApi.groups().list().addGroup(adminGroup.getName()).getAsMap();
+ assertThat(groups).hasSize(1);
+ assertThat(groups).containsKey("Administrators");
+ assertGroupInfo(adminGroup, Iterables.getOnlyElement(groups.values()));
+ }
+
+ private void assertMembers(String group, TestAccount... expectedMembers)
+ throws Exception {
+ assertMembers(
+ gApi.groups().id(group).members(),
+ TestAccount.names(expectedMembers).toArray(String.class));
+ assertAccountInfos(
+ Arrays.asList(expectedMembers),
+ gApi.groups().id(group).members());
+ }
+
+ private void assertMembers(Iterable<AccountInfo> members,
+ String... expectedNames) {
+ Iterable<String> memberNames = Iterables.transform(members,
+ new Function<AccountInfo, String>() {
+ @Override
+ public String apply(@Nullable AccountInfo info) {
+ return info.name;
+ }
+ });
+ assertThat(memberNames)
+ .containsExactlyElementsIn(Arrays.asList(expectedNames)).inOrder();
+ }
+
+ private void assertNoMembers(String group) throws Exception {
+ assertThat(gApi.groups().id(group).members().isEmpty());
+ }
+
+ private void assertIncludes(String group, String... expectedNames)
+ throws Exception {
+ assertIncludes(gApi.groups().id(group).includedGroups(), expectedNames);
+ }
+
+ private static void assertIncludes(
+ Iterable<GroupInfo> includes, String... expectedNames) {
+ Iterable<String> includeNames = Iterables.transform(
+ includes,
+ new Function<GroupInfo, String>() {
+ @Override
+ public String apply(@Nullable GroupInfo info) {
+ return info.name;
+ }
+ });
+ assertThat(includeNames)
+ .containsExactlyElementsIn(Arrays.asList(expectedNames)).inOrder();
+ }
+
+ private void assertNoIncludes(String group) throws Exception {
+ assertThat(gApi.groups().id(group).includedGroups().isEmpty());
+ }
+
+ private AccountGroup getFromCache(String name) throws Exception {
+ return groupCache.get(new AccountGroup.NameKey(name));
+ }
+
+ private String createGroup(String name) throws Exception {
+ return createGroup(name, "Administrators");
+ }
+
+ private String createGroup(String name, String owner) throws Exception {
+ name = name(name);
+ GroupInput in = new GroupInput();
+ in.name = name;
+ in.ownerId = owner;
+ gApi.groups().create(in);
+ return name;
+ }
+
+ private String createAccount(String name, String group) throws Exception {
+ name = name(name);
+ accounts.create(name, group);
+ return name;
+ }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/project/ProjectIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/project/ProjectIT.java
index 7de4712..9ae95b5 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/project/ProjectIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/project/ProjectIT.java
@@ -22,35 +22,31 @@
import com.google.gerrit.common.data.Permission;
import com.google.gerrit.extensions.api.projects.BranchInput;
import com.google.gerrit.extensions.api.projects.ProjectInput;
-import com.google.gerrit.extensions.common.ProjectInfo;
+import com.google.gerrit.extensions.api.projects.PutDescriptionInput;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.RestApiException;
import org.junit.Test;
-import java.util.List;
-
@NoHttpd
public class ProjectIT extends AbstractDaemonTest {
@Test
public void createProjectFoo() throws Exception {
- String name = "foo";
+ String name = name("foo");
assertThat(name).isEqualTo(
gApi.projects()
- .name(name)
- .create()
+ .create(name)
.get()
.name);
}
@Test
public void createProjectFooWithGitSuffix() throws Exception {
- String name = "foo";
+ String name = name("foo");
assertThat(name).isEqualTo(
gApi.projects()
- .name(name + ".git")
- .create()
+ .create(name + ".git")
.get()
.name);
}
@@ -58,7 +54,7 @@
@Test(expected = RestApiException.class)
public void createProjectFooBar() throws Exception {
ProjectInput in = new ProjectInput();
- in.name = "foo";
+ in.name = name("foo");
gApi.projects()
.name("bar")
.create(in);
@@ -67,12 +63,10 @@
@Test(expected = ResourceConflictException.class)
public void createProjectDuplicate() throws Exception {
ProjectInput in = new ProjectInput();
- in.name = "baz";
+ in.name = name("baz");
gApi.projects()
- .name("baz")
.create(in);
gApi.projects()
- .name("baz")
.create(in);
}
@@ -86,43 +80,19 @@
}
@Test
- public void listProjects() throws Exception {
- List<ProjectInfo> initialProjects = gApi.projects().list().get();
-
- gApi.projects().name("foo").create();
- gApi.projects().name("bar").create();
-
- List<ProjectInfo> allProjects = gApi.projects().list().get();
- assertThat(allProjects).hasSize(initialProjects.size() + 2);
-
- List<ProjectInfo> projectsWithDescription = gApi.projects().list()
- .withDescription(true)
- .get();
- assertThat(projectsWithDescription.get(0).description).isNotNull();
-
- List<ProjectInfo> projectsWithoutDescription = gApi.projects().list()
- .withDescription(false)
- .get();
- assertThat(projectsWithoutDescription.get(0).description).isNull();
-
- List<ProjectInfo> noMatchingProjects = gApi.projects().list()
- .withPrefix("fox")
- .get();
- assertThat(noMatchingProjects).isEmpty();
-
- List<ProjectInfo> matchingProject = gApi.projects().list()
- .withPrefix("fo")
- .get();
- assertThat(matchingProject).hasSize(1);
-
- List<ProjectInfo> limitOneProject = gApi.projects().list()
- .withLimit(1)
- .get();
- assertThat(limitOneProject).hasSize(1);
-
- List<ProjectInfo> startAtOneProjects = gApi.projects().list()
- .withStart(1)
- .get();
- assertThat(startAtOneProjects).hasSize(allProjects.size() - 1);
+ public void description() throws Exception {
+ assertThat(gApi.projects()
+ .name(project.get())
+ .description())
+ .isEmpty();
+ PutDescriptionInput in = new PutDescriptionInput();
+ in.description = "new project description";
+ gApi.projects()
+ .name(project.get())
+ .description(in);
+ assertThat(gApi.projects()
+ .name(project.get())
+ .description())
+ .isEqualTo(in.description);
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java
index 9cc8f9c..0d46ed7 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java
@@ -46,14 +46,12 @@
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.reviewdb.client.Patch;
-import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.RefUpdate;
import org.junit.Before;
import org.junit.Test;
import java.io.ByteArrayOutputStream;
-import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
@@ -75,7 +73,7 @@
public void reviewTriplet() throws Exception {
PushOneCommit.Result r = createChange();
gApi.changes()
- .id("p~master~" + r.getChangeId())
+ .id(project.get() + "~master~" + r.getChangeId())
.revision(r.getCommit().name())
.review(ReviewInput.approve());
}
@@ -108,11 +106,11 @@
public void submit() throws Exception {
PushOneCommit.Result r = createChange();
gApi.changes()
- .id("p~master~" + r.getChangeId())
+ .id(project.get() + "~master~" + r.getChangeId())
.current()
.review(ReviewInput.approve());
gApi.changes()
- .id("p~master~" + r.getChangeId())
+ .id(project.get() + "~master~" + r.getChangeId())
.current()
.submit();
}
@@ -121,14 +119,14 @@
public void submitOnBehalfOf() throws Exception {
PushOneCommit.Result r = createChange();
gApi.changes()
- .id("p~master~" + r.getChangeId())
+ .id(project.get() + "~master~" + r.getChangeId())
.current()
.review(ReviewInput.approve());
SubmitInput in = new SubmitInput();
in.onBehalfOf = admin2.email;
in.waitForMerge = true;
gApi.changes()
- .id("p~master~" + r.getChangeId())
+ .id(project.get() + "~master~" + r.getChangeId())
.current()
.submit(in);
}
@@ -153,12 +151,12 @@
.branch(in.destination)
.create(new BranchInput());
ChangeApi orig = gApi.changes()
- .id("p~master~" + r.getChangeId());
+ .id(project.get() + "~master~" + r.getChangeId());
- assertThat((Iterable<?>)orig.get().messages).hasSize(1);
+ assertThat(orig.get().messages).hasSize(1);
ChangeApi cherry = orig.revision(r.getCommit().name())
.cherryPick(in);
- assertThat((Iterable<?>)orig.get().messages).hasSize(2);
+ assertThat(orig.get().messages).hasSize(2);
String cherryPickedRevision = cherry.get().currentRevision;
String expectedMessage = String.format(
@@ -170,13 +168,33 @@
origIt.next();
assertThat(origIt.next().message).isEqualTo(expectedMessage);
- assertThat((Iterable<?>)cherry.get().messages).hasSize(1);
+ assertThat(cherry.get().messages).hasSize(1);
Iterator<ChangeMessageInfo> cherryIt = cherry.get().messages.iterator();
expectedMessage = "Patch Set 1: Cherry Picked from branch master.";
assertThat(cherryIt.next().message).isEqualTo(expectedMessage);
assertThat(cherry.get().subject).contains(in.message);
- assertThat(cherry.get().topic).isEqualTo("someTopic");
+ assertThat(cherry.get().topic).isEqualTo("someTopic-foo");
+ cherry.current().review(ReviewInput.approve());
+ cherry.current().submit();
+ }
+
+ @Test
+ public void cherryPickwithNoTopic() throws Exception {
+ PushOneCommit.Result r = pushTo("refs/for/master");
+ CherryPickInput in = new CherryPickInput();
+ in.destination = "foo";
+ in.message = "it goes to stable branch";
+ gApi.projects()
+ .name(project.get())
+ .branch(in.destination)
+ .create(new BranchInput());
+ ChangeApi orig = gApi.changes()
+ .id(project.get() + "~master~" + r.getChangeId());
+
+ ChangeApi cherry = orig.revision(r.getCommit().name())
+ .cherryPick(in);
+ assertThat(cherry.get().topic).isNull();
cherry.current().review(ReviewInput.approve());
cherry.current().submit();
}
@@ -188,11 +206,11 @@
in.destination = "master";
in.message = "it generates a new patch set\n\nChange-Id: " + r.getChangeId();
ChangeInfo cherryInfo = gApi.changes()
- .id("p~master~" + r.getChangeId())
+ .id(project.get() + "~master~" + r.getChangeId())
.revision(r.getCommit().name())
.cherryPick(in)
.get();
- assertThat((Iterable<?>)cherryInfo.messages).hasSize(2);
+ assertThat(cherryInfo.messages).hasSize(2);
Iterator<ChangeMessageInfo> cherryIt = cherryInfo.messages.iterator();
assertThat(cherryIt.next().message).isEqualTo("Uploaded patch set 1.");
assertThat(cherryIt.next().message).isEqualTo("Uploaded patch set 2.");
@@ -202,8 +220,8 @@
public void cherryPickToSameBranchWithRebase() throws Exception {
// Push a new change, then merge it
PushOneCommit.Result baseChange = createChange();
- RevisionApi baseRevision =
- gApi.changes().id("p~master~" + baseChange.getChangeId()).current();
+ String triplet = project.get() + "~master~" + baseChange.getChangeId();
+ RevisionApi baseRevision = gApi.changes().id(triplet).current();
baseRevision.review(ReviewInput.approve());
baseRevision.submit();
@@ -214,22 +232,23 @@
String subject = "Test change\n\n" +
"Change-Id: Ideadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
PushOneCommit push =
- pushFactory.create(db, admin.getIdent(), subject,
+ pushFactory.create(db, admin.getIdent(), testRepo, subject,
"another_file.txt", "another content");
- PushOneCommit.Result r2 = push.to(git, "refs/for/master");
+ PushOneCommit.Result r2 = push.to("refs/for/master");
// Change 2's parent should be change 1
assertThat(r2.getCommit().getParents()[0].name())
.isEqualTo(r1.getCommit().name());
// Cherry pick change 2 onto the same branch
- ChangeApi orig = gApi.changes().id("p~master~" + r2.getChangeId());
+ triplet = project.get() + "~master~" + r2.getChangeId();
+ ChangeApi orig = gApi.changes().id(triplet);
CherryPickInput in = new CherryPickInput();
in.destination = "master";
in.message = subject;
ChangeApi cherry = orig.revision(r2.getCommit().name()).cherryPick(in);
ChangeInfo cherryInfo = cherry.get();
- assertThat((Iterable<?>)cherryInfo.messages).hasSize(2);
+ assertThat(cherryInfo.messages).hasSize(2);
Iterator<ChangeMessageInfo> cherryIt = cherryInfo.messages.iterator();
assertThat(cherryIt.next().message).isEqualTo("Uploaded patch set 1.");
assertThat(cherryIt.next().message).isEqualTo("Uploaded patch set 2.");
@@ -252,12 +271,12 @@
.branch(in.destination)
.create(new BranchInput());
ChangeApi orig = gApi.changes()
- .id("p~master~" + r.getChangeId());
+ .id(project.get() + "~master~" + r.getChangeId());
- assertThat((Iterable<?>)orig.get().messages).hasSize(1);
+ assertThat(orig.get().messages).hasSize(1);
ChangeApi cherry = orig.revision(r.getCommit().name())
.cherryPick(in);
- assertThat((Iterable<?>)orig.get().messages).hasSize(2);
+ assertThat(orig.get().messages).hasSize(2);
assertThat(cherry.get().subject).contains(in.message);
cherry.current().review(ReviewInput.approve());
@@ -283,12 +302,13 @@
.create(new BranchInput());
PushOneCommit push =
- pushFactory.create(db, admin.getIdent(), PushOneCommit.SUBJECT,
+ pushFactory.create(db, admin.getIdent(), testRepo, PushOneCommit.SUBJECT,
PushOneCommit.FILE_NAME, "another content");
- push.to(git, "refs/heads/foo");
+ push.to("refs/heads/foo");
- ChangeApi orig = gApi.changes().id("p~master~" + r.getChangeId());
- assertThat((Iterable<?>)orig.get().messages).hasSize(1);
+ String triplet = project.get() + "~master~" + r.getChangeId();
+ ChangeApi orig = gApi.changes().id(triplet);
+ assertThat(orig.get().messages).hasSize(1);
try {
orig.revision(r.getCommit().name()).cherryPick(in);
@@ -300,12 +320,12 @@
@Test
public void canRebase() throws Exception {
- PushOneCommit push = pushFactory.create(db, admin.getIdent());
- PushOneCommit.Result r1 = push.to(git, "refs/for/master");
+ PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo);
+ PushOneCommit.Result r1 = push.to("refs/for/master");
merge(r1);
- push = pushFactory.create(db, admin.getIdent());
- PushOneCommit.Result r2 = push.to(git, "refs/for/master");
+ push = pushFactory.create(db, admin.getIdent(), testRepo);
+ PushOneCommit.Result r2 = push.to("refs/for/master");
boolean canRebase = gApi.changes()
.id(r2.getChangeId())
.revision(r2.getCommit().name())
@@ -313,9 +333,9 @@
assertThat(canRebase).isFalse();
merge(r2);
- git.checkout().setName(r1.getCommit().name()).call();
- push = pushFactory.create(db, admin.getIdent());
- PushOneCommit.Result r3 = push.to(git, "refs/for/master");
+ testRepo.reset(r1.getCommit());
+ push = pushFactory.create(db, admin.getIdent(), testRepo);
+ PushOneCommit.Result r3 = push.to("refs/for/master");
canRebase = gApi.changes()
.id(r3.getChangeId())
@@ -326,8 +346,8 @@
@Test
public void setUnsetReviewedFlag() throws Exception {
- PushOneCommit push = pushFactory.create(db, admin.getIdent());
- PushOneCommit.Result r = push.to(git, "refs/for/master");
+ PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo);
+ PushOneCommit.Result r = push.to("refs/for/master");
gApi.changes()
.id(r.getChangeId())
@@ -345,31 +365,31 @@
.current()
.setReviewed(PushOneCommit.FILE_NAME, false);
- assertThat((Iterable<?>)gApi.changes().id(r.getChangeId()).current().reviewed())
+ assertThat(gApi.changes().id(r.getChangeId()).current().reviewed())
.isEmpty();
}
@Test
public void mergeable() throws Exception {
- ObjectId initial = git.getRepository().getRef(HEAD).getLeaf().getObjectId();
+ ObjectId initial = repo().getRef(HEAD).getLeaf().getObjectId();
PushOneCommit push1 =
- pushFactory.create(db, admin.getIdent(), PushOneCommit.SUBJECT,
+ pushFactory.create(db, admin.getIdent(), testRepo, PushOneCommit.SUBJECT,
PushOneCommit.FILE_NAME, "push 1 content");
- PushOneCommit.Result r1 = push1.to(git, "refs/for/master");
+ PushOneCommit.Result r1 = push1.to("refs/for/master");
assertMergeable(r1.getChangeId(), true);
merge(r1);
// Reset HEAD to initial so the new change is a merge conflict.
- RefUpdate ru = git.getRepository().updateRef(HEAD);
+ RefUpdate ru = repo().updateRef(HEAD);
ru.setNewObjectId(initial);
assertThat(ru.forceUpdate()).isEqualTo(RefUpdate.Result.FORCED);
PushOneCommit push2 =
- pushFactory.create(db, admin.getIdent(), PushOneCommit.SUBJECT,
+ pushFactory.create(db, admin.getIdent(), testRepo, PushOneCommit.SUBJECT,
PushOneCommit.FILE_NAME, "push 2 content");
- PushOneCommit.Result r2 = push2.to(git, "refs/for/master");
+ PushOneCommit.Result r2 = push2.to("refs/for/master");
assertMergeable(r2.getChangeId(), false);
// TODO(dborowitz): Test for other-branches.
}
@@ -505,6 +525,19 @@
CommentInfo comment = Iterables.getOnlyElement(out.get(FILE_NAME));
assertThat(comment.message).isEqualTo(in.message);
assertThat(comment.author.email).isEqualTo(admin.email);
+ assertThat(comment.path).isNull();
+
+ List<CommentInfo> list = gApi.changes()
+ .id(r.getChangeId())
+ .revision(r.getCommit().name())
+ .commentsAsList();
+ assertThat(list).hasSize(1);
+
+ CommentInfo comment2 = list.get(0);
+ assertThat(comment2.path).isEqualTo(FILE_NAME);
+ assertThat(comment2.line).isEqualTo(comment.line);
+ assertThat(comment2.message).isEqualTo(comment.message);
+ assertThat(comment2.author.email).isEqualTo(comment.author.email);
assertThat(gApi.changes()
.id(r.getChangeId())
@@ -521,15 +554,14 @@
}
private PushOneCommit.Result updateChange(PushOneCommit.Result r,
- String content) throws GitAPIException, IOException {
- PushOneCommit push = pushFactory.create(db, admin.getIdent(),
+ String content) throws Exception {
+ PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo,
"test commit", "a.txt", content, r.getChangeId());
- return push.to(git, "refs/for/master");
+ return push.to("refs/for/master");
}
- private PushOneCommit.Result createDraft() throws GitAPIException,
- IOException {
- PushOneCommit push = pushFactory.create(db, admin.getIdent());
- return push.to(git, "refs/drafts/master");
+ private PushOneCommit.Result createDraft() throws Exception {
+ PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo);
+ return push.to("refs/drafts/master");
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/edit/ChangeEditIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/edit/ChangeEditIT.java
index 4726079..82f8c59 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/edit/ChangeEditIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/edit/ChangeEditIT.java
@@ -16,8 +16,6 @@
import static com.google.common.collect.Iterables.getOnlyElement;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.GitUtil.cloneProject;
-import static com.google.gerrit.acceptance.GitUtil.createProject;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
@@ -34,6 +32,8 @@
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.RestResponse;
import com.google.gerrit.acceptance.RestSession;
+import com.google.gerrit.acceptance.TestProjectInput;
+import com.google.gerrit.common.data.LabelType;
import com.google.gerrit.extensions.api.changes.ReviewInput;
import com.google.gerrit.extensions.client.ListChangesOption;
import com.google.gerrit.extensions.common.ApprovalInfo;
@@ -54,12 +54,12 @@
import com.google.gerrit.server.edit.UnchangedCommitMessageException;
import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.project.InvalidChangeOperationException;
+import com.google.gerrit.server.project.Util;
import com.google.gson.stream.JsonReader;
import com.google.gwtorm.server.SchemaFactory;
import com.google.inject.Inject;
import org.apache.commons.codec.binary.StringUtils;
-import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.RefUpdate;
@@ -109,12 +109,12 @@
@Before
public void setUp() throws Exception {
db = reviewDbProvider.open();
- changeId = newChange(git, admin.getIdent());
+ changeId = newChange(admin.getIdent());
ps = getCurrentPatchSet(changeId);
- amendChange(git, admin.getIdent(), changeId);
+ amendChange(admin.getIdent(), changeId);
change = getChange(changeId);
assertThat(ps).isNotNull();
- changeId2 = newChange2(git, admin.getIdent());
+ changeId2 = newChange2(admin.getIdent());
change2 = getChange(changeId2);
assertThat(change2).isNotNull();
ps2 = getCurrentPatchSet(changeId2);
@@ -245,9 +245,9 @@
assertThat(edit.getBasePatchSet().getPatchSetId()).isEqualTo(
current.getPatchSetId());
PushOneCommit push =
- pushFactory.create(db, admin.getIdent(), PushOneCommit.SUBJECT, FILE_NAME,
+ pushFactory.create(db, admin.getIdent(), testRepo, PushOneCommit.SUBJECT, FILE_NAME,
new String(CONTENT_NEW2), changeId2);
- push.to(git, "refs/for/master").assertOkStatus();
+ push.to("refs/for/master").assertOkStatus();
RestResponse r = adminSession.post(urlRebase());
assertThat(r.getStatusCode()).isEqualTo(SC_CONFLICT);
}
@@ -267,10 +267,11 @@
}
@Test
+ @TestProjectInput(createEmptyCommit = false)
public void updateRootCommitMessage() throws Exception {
- createProject(sshSession, "root-msg-test", null, false);
- git = cloneProject(sshSession.getUrl() + "/root-msg-test");
- changeId = newChange(git, admin.getIdent());
+ // Re-clone empty repo; TestRepository doesn't let us reset to unborn head.
+ testRepo = cloneProject(project);
+ changeId = newChange(admin.getIdent());
change = getChange(changeId);
assertThat(modifier.createEdit(change, getCurrentPatchSet(changeId)))
@@ -455,6 +456,30 @@
}
@Test
+ public void revertChanges() throws Exception {
+ assertThat(modifier.createEdit(change2, ps2)).isEqualTo(
+ RefUpdate.Result.NEW);
+ Optional<ChangeEdit> edit = editUtil.byChange(change2);
+ assertThat(modifier.restoreFile(edit.get(), FILE_NAME)).isEqualTo(
+ RefUpdate.Result.FORCED);
+ edit = editUtil.byChange(change2);
+ assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
+ ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_OLD);
+ assertThat(
+ modifier.modifyFile(editUtil.byChange(change2).get(), FILE_NAME,
+ RestSession.newRawInput(CONTENT_NEW))).isEqualTo(RefUpdate.Result.FORCED);
+ edit = editUtil.byChange(change2);
+ assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
+ ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_NEW);
+ assertThat(modifier.restoreFile(edit.get(), FILE_NAME)).isEqualTo(
+ RefUpdate.Result.FORCED);
+ edit = editUtil.byChange(change2);
+ assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
+ ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_OLD);
+ editUtil.delete(edit.get());
+ }
+
+ @Test
public void renameFileRest() throws Exception {
assertThat(modifier.createEdit(change, ps)).isEqualTo(RefUpdate.Result.NEW);
Post.Input in = new Post.Input();
@@ -624,10 +649,11 @@
@Test
public void editCommitMessageCopiesLabelScores() throws Exception {
String cr = "Code-Review";
- ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig();
- cfg.getLabelSections().get(cr)
- .setCopyAllScoresIfNoCodeChange(true);
- saveProjectConfig(allProjects, cfg);
+ ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
+ LabelType codeReview = Util.codeReview();
+ codeReview.setCopyAllScoresIfNoCodeChange(true);
+ cfg.getLabelSections().put(cr, codeReview);
+ saveProjectConfig(project, cfg);
String changeId = change.getKey().get();
ReviewInput r = new ReviewInput();
@@ -654,25 +680,25 @@
assertThat(approvals.get(0).value).isEqualTo(1);
}
- private String newChange(Git git, PersonIdent ident) throws Exception {
+ private String newChange(PersonIdent ident) throws Exception {
PushOneCommit push =
- pushFactory.create(db, ident, PushOneCommit.SUBJECT, FILE_NAME,
+ pushFactory.create(db, ident, testRepo, PushOneCommit.SUBJECT, FILE_NAME,
new String(CONTENT_OLD, StandardCharsets.UTF_8));
- return push.to(git, "refs/for/master").getChangeId();
+ return push.to("refs/for/master").getChangeId();
}
- private String amendChange(Git git, PersonIdent ident, String changeId) throws Exception {
+ private String amendChange(PersonIdent ident, String changeId) throws Exception {
PushOneCommit push =
- pushFactory.create(db, ident, PushOneCommit.SUBJECT, FILE_NAME2,
+ pushFactory.create(db, ident, testRepo, PushOneCommit.SUBJECT, FILE_NAME2,
new String(CONTENT_NEW2, StandardCharsets.UTF_8), changeId);
- return push.to(git, "refs/for/master").getChangeId();
+ return push.to("refs/for/master").getChangeId();
}
- private String newChange2(Git git, PersonIdent ident) throws Exception {
+ private String newChange2(PersonIdent ident) throws Exception {
PushOneCommit push =
- pushFactory.create(db, ident, PushOneCommit.SUBJECT, FILE_NAME,
+ pushFactory.create(db, ident, testRepo, PushOneCommit.SUBJECT, FILE_NAME,
new String(CONTENT_OLD, StandardCharsets.UTF_8));
- return push.rm(git, "refs/for/master").getChangeId();
+ return push.rm("refs/for/master").getChangeId();
}
private Change getChange(String changeId) throws Exception {
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractPushForReview.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractPushForReview.java
index e65d51e..2323270 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractPushForReview.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractPushForReview.java
@@ -16,30 +16,24 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.TruthJUnit.assume;
-import static com.google.gerrit.acceptance.GitUtil.cloneProject;
import com.google.common.collect.ImmutableSet;
import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.GitUtil;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.TestAccount;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.EditInfo;
import com.google.gerrit.extensions.common.LabelInfo;
-import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.server.notedb.NotesMigration;
import com.google.gerrit.testutil.ConfigSuite;
-import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
-import com.jcraft.jsch.JSchException;
-
-import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Config;
import org.junit.Before;
import org.junit.Test;
-import java.io.IOException;
import java.util.Set;
public abstract class AbstractPushForReview extends AbstractDaemonTest {
@@ -52,6 +46,7 @@
private NotesMigration notesMigration;
protected enum Protocol {
+ // TODO(dborowitz): TEST.
SSH, HTTP
}
@@ -62,7 +57,7 @@
sshUrl = sshSession.getUrl();
}
- protected void selectProtocol(Protocol p) throws GitAPIException, IOException {
+ protected void selectProtocol(Protocol p) throws Exception {
String url;
switch (p) {
case SSH:
@@ -74,20 +69,18 @@
default:
throw new IllegalArgumentException("unexpected protocol: " + p);
}
- git = cloneProject(url + "/" + project.get());
+ testRepo = GitUtil.cloneProject(project, url + "/" + project.get());
}
@Test
- public void testPushForMaster() throws GitAPIException, OrmException,
- IOException {
+ public void testPushForMaster() throws Exception {
PushOneCommit.Result r = pushTo("refs/for/master");
r.assertOkStatus();
r.assertChange(Change.Status.NEW, null);
}
@Test
- public void testPushForMasterWithTopic() throws GitAPIException,
- OrmException, IOException {
+ public void testPushForMasterWithTopic() throws Exception {
// specify topic in ref
String topic = "my/topic";
PushOneCommit.Result r = pushTo("refs/for/master/" + topic);
@@ -101,8 +94,7 @@
}
@Test
- public void testPushForMasterWithCc() throws GitAPIException, OrmException,
- IOException, JSchException {
+ public void testPushForMasterWithCc() throws Exception {
// cc one user
String topic = "my/topic";
PushOneCommit.Result r = pushTo("refs/for/master/" + topic + "%cc=" + user.email);
@@ -125,8 +117,7 @@
}
@Test
- public void testPushForMasterWithReviewer() throws GitAPIException,
- OrmException, IOException, JSchException {
+ public void testPushForMasterWithReviewer() throws Exception {
// add one reviewer
String topic = "my/topic";
PushOneCommit.Result r = pushTo("refs/for/master/" + topic + "%r=" + user.email);
@@ -150,8 +141,7 @@
}
@Test
- public void testPushForMasterAsDraft() throws GitAPIException, OrmException,
- IOException {
+ public void testPushForMasterAsDraft() throws Exception {
// create draft by pushing to 'refs/drafts/'
PushOneCommit.Result r = pushTo("refs/drafts/master");
r.assertOkStatus();
@@ -164,8 +154,7 @@
}
@Test
- public void testPushForMasterAsEdit() throws GitAPIException,
- IOException, RestApiException {
+ public void testPushForMasterAsEdit() throws Exception {
PushOneCommit.Result r = pushTo("refs/for/master");
r.assertOkStatus();
EditInfo edit = getEdit(r.getChangeId());
@@ -179,65 +168,59 @@
}
@Test
- public void testPushForMasterWithApprovals() throws GitAPIException,
- IOException, RestApiException {
+ public void testPushForMasterWithApprovals() throws Exception {
PushOneCommit.Result r = pushTo("refs/for/master/%l=Code-Review");
r.assertOkStatus();
ChangeInfo ci = get(r.getChangeId());
LabelInfo cr = ci.labels.get("Code-Review");
assertThat(cr.all).hasSize(1);
assertThat(cr.all.get(0).name).isEqualTo("Administrator");
- assertThat(cr.all.get(0).value.intValue()).is(1);
+ assertThat(cr.all.get(0).value).isEqualTo(1);
PushOneCommit push =
- pushFactory.create(db, admin.getIdent(), PushOneCommit.SUBJECT,
+ pushFactory.create(db, admin.getIdent(), testRepo, PushOneCommit.SUBJECT,
"b.txt", "anotherContent", r.getChangeId());
- r = push.to(git, "refs/for/master/%l=Code-Review+2");
+ r = push.to("refs/for/master/%l=Code-Review+2");
ci = get(r.getChangeId());
cr = ci.labels.get("Code-Review");
assertThat(cr.all).hasSize(1);
assertThat(cr.all.get(0).name).isEqualTo("Administrator");
- assertThat(cr.all.get(0).value.intValue()).is(2);
+ assertThat(cr.all.get(0).value).isEqualTo(2);
}
@Test
- public void testPushNewPatchsetToRefsChanges() throws GitAPIException,
- IOException, OrmException {
+ public void testPushNewPatchsetToRefsChanges() throws Exception {
PushOneCommit.Result r = pushTo("refs/for/master");
r.assertOkStatus();
PushOneCommit push =
- pushFactory.create(db, admin.getIdent(), PushOneCommit.SUBJECT,
+ pushFactory.create(db, admin.getIdent(), testRepo, PushOneCommit.SUBJECT,
"b.txt", "anotherContent", r.getChangeId());
- r = push.to(git, "refs/changes/" + r.getChange().change().getId().get());
+ r = push.to("refs/changes/" + r.getChange().change().getId().get());
r.assertOkStatus();
}
@Test
- public void testPushForMasterWithApprovals_MissingLabel() throws GitAPIException,
- IOException {
+ public void testPushForMasterWithApprovals_MissingLabel() throws Exception {
PushOneCommit.Result r = pushTo("refs/for/master/%l=Verify");
r.assertErrorStatus("label \"Verify\" is not a configured label");
}
@Test
- public void testPushForMasterWithApprovals_ValueOutOfRange() throws GitAPIException,
- IOException {
+ public void testPushForMasterWithApprovals_ValueOutOfRange() throws Exception {
PushOneCommit.Result r = pushTo("refs/for/master/%l=Code-Review-3");
r.assertErrorStatus("label \"Code-Review\": -3 is not a valid value");
}
@Test
- public void testPushForNonExistingBranch() throws GitAPIException,
- IOException {
+ public void testPushForNonExistingBranch() throws Exception {
String branchName = "non-existing";
PushOneCommit.Result r = pushTo("refs/for/" + branchName);
r.assertErrorStatus("branch " + branchName + " not found");
}
@Test
- public void testPushForMasterWithHashtags() throws GitAPIException,
- OrmException, IOException, RestApiException {
+ public void testPushForMasterWithHashtags() throws Exception {
// Hashtags currently only work when noteDB is enabled
assume().that(notesMigration.enabled()).isTrue();
@@ -250,23 +233,22 @@
r.assertChange(Change.Status.NEW, null);
Set<String> hashtags = gApi.changes().id(r.getChangeId()).getHashtags();
- assertThat((Iterable<?>)hashtags).containsExactlyElementsIn(expected);
+ assertThat(hashtags).containsExactlyElementsIn(expected);
// specify a single hashtag as option in new patch set
String hashtag2 = "tag2";
PushOneCommit push =
- pushFactory.create(db, admin.getIdent(), PushOneCommit.SUBJECT,
+ pushFactory.create(db, admin.getIdent(), testRepo, PushOneCommit.SUBJECT,
"b.txt", "anotherContent", r.getChangeId());
- r = push.to(git, "refs/for/master/%hashtag=" + hashtag2);
+ r = push.to("refs/for/master/%hashtag=" + hashtag2);
r.assertOkStatus();
expected = ImmutableSet.of(hashtag1, hashtag2);
hashtags = gApi.changes().id(r.getChangeId()).getHashtags();
- assertThat((Iterable<?>)hashtags).containsExactlyElementsIn(expected);
+ assertThat(hashtags).containsExactlyElementsIn(expected);
}
@Test
- public void testPushForMasterWithMultipleHashtags() throws GitAPIException,
- OrmException, IOException, RestApiException {
+ public void testPushForMasterWithMultipleHashtags() throws Exception {
// Hashtags currently only work when noteDB is enabled
assume().that(notesMigration.enabled()).isTrue();
@@ -281,25 +263,23 @@
r.assertChange(Change.Status.NEW, null);
Set<String> hashtags = gApi.changes().id(r.getChangeId()).getHashtags();
- assertThat((Iterable<?>)hashtags).containsExactlyElementsIn(expected);
+ assertThat(hashtags).containsExactlyElementsIn(expected);
// specify multiple hashtags as options in new patch set
String hashtag3 = "tag3";
String hashtag4 = "tag4";
PushOneCommit push =
- pushFactory.create(db, admin.getIdent(), PushOneCommit.SUBJECT,
+ pushFactory.create(db, admin.getIdent(), testRepo, PushOneCommit.SUBJECT,
"b.txt", "anotherContent", r.getChangeId());
- r = push.to(git,
- "refs/for/master%hashtag=" + hashtag3 + ",hashtag=" + hashtag4);
+ r = push.to("refs/for/master%hashtag=" + hashtag3 + ",hashtag=" + hashtag4);
r.assertOkStatus();
expected = ImmutableSet.of(hashtag1, hashtag2, hashtag3, hashtag4);
hashtags = gApi.changes().id(r.getChangeId()).getHashtags();
- assertThat((Iterable<?>)hashtags).containsExactlyElementsIn(expected);
+ assertThat(hashtags).containsExactlyElementsIn(expected);
}
@Test
- public void testPushForMasterWithHashtagsNoteDbDisabled() throws GitAPIException,
- IOException {
+ public void testPushForMasterWithHashtagsNoteDbDisabled() throws Exception {
// push with hashtags should fail when noteDb is disabled
assume().that(notesMigration.enabled()).isFalse();
PushOneCommit.Result r = pushTo("refs/for/master%hashtag=tag1");
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractSubmoduleSubscription.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractSubmoduleSubscription.java
new file mode 100644
index 0000000..8bf4511
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractSubmoduleSubscription.java
@@ -0,0 +1,82 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.acceptance.git;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.common.data.Permission;
+import com.google.gerrit.reviewdb.client.Project;
+
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevObject;
+import org.eclipse.jgit.revwalk.RevTree;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.RefSpec;
+
+public abstract class AbstractSubmoduleSubscription extends AbstractDaemonTest {
+ protected TestRepository<?> createProjectWithPush(String name)
+ throws Exception {
+ Project.NameKey project = createProject(name);
+ grant(Permission.PUSH, project, "refs/heads/*");
+ grant(Permission.SUBMIT, project, "refs/for/refs/heads/*");
+ return cloneProject(project);
+ }
+
+ protected void createSubscription(
+ TestRepository<?> repo, String branch, String subscribeToRepo,
+ String subscribeToBranch) throws Exception {
+ subscribeToRepo = name(subscribeToRepo);
+
+ // The submodule subscription module checks for gerrit.canonicalWebUrl to
+ // detect if it's configured for automatic updates. It doesn't matter if
+ // it serves from that URL.
+ String url = cfg.getString("gerrit", null, "canonicalWebUrl") + "/"
+ + subscribeToRepo;
+
+ Config cfg = new Config();
+ cfg.setString("submodule", subscribeToRepo, "path", subscribeToRepo);
+ cfg.setString("submodule", subscribeToRepo, "url", url);
+ cfg.setString("submodule", subscribeToRepo, "branch", subscribeToBranch);
+
+ repo.branch("HEAD").commit().insertChangeId()
+ .message("subject: adding new subscription")
+ .add(".gitmodules", cfg.toText().toString())
+ .create();
+
+ repo.git().push().setRemote("origin").setRefSpecs(
+ new RefSpec("HEAD:refs/heads/" + branch)).call();
+ }
+
+ protected void expectToHaveSubmoduleState(TestRepository<?> repo,
+ String branch, String submodule, ObjectId expectedId) throws Exception {
+
+ submodule = name(submodule);
+ ObjectId commitId = repo.git().fetch().setRemote("origin").call()
+ .getAdvertisedRef("refs/heads/" + branch).getObjectId();
+
+ RevWalk rw = repo.getRevWalk();
+ RevCommit c = rw.parseCommit(commitId);
+ rw.parseBody(c.getTree());
+
+ RevTree tree = c.getTree();
+ RevObject actualId = repo.get(tree, submodule);
+
+ assertThat(actualId).isEqualTo(expectedId);
+ }
+}
\ No newline at end of file
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/BUCK
index f36c447..446a183 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/BUCK
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/BUCK
@@ -5,8 +5,11 @@
'DraftChangeBlockedIT.java',
'ForcePushIT.java',
'SubmitOnPushIT.java',
+ 'SubmoduleSubscriptionsWholeTopicMergeIT.java',
+ 'SubmoduleSubscriptionsIT.java',
'VisibleRefFilterIT.java',
],
+ deps = [':submodule_util'],
labels = ['git'],
)
@@ -21,3 +24,9 @@
srcs = ['AbstractPushForReview.java'],
deps = ['//gerrit-acceptance-tests:lib'],
)
+
+java_library(
+ name = 'submodule_util',
+ srcs = ['AbstractSubmoduleSubscription.java',],
+ deps = ['//gerrit-acceptance-tests:lib',]
+)
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/DraftChangeBlockedIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/DraftChangeBlockedIT.java
index 20a698d..27b8b0a 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/DraftChangeBlockedIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/DraftChangeBlockedIT.java
@@ -21,23 +21,19 @@
import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.common.data.Permission;
-import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.ProjectConfig;
import org.junit.Before;
import org.junit.Test;
-import java.io.IOException;
-
@NoHttpd
public class DraftChangeBlockedIT extends AbstractDaemonTest {
@Before
public void setUp() throws Exception {
- ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig();
+ ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
block(cfg, Permission.PUSH, ANONYMOUS_USERS, "refs/drafts/*");
- saveProjectConfig(cfg);
- projectCache.evict(cfg.getProject());
+ saveProjectConfig(project, cfg);
}
@Test
@@ -53,13 +49,4 @@
PushOneCommit.Result r = pushTo("refs/for/master%draft");
r.assertErrorStatus("cannot upload drafts");
}
-
- private void saveProjectConfig(ProjectConfig cfg) throws IOException {
- MetaDataUpdate md = metaDataUpdateFactory.create(allProjects);
- try {
- cfg.commit(md);
- } finally {
- md.close();
- }
- }
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/ForcePushIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/ForcePushIT.java
index 5da524e..26db819 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/ForcePushIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/ForcePushIT.java
@@ -29,42 +29,42 @@
@Test
public void forcePushNotAllowed() throws Exception {
- ObjectId initial = git.getRepository().getRef(HEAD).getLeaf().getObjectId();
+ ObjectId initial = repo().getRef(HEAD).getLeaf().getObjectId();
PushOneCommit push1 =
- pushFactory.create(db, admin.getIdent(), "change1", "a.txt", "content");
- PushOneCommit.Result r1 = push1.to(git, "refs/heads/master");
+ pushFactory.create(db, admin.getIdent(), testRepo, "change1", "a.txt", "content");
+ PushOneCommit.Result r1 = push1.to("refs/heads/master");
r1.assertOkStatus();
// Reset HEAD to initial so the new change is a non-fast forward
- RefUpdate ru = git.getRepository().updateRef(HEAD);
+ RefUpdate ru = repo().updateRef(HEAD);
ru.setNewObjectId(initial);
assertThat(ru.forceUpdate()).isEqualTo(RefUpdate.Result.FORCED);
PushOneCommit push2 =
- pushFactory.create(db, admin.getIdent(), "change2", "b.txt", "content");
+ pushFactory.create(db, admin.getIdent(), testRepo, "change2", "b.txt", "content");
push2.setForce(true);
- PushOneCommit.Result r2 = push2.to(git, "refs/heads/master");
+ PushOneCommit.Result r2 = push2.to("refs/heads/master");
r2.assertErrorStatus("non-fast forward");
}
@Test
public void forcePushAllowed() throws Exception {
- ObjectId initial = git.getRepository().getRef(HEAD).getLeaf().getObjectId();
+ ObjectId initial = repo().getRef(HEAD).getLeaf().getObjectId();
grant(Permission.PUSH, project, "refs/*", true);
PushOneCommit push1 =
- pushFactory.create(db, admin.getIdent(), "change1", "a.txt", "content");
- PushOneCommit.Result r1 = push1.to(git, "refs/heads/master");
+ pushFactory.create(db, admin.getIdent(), testRepo, "change1", "a.txt", "content");
+ PushOneCommit.Result r1 = push1.to("refs/heads/master");
r1.assertOkStatus();
// Reset HEAD to initial so the new change is a non-fast forward
- RefUpdate ru = git.getRepository().updateRef(HEAD);
+ RefUpdate ru = repo().updateRef(HEAD);
ru.setNewObjectId(initial);
assertThat(ru.forceUpdate()).isEqualTo(RefUpdate.Result.FORCED);
PushOneCommit push2 =
- pushFactory.create(db, admin.getIdent(), "change2", "b.txt", "content");
+ pushFactory.create(db, admin.getIdent(), testRepo, "change2", "b.txt", "content");
push2.setForce(true);
- PushOneCommit.Result r2 = push2.to(git, "refs/heads/master");
+ PushOneCommit.Result r2 = push2.to("refs/heads/master");
r2.assertOkStatus();
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmitOnPushIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmitOnPushIT.java
index cf0945e..5066e66 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmitOnPushIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmitOnPushIT.java
@@ -32,7 +32,6 @@
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
-import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref;
@@ -55,7 +54,8 @@
private ChangeNotes.Factory changeNotesFactory;
@Inject
- private @GerritPersonIdent PersonIdent serverIdent;
+ @GerritPersonIdent
+ private PersonIdent serverIdent;
@Test
public void submitOnPush() throws Exception {
@@ -73,9 +73,9 @@
grant(Permission.CREATE, project, "refs/tags/*");
grant(Permission.PUSH, project, "refs/tags/*");
PushOneCommit.Tag tag = new PushOneCommit.Tag("v1.0");
- PushOneCommit push = pushFactory.create(db, admin.getIdent());
+ PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo);
push.setTag(tag);
- PushOneCommit.Result r = push.to(git, "refs/for/master%submit");
+ PushOneCommit.Result r = push.to("refs/for/master%submit");
r.assertOkStatus();
r.assertChange(Change.Status.MERGED, null, admin);
assertSubmitApproval(r.getPatchSetId());
@@ -90,9 +90,9 @@
grant(Permission.PUSH, project, "refs/tags/*");
PushOneCommit.AnnotatedTag tag =
new PushOneCommit.AnnotatedTag("v1.0", "annotation", admin.getIdent());
- PushOneCommit push = pushFactory.create(db, admin.getIdent());
+ PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo);
push.setTag(tag);
- PushOneCommit.Result r = push.to(git, "refs/for/master%submit");
+ PushOneCommit.Result r = push.to("refs/for/master%submit");
r.assertOkStatus();
r.assertChange(Change.Status.MERGED, null, admin);
assertSubmitApproval(r.getPatchSetId());
@@ -104,9 +104,8 @@
public void submitOnPushToRefsMetaConfig() throws Exception {
grant(Permission.SUBMIT, project, "refs/for/refs/meta/config");
- git.fetch().setRefSpecs(new RefSpec("refs/meta/config:refs/meta/config")).call();
- ObjectId objectId = git.getRepository().getRef("refs/meta/config").getObjectId();
- git.checkout().setName(objectId.getName()).call();
+ git().fetch().setRefSpecs(new RefSpec("refs/meta/config:refs/meta/config")).call();
+ testRepo.reset("refs/meta/config");
PushOneCommit.Result r = pushTo("refs/for/refs/meta/config%submit");
r.assertOkStatus();
@@ -117,10 +116,9 @@
@Test
public void submitOnPushMergeConflict() throws Exception {
- String master = "refs/heads/master";
- ObjectId objectId = git.getRepository().getRef(master).getObjectId();
- push(master, "one change", "a.txt", "some content");
- git.checkout().setName(objectId.getName()).call();
+ ObjectId objectId = repo().getRef("HEAD").getObjectId();
+ push("refs/heads/master", "one change", "a.txt", "some content");
+ testRepo.reset(objectId);
grant(Permission.SUBMIT, project, "refs/for/refs/heads/master");
PushOneCommit.Result r =
@@ -133,9 +131,9 @@
@Test
public void submitOnPushSuccessfulMerge() throws Exception {
String master = "refs/heads/master";
- ObjectId objectId = git.getRepository().getRef(master).getObjectId();
+ ObjectId objectId = repo().getRef("HEAD").getObjectId();
push(master, "one change", "a.txt", "some content");
- git.checkout().setName(objectId.getName()).call();
+ testRepo.reset(objectId);
grant(Permission.SUBMIT, project, "refs/for/refs/heads/master");
PushOneCommit.Result r =
@@ -198,7 +196,7 @@
push("refs/for/master", PushOneCommit.SUBJECT, "a.txt", "some content");
r.assertOkStatus();
- git.push()
+ git().push()
.setRefSpecs(new RefSpec(r.getCommitId().name() + ":refs/heads/master"))
.call();
assertCommit(project, "refs/heads/master");
@@ -214,10 +212,10 @@
r.assertOkStatus();
PushOneCommit push =
- pushFactory.create(db, admin.getIdent(), PushOneCommit.SUBJECT,
+ pushFactory.create(db, admin.getIdent(), testRepo, PushOneCommit.SUBJECT,
"b.txt", "anotherContent", r.getChangeId());
- r = push.to(git, "refs/heads/master");
+ r = push.to("refs/heads/master");
r.assertOkStatus();
assertCommit(project, "refs/heads/master");
@@ -255,7 +253,7 @@
try (Repository r = repoManager.openRepository(project);
RevWalk rw = new RevWalk(r)) {
RevCommit c = rw.parseCommit(r.getRef(branch).getObjectId());
- assertThat(c.getParentCount()).is(2);
+ assertThat(c.getParentCount()).isEqualTo(2);
assertThat(c.getShortMessage()).isEqualTo("Merge \"" + subject + "\"");
assertThat(c.getAuthorIdent().getEmailAddress()).isEqualTo(admin.email);
assertThat(c.getCommitterIdent().getEmailAddress()).isEqualTo(
@@ -290,17 +288,16 @@
}
private PushOneCommit.Result push(String ref, String subject,
- String fileName, String content) throws GitAPIException, IOException {
+ String fileName, String content) throws Exception {
PushOneCommit push =
- pushFactory.create(db, admin.getIdent(), subject, fileName, content);
- return push.to(git, ref);
+ pushFactory.create(db, admin.getIdent(), testRepo, subject, fileName, content);
+ return push.to(ref);
}
private PushOneCommit.Result push(String ref, String subject,
- String fileName, String content, String changeId) throws GitAPIException,
- IOException {
- PushOneCommit push = pushFactory.create(db, admin.getIdent(), subject,
+ String fileName, String content, String changeId) throws Exception {
+ PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo, subject,
fileName, content, changeId);
- return push.to(git, ref);
+ return push.to(ref);
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsIT.java
new file mode 100644
index 0000000..3ffe07c
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsIT.java
@@ -0,0 +1,201 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.acceptance.git;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevTree;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.RefSpec;
+import org.junit.Test;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class SubmoduleSubscriptionsIT extends AbstractSubmoduleSubscription {
+
+ @Test
+ public void testSubscriptionToEmptyRepo() throws Exception {
+ TestRepository<?> superRepo = createProjectWithPush("super-project");
+ TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
+
+ createSubscription(superRepo, "master", "subscribed-to-project", "master");
+ ObjectId subHEAD = pushChangeTo(subRepo, "master");
+ expectToHaveSubmoduleState(superRepo, "master",
+ "subscribed-to-project", subHEAD);
+ }
+
+ @Test
+ public void testSubscriptionToExistingRepo() throws Exception {
+ TestRepository<?> superRepo = createProjectWithPush("super-project");
+ TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
+
+ pushChangeTo(subRepo, "master");
+ createSubscription(superRepo, "master", "subscribed-to-project", "master");
+ ObjectId subHEAD = pushChangeTo(subRepo, "master");
+ expectToHaveSubmoduleState(superRepo, "master",
+ "subscribed-to-project", subHEAD);
+ }
+
+ @Test
+ public void testSubscriptionUnsubscribe() throws Exception {
+ TestRepository<?> superRepo = createProjectWithPush("super-project");
+ TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
+
+ pushChangeTo(subRepo, "master");
+ createSubscription(superRepo, "master", "subscribed-to-project", "master");
+
+ pushChangeTo(subRepo, "master");
+ ObjectId subHEADbeforeUnsubscribing = pushChangeTo(subRepo, "master");
+
+ deleteAllSubscriptions(superRepo, "master");
+ expectToHaveSubmoduleState(superRepo, "master",
+ "subscribed-to-project", subHEADbeforeUnsubscribing);
+
+ pushChangeTo(superRepo, "master", "commit after unsubscribe");
+ pushChangeTo(subRepo, "master", "commit after unsubscribe");
+ expectToHaveSubmoduleState(superRepo, "master",
+ "subscribed-to-project", subHEADbeforeUnsubscribing);
+ }
+
+ @Test
+ public void testSubscriptionUnsubscribeByDeletingGitModules() throws Exception {
+ TestRepository<?> superRepo = createProjectWithPush("super-project");
+ TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
+
+ pushChangeTo(subRepo, "master");
+ createSubscription(superRepo, "master", "subscribed-to-project", "master");
+
+ pushChangeTo(subRepo, "master");
+ ObjectId subHEADbeforeUnsubscribing = pushChangeTo(subRepo, "master");
+
+ deleteGitModulesFile(superRepo, "master");
+ expectToHaveSubmoduleState(superRepo, "master",
+ "subscribed-to-project", subHEADbeforeUnsubscribing);
+
+ pushChangeTo(superRepo, "master", "commit after unsubscribe");
+ pushChangeTo(subRepo, "master", "commit after unsubscribe");
+ expectToHaveSubmoduleState(superRepo, "master",
+ "subscribed-to-project", subHEADbeforeUnsubscribing);
+ }
+
+ @Test
+ public void testSubscriptionToDifferentBranches() throws Exception {
+ TestRepository<?> superRepo = createProjectWithPush("super-project");
+ TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
+
+ createSubscription(superRepo, "master", "subscribed-to-project", "foo");
+ ObjectId subFoo = pushChangeTo(subRepo, "foo");
+ pushChangeTo(subRepo, "master");
+
+ expectToHaveSubmoduleState(superRepo, "master",
+ "subscribed-to-project", subFoo);
+ }
+
+ @Test
+ public void testCircularSubscriptionIsDetected() throws Exception {
+ TestRepository<?> superRepo = createProjectWithPush("super-project");
+ TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
+
+ pushChangeTo(subRepo, "master");
+ createSubscription(superRepo, "master", "subscribed-to-project", "master");
+ createSubscription(subRepo, "master", "super-project", "master");
+
+ ObjectId subHEAD = pushChangeTo(subRepo, "master");
+ pushChangeTo(superRepo, "master");
+
+ expectToHaveSubmoduleState(superRepo, "master",
+ "subscribed-to-project", subHEAD);
+
+ assertThat(hasSubmodule(subRepo, "master", "super-project")).isFalse();
+ }
+
+ private static AtomicInteger contentCounter = new AtomicInteger(0);
+
+ private ObjectId pushChangeTo(TestRepository<?> repo, String branch, String message)
+ throws Exception {
+
+ ObjectId ret = repo.branch("HEAD").commit().insertChangeId()
+ .message(message)
+ .add("a.txt", "a contents: " + contentCounter.addAndGet(1))
+ .create();
+
+ repo.git().push().setRemote("origin").setRefSpecs(
+ new RefSpec("HEAD:refs/heads/" + branch)).call();
+
+ return ret;
+ }
+
+ private ObjectId pushChangeTo(TestRepository<?> repo, String branch)
+ throws Exception {
+ return pushChangeTo(repo, branch, "some change");
+ }
+
+ private void deleteAllSubscriptions(TestRepository<?> repo, String branch)
+ throws Exception {
+ repo.git().fetch().setRemote("origin").call();
+ repo.reset("refs/remotes/origin/" + branch);
+
+ ObjectId expectedId = repo.branch("HEAD").commit().insertChangeId()
+ .message("delete contents in .gitmodules")
+ .add(".gitmodules", "") // Just remove the contents of the file!
+ .create();
+ repo.git().push().setRemote("origin").setRefSpecs(
+ new RefSpec("HEAD:refs/heads/" + branch)).call();
+
+ ObjectId actualId = repo.git().fetch().setRemote("origin").call()
+ .getAdvertisedRef("refs/heads/master").getObjectId();
+ assertThat(actualId).isEqualTo(expectedId);
+ }
+
+ private void deleteGitModulesFile(TestRepository<?> repo, String branch)
+ throws Exception {
+ repo.git().fetch().setRemote("origin").call();
+ repo.reset("refs/remotes/origin/" + branch);
+
+ ObjectId expectedId = repo.branch("HEAD").commit().insertChangeId()
+ .message("delete .gitmodules")
+ .rm(".gitmodules")
+ .create();
+ repo.git().push().setRemote("origin").setRefSpecs(
+ new RefSpec("HEAD:refs/heads/" + branch)).call();
+
+ ObjectId actualId = repo.git().fetch().setRemote("origin").call()
+ .getAdvertisedRef("refs/heads/master").getObjectId();
+ assertThat(actualId).isEqualTo(expectedId);
+ }
+
+ private boolean hasSubmodule(TestRepository<?> repo, String branch,
+ String submodule) throws Exception {
+
+ ObjectId commitId = repo.git().fetch().setRemote("origin").call()
+ .getAdvertisedRef("refs/heads/" + branch).getObjectId();
+
+ RevWalk rw = repo.getRevWalk();
+ RevCommit c = rw.parseCommit(commitId);
+ rw.parseBody(c.getTree());
+
+ RevTree tree = c.getTree();
+ try {
+ repo.get(tree, submodule);
+ return true;
+ } catch (AssertionError e) {
+ return false;
+ }
+ }
+
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java
new file mode 100644
index 0000000..7823e7d
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java
@@ -0,0 +1,90 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.acceptance.git;
+
+import static com.google.gerrit.acceptance.GitUtil.getChangeId;
+
+import com.google.gerrit.acceptance.NoHttpd;
+import com.google.gerrit.extensions.api.changes.ReviewInput;
+import com.google.gerrit.testutil.ConfigSuite;
+
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.transport.RefSpec;
+import org.junit.Test;
+
+@NoHttpd
+public class SubmoduleSubscriptionsWholeTopicMergeIT
+ extends AbstractSubmoduleSubscription {
+
+ @ConfigSuite.Default
+ public static Config submitWholeTopicEnabled() {
+ return submitWholeTopicEnabledConfig();
+ }
+
+ @Test
+ public void testSubscriptionUpdateOfManyChanges() throws Exception {
+ TestRepository<?> superRepo = createProjectWithPush("super-project");
+ TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
+ createSubscription(superRepo, "master", "subscribed-to-project", "master");
+
+ ObjectId subHEAD = subRepo.branch("HEAD").commit().insertChangeId()
+ .message("some change")
+ .add("a.txt", "a contents ")
+ .create();
+ subRepo.git().push().setRemote("origin").setRefSpecs(
+ new RefSpec("HEAD:refs/heads/master")).call();
+
+ RevCommit c = subRepo.getRevWalk().parseCommit(subHEAD);
+
+ RevCommit c1 = subRepo.branch("HEAD").commit().insertChangeId()
+ .message("first change")
+ .add("asdf", "asdf\n")
+ .create();
+ subRepo.git().push().setRemote("origin")
+ .setRefSpecs(new RefSpec("HEAD:refs/for/master/" + name("topic-foo")))
+ .call();
+
+ subRepo.reset(c.getId());
+ RevCommit c2 = subRepo.branch("HEAD").commit().insertChangeId()
+ .message("qwerty")
+ .add("qwerty", "qwerty")
+ .create();
+
+ RevCommit c3 = subRepo.branch("HEAD").commit().insertChangeId()
+ .message("qwerty followup")
+ .add("qwerty", "qwerty\nqwerty\n")
+ .create();
+ subRepo.git().push().setRemote("origin")
+ .setRefSpecs(new RefSpec("HEAD:refs/for/master/" + name("topic-foo")))
+ .call();
+
+ String id1 = getChangeId(subRepo, c1).get();
+ String id2 = getChangeId(subRepo, c2).get();
+ String id3 = getChangeId(subRepo, c3).get();
+ gApi.changes().id(id1).current().review(ReviewInput.approve());
+ gApi.changes().id(id2).current().review(ReviewInput.approve());
+ gApi.changes().id(id3).current().review(ReviewInput.approve());
+
+ gApi.changes().id(id1).current().submit();
+ ObjectId subRepoId = subRepo.git().fetch().setRemote("origin").call()
+ .getAdvertisedRef("refs/heads/master").getObjectId();
+
+ expectToHaveSubmoduleState(superRepo, "master",
+ "subscribed-to-project", subRepoId);
+ }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/VisibleRefFilterIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/VisibleRefFilterIT.java
index 4a66a4169..0b07b87 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/VisibleRefFilterIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/VisibleRefFilterIT.java
@@ -68,22 +68,35 @@
private AccountGroup.UUID admins;
+ private Change.Id c1;
+ private Change.Id c2;
+ private String r1;
+ private String r2;
+
@Before
public void setUp() throws Exception {
admins = groupCache.get(new AccountGroup.NameKey("Administrators"))
.getGroupUUID();
- setUpChanges();
setUpPermissions();
+ setUpChanges();
}
private void setUpPermissions() throws Exception {
+ // Remove read permissions for all users besides admin. This method is
+ // idempotent, so is safe to call on every test setup.
ProjectConfig pc = projectCache.checkedGet(allProjects).getConfig();
for (AccessSection sec : pc.getAccessSections()) {
sec.removePermission(Permission.READ);
}
+ Util.allow(pc, Permission.READ, admins, "refs/*");
saveProjectConfig(allProjects, pc);
}
+ private static String changeRefPrefix(Change.Id id) {
+ String ps = new PatchSet.Id(id, 1).toRefName();
+ return ps.substring(0, ps.length() - 1);
+ }
+
private void setUpChanges() throws Exception {
gApi.projects()
.name(project.get())
@@ -91,12 +104,16 @@
.create(new BranchInput());
allow(Permission.SUBMIT, admins, "refs/for/refs/heads/*");
- PushOneCommit.Result mr = pushFactory.create(db, admin.getIdent())
- .to(git, "refs/for/master%submit");
+ PushOneCommit.Result mr = pushFactory.create(db, admin.getIdent(), testRepo)
+ .to("refs/for/master%submit");
mr.assertOkStatus();
- PushOneCommit.Result br = pushFactory.create(db, admin.getIdent())
- .to(git, "refs/for/branch%submit");
+ c1 = mr.getChange().getId();
+ r1 = changeRefPrefix(c1);
+ PushOneCommit.Result br = pushFactory.create(db, admin.getIdent(), testRepo)
+ .to("refs/for/branch%submit");
br.assertOkStatus();
+ c2 = br.getChange().getId();
+ r2 = changeRefPrefix(c2);
Repository repo = repoManager.openRepository(project);
try {
@@ -126,10 +143,10 @@
assertRefs(
"HEAD",
- "refs/changes/01/1/1",
- "refs/changes/01/1/meta",
- "refs/changes/02/2/1",
- "refs/changes/02/2/meta",
+ r1 + "1",
+ r1 + "meta",
+ r2 + "1",
+ r2 + "meta",
"refs/heads/branch",
"refs/heads/master",
"refs/tags/branch-tag",
@@ -143,10 +160,10 @@
assertRefs(
"HEAD",
- "refs/changes/01/1/1",
- "refs/changes/01/1/meta",
- "refs/changes/02/2/1",
- "refs/changes/02/2/meta",
+ r1 + "1",
+ r1 + "meta",
+ r2 + "1",
+ r2 + "meta",
"refs/heads/branch",
"refs/heads/master",
"refs/meta/config",
@@ -161,8 +178,8 @@
assertRefs(
"HEAD",
- "refs/changes/01/1/1",
- "refs/changes/01/1/meta",
+ r1 + "1",
+ r1 + "meta",
"refs/heads/master",
"refs/tags/master-tag");
}
@@ -173,8 +190,8 @@
allow(Permission.READ, REGISTERED_USERS, "refs/heads/branch");
assertRefs(
- "refs/changes/02/2/1",
- "refs/changes/02/2/meta",
+ r2 + "1",
+ r2 + "meta",
"refs/heads/branch",
"refs/tags/branch-tag",
// master branch is not visible but master-tag is reachable from branch
@@ -187,53 +204,57 @@
allow(Permission.READ, REGISTERED_USERS, "refs/heads/master");
deny(Permission.READ, REGISTERED_USERS, "refs/heads/branch");
- Change c1 = db.changes().get(new Change.Id(1));
- PatchSet ps1 = db.patchSets().get(new PatchSet.Id(c1.getId(), 1));
+ Change change1 = db.changes().get(c1);
+ PatchSet ps1 = db.patchSets().get(new PatchSet.Id(c1, 1));
// Admin's edit is not visible.
setApiUser(admin);
- editModifier.createEdit(c1, ps1);
+ editModifier.createEdit(change1, ps1);
// User's edit is visible.
setApiUser(user);
- editModifier.createEdit(c1, ps1);
+ editModifier.createEdit(change1, ps1);
assertRefs(
"HEAD",
- "refs/changes/01/1/1",
- "refs/changes/01/1/meta",
+ r1 + "1",
+ r1 + "meta",
"refs/heads/master",
"refs/tags/master-tag",
- "refs/users/01/1000001/edit-1/1");
+ "refs/users/01/1000001/edit-" + c1.get() + "/1");
}
@Test
public void subsetOfRefsVisibleWithAccessDatabase() throws Exception {
- deny(Permission.READ, REGISTERED_USERS, "refs/heads/master");
- allow(Permission.READ, REGISTERED_USERS, "refs/heads/branch");
- allowGlobalCapability(GlobalCapability.ACCESS_DATABASE, REGISTERED_USERS);
+ allowGlobalCapabilities(REGISTERED_USERS, GlobalCapability.ACCESS_DATABASE);
+ try {
+ deny(Permission.READ, REGISTERED_USERS, "refs/heads/master");
+ allow(Permission.READ, REGISTERED_USERS, "refs/heads/branch");
- Change c1 = db.changes().get(new Change.Id(1));
- PatchSet ps1 = db.patchSets().get(new PatchSet.Id(c1.getId(), 1));
- setApiUser(admin);
- editModifier.createEdit(c1, ps1);
- setApiUser(user);
- editModifier.createEdit(c1, ps1);
+ Change change1 = db.changes().get(c1);
+ PatchSet ps1 = db.patchSets().get(new PatchSet.Id(c1, 1));
+ setApiUser(admin);
+ editModifier.createEdit(change1, ps1);
+ setApiUser(user);
+ editModifier.createEdit(change1, ps1);
- assertRefs(
- // Change 1 is visible due to accessDatabase capability, even though
- // refs/heads/master is not.
- "refs/changes/01/1/1",
- "refs/changes/01/1/meta",
- "refs/changes/02/2/1",
- "refs/changes/02/2/meta",
- "refs/heads/branch",
- "refs/tags/branch-tag",
- // See comment in subsetOfBranchesVisibleNotIncludingHead.
- "refs/tags/master-tag",
- // All edits are visible due to accessDatabase capability.
- "refs/users/00/1000000/edit-1/1",
- "refs/users/01/1000001/edit-1/1");
+ assertRefs(
+ // Change 1 is visible due to accessDatabase capability, even though
+ // refs/heads/master is not.
+ r1 + "1",
+ r1 + "meta",
+ r2 + "1",
+ r2 + "meta",
+ "refs/heads/branch",
+ "refs/tags/branch-tag",
+ // See comment in subsetOfBranchesVisibleNotIncludingHead.
+ "refs/tags/master-tag",
+ // All edits are visible due to accessDatabase capability.
+ "refs/users/00/1000000/edit-" + c1.get() + "/1",
+ "refs/users/01/1000001/edit-" + c1.get() + "/1");
+ } finally {
+ removeGlobalCapabilities(REGISTERED_USERS, GlobalCapability.ACCESS_DATABASE);
+ }
}
/**
@@ -259,7 +280,7 @@
}
Splitter s = Splitter.on(CharMatcher.WHITESPACE).omitEmptyStrings();
- assertThat(filtered).containsSequence(
- Ordering.natural().sortedCopy(s.split(out)));
+ assertThat(filtered).containsExactlyElementsIn(
+ Ordering.natural().sortedCopy(s.split(out))).inOrder();
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/AccountAssert.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/AccountAssert.java
index c90924d..91ee332 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/AccountAssert.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/AccountAssert.java
@@ -16,8 +16,13 @@
import static com.google.common.truth.Truth.assertThat;
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
import com.google.gerrit.acceptance.TestAccount;
import com.google.gerrit.extensions.common.AccountInfo;
+import com.google.gerrit.reviewdb.client.Account;
+
+import java.util.List;
public class AccountAssert {
@@ -26,4 +31,21 @@
assertThat(a.fullName).isEqualTo(ai.name);
assertThat(a.email).isEqualTo(ai.email);
}
+
+ public static void assertAccountInfos(List<TestAccount> expected,
+ List<AccountInfo> actual) {
+ Iterable<Account.Id> expectedIds = TestAccount.ids(expected);
+ Iterable<Account.Id> actualIds = Iterables.transform(
+ actual,
+ new Function<AccountInfo, Account.Id>() {
+ @Override
+ public Account.Id apply(AccountInfo in) {
+ return new Account.Id(in._accountId);
+ }
+ });
+ assertThat(actualIds).containsExactlyElementsIn(expectedIds).inOrder();
+ for (int i = 0; i < expected.size(); i++) {
+ AccountAssert.assertAccountInfo(expected.get(i), actual.get(i));
+ }
+ }
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/CapabilitiesIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/CapabilitiesIT.java
index 6ce96ee..3e7c2bf 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/CapabilitiesIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/CapabilitiesIT.java
@@ -24,51 +24,56 @@
import static com.google.gerrit.common.data.GlobalCapability.PRIORITY;
import static com.google.gerrit.common.data.GlobalCapability.QUERY_LIMIT;
import static com.google.gerrit.common.data.GlobalCapability.RUN_AS;
+import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.GlobalCapability;
-import com.google.gerrit.common.data.Permission;
-import com.google.gerrit.common.data.PermissionRange;
-import com.google.gerrit.common.data.PermissionRule;
-import com.google.gerrit.server.git.MetaDataUpdate;
-import com.google.gerrit.server.git.ProjectConfig;
-import com.google.gerrit.server.group.SystemGroupBackend;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.apache.http.HttpStatus;
-import org.eclipse.jgit.errors.ConfigInvalidException;
import org.junit.Test;
-import java.io.IOException;
-
public class CapabilitiesIT extends AbstractDaemonTest {
@Test
public void testCapabilitiesUser() throws Exception {
- grantAllCapabilities();
- RestResponse r =
- userSession.get("/accounts/self/capabilities");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- CapabilityInfo info = (new Gson()).fromJson(r.getReader(),
- new TypeToken<CapabilityInfo>() {}.getType());
- for (String c : GlobalCapability.getAllNames()) {
- if (ADMINISTRATE_SERVER.equals(c)) {
- assertThat(info.administrateServer).isFalse();
- } else if (BATCH_CHANGES_LIMIT.equals(c)) {
- assertThat(info.batchChangesLimit.min).isEqualTo((short) 0);
- assertThat(info.batchChangesLimit.max).isEqualTo((short) DEFAULT_MAX_BATCH_CHANGES_LIMIT);
- } else if (PRIORITY.equals(c)) {
- assertThat(info.priority).isFalse();
- } else if (QUERY_LIMIT.equals(c)) {
- assertThat(info.queryLimit.min).isEqualTo((short) 0);
- assertThat(info.queryLimit.max).isEqualTo((short) DEFAULT_MAX_QUERY_LIMIT);
- } else {
- assert_().withFailureMessage(String.format("capability %s was not granted", c))
- .that((Boolean) CapabilityInfo.class.getField(c).get(info)).isTrue();
+ Iterable<String> all = Iterables.filter(GlobalCapability.getAllNames(),
+ new Predicate<String>() {
+ @Override
+ public boolean apply(String in) {
+ return !ADMINISTRATE_SERVER.equals(in) && !PRIORITY.equals(in);
+ }
+ });
+
+ allowGlobalCapabilities(REGISTERED_USERS, all);
+ try {
+ RestResponse r =
+ userSession.get("/accounts/self/capabilities");
+ assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
+ CapabilityInfo info = (new Gson()).fromJson(r.getReader(),
+ new TypeToken<CapabilityInfo>() {}.getType());
+ for (String c : GlobalCapability.getAllNames()) {
+ if (ADMINISTRATE_SERVER.equals(c)) {
+ assertThat(info.administrateServer).isFalse();
+ } else if (BATCH_CHANGES_LIMIT.equals(c)) {
+ assertThat(info.batchChangesLimit.min).isEqualTo((short) 0);
+ assertThat(info.batchChangesLimit.max).isEqualTo((short) DEFAULT_MAX_BATCH_CHANGES_LIMIT);
+ } else if (PRIORITY.equals(c)) {
+ assertThat(info.priority).isFalse();
+ } else if (QUERY_LIMIT.equals(c)) {
+ assertThat(info.queryLimit.min).isEqualTo((short) 0);
+ assertThat(info.queryLimit.max).isEqualTo((short) DEFAULT_MAX_QUERY_LIMIT);
+ } else {
+ assert_().withFailureMessage(String.format("capability %s was not granted", c))
+ .that((Boolean) CapabilityInfo.class.getField(c).get(info)).isTrue();
+ }
}
+ } finally {
+ removeGlobalCapabilities(REGISTERED_USERS, all);
}
}
@@ -101,35 +106,4 @@
}
}
}
-
- /**
- * Grant all global capabilities except ADMINISTRATE_SERVER and PRIORITY.
- * Set the default ranges for range permissions.
- */
- private void grantAllCapabilities() throws IOException,
- ConfigInvalidException {
- MetaDataUpdate md = metaDataUpdateFactory.create(allProjects);
- md.setMessage("Make super user");
- ProjectConfig config = ProjectConfig.read(md);
- AccessSection s = config.getAccessSection(
- AccessSection.GLOBAL_CAPABILITIES);
- for (String c : GlobalCapability.getAllNames()) {
- if (ADMINISTRATE_SERVER.equals(c) || PRIORITY.equals(c)) {
- continue;
- }
- Permission p = s.getPermission(c, true);
- PermissionRule rule = new PermissionRule(
- config.resolve(SystemGroupBackend.getGroup(
- SystemGroupBackend.REGISTERED_USERS)));
- if (GlobalCapability.hasRange(c)) {
- PermissionRange.WithDefaults range = GlobalCapability.getRange(c);
- if (range != null) {
- rule.setRange(range.getDefaultMin(), range.getDefaultMax());
- }
- }
- p.add(rule);
- }
- config.commit(md);
- projectCache.evict(config.getProject());
- }
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/GetAccountIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/GetAccountIT.java
index 63c6493..af90d8f 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/GetAccountIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/GetAccountIT.java
@@ -14,54 +14,51 @@
package com.google.gerrit.acceptance.rest.account;
-import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.acceptance.rest.account.AccountAssert.assertAccountInfo;
+import static org.junit.Assert.fail;
import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.acceptance.TestAccount;
-import com.google.gerrit.extensions.common.AccountInfo;
-import com.google.gerrit.extensions.restapi.Url;
+import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
-import org.apache.http.HttpStatus;
import org.junit.Test;
-import java.io.IOException;
-
+@NoHttpd
public class GetAccountIT extends AbstractDaemonTest {
@Test
public void getNonExistingAccount_NotFound() throws Exception {
- assertThat(adminSession.get("/accounts/non-existing").getStatusCode())
- .isEqualTo(HttpStatus.SC_NOT_FOUND);
+ try {
+ gApi.accounts().id("non-existing").get();
+ fail("Expected account to not exist");
+ } catch (ResourceNotFoundException expected) {
+ // Expected.
+ }
}
@Test
public void getAccount() throws Exception {
// by formatted string
- testGetAccount("/accounts/"
- + Url.encode(admin.fullName + " <" + admin.email + ">"), admin);
+ testGetAccount(admin.fullName + " <" + admin.email + ">", admin);
// by email
- testGetAccount("/accounts/" + admin.email, admin);
+ testGetAccount(admin.email, admin);
// by full name
- testGetAccount("/accounts/" + admin.fullName, admin);
+ testGetAccount(admin.fullName, admin);
// by account ID
- testGetAccount("/accounts/" + admin.id.get(), admin);
+ testGetAccount(Integer.toString(admin.id.get()), admin);
// by user name
- testGetAccount("/accounts/" + admin.username, admin);
+ testGetAccount(admin.username, admin);
// by 'self'
- testGetAccount("/accounts/self", admin);
+ testGetAccount("self", admin);
}
- private void testGetAccount(String url, TestAccount expectedAccount)
- throws IOException {
- RestResponse r = adminSession.get(url);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- assertAccountInfo(expectedAccount, newGson()
- .fromJson(r.getReader(), AccountInfo.class));
+ private void testGetAccount(String id, TestAccount expectedAccount)
+ throws Exception {
+ assertAccountInfo(expectedAccount, gApi.accounts().id(id).get());
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/StarredChangesIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/StarredChangesIT.java
deleted file mode 100644
index face299a..0000000
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/StarredChangesIT.java
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (C) 2013 The Android Open Source Project
-//
-// 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.
-
-package com.google.gerrit.acceptance.rest.account;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.PushOneCommit.Result;
-import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.reviewdb.client.Change;
-
-import org.apache.http.HttpStatus;
-import org.junit.Test;
-
-import java.io.IOException;
-
-public class StarredChangesIT extends AbstractDaemonTest {
-
- @Test
- public void starredChangeState() throws Exception {
- Result c1 = createChange();
- Result c2 = createChange();
- assertThat(getChange(c1.getChangeId()).starred).isNull();
- assertThat(getChange(c2.getChangeId()).starred).isNull();
- starChange(true, c1.getPatchSetId().getParentKey());
- starChange(true, c2.getPatchSetId().getParentKey());
- assertThat(getChange(c1.getChangeId()).starred).isTrue();
- assertThat(getChange(c2.getChangeId()).starred).isTrue();
- starChange(false, c1.getPatchSetId().getParentKey());
- starChange(false, c2.getPatchSetId().getParentKey());
- assertThat(getChange(c1.getChangeId()).starred).isNull();
- assertThat(getChange(c2.getChangeId()).starred).isNull();
- }
-
- private void starChange(boolean on, Change.Id id) throws IOException {
- String url = "/accounts/self/starred.changes/" + id.get();
- if (on) {
- RestResponse r = adminSession.put(url);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_NO_CONTENT);
- } else {
- RestResponse r = adminSession.delete(url);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_NO_CONTENT);
- }
- }
-}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java
index dec3e65..a07bde7 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java
@@ -18,23 +18,24 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assert_;
import static com.google.common.truth.TruthJUnit.assume;
-import static com.google.gerrit.acceptance.GitUtil.cloneProject;
import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_REVISION;
import static com.google.gerrit.extensions.client.ListChangesOption.DETAILED_LABELS;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.GitUtil;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.acceptance.SshSession;
+import com.google.gerrit.acceptance.TestProjectInput;
import com.google.gerrit.common.EventListener;
import com.google.gerrit.common.EventSource;
-import com.google.gerrit.extensions.api.changes.ReviewInput;
import com.google.gerrit.extensions.api.changes.SubmitInput;
+import com.google.gerrit.extensions.api.projects.BranchInfo;
+import com.google.gerrit.extensions.api.projects.ProjectInput;
import com.google.gerrit.extensions.client.ChangeStatus;
import com.google.gerrit.extensions.client.InheritableBoolean;
+import com.google.gerrit.extensions.client.ListChangesOption;
import com.google.gerrit.extensions.client.SubmitType;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.LabelInfo;
@@ -50,19 +51,14 @@
import com.google.gerrit.server.events.ChangeMergedEvent;
import com.google.gerrit.server.events.Event;
import com.google.gerrit.server.notedb.ChangeNotes;
-import com.google.gerrit.server.project.ListBranches.BranchInfo;
-import com.google.gerrit.server.project.PutConfig;
import com.google.gerrit.testutil.ConfigSuite;
import com.google.gson.reflect.TypeToken;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
-import com.jcraft.jsch.JSchException;
-
import org.apache.http.HttpStatus;
-import org.eclipse.jgit.api.Git;
-import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.diff.DiffFormatter;
+import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
@@ -116,7 +112,6 @@
}
}, listenerUser);
- project = new Project.NameKey("p2");
}
@After
@@ -127,10 +122,9 @@
protected abstract SubmitType getSubmitType();
@Test
- public void submitToEmptyRepo() throws JSchException, IOException,
- GitAPIException {
- Git git = createProject(false);
- PushOneCommit.Result change = createChange(git);
+ @TestProjectInput(createEmptyCommit = false)
+ public void submitToEmptyRepo() throws Exception {
+ PushOneCommit.Result change = createChange();
submit(change.getChangeId());
assertThat(getRemoteHead().getId()).isEqualTo(change.getCommitId());
}
@@ -138,85 +132,69 @@
@Test
public void submitWholeTopic() throws Exception {
assume().that(isSubmitWholeTopicEnabled()).isTrue();
- Git git = createProject();
PushOneCommit.Result change1 =
- createChange(git, "Change 1", "a.txt", "content", "test-topic");
+ createChange("Change 1", "a.txt", "content", "test-topic");
PushOneCommit.Result change2 =
- createChange(git, "Change 2", "b.txt", "content", "test-topic");
+ createChange("Change 2", "b.txt", "content", "test-topic");
+ PushOneCommit.Result change3 =
+ createChange("Change 3", "c.txt", "content", "test-topic");
approve(change1.getChangeId());
approve(change2.getChangeId());
- submit(change2.getChangeId());
+ approve(change3.getChangeId());
+ submit(change3.getChangeId());
change1.assertChange(Change.Status.MERGED, "test-topic", admin);
change2.assertChange(Change.Status.MERGED, "test-topic", admin);
+ change3.assertChange(Change.Status.MERGED, "test-topic", admin);
+ assertSubmitter(change1);
+ assertSubmitter(change2);
+ assertSubmitter(change3);
}
- protected Git createProject() throws JSchException, IOException,
- GitAPIException {
- return createProject(true);
- }
-
- private Git createProject(boolean emptyCommit)
- throws JSchException, IOException, GitAPIException {
- SshSession sshSession = new SshSession(server, admin);
- try {
- GitUtil.createProject(sshSession, project.get(), null, emptyCommit);
- setSubmitType(getSubmitType());
- return cloneProject(sshSession.getUrl() + "/" + project.get());
- } finally {
- sshSession.close();
+ private void assertSubmitter(PushOneCommit.Result change) throws Exception {
+ ChangeInfo info = get(change.getChangeId(), ListChangesOption.MESSAGES);
+ assertThat(info.messages).isNotNull();
+ assertThat(info.messages).hasSize(3);
+ if (getSubmitType() == SubmitType.CHERRY_PICK) {
+ assertThat(Iterables.getLast(info.messages).message).startsWith(
+ "Change has been successfully cherry-picked as ");
+ } else {
+ assertThat(Iterables.getLast(info.messages).message).isEqualTo(
+ "Change has been successfully merged into the git repository by Administrator");
}
}
- private void setSubmitType(SubmitType submitType) throws IOException {
- PutConfig.Input in = new PutConfig.Input();
- in.submitType = submitType;
- in.useContentMerge = InheritableBoolean.FALSE;
- RestResponse r =
- adminSession.put("/projects/" + project.get() + "/config", in);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- r.consume();
+ @Override
+ protected void updateProjectInput(ProjectInput in) {
+ in.submitType = getSubmitType();
+ if (in.useContentMerge == InheritableBoolean.INHERIT) {
+ in.useContentMerge = InheritableBoolean.FALSE;
+ }
}
- protected void setUseContentMerge() throws IOException {
- PutConfig.Input in = new PutConfig.Input();
- in.useContentMerge = InheritableBoolean.TRUE;
- RestResponse r =
- adminSession.put("/projects/" + project.get() + "/config", in);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- r.consume();
- }
-
- protected PushOneCommit.Result createChange(Git git) throws GitAPIException,
- IOException {
- PushOneCommit push = pushFactory.create(db, admin.getIdent());
- return push.to(git, "refs/for/master");
- }
-
- protected PushOneCommit.Result createChange(Git git, String subject,
- String fileName, String content) throws GitAPIException, IOException {
+ protected PushOneCommit.Result createChange(String subject,
+ String fileName, String content) throws Exception {
PushOneCommit push =
- pushFactory.create(db, admin.getIdent(), subject, fileName, content);
- return push.to(git, "refs/for/master");
+ pushFactory.create(db, admin.getIdent(), testRepo, subject, fileName, content);
+ return push.to("refs/for/master");
}
- protected PushOneCommit.Result createChange(Git git, String subject,
+ protected PushOneCommit.Result createChange(String subject,
String fileName, String content, String topic)
- throws GitAPIException, IOException {
+ throws Exception {
PushOneCommit push =
- pushFactory.create(db, admin.getIdent(), subject, fileName, content);
- return push.to(git, "refs/for/master/" + topic);
+ pushFactory.create(db, admin.getIdent(), testRepo, subject, fileName, content);
+ return push.to("refs/for/master/" + topic);
}
- protected void submit(String changeId) throws IOException {
+ protected void submit(String changeId) throws Exception {
submit(changeId, HttpStatus.SC_OK);
}
- protected void submitWithConflict(String changeId) throws IOException {
+ protected void submitWithConflict(String changeId) throws Exception {
submit(changeId, HttpStatus.SC_CONFLICT);
}
- protected void submitStatusOnly(String changeId)
- throws IOException, OrmException {
+ protected void submitStatusOnly(String changeId) throws Exception {
approve(changeId);
Change c = queryProvider.get().byKeyPrefix(changeId).get(0).change();
c.setStatus(Change.Status.SUBMITTED);
@@ -232,7 +210,7 @@
indexer.index(db, c);
}
- private void submit(String changeId, int expectedStatus) throws IOException {
+ private void submit(String changeId, int expectedStatus) throws Exception {
approve(changeId);
SubmitInput subm = new SubmitInput();
subm.waitForMerge = true;
@@ -266,17 +244,9 @@
b.consume();
}
- private void approve(String changeId) throws IOException {
- RestResponse r = adminSession.post(
- "/changes/" + changeId + "/revisions/current/review",
- new ReviewInput().label("Code-Review", 2));
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- r.consume();
- }
-
protected void assertCurrentRevision(String changeId, int expectedNum,
- ObjectId expectedId) throws IOException {
- ChangeInfo c = getChange(changeId, CURRENT_REVISION);
+ ObjectId expectedId) throws Exception {
+ ChangeInfo c = get(changeId, CURRENT_REVISION);
assertThat(c.currentRevision).isEqualTo(expectedId.name());
assertThat(c.revisions.get(expectedId.name())._number).isEqualTo(expectedNum);
Repository repo =
@@ -291,11 +261,11 @@
}
}
- protected void assertApproved(String changeId) throws IOException {
- ChangeInfo c = getChange(changeId, DETAILED_LABELS);
+ protected void assertApproved(String changeId) throws Exception {
+ ChangeInfo c = get(changeId, DETAILED_LABELS);
LabelInfo cr = c.labels.get("Code-Review");
assertThat(cr.all).hasSize(1);
- assertThat(cr.all.get(0).value.intValue()).isEqualTo(2);
+ assertThat(cr.all.get(0).value).isEqualTo(2);
assertThat(new Account.Id(cr.all.get(0)._accountId)).isEqualTo(admin.getId());
}
@@ -309,17 +279,17 @@
assertThat(submitter.getAccountId()).isEqualTo(admin.getId());
}
- protected void assertCherryPick(Git localGit, boolean contentMerge)
- throws IOException {
- assertRebase(localGit, contentMerge);
+ protected void assertCherryPick(TestRepository<?> testRepo,
+ boolean contentMerge) throws IOException {
+ assertRebase(testRepo, contentMerge);
RevCommit remoteHead = getRemoteHead();
assertThat(remoteHead.getFooterLines("Reviewed-On")).isNotEmpty();
assertThat(remoteHead.getFooterLines("Reviewed-By")).isNotEmpty();
}
- protected void assertRebase(Git localGit, boolean contentMerge)
+ protected void assertRebase(TestRepository<?> testRepo, boolean contentMerge)
throws IOException {
- Repository repo = localGit.getRepository();
+ Repository repo = testRepo.getRepository();
RevCommit localHead = getHead(repo);
RevCommit remoteHead = getRemoteHead();
assert_().withFailureMessage(
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/AbstractSubmitByMerge.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/AbstractSubmitByMerge.java
index 1d60607..98aae37 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/AbstractSubmitByMerge.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/AbstractSubmitByMerge.java
@@ -15,34 +15,27 @@
package com.google.gerrit.acceptance.rest.change;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.GitUtil.checkout;
import com.google.gerrit.acceptance.PushOneCommit;
+import com.google.gerrit.acceptance.TestProjectInput;
+import com.google.gerrit.extensions.client.InheritableBoolean;
-import com.jcraft.jsch.JSchException;
-
-import org.eclipse.jgit.api.Git;
-import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Test;
-import java.io.IOException;
-
public abstract class AbstractSubmitByMerge extends AbstractSubmit {
@Test
- public void submitWithMerge() throws JSchException, IOException,
- GitAPIException {
- Git git = createProject();
+ public void submitWithMerge() throws Exception {
RevCommit initialHead = getRemoteHead();
PushOneCommit.Result change =
- createChange(git, "Change 1", "a.txt", "content");
+ createChange("Change 1", "a.txt", "content");
submit(change.getChangeId());
RevCommit oldHead = getRemoteHead();
- checkout(git, initialHead.getId().getName());
+ testRepo.reset(initialHead);
PushOneCommit.Result change2 =
- createChange(git, "Change 2", "b.txt", "other content");
+ createChange("Change 2", "b.txt", "other content");
submit(change2.getChangeId());
RevCommit head = getRemoteHead();
assertThat(head.getParentCount()).isEqualTo(2);
@@ -51,21 +44,19 @@
}
@Test
- public void submitWithContentMerge() throws JSchException, IOException,
- GitAPIException {
- Git git = createProject();
- setUseContentMerge();
+ @TestProjectInput(useContentMerge = InheritableBoolean.TRUE)
+ public void submitWithContentMerge() throws Exception {
PushOneCommit.Result change =
- createChange(git, "Change 1", "a.txt", "aaa\nbbb\nccc\n");
+ createChange("Change 1", "a.txt", "aaa\nbbb\nccc\n");
submit(change.getChangeId());
PushOneCommit.Result change2 =
- createChange(git, "Change 2", "a.txt", "aaa\nbbb\nccc\nddd\n");
+ createChange("Change 2", "a.txt", "aaa\nbbb\nccc\nddd\n");
submit(change2.getChangeId());
RevCommit oldHead = getRemoteHead();
- checkout(git, change.getCommitId().getName());
+ testRepo.reset(change.getCommitId());
PushOneCommit.Result change3 =
- createChange(git, "Change 3", "a.txt", "bbb\nccc\n");
+ createChange("Change 3", "a.txt", "bbb\nccc\n");
submit(change3.getChangeId());
RevCommit head = getRemoteHead();
assertThat(head.getParentCount()).isEqualTo(2);
@@ -74,19 +65,17 @@
}
@Test
- public void submitWithContentMerge_Conflict() throws JSchException,
- IOException, GitAPIException {
- Git git = createProject();
- setUseContentMerge();
+ @TestProjectInput(useContentMerge = InheritableBoolean.TRUE)
+ public void submitWithContentMerge_Conflict() throws Exception {
RevCommit initialHead = getRemoteHead();
PushOneCommit.Result change =
- createChange(git, "Change 1", "a.txt", "content");
+ createChange("Change 1", "a.txt", "content");
submit(change.getChangeId());
RevCommit oldHead = getRemoteHead();
- checkout(git, initialHead.getId().getName());
+ testRepo.reset(initialHead);
PushOneCommit.Result change2 =
- createChange(git, "Change 2", "a.txt", "other content");
+ createChange("Change 2", "a.txt", "other content");
submitWithConflict(change2.getChangeId());
assertThat(getRemoteHead()).isEqualTo(oldHead);
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ActionsIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ActionsIT.java
index afcd5d0..66c99f1 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ActionsIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ActionsIT.java
@@ -18,18 +18,15 @@
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.PushOneCommit;
-import com.google.gerrit.acceptance.RestResponse;
import com.google.gerrit.extensions.api.changes.ReviewInput;
import com.google.gerrit.extensions.common.ActionInfo;
import com.google.gerrit.testutil.ConfigSuite;
-import com.google.gson.reflect.TypeToken;
-import org.apache.http.HttpStatus;
-import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
+import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Config;
import org.junit.Test;
-import java.io.IOException;
import java.util.Map;
public class ActionsIT extends AbstractDaemonTest {
@@ -40,7 +37,7 @@
@Test
public void revisionActionsOneChangePerTopicUnapproved() throws Exception {
- String changeId = createChangeWithTopic("foo1").getChangeId();
+ String changeId = createChangeWithTopic().getChangeId();
Map<String, ActionInfo> actions = getActions(changeId);
assertThat(actions).containsKey("cherrypick");
assertThat(actions).containsKey("rebase");
@@ -49,27 +46,21 @@
@Test
public void revisionActionsOneChangePerTopic() throws Exception {
- String changeId = createChangeWithTopic("foo1").getChangeId();
+ String changeId = createChangeWithTopic().getChangeId();
approve(changeId);
Map<String, ActionInfo> actions = getActions(changeId);
commonActionsAssertions(actions);
- if (isSubmitWholeTopicEnabled()) {
- ActionInfo info = actions.get("submit");
- assertThat(info.enabled).isTrue();
- assertThat(info.label).isEqualTo("Submit whole topic");
- assertThat(info.method).isEqualTo("POST");
- assertThat(info.title).isEqualTo("Submit all 1 changes of the same topic");
- } else {
- noSubmitWholeTopicAssertions(actions);
- }
+ // We want to treat a single change in a topic not as a whole topic,
+ // so regardless of how submitWholeTopic is configured:
+ noSubmitWholeTopicAssertions(actions);
}
@Test
public void revisionActionsTwoChangeChangesInTopic() throws Exception {
- String changeId = createChangeWithTopic("foo2").getChangeId();
+ String changeId = createChangeWithTopic().getChangeId();
approve(changeId);
// create another change with the same topic
- createChangeWithTopic("foo2").getChangeId();
+ createChangeWithTopic().getChangeId();
Map<String, ActionInfo> actions = getActions(changeId);
commonActionsAssertions(actions);
if (isSubmitWholeTopicEnabled()) {
@@ -84,11 +75,42 @@
}
@Test
+ public void revisionActionsTwoChangeChangesInTopic_conflicting() throws Exception {
+ String changeId = createChangeWithTopic().getChangeId();
+ approve(changeId);
+
+ // create another change with the same topic
+ String changeId2 = createChangeWithTopic(testRepo, "foo2", "touching b",
+ "b.txt", "real content").getChangeId();
+ approve(changeId2);
+
+ // collide with the other change in the same topic
+ testRepo.reset("HEAD~2");
+ String collidingChange = createChangeWithTopic(testRepo, "off_topic",
+ "rewriting file b", "b.txt", "garbage\ngarbage\ngarbage").getChangeId();
+ gApi.changes().id(collidingChange).current().review(ReviewInput.approve());
+ gApi.changes().id(collidingChange).current().submit();
+
+ Map<String, ActionInfo> actions = getActions(changeId);
+ commonActionsAssertions(actions);
+ if (isSubmitWholeTopicEnabled()) {
+ ActionInfo info = actions.get("submit");
+ assertThat(info.enabled).isNull();
+ assertThat(info.label).isEqualTo("Submit whole topic");
+ assertThat(info.method).isEqualTo("POST");
+ assertThat(info.title).isEqualTo(
+ "Clicking the button would fail for other changes in the topic");
+ } else {
+ noSubmitWholeTopicAssertions(actions);
+ }
+ }
+
+ @Test
public void revisionActionsTwoChangeChangesInTopicReady() throws Exception {
- String changeId = createChangeWithTopic("foo2").getChangeId();
+ String changeId = createChangeWithTopic().getChangeId();
approve(changeId);
// create another change with the same topic
- String changeId2 = createChangeWithTopic("foo2").getChangeId();
+ String changeId2 = createChangeWithTopic().getChangeId();
approve(changeId2);
Map<String, ActionInfo> actions = getActions(changeId);
commonActionsAssertions(actions);
@@ -103,15 +125,6 @@
}
}
- private Map<String, ActionInfo> getActions(String changeId)
- throws IOException {
- return newGson().fromJson(
- adminSession.get("/changes/"
- + changeId
- + "/revisions/1/actions").getReader(),
- new TypeToken<Map<String, ActionInfo>>() {}.getType());
- }
-
private void noSubmitWholeTopicAssertions(Map<String, ActionInfo> actions) {
ActionInfo info = actions.get("submit");
assertThat(info.enabled).isTrue();
@@ -127,18 +140,18 @@
assertThat(actions).containsKey("rebase");
}
- private PushOneCommit.Result createChangeWithTopic(String topic) throws GitAPIException,
- IOException {
- PushOneCommit push = pushFactory.create(db, admin.getIdent());
+ private PushOneCommit.Result createChangeWithTopic(
+ TestRepository<InMemoryRepository> repo, String topic,
+ String commitMsg, String fileName, String content) throws Exception {
+ PushOneCommit push = pushFactory.create(db, admin.getIdent(),
+ repo, commitMsg, fileName, content);
assertThat(topic).isNotEmpty();
- return push.to(git, "refs/for/master/" + topic);
+ return push.to("refs/for/master/" + name(topic));
}
- private void approve(String changeId) throws IOException {
- RestResponse r = adminSession.post(
- "/changes/" + changeId + "/revisions/current/review",
- new ReviewInput().label("Code-Review", 2));
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- r.consume();
+ private PushOneCommit.Result createChangeWithTopic()
+ throws Exception {
+ return createChangeWithTopic(testRepo, "foo2",
+ "a message", "a.txt", "content\n");
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeMessagesIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeMessagesIT.java
index 3c76355..a56a7f2 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeMessagesIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeMessagesIT.java
@@ -73,15 +73,15 @@
String changeId = createChange().getChangeId();
postMessage(changeId, "Some nits need to be fixed.");
ChangeInfo c = info(changeId);
- assertThat((Iterable<?>)c.messages).isNull();
+ assertThat(c.messages).isNull();
}
@Test
public void defaultMessage() throws Exception {
String changeId = createChange().getChangeId();
ChangeInfo c = get(changeId);
- assertThat((Iterable<?>)c.messages).isNotNull();
- assertThat((Iterable<?>)c.messages).hasSize(1);
+ assertThat(c.messages).isNotNull();
+ assertThat(c.messages).hasSize(1);
assertThat(c.messages.iterator().next().message)
.isEqualTo("Uploaded patch set 1.");
}
@@ -94,8 +94,8 @@
String secondMessage = "I like this feature.";
postMessage(changeId, secondMessage);
ChangeInfo c = get(changeId);
- assertThat((Iterable<?>)c.messages).isNotNull();
- assertThat((Iterable<?>)c.messages).hasSize(3);
+ assertThat(c.messages).isNotNull();
+ assertThat(c.messages).hasSize(3);
Iterator<ChangeMessageInfo> it = c.messages.iterator();
assertThat(it.next().message).isEqualTo("Uploaded patch set 1.");
assertMessage(firstMessage, it.next().message);
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeOwnerIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeOwnerIT.java
index 8e7daec..2229577 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeOwnerIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeOwnerIT.java
@@ -14,27 +14,22 @@
package com.google.gerrit.acceptance.rest.change;
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.GitUtil.cloneProject;
-import static com.google.gerrit.acceptance.GitUtil.initSsh;
import static com.google.gerrit.common.data.Permission.LABEL;
import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.AcceptanceTestRequestScope.Context;
import com.google.gerrit.acceptance.PushOneCommit;
-import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.acceptance.RestSession;
-import com.google.gerrit.acceptance.SshSession;
import com.google.gerrit.acceptance.TestAccount;
+import com.google.gerrit.acceptance.TestProjectInput;
import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.Permission;
import com.google.gerrit.common.data.PermissionRule;
import com.google.gerrit.extensions.api.changes.ReviewInput;
+import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.group.SystemGroupBackend;
-import org.apache.http.HttpStatus;
-import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.junit.Before;
import org.junit.Test;
@@ -45,45 +40,47 @@
private TestAccount user2;
- private RestSession sessionOwner;
- private RestSession sessionDev;
-
@Before
public void setUp() throws Exception {
- sessionOwner = new RestSession(server, user);
- SshSession sshSession = new SshSession(server, user);
- initSsh(user);
- sshSession.open();
- git = cloneProject(sshSession.getUrl() + "/" + project.get());
- sshSession.close();
+ setApiUser(user);
user2 = accounts.user2();
- sessionDev = new RestSession(server, user2);
}
@Test
+ @TestProjectInput(cloneAs = "user")
public void testChangeOwner_OwnerACLNotGranted() throws Exception {
- approve(sessionOwner, createMyChange(), HttpStatus.SC_FORBIDDEN);
+ assertApproveFails(user, createMyChange());
}
@Test
+ @TestProjectInput(cloneAs = "user")
public void testChangeOwner_OwnerACLGranted() throws Exception {
grantApproveToChangeOwner();
- approve(sessionOwner, createMyChange(), HttpStatus.SC_OK);
+ approve(user, createMyChange());
}
@Test
+ @TestProjectInput(cloneAs = "user")
public void testChangeOwner_NotOwnerACLGranted() throws Exception {
grantApproveToChangeOwner();
- approve(sessionDev, createMyChange(), HttpStatus.SC_FORBIDDEN);
+ assertApproveFails(user2, createMyChange());
}
- private void approve(RestSession s, String changeId, int expected)
- throws IOException {
- RestResponse r =
- s.post("/changes/" + changeId + "/revisions/current/review",
- new ReviewInput().label("Code-Review", 2));
- assertThat(r.getStatusCode()).isEqualTo(expected);
- r.consume();
+ private void approve(TestAccount a, String changeId) throws Exception {
+ Context old = setApiUser(a);
+ try {
+ gApi.changes().id(changeId).current().review(ReviewInput.approve());
+ } finally {
+ atrScope.set(old);
+ }
+ }
+
+ private void assertApproveFails(TestAccount a, String changeId) throws Exception {
+ try {
+ approve(a, changeId);
+ } catch (AuthException expected) {
+ // Expected.
+ }
}
private void grantApproveToChangeOwner() throws IOException,
@@ -102,9 +99,8 @@
projectCache.evict(config.getProject());
}
- private String createMyChange() throws GitAPIException,
- IOException {
- PushOneCommit push = pushFactory.create(db, user.getIdent());
- return push.to(git, "refs/for/master").getChangeId();
+ private String createMyChange() throws Exception {
+ PushOneCommit push = pushFactory.create(db, user.getIdent(), testRepo);
+ return push.to("refs/for/master").getChangeId();
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ConflictsOperatorIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ConflictsOperatorIT.java
deleted file mode 100644
index 6a1c0a6..0000000
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ConflictsOperatorIT.java
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright (C) 2013 The Android Open Source Project
-//
-// 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.
-
-package com.google.gerrit.acceptance.rest.change;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.GitUtil.checkout;
-
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.PushOneCommit;
-import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.extensions.common.ChangeInfo;
-import com.google.gson.reflect.TypeToken;
-
-import org.apache.http.HttpStatus;
-import org.eclipse.jgit.api.Git;
-import org.eclipse.jgit.api.errors.GitAPIException;
-import org.junit.Test;
-
-import java.io.IOException;
-import java.util.Set;
-
-public class ConflictsOperatorIT extends AbstractDaemonTest {
-
- private int count;
-
- @Test
- public void noConflictingChanges() throws Exception {
- PushOneCommit.Result change = createChange(git, true);
- createChange(git, false);
-
- Set<String> changes = queryConflictingChanges(change);
- assertThat((Iterable<?>)changes).isEmpty();
- }
-
- @Test
- public void conflictingChanges() throws Exception {
- PushOneCommit.Result change = createChange(git, true);
- PushOneCommit.Result conflictingChange1 = createChange(git, true);
- PushOneCommit.Result conflictingChange2 = createChange(git, true);
- createChange(git, false);
-
- Set<String> changes = queryConflictingChanges(change);
- assertChanges(changes, conflictingChange1, conflictingChange2);
- }
-
- private PushOneCommit.Result createChange(Git git, boolean conflicting)
- throws GitAPIException, IOException {
- checkout(git, "origin/master");
- String file = conflicting ? "test.txt" : "test-" + count + ".txt";
- PushOneCommit push =
- pushFactory.create(db, admin.getIdent(), "Change " + count, file,
- "content " + count);
- count++;
- return push.to(git, "refs/for/master");
- }
-
- private Set<String> queryConflictingChanges(PushOneCommit.Result change)
- throws IOException {
- RestResponse r =
- adminSession.get("/changes/?q=conflicts:" + change.getChangeId());
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- Set<ChangeInfo> changes =
- newGson().fromJson(r.getReader(),
- new TypeToken<Set<ChangeInfo>>() {}.getType());
- r.consume();
- return ImmutableSet.copyOf(Iterables.transform(changes,
- new Function<ChangeInfo, String>() {
- @Override
- public String apply(ChangeInfo input) {
- return input.id;
- }
- }));
- }
-
- private void assertChanges(Set<String> actualChanges,
- PushOneCommit.Result... expectedChanges) {
- assertThat((Iterable<?>)actualChanges).hasSize(expectedChanges.length);
- for (PushOneCommit.Result c : expectedChanges) {
- assertThat(actualChanges.contains(id(c))).isTrue();
- }
- }
-
- private String id(PushOneCommit.Result change) {
- return project.get() + "~master~" + change.getChangeId();
- }
-}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java
index 311161a..d92270c 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java
@@ -16,18 +16,22 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.TruthJUnit.assume;
+import static org.junit.Assert.fail;
import com.google.common.collect.Iterables;
import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.extensions.client.ChangeStatus;
import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.extensions.restapi.BadRequestException;
+import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
+import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.testutil.ConfigSuite;
-import org.apache.http.HttpStatus;
import org.eclipse.jgit.lib.Config;
import org.junit.Test;
+@NoHttpd
public class CreateChangeIT extends AbstractDaemonTest {
@ConfigSuite.Config
public static Config allowDraftsDisabled() {
@@ -38,9 +42,8 @@
public void createEmptyChange_MissingBranch() throws Exception {
ChangeInfo ci = new ChangeInfo();
ci.project = project.get();
- RestResponse r = adminSession.post("/changes/", ci);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_BAD_REQUEST);
- assertThat(r.getEntityContent()).contains("branch must be non-empty");
+ assertCreateFails(ci, BadRequestException.class,
+ "branch must be non-empty");
}
@Test
@@ -48,37 +51,34 @@
ChangeInfo ci = new ChangeInfo();
ci.project = project.get();
ci.branch = "master";
- RestResponse r = adminSession.post("/changes/", ci);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_BAD_REQUEST);
- assertThat(r.getEntityContent()).contains("commit message must be non-empty");
+ assertCreateFails(ci, BadRequestException.class,
+ "commit message must be non-empty");
}
@Test
public void createEmptyChange_InvalidStatus() throws Exception {
ChangeInfo ci = newChangeInfo(ChangeStatus.SUBMITTED);
- RestResponse r = adminSession.post("/changes/", ci);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_BAD_REQUEST);
- assertThat(r.getEntityContent()).contains("unsupported change status");
+ assertCreateFails(ci, BadRequestException.class,
+ "unsupported change status");
}
@Test
public void createNewChange() throws Exception {
- assertChange(newChangeInfo(ChangeStatus.NEW));
+ assertCreateSucceeds(newChangeInfo(ChangeStatus.NEW));
}
@Test
public void createDraftChange() throws Exception {
assume().that(isAllowDrafts()).isTrue();
- assertChange(newChangeInfo(ChangeStatus.DRAFT));
+ assertCreateSucceeds(newChangeInfo(ChangeStatus.DRAFT));
}
@Test
public void createDraftChangeNotAllowed() throws Exception {
assume().that(isAllowDrafts()).isFalse();
ChangeInfo ci = newChangeInfo(ChangeStatus.DRAFT);
- RestResponse r = adminSession.post("/changes/", ci);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_METHOD_NOT_ALLOWED);
- assertThat(r.getEntityContent()).contains("draft workflow is disabled");
+ assertCreateFails(ci, MethodNotAllowedException.class,
+ "draft workflow is disabled");
}
private ChangeInfo newChangeInfo(ChangeStatus status) {
@@ -91,13 +91,8 @@
return in;
}
- private void assertChange(ChangeInfo in) throws Exception {
- RestResponse r = adminSession.post("/changes/", in);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_CREATED);
-
- ChangeInfo info = newGson().fromJson(r.getReader(), ChangeInfo.class);
- ChangeInfo out = get(info.changeId);
-
+ private void assertCreateSucceeds(ChangeInfo in) throws Exception {
+ ChangeInfo out = gApi.changes().create(in).get();
assertThat(out.branch).isEqualTo(in.branch);
assertThat(out.subject).isEqualTo(in.subject);
assertThat(out.topic).isEqualTo(in.topic);
@@ -107,6 +102,18 @@
assertThat(booleanToDraftStatus(draft)).isEqualTo(in.status);
}
+ private void assertCreateFails(ChangeInfo in,
+ Class<? extends RestApiException> errType, String errSubstring)
+ throws Exception {
+ try {
+ gApi.changes().create(in);
+ fail("Expected " + errType.getSimpleName());
+ } catch (RestApiException expected) {
+ assertThat(expected).isInstanceOf(errType);
+ assertThat(expected.getMessage()).contains(errSubstring);
+ }
+ }
+
private ChangeStatus booleanToDraftStatus(Boolean draft) {
if (draft == null) {
return ChangeStatus.NEW;
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/DeleteDraftPatchSetIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/DeleteDraftPatchSetIT.java
index 871b1cc..47d071f 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/DeleteDraftPatchSetIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/DeleteDraftPatchSetIT.java
@@ -29,7 +29,6 @@
import com.google.gwtorm.server.OrmException;
import org.apache.http.HttpStatus;
-import org.eclipse.jgit.api.errors.GitAPIException;
import org.junit.Test;
import java.io.IOException;
@@ -40,7 +39,7 @@
public void deletePatchSet() throws Exception {
String changeId = createChange().getChangeId();
PatchSet ps = getCurrentPatchSet(changeId);
- String triplet = "p~master~" + changeId;
+ String triplet = project.get() + "~master~" + changeId;
ChangeInfo c = get(triplet);
assertThat(c.id).isEqualTo(triplet);
assertThat(c.status).isEqualTo(ChangeStatus.NEW);
@@ -53,7 +52,7 @@
public void deleteDraftPatchSetNoACL() throws Exception {
String changeId = createDraftChangeWith2PS();
PatchSet ps = getCurrentPatchSet(changeId);
- String triplet = "p~master~" + changeId;
+ String triplet = project.get() + "~master~" + changeId;
ChangeInfo c = get(triplet);
assertThat(c.id).isEqualTo(triplet);
assertThat(c.status).isEqualTo(ChangeStatus.DRAFT);
@@ -66,26 +65,25 @@
public void deleteDraftPatchSetAndChange() throws Exception {
String changeId = createDraftChangeWith2PS();
PatchSet ps = getCurrentPatchSet(changeId);
- String triplet = "p~master~" + changeId;
+ String triplet = project.get() + "~master~" + changeId;
ChangeInfo c = get(triplet);
assertThat(c.id).isEqualTo(triplet);
assertThat(c.status).isEqualTo(ChangeStatus.DRAFT);
RestResponse r = deletePatchSet(changeId, ps, adminSession);
assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_NO_CONTENT);
- assertThat(getChange(changeId).patches().size()).isEqualTo(1);
+ assertThat(getChange(changeId).patchSets()).hasSize(1);
ps = getCurrentPatchSet(changeId);
r = deletePatchSet(changeId, ps, adminSession);
assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_NO_CONTENT);
assertThat(queryProvider.get().byKeyPrefix(changeId)).isEmpty();
}
- private String createDraftChangeWith2PS() throws GitAPIException,
- IOException {
- PushOneCommit push = pushFactory.create(db, admin.getIdent());
- Result result = push.to(git, "refs/drafts/master");
- push = pushFactory.create(db, admin.getIdent(), PushOneCommit.SUBJECT,
+ private String createDraftChangeWith2PS() throws Exception {
+ PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo);
+ Result result = push.to("refs/drafts/master");
+ push = pushFactory.create(db, admin.getIdent(), testRepo, PushOneCommit.SUBJECT,
"b.txt", "4711", result.getChangeId());
- return push.to(git, "refs/drafts/master").getChangeId();
+ return push.to("refs/drafts/master").getChangeId();
}
private PatchSet getCurrentPatchSet(String changeId) throws OrmException {
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/DraftChangeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/DraftChangeIT.java
index a3809a9..834b873 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/DraftChangeIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/DraftChangeIT.java
@@ -45,7 +45,7 @@
PushOneCommit.Result result = createChange();
result.assertOkStatus();
String changeId = result.getChangeId();
- String triplet = "p~master~" + changeId;
+ String triplet = project.get() + "~master~" + changeId;
ChangeInfo c = get(triplet);
assertThat(c.id).isEqualTo(triplet);
assertThat(c.status).isEqualTo(ChangeStatus.NEW);
@@ -60,7 +60,7 @@
PushOneCommit.Result result = createDraftChange();
result.assertOkStatus();
String changeId = result.getChangeId();
- String triplet = "p~master~" + changeId;
+ String triplet = project.get() + "~master~" + changeId;
ChangeInfo c = get(triplet);
assertThat(c.id).isEqualTo(triplet);
assertThat(c.status).isEqualTo(ChangeStatus.DRAFT);
@@ -74,7 +74,7 @@
PushOneCommit.Result result = createDraftChange();
result.assertOkStatus();
String changeId = result.getChangeId();
- String triplet = "p~master~" + changeId;
+ String triplet = project.get() + "~master~" + changeId;
ChangeInfo c = get(triplet);
assertThat(c.id).isEqualTo(triplet);
assertThat(c.status).isEqualTo(ChangeStatus.DRAFT);
@@ -90,7 +90,7 @@
PushOneCommit.Result result = createDraftChange();
result.assertOkStatus();
String changeId = result.getChangeId();
- String triplet = "p~master~" + changeId;
+ String triplet = project.get() + "~master~" + changeId;
ChangeInfo c = get(triplet);
assertThat(c.id).isEqualTo(triplet);
assertThat(c.status).isEqualTo(ChangeStatus.DRAFT);
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/HashtagsIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/HashtagsIT.java
index 26d6a1e..6ef53ff 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/HashtagsIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/HashtagsIT.java
@@ -16,218 +16,206 @@
import static com.google.common.truth.Truth.assertThat;
-import com.google.common.base.CharMatcher;
-import com.google.common.base.Splitter;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.google.common.truth.IterableSubject;
import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.acceptance.NoHttpd;
+import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.extensions.api.changes.HashtagsInput;
import com.google.gerrit.server.notedb.NotesMigration;
import com.google.gerrit.testutil.ConfigSuite;
-import com.google.gson.reflect.TypeToken;
-import org.apache.http.HttpStatus;
import org.eclipse.jgit.lib.Config;
import org.junit.Test;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-
+@NoHttpd
public class HashtagsIT extends AbstractDaemonTest {
@ConfigSuite.Default
public static Config defaultConfig() {
return NotesMigration.allEnabledConfig();
}
- private void assertResult(RestResponse r, List<String> expected)
- throws IOException {
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- List<String> result = toHashtagList(r);
- assertThat(result).containsExactlyElementsIn(expected);
- }
-
@Test
public void testGetNoHashtags() throws Exception {
- // GET hashtags on a change with no hashtags returns an empty list
- String changeId = createChange().getChangeId();
- assertResult(GET(changeId), ImmutableList.<String>of());
+ // Get on a change with no hashtags returns an empty list.
+ PushOneCommit.Result r = createChange();
+ assertThatGet(r).isEmpty();
}
@Test
public void testAddSingleHashtag() throws Exception {
- String changeId = createChange().getChangeId();
+ PushOneCommit.Result r = createChange();
- // POST adding a single hashtag returns a single hashtag
- List<String> expected = Arrays.asList("tag2");
- assertResult(POST(changeId, "tag2", null), expected);
- assertResult(GET(changeId), expected);
+ // Adding a single hashtag returns a single hashtag.
+ addHashtags(r, "tag2");
+ assertThatGet(r).containsExactly("tag2");
- // POST adding another single hashtag to change that already has one
- // hashtag returns a sorted list of hashtags with existing and new
- expected = Arrays.asList("tag1", "tag2");
- assertResult(POST(changeId, "tag1", null), expected);
- assertResult(GET(changeId), expected);
+ // Adding another single hashtag to change that already has one hashtag
+ // returns a sorted list of hashtags with existing and new.
+ addHashtags(r, "tag1");
+ assertThatGet(r).containsExactly("tag1", "tag2").inOrder();
}
@Test
public void testAddMultipleHashtags() throws Exception {
- String changeId = createChange().getChangeId();
+ PushOneCommit.Result r = createChange();
- // POST adding multiple hashtags returns a sorted list of hashtags
- List<String> expected = Arrays.asList("tag1", "tag3");
- assertResult(POST(changeId, "tag3, tag1", null), expected);
- assertResult(GET(changeId), expected);
+ // Adding multiple hashtags returns a sorted list of hashtags.
+ addHashtags(r, "tag3", "tag1");
+ assertThatGet(r).containsExactly("tag1", "tag3").inOrder();
- // POST adding multiple hashtags to change that already has hashtags
- // returns a sorted list of hashtags with existing and new
- expected = Arrays.asList("tag1", "tag2", "tag3", "tag4");
- assertResult(POST(changeId, "tag2, tag4", null), expected);
- assertResult(GET(changeId), expected);
+ // Adding multiple hashtags to change that already has hashtags returns a
+ // sorted list of hashtags with existing and new.
+ addHashtags(r, "tag2", "tag4");
+ assertThatGet(r).containsExactly("tag1", "tag2", "tag3", "tag4").inOrder();
}
@Test
public void testAddAlreadyExistingHashtag() throws Exception {
- // POST adding a hashtag that already exists on the change returns a
- // sorted list of hashtags without duplicates
- String changeId = createChange().getChangeId();
- List<String> expected = Arrays.asList("tag2");
- assertResult(POST(changeId, "tag2", null), expected);
- assertResult(GET(changeId), expected);
- assertResult(POST(changeId, "tag2", null), expected);
- assertResult(GET(changeId), expected);
- expected = Arrays.asList("tag1", "tag2");
- assertResult(POST(changeId, "tag2, tag1", null), expected);
- assertResult(GET(changeId), expected);
+ // Adding a hashtag that already exists on the change returns a sorted list
+ // of hashtags without duplicates.
+ PushOneCommit.Result r = createChange();
+ addHashtags(r, "tag2");
+ assertThatGet(r).containsExactly("tag2");
+ addHashtags(r, "tag2");
+ assertThatGet(r).containsExactly("tag2");
+ addHashtags(r, "tag1", "tag2");
+ assertThatGet(r).containsExactly("tag1", "tag2").inOrder();
}
@Test
public void testHashtagsWithPrefix() throws Exception {
- String changeId = createChange().getChangeId();
+ PushOneCommit.Result r = createChange();
- // Leading # is stripped from added tag
- List<String> expected = Arrays.asList("tag1");
- assertResult(POST(changeId, "#tag1", null), expected);
- assertResult(GET(changeId), expected);
+ // Leading # is stripped from added tag.
+ addHashtags(r, "#tag1");
+ assertThatGet(r).containsExactly("tag1");
- // Leading # is stripped from multiple added tags
- expected = Arrays.asList("tag1", "tag2", "tag3");
- assertResult(POST(changeId, "#tag2, #tag3", null), expected);
- assertResult(GET(changeId), expected);
+ // Leading # is stripped from multiple added tags.
+ addHashtags(r, "#tag2", "#tag3");
+ assertThatGet(r).containsExactly("tag1", "tag2", "tag3").inOrder();
- // Leading # is stripped from removed tag
- expected = Arrays.asList("tag1", "tag3");
- assertResult(POST(changeId, null, "#tag2"), expected);
- assertResult(GET(changeId), expected);
+ // Leading # is stripped from removed tag.
+ removeHashtags(r, "#tag2");
+ assertThatGet(r).containsExactly("tag1", "tag3").inOrder();
- // Leading # is stripped from multiple removed tags
- expected = Collections.emptyList();
- assertResult(POST(changeId, null, "#tag1, #tag3"), expected);
- assertResult(GET(changeId), expected);
+ // Leading # is stripped from multiple removed tags.
+ removeHashtags(r, "#tag1", "#tag3");
+ assertThatGet(r).isEmpty();
- // Leading # and space are stripped from added tag
- expected = Arrays.asList("tag1");
- assertResult(POST(changeId, "# tag1", null), expected);
- assertResult(GET(changeId), expected);
+ // Leading # and space are stripped from added tag.
+ addHashtags(r, "# tag1");
+ assertThatGet(r).containsExactly("tag1");
- // Multiple leading # are stripped from added tag
- expected = Arrays.asList("tag1", "tag2");
- assertResult(POST(changeId, "##tag2", null), expected);
- assertResult(GET(changeId), expected);
+ // Multiple leading # are stripped from added tag.
+ addHashtags(r, "##tag2");
+ assertThatGet(r).containsExactly("tag1", "tag2").inOrder();
- // Multiple leading spaces and # are stripped from added tag
- expected = Arrays.asList("tag1", "tag2", "tag3");
- assertResult(POST(changeId, " # # tag3", null), expected);
- assertResult(GET(changeId), expected);
+ // Multiple leading spaces and # are stripped from added tag.
+ addHashtags(r, "# # tag3");
+ assertThatGet(r).containsExactly("tag1", "tag2", "tag3").inOrder();
}
@Test
public void testRemoveSingleHashtag() throws Exception {
- // POST removing a single tag from a change that only has that tag
- // returns an empty list
- String changeId = createChange().getChangeId();
- List<String> expected = Arrays.asList("tag1");
- assertResult(POST(changeId, "tag1", null), expected);
- assertResult(POST(changeId, null, "tag1"), ImmutableList.<String>of());
- assertResult(GET(changeId), ImmutableList.<String>of());
+ // Removing a single tag from a change that only has that tag returns an
+ // empty list.
+ PushOneCommit.Result r = createChange();
+ addHashtags(r, "tag1");
+ assertThatGet(r).containsExactly("tag1");
+ removeHashtags(r, "tag1");
+ assertThatGet(r).isEmpty();
- // POST removing a single tag from a change that has multiple tags
- // returns a sorted list of remaining tags
- expected = Arrays.asList("tag1", "tag2", "tag3");
- assertResult(POST(changeId, "tag1, tag2, tag3", null), expected);
- expected = Arrays.asList("tag1", "tag3");
- assertResult(POST(changeId, null, "tag2"), expected);
- assertResult(GET(changeId), expected);
+ // Removing a single tag from a change that has multiple tags returns a
+ // sorted list of remaining tags.
+ addHashtags(r, "tag1", "tag2", "tag3");
+ removeHashtags(r, "tag2");
+ assertThatGet(r).containsExactly("tag1", "tag3").inOrder();
}
@Test
public void testRemoveMultipleHashtags() throws Exception {
- // POST removing multiple tags from a change that only has those tags
- // returns an empty list
- String changeId = createChange().getChangeId();
- List<String> expected = Arrays.asList("tag1", "tag2");
- assertResult(POST(changeId, "tag1, tag2", null), expected);
- assertResult(POST(changeId, null, "tag1, tag2"), ImmutableList.<String>of());
- assertResult(GET(changeId), ImmutableList.<String>of());
+ // Removing multiple tags from a change that only has those tags returns an
+ // empty list.
+ PushOneCommit.Result r = createChange();
+ addHashtags(r, "tag1", "tag2");
+ assertThatGet(r).containsExactly("tag1", "tag2").inOrder();
+ removeHashtags(r, "tag1", "tag2");
+ assertThatGet(r).isEmpty();
- // POST removing multiple tags from a change that has multiple changes
- // returns a sorted list of remaining changes
- expected = Arrays.asList("tag1", "tag2", "tag3", "tag4");
- assertResult(POST(changeId, "tag1, tag2, tag3, tag4", null), expected);
- expected = Arrays.asList("tag2", "tag4");
- assertResult(POST(changeId, null, "tag1, tag3"), expected);
- assertResult(GET(changeId), expected);
+ // Removing multiple tags from a change that has multiple tags returns a
+ // sorted list of remaining tags.
+ addHashtags(r, "tag1", "tag2", "tag3", "tag4");
+ assertThatGet(r).containsExactly("tag1", "tag2", "tag3", "tag4").inOrder();
+ removeHashtags(r, "tag2", "tag4");
+ assertThatGet(r).containsExactly("tag1", "tag3").inOrder();
}
@Test
public void testRemoveNotExistingHashtag() throws Exception {
- // POST removing a single hashtag from change that has no hashtags
- // returns an empty list
- String changeId = createChange().getChangeId();
- assertResult(POST(changeId, null, "tag1"), ImmutableList.<String>of());
- assertResult(GET(changeId), ImmutableList.<String>of());
+ // Removing a single hashtag from change that has no hashtags returns an
+ // empty list.
+ PushOneCommit.Result r = createChange();
+ removeHashtags(r, "tag1");
+ assertThatGet(r).isEmpty();
- // POST removing a single non-existing tag from a change that only
- // has one other tag returns a list of only one tag
- List<String> expected = Arrays.asList("tag1");
- assertResult(POST(changeId, "tag1", null), expected);
- assertResult(POST(changeId, null, "tag4"), expected);
- assertResult(GET(changeId), expected);
+ // Removing a single non-existing tag from a change that only has one other
+ // tag returns a list of only one tag.
+ addHashtags(r, "tag1");
+ removeHashtags(r, "tag4");
+ assertThatGet(r).containsExactly("tag1");
- // POST removing a single non-existing tag from a change that has multiple
- // tags returns a sorted list of tags without any deleted
- expected = Arrays.asList("tag1", "tag2", "tag3");
- assertResult(POST(changeId, "tag1, tag2, tag3", null), expected);
- assertResult(POST(changeId, null, "tag4"), expected);
- assertResult(GET(changeId), expected);
+ // Removing a single non-existing tag from a change that has multiple tags
+ // returns a sorted list of tags without any deleted.
+ addHashtags(r, "tag1", "tag2", "tag3");
+ removeHashtags(r, "tag4");
+ assertThatGet(r).containsExactly("tag1", "tag2", "tag3").inOrder();
}
- private RestResponse GET(String changeId) throws IOException {
- return adminSession.get("/changes/" + changeId + "/hashtags/");
- }
-
- private RestResponse POST(String changeId, String toAdd, String toRemove)
- throws IOException {
+ @Test
+ public void testAddAndRemove() throws Exception {
+ // Adding and remove hashtags in a single request performs correctly.
+ PushOneCommit.Result r = createChange();
+ addHashtags(r, "tag1", "tag2");
HashtagsInput input = new HashtagsInput();
- if (toAdd != null) {
- input.add = new HashSet<>(
- Lists.newArrayList(Splitter.on(CharMatcher.anyOf(",")).split(toAdd)));
- }
- if (toRemove != null) {
- input.remove = new HashSet<>(
- Lists.newArrayList(Splitter.on(CharMatcher.anyOf(",")).split(toRemove)));
- }
- return adminSession.post("/changes/" + changeId + "/hashtags/", input);
+ input.add = Sets.newHashSet("tag3", "tag4");
+ input.remove = Sets.newHashSet("tag1");
+ gApi.changes().id(r.getChange().getId().get()).setHashtags(input);
+ assertThatGet(r).containsExactly("tag2", "tag3", "tag4");
+
+ // Adding and removing the same hashtag actually removes it.
+ addHashtags(r, "tag1", "tag2");
+ input = new HashtagsInput();
+ input.add = Sets.newHashSet("tag3", "tag4");
+ input.remove = Sets.newHashSet("tag3");
+ gApi.changes().id(r.getChange().getId().get()).setHashtags(input);
+ assertThatGet(r).containsExactly("tag1", "tag2", "tag4");
}
- private static List<String> toHashtagList(RestResponse r)
- throws IOException {
- List<String> result =
- newGson().fromJson(r.getReader(),
- new TypeToken<List<String>>() {}.getType());
- return result;
+ private IterableSubject<
+ ? extends IterableSubject<?, String, Iterable<String>>,
+ String, Iterable<String>>
+ assertThatGet(PushOneCommit.Result r) throws Exception {
+ return assertThat(gApi.changes()
+ .id(r.getChange().getId().get())
+ .getHashtags());
+ }
+
+ private void addHashtags(PushOneCommit.Result r, String... toAdd)
+ throws Exception {
+ HashtagsInput input = new HashtagsInput();
+ input.add = Sets.newHashSet(toAdd);
+ gApi.changes()
+ .id(r.getChange().getId().get())
+ .setHashtags(input);
+ }
+
+ private void removeHashtags(PushOneCommit.Result r, String... toRemove)
+ throws Exception {
+ HashtagsInput input = new HashtagsInput();
+ input.remove = Sets.newHashSet(toRemove);
+ gApi.changes()
+ .id(r.getChange().getId().get())
+ .setHashtags(input);
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ListChangesOptionsIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ListChangesOptionsIT.java
index e649415..3728a51 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ListChangesOptionsIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ListChangesOptionsIT.java
@@ -51,8 +51,8 @@
String subject = "Change subject";
String fileName = "a.txt";
PushOneCommit push = pushFactory.create(
- db, admin.getIdent(), subject, fileName, content, baseChangeId);
- PushOneCommit.Result r = push.to(git, "refs/for/master");
+ db, admin.getIdent(), testRepo, subject, fileName, content, baseChangeId);
+ PushOneCommit.Result r = push.to("refs/for/master");
r.assertOkStatus();
return r;
}
@@ -68,7 +68,7 @@
public void currentRevision() throws Exception {
ChangeInfo c = get(changeId, CURRENT_REVISION);
assertThat(c.currentRevision).isEqualTo(commitId(2));
- assertThat((Iterable<?>)c.revisions.keySet()).containsAllIn(
+ assertThat(c.revisions.keySet()).containsAllIn(
ImmutableSet.of(commitId(2)));
assertThat(c.revisions.get(commitId(2))._number).isEqualTo(3);
}
@@ -78,7 +78,7 @@
ChangeInfo c = get(changeId, CURRENT_REVISION, MESSAGES);
assertThat(c.revisions).hasSize(1);
assertThat(c.currentRevision).isEqualTo(commitId(2));
- assertThat((Iterable<?>)c.revisions.keySet()).containsAllIn(
+ assertThat(c.revisions.keySet()).containsAllIn(
ImmutableSet.of(commitId(2)));
assertThat(c.revisions.get(commitId(2))._number).isEqualTo(3);
}
@@ -87,7 +87,7 @@
public void allRevisions() throws Exception {
ChangeInfo c = get(changeId, ALL_REVISIONS);
assertThat(c.currentRevision).isEqualTo(commitId(2));
- assertThat((Iterable<?>)c.revisions.keySet()).containsAllIn(
+ assertThat(c.revisions.keySet()).containsAllIn(
ImmutableSet.of(commitId(0), commitId(1), commitId(2)));
assertThat(c.revisions.get(commitId(0))._number).isEqualTo(1);
assertThat(c.revisions.get(commitId(1))._number).isEqualTo(2);
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByCherryPickIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByCherryPickIT.java
index 4863c3e..c00a260 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByCherryPickIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByCherryPickIT.java
@@ -15,16 +15,16 @@
package com.google.gerrit.acceptance.rest.change;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.GitUtil.checkout;
import com.google.common.collect.Iterables;
import com.google.gerrit.acceptance.PushOneCommit;
+import com.google.gerrit.acceptance.TestProjectInput;
import com.google.gerrit.extensions.client.ChangeStatus;
+import com.google.gerrit.extensions.client.InheritableBoolean;
import com.google.gerrit.extensions.client.ListChangesOption;
import com.google.gerrit.extensions.client.SubmitType;
import com.google.gerrit.extensions.common.ChangeInfo;
-import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Test;
@@ -39,28 +39,26 @@
@Test
public void submitWithCherryPickIfFastForwardPossible() throws Exception {
- Git git = createProject();
- PushOneCommit.Result change = createChange(git);
+ PushOneCommit.Result change = createChange();
submit(change.getChangeId());
- assertCherryPick(git, false);
+ assertCherryPick(testRepo, false);
assertThat(getRemoteHead().getParent(0))
.isEqualTo(change.getCommit().getParent(0));
}
@Test
public void submitWithCherryPick() throws Exception {
- Git git = createProject();
RevCommit initialHead = getRemoteHead();
PushOneCommit.Result change =
- createChange(git, "Change 1", "a.txt", "content");
+ createChange("Change 1", "a.txt", "content");
submit(change.getChangeId());
RevCommit oldHead = getRemoteHead();
- checkout(git, initialHead.getId().getName());
+ testRepo.reset(initialHead);
PushOneCommit.Result change2 =
- createChange(git, "Change 2", "b.txt", "other content");
+ createChange("Change 2", "b.txt", "other content");
submit(change2.getChangeId());
- assertCherryPick(git, false);
+ assertCherryPick(testRepo, false);
RevCommit newHead = getRemoteHead();
assertThat(newHead.getParentCount()).isEqualTo(1);
assertThat(newHead.getParent(0)).isEqualTo(oldHead);
@@ -70,22 +68,21 @@
}
@Test
+ @TestProjectInput(useContentMerge = InheritableBoolean.TRUE)
public void submitWithContentMerge() throws Exception {
- Git git = createProject();
- setUseContentMerge();
PushOneCommit.Result change =
- createChange(git, "Change 1", "a.txt", "aaa\nbbb\nccc\n");
+ createChange("Change 1", "a.txt", "aaa\nbbb\nccc\n");
submit(change.getChangeId());
PushOneCommit.Result change2 =
- createChange(git, "Change 2", "a.txt", "aaa\nbbb\nccc\nddd\n");
+ createChange("Change 2", "a.txt", "aaa\nbbb\nccc\nddd\n");
submit(change2.getChangeId());
RevCommit oldHead = getRemoteHead();
- checkout(git, change.getCommitId().getName());
+ testRepo.reset(change.getCommitId());
PushOneCommit.Result change3 =
- createChange(git, "Change 3", "a.txt", "bbb\nccc\n");
+ createChange("Change 3", "a.txt", "bbb\nccc\n");
submit(change3.getChangeId());
- assertCherryPick(git, true);
+ assertCherryPick(testRepo, true);
RevCommit newHead = getRemoteHead();
assertThat(newHead.getParent(0)).isEqualTo(oldHead);
assertApproved(change3.getChangeId());
@@ -95,18 +92,17 @@
}
@Test
+ @TestProjectInput(useContentMerge = InheritableBoolean.TRUE)
public void submitWithContentMerge_Conflict() throws Exception {
- Git git = createProject();
- setUseContentMerge();
RevCommit initialHead = getRemoteHead();
PushOneCommit.Result change =
- createChange(git, "Change 1", "a.txt", "content");
+ createChange("Change 1", "a.txt", "content");
submit(change.getChangeId());
RevCommit oldHead = getRemoteHead();
- checkout(git, initialHead.getId().getName());
+ testRepo.reset(initialHead);
PushOneCommit.Result change2 =
- createChange(git, "Change 2", "a.txt", "other content");
+ createChange("Change 2", "a.txt", "other content");
submitWithConflict(change2.getChangeId());
assertThat(getRemoteHead()).isEqualTo(oldHead);
assertCurrentRevision(change2.getChangeId(), 1, change2.getCommitId());
@@ -115,19 +111,18 @@
@Test
public void submitOutOfOrder() throws Exception {
- Git git = createProject();
RevCommit initialHead = getRemoteHead();
PushOneCommit.Result change =
- createChange(git, "Change 1", "a.txt", "content");
+ createChange("Change 1", "a.txt", "content");
submit(change.getChangeId());
RevCommit oldHead = getRemoteHead();
- checkout(git, initialHead.getId().getName());
- createChange(git, "Change 2", "b.txt", "other content");
+ testRepo.reset(initialHead);
+ createChange("Change 2", "b.txt", "other content");
PushOneCommit.Result change3 =
- createChange(git, "Change 3", "c.txt", "different content");
+ createChange("Change 3", "c.txt", "different content");
submit(change3.getChangeId());
- assertCherryPick(git, false);
+ assertCherryPick(testRepo, false);
RevCommit newHead = getRemoteHead();
assertThat(newHead.getParent(0)).isEqualTo(oldHead);
assertApproved(change3.getChangeId());
@@ -138,17 +133,16 @@
@Test
public void submitOutOfOrder_Conflict() throws Exception {
- Git git = createProject();
RevCommit initialHead = getRemoteHead();
PushOneCommit.Result change =
- createChange(git, "Change 1", "a.txt", "content");
+ createChange("Change 1", "a.txt", "content");
submit(change.getChangeId());
RevCommit oldHead = getRemoteHead();
- checkout(git, initialHead.getId().getName());
- createChange(git, "Change 2", "b.txt", "other content");
+ testRepo.reset(initialHead);
+ createChange("Change 2", "b.txt", "other content");
PushOneCommit.Result change3 =
- createChange(git, "Change 3", "b.txt", "different content");
+ createChange("Change 3", "b.txt", "different content");
submitWithConflict(change3.getChangeId());
assertThat(getRemoteHead()).isEqualTo(oldHead);
assertCurrentRevision(change3.getChangeId(), 1, change3.getCommitId());
@@ -157,17 +151,16 @@
@Test
public void submitMultipleChanges() throws Exception {
- Git git = createProject();
RevCommit initialHead = getRemoteHead();
- checkout(git, initialHead.getId().getName());
- PushOneCommit.Result change2 = createChange(git, "Change 2", "b", "b");
+ testRepo.reset(initialHead);
+ PushOneCommit.Result change2 = createChange("Change 2", "b", "b");
- checkout(git, initialHead.getId().getName());
- PushOneCommit.Result change3 = createChange(git, "Change 3", "c", "c");
+ testRepo.reset(initialHead);
+ PushOneCommit.Result change3 = createChange("Change 3", "c", "c");
- checkout(git, initialHead.getId().getName());
- PushOneCommit.Result change4 = createChange(git, "Change 4", "d", "d");
+ testRepo.reset(initialHead);
+ PushOneCommit.Result change4 = createChange("Change 4", "d", "d");
submitStatusOnly(change2.getChangeId());
submitStatusOnly(change3.getChangeId());
@@ -191,12 +184,11 @@
@Test
public void submitDependentNonConflictingChangesOutOfOrder() throws Exception {
- Git git = createProject();
RevCommit initialHead = getRemoteHead();
- checkout(git, initialHead.getId().getName());
- PushOneCommit.Result change2 = createChange(git, "Change 2", "b", "b");
- PushOneCommit.Result change3 = createChange(git, "Change 3", "c", "c");
+ testRepo.reset(initialHead);
+ PushOneCommit.Result change2 = createChange("Change 2", "b", "b");
+ PushOneCommit.Result change3 = createChange("Change 3", "c", "c");
assertThat(change3.getCommit().getParent(0)).isEqualTo(change2.getCommit());
// Submit succeeds; change3 is successfully cherry-picked onto head.
@@ -220,12 +212,11 @@
@Test
public void submitDependentConflictingChangesOutOfOrder() throws Exception {
- Git git = createProject();
RevCommit initialHead = getRemoteHead();
- checkout(git, initialHead.getId().getName());
- PushOneCommit.Result change2 = createChange(git, "Change 2", "b", "b1");
- PushOneCommit.Result change3 = createChange(git, "Change 3", "b", "b2");
+ testRepo.reset(initialHead);
+ PushOneCommit.Result change2 = createChange("Change 2", "b", "b1");
+ PushOneCommit.Result change3 = createChange("Change 3", "b", "b2");
assertThat(change3.getCommit().getParent(0)).isEqualTo(change2.getCommit());
// Submit fails; change3 contains the delta "b1" -> "b2", which cannot be
@@ -244,14 +235,13 @@
@Test
public void submitSubsetOfDependentChanges() throws Exception {
- Git git = createProject();
RevCommit initialHead = getRemoteHead();
- checkout(git, initialHead.getId().getName());
- createChange(git, "Change 2", "b", "b");
- PushOneCommit.Result change3 = createChange(git, "Change 3", "c", "c");
- createChange(git, "Change 4", "d", "d");
- PushOneCommit.Result change5 = createChange(git, "Change 5", "e", "e");
+ testRepo.reset(initialHead);
+ createChange("Change 2", "b", "b");
+ PushOneCommit.Result change3 = createChange("Change 3", "c", "c");
+ createChange("Change 4", "d", "d");
+ PushOneCommit.Result change5 = createChange("Change 5", "e", "e");
// Out of the above, only submit 3 and 5.
submitStatusOnly(change3.getChangeId());
@@ -271,17 +261,16 @@
@Test
public void submitChangeAfterParentFailsDueToConflict() throws Exception {
- Git git = createProject();
RevCommit initialHead = getRemoteHead();
- checkout(git, initialHead.getId().getName());
- PushOneCommit.Result change2 = createChange(git, "Change 2", "b", "b1");
+ testRepo.reset(initialHead);
+ PushOneCommit.Result change2 = createChange("Change 2", "b", "b1");
submit(change2.getChangeId());
- checkout(git, initialHead.getId().getName());
- PushOneCommit.Result change3 = createChange(git, "Change 3", "b", "b2");
+ testRepo.reset(initialHead);
+ PushOneCommit.Result change3 = createChange("Change 3", "b", "b2");
assertThat(change3.getCommit().getParent(0)).isEqualTo(initialHead);
- PushOneCommit.Result change4 = createChange(git, "Change 3", "c", "c3");
+ PushOneCommit.Result change4 = createChange("Change 3", "c", "c3");
submitStatusOnly(change3.getChangeId());
submitStatusOnly(change4.getChangeId());
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByFastForwardIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByFastForwardIT.java
index d4e7e849..12df6fc 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByFastForwardIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByFastForwardIT.java
@@ -15,15 +15,16 @@
package com.google.gerrit.acceptance.rest.change;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.GitUtil.checkout;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.extensions.client.SubmitType;
+import com.google.gerrit.extensions.common.ActionInfo;
-import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Test;
+import java.util.Map;
+
public class SubmitByFastForwardIT extends AbstractSubmit {
@Override
@@ -33,9 +34,8 @@
@Test
public void submitWithFastForward() throws Exception {
- Git git = createProject();
RevCommit oldHead = getRemoteHead();
- PushOneCommit.Result change = createChange(git);
+ PushOneCommit.Result change = createChange();
submit(change.getChangeId());
RevCommit head = getRemoteHead();
assertThat(head.getId()).isEqualTo(change.getCommitId());
@@ -45,16 +45,23 @@
@Test
public void submitFastForwardNotPossible_Conflict() throws Exception {
- Git git = createProject();
RevCommit initialHead = getRemoteHead();
PushOneCommit.Result change =
- createChange(git, "Change 1", "a.txt", "content");
+ createChange("Change 1", "a.txt", "content");
submit(change.getChangeId());
RevCommit oldHead = getRemoteHead();
- checkout(git, initialHead.getId().getName());
+ testRepo.reset(initialHead);
PushOneCommit.Result change2 =
- createChange(git, "Change 2", "b.txt", "other content");
+ createChange("Change 2", "b.txt", "other content");
+
+ approve(change2.getChangeId());
+ Map<String, ActionInfo> actions = getActions(change2.getChangeId());
+
+ assertThat(actions).containsKey("submit");
+ ActionInfo info = actions.get("submit");
+ assertThat(info.enabled).isNull();
+
submitWithConflict(change2.getChangeId());
assertThat(getRemoteHead()).isEqualTo(oldHead);
assertSubmitter(change.getChangeId(), 1);
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByMergeAlwaysIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByMergeAlwaysIT.java
index fa913d9..ebd3d3c 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByMergeAlwaysIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByMergeAlwaysIT.java
@@ -15,12 +15,10 @@
package com.google.gerrit.acceptance.rest.change;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.GitUtil.checkout;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.extensions.client.SubmitType;
-import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Test;
@@ -35,9 +33,8 @@
@Test
public void submitWithMergeIfFastForwardPossible() throws Exception {
- Git git = createProject();
RevCommit oldHead = getRemoteHead();
- PushOneCommit.Result change = createChange(git);
+ PushOneCommit.Result change = createChange();
submit(change.getChangeId());
RevCommit head = getRemoteHead();
assertThat(head.getParentCount()).isEqualTo(2);
@@ -48,17 +45,16 @@
@Test
public void submitMultipleChanges() throws Exception {
- Git git = createProject();
RevCommit initialHead = getRemoteHead();
- checkout(git, initialHead.getId().getName());
- PushOneCommit.Result change2 = createChange(git, "Change 2", "b", "b");
+ testRepo.reset(initialHead);
+ PushOneCommit.Result change2 = createChange("Change 2", "b", "b");
- checkout(git, initialHead.getId().getName());
- PushOneCommit.Result change3 = createChange(git, "Change 3", "c", "c");
+ testRepo.reset(initialHead);
+ PushOneCommit.Result change3 = createChange("Change 3", "c", "c");
- checkout(git, initialHead.getId().getName());
- PushOneCommit.Result change4 = createChange(git, "Change 4", "d", "d");
+ testRepo.reset(initialHead);
+ PushOneCommit.Result change4 = createChange("Change 4", "d", "d");
submitStatusOnly(change2.getChangeId());
submitStatusOnly(change3.getChangeId());
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByMergeIfNecessaryIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByMergeIfNecessaryIT.java
index c1ece45..95aef9e 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByMergeIfNecessaryIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByMergeIfNecessaryIT.java
@@ -1,12 +1,10 @@
package com.google.gerrit.acceptance.rest.change;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.GitUtil.checkout;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.extensions.client.SubmitType;
-import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Test;
@@ -21,9 +19,8 @@
@Test
public void submitWithFastForward() throws Exception {
- Git git = createProject();
RevCommit oldHead = getRemoteHead();
- PushOneCommit.Result change = createChange(git);
+ PushOneCommit.Result change = createChange();
submit(change.getChangeId());
RevCommit head = getRemoteHead();
assertThat(head.getId()).isEqualTo(change.getCommitId());
@@ -33,17 +30,16 @@
@Test
public void submitMultipleChanges() throws Exception {
- Git git = createProject();
RevCommit initialHead = getRemoteHead();
- checkout(git, initialHead.getId().getName());
- PushOneCommit.Result change2 = createChange(git, "Change 2", "b", "b");
+ testRepo.reset(initialHead);
+ PushOneCommit.Result change2 = createChange("Change 2", "b", "b");
- checkout(git, initialHead.getId().getName());
- PushOneCommit.Result change3 = createChange(git, "Change 3", "c", "c");
+ testRepo.reset(initialHead);
+ PushOneCommit.Result change3 = createChange("Change 3", "c", "c");
- checkout(git, initialHead.getId().getName());
- PushOneCommit.Result change4 = createChange(git, "Change 4", "d", "d");
+ testRepo.reset(initialHead);
+ PushOneCommit.Result change4 = createChange("Change 4", "d", "d");
submitStatusOnly(change2.getChangeId());
submitStatusOnly(change3.getChangeId());
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByRebaseIfNecessaryIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByRebaseIfNecessaryIT.java
index d3e8cb5..bb26a30 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByRebaseIfNecessaryIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByRebaseIfNecessaryIT.java
@@ -15,12 +15,12 @@
package com.google.gerrit.acceptance.rest.change;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.GitUtil.checkout;
import com.google.gerrit.acceptance.PushOneCommit;
+import com.google.gerrit.acceptance.TestProjectInput;
+import com.google.gerrit.extensions.client.InheritableBoolean;
import com.google.gerrit.extensions.client.SubmitType;
-import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Test;
@@ -32,10 +32,10 @@
}
@Test
+ @TestProjectInput(useContentMerge = InheritableBoolean.TRUE)
public void submitWithFastForward() throws Exception {
- Git git = createProject();
RevCommit oldHead = getRemoteHead();
- PushOneCommit.Result change = createChange(git);
+ PushOneCommit.Result change = createChange();
submit(change.getChangeId());
RevCommit head = getRemoteHead();
assertThat(head.getId()).isEqualTo(change.getCommitId());
@@ -46,19 +46,19 @@
}
@Test
+ @TestProjectInput(useContentMerge = InheritableBoolean.TRUE)
public void submitWithRebase() throws Exception {
- Git git = createProject();
RevCommit initialHead = getRemoteHead();
PushOneCommit.Result change =
- createChange(git, "Change 1", "a.txt", "content");
+ createChange("Change 1", "a.txt", "content");
submit(change.getChangeId());
RevCommit oldHead = getRemoteHead();
- checkout(git, initialHead.getId().getName());
+ testRepo.reset(initialHead);
PushOneCommit.Result change2 =
- createChange(git, "Change 2", "b.txt", "other content");
+ createChange("Change 2", "b.txt", "other content");
submit(change2.getChangeId());
- assertRebase(git, false);
+ assertRebase(testRepo, false);
RevCommit head = getRemoteHead();
assertThat(head.getParent(0)).isEqualTo(oldHead);
assertApproved(change2.getChangeId());
@@ -68,22 +68,21 @@
}
@Test
+ @TestProjectInput(useContentMerge = InheritableBoolean.TRUE)
public void submitWithContentMerge() throws Exception {
- Git git = createProject();
- setUseContentMerge();
PushOneCommit.Result change =
- createChange(git, "Change 1", "a.txt", "aaa\nbbb\nccc\n");
+ createChange("Change 1", "a.txt", "aaa\nbbb\nccc\n");
submit(change.getChangeId());
PushOneCommit.Result change2 =
- createChange(git, "Change 2", "a.txt", "aaa\nbbb\nccc\nddd\n");
+ createChange("Change 2", "a.txt", "aaa\nbbb\nccc\nddd\n");
submit(change2.getChangeId());
RevCommit oldHead = getRemoteHead();
- checkout(git, change.getCommitId().getName());
+ testRepo.reset(change.getCommitId());
PushOneCommit.Result change3 =
- createChange(git, "Change 3", "a.txt", "bbb\nccc\n");
+ createChange("Change 3", "a.txt", "bbb\nccc\n");
submit(change3.getChangeId());
- assertRebase(git, true);
+ assertRebase(testRepo, true);
RevCommit head = getRemoteHead();
assertThat(head.getParent(0)).isEqualTo(oldHead);
assertApproved(change3.getChangeId());
@@ -93,18 +92,17 @@
}
@Test
+ @TestProjectInput(useContentMerge = InheritableBoolean.TRUE)
public void submitWithContentMerge_Conflict() throws Exception {
- Git git = createProject();
- setUseContentMerge();
RevCommit initialHead = getRemoteHead();
PushOneCommit.Result change =
- createChange(git, "Change 1", "a.txt", "content");
+ createChange("Change 1", "a.txt", "content");
submit(change.getChangeId());
RevCommit oldHead = getRemoteHead();
- checkout(git, initialHead.getId().getName());
+ testRepo.reset(initialHead);
PushOneCommit.Result change2 =
- createChange(git, "Change 2", "a.txt", "other content");
+ createChange("Change 2", "a.txt", "other content");
submitWithConflict(change2.getChangeId());
RevCommit head = getRemoteHead();
assertThat(head).isEqualTo(oldHead);
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SuggestReviewersIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SuggestReviewersIT.java
index 7fee9f4..ed6740a 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SuggestReviewersIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SuggestReviewersIT.java
@@ -16,38 +16,42 @@
import static com.google.common.truth.Truth.assertThat;
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
import com.google.common.collect.Iterables;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.GerritConfig;
import com.google.gerrit.acceptance.GerritConfigs;
-import com.google.gerrit.acceptance.RestSession;
import com.google.gerrit.acceptance.TestAccount;
-import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.GlobalCapability;
-import com.google.gerrit.common.data.Permission;
-import com.google.gerrit.common.data.PermissionRule;
+import com.google.gerrit.common.data.GroupDescription;
+import com.google.gerrit.common.data.GroupDescriptions;
+import com.google.gerrit.extensions.common.GroupInfo;
import com.google.gerrit.extensions.common.SuggestedReviewerInfo;
+import com.google.gerrit.extensions.restapi.TopLevelResource;
import com.google.gerrit.extensions.restapi.Url;
import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gerrit.server.account.CreateGroupArgs;
-import com.google.gerrit.server.account.PerformCreateGroup;
-import com.google.gerrit.server.git.MetaDataUpdate;
-import com.google.gerrit.server.git.ProjectConfig;
-import com.google.gson.reflect.TypeToken;
+import com.google.gerrit.server.group.CreateGroup;
+import com.google.gerrit.server.group.GroupsCollection;
import com.google.inject.Inject;
import org.junit.Before;
import org.junit.Test;
-import java.io.IOException;
-import java.util.Collections;
+import java.util.Arrays;
import java.util.List;
public class SuggestReviewersIT extends AbstractDaemonTest {
@Inject
- private PerformCreateGroup.Factory createGroupFactory;
+ private CreateGroup.Factory createGroupFactory;
+
+ @Inject
+ private GroupsCollection groups;
private AccountGroup group1;
+ private AccountGroup group2;
+ private AccountGroup group3;
+
private TestAccount user1;
private TestAccount user2;
private TestAccount user3;
@@ -55,22 +59,20 @@
@Before
public void setUp() throws Exception {
group1 = group("users1");
- group("users2");
- group("users3");
+ group2 = group("users2");
+ group3 = group("users3");
- user1 = accounts.create("user1", "user1@example.com", "First1 Last1",
- "users1");
- user2 = accounts.create("user2", "user2@example.com", "First2 Last2",
- "users2");
- user3 = accounts.create("user3", "user3@example.com", "First3 Last3",
- "users1", "users2");
+ user1 = user("user1", "First1 Last1", group1);
+ user2 = user("user2", "First2 Last2", group2);
+ user3 = user("user3", "First3 Last3", group1, group2);
}
@Test
@GerritConfig(name = "suggest.accounts", value = "false")
public void suggestReviewersNoResult1() throws Exception {
String changeId = createChange().getChangeId();
- List<SuggestedReviewerInfo> reviewers = suggestReviewers(changeId, "u", 6);
+ List<SuggestedReviewerInfo> reviewers =
+ suggestReviewers(changeId, name("u"), 6);
assertThat(reviewers).isEmpty();
}
@@ -82,7 +84,8 @@
})
public void suggestReviewersNoResult2() throws Exception {
String changeId = createChange().getChangeId();
- List<SuggestedReviewerInfo> reviewers = suggestReviewers(changeId, "u", 6);
+ List<SuggestedReviewerInfo> reviewers =
+ suggestReviewers(changeId, name("u"), 6);
assertThat(reviewers).isEmpty();
}
@@ -90,18 +93,20 @@
@GerritConfig(name = "suggest.from", value = "2")
public void suggestReviewersNoResult3() throws Exception {
String changeId = createChange().getChangeId();
- List<SuggestedReviewerInfo> reviewers = suggestReviewers(changeId, "u", 6);
+ List<SuggestedReviewerInfo> reviewers =
+ suggestReviewers(changeId, name("").substring(0, 1), 6);
assertThat(reviewers).isEmpty();
}
@Test
public void suggestReviewersChange() throws Exception {
String changeId = createChange().getChangeId();
- List<SuggestedReviewerInfo> reviewers = suggestReviewers(changeId, "u", 6);
+ List<SuggestedReviewerInfo> reviewers =
+ suggestReviewers(changeId, name("u"), 6);
assertThat(reviewers).hasSize(6);
- reviewers = suggestReviewers(changeId, "u", 5);
+ reviewers = suggestReviewers(changeId, name("u"), 5);
assertThat(reviewers).hasSize(5);
- reviewers = suggestReviewers(changeId, "users3", 10);
+ reviewers = suggestReviewers(changeId, group3.getName(), 10);
assertThat(reviewers).hasSize(1);
}
@@ -111,26 +116,26 @@
String changeId = createChange().getChangeId();
List<SuggestedReviewerInfo> reviewers;
- reviewers = suggestReviewers(changeId, "user2", 2);
+ reviewers = suggestReviewers(changeId, user2.username, 2);
assertThat(reviewers).hasSize(1);
- assertThat(Iterables.getOnlyElement(reviewers).account.name).isEqualTo(
- "First2 Last2");
+ assertThat(Iterables.getOnlyElement(reviewers).account.name)
+ .isEqualTo(user2.fullName);
- reviewers = suggestReviewers(new RestSession(server, user1),
- changeId, "user2", 2);
+ setApiUser(user1);
+ reviewers = suggestReviewers(changeId, user2.fullName, 2);
assertThat(reviewers).isEmpty();
- reviewers = suggestReviewers(new RestSession(server, user2),
- changeId, "user2", 2);
+ setApiUser(user2);
+ reviewers = suggestReviewers(changeId, user2.username, 2);
assertThat(reviewers).hasSize(1);
- assertThat(Iterables.getOnlyElement(reviewers).account.name).isEqualTo(
- "First2 Last2");
+ assertThat(Iterables.getOnlyElement(reviewers).account.name)
+ .isEqualTo(user2.fullName);
- reviewers = suggestReviewers(new RestSession(server, user3),
- changeId, "user2", 2);
+ setApiUser(user3);
+ reviewers = suggestReviewers(changeId, user2.username, 2);
assertThat(reviewers).hasSize(1);
- assertThat(Iterables.getOnlyElement(reviewers).account.name).isEqualTo(
- "First2 Last2");
+ assertThat(Iterables.getOnlyElement(reviewers).account.name)
+ .isEqualTo(user2.fullName);
}
@Test
@@ -139,16 +144,17 @@
String changeId = createChange().getChangeId();
List<SuggestedReviewerInfo> reviewers;
- reviewers = suggestReviewers(new RestSession(server, user1),
- changeId, "user2", 2);
+ setApiUser(user1);
+ reviewers = suggestReviewers(changeId, user2.username, 2);
assertThat(reviewers).isEmpty();
- grantCapability(GlobalCapability.VIEW_ALL_ACCOUNTS, group1);
- reviewers = suggestReviewers(new RestSession(server, user1),
- changeId, "user2", 2);
+ setApiUser(user1); // Clear cached group info.
+ allowGlobalCapabilities(group1.getGroupUUID(),
+ GlobalCapability.VIEW_ALL_ACCOUNTS);
+ reviewers = suggestReviewers(changeId, user2.username, 2);
assertThat(reviewers).hasSize(1);
- assertThat(Iterables.getOnlyElement(reviewers).account.name).isEqualTo(
- "First2 Last2");
+ assertThat(Iterables.getOnlyElement(reviewers).account.name)
+ .isEqualTo(user2.fullName);
}
@Test
@@ -156,7 +162,7 @@
public void suggestReviewersMaxNbrSuggestions() throws Exception {
String changeId = createChange().getChangeId();
List<SuggestedReviewerInfo> reviewers =
- suggestReviewers(changeId, "user", 5);
+ suggestReviewers(changeId, name("user"), 5);
assertThat(reviewers).hasSize(2);
}
@@ -193,19 +199,19 @@
reviewers = suggestReviewers(changeId, "first1 last2", 1);
assertThat(reviewers).hasSize(0);
- reviewers = suggestReviewers(changeId, "user", 8);
- assertThat(reviewers).hasSize(7);
+ reviewers = suggestReviewers(changeId, name("user"), 7);
+ assertThat(reviewers).hasSize(6);
- reviewers = suggestReviewers(changeId, "user1", 2);
+ reviewers = suggestReviewers(changeId, user1.username, 2);
assertThat(reviewers).hasSize(1);
reviewers = suggestReviewers(changeId, "example.com", 6);
assertThat(reviewers).hasSize(5);
- reviewers = suggestReviewers(changeId, "user1@example.com", 2);
+ reviewers = suggestReviewers(changeId, user1.email, 2);
assertThat(reviewers).hasSize(1);
- reviewers = suggestReviewers(changeId, "user1 example", 2);
+ reviewers = suggestReviewers(changeId, user1.username + " example", 2);
assertThat(reviewers).hasSize(1);
}
@@ -217,60 +223,47 @@
public void suggestReviewersFullTextSearchLimitMaxMatches() throws Exception {
String changeId = createChange().getChangeId();
List<SuggestedReviewerInfo> reviewers =
- suggestReviewers(changeId, "user", 3);
- assertThat(reviewers).hasSize(3);
+ suggestReviewers(changeId, name("user"), 2);
+ assertThat(reviewers).hasSize(2);
}
@Test
public void suggestReviewersWithoutLimitOptionSpecified() throws Exception {
String changeId = createChange().getChangeId();
- String query = "users3";
- List<SuggestedReviewerInfo> suggestedReviewerInfos = newGson().fromJson(
- adminSession.get("/changes/"
- + changeId
- + "/suggest_reviewers?q="
- + query)
- .getReader(),
- new TypeToken<List<SuggestedReviewerInfo>>() {}
- .getType());
+ String query = user3.username;
+ List<SuggestedReviewerInfo> suggestedReviewerInfos = gApi.changes()
+ .id(changeId)
+ .suggestReviewers(query)
+ .get();
assertThat(suggestedReviewerInfos).hasSize(1);
}
- private List<SuggestedReviewerInfo> suggestReviewers(RestSession session,
- String changeId, String query, int n) throws IOException {
- return newGson().fromJson(
- session.get("/changes/"
- + changeId
- + "/suggest_reviewers?q="
- + Url.encode(query)
- + "&n="
- + n)
- .getReader(),
- new TypeToken<List<SuggestedReviewerInfo>>() {}
- .getType());
- }
-
private List<SuggestedReviewerInfo> suggestReviewers(String changeId,
- String query, int n) throws IOException {
- return suggestReviewers(adminSession, changeId, query, n);
+ String query, int n) throws Exception {
+ return gApi.changes()
+ .id(changeId)
+ .suggestReviewers(query)
+ .withLimit(n)
+ .get();
}
private AccountGroup group(String name) throws Exception {
- CreateGroupArgs args = new CreateGroupArgs();
- args.setGroupName(name);
- args.initialMembers = Collections.singleton(admin.getId());
- return createGroupFactory.create(args).createGroup();
+ GroupInfo group = createGroupFactory.create(name(name))
+ .apply(TopLevelResource.INSTANCE, null);
+ GroupDescription.Basic d = groups.parseInternal(Url.decode(group.id));
+ return GroupDescriptions.toAccountGroup(d);
}
- private void grantCapability(String name, AccountGroup group)
+ private TestAccount user(String name, String fullName, AccountGroup... groups)
throws Exception {
- MetaDataUpdate md = metaDataUpdateFactory.create(allProjects);
- ProjectConfig config = ProjectConfig.read(md);
- AccessSection s = config.getAccessSection(
- AccessSection.GLOBAL_CAPABILITIES);
- Permission p = s.getPermission(name, true);
- p.add(new PermissionRule(config.resolve(group)));
- config.commit(md);
- projectCache.evict(config.getProject());
+ name = name(name);
+ String[] groupNames = FluentIterable.from(Arrays.asList(groups))
+ .transform(new Function<AccountGroup, String>() {
+ @Override
+ public String apply(AccountGroup in) {
+ return in.getName();
+ }
+ }).toArray(String.class);
+ return accounts.create(name, name + "@example.com", fullName, groupNames);
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/CacheOperationsIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/CacheOperationsIT.java
index 304abc8..7e68a03 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/CacheOperationsIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/CacheOperationsIT.java
@@ -22,18 +22,12 @@
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
import com.google.gerrit.common.data.GlobalCapability;
-import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.config.ListCaches.CacheInfo;
import com.google.gerrit.server.config.PostCaches;
-import com.google.gerrit.server.git.MetaDataUpdate;
-import com.google.gerrit.server.git.ProjectConfig;
-import com.google.gerrit.server.group.SystemGroupBackend;
-import com.google.gerrit.server.project.Util;
import org.apache.http.HttpStatus;
import org.junit.Test;
-import java.io.IOException;
import java.util.Arrays;
public class CacheOperationsIT extends AbstractDaemonTest {
@@ -42,7 +36,7 @@
public void flushAll() throws Exception {
RestResponse r = adminSession.get("/config/server/caches/project_list");
CacheInfo cacheInfo = newGson().fromJson(r.getReader(), CacheInfo.class);
- assertThat(cacheInfo.entries.mem.longValue()).isGreaterThan((long) 0);
+ assertThat(cacheInfo.entries.mem).isGreaterThan((long) 0);
r = adminSession.post("/config/server/caches/", new PostCaches.Input(FLUSH_ALL));
assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
@@ -71,11 +65,11 @@
public void flush() throws Exception {
RestResponse r = adminSession.get("/config/server/caches/project_list");
CacheInfo cacheInfo = newGson().fromJson(r.getReader(), CacheInfo.class);
- assertThat(cacheInfo.entries.mem.longValue()).isGreaterThan((long)0);
+ assertThat(cacheInfo.entries.mem).isGreaterThan((long)0);
r = adminSession.get("/config/server/caches/projects");
cacheInfo = newGson().fromJson(r.getReader(), CacheInfo.class);
- assertThat(cacheInfo.entries.mem.longValue()).isGreaterThan((long)1);
+ assertThat(cacheInfo.entries.mem).isGreaterThan((long)1);
r = adminSession.post("/config/server/caches/",
new PostCaches.Input(FLUSH, Arrays.asList("accounts", "project_list")));
@@ -88,7 +82,7 @@
r = adminSession.get("/config/server/caches/projects");
cacheInfo = newGson().fromJson(r.getReader(), CacheInfo.class);
- assertThat(cacheInfo.entries.mem.longValue()).isGreaterThan((long)1);
+ assertThat(cacheInfo.entries.mem).isGreaterThan((long)1);
}
@Test
@@ -109,7 +103,7 @@
public void flush_UnprocessableEntity() throws Exception {
RestResponse r = adminSession.get("/config/server/caches/projects");
CacheInfo cacheInfo = newGson().fromJson(r.getReader(), CacheInfo.class);
- assertThat(cacheInfo.entries.mem.longValue()).isGreaterThan((long)0);
+ assertThat(cacheInfo.entries.mem).isGreaterThan((long)0);
r = adminSession.post("/config/server/caches/",
new PostCaches.Input(FLUSH, Arrays.asList("projects", "unprocessable")));
@@ -118,35 +112,25 @@
r = adminSession.get("/config/server/caches/projects");
cacheInfo = newGson().fromJson(r.getReader(), CacheInfo.class);
- assertThat(cacheInfo.entries.mem.longValue()).isGreaterThan((long)0);
+ assertThat(cacheInfo.entries.mem).isGreaterThan((long)0);
}
@Test
public void flushWebSessions_Forbidden() throws Exception {
- ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig();
- AccountGroup.UUID registeredUsers =
- SystemGroupBackend.getGroup(REGISTERED_USERS).getUUID();
- Util.allow(cfg, GlobalCapability.VIEW_CACHES, registeredUsers);
- Util.allow(cfg, GlobalCapability.FLUSH_CACHES, registeredUsers);
- saveProjectConfig(cfg);
-
- RestResponse r = userSession.post("/config/server/caches/",
- new PostCaches.Input(FLUSH, Arrays.asList("projects")));
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- r.consume();
-
- r = userSession.post("/config/server/caches/",
- new PostCaches.Input(FLUSH, Arrays.asList("web_sessions")));
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_FORBIDDEN);
- }
-
- private void saveProjectConfig(ProjectConfig cfg) throws IOException {
- MetaDataUpdate md = metaDataUpdateFactory.create(allProjects);
+ allowGlobalCapabilities(REGISTERED_USERS,
+ GlobalCapability.FLUSH_CACHES, GlobalCapability.VIEW_CACHES);
try {
- cfg.commit(md);
+ RestResponse r = userSession.post("/config/server/caches/",
+ new PostCaches.Input(FLUSH, Arrays.asList("projects")));
+ assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
+ r.consume();
+
+ r = userSession.post("/config/server/caches/",
+ new PostCaches.Input(FLUSH, Arrays.asList("web_sessions")));
+ assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_FORBIDDEN);
} finally {
- md.close();
+ removeGlobalCapabilities(REGISTERED_USERS,
+ GlobalCapability.FLUSH_CACHES, GlobalCapability.VIEW_CACHES);
}
- projectCache.evict(allProjects);
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/FlushCacheIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/FlushCacheIT.java
index 9f7b419..bb63928 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/FlushCacheIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/FlushCacheIT.java
@@ -20,25 +20,18 @@
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
import com.google.gerrit.common.data.GlobalCapability;
-import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.config.ListCaches.CacheInfo;
-import com.google.gerrit.server.git.MetaDataUpdate;
-import com.google.gerrit.server.git.ProjectConfig;
-import com.google.gerrit.server.group.SystemGroupBackend;
-import com.google.gerrit.server.project.Util;
import org.apache.http.HttpStatus;
import org.junit.Test;
-import java.io.IOException;
-
public class FlushCacheIT extends AbstractDaemonTest {
@Test
public void flushCache() throws Exception {
RestResponse r = adminSession.get("/config/server/caches/groups");
CacheInfo result = newGson().fromJson(r.getReader(), CacheInfo.class);
- assertThat(result.entries.mem.longValue()).isGreaterThan((long)0);
+ assertThat(result.entries.mem).isGreaterThan((long)0);
r = adminSession.post("/config/server/caches/groups/flush");
assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
@@ -75,28 +68,18 @@
@Test
public void flushWebSessionsCache_Forbidden() throws Exception {
- ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig();
- AccountGroup.UUID registeredUsers =
- SystemGroupBackend.getGroup(REGISTERED_USERS).getUUID();
- Util.allow(cfg, GlobalCapability.VIEW_CACHES, registeredUsers);
- Util.allow(cfg, GlobalCapability.FLUSH_CACHES, registeredUsers);
- saveProjectConfig(cfg);
-
- RestResponse r = userSession.post("/config/server/caches/accounts/flush");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- r.consume();
-
- r = userSession.post("/config/server/caches/web_sessions/flush");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_FORBIDDEN);
- }
-
- private void saveProjectConfig(ProjectConfig cfg) throws IOException {
- MetaDataUpdate md = metaDataUpdateFactory.create(allProjects);
+ allowGlobalCapabilities(REGISTERED_USERS,
+ GlobalCapability.VIEW_CACHES, GlobalCapability.FLUSH_CACHES);
try {
- cfg.commit(md);
+ RestResponse r = userSession.post("/config/server/caches/accounts/flush");
+ assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
+ r.consume();
+
+ r = userSession.post("/config/server/caches/web_sessions/flush");
+ assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_FORBIDDEN);
} finally {
- md.close();
+ removeGlobalCapabilities(REGISTERED_USERS,
+ GlobalCapability.VIEW_CACHES, GlobalCapability.FLUSH_CACHES);
}
- projectCache.evict(allProjects);
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/GetCacheIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/GetCacheIT.java
index f59752c..02a1b73 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/GetCacheIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/GetCacheIT.java
@@ -34,7 +34,7 @@
assertThat(result.name).isEqualTo("accounts");
assertThat(result.type).isEqualTo(CacheType.MEM);
- assertThat(result.entries.mem.longValue()).isEqualTo(1);
+ assertThat(result.entries.mem).isAtLeast(1L);
assertThat(result.averageGet).isNotNull();
assertThat(result.averageGet).endsWith("s");
assertThat(result.entries.disk).isNull();
@@ -47,7 +47,7 @@
r = adminSession.get("/config/server/caches/accounts");
assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
result = newGson().fromJson(r.getReader(), CacheInfo.class);
- assertThat(result.entries.mem.longValue()).isEqualTo(2);
+ assertThat(result.entries.mem).isEqualTo(2);
}
@Test
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/ListCachesIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/ListCachesIT.java
index 0d0a94e..fb89e1b 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/ListCachesIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/ListCachesIT.java
@@ -45,7 +45,7 @@
assertThat(result).containsKey("accounts");
CacheInfo accountsCacheInfo = result.get("accounts");
assertThat(accountsCacheInfo.type).isEqualTo(CacheType.MEM);
- assertThat(accountsCacheInfo.entries.mem.longValue()).isEqualTo(1);
+ assertThat(accountsCacheInfo.entries.mem).isAtLeast(1L);
assertThat(accountsCacheInfo.averageGet).isNotNull();
assertThat(accountsCacheInfo.averageGet).endsWith("s");
assertThat(accountsCacheInfo.entries.disk).isNull();
@@ -59,7 +59,7 @@
assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
result = newGson().fromJson(r.getReader(),
new TypeToken<Map<String, CacheInfo>>() {}.getType());
- assertThat(result.get("accounts").entries.mem.longValue()).isEqualTo(2);
+ assertThat(result.get("accounts").entries.mem).isEqualTo(2);
}
@Test
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/AddRemoveGroupMembersIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/AddRemoveGroupMembersIT.java
deleted file mode 100644
index b9778b8..0000000
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/AddRemoveGroupMembersIT.java
+++ /dev/null
@@ -1,225 +0,0 @@
-// Copyright (C) 2013 The Android Open Source Project
-//
-// 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.
-
-package com.google.gerrit.acceptance.rest.group;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.rest.account.AccountAssert.assertAccountInfo;
-import static com.google.gerrit.acceptance.rest.group.GroupAssert.assertGroupInfo;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.acceptance.TestAccount;
-import com.google.gerrit.extensions.common.AccountInfo;
-import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gerrit.reviewdb.client.AccountGroupById;
-import com.google.gerrit.reviewdb.client.AccountGroupMember;
-import com.google.gerrit.server.group.AddIncludedGroups;
-import com.google.gerrit.server.group.AddMembers;
-import com.google.gerrit.server.group.CreateGroup;
-import com.google.gerrit.server.group.GroupJson.GroupInfo;
-import com.google.gson.reflect.TypeToken;
-import com.google.gwtorm.server.OrmException;
-import com.google.gwtorm.server.ResultSet;
-
-import org.apache.http.HttpStatus;
-import org.junit.Test;
-
-import java.io.IOException;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-public class AddRemoveGroupMembersIT extends AbstractDaemonTest {
- @Test
- public void addToNonExistingGroup_NotFound() throws Exception {
- assertThat(PUT("/groups/non-existing/members/admin").getStatusCode())
- .isEqualTo(HttpStatus.SC_NOT_FOUND);
- }
-
- @Test
- public void removeFromNonExistingGroup_NotFound() throws Exception {
- assertThat(DELETE("/groups/non-existing/members/admin"))
- .isEqualTo(HttpStatus.SC_NOT_FOUND);
- }
-
- @Test
- public void addRemoveMember() throws Exception {
- RestResponse r = PUT("/groups/Administrators/members/user");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_CREATED);
- AccountInfo ai = newGson().fromJson(r.getReader(), AccountInfo.class);
- assertAccountInfo(user, ai);
- assertMembers("Administrators", admin, user);
- r.consume();
-
- assertThat(DELETE("/groups/Administrators/members/user"))
- .isEqualTo(HttpStatus.SC_NO_CONTENT);
- assertMembers("Administrators", admin);
- }
-
- @Test
- public void addExistingMember_OK() throws Exception {
- assertThat(PUT("/groups/Administrators/members/admin").getStatusCode())
- .isEqualTo(HttpStatus.SC_OK);
- }
-
- @Test
- public void addMultipleMembers() throws Exception {
- group("users");
- TestAccount u1 = accounts.create("u1", "u1@example.com", "Full Name 1");
- TestAccount u2 = accounts.create("u2", "u2@example.com", "Full Name 2");
- List<String> members = Lists.newLinkedList();
- members.add(u1.username);
- members.add(u2.username);
- AddMembers.Input input = AddMembers.Input.fromMembers(members);
- RestResponse r = POST("/groups/users/members", input);
- List<AccountInfo> ai = newGson().fromJson(r.getReader(),
- new TypeToken<List<AccountInfo>>() {}.getType());
- assertMembers(ai, u1, u2);
- }
-
- @Test
- public void includeRemoveGroup() throws Exception {
- group("newGroup");
- RestResponse r = PUT("/groups/Administrators/groups/newGroup");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_CREATED);
- GroupInfo i = newGson().fromJson(r.getReader(), GroupInfo.class);
- r.consume();
- assertGroupInfo(groupCache.get(new AccountGroup.NameKey("newGroup")), i);
- assertIncludes("Administrators", "newGroup");
-
- assertThat(DELETE("/groups/Administrators/groups/newGroup"))
- .isEqualTo(HttpStatus.SC_NO_CONTENT);
- assertNoIncludes("Administrators");
- }
-
- @Test
- public void includeExistingGroup_OK() throws Exception {
- group("newGroup");
- PUT("/groups/Administrators/groups/newGroup").consume();
- assertThat(PUT("/groups/Administrators/groups/newGroup").getStatusCode())
- .isEqualTo(HttpStatus.SC_OK);
- }
-
- @Test
- public void addMultipleIncludes() throws Exception {
- group("newGroup1");
- group("newGroup2");
- List<String> groups = Lists.newLinkedList();
- groups.add("newGroup1");
- groups.add("newGroup2");
- AddIncludedGroups.Input input = AddIncludedGroups.Input.fromGroups(groups);
- RestResponse r = POST("/groups/Administrators/groups", input);
- List<GroupInfo> gi = newGson().fromJson(r.getReader(),
- new TypeToken<List<GroupInfo>>() {}.getType());
- assertIncludes(gi, "newGroup1", "newGroup2");
- }
-
- private RestResponse PUT(String endpoint) throws IOException {
- return adminSession.put(endpoint);
- }
-
- private int DELETE(String endpoint) throws IOException {
- RestResponse r = adminSession.delete(endpoint);
- r.consume();
- return r.getStatusCode();
- }
-
- private RestResponse POST(String endPoint, AddMembers.Input mi)
- throws IOException {
- return adminSession.post(endPoint, mi);
- }
-
- private RestResponse POST(String endPoint, AddIncludedGroups.Input gi)
- throws IOException {
- return adminSession.post(endPoint, gi);
- }
-
- private void group(String name) throws IOException {
- CreateGroup.Input in = new CreateGroup.Input();
- adminSession.put("/groups/" + name, in).consume();
- }
-
- private void assertMembers(String group, TestAccount... members)
- throws OrmException {
- AccountGroup g = groupCache.get(new AccountGroup.NameKey(group));
- Set<Account.Id> ids = Sets.newHashSet();
- ResultSet<AccountGroupMember> all =
- db.accountGroupMembers().byGroup(g.getId());
- for (AccountGroupMember m : all) {
- ids.add(m.getAccountId());
- }
- assertThat((Iterable<?>)ids).hasSize(members.length);
- for (TestAccount a : members) {
- assertThat((Iterable<?>)ids).contains(a.id);
- }
- }
-
- private void assertMembers(List<AccountInfo> ai, TestAccount... members) {
- Map<Integer, AccountInfo> infoById = Maps.newHashMap();
- for (AccountInfo i : ai) {
- infoById.put(i._accountId, i);
- }
-
- for (TestAccount a : members) {
- AccountInfo i = infoById.get(a.id.get());
- assertThat(i).isNotNull();
- assertAccountInfo(a, i);
- }
- assertThat(ai).hasSize(members.length);
- }
-
- private void assertIncludes(String group, String... includes)
- throws OrmException {
- AccountGroup g = groupCache.get(new AccountGroup.NameKey(group));
- Set<AccountGroup.UUID> ids = Sets.newHashSet();
- ResultSet<AccountGroupById> all =
- db.accountGroupById().byGroup(g.getId());
- for (AccountGroupById m : all) {
- ids.add(m.getIncludeUUID());
- }
- assertThat((Iterable<?>)ids).hasSize(includes.length);
- for (String i : includes) {
- AccountGroup.UUID id = groupCache.get(
- new AccountGroup.NameKey(i)).getGroupUUID();
- assertThat((Iterable<?>)ids).contains(id);
- }
- }
-
- private void assertIncludes(List<GroupInfo> gi, String... includes) {
- Map<String, GroupInfo> groupsByName = Maps.newHashMap();
- for (GroupInfo i : gi) {
- groupsByName.put(i.name, i);
- }
-
- for (String name : includes) {
- GroupInfo i = groupsByName.get(name);
- assertThat(i).isNotNull();
- assertGroupInfo(groupCache.get(new AccountGroup.NameKey(name)), i);
- }
- assertThat(gi).hasSize(includes.length);
- }
-
- private void assertNoIncludes(String group) throws OrmException {
- AccountGroup g = groupCache.get(new AccountGroup.NameKey(group));
- Iterator<AccountGroupById> it =
- db.accountGroupById().byGroup(g.getId()).iterator();
- assertThat(it.hasNext()).isFalse();
- }
-}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/CreateGroupIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/CreateGroupIT.java
deleted file mode 100644
index 7de450b..0000000
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/CreateGroupIT.java
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (C) 2013 The Android Open Source Project
-//
-// 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.
-
-package com.google.gerrit.acceptance.rest.group;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.rest.group.GroupAssert.assertGroupInfo;
-
-import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.acceptance.RestSession;
-import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gerrit.server.group.CreateGroup;
-import com.google.gerrit.server.group.GroupJson.GroupInfo;
-
-import org.apache.http.HttpStatus;
-import org.junit.Test;
-
-public class CreateGroupIT extends AbstractDaemonTest {
- @Test
- public void testCreateGroup() throws Exception {
- final String newGroupName = "newGroup";
- RestResponse r = adminSession.put("/groups/" + newGroupName);
- GroupInfo g = newGson().fromJson(r.getReader(), GroupInfo.class);
- assertThat(g.name).isEqualTo(newGroupName);
- AccountGroup group = groupCache.get(new AccountGroup.NameKey(newGroupName));
- assertThat(group).isNotNull();
- assertGroupInfo(group, g);
- }
-
- @Test
- public void testCreateGroupWithProperties() throws Exception {
- final String newGroupName = "newGroup";
- CreateGroup.Input in = new CreateGroup.Input();
- in.description = "Test description";
- in.visibleToAll = true;
- in.ownerId = groupCache.get(new AccountGroup.NameKey("Administrators")).getGroupUUID().get();
- RestResponse r = adminSession.put("/groups/" + newGroupName, in);
- GroupInfo g = newGson().fromJson(r.getReader(), GroupInfo.class);
- assertThat(g.name).isEqualTo(newGroupName);
- AccountGroup group = groupCache.get(new AccountGroup.NameKey(newGroupName));
- assertThat(group.getDescription()).isEqualTo(in.description);
- assertThat(group.isVisibleToAll()).isEqualTo(in.visibleToAll);
- assertThat(group.getOwnerGroupUUID().get()).isEqualTo(in.ownerId);
- }
-
- @Test
- public void testCreateGroupWithoutCapability_Forbidden() throws Exception {
- RestResponse r = (new RestSession(server, user)).put("/groups/newGroup");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_FORBIDDEN);
- }
-
- @Test
- public void testCreateGroupWhenGroupAlreadyExists_Conflict()
- throws Exception {
- RestResponse r = adminSession.put("/groups/Administrators");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_CONFLICT);
- }
-}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/DefaultGroupsIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/DefaultGroupsIT.java
deleted file mode 100644
index 8365d79..0000000
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/DefaultGroupsIT.java
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (C) 2013 The Android Open Source Project
-//
-// 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.
-
-package com.google.gerrit.acceptance.rest.group;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assert_;
-
-import com.google.common.collect.Sets;
-import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.acceptance.RestSession;
-import com.google.gerrit.acceptance.SshSession;
-import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gerrit.server.group.GroupJson.GroupInfo;
-import com.google.gson.reflect.TypeToken;
-
-import org.junit.Test;
-
-import java.util.Map;
-import java.util.Set;
-
-/**
- * An example test that tests presence of default groups in a newly initialized
- * review site.
- *
- * The test shows how to perform these checks via SSH, REST or using Gerrit
- * internals.
- */
-public class DefaultGroupsIT extends AbstractDaemonTest {
-
- @Test
- public void defaultGroupsCreated_ssh() throws Exception {
- SshSession session = new SshSession(server, admin);
- String result = session.exec("gerrit ls-groups");
- assert_().withFailureMessage(session.getError())
- .that(session.hasError()).isFalse();
- assertThat(result).contains("Administrators");
- assertThat(result).contains("Non-Interactive Users");
- session.close();
- }
-
- @Test
- public void defaultGroupsCreated_rest() throws Exception {
- RestSession session = new RestSession(server, admin);
- RestResponse r = session.get("/groups/");
- Map<String, GroupInfo> result =
- newGson().fromJson(r.getReader(),
- new TypeToken<Map<String, GroupInfo>>() {}.getType());
- Set<String> names = result.keySet();
- assertThat((Iterable<?>)names).contains("Administrators");
- assertThat((Iterable<?>)names).contains("Non-Interactive Users");
- }
-
- @Test
- public void defaultGroupsCreated_internals() throws Exception {
- Set<String> names = Sets.newHashSet();
- for (AccountGroup g : db.accountGroups().all()) {
- names.add(g.getName());
- }
- assertThat((Iterable<?>)names).contains("Administrators");
- assertThat((Iterable<?>)names).contains("Non-Interactive Users");
- }
-}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/GetGroupIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/GetGroupIT.java
deleted file mode 100644
index 8dfb5ff..0000000
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/GetGroupIT.java
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (C) 2013 The Android Open Source Project
-//
-// 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.
-
-package com.google.gerrit.acceptance.rest.group;
-
-import static com.google.gerrit.acceptance.rest.group.GroupAssert.assertGroupInfo;
-
-import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gerrit.server.group.GroupJson.GroupInfo;
-
-import org.junit.Test;
-
-import java.io.IOException;
-
-public class GetGroupIT extends AbstractDaemonTest {
- @Test
- public void testGetGroup() throws Exception {
- AccountGroup adminGroup = groupCache.get(new AccountGroup.NameKey("Administrators"));
-
- // by UUID
- testGetGroup("/groups/" + adminGroup.getGroupUUID().get(), adminGroup);
-
- // by name
- testGetGroup("/groups/" + adminGroup.getName(), adminGroup);
-
- // by legacy numeric ID
- testGetGroup("/groups/" + adminGroup.getId().get(), adminGroup);
- }
-
- private void testGetGroup(String url, AccountGroup expectedGroup)
- throws IOException {
- RestResponse r = adminSession.get(url);
- GroupInfo group = newGson().fromJson(r.getReader(), GroupInfo.class);
- assertGroupInfo(expectedGroup, group);
- }
-}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/GroupPropertiesIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/GroupPropertiesIT.java
deleted file mode 100644
index e9dd776..0000000
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/GroupPropertiesIT.java
+++ /dev/null
@@ -1,186 +0,0 @@
-// Copyright (C) 2013 The Android Open Source Project
-//
-// 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.
-
-package com.google.gerrit.acceptance.rest.group;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.rest.group.GroupAssert.assertGroupInfo;
-import static com.google.gerrit.acceptance.rest.group.GroupAssert.toBoolean;
-
-import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.extensions.restapi.Url;
-import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gerrit.server.group.GroupJson.GroupInfo;
-import com.google.gerrit.server.group.GroupOptionsInfo;
-import com.google.gerrit.server.group.PutDescription;
-import com.google.gerrit.server.group.PutName;
-import com.google.gerrit.server.group.PutOptions;
-import com.google.gerrit.server.group.PutOwner;
-import com.google.gerrit.server.group.SystemGroupBackend;
-
-import org.apache.http.HttpStatus;
-import org.junit.Test;
-
-public class GroupPropertiesIT extends AbstractDaemonTest {
- @Test
- public void testGroupName() throws Exception {
- AccountGroup.NameKey adminGroupName = new AccountGroup.NameKey("Administrators");
- String url = "/groups/" + groupCache.get(adminGroupName).getGroupUUID().get() + "/name";
-
- // get name
- RestResponse r = adminSession.get(url);
- String name = newGson().fromJson(r.getReader(), String.class);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- assertThat(name).isEqualTo("Administrators");
- r.consume();
-
- // set name with name conflict
- String newGroupName = "newGroup";
- r = adminSession.put("/groups/" + newGroupName);
- r.consume();
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_CREATED);
- PutName.Input in = new PutName.Input();
- in.name = newGroupName;
- r = adminSession.put(url, in);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_CONFLICT);
- r.consume();
-
- // set name to same name
- in = new PutName.Input();
- in.name = "Administrators";
- r = adminSession.put(url, in);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- r.consume();
-
- // rename
- in = new PutName.Input();
- in.name = "Admins";
- r = adminSession.put(url, in);
- String newName = newGson().fromJson(r.getReader(), String.class);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- assertThat(groupCache.get(new AccountGroup.NameKey(in.name))).isNotNull();
- assertThat(groupCache.get(adminGroupName)).isNull();
- assertThat(newName).isEqualTo(in.name);
- r.consume();
- }
-
- @Test
- public void testGroupDescription() throws Exception {
- AccountGroup.NameKey adminGroupName = new AccountGroup.NameKey("Administrators");
- AccountGroup adminGroup = groupCache.get(adminGroupName);
- String url = "/groups/" + adminGroup.getGroupUUID().get() + "/description";
-
- // get description
- RestResponse r = adminSession.get(url);
- String description = newGson().fromJson(r.getReader(), String.class);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- assertThat(description).isEqualTo(adminGroup.getDescription());
- r.consume();
-
- // set description
- PutDescription.Input in = new PutDescription.Input();
- in.description = "All users that can administrate the Gerrit Server.";
- r = adminSession.put(url, in);
- String newDescription = newGson().fromJson(r.getReader(), String.class);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- assertThat(newDescription).isEqualTo(in.description);
- adminGroup = groupCache.get(adminGroupName);
- assertThat(adminGroup.getDescription()).isEqualTo(in.description);
- r.consume();
-
- // delete description
- r = adminSession.delete(url);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_NO_CONTENT);
- adminGroup = groupCache.get(adminGroupName);
- assertThat(adminGroup.getDescription()).isNull();
-
- // set description to empty string
- in = new PutDescription.Input();
- in.description = "";
- r = adminSession.put(url, in);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_NO_CONTENT);
- adminGroup = groupCache.get(adminGroupName);
- assertThat(adminGroup.getDescription()).isNull();
- }
-
- @Test
- public void testGroupOptions() throws Exception {
- AccountGroup.NameKey adminGroupName = new AccountGroup.NameKey("Administrators");
- AccountGroup adminGroup = groupCache.get(adminGroupName);
- String url = "/groups/" + adminGroup.getGroupUUID().get() + "/options";
-
- // get options
- RestResponse r = adminSession.get(url);
- GroupOptionsInfo options = newGson().fromJson(r.getReader(), GroupOptionsInfo.class);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- assertThat(toBoolean(options.visibleToAll)).isEqualTo(adminGroup.isVisibleToAll());
- r.consume();
-
- // set options
- PutOptions.Input in = new PutOptions.Input();
- in.visibleToAll = !adminGroup.isVisibleToAll();
- r = adminSession.put(url, in);
- GroupOptionsInfo newOptions = newGson().fromJson(r.getReader(), GroupOptionsInfo.class);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- assertThat(toBoolean(newOptions.visibleToAll)).isEqualTo(in.visibleToAll);
- adminGroup = groupCache.get(adminGroupName);
- assertThat(adminGroup.isVisibleToAll()).isEqualTo(in.visibleToAll);
- r.consume();
- }
-
- @Test
- public void testGroupOwner() throws Exception {
- AccountGroup.NameKey adminGroupName = new AccountGroup.NameKey("Administrators");
- AccountGroup adminGroup = groupCache.get(adminGroupName);
- String url = "/groups/" + adminGroup.getGroupUUID().get() + "/owner";
-
- // get owner
- RestResponse r = adminSession.get(url);
- GroupInfo options = newGson().fromJson(r.getReader(), GroupInfo.class);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- assertGroupInfo(groupCache.get(adminGroup.getOwnerGroupUUID()), options);
- r.consume();
-
- // set owner by name
- PutOwner.Input in = new PutOwner.Input();
- in.owner = "Registered Users";
- r = adminSession.put(url, in);
- GroupInfo newOwner = newGson().fromJson(r.getReader(), GroupInfo.class);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- assertThat(newOwner.name).isEqualTo(in.owner);
- assertThat(newOwner.name).isEqualTo(
- SystemGroupBackend.getGroup(SystemGroupBackend.REGISTERED_USERS).getName());
- assertThat(SystemGroupBackend.REGISTERED_USERS.get())
- .isEqualTo(Url.decode(newOwner.id));
- r.consume();
-
- // set owner by UUID
- in = new PutOwner.Input();
- in.owner = adminGroup.getGroupUUID().get();
- r = adminSession.put(url, in);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- adminGroup = groupCache.get(adminGroupName);
- assertThat(groupCache.get(adminGroup.getOwnerGroupUUID()).getGroupUUID().get())
- .isEqualTo(in.owner);
- r.consume();
-
- // set non existing owner
- in = new PutOwner.Input();
- in.owner = "Non-Existing Group";
- r = adminSession.put(url, in);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_UNPROCESSABLE_ENTITY);
- r.consume();
- }
-}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/ListGroupIncludesIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/ListGroupIncludesIT.java
deleted file mode 100644
index 5dc49c6..0000000
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/ListGroupIncludesIT.java
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright (C) 2013 The Android Open Source Project
-//
-// 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.
-
-package com.google.gerrit.acceptance.rest.group;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.google.common.base.Function;
-import com.google.common.collect.Collections2;
-import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.common.Nullable;
-import com.google.gerrit.server.group.CreateGroup;
-import com.google.gerrit.server.group.GroupJson.GroupInfo;
-import com.google.gson.reflect.TypeToken;
-
-import org.apache.http.HttpStatus;
-import org.junit.Test;
-
-import java.io.IOException;
-import java.util.Collection;
-import java.util.List;
-
-public class ListGroupIncludesIT extends AbstractDaemonTest {
-
- @Test
- public void listNonExistingGroupIncludes_NotFound() throws Exception {
- assertThat(adminSession.get("/groups/non-existing/groups/").getStatusCode())
- .isEqualTo(HttpStatus.SC_NOT_FOUND);
- }
-
- @Test
- public void listEmptyGroupIncludes() throws Exception {
- assertThat(GET("/groups/Administrators/groups/")).isEmpty();
- }
-
- @Test
- public void listNonEmptyGroupIncludes() throws Exception {
- group("gx", "Administrators");
- group("gy", "Administrators");
- PUT("/groups/Administrators/groups/gx");
- PUT("/groups/Administrators/groups/gy");
-
- assertIncludes(GET("/groups/Administrators/groups/"), "gx", "gy");
- }
-
- @Test
- public void listOneIncludeMember() throws Exception {
- group("gx", "Administrators");
- group("gy", "Administrators");
- PUT("/groups/Administrators/groups/gx");
- PUT("/groups/Administrators/groups/gy");
-
- assertThat(GET_ONE("/groups/Administrators/groups/gx").name).isEqualTo("gx");
- }
-
- private List<GroupInfo> GET(String endpoint) throws IOException {
- RestResponse r = adminSession.get(endpoint);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- return newGson().fromJson(r.getReader(),
- new TypeToken<List<GroupInfo>>() {}.getType());
- }
-
- private GroupInfo GET_ONE(String endpoint) throws IOException {
- RestResponse r = adminSession.get(endpoint);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- return newGson().fromJson(r.getReader(), GroupInfo.class);
- }
-
- private void PUT(String endpoint) throws IOException {
- adminSession.put(endpoint).consume();
- }
-
- private void group(String name, String ownerGroup) throws IOException {
- CreateGroup.Input in = new CreateGroup.Input();
- in.ownerId = ownerGroup;
- adminSession.put("/groups/" + name, in).consume();
- }
-
- private void assertIncludes(List<GroupInfo> includes, String name,
- String... names) {
- Collection<String> includeNames = Collections2.transform(includes,
- new Function<GroupInfo, String>() {
- @Override
- public String apply(@Nullable GroupInfo info) {
- return info.name;
- }
- });
- assertThat((Iterable<?>)includeNames).contains(name);
- for (String n : names) {
- assertThat((Iterable<?>)includeNames).contains(n);
- }
- assertThat(includes).hasSize(names.length + 1);
- }
-}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/ListGroupMembersIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/ListGroupMembersIT.java
deleted file mode 100644
index 80fb960..0000000
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/ListGroupMembersIT.java
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright (C) 2013 The Android Open Source Project
-//
-// 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.
-
-package com.google.gerrit.acceptance.rest.group;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.google.common.base.Function;
-import com.google.common.collect.Collections2;
-import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.common.Nullable;
-import com.google.gerrit.extensions.common.AccountInfo;
-import com.google.gerrit.server.group.CreateGroup;
-import com.google.gson.reflect.TypeToken;
-
-import org.apache.http.HttpStatus;
-import org.junit.Test;
-
-import java.io.IOException;
-import java.util.Collection;
-import java.util.List;
-
-public class ListGroupMembersIT extends AbstractDaemonTest {
-
- @Test
- public void listNonExistingGroupMembers_NotFound() throws Exception {
- assertThat(adminSession.get("/groups/non-existing/members/").getStatusCode())
- .isEqualTo(HttpStatus.SC_NOT_FOUND);
- }
-
- @Test
- public void listEmptyGroupMembers() throws Exception {
- group("empty", "Administrators");
- assertThat(GET("/groups/empty/members/")).isEmpty();
- }
-
- @Test
- public void listNonEmptyGroupMembers() throws Exception {
- assertMembers(GET("/groups/Administrators/members/"), admin.fullName);
-
- accounts.create("admin2", "Administrators");
- assertMembers(GET("/groups/Administrators/members/"),
- admin.fullName, "admin2");
- }
-
- @Test
- public void listOneGroupMember() throws Exception {
- assertThat(GET_ONE("/groups/Administrators/members/admin").name)
- .isEqualTo(admin.fullName);
- }
-
- @Test
- public void listGroupMembersRecursively() throws Exception {
- group("gx", "Administrators");
- accounts.create("ux", "gx");
-
- group("gy", "Administrators");
- accounts.create("uy", "gy");
-
- PUT("/groups/Administrators/groups/gx");
- PUT("/groups/gx/groups/gy");
- assertMembers(GET("/groups/Administrators/members/?recursive"),
- admin.fullName, "ux", "uy");
- }
-
- private List<AccountInfo> GET(String endpoint) throws IOException {
- RestResponse r = adminSession.get(endpoint);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- return newGson().fromJson(r.getReader(),
- new TypeToken<List<AccountInfo>>() {}.getType());
- }
-
- private AccountInfo GET_ONE(String endpoint) throws IOException {
- RestResponse r = adminSession.get(endpoint);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- return newGson().fromJson(r.getReader(), AccountInfo.class);
- }
-
- private void PUT(String endpoint) throws IOException {
- adminSession.put(endpoint).consume();
- }
-
- private void group(String name, String ownerGroup)
- throws IOException {
- CreateGroup.Input in = new CreateGroup.Input();
- in.ownerId = ownerGroup;
- adminSession.put("/groups/" + name, in).consume();
- }
-
- private void assertMembers(List<AccountInfo> members, String name,
- String... names) {
- Collection<String> memberNames = Collections2.transform(members,
- new Function<AccountInfo, String>() {
- @Override
- public String apply(@Nullable AccountInfo info) {
- return info.name;
- }
- });
-
- assertThat((Iterable<?>)memberNames).contains(name);
- for (String n : names) {
- assertThat((Iterable<?>)memberNames).contains(n);
- }
- assertThat(members).hasSize(names.length + 1);
- }
-}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/ListGroupsIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/ListGroupsIT.java
deleted file mode 100644
index 763c36a..0000000
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/ListGroupsIT.java
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright (C) 2013 The Android Open Source Project
-//
-// 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.
-
-package com.google.gerrit.acceptance.rest.group;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.rest.group.GroupAssert.assertGroupInfo;
-import static com.google.gerrit.acceptance.rest.group.GroupAssert.assertGroups;
-
-import com.google.common.base.Function;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
-import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.common.Nullable;
-import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gerrit.server.group.CreateGroup;
-import com.google.gerrit.server.group.GroupJson.GroupInfo;
-import com.google.gson.reflect.TypeToken;
-
-import org.apache.http.HttpStatus;
-import org.junit.Test;
-
-import java.util.Map;
-import java.util.Set;
-
-public class ListGroupsIT extends AbstractDaemonTest {
- @Test
- public void testListAllGroups() throws Exception {
- Iterable<String> expectedGroups = Iterables.transform(groupCache.all(),
- new Function<AccountGroup, String>() {
- @Override
- @Nullable
- public String apply(@Nullable AccountGroup group) {
- return group.getName();
- }
- });
- RestResponse r = adminSession.get("/groups/");
- Map<String, GroupInfo> result =
- newGson().fromJson(r.getReader(),
- new TypeToken<Map<String, GroupInfo>>() {}.getType());
- assertGroups(expectedGroups, result.keySet());
- }
-
- @Test
- public void testOnlyVisibleGroupsReturned() throws Exception {
- String newGroupName = "newGroup";
- CreateGroup.Input in = new CreateGroup.Input();
- in.description = "a hidden group";
- in.visibleToAll = false;
- in.ownerId = groupCache.get(new AccountGroup.NameKey("Administrators"))
- .getGroupUUID().get();
- adminSession.put("/groups/" + newGroupName, in).consume();
-
- Set<String> expectedGroups = Sets.newHashSet(newGroupName);
- RestResponse r = userSession.get("/groups/");
- Map<String, GroupInfo> result =
- newGson().fromJson(r.getReader(),
- new TypeToken<Map<String, GroupInfo>>() {}.getType());
- assertThat(result).isEmpty();
-
- r = adminSession.put(
- String.format("/groups/%s/members/%s", newGroupName, user.username));
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_CREATED);
-
- r = userSession.get("/groups/");
- result = newGson().fromJson(r.getReader(),
- new TypeToken<Map<String, GroupInfo>>() {}.getType());
- assertGroups(expectedGroups, result.keySet());
- }
-
- @Test
- public void testAllGroupInfoFieldsSetCorrectly() throws Exception {
- AccountGroup adminGroup = groupCache.get(new AccountGroup.NameKey("Administrators"));
- RestResponse r = adminSession.get("/groups/?q=" + adminGroup.getName());
- Map<String, GroupInfo> result =
- newGson().fromJson(r.getReader(),
- new TypeToken<Map<String, GroupInfo>>() {}.getType());
- GroupInfo adminGroupInfo = result.get(adminGroup.getName());
- assertGroupInfo(adminGroup, adminGroupInfo);
- }
-}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/BUCK
index 1efaa60..d4365c5 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/BUCK
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/BUCK
@@ -18,6 +18,7 @@
'//lib:guava',
'//lib:junit',
'//lib:truth',
+ '//gerrit-extension-api:api',
'//gerrit-server:server',
],
)
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/BanCommitIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/BanCommitIT.java
index ceed9b6..682059c 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/BanCommitIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/BanCommitIT.java
@@ -15,18 +15,16 @@
package com.google.gerrit.acceptance.rest.project;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.GitUtil.add;
-import static com.google.gerrit.acceptance.GitUtil.createCommit;
import static com.google.gerrit.acceptance.GitUtil.pushHead;
import com.google.common.collect.Iterables;
import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.GitUtil.Commit;
import com.google.gerrit.acceptance.RestResponse;
import com.google.gerrit.server.project.BanCommit;
import com.google.gerrit.server.project.BanCommit.BanResultInfo;
import org.apache.http.HttpStatus;
+import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.PushResult;
import org.junit.Test;
@@ -34,20 +32,20 @@
@Test
public void banCommit() throws Exception {
- add(git, "a.txt", "some content");
- Commit c = createCommit(git, admin.getIdent(), "subject");
+ RevCommit c = commitBuilder()
+ .add("a.txt", "some content")
+ .create();
RestResponse r =
adminSession.put("/projects/" + project.get() + "/ban/",
- BanCommit.Input.fromCommits(c.getCommit().getName()));
+ BanCommit.Input.fromCommits(c.name()));
assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
BanResultInfo info = newGson().fromJson(r.getReader(), BanResultInfo.class);
- assertThat(Iterables.getOnlyElement(info.newlyBanned))
- .isEqualTo(c.getCommit().getName());
+ assertThat(Iterables.getOnlyElement(info.newlyBanned)).isEqualTo(c.name());
assertThat(info.alreadyBanned).isNull();
assertThat(info.ignored).isNull();
- PushResult pushResult = pushHead(git, "refs/heads/master", false);
+ PushResult pushResult = pushHead(testRepo, "refs/heads/master", false);
assertThat(pushResult.getRemoteUpdate("refs/heads/master").getMessage())
.startsWith("contains banned commit");
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/BranchAssert.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/BranchAssert.java
index c706e17..c860bf0 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/BranchAssert.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/BranchAssert.java
@@ -16,39 +16,44 @@
import static com.google.common.truth.Truth.assertThat;
-import com.google.common.base.Predicate;
+import com.google.common.base.Function;
import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.gerrit.server.project.ListBranches.BranchInfo;
+import com.google.gerrit.extensions.api.projects.BranchInfo;
import java.util.List;
public class BranchAssert {
-
public static void assertBranches(List<BranchInfo> expectedBranches,
List<BranchInfo> actualBranches) {
- List<BranchInfo> missingBranches = Lists.newArrayList(actualBranches);
- for (final BranchInfo b : expectedBranches) {
- BranchInfo info =
- Iterables.find(actualBranches, new Predicate<BranchInfo>() {
- @Override
- public boolean apply(BranchInfo info) {
- return info.ref.equals(b.ref);
- }
- }, null);
- assertThat(info).named("branch " + b.ref).isNotNull();
- assertBranchInfo(b, info);
- missingBranches.remove(info);
+ assertRefNames(refs(expectedBranches), actualBranches);
+ for (int i = 0; i < expectedBranches.size(); i++) {
+ assertBranchInfo(expectedBranches.get(i), actualBranches.get(i));
}
- assertThat(missingBranches).named("" + missingBranches).isEmpty();
+ }
+
+ public static void assertRefNames(Iterable<String> expectedRefs,
+ Iterable<BranchInfo> actualBranches) {
+ Iterable<String> actualNames = refs(actualBranches);
+ assertThat(actualNames).containsExactlyElementsIn(expectedRefs).inOrder();
}
public static void assertBranchInfo(BranchInfo expected, BranchInfo actual) {
assertThat(actual.ref).isEqualTo(expected.ref);
if (expected.revision != null) {
- assertThat(actual.revision).isEqualTo(expected.revision);
+ assertThat(actual.revision).named("revision of " + actual.ref)
+ .isEqualTo(expected.revision);
}
- assertThat(toBoolean(actual.canDelete)).isEqualTo(expected.canDelete);
+ assertThat(toBoolean(actual.canDelete)).named("can delete " + actual.ref)
+ .isEqualTo(toBoolean(expected.canDelete));
+ }
+
+ private static Iterable<String> refs(Iterable<BranchInfo> infos) {
+ return Iterables.transform(infos, new Function<BranchInfo, String>() {
+ @Override
+ public String apply(BranchInfo in) {
+ return in.ref;
+ }
+ });
}
private static boolean toBoolean(Boolean b) {
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/CreateBranchIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/CreateBranchIT.java
index 3cadf66..25a226d 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/CreateBranchIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/CreateBranchIT.java
@@ -18,17 +18,25 @@
import static com.google.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS;
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
import static com.google.gerrit.server.project.Util.block;
+import static org.junit.Assert.fail;
import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.common.data.Permission;
+import com.google.gerrit.extensions.api.projects.BranchApi;
+import com.google.gerrit.extensions.api.projects.BranchInfo;
+import com.google.gerrit.extensions.api.projects.BranchInput;
+import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.ResourceConflictException;
+import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.server.git.ProjectConfig;
-import org.apache.http.HttpStatus;
+import org.eclipse.jgit.lib.Constants;
import org.junit.Before;
import org.junit.Test;
+@NoHttpd
public class CreateBranchIT extends AbstractDaemonTest {
private Branch.NameKey branch;
@@ -39,65 +47,32 @@
@Test
public void createBranch_Forbidden() throws Exception {
- RestResponse r =
- userSession.put("/projects/" + project.get()
- + "/branches/" + branch.getShortName());
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_FORBIDDEN);
+ setApiUser(user);
+ assertCreateFails(AuthException.class);
}
@Test
public void createBranchByAdmin() throws Exception {
- RestResponse r =
- adminSession.put("/projects/" + project.get()
- + "/branches/" + branch.getShortName());
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_CREATED);
- r.consume();
-
- r = adminSession.get("/projects/" + project.get()
- + "/branches/" + branch.getShortName());
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
+ assertCreateSucceeds();
}
@Test
public void branchAlreadyExists_Conflict() throws Exception {
- RestResponse r =
- adminSession.put("/projects/" + project.get()
- + "/branches/" + branch.getShortName());
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_CREATED);
- r.consume();
-
- r = adminSession.put("/projects/" + project.get()
- + "/branches/" + branch.getShortName());
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_CONFLICT);
+ assertCreateSucceeds();
+ assertCreateFails(ResourceConflictException.class);
}
@Test
public void createBranchByProjectOwner() throws Exception {
grantOwner();
-
- RestResponse r =
- userSession.put("/projects/" + project.get()
- + "/branches/" + branch.getShortName());
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_CREATED);
- r.consume();
-
- r = adminSession.get("/projects/" + project.get()
- + "/branches/" + branch.getShortName());
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
+ setApiUser(user);
+ assertCreateSucceeds();
}
@Test
public void createBranchByAdminCreateReferenceBlocked() throws Exception {
blockCreateReference();
- RestResponse r =
- adminSession.put("/projects/" + project.get()
- + "/branches/" + branch.getShortName());
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_CREATED);
- r.consume();
-
- r = adminSession.get("/projects/" + project.get()
- + "/branches/" + branch.getShortName());
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
+ assertCreateSucceeds();
}
@Test
@@ -105,19 +80,39 @@
throws Exception {
grantOwner();
blockCreateReference();
- RestResponse r =
- userSession.put("/projects/" + project.get()
- + "/branches/" + branch.getShortName());
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_FORBIDDEN);
+ setApiUser(user);
+ assertCreateFails(AuthException.class);
}
private void blockCreateReference() throws Exception {
- ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig();
+ ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
block(cfg, Permission.CREATE, ANONYMOUS_USERS, "refs/*");
- saveProjectConfig(allProjects, cfg);
+ saveProjectConfig(project, cfg);
}
private void grantOwner() throws Exception {
allow(Permission.OWNER, REGISTERED_USERS, "refs/*");
}
+
+ private BranchApi branch() throws Exception {
+ return gApi.projects()
+ .name(branch.getParentKey().get())
+ .branch(branch.get());
+ }
+
+ private void assertCreateSucceeds() throws Exception {
+ BranchInfo created = branch().create(new BranchInput()).get();
+ assertThat(created.ref)
+ .isEqualTo(Constants.R_HEADS + branch.getShortName());
+ }
+
+ private void assertCreateFails(Class<? extends RestApiException> errType)
+ throws Exception {
+ try {
+ branch().create(new BranchInput());
+ fail("Expected " + errType.getSimpleName());
+ } catch (RestApiException expected) {
+ assertThat(expected).isInstanceOf(errType);
+ }
+ }
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java
index 68c9a5e..6347874 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java
@@ -17,15 +17,23 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.acceptance.rest.project.ProjectAssert.assertProjectInfo;
import static com.google.gerrit.acceptance.rest.project.ProjectAssert.assertProjectOwners;
+import static org.junit.Assert.fail;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
+import com.google.common.net.HttpHeaders;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.acceptance.UseLocalDisk;
import com.google.gerrit.extensions.api.projects.ProjectInput;
import com.google.gerrit.extensions.client.InheritableBoolean;
import com.google.gerrit.extensions.client.SubmitType;
import com.google.gerrit.extensions.common.ProjectInfo;
+import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.ResourceConflictException;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
+import com.google.gerrit.extensions.restapi.Url;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames;
@@ -33,6 +41,7 @@
import com.google.gerrit.server.project.ProjectState;
import org.apache.http.HttpStatus;
+import org.apache.http.message.BasicHeader;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
@@ -47,30 +56,8 @@
public class CreateProjectIT extends AbstractDaemonTest {
@Test
- public void testCreateProjectApi() throws Exception {
- final String newProjectName = "newProject";
- ProjectInfo p = gApi.projects().name(newProjectName).create().get();
- assertThat(p.name).isEqualTo(newProjectName);
- ProjectState projectState = projectCache.get(new Project.NameKey(newProjectName));
- assertThat(projectState).isNotNull();
- assertProjectInfo(projectState.getProject(), p);
- assertHead(newProjectName, "refs/heads/master");
- }
-
- @Test
- public void testCreateProjectApiWithGitSuffix() throws Exception {
- final String newProjectName = "newProject";
- ProjectInfo p = gApi.projects().name(newProjectName + ".git").create().get();
- assertThat(p.name).isEqualTo(newProjectName);
- ProjectState projectState = projectCache.get(new Project.NameKey(newProjectName));
- assertThat(projectState).isNotNull();
- assertProjectInfo(projectState.getProject(), p);
- assertHead(newProjectName, "refs/heads/master");
- }
-
- @Test
- public void testCreateProject() throws Exception {
- final String newProjectName = "newProject";
+ public void testCreateProjectHttp() throws Exception {
+ String newProjectName = name("newProject");
RestResponse r = adminSession.put("/projects/" + newProjectName);
assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_CREATED);
ProjectInfo p = newGson().fromJson(r.getReader(), ProjectInfo.class);
@@ -82,11 +69,49 @@
}
@Test
- public void testCreateProjectWithGitSuffix() throws Exception {
- final String newProjectName = "newProject";
- RestResponse r = adminSession.put("/projects/" + newProjectName + ".git");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_CREATED);
- ProjectInfo p = newGson().fromJson(r.getReader(), ProjectInfo.class);
+ public void testCreateProjectHttpWhenProjectAlreadyExists_Conflict()
+ throws Exception {
+ RestResponse r = adminSession.put("/projects/" + allProjects.get());
+ assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_CONFLICT);
+ }
+
+ @Test
+ public void testCreateProjectHttpWhenProjectAlreadyExists_PreconditionFailed()
+ throws Exception {
+ RestResponse r = adminSession.putWithHeader("/projects/" + allProjects.get(),
+ new BasicHeader(HttpHeaders.IF_NONE_MATCH, "*"));
+ assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_PRECONDITION_FAILED);
+ }
+
+ @Test
+ @UseLocalDisk
+ public void testCreateProjectHttpWithUnreasonableName_BadRequest()
+ throws Exception {
+ RestResponse r = adminSession.put("/projects/" + Url.encode(name("invalid/../name")));
+ assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_BAD_REQUEST);
+ }
+
+ @Test
+ public void testCreateProjectHttpWithNameMismatch_BadRequest() throws Exception {
+ ProjectInput in = new ProjectInput();
+ in.name = name("otherName");
+ RestResponse r = adminSession.put("/projects/" + name("someName"), in);
+ assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_BAD_REQUEST);
+ }
+
+ @Test
+ public void testCreateProjectHttpWithInvalidRefName_BadRequest()
+ throws Exception {
+ ProjectInput in = new ProjectInput();
+ in.branches = Collections.singletonList(name("invalid ref name"));
+ RestResponse r = adminSession.put("/projects/" + name("newProject"), in);
+ assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_BAD_REQUEST);
+ }
+
+ @Test
+ public void testCreateProject() throws Exception {
+ String newProjectName = name("newProject");
+ ProjectInfo p = gApi.projects().create(newProjectName).get();
assertThat(p.name).isEqualTo(newProjectName);
ProjectState projectState = projectCache.get(new Project.NameKey(newProjectName));
assertThat(projectState).isNotNull();
@@ -95,25 +120,28 @@
}
@Test
- public void testCreateProjectWithNameMismatch_BadRequest() throws Exception {
- ProjectInput in = new ProjectInput();
- in.name = "otherName";
- RestResponse r = adminSession.put("/projects/someName", in);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_BAD_REQUEST);
+ public void testCreateProjectWithGitSuffix() throws Exception {
+ String newProjectName = name("newProject");
+ ProjectInfo p = gApi.projects().create(newProjectName + ".git").get();
+ assertThat(p.name).isEqualTo(newProjectName);
+ ProjectState projectState = projectCache.get(new Project.NameKey(newProjectName));
+ assertThat(projectState).isNotNull();
+ assertProjectInfo(projectState.getProject(), p);
+ assertHead(newProjectName, "refs/heads/master");
}
@Test
public void testCreateProjectWithProperties() throws Exception {
- final String newProjectName = "newProject";
+ String newProjectName = name("newProject");
ProjectInput in = new ProjectInput();
+ in.name = newProjectName;
in.description = "Test description";
in.submitType = SubmitType.CHERRY_PICK;
in.useContributorAgreements = InheritableBoolean.TRUE;
in.useSignedOffBy = InheritableBoolean.TRUE;
in.useContentMerge = InheritableBoolean.TRUE;
in.requireChangeId = InheritableBoolean.TRUE;
- RestResponse r = adminSession.put("/projects/" + newProjectName, in);
- ProjectInfo p = newGson().fromJson(r.getReader(), ProjectInfo.class);
+ ProjectInfo p = gApi.projects().create(in).get();
assertThat(p.name).isEqualTo(newProjectName);
Project project = projectCache.get(new Project.NameKey(newProjectName)).getProject();
assertProjectInfo(project, p);
@@ -127,13 +155,16 @@
@Test
public void testCreateChildProject() throws Exception {
- final String parentName = "parent";
- RestResponse r = adminSession.put("/projects/" + parentName);
- r.consume();
- final String childName = "child";
+ String parentName = name("parent");
ProjectInput in = new ProjectInput();
+ in.name = parentName;
+ gApi.projects().create(in);
+
+ String childName = name("child");
+ in = new ProjectInput();
+ in.name = childName;
in.parent = parentName;
- r = adminSession.put("/projects/" + childName, in);
+ gApi.projects().create(in);
Project project = projectCache.get(new Project.NameKey(childName)).getProject();
assertThat(project.getParentName()).isEqualTo(in.parent);
}
@@ -142,21 +173,22 @@
public void testCreateChildProjectUnderNonExistingParent_UnprocessableEntity()
throws Exception {
ProjectInput in = new ProjectInput();
+ in.name = name("newProjectName");
in.parent = "non-existing-project";
- RestResponse r = adminSession.put("/projects/child", in);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_UNPROCESSABLE_ENTITY);
+ assertCreateFails(in, UnprocessableEntityException.class);
}
@Test
public void testCreateProjectWithOwner() throws Exception {
- final String newProjectName = "newProject";
+ String newProjectName = name("newProject");
ProjectInput in = new ProjectInput();
+ in.name = newProjectName;
in.owners = Lists.newArrayListWithCapacity(3);
in.owners.add("Anonymous Users"); // by name
in.owners.add(SystemGroupBackend.REGISTERED_USERS.get()); // by UUID
in.owners.add(Integer.toString(groupCache.get(
new AccountGroup.NameKey("Administrators")).getId().get())); // by ID
- adminSession.put("/projects/" + newProjectName, in);
+ gApi.projects().create(in);
ProjectState projectState = projectCache.get(new Project.NameKey(newProjectName));
Set<AccountGroup.UUID> expectedOwnerIds = Sets.newHashSetWithExpectedSize(3);
expectedOwnerIds.add(SystemGroupBackend.ANONYMOUS_USERS);
@@ -169,39 +201,42 @@
public void testCreateProjectWithNonExistingOwner_UnprocessableEntity()
throws Exception {
ProjectInput in = new ProjectInput();
+ in.name = name("newProjectName");
in.owners = Collections.singletonList("non-existing-group");
- RestResponse r = adminSession.put("/projects/newProject", in);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_UNPROCESSABLE_ENTITY);
+ assertCreateFails(in, UnprocessableEntityException.class);
}
@Test
public void testCreatePermissionOnlyProject() throws Exception {
- final String newProjectName = "newProject";
+ String newProjectName = name("newProject");
ProjectInput in = new ProjectInput();
+ in.name = newProjectName;
in.permissionsOnly = true;
- adminSession.put("/projects/" + newProjectName, in);
+ gApi.projects().create(in);
assertHead(newProjectName, RefNames.REFS_CONFIG);
}
@Test
public void testCreateProjectWithEmptyCommit() throws Exception {
- final String newProjectName = "newProject";
+ String newProjectName = name("newProject");
ProjectInput in = new ProjectInput();
+ in.name = newProjectName;
in.createEmptyCommit = true;
- adminSession.put("/projects/" + newProjectName, in);
+ gApi.projects().create(in);
assertEmptyCommit(newProjectName, "refs/heads/master");
}
@Test
public void testCreateProjectWithBranches() throws Exception {
- final String newProjectName = "newProject";
+ String newProjectName = name("newProject");
ProjectInput in = new ProjectInput();
+ in.name = newProjectName;
in.createEmptyCommit = true;
in.branches = Lists.newArrayListWithCapacity(3);
in.branches.add("refs/heads/test");
in.branches.add("refs/heads/master");
in.branches.add("release"); // without 'refs/heads' prefix
- adminSession.put("/projects/" + newProjectName, in);
+ gApi.projects().create(in);
assertHead(newProjectName, "refs/heads/test");
assertEmptyCommit(newProjectName, "refs/heads/test", "refs/heads/master",
"refs/heads/release");
@@ -209,15 +244,18 @@
@Test
public void testCreateProjectWithoutCapability_Forbidden() throws Exception {
- RestResponse r = userSession.put("/projects/newProject");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_FORBIDDEN);
+ setApiUser(user);
+ ProjectInput in = new ProjectInput();
+ in.name = name("newProject");
+ assertCreateFails(in, AuthException.class);
}
@Test
public void testCreateProjectWhenProjectAlreadyExists_Conflict()
throws Exception {
- RestResponse r = adminSession.put("/projects/All-Projects");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_CONFLICT);
+ ProjectInput in = new ProjectInput();
+ in.name = allProjects.get();
+ assertCreateFails(in, ResourceConflictException.class);
}
private AccountGroup.UUID groupUuid(String groupName) {
@@ -251,4 +289,14 @@
}
}
}
+
+ private void assertCreateFails(ProjectInput in,
+ Class<? extends RestApiException> errType) throws Exception {
+ try {
+ gApi.projects().create(in);
+ fail("Expected " + errType.getSimpleName());
+ } catch (RestApiException expected) {
+ assertThat(expected).isInstanceOf(errType);
+ }
+ }
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/DeleteBranchIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/DeleteBranchIT.java
index 8be6c92..a026d76 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/DeleteBranchIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/DeleteBranchIT.java
@@ -14,21 +14,25 @@
package com.google.gerrit.acceptance.rest.project;
-import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS;
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
import static com.google.gerrit.server.project.Util.block;
+import static org.junit.Assert.fail;
import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.common.data.Permission;
+import com.google.gerrit.extensions.api.projects.BranchApi;
+import com.google.gerrit.extensions.api.projects.BranchInput;
+import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.server.git.ProjectConfig;
-import org.apache.http.HttpStatus;
import org.junit.Before;
import org.junit.Test;
+@NoHttpd
public class DeleteBranchIT extends AbstractDaemonTest {
private Branch.NameKey branch;
@@ -36,62 +40,31 @@
@Before
public void setUp() throws Exception {
branch = new Branch.NameKey(project, "test");
- adminSession.put("/projects/" + project.get()
- + "/branches/" + branch.getShortName()).consume();
+ branch().create(new BranchInput());
}
@Test
public void deleteBranch_Forbidden() throws Exception {
- RestResponse r =
- userSession.delete("/projects/" + project.get()
- + "/branches/" + branch.getShortName());
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_FORBIDDEN);
- r.consume();
+ setApiUser(user);
+ assertDeleteForbidden();
}
@Test
public void deleteBranchByAdmin() throws Exception {
- RestResponse r =
- adminSession.delete("/projects/" + project.get()
- + "/branches/" + branch.getShortName());
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_NO_CONTENT);
- r.consume();
-
- r = adminSession.get("/projects/" + project.get()
- + "/branches/" + branch.getShortName());
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_NOT_FOUND);
- r.consume();
+ assertDeleteSucceeds();
}
@Test
public void deleteBranchByProjectOwner() throws Exception {
grantOwner();
-
- RestResponse r =
- userSession.delete("/projects/" + project.get()
- + "/branches/" + branch.getShortName());
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_NO_CONTENT);
- r.consume();
-
- r = userSession.get("/projects/" + project.get()
- + "/branches/" + branch.getShortName());
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_NOT_FOUND);
- r.consume();
+ setApiUser(user);
+ assertDeleteSucceeds();
}
@Test
public void deleteBranchByAdminForcePushBlocked() throws Exception {
blockForcePush();
- RestResponse r =
- adminSession.delete("/projects/" + project.get()
- + "/branches/" + branch.getShortName());
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_NO_CONTENT);
- r.consume();
-
- r = adminSession.get("/projects/" + project.get()
- + "/branches/" + branch.getShortName());
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_NOT_FOUND);
- r.consume();
+ assertDeleteSucceeds();
}
@Test
@@ -99,20 +72,43 @@
throws Exception {
grantOwner();
blockForcePush();
- RestResponse r =
- userSession.delete("/projects/" + project.get()
- + "/branches/" + branch.getShortName());
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_FORBIDDEN);
- r.consume();
+ setApiUser(user);
+ assertDeleteForbidden();
}
private void blockForcePush() throws Exception {
- ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig();
+ ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
block(cfg, Permission.PUSH, ANONYMOUS_USERS, "refs/heads/*").setForce(true);
- saveProjectConfig(allProjects, cfg);
+ saveProjectConfig(project, cfg);
}
private void grantOwner() throws Exception {
allow(Permission.OWNER, REGISTERED_USERS, "refs/*");
}
+
+ private BranchApi branch() throws Exception {
+ return gApi.projects()
+ .name(branch.getParentKey().get())
+ .branch(branch.get());
+ }
+
+ private void assertDeleteSucceeds() throws Exception {
+ branch().delete();
+ try {
+ branch().get();
+ fail("Expected ResourceNotFoundException");
+ } catch (ResourceNotFoundException expected) {
+ // Expected.
+ }
+ }
+
+ private void assertDeleteForbidden() throws Exception {
+ try {
+ branch().delete();
+ fail("Expected AuthException");
+ } catch (AuthException expected) {
+ // Expected.
+ }
+ branch().get();
+ }
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GarbageCollectionIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GarbageCollectionIT.java
index 6aa3af6..d680541 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GarbageCollectionIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GarbageCollectionIT.java
@@ -15,7 +15,6 @@
package com.google.gerrit.acceptance.rest.project;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.GitUtil.createProject;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.GcAssert;
@@ -39,8 +38,7 @@
@Before
public void setUp() throws Exception {
- project2 = new Project.NameKey("p2");
- createProject(sshSession, project2.get());
+ project2 = createProject("p2");
}
@Test
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetChildProjectIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetChildProjectIT.java
index f49408e..ea3a5db 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetChildProjectIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetChildProjectIT.java
@@ -15,87 +15,66 @@
package com.google.gerrit.acceptance.rest.project;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.GitUtil.createProject;
import static com.google.gerrit.acceptance.rest.project.ProjectAssert.assertProjectInfo;
import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.acceptance.SshSession;
+import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.extensions.common.ProjectInfo;
+import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.reviewdb.client.Project;
-import org.apache.http.HttpStatus;
import org.junit.Test;
-import java.io.IOException;
-
+@NoHttpd
public class GetChildProjectIT extends AbstractDaemonTest {
@Test
public void getNonExistingChildProject_NotFound() throws Exception {
- assertThat(
- GET("/projects/" + allProjects.get() + "/children/non-existing")
- .getStatusCode()).isEqualTo(HttpStatus.SC_NOT_FOUND);
+ assertChildNotFound(allProjects, "non-existing");
}
@Test
public void getNonChildProject_NotFound() throws Exception {
- SshSession sshSession = new SshSession(server, admin);
- Project.NameKey p1 = new Project.NameKey("p1");
- createProject(sshSession, p1.get());
- Project.NameKey p2 = new Project.NameKey("p2");
- createProject(sshSession, p2.get());
- sshSession.close();
- assertThat(
- GET("/projects/" + p1.get() + "/children/" + p2.get()).getStatusCode())
- .isEqualTo(HttpStatus.SC_NOT_FOUND);
+ Project.NameKey p1 = createProject("p1");
+ Project.NameKey p2 = createProject("p2");
+
+ assertChildNotFound(p1, p2.get());
}
@Test
public void getChildProject() throws Exception {
- SshSession sshSession = new SshSession(server, admin);
- Project.NameKey child = new Project.NameKey("p1");
- createProject(sshSession, child.get());
- sshSession.close();
- RestResponse r =
- GET("/projects/" + allProjects.get() + "/children/" + child.get());
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- ProjectInfo childInfo =
- newGson().fromJson(r.getReader(), ProjectInfo.class);
+ Project.NameKey child = createProject("p1");
+ ProjectInfo childInfo = gApi.projects().name(allProjects.get())
+ .child(child.get()).get();
+
assertProjectInfo(projectCache.get(child).getProject(), childInfo);
}
@Test
public void getGrandChildProject_NotFound() throws Exception {
- SshSession sshSession = new SshSession(server, admin);
- Project.NameKey child = new Project.NameKey("p1");
- createProject(sshSession, child.get());
- Project.NameKey grandChild = new Project.NameKey("p1.1");
- createProject(sshSession, grandChild.get(), child);
- sshSession.close();
- assertThat(
- GET("/projects/" + allProjects.get() + "/children/" + grandChild.get())
- .getStatusCode()).isEqualTo(HttpStatus.SC_NOT_FOUND);
+ Project.NameKey child = createProject("p1");
+ Project.NameKey grandChild = createProject("p1.1", child);
+
+ assertChildNotFound(allProjects, grandChild.get());
}
@Test
public void getGrandChildProjectWithRecursiveFlag() throws Exception {
- SshSession sshSession = new SshSession(server, admin);
- Project.NameKey child = new Project.NameKey("p1");
- createProject(sshSession, child.get());
- Project.NameKey grandChild = new Project.NameKey("p1.1");
- createProject(sshSession, grandChild.get(), child);
- sshSession.close();
- RestResponse r =
- GET("/projects/" + allProjects.get() + "/children/" + grandChild.get()
- + "?recursive");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- ProjectInfo grandChildInfo =
- newGson().fromJson(r.getReader(), ProjectInfo.class);
- assertProjectInfo(projectCache.get(grandChild).getProject(), grandChildInfo);
+ Project.NameKey child = createProject("p1");
+ Project.NameKey grandChild = createProject("p1.1", child);
+
+ ProjectInfo grandChildInfo = gApi.projects().name(allProjects.get())
+ .child(grandChild.get()).get(true);
+ assertProjectInfo(
+ projectCache.get(grandChild).getProject(), grandChildInfo);
}
- private RestResponse GET(String endpoint) throws IOException {
- return adminSession.get(endpoint);
+ private void assertChildNotFound(Project.NameKey parent, String child)
+ throws Exception {
+ try {
+ gApi.projects().name(parent.get()).child(child);
+ } catch (ResourceNotFoundException e) {
+ assertThat(e.getMessage()).contains(child);
+ }
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetCommitIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetCommitIT.java
index 4a20957..d3677ab 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetCommitIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetCommitIT.java
@@ -15,13 +15,12 @@
package com.google.gerrit.acceptance.rest.project;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
import com.google.common.collect.Iterables;
import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.GitUtil;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.Permission;
import com.google.gerrit.extensions.common.CommitInfo;
import com.google.gerrit.server.git.ProjectConfig;
@@ -40,13 +39,8 @@
@Before
public void setUp() throws Exception {
- repo = new TestRepository<>(repoManager.openRepository(project));
-
- ProjectConfig pc = projectCache.checkedGet(allProjects).getConfig();
- for (AccessSection sec : pc.getAccessSections()) {
- sec.removePermission(Permission.READ);
- }
- saveProjectConfig(allProjects, pc);
+ repo = GitUtil.newTestRepository(repoManager.openRepository(project));
+ blockRead(project, "refs/*");
}
@After
@@ -64,7 +58,7 @@
@Test
public void getMergedCommit_Found() throws Exception {
- allow(Permission.READ, REGISTERED_USERS, "refs/heads/*");
+ unblockRead();
RevCommit commit = repo.parseBody(repo.branch("master")
.commit()
.message("Create\n\nNew commit\n")
@@ -98,9 +92,9 @@
@Test
public void getOpenChange_Found() throws Exception {
- allow(Permission.READ, REGISTERED_USERS, "refs/heads/*");
- PushOneCommit.Result r = pushFactory.create(db, admin.getIdent())
- .to(git, "refs/for/master");
+ unblockRead();
+ PushOneCommit.Result r = pushFactory.create(db, admin.getIdent(), testRepo)
+ .to("refs/for/master");
r.assertOkStatus();
CommitInfo info = getCommit(r.getCommitId());
@@ -123,12 +117,18 @@
@Test
public void getOpenChange_NotFound() throws Exception {
- PushOneCommit.Result r = pushFactory.create(db, admin.getIdent())
- .to(git, "refs/for/master");
+ PushOneCommit.Result r = pushFactory.create(db, admin.getIdent(), testRepo)
+ .to("refs/for/master");
r.assertOkStatus();
assertNotFound(r.getCommitId());
}
+ private void unblockRead() throws Exception {
+ ProjectConfig pc = projectCache.checkedGet(project).getConfig();
+ pc.getAccessSection("refs/*").remove(new Permission(Permission.READ));
+ saveProjectConfig(project, pc);
+ }
+
private void assertNotFound(ObjectId id) throws Exception {
RestResponse r = userSession.get(
"/projects/" + project.get() + "/commits/" + id.name());
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetProjectIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetProjectIT.java
index 761e282..24b1770 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetProjectIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetProjectIT.java
@@ -17,35 +17,31 @@
import static com.google.common.truth.Truth.assertThat;
import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.extensions.common.ProjectInfo;
+import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
-import org.apache.http.HttpStatus;
import org.junit.Test;
+@NoHttpd
public class GetProjectIT extends AbstractDaemonTest {
@Test
public void getProject() throws Exception {
String name = project.get();
- RestResponse r = adminSession.get("/projects/" + name);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- ProjectInfo p = newGson().fromJson(r.getReader(), ProjectInfo.class);
+ ProjectInfo p = gApi.projects().name(name).get();
assertThat(p.name).isEqualTo(name);
}
@Test
public void getProjectWithGitSuffix() throws Exception {
String name = project.get();
- RestResponse r = adminSession.get("/projects/" + name + ".git");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- ProjectInfo p = newGson().fromJson(r.getReader(), ProjectInfo.class);
+ ProjectInfo p = gApi.projects().name(name).get();
assertThat(p.name).isEqualTo(name);
}
- @Test
+ @Test(expected = ResourceNotFoundException.class)
public void getProjectNotExisting() throws Exception {
- RestResponse r = adminSession.get("/projects/does-not-exist");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_NOT_FOUND);
+ gApi.projects().name("does-not-exist").get();
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListBranchesIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListBranchesIT.java
index 48f9ad89..3793c82 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListBranchesIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListBranchesIT.java
@@ -14,102 +14,87 @@
package com.google.gerrit.acceptance.rest.project;
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.GitUtil.createProject;
import static com.google.gerrit.acceptance.rest.project.BranchAssert.assertBranches;
+import static com.google.gerrit.acceptance.rest.project.BranchAssert.assertRefNames;
+import static org.junit.Assert.fail;
-import com.google.common.collect.Lists;
+import com.google.common.collect.ImmutableList;
import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.server.project.ListBranches.BranchInfo;
-import com.google.gson.reflect.TypeToken;
+import com.google.gerrit.acceptance.NoHttpd;
+import com.google.gerrit.acceptance.TestProjectInput;
+import com.google.gerrit.extensions.api.projects.BranchInfo;
+import com.google.gerrit.extensions.api.projects.ProjectApi.ListBranchesRequest;
+import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
-import org.apache.http.HttpStatus;
import org.junit.Test;
-import java.io.IOException;
-import java.util.Collections;
-import java.util.List;
-
+@NoHttpd
public class ListBranchesIT extends AbstractDaemonTest {
@Test
public void listBranchesOfNonExistingProject_NotFound() throws Exception {
- assertThat(GET("/projects/non-existing/branches").getStatusCode())
- .isEqualTo(HttpStatus.SC_NOT_FOUND);
+ try {
+ gApi.projects().name("non-existing").branches().get();
+ fail("Expected ResourceNotFoundException");
+ } catch (ResourceNotFoundException expected) {
+ // Expected.
+ }
}
@Test
public void listBranchesOfNonVisibleProject_NotFound() throws Exception {
blockRead(project, "refs/*");
- assertThat(
- userSession.get("/projects/" + project.get() + "/branches")
- .getStatusCode()).isEqualTo(HttpStatus.SC_NOT_FOUND);
+ setApiUser(user);
+ try {
+ gApi.projects().name(project.get()).branches().get();
+ fail("Expected ResourceNotFoundException");
+ } catch (ResourceNotFoundException expected) {
+ // Expected.
+ }
}
@Test
+ @TestProjectInput(createEmptyCommit = false)
public void listBranchesOfEmptyProject() throws Exception {
- Project.NameKey emptyProject = new Project.NameKey("empty");
- createProject(sshSession, emptyProject.get(), null, false);
- RestResponse r = adminSession.get("/projects/" + emptyProject.get() + "/branches");
- List<BranchInfo> expected = Lists.asList(
- new BranchInfo("refs/meta/config", null, false),
- new BranchInfo[] {
- new BranchInfo("HEAD", null, false)
- });
- assertBranches(expected, toBranchInfoList(r));
+ assertBranches(ImmutableList.of(
+ branch("HEAD", null, false),
+ branch("refs/meta/config", null, false)),
+ list().get());
}
@Test
public void listBranches() throws Exception {
- pushTo("refs/heads/master");
- String masterCommit = git.getRepository().getRef("master").getTarget().getObjectId().getName();
- pushTo("refs/heads/dev");
- String devCommit = git.getRepository().getRef("master").getTarget().getObjectId().getName();
- RestResponse r = adminSession.get("/projects/" + project.get() + "/branches");
- List<BranchInfo> expected = Lists.asList(
- new BranchInfo("refs/meta/config", null, false),
- new BranchInfo[] {
- new BranchInfo("HEAD", "master", false),
- new BranchInfo("refs/heads/master", masterCommit, false),
- new BranchInfo("refs/heads/dev", devCommit, true)
- });
- List<BranchInfo> result = toBranchInfoList(r);
- assertBranches(expected, result);
-
- // verify correct sorting
- assertThat(result.get(0).ref).isEqualTo("HEAD");
- assertThat(result.get(1).ref).isEqualTo("refs/meta/config");
- assertThat(result.get(2).ref).isEqualTo("refs/heads/dev");
- assertThat(result.get(3).ref).isEqualTo("refs/heads/master");
+ String master = pushTo("refs/heads/master").getCommit().name();
+ String dev = pushTo("refs/heads/dev").getCommit().name();
+ assertBranches(ImmutableList.of(
+ branch("HEAD", "master", false),
+ branch("refs/meta/config", null, false),
+ branch("refs/heads/dev", dev, true),
+ branch("refs/heads/master", master, false)),
+ list().get());
}
@Test
public void listBranchesSomeHidden() throws Exception {
blockRead(project, "refs/heads/dev");
- pushTo("refs/heads/master");
- String masterCommit = git.getRepository().getRef("master").getTarget().getObjectId().getName();
+ String master = pushTo("refs/heads/master").getCommit().name();
pushTo("refs/heads/dev");
- RestResponse r = userSession.get("/projects/" + project.get() + "/branches");
+ setApiUser(user);
// refs/meta/config is hidden since user is no project owner
- List<BranchInfo> expected = Lists.asList(
- new BranchInfo("HEAD", "master", false),
- new BranchInfo[] {
- new BranchInfo("refs/heads/master", masterCommit, false),
- });
- assertBranches(expected, toBranchInfoList(r));
+ assertBranches(ImmutableList.of(
+ branch("HEAD", "master", false),
+ branch("refs/heads/master", master, false)),
+ list().get());
}
@Test
public void listBranchesHeadHidden() throws Exception {
blockRead(project, "refs/heads/master");
pushTo("refs/heads/master");
- pushTo("refs/heads/dev");
- String devCommit = git.getRepository().getRef("master").getTarget().getObjectId().getName();
- RestResponse r = userSession.get("/projects/" + project.get() + "/branches");
+ String dev = pushTo("refs/heads/dev").getCommit().name();
+ setApiUser(user);
// refs/meta/config is hidden since user is no project owner
- assertBranches(Collections.singletonList(new BranchInfo("refs/heads/dev",
- devCommit, false)), toBranchInfoList(r));
+ assertBranches(ImmutableList.of(branch("refs/heads/dev", dev, false)),
+ list().get());
}
@Test
@@ -119,47 +104,40 @@
pushTo("refs/heads/someBranch2");
pushTo("refs/heads/someBranch3");
- // using only limit
- RestResponse r =
- adminSession.get("/projects/" + project.get() + "/branches?n=4");
- List<BranchInfo> result = toBranchInfoList(r);
- assertThat(result).hasSize(4);
- assertThat(result.get(0).ref).isEqualTo("HEAD");
- assertThat(result.get(1).ref).isEqualTo("refs/meta/config");
- assertThat(result.get(2).ref).isEqualTo("refs/heads/master");
- assertThat(result.get(3).ref).isEqualTo("refs/heads/someBranch1");
+ // Using only limit.
+ assertRefNames(ImmutableList.of(
+ "HEAD",
+ "refs/meta/config",
+ "refs/heads/master",
+ "refs/heads/someBranch1"),
+ list().withLimit(4).get());
- // limit higher than total number of branches
- r = adminSession.get("/projects/" + project.get() + "/branches?n=25");
- result = toBranchInfoList(r);
- assertThat(result).hasSize(6);
- assertThat(result.get(0).ref).isEqualTo("HEAD");
- assertThat(result.get(1).ref).isEqualTo("refs/meta/config");
- assertThat(result.get(2).ref).isEqualTo("refs/heads/master");
- assertThat(result.get(3).ref).isEqualTo("refs/heads/someBranch1");
- assertThat(result.get(4).ref).isEqualTo("refs/heads/someBranch2");
- assertThat(result.get(5).ref).isEqualTo("refs/heads/someBranch3");
+ // Limit higher than total number of branches.
+ assertRefNames(ImmutableList.of(
+ "HEAD",
+ "refs/meta/config",
+ "refs/heads/master",
+ "refs/heads/someBranch1",
+ "refs/heads/someBranch2",
+ "refs/heads/someBranch3"),
+ list().withLimit(25).get());
- // using skip only
- r = adminSession.get("/projects/" + project.get() + "/branches?s=2");
- result = toBranchInfoList(r);
- assertThat(result).hasSize(4);
- assertThat(result.get(0).ref).isEqualTo("refs/heads/master");
- assertThat(result.get(1).ref).isEqualTo("refs/heads/someBranch1");
- assertThat(result.get(2).ref).isEqualTo("refs/heads/someBranch2");
- assertThat(result.get(3).ref).isEqualTo("refs/heads/someBranch3");
+ // Using start only.
+ assertRefNames(ImmutableList.of(
+ "refs/heads/master",
+ "refs/heads/someBranch1",
+ "refs/heads/someBranch2",
+ "refs/heads/someBranch3"),
+ list().withStart(2).get());
- // skip more branches than the number of available branches
- r = adminSession.get("/projects/" + project.get() + "/branches?s=7");
- result = toBranchInfoList(r);
- assertThat(result).isEmpty();
+ // Skip more branches than the number of available branches.
+ assertRefNames(ImmutableList.<String> of(), list().withStart(7).get());
- // using skip and limit
- r = adminSession.get("/projects/" + project.get() + "/branches?s=2&n=2");
- result = toBranchInfoList(r);
- assertThat(result).hasSize(2);
- assertThat(result.get(0).ref).isEqualTo("refs/heads/master");
- assertThat(result.get(1).ref).isEqualTo("refs/heads/someBranch1");
+ // Ssing start and limit.
+ assertRefNames(ImmutableList.of(
+ "refs/heads/master",
+ "refs/heads/someBranch1"),
+ list().withStart(2).withLimit(2).get());
}
@Test
@@ -169,38 +147,34 @@
pushTo("refs/heads/someBranch2");
pushTo("refs/heads/someBranch3");
- //using substring
- RestResponse r =
- adminSession.get("/projects/" + project.get() + "/branches?m=some");
- List<BranchInfo> result = toBranchInfoList(r);
- assertThat(result).hasSize(3);
- assertThat(result.get(0).ref).isEqualTo("refs/heads/someBranch1");
- assertThat(result.get(1).ref).isEqualTo("refs/heads/someBranch2");
- assertThat(result.get(2).ref).isEqualTo("refs/heads/someBranch3");
+ // Using substring.
+ assertRefNames(ImmutableList.of(
+ "refs/heads/someBranch1",
+ "refs/heads/someBranch2",
+ "refs/heads/someBranch3"),
+ list().withSubstring("some").get());
- r = adminSession.get("/projects/" + project.get() + "/branches?m=Branch");
- result = toBranchInfoList(r);
- assertThat(result).hasSize(3);
- assertThat(result.get(0).ref).isEqualTo("refs/heads/someBranch1");
- assertThat(result.get(1).ref).isEqualTo("refs/heads/someBranch2");
- assertThat(result.get(2).ref).isEqualTo("refs/heads/someBranch3");
+ assertRefNames(ImmutableList.of(
+ "refs/heads/someBranch1",
+ "refs/heads/someBranch2",
+ "refs/heads/someBranch3"),
+ list().withSubstring("Branch").get());
- //using regex
- r = adminSession.get("/projects/" + project.get() + "/branches?r=.*ast.*r");
- result = toBranchInfoList(r);
- assertThat(result).hasSize(1);
- assertThat(result.get(0).ref).isEqualTo("refs/heads/master");
+ // Using regex.
+ assertRefNames(ImmutableList.of("refs/heads/master"),
+ list().withRegex(".*ast.*r").get());
}
- private RestResponse GET(String endpoint) throws IOException {
- return adminSession.get(endpoint);
+ private ListBranchesRequest list() throws Exception {
+ return gApi.projects().name(project.get()).branches();
}
- private static List<BranchInfo> toBranchInfoList(RestResponse r)
- throws IOException {
- List<BranchInfo> result =
- newGson().fromJson(r.getReader(),
- new TypeToken<List<BranchInfo>>() {}.getType());
- return result;
+ private static BranchInfo branch(String ref, String revision,
+ boolean canDelete) {
+ BranchInfo info = new BranchInfo();
+ info.ref = ref;
+ info.revision = revision;
+ info.canDelete = canDelete ? true : null;
+ return info;
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListChildProjectsIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListChildProjectsIT.java
index 0d3b467..80ad493 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListChildProjectsIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListChildProjectsIT.java
@@ -15,84 +15,54 @@
package com.google.gerrit.acceptance.rest.project;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.GitUtil.createProject;
-import static com.google.gerrit.acceptance.rest.project.ProjectAssert.assertProjects;
+import static com.google.gerrit.acceptance.rest.project.ProjectAssert.assertThatNameList;
import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.extensions.common.ProjectInfo;
+import com.google.gerrit.acceptance.NoHttpd;
+import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.reviewdb.client.Project;
-import com.google.gson.reflect.TypeToken;
-import org.apache.http.HttpStatus;
import org.junit.Test;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-
+@NoHttpd
public class ListChildProjectsIT extends AbstractDaemonTest {
@Test
public void listChildrenOfNonExistingProject_NotFound() throws Exception {
- assertThat(GET("/projects/non-existing/children/").getStatusCode())
- .isEqualTo(HttpStatus.SC_NOT_FOUND);
+ try {
+ gApi.projects().name(name("non-existing")).child("children");
+ } catch (ResourceNotFoundException e) {
+ assertThat(e.getMessage()).contains("non-existing");
+ }
}
@Test
public void listNoChildren() throws Exception {
- RestResponse r = GET("/projects/" + allProjects.get() + "/children/");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- List<ProjectInfo> projectInfoList = toProjectInfoList(r);
- // Project 'p' was already created in the base class
- assertThat(projectInfoList).hasSize(2);
+ assertThatNameList(gApi.projects().name(project.get()).children())
+ .isEmpty();
}
@Test
public void listChildren() throws Exception {
- Project.NameKey existingProject = new Project.NameKey("p");
- Project.NameKey child1 = new Project.NameKey("p1");
- createProject(sshSession, child1.get());
- Project.NameKey child2 = new Project.NameKey("p2");
- createProject(sshSession, child2.get());
- createProject(sshSession, "p1.1", child1);
+ Project.NameKey child1 = createProject("p1");
+ Project.NameKey child1_1 = createProject("p1.1", child1);
+ Project.NameKey child1_2 = createProject("p1.2", child1);
- RestResponse r = GET("/projects/" + allProjects.get() + "/children/");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- assertProjects(
- Arrays.asList(
- new Project.NameKey("All-Users"),
- existingProject, child1, child2),
- toProjectInfoList(r));
+ assertThatNameList(gApi.projects().name(child1.get()).children())
+ .containsExactly(child1_1, child1_2).inOrder();
}
@Test
public void listChildrenRecursively() throws Exception {
- Project.NameKey child1 = new Project.NameKey("p1");
- createProject(sshSession, child1.get());
- createProject(sshSession, "p2");
- Project.NameKey child1_1 = new Project.NameKey("p1.1");
- createProject(sshSession, child1_1.get(), child1);
- Project.NameKey child1_2 = new Project.NameKey("p1.2");
- createProject(sshSession, child1_2.get(), child1);
- Project.NameKey child1_1_1 = new Project.NameKey("p1.1.1");
- createProject(sshSession, child1_1_1.get(), child1_1);
- Project.NameKey child1_1_1_1 = new Project.NameKey("p1.1.1.1");
- createProject(sshSession, child1_1_1_1.get(), child1_1_1);
+ Project.NameKey child1 = createProject("p1");
+ createProject("p2");
+ Project.NameKey child1_1 = createProject("p1.1", child1);
+ Project.NameKey child1_2 = createProject("p1.2", child1);
+ Project.NameKey child1_1_1 = createProject("p1.1.1", child1_1);
+ Project.NameKey child1_1_1_1 = createProject("p1.1.1.1", child1_1_1);
- RestResponse r = GET("/projects/" + child1.get() + "/children/?recursive");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- assertProjects(Arrays.asList(child1_1, child1_2,
- child1_1_1, child1_1_1_1), toProjectInfoList(r));
- }
-
- private static List<ProjectInfo> toProjectInfoList(RestResponse r)
- throws IOException {
- return newGson().fromJson(r.getReader(),
- new TypeToken<List<ProjectInfo>>() {}.getType());
- }
-
- private RestResponse GET(String endpoint) throws IOException {
- return adminSession.get(endpoint);
+ assertThatNameList(gApi.projects().name(child1.get()).children(true))
+ .containsExactly(child1_1, child1_1_1, child1_1_1_1, child1_2)
+ .inOrder();
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListProjectsIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListProjectsIT.java
index 0f5bed1..1e51571 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListProjectsIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListProjectsIT.java
@@ -15,25 +15,31 @@
package com.google.gerrit.acceptance.rest.project;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.GitUtil.createProject;
-import static com.google.gerrit.acceptance.rest.project.ProjectAssert.assertProjects;
+import static com.google.gerrit.acceptance.rest.project.ProjectAssert.assertThatNameList;
+import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.extensions.api.projects.ProjectInput;
+import com.google.gerrit.acceptance.NoHttpd;
+import com.google.gerrit.acceptance.TestProjectInput;
+import com.google.gerrit.common.data.Permission;
+import com.google.gerrit.extensions.api.projects.Projects.ListRequest;
+import com.google.gerrit.extensions.api.projects.Projects.ListRequest.FilterType;
import com.google.gerrit.extensions.common.ProjectInfo;
+import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.config.AllUsersName;
-import com.google.gson.reflect.TypeToken;
+import com.google.gerrit.server.git.ProjectConfig;
+import com.google.gerrit.server.project.Util;
import com.google.inject.Inject;
-import org.apache.http.HttpStatus;
import org.junit.Test;
-import java.io.IOException;
-import java.util.Arrays;
+import java.util.List;
import java.util.Map;
+@NoHttpd
public class ListProjectsIT extends AbstractDaemonTest {
@Inject
@@ -41,206 +47,174 @@
@Test
public void listProjects() throws Exception {
- Project.NameKey someProject = new Project.NameKey("some-project");
- createProject(sshSession, someProject.get());
+ Project.NameKey someProject = createProject("some-project");
+ assertThatNameList(filter(gApi.projects().list().get()))
+ .containsExactly(allProjects, allUsers, project, someProject).inOrder();
+ }
- RestResponse r = GET("/projects/");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- Map<String, ProjectInfo> result = toProjectInfoMap(r);
- assertProjects(Arrays.asList(allUsers, someProject, project),
- result.values());
+ @Test
+ public void listProjectsFiltersInvisibleProjects() throws Exception {
+ setApiUser(user);
+ assertThatNameList(gApi.projects().list().get()).contains(project);
+
+ ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
+ Util.block(cfg, Permission.READ, REGISTERED_USERS, "refs/*");
+ saveProjectConfig(project, cfg);
+
+ assertThatNameList(filter(gApi.projects().list().get()))
+ .doesNotContain(project);
}
@Test
public void listProjectsWithBranch() throws Exception {
- RestResponse r = GET("/projects/?b=master");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- Map<String, ProjectInfo> result = toProjectInfoMap(r);
- assertThat(result.get(project.get())).isNotNull();
- assertThat(result.get(project.get()).branches).isNotNull();
- assertThat(result.get(project.get()).branches).hasSize(1);
- assertThat(result.get(project.get()).branches.get("master")).isNotNull();
+ Map<String, ProjectInfo> result = gApi.projects().list()
+ .addShowBranch("master").getAsMap();
+ assertThat(result).containsKey(project.get());
+ ProjectInfo info = result.get(project.get());
+ assertThat(info.branches).isNotNull();
+ assertThat(info.branches).hasSize(1);
+ assertThat(info.branches.get("master")).isNotNull();
}
@Test
+ @TestProjectInput(description = "Description of some-project")
public void listProjectWithDescription() throws Exception {
- ProjectInput projectInput = new ProjectInput();
- projectInput.name = "some-project";
- projectInput.description = "Description of some-project";
- gApi.projects().name(projectInput.name).create(projectInput);
-
// description not be included in the results by default.
- RestResponse r = GET("/projects/");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- Map<String, ProjectInfo> result = toProjectInfoMap(r);
- assertThat(result.get(projectInput.name)).isNotNull();
- assertThat(result.get(projectInput.name).description).isNull();
+ Map<String, ProjectInfo> result = gApi.projects().list().getAsMap();
+ assertThat(result).containsKey(project.get());
+ assertThat(result.get(project.get()).description).isNull();
- r = GET("/projects/?d");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- result = toProjectInfoMap(r);
- assertThat(result.get(projectInput.name)).isNotNull();
- assertThat(result.get(projectInput.name).description).isEqualTo(
- projectInput.description);
+ result = gApi.projects().list().withDescription(true).getAsMap();
+ assertThat(result).containsKey(project.get());
+ assertThat(result.get(project.get()).description).isEqualTo(
+ "Description of some-project");
}
@Test
public void listProjectsWithLimit() throws Exception {
for (int i = 0; i < 5; i++) {
- createProject(sshSession, new Project.NameKey("someProject" + i).get());
+ createProject("someProject" + i);
}
- RestResponse r = GET("/projects/");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- Map<String, ProjectInfo> result = toProjectInfoMap(r);
- assertThat(result).hasSize(7); // 5 plus 2 existing projects: p and
- // All-Users
-
- r = GET("/projects/?n=2");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- result = toProjectInfoMap(r);
- assertThat(result).hasSize(2);
+ String p = name("");
+ // 5, plus p which was automatically created.
+ int n = 6;
+ for (int i = 1; i <= n + 2; i++) {
+ assertThatNameList(gApi.projects().list().withPrefix(p)
+ .withLimit(i).get())
+ .hasSize(Math.min(i, n));
+ }
}
@Test
public void listProjectsWithPrefix() throws Exception {
- Project.NameKey someProject = new Project.NameKey("some-project");
- createProject(sshSession, someProject.get());
- Project.NameKey someOtherProject =
- new Project.NameKey("some-other-project");
- createProject(sshSession, someOtherProject.get());
- Project.NameKey projectAwesome = new Project.NameKey("project-awesome");
- createProject(sshSession, projectAwesome.get());
+ Project.NameKey someProject = createProject("some-project");
+ Project.NameKey someOtherProject = createProject("some-other-project");
+ createProject("project-awesome");
- assertThat(GET("/projects/?p=some&r=.*").getStatusCode()).isEqualTo(
- HttpStatus.SC_BAD_REQUEST);
- assertThat(GET("/projects/?p=some&m=some").getStatusCode()).isEqualTo(
- HttpStatus.SC_BAD_REQUEST);
-
- RestResponse r = GET("/projects/?p=some");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- Map<String, ProjectInfo> result = toProjectInfoMap(r);
- assertProjects(Arrays.asList(someProject, someOtherProject),
- result.values());
+ String p = name("some");
+ assertBadRequest(gApi.projects().list().withPrefix(p).withRegex(".*"));
+ assertBadRequest(gApi.projects().list().withPrefix(p).withSubstring(p));
+ assertThatNameList(filter(gApi.projects().list().withPrefix(p).get()))
+ .containsExactly(someOtherProject, someProject).inOrder();
}
@Test
public void listProjectsWithRegex() throws Exception {
- Project.NameKey someProject = new Project.NameKey("some-project");
- createProject(sshSession, someProject.get());
- Project.NameKey someOtherProject =
- new Project.NameKey("some-other-project");
- createProject(sshSession, someOtherProject.get());
- Project.NameKey projectAwesome = new Project.NameKey("project-awesome");
- createProject(sshSession, projectAwesome.get());
+ Project.NameKey someProject = createProject("some-project");
+ Project.NameKey someOtherProject = createProject("some-other-project");
+ Project.NameKey projectAwesome = createProject("project-awesome");
- assertThat(GET("/projects/?r=[.*some").getStatusCode()).isEqualTo(
- HttpStatus.SC_BAD_REQUEST);
- assertThat(GET("/projects/?r=.*&p=s").getStatusCode()).isEqualTo(
- HttpStatus.SC_BAD_REQUEST);
- assertThat(GET("/projects/?r=.*&m=s").getStatusCode()).isEqualTo(
- HttpStatus.SC_BAD_REQUEST);
+ assertBadRequest(gApi.projects().list().withRegex("[.*"));
+ assertBadRequest(gApi.projects().list().withRegex(".*").withPrefix("p"));
+ assertBadRequest(gApi.projects().list().withRegex(".*").withSubstring("p"));
- RestResponse r = GET("/projects/?r=.*some");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- Map<String, ProjectInfo> result = toProjectInfoMap(r);
- assertProjects(Arrays.asList(projectAwesome), result.values());
-
- r = GET("/projects/?r=some-project$");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- result = toProjectInfoMap(r);
- assertProjects(Arrays.asList(someProject), result.values());
-
- r = GET("/projects/?r=.*");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- result = toProjectInfoMap(r);
- assertProjects(Arrays.asList(someProject, someOtherProject, projectAwesome,
- project, allUsers), result.values());
+ assertThatNameList(filter(gApi.projects().list().withRegex(".*some").get()))
+ .containsExactly(projectAwesome);
+ String r = name("some-project$").replace(".", "\\.");
+ assertThatNameList(filter(gApi.projects().list().withRegex(r).get()))
+ .containsExactly(someProject);
+ assertThatNameList(filter(gApi.projects().list().withRegex(".*").get()))
+ .containsExactly(allProjects, allUsers, project, projectAwesome,
+ someOtherProject, someProject)
+ .inOrder();
}
@Test
- public void listProjectsWithSkip() throws Exception {
+ public void listProjectsWithStart() throws Exception {
for (int i = 0; i < 5; i++) {
- createProject(sshSession, new Project.NameKey("someProject" + i).get());
+ createProject(new Project.NameKey("someProject" + i).get());
}
- RestResponse r = GET("/projects/");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- Map<String, ProjectInfo> result = toProjectInfoMap(r);
- assertThat(result).hasSize(7); // 5 plus 2 existing projects: p and
- // All-Users
-
- r = GET("/projects/?S=6");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- result = toProjectInfoMap(r);
- assertThat(result).hasSize(1);
+ String p = name("");
+ List<ProjectInfo> all = gApi.projects().list().withPrefix(p).get();
+ // 5, plus p which was automatically created.
+ int n = 6;
+ assertThat(all).hasSize(n);
+ assertThatNameList(gApi.projects().list().withPrefix(p)
+ .withStart(n - 1).get())
+ .containsExactly(new Project.NameKey(Iterables.getLast(all).name));
}
@Test
public void listProjectsWithSubstring() throws Exception {
- Project.NameKey someProject = new Project.NameKey("some-project");
- createProject(sshSession, someProject.get());
- Project.NameKey someOtherProject =
- new Project.NameKey("some-other-project");
- createProject(sshSession, someOtherProject.get());
- Project.NameKey projectAwesome = new Project.NameKey("project-awesome");
- createProject(sshSession, projectAwesome.get());
+ Project.NameKey someProject = createProject("some-project");
+ Project.NameKey someOtherProject = createProject("some-other-project");
+ Project.NameKey projectAwesome = createProject("project-awesome");
- assertThat(GET("/projects/?m=some&r=.*").getStatusCode()).isEqualTo(
- HttpStatus.SC_BAD_REQUEST);
- assertThat(GET("/projects/?m=some&p=some").getStatusCode()).isEqualTo(
- HttpStatus.SC_BAD_REQUEST);
-
- RestResponse r = GET("/projects/?m=some");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- Map<String, ProjectInfo> result = toProjectInfoMap(r);
- assertProjects(
- Arrays.asList(someProject, someOtherProject, projectAwesome),
- result.values());
+ assertBadRequest(gApi.projects().list().withSubstring("some")
+ .withRegex(".*"));
+ assertBadRequest(gApi.projects().list().withSubstring("some")
+ .withPrefix("some"));
+ assertThatNameList(filter(gApi.projects().list().withSubstring("some")
+ .get()))
+ .containsExactly(projectAwesome, someOtherProject, someProject)
+ .inOrder();
}
@Test
public void listProjectsWithTree() throws Exception {
- Project.NameKey someParentProject =
- new Project.NameKey("some-parent-project");
- createProject(sshSession, someParentProject.get());
+ Project.NameKey someParentProject = createProject("some-parent-project");
Project.NameKey someChildProject =
- new Project.NameKey("some-child-project");
- createProject(sshSession, someChildProject.get(), someParentProject);
+ createProject("some-child-project", someParentProject);
- RestResponse r = GET("/projects/?tree");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- Map<String, ProjectInfo> result = toProjectInfoMap(r);
- assertThat(result.get(someChildProject.get())).isNotNull();
- assertThat(result.get(someChildProject.get()).parent).isEqualTo(
- someParentProject.get());
+ Map<String, ProjectInfo> result = gApi.projects().list().withTree(true)
+ .getAsMap();
+ assertThat(result).containsKey(someChildProject.get());
+ assertThat(result.get(someChildProject.get()).parent)
+ .isEqualTo(someParentProject.get());
}
@Test
public void listProjectWithType() throws Exception {
- RestResponse r = GET("/projects/?type=PERMISSIONS");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- Map<String, ProjectInfo> result = toProjectInfoMap(r);
+ Map<String, ProjectInfo> result = gApi.projects().list()
+ .withType(FilterType.PERMISSIONS).getAsMap();
assertThat(result).hasSize(1);
- assertThat(result.get(allProjects.get())).isNotNull();
+ assertThat(result).containsKey(allProjects.get());
- r = GET("/projects/?type=ALL");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- result = toProjectInfoMap(r);
- assertThat(result).hasSize(3);
- assertProjects(Arrays.asList(allProjects, allUsers, project),
- result.values());
+ assertThatNameList(filter(gApi.projects().list().withType(FilterType.ALL)
+ .get()))
+ .containsExactly(allProjects, allUsers, project).inOrder();
}
- private static Map<String, ProjectInfo> toProjectInfoMap(RestResponse r)
- throws IOException {
- Map<String, ProjectInfo> result =
- newGson().fromJson(r.getReader(),
- new TypeToken<Map<String, ProjectInfo>>() {}.getType());
- return result;
+ private static void assertBadRequest(ListRequest req) throws Exception {
+ try {
+ req.get();
+ } catch (BadRequestException expected) {
+ // Expected.
+ }
}
- private RestResponse GET(String endpoint) throws IOException {
- return adminSession.get(endpoint);
+ private Iterable<ProjectInfo> filter(Iterable<ProjectInfo> infos) {
+ final String prefix = name("");
+ return Iterables.filter(infos, new Predicate<ProjectInfo>() {
+ @Override
+ public boolean apply(ProjectInfo in) {
+ return in.name != null && (
+ in.name.equals(allProjects.get())
+ || in.name.equals(allUsers.get())
+ || in.name.startsWith(prefix));
+ }
+ });
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ProjectAssert.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ProjectAssert.java
index 95f46e8..db6df95 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ProjectAssert.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ProjectAssert.java
@@ -15,35 +15,43 @@
package com.google.gerrit.acceptance.rest.project;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
-import com.google.common.base.Predicate;
+import com.google.common.base.Function;
import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
+import com.google.common.truth.IterableSubject;
import com.google.gerrit.extensions.common.ProjectInfo;
import com.google.gerrit.extensions.restapi.Url;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.project.ProjectState;
-import java.util.Collection;
+import java.util.List;
import java.util.Set;
public class ProjectAssert {
-
- public static void assertProjects(Iterable<Project.NameKey> expected,
- Collection<ProjectInfo> actual) {
- for (final Project.NameKey p : expected) {
- ProjectInfo info = Iterables.find(actual, new Predicate<ProjectInfo>() {
- @Override
- public boolean apply(ProjectInfo info) {
- // 'name' is not set if returned in a map, use the id instead.
- return new Project.NameKey(info.name != null ? info.name : Url
- .decode(info.id)).equals(p);
- }}, null);
- assertThat(info).isNotNull();
- actual.remove(info);
+ public static IterableSubject<
+ ? extends IterableSubject<
+ ?, Project.NameKey, Iterable<Project.NameKey>>,
+ Project.NameKey,
+ Iterable<Project.NameKey>>
+ assertThatNameList(Iterable<ProjectInfo> actualIt) {
+ List<ProjectInfo> actual = ImmutableList.copyOf(actualIt);
+ for (ProjectInfo info : actual) {
+ assertWithMessage("missing project name").that(info.name).isNotNull();
+ assertWithMessage("project name does not match id")
+ .that(Url.decode(info.id))
+ .isEqualTo(info.name);
}
- assertThat((Iterable<?>)actual).isEmpty();
+ return assertThat(Iterables.transform(actual,
+ new Function<ProjectInfo, Project.NameKey>() {
+ @Override
+ public Project.NameKey apply(ProjectInfo in) {
+ return new Project.NameKey(in.name);
+ }
+ }));
}
public static void assertProjectInfo(Project project, ProjectInfo info) {
@@ -67,6 +75,6 @@
for (AccountGroup.UUID g : state.getOwners()) {
assertThat(expectedOwners.remove(g)).isTrue();
}
- assertThat((Iterable<?>)expectedOwners).isEmpty();
+ assertThat(expectedOwners).isEmpty();
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ProjectLevelConfigIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ProjectLevelConfigIT.java
index 7e2af65..649534b 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ProjectLevelConfigIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ProjectLevelConfigIT.java
@@ -15,16 +15,15 @@
package com.google.gerrit.acceptance.rest.project;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.GitUtil.checkout;
-import static com.google.gerrit.acceptance.GitUtil.cloneProject;
import static com.google.gerrit.acceptance.GitUtil.fetch;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.PushOneCommit;
+import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.server.project.ProjectState;
-import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Config;
import org.junit.Before;
import org.junit.Test;
@@ -32,8 +31,8 @@
public class ProjectLevelConfigIT extends AbstractDaemonTest {
@Before
public void setUp() throws Exception {
- fetch(git, RefNames.REFS_CONFIG + ":refs/heads/config");
- checkout(git, "refs/heads/config");
+ fetch(testRepo, RefNames.REFS_CONFIG + ":refs/heads/config");
+ testRepo.reset("refs/heads/config");
}
@Test
@@ -43,9 +42,9 @@
cfg.setString("s1", null, "k1", "v1");
cfg.setString("s2", "ss", "k2", "v2");
PushOneCommit push =
- pushFactory.create(db, admin.getIdent(), "Create Project Level Config",
+ pushFactory.create(db, admin.getIdent(), testRepo, "Create Project Level Config",
configName, cfg.toText());
- push.to(git, RefNames.REFS_CONFIG);
+ push.to(RefNames.REFS_CONFIG);
ProjectState state = projectCache.get(project);
assertThat(state.getConfig(configName).get().toText()).isEqualTo(
@@ -68,23 +67,28 @@
parentCfg.setString("s2", "ss", "k3", "parentValue3");
parentCfg.setString("s2", "ss", "k4", "parentValue4");
- Git parentGit =
- cloneProject(sshSession.getUrl() + "/" + allProjects.get(), false);
- fetch(parentGit, RefNames.REFS_CONFIG + ":refs/heads/config");
- checkout(parentGit, "refs/heads/config");
- PushOneCommit push =
- pushFactory.create(db, admin.getIdent(), "Create Project Level Config",
- configName, parentCfg.toText());
- push.to(parentGit, RefNames.REFS_CONFIG);
+ pushFactory.create(
+ db, admin.getIdent(), testRepo, "Create Project Level Config",
+ configName, parentCfg.toText())
+ .to(RefNames.REFS_CONFIG)
+ .assertOkStatus();
+
+ Project.NameKey childProject = createProject("child", project);
+ TestRepository<?> childTestRepo = cloneProject(childProject);
+ fetch(childTestRepo, RefNames.REFS_CONFIG + ":refs/heads/config");
+ childTestRepo.reset("refs/heads/config");
Config cfg = new Config();
cfg.setString("s1", null, "k1", "childValue1");
cfg.setString("s2", "ss", "k3", "childValue2");
- push = pushFactory.create(db, admin.getIdent(), "Create Project Level Config",
- configName, cfg.toText());
- push.to(git, RefNames.REFS_CONFIG);
- ProjectState state = projectCache.get(project);
+ pushFactory.create(
+ db, admin.getIdent(), childTestRepo, "Create Project Level Config",
+ configName, cfg.toText())
+ .to(RefNames.REFS_CONFIG)
+ .assertOkStatus();
+
+ ProjectState state = projectCache.get(childProject);
Config expectedCfg = new Config();
expectedCfg.setString("s1", null, "k1", "childValue1");
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/SetParentIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/SetParentIT.java
index ac90ac0..67d4d1f 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/SetParentIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/SetParentIT.java
@@ -15,7 +15,6 @@
package com.google.gerrit.acceptance.rest.project;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.GitUtil.createProject;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
@@ -28,8 +27,7 @@
public class SetParentIT extends AbstractDaemonTest {
@Test
public void setParent_Forbidden() throws Exception {
- String parent = "parent";
- createProject(sshSession, parent, null, true);
+ String parent = createProject("parent", null, true).get();
RestResponse r =
userSession.put("/projects/" + project.get() + "/parent",
newParentInput(parent));
@@ -39,8 +37,7 @@
@Test
public void setParent() throws Exception {
- String parent = "parent";
- createProject(sshSession, parent, null, true);
+ String parent = createProject("parent", null, true).get();
RestResponse r =
adminSession.put("/projects/" + project.get() + "/parent",
newParentInput(parent));
@@ -72,15 +69,13 @@
assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_CONFLICT);
r.consume();
- String child = "child";
- createProject(sshSession, child, project, true);
+ Project.NameKey child = createProject("child", project, true);
r = adminSession.put("/projects/" + project.get() + "/parent",
- newParentInput(child));
+ newParentInput(child.get()));
assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_CONFLICT);
r.consume();
- String grandchild = "grandchild";
- createProject(sshSession, grandchild, new Project.NameKey(child), true);
+ String grandchild = createProject("grandchild", child, true).get();
r = adminSession.put("/projects/" + project.get() + "/parent",
newParentInput(grandchild));
assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_CONFLICT);
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/TagsIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/TagsIT.java
index c6cf647..7efefa7 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/TagsIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/TagsIT.java
@@ -50,16 +50,16 @@
grant(Permission.PUSH, project, "refs/tags/*");
PushOneCommit.Tag tag1 = new PushOneCommit.Tag("v1.0");
- PushOneCommit push1 = pushFactory.create(db, admin.getIdent());
+ PushOneCommit push1 = pushFactory.create(db, admin.getIdent(), testRepo);
push1.setTag(tag1);
- PushOneCommit.Result r1 = push1.to(git, "refs/for/master%submit");
+ PushOneCommit.Result r1 = push1.to("refs/for/master%submit");
r1.assertOkStatus();
PushOneCommit.AnnotatedTag tag2 =
new PushOneCommit.AnnotatedTag("v2.0", "annotation", admin.getIdent());
- PushOneCommit push2 = pushFactory.create(db, admin.getIdent());
+ PushOneCommit push2 = pushFactory.create(db, admin.getIdent(), testRepo);
push2.setTag(tag2);
- PushOneCommit.Result r2 = push2.to(git, "refs/for/master%submit");
+ PushOneCommit.Result r2 = push2.to("refs/for/master%submit");
r2.assertOkStatus();
List<TagInfo> result =
@@ -86,16 +86,16 @@
grant(Permission.PUSH, project, "refs/tags/*");
PushOneCommit.Tag tag1 = new PushOneCommit.Tag("v1.0");
- PushOneCommit push1 = pushFactory.create(db, admin.getIdent());
+ PushOneCommit push1 = pushFactory.create(db, admin.getIdent(), testRepo);
push1.setTag(tag1);
- PushOneCommit.Result r1 = push1.to(git, "refs/for/master%submit");
+ PushOneCommit.Result r1 = push1.to("refs/for/master%submit");
r1.assertOkStatus();
pushTo("refs/heads/hidden");
PushOneCommit.Tag tag2 = new PushOneCommit.Tag("v2.0");
- PushOneCommit push2 = pushFactory.create(db, admin.getIdent());
+ PushOneCommit push2 = pushFactory.create(db, admin.getIdent(), testRepo);
push2.setTag(tag2);
- PushOneCommit.Result r2 = push2.to(git, "refs/for/hidden%submit");
+ PushOneCommit.Result r2 = push2.to("refs/for/hidden%submit");
r2.assertOkStatus();
List<TagInfo> result =
@@ -121,9 +121,9 @@
grant(Permission.PUSH, project, "refs/tags/*");
PushOneCommit.Tag tag1 = new PushOneCommit.Tag("v1.0");
- PushOneCommit push1 = pushFactory.create(db, admin.getIdent());
+ PushOneCommit push1 = pushFactory.create(db, admin.getIdent(), testRepo);
push1.setTag(tag1);
- PushOneCommit.Result r1 = push1.to(git, "refs/for/master%submit");
+ PushOneCommit.Result r1 = push1.to("refs/for/master%submit");
r1.assertOkStatus();
RestResponse response =
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/CommentsIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/CommentsIT.java
index 541d1b8..721c712 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/CommentsIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/CommentsIT.java
@@ -15,13 +15,20 @@
package com.google.gerrit.acceptance.server.change;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.acceptance.PushOneCommit.FILE_NAME;
+import static com.google.gerrit.acceptance.PushOneCommit.SUBJECT;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.acceptance.PushOneCommit;
-import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.extensions.api.changes.DraftInput;
import com.google.gerrit.extensions.api.changes.ReviewInput;
+import com.google.gerrit.extensions.api.changes.ReviewInput.CommentInput;
+import com.google.gerrit.extensions.api.changes.ReviewInput.DraftHandling;
import com.google.gerrit.extensions.client.Comment;
import com.google.gerrit.extensions.client.Side;
import com.google.gerrit.extensions.common.CommentInfo;
@@ -34,21 +41,21 @@
import com.google.gerrit.server.change.Revisions;
import com.google.gerrit.server.notedb.NotesMigration;
import com.google.gerrit.testutil.ConfigSuite;
-import com.google.gson.reflect.TypeToken;
+import com.google.gerrit.testutil.FakeEmailSender;
+import com.google.gerrit.testutil.FakeEmailSender.Message;
import com.google.inject.Inject;
import com.google.inject.Provider;
-import org.apache.http.HttpStatus;
import org.eclipse.jgit.lib.Config;
+import org.junit.Before;
import org.junit.Test;
-import java.io.IOException;
-import java.lang.reflect.Type;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+@NoHttpd
public class CommentsIT extends AbstractDaemonTest {
@ConfigSuite.Config
public static Config noteDbEnabled() {
@@ -64,7 +71,15 @@
@Inject
private Provider<PostReview> postReview;
- private final Integer lines[] = {0, 1};
+ @Inject
+ private FakeEmailSender email;
+
+ private final Integer[] lines = {0, 1};
+
+ @Before
+ public void setUp() {
+ setApiUser(user);
+ }
@Test
public void createDraft() throws Exception {
@@ -72,8 +87,7 @@
PushOneCommit.Result r = createChange();
String changeId = r.getChangeId();
String revId = r.getCommit().getName();
- ReviewInput.CommentInput comment = newCommentInfo(
- "file1", Side.REVISION, line, "comment 1");
+ DraftInput comment = newDraft("file1", Side.REVISION, line, "comment 1");
addDraft(changeId, revId, comment);
Map<String, List<CommentInfo>> result = getDraftComments(changeId, revId);
assertThat(result).hasSize(1);
@@ -87,14 +101,13 @@
for (Integer line : lines) {
String file = "file";
String contents = "contents " + line;
- PushOneCommit push = pushFactory.create(db, admin.getIdent(),
+ PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo,
"first subject", file, contents);
- PushOneCommit.Result r = push.to(git, "refs/for/master");
+ PushOneCommit.Result r = push.to("refs/for/master");
String changeId = r.getChangeId();
String revId = r.getCommit().getName();
ReviewInput input = new ReviewInput();
- ReviewInput.CommentInput comment = newCommentInfo(
- file, Side.REVISION, line, "comment 1");
+ CommentInput comment = newComment(file, Side.REVISION, line, "comment 1");
input.comments = new HashMap<>();
input.comments.put(comment.path, Lists.newArrayList(comment));
revision(r).review(input);
@@ -111,8 +124,7 @@
PushOneCommit.Result r = createChange();
String changeId = r.getChangeId();
String revId = r.getCommit().getName();
- ReviewInput.CommentInput comment = newCommentInfo(
- "file1", Side.REVISION, line, "comment 1");
+ DraftInput comment = newDraft("file1", Side.REVISION, line, "comment 1");
addDraft(changeId, revId, comment);
Map<String, List<CommentInfo>> result = getDraftComments(changeId, revId);
CommentInfo actual = Iterables.getOnlyElement(result.get(comment.path));
@@ -132,7 +144,7 @@
PushOneCommit.Result r = createChange();
String changeId = r.getChangeId();
String revId = r.getCommit().getName();
- ReviewInput.CommentInput comment = newCommentInfo(
+ DraftInput comment = newDraft(
"file1", Side.REVISION, line, "comment 1");
CommentInfo returned = addDraft(changeId, revId, comment);
CommentInfo actual = getDraftComment(changeId, revId, returned.id);
@@ -146,9 +158,8 @@
PushOneCommit.Result r = createChange();
String changeId = r.getChangeId();
String revId = r.getCommit().getName();
- ReviewInput.CommentInput comment = newCommentInfo(
- "file1", Side.REVISION, line, "comment 1");
- CommentInfo returned = addDraft(changeId, revId, comment);
+ DraftInput draft = newDraft("file1", Side.REVISION, line, "comment 1");
+ CommentInfo returned = addDraft(changeId, revId, draft);
deleteDraft(changeId, revId, returned.id);
Map<String, List<CommentInfo>> drafts = getDraftComments(changeId, revId);
assertThat(drafts).isEmpty();
@@ -161,14 +172,13 @@
for (Integer line : lines) {
String file = "file";
String contents = "contents " + line;
- PushOneCommit push = pushFactory.create(db, admin.getIdent(),
+ PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo,
"first subject", file, contents);
- PushOneCommit.Result r = push.to(git, "refs/for/master");
+ PushOneCommit.Result r = push.to("refs/for/master");
String changeId = r.getChangeId();
String revId = r.getCommit().getName();
ReviewInput input = new ReviewInput();
- ReviewInput.CommentInput comment = newCommentInfo(
- file, Side.REVISION, line, "comment 1");
+ CommentInput comment = newComment(file, Side.REVISION, line, "comment 1");
comment.updated = timestamp;
input.comments = new HashMap<>();
input.comments.put(comment.path, Lists.newArrayList(comment));
@@ -186,56 +196,228 @@
}
}
- private CommentInfo addDraft(String changeId, String revId,
- ReviewInput.CommentInput c) throws IOException {
- RestResponse r = userSession.put(
- "/changes/" + changeId + "/revisions/" + revId + "/drafts", c);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_CREATED);
- return newGson().fromJson(r.getReader(), CommentInfo.class);
+ @Test
+ public void listChangeDrafts() throws Exception {
+ PushOneCommit.Result r1 = createChange();
+
+ PushOneCommit.Result r2 = pushFactory.create(
+ db, admin.getIdent(), testRepo, SUBJECT, FILE_NAME, "new cntent",
+ r1.getChangeId())
+ .to("refs/for/master");
+
+
+ setApiUser(admin);
+ addDraft(r1.getChangeId(), r1.getCommit().getName(),
+ newDraft(FILE_NAME, Side.REVISION, 1, "nit: trailing whitespace"));
+ addDraft(r2.getChangeId(), r2.getCommit().getName(),
+ newDraft(FILE_NAME, Side.REVISION, 1, "typo: content"));
+
+ setApiUser(user);
+ addDraft(r2.getChangeId(), r2.getCommit().getName(),
+ newDraft(FILE_NAME, Side.REVISION, 1, "+1, please fix"));
+
+ setApiUser(admin);
+ Map<String, List<CommentInfo>> actual =
+ gApi.changes().id(r1.getChangeId()).drafts();
+ assertThat((Iterable<?>) actual.keySet()).containsExactly(FILE_NAME);
+ List<CommentInfo> comments = actual.get(FILE_NAME);
+ assertThat(comments).hasSize(2);
+
+ CommentInfo c1 = comments.get(0);
+ assertThat(c1.author).isNull();
+ assertThat(c1.patchSet).isEqualTo(1);
+ assertThat(c1.message).isEqualTo("nit: trailing whitespace");
+ assertThat(c1.side).isNull();
+ assertThat(c1.line).isEqualTo(1);
+
+ CommentInfo c2 = comments.get(1);
+ assertThat(c2.author).isNull();
+ assertThat(c2.patchSet).isEqualTo(2);
+ assertThat(c2.message).isEqualTo("typo: content");
+ assertThat(c2.side).isNull();
+ assertThat(c2.line).isEqualTo(1);
}
- private void updateDraft(String changeId, String revId,
- ReviewInput.CommentInput c, String uuid) throws IOException {
- RestResponse r = userSession.put(
- "/changes/" + changeId + "/revisions/" + revId + "/drafts/" + uuid, c);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
+ @Test
+ public void listChangeComments() throws Exception {
+ PushOneCommit.Result r1 = createChange();
+
+ PushOneCommit.Result r2 = pushFactory.create(
+ db, admin.getIdent(), testRepo, SUBJECT, FILE_NAME, "new cntent",
+ r1.getChangeId())
+ .to("refs/for/master");
+
+ addComment(r1, "nit: trailing whitespace");
+ addComment(r2, "typo: content");
+
+ Map<String, List<CommentInfo>> actual = gApi.changes()
+ .id(r2.getChangeId())
+ .comments();
+ assertThat(actual.keySet()).containsExactly(FILE_NAME);
+
+ List<CommentInfo> comments = actual.get(FILE_NAME);
+ assertThat(comments).hasSize(2);
+
+ CommentInfo c1 = comments.get(0);
+ assertThat(c1.author._accountId).isEqualTo(user.getId().get());
+ assertThat(c1.patchSet).isEqualTo(1);
+ assertThat(c1.message).isEqualTo("nit: trailing whitespace");
+ assertThat(c1.side).isNull();
+ assertThat(c1.line).isEqualTo(1);
+
+ CommentInfo c2 = comments.get(1);
+ assertThat(c2.author._accountId).isEqualTo(user.getId().get());
+ assertThat(c2.patchSet).isEqualTo(2);
+ assertThat(c2.message).isEqualTo("typo: content");
+ assertThat(c2.side).isNull();
+ assertThat(c2.line).isEqualTo(1);
+ }
+
+ @Test
+ public void publishCommentsAllRevisions() throws Exception {
+ PushOneCommit.Result r1 = createChange();
+
+ PushOneCommit.Result r2 = pushFactory.create(
+ db, admin.getIdent(), testRepo, SUBJECT, FILE_NAME, "new\ncntent\n",
+ r1.getChangeId())
+ .to("refs/for/master");
+
+ addDraft(r1.getChangeId(), r1.getCommit().getName(),
+ newDraft(FILE_NAME, Side.REVISION, 1, "nit: trailing whitespace"));
+ addDraft(r2.getChangeId(), r2.getCommit().getName(),
+ newDraft(FILE_NAME, Side.REVISION, 1, "join lines"));
+ addDraft(r2.getChangeId(), r2.getCommit().getName(),
+ newDraft(FILE_NAME, Side.REVISION, 2, "typo: content"));
+
+ PushOneCommit.Result other = createChange();
+ // Drafts on other changes aren't returned.
+ addDraft(other.getChangeId(), other.getCommit().getName(),
+ newDraft(FILE_NAME, Side.REVISION, 1, "unrelated comment"));
+
+ setApiUser(admin);
+ // Drafts by other users aren't returned.
+ addDraft(r2.getChangeId(), r2.getCommit().getName(),
+ newDraft(FILE_NAME, Side.REVISION, 2, "oops"));
+ setApiUser(user);
+
+ ReviewInput reviewInput = new ReviewInput();
+ reviewInput.drafts = DraftHandling.PUBLISH_ALL_REVISIONS;
+ reviewInput.message = "comments";
+ gApi.changes()
+ .id(r2.getChangeId())
+ .current()
+ .review(reviewInput);
+
+ assertThat(gApi.changes()
+ .id(r1.getChangeId())
+ .revision(r1.getCommit().name())
+ .drafts())
+ .isEmpty();
+ Map<String, List<CommentInfo>> ps1Map = gApi.changes()
+ .id(r1.getChangeId())
+ .revision(r1.getCommit().name())
+ .comments();
+ assertThat(ps1Map.keySet()).containsExactly(FILE_NAME);
+ List<CommentInfo> ps1List = ps1Map.get(FILE_NAME);
+ assertThat(ps1List).hasSize(1);
+ assertThat(ps1List.get(0).message).isEqualTo("nit: trailing whitespace");
+
+ assertThat(gApi.changes()
+ .id(r2.getChangeId())
+ .revision(r2.getCommit().name())
+ .drafts())
+ .isEmpty();
+ Map<String, List<CommentInfo>> ps2Map = gApi.changes()
+ .id(r2.getChangeId())
+ .revision(r2.getCommit().name())
+ .comments();
+ assertThat(ps2Map.keySet()).containsExactly(FILE_NAME);
+ List<CommentInfo> ps2List = ps2Map.get(FILE_NAME);
+ assertThat(ps2List).hasSize(2);
+ assertThat(ps2List.get(0).message).isEqualTo("join lines");
+ assertThat(ps2List.get(1).message).isEqualTo("typo: content");
+
+ ImmutableList<Message> messages =
+ email.getMessages(r2.getChangeId(), "comment");
+ assertThat(messages).hasSize(1);
+ String url = canonicalWebUrl.get();
+ int c = r1.getChange().getId().get();
+ assertThat(messages.get(0).body()).contains(
+ "\n"
+ + "Patch Set 2:\n"
+ + "\n"
+ + "(3 comments)\n"
+ + "\n"
+ + "comments\n"
+ + "\n"
+ + url + "#/c/" + c + "/1/a.txt\n"
+ + "File a.txt:\n"
+ + "\n"
+ + "PS1, Line 1: ew\n"
+ + "nit: trailing whitespace\n"
+ + "\n"
+ + "\n"
+ + url + "#/c/" + c + "/2/a.txt\n"
+ + "File a.txt:\n"
+ + "\n"
+ + "PS2, Line 1: ew\n"
+ + "join lines\n"
+ + "\n"
+ + "\n"
+ + "PS2, Line 2: nten\n"
+ + "typo: content\n"
+ + "\n"
+ + "\n"
+ + "-- \n");
+ }
+
+
+ private void addComment(PushOneCommit.Result r, String message)
+ throws Exception {
+ CommentInput c = new CommentInput();
+ c.line = 1;
+ c.message = message;
+ c.path = FILE_NAME;
+ ReviewInput in = new ReviewInput();
+ in.comments = ImmutableMap.<String, List<CommentInput>> of(
+ FILE_NAME, ImmutableList.of(c));
+ gApi.changes()
+ .id(r.getChangeId())
+ .revision(r.getCommit().name())
+ .review(in);
+ }
+
+ private CommentInfo addDraft(String changeId, String revId, DraftInput in)
+ throws Exception {
+ return gApi.changes().id(changeId).revision(revId).createDraft(in).get();
+ }
+
+ private void updateDraft(String changeId, String revId, DraftInput in,
+ String uuid) throws Exception {
+ gApi.changes().id(changeId).revision(revId).draft(uuid).update(in);
}
private void deleteDraft(String changeId, String revId, String uuid)
- throws IOException {
- RestResponse r = userSession.delete(
- "/changes/" + changeId + "/revisions/" + revId + "/drafts/" + uuid);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_NO_CONTENT);
+ throws Exception {
+ gApi.changes().id(changeId).revision(revId).draft(uuid).delete();
}
private Map<String, List<CommentInfo>> getPublishedComments(String changeId,
- String revId) throws IOException {
- RestResponse r = userSession.get(
- "/changes/" + changeId + "/revisions/" + revId + "/comments/");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- Type mapType = new TypeToken<Map<String, List<CommentInfo>>>() {}.getType();
- return newGson().fromJson(r.getReader(), mapType);
+ String revId) throws Exception {
+ return gApi.changes().id(changeId).revision(revId).comments();
}
private Map<String, List<CommentInfo>> getDraftComments(String changeId,
- String revId) throws IOException {
- RestResponse r = userSession.get(
- "/changes/" + changeId + "/revisions/" + revId + "/drafts/");
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- Type mapType = new TypeToken<Map<String, List<CommentInfo>>>() {}.getType();
- return newGson().fromJson(r.getReader(), mapType);
+ String revId) throws Exception {
+ return gApi.changes().id(changeId).revision(revId).drafts();
}
private CommentInfo getDraftComment(String changeId, String revId,
- String uuid) throws IOException {
- RestResponse r = userSession.get(
- "/changes/" + changeId + "/revisions/" + revId + "/drafts/" + uuid);
- assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
- return newGson().fromJson(r.getReader(), CommentInfo.class);
+ String uuid) throws Exception {
+ return gApi.changes().id(changeId).revision(revId).draft(uuid).get();
}
- private static void assertCommentInfo(ReviewInput.CommentInput expected,
- CommentInfo actual) {
+ private static void assertCommentInfo(Comment expected, CommentInfo actual) {
assertThat(actual.line).isEqualTo(expected.line);
assertThat(actual.message).isEqualTo(expected.message);
assertThat(actual.inReplyTo).isEqualTo(expected.inReplyTo);
@@ -258,21 +440,32 @@
}
}
- private ReviewInput.CommentInput newCommentInfo(String path,
- Side side, int line, String message) {
- ReviewInput.CommentInput input = new ReviewInput.CommentInput();
- input.path = path;
- input.side = side;
- input.line = line != 0 ? line : null;
- input.message = message;
+ private static CommentInput newComment(String path, Side side, int line,
+ String message) {
+ CommentInput c = new CommentInput();
+ return populate(c, path, side, line, message);
+ }
+
+ private DraftInput newDraft(String path, Side side, int line,
+ String message) {
+ DraftInput d = new DraftInput();
+ return populate(d, path, side, line, message);
+ }
+
+ private static <C extends Comment> C populate(C c, String path, Side side,
+ int line, String message) {
+ c.path = path;
+ c.side = side;
+ c.line = line != 0 ? line : null;
+ c.message = message;
if (line != 0) {
Comment.Range range = new Comment.Range();
- range.startLine = 1;
+ range.startLine = line;
range.startCharacter = 1;
- range.endLine = 1;
+ range.endLine = line;
range.endCharacter = 5;
- input.range = range;
+ c.range = range;
}
- return input;
+ return c;
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/GetRelatedIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/GetRelatedIT.java
index 6cd39ab..0dcba72 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/GetRelatedIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/GetRelatedIT.java
@@ -15,16 +15,15 @@
package com.google.gerrit.acceptance.server.change;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.GitUtil.add;
-import static com.google.gerrit.acceptance.GitUtil.createCommit;
import static com.google.gerrit.acceptance.GitUtil.pushHead;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.GitUtil.Commit;
+import com.google.gerrit.acceptance.GitUtil;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.RestSession;
+import com.google.gerrit.extensions.common.CommitInfo;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.server.change.GetRelated.ChangeAndCommit;
@@ -32,16 +31,33 @@
import com.google.gerrit.server.edit.ChangeEditModifier;
import com.google.gerrit.server.edit.ChangeEditUtil;
import com.google.gerrit.server.query.change.ChangeData;
+import com.google.gerrit.testutil.ConfigSuite;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
-import org.eclipse.jgit.api.ResetCommand.ResetType;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Test;
import java.io.IOException;
import java.util.List;
public class GetRelatedIT extends AbstractDaemonTest {
+ @ConfigSuite.Default
+ public static Config byGroup() {
+ Config cfg = new Config();
+ cfg.setBoolean("change", null, "getRelatedByAncestors", false);
+ return cfg;
+ }
+
+ @ConfigSuite.Config
+ public static Config byAncestors() {
+ Config cfg = new Config();
+ cfg.setBoolean("change", null, "getRelatedByAncestors", true);
+ return cfg;
+ }
+
@Inject
private ChangeEditUtil editUtil;
@@ -50,140 +66,158 @@
@Test
public void getRelatedNoResult() throws Exception {
- PushOneCommit push = pushFactory.create(db, admin.getIdent());
- PatchSet.Id ps = push.to(git, "refs/for/master").getPatchSetId();
- List<ChangeAndCommit> related = getRelated(ps);
- assertThat(related).isEmpty();
+ PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo);
+ assertRelated(push.to("refs/for/master").getPatchSetId());
}
@Test
public void getRelatedLinear() throws Exception {
- add(git, "a.txt", "1");
- Commit c1 = createCommit(git, admin.getIdent(), "subject: 1");
- add(git, "b.txt", "2");
- Commit c2 = createCommit(git, admin.getIdent(), "subject: 2");
- pushHead(git, "refs/for/master", false);
+ RevCommit c1_1 = commitBuilder()
+ .add("a.txt", "1")
+ .message("subject: 1")
+ .create();
+ String id1 = getChangeId(c1_1);
+ RevCommit c2_2 = commitBuilder()
+ .add("b.txt", "2")
+ .message("subject: 2")
+ .create();
+ String id2 = getChangeId(c2_2);
+ pushHead(testRepo, "refs/for/master", false);
- for (Commit c : ImmutableList.of(c2, c1)) {
- List<ChangeAndCommit> related = getRelated(getPatchSetId(c));
- assertThat(related).hasSize(2);
- assertThat(related.get(0).changeId)
- .named("related to " + c.getChangeId()).isEqualTo(c2.getChangeId());
- assertThat(related.get(1).changeId)
- .named("related to " + c.getChangeId()).isEqualTo(c1.getChangeId());
+ for (RevCommit c : ImmutableList.of(c2_2, c1_1)) {
+ assertRelated(getPatchSetId(c),
+ changeAndCommit(id2, c2_2, 1, 1),
+ changeAndCommit(id1, c1_1, 1, 1));
}
}
@Test
public void getRelatedReorder() throws Exception {
// Create two commits and push.
- add(git, "a.txt", "1");
- Commit c1 = createCommit(git, admin.getIdent(), "subject: 1");
- add(git, "b.txt", "2");
- Commit c2 = createCommit(git, admin.getIdent(), "subject: 2");
- pushHead(git, "refs/for/master", false);
- PatchSet.Id c1ps1 = getPatchSetId(c1);
- PatchSet.Id c2ps1 = getPatchSetId(c2);
+ RevCommit c1_1 = commitBuilder()
+ .add("a.txt", "1")
+ .message("subject: 1")
+ .create();
+ String id1 = getChangeId(c1_1);
+ RevCommit c2_1 = commitBuilder()
+ .add("b.txt", "2")
+ .message("subject: 2")
+ .create();
+ String id2 = getChangeId(c2_1);
+ pushHead(testRepo, "refs/for/master", false);
+ PatchSet.Id ps1_1 = getPatchSetId(c1_1);
+ PatchSet.Id ps2_1 = getPatchSetId(c2_1);
// Swap the order of commits and push again.
- git.reset().setMode(ResetType.HARD).setRef("HEAD^^").call();
- git.cherryPick().include(c2.getCommit()).include(c1.getCommit()).call();
- pushHead(git, "refs/for/master", false);
- PatchSet.Id c1ps2 = getPatchSetId(c1);
- PatchSet.Id c2ps2 = getPatchSetId(c2);
+ testRepo.reset("HEAD~2");
+ RevCommit c2_2 = testRepo.cherryPick(c2_1);
+ RevCommit c1_2 = testRepo.cherryPick(c1_1);
+ pushHead(testRepo, "refs/for/master", false);
+ PatchSet.Id ps1_2 = getPatchSetId(c1_1);
+ PatchSet.Id ps2_2 = getPatchSetId(c2_1);
- for (PatchSet.Id ps : ImmutableList.of(c2ps2, c1ps2)) {
- List<ChangeAndCommit> related = getRelated(ps);
- assertThat(related).hasSize(2);
- assertThat(related.get(0).changeId).named("related to " + ps).isEqualTo(
- c1.getChangeId());
- assertThat(related.get(1).changeId).named("related to " + ps).isEqualTo(
- c2.getChangeId());
+ for (PatchSet.Id ps : ImmutableList.of(ps2_2, ps1_2)) {
+ assertRelated(ps,
+ changeAndCommit(id1, c1_2, 2, 2),
+ changeAndCommit(id2, c2_2, 2, 2));
}
- for (PatchSet.Id ps : ImmutableList.of(c2ps1, c1ps1)) {
- List<ChangeAndCommit> related = getRelated(ps);
- assertThat(related).hasSize(2);
- assertThat(related.get(0).changeId).named("related to " + ps).isEqualTo(
- c2.getChangeId());
- assertThat(related.get(1).changeId).named("related to " + ps).isEqualTo(
- c1.getChangeId());
+ for (PatchSet.Id ps : ImmutableList.of(ps2_1, ps1_1)) {
+ assertRelated(ps,
+ changeAndCommit(id2, c2_1, 1, 2),
+ changeAndCommit(id1, c1_1, 1, 2));
}
}
@Test
public void getRelatedReorderAndExtend() throws Exception {
// Create two commits and push.
- add(git, "a.txt", "1");
- Commit c1 = createCommit(git, admin.getIdent(), "subject: 1");
- add(git, "b.txt", "2");
- Commit c2 = createCommit(git, admin.getIdent(), "subject: 2");
- pushHead(git, "refs/for/master", false);
- PatchSet.Id c1ps1 = getPatchSetId(c1);
- PatchSet.Id c2ps1 = getPatchSetId(c2);
+ ObjectId initial = repo().getRef("HEAD").getObjectId();
+ RevCommit c1_1 = commitBuilder()
+ .add("a.txt", "1")
+ .message("subject: 1")
+ .create();
+ String id1 = getChangeId(c1_1);
+ RevCommit c2_1 = commitBuilder()
+ .add("b.txt", "2")
+ .message("subject: 2")
+ .create();
+ String id2 = getChangeId(c2_1);
+ pushHead(testRepo, "refs/for/master", false);
+ PatchSet.Id ps1_1 = getPatchSetId(c1_1);
+ PatchSet.Id ps2_1 = getPatchSetId(c2_1);
// Swap the order of commits, create a new commit on top, and push again.
- git.reset().setMode(ResetType.HARD).setRef("HEAD^^").call();
- git.cherryPick().include(c2.getCommit()).include(c1.getCommit()).call();
- add(git, "c.txt", "3");
- Commit c3 = createCommit(git, admin.getIdent(), "subject: 3");
- pushHead(git, "refs/for/master", false);
- PatchSet.Id c1ps2 = getPatchSetId(c1);
- PatchSet.Id c2ps2 = getPatchSetId(c2);
- PatchSet.Id c3ps1 = getPatchSetId(c3);
+ testRepo.reset(initial);
+ RevCommit c2_2 = testRepo.cherryPick(c2_1);
+ RevCommit c1_2 = testRepo.cherryPick(c1_1);
+ RevCommit c3_1 = commitBuilder()
+ .add("c.txt", "3")
+ .message("subject: 3")
+ .create();
+ String id3 = getChangeId(c3_1);
+ pushHead(testRepo, "refs/for/master", false);
+ PatchSet.Id ps1_2 = getPatchSetId(c1_1);
+ PatchSet.Id ps2_2 = getPatchSetId(c2_1);
+ PatchSet.Id ps3_1 = getPatchSetId(c3_1);
-
- for (PatchSet.Id ps : ImmutableList.of(c3ps1, c2ps2, c1ps2)) {
- List<ChangeAndCommit> related = getRelated(ps);
- assertThat(related).hasSize(3);
- assertThat(related.get(0).changeId).named("related to " + ps).isEqualTo(
- c3.getChangeId());
- assertThat(related.get(1).changeId).named("related to " + ps).isEqualTo(
- c1.getChangeId());
- assertThat(related.get(2).changeId).named("related to " + ps).isEqualTo(
- c2.getChangeId());
+ for (PatchSet.Id ps : ImmutableList.of(ps3_1, ps2_2, ps1_2)) {
+ assertRelated(ps,
+ changeAndCommit(id3, c3_1, 1, 1),
+ changeAndCommit(id1, c1_2, 2, 2),
+ changeAndCommit(id2, c2_2, 2, 2));
}
- for (PatchSet.Id ps : ImmutableList.of(c2ps1, c1ps1)) {
- List<ChangeAndCommit> related = getRelated(ps);
- assertThat(related).hasSize(3);
- assertThat(related.get(0).changeId).named("related to " + ps).isEqualTo(
- c3.getChangeId());
- assertThat(related.get(1).changeId).named("related to " + ps).isEqualTo(
- c2.getChangeId());
- assertThat(related.get(2).changeId).named("related to " + ps).isEqualTo(
- c1.getChangeId());
+ for (PatchSet.Id ps : ImmutableList.of(ps2_1, ps1_1)) {
+ assertRelated(ps,
+ changeAndCommit(id3, c3_1, 1, 1),
+ changeAndCommit(id2, c2_1, 1, 2),
+ changeAndCommit(id1, c1_1, 1, 2));
}
}
@Test
public void getRelatedEdit() throws Exception {
- add(git, "a.txt", "1");
- Commit c1 = createCommit(git, admin.getIdent(), "subject: 1");
- add(git, "b.txt", "2");
- Commit c2 = createCommit(git, admin.getIdent(), "subject: 2");
- add(git, "b.txt", "3");
- Commit c3 = createCommit(git, admin.getIdent(), "subject: 3");
- pushHead(git, "refs/for/master", false);
+ RevCommit c1_1 = commitBuilder()
+ .add("a.txt", "1")
+ .message("subject: 1")
+ .create();
+ String id1 = getChangeId(c1_1);
+ RevCommit c2_1 = commitBuilder()
+ .add("b.txt", "2")
+ .message("subject: 2")
+ .create();
+ String id2 = getChangeId(c2_1);
+ RevCommit c3_1 = commitBuilder()
+ .add("c.txt", "3")
+ .message("subject: 3")
+ .create();
+ String id3 = getChangeId(c3_1);
+ pushHead(testRepo, "refs/for/master", false);
- Change ch2 = getChange(c2).change();
+ Change ch2 = getChange(c2_1).change();
editModifier.createEdit(ch2, getPatchSet(ch2));
editModifier.modifyFile(editUtil.byChange(ch2).get(), "a.txt",
RestSession.newRawInput(new byte[] {'a'}));
- String editRev = editUtil.byChange(ch2).get().getRevision().get();
+ ObjectId editRev =
+ ObjectId.fromString(editUtil.byChange(ch2).get().getRevision().get());
- List<ChangeAndCommit> related = getRelated(ch2.getId(), 0);
- assertThat(related).hasSize(3);
- assertThat(related.get(0).changeId).named("related to " + c2.getChangeId())
- .isEqualTo(c3.getChangeId());
- assertThat(related.get(1).changeId).named("related to " + c2.getChangeId())
- .isEqualTo(c2.getChangeId());
- assertThat(related.get(1)._revisionNumber.intValue()).named(
- "has edit revision number").isEqualTo(0);
- assertThat(related.get(1).commit.commit).named(
- "has edit revision " + editRev).isEqualTo(editRev);
- assertThat(related.get(2).changeId).named("related to " + c2.getChangeId())
- .isEqualTo(c1.getChangeId());
+ PatchSet.Id ps1_1 = getPatchSetId(c1_1);
+ PatchSet.Id ps2_1 = getPatchSetId(c2_1);
+ PatchSet.Id ps2_edit = new PatchSet.Id(ch2.getId(), 0);
+ PatchSet.Id ps3_1 = getPatchSetId(c3_1);
+
+ for (PatchSet.Id ps : ImmutableList.of(ps1_1, ps2_1, ps3_1)) {
+ assertRelated(ps,
+ changeAndCommit(id3, c3_1, 1, 1),
+ changeAndCommit(id2, c2_1, 1, 1),
+ changeAndCommit(id1, c1_1, 1, 1));
+ }
+
+ assertRelated(ps2_edit,
+ changeAndCommit(id3, c3_1, 1, 1),
+ changeAndCommit(id2, editRev, 0, 1),
+ changeAndCommit(id1, c1_1, 1, 1));
}
private List<ChangeAndCommit> getRelated(PatchSet.Id ps) throws IOException {
@@ -198,7 +232,11 @@
RelatedInfo.class).changes;
}
- private PatchSet.Id getPatchSetId(Commit c) throws OrmException {
+ private String getChangeId(RevCommit c) throws Exception {
+ return GitUtil.getChangeId(testRepo, c).get();
+ }
+
+ private PatchSet.Id getPatchSetId(ObjectId c) throws OrmException {
return getChange(c).change().currentPatchSetId();
}
@@ -206,8 +244,38 @@
return db.patchSets().get(c.currentPatchSetId());
}
- private ChangeData getChange(Commit c) throws OrmException {
- return Iterables.getOnlyElement(
- queryProvider.get().byKeyPrefix(c.getChangeId()));
+ private ChangeData getChange(ObjectId c) throws OrmException {
+ return Iterables.getOnlyElement(queryProvider.get().byCommit(c));
+ }
+
+ private static ChangeAndCommit changeAndCommit(String changeId,
+ ObjectId commitId, int revisionNum, int currentRevisionNum) {
+ ChangeAndCommit result = new ChangeAndCommit();
+ result.changeId = changeId;
+ result.commit = new CommitInfo();
+ result.commit.commit = commitId.name();
+ result._revisionNumber = revisionNum;
+ result._currentRevisionNumber = currentRevisionNum;
+ return result;
+ }
+
+ private void assertRelated(PatchSet.Id psId, ChangeAndCommit... expected)
+ throws Exception {
+ List<ChangeAndCommit> actual = getRelated(psId);
+ assertThat(actual).hasSize(expected.length);
+ for (int i = 0; i < actual.size(); i++) {
+ String name = "index " + i + " related to " + psId;
+ ChangeAndCommit a = actual.get(i);
+ ChangeAndCommit e = expected[i];
+ assertThat(a.changeId).named("Change-Id of " + name)
+ .isEqualTo(e.changeId);
+ assertThat(a.commit.commit).named("commit of " + name)
+ .isEqualTo(e.commit.commit);
+ // Don't bother checking _changeNumber; assume changeId is sufficient.
+ assertThat(a._revisionNumber).named("revision of " + name)
+ .isEqualTo(e._revisionNumber);
+ assertThat(a._currentRevisionNumber).named("current revision of " + name)
+ .isEqualTo(e._currentRevisionNumber);
+ }
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/PatchListCacheIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/PatchListCacheIT.java
index d598b06..57b00bc 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/PatchListCacheIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/PatchListCacheIT.java
@@ -15,14 +15,10 @@
package com.google.gerrit.acceptance.server.change;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.GitUtil.add;
-import static com.google.gerrit.acceptance.GitUtil.amendCommit;
-import static com.google.gerrit.acceptance.GitUtil.createCommit;
+import static com.google.gerrit.acceptance.GitUtil.getChangeId;
import static com.google.gerrit.acceptance.GitUtil.pushHead;
-import static com.google.gerrit.acceptance.GitUtil.rm;
import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.GitUtil.Commit;
import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
@@ -34,8 +30,8 @@
import com.google.gerrit.server.patch.PatchListNotAvailableException;
import com.google.inject.Inject;
-import org.eclipse.jgit.api.ResetCommand.ResetType;
import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Test;
import java.util.List;
@@ -55,28 +51,35 @@
@Test
public void listPatchesAgainstBase() throws Exception {
- add(git, FILE_D, "4");
- createCommit(git, admin.getIdent(), SUBJECT_1);
- pushHead(git, "refs/heads/master", false);
+ commitBuilder()
+ .add(FILE_D, "4")
+ .message(SUBJECT_1)
+ .create();
+ pushHead(testRepo, "refs/heads/master", false);
// Change 1, 1 (+FILE_A, -FILE_D)
- add(git, FILE_A, "1");
- rm(git, FILE_D);
- Commit c = createCommit(git, admin.getIdent(), SUBJECT_2);
- pushHead(git, "refs/for/master", false);
+ RevCommit c = commitBuilder()
+ .add(FILE_A, "1")
+ .rm(FILE_D)
+ .message(SUBJECT_2)
+ .insertChangeId()
+ .create();
+ String id = getChangeId(testRepo, c).get();
+ pushHead(testRepo, "refs/for/master", false);
// Compare Change 1,1 with Base (+FILE_A, -FILE_D)
- List<PatchListEntry> entries = getCurrentPatches(c.getChangeId());
+ List<PatchListEntry> entries = getCurrentPatches(id);
assertThat(entries).hasSize(3);
assertAdded(Patch.COMMIT_MSG, entries.get(0));
assertAdded(FILE_A, entries.get(1));
assertDeleted(FILE_D, entries.get(2));
// Change 1,2 (+FILE_A, +FILE_B, -FILE_D)
- add(git, FILE_B, "2");
- c = amendCommit(git, admin.getIdent(), SUBJECT_2, c.getChangeId());
- pushHead(git, "refs/for/master", false);
- entries = getCurrentPatches(c.getChangeId());
+ c = amendBuilder()
+ .add(FILE_B, "2")
+ .create();
+ pushHead(testRepo, "refs/for/master", false);
+ entries = getCurrentPatches(id);
// Compare Change 1,2 with Base (+FILE_A, +FILE_B, -FILE_D)
assertThat(entries).hasSize(4);
@@ -88,33 +91,40 @@
@Test
public void listPatchesAgainstBaseWithRebase() throws Exception {
- add(git, FILE_D, "4");
- createCommit(git, admin.getIdent(), SUBJECT_1);
- pushHead(git, "refs/heads/master", false);
+ commitBuilder()
+ .add(FILE_D, "4")
+ .message(SUBJECT_1)
+ .create();
+ pushHead(testRepo, "refs/heads/master", false);
// Change 1,1 (+FILE_A, -FILE_D)
- add(git, FILE_A, "1");
- rm(git, FILE_D);
- Commit c = createCommit(git, admin.getIdent(), SUBJECT_2);
- pushHead(git, "refs/for/master", false);
- List<PatchListEntry> entries = getCurrentPatches(c.getChangeId());
+ RevCommit c = commitBuilder()
+ .add(FILE_A, "1")
+ .rm(FILE_D)
+ .message(SUBJECT_2)
+ .create();
+ String id = getChangeId(testRepo, c).get();
+ pushHead(testRepo, "refs/for/master", false);
+ List<PatchListEntry> entries = getCurrentPatches(id);
assertThat(entries).hasSize(3);
assertAdded(Patch.COMMIT_MSG, entries.get(0));
assertAdded(FILE_A, entries.get(1));
assertDeleted(FILE_D, entries.get(2));
// Change 2,1 (+FILE_B)
- git.reset().setMode(ResetType.HARD).setRef("HEAD~1").call();
- add(git, FILE_B, "2");
- createCommit(git, admin.getIdent(), SUBJECT_3);
- pushHead(git, "refs/for/master", false);
+ testRepo.reset("HEAD~1");
+ commitBuilder()
+ .add(FILE_B, "2")
+ .message(SUBJECT_3)
+ .create();
+ pushHead(testRepo, "refs/for/master", false);
// Change 1,2 (+FILE_A, -FILE_D))
- git.cherryPick().include(c.getCommit()).call();
- pushHead(git, "refs/for/master", false);
+ testRepo.cherryPick(c);
+ pushHead(testRepo, "refs/for/master", false);
// Compare Change 1,2 with Base (+FILE_A, -FILE_D))
- entries = getCurrentPatches(c.getChangeId());
+ entries = getCurrentPatches(id);
assertThat(entries).hasSize(3);
assertAdded(Patch.COMMIT_MSG, entries.get(0));
assertAdded(FILE_A, entries.get(1));
@@ -123,24 +133,27 @@
@Test
public void listPatchesAgainstOtherPatchSet() throws Exception {
- add(git, FILE_D, "4");
- createCommit(git, admin.getIdent(), SUBJECT_1);
- pushHead(git, "refs/heads/master", false);
+ commitBuilder()
+ .add(FILE_D, "4")
+ .message(SUBJECT_1)
+ .create();
+ pushHead(testRepo, "refs/heads/master", false);
// Change 1,1 (+FILE_A, +FILE_C, -FILE_D)
- add(git, FILE_A, "1");
- add(git, FILE_C, "3");
- rm(git, FILE_D);
- Commit c = createCommit(git, admin.getIdent(), SUBJECT_2);
- pushHead(git, "refs/for/master", false);
- ObjectId a = getCurrentRevisionId(c.getChangeId());
+ RevCommit a = commitBuilder()
+ .add(FILE_A, "1")
+ .add(FILE_C, "3")
+ .rm(FILE_D)
+ .message(SUBJECT_2)
+ .create();
+ pushHead(testRepo, "refs/for/master", false);
// Change 1,2 (+FILE_A, +FILE_B, -FILE_D)
- add(git, FILE_B, "2");
- rm(git, FILE_C);
- c = amendCommit(git, admin.getIdent(), SUBJECT_2, c.getChangeId());
- pushHead(git, "refs/for/master", false);
- ObjectId b = getCurrentRevisionId(c.getChangeId());
+ RevCommit b = amendBuilder()
+ .add(FILE_B, "2")
+ .rm(FILE_C)
+ .create();
+ pushHead(testRepo, "refs/for/master", false);
// Compare Change 1,1 with Change 1,2 (+FILE_B)
List<PatchListEntry> entries = getPatches(a, b);
@@ -151,29 +164,34 @@
@Test
public void listPatchesAgainstOtherPatchSetWithRebase() throws Exception {
- add(git, FILE_D, "4");
- createCommit(git, admin.getIdent(), SUBJECT_1);
- pushHead(git, "refs/heads/master", false);
+ commitBuilder()
+ .add(FILE_D, "4")
+ .message(SUBJECT_1)
+ .create();
+ pushHead(testRepo, "refs/heads/master", false);
// Change 1,1 (+FILE_A, -FILE_D)
- add(git, FILE_A, "1");
- rm(git, FILE_D);
- Commit c = createCommit(git, admin.getIdent(), SUBJECT_2);
- pushHead(git, "refs/for/master", false);
- ObjectId a = getCurrentRevisionId(c.getChangeId());
+ RevCommit a = commitBuilder()
+ .add(FILE_A, "1")
+ .rm(FILE_D)
+ .message(SUBJECT_2)
+ .create();
+ pushHead(testRepo, "refs/for/master", false);
// Change 2,1 (+FILE_B)
- git.reset().setMode(ResetType.HARD).setRef("HEAD~1").call();
- add(git, FILE_B, "2");
- createCommit(git, admin.getIdent(), SUBJECT_3);
- pushHead(git, "refs/for/master", false);
+ testRepo.reset("HEAD~1");
+ commitBuilder()
+ .add(FILE_B, "2")
+ .message(SUBJECT_3)
+ .create();
+ pushHead(testRepo, "refs/for/master", false);
// Change 1,2 (+FILE_A, +FILE_C, -FILE_D)
- git.cherryPick().include(c.getCommit()).call();
- add(git, FILE_C, "2");
- c = amendCommit(git, admin.getIdent(), SUBJECT_2, c.getChangeId());
- pushHead(git, "refs/for/master", false);
- ObjectId b = getCurrentRevisionId(c.getChangeId());
+ testRepo.cherryPick(a);
+ RevCommit b = amendBuilder()
+ .add(FILE_C, "2")
+ .create();
+ pushHead(testRepo, "refs/for/master", false);
// Compare Change 1,1 with Change 1,2 (+FILE_C)
List<PatchListEntry> entries = getPatches(a, b);
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/CustomLabelIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/CustomLabelIT.java
index cd76c12..da83157 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/CustomLabelIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/CustomLabelIT.java
@@ -28,7 +28,6 @@
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.LabelInfo;
import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.group.SystemGroupBackend;
import com.google.gerrit.server.project.Util;
@@ -39,29 +38,29 @@
@NoHttpd
public class CustomLabelIT extends AbstractDaemonTest {
- private final LabelType Q = category("CustomLabel",
+ private final LabelType label = category("CustomLabel",
value(1, "Positive"),
value(0, "No score"),
value(-1, "Negative"));
@Before
public void setUp() throws Exception {
- ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig();
+ ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
AccountGroup.UUID anonymousUsers =
SystemGroupBackend.getGroup(ANONYMOUS_USERS).getUUID();
- Util.allow(cfg, Permission.forLabel(Q.getName()), -1, 1, anonymousUsers,
+ Util.allow(cfg, Permission.forLabel(label.getName()), -1, 1, anonymousUsers,
"refs/heads/*");
- saveProjectConfig(cfg);
+ saveProjectConfig(project, cfg);
}
@Test
public void customLabelNoOp_NegativeVoteNotBlock() throws Exception {
- Q.setFunctionName("NoOp");
+ label.setFunctionName("NoOp");
saveLabelConfig();
PushOneCommit.Result r = createChange();
- revision(r).review(new ReviewInput().label(Q.getName(), -1));
+ revision(r).review(new ReviewInput().label(label.getName(), -1));
ChangeInfo c = get(r.getChangeId());
- LabelInfo q = c.labels.get(Q.getName());
+ LabelInfo q = c.labels.get(label.getName());
assertThat(q.all).hasSize(1);
assertThat(q.rejected).isNotNull();
assertThat(q.blocking).isNull();
@@ -69,12 +68,12 @@
@Test
public void customLabelNoBlock_NegativeVoteNotBlock() throws Exception {
- Q.setFunctionName("NoBlock");
+ label.setFunctionName("NoBlock");
saveLabelConfig();
PushOneCommit.Result r = createChange();
- revision(r).review(new ReviewInput().label(Q.getName(), -1));
+ revision(r).review(new ReviewInput().label(label.getName(), -1));
ChangeInfo c = get(r.getChangeId());
- LabelInfo q = c.labels.get(Q.getName());
+ LabelInfo q = c.labels.get(label.getName());
assertThat(q.all).hasSize(1);
assertThat(q.rejected).isNotNull();
assertThat(q.blocking).isNull();
@@ -82,12 +81,12 @@
@Test
public void customLabelMaxNoBlock_NegativeVoteNotBlock() throws Exception {
- Q.setFunctionName("MaxNoBlock");
+ label.setFunctionName("MaxNoBlock");
saveLabelConfig();
PushOneCommit.Result r = createChange();
- revision(r).review(new ReviewInput().label(Q.getName(), -1));
+ revision(r).review(new ReviewInput().label(label.getName(), -1));
ChangeInfo c = get(r.getChangeId());
- LabelInfo q = c.labels.get(Q.getName());
+ LabelInfo q = c.labels.get(label.getName());
assertThat(q.all).hasSize(1);
assertThat(q.rejected).isNotNull();
assertThat(q.blocking).isNull();
@@ -95,12 +94,12 @@
@Test
public void customLabelAnyWithBlock_NegativeVoteBlock() throws Exception {
- Q.setFunctionName("AnyWithBlock");
+ label.setFunctionName("AnyWithBlock");
saveLabelConfig();
PushOneCommit.Result r = createChange();
- revision(r).review(new ReviewInput().label(Q.getName(), -1));
+ revision(r).review(new ReviewInput().label(label.getName(), -1));
ChangeInfo c = get(r.getChangeId());
- LabelInfo q = c.labels.get(Q.getName());
+ LabelInfo q = c.labels.get(label.getName());
assertThat(q.all).hasSize(1);
assertThat(q.disliked).isNull();
assertThat(q.rejected).isNotNull();
@@ -111,9 +110,9 @@
public void customLabelMaxWithBlock_NegativeVoteBlock() throws Exception {
saveLabelConfig();
PushOneCommit.Result r = createChange();
- revision(r).review(new ReviewInput().label(Q.getName(), -1));
+ revision(r).review(new ReviewInput().label(label.getName(), -1));
ChangeInfo c = get(r.getChangeId());
- LabelInfo q = c.labels.get(Q.getName());
+ LabelInfo q = c.labels.get(label.getName());
assertThat(q.all).hasSize(1);
assertThat(q.disliked).isNull();
assertThat(q.rejected).isNotNull();
@@ -121,18 +120,8 @@
}
private void saveLabelConfig() throws Exception {
- ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig();
- cfg.getLabelSections().put(Q.getName(), Q);
- saveProjectConfig(cfg);
- }
-
- private void saveProjectConfig(ProjectConfig cfg) throws Exception {
- MetaDataUpdate md = metaDataUpdateFactory.create(allProjects);
- try {
- cfg.commit(md);
- } finally {
- md.close();
- }
- projectCache.evict(allProjects);
+ ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
+ cfg.getLabelSections().put(label.getName(), label);
+ saveProjectConfig(project, cfg);
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/LabelTypeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/LabelTypeIT.java
index efb4615..9d44ad6 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/LabelTypeIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/LabelTypeIT.java
@@ -14,7 +14,6 @@
package com.google.gerrit.acceptance.server.project;
-import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.truth.Truth.assertThat;
import com.google.gerrit.acceptance.AbstractDaemonTest;
@@ -28,6 +27,7 @@
import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.notedb.NotesMigration;
+import com.google.gerrit.server.project.Util;
import com.google.gerrit.testutil.ConfigSuite;
import org.eclipse.jgit.lib.Config;
@@ -46,15 +46,15 @@
@Before
public void setUp() throws Exception {
- ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig();
- codeReview = checkNotNull(cfg.getLabelSections().get("Code-Review"));
+ ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
+ codeReview = Util.codeReview();
codeReview.setDefaultValue((short)-1);
+ cfg.getLabelSections().put(codeReview.getName(), codeReview);
saveProjectConfig(cfg);
}
@Test
public void noCopyMinScoreOnRework() throws Exception {
- //allProjects only has it true by default
codeReview.setCopyMinScore(false);
saveLabelConfig();
@@ -143,15 +143,15 @@
String file = "a.txt";
String contents = "contents";
- PushOneCommit push = pushFactory.create(db, admin.getIdent(),
+ PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo,
"first subject", file, contents);
- PushOneCommit.Result r = push.to(git, "refs/for/master");
+ PushOneCommit.Result r = push.to("refs/for/master");
revision(r).review(ReviewInput.recommend());
assertApproval(r, 1);
- push = pushFactory.create(db, admin.getIdent(),
+ push = pushFactory.create(db, admin.getIdent(), testRepo,
"second subject", file, contents, r.getChangeId());
- r = push.to(git, "refs/for/master");
+ r = push.to("refs/for/master");
assertApproval(r, 0);
}
@@ -162,15 +162,15 @@
codeReview.setCopyAllScoresIfNoCodeChange(true);
saveLabelConfig();
- PushOneCommit push = pushFactory.create(db, admin.getIdent(),
+ PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo,
"first subject", file, contents);
- PushOneCommit.Result r = push.to(git, "refs/for/master");
+ PushOneCommit.Result r = push.to("refs/for/master");
revision(r).review(ReviewInput.recommend());
assertApproval(r, 1);
- push = pushFactory.create(db, admin.getIdent(),
+ push = pushFactory.create(db, admin.getIdent(), testRepo,
"second subject", file, contents, r.getChangeId());
- r = push.to(git, "refs/for/master");
+ r = push.to("refs/for/master");
assertApproval(r, 1);
}
@@ -180,18 +180,18 @@
String file = "a.txt";
String contents = "contents";
- PushOneCommit push = pushFactory.create(db, admin.getIdent());
- PushOneCommit.Result r1 = push.to(git, "refs/for/master");
+ PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo);
+ PushOneCommit.Result r1 = push.to("refs/for/master");
merge(r1);
- push = pushFactory.create(db, admin.getIdent(),
+ push = pushFactory.create(db, admin.getIdent(), testRepo,
"non-conflicting", "b.txt", "other contents");
- PushOneCommit.Result r2 = push.to(git, "refs/for/master");
+ PushOneCommit.Result r2 = push.to("refs/for/master");
merge(r2);
- git.checkout().setName(r1.getCommit().name()).call();
- push = pushFactory.create(db, admin.getIdent(), subject, file, contents);
- PushOneCommit.Result r3 = push.to(git, "refs/for/master");
+ testRepo.reset(r1.getCommit());
+ push = pushFactory.create(db, admin.getIdent(), testRepo, subject, file, contents);
+ PushOneCommit.Result r3 = push.to("refs/for/master");
revision(r3).review(ReviewInput.recommend());
assertApproval(r3, 1);
@@ -207,18 +207,18 @@
codeReview.setCopyAllScoresOnTrivialRebase(true);
saveLabelConfig();
- PushOneCommit push = pushFactory.create(db, admin.getIdent());
- PushOneCommit.Result r1 = push.to(git, "refs/for/master");
+ PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo);
+ PushOneCommit.Result r1 = push.to("refs/for/master");
merge(r1);
- push = pushFactory.create(db, admin.getIdent(),
+ push = pushFactory.create(db, admin.getIdent(), testRepo,
"non-conflicting", "b.txt", "other contents");
- PushOneCommit.Result r2 = push.to(git, "refs/for/master");
+ PushOneCommit.Result r2 = push.to("refs/for/master");
merge(r2);
- git.checkout().setName(r1.getCommit().name()).call();
- push = pushFactory.create(db, admin.getIdent(), subject, file, contents);
- PushOneCommit.Result r3 = push.to(git, "refs/for/master");
+ testRepo.reset(r1.getCommit());
+ push = pushFactory.create(db, admin.getIdent(), testRepo, subject, file, contents);
+ PushOneCommit.Result r3 = push.to("refs/for/master");
revision(r3).review(ReviewInput.recommend());
assertApproval(r3, 1);
@@ -232,11 +232,11 @@
saveLabelConfig();
PushOneCommit.Result r1 = createChange();
- git.checkout().setName(r1.getCommit().name()).call();
+ testRepo.reset(r1.getCommit());
- PushOneCommit push = pushFactory.create(db, admin.getIdent(),
+ PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo,
PushOneCommit.SUBJECT, "b.txt", "other contents");
- PushOneCommit.Result r2 = push.to(git, "refs/for/master");
+ PushOneCommit.Result r2 = push.to("refs/for/master");
revision(r2).review(ReviewInput.recommend());
@@ -262,11 +262,11 @@
PushOneCommit.Result r1 = createChange();
- git.checkout().setName(r1.getCommit().name()).call();
+ testRepo.reset(r1.getCommit());
- PushOneCommit push = pushFactory.create(db, admin.getIdent(),
+ PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo,
PushOneCommit.SUBJECT, "b.txt", "other contents");
- PushOneCommit.Result r2 = push.to(git, "refs/for/master");
+ PushOneCommit.Result r2 = push.to("refs/for/master");
revision(r2).review(ReviewInput.recommend());
@@ -288,38 +288,38 @@
String file = "a.txt";
String contents = "contents";
- PushOneCommit push = pushFactory.create(db, admin.getIdent(),
+ PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo,
PushOneCommit.SUBJECT, file, contents);
- PushOneCommit.Result base = push.to(git, "refs/for/master");
+ PushOneCommit.Result base = push.to("refs/for/master");
merge(base);
- push = pushFactory.create(db, admin.getIdent(),
+ push = pushFactory.create(db, admin.getIdent(), testRepo,
PushOneCommit.SUBJECT, file, contents + "M");
- PushOneCommit.Result basePlusM = push.to(git, "refs/for/master");
+ PushOneCommit.Result basePlusM = push.to("refs/for/master");
merge(basePlusM);
- push = pushFactory.create(db, admin.getIdent(),
+ push = pushFactory.create(db, admin.getIdent(), testRepo,
PushOneCommit.SUBJECT, file, contents);
- PushOneCommit.Result basePlusMMinusM = push.to(git, "refs/for/master");
+ PushOneCommit.Result basePlusMMinusM = push.to("refs/for/master");
merge(basePlusMMinusM);
- git.checkout().setName(base.getCommit().name()).call();
- push = pushFactory.create(db, admin.getIdent(),
+ testRepo.reset(base.getCommit());
+ push = pushFactory.create(db, admin.getIdent(), testRepo,
PushOneCommit.SUBJECT, file, contents + "MM");
- PushOneCommit.Result patchSet = push.to(git, "refs/for/master");
+ PushOneCommit.Result patchSet = push.to("refs/for/master");
revision(patchSet).review(ReviewInput.recommend());
return patchSet;
}
private void saveLabelConfig() throws Exception {
- ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig();
+ ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
cfg.getLabelSections().clear();
cfg.getLabelSections().put(codeReview.getName(), codeReview);
saveProjectConfig(cfg);
}
private void saveProjectConfig(ProjectConfig cfg) throws Exception {
- MetaDataUpdate md = metaDataUpdateFactory.create(allProjects);
+ MetaDataUpdate md = metaDataUpdateFactory.create(project);
try {
cfg.commit(md);
} finally {
@@ -356,6 +356,6 @@
assertThat((int) cr.defaultValue).isEqualTo(-1);
assertThat(cr.all).hasSize(1);
assertThat(cr.all.get(0).name).isEqualTo("Administrator");
- assertThat(cr.all.get(0).value.intValue()).isEqualTo(expected);
+ assertThat(cr.all.get(0).value).isEqualTo(expected);
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/ProjectWatchIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/ProjectWatchIT.java
new file mode 100644
index 0000000..bab8e33
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/ProjectWatchIT.java
@@ -0,0 +1,78 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.acceptance.server.project;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.NoHttpd;
+import com.google.gerrit.acceptance.PushOneCommit;
+import com.google.gerrit.reviewdb.client.AccountProjectWatch.NotifyType;
+import com.google.gerrit.server.git.NotifyConfig;
+import com.google.gerrit.server.git.ProjectConfig;
+import com.google.gerrit.server.mail.Address;
+import com.google.gerrit.testutil.FakeEmailSender;
+import com.google.gerrit.testutil.FakeEmailSender.Message;
+import com.google.inject.Inject;
+
+import org.junit.Test;
+
+import java.util.EnumSet;
+import java.util.List;
+
+@NoHttpd
+public class ProjectWatchIT extends AbstractDaemonTest {
+ @Inject
+ private FakeEmailSender sender;
+
+ @Test
+ public void newPatchSetsNotifyConfig() throws Exception {
+ Address addr = new Address("Watcher", "watcher@example.com");
+ NotifyConfig nc = new NotifyConfig();
+ nc.addEmail(addr);
+ nc.setName("new-patch-set");
+ nc.setHeader(NotifyConfig.Header.CC);
+ nc.setTypes(EnumSet.of(NotifyType.NEW_PATCHSETS));
+ nc.setFilter("message:sekret");
+
+ ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
+ cfg.putNotifyConfig("watch", nc);
+ saveProjectConfig(project, cfg);
+
+ PushOneCommit.Result r = pushFactory.create(db, admin.getIdent(), testRepo,
+ "original subject", "a", "a1")
+ .to("refs/for/master");
+ r.assertOkStatus();
+
+ r = pushFactory.create(db, admin.getIdent(), testRepo,
+ "super sekret subject", "a", "a2", r.getChangeId())
+ .to("refs/for/master");
+ r.assertOkStatus();
+
+ r = pushFactory.create(db, admin.getIdent(), testRepo,
+ "back to original subject", "a", "a3")
+ .to("refs/for/master");
+ r.assertOkStatus();
+
+ List<Message> messages = sender.getMessages();
+ assertThat(messages).hasSize(1);
+ Message m = messages.get(0);
+ assertThat(m.rcpt()).containsExactly(addr);
+ assertThat(m.body()).contains("Change subject: super sekret subject\n");
+ assertThat(m.body()).contains("Gerrit-PatchSet: 2\n");
+ }
+
+ // TODO(anybody reading this): More tests.
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/BUCK
index 2ea5dec..d067b34 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/BUCK
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/BUCK
@@ -2,5 +2,6 @@
acceptance_tests(
srcs = glob(['*IT.java']),
+ deps = ['//lib/commons:compress'],
labels = ['ssh'],
)
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/BanCommitIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/BanCommitIT.java
index e483716..3bef84b 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/BanCommitIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/BanCommitIT.java
@@ -16,14 +16,12 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assert_;
-import static com.google.gerrit.acceptance.GitUtil.add;
-import static com.google.gerrit.acceptance.GitUtil.createCommit;
import static com.google.gerrit.acceptance.GitUtil.pushHead;
import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.GitUtil.Commit;
import com.google.gerrit.acceptance.NoHttpd;
+import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.PushResult;
import org.junit.Test;
@@ -34,17 +32,17 @@
@Test
public void banCommit() throws Exception {
- add(git, "a.txt", "some content");
- Commit c = createCommit(git, admin.getIdent(), "subject");
+ RevCommit c = commitBuilder()
+ .add("a.txt", "some content")
+ .create();
String response =
- sshSession.exec("gerrit ban-commit " + project.get() + " "
- + c.getCommit().getName());
+ sshSession.exec("gerrit ban-commit " + project.get() + " " + c.name());
assert_().withFailureMessage(sshSession.getError())
.that(sshSession.hasError()).isFalse();
assertThat(response.toLowerCase(Locale.US)).doesNotContain("error");
- PushResult pushResult = pushHead(git, "refs/heads/master", false);
+ PushResult pushResult = pushHead(testRepo, "refs/heads/master", false);
assertThat(pushResult.getRemoteUpdate("refs/heads/master").getMessage())
.startsWith("contains banned commit");
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/GarbageCollectionIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/GarbageCollectionIT.java
index 2bdd894..4f9f190 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/GarbageCollectionIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/GarbageCollectionIT.java
@@ -16,7 +16,6 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assert_;
-import static com.google.gerrit.acceptance.GitUtil.createProject;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.GcAssert;
@@ -52,11 +51,8 @@
@Before
public void setUp() throws Exception {
- project2 = new Project.NameKey("p2");
- createProject(sshSession, project2.get());
-
- project3 = new Project.NameKey("p3");
- createProject(sshSession, project3.get());
+ project2 = createProject("p2");
+ project3 = createProject("p3");
}
@Test
@@ -97,7 +93,7 @@
GarbageCollectionResult result = garbageCollectionFactory.create().run(
Arrays.asList(allProjects, project, project2, project3));
assertThat(result.hasErrors()).isTrue();
- assertThat(result.getErrors().size()).isEqualTo(1);
+ assertThat(result.getErrors()).hasSize(1);
GarbageCollectionResult.Error error = result.getErrors().get(0);
assertThat(error.getType()).isEqualTo(
GarbageCollectionResult.Error.Type.GC_ALREADY_SCHEDULED);
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/JschVerifyFalseBugIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/JschVerifyFalseBugIT.java
index c9e0a89..7fb99b6 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/JschVerifyFalseBugIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/JschVerifyFalseBugIT.java
@@ -15,11 +15,11 @@
package com.google.gerrit.acceptance.ssh;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.GitUtil.cloneProject;
-import static com.google.gerrit.acceptance.GitUtil.createProject;
import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.GitUtil;
import com.google.gerrit.acceptance.NoHttpd;
+import com.google.gerrit.reviewdb.client.Project;
import org.junit.Ignore;
import org.junit.Test;
@@ -50,8 +50,8 @@
public Void call() throws Exception {
for (int i = 1; i < 100; i++) {
String p = "p" + i;
- createProject(sshSession, p);
- cloneProject(sshSession.getUrl() + "/" + p);
+ createProject(p);
+ GitUtil.cloneProject(new Project.NameKey(p), sshSession);
}
return null;
}
@@ -62,6 +62,6 @@
for (Future<Void> future : futures) {
future.get();
}
- assertThat(futures.size()).isEqualTo(threads);
+ assertThat(futures).hasSize(threads);
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/UploadArchiveIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/UploadArchiveIT.java
new file mode 100644
index 0000000..88821ce
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/UploadArchiveIT.java
@@ -0,0 +1,127 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.acceptance.ssh;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.base.Splitter;
+import com.google.common.collect.Iterables;
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.GerritConfig;
+import com.google.gerrit.acceptance.NoHttpd;
+import com.google.gerrit.acceptance.PushOneCommit;
+
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
+import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
+import org.eclipse.jgit.transport.PacketLineIn;
+import org.eclipse.jgit.transport.PacketLineOut;
+import org.eclipse.jgit.util.IO;
+import org.junit.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Set;
+import java.util.TreeSet;
+
+@NoHttpd
+public class UploadArchiveIT extends AbstractDaemonTest {
+
+ @Test
+ @GerritConfig(name = "download.archive", value = "off")
+ public void archiveFeatureOff() throws Exception {
+ archiveNotPermitted();
+ }
+
+ @Test
+ @GerritConfig(name = "download.archive", values = {"tar", "tbz2", "tgz", "txz"})
+ public void zipFormatDisabled() throws Exception {
+ archiveNotPermitted();
+ }
+
+ @Test
+ public void zipFormat() throws Exception {
+ PushOneCommit.Result r = createChange();
+ String abbreviated = r.getCommitId().abbreviate(8).name();
+ String c = command(r, abbreviated);
+
+ InputStream out =
+ sshSession.exec2("git-upload-archive " + project.get(),
+ argumentsToInputStream(c));
+
+ // Wrap with PacketLineIn to read ACK bytes from output stream
+ PacketLineIn in = new PacketLineIn(out);
+ String tmp = in.readString();
+ assertThat(tmp).isEqualTo("ACK");
+ tmp = in.readString();
+
+ // Skip length (4 bytes) + 1 byte
+ // to position the output stream to the raw zip stream
+ byte[] buffer = new byte[5];
+ IO.readFully(out, buffer, 0, 5);
+ Set<String> entryNames = new TreeSet<>();
+ try (ZipArchiveInputStream zip = new ZipArchiveInputStream(out)) {
+ ZipArchiveEntry zipEntry = zip.getNextZipEntry();
+ while (zipEntry != null) {
+ String name = zipEntry.getName();
+ entryNames.add(name);
+ zipEntry = zip.getNextZipEntry();
+ }
+ }
+
+ assertThat(entryNames.size()).isEqualTo(1);
+ assertThat(Iterables.getOnlyElement(entryNames)).isEqualTo(
+ String.format("%s/%s", abbreviated, PushOneCommit.FILE_NAME));
+ }
+
+ private String command(PushOneCommit.Result r, String abbreviated) {
+ String c = "-f=zip "
+ + "-9 "
+ + "--prefix=" + abbreviated + "/ "
+ + r.getCommit().name() + " "
+ + PushOneCommit.FILE_NAME;
+ return c;
+ }
+
+ private void archiveNotPermitted() throws Exception {
+ PushOneCommit.Result r = createChange();
+ String abbreviated = r.getCommitId().abbreviate(8).name();
+ String c = command(r, abbreviated);
+
+ InputStream out =
+ sshSession.exec2("git-upload-archive " + project.get(),
+ argumentsToInputStream(c));
+
+ // Wrap with PacketLineIn to read ACK bytes from output stream
+ PacketLineIn in = new PacketLineIn(out);
+ String tmp = in.readString();
+ assertThat(tmp).isEqualTo("ACK");
+ tmp = in.readString();
+ tmp = in.readString();
+ tmp = tmp.substring(1);
+ assertThat(tmp).isEqualTo("fatal: upload-archive not permitted");
+ }
+
+ private InputStream argumentsToInputStream(String c) throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ PacketLineOut pctOut = new PacketLineOut(out);
+ for (String arg : Splitter.on(' ').split(c)) {
+ pctOut.writeString("argument " + arg);
+ }
+ pctOut.end();
+ return new ByteArrayInputStream(out.toByteArray());
+ }
+}
diff --git a/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java b/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java
index 5870f91..fcacf78 100644
--- a/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java
+++ b/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java
@@ -37,7 +37,9 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
@@ -51,7 +53,7 @@
private final DefaultCacheFactory defaultFactory;
private final Config config;
- private final File cacheDir;
+ private final Path cacheDir;
private final List<H2CacheImpl<?, ?>> caches;
private final DynamicMap<Cache<?, ?>> cacheMap;
private final ExecutorService executor;
@@ -65,23 +67,7 @@
DynamicMap<Cache<?, ?>> cacheMap) {
defaultFactory = defaultCacheFactory;
config = cfg;
-
- File loc = site.resolve(cfg.getString("cache", null, "directory"));
- if (loc == null) {
- cacheDir = null;
- } else if (loc.exists() || loc.mkdirs()) {
- if (loc.canWrite()) {
- log.info("Enabling disk cache " + loc.getAbsolutePath());
- cacheDir = loc;
- } else {
- log.warn("Can't write to disk cache: " + loc.getAbsolutePath());
- cacheDir = null;
- }
- } else {
- log.warn("Can't create disk cache: " + loc.getAbsolutePath());
- cacheDir = null;
- }
-
+ cacheDir = getCacheDir(site, cfg.getString("cache", null, "directory"));
caches = Lists.newLinkedList();
this.cacheMap = cacheMap;
@@ -103,6 +89,27 @@
}
}
+ private static Path getCacheDir(SitePaths site, String name) {
+ if (name == null) {
+ return null;
+ }
+ Path loc = site.resolve(name);
+ if (!Files.exists(loc)) {
+ try {
+ Files.createDirectories(loc);
+ } catch (IOException e) {
+ log.warn("Can't create disk cache: " + loc.toAbsolutePath());
+ return null;
+ }
+ }
+ if (!Files.isWritable(loc)) {
+ log.warn("Can't write to disk cache: " + loc.toAbsolutePath());
+ return null;
+ }
+ log.info("Enabling disk cache " + loc.toAbsolutePath());
+ return loc;
+ }
+
@Override
public void start() {
if (executor != null) {
@@ -213,8 +220,7 @@
TypeLiteral<K> keyType,
long maxSize,
Long expireAfterWrite) {
- File db = new File(cacheDir, name).getAbsoluteFile();
- String url = "jdbc:h2:" + db.toURI().toString();
+ String url = "jdbc:h2:" + cacheDir.resolve(name).toUri();
return new SqlStore<>(url, keyType, maxSize,
expireAfterWrite == null ? 0 : expireAfterWrite.longValue());
}
diff --git a/gerrit-common/BUCK b/gerrit-common/BUCK
index 88e503e..484136a 100644
--- a/gerrit-common/BUCK
+++ b/gerrit-common/BUCK
@@ -51,6 +51,7 @@
'//lib:guava',
'//lib/jgit:jgit',
'//lib/joda:joda-time',
+ '//lib/log:api',
],
visibility = ['PUBLIC'],
)
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/FileUtil.java b/gerrit-common/src/main/java/com/google/gerrit/common/FileUtil.java
index bed10d6..2335b8d1 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/FileUtil.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/FileUtil.java
@@ -21,6 +21,8 @@
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.Arrays;
public class FileUtil {
@@ -42,6 +44,11 @@
}
}
+ public static void chmod(final int mode, final Path path) {
+ // TODO(dborowitz): Is there a portable way to do this with NIO?
+ chmod(mode, path.toFile());
+ }
+
public static void chmod(final int mode, final File path) {
path.setReadable(false, false /* all */);
path.setWritable(false, false /* all */);
@@ -61,6 +68,33 @@
}
}
+ /**
+ * Get the last modified time of a path.
+ * <p>
+ * Equivalent to {@code File#lastModified()}, returning 0 on errors, including
+ * file not found. Callers that prefer exceptions can use {@link
+ * Files#getLastModifiedTime(Path, java.nio.file.LinkOption...)}.
+ *
+ * @param p path.
+ * @return last modified time, in milliseconds since epoch.
+ */
+ public static long lastModified(Path p) {
+ try {
+ return Files.getLastModifiedTime(p).toMillis();
+ } catch (IOException e) {
+ return 0;
+ }
+ }
+
+ public static Path mkdirsOrDie(Path p, String errMsg) {
+ try {
+ Files.createDirectories(p);
+ return p;
+ } catch (IOException e) {
+ throw new Die(errMsg + ": " + p, e);
+ }
+ }
+
private FileUtil() {
}
-}
\ No newline at end of file
+}
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/IoUtil.java b/gerrit-common/src/main/java/com/google/gerrit/common/IoUtil.java
index c45d9f9..9a30696 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/IoUtil.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/IoUtil.java
@@ -16,7 +16,6 @@
import com.google.common.collect.Sets;
-import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -25,6 +24,7 @@
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
+import java.nio.file.Path;
import java.util.Arrays;
import java.util.Set;
@@ -53,7 +53,7 @@
}.start();
}
- public static void loadJARs(File... jars) {
+ public static void loadJARs(Iterable<Path> jars) {
ClassLoader cl = IoUtil.class.getClassLoader();
if (!(cl instanceof URLClassLoader)) {
throw noAddURL("Not loaded by URLClassLoader", null);
@@ -71,9 +71,9 @@
}
Set<URL> have = Sets.newHashSet(Arrays.asList(urlClassLoader.getURLs()));
- for (File path : jars) {
+ for (Path path : jars) {
try {
- URL url = path.toURI().toURL();
+ URL url = path.toUri().toURL();
if (have.add(url)) {
addURL.invoke(cl, url);
}
@@ -86,6 +86,10 @@
}
}
+ public static void loadJARs(Path... jars) {
+ loadJARs(Arrays.asList(jars));
+ }
+
private static UnsupportedOperationException noAddURL(String m, Throwable why) {
String prefix = "Cannot extend classpath: ";
return new UnsupportedOperationException(prefix + m, why);
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/PluginData.java b/gerrit-common/src/main/java/com/google/gerrit/common/PluginData.java
index ffdae9d..27dc639 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/PluginData.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/PluginData.java
@@ -14,18 +14,18 @@
package com.google.gerrit.common;
-import java.io.File;
+import java.nio.file.Path;
import java.util.Objects;
public class PluginData {
public final String name;
public final String version;
- public final File pluginFile;
+ public final Path pluginPath;
- public PluginData(String name, String version, File pluginFile) {
+ public PluginData(String name, String version, Path pluginPath) {
this.name = name;
this.version = version;
- this.pluginFile = pluginFile;
+ this.pluginPath = pluginPath;
}
@Override
@@ -33,13 +33,13 @@
if (obj instanceof PluginData) {
PluginData o = (PluginData) obj;
return Objects.equals(name, o.name) && Objects.equals(version, o.version)
- && Objects.equals(pluginFile, o.pluginFile);
+ && Objects.equals(pluginPath, o.pluginPath);
}
return super.equals(obj);
}
@Override
public int hashCode() {
- return Objects.hash(name, version, pluginFile);
+ return Objects.hash(name, version, pluginPath);
}
-}
\ No newline at end of file
+}
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/SiteLibraryLoaderUtil.java b/gerrit-common/src/main/java/com/google/gerrit/common/SiteLibraryLoaderUtil.java
index a98e0a5..2511a51 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/SiteLibraryLoaderUtil.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/SiteLibraryLoaderUtil.java
@@ -14,41 +14,57 @@
package com.google.gerrit.common;
-import java.io.File;
-import java.io.FileFilter;
-import java.util.Arrays;
-import java.util.Comparator;
+import static com.google.gerrit.common.FileUtil.lastModified;
+
+import com.google.common.collect.ComparisonChain;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Ordering;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.util.List;
public final class SiteLibraryLoaderUtil {
+ private static final Logger log =
+ LoggerFactory.getLogger(SiteLibraryLoaderUtil.class);
- public static void loadSiteLib(File libdir) {
- File[] jars = listJars(libdir);
- if (jars != null && 0 < jars.length) {
- Arrays.sort(jars, new Comparator<File>() {
- @Override
- public int compare(File a, File b) {
- // Sort by reverse last-modified time so newer JARs are first.
- int cmp = Long.compare(b.lastModified(), a.lastModified());
- if (cmp != 0) {
- return cmp;
- }
- return a.getName().compareTo(b.getName());
- }
- });
- IoUtil.loadJARs(jars);
+ public static void loadSiteLib(Path libdir) {
+ try {
+ IoUtil.loadJARs(listJars(libdir));
+ } catch (IOException e) {
+ log.error("Error scanning lib directory " + libdir, e);
}
}
- public static File[] listJars(File libdir) {
- File[] jars = libdir.listFiles(new FileFilter() {
+ public static List<Path> listJars(Path dir) throws IOException {
+ DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<Path>() {
@Override
- public boolean accept(File path) {
- String name = path.getName();
- return (name.endsWith(".jar") || name.endsWith(".zip"))
- && path.isFile();
+ public boolean accept(Path entry) throws IOException {
+ String name = entry.getFileName().toString();
+ return (name.endsWith(".jar") || name.endsWith(".zip"))
+ && Files.isRegularFile(entry);
}
- });
- return jars;
+ };
+ try (DirectoryStream<Path> jars = Files.newDirectoryStream(dir, filter)) {
+ return new Ordering<Path>() {
+ @Override
+ public int compare(Path a, Path b) {
+ // Sort by reverse last-modified time so newer JARs are first.
+ return ComparisonChain.start()
+ .compare(lastModified(b), lastModified(a))
+ .compare(a, b)
+ .result();
+ }
+ }.sortedCopy(jars);
+ } catch (NoSuchFileException nsfe) {
+ return ImmutableList.of();
+ }
}
private SiteLibraryLoaderUtil() {
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeInfo.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeInfo.java
index a744122..d0f8cd3 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeInfo.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeInfo.java
@@ -107,7 +107,7 @@
return latest;
}
- public java.sql.Timestamp getLastUpdatedOn() {
+ public Timestamp getLastUpdatedOn() {
return lastUpdatedOn;
}
}
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/CommentDetail.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/CommentDetail.java
index db78c4d..1b98b09 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/CommentDetail.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/CommentDetail.java
@@ -136,7 +136,9 @@
parentMap.put(parentUuid, l);
}
l.add(c);
- if (parentUuid == null) rootComments.add(c);
+ if (parentUuid == null) {
+ rootComments.add(c);
+ }
}
// Add the comments in the list, starting with the head and then going through all the
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/GerritConfig.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/GerritConfig.java
index d911390..045591c 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/GerritConfig.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/GerritConfig.java
@@ -16,10 +16,7 @@
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Account.FieldName;
-import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadCommand;
-import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadScheme;
import com.google.gerrit.reviewdb.client.AuthType;
-import com.google.gerrit.reviewdb.client.Project;
import java.util.List;
import java.util.Set;
@@ -36,17 +33,11 @@
protected boolean httpPasswordSettingsEnabled = true;
protected GitwebConfig gitweb;
- protected boolean useContributorAgreements;
- protected boolean useContactInfo;
- protected boolean allowRegisterNewEmail;
protected AuthType authType;
- protected Set<DownloadScheme> downloadSchemes;
- protected Set<DownloadCommand> downloadCommands;
protected String gitDaemonUrl;
protected String gitHttpUrl;
protected String sshdAddress;
protected String editFullNameUrl;
- protected Project.NameKey wildProject;
protected Set<Account.FieldName> editableAccountFields;
protected boolean documentationAvailable;
protected String anonymousCowardName;
@@ -138,30 +129,10 @@
httpPasswordUrl = url;
}
- public AuthType getAuthType() {
- return authType;
- }
-
public void setAuthType(final AuthType t) {
authType = t;
}
- public Set<DownloadScheme> getDownloadSchemes() {
- return downloadSchemes;
- }
-
- public void setDownloadSchemes(final Set<DownloadScheme> s) {
- downloadSchemes = s;
- }
-
- public Set<DownloadCommand> getDownloadCommands() {
- return downloadCommands;
- }
-
- public void setDownloadCommands(final Set<DownloadCommand> downloadCommands) {
- this.downloadCommands = downloadCommands;
- }
-
public GitwebConfig getGitwebLink() {
return gitweb;
}
@@ -170,22 +141,6 @@
gitweb = w;
}
- public boolean isUseContributorAgreements() {
- return useContributorAgreements;
- }
-
- public void setUseContributorAgreements(final boolean r) {
- useContributorAgreements = r;
- }
-
- public boolean isUseContactInfo() {
- return useContactInfo;
- }
-
- public void setUseContactInfo(final boolean r) {
- useContactInfo = r;
- }
-
public String getGitDaemonUrl() {
return gitDaemonUrl;
}
@@ -216,22 +171,6 @@
sshdAddress = addr;
}
- public Project.NameKey getWildProject() {
- return wildProject;
- }
-
- public void setWildProject(final Project.NameKey wp) {
- wildProject = wp;
- }
-
- public boolean canEdit(final Account.FieldName f) {
- return editableAccountFields.contains(f);
- }
-
- public Set<Account.FieldName> getEditableAccountFields() {
- return editableAccountFields;
- }
-
public void setEditableAccountFields(final Set<Account.FieldName> af) {
editableAccountFields = af;
}
@@ -261,9 +200,9 @@
}
public boolean siteHasUsernames() {
- if (getAuthType() == AuthType.CUSTOM_EXTENSION
+ if (authType == AuthType.CUSTOM_EXTENSION
&& getHttpPasswordUrl() != null
- && !canEdit(FieldName.USER_NAME)) {
+ && !editableAccountFields.contains(FieldName.USER_NAME)) {
return false;
}
return true;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/GitWebType.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/GitWebType.java
index 8219d27..0aff539 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/GitWebType.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/GitWebType.java
@@ -47,10 +47,6 @@
type = new GitWebType();
// The custom name is not defined, let's keep the old style of using GitWeb
type.setLinkName("gitweb");
-
- } else if (name.equalsIgnoreCase("disabled")) {
- type = null;
-
} else {
type = null;
}
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/HostPageData.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/HostPageData.java
index 430c23c..fa3d7a8 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/HostPageData.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/HostPageData.java
@@ -30,6 +30,7 @@
public Theme theme;
public List<String> plugins;
public List<Message> messages;
+ public Integer pluginsLoadTimeout;
public boolean isNoteDbEnabled;
public static class Theme {
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchScript.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchScript.java
index 046df1d..7bab43a 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchScript.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchScript.java
@@ -57,6 +57,8 @@
protected boolean intralineFailure;
protected boolean intralineTimeout;
protected boolean binary;
+ protected transient String commitIdA;
+ protected transient String commitIdB;
public PatchScript(final Change.Key ck, final ChangeType ct, final String on,
final String nn, final FileMode om, final FileMode nm,
@@ -65,7 +67,8 @@
final List<Edit> e, final DisplayMethod ma, final DisplayMethod mb,
final String mta, final String mtb, final CommentDetail cd,
final List<Patch> hist, final boolean hf, final boolean id,
- final boolean idf, final boolean idt, boolean bin) {
+ final boolean idf, final boolean idt, boolean bin,
+ final String cma, final String cmb) {
changeId = ck;
changeType = ct;
oldName = on;
@@ -88,6 +91,8 @@
intralineFailure = idf;
intralineTimeout = idt;
binary = bin;
+ commitIdA = cma;
+ commitIdB = cmb;
}
protected PatchScript() {
@@ -200,4 +205,12 @@
public boolean isBinary() {
return binary;
}
+
+ public String getCommitIdA() {
+ return commitIdA;
+ }
+
+ public String getCommitIdB() {
+ return commitIdB;
+ }
}
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/PermissionRange.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/PermissionRange.java
index 7be8e4e..8d09b88 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/PermissionRange.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/PermissionRange.java
@@ -125,11 +125,15 @@
r.append(' ');
} else {
if (getMin() != getMax()) {
- if (0 <= getMin()) r.append('+');
+ if (0 <= getMin()) {
+ r.append('+');
+ }
r.append(getMin());
r.append("..");
}
- if (0 <= getMax()) r.append('+');
+ if (0 <= getMax()) {
+ r.append('+');
+ }
r.append(getMax());
r.append(' ');
}
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/PermissionRule.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/PermissionRule.java
index 3ba7adf..ec5ca06 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/PermissionRule.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/PermissionRule.java
@@ -126,8 +126,12 @@
@Override
public int compareTo(PermissionRule o) {
int cmp = action(this) - action(o);
- if (cmp == 0) cmp = range(o) - range(this);
- if (cmp == 0) cmp = group(this).compareTo(group(o));
+ if (cmp == 0) {
+ cmp = range(o) - range(this);
+ }
+ if (cmp == 0) {
+ cmp = group(this).compareTo(group(o));
+ }
return cmp;
}
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/errors/ProjectCreationFailedException.java b/gerrit-common/src/main/java/com/google/gerrit/common/errors/ProjectCreationFailedException.java
deleted file mode 100644
index 0437d77..0000000
--- a/gerrit-common/src/main/java/com/google/gerrit/common/errors/ProjectCreationFailedException.java
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (C) 2011 The Android Open Source Project
-//
-// 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.
-
-package com.google.gerrit.common.errors;
-
-/** Error indicating failed to create new project. */
-public class ProjectCreationFailedException extends Exception {
- private static final long serialVersionUID = 1L;
-
- public ProjectCreationFailedException(final String message) {
- this(message, null);
- }
-
- public ProjectCreationFailedException(final String message,
- final Throwable why) {
- super(message, why);
- }
-}
diff --git a/gerrit-extension-api/pom.xml b/gerrit-extension-api/pom.xml
index 38b802a..d0204e4 100644
--- a/gerrit-extension-api/pom.xml
+++ b/gerrit-extension-api/pom.xml
@@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-extension-api</artifactId>
- <version>2.11.1</version>
+ <version>2.12-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Gerrit Code Review - Extension API</name>
<description>API for Gerrit Extensions</description>
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/annotations/PluginData.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/annotations/PluginData.java
index 75238a8..4893beff 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/annotations/PluginData.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/annotations/PluginData.java
@@ -18,24 +18,25 @@
import com.google.inject.BindingAnnotation;
-import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
/**
* Local path where a plugin can store its own private data.
* <p>
* A plugin or extension may receive this string by Guice injection to discover
* a directory where it can store configuration or other data that is private:
+ * <p>
+ * This binding is on both {@link java.io.File} and {@link java.nio.file.Path},
+ * pointing to the same location. The {@code File} version should be considered
+ * deprecated and may be removed in a future version.
*
* <pre>
* {@literal @Inject}
- * MyType(@PluginData java.io.File myDir) {
- * new FileInputStream(new File(myDir, "my.config"));
+ * MyType(@PluginData java.nio.file.Path myDir) {
+ * this.in = Files.newInputStream(myDir.resolve("my.config"));
* }
* </pre>
*/
-@Target({ElementType.PARAMETER, ElementType.FIELD})
@Retention(RUNTIME)
@BindingAnnotation
public @interface PluginData {
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/GerritApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/GerritApi.java
index cc5807b..1435d9e 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/GerritApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/GerritApi.java
@@ -16,12 +16,14 @@
import com.google.gerrit.extensions.api.accounts.Accounts;
import com.google.gerrit.extensions.api.changes.Changes;
+import com.google.gerrit.extensions.api.groups.Groups;
import com.google.gerrit.extensions.api.projects.Projects;
import com.google.gerrit.extensions.restapi.NotImplementedException;
public interface GerritApi {
public Accounts accounts();
public Changes changes();
+ public Groups groups();
public Projects projects();
/**
@@ -40,6 +42,11 @@
}
@Override
+ public Groups groups() {
+ throw new NotImplementedException();
+ }
+
+ @Override
public Projects projects() {
throw new NotImplementedException();
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/Accounts.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/Accounts.java
index 71a93d3..32f8488 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/Accounts.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/Accounts.java
@@ -14,9 +14,12 @@
package com.google.gerrit.extensions.api.accounts;
+import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.restapi.NotImplementedException;
import com.google.gerrit.extensions.restapi.RestApiException;
+import java.util.List;
+
public interface Accounts {
/**
* Look up an account by ID.
@@ -42,6 +45,69 @@
AccountApi self() throws RestApiException;
/**
+ * Suggest users for a given query.
+ * <p>
+ * Example code:
+ * {@code suggestAccounts().withQuery("Reviewer").withLimit(5).get()}
+ *
+ * @return API for setting parameters and getting result.
+ */
+ SuggestAccountsRequest suggestAccounts() throws RestApiException;
+
+ /**
+ * Suggest users for a given query.
+ * <p>
+ * Shortcut API for {@code suggestAccounts().withQuery(String)}.
+ *
+ * @see #suggestAccounts()
+ */
+ SuggestAccountsRequest suggestAccounts(String query)
+ throws RestApiException;
+
+ /**
+ * API for setting parameters and getting result.
+ * Used for {@code suggestAccounts()}.
+ *
+ * @see #suggestAccounts()
+ */
+ public abstract class SuggestAccountsRequest {
+ private String query;
+ private int limit;
+
+ /**
+ * Executes query and returns a list of accounts.
+ */
+ public abstract List<AccountInfo> get() throws RestApiException;
+
+ /**
+ * Set query.
+ *
+ * @param query needs to be in human-readable form.
+ */
+ public SuggestAccountsRequest withQuery(String query) {
+ this.query = query;
+ return this;
+ }
+
+ /**
+ * Set limit for returned list of accounts.
+ * Optional; server-default is used when not provided.
+ */
+ public SuggestAccountsRequest withLimit(int limit) {
+ this.limit = limit;
+ return this;
+ }
+
+ public String getQuery() {
+ return query;
+ }
+
+ public int getLimit() {
+ return limit;
+ }
+ }
+
+ /**
* A default implementation which allows source compatibility
* when adding new methods to the interface.
**/
@@ -55,5 +121,16 @@
public AccountApi self() throws RestApiException {
throw new NotImplementedException();
}
+
+ @Override
+ public SuggestAccountsRequest suggestAccounts() throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public SuggestAccountsRequest suggestAccounts(String query)
+ throws RestApiException {
+ throw new NotImplementedException();
+ }
}
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
index 06f0a75..6781af2 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
@@ -16,6 +16,7 @@
import com.google.gerrit.extensions.client.ListChangesOption;
import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.extensions.common.CommentInfo;
import com.google.gerrit.extensions.common.EditInfo;
import com.google.gerrit.extensions.common.SuggestedReviewerInfo;
import com.google.gerrit.extensions.restapi.NotImplementedException;
@@ -23,6 +24,7 @@
import java.util.EnumSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
public interface ChangeApi {
@@ -106,6 +108,24 @@
*/
Set<String> getHashtags() throws RestApiException;
+ /**
+ * Get all published comments on a change.
+ *
+ * @return comments in a map keyed by path; comments have the {@code revision}
+ * field set to indicate their patch set.
+ * @throws RestApiException
+ */
+ Map<String, List<CommentInfo>> comments() throws RestApiException;
+
+ /**
+ * Get all draft comments for the current user on a change.
+ *
+ * @return drafts in a map keyed by path; comments have the {@code revision}
+ * field set to indicate their patch set.
+ * @throws RestApiException
+ */
+ Map<String, List<CommentInfo>> drafts() throws RestApiException;
+
ChangeInfo check() throws RestApiException;
ChangeInfo check(FixInput fix) throws RestApiException;
@@ -250,6 +270,16 @@
}
@Override
+ public Map<String, List<CommentInfo>> comments() throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public Map<String, List<CommentInfo>> drafts() throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
public ChangeInfo check() throws RestApiException {
throw new NotImplementedException();
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/Changes.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/Changes.java
index 8ab3080..da8aeb2 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/Changes.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/Changes.java
@@ -116,6 +116,23 @@
public EnumSet<ListChangesOption> getOptions() {
return options;
}
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(getClass().getSimpleName())
+ .append('{')
+ .append(query);
+ if (limit != 0) {
+ sb.append(", limit=").append(limit);
+ }
+ if (start != 0) {
+ sb.append(", start=").append(start);
+ }
+ if (!options.isEmpty()) {
+ sb.append("options=").append(options);
+ }
+ return sb.append('}').toString();
+ }
}
/**
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ReviewInput.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ReviewInput.java
index dd2ce92..2d2e4e9 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ReviewInput.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ReviewInput.java
@@ -61,7 +61,17 @@
public String onBehalfOf;
public static enum DraftHandling {
- DELETE, PUBLISH, KEEP
+ /** Delete pending drafts on this revision only. */
+ DELETE,
+
+ /** Publish pending drafts on this revision only. */
+ PUBLISH,
+
+ /** Leave pending drafts alone. */
+ KEEP,
+
+ /** Publish pending drafts on all revisions. */
+ PUBLISH_ALL_REVISIONS
}
public static enum NotifyHandling {
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
index b940cc9..3d1e3bd 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
@@ -14,6 +14,7 @@
package com.google.gerrit.extensions.api.changes;
+import com.google.gerrit.extensions.common.ActionInfo;
import com.google.gerrit.extensions.common.CommentInfo;
import com.google.gerrit.extensions.common.FileInfo;
import com.google.gerrit.extensions.common.MergeableInfo;
@@ -49,11 +50,16 @@
Map<String, List<CommentInfo>> comments() throws RestApiException;
Map<String, List<CommentInfo>> drafts() throws RestApiException;
+ List<CommentInfo> commentsAsList() throws RestApiException;
+ List<CommentInfo> draftsAsList() throws RestApiException;
+
DraftApi createDraft(DraftInput in) throws RestApiException;
DraftApi draft(String id) throws RestApiException;
CommentApi comment(String id) throws RestApiException;
+ Map<String, ActionInfo> actions() throws RestApiException;
+
/**
* A default implementation which allows source compatibility
* when adding new methods to the interface.
@@ -145,6 +151,16 @@
}
@Override
+ public List<CommentInfo> commentsAsList() throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public List<CommentInfo> draftsAsList() throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
public Map<String, List<CommentInfo>> drafts() throws RestApiException {
throw new NotImplementedException();
}
@@ -163,5 +179,10 @@
public CommentApi comment(String id) throws RestApiException {
throw new NotImplementedException();
}
+
+ @Override
+ public Map<String, ActionInfo> actions() throws RestApiException {
+ throw new NotImplementedException();
+ }
}
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/groups/GroupApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/groups/GroupApi.java
new file mode 100644
index 0000000..417e371
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/groups/GroupApi.java
@@ -0,0 +1,135 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.extensions.api.groups;
+
+import com.google.gerrit.extensions.common.AccountInfo;
+import com.google.gerrit.extensions.common.GroupInfo;
+import com.google.gerrit.extensions.common.GroupOptionsInfo;
+import com.google.gerrit.extensions.restapi.RestApiException;
+
+import java.util.List;
+
+public interface GroupApi {
+ /** @return group info with no {@code ListGroupsOption}s set. */
+ GroupInfo get() throws RestApiException;
+
+ /** @return group info with all {@code ListGroupsOption}s set. */
+ GroupInfo detail() throws RestApiException;
+
+ /** @return group name. */
+ String name() throws RestApiException;
+
+ /**
+ * Set group name.
+ *
+ * @param name new name.
+ * @throws RestApiException
+ */
+ void name(String name) throws RestApiException;
+
+ /** @return owning group info. */
+ GroupInfo owner() throws RestApiException;
+
+ /**
+ * Set group owner.
+ *
+ * @param owner identifier of new group owner.
+ * @throws RestApiException
+ */
+ void owner(String owner) throws RestApiException;
+
+ /** @return group description. */
+ String description() throws RestApiException;
+
+ /**
+ * Set group decsription.
+ *
+ * @param description new description.
+ * @throws RestApiException
+ */
+ void description(String description) throws RestApiException;
+
+ /** @return group options. */
+ GroupOptionsInfo options() throws RestApiException;
+
+ /**
+ * Set group options.
+ *
+ * @param options new options.
+ * @throws RestApiException
+ */
+ void options(GroupOptionsInfo options) throws RestApiException;
+
+ /**
+ * List group members, non-recursively.
+ *
+ * @return group members.
+ * @throws RestApiException
+ */
+ List<AccountInfo> members() throws RestApiException;
+
+ /**
+ * List group members.
+ *
+ * @param recursive whether to recursively included groups.
+ * @return group members.
+ * @throws RestApiException
+ */
+ List<AccountInfo> members(boolean recursive) throws RestApiException;
+
+ /**
+ * Add members to a group.
+ *
+ * @param members list of member identifiers, in any format accepted by
+ * {@link com.google.gerrit.extensions.api.accounts.Accounts#id(String)}
+ * @throws RestApiException
+ */
+ void addMembers(String... members) throws RestApiException;
+
+ /**
+ * Remove members from a group.
+ *
+ * @param members list of member identifiers, in any format accepted by
+ * {@link com.google.gerrit.extensions.api.accounts.Accounts#id(String)}
+ * @throws RestApiException
+ */
+ void removeMembers(String... members) throws RestApiException;
+
+ /**
+ * List included groups.
+ *
+ * @return included groups.
+ * @throws RestApiException
+ */
+ List<GroupInfo> includedGroups() throws RestApiException;
+
+ /**
+ * Add groups to be included in this one.
+ *
+ * @param groups list of group identifiers, in any format accepted by
+ * {@link Groups#id(String)}
+ * @throws RestApiException
+ */
+ void addGroups(String... groups) throws RestApiException;
+
+ /**
+ * Remove included groups from this one.
+ *
+ * @param groups list of group identifiers, in any format accepted by
+ * {@link Groups#id(String)}
+ * @throws RestApiException
+ */
+ void removeGroups(String... groups) throws RestApiException;
+}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/groups/GroupInput.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/groups/GroupInput.java
new file mode 100644
index 0000000..28665fe
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/groups/GroupInput.java
@@ -0,0 +1,22 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.extensions.api.groups;
+
+public class GroupInput {
+ public String name;
+ public String description;
+ public Boolean visibleToAll;
+ public String ownerId;
+}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/groups/Groups.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/groups/Groups.java
new file mode 100644
index 0000000..ab09e5f
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/groups/Groups.java
@@ -0,0 +1,167 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.extensions.api.groups;
+
+import com.google.gerrit.extensions.client.ListGroupsOption;
+import com.google.gerrit.extensions.common.GroupInfo;
+import com.google.gerrit.extensions.restapi.RestApiException;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Map;
+
+public interface Groups {
+ /**
+ * Look up a group by ID.
+ * <p>
+ * <strong>Note:</strong> This method eagerly reads the group. Methods that
+ * mutate the group do not necessarily re-read the group. Therefore, calling a
+ * getter method on an instance after calling a mutation method on that same
+ * instance is not guaranteed to reflect the mutation. It is not recommended
+ * to store references to {@code groupApi} instances.
+ *
+ * @param id any identifier supported by the REST API, including group name or
+ * UUID.
+ * @return API for accessing the group.
+ * @throws RestApiException if an error occurred.
+ */
+ GroupApi id(String id) throws RestApiException;
+
+ /** Create a new group with the given name and default options. */
+ GroupApi create(String name) throws RestApiException;
+
+ /** Create a new group. */
+ GroupApi create(GroupInput input) throws RestApiException;
+
+ /** @return new request for listing groups. */
+ ListRequest list();
+
+ public abstract class ListRequest {
+ private final EnumSet<ListGroupsOption> options =
+ EnumSet.noneOf(ListGroupsOption.class);
+ private final List<String> projects = new ArrayList<>();
+ private final List<String> groups = new ArrayList<>();
+
+ private boolean visibleToAll;
+ private String user;
+ private boolean owned;
+ private int limit;
+ private int start;
+ private String substring;
+
+ public List<GroupInfo> get() throws RestApiException {
+ Map<String, GroupInfo> map = getAsMap();
+ List<GroupInfo> result = new ArrayList<>(map.size());
+ for (Map.Entry<String, GroupInfo> e : map.entrySet()) {
+ // ListGroups "helpfully" nulls out names when converting to a map.
+ e.getValue().name = e.getKey();
+ result.add(e.getValue());
+ }
+ return Collections.unmodifiableList(result);
+ }
+
+ public abstract Map<String, GroupInfo> getAsMap() throws RestApiException;
+
+ public ListRequest addOption(ListGroupsOption option) {
+ options.add(option);
+ return this;
+ }
+
+ public ListRequest addOptions(ListGroupsOption... options) {
+ return addOptions(Arrays.asList(options));
+ }
+
+ public ListRequest addOptions(Iterable<ListGroupsOption> options) {
+ for (ListGroupsOption option : options) {
+ this.options.add(option);
+ }
+ return this;
+ }
+
+ public ListRequest withProject(String project) {
+ projects.add(project);
+ return this;
+ }
+
+ public ListRequest addGroup(String uuid) {
+ groups.add(uuid);
+ return this;
+ }
+
+ public ListRequest withVisibleToAll(boolean visible) {
+ visibleToAll = visible;
+ return this;
+ }
+
+ public ListRequest withUser(String user) {
+ this.user = user;
+ return this;
+ }
+
+ public ListRequest withLimit(int limit) {
+ this.limit = limit;
+ return this;
+ }
+
+ public ListRequest withStart(int start) {
+ this.start = start;
+ return this;
+ }
+
+ public ListRequest withSubstring(String substring) {
+ this.substring = substring;
+ return this;
+ }
+
+ public EnumSet<ListGroupsOption> getOptions() {
+ return options;
+ }
+
+ public List<String> getProjects() {
+ return Collections.unmodifiableList(projects);
+ }
+
+ public List<String> getGroups() {
+ return Collections.unmodifiableList(groups);
+ }
+
+ public boolean getVisibleToAll() {
+ return visibleToAll;
+ }
+
+ public String getUser() {
+ return user;
+ }
+
+ public boolean getOwned() {
+ return owned;
+ }
+
+ public int getLimit() {
+ return limit;
+ }
+
+ public int getStart() {
+ return start;
+ }
+
+ public String getSubstring() {
+ return substring;
+ }
+ }
+}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/BranchApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/BranchApi.java
index f88a2cb..91cb70e 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/BranchApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/BranchApi.java
@@ -20,6 +20,10 @@
public interface BranchApi {
BranchApi create(BranchInput in) throws RestApiException;
+ BranchInfo get() throws RestApiException;
+
+ void delete() throws RestApiException;
+
/**
* A default implementation which allows source compatibility
* when adding new methods to the interface.
@@ -29,5 +33,15 @@
public BranchApi create(BranchInput in) throws RestApiException {
throw new NotImplementedException();
}
+
+ @Override
+ public BranchInfo get() throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void delete() throws RestApiException {
+ throw new NotImplementedException();
+ }
}
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/BranchInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/BranchInfo.java
new file mode 100644
index 0000000..b973806
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/BranchInfo.java
@@ -0,0 +1,29 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.extensions.api.projects;
+
+import com.google.gerrit.extensions.common.ActionInfo;
+import com.google.gerrit.extensions.common.WebLinkInfo;
+
+import java.util.List;
+import java.util.Map;
+
+public class BranchInfo {
+ public String ref;
+ public String revision;
+ public Boolean canDelete;
+ public Map<String, ActionInfo> actions;
+ public List<WebLinkInfo> webLinks;
+}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ChildProjectApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ChildProjectApi.java
new file mode 100644
index 0000000..a930f0d
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ChildProjectApi.java
@@ -0,0 +1,40 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.extensions.api.projects;
+
+import com.google.gerrit.extensions.common.ProjectInfo;
+import com.google.gerrit.extensions.restapi.NotImplementedException;
+import com.google.gerrit.extensions.restapi.RestApiException;
+
+public interface ChildProjectApi {
+ ProjectInfo get() throws RestApiException;
+ ProjectInfo get(boolean recursive) throws RestApiException;
+
+ /**
+ * A default implementation which allows source compatibility
+ * when adding new methods to the interface.
+ **/
+ public class NotImplemented implements ChildProjectApi {
+ @Override
+ public ProjectInfo get() throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public ProjectInfo get(boolean recursive) throws RestApiException {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ProjectApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ProjectApi.java
index 07a48a1..102b1ce 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ProjectApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ProjectApi.java
@@ -18,10 +18,67 @@
import com.google.gerrit.extensions.restapi.NotImplementedException;
import com.google.gerrit.extensions.restapi.RestApiException;
+import java.util.List;
+
public interface ProjectApi {
ProjectApi create() throws RestApiException;
ProjectApi create(ProjectInput in) throws RestApiException;
- ProjectInfo get();
+ ProjectInfo get() throws RestApiException;
+
+ String description() throws RestApiException;
+ void description(PutDescriptionInput in) throws RestApiException;
+
+ ListBranchesRequest branches();
+
+ public abstract class ListBranchesRequest {
+ private int limit;
+ private int start;
+ private String substring;
+ private String regex;
+
+ public abstract List<BranchInfo> get() throws RestApiException;
+
+ public ListBranchesRequest withLimit(int limit) {
+ this.limit = limit;
+ return this;
+ }
+
+ public ListBranchesRequest withStart(int start) {
+ this.start = start;
+ return this;
+ }
+
+ public ListBranchesRequest withSubstring(String substring) {
+ this.substring = substring;
+ return this;
+ }
+
+ public ListBranchesRequest withRegex(String regex) {
+ this.regex = regex;
+ return this;
+ }
+
+ public int getLimit() {
+ return limit;
+ }
+
+ public int getStart() {
+ return start;
+ }
+
+ public String getSubstring() {
+ return substring;
+ }
+
+ public String getRegex() {
+ return regex;
+ }
+
+ }
+
+ List<ProjectInfo> children() throws RestApiException;
+ List<ProjectInfo> children(boolean recursive) throws RestApiException;
+ ChildProjectApi child(String name) throws RestApiException;
/**
* Look up a branch by refname.
@@ -33,9 +90,10 @@
* to store references to {@code BranchApi} instances.
*
* @param ref branch name, with or without "refs/heads/" prefix.
+ * @throws RestApiException if a problem occurred reading the project.
* @return API for accessing the branch.
*/
- BranchApi branch(String ref);
+ BranchApi branch(String ref) throws RestApiException;
/**
* A default implementation which allows source compatibility
@@ -53,12 +111,43 @@
}
@Override
- public ProjectInfo get() {
+ public ProjectInfo get() throws RestApiException {
throw new NotImplementedException();
}
@Override
- public BranchApi branch(String ref) {
+ public String description() throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void description(PutDescriptionInput in)
+ throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public ListBranchesRequest branches() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public List<ProjectInfo> children() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public List<ProjectInfo> children(boolean recursive) throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public ChildProjectApi child(String name) throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public BranchApi branch(String ref) throws RestApiException {
throw new NotImplementedException();
}
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/Projects.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/Projects.java
index 736d375..0e848b9 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/Projects.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/Projects.java
@@ -18,7 +18,11 @@
import com.google.gerrit.extensions.restapi.NotImplementedException;
import com.google.gerrit.extensions.restapi.RestApiException;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
public interface Projects {
/**
@@ -36,15 +40,54 @@
*/
ProjectApi name(String name) throws RestApiException;
+ /**
+ * Create a project using the default configuration.
+ *
+ * @param name project name.
+ * @return API for accessing the newly-created project.
+ * @throws RestApiException if an error occurred.
+ */
+ ProjectApi create(String name) throws RestApiException;
+
+ /**
+ * Create a project.
+ *
+ * @param in project creation input; name must be set.
+ * @return API for accessing the newly-created project.
+ * @throws RestApiException if an error occurred.
+ */
+ ProjectApi create(ProjectInput in) throws RestApiException;
+
ListRequest list();
public abstract class ListRequest {
+ public static enum FilterType {
+ CODE, PARENT_CANDIDATES, PERMISSIONS, ALL
+ }
+
+ private final List<String> branches = new ArrayList<>();
private boolean description;
private String prefix;
+ private String substring;
+ private String regex;
private int limit;
private int start;
+ private boolean showTree;
+ private FilterType type = FilterType.ALL;
- public abstract List<ProjectInfo> get() throws RestApiException;
+ public List<ProjectInfo> get() throws RestApiException {
+ Map<String, ProjectInfo> map = getAsMap();
+ List<ProjectInfo> result = new ArrayList<>(map.size());
+ for (Map.Entry<String, ProjectInfo> e : map.entrySet()) {
+ // ListProjects "helpfully" nulls out names when converting to a map.
+ e.getValue().name = e.getKey();
+ result.add(e.getValue());
+ }
+ return Collections.unmodifiableList(result);
+ }
+
+ public abstract SortedMap<String, ProjectInfo> getAsMap()
+ throws RestApiException;
public ListRequest withDescription(boolean description) {
this.description = description;
@@ -56,6 +99,16 @@
return this;
}
+ public ListRequest withSubstring(String substring) {
+ this.substring = substring;
+ return this;
+ }
+
+ public ListRequest withRegex(String regex) {
+ this.regex = regex;
+ return this;
+ }
+
public ListRequest withLimit(int limit) {
this.limit = limit;
return this;
@@ -66,6 +119,21 @@
return this;
}
+ public ListRequest addShowBranch(String branch) {
+ branches.add(branch);
+ return this;
+ }
+
+ public ListRequest withTree(boolean show) {
+ showTree = show;
+ return this;
+ }
+
+ public ListRequest withType(FilterType type) {
+ this.type = type != null ? type : FilterType.ALL;
+ return this;
+ }
+
public boolean getDescription() {
return description;
}
@@ -74,6 +142,14 @@
return prefix;
}
+ public String getSubstring() {
+ return substring;
+ }
+
+ public String getRegex() {
+ return regex;
+ }
+
public int getLimit() {
return limit;
}
@@ -81,6 +157,18 @@
public int getStart() {
return start;
}
+
+ public List<String> getBranches() {
+ return Collections.unmodifiableList(branches);
+ }
+
+ public boolean getShowTree() {
+ return showTree;
+ }
+
+ public FilterType getFilterType() {
+ return type;
+ }
}
/**
@@ -94,6 +182,16 @@
}
@Override
+ public ProjectApi create(ProjectInput in) throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public ProjectApi create(String name) throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
public ListRequest list() {
throw new NotImplementedException();
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/PutDescriptionInput.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/PutDescriptionInput.java
new file mode 100644
index 0000000..7ea9fb6
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/PutDescriptionInput.java
@@ -0,0 +1,23 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.extensions.api.projects;
+
+import com.google.gerrit.extensions.restapi.DefaultInput;
+
+public class PutDescriptionInput {
+ @DefaultInput
+ public String description;
+ public String commitMessage;
+}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/Comment.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/Comment.java
index e79df1c..b9863d7 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/Comment.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/Comment.java
@@ -17,6 +17,13 @@
import java.sql.Timestamp;
public abstract class Comment {
+ /**
+ * Patch set number containing this commit.
+ * <p>
+ * Only set in contexts where comments may come from multiple patch sets.
+ */
+ public Integer patchSet;
+
public String id;
public String path;
public Side side;
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/ListChangesOption.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/ListChangesOption.java
index 54617a7..5caa903 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/ListChangesOption.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/ListChangesOption.java
@@ -15,6 +15,7 @@
package com.google.gerrit.extensions.client;
import java.util.EnumSet;
+import java.util.Set;
/** Output options available for retrieval change details. */
public enum ListChangesOption {
@@ -58,7 +59,10 @@
CHECK(15),
/** Include allowed change actions client could perform. */
- CHANGE_ACTIONS(16);
+ CHANGE_ACTIONS(16),
+
+ /** Include a copy of commit messages including review footers. */
+ COMMIT_FOOTERS(17);
private final int value;
@@ -87,7 +91,7 @@
return r;
}
- public static int toBits(EnumSet<ListChangesOption> set) {
+ public static int toBits(Set<ListChangesOption> set) {
int r = 0;
for (ListChangesOption o : set) {
r |= 1 << o.value;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/groups/ListGroupsOption.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/ListGroupsOption.java
similarity index 96%
rename from gerrit-common/src/main/java/com/google/gerrit/common/groups/ListGroupsOption.java
rename to gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/ListGroupsOption.java
index 9da7fd5..d87f73e 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/groups/ListGroupsOption.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/ListGroupsOption.java
@@ -12,11 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.common.groups;
+package com.google.gerrit.extensions.client;
import java.util.EnumSet;
-
/** Output options available when using {@code /groups/} RPCs. */
public enum ListGroupsOption {
/** Return information on the direct group members. */
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ChangeType.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ChangeType.java
index d55580c..d26ea23 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ChangeType.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ChangeType.java
@@ -32,5 +32,5 @@
COPIED,
/** Sufficient amount of content changed to claim the file was rewritten. */
- REWRITE;
+ REWRITE
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/DiffInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/DiffInfo.java
index 62b1dc7..58b2d39 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/DiffInfo.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/DiffInfo.java
@@ -42,6 +42,8 @@
}
public static class FileMeta {
+ // The ID of the commit containing the file
+ public transient String commitId;
// The name of the file
public String name;
// The content type of the file
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/GroupInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/GroupInfo.java
new file mode 100644
index 0000000..f956a03
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/GroupInfo.java
@@ -0,0 +1,32 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.extensions.common;
+
+import java.util.List;
+
+public class GroupInfo extends GroupBaseInfo {
+ public String url;
+ public GroupOptionsInfo options;
+
+ // These fields are only supplied for internal groups.
+ public String description;
+ public Integer groupId;
+ public String owner;
+ public String ownerId;
+
+ // These fields are only supplied for internal groups, and only if requested.
+ public List<AccountInfo> members;
+ public List<GroupInfo> includes;
+}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/GroupOptionsInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/GroupOptionsInfo.java
new file mode 100644
index 0000000..074e1a4
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/GroupOptionsInfo.java
@@ -0,0 +1,19 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.extensions.common;
+
+public class GroupOptionsInfo {
+ public Boolean visibleToAll;
+}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ProblemInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ProblemInfo.java
index a117d07..d04b346 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ProblemInfo.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ProblemInfo.java
@@ -16,7 +16,7 @@
public class ProblemInfo {
public static enum Status {
- FIXED, FIX_FAILED;
+ FIXED, FIX_FAILED
}
public String message;
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/RevisionInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/RevisionInfo.java
index 4b8eec1..7c71ba3 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/RevisionInfo.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/RevisionInfo.java
@@ -29,4 +29,5 @@
public CommitInfo commit;
public Map<String, FileInfo> files;
public Map<String, ActionInfo> actions;
+ public String commitWithFooters;
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/GarbageCollectorListener.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/GarbageCollectorListener.java
new file mode 100644
index 0000000..eb223c6
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/GarbageCollectorListener.java
@@ -0,0 +1,40 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.extensions.events;
+
+import com.google.gerrit.extensions.annotations.ExtensionPoint;
+
+import java.util.Properties;
+
+/**
+ * Notified whenever the garbage collector has run successfully on a project.
+ */
+@ExtensionPoint
+public interface GarbageCollectorListener {
+ public interface Event {
+ /** @return The name of the project that has been garbage collected. */
+ String getProjectName();
+
+ /**
+ * Properties describing the result of the garbage collection performed by
+ * JGit
+ *
+ * @see <a href="http://download.eclipse.org/jgit/site/3.7.0.201502260915-r/apidocs/org/eclipse/jgit/api/GarbageCollectCommand.html#call%28%29">GarbageCollectCommand</a>
+ */
+ Properties getStatistics();
+ }
+
+ void onGarbageCollected(Event event);
+}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/GitReferenceUpdatedListener.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/GitReferenceUpdatedListener.java
index 49a697e..a838baf 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/GitReferenceUpdatedListener.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/GitReferenceUpdatedListener.java
@@ -25,6 +25,9 @@
String getRefName();
String getOldObjectId();
String getNewObjectId();
+ boolean isCreate();
+ boolean isDelete();
+ boolean isNonFastForward();
}
void onGitReferenceUpdated(Event event);
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicItem.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicItem.java
index 1388637..7de740dc 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicItem.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicItem.java
@@ -67,7 +67,9 @@
* <p>
* Items must be defined in a Guice module before they can be bound:
* <pre>
+ * {@code
* DynamicSet.itemOf(binder(), new TypeLiteral<Thing<Foo>>() {});
+ * }
* </pre>
*
* @param binder a new binder created in the module.
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicMap.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicMap.java
index abf944a..b777899 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicMap.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicMap.java
@@ -67,10 +67,12 @@
* Maps must be defined in a Guice module before they can be bound:
*
* <pre>
+ * {@code
* DynamicMap.mapOf(binder(), new TypeLiteral<Thing<Bar>>(){});
* bind(new TypeLiteral<Thing<Bar>>() {})
* .annotatedWith(Exports.named("foo"))
* .to(Impl.class);
+ * }
* </pre>
*
* @param binder a new binder created in the module.
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicSet.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicSet.java
index 82613c7..8bc39a5 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicSet.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicSet.java
@@ -61,7 +61,9 @@
* <p>
* Sets must be defined in a Guice module before they can be bound:
* <pre>
+ * {@code
* DynamicSet.setOf(binder(), new TypeLiteral<Thing<Foo>>() {});
+ * }
* </pre>
*
* @param binder a new binder created in the module.
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/BinaryResult.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/BinaryResult.java
index 18f356b..92fefed 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/BinaryResult.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/BinaryResult.java
@@ -196,8 +196,9 @@
} catch (UnsupportedCharsetException | CharacterCodingException e) {
// Fallback to ISO-8850-1 style encoding.
StringBuilder r = new StringBuilder(data.length);
- for (byte b : data)
- r.append((char) (b & 0xff));
+ for (byte b : data) {
+ r.append((char) (b & 0xff));
+ }
return r.toString();
}
}
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyHelpPopup.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyHelpPopup.java
index b015274..191ffd7 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyHelpPopup.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyHelpPopup.java
@@ -114,7 +114,7 @@
}
private void populate(final Grid lists) {
- int end[] = new int[5];
+ int[] end = new int[5];
int column = 0;
for (final KeyCommandSet set : combinedSetsByName()) {
int row = end[column];
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/linker/server/UserAgentRule.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/linker/server/UserAgentRule.java
index eb87e7f..6c820a8 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/linker/server/UserAgentRule.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/linker/server/UserAgentRule.java
@@ -67,9 +67,6 @@
if (v >= 8000) {
return "ie8";
}
- if (v >= 6000) {
- return "ie6";
- }
}
return null;
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/SafeHtmlBuilder.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/SafeHtmlBuilder.java
index 69da38d..0e7f7eb 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/SafeHtmlBuilder.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/SafeHtmlBuilder.java
@@ -162,7 +162,7 @@
}
/**
- * Open an element, appending "<tagName>" to the buffer.
+ * Open an element, appending "{@code <tagName>}" to the buffer.
* <p>
* After the element is open the attributes may be manipulated until the next
* {@code append}, {@code openElement}, {@code closeSelf} or
diff --git a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/Resources.java b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/Resources.java
index c4e2167..0db7ea4 100644
--- a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/Resources.java
+++ b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/Resources.java
@@ -18,90 +18,90 @@
import com.google.gwt.resources.client.ImageResource;
public interface Resources extends ClientBundle {
+ @Source("addFileComment.png")
+ public ImageResource addFileComment();
+
+ @Source("arrowDown.png")
+ public ImageResource arrowDown();
+
@Source("arrowRight.png")
public ImageResource arrowRight();
@Source("arrowUp.png")
public ImageResource arrowUp();
- @Source("arrowDown.png")
- public ImageResource arrowDown();
-
- @Source("editText.png")
- public ImageResource edit();
-
- @Source("mediaFloppy.png")
- public ImageResource save();
-
- @Source("starOpen.png")
- public ImageResource starOpen();
-
- @Source("starFilled.png")
- public ImageResource starFilled();
-
- @Source("greenCheck.png")
- public ImageResource greenCheck();
-
- @Source("redNot.png")
- public ImageResource redNot();
-
- @Source("editUndo.png")
- public ImageResource editUndo();
-
- @Source("downloadIcon.png")
- public ImageResource downloadIcon();
-
- @Source("queryIcon.png")
- public ImageResource queryIcon();
-
- @Source("addFileComment.png")
- public ImageResource addFileComment();
-
- @Source("diffy26.png")
- public ImageResource gerritAvatar26();
-
- @Source("draftComments.png")
- public ImageResource draftComments();
-
- @Source("readOnly.png")
- public ImageResource readOnly();
-
- @Source("gear.png")
- public ImageResource gear();
-
- @Source("info.png")
- public ImageResource info();
-
- @Source("warning.png")
- public ImageResource warning();
-
- @Source("listAdd.png")
- public ImageResource listAdd();
-
- @Source("merge.png")
- public ImageResource merge();
+ @Source("deleteHover.png")
+ public ImageResource deleteHover();
@Source("deleteNormal.png")
public ImageResource deleteNormal();
- @Source("deleteHover.png")
- public ImageResource deleteHover();
+ @Source("diffy26.png")
+ public ImageResource gerritAvatar26();
- @Source("undoNormal.png")
- public ImageResource undoNormal();
+ @Source("downloadIcon.png")
+ public ImageResource downloadIcon();
- @Source("goPrev.png")
- public ImageResource goPrev();
+ @Source("draftComments.png")
+ public ImageResource draftComments();
+
+ @Source("editText.png")
+ public ImageResource edit();
+
+ @Source("editUndo.png")
+ public ImageResource editUndo();
+
+ @Source("gear.png")
+ public ImageResource gear();
@Source("goNext.png")
public ImageResource goNext();
+ @Source("goPrev.png")
+ public ImageResource goPrev();
+
@Source("goUp.png")
public ImageResource goUp();
+ @Source("greenCheck.png")
+ public ImageResource greenCheck();
+
+ @Source("info.png")
+ public ImageResource info();
+
+ @Source("listAdd.png")
+ public ImageResource listAdd();
+
+ @Source("mediaFloppy.png")
+ public ImageResource save();
+
+ @Source("merge.png")
+ public ImageResource merge();
+
+ @Source("queryIcon.png")
+ public ImageResource queryIcon();
+
+ @Source("readOnly.png")
+ public ImageResource readOnly();
+
+ @Source("redNot.png")
+ public ImageResource redNot();
+
@Source("sideBySideDiff.png")
public ImageResource sideBySideDiff();
+ @Source("starFilled.png")
+ public ImageResource starFilled();
+
+ @Source("starOpen.png")
+ public ImageResource starOpen();
+
+ @Source("undoNormal.png")
+ public ImageResource undoNormal();
+
@Source("unifiedDiff.png")
public ImageResource unifiedDiff();
+
+ @Source("warning.png")
+ public ImageResource warning();
}
diff --git a/gerrit-gwtui/BUCK b/gerrit-gwtui/BUCK
index aad5e0b..9eb0bf6 100644
--- a/gerrit-gwtui/BUCK
+++ b/gerrit-gwtui/BUCK
@@ -2,6 +2,7 @@
include_defs('//tools/gwt-constants.defs')
from multiprocessing import cpu_count
+CPU_COUNT = cpu_count()
DEPS = GWT_COMMON_DEPS + [
'//gerrit-gwtexpui:CSS',
'//lib:gwtjsonrpc',
@@ -29,8 +30,8 @@
name = 'ui_opt',
modules = [MODULE],
module_deps = [':ui_module'],
- deps = DEPS + [':ui_dbg'],
- local_workers = cpu_count(),
+ deps = DEPS + ([':ui_dbg'] if CPU_COUNT < 8 else []),
+ local_workers = CPU_COUNT,
strict = True,
experimental_args = GWT_COMPILER_ARGS,
vm_args = GWT_JVM_ARGS,
@@ -41,7 +42,7 @@
modules = [MODULE],
module_deps = [':ui_module'],
deps = DEPS + [':ui_dbg'],
- local_workers = cpu_count(),
+ local_workers = CPU_COUNT,
strict = True,
experimental_args = GWT_COMPILER_ARGS + ['-compileReport'],
vm_args = GWT_JVM_ARGS,
@@ -54,7 +55,7 @@
optimize = 0,
module_deps = [':ui_module'],
deps = DEPS,
- local_workers = cpu_count(),
+ local_workers = CPU_COUNT,
strict = True,
experimental_args = GWT_COMPILER_ARGS,
vm_args = GWT_JVM_ARGS,
diff --git a/gerrit-gwtui/gwt.defs b/gerrit-gwtui/gwt.defs
index cd206c0..0e5928d 100644
--- a/gerrit-gwtui/gwt.defs
+++ b/gerrit-gwtui/gwt.defs
@@ -17,7 +17,7 @@
'firefox',
'gecko1_8',
'safari',
- 'msie', 'ie6', 'ie8', 'ie9',
+ 'msie', 'ie8', 'ie9',
]
ALIASES = {
'chrome': 'safari',
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/GerritGwtUI.gwt.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/GerritGwtUI.gwt.xml
index fd717ee..0f5065f 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/GerritGwtUI.gwt.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/GerritGwtUI.gwt.xml
@@ -40,5 +40,8 @@
<set-property name='gwt.logging.logLevel' value='SEVERE'/>
+ <!-- Disable GSS -->
+ <set-configuration-property name='CssResource.enableGss' value='false'/>
+
<entry-point class='com.google.gerrit.client.Gerrit'/>
</module>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/UserAgent.gwt.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/UserAgent.gwt.xml
index e6f3acb..c02518b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/UserAgent.gwt.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/UserAgent.gwt.xml
@@ -21,10 +21,9 @@
<when-property-is name="user.agent" value="gecko1_8" />
</replace-with>
- <replace-with class="com.google.gerrit.client.ui.FancyFlexTableImplIE6">
+ <replace-with class="com.google.gerrit.client.ui.FancyFlexTableImplIE8">
<when-type-is class="com.google.gerrit.client.ui.FancyFlexTableImpl" />
<any>
- <when-property-is name="user.agent" value="ie6"/>
<when-property-is name="user.agent" value="ie8"/>
</any>
</replace-with>
@@ -32,7 +31,6 @@
<replace-with class="com.google.gerrit.client.Themer.ThemerIE">
<when-type-is class="com.google.gerrit.client.Themer" />
<any>
- <when-property-is name="user.agent" value="ie6"/>
<when-property-is name="user.agent" value="ie8"/>
<when-property-is name="user.agent" value="ie9"/>
<when-property-is name="user.agent" value="ie10"/>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/AvatarImage.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/AvatarImage.java
index 053999a..7f17f4f 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/AvatarImage.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/AvatarImage.java
@@ -72,7 +72,7 @@
} else if (isGerritServer(account)) {
setVisible(true);
setResource(Gerrit.RESOURCES.gerritAvatar26());
- } else if (account.has_avatar_info()) {
+ } else if (account.hasAvatarInfo()) {
setVisible(false);
AvatarInfo info = account.avatar(size);
if (info != null) {
@@ -121,7 +121,7 @@
}
private static boolean isGerritServer(AccountInfo account) {
- return account._account_id() == 0
+ return account._accountId() == 0
&& Util.C.messageNoAuthor().equals(account.name());
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
index e2bf142..e43139c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
@@ -341,7 +341,7 @@
private static String legacyChange(final String token) {
final String s = skip(token);
- final String t[] = s.split(",", 2);
+ final String[] t = s.split(",", 2);
if (t.length > 1 && matchPrefix("patchset=", t[1])) {
return PageLinks.toChange(PatchSet.Id.parse(t[0] + "," + skip(t[1])));
}
@@ -695,7 +695,7 @@
}
if (matchExact(SETTINGS_AGREEMENTS, token)
- && Gerrit.getConfig().isUseContributorAgreements()) {
+ && Gerrit.info().auth().useContributorAgreements()) {
return new MyAgreementsScreen();
}
@@ -707,11 +707,13 @@
return new RegisterScreen("/" + skip(token));
}
- if (matchPrefix("/VE/", token) || matchPrefix("VE,", token))
+ if (matchPrefix("/VE/", token) || matchPrefix("VE,", token)) {
return new ValidateEmailScreen(skip(token));
+ }
- if (matchExact(SETTINGS_NEW_AGREEMENT, token))
+ if (matchExact(SETTINGS_NEW_AGREEMENT, token)) {
return new NewAgreementScreen();
+ }
if (matchPrefix(SETTINGS_NEW_AGREEMENT + "/", token)) {
return new NewAgreementScreen(skip(token));
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/FormatUtil.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/FormatUtil.java
index 5b51b48..30980e1 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/FormatUtil.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/FormatUtil.java
@@ -144,8 +144,8 @@
StringBuilder b = new StringBuilder().append(name);
if (info.email() != null) {
b.append(" <").append(info.email()).append(">");
- } else if (info._account_id() > 0) {
- b.append(" (").append(info._account_id()).append(")");
+ } else if (info._accountId() > 0) {
+ b.append(" (").append(info._accountId()).append(")");
}
return b.toString();
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
index 296f93f..c176a09 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
@@ -28,6 +28,7 @@
import com.google.gerrit.client.changes.ChangeConstants;
import com.google.gerrit.client.changes.ChangeListScreen;
import com.google.gerrit.client.config.ConfigServerApi;
+import com.google.gerrit.client.config.ServerInfo;
import com.google.gerrit.client.extensions.TopMenu;
import com.google.gerrit.client.extensions.TopMenuItem;
import com.google.gerrit.client.extensions.TopMenuList;
@@ -49,7 +50,6 @@
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountDiffPreference;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
-import com.google.gerrit.reviewdb.client.AuthType;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gwt.aria.client.Roles;
import com.google.gwt.core.client.EntryPoint;
@@ -101,11 +101,12 @@
GWT.create(GerritResources.class);
public static final SystemInfoService SYSTEM_SVC;
public static final EventBus EVENT_BUS = GWT.create(SimpleEventBus.class);
- public static Themer THEMER = GWT.create(Themer.class);
+ public static final Themer THEMER = GWT.create(Themer.class);
public static final String PROJECT_NAME_MENU_VAR = "${projectName}";
private static String myHost;
private static GerritConfig myConfig;
+ private static ServerInfo myServerInfo;
private static HostPageData.Theme myTheme;
private static Account myAccount;
private static String defaultScreenToken;
@@ -288,6 +289,11 @@
return myConfig;
}
+ /** Get the public configuration data used by this Gerrit instance. */
+ public static ServerInfo info() {
+ return myServerInfo;
+ }
+
public static GitwebLink getGitwebLink() {
GitwebConfig gw = getConfig().getGitwebLink();
return gw != null && gw.type != null ? new GitwebLink(gw) : null;
@@ -426,8 +432,16 @@
initHostname();
Window.setTitle(M.windowTitle1(myHost));
- final HostPageDataService hpd = GWT.create(HostPageDataService.class);
- hpd.load(new GerritCallback<HostPageData>() {
+ RpcStatus.INSTANCE = new RpcStatus();
+ CallbackGroup cbg = new CallbackGroup();
+ ConfigServerApi.serverInfo(cbg.add(new GerritCallback<ServerInfo>() {
+ @Override
+ public void onSuccess(ServerInfo info) {
+ myServerInfo = info;
+ }
+ }));
+ HostPageDataService hpd = GWT.create(HostPageDataService.class);
+ hpd.load(cbg.addFinal(new GerritCallback<HostPageData>() {
@Override
public void onSuccess(final HostPageData result) {
Document.get().getElementById("gerrit_hostpagedata").removeFromParent();
@@ -444,7 +458,7 @@
}
onModuleLoad2(result);
}
- });
+ }));
}
private static void initHostname() {
@@ -538,7 +552,6 @@
};
gBody.add(body);
- RpcStatus.INSTANCE = new RpcStatus();
JsonUtil.addRpcStartHandler(RpcStatus.INSTANCE);
JsonUtil.addRpcCompleteHandler(RpcStatus.INSTANCE);
JsonUtil.setDefaultXsrfManager(new XsrfManager() {
@@ -579,6 +592,7 @@
AccountApi.self().view("preferences").get(cbg.add(createMyMenuBarCallback()));
}
PluginLoader.load(hpd.plugins,
+ hpd.pluginsLoadTimeout,
cbg.addFinal(new GerritCallback<VoidResult>() {
@Override
public void onSuccess(VoidResult result) {
@@ -704,9 +718,9 @@
}
if (signedIn) {
- whoAmI(cfg.getAuthType() != AuthType.CLIENT_SSL_CERT_LDAP);
+ whoAmI(!info().auth().isClientSslCertLdap());
} else {
- switch (cfg.getAuthType()) {
+ switch (info().auth().authType()) {
case CLIENT_SSL_CERT_LDAP:
break;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/MessageOfTheDayBar.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/MessageOfTheDayBar.ui.xml
index ff50ec6..36d08b1 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/MessageOfTheDayBar.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/MessageOfTheDayBar.ui.xml
@@ -18,7 +18,7 @@
xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:c='urn:import:com.google.gwtexpui.globalkey.client'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
- <ui:style>
+ <ui:style gss='false'>
.popup {
position: fixed;
top: 5px;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/RelativeDateFormatter.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/RelativeDateFormatter.java
index 5fc8cb3..443a6a8 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/RelativeDateFormatter.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/RelativeDateFormatter.java
@@ -47,7 +47,9 @@
long ageMillis = (new Date()).getTime() - when.getTime();
// shouldn't happen in a perfect world
- if (ageMillis < 0) return Util.C.inTheFuture();
+ if (ageMillis < 0) {
+ return Util.C.inTheFuture();
+ }
// seconds
if (ageMillis < upperLimit(MINUTE_IN_MILLIS)) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchPanel.java
index d5805ef..94198cb 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchPanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchPanel.java
@@ -58,11 +58,12 @@
final SuggestBox suggestBox = new SuggestBox(
new RemoteSuggestOracle(new SearchSuggestOracle()),
searchBox, suggestionDisplay);
- searchBox.setStyleName("gwt-TextBox");
+ searchBox.setStyleName("searchTextBox");
searchBox.setVisibleLength(70);
searchBox.setHintText(Gerrit.C.searchHint());
final Button searchButton = new Button(Gerrit.C.searchButton());
+ searchButton.setStyleName("searchButton");
searchButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/UserPopupPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/UserPopupPanel.java
index 90348db..c8bb731 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/UserPopupPanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/UserPopupPanel.java
@@ -16,7 +16,6 @@
import com.google.gerrit.client.account.AccountInfo;
import com.google.gerrit.client.ui.InlineHyperlink;
-import com.google.gerrit.reviewdb.client.AuthType;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.AnchorElement;
import com.google.gwt.dom.client.Element;
@@ -53,8 +52,8 @@
if (showSettingsLink) {
if (Gerrit.getConfig().getSwitchAccountUrl() != null) {
switchAccount.setHref(Gerrit.getConfig().getSwitchAccountUrl());
- } else if (Gerrit.getConfig().getAuthType() == AuthType.DEVELOPMENT_BECOME_ANY_ACCOUNT
- || Gerrit.getConfig().getAuthType() == AuthType.OPENID) {
+ } else if (Gerrit.info().auth().isDev()
+ || Gerrit.info().auth().isOpenId()) {
switchAccount.setHref(Gerrit.selfRedirect("/login/"));
} else {
switchAccount.removeFromParent();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/UserPopupPanel.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/UserPopupPanel.ui.xml
index cd51485..8f5073d 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/UserPopupPanel.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/UserPopupPanel.ui.xml
@@ -19,7 +19,7 @@
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:gerrit='urn:import:com.google.gerrit.client'
xmlns:u='urn:import:com.google.gerrit.client.ui'>
- <ui:style>
+ <ui:style gss='false'>
.panel {
padding: 8px;
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountInfo.java
index 1127374..36fa98d 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountInfo.java
@@ -18,7 +18,7 @@
import com.google.gwt.core.client.JsArray;
public class AccountInfo extends JavaScriptObject {
- public final native int _account_id() /*-{ return this._account_id || 0; }-*/;
+ public final native int _accountId() /*-{ return this._account_id || 0; }-*/;
public final native String name() /*-{ return this.name; }-*/;
public final native String email() /*-{ return this.email; }-*/;
public final native String username() /*-{ return this.username; }-*/;
@@ -29,7 +29,7 @@
* available, such as when no plugin is installed. This method returns
* false if the server did not check on avatars for the account.
*/
- public final native boolean has_avatar_info()
+ public final native boolean hasAvatarInfo()
/*-{ return this.hasOwnProperty('avatars') }-*/;
public final AvatarInfo avatar(int sz) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/ContactPanelFull.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/ContactPanelFull.java
index 4b8f0e2..33d11a8 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/ContactPanelFull.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/ContactPanelFull.java
@@ -65,7 +65,7 @@
hasContact.setStyleName(Gerrit.RESOURCES.css().accountContactOnFile());
hasContact.setVisible(false);
- if (Gerrit.getConfig().isUseContactInfo()) {
+ if (Gerrit.info().hasContactStore()) {
body.add(privhtml);
body.add(hasContact);
body.add(infoSecure);
@@ -116,7 +116,7 @@
@Override
ContactInformation toContactInformation() {
final ContactInformation info;
- if (Gerrit.getConfig().isUseContactInfo()) {
+ if (Gerrit.info().hasContactStore()) {
info = new ContactInformation();
info.setAddress(addressTxt.getText());
info.setCountry(countryTxt.getText());
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/ContactPanelShort.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/ContactPanelShort.java
index b5fe70f..2d9aa73 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/ContactPanelShort.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/ContactPanelShort.java
@@ -23,7 +23,6 @@
import com.google.gerrit.common.errors.EmailException;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Account.FieldName;
-import com.google.gerrit.reviewdb.client.AuthType;
import com.google.gerrit.reviewdb.client.ContactInformation;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.event.dom.client.ChangeEvent;
@@ -48,7 +47,8 @@
class ContactPanelShort extends Composite {
protected final FlowPanel body;
- protected int labelIdx, fieldIdx;
+ protected int labelIdx;
+ protected int fieldIdx;
protected Button save;
private String currentEmail;
@@ -100,7 +100,7 @@
}
int row = 0;
- if (!Gerrit.getConfig().canEdit(FieldName.USER_NAME)
+ if (!Gerrit.info().auth().canEdit(FieldName.USER_NAME)
&& Gerrit.getConfig().siteHasUsernames()) {
infoPlainText.resizeRows(infoPlainText.getRowCount() + 1);
row(infoPlainText, row++, Util.C.userName(), new UsernameField());
@@ -167,11 +167,11 @@
}
private boolean canEditFullName() {
- return Gerrit.getConfig().canEdit(Account.FieldName.FULL_NAME);
+ return Gerrit.info().auth().canEdit(Account.FieldName.FULL_NAME);
}
private boolean canRegisterNewEmail() {
- return Gerrit.getConfig().canEdit(Account.FieldName.REGISTER_NEW_EMAIL);
+ return Gerrit.info().auth().canEdit(Account.FieldName.REGISTER_NEW_EMAIL);
}
void hideSaveButton() {
@@ -274,7 +274,7 @@
@Override
public void onSuccess(EmailInfo result) {
box.hide();
- if (Gerrit.getConfig().getAuthType() == AuthType.DEVELOPMENT_BECOME_ANY_ACCOUNT) {
+ if (Gerrit.info().auth().isDev()) {
currentEmail = addr;
if (emailPick.getItemCount() == 0) {
final Account me = Gerrit.getUserAccount();
@@ -324,7 +324,7 @@
buttons.add(register);
buttons.add(cancel);
- if (Gerrit.getConfig().getAuthType() != AuthType.DEVELOPMENT_BECOME_ANY_ACCOUNT) {
+ if (!Gerrit.info().auth().isDev()) {
body.add(new HTML(Util.C.descRegisterNewEmail()));
}
body.add(inEmail);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/DiffPreferences.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/DiffPreferences.java
index 292e0b9..54541e4 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/DiffPreferences.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/DiffPreferences.java
@@ -68,12 +68,44 @@
public final void ignoreWhitespace(Whitespace i) {
setIgnoreWhitespaceRaw(i.toString());
}
- private final native void setIgnoreWhitespaceRaw(String i) /*-{ this.ignore_whitespace = i }-*/;
public final void theme(Theme i) {
setThemeRaw(i != null ? i.toString() : Theme.DEFAULT.toString());
}
- private final native void setThemeRaw(String i) /*-{ this.theme = i }-*/;
+
+ public final void showLineNumbers(boolean s) {
+ hideLineNumbers(!s);
+ }
+
+ public final Whitespace ignoreWhitespace() {
+ String s = ignoreWhitespaceRaw();
+ return s != null ? Whitespace.valueOf(s) : Whitespace.IGNORE_NONE;
+ }
+
+ public final Theme theme() {
+ String s = themeRaw();
+ return s != null ? Theme.valueOf(s) : Theme.DEFAULT;
+ }
+
+ public final int tabSize() {
+ return get("tab_size", 8);
+ }
+
+ public final int context() {
+ return get("context", 10);
+ }
+
+ public final int lineLength() {
+ return get("line_length", 100);
+ }
+
+ public final boolean showLineNumbers() {
+ return !hideLineNumbers();
+ }
+
+ public final boolean autoReview() {
+ return !manualReview();
+ }
public final native void tabSize(int t) /*-{ this.tab_size = t }-*/;
public final native void lineLength(int c) /*-{ this.line_length = c }-*/;
@@ -90,23 +122,6 @@
public final native void manualReview(boolean r) /*-{ this.manual_review = r }-*/;
public final native void renderEntireFile(boolean r) /*-{ this.render_entire_file = r }-*/;
public final native void hideEmptyPane(boolean s) /*-{ this.hide_empty_pane = s }-*/;
- public final void showLineNumbers(boolean s) { hideLineNumbers(!s); }
-
- public final Whitespace ignoreWhitespace() {
- String s = ignoreWhitespaceRaw();
- return s != null ? Whitespace.valueOf(s) : Whitespace.IGNORE_NONE;
- }
- private final native String ignoreWhitespaceRaw() /*-{ return this.ignore_whitespace }-*/;
-
- public final Theme theme() {
- String s = themeRaw();
- return s != null ? Theme.valueOf(s) : Theme.DEFAULT;
- }
- private final native String themeRaw() /*-{ return this.theme }-*/;
-
- public final int tabSize() {return get("tab_size", 8); }
- public final int context() {return get("context", 10); }
- public final int lineLength() {return get("line_length", 100); }
public final native boolean intralineDifference() /*-{ return this.intraline_difference || false }-*/;
public final native boolean showLineEndings() /*-{ return this.show_line_endings || false }-*/;
public final native boolean showTabs() /*-{ return this.show_tabs || false }-*/;
@@ -119,11 +134,12 @@
public final native boolean manualReview() /*-{ return this.manual_review || false }-*/;
public final native boolean renderEntireFile() /*-{ return this.render_entire_file || false }-*/;
public final native boolean hideEmptyPane() /*-{ return this.hide_empty_pane || false }-*/;
- public final boolean showLineNumbers() { return !hideLineNumbers(); }
- public final boolean autoReview() { return !manualReview(); }
- private final native int get(String n, int d)
- /*-{ return this.hasOwnProperty(n) ? this[n] : d }-*/;
+ private final native void setThemeRaw(String i) /*-{ this.theme = i }-*/;
+ private final native void setIgnoreWhitespaceRaw(String i) /*-{ this.ignore_whitespace = i }-*/;
+ private final native String ignoreWhitespaceRaw() /*-{ return this.ignore_whitespace }-*/;
+ private final native String themeRaw() /*-{ return this.theme }-*/;
+ private final native int get(String n, int d) /*-{ return this.hasOwnProperty(n) ? this[n] : d }-*/;
protected DiffPreferences() {
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyAgreementsScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyAgreementsScreen.java
index 0908f6b..308cf30 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyAgreementsScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyAgreementsScreen.java
@@ -47,7 +47,7 @@
});
}
- private class AgreementTable extends FancyFlexTable<ContributorAgreement> {
+ private static class AgreementTable extends FancyFlexTable<ContributorAgreement> {
AgreementTable() {
table.setWidth("");
table.setText(0, 1, Util.C.agreementStatus());
@@ -61,8 +61,9 @@
}
void display(final AgreementInfo result) {
- while (1 < table.getRowCount())
+ while (1 < table.getRowCount()) {
table.removeRow(table.getRowCount() - 1);
+ }
for (final String k : result.accepted) {
addOne(result, k);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyIdentitiesScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyIdentitiesScreen.java
index 1191696..b638575 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyIdentitiesScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyIdentitiesScreen.java
@@ -21,7 +21,6 @@
import com.google.gerrit.client.ui.FancyFlexTable;
import com.google.gerrit.common.auth.openid.OpenIdUrls;
import com.google.gerrit.reviewdb.client.AccountExternalId;
-import com.google.gerrit.reviewdb.client.AuthType;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
@@ -59,8 +58,8 @@
});
add(deleteIdentity);
- if (Gerrit.getConfig().getAuthType() == AuthType.OPENID
- || Gerrit.getConfig().getAuthType() == AuthType.OAUTH) {
+ if (Gerrit.info().auth().isOpenId()
+ || Gerrit.info().auth().isOAuth()) {
Button linkIdentity = new Button(Util.C.buttonLinkIdentity());
linkIdentity.addClickHandler(new ClickHandler() {
@Override
@@ -180,8 +179,9 @@
}
});
- while (1 < table.getRowCount())
+ while (1 < table.getRowCount()) {
table.removeRow(table.getRowCount() - 1);
+ }
for (final AccountExternalId k : result) {
addOneId(k);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyPreferencesScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyPreferencesScreen.java
index 803ac55..6867bab 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyPreferencesScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyPreferencesScreen.java
@@ -117,7 +117,8 @@
FlowPanel dateTimePanel = new FlowPanel();
- final int labelIdx, fieldIdx;
+ final int labelIdx;
+ final int fieldIdx;
if (LocaleInfo.getCurrentLocale().isRTL()) {
labelIdx = 1;
fieldIdx = 0;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyProfileScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyProfileScreen.java
index 52246b2..ff6fffb 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyProfileScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyProfileScreen.java
@@ -33,7 +33,8 @@
public class MyProfileScreen extends SettingsScreen {
private AvatarImage avatar;
private Anchor changeAvatar;
- private int labelIdx, fieldIdx;
+ private int labelIdx;
+ private int fieldIdx;
private Grid info;
@Override
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyWatchesTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyWatchesTable.java
index 67f5b4a..08effdc 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyWatchesTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyWatchesTable.java
@@ -113,8 +113,9 @@
}
public void display(final List<AccountProjectWatchInfo> result) {
- while (2 < table.getRowCount())
+ while (2 < table.getRowCount()) {
table.removeRow(table.getRowCount() - 1);
+ }
for (final AccountProjectWatchInfo k : result) {
final int row = table.getRowCount();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/RegisterScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/RegisterScreen.java
index 2810931..5f1e383 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/RegisterScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/RegisterScreen.java
@@ -70,7 +70,7 @@
formBody.add(contactGroup);
if (Gerrit.getUserAccount().getUserName() == null
- && Gerrit.getConfig().canEdit(FieldName.USER_NAME)) {
+ && Gerrit.info().auth().canEdit(FieldName.USER_NAME)) {
final FlowPanel fp = new FlowPanel();
fp.setStyleName(Gerrit.RESOURCES.css().registerScreenSection());
fp.add(new SmallHeading(Util.C.welcomeUsernameHeading()));
@@ -116,7 +116,7 @@
final FlowPanel choices = new FlowPanel();
choices.setStyleName(Gerrit.RESOURCES.css().registerScreenNextLinks());
- if (Gerrit.getConfig().isUseContributorAgreements()) {
+ if (Gerrit.info().auth().useContributorAgreements()) {
final FlowPanel agreementGroup = new FlowPanel();
agreementGroup.setStyleName(Gerrit.RESOURCES.css().registerScreenSection());
agreementGroup.add(new SmallHeading(Util.C.welcomeAgreementHeading()));
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/SettingsScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/SettingsScreen.java
index c689b49..ca4ac20 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/SettingsScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/SettingsScreen.java
@@ -34,7 +34,7 @@
}
link(Util.C.tabWebIdentities(), PageLinks.SETTINGS_WEBIDENT);
link(Util.C.tabMyGroups(), PageLinks.SETTINGS_MYGROUPS);
- if (Gerrit.getConfig().isUseContributorAgreements()) {
+ if (Gerrit.info().auth().useContributorAgreements()) {
link(Util.C.tabAgreements(), PageLinks.SETTINGS_AGREEMENTS);
}
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/SshPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/SshPanel.java
index 0cfc0984..37ad764 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/SshPanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/SshPanel.java
@@ -306,8 +306,9 @@
setKeyTableVisible(false);
showAddKeyBlock(true);
} else {
- while (1 < table.getRowCount())
+ while (1 < table.getRowCount()) {
table.removeRow(table.getRowCount() - 1);
+ }
for (final SshKeyInfo k : result) {
addOneKey(k);
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/UsernameField.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/UsernameField.java
index 9975887..e440d55 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/UsernameField.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/UsernameField.java
@@ -86,7 +86,7 @@
}
private boolean canEditUserName() {
- return Gerrit.getConfig().canEdit(Account.FieldName.USER_NAME);
+ return Gerrit.info().auth().canEdit(Account.FieldName.USER_NAME);
}
private void confirmSetUserName() {
@@ -142,7 +142,7 @@
setUserName.setEnabled(on);
}
- private final class UserNameValidator implements KeyPressHandler {
+ private static final class UserNameValidator implements KeyPressHandler {
@Override
public void onKeyPress(final KeyPressEvent event) {
final char code = event.getCharCode();
@@ -178,10 +178,11 @@
default:
final TextBox box = (TextBox) event.getSource();
final String re;
- if (box.getCursorPos() == 0)
+ if (box.getCursorPos() == 0) {
re = Account.USER_NAME_PATTERN_FIRST;
- else
+ } else {
re = Account.USER_NAME_PATTERN_REST;
+ }
if (!String.valueOf(code).matches("^" + re + "$")) {
event.preventDefault();
event.stopPropagation();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccessSectionEditor.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccessSectionEditor.java
index 157748f..aa72300 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccessSectionEditor.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccessSectionEditor.java
@@ -250,8 +250,7 @@
if (value.getPermission(permissionName) != null) {
return;
}
- if (Gerrit.getConfig().getWildProject()
- .equals(projectAccess.getProjectName())
+ if (Gerrit.info().gerrit().isAllProjects(projectAccess.getProjectName())
&& !Permission.canBeOnAllProjects(value.getName(), permissionName)) {
return;
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccessSectionEditor.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccessSectionEditor.ui.xml
index b31e02e..52f3588 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccessSectionEditor.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccessSectionEditor.ui.xml
@@ -24,7 +24,7 @@
ui:generateLocales='default,en'
>
<ui:with field='res' type='com.google.gerrit.client.admin.AdminResources'/>
-<ui:style>
+<ui:style gss='false'>
@eval selectionColor com.google.gerrit.client.Gerrit.getTheme().selectionColor;
@eval trimColor com.google.gerrit.client.Gerrit.getTheme().trimColor;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupMembersScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupMembersScreen.java
index cf3e940..1e3f918 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupMembersScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupMembersScreen.java
@@ -248,7 +248,7 @@
for (int row = 1; row < table.getRowCount(); row++) {
final AccountInfo i = getRowItem(row);
if (i != null && ((CheckBox) table.getWidget(row, 1)).getValue()) {
- ids.add(i._account_id());
+ ids.add(i._accountId());
}
}
if (!ids.isEmpty()) {
@@ -258,7 +258,7 @@
public void onSuccess(final VoidResult result) {
for (int row = 1; row < table.getRowCount();) {
final AccountInfo i = getRowItem(row);
- if (i != null && ids.contains(i._account_id())) {
+ if (i != null && ids.contains(i._accountId())) {
table.removeRow(row);
} else {
row++;
@@ -270,8 +270,9 @@
}
void display(final List<AccountInfo> result) {
- while (1 < table.getRowCount())
+ while (1 < table.getRowCount()) {
table.removeRow(table.getRowCount() - 1);
+ }
for (final AccountInfo i : result) {
final int row = table.getRowCount();
@@ -295,7 +296,7 @@
return cmp;
}
- return a._account_id() - b._account_id();
+ return a._accountId() - b._accountId();
}
public String nullToEmpty(String str) {
@@ -376,8 +377,9 @@
}
void display(List<GroupInfo> list) {
- while (1 < table.getRowCount())
+ while (1 < table.getRowCount()) {
table.removeRow(table.getRowCount() - 1);
+ }
for (final GroupInfo i : list) {
final int row = table.getRowCount();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
index 4446354..affbe61 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
@@ -20,7 +20,7 @@
buttonBrowseProjects = Browse
projects = All projects
projectRepoBrowser = Repository Browser
-useContentMerge = Automatically resolve conflicts
+useContentMerge = Allow content merges
useContributorAgreements = Require a valid contributor agreement to upload
useSignedOffBy = Require <code>Signed-off-by</code> in commit message
createNewChangeForAllNotInTarget = Create a new change for every commit not in the target branch
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/CreateChangeAction.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/CreateChangeAction.java
index 1ffd6f0..9092508 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/CreateChangeAction.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/CreateChangeAction.java
@@ -44,7 +44,7 @@
public void onSuccess(ChangeInfo result) {
sent = true;
hide();
- Gerrit.display(PageLinks.toChange(result.legacy_id()));
+ Gerrit.display(PageLinks.toChange(result.legacyId()));
}
@Override
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/EditConfigAction.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/EditConfigAction.java
index 86a31ee..0fac957 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/EditConfigAction.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/EditConfigAction.java
@@ -32,7 +32,7 @@
@Override
public void onSuccess(ChangeInfo result) {
Gerrit.display(Dispatcher.toEditScreen(
- new PatchSet.Id(result.legacy_id(), 1), "project.config"));
+ new PatchSet.Id(result.legacyId(), 1), "project.config"));
}
@Override
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java
index 1b420b4..aed1dc2 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java
@@ -103,8 +103,9 @@
}
public void displaySubset(List<GroupInfo> list, String toHighlight, int fromIndex, int toIndex) {
- while (1 < table.getRowCount())
+ while (1 < table.getRowCount()) {
table.removeRow(table.getRowCount() - 1);
+ }
Collections.sort(list, new Comparator<GroupInfo>() {
@Override
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionEditor.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionEditor.ui.xml
index ada070d..00c41dc 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionEditor.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionEditor.ui.xml
@@ -24,7 +24,7 @@
ui:generateLocales='default,en'
>
<ui:with field='res' type='com.google.gerrit.client.admin.AdminResources'/>
-<ui:style>
+<ui:style gss='false'>
@eval selectionColor com.google.gerrit.client.Gerrit.getTheme().selectionColor;
@eval backgroundColor com.google.gerrit.client.Gerrit.getTheme().backgroundColor;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionRuleEditor.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionRuleEditor.ui.xml
index 4d322c0..644fef4 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionRuleEditor.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionRuleEditor.ui.xml
@@ -25,7 +25,7 @@
ui:generateLocales='default,en'
>
<ui:with field='res' type='com.google.gerrit.client.admin.AdminResources'/>
-<ui:style>
+<ui:style gss='false'>
@eval selectionColor com.google.gerrit.client.Gerrit.getTheme().selectionColor;
.panel {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PluginListScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PluginListScreen.java
index e1c73fa..4dcb52f 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PluginListScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PluginListScreen.java
@@ -60,7 +60,7 @@
add(pluginPanel);
}
- private class PluginTable extends FancyFlexTable<PluginInfo> {
+ private static class PluginTable extends FancyFlexTable<PluginInfo> {
PluginTable() {
table.setText(0, 1, Util.C.columnPluginName());
table.setText(0, 2, Util.C.columnPluginSettings());
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessEditor.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessEditor.ui.xml
index 120824b..0db4779 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessEditor.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessEditor.ui.xml
@@ -22,7 +22,7 @@
ui:generateKeys='com.google.gwt.i18n.rebind.keygen.MD5KeyGenerator'
ui:generateLocales='default,en'
>
-<ui:style>
+<ui:style gss='false'>
.inheritsFrom {
margin-bottom: 0.5em;
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessScreen.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessScreen.ui.xml
index ab26ba8..724c7a1 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessScreen.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessScreen.ui.xml
@@ -23,7 +23,7 @@
ui:generateKeys='com.google.gwt.i18n.rebind.keygen.MD5KeyGenerator'
ui:generateLocales='default,en'
>
-<ui:style>
+<ui:style gss='false'>
@external .gwt-TextArea;
.commitMessage {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectBranchesScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectBranchesScreen.java
index c5f7225..a8dd9c5 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectBranchesScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectBranchesScreen.java
@@ -444,8 +444,9 @@
void displaySubset(List<BranchInfo> branches, int fromIndex, int toIndex) {
canDelete = false;
- while (1 < table.getRowCount())
+ while (1 < table.getRowCount()) {
table.removeRow(table.getRowCount() - 1);
+ }
for (BranchInfo k : branches.subList(fromIndex, toIndex)) {
final int row = table.getRowCount();
@@ -484,8 +485,8 @@
actionsPanel.add(new Anchor(c.getLinkName(), false,
c.toBranch(new Branch.NameKey(getProjectKey(), k.ref()))));
}
- if (k.web_links() != null) {
- for (WebLinkInfo webLink : Natives.asList(k.web_links())) {
+ if (k.webLinks() != null) {
+ for (WebLinkInfo webLink : Natives.asList(k.webLinks())) {
actionsPanel.add(webLink.toAnchor());
}
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java
index 6cb9295..08ab2c0 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java
@@ -38,7 +38,6 @@
import com.google.gerrit.extensions.client.InheritableBoolean;
import com.google.gerrit.extensions.client.ProjectState;
import com.google.gerrit.extensions.client.SubmitType;
-import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadCommand;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
@@ -265,7 +264,7 @@
grid.addHeader(new SmallHeading(Util.C.headingAgreements()));
contributorAgreements = newInheritedBooleanBox();
- if (Gerrit.getConfig().isUseContributorAgreements()) {
+ if (Gerrit.info().auth().useContributorAgreements()) {
saveEnabler.listenTo(contributorAgreements);
grid.add(Util.C.useContributorAgreements(), contributorAgreements);
}
@@ -306,12 +305,12 @@
if (box.getValue(i).startsWith(InheritableBoolean.INHERIT.name())) {
inheritedIndex = i;
}
- if (box.getValue(i).startsWith(inheritedBoolean.configured_value().name())) {
+ if (box.getValue(i).startsWith(inheritedBoolean.configuredValue().name())) {
box.setSelectedIndex(i);
}
}
if (inheritedIndex >= 0) {
- if (getProjectKey().equals(Gerrit.getConfig().getWildProject())) {
+ if (Gerrit.info().gerrit().isAllProjects(getProjectKey())) {
if (box.getSelectedIndex() == inheritedIndex) {
for (int i = 0; i < box.getItemCount(); i++) {
if (box.getValue(i).equals(InheritableBoolean.FALSE.name())) {
@@ -323,7 +322,7 @@
box.removeItem(inheritedIndex);
} else {
box.setItemText(inheritedIndex, InheritableBoolean.INHERIT.name() + " ("
- + inheritedBoolean.inherited_value() + ")");
+ + inheritedBoolean.inheritedValue() + ")");
}
}
}
@@ -342,20 +341,20 @@
void display(ConfigInfo result) {
descTxt.setText(result.description());
- setBool(contributorAgreements, result.use_contributor_agreements());
- setBool(signedOffBy, result.use_signed_off_by());
- setBool(contentMerge, result.use_content_merge());
- setBool(newChangeForAllNotInTarget, result.create_new_change_for_all_not_in_target());
- setBool(requireChangeID, result.require_change_id());
- setSubmitType(result.submit_type());
+ setBool(contributorAgreements, result.useContributorAgreements());
+ setBool(signedOffBy, result.useSignedOffBy());
+ setBool(contentMerge, result.useContentMerge());
+ setBool(newChangeForAllNotInTarget, result.createNewChangeForAllNotInTarget());
+ setBool(requireChangeID, result.requireChangeId());
+ setSubmitType(result.submitType());
setState(result.state());
- maxObjectSizeLimit.setText(result.max_object_size_limit().configured_value());
- if (result.max_object_size_limit().inherited_value() != null) {
+ maxObjectSizeLimit.setText(result.maxObjectSizeLimit().configuredValue());
+ if (result.maxObjectSizeLimit().inheritedValue() != null) {
effectiveMaxObjectSizeLimit.setVisible(true);
effectiveMaxObjectSizeLimit.setText(
- Util.M.effectiveMaxObjectSizeLimit(result.max_object_size_limit().value()));
+ Util.M.effectiveMaxObjectSizeLimit(result.maxObjectSizeLimit().value()));
effectiveMaxObjectSizeLimit.setTitle(
- Util.M.globalMaxObjectSizeLimit(result.max_object_size_limit().inherited_value()));
+ Util.M.globalMaxObjectSizeLimit(result.maxObjectSizeLimit().inheritedValue()));
} else {
effectiveMaxObjectSizeLimit.setVisible(false);
}
@@ -674,19 +673,16 @@
public class ProjectDownloadPanel extends DownloadPanel {
public ProjectDownloadPanel(String project, boolean isAllowsAnonymous) {
- super(project, null, isAllowsAnonymous);
+ super(project, isAllowsAnonymous);
}
@Override
public void populateDownloadCommandLinks() {
if (!urls.isEmpty()) {
- if (allowedCommands.contains(DownloadCommand.CHECKOUT)
- || allowedCommands.contains(DownloadCommand.DEFAULT_DOWNLOADS)) {
- commands.add(cmdLinkfactory.new CloneCommandLink());
- if (Gerrit.getConfig().getSshdAddress() != null && hasUserName()) {
- commands.add(
- cmdLinkfactory.new CloneWithCommitMsgHookCommandLink(getProjectKey()));
- }
+ commands.add(cmdLinkfactory.new CloneCommandLink());
+ if (Gerrit.getConfig().getSshdAddress() != null && hasUserName()) {
+ commands.add(
+ cmdLinkfactory.new CloneWithCommitMsgHookCommandLink(getProjectKey()));
}
}
}
@@ -698,7 +694,7 @@
&& Gerrit.getUserAccount().getUserName().length() > 0;
}
- private class LabeledWidgetsGrid extends FlexTable {
+ private static class LabeledWidgetsGrid extends FlexTable {
private String labelSuffix;
public LabeledWidgetsGrid() {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectListScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectListScreen.java
index 828352c..0dff684 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectListScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectListScreen.java
@@ -186,7 +186,7 @@
private void addWebLinks(int row, ProjectInfo k) {
GitwebLink gitWebLink = Gerrit.getGitwebLink();
- List<WebLinkInfo> webLinks = Natives.asList(k.web_links());
+ List<WebLinkInfo> webLinks = Natives.asList(k.webLinks());
if (gitWebLink != null || (webLinks != null && !webLinks.isEmpty())) {
FlowPanel p = new FlowPanel();
table.setWidget(row, ProjectsTable.C_REPO_BROWSER, p);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ValueEditor.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ValueEditor.ui.xml
index e5f6649..137ad2b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ValueEditor.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ValueEditor.ui.xml
@@ -19,7 +19,7 @@
xmlns:g='urn:import:com.google.gwt.user.client.ui'
>
<ui:with field='ico' type='com.google.gerrit.client.GerritResources'/>
-<ui:style>
+<ui:style gss='false'>
.panel {
position: relative;
white-space: nowrap;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ActionContext.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ActionContext.java
index 2b40954..b7307be 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ActionContext.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ActionContext.java
@@ -114,7 +114,9 @@
return e.options[e.selectedIndex].text;
},
- popup: function(e){this._p=@com.google.gerrit.client.api.PopupHelper::popup(Lcom/google/gerrit/client/api/ActionContext;Lcom/google/gwt/dom/client/Element;)(this,e)},
+ popup: function(e){
+ this._p=@com.google.gerrit.client.api.PopupHelper::popup(
+ Lcom/google/gerrit/client/api/ActionContext;Lcom/google/gwt/dom/client/Element;)(this,e)},
hide: function() {
this._p.@com.google.gerrit.client.api.PopupHelper::hide()();
delete this['_p'];
@@ -125,11 +127,18 @@
if (m == 'get' || m == 'delete' || i==null) this[m](b);
else this[m](i,b);
},
- get: function(b){@com.google.gerrit.client.api.ActionContext::get(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;)(this._u,b)},
- post: function(i,b){@com.google.gerrit.client.api.ActionContext::post(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;Lcom/google/gwt/core/client/JavaScriptObject;)(this._u,i,b)},
- put: function(i,b){@com.google.gerrit.client.api.ActionContext::put(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;Lcom/google/gwt/core/client/JavaScriptObject;)(this._u,i,b)},
- 'delete': function(b){@com.google.gerrit.client.api.ActionContext::delete(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;)(this._u,b)},
- del: function(b){@com.google.gerrit.client.api.ActionContext::delete(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;)(this._u,b)},
+ get: function(b){@com.google.gerrit.client.api.ActionContext::get(
+ Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;)(this._u,b)},
+ post: function(i,b){@com.google.gerrit.client.api.ActionContext::post(
+ Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;Lcom/google/gwt/core/client/JavaScriptObject;)(
+ this._u,i,b)},
+ put: function(i,b){@com.google.gerrit.client.api.ActionContext::put(
+ Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;Lcom/google/gwt/core/client/JavaScriptObject;)(
+ this._u,i,b)},
+ 'delete': function(b){@com.google.gerrit.client.api.ActionContext::delete(
+ Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;)(this._u,b)},
+ del: function(b){@com.google.gerrit.client.api.ActionContext::delete(
+ Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;)(this._u,b)},
};
}-*/;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ChangeGlue.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ChangeGlue.java
index a5243ae..e831e8b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ChangeGlue.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ChangeGlue.java
@@ -42,7 +42,7 @@
ChangeInfo change,
ActionInfo action,
ActionButton button) {
- RestApi api = ChangeApi.change(change.legacy_id().get()).view(action.id());
+ RestApi api = ChangeApi.change(change.legacyId().get()).view(action.id());
JavaScriptObject f = get(action.id());
if (f != null) {
ActionContext c = ActionContext.create(api);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/DefaultActions.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/DefaultActions.java
index 0e4048d..c092375 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/DefaultActions.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/DefaultActions.java
@@ -29,7 +29,7 @@
class DefaultActions {
static void invoke(ChangeInfo change, ActionInfo action, RestApi api) {
- invoke(action, api, callback(PageLinks.toChange(change.legacy_id())));
+ invoke(action, api, callback(PageLinks.toChange(change.legacyId())));
}
static void invoke(Project.NameKey project, ActionInfo action, RestApi api) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/EditGlue.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/EditGlue.java
index ebcafb8..f968fd2 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/EditGlue.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/EditGlue.java
@@ -29,7 +29,7 @@
ActionInfo action,
ActionButton button) {
RestApi api = ChangeApi.edit(
- change.legacy_id().get())
+ change.legacyId().get())
.view(action.id());
JavaScriptObject f = get(action.id());
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/Plugin.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/Plugin.java
index 931a04d..6acb420 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/Plugin.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/Plugin.java
@@ -61,11 +61,18 @@
screen: function(p,c){G._screen(this.name,p,c)},
url: function (u){return G.url(this._url(u))},
- get: function(u,b){@com.google.gerrit.client.api.ActionContext::get(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),b)},
- post: function(u,i,b){@com.google.gerrit.client.api.ActionContext::post(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),i,b)},
- put: function(u,i,b){@com.google.gerrit.client.api.ActionContext::put(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),i,b)},
- 'delete': function(u,b){@com.google.gerrit.client.api.ActionContext::delete(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),b)},
- del: function(u,b){@com.google.gerrit.client.api.ActionContext::delete(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),b)},
+ get: function(u,b){@com.google.gerrit.client.api.ActionContext::get(
+ Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),b)},
+ post: function(u,i,b){@com.google.gerrit.client.api.ActionContext::post(
+ Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;Lcom/google/gwt/core/client/JavaScriptObject;)(
+ this._api(u),i,b)},
+ put: function(u,i,b){@com.google.gerrit.client.api.ActionContext::put(
+ Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;Lcom/google/gwt/core/client/JavaScriptObject;)(
+ this._api(u),i,b)},
+ 'delete': function(u,b){@com.google.gerrit.client.api.ActionContext::delete(
+ Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),b)},
+ del: function(u,b){@com.google.gerrit.client.api.ActionContext::delete(
+ Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),b)},
_loadedGwt: function(){@com.google.gerrit.client.api.PluginLoader::loaded()()},
_api: function(u){return @com.google.gerrit.client.rpc.RestApi::new(Ljava/lang/String;)(this._url(u))},
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/PluginLoader.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/PluginLoader.java
index f0fb436..ceb0eee 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/PluginLoader.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/PluginLoader.java
@@ -32,15 +32,14 @@
/** Loads JavaScript plugins with a progress meter visible. */
public class PluginLoader extends DialogBox {
- private static final int MAX_LOAD_TIME_MILLIS = 5000;
private static PluginLoader self;
public static void load(List<String> plugins,
- AsyncCallback<VoidResult> callback) {
+ int loadTimeout, AsyncCallback<VoidResult> callback) {
if (plugins == null || plugins.isEmpty()) {
callback.onSuccess(VoidResult.create());
} else {
- self = new PluginLoader(callback);
+ self = new PluginLoader(loadTimeout, callback);
self.load(plugins);
self.startTimers();
self.center();
@@ -51,6 +50,7 @@
self.loadedOne();
}
+ private final int loadTimeout;
private final AsyncCallback<VoidResult> callback;
private ProgressBar progress;
private Timer show;
@@ -58,9 +58,10 @@
private Timer timeout;
private boolean visible;
- private PluginLoader(AsyncCallback<VoidResult> cb) {
+ private PluginLoader(int loadTimeout, AsyncCallback<VoidResult> cb) {
super(/* auto hide */false, /* modal */true);
callback = cb;
+ this.loadTimeout = loadTimeout;
progress = new ProgressBar(Gerrit.C.loadingPlugins());
setStyleName(Gerrit.RESOURCES.css().errorDialog());
@@ -98,7 +99,7 @@
@Override
public void run() {
- progress.setValue(100 * ++cycle * 250 / MAX_LOAD_TIME_MILLIS);
+ progress.setValue(100 * ++cycle * 250 / loadTimeout);
}
};
update.scheduleRepeating(250);
@@ -109,7 +110,7 @@
finish();
}
};
- timeout.schedule(MAX_LOAD_TIME_MILLIS);
+ timeout.schedule(loadTimeout);
}
private void loadedOne() {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/RevisionGlue.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/RevisionGlue.java
index fb489cc..d708e8c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/RevisionGlue.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/RevisionGlue.java
@@ -29,7 +29,7 @@
ActionInfo action,
ActionButton button) {
RestApi api = ChangeApi.revision(
- change.legacy_id().get(),
+ change.legacyId().get(),
revision.name())
.view(action.id());
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ActionMessageBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ActionMessageBox.ui.xml
index d639150..a9e1bb3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ActionMessageBox.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ActionMessageBox.ui.xml
@@ -19,7 +19,7 @@
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:c='urn:import:com.google.gwtexpui.globalkey.client'>
<ui:with field='res' type='com.google.gerrit.client.change.Resources'/>
- <ui:style type='com.google.gerrit.client.change.ActionMessageBox.Style'>
+ <ui:style gss='false' type='com.google.gerrit.client.change.ActionMessageBox.Style'>
@eval trimColor com.google.gerrit.client.Gerrit.getTheme().trimColor;
.popup { background-color: trimColor; }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.java
index edf1105..10d77cb 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.java
@@ -36,9 +36,8 @@
class Actions extends Composite {
private static final String[] CORE = {
- "abandon", "restore", "revert", "topic",
- "cherrypick", "submit", "rebase", "message",
- "publish", "followup", "/"};
+ "abandon", "cherrypick", "followup", "hashtags", "publish",
+ "rebase", "restore", "revert", "submit", "topic", "/"};
interface Binder extends UiBinder<FlowPanel, Actions> {}
private static final Binder uiBinder = GWT.create(Binder.class);
@@ -65,7 +64,8 @@
private String message;
private String branch;
private String key;
- private boolean canSubmit;
+
+ private boolean rebaseParentNotCurrent = true;
Actions() {
initWidget(uiBinder.createAndBindUi(this));
@@ -78,20 +78,25 @@
boolean hasUser = Gerrit.isSignedIn();
RevisionInfo revInfo = info.revision(revision);
CommitInfo commit = revInfo.commit();
- changeId = info.legacy_id();
+ changeId = info.legacyId();
project = info.project();
subject = commit.subject();
message = commit.message();
branch = info.branch();
- key = info.change_id();
+ key = info.changeId();
changeInfo = info;
initChangeActions(info, hasUser);
- initRevisionActions(info, revInfo, hasUser);
+
+ NativeMap<ActionInfo> actionMap = revInfo.hasActions()
+ ? revInfo.actions()
+ : NativeMap.<ActionInfo> create();
+ actionMap.copyKeysIntoChildren("id");
+ reloadRevisionActions(actionMap);
}
private void initChangeActions(ChangeInfo info, boolean hasUser) {
- NativeMap<ActionInfo> actions = info.has_actions()
+ NativeMap<ActionInfo> actions = info.hasActions()
? info.actions()
: NativeMap.<ActionInfo> create();
actions.copyKeysIntoChildren("id");
@@ -107,34 +112,35 @@
}
}
- private void initRevisionActions(ChangeInfo info, RevisionInfo revInfo,
- boolean hasUser) {
- NativeMap<ActionInfo> actions = revInfo.has_actions()
- ? revInfo.actions()
- : NativeMap.<ActionInfo> create();
- actions.copyKeysIntoChildren("id");
+ void reloadRevisionActions(NativeMap<ActionInfo> actions) {
+ if (!Gerrit.isSignedIn()) {
+ return;
+ }
+ boolean canSubmit = actions.containsKey("submit");
+ if (canSubmit) {
+ ActionInfo action = actions.get("submit");
+ submit.setTitle(action.title());
+ submit.setEnabled(action.enabled());
+ submit.setHTML(new SafeHtmlBuilder()
+ .openDiv()
+ .append(action.label())
+ .closeDiv());
+ submit.setEnabled(action.enabled());
+ }
+ submit.setVisible(canSubmit);
- canSubmit = false;
- if (hasUser) {
- canSubmit = actions.containsKey("submit");
- if (canSubmit) {
- ActionInfo action = actions.get("submit");
- submit.setTitle(action.title());
- submit.setEnabled(action.enabled());
- submit.setHTML(new SafeHtmlBuilder()
- .openDiv()
- .append(action.label())
- .closeDiv());
- }
- a2b(actions, "cherrypick", cherrypick);
- a2b(actions, "rebase", rebase);
- if (rebase.isVisible()) {
- // it is the rebase button in RebaseDialog that the server wants to disable
- rebase.setEnabled(true);
- }
- for (String id : filterNonCore(actions)) {
- add(new ActionButton(info, revInfo, actions.get(id)));
- }
+ a2b(actions, "cherrypick", cherrypick);
+ a2b(actions, "rebase", rebase);
+
+ // The rebase button on change screen is always enabled.
+ // It is the "Rebase" button in the RebaseDialog that might be disabled.
+ rebaseParentNotCurrent = rebase.isEnabled();
+ if (rebase.isVisible()) {
+ rebase.setEnabled(true);
+ }
+ RevisionInfo revInfo = changeInfo.revision(revision);
+ for (String id : filterNonCore(actions)) {
+ add(new ActionButton(changeInfo, revInfo, actions.get(id)));
}
}
@@ -150,10 +156,6 @@
return ids;
}
- void setSubmitEnabled() {
- submit.setVisible(canSubmit);
- }
-
@UiHandler("followUp")
void onFollowUp(@SuppressWarnings("unused") ClickEvent e) {
if (followUpAction == null) {
@@ -181,16 +183,8 @@
@UiHandler("rebase")
void onRebase(@SuppressWarnings("unused") ClickEvent e) {
- boolean enabled = true;
- RevisionInfo revInfo = changeInfo.revision(revision);
- if (revInfo.has_actions()) {
- NativeMap<ActionInfo> actions = revInfo.actions();
- if (actions.containsKey("rebase")) {
- enabled = actions.get("rebase").enabled();
- }
- }
RebaseAction.call(rebase, project, changeInfo.branch(), changeId, revision,
- enabled);
+ rebaseParentNotCurrent);
}
@UiHandler("submit")
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.ui.xml
index 40d732a..bc5a321 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.ui.xml
@@ -17,7 +17,7 @@
<ui:UiBinder
xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
- <ui:style>
+ <ui:style gss='false'>
@def BUTTON_HEIGHT 14px;
#change_actions {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileAction.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileAction.java
index f74ebf6..3a3ffe2 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileAction.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileAction.java
@@ -1,16 +1,16 @@
-//Copyright (C) 2013 The Android Open Source Project
+// Copyright (C) 2013 The Android Open Source Project
//
-//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
+// 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
+// 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.
+// 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.
package com.google.gerrit.client.change;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileBox.java
index 7245e47..09de2c8 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileBox.java
@@ -1,16 +1,16 @@
-//Copyright (C) 2013 The Android Open Source Project
+// Copyright (C) 2013 The Android Open Source Project
//
-//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
+// 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
+// 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.
+// 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.
package com.google.gerrit.client.change;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileBox.ui.xml
index d8236e6..c3539bc 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileBox.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileBox.ui.xml
@@ -19,7 +19,7 @@
xmlns:u='urn:import:com.google.gerrit.client.ui'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<ui:with field='res' type='com.google.gerrit.client.change.Resources'/>
- <ui:style>
+ <ui:style gss='false'>
.cancel { float: right; }
</ui:style>
<g:HTMLPanel>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen.java
index 4d7dac2..4133c13 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen.java
@@ -113,6 +113,7 @@
String label_need();
String replyBox();
String selected();
+ String highlight();
String hashtagName();
}
@@ -131,11 +132,10 @@
private String base;
private String revision;
private ChangeInfo changeInfo;
+ private boolean hasDraftComments;
private CommentLinkProcessor commentLinkProcessor;
private EditInfo edit;
- private KeyCommandSet keysNavigation;
- private KeyCommandSet keysAction;
private List<HandlerRegistration> handlers = new ArrayList<>(4);
private UpdateCheckTimer updateCheck;
private Timestamp lastDisplayedUpdate;
@@ -248,7 +248,7 @@
void loadChangeInfo(boolean fg, AsyncCallback<ChangeInfo> cb) {
RestApi call = ChangeApi.detail(changeId.get());
ChangeList.addOptions(call, EnumSet.of(
- ListChangesOption.CURRENT_ACTIONS,
+ ListChangesOption.CHANGE_ACTIONS,
ListChangesOption.ALL_REVISIONS));
if (!fg) {
call.background();
@@ -256,6 +256,18 @@
call.get(cb);
}
+ void loadRevisionInfo() {
+ RestApi call = ChangeApi.actions(changeId.get(), revision);
+ call.background();
+ call.get(new GerritCallback<NativeMap<ActionInfo>>() {
+ @Override
+ public void onSuccess(NativeMap<ActionInfo> actionMap) {
+ actionMap.copyKeysIntoChildren("id");
+ renderRevisionInfo(changeInfo, actionMap);
+ }
+ });
+ }
+
@Override
protected void onUnload() {
if (replyAction != null) {
@@ -281,84 +293,24 @@
labels.init(style);
reviewers.init(style, ccText);
hashtags.init(style);
-
- keysNavigation = new KeyCommandSet(Gerrit.C.sectionNavigation());
- keysNavigation.add(new KeyCommand(0, 'u', Util.C.upToChangeList()) {
- @Override
- public void onKeyPress(final KeyPressEvent event) {
- Gerrit.displayLastChangeList();
- }
- });
- keysNavigation.add(new KeyCommand(0, 'R', Util.C.keyReloadChange()) {
- @Override
- public void onKeyPress(final KeyPressEvent event) {
- Gerrit.display(PageLinks.toChange(changeId));
- }
- });
- keysNavigation.add(new KeyCommand(0, 'n', Util.C.keyNextPatchSet()) {
- @Override
- public void onKeyPress(final KeyPressEvent event) {
- gotoSibling(1);
- }
- }, new KeyCommand(0, 'p', Util.C.keyPreviousPatchSet()) {
- @Override
- public void onKeyPress(final KeyPressEvent event) {
- gotoSibling(-1);
- }
- });
-
- keysAction = new KeyCommandSet(Gerrit.C.sectionActions());
- keysAction.add(new KeyCommand(0, 'a', Util.C.keyPublishComments()) {
- @Override
- public void onKeyPress(KeyPressEvent event) {
- if (Gerrit.isSignedIn()) {
- onReply(null);
- } else {
- Gerrit.doSignIn(getToken());
- }
- }
- });
- keysAction.add(new KeyCommand(0, 'x', Util.C.keyExpandAllMessages()) {
- @Override
- public void onKeyPress(KeyPressEvent event) {
- onExpandAll(null);
- }
- });
- keysAction.add(new KeyCommand(0, 'z', Util.C.keyCollapseAllMessages()) {
- @Override
- public void onKeyPress(KeyPressEvent event) {
- onCollapseAll(null);
- }
- });
- if (Gerrit.isSignedIn()) {
- keysAction.add(new KeyCommand(0, 's', Util.C.changeTableStar()) {
- @Override
- public void onKeyPress(KeyPressEvent event) {
- star.setValue(!star.getValue(), true);
- }
- });
- keysAction.add(new KeyCommand(0, 'c', Util.C.keyAddReviewers()) {
- @Override
- public void onKeyPress(KeyPressEvent event) {
- reviewers.onOpenForm();
- }
- });
- }
}
private void initReplyButton(ChangeInfo info, String revision) {
- if (!info.revision(revision).is_edit()) {
+ if (!info.revision(revision).isEdit()) {
reply.setTitle(Gerrit.getConfig().getReplyTitle());
reply.setHTML(new SafeHtmlBuilder()
.openDiv()
.append(Gerrit.getConfig().getReplyLabel())
.closeDiv());
+ if (hasDraftComments) {
+ reply.setStyleName(style.highlight());
+ }
reply.setVisible(true);
}
}
private void gotoSibling(final int offset) {
- if (offset > 0 && changeInfo.current_revision().equals(revision)) {
+ if (offset > 0 && changeInfo.currentRevision().equals(revision)) {
return;
}
@@ -372,7 +324,7 @@
if (revision.equals(revisions.get(i).name())) {
if (0 <= i + offset && i + offset < revisions.length()) {
Gerrit.display(PageLinks.toChange(
- new PatchSet.Id(changeInfo.legacy_id(),
+ new PatchSet.Id(changeInfo.legacyId(),
revisions.get(i + offset)._number())));
return;
}
@@ -384,7 +336,7 @@
private void initIncludedInAction(ChangeInfo info) {
if (info.status() == Status.MERGED) {
includedInAction = new IncludedInAction(
- info.legacy_id(),
+ info.legacyId(),
style, headerLine, includedIn);
includedIn.setVisible(true);
}
@@ -392,7 +344,7 @@
private void initChangeAction(ChangeInfo info) {
if (info.status() == Status.DRAFT) {
- NativeMap<ActionInfo> actions = info.has_actions()
+ NativeMap<ActionInfo> actions = info.hasActions()
? info.actions()
: NativeMap.<ActionInfo> create();
actions.copyKeysIntoChildren("id");
@@ -403,11 +355,12 @@
}
}
- private void initRevisionsAction(ChangeInfo info, String revision) {
+ private void initRevisionsAction(ChangeInfo info, String revision,
+ NativeMap<ActionInfo> actions) {
int currentPatchSet;
- if (info.current_revision() != null
- && info.revisions().containsKey(info.current_revision())) {
- currentPatchSet = info.revision(info.current_revision())._number();
+ if (info.currentRevision() != null
+ && info.revisions().containsKey(info.currentRevision())) {
+ currentPatchSet = info.revision(info.currentRevision())._number();
} else {
JsArray<RevisionInfo> revList = info.revisions().values();
RevisionInfo.sortRevisionInfoByNumber(revList);
@@ -426,16 +379,11 @@
patchSetsText.setInnerText(Resources.M.patchSets(
currentlyViewedPatchSet, currentPatchSet));
patchSetsAction = new PatchSetsAction(
- info.legacy_id(), revision, edit,
+ info.legacyId(), revision, edit,
style, headerLine, patchSets);
RevisionInfo revInfo = info.revision(revision);
if (revInfo.draft()) {
- NativeMap<ActionInfo> actions = revInfo.has_actions()
- ? revInfo.actions()
- : NativeMap.<ActionInfo> create();
- actions.copyKeysIntoChildren("id");
-
if (actions.containsKey("publish")) {
publish.setVisible(true);
publish.setTitle(actions.get("publish").title());
@@ -454,20 +402,20 @@
private void initProjectLinks(final ChangeInfo info) {
projectSettingsLink.setHref(
- "#" + PageLinks.toProject(info.project_name_key()));
+ "#" + PageLinks.toProject(info.projectNameKey()));
projectSettings.addDomHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
if (Hyperlink.impl.handleAsClick((Event) event.getNativeEvent())) {
event.stopPropagation();
event.preventDefault();
- Gerrit.display(PageLinks.toProject(info.project_name_key()));
+ Gerrit.display(PageLinks.toProject(info.projectNameKey()));
}
}
}, ClickEvent.getType());
projectDashboard.setText(info.project());
projectDashboard.setTargetHistoryToken(
- PageLinks.toProjectDefaultDashboard(info.project_name_key()));
+ PageLinks.toProjectDefaultDashboard(info.projectNameKey()));
}
private void initBranchLink(ChangeInfo info) {
@@ -475,7 +423,7 @@
branchLink.setTargetHistoryToken(
PageLinks.toChangeQuery(
BranchLink.query(
- info.project_name_key(),
+ info.projectNameKey(),
info.status(),
info.branch(),
null)));
@@ -505,7 +453,7 @@
reviewMode.setVisible(false);
}
- if (rev.is_edit()) {
+ if (rev.isEdit()) {
if (info.hasEditBasedOnCurrentPatchSet()) {
publishEdit.setVisible(true);
} else {
@@ -517,11 +465,11 @@
}
private boolean isEditModeEnabled(ChangeInfo info, RevisionInfo rev) {
- if (rev.is_edit()) {
+ if (rev.isEdit()) {
return true;
}
if (edit == null) {
- return revision.equals(info.current_revision());
+ return revision.equals(info.currentRevision());
}
return rev._number() == RevisionInfo.findEditParent(
info.revisions().values());
@@ -566,7 +514,94 @@
@Override
public void registerKeys() {
super.registerKeys();
+
+ KeyCommandSet keysNavigation = new KeyCommandSet(Gerrit.C.sectionNavigation());
+ keysNavigation.add(new KeyCommand(0, 'u', Util.C.upToChangeList()) {
+ @Override
+ public void onKeyPress(final KeyPressEvent event) {
+ Gerrit.displayLastChangeList();
+ }
+ });
+ keysNavigation.add(new KeyCommand(0, 'R', Util.C.keyReloadChange()) {
+ @Override
+ public void onKeyPress(final KeyPressEvent event) {
+ Gerrit.display(PageLinks.toChange(changeId));
+ }
+ });
+ keysNavigation.add(new KeyCommand(0, 'n', Util.C.keyNextPatchSet()) {
+ @Override
+ public void onKeyPress(final KeyPressEvent event) {
+ gotoSibling(1);
+ }
+ }, new KeyCommand(0, 'p', Util.C.keyPreviousPatchSet()) {
+ @Override
+ public void onKeyPress(final KeyPressEvent event) {
+ gotoSibling(-1);
+ }
+ });
handlers.add(GlobalKey.add(this, keysNavigation));
+
+ KeyCommandSet keysAction = new KeyCommandSet(Gerrit.C.sectionActions());
+ keysAction.add(new KeyCommand(0, 'a', Util.C.keyPublishComments()) {
+ @Override
+ public void onKeyPress(KeyPressEvent event) {
+ if (Gerrit.isSignedIn()) {
+ onReply(null);
+ } else {
+ Gerrit.doSignIn(getToken());
+ }
+ }
+ });
+ keysAction.add(new KeyCommand(0, 'x', Util.C.keyExpandAllMessages()) {
+ @Override
+ public void onKeyPress(KeyPressEvent event) {
+ onExpandAll(null);
+ }
+ });
+ keysAction.add(new KeyCommand(0, 'z', Util.C.keyCollapseAllMessages()) {
+ @Override
+ public void onKeyPress(KeyPressEvent event) {
+ onCollapseAll(null);
+ }
+ });
+ keysAction.add(new KeyCommand(0, 's', Util.C.changeTableStar()) {
+ @Override
+ public void onKeyPress(KeyPressEvent event) {
+ if (Gerrit.isSignedIn()) {
+ star.setValue(!star.getValue(), true);
+ } else {
+ Gerrit.doSignIn(getToken());
+ }
+ }
+ });
+ keysAction.add(new KeyCommand(0, 'c', Util.C.keyAddReviewers()) {
+ @Override
+ public void onKeyPress(KeyPressEvent event) {
+ if (Gerrit.isSignedIn()) {
+ reviewers.onOpenForm();
+ } else {
+ Gerrit.doSignIn(getToken());
+ }
+ }
+ });
+ keysAction.add(new KeyCommand(0, 't', Util.C.keyEditTopic()) {
+ @Override
+ public void onKeyPress(KeyPressEvent event) {
+ if (Gerrit.isSignedIn()) {
+ // In Firefox this event is mistakenly called when F5 is pressed so
+ // differentiate F5 from 't' by checking the charCode(F5=0, t=116).
+ if (event.getNativeEvent().getCharCode() == 0) {
+ Window.Location.reload();
+ return;
+ }
+ if (topic.canEdit()) {
+ topic.onEdit();
+ }
+ } else {
+ Gerrit.doSignIn(getToken());
+ }
+ }
+ });
handlers.add(GlobalKey.add(this, keysAction));
files.registerKeys();
}
@@ -746,9 +781,9 @@
private void loadConfigInfo(final ChangeInfo info, final String base) {
info.revisions().copyKeysIntoChildren("name");
if (edit != null) {
- edit.set_name(edit.commit().commit());
- info.set_edit(edit);
- if (edit.has_files()) {
+ edit.setName(edit.commit().commit());
+ info.setEdit(edit);
+ if (edit.hasFiles()) {
edit.files().copyKeysIntoChildren("path");
}
info.revisions().put(edit.name(), RevisionInfo.fromEdit(edit));
@@ -766,14 +801,14 @@
if (revision == null) {
RevisionInfo.sortRevisionInfoByNumber(list);
RevisionInfo rev = list.get(list.length() - 1);
- if (rev.is_edit()) {
- info.set_current_revision(rev.name());
+ if (rev.isEdit()) {
+ info.setCurrentRevision(rev.name());
}
} else if (revision.equals("edit") || revision.equals("0")) {
for (int i = 0; i < list.length(); i++) {
RevisionInfo r = list.get(i);
- if (r.is_edit()) {
- info.set_current_revision(r.name());
+ if (r.isEdit()) {
+ info.setCurrentRevision(r.name());
break;
}
}
@@ -784,7 +819,7 @@
CallbackGroup group = new CallbackGroup();
Timestamp lastReply = myLastReply(info);
- if (rev.is_edit()) {
+ if (rev.isEdit()) {
loadFileList(b, rev, lastReply, group, null, null);
} else {
loadDiff(b, rev, lastReply, group);
@@ -798,7 +833,7 @@
RevisionInfoCache.add(changeId, rev);
ConfigInfoCache.add(info);
- ConfigInfoCache.get(info.project_name_key(),
+ ConfigInfoCache.get(info.projectNameKey(),
group.addFinal(new ScreenLoadCallback<ConfigInfoCache.Entry>(this) {
@Override
protected void preDisplay(Entry result) {
@@ -806,16 +841,17 @@
commentLinkProcessor = result.getCommentLinkProcessor();
setTheme(result.getTheme());
renderChangeInfo(info);
+ loadRevisionInfo();
}
}));
}
static Timestamp myLastReply(ChangeInfo info) {
if (Gerrit.isSignedIn() && info.messages() != null) {
- int self = Gerrit.getUserAccountInfo()._account_id();
+ int self = Gerrit.getUserAccountInfo()._accountId();
for (int i = info.messages().length() - 1; i >= 0; i--) {
MessageInfo m = info.messages().get(i);
- if (m.author() != null && m.author()._account_id() == self) {
+ if (m.author() != null && m.author()._accountId() == self) {
return m.date();
}
}
@@ -872,16 +908,19 @@
}
private List<NativeMap<JsArray<CommentInfo>>> loadComments(
- RevisionInfo rev, CallbackGroup group) {
- final int id = rev._number();
+ final RevisionInfo rev, CallbackGroup group) {
final List<NativeMap<JsArray<CommentInfo>>> r = new ArrayList<>(1);
- ChangeApi.revision(changeId.get(), rev.name())
- .view("comments")
+ // TODO(dborowitz): Could eliminate this call by adding an option to include
+ // inline comments in the change detail.
+ ChangeApi.comments(changeId.get())
.get(group.add(new AsyncCallback<NativeMap<JsArray<CommentInfo>>>() {
@Override
public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
- r.add(result);
- history.addComments(id, result);
+ // Return value is used for populating the file table, so only count
+ // comments for the current revision. Still include all comments in
+ // the history table.
+ r.add(filterForRevision(result, rev._number()));
+ history.addComments(result);
}
@Override
@@ -891,6 +930,23 @@
return r;
}
+ private static NativeMap<JsArray<CommentInfo>> filterForRevision(
+ NativeMap<JsArray<CommentInfo>> comments, int id) {
+ NativeMap<JsArray<CommentInfo>> filtered = NativeMap.create();
+ for (String k : comments.keySet()) {
+ JsArray<CommentInfo> allRevisions = comments.get(k);
+ JsArray<CommentInfo> thisRevision = JsArray.createArray().cast();
+ for (int i = 0; i < allRevisions.length(); i++) {
+ CommentInfo c = allRevisions.get(i);
+ if (c.patchSet() == id) {
+ thisRevision.push(c);
+ }
+ }
+ filtered.put(k, thisRevision);
+ }
+ return filtered;
+ }
+
private List<NativeMap<JsArray<CommentInfo>>> loadDrafts(
RevisionInfo rev, CallbackGroup group) {
final List<NativeMap<JsArray<CommentInfo>>> r = new ArrayList<>(1);
@@ -901,6 +957,7 @@
@Override
public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
r.add(result);
+ hasDraftComments = !result.isEmpty();
}
@Override
@@ -914,7 +971,7 @@
}
private void loadCommit(final RevisionInfo rev, CallbackGroup group) {
- if (rev.is_edit()) {
+ if (rev.isEdit()) {
return;
}
@@ -922,7 +979,7 @@
group.add(new AsyncCallback<CommitInfo>() {
@Override
public void onSuccess(CommitInfo info) {
- rev.set_commit(info);
+ rev.setCommit(info);
}
@Override
@@ -933,7 +990,6 @@
private void loadSubmitType(final Change.Status status, final boolean canSubmit) {
if (canSubmit) {
- actions.setSubmitEnabled();
if (status == Change.Status.NEW) {
statusText.setInnerText(Util.C.readyToSubmit());
}
@@ -963,7 +1019,7 @@
private RevisionInfo resolveRevisionToDisplay(ChangeInfo info) {
RevisionInfo rev = resolveRevisionOrPatchSetId(info, revision,
- info.current_revision());
+ info.currentRevision());
if (rev != null) {
revision = rev.name();
return rev;
@@ -980,7 +1036,7 @@
return rev;
} else {
new ErrorDialog(
- Resources.M.changeWithNoRevisions(info.legacy_id().get())).center();
+ Resources.M.changeWithNoRevisions(info.legacyId().get())).center();
throw new IllegalStateException("no revision, cannot proceed");
}
}
@@ -1043,18 +1099,7 @@
private void renderChangeInfo(ChangeInfo info) {
changeInfo = info;
lastDisplayedUpdate = info.updated();
- RevisionInfo revisionInfo = info.revision(revision);
- boolean current = revision.equals(info.current_revision())
- && !revisionInfo.is_edit();
- if (revisionInfo.is_edit()) {
- statusText.setInnerText(Util.C.changeEdit());
- } else if (!current) {
- statusText.setInnerText(Util.C.notCurrent());
- labels.setVisible(false);
- } else {
- statusText.setInnerText(Util.toLongString(info.status()));
- }
labels.set(info);
renderOwner(info);
@@ -1063,7 +1108,6 @@
initReplyButton(info, revision);
initIncludedInAction(info);
initChangeAction(info);
- initRevisionsAction(info, revision);
initDownloadAction(info, revision);
initProjectLinks(info);
initBranchLink(info);
@@ -1072,7 +1116,7 @@
star.setValue(info.starred());
permalink.setHref(ChangeLink.permalink(changeId));
- permalink.setText(String.valueOf(info.legacy_id()));
+ permalink.setText(String.valueOf(info.legacyId()));
topic.set(info, revision);
commit.set(commentLinkProcessor, info, revision);
related.set(info, revision);
@@ -1083,23 +1127,45 @@
setVisible(hashtagTableRow, false);
}
+ StringBuilder sb = new StringBuilder();
+ sb.append(Util.M.changeScreenTitleId(info.idAbbreviated()));
+ if (info.subject() != null) {
+ sb.append(": ");
+ sb.append(info.subject());
+ }
+ setWindowTitle(sb.toString());
+
+ // Although this is related to the revision, we can process it early to
+ // render it faster.
+ if (!info.status().isOpen()
+ || !revision.equals(info.currentRevision())
+ || info.revision(revision).isEdit()) {
+ setVisible(strategy, false);
+ }
+
+ // Properly render revision actions initially while waiting for
+ // the callback to populate them correctly.
+ NativeMap<ActionInfo> emptyMap = NativeMap.<ActionInfo> create();
+ initRevisionsAction(info, revision, emptyMap);
+ quickApprove.setVisible(false);
+ actions.reloadRevisionActions(emptyMap);
+
+ RevisionInfo revisionInfo = info.revision(revision);
+ boolean current = revision.equals(info.currentRevision())
+ && !revisionInfo.isEdit();
+
+ if (revisionInfo.isEdit()) {
+ statusText.setInnerText(Util.C.changeEdit());
+ } else if (!current) {
+ statusText.setInnerText(Util.C.notCurrent());
+ labels.setVisible(false);
+ } else {
+ statusText.setInnerText(Util.toLongString(info.status()));
+ }
+
if (Gerrit.isSignedIn()) {
- replyAction = new ReplyAction(info, revision,
+ replyAction = new ReplyAction(info, revision, hasDraftComments,
style, commentLinkProcessor, reply, quickApprove);
- if (topic.canEdit()) {
- keysAction.add(new KeyCommand(0, 't', Util.C.keyEditTopic()) {
- @Override
- public void onKeyPress(KeyPressEvent event) {
- // In Firefox this event is mistakenly called when F5 is pressed so
- // differentiate F5 from 't' by checking the charCode(F5=0, t=116).
- if (event.getNativeEvent().getCharCode() == 0) {
- Window.Location.reload();
- return;
- }
- topic.onEdit();
- }
- });
- }
}
history.set(commentLinkProcessor, replyAction, changeId, info);
@@ -1108,16 +1174,15 @@
loadSubmitType(info.status(), isSubmittable(info));
} else {
quickApprove.setVisible(false);
- setVisible(strategy, false);
}
+ }
- StringBuilder sb = new StringBuilder();
- sb.append(Util.M.changeScreenTitleId(info.id_abbreviated()));
- if (info.subject() != null) {
- sb.append(": ");
- sb.append(info.subject());
- }
- setWindowTitle(sb.toString());
+ private void renderRevisionInfo(ChangeInfo info,
+ NativeMap<ActionInfo> actionMap) {
+ initRevisionsAction(info, revision, actionMap);
+ commit.setParentNotCurrent(actionMap.containsKey("rebase")
+ && actionMap.get("rebase").enabled());
+ actions.reloadRevisionActions(actionMap);
}
private void renderOwner(ChangeInfo info) {
@@ -1138,7 +1203,7 @@
? info.owner().name()
: info.owner().email() != null
? info.owner().email()
- : String.valueOf(info.owner()._account_id()), Change.Status.NEW));
+ : String.valueOf(info.owner()._accountId()), Change.Status.NEW));
}
private void renderSubmitType(String action) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen.ui.xml
index 6f8d3aa..830369d 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen.ui.xml
@@ -21,7 +21,7 @@
xmlns:x='urn:import:com.google.gerrit.client.ui'>
<ui:with field='ico' type='com.google.gerrit.client.GerritResources'/>
<ui:with field='res' type='com.google.gerrit.client.change.Resources'/>
- <ui:style type='com.google.gerrit.client.change.ChangeScreen.Style'>
+ <ui:style gss='false' type='com.google.gerrit.client.change.ChangeScreen.Style'>
@eval textColor com.google.gerrit.client.Gerrit.getTheme().textColor;
@eval trimColor com.google.gerrit.client.Gerrit.getTheme().trimColor;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CherryPickAction.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CherryPickAction.java
index bcd8f6b..357f04c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CherryPickAction.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CherryPickAction.java
@@ -47,7 +47,7 @@
@Override
public void onSend() {
- ChangeApi.cherrypick(info.legacy_id().get(), revision,
+ ChangeApi.cherrypick(info.legacyId().get(), revision,
getDestinationBranch(),
getMessageText(),
new GerritCallback<ChangeInfo>() {
@@ -55,7 +55,7 @@
public void onSuccess(ChangeInfo result) {
sent = true;
hide();
- Gerrit.display(PageLinks.toChange(result.legacy_id()));
+ Gerrit.display(PageLinks.toChange(result.legacyId()));
}
@Override
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CommitBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CommitBox.java
index 93db1a7..f75f6a1 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CommitBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CommitBox.java
@@ -19,13 +19,11 @@
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.GitwebLink;
import com.google.gerrit.client.WebLinkInfo;
-import com.google.gerrit.client.actions.ActionInfo;
import com.google.gerrit.client.account.AccountInfo;
import com.google.gerrit.client.changes.ChangeInfo;
import com.google.gerrit.client.changes.ChangeInfo.CommitInfo;
import com.google.gerrit.client.changes.ChangeInfo.GitPerson;
import com.google.gerrit.client.changes.ChangeInfo.RevisionInfo;
-import com.google.gerrit.client.rpc.NativeMap;
import com.google.gerrit.client.rpc.Natives;
import com.google.gerrit.client.ui.CommentLinkProcessor;
import com.google.gerrit.client.ui.InlineHyperlink;
@@ -111,8 +109,8 @@
CommitInfo commit = revInfo.commit();
commitName.setText(revision);
- idText.setText("Change-Id: " + change.change_id());
- idText.setPreviewText(change.change_id());
+ idText.setText("Change-Id: " + change.changeId());
+ idText.setPreviewText(change.changeId());
formatLink(commit.author(), authorPanel, authorNameEmail, authorDate,
change);
@@ -127,15 +125,10 @@
}
setParents(change.project(), revInfo.commit().parents());
+ }
+ void setParentNotCurrent(boolean parentNotCurrent) {
// display the orange ball if parent has moved on (not current)
- boolean parentNotCurrent = false;
- if (revInfo.has_actions()) {
- NativeMap<ActionInfo> actions = revInfo.actions();
- if (actions.containsKey("rebase")) {
- parentNotCurrent = actions.get("rebase").enabled();
- }
- }
UIObject.setVisible(parentNotCurrentText, parentNotCurrent);
parentNotCurrentText.setInnerText(parentNotCurrent ? "\u25CF" : "");
}
@@ -148,7 +141,7 @@
gw.getLinkName());
}
- JsArray<WebLinkInfo> links = revInfo.commit().web_links();
+ JsArray<WebLinkInfo> links = revInfo.commit().webLinks();
if (links != null) {
for (WebLinkInfo link : Natives.asList(links)) {
webLinkPanel.add(link.toAnchor());
@@ -198,7 +191,7 @@
a.setStyleName(style.parentWebLink());
panel.add(a);
}
- JsArray<WebLinkInfo> links = c.web_links();
+ JsArray<WebLinkInfo> links = c.webLinks();
if (links != null) {
for (WebLinkInfo link : Natives.asList(links)) {
panel.add(link.toAnchor());
@@ -219,7 +212,7 @@
// only try to fetch the avatar image for author and committer if an avatar
// plugin is installed, if the change owner has no avatar info assume that
// no avatar plugin is installed
- if (change.owner().has_avatar_info()) {
+ if (change.owner().hasAvatarInfo()) {
AvatarImage avatar;
if (change.owner().email().equals(person.email())) {
avatar = new AvatarImage(change.owner());
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CommitBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CommitBox.ui.xml
index 93312fa..5f476be 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CommitBox.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CommitBox.ui.xml
@@ -21,7 +21,7 @@
xmlns:clippy='urn:import:com.google.gwtexpui.clippy.client'>
<ui:with field='ico' type='com.google.gerrit.client.GerritResources'/>
<ui:image field="toggle" src="moreLess.png"/>
- <ui:style type='com.google.gerrit.client.change.CommitBox.Style'>
+ <ui:style gss='false' type='com.google.gerrit.client.change.CommitBox.Style'>
@eval trimColor com.google.gerrit.client.Gerrit.getTheme().trimColor;
.collapsed .scroll { height: 250px }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DeleteFileAction.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DeleteFileAction.java
index ee94564..ce17013 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DeleteFileAction.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DeleteFileAction.java
@@ -1,16 +1,16 @@
-//Copyright (C) 2015 The Android Open Source Project
+// Copyright (C) 2015 The Android Open Source Project
//
-//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
+// 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
+// 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.
+// 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.
package com.google.gerrit.client.change;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DeleteFileBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DeleteFileBox.java
index e55b7ed..aa2b6f0 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DeleteFileBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DeleteFileBox.java
@@ -1,16 +1,16 @@
-//Copyright (C) 2015 The Android Open Source Project
+// Copyright (C) 2015 The Android Open Source Project
//
-//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
+// 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
+// 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.
+// 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.
package com.google.gerrit.client.change;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DeleteFileBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DeleteFileBox.ui.xml
index 4e7b2ba..9e79f752 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DeleteFileBox.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DeleteFileBox.ui.xml
@@ -19,7 +19,7 @@
xmlns:u='urn:import:com.google.gerrit.client.ui'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<ui:with field='res' type='com.google.gerrit.client.change.Resources'/>
- <ui:style>
+ <ui:style gss='false'>
.cancel { float: right; }
</ui:style>
<g:HTMLPanel>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DownloadAction.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DownloadAction.java
index b1bb4e0..34e67dd 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DownloadAction.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DownloadAction.java
@@ -30,7 +30,7 @@
Widget downloadButton) {
super(style, relativeTo, downloadButton);
this.downloadBox = new DownloadBox(info, revision,
- new PatchSet.Id(info.legacy_id(),
+ new PatchSet.Id(info.legacyId(),
info.revision(revision)._number()));
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DownloadBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DownloadBox.java
index 49389f3..0303a88 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DownloadBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DownloadBox.java
@@ -80,7 +80,7 @@
protected void onLoad() {
if (fetch == null) {
if (psId.get() == 0) {
- ChangeApi.editWithCommands(change.legacy_id().get()).get(
+ ChangeApi.editWithCommands(change.legacyId().get()).get(
new AsyncCallback<EditInfo>() {
@Override
public void onSuccess(EditInfo result) {
@@ -93,9 +93,9 @@
}
});
} else {
- RestApi call = ChangeApi.detail(change.legacy_id().get());
+ RestApi call = ChangeApi.detail(change.legacyId().get());
ChangeList.addOptions(call, EnumSet.of(
- revision.equals(change.current_revision())
+ revision.equals(change.currentRevision())
? ListChangesOption.CURRENT_REVISION
: ListChangesOption.ALL_REVISIONS,
ListChangesOption.DOWNLOAD_COMMANDS));
@@ -268,7 +268,7 @@
if (scheme != null && scheme != pref.getDownloadUrl()) {
pref.setDownloadUrl(scheme);
PreferenceInput in = PreferenceInput.create();
- in.download_scheme(scheme);
+ in.downloadScheme(scheme);
AccountApi.self().view("preferences")
.put(in, new AsyncCallback<JavaScriptObject>() {
@Override
@@ -303,11 +303,11 @@
return createObject().cast();
}
- final void download_scheme(DownloadScheme s) {
- download_scheme0(s.name());
+ final void downloadScheme(DownloadScheme s) {
+ downloadScheme0(s.name());
}
- private final native void download_scheme0(String n) /*-{
+ private final native void downloadScheme0(String n) /*-{
this.download_scheme = n;
}-*/;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileComments.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileComments.java
index 7172011..e73c70a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileComments.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileComments.java
@@ -26,8 +26,6 @@
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTMLPanel;
-import java.util.Collections;
-import java.util.Comparator;
import java.util.List;
class FileComments extends Composite {
@@ -38,22 +36,15 @@
@UiField FlowPanel comments;
FileComments(CommentLinkProcessor clp,
- PatchSet.Id ps,
+ PatchSet.Id defaultPs,
String title,
List<CommentInfo> list) {
initWidget(uiBinder.createAndBindUi(this));
- path.setTargetHistoryToken(url(ps, list.get(0)));
+ path.setTargetHistoryToken(url(defaultPs, list.get(0)));
path.setText(title);
-
- Collections.sort(list, new Comparator<CommentInfo>() {
- @Override
- public int compare(CommentInfo a, CommentInfo b) {
- return a.line() - b.line();
- }
- });
for (CommentInfo c : list) {
- comments.add(new LineComment(clp, ps, c));
+ comments.add(new LineComment(clp, defaultPs, c));
}
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileComments.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileComments.ui.xml
index 5de04cc..e463e95 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileComments.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileComments.ui.xml
@@ -18,7 +18,7 @@
xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:c='urn:import:com.google.gerrit.client.ui'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
- <ui:style>
+ <ui:style gss='false'>
.box {
}
.path {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java
index 2947be8..dd8df36 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java
@@ -87,7 +87,7 @@
String deltaColumn2();
String inserted();
String deleted();
- String removeButton();
+ String restoreDelete();
}
public static enum Mode {
@@ -516,8 +516,8 @@
for (int i = 0; i < list.length(); i++) {
FileInfo info = list.get(i);
if (!Patch.COMMIT_MSG.equals(info.path()) && !info.binary()) {
- inserted += info.lines_inserted();
- deleted += info.lines_deleted();
+ inserted += info.linesInserted();
+ deleted += info.linesDeleted();
}
}
}
@@ -548,7 +548,7 @@
if (mode == Mode.REVIEW) {
sb.openTh().setStyleName(R.css().reviewed()).closeTh();
} else {
- sb.openTh().setStyleName(R.css().removeButton()).closeTh();
+ sb.openTh().setStyleName(R.css().restoreDelete()).closeTh();
}
sb.openTh().setStyleName(R.css().status()).closeTh();
sb.openTh().append(Util.C.patchTableColumnName()).closeTh();
@@ -592,20 +592,26 @@
}
private void columnDeleteRestore(SafeHtmlBuilder sb, FileInfo info) {
- sb.openTd().setStyleName(R.css().removeButton());
+ sb.openTd().setStyleName(R.css().restoreDelete());
if (hasUser) {
if (!Patch.COMMIT_MSG.equals(info.path())) {
boolean editable = isEditable(info);
- sb.openElement("button")
- .setAttribute("title", editable
- ? Resources.C.removeFileInline()
- : Resources.C.restoreFileInline())
- .setAttribute("onclick", (editable ? DELETE : RESTORE)
- + "(event," + info._row() + ")")
- .append(new ImageResourceRenderer().render(editable
- ? Gerrit.RESOURCES.redNot()
- : Gerrit.RESOURCES.editUndo()))
+ sb.openDiv()
+ .openElement("button")
+ .setAttribute("title", Resources.C.restoreFileInline())
+ .setAttribute("onclick", RESTORE + "(event," + info._row() + ")")
+ .append(new ImageResourceRenderer().render(
+ Gerrit.RESOURCES.editUndo()))
.closeElement("button");
+ if (editable) {
+ sb.openElement("button")
+ .setAttribute("title", Resources.C.removeFileInline())
+ .setAttribute("onclick", DELETE + "(event," + info._row() + ")")
+ .append(new ImageResourceRenderer().render(
+ Gerrit.RESOURCES.redNot()))
+ .closeElement("button");
+ }
+ sb.closeDiv();
}
}
sb.closeTd();
@@ -657,10 +663,10 @@
}
sb.closeAnchor();
- if (info.old_path() != null) {
+ if (info.oldPath() != null) {
sb.br();
sb.openSpan().setStyleName(R.css().renameCopySource())
- .append(info.old_path())
+ .append(info.oldPath())
.closeSpan();
}
sb.closeTd();
@@ -733,16 +739,16 @@
sb.openTd().setStyleName(R.css().deltaColumn1());
if (!Patch.COMMIT_MSG.equals(info.path()) && !info.binary()) {
if (showChangeSizeBars) {
- sb.append(info.lines_inserted() + info.lines_deleted());
+ sb.append(info.linesInserted() + info.linesDeleted());
} else if (!ChangeType.DELETED.matches(info.status())) {
if (ChangeType.ADDED.matches(info.status())) {
- sb.append(info.lines_inserted())
+ sb.append(info.linesInserted())
.append(" lines");
} else {
sb.append("+")
- .append(info.lines_inserted())
+ .append(info.linesInserted())
.append(", -")
- .append(info.lines_deleted());
+ .append(info.linesDeleted());
}
}
}
@@ -753,24 +759,24 @@
sb.openTd().setStyleName(R.css().deltaColumn2());
if (showChangeSizeBars
&& !Patch.COMMIT_MSG.equals(info.path()) && !info.binary()
- && (info.lines_inserted() != 0 || info.lines_deleted() != 0)) {
+ && (info.linesInserted() != 0 || info.linesDeleted() != 0)) {
int w = 80;
int t = inserted + deleted;
- int i = Math.max(5, (int) (((double) w) * info.lines_inserted() / t));
- int d = Math.max(5, (int) (((double) w) * info.lines_deleted() / t));
+ int i = Math.max(5, (int) (((double) w) * info.linesInserted() / t));
+ int d = Math.max(5, (int) (((double) w) * info.linesDeleted() / t));
sb.setAttribute(
"title",
- Util.M.patchTableSize_LongModify(info.lines_inserted(),
- info.lines_deleted()));
+ Util.M.patchTableSize_LongModify(info.linesInserted(),
+ info.linesDeleted()));
- if (0 < info.lines_inserted()) {
+ if (0 < info.linesInserted()) {
sb.openDiv()
.setStyleName(R.css().inserted())
.setAttribute("style", "width:" + i + "px")
.closeDiv();
}
- if (0 < info.lines_deleted()) {
+ if (0 < info.linesDeleted()) {
sb.openDiv()
.setStyleName(R.css().deleted())
.setAttribute("style", "width:" + d + "px")
@@ -786,7 +792,7 @@
if (mode == Mode.REVIEW) {
sb.openTh().setStyleName(R.css().reviewed()).closeTh();
} else {
- sb.openTh().setStyleName(R.css().removeButton()).closeTh();
+ sb.openTh().setStyleName(R.css().restoreDelete()).closeTh();
}
sb.openTh().setStyleName(R.css().status()).closeTh();
sb.openTd().closeTd(); // path
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FollowUpAction.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FollowUpAction.java
index 5a7df72..30394d6 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FollowUpAction.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FollowUpAction.java
@@ -39,7 +39,7 @@
new GerritCallback<ChangeInfo>() {
@Override
public void onSuccess(ChangeInfo result) {
- Gerrit.display(PageLinks.toChange(result.legacy_id()));
+ Gerrit.display(PageLinks.toChange(result.legacyId()));
hide();
}
});
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Hashtags.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Hashtags.java
index faba10d..d2afbcf 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Hashtags.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Hashtags.java
@@ -51,6 +51,8 @@
private static final String REMOVE;
private static final String DATA_ID = "data-id";
+ private boolean canEdit;
+
static {
REMOVE = DOM.createUniqueId().replace('-', '_');
init(REMOVE);
@@ -121,9 +123,10 @@
}
void set(ChangeInfo info) {
- this.changeId = info.legacy_id();
+ canEdit = info.hasActions() && info.actions().containsKey("hashtags");
+ this.changeId = info.legacyId();
display(info);
- openForm.setVisible(Gerrit.isSignedIn());
+ openForm.setVisible(canEdit);
}
@UiHandler("openForm")
@@ -165,13 +168,15 @@
"#" + PageLinks.toChangeQuery("hashtag:\"" + hashtagName + "\""))
.setAttribute("role", "listitem")
.append("#").append(hashtagName)
- .closeAnchor()
- .openElement("button")
- .setAttribute("title", "Remove hashtag")
- .setAttribute("onclick", REMOVE + "(event)")
- .append("×")
- .closeElement("button")
- .closeSpan();
+ .closeAnchor();
+ if (canEdit) {
+ html.openElement("button")
+ .setAttribute("title", "Remove hashtag")
+ .setAttribute("onclick", REMOVE + "(event)")
+ .append("×")
+ .closeElement("button");
+ }
+ html.closeSpan();
if (itr.hasNext()) {
html.append(' ');
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Hashtags.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Hashtags.ui.xml
index dd06c77..ba4d6cc 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Hashtags.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Hashtags.ui.xml
@@ -19,7 +19,7 @@
xmlns:c='urn:import:com.google.gwtexpui.globalkey.client'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<ui:with field='res' type='com.google.gerrit.client.change.Resources'/>
- <ui:style>
+ <ui:style gss='false'>
button.openAdd {
margin: 3px 3px 0 0;
float: right;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/History.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/History.java
index 7635d81..47a870b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/History.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/History.java
@@ -14,8 +14,6 @@
package com.google.gerrit.client.change;
-import com.google.gerrit.client.account.AccountInfo;
-import com.google.gerrit.client.changes.ChangeApi;
import com.google.gerrit.client.changes.ChangeInfo;
import com.google.gerrit.client.changes.ChangeInfo.MessageInfo;
import com.google.gerrit.client.changes.CommentInfo;
@@ -23,9 +21,7 @@
import com.google.gerrit.client.rpc.Natives;
import com.google.gerrit.client.ui.CommentLinkProcessor;
import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gwt.core.client.JsArray;
-import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Widget;
@@ -33,22 +29,15 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Set;
class History extends FlowPanel {
private CommentLinkProcessor clp;
private ReplyAction replyAction;
private Change.Id changeId;
- private final Set<Integer> loaded = new HashSet<>();
- private final Map<AuthorRevision, List<CommentInfo>> byAuthor =
- new HashMap<>();
-
- private final List<Integer> toLoad = new ArrayList<>(4);
- private int active;
+ private final Map<Integer, List<CommentInfo>> byAuthor = new HashMap<>();
void set(CommentLinkProcessor clp, ReplyAction ra,
Change.Id id, ChangeInfo info) {
@@ -60,9 +49,7 @@
if (messages != null) {
for (MessageInfo msg : Natives.asList(messages)) {
Message ui = new Message(this, msg);
- if (loaded.contains(msg._revisionNumber())) {
- ui.addComments(comments(msg));
- }
+ ui.addComments(comments(msg));
add(ui);
}
autoOpen(ChangeScreen.myLastReply(info));
@@ -99,18 +86,16 @@
replyAction.onReply(info);
}
- void addComments(int id, NativeMap<JsArray<CommentInfo>> map) {
- loaded.add(id);
-
+ void addComments(NativeMap<JsArray<CommentInfo>> map) {
for (String path : map.keySet()) {
for (CommentInfo c : Natives.asList(map.get(path))) {
c.path(path);
if (c.author() != null) {
- AuthorRevision k = new AuthorRevision(c.author(), id);
- List<CommentInfo> l = byAuthor.get(k);
+ int authorId = c.author()._accountId();
+ List<CommentInfo> l = byAuthor.get(authorId);
if (l == null) {
l = new ArrayList<>();
- byAuthor.put(k, l);
+ byAuthor.put(authorId, l);
}
l.add(c);
}
@@ -118,58 +103,13 @@
}
}
- void load(int revisionNumber) {
- if (revisionNumber > 0 && loaded.add(revisionNumber)) {
- toLoad.add(revisionNumber);
- start();
- }
- }
-
- private void start() {
- if (active >= 2 || toLoad.isEmpty() || !isAttached()) {
- return;
- }
-
- final int revisionNumber = toLoad.remove(0);
- active++;
- ChangeApi.revision(new PatchSet.Id(changeId, revisionNumber))
- .view("comments")
- .get(new AsyncCallback<NativeMap<JsArray<CommentInfo>>>() {
- @Override
- public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
- addComments(revisionNumber, result);
- update(revisionNumber);
- --active;
- start();
- }
-
- @Override
- public void onFailure(Throwable caught) {
- loaded.remove(revisionNumber);
- loaded.removeAll(toLoad);
- toLoad.clear();
- active--;
- }
- });
- }
-
- private void update(int revisionNumber) {
- for (Widget child : getChildren()) {
- Message ui = (Message) child;
- MessageInfo info = ui.getMessageInfo();
- if (info._revisionNumber() == revisionNumber) {
- ui.addComments(comments(info));
- }
- }
- }
-
private List<CommentInfo> comments(MessageInfo msg) {
if (msg.author() == null) {
return Collections.emptyList();
}
- AuthorRevision k = new AuthorRevision(msg.author(), msg._revisionNumber());
- List<CommentInfo> list = byAuthor.get(k);
+ int authorId = msg.author()._accountId();
+ List<CommentInfo> list = byAuthor.get(authorId);
if (list == null) {
return Collections.emptyList();
}
@@ -187,34 +127,10 @@
if (match.isEmpty()) {
return Collections.emptyList();
} else if (other.isEmpty()) {
- byAuthor.remove(k);
+ byAuthor.remove(authorId);
} else {
- byAuthor.put(k, other);
+ byAuthor.put(authorId, other);
}
return match;
}
-
- private static final class AuthorRevision {
- final int author;
- final int revision;
-
- AuthorRevision(AccountInfo author, int revision) {
- this.author = author._account_id();
- this.revision = revision;
- }
-
- @Override
- public int hashCode() {
- return author * 31 + revision;
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof AuthorRevision)) {
- return false;
- }
- AuthorRevision b = (AuthorRevision) o;
- return author == b.author && revision == b.revision;
- }
- }
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/IncludedInBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/IncludedInBox.ui.xml
index 59b05f0..e59420c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/IncludedInBox.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/IncludedInBox.ui.xml
@@ -17,7 +17,7 @@
<ui:UiBinder
xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
- <ui:style type='com.google.gerrit.client.change.IncludedInBox.Style'>
+ <ui:style gss='false' type='com.google.gerrit.client.change.IncludedInBox.Style'>
.includedInBox {
min-width: 300px;
max-width: 580px;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Labels.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Labels.java
index a416894..f192a71 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Labels.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Labels.java
@@ -115,7 +115,8 @@
private Widget renderUsers(LabelInfo label) {
Map<Integer, List<ApprovalInfo>> m = new HashMap<>(4);
- int approved = 0, rejected = 0;
+ int approved = 0;
+ int rejected = 0;
for (ApprovalInfo ai : Natives.asList(label.all())) {
if (ai.value() != 0) {
@@ -142,7 +143,7 @@
String val = LabelValue.formatValue(v.shortValue());
html.openSpan();
- html.setAttribute("title", label.value_text(val));
+ html.setAttribute("title", label.valueText(val));
if (v.intValue() == approved) {
html.setStyleName(style.label_ok());
} else if (v.intValue() == rejected) {
@@ -171,12 +172,12 @@
private static boolean isApproved(LabelInfo label, ApprovalInfo ai) {
return label.approved() != null
- && label.approved()._account_id() == ai._account_id();
+ && label.approved()._accountId() == ai._accountId();
}
private static boolean isRejected(LabelInfo label, ApprovalInfo ai) {
return label.rejected() != null
- && label.rejected()._account_id() == ai._account_id();
+ && label.rejected()._accountId() == ai._accountId();
}
private String getStyleForLabel(LabelInfo label) {
@@ -233,12 +234,12 @@
} else if (ai.email() != null) {
name = ai.email();
} else {
- name = Integer.toString(ai._account_id());
+ name = Integer.toString(ai._accountId());
}
String votableCategories = "";
if (votable != null) {
- Set<String> s = votable.get(ai._account_id()).votableLabels();
+ Set<String> s = votable.get(ai._accountId()).votableLabels();
if (!s.isEmpty()) {
StringBuilder sb = new StringBuilder(Util.C.votable());
sb.append(" ");
@@ -253,7 +254,7 @@
}
html.openSpan()
.setAttribute("role", "listitem")
- .setAttribute(DATA_ID, ai._account_id())
+ .setAttribute(DATA_ID, ai._accountId())
.setAttribute("title", getTitle(ai, votableCategories))
.setStyleName(style.label_user());
if (img != null) {
@@ -269,7 +270,7 @@
html.closeSelf();
}
html.append(name);
- if (removable.contains(ai._account_id())) {
+ if (removable.contains(ai._accountId())) {
html.openElement("button")
.setAttribute("title", Util.M.removeReviewer(name))
.setAttribute("onclick", REMOVE + "(event)")
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/LineComment.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/LineComment.java
index 8fa5a68..2d5dce0 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/LineComment.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/LineComment.java
@@ -33,15 +33,30 @@
interface Binder extends UiBinder<HTMLPanel, LineComment> {}
private static final Binder uiBinder = GWT.create(Binder.class);
+ @UiField Element psLoc;
+ @UiField Element psNum;
@UiField Element fileLoc;
@UiField Element lineLoc;
@UiField InlineHyperlink line;
@UiField Element message;
- LineComment(CommentLinkProcessor clp, PatchSet.Id ps, CommentInfo info) {
+ LineComment(CommentLinkProcessor clp,
+ PatchSet.Id defaultPs,
+ CommentInfo info) {
initWidget(uiBinder.createAndBindUi(this));
- if (info.has_line()) {
+ PatchSet.Id ps;
+ if (info.patchSet() != defaultPs.get()) {
+ ps = new PatchSet.Id(defaultPs.getParentKey(), info.patchSet());
+ psNum.setInnerText(Integer.toString(info.patchSet()));
+ } else {
+ ps = defaultPs;
+ psLoc.removeFromParent();
+ psLoc = null;
+ psNum= null;
+ }
+
+ if (info.hasLine()) {
fileLoc.removeFromParent();
fileLoc = null;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/LineComment.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/LineComment.ui.xml
index 8dc1245..2890832 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/LineComment.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/LineComment.ui.xml
@@ -18,7 +18,7 @@
xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:c='urn:import:com.google.gerrit.client.ui'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
- <ui:style>
+ <ui:style gss='false'>
.box {
position: relative;
}
@@ -29,13 +29,16 @@
font-weight: bold;
}
.message {
- margin-left: 111px;
+ margin-left: 135px;
}
</ui:style>
<g:HTMLPanel styleName='{style.box}'>
- <div class='{style.location}' ui:field='fileLoc'><ui:msg>File Comment</ui:msg></div>
- <div class='{style.location}' ui:field='lineLoc'><ui:msg>Line <c:InlineHyperlink ui:field='line'/>:</ui:msg></div>
+ <div class='{style.location}'>
+ <span ui:field='psLoc'><ui:msg>PS<span ui:field='psNum'/>, </ui:msg></span>
+ <span ui:field='fileLoc'><ui:msg>File Comment</ui:msg></span>
+ <span ui:field='lineLoc'><ui:msg>Line <c:InlineHyperlink ui:field='line'/>:</ui:msg></span>
+ </div>
<div class='{style.message}' ui:field='message'/>
</g:HTMLPanel>
</ui:UiBinder>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Message.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Message.java
index 22d39a7..bc1ac30 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Message.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Message.java
@@ -121,13 +121,9 @@
}
void setOpen(boolean open) {
- if (open && info._revisionNumber() > 0) {
- if (commentList == null) {
- history.load(info._revisionNumber());
- } else if (!commentList.isEmpty()) {
- renderComments(commentList);
- commentList = Collections.emptyList();
- }
+ if (open && info._revisionNumber() > 0 && !commentList.isEmpty()) {
+ renderComments(commentList);
+ commentList = Collections.emptyList();
}
setName(open);
@@ -156,7 +152,6 @@
void autoOpen() {
if (commentList == null) {
autoOpen = true;
- history.load(info._revisionNumber());
} else if (!commentList.isEmpty()) {
setOpen(true);
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Message.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Message.ui.xml
index 42cb39b..e362c07 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Message.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Message.ui.xml
@@ -18,7 +18,7 @@
xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:c='urn:import:com.google.gerrit.client'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
- <ui:style type='com.google.gerrit.client.change.Message.Style'>
+ <ui:style gss='false' type='com.google.gerrit.client.change.Message.Style'>
.messageBox {
position: relative;
width: 1168px;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/PatchSetsBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/PatchSetsBox.java
index 665eff5..f3ab35e 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/PatchSetsBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/PatchSetsBox.java
@@ -128,7 +128,7 @@
@Override
public void onSuccess(ChangeInfo result) {
if (edit != null) {
- edit.set_name(edit.commit().commit());
+ edit.setName(edit.commit().commit());
result.revisions().put(edit.name(), RevisionInfo.fromEdit(edit));
}
render(result.revisions());
@@ -187,7 +187,7 @@
if (r.draft()) {
sb.append(Resources.C.draft()).append(' ');
}
- if (r.has_draft_comments()) {
+ if (r.hasDraftComments()) {
sb.openSpan()
.addStyleName(style.draft_comment())
.setAttribute("title", Resources.C.draftCommentsTooltip())
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/PatchSetsBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/PatchSetsBox.ui.xml
index bd69cd6..7537aa4 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/PatchSetsBox.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/PatchSetsBox.ui.xml
@@ -18,7 +18,7 @@
xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<ui:with field='res' type='com.google.gerrit.client.change.Resources'/>
- <ui:style type='com.google.gerrit.client.change.PatchSetsBox.Style'>
+ <ui:style gss='false' type='com.google.gerrit.client.change.PatchSetsBox.Style'>
@eval selectionColor com.google.gerrit.client.Gerrit.getTheme().selectionColor;
.revisionBox {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/QuickApprove.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/QuickApprove.java
index 6638dbe..105a3c8 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/QuickApprove.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/QuickApprove.java
@@ -19,6 +19,7 @@
import com.google.gerrit.client.changes.ChangeInfo;
import com.google.gerrit.client.changes.ChangeInfo.LabelInfo;
import com.google.gerrit.client.changes.ReviewInput;
+import com.google.gerrit.client.changes.ReviewInput.DraftHandling;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.rpc.Natives;
import com.google.gerrit.common.PageLinks;
@@ -41,12 +42,12 @@
}
void set(ChangeInfo info, String commit, ReplyAction action) {
- if (!info.has_permitted_labels() || !info.status().isOpen()) {
+ if (!info.hasPermittedLabels() || !info.status().isOpen()) {
// Quick approve needs at least one label on an open change.
setVisible(false);
return;
}
- if (info.revision(commit).is_edit() || info.revision(commit).draft()) {
+ if (info.revision(commit).isEdit() || info.revision(commit).draft()) {
setVisible(false);
return;
}
@@ -55,52 +56,28 @@
String qValueStr = null;
short qValue = 0;
- for (LabelInfo label : Natives.asList(info.all_labels().values())) {
- if (!info.permitted_labels().containsKey(label.name())) {
- continue;
- }
-
- JsArrayString values = info.permitted_values(label.name());
- if (values.length() == 0) {
- continue;
- }
-
- switch (label.status()) {
- case NEED: // Label is required for submit.
- break;
-
- case OK: // Label already applied.
- case MAY: // Label is not required.
- continue;
-
- case REJECT: // Submit cannot happen, do not quick approve.
- case IMPOSSIBLE:
- setVisible(false);
- return;
- }
-
+ int index = info.getMissingLabelIndex();
+ if (index != -1) {
+ LabelInfo label = Natives.asList(info.allLabels().values()).get(index);
+ JsArrayString values = info.permittedValues(label.name());
String s = values.get(values.length() - 1);
short v = LabelInfo.parseValue(s);
- if (v > 0 && s.equals(label.max_value())) {
- if (qName != null) {
- // Quick approve is available for one label only.
- setVisible(false);
- return;
- }
-
+ if (v > 0 && s.equals(label.maxValue())) {
qName = label.name();
qValueStr = s;
qValue = v;
}
}
- if (qName != null) {
- changeId = info.legacy_id();
+ if (qName != null) {
+ changeId = info.legacyId();
revision = commit;
input = ReviewInput.create();
+ input.drafts(DraftHandling.PUBLISH_ALL_REVISIONS);
input.label(qName, qValue);
replyAction = action;
setText(qName + qValueStr);
+ setVisible(true);
} else {
setVisible(false);
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java
index 0c78a67..0020c50 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java
@@ -59,6 +59,7 @@
String pointer();
String row();
String subject();
+ String submittable();
String tabPanel();
}
@@ -171,6 +172,7 @@
getTab(Tab.CHERRY_PICKS).setShowBranches(true);
getTab(Tab.SAME_TOPIC).setShowBranches(true);
getTab(Tab.SAME_TOPIC).setShowProjects(true);
+ getTab(Tab.SAME_TOPIC).setShowSubmittable(true);
}
void set(final ChangeInfo info, final String revision) {
@@ -178,7 +180,7 @@
setForOpenChange(info, revision);
}
- ChangeApi.revision(info.legacy_id().get(), revision).view("related")
+ ChangeApi.revision(info.legacyId().get(), revision).view("related")
.get(new TabCallback<RelatedInfo>(Tab.RELATED_CHANGES, info.project(), revision) {
@Override
public JsArray<ChangeAndCommit> convert(RelatedInfo result) {
@@ -188,8 +190,8 @@
StringBuilder cherryPicksQuery = new StringBuilder();
cherryPicksQuery.append(op("project", info.project()));
- cherryPicksQuery.append(" ").append(op("change", info.change_id()));
- cherryPicksQuery.append(" ").append(op("-change", info.legacy_id().get()));
+ cherryPicksQuery.append(" ").append(op("change", info.changeId()));
+ cherryPicksQuery.append(" ").append(op("-change", info.legacyId().get()));
cherryPicksQuery.append(" -is:abandoned");
ChangeList.query(cherryPicksQuery.toString(),
EnumSet.of(ListChangesOption.CURRENT_REVISION, ListChangesOption.CURRENT_COMMIT),
@@ -199,9 +201,11 @@
StringBuilder topicQuery = new StringBuilder();
topicQuery.append("status:open");
topicQuery.append(" ").append(op("topic", info.topic()));
- topicQuery.append(" ").append(op("-change", info.legacy_id().get()));
ChangeList.query(topicQuery.toString(),
- EnumSet.of(ListChangesOption.CURRENT_REVISION, ListChangesOption.CURRENT_COMMIT),
+ EnumSet.of(ListChangesOption.CURRENT_REVISION,
+ ListChangesOption.CURRENT_COMMIT,
+ ListChangesOption.DETAILED_LABELS,
+ ListChangesOption.LABELS),
new TabChangeListCallback(Tab.SAME_TOPIC, info.project(), revision));
}
}
@@ -211,7 +215,7 @@
StringBuilder conflictsQuery = new StringBuilder();
conflictsQuery.append("status:open");
conflictsQuery.append(" is:mergeable");
- conflictsQuery.append(" ").append(op("conflicts", info.legacy_id().get()));
+ conflictsQuery.append(" ").append(op("conflicts", info.legacyId().get()));
ChangeList.query(conflictsQuery.toString(),
EnumSet.of(ListChangesOption.CURRENT_REVISION, ListChangesOption.CURRENT_COMMIT),
new TabChangeListCallback(Tab.CONFLICTING_CHANGES, info.project(), revision));
@@ -319,15 +323,16 @@
protected JsArray<ChangeAndCommit> convert(ChangeList l) {
JsArray<ChangeAndCommit> arr = JavaScriptObject.createArray().cast();
for (ChangeInfo i : Natives.asList(l)) {
- if (i.current_revision() != null && i.revisions().containsKey(i.current_revision())) {
- RevisionInfo currentRevision = i.revision(i.current_revision());
+ if (i.currentRevision() != null && i.revisions().containsKey(i.currentRevision())) {
+ RevisionInfo currentRevision = i.revision(i.currentRevision());
ChangeAndCommit c = ChangeAndCommit.create();
- c.set_id(i.id());
- c.set_commit(currentRevision.commit());
- c.set_change_number(i.legacy_id().get());
- c.set_revision_number(currentRevision._number());
- c.set_branch(i.branch());
- c.set_project(i.project());
+ c.setId(i.id());
+ c.setCommit(currentRevision.commit());
+ c.setChangeNumber(i.legacyId().get());
+ c.setRevisionNumber(currentRevision._number());
+ c.setBranch(i.branch());
+ c.setProject(i.project());
+ c.setSubmittable(i.submittable() && i.mergeable());
arr.push(c);
}
}
@@ -350,56 +355,60 @@
public final native CommitInfo commit() /*-{ return this.commit }-*/;
final native String branch() /*-{ return this.branch }-*/;
final native String project() /*-{ return this.project }-*/;
+ final native boolean submittable() /*-{ return this._submittable ? true : false; }-*/;
- final native void set_id(String i)
+ final native void setId(String i)
/*-{ if(i)this.change_id=i; }-*/;
- final native void set_commit(CommitInfo c)
+ final native void setCommit(CommitInfo c)
/*-{ if(c)this.commit=c; }-*/;
- final native void set_branch(String b)
+ final native void setBranch(String b)
/*-{ if(b)this.branch=b; }-*/;
- final native void set_project(String b)
+ final native void setProject(String b)
/*-{ if(b)this.project=b; }-*/;
- public final Change.Id legacy_id() {
- return has_change_number() ? new Change.Id(_change_number()) : null;
+ public final Change.Id legacyId() {
+ return hasChangeNumber() ? new Change.Id(_changeNumber()) : null;
}
- public final PatchSet.Id patch_set_id() {
- return has_change_number() && has_revision_number()
- ? new PatchSet.Id(legacy_id(), _revision_number())
+ public final PatchSet.Id patchSetId() {
+ return hasChangeNumber() && hasRevisionNumber()
+ ? new PatchSet.Id(legacyId(), _revisionNumber())
: null;
}
- public final native boolean has_change_number()
+ public final native boolean hasChangeNumber()
/*-{ return this.hasOwnProperty('_change_number') }-*/;
- final native boolean has_revision_number()
+ final native boolean hasRevisionNumber()
/*-{ return this.hasOwnProperty('_revision_number') }-*/;
- final native boolean has_current_revision_number()
+ final native boolean hasCurrentRevisionNumber()
/*-{ return this.hasOwnProperty('_current_revision_number') }-*/;
- final native int _change_number()
+ final native int _changeNumber()
/*-{ return this._change_number }-*/;
- final native int _revision_number()
+ final native int _revisionNumber()
/*-{ return this._revision_number }-*/;
- final native int _current_revision_number()
+ final native int _currentRevisionNumber()
/*-{ return this._current_revision_number }-*/;
- final native void set_change_number(int n)
+ final native void setChangeNumber(int n)
/*-{ this._change_number=n; }-*/;
- final native void set_revision_number(int n)
+ final native void setRevisionNumber(int n)
/*-{ this._revision_number=n; }-*/;
- final native void set_current_revision_number(int n)
+ final native void setCurrentRevisionNumber(int n)
/*-{ this._current_revision_number=n; }-*/;
+ final native void setSubmittable(boolean s)
+ /*-{ this._submittable=s; }-*/;
+
protected ChangeAndCommit() {
}
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChangesTab.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChangesTab.java
index 96d0d10..1a09fc5 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChangesTab.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChangesTab.java
@@ -68,7 +68,8 @@
AbstractImagePrototype.create(Gerrit.RESOURCES.arrowRight()).getSafeHtml();
private static final native String init(String o) /*-{
- $wnd[o] = $entry(@com.google.gerrit.client.change.RelatedChangesTab::onOpen(Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/dom/client/Element;));
+ $wnd[o] = $entry(@com.google.gerrit.client.change.RelatedChangesTab::onOpen(
+ Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/dom/client/Element;));
return o + '(event,this)';
}-*/;
@@ -86,6 +87,7 @@
private boolean showBranches;
private boolean showProjects;
+ private boolean showSubmittable;
private boolean showIndirectAncestors;
private boolean registerKeys;
private int maxHeight;
@@ -111,6 +113,10 @@
this.showProjects = showProjects;
}
+ void setShowSubmittable(boolean submittable) {
+ this.showSubmittable = submittable;
+ }
+
void setShowIndirectAncestors(boolean showIndirectAncestors) {
this.showIndirectAncestors = showIndirectAncestors;
}
@@ -296,19 +302,23 @@
sb.openSpan();
GitwebLink gw = Gerrit.getGitwebLink();
- if (gw != null && (!info.has_change_number() || !info.has_revision_number())) {
+ if (gw != null && (!info.hasChangeNumber() || !info.hasRevisionNumber())) {
sb.setStyleName(RelatedChanges.R.css().gitweb());
sb.setAttribute("title", gw.getLinkName());
- sb.append('\u25CF');
+ sb.append('\u25CF'); // Unicode 'BLACK CIRCLE'
} else if (notConnected) {
sb.setStyleName(RelatedChanges.R.css().indirect());
sb.setAttribute("title", Resources.C.indirectAncestor());
sb.append('~');
- } else if (info.has_current_revision_number() && info.has_revision_number()
- && info._current_revision_number() != info._revision_number()) {
+ } else if (info.hasCurrentRevisionNumber() && info.hasRevisionNumber()
+ && info._currentRevisionNumber() != info._revisionNumber()) {
sb.setStyleName(RelatedChanges.R.css().notCurrent());
sb.setAttribute("title", Util.C.notCurrent());
- sb.append('\u25CF');
+ sb.append('\u25CF'); // Unicode 'BLACK CIRCLE'
+ } else if (showSubmittable && info.submittable()) {
+ sb.setStyleName(RelatedChanges.R.css().submittable());
+ sb.setAttribute("title", Util.C.submittable());
+ sb.append('\u2713'); // Unicode 'CHECK MARK'
} else {
sb.setStyleName(RelatedChanges.R.css().current());
}
@@ -318,8 +328,8 @@
}
private String url() {
- if (info.has_change_number() && info.has_revision_number()) {
- PatchSet.Id id = info.patch_set_id();
+ if (info.hasChangeNumber() && info.hasRevisionNumber()) {
+ PatchSet.Id id = info.patchSetId();
return "#" + PageLinks.toChange(
id.getParentKey(),
id.getId());
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RenameFileAction.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RenameFileAction.java
index 1f11e65..d4b6c42 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RenameFileAction.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RenameFileAction.java
@@ -1,16 +1,16 @@
-//Copyright (C) 2015 The Android Open Source Project
+// Copyright (C) 2015 The Android Open Source Project
//
-//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
+// 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
+// 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.
+// 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.
package com.google.gerrit.client.change;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RenameFileBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RenameFileBox.java
index 77348f7..d6ab9ae 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RenameFileBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RenameFileBox.java
@@ -1,16 +1,16 @@
-//Copyright (C) 2015 The Android Open Source Project
+// Copyright (C) 2015 The Android Open Source Project
//
-//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
+// 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
+// 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.
+// 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.
package com.google.gerrit.client.change;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RenameFileBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RenameFileBox.ui.xml
index 27849ee..17e8797 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RenameFileBox.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RenameFileBox.ui.xml
@@ -20,7 +20,7 @@
xmlns:u='urn:import:com.google.gerrit.client.ui'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<ui:with field='res' type='com.google.gerrit.client.change.Resources'/>
- <ui:style>
+ <ui:style gss='false'>
.cancel { float: right; }
</ui:style>
<g:HTMLPanel>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyAction.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyAction.java
index 6e40979..cccab34 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyAction.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyAction.java
@@ -33,6 +33,7 @@
class ReplyAction {
private final PatchSet.Id psId;
private final String revision;
+ private final boolean hasDraftComments;
private final ChangeScreen.Style style;
private final CommentLinkProcessor clp;
private final Widget replyButton;
@@ -47,23 +48,25 @@
ReplyAction(
ChangeInfo info,
String revision,
+ boolean hasDraftComments,
ChangeScreen.Style style,
CommentLinkProcessor clp,
Widget replyButton,
Widget quickApproveButton) {
this.psId = new PatchSet.Id(
- info.legacy_id(),
+ info.legacyId(),
info.revisions().get(revision)._number());
this.revision = revision;
+ this.hasDraftComments = hasDraftComments;
this.style = style;
this.clp = clp;
this.replyButton = replyButton;
this.quickApproveButton = quickApproveButton;
- boolean current = revision.equals(info.current_revision());
- allLabels = info.all_labels();
- permittedLabels = current && info.has_permitted_labels()
- ? info.permitted_labels()
+ boolean current = revision.equals(info.currentRevision());
+ allLabels = info.allLabels();
+ permittedLabels = current && info.hasPermittedLabels()
+ ? info.permittedLabels()
: NativeMap.<JsArrayString> create();
}
@@ -111,11 +114,15 @@
public void onClose(CloseEvent<PopupPanel> event) {
if (popup == p) {
popup = null;
+ if (hasDraftComments || replyBox.hasMessage()) {
+ replyButton.setStyleName(style.highlight());
+ }
}
}
});
p.add(replyBox);
Window.scrollTo(0, 0);
+ replyButton.removeStyleName(style.highlight());
p.showRelativeTo(replyButton);
GlobalKey.dialog(p);
popup = p;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyBox.java
index f9054fe..aec617a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyBox.java
@@ -21,9 +21,9 @@
import com.google.gerrit.client.changes.ChangeInfo.ApprovalInfo;
import com.google.gerrit.client.changes.ChangeInfo.LabelInfo;
import com.google.gerrit.client.changes.ChangeInfo.MessageInfo;
-import com.google.gerrit.client.changes.CommentApi;
import com.google.gerrit.client.changes.CommentInfo;
import com.google.gerrit.client.changes.ReviewInput;
+import com.google.gerrit.client.changes.ReviewInput.DraftHandling;
import com.google.gerrit.client.changes.Util;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.rpc.NativeMap;
@@ -140,19 +140,19 @@
protected void onLoad() {
commentsPanel.setVisible(false);
post.setEnabled(false);
- CommentApi.drafts(psId, new AsyncCallback<NativeMap<JsArray<CommentInfo>>>() {
- @Override
- public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
- attachComments(result);
- displayComments(result);
- post.setEnabled(true);
- }
+ ChangeApi.drafts(psId.getParentKey().get())
+ .get(new AsyncCallback<NativeMap<JsArray<CommentInfo>>>() {
+ @Override
+ public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
+ displayComments(result);
+ post.setEnabled(true);
+ }
- @Override
- public void onFailure(Throwable caught) {
- post.setEnabled(true);
- }
- });
+ @Override
+ public void onFailure(Throwable caught) {
+ post.setEnabled(true);
+ }
+ });
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
@@ -180,8 +180,15 @@
postReview();
}
+ boolean hasMessage() {
+ return !message.getText().trim().isEmpty();
+ }
+
private void postReview() {
in.message(message.getText().trim());
+ // Don't send any comments in the request; just publish everything, even if
+ // e.g. a draft was modified in another tab since we last looked it up.
+ in.drafts(DraftHandling.PUBLISH_ALL_REVISIONS);
in.prePost();
ChangeApi.revision(psId.getParentKey().get(), revision)
.view("review")
@@ -284,7 +291,7 @@
List<LabelAndValues> checkboxes = new ArrayList<>(labels.size());
int row = 1;
for (LabelAndValues lv : labels) {
- if (isCheckBox(lv.info.value_set())) {
+ if (isCheckBox(lv.info.valueSet())) {
checkboxes.add(lv);
} else {
renderRadio(row++, columns, lv);
@@ -321,7 +328,7 @@
fmt.setStyleName(row, labelHelpColumn, style.label_help());
ApprovalInfo self = Gerrit.isSignedIn()
- ? lv.info.for_user(Gerrit.getUserAccount().getId().get())
+ ? lv.info.forUser(Gerrit.getUserAccount().getId().get())
: null;
final LabelRadioGroup group =
@@ -329,7 +336,7 @@
for (int i = 0; i < columns.size(); i++) {
Short v = columns.get(i);
if (lv.permitted.contains(v)) {
- String text = lv.info.value_text(LabelValue.formatValue(v));
+ String text = lv.info.valueText(LabelValue.formatValue(v));
LabelRadioButton b = new LabelRadioButton(group, text, v);
if ((self != null && v == self.value()) || (self == null && v.equals(dv))) {
b.setValue(true);
@@ -345,7 +352,7 @@
private void renderCheckBox(int row, LabelAndValues lv) {
ApprovalInfo self = Gerrit.isSignedIn()
- ? lv.info.for_user(Gerrit.getUserAccount().getId().get())
+ ? lv.info.forUser(Gerrit.getUserAccount().getId().get())
: null;
final String id = lv.info.name();
@@ -366,7 +373,7 @@
CellFormatter fmt = labelsTable.getCellFormatter();
fmt.setStyleName(row, labelHelpColumn, style.label_help());
- labelsTable.setText(row, labelHelpColumn, lv.info.value_text("+1"));
+ labelsTable.setText(row, labelHelpColumn, lv.info.valueText("+1"));
}
private static boolean isCheckBox(Set<Short> values) {
@@ -375,11 +382,6 @@
&& values.contains((short) 1);
}
- private void attachComments(NativeMap<JsArray<CommentInfo>> result) {
- in.drafts(ReviewInput.DraftHandling.KEEP);
- in.comments(result);
- }
-
private void displayComments(NativeMap<JsArray<CommentInfo>> m) {
comments.clear();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyBox.ui.xml
index a17d648..52f6b6a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyBox.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyBox.ui.xml
@@ -18,7 +18,7 @@
xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<ui:with field='res' type='com.google.gerrit.client.change.Resources'/>
- <ui:style type='com.google.gerrit.client.change.ReplyBox.Styles'>
+ <ui:style gss='false' type='com.google.gerrit.client.change.ReplyBox.Styles'>
.replyBox {
}
.label_name {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RevertAction.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RevertAction.java
index 47d6cad..fe0e6d0 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RevertAction.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RevertAction.java
@@ -48,7 +48,7 @@
public void onSuccess(ChangeInfo result) {
sent = true;
hide();
- Gerrit.display(PageLinks.toChange(result.legacy_id()));
+ Gerrit.display(PageLinks.toChange(result.legacyId()));
}
@Override
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Reviewers.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Reviewers.java
index 18e5e87..ce35747 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Reviewers.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Reviewers.java
@@ -100,7 +100,7 @@
}
void set(ChangeInfo info) {
- this.changeId = info.legacy_id();
+ this.changeId = info.legacyId();
display(info);
reviewerSuggestOracle.setChange(changeId);
openForm.setVisible(Gerrit.isSignedIn());
@@ -125,7 +125,7 @@
@UiHandler("addMe")
void onAddMe(@SuppressWarnings("unused") ClickEvent e) {
- String accountId = String.valueOf(Gerrit.getUserAccountInfo()._account_id());
+ String accountId = String.valueOf(Gerrit.getUserAccountInfo()._accountId());
addReviewer(accountId, false);
}
@@ -198,22 +198,22 @@
private void display(ChangeInfo info) {
Map<Integer, AccountInfo> r = new HashMap<>();
Map<Integer, AccountInfo> cc = new HashMap<>();
- for (LabelInfo label : Natives.asList(info.all_labels().values())) {
+ for (LabelInfo label : Natives.asList(info.allLabels().values())) {
if (label.all() != null) {
for (ApprovalInfo ai : Natives.asList(label.all())) {
- (ai.value() != 0 ? r : cc).put(ai._account_id(), ai);
+ (ai.value() != 0 ? r : cc).put(ai._accountId(), ai);
}
}
}
for (Integer i : r.keySet()) {
cc.remove(i);
}
- cc.remove(info.owner()._account_id());
+ cc.remove(info.owner()._accountId());
Set<Integer> removable = new HashSet<>();
- if (info.removable_reviewers() != null) {
- for (AccountInfo a : Natives.asList(info.removable_reviewers())) {
- removable.add(a._account_id());
+ if (info.removableReviewers() != null) {
+ for (AccountInfo a : Natives.asList(info.removableReviewers())) {
+ removable.add(a._accountId());
}
}
@@ -227,8 +227,8 @@
reviewersText.setInnerSafeHtml(rHtml);
ccText.setInnerSafeHtml(ccHtml);
if (Gerrit.isSignedIn()) {
- int currentUser = Gerrit.getUserAccountInfo()._account_id();
- boolean showAddMeButton = info.owner()._account_id() != currentUser
+ int currentUser = Gerrit.getUserAccountInfo()._accountId();
+ boolean showAddMeButton = info.owner()._accountId() != currentUser
&& !cc.containsKey(currentUser)
&& !r.containsKey(currentUser);
addMe.setVisible(showAddMeButton);
@@ -241,13 +241,13 @@
LabelInfo label = change.label(name);
if (label.all() != null) {
for (ApprovalInfo ai : Natives.asList(label.all())) {
- int id = ai._account_id();
+ int id = ai._accountId();
VotableInfo ad = d.get(id);
if (ad == null) {
ad = new VotableInfo();
d.put(id, ad);
}
- if (ai.has_value()) {
+ if (ai.hasValue()) {
ad.votable(name);
}
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Reviewers.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Reviewers.ui.xml
index 9924c1d..22e35e2 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Reviewers.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Reviewers.ui.xml
@@ -20,7 +20,7 @@
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:u='urn:import:com.google.gerrit.client.ui'>
<ui:with field='res' type='com.google.gerrit.client.change.Resources'/>
- <ui:style>
+ <ui:style gss='false'>
button.openAdd {
margin: 3px 3px 0 0;
float: right;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/SubmitAction.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/SubmitAction.java
index 09d3476..f45b983 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/SubmitAction.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/SubmitAction.java
@@ -27,7 +27,7 @@
class SubmitAction {
static void call(ChangeInfo changeInfo, RevisionInfo revisionInfo) {
if (ChangeGlue.onSubmitChange(changeInfo, revisionInfo)) {
- final Change.Id changeId = changeInfo.legacy_id();
+ final Change.Id changeId = changeInfo.legacyId();
ChangeApi.submit(
changeId.get(), revisionInfo.name(),
new GerritCallback<SubmitInfo>() {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Topic.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Topic.java
index 9f45678..b3eff93 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Topic.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Topic.java
@@ -68,12 +68,10 @@
}
void set(ChangeInfo info, String revision) {
- canEdit = info.has_actions()
- && info.actions().containsKey("topic")
- && info.actions().get("topic").enabled();
+ canEdit = info.hasActions() && info.actions().containsKey("topic");
psId = new PatchSet.Id(
- info.legacy_id(),
+ info.legacyId(),
info.revisions().get(revision)._number());
initTopicLink(info);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Topic.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Topic.ui.xml
index ae46b10..e7e24b4 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Topic.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Topic.ui.xml
@@ -21,7 +21,7 @@
xmlns:x='urn:import:com.google.gerrit.client.ui'>
<ui:with field='ico' type='com.google.gerrit.client.GerritResources'/>
<ui:with field='res' type='com.google.gerrit.client.change.Resources'/>
- <ui:style>
+ <ui:style gss='false'>
.show { cursor: pointer; }
.edit, .cancel { float: right; }
</ui:style>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/UpdateAvailableBar.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/UpdateAvailableBar.java
index cdbc693..2daa9ea 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/UpdateAvailableBar.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/UpdateAvailableBar.java
@@ -48,7 +48,7 @@
HashSet<Integer> seen = new HashSet<>();
StringBuilder r = new StringBuilder();
for (MessageInfo m : newMessages) {
- int a = m.author() != null ? m.author()._account_id() : 0;
+ int a = m.author() != null ? m.author()._accountId() : 0;
if (seen.add(a)) {
if (r.length() > 0) {
r.append(", ");
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/UpdateAvailableBar.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/UpdateAvailableBar.ui.xml
index 1c46b8c..1d5592b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/UpdateAvailableBar.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/UpdateAvailableBar.ui.xml
@@ -18,7 +18,7 @@
xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:c='urn:import:com.google.gwtexpui.globalkey.client'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
- <ui:style>
+ <ui:style gss='false'>
.popup {
position: fixed;
bottom: 0;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/file_table.css b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/file_table.css
index 2803db3..f0101cb 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/file_table.css
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/file_table.css
@@ -13,14 +13,14 @@
* limitations under the License.
*/
-.pointer, .reviewed, .removeButton {
+.pointer, .reviewed, .restoreDelete {
padding: 0px;
vertical-align: top;
}
.pointer {
width: 12px;
}
-.reviewed, .removeButton {
+.reviewed {
height: 19px;
width: 20px;
}
@@ -96,7 +96,11 @@
background-color: #d44;
}
-.removeButton button {
+.restoreDelete div {
+ white-space: nowrap;
+}
+
+.restoreDelete button {
cursor: pointer;
padding: 0;
margin: 0 0 0 5px;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/related_changes.css b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/related_changes.css
index 2e62b98..c0c828a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/related_changes.css
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/related_changes.css
@@ -68,7 +68,8 @@
.current,
.gitweb,
.indirect,
-.notCurrent {
+.notCurrent,
+.submittable {
display: inline-block;
text-align: center;
vertical-align: top;
@@ -87,3 +88,8 @@
.notCurrent {
color: #FFA62F; /* orange */
}
+
+.submittable {
+ color: #090; /* green */
+ font-weight: bold;
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/AccountDashboardScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/AccountDashboardScreen.java
index d9e9878..9974532 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/AccountDashboardScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/AccountDashboardScreen.java
@@ -18,7 +18,9 @@
import com.google.gerrit.client.NotFoundScreen;
import com.google.gerrit.client.rpc.Natives;
import com.google.gerrit.client.rpc.ScreenLoadCallback;
+import com.google.gerrit.client.ui.InlineHyperlink;
import com.google.gerrit.client.ui.Screen;
+import com.google.gerrit.common.PageLinks;
import com.google.gerrit.extensions.client.ListChangesOption;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gwt.core.client.JsArray;
@@ -28,8 +30,16 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
+import java.util.Set;
public class AccountDashboardScreen extends Screen implements ChangeListScreen {
+ private static final Set<ListChangesOption> MY_DASHBOARD_OPTIONS;
+ static {
+ EnumSet<ListChangesOption> options = EnumSet.copyOf(ChangeTable.OPTIONS);
+ options.add(ListChangesOption.REVIEWED);
+ MY_DASHBOARD_OPTIONS = Collections.unmodifiableSet(options);
+ }
+
private final Account.Id ownerId;
private final boolean mine;
private ChangeTable table;
@@ -61,10 +71,14 @@
incoming = new ChangeTable.Section();
closed = new ChangeTable.Section();
- outgoing.setTitleText(Util.C.outgoingReviews());
- incoming.setTitleText(Util.C.incomingReviews());
+ String who = mine ? "self" : ownerId.toString();
+ outgoing.setTitleWidget(new InlineHyperlink(Util.C.outgoingReviews(),
+ PageLinks.toChangeQuery(queryOutgoing(who))));
+ incoming.setTitleWidget(new InlineHyperlink(Util.C.incomingReviews(),
+ PageLinks.toChangeQuery(queryIncoming(who))));
incoming.setHighlightUnreviewed(mine);
- closed.setTitleText(Util.C.recentlyClosed());
+ closed.setTitleWidget(new InlineHyperlink(Util.C.recentlyClosed(),
+ PageLinks.toChangeQuery(queryClosed(who))));
table.addSection(outgoing);
table.addSection(incoming);
@@ -73,24 +87,34 @@
table.setSavePointerId("owner:" + ownerId);
}
+ private static String queryOutgoing(String who) {
+ return "is:open owner:" + who;
+ }
+
+ private static String queryIncoming(String who) {
+ return "is:open reviewer:" + who + " -owner:" + who;
+ }
+
+ private static String queryClosed(String who) {
+ return "is:closed (owner:" + who + " OR reviewer:" + who + ")";
+ }
+
@Override
protected void onLoad() {
super.onLoad();
String who = mine ? "self" : ownerId.toString();
- ChangeList.query(
+ ChangeList.queryMultiple(
new ScreenLoadCallback<JsArray<ChangeList>>(this) {
@Override
protected void preDisplay(JsArray<ChangeList> result) {
display(result);
}
},
- mine
- ? EnumSet.of(ListChangesOption.REVIEWED)
- : EnumSet.noneOf(ListChangesOption.class),
- "is:open owner:" + who,
- "is:open reviewer:" + who + " -owner:" + who,
- "is:closed (owner:" + who + " OR reviewer:" + who + ") -age:4w limit:10");
+ mine ? MY_DASHBOARD_OPTIONS : DashboardTable.OPTIONS,
+ queryOutgoing(who),
+ queryIncoming(who),
+ queryClosed(who) + " -age:4w limit:10");
}
@Override
@@ -144,7 +168,9 @@
@Override
public int compare(ChangeInfo a, ChangeInfo b) {
int cmp = a.created().compareTo(b.created());
- if (cmp != 0) return cmp;
+ if (cmp != 0) {
+ return cmp;
+ }
return a._number() - b._number();
}
};
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeApi.java
index 98595e7..7a5e239 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeApi.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeApi.java
@@ -51,7 +51,7 @@
input.project(emptyToNull(project));
input.branch(emptyToNull(branch));
input.subject(emptyToNull(subject));
- input.base_change(emptyToNull(base));
+ input.baseChange(emptyToNull(base));
if (Gerrit.getConfig().isAllowDraftChanges()) {
input.status(Change.Status.DRAFT.toString());
@@ -95,6 +95,21 @@
return call(id, "detail");
}
+ public static RestApi actions(int id, String revision) {
+ if (revision == null || revision.equals("")) {
+ revision = "current";
+ }
+ return call(id, revision, "actions");
+ }
+
+ public static RestApi comments(int id) {
+ return call(id, "comments");
+ }
+
+ public static RestApi drafts(int id) {
+ return call(id, "drafts");
+ }
+
public static void edit(int id, AsyncCallback<EditInfo> cb) {
edit(id).get(cb);
}
@@ -172,7 +187,7 @@
/** Submit a specific revision of a change. */
public static void submit(int id, String commit, AsyncCallback<SubmitInfo> cb) {
SubmitInput in = SubmitInput.create();
- in.wait_for_merge(true);
+ in.waitForMerge(true);
call(id, commit, "submit").post(in, cb);
}
@@ -236,7 +251,7 @@
public final native void branch(String b) /*-{ if(b)this.branch=b; }-*/;
public final native void project(String p) /*-{ if(p)this.project=p; }-*/;
public final native void subject(String s) /*-{ if(s)this.subject=s; }-*/;
- public final native void base_change(String b) /*-{ if(b)this.base_change=b; }-*/;
+ public final native void baseChange(String b) /*-{ if(b)this.base_change=b; }-*/;
public final native void status(String s) /*-{ if(s)this.status=s; }-*/;
protected CreateChangeInput() {
@@ -266,7 +281,7 @@
}
private static class SubmitInput extends JavaScriptObject {
- final native void wait_for_merge(boolean b) /*-{ this.wait_for_merge=b; }-*/;
+ final native void waitForMerge(boolean b) /*-{ this.wait_for_merge=b; }-*/;
static SubmitInput create() {
return (SubmitInput) createObject();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.java
index 6531129..efaa7c2 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.java
@@ -22,6 +22,7 @@
String statusLongMerged();
String statusLongAbandoned();
String statusLongDraft();
+ String submittable();
String readyToSubmit();
String mergeConflict();
String notCurrent();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.properties
index 45415c5..40c6d24 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.properties
@@ -3,6 +3,7 @@
statusLongMerged = Merged
statusLongAbandoned = Abandoned
statusLongDraft = Draft
+submittable = Submittable
readyToSubmit = Ready to Submit
mergeConflict = Merge Conflict
notCurrent = Not Current
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeEditApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeEditApi.java
index a00e329..0928cd8 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeEditApi.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeEditApi.java
@@ -76,15 +76,15 @@
public static void rename(int id, String path, String newPath,
AsyncCallback<VoidResult> cb) {
Input in = Input.create();
- in.old_path(path);
- in.new_path(newPath);
+ in.oldPath(path);
+ in.newPath(newPath);
ChangeApi.edit(id).post(in, cb);
}
/** Restore (undo delete/modify) a file in the pending edit. */
public static void restore(int id, String path, AsyncCallback<VoidResult> cb) {
Input in = Input.create();
- in.restore_path(path);
+ in.restorePath(path);
ChangeApi.edit(id).post(in, cb);
}
@@ -101,9 +101,9 @@
return createObject().cast();
}
- final native void restore_path(String p) /*-{ this.restore_path=p }-*/;
- final native void old_path(String p) /*-{ this.old_path=p }-*/;
- final native void new_path(String p) /*-{ this.new_path=p }-*/;
+ final native void restorePath(String p) /*-{ this.restore_path=p }-*/;
+ final native void oldPath(String p) /*-{ this.old_path=p }-*/;
+ final native void newPath(String p) /*-{ this.new_path=p }-*/;
protected Input() {
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java
index fff792f..9052fef 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java
@@ -34,30 +34,31 @@
import java.sql.Timestamp;
import java.util.Collections;
import java.util.Comparator;
+import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
public class ChangeInfo extends JavaScriptObject {
public final void init() {
- if (all_labels() != null) {
- all_labels().copyKeysIntoChildren("_name");
+ if (allLabels() != null) {
+ allLabels().copyKeysIntoChildren("_name");
}
}
- public final Project.NameKey project_name_key() {
+ public final Project.NameKey projectNameKey() {
return new Project.NameKey(project());
}
- public final Change.Id legacy_id() {
+ public final Change.Id legacyId() {
return new Change.Id(_number());
}
public final Timestamp created() {
- Timestamp ts = _get_cts();
+ Timestamp ts = _getCts();
if (ts == null) {
ts = JavaSqlTimestamp_JsonSerializer.parseTimestamp(createdRaw());
- _set_cts(ts);
+ _setCts(ts);
}
return ts;
}
@@ -65,18 +66,18 @@
public final boolean hasEditBasedOnCurrentPatchSet() {
JsArray<RevisionInfo> revList = revisions().values();
RevisionInfo.sortRevisionInfoByNumber(revList);
- return revList.get(revList.length() - 1).is_edit();
+ return revList.get(revList.length() - 1).isEdit();
}
- private final native Timestamp _get_cts() /*-{ return this._cts; }-*/;
- private final native void _set_cts(Timestamp ts) /*-{ this._cts = ts; }-*/;
+ private final native Timestamp _getCts() /*-{ return this._cts; }-*/;
+ private final native void _setCts(Timestamp ts) /*-{ this._cts = ts; }-*/;
public final Timestamp updated() {
return JavaSqlTimestamp_JsonSerializer.parseTimestamp(updatedRaw());
}
- public final String id_abbreviated() {
- return new Change.Key(change_id()).abbreviate();
+ public final String idAbbreviated() {
+ return new Change.Key(changeId()).abbreviate();
}
public final Change.Status status() {
@@ -84,14 +85,14 @@
}
public final Set<String> labels() {
- return all_labels().keySet();
+ return allLabels().keySet();
}
public final native String id() /*-{ return this.id; }-*/;
public final native String project() /*-{ return this.project; }-*/;
public final native String branch() /*-{ return this.branch; }-*/;
public final native String topic() /*-{ return this.topic; }-*/;
- public final native String change_id() /*-{ return this.change_id; }-*/;
+ public final native String changeId() /*-{ return this.change_id; }-*/;
public final native boolean mergeable() /*-{ return this.mergeable || false; }-*/;
public final native int insertions() /*-{ return this.insertions; }-*/;
public final native int deletions() /*-{ return this.deletions; }-*/;
@@ -102,35 +103,92 @@
private final native String updatedRaw() /*-{ return this.updated; }-*/;
public final native boolean starred() /*-{ return this.starred ? true : false; }-*/;
public final native boolean reviewed() /*-{ return this.reviewed ? true : false; }-*/;
- public final native NativeMap<LabelInfo> all_labels() /*-{ return this.labels; }-*/;
+ public final native NativeMap<LabelInfo> allLabels() /*-{ return this.labels; }-*/;
public final native LabelInfo label(String n) /*-{ return this.labels[n]; }-*/;
- public final native String current_revision() /*-{ return this.current_revision; }-*/;
- public final native void set_current_revision(String r) /*-{ this.current_revision = r; }-*/;
+ public final native String currentRevision() /*-{ return this.current_revision; }-*/;
+ public final native void setCurrentRevision(String r) /*-{ this.current_revision = r; }-*/;
+ private final native void setSubmittable(boolean x) /*-{ this.submittable = x; }-*/;
public final native NativeMap<RevisionInfo> revisions() /*-{ return this.revisions; }-*/;
public final native RevisionInfo revision(String n) /*-{ return this.revisions[n]; }-*/;
public final native JsArray<MessageInfo> messages() /*-{ return this.messages; }-*/;
- public final native void set_edit(EditInfo edit) /*-{ this.edit = edit; }-*/;
+ public final native void setEdit(EditInfo edit) /*-{ this.edit = edit; }-*/;
public final native EditInfo edit() /*-{ return this.edit; }-*/;
- public final native boolean has_edit() /*-{ return this.hasOwnProperty('edit') }-*/;
+ public final native boolean hasEdit() /*-{ return this.hasOwnProperty('edit') }-*/;
public final native JsArrayString hashtags() /*-{ return this.hashtags; }-*/;
- public final native boolean has_permitted_labels()
+ public final native boolean hasPermittedLabels()
/*-{ return this.hasOwnProperty('permitted_labels') }-*/;
- public final native NativeMap<JsArrayString> permitted_labels()
+ public final native NativeMap<JsArrayString> permittedLabels()
/*-{ return this.permitted_labels; }-*/;
- public final native JsArrayString permitted_values(String n)
+ public final native JsArrayString permittedValues(String n)
/*-{ return this.permitted_labels[n]; }-*/;
- public final native JsArray<AccountInfo> removable_reviewers()
+ public final native JsArray<AccountInfo> removableReviewers()
/*-{ return this.removable_reviewers; }-*/;
- public final native boolean has_actions() /*-{ return this.hasOwnProperty('actions') }-*/;
+ public final native boolean hasActions() /*-{ return this.hasOwnProperty('actions') }-*/;
public final native NativeMap<ActionInfo> actions() /*-{ return this.actions; }-*/;
final native int _number() /*-{ return this._number; }-*/;
final native boolean _more_changes()
/*-{ return this._more_changes ? true : false; }-*/;
+ public final boolean submittable() {
+ init();
+ getMissingLabelIndex();
+ return _submittable();
+ }
+
+ private final native boolean _submittable()
+ /*-{ return this.submittable ? true : false; }-*/;
+
+ /**
+ * As a side effect this.submittable is evaluated and set accordingly.
+ *
+ * @return the index of the missing label or -1
+ * if no label is missing, or if more than one label is missing.
+ */
+ public final int getMissingLabelIndex() {
+ int i = -1;
+ int ret = -1;
+ List<LabelInfo> labels = Natives.asList(allLabels().values());
+ for (LabelInfo label : labels) {
+ i++;
+ if (!permittedLabels().containsKey(label.name())) {
+ continue;
+ }
+
+ JsArrayString values = permittedValues(label.name());
+ if (values.length() == 0) {
+ continue;
+ }
+
+ switch (label.status()) {
+ case NEED: // Label is required for submit.
+ if (ret != -1) {
+ // more than one label is missing, so it's unclear which to quick
+ // approve, return -1
+ setSubmittable(false);
+ return -1;
+ } else {
+ ret = i;
+ }
+ continue;
+
+ case OK: // Label already applied.
+ case MAY: // Label is not required.
+ continue;
+
+ case REJECT: // Submit cannot happen, do not quick approve.
+ case IMPOSSIBLE:
+ setSubmittable(false);
+ return -1;
+ }
+ }
+ setSubmittable(ret == -1);
+ return ret;
+ }
+
protected ChangeInfo() {
}
@@ -155,10 +213,10 @@
public final native AccountInfo disliked() /*-{ return this.disliked; }-*/;
public final native JsArray<ApprovalInfo> all() /*-{ return this.all; }-*/;
- public final ApprovalInfo for_user(int user) {
+ public final ApprovalInfo forUser(int user) {
JsArray<ApprovalInfo> all = all();
for (int i = 0; all != null && i < all.length(); i++) {
- if (all.get(i)._account_id() == user) {
+ if (all.get(i)._accountId() == user) {
return all.get(i);
}
}
@@ -169,7 +227,7 @@
public final Set<String> values() {
return Natives.keys(_values());
}
- public final native String value_text(String n) /*-{ return this.values[n]; }-*/;
+ public final native String valueText(String n) /*-{ return this.values[n]; }-*/;
public final native boolean optional() /*-{ return this.optional ? true : false; }-*/;
public final native boolean blocking() /*-{ return this.blocking ? true : false; }-*/;
@@ -182,11 +240,11 @@
return 0;
}-*/;
- public final String max_value() {
- return LabelValue.formatValue(value_set().last());
+ public final String maxValue() {
+ return LabelValue.formatValue(valueSet().last());
}
- public final SortedSet<Short> value_set() {
+ public final SortedSet<Short> valueSet() {
SortedSet<Short> values = new TreeSet<>();
for (String v : values()) {
values.add(parseValue(v));
@@ -208,7 +266,7 @@
}
public static class ApprovalInfo extends AccountInfo {
- public final native boolean has_value() /*-{ return this.hasOwnProperty('value'); }-*/;
+ public final native boolean hasValue() /*-{ return this.hasOwnProperty('value'); }-*/;
public final native short value() /*-{ return this.value || 0; }-*/;
protected ApprovalInfo() {
@@ -217,17 +275,17 @@
public static class EditInfo extends JavaScriptObject {
public final native String name() /*-{ return this.name; }-*/;
- public final native String set_name(String n) /*-{ this.name = n; }-*/;
- public final native String base_revision() /*-{ return this.base_revision; }-*/;
+ public final native String setName(String n) /*-{ this.name = n; }-*/;
+ public final native String baseRevision() /*-{ return this.base_revision; }-*/;
public final native CommitInfo commit() /*-{ return this.commit; }-*/;
- public final native boolean has_actions() /*-{ return this.hasOwnProperty('actions') }-*/;
+ public final native boolean hasActions() /*-{ return this.hasOwnProperty('actions') }-*/;
public final native NativeMap<ActionInfo> actions() /*-{ return this.actions; }-*/;
- public final native boolean has_fetch() /*-{ return this.hasOwnProperty('fetch') }-*/;
+ public final native boolean hasFetch() /*-{ return this.hasOwnProperty('fetch') }-*/;
public final native NativeMap<FetchInfo> fetch() /*-{ return this.fetch; }-*/;
- public final native boolean has_files() /*-{ return this.hasOwnProperty('files') }-*/;
+ public final native boolean hasFiles() /*-{ return this.hasOwnProperty('files') }-*/;
public final native NativeMap<FileInfo> files() /*-{ return this.files; }-*/;
protected EditInfo() {
@@ -249,19 +307,19 @@
public final native int _number() /*-{ return this._number; }-*/;
public final native String name() /*-{ return this.name; }-*/;
public final native boolean draft() /*-{ return this.draft || false; }-*/;
- public final native boolean has_draft_comments() /*-{ return this.has_draft_comments || false; }-*/;
- public final native boolean is_edit() /*-{ return this._number == 0; }-*/;
+ public final native boolean hasDraftComments() /*-{ return this.has_draft_comments || false; }-*/;
+ public final native boolean isEdit() /*-{ return this._number == 0; }-*/;
public final native CommitInfo commit() /*-{ return this.commit; }-*/;
- public final native void set_commit(CommitInfo c) /*-{ this.commit = c; }-*/;
- public final native String edit_base() /*-{ return this.edit_base; }-*/;
+ public final native void setCommit(CommitInfo c) /*-{ this.commit = c; }-*/;
+ public final native String editBase() /*-{ return this.edit_base; }-*/;
- public final native boolean has_files() /*-{ return this.hasOwnProperty('files') }-*/;
+ public final native boolean hasFiles() /*-{ return this.hasOwnProperty('files') }-*/;
public final native NativeMap<FileInfo> files() /*-{ return this.files; }-*/;
- public final native boolean has_actions() /*-{ return this.hasOwnProperty('actions') }-*/;
+ public final native boolean hasActions() /*-{ return this.hasOwnProperty('actions') }-*/;
public final native NativeMap<ActionInfo> actions() /*-{ return this.actions; }-*/;
- public final native boolean has_fetch() /*-{ return this.hasOwnProperty('fetch') }-*/;
+ public final native boolean hasFetch() /*-{ return this.hasOwnProperty('fetch') }-*/;
public final native NativeMap<FetchInfo> fetch() /*-{ return this.fetch; }-*/;
public static void sortRevisionInfoByNumber(JsArray<RevisionInfo> list) {
@@ -273,7 +331,7 @@
}
private int num(RevisionInfo r) {
- return !r.is_edit() ? 2 * (r._number() - 1) + 1 : 2 * editParent;
+ return !r.isEdit() ? 2 * (r._number() - 1) + 1 : 2 * editParent;
}
});
}
@@ -282,8 +340,8 @@
for (int i = 0; i < list.length(); i++) {
// edit under revisions?
RevisionInfo editInfo = list.get(i);
- if (editInfo.is_edit()) {
- String parentRevision = editInfo.edit_base();
+ if (editInfo.isEdit()) {
+ String parentRevision = editInfo.editBase();
// find parent
for (int j = 0; j < list.length(); j++) {
RevisionInfo parentInfo = list.get(j);
@@ -323,7 +381,7 @@
public final native GitPerson committer() /*-{ return this.committer; }-*/;
public final native String subject() /*-{ return this.subject; }-*/;
public final native String message() /*-{ return this.message; }-*/;
- public final native JsArray<WebLinkInfo> web_links() /*-{ return this.web_links; }-*/;
+ public final native JsArray<WebLinkInfo> webLinks() /*-{ return this.web_links; }-*/;
protected CommitInfo() {
}
@@ -357,7 +415,7 @@
}
public static class MergeableInfo extends JavaScriptObject {
- public final native String submit_type() /*-{ return this.submit_type }-*/;
+ public final native String submitType() /*-{ return this.submit_type }-*/;
public final native boolean mergeable() /*-{ return this.mergeable }-*/;
protected MergeableInfo() {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeList.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeList.java
index b1866dd..5fcaf24 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeList.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeList.java
@@ -20,52 +20,68 @@
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwtorm.client.KeyUtil;
-import java.util.EnumSet;
+import java.util.Set;
/** List of changes available from {@code /changes/}. */
public class ChangeList extends JsArray<ChangeInfo> {
private static final String URI = "/changes/";
- private static final EnumSet<ListChangesOption> OPTIONS = EnumSet.of(
- ListChangesOption.LABELS, ListChangesOption.DETAILED_ACCOUNTS);
- /** Run 2 or more queries in a single remote invocation. */
- public static void query(
- AsyncCallback<JsArray<ChangeList>> callback,
- EnumSet<ListChangesOption> options,
+ /** Run multiple queries in a single remote invocation. */
+ public static void queryMultiple(
+ final AsyncCallback<JsArray<ChangeList>> callback,
+ Set<ListChangesOption> options,
String... queries) {
- assert queries.length >= 2; // At least 2 is required for correct result.
+ if (queries.length == 0) {
+ return;
+ }
RestApi call = new RestApi(URI);
for (String q : queries) {
call.addParameterRaw("q", KeyUtil.encode(q));
}
- OPTIONS.addAll(options);
- addOptions(call, OPTIONS);
- call.get(callback);
+ addOptions(call, options);
+ if (queries.length == 1) {
+ // Server unwraps a single query, so wrap it back in an array for the
+ // callback.
+ call.get(new AsyncCallback<ChangeList>() {
+ @Override
+ public void onSuccess(ChangeList result) {
+ JsArray<ChangeList> wrapped = JsArray.createArray(1).cast();
+ wrapped.set(0, result);
+ callback.onSuccess(wrapped);
+ }
+
+ @Override
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+ });
+ } else {
+ call.get(callback);
+ }
}
public static void query(String query,
- EnumSet<ListChangesOption> options,
+ Set<ListChangesOption> options,
AsyncCallback<ChangeList> callback) {
- RestApi call = newQuery(query);
- addOptions(call, options);
- call.get(callback);
+ query(query, options, callback, 0, 0);
}
- public static void next(String query,
- int start, int limit,
- AsyncCallback<ChangeList> callback) {
+ public static void query(String query,
+ Set<ListChangesOption> options,
+ AsyncCallback<ChangeList> callback,
+ int start, int limit) {
RestApi call = newQuery(query);
if (limit > 0) {
call.addParameter("n", limit);
}
- addOptions(call, OPTIONS);
+ addOptions(call, options);
if (start != 0) {
call.addParameter("S", start);
}
call.get(callback);
}
- public static void addOptions(RestApi call, EnumSet<ListChangesOption> s) {
+ public static void addOptions(RestApi call, Set<ListChangesOption> s) {
call.addParameterRaw("O", Integer.toHexString(ListChangesOption.toBits(s)));
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable.java
index 8b71448..c52ac32 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable.java
@@ -27,6 +27,7 @@
import com.google.gerrit.client.ui.NeedsSignInKeyCommand;
import com.google.gerrit.client.ui.ProjectLink;
import com.google.gerrit.common.PageLinks;
+import com.google.gerrit.extensions.client.ListChangesOption;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.ReviewCategoryStrategy;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gwt.dom.client.Element;
@@ -45,9 +46,17 @@
import java.util.ArrayList;
import java.util.Collections;
+import java.util.EnumSet;
import java.util.List;
+import java.util.Set;
public class ChangeTable extends NavigationTable<ChangeInfo> {
+ // If changing default options, also update in
+ // ChangeIT#defaultSearchDoesNotTouchDatabase().
+ static final Set<ListChangesOption> OPTIONS =
+ Collections.unmodifiableSet(EnumSet.of(
+ ListChangesOption.LABELS, ListChangesOption.DETAILED_ACCOUNTS));
+
private static final int C_STAR = 1;
private static final int C_ID = 2;
private static final int C_SUBJECT = 3;
@@ -118,13 +127,13 @@
@Override
protected Object getRowItemKey(final ChangeInfo item) {
- return item.legacy_id();
+ return item.legacyId();
}
@Override
protected void onOpenRow(final int row) {
final ChangeInfo c = getRowItem(row);
- final Change.Id id = c.legacy_id();
+ final Change.Id id = c.legacyId();
Gerrit.display(PageLinks.toChange(id));
}
@@ -208,10 +217,10 @@
CellFormatter fmt = table.getCellFormatter();
if (Gerrit.isSignedIn()) {
table.setWidget(row, C_STAR, StarredChanges.createIcon(
- c.legacy_id(),
+ c.legacyId(),
c.starred()));
}
- table.setWidget(row, C_ID, new TableChangeLink(String.valueOf(c.legacy_id()), c));
+ table.setWidget(row, C_ID, new TableChangeLink(String.valueOf(c.legacyId()), c));
String subject = Util.cropSubject(c.subject());
table.setWidget(row, C_SUBJECT, new TableChangeLink(subject, c));
@@ -229,8 +238,8 @@
table.setText(row, C_OWNER, "");
}
- table.setWidget(row, C_PROJECT, new ProjectLink(c.project_name_key()));
- table.setWidget(row, C_BRANCH, new BranchLink(c.project_name_key(), c
+ table.setWidget(row, C_PROJECT, new ProjectLink(c.projectNameKey()));
+ table.setWidget(row, C_BRANCH, new BranchLink(c.projectNameKey(), c
.status(), c.branch(), c.topic()));
if (Gerrit.isSignedIn()
&& Gerrit.getUserAccount().getGeneralPreferences()
@@ -447,7 +456,7 @@
private final class TableChangeLink extends ChangeLink {
private TableChangeLink(final String text, final ChangeInfo c) {
- super(text, c.legacy_id());
+ super(text, c.legacyId());
}
@Override
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CommentInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CommentInfo.java
index 52e5d40..c69ee57 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CommentInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CommentInfo.java
@@ -29,7 +29,7 @@
n.path(path);
n.side(side);
if (range != null) {
- n.line(range.end_line());
+ n.line(range.endLine());
n.range(range);
} else if (line > 0) {
n.line(line);
@@ -41,11 +41,11 @@
CommentInfo n = createObject().cast();
n.path(r.path());
n.side(r.side());
- n.in_reply_to(r.id());
- if (r.has_range()) {
- n.line(r.range().end_line());
+ n.inReplyTo(r.id());
+ if (r.hasRange()) {
+ n.line(r.range().endLine());
n.range(r.range());
- } else if (r.has_line()) {
+ } else if (r.hasLine()) {
n.line(r.line());
}
return n;
@@ -56,12 +56,12 @@
n.path(s.path());
n.side(s.side());
n.id(s.id());
- n.in_reply_to(s.in_reply_to());
+ n.inReplyTo(s.inReplyTo());
n.message(s.message());
- if (s.has_range()) {
- n.line(s.range().end_line());
+ if (s.hasRange()) {
+ n.line(s.range().endLine());
n.range(s.range());
- } else if (s.has_line()) {
+ } else if (s.hasLine()) {
n.line(s.line());
}
return n;
@@ -71,7 +71,7 @@
public final native void id(String i) /*-{ this.id = i }-*/;
public final native void line(int n) /*-{ this.line = n }-*/;
public final native void range(CommentRange r) /*-{ this.range = r }-*/;
- public final native void in_reply_to(String i) /*-{ this.in_reply_to = i }-*/;
+ public final native void inReplyTo(String i) /*-{ this.in_reply_to = i }-*/;
public final native void message(String m) /*-{ this.message = m }-*/;
public final void side(Side side) {
@@ -81,7 +81,8 @@
public final native String path() /*-{ return this.path }-*/;
public final native String id() /*-{ return this.id }-*/;
- public final native String in_reply_to() /*-{ return this.in_reply_to }-*/;
+ public final native String inReplyTo() /*-{ return this.in_reply_to }-*/;
+ public final native int patchSet() /*-{ return this.patch_set }-*/;
public final Side side() {
String s = sideRaw();
@@ -108,8 +109,8 @@
public final native AccountInfo author() /*-{ return this.author }-*/;
public final native int line() /*-{ return this.line || 0 }-*/;
- public final native boolean has_line() /*-{ return this.hasOwnProperty('line') }-*/;
- public final native boolean has_range() /*-{ return this.hasOwnProperty('range') }-*/;
+ public final native boolean hasLine() /*-{ return this.hasOwnProperty('line') }-*/;
+ public final native boolean hasRange() /*-{ return this.hasOwnProperty('range') }-*/;
public final native CommentRange range() /*-{ return this.range }-*/;
public final native String message() /*-{ return this.message }-*/;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/DashboardTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/DashboardTable.java
index 9e97c56..26e11ae 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/DashboardTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/DashboardTable.java
@@ -20,14 +20,12 @@
import com.google.gerrit.client.ui.InlineHyperlink;
import com.google.gerrit.client.ui.Screen;
import com.google.gerrit.common.PageLinks;
-import com.google.gerrit.extensions.client.ListChangesOption;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.http.client.URL;
import com.google.gwtexpui.globalkey.client.KeyCommand;
import java.util.ArrayList;
-import java.util.EnumSet;
import java.util.List;
import java.util.ListIterator;
@@ -104,33 +102,19 @@
@Override
protected void onLoad() {
super.onLoad();
-
- if (queries.size() == 1) {
- ChangeList.next(queries.get(0),
- 0, 0,
- new GerritCallback<ChangeList>() {
- @Override
- public void onSuccess(ChangeList result) {
- updateColumnsForLabels(result);
- sections.get(0).display(result);
- finishDisplay();
+ ChangeList.queryMultiple(
+ new GerritCallback<JsArray<ChangeList>>() {
+ @Override
+ public void onSuccess(JsArray<ChangeList> result) {
+ List<ChangeList> cls = Natives.asList(result);
+ updateColumnsForLabels(cls.toArray(new ChangeList[cls.size()]));
+ for (int i = 0; i < cls.size(); i++) {
+ sections.get(i).display(cls.get(i));
}
- });
- } else if (! queries.isEmpty()) {
- ChangeList.query(
- new GerritCallback<JsArray<ChangeList>>() {
- @Override
- public void onSuccess(JsArray<ChangeList> result) {
- List<ChangeList> cls = Natives.asList(result);
- updateColumnsForLabels(cls.toArray(new ChangeList[cls.size()]));
- for (int i = 0; i < cls.size(); i++) {
- sections.get(i).display(cls.get(i));
- }
- finishDisplay();
- }
- },
- EnumSet.noneOf(ListChangesOption.class),
- queries.toArray(new String[queries.size()]));
- }
+ finishDisplay();
+ }
+ },
+ OPTIONS,
+ queries.toArray(new String[queries.size()]));
}
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/QueryScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/QueryScreen.java
index 488b34b..dddbd61 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/QueryScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/QueryScreen.java
@@ -54,7 +54,7 @@
if (isAttached()) {
if (result.length() == 1 && isSingleQuery(query)) {
ChangeInfo c = result.get(0);
- Change.Id id = c.legacy_id();
+ Change.Id id = c.legacyId();
Gerrit.display(PageLinks.toChange(id));
} else {
display(result);
@@ -74,7 +74,8 @@
@Override
protected void onLoad() {
super.onLoad();
- ChangeList.next(query, start, pageSize, loadCallback());
+ ChangeList.query(
+ query, ChangeTable.OPTIONS, loadCallback(), start, pageSize);
}
private static boolean isSingleQuery(String query) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ReviewInput.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ReviewInput.java
index 7651495..096dbd0 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ReviewInput.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ReviewInput.java
@@ -24,7 +24,7 @@
}
public static enum DraftHandling {
- DELETE, PUBLISH, KEEP
+ DELETE, PUBLISH, KEEP, PUBLISH_ALL_REVISIONS
}
public static ReviewInput create() {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/config/AuthInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/config/AuthInfo.java
new file mode 100644
index 0000000..5e66d83
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/config/AuthInfo.java
@@ -0,0 +1,82 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.client.config;
+
+import com.google.gerrit.client.rpc.Natives;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AuthType;
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArray;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class AuthInfo extends JavaScriptObject {
+ public final AuthType authType() {
+ return AuthType.valueOf(authTypeRaw());
+ }
+
+ public final boolean isOpenId() {
+ return authType() == AuthType.OPENID;
+ }
+
+ public final boolean isOAuth() {
+ return authType() == AuthType.OAUTH;
+ }
+
+ public final boolean isDev() {
+ return authType() == AuthType.DEVELOPMENT_BECOME_ANY_ACCOUNT;
+ }
+
+ public final boolean isClientSslCertLdap() {
+ return authType() == AuthType.CLIENT_SSL_CERT_LDAP;
+ }
+
+ public final boolean isCustomExtension() {
+ return authType() == AuthType.CUSTOM_EXTENSION;
+ }
+
+ public final boolean canEdit(Account.FieldName f) {
+ return editableAccountFields().contains(f);
+ }
+
+ public final List<Account.FieldName> editableAccountFields() {
+ List<Account.FieldName> fields = new ArrayList<>();
+ for (AccountFieldNameInfo f : Natives.asList(_editableAccountFields())) {
+ fields.add(f.get());
+ }
+ return fields;
+ }
+
+ public final native boolean useContributorAgreements()
+ /*-{ return this.use_contributor_agreements || false; }-*/;
+ private final native String authTypeRaw() /*-{ return this.auth_type; }-*/;
+ private final native JsArray<AccountFieldNameInfo> _editableAccountFields()
+ /*-{ return this.editable_account_fields; }-*/;
+
+ protected AuthInfo() {
+ }
+
+ private static class AccountFieldNameInfo extends JavaScriptObject {
+ final Account.FieldName get() {
+ return Account.FieldName.valueOf(getRaw());
+ }
+
+ private final native String getRaw() /*-{ return this; }-*/;
+
+ protected AccountFieldNameInfo() {
+ }
+ }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/config/ConfigServerApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/config/ConfigServerApi.java
index 5dedaf0..5d79390 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/config/ConfigServerApi.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/config/ConfigServerApi.java
@@ -37,4 +37,8 @@
public static void defaultPreferences(AsyncCallback<Preferences> cb) {
new RestApi("/config/server/preferences").get(cb);
}
+
+ public static void serverInfo(AsyncCallback<ServerInfo> cb) {
+ new RestApi("/config/server/info").get(cb);
+ }
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/config/DownloadInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/config/DownloadInfo.java
new file mode 100644
index 0000000..e97d472
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/config/DownloadInfo.java
@@ -0,0 +1,85 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.client.config;
+
+import com.google.gerrit.client.rpc.NativeMap;
+import com.google.gerrit.client.rpc.NativeString;
+import com.google.gerrit.client.rpc.Natives;
+import com.google.gwt.core.client.JavaScriptObject;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class DownloadInfo extends JavaScriptObject {
+ public final Set<String> schemes() {
+ return Natives.keys(_schemes());
+ }
+ public final native DownloadSchemeInfo scheme(String n) /*-{ return this.schemes[n]; }-*/;
+ private final native NativeMap<DownloadSchemeInfo> _schemes() /*-{ return this.schemes; }-*/;
+
+ protected DownloadInfo() {
+ }
+
+ public static class DownloadSchemeInfo extends JavaScriptObject {
+ public final Set<String> commandNames() {
+ return Natives.keys(_commands());
+ }
+
+ public final Set<DownloadCommandInfo> commands(String project) {
+ Set<DownloadCommandInfo> commands = new HashSet<>();
+ for (String commandName : commandNames()) {
+ commands.add(new DownloadCommandInfo(commandName, command(commandName,
+ project)));
+ }
+ return commands;
+ }
+
+ public final String command(String commandName, String project) {
+ return command(commandName).replaceAll("\\$\\{project\\}", project);
+ }
+
+ public final String getUrl(String project) {
+ return url().replaceAll("\\$\\{project\\}", project);
+ }
+
+ public final native String name() /*-{ return this.name; }-*/;
+ public final native String url() /*-{ return this.url; }-*/;
+ public final native boolean isAuthRequired() /*-{ return this.is_auth_required || false; }-*/;
+ public final native boolean isAuthSupported() /*-{ return this.is_auth_supported || false; }-*/;
+ public final native String command(String n) /*-{ return this.commands[n]; }-*/;
+ private final native NativeMap<NativeString> _commands() /*-{ return this.commands; }-*/;
+
+ protected DownloadSchemeInfo() {
+ }
+ }
+
+ public static class DownloadCommandInfo {
+ private final String name;
+ private final String command;
+
+ DownloadCommandInfo(String name, String command) {
+ this.name = name;
+ this.command = command;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ public String command() {
+ return command;
+ }
+ }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/config/GerritInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/config/GerritInfo.java
new file mode 100644
index 0000000..33036ad
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/config/GerritInfo.java
@@ -0,0 +1,42 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.client.config;
+
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gwt.core.client.JavaScriptObject;
+
+public class GerritInfo extends JavaScriptObject {
+ public final Project.NameKey allProjectsNameKey() {
+ return new Project.NameKey(allProjects());
+ }
+
+ public final boolean isAllProjects(Project.NameKey p) {
+ return allProjectsNameKey().equals(p);
+ }
+
+ public final Project.NameKey allUsersNameKey() {
+ return new Project.NameKey(allUsers());
+ }
+
+ public final boolean isAllUsers(Project.NameKey p) {
+ return allUsersNameKey().equals(p);
+ }
+
+ public final native String allProjects() /*-{ return this.all_projects; }-*/;
+ public final native String allUsers() /*-{ return this.all_users; }-*/;
+
+ protected GerritInfo() {
+ }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/config/ServerInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/config/ServerInfo.java
new file mode 100644
index 0000000..a1e8dbc
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/config/ServerInfo.java
@@ -0,0 +1,38 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.client.config;
+
+import com.google.gwt.core.client.JavaScriptObject;
+
+public class ServerInfo extends JavaScriptObject {
+ public final native AuthInfo auth() /*-{ return this.auth; }-*/;
+ public final native ContactStoreInfo contactStore() /*-{ return this.contact_store; }-*/;
+ public final native DownloadInfo download() /*-{ return this.download; }-*/;
+ public final native GerritInfo gerrit() /*-{ return this.gerrit; }-*/;
+
+ public final boolean hasContactStore() {
+ return contactStore() != null;
+ }
+
+ protected ServerInfo() {
+ }
+
+ public static class ContactStoreInfo extends JavaScriptObject {
+ public final native String url() /*-{ return this.url; }-*/;
+
+ protected ContactStoreInfo() {
+ }
+ }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/ChunkManager.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/ChunkManager.java
index fed8f91..8ff11e8 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/ChunkManager.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/ChunkManager.java
@@ -124,7 +124,7 @@
padding = new ArrayList<>();
paddingDivs = new ArrayList<>();
- String diffColor = diff.meta_a() == null || diff.meta_b() == null
+ String diffColor = diff.metaA() == null || diff.metaB() == null
? DiffTable.style.intralineBg()
: DiffTable.style.diff();
@@ -175,8 +175,8 @@
colorLines(cmA, color, startA, aLen);
colorLines(cmB, color, startB, bLen);
- markEdit(cmA, startA, a, region.edit_a());
- markEdit(cmB, startB, b, region.edit_b());
+ markEdit(cmA, startA, a, region.editA());
+ markEdit(cmB, startB, b, region.editB());
addPadding(cmA, startA + aLen - 1, bLen - aLen);
addPadding(cmB, startB + bLen - 1, aLen - bLen);
addGutterTag(region, startA, startB);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentBox.java
index ca56bf4..0e85a2f 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentBox.java
@@ -1,4 +1,4 @@
-//Copyright (C) 2013 The Android Open Source Project
+// Copyright (C) 2013 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentManager.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentManager.java
index 514a3be..4e1a3e1 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentManager.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentManager.java
@@ -218,8 +218,8 @@
info,
expandAll);
- if (info.in_reply_to() != null) {
- PublishedBox r = published.get(info.in_reply_to());
+ if (info.inReplyTo() != null) {
+ PublishedBox r = published.get(info.inReplyTo());
if (r != null) {
r.setReplyBox(box);
}
@@ -391,7 +391,8 @@
return w;
}
- int lineA, lineB;
+ int lineA;
+ int lineB;
if (line == 0) {
lineA = lineB = 0;
} else if (side == DisplaySide.A) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentRange.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentRange.java
index a38a6ca..9f46e9b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentRange.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentRange.java
@@ -38,10 +38,10 @@
to.line() + 1, to.ch());
}
- public final native int start_line() /*-{ return this.start_line; }-*/;
- public final native int start_character() /*-{ return this.start_character; }-*/;
- public final native int end_line() /*-{ return this.end_line; }-*/;
- public final native int end_character() /*-{ return this.end_character; }-*/;
+ public final native int startLine() /*-{ return this.start_line; }-*/;
+ public final native int startCharacter() /*-{ return this.start_character; }-*/;
+ public final native int endLine() /*-{ return this.end_line; }-*/;
+ public final native int endCharacter() /*-{ return this.end_character; }-*/;
private final native void set(int sl, int sc, int el, int ec) /*-{
this.start_line = sl;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffChunkInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffChunkInfo.java
index 9b3ac38..1e5c5e5 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffChunkInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffChunkInfo.java
@@ -1,4 +1,4 @@
-//Copyright (C) 2013 The Android Open Source Project
+// Copyright (C) 2013 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffInfo.java
index 7140e07..f7f4528 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffInfo.java
@@ -30,24 +30,24 @@
public static final String GITLINK = "x-git/gitlink";
public static final String SYMLINK = "x-git/symlink";
- public final native FileMeta meta_a() /*-{ return this.meta_a; }-*/;
- public final native FileMeta meta_b() /*-{ return this.meta_b; }-*/;
- public final native JsArrayString diff_header() /*-{ return this.diff_header; }-*/;
+ public final native FileMeta metaA() /*-{ return this.meta_a; }-*/;
+ public final native FileMeta metaB() /*-{ return this.meta_b; }-*/;
+ public final native JsArrayString diffHeader() /*-{ return this.diff_header; }-*/;
public final native JsArray<Region> content() /*-{ return this.content; }-*/;
- public final native JsArray<DiffWebLinkInfo> web_links() /*-{ return this.web_links; }-*/;
+ public final native JsArray<DiffWebLinkInfo> webLinks() /*-{ return this.web_links; }-*/;
public final native boolean binary() /*-{ return this.binary || false; }-*/;
- public final List<WebLinkInfo> side_by_side_web_links() {
+ public final List<WebLinkInfo> sideBySideWebLinks() {
return filterWebLinks(DiffView.SIDE_BY_SIDE);
}
- public final List<WebLinkInfo> unified_web_links() {
+ public final List<WebLinkInfo> unifiedWebLinks() {
return filterWebLinks(DiffView.UNIFIED_DIFF);
}
private final List<WebLinkInfo> filterWebLinks(DiffView diffView) {
List<WebLinkInfo> filteredDiffWebLinks = new LinkedList<>();
- List<DiffWebLinkInfo> allDiffWebLinks = Natives.asList(web_links());
+ List<DiffWebLinkInfo> allDiffWebLinks = Natives.asList(webLinks());
if (allDiffWebLinks != null) {
for (DiffWebLinkInfo webLink : allDiffWebLinks) {
if (diffView == DiffView.SIDE_BY_SIDE
@@ -63,22 +63,22 @@
return filteredDiffWebLinks;
}
- public final ChangeType change_type() {
- return ChangeType.valueOf(change_typeRaw());
+ public final ChangeType changeType() {
+ return ChangeType.valueOf(changeTypeRaw());
}
- private final native String change_typeRaw()
+ private final native String changeTypeRaw()
/*-{ return this.change_type }-*/;
- public final IntraLineStatus intraline_status() {
- String s = intraline_statusRaw();
+ public final IntraLineStatus intralineStatus() {
+ String s = intralineStatusRaw();
return s != null
? IntraLineStatus.valueOf(s)
: IntraLineStatus.OFF;
}
- private final native String intraline_statusRaw()
+ private final native String intralineStatusRaw()
/*-{ return this.intraline_status }-*/;
- public final boolean has_skip() {
+ public final boolean hasSkip() {
JsArray<Region> c = content();
for (int i = 0; i < c.length(); i++) {
if (c.get(i).skip() != 0) {
@@ -88,7 +88,7 @@
return false;
}
- public final String text_a() {
+ public final String textA() {
StringBuilder s = new StringBuilder();
JsArray<Region> c = content();
for (int i = 0; i < c.length(); i++) {
@@ -103,7 +103,7 @@
return s.toString();
}
- public final String text_b() {
+ public final String textB() {
StringBuilder s = new StringBuilder();
JsArray<Region> c = content();
for (int i = 0; i < c.length(); i++) {
@@ -133,9 +133,9 @@
public static class FileMeta extends JavaScriptObject {
public final native String name() /*-{ return this.name; }-*/;
- public final native String content_type() /*-{ return this.content_type; }-*/;
+ public final native String contentType() /*-{ return this.content_type; }-*/;
public final native int lines() /*-{ return this.lines || 0 }-*/;
- public final native JsArray<WebLinkInfo> web_links() /*-{ return this.web_links; }-*/;
+ public final native JsArray<WebLinkInfo> webLinks() /*-{ return this.web_links; }-*/;
protected FileMeta() {
}
@@ -148,8 +148,8 @@
public final native int skip() /*-{ return this.skip || 0; }-*/;
public final native boolean common() /*-{ return this.common || false; }-*/;
- public final native JsArray<Span> edit_a() /*-{ return this.edit_a }-*/;
- public final native JsArray<Span> edit_b() /*-{ return this.edit_b }-*/;
+ public final native JsArray<Span> editA() /*-{ return this.edit_a }-*/;
+ public final native JsArray<Span> editB() /*-{ return this.edit_b }-*/;
protected Region() {
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.java
index 1105476..b188c59 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.java
@@ -1,4 +1,4 @@
-//Copyright (C) 2013 The Android Open Source Project
+// Copyright (C) 2013 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -151,13 +151,13 @@
void set(DiffPreferences prefs, JsArray<RevisionInfo> list, DiffInfo info,
boolean editExists, int currentPatchSet, boolean open, boolean binary) {
- this.changeType = info.change_type();
- patchSetSelectBoxA.setUpPatchSetNav(list, info.meta_a(), editExists,
+ this.changeType = info.changeType();
+ patchSetSelectBoxA.setUpPatchSetNav(list, info.metaA(), editExists,
currentPatchSet, open, binary);
- patchSetSelectBoxB.setUpPatchSetNav(list, info.meta_b(), editExists,
+ patchSetSelectBoxB.setUpPatchSetNav(list, info.metaB(), editExists,
currentPatchSet, open, binary);
- JsArrayString hdr = info.diff_header();
+ JsArrayString hdr = info.diffHeader();
if (hdr != null) {
StringBuilder b = new StringBuilder();
for (int i = 1; i < hdr.length(); i++) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.ui.xml
index 504d9c0..99ecc9b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.ui.xml
@@ -17,7 +17,7 @@
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:d='urn:import:com.google.gerrit.client.diff'>
- <ui:style type='com.google.gerrit.client.diff.DiffTable.DiffTableStyle'>
+ <ui:style gss='false' type='com.google.gerrit.client.diff.DiffTable.DiffTableStyle'>
@external .CodeMirror, .CodeMirror-selectedtext;
@external .CodeMirror-linenumber;
@external .CodeMirror-overlayscroll-vertical, .CodeMirror-scroll;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DraftBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DraftBox.java
index 5bf56c2..21b2f50 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DraftBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DraftBox.java
@@ -1,4 +1,4 @@
-//Copyright (C) 2013 The Android Open Source Project
+// Copyright (C) 2013 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -244,7 +244,7 @@
}
private void restoreSelection() {
- if (getFromTo() != null && comment.in_reply_to() == null) {
+ if (getFromTo() != null && comment.inReplyTo() == null) {
getCm().setSelection(getFromTo().from(), getFromTo().to());
}
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DraftBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DraftBox.ui.xml
index 0c97e8b..a363c06 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DraftBox.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DraftBox.ui.xml
@@ -20,7 +20,7 @@
xmlns:e='urn:import:com.google.gwtexpui.globalkey.client'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<ui:with field='res' type='com.google.gerrit.client.diff.Resources'/>
- <ui:style>
+ <ui:style gss='false'>
.draft {
width: 45px;
text-align: center;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/FileInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/FileInfo.java
index c4459b6..77b28d4 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/FileInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/FileInfo.java
@@ -25,9 +25,9 @@
public class FileInfo extends JavaScriptObject {
public final native String path() /*-{ return this.path; }-*/;
- public final native String old_path() /*-{ return this.old_path; }-*/;
- public final native int lines_inserted() /*-{ return this.lines_inserted || 0; }-*/;
- public final native int lines_deleted() /*-{ return this.lines_deleted || 0; }-*/;
+ public final native String oldPath() /*-{ return this.old_path; }-*/;
+ public final native int linesInserted() /*-{ return this.lines_inserted || 0; }-*/;
+ public final native int linesDeleted() /*-{ return this.lines_deleted || 0; }-*/;
public final native boolean binary() /*-{ return this.binary || false; }-*/;
public final native String status() /*-{ return this.status; }-*/;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.java
index 2c551c0..42ae61d 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.java
@@ -67,7 +67,7 @@
}
private static enum ReviewedState {
- AUTO_REVIEW, LOADED;
+ AUTO_REVIEW, LOADED
}
@UiField CheckBox reviewed;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.ui.xml
index c58eef7..f13c9a3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.ui.xml
@@ -20,7 +20,7 @@
xmlns:x='urn:import:com.google.gerrit.client.ui'>
<ui:with field='ico' type='com.google.gerrit.client.GerritResources'/>
<ui:with field='res' type='com.google.gerrit.client.diff.Resources'/>
- <ui:style>
+ <ui:style gss='false'>
.header {
position: relative;
height: 16px;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/InsertCommentBubble.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/InsertCommentBubble.java
index 7287a65..7c8bc21 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/InsertCommentBubble.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/InsertCommentBubble.java
@@ -1,4 +1,4 @@
-//Copyright (C) 2014 The Android Open Source Project
+// Copyright (C) 2014 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/InsertCommentBubble.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/InsertCommentBubble.ui.xml
index d7c8fc9..6a18c4d 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/InsertCommentBubble.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/InsertCommentBubble.ui.xml
@@ -18,7 +18,7 @@
xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<ui:with field='res' type='com.google.gerrit.client.GerritResources'/>
- <ui:style>
+ <ui:style gss='false'>
.bubble {
z-index: 150;
white-space: nowrap;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PatchSetSelectBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PatchSetSelectBox.java
index aed2218..e597398 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PatchSetSelectBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PatchSetSelectBox.java
@@ -1,4 +1,4 @@
-//Copyright (C) 2013 The Android Open Source Project
+// Copyright (C) 2013 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -116,7 +116,7 @@
linkPanel.add(createEditIcon());
}
}
- List<WebLinkInfo> webLinks = Natives.asList(meta.web_links());
+ List<WebLinkInfo> webLinks = Natives.asList(meta.webLinks());
if (webLinks != null) {
for (WebLinkInfo webLink : webLinks) {
linkPanel.add(webLink.toAnchor());
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PatchSetSelectBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PatchSetSelectBox.ui.xml
index cc8dd74..6e526ec 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PatchSetSelectBox.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PatchSetSelectBox.ui.xml
@@ -20,7 +20,7 @@
<ui:with field='res' type='com.google.gerrit.client.GerritResources'/>
<ui:with field='patchConstants'
type='com.google.gerrit.client.patches.PatchConstants'/>
- <ui:style type='com.google.gerrit.client.diff.PatchSetSelectBox.BoxStyle'>
+ <ui:style gss='false' type='com.google.gerrit.client.diff.PatchSetSelectBox.BoxStyle'>
@eval selectionColor com.google.gerrit.client.Gerrit.getTheme().selectionColor;
@eval trimColor com.google.gerrit.client.Gerrit.getTheme().trimColor;
.table {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.ui.xml
index 62d2eac..e011091 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.ui.xml
@@ -17,7 +17,7 @@
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:x='urn:import:com.google.gerrit.client.ui'>
- <ui:style type='com.google.gerrit.client.diff.PreferencesBox.Style'>
+ <ui:style gss='false' type='com.google.gerrit.client.diff.PreferencesBox.Style'>
@external .gwt-TextBox;
@external .gwt-ToggleButton .html-face;
@external .gwt-ToggleButton-up;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PublishedBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PublishedBox.java
index 7d74c2b..a32d7b8 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PublishedBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PublishedBox.java
@@ -1,4 +1,4 @@
-//Copyright (C) 2013 The Android Open Source Project
+// Copyright (C) 2013 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PublishedBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PublishedBox.ui.xml
index bcc34e2..46b76ca 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PublishedBox.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PublishedBox.ui.xml
@@ -19,7 +19,7 @@
xmlns:c='urn:import:com.google.gerrit.client'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<ui:with field='res' type='com.google.gerrit.client.diff.Resources'/>
- <ui:style type='com.google.gerrit.client.diff.PublishedBox.Style'>
+ <ui:style gss='false' type='com.google.gerrit.client.diff.PublishedBox.Style'>
.avatar {
position: absolute;
width: 26px;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide.java
index d06b59e..a8b6065 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide.java
@@ -238,11 +238,11 @@
changeStatus = info.status();
info.revisions().copyKeysIntoChildren("name");
if (edit != null) {
- edit.set_name(edit.commit().commit());
- info.set_edit(edit);
+ edit.setName(edit.commit().commit());
+ info.setEdit(edit);
info.revisions().put(edit.name(), RevisionInfo.fromEdit(edit));
}
- int currentPatchSet = info.revision(info.current_revision())._number();
+ int currentPatchSet = info.revision(info.currentRevision())._number();
JsArray<RevisionInfo> list = info.revisions().values();
RevisionInfo.sortRevisionInfoByNumber(list);
diffTable.set(prefs, list, diff, edit != null, currentPatchSet,
@@ -570,8 +570,8 @@
diffTable.addStyleName(DiffTable.style.showLineNumbers());
}
- cmA = newCM(diff.meta_a(), diff.text_a(), diffTable.cmA);
- cmB = newCM(diff.meta_b(), diff.text_b(), diffTable.cmB);
+ cmA = newCM(diff.metaA(), diff.textA(), diffTable.cmA);
+ cmB = newCM(diff.metaB(), diff.textB(), diffTable.cmB);
cmA.extras().side(DisplaySide.A);
cmB.extras().side(DisplaySide.B);
@@ -606,7 +606,7 @@
chunkManager.getLineMapper());
prefsAction = new PreferencesAction(this, prefs);
- header.init(prefsAction, getLinks(), diff.side_by_side_web_links());
+ header.init(prefsAction, getLinks(), diff.sideBySideWebLinks());
scrollSynchronizer.setAutoHideDiffTableHeader(prefs.autoHideDiffTableHeader());
if (prefs.syntaxHighlighting() && fileSize.compareTo(FileSize.SMALL) > 0) {
@@ -654,7 +654,7 @@
}
DiffInfo.IntraLineStatus getIntraLineStatus() {
- return diff.intraline_status();
+ return diff.intralineStatus();
}
boolean canEnableRenderEntireFile(DiffPreferences prefs) {
@@ -663,7 +663,7 @@
}
String getContentType() {
- return getContentType(diff.meta_b());
+ return getContentType(diff.metaB());
}
void setThemeStyles(boolean d) {
@@ -716,8 +716,8 @@
@Override
public void onSuccess(Void result) {
if (prefs.syntaxHighlighting()) {
- cmA.setOption("mode", getContentType(diff.meta_a()));
- cmB.setOption("mode", getContentType(diff.meta_b()));
+ cmA.setOption("mode", getContentType(diff.metaA()));
+ cmB.setOption("mode", getContentType(diff.metaB()));
}
}
@@ -923,7 +923,7 @@
int offset = 6;
// Adjust for merge commits, which have two parent lines
- if (diff.text_b().startsWith("Merge")) {
+ if (diff.textB().startsWith("Merge")) {
offset += 1;
}
@@ -983,8 +983,8 @@
private String getContentType(DiffInfo.FileMeta meta) {
if (prefs.syntaxHighlighting() && meta != null
- && meta.content_type() != null) {
- ModeInfo m = ModeInfo.findMode(meta.content_type(), path);
+ && meta.contentType() != null) {
+ ModeInfo m = ModeInfo.findMode(meta.contentType(), path);
return m != null ? m.mime() : null;
}
return null;
@@ -992,8 +992,8 @@
private void injectMode(DiffInfo diffInfo, AsyncCallback<Void> cb) {
new ModeInjector()
- .add(getContentType(diffInfo.meta_a()))
- .add(getContentType(diffInfo.meta_b()))
+ .add(getContentType(diffInfo.metaA()))
+ .add(getContentType(diffInfo.metaB()))
.inject(cb);
}
@@ -1043,8 +1043,8 @@
@Override
public void onSuccess(DiffInfo info) {
new ModeInjector()
- .add(getContentType(info.meta_a()))
- .add(getContentType(info.meta_b()))
+ .add(getContentType(info.metaA()))
+ .add(getContentType(info.metaB()))
.inject(CallbackGroup.<Void> emptyCallback());
}
@@ -1085,8 +1085,8 @@
}
private static FileSize bucketFileSize(DiffInfo diff) {
- FileMeta a = diff.meta_a();
- FileMeta b = diff.meta_b();
+ FileMeta a = diff.metaA();
+ FileMeta b = diff.metaB();
FileSize[] sizes = FileSize.values();
for (int i = sizes.length - 1; 0 <= i; i--) {
FileSize s = sizes[i];
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide.ui.xml
index da5b351..a4c2eb9 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide.ui.xml
@@ -17,7 +17,7 @@
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:d='urn:import:com.google.gerrit.client.diff'>
- <ui:style>
+ <ui:style gss='false'>
.sbs {
margin-left: -5px;
margin-right: -5px;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SkipBar.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SkipBar.java
index 4c12cc0..258eec6 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SkipBar.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SkipBar.java
@@ -1,4 +1,4 @@
-//Copyright (C) 2013 The Android Open Source Project
+// Copyright (C) 2013 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SkipBar.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SkipBar.ui.xml
index 0ff23a7..bf3c425 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SkipBar.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SkipBar.ui.xml
@@ -16,7 +16,7 @@
-->
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
- <ui:style type='com.google.gerrit.client.diff.SkipBar.SkipBarStyle'>
+ <ui:style gss='false' type='com.google.gerrit.client.diff.SkipBar.SkipBarStyle'>
.skipBar {
background-color: #def;
height: 1.3em;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SkipManager.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SkipManager.java
index 4972f5d..a344e6b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SkipManager.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SkipManager.java
@@ -45,7 +45,8 @@
JsArray<Region> regions = diff.content();
List<SkippedLine> skips = new ArrayList<>();
- int lineA = 0, lineB = 0;
+ int lineA = 0;
+ int lineB = 0;
for (int i = 0; i < regions.length(); i++) {
Region current = regions.get(i);
if (current.ab() != null || current.common() || current.skip() > 0) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadCommandLink.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadCommandLink.java
index cea9106..d4237f9 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadCommandLink.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadCommandLink.java
@@ -15,8 +15,6 @@
package com.google.gerrit.client.download;
import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
-import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadCommand;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gwt.aria.client.Roles;
import com.google.gwt.event.dom.client.ClickEvent;
@@ -25,89 +23,15 @@
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwtexpui.clippy.client.CopyableLabel;
-import com.google.gwtjsonrpc.common.AsyncCallback;
-import com.google.gwtjsonrpc.common.VoidResult;
public abstract class DownloadCommandLink extends Anchor implements ClickHandler {
public static class CopyableCommandLinkFactory {
protected CopyableLabel copyLabel = null;
protected Widget widget;
- public class CheckoutCommandLink extends DownloadCommandLink {
- public CheckoutCommandLink () {
- super(DownloadCommand.CHECKOUT, "checkout");
- }
-
- @Override
- protected void setCurrentUrl(DownloadUrlLink link) {
- widget.setVisible(true);
- copyLabel.setText("git fetch " + link.getUrlData()
- + " && git checkout FETCH_HEAD");
- }
- }
-
- public class PullCommandLink extends DownloadCommandLink {
- public PullCommandLink() {
- super(DownloadCommand.PULL, "pull");
- }
-
- @Override
- protected void setCurrentUrl(DownloadUrlLink link) {
- widget.setVisible(true);
- copyLabel.setText("git pull " + link.getUrlData());
- }
- }
-
- public class CherryPickCommandLink extends DownloadCommandLink {
- public CherryPickCommandLink() {
- super(DownloadCommand.CHERRY_PICK, "cherry-pick");
- }
-
- @Override
- protected void setCurrentUrl(DownloadUrlLink link) {
- widget.setVisible(true);
- copyLabel.setText("git fetch " + link.getUrlData()
- + " && git cherry-pick FETCH_HEAD");
- }
- }
-
- public class FormatPatchCommandLink extends DownloadCommandLink {
- public FormatPatchCommandLink() {
- super(DownloadCommand.FORMAT_PATCH, "patch");
- }
-
- @Override
- protected void setCurrentUrl(DownloadUrlLink link) {
- widget.setVisible(true);
- copyLabel.setText("git fetch " + link.getUrlData()
- + " && git format-patch -1 --stdout FETCH_HEAD");
- }
- }
-
- public class RepoCommandLink extends DownloadCommandLink {
- String projectName;
- String ref;
- public RepoCommandLink(String project, String ref) {
- super(DownloadCommand.REPO_DOWNLOAD, "repo download");
- this.projectName = project;
- this.ref = ref;
- }
-
- @Override
- protected void setCurrentUrl(DownloadUrlLink link) {
- widget.setVisible(false);
- final StringBuilder r = new StringBuilder();
- r.append("repo download ");
- r.append(projectName);
- r.append(" ");
- r.append(ref);
- copyLabel.setText(r.toString());
- }
- }
-
public class CloneCommandLink extends DownloadCommandLink {
public CloneCommandLink() {
- super(DownloadCommand.CHECKOUT, "clone");
+ super("clone");
}
@Override
@@ -121,7 +45,7 @@
private final Project.NameKey project;
public CloneWithCommitMsgHookCommandLink(Project.NameKey project) {
- super(DownloadCommand.CHECKOUT, "clone with commit-msg hook");
+ super("clone with commit-msg hook");
this.project = project;
}
@@ -175,12 +99,8 @@
}
}
- final DownloadCommand cmdType;
-
- public DownloadCommandLink(DownloadCommand cmdType,
- String text) {
+ public DownloadCommandLink(String text) {
super(text);
- this.cmdType = cmdType;
setStyleName(Gerrit.RESOURCES.css().downloadLink());
Roles.getTabRole().set(getElement());
addClickHandler(this);
@@ -192,28 +112,6 @@
event.stopPropagation();
select();
-
- if (Gerrit.isSignedIn()) {
- // If the user is signed-in, remember this choice for future panels.
- //
- AccountGeneralPreferences pref =
- Gerrit.getUserAccount().getGeneralPreferences();
- pref.setDownloadCommand(cmdType);
- com.google.gerrit.client.account.Util.ACCOUNT_SVC.changePreferences(pref,
- new AsyncCallback<VoidResult>() {
- @Override
- public void onFailure(Throwable caught) {
- }
-
- @Override
- public void onSuccess(VoidResult result) {
- }
- });
- }
- }
-
- public DownloadCommand getCmdType() {
- return cmdType;
}
void select() {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadCommandPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadCommandPanel.java
index d17d6c2..5b7d015 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadCommandPanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadCommandPanel.java
@@ -15,8 +15,6 @@
package com.google.gerrit.client.download;
import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
-import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadCommand;
import com.google.gwt.aria.client.Roles;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Widget;
@@ -34,7 +32,7 @@
return getWidgetCount() == 0;
}
- public void select(AccountGeneralPreferences.DownloadCommand cmdType) {
+ public void select() {
DownloadCommandLink first = null;
for (Widget w : this) {
@@ -43,10 +41,6 @@
if (first == null) {
first = d;
}
- if (d.cmdType == cmdType) {
- d.select();
- return;
- }
}
}
@@ -70,9 +64,6 @@
private void update() {
if (currentCommand != null && currentUrl != null) {
currentCommand.setCurrentUrl(currentUrl);
- } else if (currentCommand != null &&
- currentCommand.getCmdType().equals(DownloadCommand.REPO_DOWNLOAD)) {
- currentCommand.setCurrentUrl(null);
}
}
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadPanel.java
index 350dbed..19c65a9 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadPanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadPanel.java
@@ -16,32 +16,24 @@
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
-import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadCommand;
-import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadScheme;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.InlineLabel;
import com.google.gwtexpui.clippy.client.CopyableLabel;
-import java.util.Set;
-
public abstract class DownloadPanel extends FlowPanel {
protected String projectName;
- protected Set<DownloadScheme> allowedSchemes =
- Gerrit.getConfig().getDownloadSchemes();
- protected Set<DownloadCommand> allowedCommands =
- Gerrit.getConfig().getDownloadCommands();
protected DownloadCommandLink.CopyableCommandLinkFactory cmdLinkfactory;
protected DownloadCommandPanel commands = new DownloadCommandPanel();
protected DownloadUrlPanel urls = new DownloadUrlPanel(commands);
protected CopyableLabel copyLabel = new CopyableLabel("");
- public DownloadPanel(String project, String ref, boolean allowAnonymous) {
+ public DownloadPanel(String project, boolean allowAnonymous) {
this.projectName = project;
copyLabel.setStyleName(Gerrit.RESOURCES.css().downloadLinkCopyLabel());
- urls.add(DownloadUrlLink.createDownloadUrlLinks(project, ref, allowAnonymous));
+ urls.add(DownloadUrlLink.createDownloadUrlLinks(project, allowAnonymous));
cmdLinkfactory = new DownloadCommandLink.CopyableCommandLinkFactory(
copyLabel, urls);
@@ -58,7 +50,7 @@
pref = new AccountGeneralPreferences();
pref.resetToDefaults();
}
- commands.select(pref.getDownloadCommand());
+ commands.select();
urls.select(pref.getDownloadUrl());
FlowPanel p = new FlowPanel();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadUrlLink.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadUrlLink.java
index ce5c060..275b918 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadUrlLink.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadUrlLink.java
@@ -17,7 +17,6 @@
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadScheme;
-import com.google.gerrit.reviewdb.client.AuthType;
import com.google.gwt.aria.client.Roles;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
@@ -33,28 +32,9 @@
import java.util.Set;
public class DownloadUrlLink extends Anchor implements ClickHandler {
- public static class DownloadRefUrlLink extends DownloadUrlLink {
- protected String projectName;
- protected String ref;
-
- protected DownloadRefUrlLink(DownloadScheme urlType,
- String text, String project, String ref) {
- super(urlType, text);
- this.projectName = project;
- this.ref = ref;
- }
-
- protected void appendRef(StringBuilder r) {
- if (ref != null) {
- r.append(" ");
- r.append(ref);
- }
- }
- }
-
- public static class AnonGitLink extends DownloadRefUrlLink {
- public AnonGitLink(String project, String ref) {
- super(DownloadScheme.ANON_GIT, Util.M.anonymousDownload("Git"), project, ref);
+ public static class AnonGitLink extends DownloadUrlLink {
+ public AnonGitLink(String project) {
+ super(DownloadScheme.ANON_GIT, Util.M.anonymousDownload("Git"), project);
}
@Override
@@ -62,14 +42,13 @@
StringBuilder r = new StringBuilder();
r.append(Gerrit.getConfig().getGitDaemonUrl());
r.append(projectName);
- appendRef(r);
return r.toString();
}
}
- public static class AnonHttpLink extends DownloadRefUrlLink {
- public AnonHttpLink(String project, String ref) {
- super(DownloadScheme.ANON_HTTP, Util.M.anonymousDownload("HTTP"), project, ref);
+ public static class AnonHttpLink extends DownloadUrlLink {
+ public AnonHttpLink(String project) {
+ super(DownloadScheme.ANON_HTTP, Util.M.anonymousDownload("HTTP"), project);
}
@Override
@@ -81,14 +60,13 @@
r.append(hostPageUrl);
}
r.append(projectName);
- appendRef(r);
return r.toString();
}
}
- public static class SshLink extends DownloadRefUrlLink {
- public SshLink(String project, String ref) {
- super(DownloadScheme.SSH, "SSH", project, ref);
+ public static class SshLink extends DownloadUrlLink {
+ public SshLink(String project) {
+ super(DownloadScheme.SSH, "SSH", project);
}
@Override
@@ -107,16 +85,15 @@
r.append(sshAddr);
r.append("/");
r.append(projectName);
- appendRef(r);
return r.toString();
}
}
- public static class HttpLink extends DownloadRefUrlLink {
+ public static class HttpLink extends DownloadUrlLink {
protected boolean anonymous;
- public HttpLink(String project, String ref, boolean anonymous) {
- super(DownloadScheme.HTTP, "HTTP", project, ref);
+ public HttpLink(String project, boolean anonymous) {
+ super(DownloadScheme.HTTP, "HTTP", project);
this.anonymous = anonymous;
}
@@ -145,46 +122,41 @@
r.append(base.substring(s));
}
r.append(projectName);
- appendRef(r);
return r.toString();
}
}
public static boolean siteReliesOnHttp() {
return Gerrit.getConfig().getGitHttpUrl() != null
- && Gerrit.getConfig().getAuthType() == AuthType.CUSTOM_EXTENSION
+ && Gerrit.info().auth().isCustomExtension()
&& !Gerrit.getConfig().siteHasUsernames();
}
public static List<DownloadUrlLink> createDownloadUrlLinks(String project,
- String ref, boolean allowAnonymous) {
+ boolean allowAnonymous) {
List<DownloadUrlLink> urls = new ArrayList<>();
- Set<DownloadScheme> allowedSchemes = Gerrit.getConfig().getDownloadSchemes();
+ Set<String> allowedSchemes = Gerrit.info().download().schemes();
if (allowAnonymous
&& Gerrit.getConfig().getGitDaemonUrl() != null
- && (allowedSchemes.contains(DownloadScheme.ANON_GIT) ||
- allowedSchemes.contains(DownloadScheme.DEFAULT_DOWNLOADS))) {
- urls.add(new DownloadUrlLink.AnonGitLink(project, ref));
+ && allowedSchemes.contains("git")) {
+ urls.add(new DownloadUrlLink.AnonGitLink(project));
}
if (allowAnonymous
- && (allowedSchemes.contains(DownloadScheme.ANON_HTTP) ||
- allowedSchemes.contains(DownloadScheme.DEFAULT_DOWNLOADS))) {
- urls.add(new DownloadUrlLink.AnonHttpLink(project, ref));
+ && allowedSchemes.contains("anonymous http")) {
+ urls.add(new DownloadUrlLink.AnonHttpLink(project));
}
if (Gerrit.getConfig().getSshdAddress() != null
&& hasUserName()
- && (allowedSchemes.contains(DownloadScheme.SSH) ||
- allowedSchemes.contains(DownloadScheme.DEFAULT_DOWNLOADS))) {
- urls.add(new DownloadUrlLink.SshLink(project, ref));
+ && allowedSchemes.contains("ssh")) {
+ urls.add(new DownloadUrlLink.SshLink(project));
}
if ((hasUserName() || siteReliesOnHttp())
- && (allowedSchemes.contains(DownloadScheme.HTTP)
- || allowedSchemes.contains(DownloadScheme.DEFAULT_DOWNLOADS))) {
- urls.add(new DownloadUrlLink.HttpLink(project, ref, allowAnonymous));
+ && allowedSchemes.contains("http")) {
+ urls.add(new DownloadUrlLink.HttpLink(project, allowAnonymous));
}
return urls;
}
@@ -196,21 +168,11 @@
}
protected DownloadScheme urlType;
+ protected String projectName;
protected String urlData;
protected String hostPageUrl = GWT.getHostPageBaseURL();
- public DownloadUrlLink(DownloadScheme urlType, String text, String urlData) {
- this(text);
- this.urlType = urlType;
- this.urlData = urlData;
- }
-
- public DownloadUrlLink(DownloadScheme urlType, String text) {
- this(text);
- this.urlType = urlType;
- }
-
- public DownloadUrlLink(String text) {
+ public DownloadUrlLink(DownloadScheme urlType, String text, String project) {
super(text);
setStyleName(Gerrit.RESOURCES.css().downloadLink());
Roles.getTabRole().set(getElement());
@@ -219,6 +181,8 @@
if (!hostPageUrl.endsWith("/")) {
hostPageUrl += "/";
}
+ this.urlType = urlType;
+ this.projectName = project;
}
public String getUrlData() {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditFileInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditFileInfo.java
index c833c5d..dda5fc2 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditFileInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditFileInfo.java
@@ -19,7 +19,7 @@
import com.google.gwt.core.client.JsArray;
public class EditFileInfo extends JavaScriptObject {
- public final native JsArray<DiffWebLinkInfo> web_links() /*-{ return this.web_links; }-*/;
+ public final native JsArray<DiffWebLinkInfo> webLinks() /*-{ return this.web_links; }-*/;
protected EditFileInfo() {
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java
index dd36657..e463607 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java
@@ -185,7 +185,7 @@
.get(group1.add(new AsyncCallback<DiffInfo>() {
@Override
public void onSuccess(DiffInfo diffInfo) {
- diffLinks = diffInfo.web_links();
+ diffLinks = diffInfo.webLinks();
}
@Override
@@ -377,7 +377,7 @@
renderLinksToDiff();
if (editInfo != null) {
- renderLinks(Natives.asList(editInfo.web_links()));
+ renderLinks(Natives.asList(editInfo.webLinks()));
} else if (diffLinks != null) {
renderLinks(Natives.asList(diffLinks));
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.ui.xml
index 93c3bb9..a82dc49 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.ui.xml
@@ -16,7 +16,7 @@
-->
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
- <ui:style>
+ <ui:style gss='false'>
@external .CodeMirror, .CodeMirror-cursor;
.header {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css b/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
index 8d961ca..0ee9fba 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
@@ -48,6 +48,10 @@
font-family: norm-font;
}
+button {
+ padding: 1px 6px;
+}
+
.gerritBody {
font-size: small;
padding-left: 5px;
@@ -297,13 +301,22 @@
white-space: nowrap;
display: inline;
}
-.searchPanel .gwt-TextBox {
+.searchPanel .searchTextBox {
font-size: 9pt;
+ margin: 5.286px 3px 0 0;
}
-.searchPanel .gwt-Button {
- font-size: 9pt;
- margin-left: 2px;
- padding: 3px 6px;
+.searchPanel .searchButton {
+ text-align: center;
+ font-size: 8pt;
+ font-weight: bold;
+ cursor: pointer;
+ border: 2px solid;
+ color: #FFF;
+ border-color: rgba(0, 0, 0, 0.15);
+ height: 14px;
+ background-color: #53A93F;
+ border-radius: 2px;
+ box-sizing: content-box;
}
.suggestBoxPopup {
z-index: 200;
@@ -345,7 +358,7 @@
opacity: 0.80;
}
}
-@if user.agent ie6 ie8 {
+@if user.agent ie8 {
/* IE just doesn't do opacity the way we want, make our dialog
* stand out in a way that it can't be missed against the page
*/
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupApi.java
index 0b178f2..e2b1112 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupApi.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupApi.java
@@ -125,7 +125,7 @@
} else {
MemberInput input = MemberInput.create();
for (String member : members) {
- input.add_member(member);
+ input.addMember(member);
}
members(group).post(input, cb);
}
@@ -139,7 +139,7 @@
} else {
MemberInput in = MemberInput.create();
for (Integer id : ids) {
- in.add_member(id.toString());
+ in.addMember(id.toString());
}
group(group).view("members.delete").post(in, cb);
}
@@ -172,7 +172,7 @@
} else {
IncludedGroupInput input = IncludedGroupInput.create();
for (String includedGroup : includedGroups) {
- input.add_group(includedGroup);
+ input.addGroup(includedGroup);
}
groups(group).post(input, cb);
}
@@ -187,7 +187,7 @@
} else {
IncludedGroupInput in = IncludedGroupInput.create();
for (AccountGroup.UUID g : ids) {
- in.add_group(g.get());
+ in.addGroup(g.get());
}
group(group).view("groups.delete").post(in, cb);
}
@@ -235,7 +235,7 @@
private static class MemberInput extends JavaScriptObject {
final native void init() /*-{ this.members = []; }-*/;
- final native void add_member(String n) /*-{ this.members.push(n); }-*/;
+ final native void addMember(String n) /*-{ this.members.push(n); }-*/;
static MemberInput create() {
MemberInput m = (MemberInput) createObject();
@@ -249,7 +249,7 @@
private static class IncludedGroupInput extends JavaScriptObject {
final native void init() /*-{ this.groups = []; }-*/;
- final native void add_group(String n) /*-{ this.groups.push(n); }-*/;
+ final native void addGroup(String n) /*-{ this.groups.push(n); }-*/;
static IncludedGroupInput create() {
IncludedGroupInput g = (IncludedGroupInput) createObject();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AbstractPatchContentTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AbstractPatchContentTable.java
index efeb2ec..63823ea 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AbstractPatchContentTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AbstractPatchContentTable.java
@@ -1,4 +1,4 @@
-//Copyright (C) 2008 The Android Open Source Project
+// Copyright (C) 2008 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -546,7 +546,7 @@
private CommentEditorPanel findOrCreateCommentEditor(final int suggestRow,
final int column, final PatchLineComment newComment, final boolean create) {
int row = suggestRow;
- int spans[] = new int[column + 1];
+ int[] spans = new int[column + 1];
FIND_ROW: while (row < table.getRowCount()) {
int col = 0;
for (int cell = 0; row < table.getRowCount()
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/CommentEditorPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/CommentEditorPanel.java
index 2538102..8642556 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/CommentEditorPanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/CommentEditorPanel.java
@@ -345,7 +345,7 @@
if (c.getLine() > 0) {
i.line(c.getLine());
}
- i.in_reply_to(c.getParentUuid());
+ i.inReplyTo(c.getParentUuid());
i.message(c.getMessage());
return i;
}
@@ -359,7 +359,7 @@
i.id()),
i.line(),
Gerrit.getUserAccount().getId(),
- i.in_reply_to(),
+ i.inReplyTo(),
i.updated());
p.setMessage(i.message());
p.setSide((short) (i.side() == Side.PARENT ? 0 : 1));
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/CommitMessageBlock.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/CommitMessageBlock.ui.xml
index ca81537..f1bf3de 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/CommitMessageBlock.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/CommitMessageBlock.ui.xml
@@ -20,7 +20,7 @@
<ui:with field='res' type='com.google.gerrit.client.GerritResources'/>
- <ui:style>
+ <ui:style gss='false'>
@eval selectionColor com.google.gerrit.client.Gerrit.getTheme().selectionColor;
@eval trimColor com.google.gerrit.client.Gerrit.getTheme().trimColor;
@eval backgroundColor com.google.gerrit.client.Gerrit.getTheme().backgroundColor;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/NavLinks.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/NavLinks.java
index 2a04c38..352ade7 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/NavLinks.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/NavLinks.java
@@ -54,7 +54,7 @@
private final KeyCommandSet keys;
private final Grid table;
- private KeyCommand cmds[] = new KeyCommand[2];
+ private KeyCommand[] cmds = new KeyCommand[2];
NavLinks(KeyCommandSet kcs, PatchSet.Id forPatch) {
patchSetId = forPatch;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScriptSettingsPanel.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScriptSettingsPanel.ui.xml
index 586b767..5164302 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScriptSettingsPanel.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScriptSettingsPanel.ui.xml
@@ -22,7 +22,7 @@
ui:generateKeys='com.google.gwt.i18n.rebind.keygen.MD5KeyGenerator'
ui:generateLocales='default,en'
>
-<ui:style>
+<ui:style gss='false'>
@external .gwt-TextBox;
@external .gwt-ListBox;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.ui.xml
index 338e950..8977876 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.ui.xml
@@ -18,7 +18,7 @@
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<ui:with field='res' type='com.google.gerrit.client.GerritResources'/>
- <ui:style type='com.google.gerrit.client.patches.PatchSetSelectBox.BoxStyle'>
+ <ui:style gss='false' type='com.google.gerrit.client.patches.PatchSetSelectBox.BoxStyle'>
@eval selectionColor com.google.gerrit.client.Gerrit.getTheme().selectionColor;
@eval backgroundColor com.google.gerrit.client.Gerrit.getTheme().backgroundColor;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedPatchScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedPatchScreen.java
index a5c1484..2479322 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedPatchScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedPatchScreen.java
@@ -251,7 +251,7 @@
}
private List<WebLinkInfo> getWebLinks(DiffInfo diffInfo) {
- return diffInfo.unified_web_links();
+ return diffInfo.unifiedWebLinks();
}
private String getSideBySideDiffUrl() {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/BranchInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/BranchInfo.java
index 6c1a841..0284aa3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/BranchInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/BranchInfo.java
@@ -17,22 +17,20 @@
import com.google.gerrit.client.WebLinkInfo;
import com.google.gerrit.client.actions.ActionInfo;
import com.google.gerrit.client.rpc.NativeMap;
-import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArray;
public class BranchInfo extends JavaScriptObject {
public final String getShortName() {
- return ref().startsWith(Branch.R_HEADS)
- ? ref().substring(Branch.R_HEADS.length())
- : ref();
+ return RefNames.shortName(ref());
}
public final native String ref() /*-{ return this.ref; }-*/;
public final native String revision() /*-{ return this.revision; }-*/;
public final native boolean canDelete() /*-{ return this['can_delete'] ? true : false; }-*/;
public final native NativeMap<ActionInfo> actions() /*-{ return this.actions }-*/;
- public final native JsArray<WebLinkInfo> web_links() /*-{ return this.web_links; }-*/;
+ public final native JsArray<WebLinkInfo> webLinks() /*-{ return this.web_links; }-*/;
protected BranchInfo() {
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ConfigInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ConfigInfo.java
index 7aa5be5..b91c5de 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ConfigInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ConfigInfo.java
@@ -35,23 +35,23 @@
public final native String description()
/*-{ return this.description }-*/;
- public final native InheritedBooleanInfo require_change_id()
+ public final native InheritedBooleanInfo requireChangeId()
/*-{ return this.require_change_id; }-*/;
- public final native InheritedBooleanInfo use_content_merge()
+ public final native InheritedBooleanInfo useContentMerge()
/*-{ return this.use_content_merge; }-*/;
- public final native InheritedBooleanInfo use_contributor_agreements()
+ public final native InheritedBooleanInfo useContributorAgreements()
/*-{ return this.use_contributor_agreements; }-*/;
- public final native InheritedBooleanInfo create_new_change_for_all_not_in_target()
+ public final native InheritedBooleanInfo createNewChangeForAllNotInTarget()
/*-{ return this.create_new_change_for_all_not_in_target; }-*/;
- public final native InheritedBooleanInfo use_signed_off_by()
+ public final native InheritedBooleanInfo useSignedOffBy()
/*-{ return this.use_signed_off_by; }-*/;
- public final SubmitType submit_type() {
- return SubmitType.valueOf(submit_typeRaw());
+ public final SubmitType submitType() {
+ return SubmitType.valueOf(submitTypeRaw());
}
public final native NativeMap<NativeMap<ConfigParameterInfo>> pluginConfig()
@@ -63,7 +63,7 @@
public final native NativeMap<ActionInfo> actions()
/*-{ return this.actions; }-*/;
- private final native String submit_typeRaw()
+ private final native String submitTypeRaw()
/*-{ return this.submit_type }-*/;
public final ProjectState state() {
@@ -75,7 +75,7 @@
private final native String stateRaw()
/*-{ return this.state }-*/;
- public final native MaxObjectSizeLimitInfo max_object_size_limit()
+ public final native MaxObjectSizeLimitInfo maxObjectSizeLimit()
/*-{ return this.max_object_size_limit; }-*/;
private final native NativeMap<CommentLinkInfo> commentlinks0()
@@ -131,13 +131,13 @@
public final native boolean value()
/*-{ return this.value ? true : false; }-*/;
- public final native boolean inherited_value()
+ public final native boolean inheritedValue()
/*-{ return this.inherited_value ? true : false; }-*/;
- public final InheritableBoolean configured_value() {
- return InheritableBoolean.valueOf(configured_valueRaw());
+ public final InheritableBoolean configuredValue() {
+ return InheritableBoolean.valueOf(configuredValueRaw());
}
- private final native String configured_valueRaw()
+ private final native String configuredValueRaw()
/*-{ return this.configured_value }-*/;
public final void setConfiguredValue(InheritableBoolean v) {
@@ -152,8 +152,8 @@
public static class MaxObjectSizeLimitInfo extends JavaScriptObject {
public final native String value() /*-{ return this.value; }-*/;
- public final native String inherited_value() /*-{ return this.inherited_value; }-*/;
- public final native String configured_value() /*-{ return this.configured_value }-*/;
+ public final native String inheritedValue() /*-{ return this.inherited_value; }-*/;
+ public final native String configuredValue() /*-{ return this.configured_value }-*/;
protected MaxObjectSizeLimitInfo() {
}
@@ -179,8 +179,8 @@
public static class ConfigParameterValue extends JavaScriptObject {
final native void init() /*-{ this.values = []; }-*/;
- final native void add_value(String v) /*-{ this.values.push(v); }-*/;
- final native void set_value(String v) /*-{ if(v)this.value = v; }-*/;
+ final native void addValue(String v) /*-{ this.values.push(v); }-*/;
+ final native void setValue(String v) /*-{ if(v)this.value = v; }-*/;
public static ConfigParameterValue create() {
ConfigParameterValue v = createObject().cast();
return v;
@@ -189,13 +189,13 @@
public final ConfigParameterValue values(String[] values) {
init();
for (String v : values) {
- add_value(v);
+ addValue(v);
}
return this;
}
public final ConfigParameterValue value(String v) {
- set_value(v);
+ setValue(v);
return this;
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ConfigInfoCache.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ConfigInfoCache.java
index c22b007..e000a97 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ConfigInfoCache.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ConfigInfoCache.java
@@ -61,7 +61,7 @@
}
public static void add(ChangeInfo info) {
- instance.changeToProject.put(info.legacy_id().get(), info.project());
+ instance.changeToProject.put(info.legacyId().get(), info.project());
}
private final LinkedHashMap<String, Entry> cache;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java
index b121d07..d81dfe5 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java
@@ -84,7 +84,7 @@
} else {
DeleteBranchesInput d = DeleteBranchesInput.create();
for (String ref : refs) {
- d.add_branch(ref);
+ d.addBranch(ref);
}
project(name).view("branches:delete").post(d, cb);
}
@@ -317,6 +317,6 @@
}
final native void init() /*-{ this.branches = []; }-*/;
- final native void add_branch(String b) /*-{ this.branches.push(b); }-*/;
+ final native void addBranch(String b) /*-{ this.branches.push(b); }-*/;
}
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectInfo.java
index fe9872c..029e59b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectInfo.java
@@ -30,7 +30,7 @@
public final native String name() /*-{ return this.name; }-*/;
public final native String description() /*-{ return this.description; }-*/;
- public final native JsArray<WebLinkInfo> web_links() /*-{ return this.web_links; }-*/;
+ public final native JsArray<WebLinkInfo> webLinks() /*-{ return this.web_links; }-*/;
public final ProjectState state() {
return ProjectState.valueOf(getStringState());
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AccountLinkPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AccountLinkPanel.java
index cdad972..2633e3b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AccountLinkPanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AccountLinkPanel.java
@@ -71,8 +71,8 @@
return ai.email();
} else if (ai.name() != null) {
return ai.name();
- } else if (ai._account_id() != 0) {
- return "" + ai._account_id();
+ } else if (ai._accountId() != 0) {
+ return "" + ai._accountId();
} else {
return "";
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/BranchLink.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/BranchLink.java
index c9a0590..6af4b78 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/BranchLink.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/BranchLink.java
@@ -17,9 +17,9 @@
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.changes.QueryScreen;
import com.google.gerrit.common.PageLinks;
-import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.RefNames;
/** Link to the open changes of a project. */
public class BranchLink extends InlineHyperlink {
@@ -61,10 +61,10 @@
String branch, String topic) {
String query = PageLinks.projectQuery(project, status);
- if (branch.startsWith(Branch.R_REFS)) {
- if (branch.startsWith(Branch.R_HEADS)) {
+ if (branch.startsWith(RefNames.REFS)) {
+ if (branch.startsWith(RefNames.REFS_HEADS)) {
query += " " + PageLinks.op("branch", //
- branch.substring(Branch.R_HEADS.length()));
+ branch.substring(RefNames.REFS_HEADS.length()));
} else {
query += " " + PageLinks.op("ref", branch);
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CherryPickDialog.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CherryPickDialog.java
index 00269f9..f69e042 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CherryPickDialog.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CherryPickDialog.java
@@ -82,7 +82,7 @@
return newBranch.getText();
}
- class BranchSuggestion implements Suggestion {
+ static class BranchSuggestion implements Suggestion {
private BranchInfo branch;
public BranchSuggestion(BranchInfo branch) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CreateChangeDialog.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CreateChangeDialog.java
index 021f39c..a2b4aa8 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CreateChangeDialog.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CreateChangeDialog.java
@@ -19,7 +19,6 @@
import com.google.gerrit.client.projects.ProjectApi;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.rpc.Natives;
-import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.user.client.ui.FlowPanel;
@@ -82,7 +81,7 @@
return newChange.getText();
}
- class BranchSuggestion implements Suggestion {
+ static class BranchSuggestion implements Suggestion {
private BranchInfo branch;
public BranchSuggestion(BranchInfo branch) {
@@ -91,10 +90,7 @@
@Override
public String getDisplayString() {
- if (branch.ref().startsWith(Branch.R_HEADS)) {
- return branch.ref().substring(Branch.R_HEADS.length());
- }
- return branch.ref();
+ return branch.getShortName();
}
@Override
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/FancyFlexTableImplIE6.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/FancyFlexTableImplIE8.java
similarity index 96%
rename from gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/FancyFlexTableImplIE6.java
rename to gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/FancyFlexTableImplIE8.java
index 59feba8..76ad0e7 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/FancyFlexTableImplIE6.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/FancyFlexTableImplIE8.java
@@ -21,7 +21,7 @@
import com.google.gwtexpui.safehtml.client.SafeHtml;
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
-public class FancyFlexTableImplIE6 extends FancyFlexTableImpl {
+public class FancyFlexTableImplIE8 extends FancyFlexTableImpl {
@Override
public void resetHtml(final FlexTable myTable, final SafeHtml bodyHtml) {
final Element oldBody = getBodyElement(myTable);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectsTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectsTable.java
index 6637957..bb55b69 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectsTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectsTable.java
@@ -65,8 +65,9 @@
}
public void displaySubset(ProjectMap projects, int fromIndex, int toIndex) {
- while (1 < table.getRowCount())
+ while (1 < table.getRowCount()) {
table.removeRow(table.getRowCount() - 1);
+ }
List<ProjectInfo> list = Natives.asList(projects.values());
Collections.sort(list, new Comparator<ProjectInfo>() {
@@ -75,8 +76,9 @@
return a.name().compareTo(b.name());
}
});
- for(ProjectInfo p : list.subList(fromIndex, toIndex))
+ for (ProjectInfo p : list.subList(fromIndex, toIndex)) {
insert(table.getRowCount(), p);
+ }
finishDisplay();
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/RebaseDialog.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/RebaseDialog.java
index 5f47d98..2744877 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/RebaseDialog.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/RebaseDialog.java
@@ -20,6 +20,7 @@
import com.google.gerrit.client.changes.Util;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.rpc.Natives;
+import com.google.gerrit.extensions.client.ListChangesOption;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
@@ -29,6 +30,7 @@
import com.google.gwtexpui.globalkey.client.GlobalKey;
import com.google.gwtexpui.safehtml.client.HighlightSuggestOracle;
+import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
@@ -51,10 +53,10 @@
String query = request.getQuery().toLowerCase();
LinkedList<ChangeSuggestion> suggestions = new LinkedList<>();
for (final ChangeInfo ci : changes) {
- if (changeId.equals(ci.legacy_id())) {
+ if (changeId.equals(ci.legacyId())) {
continue; // do not suggest current change
}
- String id = String.valueOf(ci.legacy_id().get());
+ String id = String.valueOf(ci.legacyId().get());
if (id.contains(query) || ci.subject().toLowerCase().contains(query)) {
suggestions.add(new ChangeSuggestion(ci));
if (suggestions.size() >= 50) { // limit to 50 suggestions
@@ -76,8 +78,10 @@
public void onClick(ClickEvent event) {
boolean checked = ((CheckBox) event.getSource()).getValue();
if (checked) {
- ChangeList.next("project:" + project + " AND branch:" + branch
- + " AND is:open NOT age:90d", 0, 1000,
+ ChangeList.query(
+ "project:" + project + " AND branch:" + branch
+ + " AND is:open NOT age:90d",
+ Collections.<ListChangesOption> emptySet(),
new GerritCallback<ChangeList>() {
@Override
public void onSuccess(ChangeList result) {
@@ -136,12 +140,12 @@
@Override
public String getDisplayString() {
- return String.valueOf(change.legacy_id().get()) + ": " + change.subject();
+ return String.valueOf(change.legacyId().get()) + ": " + change.subject();
}
@Override
public String getReplacementString() {
- return String.valueOf(change.legacy_id().get());
+ return String.valueOf(change.legacyId().get());
}
}
}
diff --git a/gerrit-gwtui/src/main/java/net/codemirror/lib/CodeMirror.java b/gerrit-gwtui/src/main/java/net/codemirror/lib/CodeMirror.java
index 1c9ad3c..639e5e7 100644
--- a/gerrit-gwtui/src/main/java/net/codemirror/lib/CodeMirror.java
+++ b/gerrit-gwtui/src/main/java/net/codemirror/lib/CodeMirror.java
@@ -112,9 +112,24 @@
}-*/;
public enum LineClassWhere {
- TEXT { @Override String value() { return "text"; } },
- BACKGROUND { @Override String value() { return "background"; } },
- WRAP { @Override String value() { return "wrap"; } };
+ TEXT {
+ @Override
+ String value() {
+ return "text";
+ }
+ },
+ BACKGROUND {
+ @Override
+ String value() {
+ return "background";
+ }
+ },
+ WRAP {
+ @Override
+ String value() {
+ return "wrap";
+ }
+ };
abstract String value();
}
diff --git a/gerrit-gwtui/src/main/java/net/codemirror/lib/TextMarker.java b/gerrit-gwtui/src/main/java/net/codemirror/lib/TextMarker.java
index 2d69015..eac8510 100644
--- a/gerrit-gwtui/src/main/java/net/codemirror/lib/TextMarker.java
+++ b/gerrit-gwtui/src/main/java/net/codemirror/lib/TextMarker.java
@@ -35,8 +35,8 @@
public static FromTo create(CommentRange range) {
return create(
- Pos.create(range.start_line() - 1, range.start_character()),
- Pos.create(range.end_line() - 1, range.end_character()));
+ Pos.create(range.startLine() - 1, range.startCharacter()),
+ Pos.create(range.endLine() - 1, range.endCharacter()));
}
public final native Pos from() /*-{ return this.from }-*/;
diff --git a/gerrit-gwtui/src/main/java/net/codemirror/mode/ModeInfo.java b/gerrit-gwtui/src/main/java/net/codemirror/mode/ModeInfo.java
index d6b194b..782500d 100644
--- a/gerrit-gwtui/src/main/java/net/codemirror/mode/ModeInfo.java
+++ b/gerrit-gwtui/src/main/java/net/codemirror/mode/ModeInfo.java
@@ -62,6 +62,7 @@
Modes.I.php(),
Modes.I.pig(),
Modes.I.properties(),
+ Modes.I.puppet(),
Modes.I.python(),
Modes.I.r(),
Modes.I.rst(),
diff --git a/gerrit-gwtui/src/main/java/net/codemirror/mode/Modes.java b/gerrit-gwtui/src/main/java/net/codemirror/mode/Modes.java
index e511be5..8170c2b 100644
--- a/gerrit-gwtui/src/main/java/net/codemirror/mode/Modes.java
+++ b/gerrit-gwtui/src/main/java/net/codemirror/mode/Modes.java
@@ -47,6 +47,7 @@
@Source("php.js") @DoNotEmbed DataResource php();
@Source("pig.js") @DoNotEmbed DataResource pig();
@Source("properties.js") @DoNotEmbed DataResource properties();
+ @Source("puppet.js") @DoNotEmbed DataResource puppet();
@Source("python.js") @DoNotEmbed DataResource python();
@Source("r.js") @DoNotEmbed DataResource r();
@Source("rst.js") @DoNotEmbed DataResource rst();
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ContainerAuthFilter.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ContainerAuthFilter.java
index 91fb6af..378c4d5 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ContainerAuthFilter.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ContainerAuthFilter.java
@@ -52,8 +52,6 @@
*/
@Singleton
class ContainerAuthFilter implements Filter {
- public static final String REALM_NAME = "Gerrit Code Review";
-
private final DynamicItem<WebSession> session;
private final AccountCache accountCache;
private final Config config;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GerritConfigProvider.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GerritConfigProvider.java
index 4b0e46c..eadc536 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GerritConfigProvider.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GerritConfigProvider.java
@@ -16,22 +16,18 @@
import com.google.common.base.Function;
import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.gerrit.common.data.GerritConfig;
import com.google.gerrit.common.data.GitwebConfig;
-import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.server.account.Realm;
import com.google.gerrit.server.change.ArchiveFormat;
import com.google.gerrit.server.change.GetArchive;
-import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.AnonymousCowardName;
import com.google.gerrit.server.config.AuthConfig;
import com.google.gerrit.server.config.ConfigUtil;
-import com.google.gerrit.server.config.DownloadConfig;
import com.google.gerrit.server.config.GerritServerConfig;
-import com.google.gerrit.server.contact.ContactStore;
-import com.google.gerrit.server.mail.EmailSender;
import com.google.gerrit.server.ssh.SshInfo;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -40,8 +36,6 @@
import org.eclipse.jgit.lib.Config;
import java.net.MalformedURLException;
-import java.util.HashSet;
-import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletContext;
@@ -50,42 +44,32 @@
private final Realm realm;
private final Config cfg;
private final AuthConfig authConfig;
- private final DownloadConfig downloadConfig;
private final GetArchive.AllowedFormats archiveFormats;
private final GitWebConfig gitWebConfig;
- private final AllProjectsName wildProject;
private final SshInfo sshInfo;
- private EmailSender emailSender;
- private final ContactStore contactStore;
private final ServletContext servletContext;
private final String anonymousCowardName;
@Inject
- GerritConfigProvider(final Realm r, @GerritServerConfig final Config gsc,
- final AuthConfig ac, final GitWebConfig gwc, final AllProjectsName wp,
- final SshInfo si, final ContactStore cs,
- final ServletContext sc, final DownloadConfig dc,
- final GetArchive.AllowedFormats af,
- final @AnonymousCowardName String acn) {
+ GerritConfigProvider(Realm r,
+ @GerritServerConfig Config gsc,
+ AuthConfig ac,
+ GitWebConfig gwc,
+ SshInfo si,
+ ServletContext sc,
+ GetArchive.AllowedFormats af,
+ @AnonymousCowardName String acn) {
realm = r;
cfg = gsc;
authConfig = ac;
- downloadConfig = dc;
archiveFormats = af;
gitWebConfig = gwc;
sshInfo = si;
- wildProject = wp;
- contactStore = cs;
servletContext = sc;
anonymousCowardName = acn;
}
- @Inject(optional = true)
- void setEmailSender(final EmailSender d) {
- emailSender = d;
- }
-
private GerritConfig create() throws MalformedURLException {
final GerritConfig config = new GerritConfig();
switch (authConfig.getAuthType()) {
@@ -118,15 +102,9 @@
break;
}
config.setSwitchAccountUrl(cfg.getString("auth", null, "switchAccountUrl"));
- config.setUseContributorAgreements(cfg.getBoolean("auth",
- "contributoragreements", false));
config.setGitDaemonUrl(cfg.getString("gerrit", null, "canonicalgiturl"));
config.setGitHttpUrl(cfg.getString("gerrit", null, "gitHttpUrl"));
- config.setUseContactInfo(contactStore != null && contactStore.isEnabled());
- config.setDownloadSchemes(downloadConfig.getDownloadSchemes());
- config.setDownloadCommands(downloadConfig.getDownloadCommands());
config.setAuthType(authConfig.getAuthType());
- config.setWildProject(wildProject);
config.setDocumentationAvailable(servletContext
.getResource("/Documentation/index.html") != null);
config.setAnonymousCowardName(anonymousCowardName);
@@ -134,8 +112,18 @@
config.setChangeUpdateDelay((int) ConfigUtil.getTimeUnit(
cfg, "change", null, "updateDelay", 30, TimeUnit.SECONDS));
config.setLargeChangeSize(cfg.getInt("change", "largeChange", 500));
+
+ // Zip is not supported because it may be interpreted by a Java plugin as a
+ // valid JAR file, whose code would have access to cookies on the domain.
config.setArchiveFormats(Lists.newArrayList(Iterables.transform(
- archiveFormats.getAllowed(),
+ Iterables.filter(
+ archiveFormats.getAllowed(),
+ new Predicate<ArchiveFormat>() {
+ @Override
+ public boolean apply(ArchiveFormat format) {
+ return (format != ArchiveFormat.ZIP);
+ }
+ }),
new Function<ArchiveFormat, String>() {
@Override
public String apply(ArchiveFormat in) {
@@ -146,17 +134,7 @@
config.setReportBugUrl(cfg.getString("gerrit", null, "reportBugUrl"));
config.setReportBugText(cfg.getString("gerrit", null, "reportBugText"));
- final Set<Account.FieldName> fields = new HashSet<>();
- for (final Account.FieldName n : Account.FieldName.values()) {
- if (realm.allowsEdit(n)) {
- fields.add(n);
- }
- }
- if (emailSender != null && emailSender.isEnabled()
- && realm.allowsEdit(Account.FieldName.REGISTER_NEW_EMAIL)) {
- fields.add(Account.FieldName.REGISTER_NEW_EMAIL);
- }
- config.setEditableAccountFields(fields);
+ config.setEditableAccountFields(realm.getEditableFields());
if (gitWebConfig.getUrl() != null) {
config.setGitwebLink(new GitwebConfig(gitWebConfig.getUrl(), gitWebConfig
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitWebConfig.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitWebConfig.java
index 9d47977..7dc0c17 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitWebConfig.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitWebConfig.java
@@ -14,6 +14,9 @@
package com.google.gerrit.httpd;
+import static java.nio.file.Files.isExecutable;
+import static java.nio.file.Files.isRegularFile;
+
import com.google.gerrit.common.data.GitWebType;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.SitePaths;
@@ -23,16 +26,17 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
public class GitWebConfig {
private static final Logger log = LoggerFactory.getLogger(GitWebConfig.class);
private final String url;
- private final File gitweb_cgi;
- private final File gitweb_css;
- private final File gitweb_js;
- private final File git_logo_png;
+ private final Path gitweb_cgi;
+ private final Path gitweb_css;
+ private final Path gitweb_js;
+ private final Path git_logo_png;
private GitWebType type;
@Inject
@@ -117,20 +121,20 @@
return;
}
- final File pkgCgi = new File("/usr/lib/cgi-bin/gitweb.cgi");
+ final Path pkgCgi = Paths.get("/usr/lib/cgi-bin/gitweb.cgi");
String[] resourcePaths = {"/usr/share/gitweb/static", "/usr/share/gitweb",
"/var/www/static", "/var/www"};
- File cgi;
+ Path cgi;
if (cfgCgi != null) {
// Use the CGI script configured by the administrator, failing if it
// cannot be used as specified.
//
cgi = sitePaths.resolve(cfgCgi);
- if (!cgi.isFile()) {
+ if (!isRegularFile(cgi)) {
throw new IllegalStateException("Cannot find gitweb.cgi: " + cgi);
}
- if (!cgi.canExecute()) {
+ if (!isExecutable(cgi)) {
throw new IllegalStateException("Cannot execute gitweb.cgi: " + cgi);
}
@@ -138,11 +142,11 @@
// Assume the administrator pointed us to the distribution,
// which also has the corresponding CSS and logo file.
//
- String absPath = cgi.getParentFile().getAbsolutePath();
+ String absPath = cgi.getParent().toAbsolutePath().toString();
resourcePaths = new String[] {absPath + "/static", absPath};
}
- } else if (pkgCgi.isFile() && pkgCgi.canExecute()) {
+ } else if (isRegularFile(pkgCgi) && isExecutable(pkgCgi)) {
// Use the OS packaged CGI.
//
log.debug("Assuming gitweb at " + pkgCgi);
@@ -154,13 +158,15 @@
resourcePaths = new String[] {};
}
- File css = null, js = null, logo = null;
+ Path css = null;
+ Path js = null;
+ Path logo = null;
for (String path : resourcePaths) {
- File dir = new File(path);
- css = new File(dir, "gitweb.css");
- js = new File(dir, "gitweb.js");
- logo = new File(dir, "git-logo.png");
- if (css.isFile() && logo.isFile()) {
+ Path dir = Paths.get(path);
+ css = dir.resolve("gitweb.css");
+ js = dir.resolve("gitweb.js");
+ logo = dir.resolve("git-logo.png");
+ if (isRegularFile(css) && isRegularFile(logo)) {
break;
}
}
@@ -191,22 +197,22 @@
}
/** @return local path to the CGI executable; null if we shouldn't execute. */
- public File getGitwebCGI() {
+ public Path getGitwebCGI() {
return gitweb_cgi;
}
/** @return local path of the {@code gitweb.css} matching the CGI. */
- public File getGitwebCSS() {
+ public Path getGitwebCSS() {
return gitweb_css;
}
/** @return local path of the {@code gitweb.js} for the CGI. */
- public File getGitwebJS() {
+ public Path getGitwebJS() {
return gitweb_js;
}
/** @return local path of the {@code git-logo.png} for the CGI. */
- public File getGitLogoPNG() {
+ public Path getGitLogoPNG() {
return git_logo_png;
}
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/HtmlDomUtil.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/HtmlDomUtil.java
index 1a2d3f6..1eb88b1 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/HtmlDomUtil.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/HtmlDomUtil.java
@@ -14,6 +14,8 @@
package com.google.gerrit.httpd;
+import com.google.common.io.ByteStreams;
+
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
@@ -21,14 +23,14 @@
import org.xml.sax.SAXException;
import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
-import java.io.InputStreamReader;
import java.io.StringWriter;
-import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
import java.util.zip.GZIPOutputStream;
import javax.xml.parsers.DocumentBuilder;
@@ -36,7 +38,6 @@
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
@@ -49,21 +50,21 @@
/** Utility functions to deal with HTML using W3C DOM operations. */
public class HtmlDomUtil {
/** Standard character encoding we prefer (UTF-8). */
- public static final String ENC = "UTF-8";
+ public static final Charset ENC = StandardCharsets.UTF_8;
/** DOCTYPE for a standards mode HTML document. */
public static final String HTML_STRICT =
"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd";
/** Convert a document to a UTF-8 byte sequence. */
- public static byte[] toUTF8(final Document hostDoc) throws IOException {
+ public static byte[] toUTF8(Document hostDoc) throws IOException {
return toString(hostDoc).getBytes(ENC);
}
/** Compress the document. */
- public static byte[] compress(final byte[] raw) throws IOException {
- final ByteArrayOutputStream out = new ByteArrayOutputStream();
- final GZIPOutputStream gz = new GZIPOutputStream(out);
+ public static byte[] compress(byte[] raw) throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ GZIPOutputStream gz = new GZIPOutputStream(out);
gz.write(raw);
gz.finish();
gz.flush();
@@ -71,43 +72,39 @@
}
/** Convert a document to a String, assuming later encoding to UTF-8. */
- public static String toString(final Document hostDoc) throws IOException {
+ public static String toString(Document hostDoc) throws IOException {
try {
- final StringWriter out = new StringWriter();
- final DOMSource domSource = new DOMSource(hostDoc);
- final StreamResult streamResult = new StreamResult(out);
- final TransformerFactory tf = TransformerFactory.newInstance();
- final Transformer serializer = tf.newTransformer();
- serializer.setOutputProperty(OutputKeys.ENCODING, ENC);
+ StringWriter out = new StringWriter();
+ DOMSource domSource = new DOMSource(hostDoc);
+ StreamResult streamResult = new StreamResult(out);
+ TransformerFactory tf = TransformerFactory.newInstance();
+ Transformer serializer = tf.newTransformer();
+ serializer.setOutputProperty(OutputKeys.ENCODING, ENC.name());
serializer.setOutputProperty(OutputKeys.METHOD, "html");
serializer.setOutputProperty(OutputKeys.INDENT, "no");
serializer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,
HtmlDomUtil.HTML_STRICT);
serializer.transform(domSource, streamResult);
return out.toString();
- } catch (TransformerConfigurationException e) {
- final IOException r = new IOException("Error transforming page");
- r.initCause(e);
- throw r;
} catch (TransformerException e) {
- final IOException r = new IOException("Error transforming page");
+ IOException r = new IOException("Error transforming page");
r.initCause(e);
throw r;
}
}
/** Find an element by its "id" attribute; null if no element is found. */
- public static Element find(final Node parent, final String name) {
- final NodeList list = parent.getChildNodes();
+ public static Element find(Node parent, String name) {
+ NodeList list = parent.getChildNodes();
for (int i = 0; i < list.getLength(); i++) {
- final Node n = list.item(i);
+ Node n = list.item(i);
if (n instanceof Element) {
- final Element e = (Element) n;
+ Element e = (Element) n;
if (name.equals(e.getAttribute("id"))) {
return e;
}
}
- final Element r = find(n, name);
+ Element r = find(n, name);
if (r != null) {
return r;
}
@@ -116,9 +113,8 @@
}
/** Append an HTML <input type="hidden"> to the form. */
- public static void addHidden(final Element form, final String name,
- final String value) {
- final Element in = form.getOwnerDocument().createElement("input");
+ public static void addHidden(Element form, String name, String value) {
+ Element in = form.getOwnerDocument().createElement("input");
in.setAttribute("type", "hidden");
in.setAttribute("name", name);
in.setAttribute("value", value);
@@ -135,51 +131,38 @@
}
/** Clone a document so it can be safely modified on a per-request basis. */
- public static Document clone(final Document doc) throws IOException {
- final Document d;
+ public static Document clone(Document doc) throws IOException {
+ Document d;
try {
d = newBuilder().newDocument();
} catch (ParserConfigurationException e) {
throw new IOException("Cannot clone document");
}
- final Node n = d.importNode(doc.getDocumentElement(), true);
+ Node n = d.importNode(doc.getDocumentElement(), true);
d.appendChild(n);
return d;
}
/** Parse an XHTML file from our CLASSPATH and return the instance. */
- public static Document parseFile(final Class<?> context, final String name)
+ public static Document parseFile(Class<?> context, String name)
throws IOException {
- final InputStream in;
-
- in = context.getResourceAsStream(name);
- if (in == null) {
- return null;
- }
- try {
- try {
- try {
- final Document doc = newBuilder().parse(in);
- compact(doc);
- return doc;
- } catch (SAXException e) {
- throw new IOException("Error reading " + name, e);
- } catch (ParserConfigurationException e) {
- throw new IOException("Error reading " + name, e);
- }
- } finally {
- in.close();
+ try (InputStream in = context.getResourceAsStream(name)) {
+ if (in == null) {
+ return null;
}
- } catch (IOException e) {
+ Document doc = newBuilder().parse(in);
+ compact(doc);
+ return doc;
+ } catch (SAXException | ParserConfigurationException | IOException e) {
throw new IOException("Error reading " + name, e);
}
}
- private static void compact(final Document doc) {
+ private static void compact(Document doc) {
try {
- final String expr = "//text()[normalize-space(.) = '']";
- final XPathFactory xp = XPathFactory.newInstance();
- final XPathExpression e = xp.newXPath().compile(expr);
+ String expr = "//text()[normalize-space(.) = '']";
+ XPathFactory xp = XPathFactory.newInstance();
+ XPathExpression e = xp.newXPath().compile(expr);
NodeList empty = (NodeList) e.evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < empty.getLength(); i++) {
Node node = empty.item(i);
@@ -191,78 +174,50 @@
}
/** Read a Read a UTF-8 text file from our CLASSPATH and return it. */
- public static String readFile(final Class<?> context, final String name)
+ public static String readFile(Class<?> context, String name)
throws IOException {
- final InputStream in = context.getResourceAsStream(name);
- if (in == null) {
- return null;
- }
- try {
- return asString(in);
+ try (InputStream in = context.getResourceAsStream(name)) {
+ if (in == null) {
+ return null;
+ }
+ return new String(ByteStreams.toByteArray(in), ENC);
} catch (IOException e) {
throw new IOException("Error reading " + name, e);
}
}
/** Parse an XHTML file from the local drive and return the instance. */
- public static Document parseFile(final File path) throws IOException {
- try {
- final InputStream in = new FileInputStream(path);
- try {
- try {
- final Document doc = newBuilder().parse(in);
- compact(doc);
- return doc;
- } catch (SAXException e) {
- throw new IOException("Error reading " + path, e);
- } catch (ParserConfigurationException e) {
- throw new IOException("Error reading " + path, e);
- }
- } finally {
- in.close();
- }
- } catch (FileNotFoundException e) {
+ public static Document parseFile(Path path) throws IOException {
+ try (InputStream in = Files.newInputStream(path)) {
+ Document doc = newBuilder().parse(in);
+ compact(doc);
+ return doc;
+ } catch (NoSuchFileException e) {
return null;
- } catch (IOException e) {
+ } catch (SAXException | ParserConfigurationException | IOException e) {
throw new IOException("Error reading " + path, e);
}
}
/** Read a UTF-8 text file from the local drive. */
- public static String readFile(final File parentDir, final String name)
+ public static String readFile(Path parentDir, String name)
throws IOException {
if (parentDir == null) {
return null;
}
- final File path = new File(parentDir, name);
- try {
- return asString(new FileInputStream(path));
- } catch (FileNotFoundException e) {
+ Path path = parentDir.resolve(name);
+ try (InputStream in = Files.newInputStream(path)) {
+ return new String(ByteStreams.toByteArray(in), ENC);
+ } catch (NoSuchFileException e) {
return null;
} catch (IOException e) {
throw new IOException("Error reading " + path, e);
}
}
- private static String asString(final InputStream in)
- throws UnsupportedEncodingException, IOException {
- try {
- final StringBuilder w = new StringBuilder();
- final InputStreamReader r = new InputStreamReader(in, ENC);
- final char[] buf = new char[512];
- int n;
- while ((n = r.read(buf)) > 0) {
- w.append(buf, 0, n);
- }
- return w.toString();
- } finally {
- in.close();
- }
- }
-
private static DocumentBuilder newBuilder()
throws ParserConfigurationException {
- final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
factory.setExpandEntityReferences(false);
factory.setIgnoringComments(true);
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java
index 8c469a9..400b146 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java
@@ -186,7 +186,7 @@
return MoreObjects.firstNonNull(req.getCharacterEncoding(), "UTF-8");
}
- class Response extends HttpServletResponseWrapper {
+ static class Response extends HttpServletResponseWrapper {
private static final String WWW_AUTHENTICATE = "WWW-Authenticate";
Response(HttpServletResponse rsp) {
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectDigestFilter.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectDigestFilter.java
index 12de344..33b9fed 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectDigestFilter.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectDigestFilter.java
@@ -260,8 +260,12 @@
} else {
int space = auth.indexOf(' ', eq + 1);
int comma = auth.indexOf(',', eq + 1);
- if (space < 0) space = auth.length();
- if (comma < 0) comma = auth.length();
+ if (space < 0) {
+ space = auth.length();
+ }
+ if (comma < 0) {
+ comma = auth.length();
+ }
final int e = Math.min(space, comma);
value = auth.substring(eq + 1, e);
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java
index b8a8092..c1c3b2b 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java
@@ -54,8 +54,6 @@
@SuppressWarnings("serial")
@Singleton
class BecomeAnyAccountLoginServlet extends HttpServlet {
- private static final boolean IS_DEV = Boolean.getBoolean("Gerrit.GwtDevMode");
-
private final SchemaFactory<ReviewDb> schema;
private final DynamicItem<WebSession> webSession;
private final AccountManager accountManager;
@@ -104,7 +102,7 @@
throw new ServletException(e);
}
rsp.setContentType("text/html");
- rsp.setCharacterEncoding(HtmlDomUtil.ENC);
+ rsp.setCharacterEncoding(HtmlDomUtil.ENC.name());
rsp.setContentLength(raw.length);
final OutputStream out = rsp.getOutputStream();
try {
@@ -120,14 +118,6 @@
final StringBuilder rdr = new StringBuilder();
rdr.append(req.getContextPath());
rdr.append("/");
- if (IS_DEV && req.getParameter("gwt.codesvr") != null) {
- if (rdr.indexOf("?") < 0) {
- rdr.append("?");
- } else {
- rdr.append("&");
- }
- rdr.append("gwt.codesvr=").append(req.getParameter("gwt.codesvr"));
- }
if (res.isNew()) {
rdr.append('#' + PageLinks.REGISTER);
@@ -138,7 +128,7 @@
} else {
rsp.setContentType("text/html");
- rsp.setCharacterEncoding(HtmlDomUtil.ENC);
+ rsp.setCharacterEncoding(HtmlDomUtil.ENC.name());
final Writer out = rsp.getWriter();
out.write("<html>");
out.write("<body>");
@@ -155,12 +145,6 @@
if (doc == null) {
throw new FileNotFoundException("No " + pageName + " in webapp");
}
- if (!IS_DEV) {
- final Element devmode = HtmlDomUtil.find(doc, "gwtdevmode");
- if (devmode != null) {
- devmode.getParentNode().removeChild(devmode);
- }
- }
Element userlistElement = HtmlDomUtil.find(doc, "userlist");
ReviewDb db = schema.open();
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/container/HttpAuthFilter.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/container/HttpAuthFilter.java
index 19c8342..b5400b2 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/container/HttpAuthFilter.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/container/HttpAuthFilter.java
@@ -110,7 +110,7 @@
CacheHeaders.setNotCacheable(rsp);
rsp.setContentType("text/html");
- rsp.setCharacterEncoding(HtmlDomUtil.ENC);
+ rsp.setCharacterEncoding(HtmlDomUtil.ENC.name());
rsp.setContentLength(tosend.length);
final OutputStream out = rsp.getOutputStream();
try {
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/container/HttpsClientSslCertLoginServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/container/HttpsClientSslCertLoginServlet.java
index 8652ef0..4c7ce7b 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/container/HttpsClientSslCertLoginServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/container/HttpsClientSslCertLoginServlet.java
@@ -1,4 +1,4 @@
-//Copyright (C) 2011 The Android Open Source Project
+// Copyright (C) 2011 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitLogoServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitLogoServlet.java
index 41aa552..3396f2b 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitLogoServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitLogoServlet.java
@@ -14,16 +14,19 @@
package com.google.gerrit.httpd.gitweb;
+import static com.google.gerrit.common.FileUtil.lastModified;
+
+import com.google.common.io.ByteStreams;
import com.google.gerrit.httpd.GitWebConfig;
import com.google.gwtexpui.server.CacheHeaders;
import com.google.inject.Inject;
import com.google.inject.Singleton;
-import org.eclipse.jgit.util.IO;
-
-import java.io.File;
-import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletOutputStream;
@@ -38,16 +41,16 @@
private final byte[] raw;
@Inject
- GitLogoServlet(final GitWebConfig gitWebConfig) throws IOException {
+ GitLogoServlet(GitWebConfig gitWebConfig) throws IOException {
byte[] png;
- final File src = gitWebConfig.getGitLogoPNG();
+ Path src = gitWebConfig.getGitLogoPNG();
if (src != null) {
- try {
- png = IO.readFully(src);
- } catch (FileNotFoundException e) {
+ try (InputStream in = Files.newInputStream(src)) {
+ png = ByteStreams.toByteArray(in);
+ } catch (NoSuchFileException e) {
png = null;
}
- modified = src.lastModified();
+ modified = lastModified(src);
} else {
modified = -1;
png = null;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebCssServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebCssServlet.java
index 4a39b97..5625334 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebCssServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebCssServlet.java
@@ -14,6 +14,8 @@
package com.google.gerrit.httpd.gitweb;
+import static com.google.gerrit.common.FileUtil.lastModified;
+
import com.google.gerrit.httpd.GitWebConfig;
import com.google.gerrit.httpd.HtmlDomUtil;
import com.google.gerrit.server.config.SitePaths;
@@ -22,8 +24,8 @@
import com.google.inject.Inject;
import com.google.inject.Singleton;
-import java.io.File;
import java.io.IOException;
+import java.nio.file.Path;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletOutputStream;
@@ -55,14 +57,14 @@
private final byte[] raw_css;
private final byte[] gz_css;
- GitWebCssServlet(final File src)
+ GitWebCssServlet(final Path src)
throws IOException {
if (src != null) {
- final File dir = src.getParentFile();
- final String name = src.getName();
+ final Path dir = src.getParent();
+ final String name = src.getFileName().toString();
final String raw = HtmlDomUtil.readFile(dir, name);
if (raw != null) {
- modified = src.lastModified();
+ modified = lastModified(src);
raw_css = raw.getBytes(ENC);
gz_css = HtmlDomUtil.compress(raw_css);
} else {
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebJavaScriptServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebJavaScriptServlet.java
index d71732a..6926afd 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebJavaScriptServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebJavaScriptServlet.java
@@ -14,16 +14,19 @@
package com.google.gerrit.httpd.gitweb;
+import static com.google.gerrit.common.FileUtil.lastModified;
+
+import com.google.common.io.ByteStreams;
import com.google.gerrit.httpd.GitWebConfig;
import com.google.gwtexpui.server.CacheHeaders;
import com.google.inject.Inject;
import com.google.inject.Singleton;
-import org.eclipse.jgit.util.IO;
-
-import java.io.File;
-import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletOutputStream;
@@ -40,14 +43,14 @@
@Inject
GitWebJavaScriptServlet(final GitWebConfig gitWebConfig) throws IOException {
byte[] png;
- final File src = gitWebConfig.getGitwebJS();
+ Path src = gitWebConfig.getGitwebJS();
if (src != null) {
- try {
- png = IO.readFully(src);
- } catch (FileNotFoundException e) {
+ try (InputStream in = Files.newInputStream(src)) {
+ png = ByteStreams.toByteArray(in);
+ } catch (NoSuchFileException e) {
png = null;
}
- modified = src.lastModified();
+ modified = lastModified(src);
} else {
modified = -1;
png = null;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebServlet.java
index 573725c..cf43041 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebServlet.java
@@ -29,6 +29,8 @@
package com.google.gerrit.httpd.gitweb;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
import com.google.gerrit.common.PageLinks;
import com.google.gerrit.common.data.GerritConfig;
import com.google.gerrit.extensions.restapi.Url;
@@ -55,7 +57,6 @@
import java.io.BufferedReader;
import java.io.EOFException;
import java.io.File;
-import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -63,6 +64,8 @@
import java.io.PrintWriter;
import java.net.URI;
import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
@@ -84,7 +87,7 @@
private final Set<String> deniedActions;
private final int bufferSize = 8192;
- private final File gitwebCgi;
+ private final Path gitwebCgi;
private final URI gitwebUrl;
private final LocalDiskRepositoryManager repoManager;
private final ProjectControl.Factory projectControl;
@@ -145,28 +148,30 @@
private void makeSiteConfig(final SitePaths site,
final GerritConfig gerritConfig) throws IOException {
- if (!site.tmp_dir.exists()) {
- site.tmp_dir.mkdirs();
+ if (!Files.exists(site.tmp_dir)) {
+ Files.createDirectories(site.tmp_dir);
}
- File myconf = File.createTempFile("gitweb_config", ".perl", site.tmp_dir);
+ Path myconf = Files.createTempFile(site.tmp_dir, "gitweb_config", ".perl");
// To make our configuration file only readable or writable by us;
// this reduces the chances of someone tampering with the file.
//
- myconf.setWritable(false, false /* all */);
- myconf.setReadable(false, false /* all */);
- myconf.setExecutable(false, false /* all */);
+ // TODO(dborowitz): Is there a portable way to do this with NIO?
+ File myconfFile = myconf.toFile();
+ myconfFile.setWritable(false, false /* all */);
+ myconfFile.setReadable(false, false /* all */);
+ myconfFile.setExecutable(false, false /* all */);
- myconf.setWritable(true, true /* owner only */);
- myconf.setReadable(true, true /* owner only */);
+ myconfFile.setWritable(true, true /* owner only */);
+ myconfFile.setReadable(true, true /* owner only */);
- myconf.deleteOnExit();
+ myconfFile.deleteOnExit();
_env.set("GIT_DIR", ".");
- _env.set("GITWEB_CONFIG", myconf.getAbsolutePath());
+ _env.set("GITWEB_CONFIG", myconf.toAbsolutePath().toString());
- final PrintWriter p = new PrintWriter(new FileWriter(myconf));
- try {
+ try (PrintWriter p =
+ new PrintWriter(Files.newBufferedWriter(myconf, UTF_8))) {
p.print("# Autogenerated by Gerrit Code Review \n");
p.print("# DO NOT EDIT\n");
p.print("\n");
@@ -174,12 +179,12 @@
// We are mounted at the same level in the context as the main
// UI, so we can include the same header and footer scheme.
//
- final File hdr = site.site_header;
- if (hdr.isFile()) {
+ Path hdr = site.site_header;
+ if (Files.isRegularFile(hdr)) {
p.print("$site_header = " + quoteForPerl(hdr) + ";\n");
}
- final File ftr = site.site_footer;
- if (ftr.isFile()) {
+ Path ftr = site.site_footer;
+ if (Files.isRegularFile(ftr)) {
p.print("$site_footer = " + quoteForPerl(ftr) + ";\n");
}
@@ -192,8 +197,8 @@
p.print("$logo = 'gitweb-logo.png';\n");
p.print("$javascript = 'gitweb.js';\n");
p.print("@stylesheets = ('gitweb-default.css');\n");
- final File css = site.site_css;
- if (css.isFile()) {
+ Path css = site.site_css;
+ if (Files.isRegularFile(css)) {
p.print("push @stylesheets, 'gitweb-site.css';\n");
}
@@ -294,15 +299,15 @@
// If the administrator has created a site-specific gitweb_config,
// load that before we perform any final overrides.
//
- final File sitecfg = site.site_gitweb;
- if (sitecfg.isFile()) {
+ Path sitecfg = site.site_gitweb;
+ if (Files.isRegularFile(sitecfg)) {
p.print("$GITWEB_CONFIG = " + quoteForPerl(sitecfg) + ";\n");
p.print("if (-e $GITWEB_CONFIG) {\n");
p.print(" do " + quoteForPerl(sitecfg) + ";\n");
p.print("}\n");
}
- final File root = repoManager.getBasePath();
+ Path root = repoManager.getBasePath();
p.print("$projectroot = " + quoteForPerl(root) + ";\n");
// Permit exporting only the project we were started for.
@@ -326,18 +331,16 @@
//
p.print("$feature{'forks'}{'override'} = 0;\n");
p.print("$feature{'forks'}{'default'} = [0];\n");
- } finally {
- p.close();
}
- myconf.setReadOnly();
+ myconfFile.setReadOnly();
}
- private String quoteForPerl(File value) {
- return quoteForPerl(value.getAbsolutePath());
+ private static String quoteForPerl(Path value) {
+ return quoteForPerl(value.toAbsolutePath().toString());
}
- private String quoteForPerl(String value) {
+ private static String quoteForPerl(String value) {
if (value == null || value.isEmpty()) {
return "''";
}
@@ -455,9 +458,10 @@
private void exec(final HttpServletRequest req,
final HttpServletResponse rsp, final ProjectControl project) throws IOException {
final Process proc =
- Runtime.getRuntime().exec(new String[] {gitwebCgi.getAbsolutePath()},
+ Runtime.getRuntime().exec(
+ new String[] {gitwebCgi.toAbsolutePath().toString()},
makeEnv(req, project),
- gitwebCgi.getAbsoluteFile().getParentFile());
+ gitwebCgi.toAbsolutePath().getParent().toFile());
copyStderrToLog(proc.getErrorStream());
if (0 < req.getContentLength()) {
@@ -535,7 +539,7 @@
//
env.set("REQUEST_METHOD", req.getMethod());
env.set("SCRIPT_NAME", req.getContextPath() + req.getServletPath());
- env.set("SCRIPT_FILENAME", gitwebCgi.getAbsolutePath());
+ env.set("SCRIPT_FILENAME", gitwebCgi.toAbsolutePath().toString());
env.set("SERVER_NAME", req.getServerName());
env.set("SERVER_PORT", Integer.toString(req.getServerPort()));
env.set("SERVER_PROTOCOL", req.getProtocol());
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/ContextMapper.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/ContextMapper.java
index 47ef520..6afe52a 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/ContextMapper.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/ContextMapper.java
@@ -45,7 +45,7 @@
return base + name;
}
- private class WrappedRequest extends HttpServletRequestWrapper {
+ private static class WrappedRequest extends HttpServletRequestWrapper {
private final String contextPath;
private final String pathInfo;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java
index 64b754d..405a861 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java
@@ -14,6 +14,7 @@
package com.google.gerrit.httpd.plugins;
+import static com.google.gerrit.common.FileUtil.lastModified;
import static com.google.gerrit.server.plugins.PluginEntry.ATTR_CHARACTER_ENCODING;
import static com.google.gerrit.server.plugins.PluginEntry.ATTR_CONTENT_TYPE;
@@ -24,6 +25,7 @@
import com.google.common.cache.Cache;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
+import com.google.common.io.ByteStreams;
import com.google.common.net.HttpHeaders;
import com.google.gerrit.extensions.registration.RegistrationHandle;
import com.google.gerrit.httpd.resources.Resource;
@@ -55,14 +57,14 @@
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
@@ -303,7 +305,7 @@
}
if (!entry.isPresent() && file.endsWith("/index.html")) {
String pfx = file.substring(0, file.length() - "index.html".length());
- long pluginLastModified = holder.plugin.getSrcFile().lastModified();
+ long pluginLastModified = lastModified(holder.plugin.getSrcFile());
if (hasUpToDateCachedResource(rsc, pluginLastModified)) {
rsc.send(req, res);
} else {
@@ -611,12 +613,12 @@
private void sendJsPlugin(Plugin plugin, PluginResourceKey key,
HttpServletRequest req, HttpServletResponse res) throws IOException {
- File pluginFile = plugin.getSrcFile();
+ Path path = plugin.getSrcFile();
if (req.getRequestURI().endsWith(getJsPluginPath(plugin))
- && pluginFile.exists()) {
- res.setHeader("Content-Length", Long.toString(pluginFile.length()));
+ && Files.exists(path)) {
+ res.setHeader("Content-Length", Long.toString(Files.size(path)));
res.setContentType("application/javascript");
- writeToResponse(res, new FileInputStream(pluginFile));
+ writeToResponse(res, Files.newInputStream(path));
} else {
resourceCache.put(key, Resource.NOT_FOUND);
Resource.NOT_FOUND.send(req, res);
@@ -624,25 +626,15 @@
}
private static String getJsPluginPath(Plugin plugin) {
- return String.format("/plugins/%s/static/%s", plugin.getName(), plugin.getSrcFile()
- .getName());
+ return String.format("/plugins/%s/static/%s", plugin.getName(),
+ plugin.getSrcFile().getFileName());
}
- private void writeToResponse(HttpServletResponse res, InputStream in)
+ private void writeToResponse(HttpServletResponse res, InputStream inputStream)
throws IOException {
- try {
- OutputStream out = res.getOutputStream();
- try {
- byte[] tmp = new byte[1024];
- int n;
- while ((n = in.read(tmp)) > 0) {
- out.write(tmp, 0, n);
- }
- } finally {
- out.close();
- }
- } finally {
- in.close();
+ try (OutputStream out = res.getOutputStream();
+ InputStream in = inputStream) {
+ ByteStreams.copy(in, out);
}
}
@@ -674,9 +666,9 @@
}
private static String getPrefix(Plugin plugin, String attr, String def) {
- File srcFile = plugin.getSrcFile();
+ Path path = plugin.getSrcFile();
PluginContentScanner scanner = plugin.getContentScanner();
- if (srcFile == null || scanner == PluginContentScanner.EMPTY) {
+ if (path == null || scanner == PluginContentScanner.EMPTY) {
return def;
}
try {
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/HostPageServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/HostPageServlet.java
index 90c5ff4..e0d4b51 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/HostPageServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/HostPageServlet.java
@@ -14,6 +14,8 @@
package com.google.gerrit.httpd.raw;
+import static com.google.gerrit.common.FileUtil.lastModified;
+
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.hash.Hasher;
@@ -30,6 +32,7 @@
import com.google.gerrit.httpd.WebSession;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.config.ConfigUtil;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.notedb.NotesMigration;
@@ -47,14 +50,15 @@
import org.w3c.dom.Element;
import org.w3c.dom.Node;
-import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringWriter;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.TimeUnit;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
@@ -68,8 +72,8 @@
public class HostPageServlet extends HttpServlet {
private static final Logger log =
LoggerFactory.getLogger(HostPageServlet.class);
- private static final boolean IS_DEV = Boolean.getBoolean("Gerrit.GwtDevMode");
private static final String HPD_ID = "gerrit_hostpagedata";
+ private static final int DEFAULT_JS_LOAD_TIMEOUT = 5000;
private final Provider<CurrentUser> currentUser;
private final DynamicItem<WebSession> session;
@@ -84,6 +88,7 @@
private final boolean refreshHeaderFooter;
private final StaticServlet staticServlet;
private final boolean isNoteDbEnabled;
+ private final Integer pluginsLoadTimeout;
private volatile Page page;
@Inject
@@ -107,6 +112,7 @@
refreshHeaderFooter = cfg.getBoolean("site", "refreshHeaderFooter", true);
staticServlet = ss;
isNoteDbEnabled = migration.enabled();
+ pluginsLoadTimeout = getPluginsLoadTimeout(cfg);
final String pageName = "HostPage.html";
template = HtmlDomUtil.parseFile(getClass(), pageName);
@@ -122,54 +128,54 @@
}
String src = "gerrit_ui/gerrit_ui.nocache.js";
- if (!IS_DEV) {
- Element devmode = HtmlDomUtil.find(template, "gwtdevmode");
- if (devmode != null) {
- devmode.getParentNode().removeChild(devmode);
- }
-
- InputStream in = servletContext.getResourceAsStream("/" + src);
- if (in != null) {
- Hasher md = Hashing.md5().newHasher();
+ InputStream in = servletContext.getResourceAsStream("/" + src);
+ if (in != null) {
+ Hasher md = Hashing.md5().newHasher();
+ try {
try {
- try {
- final byte[] buf = new byte[1024];
- int n;
- while ((n = in.read(buf)) > 0) {
- md.putBytes(buf, 0, n);
- }
- } finally {
- in.close();
+ final byte[] buf = new byte[1024];
+ int n;
+ while ((n = in.read(buf)) > 0) {
+ md.putBytes(buf, 0, n);
}
- } catch (IOException e) {
- throw new IOException("Failed reading " + src, e);
+ } finally {
+ in.close();
}
- src += "?content=" + md.hash().toString();
- } else {
- log.debug("No " + src + " in webapp root; keeping noncache.js URL");
+ } catch (IOException e) {
+ throw new IOException("Failed reading " + src, e);
}
+ src += "?content=" + md.hash().toString();
+ } else {
+ log.debug("No " + src + " in webapp root; keeping noncache.js URL");
}
noCacheName = src;
page = new Page();
}
+ private static int getPluginsLoadTimeout(final Config cfg) {
+ long cfgValue =
+ ConfigUtil.getTimeUnit(cfg, "plugins", null, "jsLoadTimeout",
+ DEFAULT_JS_LOAD_TIMEOUT, TimeUnit.MILLISECONDS);
+ if (cfgValue < 0) {
+ return 0;
+ }
+ return (int) cfgValue;
+ }
+
private void json(final Object data, final StringWriter w) {
JsonServlet.defaultGsonBuilder().create().toJson(data, w);
}
private Page get() {
Page p = page;
- if (refreshHeaderFooter && p.isStale()) {
- final Page newPage;
- try {
- newPage = new Page();
- } catch (IOException e) {
- log.error("Cannot refresh site header/footer", e);
- return p;
+ try {
+ if (refreshHeaderFooter && p.isStale()) {
+ p = new Page();
+ page = p;
}
- p = newPage;
- page = p;
+ } catch (IOException e) {
+ log.error("Cannot refresh site header/footer", e);
}
return p;
}
@@ -216,7 +222,7 @@
CacheHeaders.setNotCacheable(rsp);
rsp.setContentType("text/html");
- rsp.setCharacterEncoding(HtmlDomUtil.ENC);
+ rsp.setCharacterEncoding(HtmlDomUtil.ENC.name());
rsp.setContentLength(tosend.length);
final OutputStream out = rsp.getOutputStream();
try {
@@ -288,16 +294,16 @@
}
private static class FileInfo {
- private final File path;
+ private final Path path;
private final long time;
- FileInfo(final File p) {
+ FileInfo(Path p) {
path = p;
- time = path.lastModified();
+ time = lastModified(path);
}
boolean isStale() {
- return time != path.lastModified();
+ return time != lastModified(path);
}
}
@@ -319,6 +325,7 @@
pageData.version = Version.getVersion();
pageData.config = config;
pageData.isNoteDbEnabled = isNoteDbEnabled;
+ pageData.pluginsLoadTimeout = pluginsLoadTimeout;
final StringWriter w = new StringWriter();
w.write("var " + HPD_ID + "=");
@@ -364,8 +371,8 @@
}
}
- private FileInfo injectCssFile(final Document hostDoc, final String id,
- final File src) throws IOException {
+ private FileInfo injectCssFile(Document hostDoc, String id, Path src)
+ throws IOException {
final FileInfo info = new FileInfo(src);
final Element banner = HtmlDomUtil.find(hostDoc, id);
if (banner == null) {
@@ -376,7 +383,8 @@
banner.removeChild(banner.getFirstChild());
}
- String css = HtmlDomUtil.readFile(src.getParentFile(), src.getName());
+ String css =
+ HtmlDomUtil.readFile(src.getParent(), src.getFileName().toString());
if (css == null) {
return info;
}
@@ -385,8 +393,8 @@
return info;
}
- private FileInfo injectXmlFile(final Document hostDoc, final String id,
- final File src) throws IOException {
+ private FileInfo injectXmlFile(Document hostDoc, String id, Path src)
+ throws IOException {
final FileInfo info = new FileInfo(src);
final Element banner = HtmlDomUtil.find(hostDoc, id);
if (banner == null) {
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/LegacyGerritServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/LegacyGerritServlet.java
index 9c267a8..00568f0 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/LegacyGerritServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/LegacyGerritServlet.java
@@ -68,7 +68,7 @@
CacheHeaders.setNotCacheable(rsp);
rsp.setContentType("text/html");
- rsp.setCharacterEncoding(HtmlDomUtil.ENC);
+ rsp.setCharacterEncoding(HtmlDomUtil.ENC.name());
rsp.setContentLength(tosend.length);
final OutputStream out = rsp.getOutputStream();
try {
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/RobotsServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/RobotsServlet.java
index 1d8e74d..2f5bc3a 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/RobotsServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/RobotsServlet.java
@@ -14,6 +14,9 @@
package com.google.gerrit.httpd.raw;
+import static java.nio.file.Files.exists;
+import static java.nio.file.Files.isReadable;
+
import com.google.common.io.ByteStreams;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.SitePaths;
@@ -24,11 +27,11 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
@@ -58,13 +61,13 @@
private static final Logger log =
LoggerFactory.getLogger(RobotsServlet.class);
- private final File robotsFile;
+ private final Path robotsFile;
@Inject
RobotsServlet(@GerritServerConfig final Config config, final SitePaths sitePaths) {
- File file = sitePaths.resolve(
+ Path file = sitePaths.resolve(
config.getString("httpd", null, "robotsFile"));
- if (file != null && (!file.exists() || !file.canRead())) {
+ if (file != null && (!exists(file) || !isReadable(file))) {
log.warn("Cannot read httpd.robotsFile, using default");
file = null;
}
@@ -75,23 +78,16 @@
protected void doGet(final HttpServletRequest req, final HttpServletResponse rsp)
throws IOException {
rsp.setContentType("text/plain");
- InputStream in = openRobotsFile();
- try {
- OutputStream out = rsp.getOutputStream();
- try {
- ByteStreams.copy(in, out);
- } finally {
- out.close();
- }
- } finally {
- in.close();
+ try (InputStream in = openRobotsFile();
+ OutputStream out = rsp.getOutputStream()) {
+ ByteStreams.copy(in, out);
}
}
private InputStream openRobotsFile() {
if (robotsFile != null) {
try {
- return new FileInputStream(robotsFile);
+ return Files.newInputStream(robotsFile);
} catch (IOException e) {
log.warn("Cannot read " + robotsFile + "; using default", e);
}
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/SshInfoServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/SshInfoServlet.java
index 83120e0..b85cdf0 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/SshInfoServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/SshInfoServlet.java
@@ -40,12 +40,14 @@
* <p>
* Versions of Git before 1.5.3 may require setting the username and port
* properties in the user's {@code ~/.ssh/config} file, and using a host
- * alias through a URL such as <code>gerrit-alias:/tools/gerrit.git:
+ * alias through a URL such as {@code gerrit-alias:/tools/gerrit.git}:
* <pre>
+ * {@code
* Host gerrit-alias
* User sop@google.com
* Hostname gerrit.com
* Port 8010
+ * }
* </pre>
*/
@SuppressWarnings("serial")
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/StaticServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/StaticServlet.java
index 52b7a5c9..e690334 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/StaticServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/StaticServlet.java
@@ -17,6 +17,7 @@
import static com.google.common.net.HttpHeaders.CONTENT_ENCODING;
import static com.google.common.net.HttpHeaders.ETAG;
import static com.google.common.net.HttpHeaders.IF_NONE_MATCH;
+import static com.google.gerrit.common.FileUtil.lastModified;
import static java.util.concurrent.TimeUnit.DAYS;
import static java.util.concurrent.TimeUnit.MINUTES;
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
@@ -30,7 +31,7 @@
import com.google.common.cache.Weigher;
import com.google.common.collect.Maps;
import com.google.common.hash.Hashing;
-import com.google.common.io.ByteStreams;
+import com.google.gerrit.common.FileUtil;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.httpd.HtmlDomUtil;
import com.google.gerrit.server.config.GerritServerConfig;
@@ -44,11 +45,11 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
import java.util.Map;
import java.util.concurrent.ExecutionException;
@@ -89,21 +90,19 @@
return type != null ? type : "application/octet-stream";
}
- private final File staticBase;
- private final String staticBasePath;
+ private final Path staticBase;
private final boolean refresh;
private final LoadingCache<String, Resource> cache;
@Inject
StaticServlet(@GerritServerConfig Config cfg, SitePaths site) {
- File f;
+ Path p;
try {
- f = site.static_dir.getCanonicalFile();
+ p = site.static_dir.toRealPath().normalize();
} catch (IOException e) {
- f = site.static_dir.getAbsoluteFile();
+ p = site.static_dir.toAbsolutePath().normalize();
}
- staticBase = f;
- staticBasePath = staticBase.getPath() + File.separator;
+ staticBase = p;
refresh = cfg.getBoolean("site", "refreshHeaderFooter", true);
cache = CacheBuilder.newBuilder()
.maximumWeight(1 << 20)
@@ -131,7 +130,8 @@
}
}
- private Resource getResource(HttpServletRequest req) throws ExecutionException {
+ private Resource getResource(HttpServletRequest req)
+ throws ExecutionException {
String name = CharMatcher.is('/').trimFrom(req.getPathInfo());
if (isUnreasonableName(name)) {
return Resource.NOT_FOUND;
@@ -150,13 +150,12 @@
}
private static boolean isUnreasonableName(String name) {
- if (name.length() < 1) return true;
- if (name.contains("\\")) return true; // no windows/dos style paths
- if (name.startsWith("../")) return true; // no "../etc/passwd"
- if (name.contains("/../")) return true; // no "foo/../etc/passwd"
- if (name.contains("/./")) return true; // "foo/./foo" is insane to ask
- if (name.contains("//")) return true; // windows UNC path can be "//..."
- return false; // is a reasonable name
+ return name.length() < 1
+ || name.contains("\\") // no windows/dos style paths
+ || name.startsWith("../") // no "../etc/passwd"
+ || name.contains("/../") // no "foo/../etc/passwd"
+ || name.contains("/./") // "foo/./foo" is insane to ask
+ || name.contains("//"); // windows UNC path can be "//..."
}
@Override
@@ -209,29 +208,22 @@
}
private Resource loadResource(String name) throws IOException {
- File p = new File(staticBase, name);
+ Path p = staticBase.resolve(name);
try {
- p = p.getCanonicalFile();
+ p = p.toRealPath().normalize();
} catch (IOException e) {
return Resource.NOT_FOUND;
}
- if (!p.getPath().startsWith(staticBasePath)) {
+ if (!p.startsWith(staticBase)) {
return Resource.NOT_FOUND;
}
- long ts = p.lastModified();
- FileInputStream in;
- try {
- in = new FileInputStream(p);
- } catch (FileNotFoundException e) {
- return Resource.NOT_FOUND;
- }
-
+ long ts = FileUtil.lastModified(p);
byte[] raw;
try {
- raw = ByteStreams.toByteArray(in);
- } finally {
- in.close();
+ raw = Files.readAllBytes(p);
+ } catch (NoSuchFileException e) {
+ return Resource.NOT_FOUND;
}
return new Resource(p, ts, contentType(name), raw);
}
@@ -239,13 +231,13 @@
static class Resource {
static final Resource NOT_FOUND = new Resource(null, -1, "", new byte[] {});
- final File src;
+ final Path src;
final long lastModified;
final String contentType;
final String etag;
final byte[] raw;
- Resource(File src, long lastModified, String contentType, byte[] raw) {
+ Resource(Path src, long lastModified, String contentType, byte[] raw) {
this.src = src;
this.lastModified = lastModified;
this.contentType = contentType;
@@ -254,7 +246,7 @@
}
boolean isStale() {
- return lastModified != src.lastModified();
+ return lastModified != lastModified(src);
}
}
}
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/RestApiServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
index 6f4cc08..0045649 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
@@ -46,7 +46,7 @@
import com.google.common.math.IntMath;
import com.google.common.net.HttpHeaders;
import com.google.gerrit.audit.AuditService;
-import com.google.gerrit.audit.HttpAuditEvent;
+import com.google.gerrit.audit.ExtendedHttpAuditEvent;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.extensions.registration.DynamicItem;
@@ -142,6 +142,8 @@
private static final String JSON_TYPE = "application/json";
private static final String FORM_TYPE = "application/x-www-form-urlencoded";
+ private static final int HEAP_EST_SIZE = 10 * 8 * 1024; // Presize 10 blocks.
+
/**
* Garbage prefix inserted before JSON output to prevent XSSI.
* <p>
@@ -202,6 +204,8 @@
Object result = null;
Multimap<String, String> params = LinkedHashMultimap.create();
Object inputRequestBody = null;
+ RestResource rsrc = TopLevelResource.INSTANCE;
+ ViewData viewData = null;
try {
checkUserSession(req);
@@ -211,8 +215,8 @@
CapabilityUtils.checkRequiresCapability(globals.currentUser,
null, rc.getClass());
- RestResource rsrc = TopLevelResource.INSTANCE;
- ViewData viewData = new ViewData(null, null);
+ viewData = new ViewData(null, null);
+
if (path.isEmpty()) {
if (isGetOrHead(req)) {
viewData = new ViewData(null, rc.list());
@@ -384,10 +388,10 @@
status = SC_INTERNAL_SERVER_ERROR;
handleException(e, req, res);
} finally {
- globals.auditService.dispatch(new HttpAuditEvent(globals.webSession.get()
- .getSessionId(), globals.currentUser.get(), req.getRequestURI(),
- auditStartTs, params, req.getMethod(), inputRequestBody, status,
- result));
+ globals.auditService.dispatch(new ExtendedHttpAuditEvent(globals.webSession.get()
+ .getSessionId(), globals.currentUser.get(), req,
+ auditStartTs, params, inputRequestBody, status,
+ result, rsrc, viewData == null ? null : viewData.view));
}
}
@@ -656,7 +660,7 @@
Multimap<String, String> config,
Object result)
throws IOException {
- TemporaryBuffer.Heap buf = heap(Integer.MAX_VALUE);
+ TemporaryBuffer.Heap buf = heap(HEAP_EST_SIZE, Integer.MAX_VALUE);
buf.write(JSON_MAGIC);
Writer w = new BufferedWriter(new OutputStreamWriter(buf, UTF_8));
Gson gson = newGson(config, req);
@@ -781,7 +785,7 @@
private static BinaryResult stackJsonString(HttpServletResponse res,
final BinaryResult src) throws IOException {
- TemporaryBuffer.Heap buf = heap(Integer.MAX_VALUE);
+ TemporaryBuffer.Heap buf = heap(HEAP_EST_SIZE, Integer.MAX_VALUE);
buf.write(JSON_MAGIC);
try(Writer w = new BufferedWriter(new OutputStreamWriter(buf, UTF_8));
JsonWriter json = new JsonWriter(w)) {
@@ -958,7 +962,8 @@
if (user instanceof AnonymousUser) {
throw new AuthException("Authentication required");
} else if (!globals.webSession.get().isAccessPathOk(AccessPath.REST_API)) {
- throw new AuthException("Invalid authentication method. In order to authenticate, prefix the REST endpoint URL with /a/ (e.g. http://example.com/a/projects/).");
+ throw new AuthException("Invalid authentication method. In order to authenticate, "
+ + "prefix the REST endpoint URL with /a/ (e.g. http://example.com/a/projects/).");
}
}
user.setAccessPath(AccessPath.REST_API);
@@ -1053,10 +1058,15 @@
return false;
}
+ private static int base64MaxSize(long n) {
+ return 4 * IntMath.divide((int) n, 3, CEILING);
+ }
+
private static BinaryResult base64(BinaryResult bin)
throws IOException {
- int max = 4 * IntMath.divide((int) bin.getContentLength(), 3, CEILING);
- TemporaryBuffer.Heap buf = heap(max);
+ int maxSize = base64MaxSize(bin.getContentLength());
+ int estSize = Math.min(base64MaxSize(HEAP_EST_SIZE), maxSize);
+ TemporaryBuffer.Heap buf = heap(estSize, maxSize);
OutputStream encoded = BaseEncoding.base64().encodingStream(
new OutputStreamWriter(buf, ISO_8859_1));
bin.writeTo(encoded);
@@ -1066,7 +1076,7 @@
private static BinaryResult compress(BinaryResult bin)
throws IOException {
- TemporaryBuffer.Heap buf = heap(20 << 20);
+ TemporaryBuffer.Heap buf = heap(HEAP_EST_SIZE, 20 << 20);
GZIPOutputStream gz = new GZIPOutputStream(buf);
bin.writeTo(gz);
gz.close();
@@ -1083,8 +1093,8 @@
}.setContentLength(buf.length());
}
- private static Heap heap(int max) {
- return new TemporaryBuffer.Heap(max);
+ private static Heap heap(int est, int max) {
+ return new TemporaryBuffer.Heap(est, max);
}
@SuppressWarnings("serial")
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountServiceImpl.java
index e1c9e3c..a12d8d5 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountServiceImpl.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountServiceImpl.java
@@ -201,8 +201,9 @@
public VoidResult run(final ReviewDb db) throws OrmException, Failure {
final Account.Id me = getAccountId();
for (final AccountProjectWatch.Key keyId : keys) {
- if (!me.equals(keyId.getParentKey()))
+ if (!me.equals(keyId.getParentKey())) {
throw new Failure(new NoSuchEntityException());
+ }
}
db.accountProjectWatches().deleteKeys(keys);
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ReviewProjectAccess.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ReviewProjectAccess.java
index 9437bbe..dff2cd0 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ReviewProjectAccess.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ReviewProjectAccess.java
@@ -14,13 +14,16 @@
package com.google.gerrit.httpd.rpc.project;
+import com.google.gerrit.common.FooterConstants;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.common.data.PermissionRule;
+import com.google.gerrit.common.errors.EmailException;
import com.google.gerrit.extensions.api.changes.AddReviewerInput;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
+import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
@@ -100,6 +103,7 @@
protected Change.Id updateProjectConfig(ProjectControl ctl,
ProjectConfig config, MetaDataUpdate md, boolean parentProjectUpdate)
throws IOException, OrmException {
+ md.setInsertChangeId(true);
Change.Id changeId = new Change.Id(db.nextChangeId());
RevCommit commit =
config.commitToNewRef(md, new PatchSet.Id(changeId,
@@ -109,7 +113,7 @@
}
Change change = new Change(
- new Change.Key("I" + commit.name()),
+ getChangeId(commit),
changeId,
user.getAccountId(),
new Branch.NameKey(
@@ -133,6 +137,14 @@
return changeId;
}
+ private static Change.Key getChangeId(RevCommit commit) {
+ List<String> idList = commit.getFooterLines(FooterConstants.CHANGE_ID);
+ Change.Key changeKey = !idList.isEmpty()
+ ? new Change.Key(idList.get(idList.size() - 1).trim())
+ : new Change.Key("I" + commit.name());
+ return changeKey;
+ }
+
private void addProjectOwnersAsReviewers(ChangeResource rsrc) {
final String projectOwners =
groupBackend.get(SystemGroupBackend.PROJECT_OWNERS).getName();
@@ -140,7 +152,7 @@
AddReviewerInput input = new AddReviewerInput();
input.reviewer = projectOwners;
reviewersProvider.get().apply(rsrc, input);
- } catch (Exception e) {
+ } catch (IOException | OrmException | RestApiException | EmailException e) {
// one of the owner groups is not visible to the user and this it why it
// can't be added as reviewer
}
@@ -156,7 +168,7 @@
AddReviewerInput input = new AddReviewerInput();
input.reviewer = r.getGroup().getUUID().get();
reviewersProvider.get().apply(rsrc, input);
- } catch (Exception e) {
+ } catch (IOException | OrmException | RestApiException | EmailException e) {
// ignore
}
}
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/template/SiteHeaderFooter.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/template/SiteHeaderFooter.java
index 321f032..9c067de 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/template/SiteHeaderFooter.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/template/SiteHeaderFooter.java
@@ -14,6 +14,8 @@
package com.google.gerrit.httpd.template;
+import static com.google.gerrit.common.FileUtil.lastModified;
+
import com.google.common.base.Strings;
import com.google.gerrit.httpd.HtmlDomUtil;
import com.google.gerrit.server.config.GerritServerConfig;
@@ -27,8 +29,8 @@
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import java.io.File;
import java.io.IOException;
+import java.nio.file.Path;
@Singleton
public class SiteHeaderFooter {
@@ -43,13 +45,13 @@
this.refreshHeaderFooter = cfg.getBoolean("site", "refreshHeaderFooter", true);
this.sitePaths = sitePaths;
- Template t = new Template(sitePaths);
try {
+ Template t = new Template(sitePaths);
t.load();
+ template = t;
} catch (IOException e) {
log.warn("Cannot load site header or footer", e);
}
- template = t;
}
public Document parse(Class<?> clazz, String name) throws IOException {
@@ -118,8 +120,8 @@
void load() throws IOException {
css = HtmlDomUtil.readFile(
- cssFile.path.getParentFile(),
- cssFile.path.getName());
+ cssFile.path.getParent(),
+ cssFile.path.getFileName().toString());
header = readXml(headerFile);
footer = readXml(footerFile);
}
@@ -135,16 +137,16 @@
}
private static class FileInfo {
- final File path;
+ final Path path;
final long time;
- FileInfo(File p) {
+ FileInfo(Path p) {
path = p;
- time = path.lastModified();
+ time = lastModified(p);
}
boolean isStale() {
- return time != path.lastModified();
+ return time != lastModified(path);
}
}
}
diff --git a/gerrit-httpd/src/main/resources/com/google/gerrit/httpd/auth/become/BecomeAnyAccount.html b/gerrit-httpd/src/main/resources/com/google/gerrit/httpd/auth/become/BecomeAnyAccount.html
index c660311..23d5856 100644
--- a/gerrit-httpd/src/main/resources/com/google/gerrit/httpd/auth/become/BecomeAnyAccount.html
+++ b/gerrit-httpd/src/main/resources/com/google/gerrit/httpd/auth/become/BecomeAnyAccount.html
@@ -1,34 +1,6 @@
<html>
<head>
<title>Gerrit Code Review</title>
- <script id="gwtdevmode">
- (function () {
- var pn = 'gwt.codesvr';
- var cn = 'gerrit_ui.' + pn;
-
- var p_start = window.location.search.indexOf(pn + '=');
- if (p_start != -1) {
- p_start = p_start + pn.length + 1;
- var p_end = window.location.search.indexOf(";", p_start);
- if (p_end == -1) p_end = window.location.search.length;
- var v = window.location.search.substring(p_start, p_end);
-
- var e = new Date();
- e.setDate(e.getDate() + 1);
- document.cookie = cn + "=" + v + ';expires=' + e.toGMTString();
-
- } else if (document.cookie.length != 0) {
- var c_start = document.cookie.indexOf(cn + '=');
- if (c_start != -1) {
- c_start = c_start + cn.length + 1;
- var c_end = document.cookie.indexOf(";", c_start);
- if (c_end == -1) c_end = document.cookie.length;
- var v = document.cookie.substring(c_start, c_end);
- window.location.replace('?' + pn + '=' + v + document.location.hash);
- }
- }
- })();
- </script>
<style id="gerrit_sitecss" type="text/css"></style>
</head>
<body>
diff --git a/gerrit-httpd/src/main/resources/com/google/gerrit/httpd/raw/HostPage.html b/gerrit-httpd/src/main/resources/com/google/gerrit/httpd/raw/HostPage.html
index 9f3fa1e..d2a333e 100644
--- a/gerrit-httpd/src/main/resources/com/google/gerrit/httpd/raw/HostPage.html
+++ b/gerrit-httpd/src/main/resources/com/google/gerrit/httpd/raw/HostPage.html
@@ -2,34 +2,6 @@
<head>
<title>Gerrit Code Review</title>
<meta name="gwt:property" content="locale=en_US" />
- <script id="gwtdevmode">
- (function () {
- var pn = 'gwt.codesvr';
- var cn = 'gerrit_ui.' + pn;
-
- var p_start = window.location.search.indexOf(pn + '=');
- if (p_start != -1) {
- p_start = p_start + pn.length + 1;
- var p_end = window.location.search.indexOf(";", p_start);
- if (p_end == -1) p_end = window.location.search.length;
- var v = window.location.search.substring(p_start, p_end);
-
- var e = new Date();
- e.setDate(e.getDate() + 1);
- document.cookie = cn + "=" + v + ';expires=' + e.toGMTString();
-
- } else if (document.cookie.length != 0) {
- var c_start = document.cookie.indexOf(cn + '=');
- if (c_start != -1) {
- c_start = c_start + cn.length + 1;
- var c_end = document.cookie.indexOf(";", c_start);
- if (c_end == -1) c_end = document.cookie.length;
- var v = document.cookie.substring(c_start, c_end);
- window.location.replace('?' + pn + '=' + v + document.location.hash);
- }
- }
- })();
- </script>
<script id="gerrit_hostpagedata"></script>
<style id="gerrit_sitecss" type="text/css"></style>
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
diff --git a/gerrit-launcher/src/main/java/com/google/gerrit/launcher/GerritLauncher.java b/gerrit-launcher/src/main/java/com/google/gerrit/launcher/GerritLauncher.java
index 4ee9676..e3e6d48 100644
--- a/gerrit-launcher/src/main/java/com/google/gerrit/launcher/GerritLauncher.java
+++ b/gerrit-launcher/src/main/java/com/google/gerrit/launcher/GerritLauncher.java
@@ -46,11 +46,11 @@
private static final String pkg = "com.google.gerrit.pgm";
public static final String NOT_ARCHIVED = "NOT_ARCHIVED";
- public static void main(final String argv[]) throws Exception {
+ public static void main(final String[] argv) throws Exception {
System.exit(mainImpl(argv));
}
- public static int mainImpl(final String argv[]) throws Exception {
+ public static int mainImpl(final String[] argv) throws Exception {
if (argv.length == 0) {
File me;
try {
@@ -88,11 +88,15 @@
// Run the application class
//
- final ClassLoader cl = libClassLoader();
+ final ClassLoader cl = libClassLoader(isProlog(programClassName(argv[0])));
Thread.currentThread().setContextClassLoader(cl);
return invokeProgram(cl, argv);
}
+ private static boolean isProlog(String cn) {
+ return "PrologShell".equals(cn) || "Rulec".equals(cn);
+ }
+
private static String getVersion(final File me) {
if (me == null) {
return "";
@@ -122,20 +126,7 @@
Class<?> clazz;
try {
try {
- String cn = name;
- if (cn.equals(cn.toLowerCase())) {
- StringBuilder buf = new StringBuilder();
- buf.append(Character.toUpperCase(cn.charAt(0)));
- for (int i = 1; i < cn.length(); i++) {
- if (cn.charAt(i) == '-' && i + 1 < cn.length()) {
- i++;
- buf.append(Character.toUpperCase(cn.charAt(i)));
- } else {
- buf.append(cn.charAt(i));
- }
- }
- cn = buf.toString();
- }
+ String cn = programClassName(name);
clazz = Class.forName(pkg + "." + cn, true, loader);
} catch (ClassNotFoundException cnfe) {
if (name.equals(name.toLowerCase())) {
@@ -181,7 +172,25 @@
}
}
- private static ClassLoader libClassLoader() throws IOException {
+ private static String programClassName(String cn) {
+ if (cn.equals(cn.toLowerCase())) {
+ StringBuilder buf = new StringBuilder();
+ buf.append(Character.toUpperCase(cn.charAt(0)));
+ for (int i = 1; i < cn.length(); i++) {
+ if (cn.charAt(i) == '-' && i + 1 < cn.length()) {
+ i++;
+ buf.append(Character.toUpperCase(cn.charAt(i)));
+ } else {
+ buf.append(cn.charAt(i));
+ }
+ }
+ return buf.toString();
+ }
+ return cn;
+ }
+
+ private static ClassLoader libClassLoader(boolean prologCompiler)
+ throws IOException {
final File path;
try {
path = getDistributionArchive();
@@ -201,10 +210,16 @@
final ZipEntry ze = e.nextElement();
if (ze.isDirectory()) {
continue;
- } else if (ze.getName().startsWith("WEB-INF/lib/")) {
+ }
+
+ String name = ze.getName();
+ if (name.startsWith("WEB-INF/lib/")) {
extractJar(zf, ze, jars);
- } else if (ze.getName().startsWith("WEB-INF/pgm-lib/")) {
- extractJar(zf, ze, jars);
+ } else if (name.startsWith("WEB-INF/pgm-lib/")) {
+ // Some Prolog tools are restricted.
+ if (prologCompiler || !name.startsWith("WEB-INF/pgm-lib/prolog-")) {
+ extractJar(zf, ze, jars);
+ }
}
}
} finally {
diff --git a/gerrit-lucene/BUCK b/gerrit-lucene/BUCK
index 2b45d2b..a146774 100644
--- a/gerrit-lucene/BUCK
+++ b/gerrit-lucene/BUCK
@@ -34,7 +34,9 @@
'//lib/jgit:jgit',
'//lib/log:api',
'//lib/lucene:analyzers-common',
+ '//lib/lucene:backward-codecs',
'//lib/lucene:core',
+ '//lib/lucene:misc',
],
visibility = ['PUBLIC'],
)
diff --git a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/AutoCommitWriter.java b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/AutoCommitWriter.java
index e0c13ae..27ded17 100644
--- a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/AutoCommitWriter.java
+++ b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/AutoCommitWriter.java
@@ -14,7 +14,6 @@
package com.google.gerrit.lucene;
-import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
@@ -43,13 +42,6 @@
}
@Override
- public void addDocument(Iterable<? extends IndexableField> doc,
- Analyzer analyzer) throws IOException {
- super.addDocument(doc, analyzer);
- autoFlush();
- }
-
- @Override
public void addDocuments(
Iterable<? extends Iterable<? extends IndexableField>> docs)
throws IOException {
@@ -58,14 +50,6 @@
}
@Override
- public void addDocuments(
- Iterable<? extends Iterable<? extends IndexableField>> docs,
- Analyzer analyzer) throws IOException {
- super.addDocuments(docs, analyzer);
- autoFlush();
- }
-
- @Override
public void updateDocuments(Term delTerm,
Iterable<? extends Iterable<? extends IndexableField>> docs)
throws IOException {
@@ -74,14 +58,6 @@
}
@Override
- public void updateDocuments(Term delTerm,
- Iterable<? extends Iterable<? extends IndexableField>> docs,
- Analyzer analyzer) throws IOException {
- super.updateDocuments(delTerm, docs, analyzer);
- autoFlush();
- }
-
- @Override
public void deleteDocuments(Term... term) throws IOException {
super.deleteDocuments(term);
autoFlush();
@@ -111,13 +87,6 @@
}
@Override
- public void updateDocument(Term term, Iterable<? extends IndexableField> doc,
- Analyzer analyzer) throws IOException {
- super.updateDocument(term, doc, analyzer);
- autoFlush();
- }
-
- @Override
public void deleteAll() throws IOException {
super.deleteAll();
autoFlush();
diff --git a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneChangeIndex.java b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneChangeIndex.java
index e8825c5..64da702 100644
--- a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneChangeIndex.java
+++ b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneChangeIndex.java
@@ -14,7 +14,8 @@
package com.google.gerrit.lucene;
-import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.Iterables.getOnlyElement;
import static com.google.gerrit.server.git.QueueProvider.QueueType.INTERACTIVE;
import static com.google.gerrit.server.index.IndexRewriteImpl.CLOSED_STATUSES;
import static com.google.gerrit.server.index.IndexRewriteImpl.OPEN_STATUSES;
@@ -30,7 +31,7 @@
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.config.ConfigUtil;
import com.google.gerrit.server.config.GerritServerConfig;
@@ -38,8 +39,8 @@
import com.google.gerrit.server.index.ChangeField;
import com.google.gerrit.server.index.ChangeField.ChangeProtoField;
import com.google.gerrit.server.index.ChangeField.PatchSetApprovalProtoField;
+import com.google.gerrit.server.index.ChangeField.PatchSetProtoField;
import com.google.gerrit.server.index.ChangeIndex;
-import com.google.gerrit.server.index.ChangeSchemas;
import com.google.gerrit.server.index.FieldDef;
import com.google.gerrit.server.index.FieldDef.FillArgs;
import com.google.gerrit.server.index.FieldType;
@@ -51,6 +52,7 @@
import com.google.gerrit.server.query.QueryParseException;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.query.change.ChangeDataSource;
+import com.google.gwtorm.protobuf.ProtobufCodec;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.ResultSet;
import com.google.inject.Provider;
@@ -64,9 +66,12 @@
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.IntField;
import org.apache.lucene.document.LongField;
+import org.apache.lucene.document.NumericDocValuesField;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
+import org.apache.lucene.index.DirectoryReader;
+import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
@@ -76,22 +81,26 @@
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
+import org.apache.lucene.search.SearcherFactory;
import org.apache.lucene.search.SearcherManager;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.TopDocs;
+import org.apache.lucene.search.TopFieldDocs;
import org.apache.lucene.store.RAMDirectory;
+import org.apache.lucene.uninverting.UninvertingReader;
import org.apache.lucene.util.BytesRef;
-import org.apache.lucene.util.Version;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.File;
import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.sql.Timestamp;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
@@ -119,54 +128,20 @@
private static final String CHANGE_FIELD = ChangeField.CHANGE.getName();
private static final String DELETED_FIELD = ChangeField.DELETED.getName();
private static final String ID_FIELD = ChangeField.LEGACY_ID.getName();
+ private static final String ID_SORT_FIELD =
+ sortFieldName(ChangeField.LEGACY_ID);
private static final String MERGEABLE_FIELD = ChangeField.MERGEABLE.getName();
+ private static final String PATCH_SET_FIELD = ChangeField.PATCH_SET.getName();
+ private static final String UPDATED_SORT_FIELD =
+ sortFieldName(ChangeField.UPDATED);
+
private static final ImmutableSet<String> FIELDS = ImmutableSet.of(
ADDED_FIELD, APPROVAL_FIELD, CHANGE_FIELD, DELETED_FIELD, ID_FIELD,
- MERGEABLE_FIELD);
+ MERGEABLE_FIELD, PATCH_SET_FIELD);
+
private static final Map<String, String> CUSTOM_CHAR_MAPPING = ImmutableMap.of(
"_", " ", ".", " ");
- private static final Map<Schema<ChangeData>, Version> LUCENE_VERSIONS;
- static {
- ImmutableMap.Builder<Schema<ChangeData>, Version> versions =
- ImmutableMap.builder();
- @SuppressWarnings("deprecation")
- Version lucene43 = Version.LUCENE_43;
- @SuppressWarnings("deprecation")
- Version lucene44 = Version.LUCENE_44;
- @SuppressWarnings("deprecation")
- Version lucene46 = Version.LUCENE_46;
- @SuppressWarnings("deprecation")
- Version lucene47 = Version.LUCENE_47;
- @SuppressWarnings("deprecation")
- Version lucene48 = Version.LUCENE_48;
- @SuppressWarnings("deprecation")
- Version lucene410 = Version.LUCENE_4_10_0;
- // We are using 4.10.2 but there is no difference in the index
- // format since 4.10.1, so we reuse the version here.
- @SuppressWarnings("deprecation")
- Version lucene4101 = Version.LUCENE_4_10_1;
- for (Map.Entry<Integer, Schema<ChangeData>> e
- : ChangeSchemas.ALL.entrySet()) {
- if (e.getKey() <= 3) {
- versions.put(e.getValue(), lucene43);
- } else if (e.getKey() <= 5) {
- versions.put(e.getValue(), lucene44);
- } else if (e.getKey() <= 8) {
- versions.put(e.getValue(), lucene46);
- } else if (e.getKey() <= 10) {
- versions.put(e.getValue(), lucene47);
- } else if (e.getKey() <= 11) {
- versions.put(e.getValue(), lucene48);
- } else if (e.getKey() <= 13) {
- versions.put(e.getValue(), lucene410);
- } else {
- versions.put(e.getValue(), lucene4101);
- }
- }
- LUCENE_VERSIONS = versions.build();
- }
-
public static void setReady(SitePaths sitePaths, int version, boolean ready)
throws IOException {
try {
@@ -179,6 +154,10 @@
}
}
+ private static String sortFieldName(FieldDef<?, ?> f) {
+ return f.getName() + "_SORT";
+ }
+
static interface Factory {
LuceneChangeIndex create(Schema<ChangeData> schema, String base);
}
@@ -187,12 +166,13 @@
private final IndexWriterConfig luceneConfig;
private long commitWithinMs;
- private GerritIndexWriterConfig(Version version, Config cfg, String name) {
+ private GerritIndexWriterConfig(Config cfg, String name) {
CustomMappingAnalyzer analyzer =
new CustomMappingAnalyzer(new StandardAnalyzer(
CharArraySet.EMPTY_SET), CUSTOM_CHAR_MAPPING);
- luceneConfig = new IndexWriterConfig(version, analyzer);
- luceneConfig.setOpenMode(OpenMode.CREATE_OR_APPEND);
+ luceneConfig = new IndexWriterConfig(analyzer)
+ .setOpenMode(OpenMode.CREATE_OR_APPEND)
+ .setCommitOnClose(true);
double m = 1 << 20;
luceneConfig.setRAMBufferSizeMB(cfg.getLong(
"index", name, "ramBufferSize",
@@ -223,12 +203,22 @@
private final ListeningExecutorService executor;
private final Provider<ReviewDb> db;
private final ChangeData.Factory changeDataFactory;
- private final File dir;
private final Schema<ChangeData> schema;
private final QueryBuilder queryBuilder;
private final SubIndex openIndex;
private final SubIndex closedIndex;
+ /**
+ * Whether to use DocValues for range/sorted numeric fields.
+ * <p>
+ * Lucene 5 removed support for sorting based on normal numeric fields, so we
+ * use the newer API for more strongly typed numeric fields in newer schema
+ * versions. These fields also are not stored, so we need to store auxiliary
+ * stored-only field for them as well.
+ */
+ // TODO(dborowitz): Delete when we delete support for pre-Lucene-5.0 schemas.
+ private final boolean useDocValuesForSorting;
+
@AssistedInject
LuceneChangeIndex(
@GerritServerConfig Config cfg,
@@ -245,15 +235,8 @@
this.db = db;
this.changeDataFactory = changeDataFactory;
this.schema = schema;
+ this.useDocValuesForSorting = schema.getVersion() >= 15;
- if (base == null) {
- dir = LuceneVersionManager.getDir(sitePaths, schema);
- } else {
- dir = new File(base);
- }
- Version luceneVersion = checkNotNull(
- LUCENE_VERSIONS.get(schema),
- "unknown Lucene version for index schema: %s", schema);
CustomMappingAnalyzer analyzer =
new CustomMappingAnalyzer(new StandardAnalyzer(CharArraySet.EMPTY_SET),
CUSTOM_CHAR_MAPPING);
@@ -263,19 +246,44 @@
BooleanQuery.getMaxClauseCount()));
GerritIndexWriterConfig openConfig =
- new GerritIndexWriterConfig(luceneVersion, cfg, "changes_open");
+ new GerritIndexWriterConfig(cfg, "changes_open");
GerritIndexWriterConfig closedConfig =
- new GerritIndexWriterConfig(luceneVersion, cfg, "changes_closed");
+ new GerritIndexWriterConfig(cfg, "changes_closed");
+ SearcherFactory searcherFactory = newSearcherFactory();
if (cfg.getBoolean("index", "lucene", "testInmemory", false)) {
- openIndex = new SubIndex(new RAMDirectory(), "ramOpen", openConfig);
- closedIndex = new SubIndex(new RAMDirectory(), "ramClosed", closedConfig);
+ openIndex = new SubIndex(new RAMDirectory(), "ramOpen", openConfig,
+ searcherFactory);
+ closedIndex = new SubIndex(new RAMDirectory(), "ramClosed", closedConfig,
+ searcherFactory);
} else {
- openIndex = new SubIndex(new File(dir, CHANGES_OPEN), openConfig);
- closedIndex = new SubIndex(new File(dir, CHANGES_CLOSED), closedConfig);
+ Path dir = base != null ? Paths.get(base)
+ : LuceneVersionManager.getDir(sitePaths, schema);
+ openIndex = new SubIndex(dir.resolve(CHANGES_OPEN), openConfig,
+ searcherFactory);
+ closedIndex = new SubIndex(dir.resolve(CHANGES_CLOSED), closedConfig,
+ searcherFactory);
}
}
+ private SearcherFactory newSearcherFactory() {
+ if (useDocValuesForSorting) {
+ return new SearcherFactory();
+ }
+ final Map<String, UninvertingReader.Type> mapping = ImmutableMap.of(
+ ChangeField.LEGACY_ID.getName(), UninvertingReader.Type.INTEGER,
+ ChangeField.UPDATED.getName(), UninvertingReader.Type.LONG);
+ return new SearcherFactory() {
+ @Override
+ public IndexSearcher newSearcher(IndexReader reader) throws IOException {
+ checkState(reader instanceof DirectoryReader,
+ "expected DirectoryReader, found %s", reader.getClass().getName());
+ return new IndexSearcher(
+ UninvertingReader.wrap((DirectoryReader) reader, mapping));
+ }
+ };
+ }
+
@Override
public void close() {
List<ListenableFuture<?>> closeFutures = Lists.newArrayListWithCapacity(2);
@@ -358,12 +366,18 @@
setReady(sitePaths, schema.getVersion(), ready);
}
- private static Sort getSort() {
- return new Sort(
- new SortField(
- ChangeField.UPDATED.getName(), SortField.Type.LONG, true),
- new SortField(
- ChangeField.LEGACY_ID.getName(), SortField.Type.INT, true));
+ private Sort getSort() {
+ if (useDocValuesForSorting) {
+ return new Sort(
+ new SortField(UPDATED_SORT_FIELD, SortField.Type.LONG, true),
+ new SortField(ID_SORT_FIELD, SortField.Type.LONG, true));
+ } else {
+ return new Sort(
+ new SortField(
+ ChangeField.UPDATED.getName(), SortField.Type.LONG, true),
+ new SortField(
+ ChangeField.LEGACY_ID.getName(), SortField.Type.INT, true));
+ }
}
private class QuerySource implements ChangeDataSource {
@@ -402,7 +416,7 @@
IndexSearcher[] searchers = new IndexSearcher[indexes.size()];
try {
int realLimit = start + limit;
- TopDocs[] hits = new TopDocs[indexes.size()];
+ TopFieldDocs[] hits = new TopFieldDocs[indexes.size()];
for (int i = 0; i < indexes.size(); i++) {
searchers[i] = indexes.get(i).acquire();
hits[i] = searchers[i].search(query, realLimit, sort);
@@ -462,18 +476,19 @@
cb.bytes, cb.offset, cb.length);
ChangeData cd = changeDataFactory.create(db.get(), change);
- // Approvals.
- BytesRef[] approvalsBytes = doc.getBinaryValues(APPROVAL_FIELD);
- if (approvalsBytes != null) {
- List<PatchSetApproval> approvals =
- Lists.newArrayListWithCapacity(approvalsBytes.length);
- for (BytesRef ab : approvalsBytes) {
- approvals.add(PatchSetApprovalProtoField.CODEC.decode(
- ab.bytes, ab.offset, ab.length));
- }
- cd.setCurrentApprovals(approvals);
+ // Patch sets.
+ List<PatchSet> patchSets =
+ decodeProtos(doc, PATCH_SET_FIELD, PatchSetProtoField.CODEC);
+ if (!patchSets.isEmpty()) {
+ // Will be an empty list for schemas prior to when this field was stored;
+ // this cannot be valid since a change needs at least one patch set.
+ cd.setPatchSets(patchSets);
}
+ // Approvals.
+ cd.setCurrentApprovals(
+ decodeProtos(doc, APPROVAL_FIELD, PatchSetApprovalProtoField.CODEC));
+
// Changed lines.
IndexableField added = doc.getField(ADDED_FIELD);
IndexableField deleted = doc.getField(DELETED_FIELD);
@@ -494,6 +509,19 @@
return cd;
}
+ private static <T> List<T> decodeProtos(Document doc, String fieldName,
+ ProtobufCodec<T> codec) {
+ BytesRef[] bytesRefs = doc.getBinaryValues(fieldName);
+ if (bytesRefs.length == 0) {
+ return Collections.emptyList();
+ }
+ List<T> result = new ArrayList<>(bytesRefs.length);
+ for (BytesRef r : bytesRefs) {
+ result.add(codec.decode(r.bytes, r.offset, r.length));
+ }
+ return result;
+ }
+
private Document toDocument(ChangeData cd) {
Document result = new Document();
for (Values<ChangeData> vs : schema.buildFields(cd, fillArgs)) {
@@ -509,6 +537,16 @@
FieldType<?> type = values.getField().getType();
Store store = store(values.getField());
+ if (useDocValuesForSorting) {
+ if (values.getField() == ChangeField.LEGACY_ID) {
+ int v = (Integer) getOnlyElement(values.getValues());
+ doc.add(new NumericDocValuesField(ID_SORT_FIELD, v));
+ } else if (values.getField() == ChangeField.UPDATED) {
+ long t = ((Timestamp) getOnlyElement(values.getValues())).getTime();
+ doc.add(new NumericDocValuesField(UPDATED_SORT_FIELD, t));
+ }
+ }
+
if (type == FieldType.INTEGER || type == FieldType.INTEGER_RANGE) {
for (Object value : values.getValues()) {
doc.add(new IntField(name, (Integer) value, store));
@@ -535,7 +573,7 @@
doc.add(new StoredField(name, (byte[]) value));
}
} else {
- throw QueryBuilder.badFieldType(type);
+ throw FieldType.badFieldType(type);
}
}
diff --git a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneIndexModule.java b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneIndexModule.java
index 672a7c9..35d6636 100644
--- a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneIndexModule.java
+++ b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneIndexModule.java
@@ -16,6 +16,7 @@
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.lifecycle.LifecycleModule;
+import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.index.ChangeSchemas;
import com.google.gerrit.server.index.IndexCollection;
import com.google.gerrit.server.index.IndexConfig;
@@ -26,6 +27,8 @@
import com.google.inject.Provides;
import com.google.inject.Singleton;
+import org.eclipse.jgit.lib.Config;
+
public class LuceneIndexModule extends LifecycleModule {
private final Integer singleVersion;
private final int threads;
@@ -44,7 +47,6 @@
@Override
protected void configure() {
- bind(IndexConfig.class).toInstance(IndexConfig.createDefault());
factory(LuceneChangeIndex.Factory.class);
install(new IndexModule(threads));
if (singleVersion == null && base == null) {
@@ -54,7 +56,13 @@
}
}
- private class MultiVersionModule extends LifecycleModule {
+ @Provides
+ @Singleton
+ IndexConfig getIndexConfig(@GerritServerConfig Config cfg) {
+ return IndexConfig.fromConfig(cfg);
+ }
+
+ private static class MultiVersionModule extends LifecycleModule {
@Override
public void configure() {
factory(OnlineReindexer.Factory.class);
diff --git a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneVersionManager.java b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneVersionManager.java
index c3570a1..109525a 100644
--- a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneVersionManager.java
+++ b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneVersionManager.java
@@ -20,6 +20,7 @@
import com.google.common.collect.Maps;
import com.google.common.primitives.Ints;
import com.google.gerrit.extensions.events.LifecycleListener;
+import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.index.ChangeSchemas;
import com.google.gerrit.server.index.IndexCollection;
@@ -36,8 +37,10 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.File;
import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.Collection;
import java.util.List;
import java.util.TreeMap;
@@ -65,15 +68,16 @@
}
}
- static File getDir(SitePaths sitePaths, Schema<ChangeData> schema) {
- return new File(sitePaths.index_dir, String.format("%s%04d",
+ static Path getDir(SitePaths sitePaths, Schema<ChangeData> schema) {
+ return sitePaths.index_dir.resolve(String.format("%s%04d",
CHANGES_PREFIX, schema.getVersion()));
}
static FileBasedConfig loadGerritIndexConfig(SitePaths sitePaths)
throws ConfigInvalidException, IOException {
FileBasedConfig cfg = new FileBasedConfig(
- new File(sitePaths.index_dir, "gerrit_index.config"), FS.detect());
+ sitePaths.index_dir.resolve("gerrit_index.config").toFile(),
+ FS.detect());
cfg.load();
return cfg;
}
@@ -90,9 +94,11 @@
private final LuceneChangeIndex.Factory indexFactory;
private final IndexCollection indexes;
private final OnlineReindexer.Factory reindexerFactory;
+ private final boolean onlineUpgrade;
@Inject
LuceneVersionManager(
+ @GerritServerConfig Config cfg,
SitePaths sitePaths,
LuceneChangeIndex.Factory indexFactory,
IndexCollection indexes,
@@ -101,6 +107,7 @@
this.indexFactory = indexFactory;
this.indexes = indexes;
this.reindexerFactory = reindexerFactory;
+ this.onlineUpgrade = cfg.getBoolean("index", null, "onlineUpgrade", true);
}
@Override
@@ -114,10 +121,10 @@
throw fail(e);
}
- if (!sitePaths.index_dir.exists()) {
+ if (!Files.exists(sitePaths.index_dir)) {
throw new ProvisionException("No index versions ready; run Reindex");
- } else if (!sitePaths.index_dir.isDirectory()) {
- log.warn("Not a directory: %s", sitePaths.index_dir.getAbsolutePath());
+ } else if (!Files.exists(sitePaths.index_dir)) {
+ log.warn("Not a directory: %s", sitePaths.index_dir.toAbsolutePath());
throw new ProvisionException("No index versions ready; run Reindex");
}
@@ -130,7 +137,7 @@
if (v.schema == null) {
continue;
}
- if (write.isEmpty()) {
+ if (write.isEmpty() && onlineUpgrade) {
write.add(v);
}
if (v.ready) {
@@ -159,7 +166,7 @@
}
int latest = write.get(0).version;
- if (latest != search.version) {
+ if (onlineUpgrade && latest != search.version) {
reindexerFactory.create(latest).start();
}
}
@@ -167,29 +174,35 @@
private TreeMap<Integer, Version> scanVersions(Config cfg) {
TreeMap<Integer, Version> versions = Maps.newTreeMap();
for (Schema<ChangeData> schema : ChangeSchemas.ALL.values()) {
- File f = getDir(sitePaths, schema);
- boolean exists = f.exists() && f.isDirectory();
- if (f.exists() && !f.isDirectory()) {
- log.warn("Not a directory: %s", f.getAbsolutePath());
+ Path p = getDir(sitePaths, schema);
+ boolean isDir = Files.isDirectory(p);
+ if (Files.exists(p) && !isDir) {
+ log.warn("Not a directory: %s", p.toAbsolutePath());
}
int v = schema.getVersion();
- versions.put(v, new Version(schema, v, exists, getReady(cfg, v)));
+ versions.put(v, new Version(schema, v, isDir, getReady(cfg, v)));
}
- for (File f : sitePaths.index_dir.listFiles()) {
- if (!f.getName().startsWith(CHANGES_PREFIX)) {
- continue;
+ try (DirectoryStream<Path> paths =
+ Files.newDirectoryStream(sitePaths.index_dir)) {
+ for (Path p : paths) {
+ String n = p.getFileName().toString();
+ if (!n.startsWith(CHANGES_PREFIX)) {
+ continue;
+ }
+ String versionStr = n.substring(CHANGES_PREFIX.length());
+ Integer v = Ints.tryParse(versionStr);
+ if (v == null || versionStr.length() != 4) {
+ log.warn("Unrecognized version in index directory: {}",
+ p.toAbsolutePath());
+ continue;
+ }
+ if (!versions.containsKey(v)) {
+ versions.put(v, new Version(null, v, true, getReady(cfg, v)));
+ }
}
- String versionStr = f.getName().substring(CHANGES_PREFIX.length());
- Integer v = Ints.tryParse(versionStr);
- if (v == null || versionStr.length() != 4) {
- log.warn("Unrecognized version in index directory: {}",
- f.getAbsolutePath());
- continue;
- }
- if (!versions.containsKey(v)) {
- versions.put(v, new Version(null, v, true, getReady(cfg, v)));
- }
+ } catch (IOException e) {
+ log.error("Error scanning index directory: " + sitePaths.index_dir, e);
}
return versions;
}
diff --git a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/QueryBuilder.java b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/QueryBuilder.java
index 28af057..218bb71 100644
--- a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/QueryBuilder.java
+++ b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/QueryBuilder.java
@@ -148,7 +148,7 @@
} else if (p.getType() == FieldType.FULL_TEXT) {
return fullTextQuery(p);
} else {
- throw badFieldType(p.getType());
+ throw FieldType.badFieldType(p.getType());
}
}
@@ -164,8 +164,8 @@
try {
// Can't use IntPredicate because it and IndexPredicate are different
// subclasses of OperatorPredicate.
- value = Integer.valueOf(p.getValue());
- } catch (IllegalArgumentException e) {
+ value = Integer.parseInt(p.getValue());
+ } catch (NumberFormatException e) {
throw new QueryParseException("not an integer: " + p.getValue());
}
return new TermQuery(intTerm(p.getField().getName(), value));
@@ -249,8 +249,4 @@
public int toIndexTimeInMinutes(Date ts) {
return (int) (ts.getTime() / 60000);
}
-
- public static IllegalArgumentException badFieldType(FieldType<?> t) {
- return new IllegalArgumentException("unknown index field type " + t);
- }
}
diff --git a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/SubIndex.java b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/SubIndex.java
index e024f76..5778008 100644
--- a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/SubIndex.java
+++ b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/SubIndex.java
@@ -28,17 +28,17 @@
import org.apache.lucene.index.TrackingIndexWriter;
import org.apache.lucene.search.ControlledRealTimeReopenThread;
import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.ReferenceManager;
import org.apache.lucene.search.ReferenceManager.RefreshListener;
import org.apache.lucene.search.SearcherFactory;
-import org.apache.lucene.search.SearcherManager;
import org.apache.lucene.store.AlreadyClosedException;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.File;
import java.io.IOException;
+import java.nio.file.Path;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
@@ -52,16 +52,19 @@
private final Directory dir;
private final TrackingIndexWriter writer;
- private final SearcherManager searcherManager;
+ private final ReferenceManager<IndexSearcher> searcherManager;
private final ControlledRealTimeReopenThread<IndexSearcher> reopenThread;
private final Set<NrtFuture> notDoneNrtFutures;
- SubIndex(File file, GerritIndexWriterConfig writerConfig) throws IOException {
- this(FSDirectory.open(file), file.getName(), writerConfig);
+ SubIndex(Path path, GerritIndexWriterConfig writerConfig,
+ SearcherFactory searcherFactory) throws IOException {
+ this(FSDirectory.open(path), path.getFileName().toString(), writerConfig,
+ searcherFactory);
}
SubIndex(Directory dir, final String dirName,
- GerritIndexWriterConfig writerConfig) throws IOException {
+ GerritIndexWriterConfig writerConfig,
+ SearcherFactory searcherFactory) throws IOException {
this.dir = dir;
IndexWriter delegateWriter;
long commitPeriod = writerConfig.getCommitWithinMs();
@@ -103,8 +106,8 @@
}, commitPeriod, commitPeriod, MILLISECONDS);
}
writer = new TrackingIndexWriter(delegateWriter);
- searcherManager = new SearcherManager(
- writer.getIndexWriter(), true, new SearcherFactory());
+ searcherManager = new WrappableSearcherManager(
+ writer.getIndexWriter(), true, searcherFactory);
notDoneNrtFutures = Sets.newConcurrentHashSet();
@@ -124,6 +127,8 @@
// searching generation being up to date when calling
// reopenThread.waitForGeneration(gen, 0), therefore the reopen thread's
// internal listener needs to be called first.
+ // TODO(dborowitz): This may have been fixed by
+ // http://issues.apache.org/jira/browse/LUCENE-5461
searcherManager.addListener(new RefreshListener() {
@Override
public void beforeRefresh() throws IOException {
@@ -157,12 +162,9 @@
}
try {
- writer.getIndexWriter().commit();
- try {
- writer.getIndexWriter().close();
- } catch (AlreadyClosedException e) {
- // Ignore.
- }
+ writer.getIndexWriter().close();
+ } catch (AlreadyClosedException e) {
+ // Ignore.
} catch (IOException e) {
log.warn("error closing Lucene writer", e);
}
diff --git a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/WrappableSearcherManager.java b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/WrappableSearcherManager.java
new file mode 100644
index 0000000..981f909
--- /dev/null
+++ b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/WrappableSearcherManager.java
@@ -0,0 +1,220 @@
+package com.google.gerrit.lucene;
+
+/*
+ * 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.
+ */
+
+import org.apache.lucene.index.DirectoryReader;
+import org.apache.lucene.index.FilterDirectoryReader;
+import org.apache.lucene.index.FilterLeafReader;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.ReferenceManager;
+import org.apache.lucene.search.SearcherFactory;
+import org.apache.lucene.store.Directory;
+
+import java.io.IOException;
+
+/**
+ * Utility class to safely share {@link IndexSearcher} instances across multiple
+ * threads, while periodically reopening. This class ensures each searcher is
+ * closed only once all threads have finished using it.
+ *
+ * <p>
+ * Use {@link #acquire} to obtain the current searcher, and {@link #release} to
+ * release it, like this:
+ *
+ * <pre class="prettyprint">
+ * IndexSearcher s = manager.acquire();
+ * try {
+ * // Do searching, doc retrieval, etc. with s
+ * } finally {
+ * manager.release(s);
+ * }
+ * // Do not use s after this!
+ * s = null;
+ * </pre>
+ *
+ * <p>
+ * In addition you should periodically call {@link #maybeRefresh}. While it's
+ * possible to call this just before running each query, this is discouraged
+ * since it penalizes the unlucky queries that need to refresh. It's better to use
+ * a separate background thread, that periodically calls {@link #maybeRefresh}. Finally,
+ * be sure to call {@link #close} once you are done.
+ *
+ * @see SearcherFactory
+ *
+ * @lucene.experimental
+ */
+// This file was copied from:
+// https://github.com/apache/lucene-solr/blob/lucene_solr_5_0/lucene/core/src/java/org/apache/lucene/search/SearcherManager.java
+// The only change (other than class name and import fixes)
+// is to skip the check in getSearcher that searcherFactory.newSearcher wraps
+// the provided searcher exactly.
+final class WrappableSearcherManager extends ReferenceManager<IndexSearcher> {
+
+ private final SearcherFactory searcherFactory;
+
+ /**
+ * Creates and returns a new SearcherManager from the given
+ * {@link IndexWriter}.
+ *
+ * @param writer
+ * the IndexWriter to open the IndexReader from.
+ * @param applyAllDeletes
+ * If <code>true</code>, all buffered deletes will be applied (made
+ * visible) in the {@link IndexSearcher} / {@link DirectoryReader}.
+ * If <code>false</code>, the deletes may or may not be applied, but
+ * remain buffered (in IndexWriter) so that they will be applied in
+ * the future. Applying deletes can be costly, so if your app can
+ * tolerate deleted documents being returned you might gain some
+ * performance by passing <code>false</code>. See
+ * {@link DirectoryReader#openIfChanged(DirectoryReader, IndexWriter, boolean)}.
+ * @param searcherFactory
+ * An optional {@link SearcherFactory}. Pass <code>null</code> if you
+ * don't require the searcher to be warmed before going live or other
+ * custom behavior.
+ *
+ * @throws IOException if there is a low-level I/O error
+ */
+ public WrappableSearcherManager(IndexWriter writer, boolean applyAllDeletes, SearcherFactory searcherFactory) throws IOException {
+ if (searcherFactory == null) {
+ searcherFactory = new SearcherFactory();
+ }
+ this.searcherFactory = searcherFactory;
+ current = getSearcher(searcherFactory, DirectoryReader.open(writer, applyAllDeletes));
+ }
+
+ /**
+ * Creates and returns a new SearcherManager from the given {@link Directory}.
+ * @param dir the directory to open the DirectoryReader on.
+ * @param searcherFactory An optional {@link SearcherFactory}. Pass
+ * <code>null</code> if you don't require the searcher to be warmed
+ * before going live or other custom behavior.
+ *
+ * @throws IOException if there is a low-level I/O error
+ */
+ public WrappableSearcherManager(Directory dir, SearcherFactory searcherFactory) throws IOException {
+ if (searcherFactory == null) {
+ searcherFactory = new SearcherFactory();
+ }
+ this.searcherFactory = searcherFactory;
+ current = getSearcher(searcherFactory, DirectoryReader.open(dir));
+ }
+
+ /**
+ * Creates and returns a new SearcherManager from an existing {@link DirectoryReader}. Note that
+ * this steals the incoming reference.
+ *
+ * @param reader the DirectoryReader.
+ * @param searcherFactory An optional {@link SearcherFactory}. Pass
+ * <code>null</code> if you don't require the searcher to be warmed
+ * before going live or other custom behavior.
+ *
+ * @throws IOException if there is a low-level I/O error
+ */
+ public WrappableSearcherManager(DirectoryReader reader, SearcherFactory searcherFactory) throws IOException {
+ if (searcherFactory == null) {
+ searcherFactory = new SearcherFactory();
+ }
+ this.searcherFactory = searcherFactory;
+ this.current = getSearcher(searcherFactory, reader);
+ }
+
+ @Override
+ protected void decRef(IndexSearcher reference) throws IOException {
+ reference.getIndexReader().decRef();
+ }
+
+ @Override
+ protected IndexSearcher refreshIfNeeded(IndexSearcher referenceToRefresh) throws IOException {
+ final IndexReader r = referenceToRefresh.getIndexReader();
+ assert r instanceof DirectoryReader: "searcher's IndexReader should be a DirectoryReader, but got " + r;
+ final IndexReader newReader = DirectoryReader.openIfChanged((DirectoryReader) r);
+ if (newReader == null) {
+ return null;
+ } else {
+ return getSearcher(searcherFactory, newReader);
+ }
+ }
+
+ @Override
+ protected boolean tryIncRef(IndexSearcher reference) {
+ return reference.getIndexReader().tryIncRef();
+ }
+
+ @Override
+ protected int getRefCount(IndexSearcher reference) {
+ return reference.getIndexReader().getRefCount();
+ }
+
+ /**
+ * Returns <code>true</code> if no changes have occured since this searcher
+ * ie. reader was opened, otherwise <code>false</code>.
+ * @see DirectoryReader#isCurrent()
+ */
+ public boolean isSearcherCurrent() throws IOException {
+ final IndexSearcher searcher = acquire();
+ try {
+ final IndexReader r = searcher.getIndexReader();
+ assert r instanceof DirectoryReader: "searcher's IndexReader should be a DirectoryReader, but got " + r;
+ return ((DirectoryReader) r).isCurrent();
+ } finally {
+ release(searcher);
+ }
+ }
+
+ /** Expert: creates a searcher from the provided {@link
+ * IndexReader} using the provided {@link
+ * SearcherFactory}. NOTE: this decRefs incoming reader
+ * on throwing an exception. */
+ @SuppressWarnings("resource")
+ public static IndexSearcher getSearcher(SearcherFactory searcherFactory, IndexReader reader) throws IOException {
+ boolean success = false;
+ final IndexSearcher searcher;
+ try {
+ searcher = searcherFactory.newSearcher(reader);
+ // Modification for Gerrit: Allow searcherFactory to transitively wrap the
+ // provided reader.
+ IndexReader unwrapped = searcher.getIndexReader();
+ while (true) {
+ if (unwrapped == reader) {
+ break;
+ } else if (unwrapped instanceof FilterDirectoryReader) {
+ unwrapped = ((FilterDirectoryReader) unwrapped).getDelegate();
+ } else if (unwrapped instanceof FilterLeafReader) {
+ unwrapped = ((FilterLeafReader) unwrapped).getDelegate();
+ } else {
+ break;
+ }
+ }
+
+ if (unwrapped != reader) {
+ throw new IllegalStateException(
+ "SearcherFactory must wrap the provided reader (got " +
+ searcher.getIndexReader() +
+ " but expected " + reader + ")");
+ }
+ success = true;
+ } finally {
+ if (!success) {
+ reader.decRef();
+ }
+ }
+ return searcher;
+ }
+}
diff --git a/gerrit-main/src/main/java/Main.java b/gerrit-main/src/main/java/Main.java
index d3c9fdd..54cf20e 100644
--- a/gerrit-main/src/main/java/Main.java
+++ b/gerrit-main/src/main/java/Main.java
@@ -20,7 +20,7 @@
// to jump into the real main code.
//
- public static void main(final String argv[]) throws Exception {
+ public static void main(final String[] argv) throws Exception {
if (onSupportedJavaVersion()) {
com.google.gerrit.launcher.GerritLauncher.main(argv);
diff --git a/gerrit-pgm/BUCK b/gerrit-pgm/BUCK
index 9a317cd..10d6dda 100644
--- a/gerrit-pgm/BUCK
+++ b/gerrit-pgm/BUCK
@@ -18,7 +18,8 @@
'//lib/guice:guice-servlet',
'//lib/jgit:jgit',
'//lib/log:api',
- '//lib/log:log4j',
+ '//lib/log:jsonevent-layout',
+ '//lib/log:log4j'
]
java_library(
@@ -91,7 +92,7 @@
java_library(
name = 'pgm',
- srcs = glob([SRCS + '*.java']),
+ srcs = glob([SRCS + '*.java', SRCS + 'rules/*.java']),
resources = glob([RSRCS + '*']),
deps = DEPS + [
':http',
@@ -106,7 +107,9 @@
'//lib:args4j',
'//lib:gwtorm',
'//lib:servlet-api-3_1',
- '//lib/prolog:prolog-cafe',
+ '//lib/prolog:cafeteria',
+ '//lib/prolog:compiler',
+ '//lib/prolog:runtime',
],
provided_deps = ['//gerrit-launcher:launcher'],
visibility = [
@@ -125,7 +128,9 @@
':init',
':init-api',
':pgm',
+ '//gerrit-common:server',
'//gerrit-server:server',
+ '//lib:guava',
'//lib:junit',
'//lib/easymock:easymock',
'//lib/guice:guice',
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java
index 2b9af2f..1afa243 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java
@@ -15,6 +15,7 @@
package com.google.gerrit.pgm;
import static com.google.gerrit.server.schema.DataSourceProvider.Context.MULTI_USER;
+import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.MoreObjects;
@@ -93,10 +94,10 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.Thread.UncaughtExceptionHandler;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
@@ -148,9 +149,10 @@
private Injector sshInjector;
private Injector webInjector;
private Injector httpdInjector;
- private File runFile;
+ private Path runFile;
private boolean test;
private AbstractModule luceneModule;
+ private Module emailModule;
private Runnable serverStarted;
@@ -184,7 +186,7 @@
});
if (runId != null) {
- runFile = new File(new File(getSitePath(), "logs"), "gerrit.run");
+ runFile = getSitePath().resolve("logs").resolve("gerrit.run");
}
if (httpd == null) {
@@ -195,11 +197,6 @@
throw die("No services enabled, nothing to do");
}
- if (consoleLog) {
- } else {
- manager.add(ErrorLogFile.start(getSitePath()));
- }
-
try {
start();
RuntimeShutdown.add(new Runnable() {
@@ -207,7 +204,11 @@
public void run() {
log.info("caught shutdown, cleaning up");
if (runId != null) {
- runFile.delete();
+ try {
+ Files.delete(runFile);
+ } catch (IOException err) {
+ log.warn("failed to delete " + runFile, err);
+ }
}
manager.stop();
}
@@ -216,15 +217,8 @@
log.info("Gerrit Code Review " + myVersion() + " ready");
if (runId != null) {
try {
- runFile.createNewFile();
- runFile.setReadable(true, false);
-
- FileOutputStream out = new FileOutputStream(runFile);
- try {
- out.write((runId + "\n").getBytes("UTF-8"));
- } finally {
- out.close();
- }
+ Files.write(runFile, (runId + "\n").getBytes(UTF_8));
+ runFile.toFile().setReadable(true, false);
} catch (IOException err) {
log.warn("Cannot write --run-id to " + runFile, err);
}
@@ -264,13 +258,18 @@
}
@VisibleForTesting
+ public void setEmailModuleForTesting(Module module) {
+ emailModule = module;
+ }
+
+ @VisibleForTesting
public void setLuceneModule(LuceneIndexModule m) {
luceneModule = m;
test = true;
}
@VisibleForTesting
- public void start() {
+ public void start() throws IOException {
if (dbInjector == null) {
dbInjector = createDbInjector(MULTI_USER);
}
@@ -280,6 +279,11 @@
.setDbCfgInjector(dbInjector, cfgInjector);
manager.add(dbInjector, cfgInjector, sysInjector);
+ if (!consoleLog) {
+ manager.add(ErrorLogFile.start(getSitePath(),
+ cfgInjector.getInstance(Key.get(Config.class, GerritServerConfig.class))));
+ }
+
sshd &= !sshdOff();
if (sshd) {
initSshd();
@@ -325,7 +329,11 @@
modules.add(new ChangeCacheImplModule(slave));
modules.add(new InternalAccountDirectory.Module());
modules.add(new DefaultCacheFactory.Module());
- modules.add(new SmtpEmailSender.Module());
+ if (emailModule != null) {
+ modules.add(emailModule);
+ } else {
+ modules.add(new SmtpEmailSender.Module());
+ }
modules.add(new SignedTokenEmailTokenVerifier.Module());
modules.add(new PluginRestApiModule());
modules.add(new RestCacheAdminModule());
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java
index 38b1824..e2775c1 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java
@@ -37,8 +37,8 @@
import org.kohsuke.args4j.Option;
-import java.io.File;
import java.io.IOException;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
@@ -70,7 +70,7 @@
super(new WarDistribution(), null);
}
- public Init(File sitePath) {
+ public Init(Path sitePath) {
super(sitePath, true, true, new WarDistribution(), null);
batchMode = true;
noAutoStart = true;
@@ -106,7 +106,7 @@
modules.add(new AbstractModule() {
@Override
protected void configure() {
- bind(File.class).annotatedWith(SitePath.class).toInstance(getSitePath());
+ bind(Path.class).annotatedWith(SitePath.class).toInstance(getSitePath());
bind(Browser.class);
bind(String.class).annotatedWith(SecureStoreClassName.class)
.toProvider(Providers.of(getConfiguredSecureStoreClass()));
@@ -157,8 +157,8 @@
}
void startDaemon(SiteRun run) {
- final String[] argv = {run.site.gerrit_sh.getAbsolutePath(), "start"};
- final Process proc;
+ String[] argv = {run.site.gerrit_sh.toAbsolutePath().toString(), "start"};
+ Process proc;
try {
System.err.println("Executing " + argv[0] + " " + argv[1]);
proc = Runtime.getRuntime().exec(argv);
@@ -177,7 +177,7 @@
for (;;) {
try {
- final int rc = proc.waitFor();
+ int rc = proc.waitFor();
if (rc != 0) {
System.err.println("error: cannot start Gerrit: exit status " + rc);
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Ls.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Ls.java
index 7e7b602..2bcd6ea 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Ls.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Ls.java
@@ -39,6 +39,7 @@
show &= !ze.isDirectory();
show &= !name.startsWith("WEB-INF/classes/");
show &= !name.startsWith("WEB-INF/lib/");
+ show &= !name.startsWith("WEB-INF/pgm-lib/");
show &= !name.equals("WEB-INF/web.xml");
if (show) {
if (name.startsWith("WEB-INF/")) {
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/PrologShell.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/PrologShell.java
index fa434a6..58162a1 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/PrologShell.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/PrologShell.java
@@ -16,11 +16,10 @@
import com.google.gerrit.pgm.util.AbstractProgram;
+import com.googlecode.prolog_cafe.exceptions.HaltException;
import com.googlecode.prolog_cafe.lang.BufferingPrologControl;
-import com.googlecode.prolog_cafe.lang.HaltException;
import com.googlecode.prolog_cafe.lang.Prolog;
import com.googlecode.prolog_cafe.lang.PrologClassLoader;
-import com.googlecode.prolog_cafe.lang.PrologMain;
import com.googlecode.prolog_cafe.lang.SymbolTerm;
import org.kohsuke.args4j.Option;
@@ -28,7 +27,6 @@
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.EnumSet;
import java.util.List;
public class PrologShell extends AbstractProgram {
@@ -41,14 +39,10 @@
BufferingPrologControl pcl = new BufferingPrologControl();
pcl.setPrologClassLoader(new PrologClassLoader(getClass().getClassLoader()));
- pcl.setEnabled(EnumSet.allOf(Prolog.Feature.class), false);
pcl.setEnabled(Prolog.Feature.IO, true);
- pcl.setEnabled(Prolog.Feature.STATISTICS_RUNTIME, true);
-
+ pcl.setEnabled(Prolog.Feature.STATISTICS, true);
+ pcl.configureUserIO(System.in, System.out, System.err);
pcl.initialize(Prolog.BUILTIN);
- pcl.execute(Prolog.BUILTIN, "set_prolog_flag",
- SymbolTerm.intern("print_stack_trace"),
- SymbolTerm.intern("on"));
for (String file : fileName) {
String path;
@@ -76,8 +70,6 @@
System.err.format("Gerrit Code Review %s - Interactive Prolog Shell",
com.google.gerrit.common.Version.getVersion());
System.err.println();
- System.err.println("based on " + PrologMain.VERSION);
- System.err.println(" " + PrologMain.COPYRIGHT);
System.err.println("(type Ctrl-D or \"halt.\" to exit,"
+ " \"['path/to/file.pl'].\" to load a file)");
System.err.println();
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/RebuildNotedb.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/RebuildNotedb.java
index ab20f53..a29a8e0 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/RebuildNotedb.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/RebuildNotedb.java
@@ -244,7 +244,7 @@
}
}
- private class RebuildListener implements Runnable {
+ private static class RebuildListener implements Runnable {
private Change.Id changeId;
private ListenableFuture<?> future;
private AtomicBoolean ok;
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Rulec.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Rulec.java
index 17a54d4..8f1b354 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Rulec.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Rulec.java
@@ -17,15 +17,15 @@
import static com.google.gerrit.server.schema.DataSourceProvider.Context.SINGLE_USER;
import com.google.gerrit.lifecycle.LifecycleManager;
+import com.google.gerrit.pgm.rules.PrologCompiler;
import com.google.gerrit.pgm.util.SiteProgram;
import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.rules.PrologCompiler;
import com.google.gerrit.server.config.FactoryModule;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.inject.Inject;
import com.google.inject.Injector;
-import com.googlecode.prolog_cafe.compiler.CompileException;
+import com.googlecode.prolog_cafe.exceptions.CompileException;
import org.eclipse.jgit.lib.Repository;
import org.kohsuke.args4j.Argument;
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/SwitchSecureStore.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/SwitchSecureStore.java
index f2feae1..ac84e82 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/SwitchSecureStore.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/SwitchSecureStore.java
@@ -19,7 +19,6 @@
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
-import com.google.common.io.Files;
import com.google.gerrit.common.IoUtil;
import com.google.gerrit.common.SiteLibraryLoaderUtil;
import com.google.gerrit.pgm.util.SiteProgram;
@@ -37,8 +36,10 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.File;
import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.jar.JarFile;
@@ -47,7 +48,7 @@
public class SwitchSecureStore extends SiteProgram {
private static String getSecureStoreClassFromGerritConfig(SitePaths sitePaths) {
FileBasedConfig cfg =
- new FileBasedConfig(sitePaths.gerrit_config, FS.DETECTED);
+ new FileBasedConfig(sitePaths.gerrit_config.toFile(), FS.DETECTED);
try {
cfg.load();
} catch (IOException | ConfigInvalidException e) {
@@ -67,14 +68,14 @@
@Override
public int run() throws Exception {
SitePaths sitePaths = new SitePaths(getSitePath());
- File newSecureStoreFile = new File(newSecureStoreLib);
- if (!newSecureStoreFile.exists()) {
- log.error(String.format("File %s doesn't exists",
- newSecureStoreFile.getAbsolutePath()));
+ Path newSecureStorePath = Paths.get(newSecureStoreLib);
+ if (!Files.exists(newSecureStorePath)) {
+ log.error(String.format("File %s doesn't exist",
+ newSecureStorePath.toAbsolutePath()));
return -1;
}
- String newSecureStore = getNewSecureStoreClassName(newSecureStoreFile);
+ String newSecureStore = getNewSecureStoreClassName(newSecureStorePath);
String currentSecureStoreName = getCurrentSecureStoreClassName(sitePaths);
if (currentSecureStoreName.equals(newSecureStore)) {
@@ -83,7 +84,7 @@
return -1;
}
- IoUtil.loadJARs(newSecureStoreFile);
+ IoUtil.loadJARs(newSecureStorePath);
SiteLibraryLoaderUtil.loadSiteLib(sitePaths.lib_dir);
log.info("Current secureStoreClass property ({}) will be replaced with {}",
@@ -96,7 +97,7 @@
migrateProperties(currentStore, newStore);
removeOldLib(sitePaths, currentSecureStoreName);
- copyNewLib(sitePaths, newSecureStoreFile);
+ copyNewLib(sitePaths, newSecureStorePath);
updateGerritConfig(sitePaths, newSecureStore);
@@ -123,14 +124,17 @@
}
}
- private void removeOldLib(SitePaths sitePaths, String currentSecureStoreName) {
- File oldSecureStore =
+ private void removeOldLib(SitePaths sitePaths, String currentSecureStoreName)
+ throws IOException {
+ Path oldSecureStore =
findJarWithSecureStore(sitePaths, currentSecureStoreName);
if (oldSecureStore != null) {
log.info("Removing old SecureStore ({}) from lib/ directory",
- oldSecureStore.getName());
- if (!oldSecureStore.delete()) {
- log.error("Cannot remove {}", oldSecureStore.getAbsolutePath());
+ oldSecureStore.getFileName());
+ try {
+ Files.delete(oldSecureStore);
+ } catch (IOException e) {
+ log.error("Cannot remove {}", oldSecureStore.toAbsolutePath(), e);
}
} else {
log.info("Cannot find jar with old SecureStore ({}) in lib/ directory",
@@ -138,12 +142,12 @@
}
}
- private void copyNewLib(SitePaths sitePaths, File newSecureStoreFile)
+ private void copyNewLib(SitePaths sitePaths, Path newSecureStorePath)
throws IOException {
log.info("Copy new SecureStore ({}) into lib/ directory",
- newSecureStoreFile.getName());
- Files.copy(newSecureStoreFile, new File(sitePaths.lib_dir,
- newSecureStoreFile.getName()));
+ newSecureStorePath.getFileName());
+ Files.copy(newSecureStorePath,
+ sitePaths.lib_dir.resolve(newSecureStorePath.getFileName()));
}
private void updateGerritConfig(SitePaths sitePaths, String newSecureStore)
@@ -151,13 +155,13 @@
log.info("Set gerrit.secureStoreClass property of gerrit.config to {}",
newSecureStore);
FileBasedConfig config =
- new FileBasedConfig(sitePaths.gerrit_config, FS.DETECTED);
+ new FileBasedConfig(sitePaths.gerrit_config.toFile(), FS.DETECTED);
config.load();
config.setString("gerrit", null, "secureStoreClass", newSecureStore);
config.save();
}
- private String getNewSecureStoreClassName(File secureStore)
+ private String getNewSecureStoreClassName(Path secureStore)
throws IOException {
JarScanner scanner = new JarScanner(secureStore);
List<String> newSecureStores =
@@ -165,12 +169,12 @@
if (newSecureStores.isEmpty()) {
throw new RuntimeException(String.format(
"Cannot find implementation of SecureStore interface in %s",
- secureStore.getAbsolutePath()));
+ secureStore.toAbsolutePath()));
}
if (newSecureStores.size() > 1) {
throw new RuntimeException(String.format(
"Found too many implementations of SecureStore:\n%s\nin %s", Joiner
- .on("\n").join(newSecureStores), secureStore.getAbsolutePath()));
+ .on("\n").join(newSecureStores), secureStore.toAbsolutePath()));
}
return Iterables.getOnlyElement(newSecureStores);
}
@@ -195,15 +199,12 @@
}
}
- private File findJarWithSecureStore(SitePaths sitePaths,
- String secureStoreClass) {
- File[] jars = SiteLibraryLoaderUtil.listJars(sitePaths.lib_dir);
- if (jars == null || jars.length == 0) {
- return null;
- }
+ private Path findJarWithSecureStore(SitePaths sitePaths,
+ String secureStoreClass) throws IOException {
+ List<Path> jars = SiteLibraryLoaderUtil.listJars(sitePaths.lib_dir);
String secureStoreClassPath = secureStoreClass.replace('.', '/') + ".class";
- for (File jar : jars) {
- try (JarFile jarFile = new JarFile(jar)) {
+ for (Path jar : jars) {
+ try (JarFile jarFile = new JarFile(jar.toFile())) {
ZipEntry entry = jarFile.getEntry(secureStoreClassPath);
if (entry != null) {
return jar;
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyServer.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyServer.java
index 907624d..80d69f1 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyServer.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyServer.java
@@ -81,6 +81,8 @@
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.Enumeration;
@@ -220,22 +222,22 @@
} else if ("https".equals(u.getScheme())) {
SslContextFactory ssl = new SslContextFactory();
- final File keystore = getFile(cfg, "sslkeystore", "etc/keystore");
+ final Path keystore = getFile(cfg, "sslkeystore", "etc/keystore");
String password = cfg.getString("httpd", null, "sslkeypassword");
if (password == null) {
password = "gerrit";
}
- ssl.setKeyStorePath(keystore.getAbsolutePath());
- ssl.setTrustStorePath(keystore.getAbsolutePath());
+ ssl.setKeyStorePath(keystore.toAbsolutePath().toString());
+ ssl.setTrustStorePath(keystore.toAbsolutePath().toString());
ssl.setKeyStorePassword(password);
ssl.setTrustStorePassword(password);
if (AuthType.CLIENT_SSL_CERT_LDAP.equals(authType)) {
ssl.setNeedClientAuth(true);
- File crl = getFile(cfg, "sslcrl", "etc/crl.pem");
- if (crl.exists()) {
- ssl.setCrlPath(crl.getAbsolutePath());
+ Path crl = getFile(cfg, "sslcrl", "etc/crl.pem");
+ if (Files.exists(crl)) {
+ ssl.setCrlPath(crl.toAbsolutePath().toString());
ssl.setValidatePeerCerts(true);
}
}
@@ -340,7 +342,7 @@
return r;
}
- private File getFile(final Config cfg, final String name, final String def) {
+ private Path getFile(Config cfg, String name, String def) {
String path = cfg.getString("httpd", null, name);
if (path == null || path.length() == 0) {
path = def;
@@ -525,11 +527,13 @@
final ZipEntry ze = e.nextElement();
final String name = ze.getName();
- if (ze.isDirectory()) continue;
- if (name.startsWith("WEB-INF/")) continue;
- if (name.startsWith("META-INF/")) continue;
- if (name.startsWith("com/google/gerrit/launcher/")) continue;
- if (name.equals("Main.class")) continue;
+ if (ze.isDirectory()
+ || name.startsWith("WEB-INF/")
+ || name.startsWith("META-INF/")
+ || name.startsWith("com/google/gerrit/launcher/")
+ || name.equals("Main.class")) {
+ continue;
+ }
final File rawtmp = new File(dstwar, name);
mkdir(rawtmp.getParentFile());
@@ -559,8 +563,9 @@
private static void mkdir(File dir) throws IOException {
if (!dir.isDirectory()) {
mkdir(dir.getParentFile());
- if (!dir.mkdir())
+ if (!dir.mkdir()) {
throw new IOException("Cannot mkdir " + dir.getAbsolutePath());
+ }
dir.deleteOnExit();
}
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/BaseInit.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/BaseInit.java
index c9e76c8..534ef050 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/BaseInit.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/BaseInit.java
@@ -56,9 +56,14 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
@@ -86,12 +91,12 @@
this.pluginsToInstall = pluginsToInstall;
}
- public BaseInit(File sitePath, boolean standalone, boolean initDb,
+ public BaseInit(Path sitePath, boolean standalone, boolean initDb,
PluginsDistribution pluginsDistribution, List<String> pluginsToInstall) {
this(sitePath, null, standalone, initDb, pluginsDistribution, pluginsToInstall);
}
- public BaseInit(File sitePath, final Provider<DataSource> dsProvider,
+ public BaseInit(Path sitePath, final Provider<DataSource> dsProvider,
boolean standalone, boolean initDb,
PluginsDistribution pluginsDistribution, List<String> pluginsToInstall) {
super(sitePath, dsProvider);
@@ -132,7 +137,7 @@
throw failure;
}
- System.err.println("Initialized " + getSitePath().getCanonicalPath());
+ System.err.println("Initialized " + getSitePath().toRealPath().normalize());
afterInit(run);
return 0;
}
@@ -208,7 +213,7 @@
private SiteInit createSiteInit() {
final ConsoleUI ui = getConsoleUI();
- final File sitePath = getSitePath();
+ final Path sitePath = getSitePath();
final List<Module> m = new ArrayList<>();
final SecureStoreInitData secureStoreInitData = discoverSecureStoreClass();
final String currentSecureStoreClassName = getConfiguredSecureStoreClass();
@@ -228,7 +233,7 @@
@Override
protected void configure() {
bind(ConsoleUI.class).toInstance(ui);
- bind(File.class).annotatedWith(SitePath.class).toInstance(sitePath);
+ bind(Path.class).annotatedWith(SitePath.class).toInstance(sitePath);
List<String> plugins =
MoreObjects.firstNonNull(
getInstallPlugins(), Lists.<String> newArrayList());
@@ -287,8 +292,8 @@
}
try {
- File secureStoreLib = new File(secureStore);
- if (!secureStoreLib.exists()) {
+ Path secureStoreLib = Paths.get(secureStore);
+ if (!Files.exists(secureStoreLib)) {
throw new InvalidSecureStoreException(String.format(
"File %s doesn't exist", secureStore));
}
@@ -408,15 +413,41 @@
return sysInjector;
}
- private static void recursiveDelete(File path) {
- File[] entries = path.listFiles();
- if (entries != null) {
- for (File e : entries) {
- recursiveDelete(e);
- }
- }
- if (!path.delete() && path.exists()) {
- System.err.println("warn: Cannot remove " + path);
+ private static void recursiveDelete(Path path) {
+ final String msg = "warn: Cannot remove ";
+ try {
+ Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
+ @Override
+ public FileVisitResult visitFile(Path f, BasicFileAttributes attrs)
+ throws IOException {
+ try {
+ Files.delete(f);
+ } catch (IOException e) {
+ System.err.println(msg + f);
+ }
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException err) {
+ try {
+ // Previously warned if err was not null; if dir is not empty as a
+ // result, will cause an error that will be logged below.
+ Files.delete(dir);
+ } catch (IOException e) {
+ System.err.println(msg + dir);
+ }
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFileFailed(Path f, IOException e) {
+ System.err.println(msg + f);
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ } catch (IOException e) {
+ System.err.println(msg + path);
}
}
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/Browser.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/Browser.java
index 5a1eab2..98bee3d 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/Browser.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/Browser.java
@@ -31,7 +31,7 @@
private final Config cfg;
@Inject
- Browser(final @GerritServerConfig Config cfg) {
+ Browser(@GerritServerConfig final Config cfg) {
this.cfg = cfg;
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/H2Initializer.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/H2Initializer.java
index e20346a..6d60ad1 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/H2Initializer.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/H2Initializer.java
@@ -14,12 +14,14 @@
package com.google.gerrit.pgm.init;
-import com.google.gerrit.pgm.init.api.InitUtil;
+import static com.google.gerrit.pgm.init.api.InitUtil.die;
+
+import com.google.gerrit.common.FileUtil;
import com.google.gerrit.pgm.init.api.Section;
import com.google.gerrit.server.config.SitePaths;
import com.google.inject.Inject;
-import java.io.File;
+import java.nio.file.Path;
class H2Initializer implements DatabaseConfigInitializer {
@@ -33,18 +35,17 @@
@Override
public void initConfig(Section databaseSection) {
String path = databaseSection.get("database");
+ Path db;
if (path == null) {
- path = "db/ReviewDB";
- databaseSection.set("database", path);
+ db = site.resolve("db").resolve("ReviewDB");
+ databaseSection.set("database", db.toString());
+ } else {
+ db = site.resolve(path);
}
- File db = site.resolve(path);
if (db == null) {
- throw InitUtil.die("database.database must be supplied for H2");
+ throw die("database.database must be supplied for H2");
}
- db = db.getParentFile();
- if (!db.exists() && !db.mkdirs()) {
- throw InitUtil.die("cannot create database.database "
- + db.getAbsolutePath());
- }
+ db = db.getParent();
+ FileUtil.mkdirsOrDie(db, "cannot create database.database");
}
-}
\ No newline at end of file
+}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitAdminUser.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitAdminUser.java
index c1f0090..e0cb4c4 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitAdminUser.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitAdminUser.java
@@ -23,6 +23,7 @@
import com.google.gerrit.reviewdb.client.AccountExternalId;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupMember;
+import com.google.gerrit.reviewdb.client.AccountSshKey;
import com.google.gerrit.reviewdb.client.AuthType;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gwtorm.server.SchemaFactory;
@@ -30,6 +31,11 @@
import org.apache.commons.validator.routines.EmailValidator;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.Collections;
public class InitAdminUser implements InitStep {
@@ -70,8 +76,9 @@
Account.Id id = new Account.Id(db.nextAccountId());
String username = ui.readString("admin", "username");
String name = ui.readString("Administrator", "name");
- String email = readEmail();
String httpPassword = ui.readString("secret", "HTTP password");
+ AccountSshKey sshKey = readSshKey(id);
+ String email = readEmail(sshKey);
AccountExternalId extUser =
new AccountExternalId(id, new AccountExternalId.Key(
@@ -98,6 +105,10 @@
new AccountGroupMember(new AccountGroupMember.Key(id,
new AccountGroup.Id(1)));
db.accountGroupMembers().insert(Collections.singleton(m));
+
+ if (sshKey != null) {
+ db.accountSshKeys().insert(Collections.singleton(sshKey));
+ }
}
}
} finally {
@@ -105,12 +116,47 @@
}
}
- private String readEmail() {
- String email = ui.readString("admin@example.com", "email");
+ private String readEmail(AccountSshKey sshKey) {
+ String defaultEmail = "admin@example.com";
+ if (sshKey != null && sshKey.getComment() != null) {
+ String c = sshKey.getComment().trim();
+ if (EmailValidator.getInstance().isValid(c)) {
+ defaultEmail = c;
+ }
+ }
+ return readEmail(defaultEmail);
+ }
+
+ private String readEmail(String defaultEmail) {
+ String email = ui.readString(defaultEmail, "email");
if (email != null && !EmailValidator.getInstance().isValid(email)) {
ui.message("error: invalid email address\n");
- return readEmail();
+ return readEmail(defaultEmail);
}
return email;
}
+
+ private AccountSshKey readSshKey(Account.Id id) throws IOException {
+ String defaultPublicSshKeyFile = "";
+ Path defaultPublicSshKeyPath =
+ Paths.get(System.getProperty("user.home"), ".ssh", "id_rsa.pub");
+ if (Files.exists(defaultPublicSshKeyPath)) {
+ defaultPublicSshKeyFile = defaultPublicSshKeyPath.toString();
+ }
+ String publicSshKeyFile =
+ ui.readString(defaultPublicSshKeyFile, "public SSH key file");
+ return !Strings.isNullOrEmpty(publicSshKeyFile)
+ ? createSshKey(id, publicSshKeyFile) : null;
+ }
+
+ private AccountSshKey createSshKey(Account.Id id, String keyFile)
+ throws IOException {
+ Path p = Paths.get(keyFile);
+ if (!Files.exists(p)) {
+ throw new IOException(String.format(
+ "Cannot add public SSH key: %s is not a file", keyFile));
+ }
+ String content = new String(Files.readAllBytes(p), StandardCharsets.UTF_8);
+ return new AccountSshKey(new AccountSshKey.Id(id, 0), content);
+ }
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitCache.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitCache.java
index 8da4a03..4e5d044 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitCache.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitCache.java
@@ -14,15 +14,14 @@
package com.google.gerrit.pgm.init;
-import static com.google.gerrit.pgm.init.api.InitUtil.die;
-
+import com.google.gerrit.common.FileUtil;
import com.google.gerrit.pgm.init.api.InitStep;
import com.google.gerrit.pgm.init.api.Section;
import com.google.gerrit.server.config.SitePaths;
import com.google.inject.Inject;
import com.google.inject.Singleton;
-import java.io.File;
+import java.nio.file.Path;
/** Initialize the {@code cache} configuration section. */
@Singleton
@@ -52,10 +51,8 @@
cache.set("directory", path);
}
- final File loc = site.resolve(path);
- if (!loc.exists() && !loc.mkdirs()) {
- throw die("cannot create cache.directory " + loc.getAbsolutePath());
- }
+ Path loc = site.resolve(path);
+ FileUtil.mkdirsOrDie(loc, "cannot create cache.directory");
}
@Override
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitContainer.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitContainer.java
index f830854..60ff665 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitContainer.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitContainer.java
@@ -17,6 +17,7 @@
import static com.google.gerrit.pgm.init.api.InitUtil.die;
import static com.google.gerrit.pgm.init.api.InitUtil.username;
+import com.google.common.io.ByteStreams;
import com.google.gerrit.launcher.GerritLauncher;
import com.google.gerrit.pgm.init.api.ConsoleUI;
import com.google.gerrit.pgm.init.api.InitStep;
@@ -28,11 +29,12 @@
import org.eclipse.jgit.internal.storage.file.LockFile;
import org.eclipse.jgit.util.FS;
-import java.io.File;
-import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
/** Initialize the {@code container} configuration section. */
@Singleton
@@ -56,9 +58,9 @@
container.string("Run as", "user", username());
container.string("Java runtime", "javaHome", javaHome());
- File myWar;
+ Path myWar;
try {
- myWar = GerritLauncher.getDistributionArchive();
+ myWar = GerritLauncher.getDistributionArchive().toPath();
} catch (FileNotFoundException e) {
System.err.println("warn: Cannot find distribution archive (e.g. gerrit.war)");
myWar = null;
@@ -66,53 +68,41 @@
String path = container.get("war");
if (path != null) {
- path = container.string("Gerrit runtime", "war", //
- myWar != null ? myWar.getAbsolutePath() : null);
+ path = container.string("Gerrit runtime", "war",
+ myWar != null ? myWar.toAbsolutePath().toString() : null);
if (path == null || path.isEmpty()) {
throw die("container.war is required");
}
} else if (myWar != null) {
final boolean copy;
- final File siteWar = site.gerrit_war;
- if (siteWar.exists()) {
- copy = ui.yesno(true, "Upgrade %s", siteWar.getPath());
+ final Path siteWar = site.gerrit_war;
+ if (Files.exists(siteWar)) {
+ copy = ui.yesno(true, "Upgrade %s", siteWar);
} else {
- copy = ui.yesno(true, "Copy %s to %s", myWar.getName(), siteWar.getPath());
+ copy = ui.yesno(true, "Copy %s to %s", myWar.getFileName(), siteWar);
if (copy) {
container.unset("war");
} else {
- container.set("war", myWar.getAbsolutePath());
+ container.set("war", myWar.toAbsolutePath().toString());
}
}
if (copy) {
if (!ui.isBatch()) {
- System.err.format("Copying %s to %s", myWar.getName(), siteWar.getPath());
+ System.err.format("Copying %s to %s", myWar.getFileName(), siteWar);
System.err.println();
}
- FileInputStream in = new FileInputStream(myWar);
- try {
- siteWar.getParentFile().mkdirs();
+ try (InputStream in = Files.newInputStream(myWar)) {
+ Files.createDirectories(siteWar.getParent());
- LockFile lf = new LockFile(siteWar, FS.DETECTED);
+ LockFile lf = new LockFile(siteWar.toFile(), FS.DETECTED);
if (!lf.lock()) {
throw new IOException("Cannot lock " + siteWar);
}
-
try {
- final OutputStream out = lf.getOutputStream();
- try {
- final byte[] tmp = new byte[4096];
- for (;;) {
- int n = in.read(tmp);
- if (n < 0) {
- break;
- }
- out.write(tmp, 0, n);
- }
- } finally {
- out.close();
+ try (OutputStream out = lf.getOutputStream()) {
+ ByteStreams.copy(in, out);
}
if (!lf.commit()) {
throw new IOException("Cannot commit " + siteWar);
@@ -120,8 +110,6 @@
} finally {
lf.unlock();
}
- } finally {
- in.close();
}
}
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitGitManager.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitGitManager.java
index 067b103..d8fd509 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitGitManager.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitGitManager.java
@@ -16,13 +16,14 @@
import static com.google.gerrit.pgm.init.api.InitUtil.die;
+import com.google.gerrit.common.FileUtil;
import com.google.gerrit.pgm.init.api.ConsoleUI;
import com.google.gerrit.pgm.init.api.InitStep;
import com.google.gerrit.pgm.init.api.Section;
import com.google.inject.Inject;
import com.google.inject.Singleton;
-import java.io.File;
+import java.nio.file.Path;
/** Initialize the GitRepositoryManager configuration section. */
@Singleton
@@ -40,13 +41,11 @@
public void run() {
ui.header("Git Repositories");
- File d = gerrit.path("Location of Git repositories", "basePath", "git");
+ Path d = gerrit.path("Location of Git repositories", "basePath", "git");
if (d == null) {
throw die("gerrit.basePath is required");
}
- if (!d.exists() && !d.mkdirs()) {
- throw die("Cannot create " + d);
- }
+ FileUtil.mkdirsOrDie(d, "Cannot create");
}
@Override
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitHttpd.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitHttpd.java
index c8f1cd7..a907d46 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitHttpd.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitHttpd.java
@@ -29,10 +29,11 @@
import com.google.inject.Inject;
import com.google.inject.Singleton;
-import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Path;
/** Initialize the {@code httpd} configuration section. */
@Singleton
@@ -57,7 +58,8 @@
public void run() throws IOException, InterruptedException {
ui.header("HTTP Daemon");
- boolean proxy = false, ssl = false;
+ boolean proxy = false;
+ boolean ssl = false;
String address = "*";
int port = -1;
String context = "/";
@@ -149,8 +151,9 @@
return;
}
- final File store = site.ssl_keystore;
- if (!ui.yesno(!store.exists(), "Create new self-signed SSL certificate")) {
+ Path store = site.ssl_keystore;
+ if (!ui.yesno(!Files.exists(store),
+ "Create new self-signed SSL certificate")) {
return;
}
@@ -167,15 +170,17 @@
final String dname =
"CN=" + hostname + ",OU=Gerrit Code Review,O=" + domainOf(hostname);
- final File tmpdir = new File(site.etc_dir, "tmp.sslcertgen");
- if (!tmpdir.mkdir()) {
- throw die("Cannot create directory " + tmpdir);
+ Path tmpdir = site.etc_dir.resolve("tmp.sslcertgen");
+ try {
+ Files.createDirectory(tmpdir);
+ } catch (IOException e) {
+ throw die("Cannot create directory " + tmpdir, e);
}
chmod(0600, tmpdir);
- final File tmpstore = new File(tmpdir, "keystore");
+ Path tmpstore = tmpdir.resolve("keystore");
Runtime.getRuntime().exec(new String[] {"keytool", //
- "-keystore", tmpstore.getAbsolutePath(), //
+ "-keystore", tmpstore.toAbsolutePath().toString(), //
"-storepass", ssl_pass, //
"-genkeypair", //
"-alias", hostname, //
@@ -186,11 +191,15 @@
}).waitFor();
chmod(0600, tmpstore);
- if (!tmpstore.renameTo(store)) {
- throw die("Cannot rename " + tmpstore + " to " + store);
+ try {
+ Files.move(tmpstore, store);
+ } catch (IOException e) {
+ throw die("Cannot rename " + tmpstore + " to " + store, e);
}
- if (!tmpdir.delete()) {
- throw die("Cannot delete " + tmpdir);
+ try {
+ Files.delete(tmpdir);
+ } catch (IOException e) {
+ throw die("Cannot delete " + tmpdir, e);
}
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitLabels.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitLabels.java
index 8fb05ca..b6b4cc1 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitLabels.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitLabels.java
@@ -26,6 +26,8 @@
@Singleton
public class InitLabels implements InitStep {
+ private static final String KEY_COPY_ALL_SCORES_IF_NO_CODE_CHANGE =
+ "copyAllScoresIfNoCodeChange";
private static final String KEY_LABEL = "label";
private static final String KEY_FUNCTION = "function";
private static final String KEY_VALUE = "value";
@@ -58,6 +60,7 @@
cfg.setString(KEY_LABEL, LABEL_VERIFIED, KEY_FUNCTION, "MaxWithBlock");
cfg.setStringList(KEY_LABEL, LABEL_VERIFIED, KEY_VALUE,
Arrays.asList(new String[] {"-1 Fails", " 0 No score", "+1 Verified"}));
+ cfg.setBoolean(KEY_LABEL, LABEL_VERIFIED, KEY_COPY_ALL_SCORES_IF_NO_CODE_CHANGE, true);
allProjectsConfig.save("Configure 'Verified' label");
}
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitPluginStepsLoader.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitPluginStepsLoader.java
index fa9f710..3476de5 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitPluginStepsLoader.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitPluginStepsLoader.java
@@ -15,6 +15,7 @@
package com.google.gerrit.pgm.init;
import com.google.common.base.MoreObjects;
+import com.google.common.collect.Ordering;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.pgm.init.api.ConsoleUI;
import com.google.gerrit.pgm.init.api.InitStep;
@@ -26,23 +27,22 @@
import com.google.inject.Injector;
import com.google.inject.Singleton;
-import java.io.File;
-import java.io.FileFilter;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
-import java.util.Comparator;
import java.util.List;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
@Singleton
public class InitPluginStepsLoader {
- private final File pluginsDir;
+ private final Path pluginsDir;
private final Injector initInjector;
final ConsoleUI ui;
@@ -55,10 +55,10 @@
}
public Collection<InitStep> getInitSteps() {
- List<File> jars = scanJarsInPluginsDirectory();
+ List<Path> jars = scanJarsInPluginsDirectory();
ArrayList<InitStep> pluginsInitSteps = new ArrayList<>();
- for (File jar : jars) {
+ for (Path jar : jars) {
InitStep init = loadInitStep(jar);
if (init != null) {
pluginsInitSteps.add(init);
@@ -68,12 +68,12 @@
}
@SuppressWarnings("resource")
- private InitStep loadInitStep(File jar) {
+ private InitStep loadInitStep(Path jar) {
try {
URLClassLoader pluginLoader =
- new URLClassLoader(new URL[] {jar.toURI().toURL()},
+ new URLClassLoader(new URL[] {jar.toUri().toURL()},
InitPluginStepsLoader.class.getClassLoader());
- try (JarFile jarFile = new JarFile(jar)) {
+ try (JarFile jarFile = new JarFile(jar.toFile())) {
Attributes jarFileAttributes = jarFile.getManifest().getMainAttributes();
String initClassName = jarFileAttributes.getValue("Gerrit-InitStep");
if (initClassName == null) {
@@ -86,12 +86,12 @@
} catch (ClassCastException e) {
ui.message(
"WARN: InitStep from plugin %s does not implement %s (Exception: %s)\n",
- jar.getName(), InitStep.class.getName(), e.getMessage());
+ jar.getFileName(), InitStep.class.getName(), e.getMessage());
return null;
} catch (NoClassDefFoundError e) {
ui.message(
"WARN: Failed to run InitStep from plugin %s (Missing class: %s)\n",
- jar.getName(), e.getMessage());
+ jar.getFileName(), e.getMessage());
return null;
}
} catch (Exception e) {
@@ -102,11 +102,10 @@
}
}
- private Injector getPluginInjector(final File jarFile) throws IOException {
- final String pluginName =
- MoreObjects.firstNonNull(
- JarPluginProvider.getJarPluginName(jarFile),
- PluginLoader.nameOf(jarFile));
+ private Injector getPluginInjector(Path jarPath) throws IOException {
+ final String pluginName = MoreObjects.firstNonNull(
+ JarPluginProvider.getJarPluginName(jarPath),
+ PluginLoader.nameOf(jarPath));
return initInjector.createChildInjector(new AbstractModule() {
@Override
protected void configure() {
@@ -116,27 +115,24 @@
});
}
- private List<File> scanJarsInPluginsDirectory() {
- if (pluginsDir == null || !pluginsDir.exists()) {
+ private List<Path> scanJarsInPluginsDirectory() {
+ if (pluginsDir == null || !Files.isDirectory(pluginsDir)) {
return Collections.emptyList();
}
- File[] matches = pluginsDir.listFiles(new FileFilter() {
+ DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<Path>() {
@Override
- public boolean accept(File pathname) {
- String n = pathname.getName();
- return (n.endsWith(".jar") && pathname.isFile());
+ public boolean accept(Path entry) throws IOException {
+ return entry.getFileName().toString().endsWith(".jar")
+ && Files.isRegularFile(entry);
}
- });
- if (matches == null) {
- ui.message("WARN: Cannot list %s", pluginsDir.getAbsolutePath());
+ };
+ try (DirectoryStream<Path> paths =
+ Files.newDirectoryStream(pluginsDir, filter)) {
+ return Ordering.natural().sortedCopy(paths);
+ } catch (IOException e) {
+ ui.message("WARN: Cannot list %s: %s", pluginsDir.toAbsolutePath(),
+ e.getMessage());
return Collections.emptyList();
}
- Arrays.sort(matches, new Comparator<File>() {
- @Override
- public int compare(File o1, File o2) {
- return o1.getName().compareTo(o2.getName());
- }
- });
- return Arrays.asList(matches);
}
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitPlugins.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitPlugins.java
index 72400a4..a714ac9 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitPlugins.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitPlugins.java
@@ -25,9 +25,10 @@
import com.google.inject.Injector;
import com.google.inject.Singleton;
-import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.Collection;
import java.util.List;
import java.util.jar.Attributes;
@@ -56,10 +57,10 @@
pluginsDistribution.foreach(new PluginsDistribution.Processor() {
@Override
public void process(String pluginName, InputStream in) throws IOException {
- File tmpPlugin = JarPluginProvider.storeInTemp(pluginName, in, site);
+ Path tmpPlugin = JarPluginProvider.storeInTemp(pluginName, in, site);
String pluginVersion = getVersion(tmpPlugin);
if (deleteTempPluginFile) {
- tmpPlugin.delete();
+ Files.delete(tmpPlugin);
}
result.add(new PluginData(pluginName, pluginVersion, tmpPlugin));
}
@@ -110,37 +111,39 @@
for (PluginData plugin : plugins) {
String pluginName = plugin.name;
try {
- final File tmpPlugin = plugin.pluginFile;
+ final Path tmpPlugin = plugin.pluginPath;
if (!(initFlags.installPlugins.contains(pluginName) || ui.yesno(false,
"Install plugin %s version %s", pluginName, plugin.version))) {
- tmpPlugin.delete();
+ Files.deleteIfExists(tmpPlugin);
continue;
}
- final File p = new File(site.plugins_dir, plugin.name + ".jar");
- if (p.exists()) {
+ final Path p = site.plugins_dir.resolve(plugin.name + ".jar");
+ if (Files.exists(p)) {
final String installedPluginVersion = getVersion(p);
if (!ui.yesno(false,
"version %s is already installed, overwrite it",
installedPluginVersion)) {
- tmpPlugin.delete();
+ Files.deleteIfExists(tmpPlugin);
continue;
}
- if (!p.delete()) {
+ try {
+ Files.delete(p);
+ } catch (IOException e) {
throw new IOException("Failed to delete plugin " + pluginName
- + ": " + p.getAbsolutePath());
+ + ": " + p.toAbsolutePath(), e);
}
}
- if (!tmpPlugin.renameTo(p)) {
+ try {
+ Files.move(tmpPlugin, p);
+ } catch (IOException e) {
throw new IOException("Failed to install plugin " + pluginName
- + ": " + tmpPlugin.getAbsolutePath() + " -> "
- + p.getAbsolutePath());
+ + ": " + tmpPlugin.toAbsolutePath() + " -> "
+ + p.toAbsolutePath(), e);
}
} finally {
- if (plugin.pluginFile.exists()) {
- plugin.pluginFile.delete();
- }
+ Files.deleteIfExists(plugin.pluginPath);
}
}
if (plugins.isEmpty()) {
@@ -167,11 +170,11 @@
}
}
- private static String getVersion(final File plugin) throws IOException {
- final JarFile jarFile = new JarFile(plugin);
+ private static String getVersion(Path plugin) throws IOException {
+ JarFile jarFile = new JarFile(plugin.toFile());
try {
- final Manifest manifest = jarFile.getManifest();
- final Attributes main = manifest.getMainAttributes();
+ Manifest manifest = jarFile.getManifest();
+ Attributes main = manifest.getMainAttributes();
return main.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
} finally {
jarFile.close();
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitSendEmail.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitSendEmail.java
index 51eaa22..5c7eefd 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitSendEmail.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitSendEmail.java
@@ -25,6 +25,8 @@
import com.google.inject.Inject;
import com.google.inject.Singleton;
+import java.nio.file.Files;
+
/** Initialize the {@code sendemail} configuration section. */
@Singleton
class InitSendEmail implements InitStep {
@@ -54,7 +56,7 @@
true);
String username = null;
- if (site.gerrit_config.exists()) {
+ if (Files.exists(site.gerrit_config)) {
username = sendemail.get("smtpUser");
} else if ((enc != null && enc != Encryption.NONE) || !isLocal(hostname)) {
username = username();
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitSshd.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitSshd.java
index ed18d73..c654c8d 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitSshd.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitSshd.java
@@ -17,6 +17,7 @@
import static com.google.gerrit.common.FileUtil.chmod;
import static com.google.gerrit.pgm.init.api.InitUtil.die;
import static com.google.gerrit.pgm.init.api.InitUtil.hostname;
+import static java.nio.file.Files.exists;
import com.google.gerrit.pgm.init.api.ConsoleUI;
import com.google.gerrit.pgm.init.api.InitStep;
@@ -29,9 +30,10 @@
import org.apache.sshd.common.util.SecurityUtils;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
-import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
+import java.nio.file.Files;
+import java.nio.file.Path;
/** Initialize the {@code sshd} configuration section. */
@Singleton
@@ -74,9 +76,9 @@
port = ui.readInt(port, "Listen on port");
sshd.set("listenAddress", SocketUtil.format(hostname, port));
- if (site.ssh_rsa.exists() || site.ssh_dsa.exists()) {
+ if (exists(site.ssh_rsa) || exists(site.ssh_dsa)) {
libraries.bouncyCastleSSL.downloadRequired();
- } else if (!site.ssh_key.exists()) {
+ } else if (!exists(site.ssh_key)) {
libraries.bouncyCastleSSL.downloadOptional();
}
@@ -90,9 +92,9 @@
}
private void generateSshHostKeys() throws InterruptedException, IOException {
- if (!site.ssh_key.exists() //
- && !site.ssh_rsa.exists() //
- && !site.ssh_dsa.exists()) {
+ if (!exists(site.ssh_key) //
+ && !exists(site.ssh_rsa) //
+ && !exists(site.ssh_dsa)) {
System.err.print("Generating SSH host key ...");
System.err.flush();
@@ -108,7 +110,7 @@
"-t", "rsa", //
"-P", "", //
"-C", comment, //
- "-f", site.ssh_rsa.getAbsolutePath() //
+ "-f", site.ssh_rsa.toAbsolutePath().toString() //
}).waitFor();
System.err.print(" dsa...");
@@ -118,7 +120,7 @@
"-t", "dsa", //
"-P", "", //
"-C", comment, //
- "-f", site.ssh_dsa.getAbsolutePath() //
+ "-f", site.ssh_dsa.toAbsolutePath().toString() //
}).waitFor();
} else {
@@ -128,28 +130,34 @@
// short period of time. We try to reduce that risk by creating
// the key within a temporary directory.
//
- final File tmpdir = new File(site.etc_dir, "tmp.sshkeygen");
- if (!tmpdir.mkdir()) {
- throw die("Cannot create directory " + tmpdir);
+ Path tmpdir = site.etc_dir.resolve("tmp.sshkeygen");
+ try {
+ Files.createDirectory(tmpdir);
+ } catch (IOException e) {
+ throw die("Cannot create directory " + tmpdir, e);
}
chmod(0600, tmpdir);
- final File tmpkey = new File(tmpdir, site.ssh_key.getName());
- final SimpleGeneratorHostKeyProvider p;
+ Path tmpkey = tmpdir.resolve(site.ssh_key.getFileName().toString());
+ SimpleGeneratorHostKeyProvider p;
System.err.print(" rsa(simple)...");
System.err.flush();
p = new SimpleGeneratorHostKeyProvider();
- p.setPath(tmpkey.getAbsolutePath());
+ p.setPath(tmpkey.toAbsolutePath().toString());
p.setAlgorithm("RSA");
p.loadKeys(); // forces the key to generate.
chmod(0600, tmpkey);
- if (!tmpkey.renameTo(site.ssh_key)) {
- throw die("Cannot rename " + tmpkey + " to " + site.ssh_key);
+ try {
+ Files.move(tmpkey, site.ssh_key);
+ } catch (IOException e) {
+ throw die("Cannot rename " + tmpkey + " to " + site.ssh_key, e);
}
- if (!tmpdir.delete()) {
- throw die("Cannot delete " + tmpdir);
+ try {
+ Files.delete(tmpdir);
+ } catch (IOException e) {
+ throw die("Cannot delete " + tmpdir, e);
}
}
System.err.println(" done");
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/LibraryDownloader.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/LibraryDownloader.java
index 4bf1c88..00c7c58 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/LibraryDownloader.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/LibraryDownloader.java
@@ -15,21 +15,19 @@
package com.google.gerrit.pgm.init;
import com.google.common.base.Strings;
-import com.google.common.io.Files;
+import com.google.common.hash.Funnels;
+import com.google.common.hash.Hasher;
+import com.google.common.hash.Hashing;
+import com.google.common.io.ByteStreams;
import com.google.gerrit.common.Die;
import com.google.gerrit.common.IoUtil;
import com.google.gerrit.pgm.init.api.ConsoleUI;
import com.google.gerrit.server.config.SitePaths;
import com.google.inject.Inject;
-import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.util.HttpSupport;
-import java.io.File;
-import java.io.FileInputStream;
import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -38,15 +36,17 @@
import java.net.ProxySelector;
import java.net.URISyntaxException;
import java.net.URL;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
/** Get optional or required 3rd party library files into $site_path/lib. */
class LibraryDownloader {
private final ConsoleUI ui;
- private final File lib_dir;
+ private final Path lib_dir;
private boolean required;
private String name;
@@ -55,7 +55,7 @@
private String remove;
private List<LibraryDownloader> needs;
private LibraryDownloader neededBy;
- private File dst;
+ private Path dst;
private boolean download; // download or copy
private boolean exists;
@@ -118,8 +118,8 @@
name = jarName;
}
- dst = new File(lib_dir, jarName);
- if (dst.exists()) {
+ dst = lib_dir.resolve(jarName);
+ if (Files.exists(dst)) {
exists = true;
} else if (shouldGet()) {
doGet();
@@ -158,8 +158,12 @@
}
private void doGet() {
- if (!lib_dir.exists() && !lib_dir.mkdirs()) {
- throw new Die("Cannot create " + lib_dir);
+ if (!Files.exists(lib_dir)) {
+ try {
+ Files.createDirectories(lib_dir);
+ } catch (IOException e) {
+ throw new Die("Cannot create " + lib_dir, e);
+ }
}
try {
@@ -171,7 +175,11 @@
}
verifyFileChecksum();
} catch (IOException err) {
- dst.delete();
+ try {
+ Files.delete(dst);
+ } catch (IOException e) {
+ // Delete failed; leave alone.
+ }
if (ui.isBatch()) {
throw new Die("error: Cannot get " + jarUrl, err);
@@ -186,13 +194,13 @@
System.err.println();
System.err.println("and save as:");
System.err.println();
- System.err.println(" " + dst.getAbsolutePath());
+ System.err.println(" " + dst.toAbsolutePath());
System.err.println();
System.err.flush();
ui.waitForUser();
- if (dst.exists()) {
+ if (Files.exists(dst)) {
verifyFileChecksum();
} else if (!ui.yesno(!required, "Continue without this library")) {
@@ -200,7 +208,7 @@
}
}
- if (dst.exists()) {
+ if (Files.exists(dst)) {
exists = true;
IoUtil.loadJARs(dst);
}
@@ -208,131 +216,120 @@
private void removeStaleVersions() {
if (!Strings.isNullOrEmpty(remove)) {
- String[] names = lib_dir.list(new FilenameFilter() {
+ DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<Path>() {
@Override
- public boolean accept(File dir, String name) {
- return name.matches("^" + remove + "$");
+ public boolean accept(Path entry) {
+ return entry.getFileName().toString()
+ .matches("^" + remove + "$");
}
- });
- if (names != null) {
- for (String old : names) {
+ };
+ try (DirectoryStream<Path> paths =
+ Files.newDirectoryStream(lib_dir, filter)) {
+ for (Path p : paths) {
+ String old = p.getFileName().toString();
String bak = "." + old + ".backup";
ui.message("Renaming %s to %s", old, bak);
- if (!new File(lib_dir, old).renameTo(new File(lib_dir, bak))) {
- throw new Die("cannot rename " + old);
+ try {
+ Files.move(p, p.resolveSibling(bak));
+ } catch (IOException e) {
+ throw new Die("cannot rename " + old, e);
}
}
+ } catch (IOException e) {
+ throw new Die("cannot remove stale library versions", e);
}
}
}
private void doGetByLocalCopy() throws IOException {
System.err.print("Copying " + jarUrl + " ...");
- File f = url2file(jarUrl);
- if (!f.exists()) {
+ Path p = url2file(jarUrl);
+ if (!Files.exists(p)) {
StringBuilder msg = new StringBuilder()
.append("\n")
.append("Can not find the %s at this location: %s\n")
.append("Please provide alternative URL");
- f = url2file(ui.readString(null, msg.toString(), name, jarUrl));
+ p = url2file(ui.readString(null, msg.toString(), name, jarUrl));
}
- Files.copy(f, dst);
+ Files.copy(p, dst);
}
- private static File url2file(final String urlString) throws IOException {
+ private static Path url2file(final String urlString) throws IOException {
final URL url = new URL(urlString);
try {
- return new File(url.toURI());
+ return Paths.get(url.toURI());
} catch (URISyntaxException e) {
- return new File(url.getPath());
+ return Paths.get(url.getPath());
}
}
private void doGetByHttp() throws IOException {
System.err.print("Downloading " + jarUrl + " ...");
System.err.flush();
- try {
- final ProxySelector proxySelector = ProxySelector.getDefault();
- final URL url = new URL(jarUrl);
- final Proxy proxy = HttpSupport.proxyFor(proxySelector, url);
- final HttpURLConnection c = (HttpURLConnection) url.openConnection(proxy);
- final InputStream in;
-
- switch (HttpSupport.response(c)) {
- case HttpURLConnection.HTTP_OK:
- in = c.getInputStream();
- break;
-
- case HttpURLConnection.HTTP_NOT_FOUND:
- throw new FileNotFoundException(url.toString());
-
- default:
- throw new IOException(url.toString() + ": " + HttpSupport.response(c)
- + " " + c.getResponseMessage());
- }
-
- try {
- final OutputStream out = new FileOutputStream(dst);
- try {
- final byte[] buf = new byte[8192];
- int n;
- while ((n = in.read(buf)) > 0) {
- out.write(buf, 0, n);
- }
- } finally {
- out.close();
- }
- } finally {
- in.close();
- }
+ try (InputStream in = openHttpStream(jarUrl);
+ OutputStream out = Files.newOutputStream(dst)) {
+ ByteStreams.copy(in, out);
System.err.println(" OK");
System.err.flush();
} catch (IOException err) {
- dst.delete();
+ deleteDst();
System.err.println(" !! FAIL !!");
System.err.flush();
throw err;
}
}
+ private static InputStream openHttpStream(String urlStr) throws IOException {
+ ProxySelector proxySelector = ProxySelector.getDefault();
+ URL url = new URL(urlStr);
+ Proxy proxy = HttpSupport.proxyFor(proxySelector, url);
+ HttpURLConnection c = (HttpURLConnection) url.openConnection(proxy);
+
+ switch (HttpSupport.response(c)) {
+ case HttpURLConnection.HTTP_OK:
+ return c.getInputStream();
+
+ case HttpURLConnection.HTTP_NOT_FOUND:
+ throw new FileNotFoundException(url.toString());
+
+ default:
+ throw new IOException(url.toString() + ": " + HttpSupport.response(c)
+ + " " + c.getResponseMessage());
+ }
+ }
+
private void verifyFileChecksum() {
- if (sha1 != null) {
- try {
- final MessageDigest md = MessageDigest.getInstance("SHA-1");
- final FileInputStream in = new FileInputStream(dst);
- try {
- final byte[] buf = new byte[8192];
- int n;
- while ((n = in.read(buf)) > 0) {
- md.update(buf, 0, n);
- }
- } finally {
- in.close();
- }
+ if (sha1 == null) {
+ return;
+ }
+ Hasher h = Hashing.sha1().newHasher();
+ try (InputStream in = Files.newInputStream(dst);
+ OutputStream out = Funnels.asOutputStream(h)) {
+ ByteStreams.copy(in, out);
+ } catch (IOException e) {
+ deleteDst();
+ throw new Die("cannot checksum " + dst, e);
+ }
+ if (sha1.equals(h.hash().toString())) {
+ System.err.println("Checksum " + dst.getFileName() + " OK");
+ System.err.flush();
+ } else if (ui.isBatch()) {
+ deleteDst();
+ throw new Die(dst + " SHA-1 checksum does not match");
- if (sha1.equals(ObjectId.fromRaw(md.digest()).name())) {
- System.err.println("Checksum " + dst.getName() + " OK");
- System.err.flush();
+ } else if (!ui.yesno(null /* force an answer */,
+ "error: SHA-1 checksum does not match\n" + "Use %s anyway",//
+ dst.getFileName())) {
+ deleteDst();
+ throw new Die("aborted by user");
+ }
+ }
- } else if (ui.isBatch()) {
- dst.delete();
- throw new Die(dst + " SHA-1 checksum does not match");
-
- } else if (!ui.yesno(null /* force an answer */,
- "error: SHA-1 checksum does not match\n" + "Use %s anyway",//
- dst.getName())) {
- dst.delete();
- throw new Die("aborted by user");
- }
-
- } catch (IOException checksumError) {
- dst.delete();
- throw new Die("cannot checksum " + dst, checksumError);
-
- } catch (NoSuchAlgorithmException checksumError) {
- dst.delete();
- throw new Die("cannot checksum " + dst, checksumError);
- }
+ private void deleteDst() {
+ try {
+ Files.delete(dst);
+ } catch (IOException e) {
+ System.err.println(" Failed to clean up lib: " + dst);
}
}
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SecureStoreInitData.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SecureStoreInitData.java
index 8926759..49877dc 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SecureStoreInitData.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SecureStoreInitData.java
@@ -14,13 +14,13 @@
package com.google.gerrit.pgm.init;
-import java.io.File;
+import java.nio.file.Path;
class SecureStoreInitData {
- final File jarFile;
+ final Path jarFile;
final String className;
- SecureStoreInitData(File jar, String className) {
+ SecureStoreInitData(Path jar, String className) {
this.className = className;
this.jarFile = jar;
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java
index 10c9bad..8a227ac 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java
@@ -21,7 +21,7 @@
import static com.google.gerrit.pgm.init.api.InitUtil.savePublic;
import static com.google.gerrit.pgm.init.api.InitUtil.version;
-import com.google.common.io.Files;
+import com.google.gerrit.common.FileUtil;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.pgm.init.api.ConsoleUI;
import com.google.gerrit.pgm.init.api.InitFlags;
@@ -35,8 +35,9 @@
import com.google.inject.Injector;
import com.google.inject.TypeLiteral;
-import java.io.File;
import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
@@ -53,7 +54,7 @@
public SitePathInitializer(final Injector injector, final ConsoleUI ui,
final InitFlags flags, final SitePaths site,
final Section.Factory sectionFactory,
- final @Nullable SecureStoreInitData secureStoreInitData) {
+ @Nullable final SecureStoreInitData secureStoreInitData) {
this.ui = ui;
this.flags = flags;
this.site = site;
@@ -66,12 +67,10 @@
ui.header("Gerrit Code Review %s", version());
if (site.isNew) {
- if (!ui.yesno(true, "Create '%s'", site.site_path.getCanonicalPath())) {
+ if (!ui.yesno(true, "Create '%s'", site.site_path.toAbsolutePath())) {
throw die("aborted by user");
}
- if (!site.site_path.isDirectory() && !site.site_path.mkdirs()) {
- throw die("Cannot make directory " + site.site_path);
- }
+ FileUtil.mkdirsOrDie(site.site_path, "Cannot make directory");
flags.deleteOnFailure = true;
}
@@ -132,7 +131,8 @@
private void saveSecureStore() throws IOException {
if (secureStoreInitData != null) {
- File dst = new File(site.lib_dir, secureStoreInitData.jarFile.getName());
+ Path dst =
+ site.lib_dir.resolve(secureStoreInitData.jarFile.getFileName());
Files.copy(secureStoreInitData.jarFile, dst);
Section gerritSection = sectionFactory.get("gerrit", null);
gerritSection.set("secureStoreClass", secureStoreInitData.className);
@@ -140,7 +140,7 @@
}
private void extractMailExample(String orig) throws Exception {
- File ex = new File(site.mail_dir, orig + ".example");
+ Path ex = site.mail_dir.resolve(orig + ".example");
extract(ex, OutgoingEmail.class, orig);
chmod(0444, ex);
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/UpgradeFrom2_0_x.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/UpgradeFrom2_0_x.java
index 8c13540..21cd3c8 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/UpgradeFrom2_0_x.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/UpgradeFrom2_0_x.java
@@ -30,13 +30,14 @@
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.storage.file.FileBasedConfig;
-import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.URLDecoder;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Map;
import java.util.Properties;
@@ -64,8 +65,8 @@
private final FileBasedConfig cfg;
private final SecureStore sec;
- private final File site_path;
- private final File etc_dir;
+ private final Path site_path;
+ private final Path etc_dir;
private final Section.Factory sections;
@Inject
@@ -82,7 +83,7 @@
boolean isNeedUpgrade() {
for (String name : etcFiles) {
- if (new File(site_path, name).exists()) {
+ if (Files.exists(site_path.resolve(name))) {
return true;
}
}
@@ -95,19 +96,21 @@
return;
}
- if (!ui.yesno(true, "Upgrade '%s'", site_path.getCanonicalPath())) {
+ if (!ui.yesno(true, "Upgrade '%s'", site_path.toAbsolutePath())) {
throw die("aborted by user");
}
for (String name : etcFiles) {
- final File src = new File(site_path, name);
- final File dst = new File(etc_dir, name);
- if (src.exists()) {
- if (dst.exists()) {
+ Path src = site_path.resolve(name);
+ Path dst = etc_dir.resolve(name);
+ if (Files.exists(src)) {
+ if (Files.exists(dst)) {
throw die("File " + src + " would overwrite " + dst);
}
- if (!src.renameTo(dst)) {
- throw die("Cannot rename " + src + " to " + dst);
+ try {
+ Files.move(src, dst);
+ } catch (IOException e) {
+ throw die("Cannot rename " + src + " to " + dst, e);
}
}
}
@@ -256,23 +259,18 @@
private Properties readGerritServerProperties() throws IOException {
final Properties srvprop = new Properties();
final String name = System.getProperty("GerritServer");
- File path;
+ Path path;
if (name != null) {
- path = new File(name);
+ path = Paths.get(name);
} else {
- path = new File(site_path, "GerritServer.properties");
- if (!path.exists()) {
- path = new File("GerritServer.properties");
+ path = site_path.resolve("GerritServer.properties");
+ if (!Files.exists(path)) {
+ path = Paths.get("GerritServer.properties");
}
}
- if (path.exists()) {
- try {
- final InputStream in = new FileInputStream(path);
- try {
- srvprop.load(in);
- } finally {
- in.close();
- }
+ if (Files.exists(path)) {
+ try (InputStream in = Files.newInputStream(path)) {
+ srvprop.load(in);
} catch (IOException e) {
throw new IOException("Cannot read " + name, e);
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/AllProjectsConfig.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/AllProjectsConfig.java
index f45a970..10d93ee 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/AllProjectsConfig.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/AllProjectsConfig.java
@@ -40,6 +40,7 @@
import java.io.File;
import java.io.IOException;
+import java.nio.file.Path;
public class AllProjectsConfig extends VersionedMetaData {
@@ -68,11 +69,11 @@
}
private File getPath() {
- File basePath = site.resolve(flags.cfg.getString("gerrit", null, "basePath"));
+ Path basePath = site.resolve(flags.cfg.getString("gerrit", null, "basePath"));
if (basePath == null) {
throw new IllegalStateException("gerrit.basePath must be configured");
}
- return FileKey.resolve(new File(basePath, project), FS.DETECTED);
+ return FileKey.resolve(basePath.resolve(project).toFile(), FS.DETECTED);
}
public AllProjectsConfig load() throws IOException, ConfigInvalidException {
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/InitFlags.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/InitFlags.java
index 2a8155e..c8f03cc 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/InitFlags.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/InitFlags.java
@@ -47,11 +47,11 @@
@Inject
public InitFlags(final SitePaths site,
final SecureStore secureStore,
- final @InstallPlugins List<String> installPlugins) throws IOException,
+ @InstallPlugins final List<String> installPlugins) throws IOException,
ConfigInvalidException {
sec = secureStore;
this.installPlugins = installPlugins;
- cfg = new FileBasedConfig(site.gerrit_config, FS.DETECTED);
+ cfg = new FileBasedConfig(site.gerrit_config.toFile(), FS.DETECTED);
cfg.load();
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/InitUtil.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/InitUtil.java
index 881208d..904af2f 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/InitUtil.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/InitUtil.java
@@ -16,14 +16,15 @@
import static com.google.gerrit.common.FileUtil.modified;
+import com.google.common.io.ByteStreams;
import com.google.gerrit.common.Die;
import org.eclipse.jgit.internal.storage.file.LockFile;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.util.FS;
-import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.SystemReader;
+import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -33,7 +34,10 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.util.Arrays;
/** Utility functions to help initialize a site. */
public class InitUtil {
@@ -51,9 +55,18 @@
}
}
- public static void mkdir(final File path) {
- if (!path.isDirectory() && !path.mkdir()) {
- throw die("Cannot make directory " + path);
+ public static void mkdir(File file) {
+ mkdir(file.toPath());
+ }
+
+ public static void mkdir(Path path) {
+ if (Files.isDirectory(path)) {
+ return;
+ }
+ try {
+ Files.createDirectory(path);
+ } catch (IOException e) {
+ throw die("Cannot make directory " + path, e);
}
}
@@ -109,12 +122,11 @@
return name;
}
- public static void extract(final File dst, final Class<?> sibling,
- final String name) throws IOException {
+ public static void extract(Path dst, Class<?> sibling, String name)
+ throws IOException {
try (InputStream in = open(sibling, name)) {
if (in != null) {
- ByteBuffer buf = IO.readWholeStream(in, 8192);
- copy(dst, buf);
+ copy(dst, ByteStreams.toByteArray(in));
}
}
}
@@ -136,35 +148,28 @@
return in;
}
- public static void copy(final File dst, final ByteBuffer buf)
+ public static void copy(Path dst, byte[] buf)
throws FileNotFoundException, IOException {
// If the file already has the content we want to put there,
// don't attempt to overwrite the file.
//
- try {
- if (buf.equals(ByteBuffer.wrap(IO.readFully(dst)))) {
+ try (InputStream in = Files.newInputStream(dst)) {
+ if (Arrays.equals(buf, ByteStreams.toByteArray(in))) {
return;
}
- } catch (FileNotFoundException notFound) {
+ } catch (NoSuchFileException notFound) {
// Fall through and write the file.
}
- dst.getParentFile().mkdirs();
- LockFile lf = new LockFile(dst, FS.DETECTED);
+ Files.createDirectories(dst.getParent());
+ LockFile lf = new LockFile(dst.toFile(), FS.DETECTED);
if (!lf.lock()) {
throw new IOException("Cannot lock " + dst);
}
try {
- final OutputStream out = lf.getOutputStream();
- try {
- final byte[] tmp = new byte[4096];
- while (0 < buf.remaining()) {
- int n = Math.min(buf.remaining(), tmp.length);
- buf.get(tmp, 0, n);
- out.write(tmp, 0, n);
- }
- } finally {
- out.close();
+ try (InputStream in = new ByteArrayInputStream(buf);
+ OutputStream out = lf.getOutputStream()) {
+ ByteStreams.copy(in, out);
}
if (!lf.commit()) {
throw new IOException("Cannot commit " + dst);
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/Section.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/Section.java
index fbd8ecd..52b0daa 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/Section.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/Section.java
@@ -20,7 +20,7 @@
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
-import java.io.File;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Set;
@@ -68,10 +68,9 @@
flags.cfg.setStringList(section, subsection, name, all);
}
- } else if (all.size() == 0) {
} else if (all.size() == 1) {
flags.cfg.unset(section, subsection, name);
- } else {
+ } else if (all.size() != 0) {
all.remove(0);
flags.cfg.setStringList(section, subsection, name, all);
}
@@ -106,7 +105,7 @@
return nv;
}
- public File path(final String title, final String name, final String defValue) {
+ public Path path(final String title, final String name, final String defValue) {
return site.resolve(string(title, name, defValue));
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/rules/PrologCompiler.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/rules/PrologCompiler.java
similarity index 80%
rename from gerrit-server/src/main/java/com/google/gerrit/rules/PrologCompiler.java
rename to gerrit-pgm/src/main/java/com/google/gerrit/pgm/rules/PrologCompiler.java
index 4724bc2..ca8b183 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/rules/PrologCompiler.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/rules/PrologCompiler.java
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.rules;
+package com.google.gerrit.pgm.rules;
import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.common.Version;
@@ -22,8 +22,8 @@
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
-import com.googlecode.prolog_cafe.compiler.CompileException;
import com.googlecode.prolog_cafe.compiler.Compiler;
+import com.googlecode.prolog_cafe.exceptions.CompileException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.Config;
@@ -35,8 +35,11 @@
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
import java.net.URL;
import java.net.URLClassLoader;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -67,14 +70,14 @@
NO_RULES, COMPILED
}
- private final File ruleDir;
+ private final Path ruleDir;
private final Repository git;
@Inject
PrologCompiler(@GerritServerConfig Config config, SitePaths site,
@Assisted Repository gitRepository) {
- File cacheDir = site.resolve(config.getString("cache", null, "directory"));
- ruleDir = cacheDir != null ? new File(cacheDir, "rules") : null;
+ Path cacheDir = site.resolve(config.getString("cache", null, "directory"));
+ ruleDir = cacheDir != null ? cacheDir.resolve("rules") : null;
git = gitRepository;
}
@@ -93,9 +96,7 @@
if (ruleDir == null) {
throw new CompileException("Caching not enabled");
}
- if (!ruleDir.isDirectory() && !ruleDir.mkdir()) {
- throw new IOException("Cannot create " + ruleDir);
- }
+ Files.createDirectories(ruleDir);
File tempDir = File.createTempFile("GerritCodeReview_", ".rulec");
if (!tempDir.delete() || !tempDir.mkdir()) {
@@ -111,9 +112,9 @@
compileProlog(rulesId, tempDir);
compileJava(tempDir);
- File jarFile = new File(ruleDir, "rules-" + rulesId.getName() + ".jar");
+ Path jarPath = ruleDir.resolve("rules-" + rulesId.getName() + ".jar");
List<String> classFiles = getRelativePaths(tempDir, ".class");
- createJar(jarFile, classFiles, tempDir, metaConfig, rulesId);
+ createJar(jarPath, classFiles, tempDir, metaConfig, rulesId);
return Status.COMPILED;
} finally {
@@ -222,51 +223,51 @@
}
/** Takes compiled prolog .class files, puts them into the jar file. */
- private void createJar(File archiveFile, List<String> toBeJared,
+ private void createJar(Path archiveFile, List<String> toBeJared,
File tempDir, ObjectId metaConfig, ObjectId rulesId) throws IOException {
long now = TimeUtil.nowMs();
- File tmpjar = File.createTempFile(".rulec_", ".jar", archiveFile.getParentFile());
- try {
- Manifest mf = new Manifest();
- mf.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
- mf.getMainAttributes().putValue("Built-by", "Gerrit Code Review " + Version.getVersion());
- if (git.getDirectory() != null) {
- mf.getMainAttributes().putValue("Source-Repository", git.getDirectory().getPath());
- }
- mf.getMainAttributes().putValue("Source-Commit", metaConfig.name());
- mf.getMainAttributes().putValue("Source-Blob", rulesId.name());
+ Manifest mf = new Manifest();
+ mf.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
+ mf.getMainAttributes().putValue("Built-by", "Gerrit Code Review " + Version.getVersion());
+ if (git.getDirectory() != null) {
+ mf.getMainAttributes().putValue("Source-Repository", git.getDirectory().getPath());
+ }
+ mf.getMainAttributes().putValue("Source-Commit", metaConfig.name());
+ mf.getMainAttributes().putValue("Source-Blob", rulesId.name());
- try (FileOutputStream stream = new FileOutputStream(tmpjar);
- JarOutputStream out = new JarOutputStream(stream, mf)) {
- byte buffer[] = new byte[10240];
- for (String path : toBeJared) {
- JarEntry jarAdd = new JarEntry(path);
- File f = new File(tempDir, path);
- jarAdd.setTime(now);
- out.putNextEntry(jarAdd);
- if (f.isFile()) {
- FileInputStream in = new FileInputStream(f);
- try {
- while (true) {
- int nRead = in.read(buffer, 0, buffer.length);
- if (nRead <= 0) {
- break;
- }
- out.write(buffer, 0, nRead);
+ Path tmpjar =
+ Files.createTempFile(archiveFile.getParent(), ".rulec_", ".jar");
+ try (OutputStream stream = Files.newOutputStream(tmpjar);
+ JarOutputStream out = new JarOutputStream(stream, mf)) {
+ byte[] buffer = new byte[10240];
+ // TODO: fixify this loop
+ for (String path : toBeJared) {
+ JarEntry jarAdd = new JarEntry(path);
+ File f = new File(tempDir, path);
+ jarAdd.setTime(now);
+ out.putNextEntry(jarAdd);
+ if (f.isFile()) {
+ FileInputStream in = new FileInputStream(f);
+ try {
+ while (true) {
+ int nRead = in.read(buffer, 0, buffer.length);
+ if (nRead <= 0) {
+ break;
}
- } finally {
- in.close();
+ out.write(buffer, 0, nRead);
}
+ } finally {
+ in.close();
}
- out.closeEntry();
}
+ out.closeEntry();
}
+ }
- if (!tmpjar.renameTo(archiveFile)) {
- throw new IOException("Cannot replace " + archiveFile);
- }
- } finally {
- tmpjar.delete();
+ try {
+ Files.move(tmpjar, archiveFile);
+ } catch (IOException e) {
+ throw new IOException("Cannot replace " + archiveFile, e);
}
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/BatchProgramModule.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/BatchProgramModule.java
index 23983b7..60d4acc 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/BatchProgramModule.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/BatchProgramModule.java
@@ -87,6 +87,7 @@
install(reviewDbModule);
install(new DiffExecutorModule());
install(PatchListCacheImpl.module());
+
// Plugins are not loaded and we're just running through each change
// once, so don't worry about cache removal.
bind(new TypeLiteral<DynamicSet<CacheRemovalListener>>() {})
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/ErrorLogFile.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/ErrorLogFile.java
index a766d1e..ee0a0e6 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/ErrorLogFile.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/ErrorLogFile.java
@@ -14,22 +14,26 @@
package com.google.gerrit.pgm.util;
-import com.google.gerrit.common.Die;
+import com.google.gerrit.common.FileUtil;
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.util.SystemLog;
+import net.logstash.log4j.JSONEventLayoutV1;
+
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
+import org.eclipse.jgit.lib.Config;
-import java.io.File;
-import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.file.Path;
public class ErrorLogFile {
static final String LOG_NAME = "error_log";
+ static final String JSON_SUFFIX = ".json";
public static void errorOnlyConsole() {
LogManager.resetConfiguration();
@@ -47,14 +51,12 @@
root.addAppender(dst);
}
- public static LifecycleListener start(final File sitePath)
- throws FileNotFoundException {
- final File logdir = new SitePaths(sitePath).logs_dir;
- if (!logdir.exists() && !logdir.mkdirs()) {
- throw new Die("Cannot create log directory: " + logdir);
- }
+ public static LifecycleListener start(final Path sitePath, final Config config)
+ throws IOException {
+ Path logdir = FileUtil.mkdirsOrDie(new SitePaths(sitePath).logs_dir,
+ "Cannot create log directory");
if (SystemLog.shouldConfigure()) {
- initLogSystem(logdir);
+ initLogSystem(logdir, config);
}
return new LifecycleListener() {
@@ -69,10 +71,21 @@
};
}
- private static void initLogSystem(final File logdir) {
+ private static void initLogSystem(Path logdir, Config config) {
final Logger root = LogManager.getRootLogger();
root.removeAllAppenders();
- root.addAppender(SystemLog.createAppender(logdir, LOG_NAME,
- new PatternLayout("[%d] %-5p %c %x: %m%n")));
+
+ boolean json = config.getBoolean("log", "jsonLogging", false);
+ boolean text = config.getBoolean("log", "textLogging", true) || !json;
+
+ if (text) {
+ root.addAppender(SystemLog.createAppender(logdir, LOG_NAME,
+ new PatternLayout("[%d] %-5p %c %x: %m%n")));
+ }
+
+ if (json) {
+ root.addAppender(SystemLog.createAppender(logdir, LOG_NAME + JSON_SUFFIX,
+ new JSONEventLayoutV1()));
+ }
}
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/LogFileCompressor.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/LogFileCompressor.java
index db74ac3..1107208 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/LogFileCompressor.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/LogFileCompressor.java
@@ -16,6 +16,7 @@
import static java.util.concurrent.TimeUnit.HOURS;
+import com.google.common.io.ByteStreams;
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.gerrit.server.config.SitePaths;
@@ -25,12 +26,12 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.zip.GZIPOutputStream;
/** Compresses the old error logs. */
@@ -65,76 +66,78 @@
}
}
- private final File logs_dir;
+ private final Path logs_dir;
@Inject
LogFileCompressor(final SitePaths site) {
logs_dir = resolve(site.logs_dir);
}
- private static File resolve(final File logs_dir) {
+ private static Path resolve(Path p) {
try {
- return logs_dir.getCanonicalFile();
+ return p.toRealPath().normalize();
} catch (IOException e) {
- return logs_dir.getAbsoluteFile();
+ return p.toAbsolutePath().normalize();
}
}
@Override
public void run() {
- final File[] list = logs_dir.listFiles();
- if (list == null) {
+ if (!Files.isDirectory(logs_dir)) {
return;
}
-
- for (final File entry : list) {
- if (!isLive(entry) && !isCompressed(entry) && isLogFile(entry)) {
- compress(entry);
+ try (DirectoryStream<Path> list = Files.newDirectoryStream(logs_dir)) {
+ for (Path entry : list) {
+ if (!isLive(entry) && !isCompressed(entry) && isLogFile(entry)) {
+ compress(entry);
+ }
}
+ } catch (IOException e) {
+ log.error("Error listing logs to compress in " + logs_dir, e);
}
}
- private boolean isLive(final File entry) {
- final String name = entry.getName();
+ private boolean isLive(Path entry) {
+ String name = entry.getFileName().toString();
return name.endsWith("_log")
|| name.endsWith(".log")
|| name.endsWith(".run")
|| name.endsWith(".pid");
}
- private boolean isCompressed(final File entry) {
- final String name = entry.getName();
+ private boolean isCompressed(Path entry) {
+ String name = entry.getFileName().toString();
return name.endsWith(".gz") //
|| name.endsWith(".zip") //
|| name.endsWith(".bz2");
}
- private boolean isLogFile(final File entry) {
- return entry.isFile();
+ private boolean isLogFile(Path entry) {
+ return Files.isRegularFile(entry);
}
- private void compress(final File src) {
- final File dir = src.getParentFile();
- final File dst = new File(dir, src.getName() + ".gz");
- final File tmp = new File(dir, ".tmp." + src.getName());
+ private void compress(Path src) {
+ Path dst = src.resolveSibling(src.getFileName() + ".gz");
+ Path tmp = src.resolveSibling(".tmp." + src.getFileName());
try {
- try (InputStream in = new FileInputStream(src);
- FileOutputStream fo = new FileOutputStream(tmp);
- OutputStream out = new GZIPOutputStream(fo)) {
- final byte[] buf = new byte[2048];
- int n;
- while (0 < (n = in.read(buf))) {
- out.write(buf, 0, n);
- }
- tmp.setReadOnly();
+ try (InputStream in = Files.newInputStream(src);
+ OutputStream out = new GZIPOutputStream(Files.newOutputStream(tmp))) {
+ ByteStreams.copy(in, out);
}
- if (!tmp.renameTo(dst)) {
- throw new IOException("Cannot rename " + tmp + " to " + dst);
+ tmp.toFile().setReadOnly();
+ try {
+ Files.move(tmp, dst);
+ } catch (IOException e) {
+ throw new IOException("Cannot rename " + tmp + " to " + dst, e);
}
- src.delete();
+ Files.delete(src);
} catch (IOException e) {
log.error("Cannot compress " + src, e);
- tmp.delete();
+ try {
+ Files.deleteIfExists(tmp);
+ } catch (IOException e2) {
+ log.warn("Failed to delete temporary log file " + tmp, e2);
+ }
}
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteLibraryBasedDataSourceProvider.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteLibraryBasedDataSourceProvider.java
index c713b79..048c2ee 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteLibraryBasedDataSourceProvider.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteLibraryBasedDataSourceProvider.java
@@ -24,14 +24,14 @@
import org.eclipse.jgit.lib.Config;
-import java.io.File;
+import java.nio.file.Path;
import javax.sql.DataSource;
/** Loads the site library if not yet loaded. */
@Singleton
public class SiteLibraryBasedDataSourceProvider extends DataSourceProvider {
- private final File libdir;
+ private final Path libdir;
private boolean init;
@Inject
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteProgram.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteProgram.java
index 9763b1a..6eb313e 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteProgram.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteProgram.java
@@ -50,8 +50,10 @@
import org.eclipse.jgit.lib.Config;
import org.kohsuke.args4j.Option;
-import java.io.File;
import java.lang.annotation.Annotation;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
@@ -61,30 +63,30 @@
public abstract class SiteProgram extends AbstractProgram {
@Option(name = "--site-path", aliases = {"-d"}, usage = "Local directory containing site data")
- private File sitePath = new File(".");
+ private void setSitePath(String path) {
+ sitePath = Paths.get(path);
+ }
protected Provider<DataSource> dsProvider;
+ private Path sitePath = Paths.get(".");
+
protected SiteProgram() {
}
- protected SiteProgram(File sitePath, final Provider<DataSource> dsProvider) {
+ protected SiteProgram(Path sitePath, final Provider<DataSource> dsProvider) {
this.sitePath = sitePath;
this.dsProvider = dsProvider;
}
/** @return the site path specified on the command line. */
- protected File getSitePath() {
- File path = sitePath.getAbsoluteFile();
- if (".".equals(path.getName())) {
- path = path.getParentFile();
- }
- return path;
+ protected Path getSitePath() {
+ return sitePath;
}
/** Ensures we are running inside of a valid site, otherwise throws a Die. */
protected void mustHaveValidSite() throws Die {
- if (!new File(new File(getSitePath(), "etc"), "gerrit.config").exists()) {
+ if (!Files.exists(sitePath.resolve("etc").resolve("gerrit.config"))) {
throw die("not a Gerrit site: '" + getSitePath() + "'\n"
+ "Perhaps you need to run init first?");
}
@@ -92,13 +94,13 @@
/** @return provides database connectivity and site path. */
protected Injector createDbInjector(final DataSourceProvider.Context context) {
- final File sitePath = getSitePath();
+ final Path sitePath = getSitePath();
final List<Module> modules = new ArrayList<>();
Module sitePathModule = new AbstractModule() {
@Override
protected void configure() {
- bind(File.class).annotatedWith(SitePath.class).toInstance(sitePath);
+ bind(Path.class).annotatedWith(SitePath.class).toInstance(sitePath);
bind(String.class).annotatedWith(SecureStoreClassName.class)
.toProvider(Providers.of(getConfiguredSecureStoreClass()));
}
@@ -198,7 +200,7 @@
modules.add(new AbstractModule() {
@Override
protected void configure() {
- bind(File.class).annotatedWith(SitePath.class).toInstance(sitePath);
+ bind(Path.class).annotatedWith(SitePath.class).toInstance(getSitePath());
}
});
modules.add(new GerritServerConfigModule());
diff --git a/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/InitTestCase.java b/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/InitTestCase.java
index 4d7370b..150309e 100644
--- a/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/InitTestCase.java
+++ b/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/InitTestCase.java
@@ -16,11 +16,11 @@
import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
-import java.io.File;
import java.io.IOException;
+import java.nio.file.Path;
public abstract class InitTestCase extends LocalDiskRepositoryTestCase {
- protected File newSitePath() throws IOException {
- return new File(createWorkRepository().getWorkTree(), "test_site");
+ protected Path newSitePath() throws IOException {
+ return createWorkRepository().getWorkTree().toPath().resolve("test_site");
}
}
diff --git a/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/LibrariesTest.java b/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/LibrariesTest.java
index a37c97d..2198788 100644
--- a/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/LibrariesTest.java
+++ b/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/LibrariesTest.java
@@ -25,13 +25,12 @@
import org.junit.Test;
-import java.io.File;
-import java.io.FileNotFoundException;
+import java.nio.file.Paths;
public class LibrariesTest {
@Test
- public void testCreate() throws FileNotFoundException {
- final SitePaths site = new SitePaths(new File("."));
+ public void testCreate() throws Exception {
+ final SitePaths site = new SitePaths(Paths.get("."));
final ConsoleUI ui = createStrictMock(ConsoleUI.class);
replay(ui);
diff --git a/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/UpgradeFrom2_0_xTest.java b/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/UpgradeFrom2_0_xTest.java
index 720d108..dc7ce59 100644
--- a/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/UpgradeFrom2_0_xTest.java
+++ b/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/UpgradeFrom2_0_xTest.java
@@ -14,6 +14,7 @@
package com.google.gerrit.pgm.init;
+import static java.nio.charset.StandardCharsets.UTF_8;
import static org.easymock.EasyMock.createStrictMock;
import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.expect;
@@ -24,6 +25,8 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import com.google.common.io.ByteStreams;
+import com.google.gerrit.common.FileUtil;
import com.google.gerrit.pgm.init.api.ConsoleUI;
import com.google.gerrit.pgm.init.api.InitFlags;
import com.google.gerrit.pgm.init.api.Section;
@@ -34,13 +37,12 @@
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.util.FS;
-import org.eclipse.jgit.util.IO;
import org.junit.Test;
-import java.io.File;
-import java.io.FileWriter;
import java.io.IOException;
-import java.io.Writer;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
@@ -49,23 +51,17 @@
@Test
public void testUpgrade() throws IOException, ConfigInvalidException {
- final File p = newSitePath();
+ final Path p = newSitePath();
final SitePaths site = new SitePaths(p);
assertTrue(site.isNew);
- assertTrue(site.site_path.mkdir());
- assertTrue(site.etc_dir.mkdir());
+ FileUtil.mkdirsOrDie(site.etc_dir, "Failed to create");
for (String n : UpgradeFrom2_0_x.etcFiles) {
- Writer w = new FileWriter(new File(p, n));
- try {
- w.write("# " + n + "\n");
- } finally {
- w.close();
- }
+ Files.write(p.resolve(n), ("# " + n + "\n").getBytes(UTF_8));
}
FileBasedConfig old =
- new FileBasedConfig(new File(p, "gerrit.config"), FS.DETECTED);
+ new FileBasedConfig(p.resolve("gerrit.config").toFile(), FS.DETECTED);
old.setString("ldap", null, "username", "ldap.user");
old.setString("ldap", null, "password", "ldap.s3kr3t");
@@ -85,8 +81,11 @@
}
};
- expect(ui.yesno(eq(true), eq("Upgrade '%s'"), eq(p.getCanonicalPath())))
- .andReturn(true);
+ expect(ui.yesno(
+ eq(true),
+ eq("Upgrade '%s'"),
+ eq(p.toAbsolutePath().normalize())))
+ .andReturn(true);
replay(ui);
UpgradeFrom2_0_x u = new UpgradeFrom2_0_x(site, flags, ui, sections);
@@ -96,13 +95,17 @@
verify(ui);
for (String n : UpgradeFrom2_0_x.etcFiles) {
- if ("gerrit.config".equals(n)) continue;
- if ("secure.config".equals(n)) continue;
- assertEquals("# " + n + "\n",//
- new String(IO.readFully(new File(site.etc_dir, n)), "UTF-8"));
+ if ("gerrit.config".equals(n) || "secure.config".equals(n)) {
+ continue;
+ }
+ try (InputStream in = Files.newInputStream(site.etc_dir.resolve(n))) {
+ assertEquals("# " + n + "\n",
+ new String(ByteStreams.toByteArray(in), UTF_8));
+ }
}
- FileBasedConfig cfg = new FileBasedConfig(site.gerrit_config, FS.DETECTED);
+ FileBasedConfig cfg =
+ new FileBasedConfig(site.gerrit_config.toFile(), FS.DETECTED);
cfg.load();
assertEquals("email.user", cfg.getString("sendemail", null, "smtpUser"));
diff --git a/gerrit-plugin-api/pom.xml b/gerrit-plugin-api/pom.xml
index 17cf79a..eb2ec31 100644
--- a/gerrit-plugin-api/pom.xml
+++ b/gerrit-plugin-api/pom.xml
@@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-plugin-api</artifactId>
- <version>2.11.1</version>
+ <version>2.12-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Gerrit Code Review - Plugin API</name>
<description>API for Gerrit Plugins</description>
diff --git a/gerrit-plugin-archetype/pom.xml b/gerrit-plugin-archetype/pom.xml
index 8f9684a..1da5d51 100644
--- a/gerrit-plugin-archetype/pom.xml
+++ b/gerrit-plugin-archetype/pom.xml
@@ -20,7 +20,7 @@
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-plugin-archetype</artifactId>
- <version>2.11.1</version>
+ <version>2.12-SNAPSHOT</version>
<name>Gerrit Code Review - Plugin Archetype</name>
<description>Maven Archetype for Gerrit Plugins</description>
<url>http://code.google.com/p/gerrit/</url>
diff --git a/gerrit-plugin-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.ui.prefs b/gerrit-plugin-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.ui.prefs
index d4218a5..7397758 100644
--- a/gerrit-plugin-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.ui.prefs
+++ b/gerrit-plugin-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.ui.prefs
@@ -1,10 +1,9 @@
-#Wed Jul 29 11:31:38 PDT 2009
eclipse.preferences.version=1
editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
formatter_profile=_Google Format
formatter_settings_version=11
org.eclipse.jdt.ui.ignorelowercasenames=true
-org.eclipse.jdt.ui.importorder=com.google;com;junit;net;org;java;javax;
+org.eclipse.jdt.ui.importorder=\#;com.google;com;dk;eu;junit;net;org;java;javax;
org.eclipse.jdt.ui.ondemandthreshold=99
org.eclipse.jdt.ui.staticondemandthreshold=99
org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates/>
diff --git a/gerrit-plugin-gwt-archetype/pom.xml b/gerrit-plugin-gwt-archetype/pom.xml
index f384bc1..bd4d738 100644
--- a/gerrit-plugin-gwt-archetype/pom.xml
+++ b/gerrit-plugin-gwt-archetype/pom.xml
@@ -20,7 +20,7 @@
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-plugin-gwt-archetype</artifactId>
- <version>2.11.1</version>
+ <version>2.12-SNAPSHOT</version>
<name>Gerrit Code Review - Web UI GWT Plugin Archetype</name>
<description>Maven Archetype for Gerrit Web UI GWT Plugins</description>
<url>http://code.google.com/p/gerrit/</url>
diff --git a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.ui.prefs b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.ui.prefs
index d4218a5..7397758 100644
--- a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.ui.prefs
+++ b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.ui.prefs
@@ -1,10 +1,9 @@
-#Wed Jul 29 11:31:38 PDT 2009
eclipse.preferences.version=1
editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
formatter_profile=_Google Format
formatter_settings_version=11
org.eclipse.jdt.ui.ignorelowercasenames=true
-org.eclipse.jdt.ui.importorder=com.google;com;junit;net;org;java;javax;
+org.eclipse.jdt.ui.importorder=\#;com.google;com;dk;eu;junit;net;org;java;javax;
org.eclipse.jdt.ui.ondemandthreshold=99
org.eclipse.jdt.ui.staticondemandthreshold=99
org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates/>
diff --git a/gerrit-plugin-gwtui/pom.xml b/gerrit-plugin-gwtui/pom.xml
index e4fc192..fa261be 100644
--- a/gerrit-plugin-gwtui/pom.xml
+++ b/gerrit-plugin-gwtui/pom.xml
@@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-plugin-gwtui</artifactId>
- <version>2.11.1</version>
+ <version>2.12-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Gerrit Code Review - Plugin GWT UI</name>
<description>Common Classes for Gerrit GWT UI Plugins</description>
diff --git a/gerrit-plugin-js-archetype/pom.xml b/gerrit-plugin-js-archetype/pom.xml
index 559d9de..11d4d83 100644
--- a/gerrit-plugin-js-archetype/pom.xml
+++ b/gerrit-plugin-js-archetype/pom.xml
@@ -20,7 +20,7 @@
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-plugin-js-archetype</artifactId>
- <version>2.11.1</version>
+ <version>2.12-SNAPSHOT</version>
<name>Gerrit Code Review - Web UI JavaScript Plugin Archetype</name>
<description>Maven Archetype for Gerrit Web UI JavaScript Plugins</description>
<url>http://code.google.com/p/gerrit/</url>
diff --git a/gerrit-plugin-js-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.ui.prefs b/gerrit-plugin-js-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.ui.prefs
index d4218a5..7397758 100644
--- a/gerrit-plugin-js-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.ui.prefs
+++ b/gerrit-plugin-js-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.ui.prefs
@@ -1,10 +1,9 @@
-#Wed Jul 29 11:31:38 PDT 2009
eclipse.preferences.version=1
editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
formatter_profile=_Google Format
formatter_settings_version=11
org.eclipse.jdt.ui.ignorelowercasenames=true
-org.eclipse.jdt.ui.importorder=com.google;com;junit;net;org;java;javax;
+org.eclipse.jdt.ui.importorder=\#;com.google;com;dk;eu;junit;net;org;java;javax;
org.eclipse.jdt.ui.ondemandthreshold=99
org.eclipse.jdt.ui.staticondemandthreshold=99
org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates/>
diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/PrettyFormatter.gwt.xml b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/PrettyFormatter.gwt.xml
index 48591f8..fd88f6c 100644
--- a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/PrettyFormatter.gwt.xml
+++ b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/PrettyFormatter.gwt.xml
@@ -14,10 +14,9 @@
limitations under the License.
-->
<module>
- <replace-with class='com.google.gerrit.prettify.client.PrivateScopeImplIE6'>
+ <replace-with class='com.google.gerrit.prettify.client.PrivateScopeImplIE8'>
<when-type-is class='com.google.gerrit.prettify.client.PrivateScopeImpl'/>
<any>
- <when-property-is name="user.agent" value="ie6" />
<when-property-is name="user.agent" value="ie8" />
</any>
</replace-with>
diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrivateScopeImplIE6.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrivateScopeImplIE8.java
similarity index 90%
rename from gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrivateScopeImplIE6.java
rename to gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrivateScopeImplIE8.java
index abb4e15..0496d91 100644
--- a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrivateScopeImplIE6.java
+++ b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrivateScopeImplIE8.java
@@ -16,8 +16,8 @@
import com.google.gwt.core.client.JavaScriptObject;
-/** IE6 requires us to initialize the document before we can use it. */
-public class PrivateScopeImplIE6 extends PrivateScopeImpl {
+/** MSIE requires us to initialize the document before we can use it. */
+public class PrivateScopeImplIE8 extends PrivateScopeImpl {
private JavaScriptObject context;
@Override
diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/EditList.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/EditList.java
index 6a42a8e..ec5c78d8 100644
--- a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/EditList.java
+++ b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/EditList.java
@@ -68,8 +68,9 @@
private int findCombinedEnd(final int i) {
int end = i + 1;
- while (end < edits.size() && (combineA(end) || combineB(end)))
+ while (end < edits.size() && (combineA(end) || combineB(end))) {
end++;
+ }
return end - 1;
}
diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/SparseFileContent.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/SparseFileContent.java
index b6e3bf9..a57146f 100644
--- a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/SparseFileContent.java
+++ b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/SparseFileContent.java
@@ -130,10 +130,11 @@
return size();
}
- if (idx < cur.base)
+ if (idx < cur.base) {
high = mid;
- else
+ } else {
low = mid + 1;
+ }
} while (low < high);
return size();
@@ -183,10 +184,11 @@
currentRangeIdx = mid;
return cur.get(idx);
}
- if (idx < cur.base)
+ if (idx < cur.base) {
high = mid;
- else
+ } else {
low = mid + 1;
+ }
} while (low < high);
return null;
}
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Account.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Account.java
index d4fb311..2750380 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Account.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Account.java
@@ -14,7 +14,7 @@
package com.google.gerrit.reviewdb.client;
-import static com.google.gerrit.reviewdb.client.RefNames.REFS_USER;
+import static com.google.gerrit.reviewdb.client.RefNames.REFS_USERS;
import com.google.gwtorm.client.Column;
import com.google.gwtorm.client.IntKey;
@@ -111,8 +111,8 @@
if (name == null) {
return null;
}
- if (name.startsWith(REFS_USER)) {
- return fromRefPart(name.substring(REFS_USER.length()));
+ if (name.startsWith(REFS_USERS)) {
+ return fromRefPart(name.substring(REFS_USERS.length()));
}
return null;
}
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Branch.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Branch.java
index e1a15e5..3f04306 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Branch.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Branch.java
@@ -19,9 +19,6 @@
/** Line of development within a {@link Project}. */
public final class Branch {
- public static final String R_HEADS = "refs/heads/";
- public static final String R_REFS = "refs/";
-
/** Branch name key */
public static class NameKey extends StringKey<Project.NameKey> {
private static final long serialVersionUID = 1L;
@@ -36,9 +33,9 @@
projectName = new Project.NameKey();
}
- public NameKey(final Project.NameKey proj, final String n) {
+ public NameKey(final Project.NameKey proj, final String branchName) {
projectName = proj;
- branchName = n;
+ set(branchName);
}
@Override
@@ -48,7 +45,7 @@
@Override
protected void set(String newValue) {
- branchName = newValue;
+ branchName = RefNames.fullName(newValue);
}
@Override
@@ -57,15 +54,7 @@
}
public String getShortName() {
- final String n = get();
-
- // Git style branches will tend to start with "refs/heads/".
- //
- if (n.startsWith(R_HEADS)) {
- return n.substring(R_HEADS.length());
- }
-
- return n;
+ return RefNames.shortName(get());
}
}
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchSet.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchSet.java
index 48623bd..4ec957e 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchSet.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchSet.java
@@ -20,6 +20,8 @@
import com.google.gwtorm.client.IntKey;
import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.List;
/** A single revision of a {@link Change}. */
public final class PatchSet {
@@ -28,6 +30,41 @@
return Id.fromRef(name) != null;
}
+ public static String joinGroups(Iterable<String> groups) {
+ if (groups == null) {
+ return null;
+ }
+ StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ for (String g : groups) {
+ if (!first) {
+ sb.append(',');
+ } else {
+ first = false;
+ }
+ sb.append(g);
+ }
+ return sb.toString();
+ }
+
+ public static List<String> splitGroups(String joinedGroups) {
+ if (joinedGroups == null) {
+ return null;
+ }
+ List<String> groups = new ArrayList<>();
+ int i = 0;
+ while (true) {
+ int idx = joinedGroups.indexOf(',', i);
+ if (idx < 0) {
+ groups.add(joinedGroups.substring(i, joinedGroups.length()));
+ break;
+ }
+ groups.add(joinedGroups.substring(i, idx));
+ i = idx + 1;
+ }
+ return groups;
+ }
+
public static class Id extends IntKey<Change.Id> {
private static final long serialVersionUID = 1L;
@@ -140,6 +177,18 @@
@Column(id = 5)
protected boolean draft;
+ /**
+ * Opaque group identifier, usually assigned during creation.
+ * <p>
+ * This field is actually a comma-separated list of values, as in rare cases
+ * involving merge commits a patch set may belong to multiple groups.
+ * <p>
+ * Changes on the same branch having patch sets with intersecting groups are
+ * considered related, as in the "Related Changes" tab.
+ */
+ @Column(id = 6, notNull = false)
+ protected String groups;
+
protected PatchSet() {
}
@@ -187,6 +236,14 @@
draft = draftStatus;
}
+ public List<String> getGroups() {
+ return splitGroups(groups);
+ }
+
+ public void setGroups(Iterable<String> groups) {
+ this.groups = joinGroups(groups);
+ }
+
public String getRefName() {
return id.toRefName();
}
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/RefNames.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/RefNames.java
index 072982a..4154913 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/RefNames.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/RefNames.java
@@ -17,6 +17,10 @@
/** Constants and utilities for Gerrit-specific ref names. */
public class RefNames {
+ public static final String REFS = "refs/";
+
+ public static final String REFS_HEADS = "refs/heads/";
+
public static final String REFS_CHANGES = "refs/changes/";
/** Note tree listing commits we refuse {@code refs/meta/reject-commits} */
@@ -26,7 +30,10 @@
public static final String REFS_CONFIG = "refs/meta/config";
/** Preference settings for a user {@code refs/users} */
- public static final String REFS_USER = "refs/users/";
+ public static final String REFS_USERS = "refs/users/";
+
+ /** Default user preference settings */
+ public static final String REFS_USERS_DEFAULT = RefNames.REFS_USERS + "default";
/** Configurations of project-specific dashboards (canned search queries). */
public static final String REFS_DASHBOARDS = "refs/meta/dashboards/";
@@ -48,9 +55,19 @@
/** Suffix of a meta ref in the notedb. */
public static final String META_SUFFIX = "/meta";
+ public static String fullName(String ref) {
+ return (ref.startsWith(REFS) ? "" : REFS_HEADS) + ref;
+ }
+
+ public static final String shortName(String ref) {
+ return ref.startsWith(REFS_HEADS)
+ ? ref.substring(REFS_HEADS.length())
+ : ref;
+ }
+
public static String refsUsers(Account.Id accountId) {
StringBuilder r = new StringBuilder();
- r.append(REFS_USER);
+ r.append(REFS_USERS);
int account = accountId.get();
int m = account % 100;
if (m < 10) {
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/RevId.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/RevId.java
index 1a64ee7..a73fe5d 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/RevId.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/RevId.java
@@ -64,4 +64,9 @@
public boolean equals(Object o) {
return (o instanceof RevId) && id.equals(((RevId) o).id);
}
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "{" + id + "}";
+ }
}
diff --git a/gerrit-reviewdb/src/test/java/com/google/gerrit/reviewdb/client/PatchSetTest.java b/gerrit-reviewdb/src/test/java/com/google/gerrit/reviewdb/client/PatchSetTest.java
index 33da24a..87e5b88 100644
--- a/gerrit-reviewdb/src/test/java/com/google/gerrit/reviewdb/client/PatchSetTest.java
+++ b/gerrit-reviewdb/src/test/java/com/google/gerrit/reviewdb/client/PatchSetTest.java
@@ -14,10 +14,11 @@
package com.google.gerrit.reviewdb.client;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.reviewdb.client.PatchSet.joinGroups;
+import static com.google.gerrit.reviewdb.client.PatchSet.splitGroups;
+
+import com.google.common.collect.ImmutableList;
import org.junit.Test;
@@ -62,14 +63,34 @@
assertNotRef("refs/changes/34/1234foo");
}
+ @Test
+ public void testSplitGroups() {
+ assertThat(splitGroups(null)).isNull();
+ assertThat(splitGroups("")).containsExactly("");
+ assertThat(splitGroups("abcd")).containsExactly("abcd");
+ assertThat(splitGroups("ab,cd")).containsExactly("ab", "cd").inOrder();
+ assertThat(splitGroups("ab,")).containsExactly("ab", "").inOrder();
+ assertThat(splitGroups(",cd")).containsExactly("", "cd").inOrder();
+ }
+
+ @Test
+ public void testJoinGroups() {
+ assertThat(joinGroups(null)).isNull();
+ assertThat(joinGroups(ImmutableList.of(""))).isEqualTo("");
+ assertThat(joinGroups(ImmutableList.of("abcd"))).isEqualTo("abcd");
+ assertThat(joinGroups(ImmutableList.of("ab", "cd"))).isEqualTo("ab,cd");
+ assertThat(joinGroups(ImmutableList.of("ab", ""))).isEqualTo("ab,");
+ assertThat(joinGroups(ImmutableList.of("", "cd"))).isEqualTo(",cd");
+ }
+
private static void assertRef(int changeId, int psId, String refName) {
- assertTrue(PatchSet.isRef(refName));
- assertEquals(new PatchSet.Id(new Change.Id(changeId), psId),
- PatchSet.Id.fromRef(refName));
+ assertThat(PatchSet.isRef(refName)).isTrue();
+ assertThat(PatchSet.Id.fromRef(refName))
+ .isEqualTo(new PatchSet.Id(new Change.Id(changeId), psId));
}
private static void assertNotRef(String refName) {
- assertFalse(PatchSet.isRef(refName));
- assertNull(PatchSet.Id.fromRef(refName));
+ assertThat(PatchSet.isRef(refName)).isFalse();
+ assertThat(PatchSet.Id.fromRef(refName)).isNull();
}
}
diff --git a/gerrit-reviewdb/src/test/java/com/google/gerrit/reviewdb/client/RefNamesTest.java b/gerrit-reviewdb/src/test/java/com/google/gerrit/reviewdb/client/RefNamesTest.java
new file mode 100644
index 0000000..b0981a7
--- /dev/null
+++ b/gerrit-reviewdb/src/test/java/com/google/gerrit/reviewdb/client/RefNamesTest.java
@@ -0,0 +1,50 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.reviewdb.client;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+
+public class RefNamesTest {
+ private final Account.Id accountId = new Account.Id(1011123);
+ private final Change.Id changeId = new Change.Id(67473);
+ private final PatchSet.Id psId = new PatchSet.Id(changeId, 42);
+
+ @Test
+ public void fullName() throws Exception {
+ assertThat(RefNames.fullName("refs/meta/config")).isEqualTo("refs/meta/config");
+ assertThat(RefNames.fullName("refs/heads/master")).isEqualTo("refs/heads/master");
+ assertThat(RefNames.fullName("master")).isEqualTo("refs/heads/master");
+ assertThat(RefNames.fullName("refs/tags/v1.0")).isEqualTo("refs/tags/v1.0");
+ }
+
+ @Test
+ public void refsUsers() throws Exception {
+ assertThat(RefNames.refsUsers(accountId)).isEqualTo("refs/users/23/1011123");
+ }
+
+ @Test
+ public void refsDraftComments() throws Exception {
+ assertThat(RefNames.refsDraftComments(accountId, changeId))
+ .isEqualTo("refs/draft-comments/23/1011123-67473");
+ }
+
+ @Test
+ public void refsEdit() throws Exception {
+ assertThat(RefNames.refsEdit(accountId, changeId, psId))
+ .isEqualTo("refs/users/23/1011123/edit-67473/42");
+ }
+}
diff --git a/gerrit-server/BUCK b/gerrit-server/BUCK
index 7202dc3..5cda4dd 100644
--- a/gerrit-server/BUCK
+++ b/gerrit-server/BUCK
@@ -48,6 +48,7 @@
'//lib/antlr:java_runtime',
'//lib/auto:auto-value',
'//lib/commons:codec',
+ '//lib/commons:compress',
'//lib/commons:dbcp',
'//lib/commons:lang',
'//lib/commons:net',
@@ -59,6 +60,7 @@
'//lib/jgit:jgit-archive',
'//lib/joda:joda-time',
'//lib/log:api',
+ '//lib/log:jsonevent-layout',
'//lib/log:log4j',
'//lib/lucene:analyzers-common',
'//lib/lucene:core',
@@ -66,7 +68,7 @@
'//lib/ow2:ow2-asm',
'//lib/ow2:ow2-asm-tree',
'//lib/ow2:ow2-asm-util',
- '//lib/prolog:prolog-cafe',
+ '//lib/prolog:runtime',
],
provided_deps = [
'//lib:servlet-api-3_1',
@@ -94,16 +96,19 @@
':server',
'//gerrit-common:server',
'//gerrit-cache-h2:cache-h2',
+ '//gerrit-extension-api:api',
'//gerrit-lucene:lucene',
'//gerrit-reviewdb:server',
'//lib:guava',
'//lib:gwtorm',
'//lib:h2',
'//lib:junit',
+ '//lib/auto:auto-value',
'//lib/guice:guice',
'//lib/guice:guice-servlet',
'//lib/jgit:jgit',
'//lib/jgit:junit',
+ '//lib/log:api',
'//lib/log:impl_log4j',
'//lib/log:log4j',
],
@@ -134,7 +139,7 @@
'//gerrit-common:server',
'//lib:junit',
'//lib/guice:guice',
- '//lib/prolog:prolog-cafe',
+ '//lib/prolog:runtime',
],
)
@@ -155,7 +160,7 @@
'//lib:truth',
'//lib/jgit:jgit',
'//lib/guice:guice',
- '//lib/prolog:prolog-cafe',
+ '//lib/prolog:runtime',
],
)
@@ -217,7 +222,7 @@
'//lib/joda:joda-time',
'//lib:parboiled-core',
'//lib:parboiled-java',
- '//lib/prolog:prolog-cafe',
+ '//lib/prolog:runtime',
],
source_under_test = [':server'],
visibility = ['//tools/eclipse:classpath'],
diff --git a/gerrit-server/src/main/java/com/google/gerrit/audit/AuditEvent.java b/gerrit-server/src/main/java/com/google/gerrit/audit/AuditEvent.java
index e25b7cb..14f12b8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/audit/AuditEvent.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/audit/AuditEvent.java
@@ -79,9 +79,15 @@
@Override
public boolean equals(Object obj) {
- if (this == obj) return true;
- if (obj == null) return false;
- if (getClass() != obj.getClass()) return false;
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
AuditEvent other = (AuditEvent) obj;
return this.uuid.equals(other.uuid);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/audit/ExtendedHttpAuditEvent.java b/gerrit-server/src/main/java/com/google/gerrit/audit/ExtendedHttpAuditEvent.java
new file mode 100644
index 0000000..78fe38c
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/audit/ExtendedHttpAuditEvent.java
@@ -0,0 +1,55 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.audit;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Multimap;
+import com.google.gerrit.extensions.restapi.RestResource;
+import com.google.gerrit.extensions.restapi.RestView;
+import com.google.gerrit.server.CurrentUser;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * Extended audit event. Adds request, resource and view data to HttpAuditEvent.
+ */
+public class ExtendedHttpAuditEvent extends HttpAuditEvent {
+ public final HttpServletRequest httpRequest;
+ public final RestResource resource;
+ public final RestView<? extends RestResource> view;
+
+ /**
+ * Creates a new audit event with results
+ *
+ * @param sessionId session id the event belongs to
+ * @param who principal that has generated the event
+ * @param httpRequest the HttpServletRequest
+ * @param when time-stamp of when the event started
+ * @param params parameters of the event
+ * @param result result of the event
+ * @param resource REST resource data
+ * @param view view rendering object
+ */
+ public ExtendedHttpAuditEvent(String sessionId, CurrentUser who,
+ HttpServletRequest httpRequest, long when, Multimap<String, ?> params,
+ Object input, int status, Object result, RestResource resource,
+ RestView<RestResource> view) {
+ super(sessionId, who, httpRequest.getRequestURI(), when, params, httpRequest.getMethod(),
+ input, status, result);
+ this.httpRequest = Preconditions.checkNotNull(httpRequest);
+ this.resource = resource;
+ this.view = view;
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHookRunner.java b/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHookRunner.java
index 8bd082d..19c3145 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHookRunner.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHookRunner.java
@@ -14,13 +14,13 @@
package com.google.gerrit.common;
-import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.google.gerrit.common.data.ContributorAgreement;
import com.google.gerrit.common.data.LabelType;
import com.google.gerrit.common.data.LabelTypes;
import com.google.gerrit.extensions.events.LifecycleListener;
+import com.google.gerrit.extensions.events.NewProjectCreatedListener;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.gerrit.reviewdb.client.Account;
@@ -41,11 +41,11 @@
import com.google.gerrit.server.events.ChangeRestoredEvent;
import com.google.gerrit.server.events.CommentAddedEvent;
import com.google.gerrit.server.events.DraftPublishedEvent;
-import com.google.gerrit.server.events.Event;
import com.google.gerrit.server.events.EventFactory;
import com.google.gerrit.server.events.HashtagsChangedEvent;
import com.google.gerrit.server.events.MergeFailedEvent;
import com.google.gerrit.server.events.PatchSetCreatedEvent;
+import com.google.gerrit.server.events.ProjectCreatedEvent;
import com.google.gerrit.server.events.RefUpdatedEvent;
import com.google.gerrit.server.events.ReviewerAddedEvent;
import com.google.gerrit.server.events.TopicChangedEvent;
@@ -66,12 +66,14 @@
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
-import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.io.StringWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -88,7 +90,7 @@
/** Spawns local executables when a hook action occurs. */
@Singleton
public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
- EventSource, LifecycleListener {
+ EventSource, LifecycleListener, NewProjectCreatedListener {
/** A logger for this class. */
private static final Logger log = LoggerFactory.getLogger(ChangeHookRunner.class);
@@ -99,18 +101,19 @@
bind(ChangeHooks.class).to(ChangeHookRunner.class);
bind(EventDispatcher.class).to(ChangeHookRunner.class);
bind(EventSource.class).to(ChangeHookRunner.class);
+ DynamicSet.bind(binder(), NewProjectCreatedListener.class).to(ChangeHookRunner.class);
listener().to(ChangeHookRunner.class);
}
}
private static class EventListenerHolder {
- final EventListener listener;
- final CurrentUser user;
+ final EventListener listener;
+ final CurrentUser user;
- EventListenerHolder(EventListener l, CurrentUser u) {
- listener = l;
- user = u;
- }
+ EventListenerHolder(EventListener l, CurrentUser u) {
+ listener = l;
+ user = u;
+ }
}
/** Container class used to hold the return code and output of script hook execution */
@@ -169,44 +172,47 @@
/** Listeners to receive all changes as they happen. */
private final DynamicSet<EventListener> unrestrictedListeners;
- /** Filename of the new patchset hook. */
- private final File patchsetCreatedHook;
+ /** Path of the new patchset hook. */
+ private final Path patchsetCreatedHook;
- /** Filename of the draft published hook. */
- private final File draftPublishedHook;
+ /** Path of the draft published hook. */
+ private final Path draftPublishedHook;
- /** Filename of the new comments hook. */
- private final File commentAddedHook;
+ /** Path of the new comments hook. */
+ private final Path commentAddedHook;
- /** Filename of the change merged hook. */
- private final File changeMergedHook;
+ /** Path of the change merged hook. */
+ private final Path changeMergedHook;
- /** Filename of the merge failed hook. */
- private final File mergeFailedHook;
+ /** Path of the merge failed hook. */
+ private final Path mergeFailedHook;
- /** Filename of the change abandoned hook. */
- private final File changeAbandonedHook;
+ /** Path of the change abandoned hook. */
+ private final Path changeAbandonedHook;
- /** Filename of the change restored hook. */
- private final File changeRestoredHook;
+ /** Path of the change restored hook. */
+ private final Path changeRestoredHook;
- /** Filename of the ref updated hook. */
- private final File refUpdatedHook;
+ /** Path of the ref updated hook. */
+ private final Path refUpdatedHook;
- /** Filename of the reviewer added hook. */
- private final File reviewerAddedHook;
+ /** Path of the reviewer added hook. */
+ private final Path reviewerAddedHook;
- /** Filename of the topic changed hook. */
- private final File topicChangedHook;
+ /** Path of the topic changed hook. */
+ private final Path topicChangedHook;
- /** Filename of the cla signed hook. */
- private final File claSignedHook;
+ /** Path of the cla signed hook. */
+ private final Path claSignedHook;
- /** Filename of the update hook. */
- private final File refUpdateHook;
+ /** Path of the update hook. */
+ private final Path refUpdateHook;
- /** Filename of the hashtags changed hook */
- private final File hashtagsChangedHook;
+ /** Path of the hashtags changed hook */
+ private final Path hashtagsChangedHook;
+
+ /** Path of the project created hook. */
+ private final Path projectCreatedHook;
private final String anonymousCowardName;
@@ -240,15 +246,15 @@
* @param projectCache the project cache instance for the server.
*/
@Inject
- public ChangeHookRunner(final WorkQueue queue,
- final GitRepositoryManager repoManager,
- final @GerritServerConfig Config config,
- final @AnonymousCowardName String anonymousCowardName,
- final SitePaths sitePath,
- final ProjectCache projectCache,
- final AccountCache accountCache,
- final EventFactory eventFactory,
- final DynamicSet<EventListener> unrestrictedListeners) {
+ public ChangeHookRunner(WorkQueue queue,
+ GitRepositoryManager repoManager,
+ @GerritServerConfig Config config,
+ @AnonymousCowardName String anonymousCowardName,
+ SitePaths sitePath,
+ ProjectCache projectCache,
+ AccountCache accountCache,
+ EventFactory eventFactory,
+ DynamicSet<EventListener> unrestrictedListeners) {
this.anonymousCowardName = anonymousCowardName;
this.repoManager = repoManager;
this.hookQueue = queue.createQueue(1, "hook");
@@ -258,21 +264,31 @@
this.sitePaths = sitePath;
this.unrestrictedListeners = unrestrictedListeners;
- final File hooksPath = sitePath.resolve(getValue(config, "hooks", "path", sitePath.hooks_dir.getAbsolutePath()));
+ Path hooksPath;
+ String hooksPathConfig = config.getString("hooks", null, "path");
+ if (hooksPathConfig != null) {
+ hooksPath = Paths.get(hooksPathConfig);
+ } else {
+ hooksPath = sitePath.hooks_dir;
+ }
- patchsetCreatedHook = sitePath.resolve(new File(hooksPath, getValue(config, "hooks", "patchsetCreatedHook", "patchset-created")).getPath());
- draftPublishedHook = sitePath.resolve(new File(hooksPath, getValue(config, "hooks", "draftPublishedHook", "draft-published")).getPath());
- commentAddedHook = sitePath.resolve(new File(hooksPath, getValue(config, "hooks", "commentAddedHook", "comment-added")).getPath());
- changeMergedHook = sitePath.resolve(new File(hooksPath, getValue(config, "hooks", "changeMergedHook", "change-merged")).getPath());
- mergeFailedHook = sitePath.resolve(new File(hooksPath, getValue(config, "hooks", "mergeFailedHook", "merge-failed")).getPath());
- changeAbandonedHook = sitePath.resolve(new File(hooksPath, getValue(config, "hooks", "changeAbandonedHook", "change-abandoned")).getPath());
- changeRestoredHook = sitePath.resolve(new File(hooksPath, getValue(config, "hooks", "changeRestoredHook", "change-restored")).getPath());
- refUpdatedHook = sitePath.resolve(new File(hooksPath, getValue(config, "hooks", "refUpdatedHook", "ref-updated")).getPath());
- reviewerAddedHook = sitePath.resolve(new File(hooksPath, getValue(config, "hooks", "reviewerAddedHook", "reviewer-added")).getPath());
- topicChangedHook = sitePath.resolve(new File(hooksPath, getValue(config, "hooks", "topicChangedHook", "topic-changed")).getPath());
- claSignedHook = sitePath.resolve(new File(hooksPath, getValue(config, "hooks", "claSignedHook", "cla-signed")).getPath());
- refUpdateHook = sitePath.resolve(new File(hooksPath, getValue(config, "hooks", "refUpdateHook", "ref-update")).getPath());
- hashtagsChangedHook = sitePath.resolve(new File(hooksPath, getValue(config, "hooks", "hashtagsChangedHook", "hashtags-changed")).getPath());
+ // When adding a new hook, make sure to check that the setting name
+ // canonicalizes correctly in hook() below.
+ patchsetCreatedHook = hook(config, hooksPath, "patchset-created");
+ draftPublishedHook = hook(config, hooksPath, "draft-published");
+ commentAddedHook = hook(config, hooksPath, "comment-added");
+ changeMergedHook = hook(config, hooksPath, "change-merged");
+ mergeFailedHook = hook(config, hooksPath, "merge-failed");
+ changeAbandonedHook = hook(config, hooksPath, "change-abandoned");
+ changeRestoredHook = hook(config, hooksPath, "change-restored");
+ refUpdatedHook = hook(config, hooksPath, "ref-updated");
+ reviewerAddedHook = hook(config, hooksPath, "reviewer-added");
+ topicChangedHook = hook(config, hooksPath, "topic-changed");
+ claSignedHook = hook(config, hooksPath, "cla-signed");
+ refUpdateHook = hook(config, hooksPath, "ref-update");
+ hashtagsChangedHook = hook(config, hooksPath, "hashtags-changed");
+ projectCreatedHook = hook(config, hooksPath, "project-created");
+
syncHookTimeout = config.getInt("hooks", "syncHookTimeout", 30);
syncHookThreadPool = Executors.newCachedThreadPool(
new ThreadFactoryBuilder()
@@ -280,28 +296,20 @@
.build());
}
+ private static Path hook(Config config, Path path, String name) {
+ String setting = name.replace("-", "") + "hook";
+ String value = config.getString("hooks", null, setting);
+ return path.resolve(value != null ? value : name);
+ }
+
@Override
public void addEventListener(EventListener listener, CurrentUser user) {
- listeners.put(listener, new EventListenerHolder(listener, user));
+ listeners.put(listener, new EventListenerHolder(listener, user));
}
@Override
public void removeEventListener(EventListener listener) {
- listeners.remove(listener);
- }
-
- /**
- * Helper Method for getting values from the config.
- *
- * @param config Config file to get value from.
- * @param section Section to look in.
- * @param setting Setting to get.
- * @param fallback Fallback value.
- * @return Setting value if found, else fallback.
- */
- private String getValue(final Config config, final String section, final String setting, final String fallback) {
- final String result = config.getString(section, null, setting);
- return Strings.isNullOrEmpty(result) ? fallback : result;
+ listeners.remove(listener);
}
/**
@@ -310,20 +318,20 @@
* @param name Project to get repo for,
* @return Repository or null.
*/
- private Repository openRepository(final Project.NameKey name) {
- try {
- return repoManager.openRepository(name);
- } catch (IOException err) {
- log.warn("Cannot open repository " + name.get(), err);
- return null;
- }
+ private Repository openRepository(Project.NameKey name) {
+ try {
+ return repoManager.openRepository(name);
+ } catch (IOException err) {
+ log.warn("Cannot open repository " + name.get(), err);
+ return null;
+ }
}
private void addArg(List<String> args, String name, String value) {
- if (value != null) {
- args.add(name);
- args.add(value);
- }
+ if (value != null) {
+ args.add(name);
+ args.add(value);
+ }
}
/**
@@ -331,10 +339,10 @@
*
*/
@Override
- public HookResult doRefUpdateHook(final Project project, final String refname,
- final Account uploader, final ObjectId oldId, final ObjectId newId) {
+ public HookResult doRefUpdateHook(Project project, String refname,
+ Account uploader, ObjectId oldId, ObjectId newId) {
- final List<String> args = new ArrayList<>();
+ List<String> args = new ArrayList<>();
addArg(args, "--project", project.getName());
addArg(args, "--refname", refname);
addArg(args, "--uploader", getDisplayName(uploader));
@@ -344,6 +352,20 @@
return runSyncHook(project.getNameKey(), refUpdateHook, args);
}
+ @Override
+ public void doProjectCreatedHook(Project.NameKey project, String headName) {
+ ProjectCreatedEvent event = new ProjectCreatedEvent();
+ event.projectName = project.get();
+ event.headName = headName;
+ fireEvent(project, event);
+
+ List<String> args = new ArrayList<>();
+ addArg(args, "--project", project.get());
+ addArg(args, "--head", headName);
+
+ runHook(project, projectCreatedHook, args);
+ }
+
/**
* Fire the Patchset Created Hook.
*
@@ -352,219 +374,222 @@
* @throws OrmException
*/
@Override
- public void doPatchsetCreatedHook(final Change change, final PatchSet patchSet,
- final ReviewDb db) throws OrmException {
- final PatchSetCreatedEvent event = new PatchSetCreatedEvent();
- final AccountState uploader = accountCache.get(patchSet.getUploader());
- final AccountState owner = accountCache.get(change.getOwner());
+ public void doPatchsetCreatedHook(Change change, PatchSet patchSet,
+ ReviewDb db) throws OrmException {
+ PatchSetCreatedEvent event = new PatchSetCreatedEvent();
+ AccountState uploader = accountCache.get(patchSet.getUploader());
+ AccountState owner = accountCache.get(change.getOwner());
- event.change = eventFactory.asChangeAttribute(change);
- event.patchSet = eventFactory.asPatchSetAttribute(patchSet);
- event.uploader = eventFactory.asAccountAttribute(uploader.getAccount());
- fireEvent(change, event, db);
+ event.change = eventFactory.asChangeAttribute(change);
+ event.patchSet = eventFactory.asPatchSetAttribute(patchSet);
+ event.uploader = eventFactory.asAccountAttribute(uploader.getAccount());
+ fireEvent(change, event, db);
- final List<String> args = new ArrayList<>();
- addArg(args, "--change", event.change.id);
- addArg(args, "--is-draft", String.valueOf(patchSet.isDraft()));
- addArg(args, "--kind", String.valueOf(event.patchSet.kind));
- addArg(args, "--change-url", event.change.url);
- addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
- addArg(args, "--project", event.change.project);
- addArg(args, "--branch", event.change.branch);
- addArg(args, "--topic", event.change.topic);
- addArg(args, "--uploader", getDisplayName(uploader.getAccount()));
- addArg(args, "--commit", event.patchSet.revision);
- addArg(args, "--patchset", event.patchSet.number);
+ List<String> args = new ArrayList<>();
+ addArg(args, "--change", event.change.id);
+ addArg(args, "--is-draft", String.valueOf(patchSet.isDraft()));
+ addArg(args, "--kind", String.valueOf(event.patchSet.kind));
+ addArg(args, "--change-url", event.change.url);
+ addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
+ addArg(args, "--project", event.change.project);
+ addArg(args, "--branch", event.change.branch);
+ addArg(args, "--topic", event.change.topic);
+ addArg(args, "--uploader", getDisplayName(uploader.getAccount()));
+ addArg(args, "--commit", event.patchSet.revision);
+ addArg(args, "--patchset", event.patchSet.number);
- runHook(change.getProject(), patchsetCreatedHook, args);
+ runHook(change.getProject(), patchsetCreatedHook, args);
}
@Override
- public void doDraftPublishedHook(final Change change, final PatchSet patchSet,
- final ReviewDb db) throws OrmException {
- final DraftPublishedEvent event = new DraftPublishedEvent();
- final AccountState uploader = accountCache.get(patchSet.getUploader());
- final AccountState owner = accountCache.get(change.getOwner());
+ public void doDraftPublishedHook(Change change, PatchSet patchSet,
+ ReviewDb db) throws OrmException {
+ DraftPublishedEvent event = new DraftPublishedEvent();
+ AccountState uploader = accountCache.get(patchSet.getUploader());
+ AccountState owner = accountCache.get(change.getOwner());
- event.change = eventFactory.asChangeAttribute(change);
- event.patchSet = eventFactory.asPatchSetAttribute(patchSet);
- event.uploader = eventFactory.asAccountAttribute(uploader.getAccount());
- fireEvent(change, event, db);
+ event.change = eventFactory.asChangeAttribute(change);
+ event.patchSet = eventFactory.asPatchSetAttribute(patchSet);
+ event.uploader = eventFactory.asAccountAttribute(uploader.getAccount());
+ fireEvent(change, event, db);
- final List<String> args = new ArrayList<>();
- addArg(args, "--change", event.change.id);
- addArg(args, "--change-url", event.change.url);
- addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
- addArg(args, "--project", event.change.project);
- addArg(args, "--branch", event.change.branch);
- addArg(args, "--topic", event.change.topic);
- addArg(args, "--uploader", getDisplayName(uploader.getAccount()));
- addArg(args, "--commit", event.patchSet.revision);
- addArg(args, "--patchset", event.patchSet.number);
+ List<String> args = new ArrayList<>();
+ addArg(args, "--change", event.change.id);
+ addArg(args, "--change-url", event.change.url);
+ addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
+ addArg(args, "--project", event.change.project);
+ addArg(args, "--branch", event.change.branch);
+ addArg(args, "--topic", event.change.topic);
+ addArg(args, "--uploader", getDisplayName(uploader.getAccount()));
+ addArg(args, "--commit", event.patchSet.revision);
+ addArg(args, "--patchset", event.patchSet.number);
- runHook(change.getProject(), draftPublishedHook, args);
+ runHook(change.getProject(), draftPublishedHook, args);
}
@Override
- public void doCommentAddedHook(final Change change, final Account account,
- final PatchSet patchSet, final String comment, final Map<String, Short> approvals,
- final ReviewDb db) throws OrmException {
- final CommentAddedEvent event = new CommentAddedEvent();
- final AccountState owner = accountCache.get(change.getOwner());
+ public void doCommentAddedHook(Change change, Account account,
+ PatchSet patchSet, String comment, Map<String, Short> approvals,
+ ReviewDb db) throws OrmException {
+ CommentAddedEvent event = new CommentAddedEvent();
+ AccountState owner = accountCache.get(change.getOwner());
- event.change = eventFactory.asChangeAttribute(change);
- event.author = eventFactory.asAccountAttribute(account);
- event.patchSet = eventFactory.asPatchSetAttribute(patchSet);
- event.comment = comment;
+ event.change = eventFactory.asChangeAttribute(change);
+ event.author = eventFactory.asAccountAttribute(account);
+ event.patchSet = eventFactory.asPatchSetAttribute(patchSet);
+ event.comment = comment;
- LabelTypes labelTypes = projectCache.get(change.getProject()).getLabelTypes();
- if (approvals.size() > 0) {
- event.approvals = new ApprovalAttribute[approvals.size()];
- int i = 0;
- for (Map.Entry<String, Short> approval : approvals.entrySet()) {
- event.approvals[i++] = getApprovalAttribute(labelTypes, approval);
- }
- }
-
- fireEvent(change, event, db);
-
- final List<String> args = new ArrayList<>();
- addArg(args, "--change", event.change.id);
- addArg(args, "--is-draft", patchSet.isDraft() ? "true" : "false");
- addArg(args, "--change-url", event.change.url);
- addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
- addArg(args, "--project", event.change.project);
- addArg(args, "--branch", event.change.branch);
- addArg(args, "--topic", event.change.topic);
- addArg(args, "--author", getDisplayName(account));
- addArg(args, "--commit", event.patchSet.revision);
- addArg(args, "--comment", comment == null ? "" : comment);
+ LabelTypes labelTypes = projectCache.get(change.getProject()).getLabelTypes();
+ if (approvals.size() > 0) {
+ event.approvals = new ApprovalAttribute[approvals.size()];
+ int i = 0;
for (Map.Entry<String, Short> approval : approvals.entrySet()) {
- LabelType lt = labelTypes.byLabel(approval.getKey());
- if (lt != null) {
- addArg(args, "--" + lt.getName(), Short.toString(approval.getValue()));
- }
+ event.approvals[i++] = getApprovalAttribute(labelTypes, approval);
}
+ }
- runHook(change.getProject(), commentAddedHook, args);
+ fireEvent(change, event, db);
+
+ List<String> args = new ArrayList<>();
+ addArg(args, "--change", event.change.id);
+ addArg(args, "--is-draft", patchSet.isDraft() ? "true" : "false");
+ addArg(args, "--change-url", event.change.url);
+ addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
+ addArg(args, "--project", event.change.project);
+ addArg(args, "--branch", event.change.branch);
+ addArg(args, "--topic", event.change.topic);
+ addArg(args, "--author", getDisplayName(account));
+ addArg(args, "--commit", event.patchSet.revision);
+ addArg(args, "--comment", comment == null ? "" : comment);
+ for (Map.Entry<String, Short> approval : approvals.entrySet()) {
+ LabelType lt = labelTypes.byLabel(approval.getKey());
+ if (lt != null) {
+ addArg(args, "--" + lt.getName(), Short.toString(approval.getValue()));
+ }
+ }
+
+ runHook(change.getProject(), commentAddedHook, args);
}
@Override
- public void doChangeMergedHook(final Change change, final Account account,
- final PatchSet patchSet, final ReviewDb db, String mergeResultRev)
- throws OrmException {
- final ChangeMergedEvent event = new ChangeMergedEvent();
- final AccountState owner = accountCache.get(change.getOwner());
+ public void doChangeMergedHook(Change change, Account account,
+ PatchSet patchSet, ReviewDb db, String mergeResultRev)
+ throws OrmException {
+ ChangeMergedEvent event = new ChangeMergedEvent();
+ AccountState owner = accountCache.get(change.getOwner());
- event.change = eventFactory.asChangeAttribute(change);
- event.submitter = eventFactory.asAccountAttribute(account);
- event.patchSet = eventFactory.asPatchSetAttribute(patchSet);
- event.newRev = mergeResultRev;
- fireEvent(change, event, db);
+ event.change = eventFactory.asChangeAttribute(change);
+ event.submitter = eventFactory.asAccountAttribute(account);
+ event.patchSet = eventFactory.asPatchSetAttribute(patchSet);
+ event.newRev = mergeResultRev;
+ fireEvent(change, event, db);
- final List<String> args = new ArrayList<>();
- addArg(args, "--change", event.change.id);
- addArg(args, "--change-url", event.change.url);
- addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
- addArg(args, "--project", event.change.project);
- addArg(args, "--branch", event.change.branch);
- addArg(args, "--topic", event.change.topic);
- addArg(args, "--submitter", getDisplayName(account));
- addArg(args, "--commit", event.patchSet.revision);
- addArg(args, "--newrev", mergeResultRev);
+ List<String> args = new ArrayList<>();
+ addArg(args, "--change", event.change.id);
+ addArg(args, "--change-url", event.change.url);
+ addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
+ addArg(args, "--project", event.change.project);
+ addArg(args, "--branch", event.change.branch);
+ addArg(args, "--topic", event.change.topic);
+ addArg(args, "--submitter", getDisplayName(account));
+ addArg(args, "--commit", event.patchSet.revision);
+ addArg(args, "--newrev", mergeResultRev);
- runHook(change.getProject(), changeMergedHook, args);
+ runHook(change.getProject(), changeMergedHook, args);
}
@Override
- public void doMergeFailedHook(final Change change, final Account account,
- final PatchSet patchSet, final String reason,
- final ReviewDb db) throws OrmException {
- final MergeFailedEvent event = new MergeFailedEvent();
- final AccountState owner = accountCache.get(change.getOwner());
+ public void doMergeFailedHook(Change change, Account account,
+ PatchSet patchSet, String reason,
+ ReviewDb db) throws OrmException {
+ MergeFailedEvent event = new MergeFailedEvent();
+ AccountState owner = accountCache.get(change.getOwner());
- event.change = eventFactory.asChangeAttribute(change);
- event.submitter = eventFactory.asAccountAttribute(account);
- event.patchSet = eventFactory.asPatchSetAttribute(patchSet);
- event.reason = reason;
- fireEvent(change, event, db);
+ event.change = eventFactory.asChangeAttribute(change);
+ event.submitter = eventFactory.asAccountAttribute(account);
+ event.patchSet = eventFactory.asPatchSetAttribute(patchSet);
+ event.reason = reason;
+ fireEvent(change, event, db);
- final List<String> args = new ArrayList<>();
- addArg(args, "--change", event.change.id);
- addArg(args, "--change-url", event.change.url);
- addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
- addArg(args, "--project", event.change.project);
- addArg(args, "--branch", event.change.branch);
- addArg(args, "--topic", event.change.topic);
- addArg(args, "--submitter", getDisplayName(account));
- addArg(args, "--commit", event.patchSet.revision);
- addArg(args, "--reason", reason == null ? "" : reason);
+ List<String> args = new ArrayList<>();
+ addArg(args, "--change", event.change.id);
+ addArg(args, "--change-url", event.change.url);
+ addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
+ addArg(args, "--project", event.change.project);
+ addArg(args, "--branch", event.change.branch);
+ addArg(args, "--topic", event.change.topic);
+ addArg(args, "--submitter", getDisplayName(account));
+ addArg(args, "--commit", event.patchSet.revision);
+ addArg(args, "--reason", reason == null ? "" : reason);
- runHook(change.getProject(), mergeFailedHook, args);
+ runHook(change.getProject(), mergeFailedHook, args);
}
@Override
- public void doChangeAbandonedHook(final Change change, final Account account,
- final PatchSet patchSet, final String reason, final ReviewDb db)
+ public void doChangeAbandonedHook(Change change, Account account,
+ PatchSet patchSet, String reason, ReviewDb db)
throws OrmException {
- final ChangeAbandonedEvent event = new ChangeAbandonedEvent();
- final AccountState owner = accountCache.get(change.getOwner());
+ ChangeAbandonedEvent event = new ChangeAbandonedEvent();
+ AccountState owner = accountCache.get(change.getOwner());
- event.change = eventFactory.asChangeAttribute(change);
- event.abandoner = eventFactory.asAccountAttribute(account);
- event.patchSet = eventFactory.asPatchSetAttribute(patchSet);
- event.reason = reason;
- fireEvent(change, event, db);
+ event.change = eventFactory.asChangeAttribute(change);
+ event.abandoner = eventFactory.asAccountAttribute(account);
+ event.patchSet = eventFactory.asPatchSetAttribute(patchSet);
+ event.reason = reason;
+ fireEvent(change, event, db);
- final List<String> args = new ArrayList<>();
- addArg(args, "--change", event.change.id);
- addArg(args, "--change-url", event.change.url);
- addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
- addArg(args, "--project", event.change.project);
- addArg(args, "--branch", event.change.branch);
- addArg(args, "--topic", event.change.topic);
- addArg(args, "--abandoner", getDisplayName(account));
- addArg(args, "--commit", event.patchSet.revision);
- addArg(args, "--reason", reason == null ? "" : reason);
+ List<String> args = new ArrayList<>();
+ addArg(args, "--change", event.change.id);
+ addArg(args, "--change-url", event.change.url);
+ addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
+ addArg(args, "--project", event.change.project);
+ addArg(args, "--branch", event.change.branch);
+ addArg(args, "--topic", event.change.topic);
+ addArg(args, "--abandoner", getDisplayName(account));
+ addArg(args, "--commit", event.patchSet.revision);
+ addArg(args, "--reason", reason == null ? "" : reason);
- runHook(change.getProject(), changeAbandonedHook, args);
+ runHook(change.getProject(), changeAbandonedHook, args);
}
@Override
- public void doChangeRestoredHook(final Change change, final Account account,
- final PatchSet patchSet, final String reason, final ReviewDb db)
+ public void doChangeRestoredHook(Change change, Account account,
+ PatchSet patchSet, String reason, ReviewDb db)
throws OrmException {
- final ChangeRestoredEvent event = new ChangeRestoredEvent();
- final AccountState owner = accountCache.get(change.getOwner());
+ ChangeRestoredEvent event = new ChangeRestoredEvent();
+ AccountState owner = accountCache.get(change.getOwner());
- event.change = eventFactory.asChangeAttribute(change);
- event.restorer = eventFactory.asAccountAttribute(account);
- event.patchSet = eventFactory.asPatchSetAttribute(patchSet);
- event.reason = reason;
- fireEvent(change, event, db);
+ event.change = eventFactory.asChangeAttribute(change);
+ event.restorer = eventFactory.asAccountAttribute(account);
+ event.patchSet = eventFactory.asPatchSetAttribute(patchSet);
+ event.reason = reason;
+ fireEvent(change, event, db);
- final List<String> args = new ArrayList<>();
- addArg(args, "--change", event.change.id);
- addArg(args, "--change-url", event.change.url);
- addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
- addArg(args, "--project", event.change.project);
- addArg(args, "--branch", event.change.branch);
- addArg(args, "--topic", event.change.topic);
- addArg(args, "--restorer", getDisplayName(account));
- addArg(args, "--commit", event.patchSet.revision);
- addArg(args, "--reason", reason == null ? "" : reason);
+ List<String> args = new ArrayList<>();
+ addArg(args, "--change", event.change.id);
+ addArg(args, "--change-url", event.change.url);
+ addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
+ addArg(args, "--project", event.change.project);
+ addArg(args, "--branch", event.change.branch);
+ addArg(args, "--topic", event.change.topic);
+ addArg(args, "--restorer", getDisplayName(account));
+ addArg(args, "--commit", event.patchSet.revision);
+ addArg(args, "--reason", reason == null ? "" : reason);
- runHook(change.getProject(), changeRestoredHook, args);
+ runHook(change.getProject(), changeRestoredHook, args);
}
@Override
- public void doRefUpdatedHook(final Branch.NameKey refName, final RefUpdate refUpdate, final Account account) {
- doRefUpdatedHook(refName, refUpdate.getOldObjectId(), refUpdate.getNewObjectId(), account);
+ public void doRefUpdatedHook(Branch.NameKey refName, RefUpdate refUpdate,
+ Account account) {
+ doRefUpdatedHook(refName, refUpdate.getOldObjectId(),
+ refUpdate.getNewObjectId(), account);
}
@Override
- public void doRefUpdatedHook(final Branch.NameKey refName, final ObjectId oldId, final ObjectId newId, final Account account) {
- final RefUpdatedEvent event = new RefUpdatedEvent();
+ public void doRefUpdatedHook(Branch.NameKey refName, ObjectId oldId,
+ ObjectId newId, Account account) {
+ RefUpdatedEvent event = new RefUpdatedEvent();
if (account != null) {
event.submitter = eventFactory.asAccountAttribute(account);
@@ -572,7 +597,7 @@
event.refUpdate = eventFactory.asRefUpdateAttribute(oldId, newId, refName);
fireEvent(refName, event);
- final List<String> args = new ArrayList<>();
+ List<String> args = new ArrayList<>();
addArg(args, "--oldrev", event.refUpdate.oldRev);
addArg(args, "--newrev", event.refUpdate.newRev);
addArg(args, "--refname", event.refUpdate.refName);
@@ -585,17 +610,17 @@
}
@Override
- public void doReviewerAddedHook(final Change change, final Account account,
- final PatchSet patchSet, final ReviewDb db) throws OrmException {
- final ReviewerAddedEvent event = new ReviewerAddedEvent();
- final AccountState owner = accountCache.get(change.getOwner());
+ public void doReviewerAddedHook(Change change, Account account,
+ PatchSet patchSet, ReviewDb db) throws OrmException {
+ ReviewerAddedEvent event = new ReviewerAddedEvent();
+ AccountState owner = accountCache.get(change.getOwner());
event.change = eventFactory.asChangeAttribute(change);
event.patchSet = eventFactory.asPatchSetAttribute(patchSet);
event.reviewer = eventFactory.asAccountAttribute(account);
fireEvent(change, event, db);
- final List<String> args = new ArrayList<>();
+ List<String> args = new ArrayList<>();
addArg(args, "--change", event.change.id);
addArg(args, "--change-url", event.change.url);
addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
@@ -607,18 +632,18 @@
}
@Override
- public void doTopicChangedHook(final Change change, final Account account,
- final String oldTopic, final ReviewDb db)
+ public void doTopicChangedHook(Change change, Account account,
+ String oldTopic, ReviewDb db)
throws OrmException {
- final TopicChangedEvent event = new TopicChangedEvent();
- final AccountState owner = accountCache.get(change.getOwner());
+ TopicChangedEvent event = new TopicChangedEvent();
+ AccountState owner = accountCache.get(change.getOwner());
event.change = eventFactory.asChangeAttribute(change);
event.changer = eventFactory.asAccountAttribute(account);
event.oldTopic = oldTopic;
fireEvent(change, event, db);
- final List<String> args = new ArrayList<>();
+ List<String> args = new ArrayList<>();
addArg(args, "--change", event.change.id);
addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
addArg(args, "--project", event.change.project);
@@ -653,7 +678,7 @@
fireEvent(change, event, db);
- final List<String> args = new ArrayList<>();
+ List<String> args = new ArrayList<>();
addArg(args, "--change", event.change.id);
addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
addArg(args, "--project", event.change.project);
@@ -680,7 +705,7 @@
@Override
public void doClaSignupHook(Account account, ContributorAgreement cla) {
if (account != null) {
- final List<String> args = new ArrayList<>();
+ List<String> args = new ArrayList<>();
addArg(args, "--submitter", getDisplayName(account));
addArg(args, "--user-id", account.getId().toString());
addArg(args, "--cla-name", cla.getName());
@@ -690,60 +715,85 @@
}
@Override
- public void postEvent(final Change change, final Event event,
- final ReviewDb db) throws OrmException {
+ public void postEvent(Change change, com.google.gerrit.server.events.Event event,
+ ReviewDb db) throws OrmException {
fireEvent(change, event, db);
}
@Override
- public void postEvent(final Branch.NameKey branchName,
- final Event event) {
+ public void postEvent(Branch.NameKey branchName, com.google.gerrit.server.events.Event event) {
fireEvent(branchName, event);
}
- private void fireEventForUnrestrictedListeners(final Event event) {
+ private void fireEventForUnrestrictedListeners(com.google.gerrit.server.events.Event event) {
for (EventListener listener : unrestrictedListeners) {
- listener.onEvent(event);
+ listener.onEvent(event);
}
}
- private void fireEvent(final Change change, final Event event,
- final ReviewDb db) throws OrmException {
+ private void fireEvent(Change change, com.google.gerrit.server.events.Event event,
+ ReviewDb db) throws OrmException {
for (EventListenerHolder holder : listeners.values()) {
- if (isVisibleTo(change, holder.user, db)) {
- holder.listener.onEvent(event);
- }
- }
-
- fireEventForUnrestrictedListeners( event );
- }
-
- private void fireEvent(Branch.NameKey branchName, final Event event) {
- for (EventListenerHolder holder : listeners.values()) {
- if (isVisibleTo(branchName, holder.user)) {
- holder.listener.onEvent(event);
- }
- }
-
- fireEventForUnrestrictedListeners( event );
- }
-
- private boolean isVisibleTo(Change change, CurrentUser user, ReviewDb db) throws OrmException {
- final ProjectState pe = projectCache.get(change.getProject());
- if (pe == null) {
- return false;
+ if (isVisibleTo(change, holder.user, db)) {
+ holder.listener.onEvent(event);
}
- final ProjectControl pc = pe.controlFor(user);
- return pc.controlFor(change).isVisible(db);
+ }
+
+ fireEventForUnrestrictedListeners( event );
+ }
+
+ private void fireEvent(Project.NameKey project, ProjectCreatedEvent event) {
+ for (EventListenerHolder holder : listeners.values()) {
+ if (isVisibleTo(project, event, holder.user)) {
+ holder.listener.onEvent(event);
+ }
+ }
+
+ fireEventForUnrestrictedListeners(event);
+ }
+
+ private void fireEventForUnrestrictedListeners(ProjectCreatedEvent event) {
+ for (EventListener listener : unrestrictedListeners) {
+ listener.onEvent(event);
+ }
+ }
+
+ private boolean isVisibleTo(Project.NameKey project, ProjectCreatedEvent event, CurrentUser user) {
+ ProjectState pe = projectCache.get(project);
+ if (pe == null) {
+ return false;
+ }
+ ProjectControl pc = pe.controlFor(user);
+ return pc.controlForRef(event.getHeadName()).isVisible();
+ }
+
+ private void fireEvent(Branch.NameKey branchName, com.google.gerrit.server.events.Event event) {
+ for (EventListenerHolder holder : listeners.values()) {
+ if (isVisibleTo(branchName, holder.user)) {
+ holder.listener.onEvent(event);
+ }
+ }
+
+ fireEventForUnrestrictedListeners(event);
+ }
+
+ private boolean isVisibleTo(Change change, CurrentUser user, ReviewDb db)
+ throws OrmException {
+ ProjectState pe = projectCache.get(change.getProject());
+ if (pe == null) {
+ return false;
+ }
+ ProjectControl pc = pe.controlFor(user);
+ return pc.controlFor(change).isVisible(db);
}
private boolean isVisibleTo(Branch.NameKey branchName, CurrentUser user) {
- final ProjectState pe = projectCache.get(branchName.getParentKey());
- if (pe == null) {
- return false;
- }
- final ProjectControl pc = pe.controlFor(user);
- return pc.controlForRef(branchName).isVisible();
+ ProjectState pe = projectCache.get(branchName.getParentKey());
+ if (pe == null) {
+ return false;
+ }
+ ProjectControl pc = pe.controlFor(user);
+ return pc.controlForRef(branchName).isVisible();
}
/**
@@ -753,14 +803,14 @@
*/
private ApprovalAttribute getApprovalAttribute(LabelTypes labelTypes,
Entry<String, Short> approval) {
- ApprovalAttribute a = new ApprovalAttribute();
- a.type = approval.getKey();
- LabelType lt = labelTypes.byLabel(approval.getKey());
- if (lt != null) {
- a.description = lt.getName();
- }
- a.value = Short.toString(approval.getValue());
- return a;
+ ApprovalAttribute a = new ApprovalAttribute();
+ a.type = approval.getKey();
+ LabelType lt = labelTypes.byLabel(approval.getKey());
+ if (lt != null) {
+ a.description = lt.getName();
+ }
+ a.value = Short.toString(approval.getValue());
+ return a;
}
/**
@@ -769,16 +819,18 @@
* @param account Account to get name for.
* @return Name for this account.
*/
- private String getDisplayName(final Account account) {
- if (account != null) {
- String result = (account.getFullName() == null) ? anonymousCowardName : account.getFullName();
- if (account.getPreferredEmail() != null) {
- result += " (" + account.getPreferredEmail() + ")";
- }
- return result;
+ private String getDisplayName(Account account) {
+ if (account != null) {
+ String result = (account.getFullName() == null)
+ ? anonymousCowardName
+ : account.getFullName();
+ if (account.getPreferredEmail() != null) {
+ result += " (" + account.getPreferredEmail() + ")";
}
+ return result;
+ }
- return anonymousCowardName;
+ return anonymousCowardName;
}
/**
@@ -788,23 +840,23 @@
* @param hook the hook to execute.
* @param args Arguments to use to run the hook.
*/
- private synchronized void runHook(Project.NameKey project, File hook,
+ private synchronized void runHook(Project.NameKey project, Path hook,
List<String> args) {
- if (project != null && hook.exists()) {
+ if (project != null && Files.exists(hook)) {
hookQueue.execute(new AsyncHookTask(project, hook, args));
}
}
- private synchronized void runHook(File hook, List<String> args) {
- if (hook.exists()) {
+ private synchronized void runHook(Path hook, List<String> args) {
+ if (Files.exists(hook)) {
hookQueue.execute(new AsyncHookTask(null, hook, args));
}
}
private HookResult runSyncHook(Project.NameKey project,
- File hook, List<String> args) {
+ Path hook, List<String> args) {
- if (!hook.exists()) {
+ if (!Files.exists(hook)) {
return null;
}
@@ -818,10 +870,10 @@
try {
return task.get(syncHookTimeout, TimeUnit.SECONDS);
} catch (TimeoutException e) {
- message = "Synchronous hook timed out " + hook.getAbsolutePath();
+ message = "Synchronous hook timed out " + hook.toAbsolutePath();
log.error(message);
} catch (Exception e) {
- message = "Error running hook " + hook.getAbsolutePath();
+ message = "Error running hook " + hook.toAbsolutePath();
log.error(message, e);
}
@@ -849,12 +901,12 @@
private class HookTask {
private final Project.NameKey project;
- private final File hook;
+ private final Path hook;
private final List<String> args;
private StringWriter output;
private Process ps;
- protected HookTask(Project.NameKey project, File hook, List<String> args) {
+ protected HookTask(Project.NameKey project, Path hook, List<String> args) {
this.project = project;
this.hook = hook;
this.args = args;
@@ -869,19 +921,19 @@
HookResult result = null;
try {
- final List<String> argv = new ArrayList<>(1 + args.size());
- argv.add(hook.getAbsolutePath());
+ List<String> argv = new ArrayList<>(1 + args.size());
+ argv.add(hook.toAbsolutePath().toString());
argv.addAll(args);
- final ProcessBuilder pb = new ProcessBuilder(argv);
+ ProcessBuilder pb = new ProcessBuilder(argv);
pb.redirectErrorStream(true);
if (project != null) {
repo = openRepository(project);
}
- final Map<String, String> env = pb.environment();
- env.put("GERRIT_SITE", sitePaths.site_path.getAbsolutePath());
+ Map<String, String> env = pb.environment();
+ env.put("GERRIT_SITE", sitePaths.site_path.toAbsolutePath().toString());
if (repo != null) {
pb.directory(repo.getDirectory());
@@ -906,7 +958,7 @@
} catch (InterruptedException iex) {
// InterruptedExeception - timeout or cancel
} catch (Throwable err) {
- log.error("Error running hook " + hook.getAbsolutePath(), err);
+ log.error("Error running hook " + hook.toAbsolutePath(), err);
} finally {
if (repo != null) {
repo.close();
@@ -914,7 +966,7 @@
}
if (result != null) {
- final int exitValue = result.getExitValue();
+ int exitValue = result.getExitValue();
if (exitValue == 0) {
log.debug("hook[" + getName() + "] exitValue:" + exitValue);
} else {
@@ -949,12 +1001,12 @@
}
protected String getName() {
- return hook.getName();
+ return hook.getFileName().toString();
}
@Override
public String toString() {
- return "hook " + hook.getName();
+ return "hook " + hook.getFileName();
}
public void cancel() {
@@ -966,7 +1018,7 @@
private final class SyncHookTask extends HookTask
implements Callable<HookResult> {
- private SyncHookTask(Project.NameKey project, File hook, List<String> args) {
+ private SyncHookTask(Project.NameKey project, Path hook, List<String> args) {
super(project, hook, args);
}
@@ -979,7 +1031,7 @@
/** Runnable type used to run asynchronous hooks */
private final class AsyncHookTask extends HookTask implements Runnable {
- private AsyncHookTask(Project.NameKey project, File hook, List<String> args) {
+ private AsyncHookTask(Project.NameKey project, Path hook, List<String> args) {
super(project, hook, args);
}
@@ -988,4 +1040,10 @@
super.runHook();
}
}
+
+ @Override
+ public void onNewProjectCreated(NewProjectCreatedListener.Event event) {
+ Project.NameKey project = new Project.NameKey(event.getProjectName());
+ doProjectCreatedHook(project, event.getHeadName());
+ }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHooks.java b/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHooks.java
index 7f7e8b2..b16a8a5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHooks.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHooks.java
@@ -181,4 +181,12 @@
public void doHashtagsChangedHook(Change change, Account account,
Set<String>added, Set<String> removed, Set<String> hashtags,
ReviewDb db) throws OrmException;
+
+ /**
+ * Fire the project created hook
+ *
+ * @param project The project that was created
+ * @param headName The head name of the created project
+ */
+ public void doProjectCreatedHook(Project.NameKey project, String headName);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/common/DisabledChangeHooks.java b/gerrit-server/src/main/java/com/google/gerrit/common/DisabledChangeHooks.java
index 156672e..bed77a7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/common/DisabledChangeHooks.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/common/DisabledChangeHooks.java
@@ -114,6 +114,10 @@
}
@Override
+ public void doProjectCreatedHook(Project.NameKey project, String headName) {
+ }
+
+ @Override
public void postEvent(Change change, Event event, ReviewDb db) {
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/rules/PrologEnvironment.java b/gerrit-server/src/main/java/com/google/gerrit/rules/PrologEnvironment.java
index 2afdffc..26c0fd0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/rules/PrologEnvironment.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/rules/PrologEnvironment.java
@@ -28,6 +28,7 @@
import com.googlecode.prolog_cafe.lang.BufferingPrologControl;
import com.googlecode.prolog_cafe.lang.Predicate;
+import com.googlecode.prolog_cafe.lang.PredicateEncoder;
import com.googlecode.prolog_cafe.lang.Prolog;
import com.googlecode.prolog_cafe.lang.PrologMachineCopy;
@@ -50,11 +51,8 @@
* A single copy of the Prolog interpreter, for the current thread.
*/
public class PrologEnvironment extends BufferingPrologControl {
-
private static final Logger log =
- LoggerFactory.getLogger(PrologEnvironment.class);
-
- static final int MAX_ARITY = 8;
+ LoggerFactory.getLogger(PrologEnvironment.class);
public static interface Factory {
/**
@@ -68,19 +66,14 @@
private final Args args;
private final Map<StoredValue<Object>, Object> storedValues;
- private int reductionLimit;
- private int reductionsRemaining;
private List<Runnable> cleanup;
@Inject
PrologEnvironment(Args a, @Assisted PrologMachineCopy src) {
super(src);
- setMaxArity(MAX_ARITY);
setEnabled(EnumSet.allOf(Prolog.Feature.class), false);
args = a;
storedValues = new HashMap<>();
- reductionLimit = a.reductionLimit;
- reductionsRemaining = reductionLimit;
cleanup = new LinkedList<>();
}
@@ -89,25 +82,9 @@
}
@Override
- public boolean isEngineStopped() {
- if (super.isEngineStopped()) {
- return true;
- } else if (--reductionsRemaining <= 0) {
- throw new ReductionLimitException(reductionLimit);
- }
- return false;
- }
-
- @Override
public void setPredicate(Predicate goal) {
super.setPredicate(goal);
- reductionLimit = args.reductionLimit(goal);
- reductionsRemaining = reductionLimit;
- }
-
- /** @return number of reductions during execution. */
- public int getReductions() {
- return reductionLimit - reductionsRemaining;
+ setReductionLimit(args.reductionLimit(goal));
}
/**
@@ -177,6 +154,19 @@
@Singleton
public static class Args {
+ private static final Class<Predicate> CONSULT_STREAM_2;
+ static {
+ try {
+ @SuppressWarnings("unchecked")
+ Class<Predicate> c = (Class<Predicate>) Class.forName(
+ PredicateEncoder.encode(Prolog.BUILTIN, "consult_stream", 2),
+ false, RulesCache.class.getClassLoader());
+ CONSULT_STREAM_2 = c;
+ } catch (ClassNotFoundException e) {
+ throw new LinkageError("cannot find predicate consult_stream", e);
+ }
+ }
+
private final ProjectCache projectCache;
private final GitRepositoryManager repositoryManager;
private final PatchListCache patchListCache;
@@ -210,8 +200,7 @@
}
private int reductionLimit(Predicate goal) {
- if ("com.googlecode.prolog_cafe.builtin.PRED_consult_stream_2"
- .equals(goal.getClass().getName())) {
+ if (goal.getClass() == CONSULT_STREAM_2) {
return compileLimit;
}
return reductionLimit;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/rules/ReductionLimitException.java b/gerrit-server/src/main/java/com/google/gerrit/rules/ReductionLimitException.java
deleted file mode 100644
index 2c27240..0000000
--- a/gerrit-server/src/main/java/com/google/gerrit/rules/ReductionLimitException.java
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (C) 2014 The Android Open Source Project
-//
-// 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.
-
-package com.google.gerrit.rules;
-
-/** Thrown by {@link PrologEnvironment} if a script runs too long. */
-public class ReductionLimitException extends RuntimeException {
- private static final long serialVersionUID = 1L;
-
- ReductionLimitException(int limit) {
- super(String.format("exceeded reduction limit of %d", limit));
- }
-}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/rules/RulesCache.java b/gerrit-server/src/main/java/com/google/gerrit/rules/RulesCache.java
index 5dea6a2..658bb35 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/rules/RulesCache.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/rules/RulesCache.java
@@ -16,6 +16,7 @@
import static com.googlecode.prolog_cafe.lang.PrologMachineCopy.save;
+import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.gerrit.extensions.registration.DynamicSet;
@@ -27,13 +28,18 @@
import com.google.inject.Inject;
import com.google.inject.Singleton;
-import com.googlecode.prolog_cafe.compiler.CompileException;
+import com.googlecode.prolog_cafe.exceptions.CompileException;
+import com.googlecode.prolog_cafe.exceptions.SyntaxException;
+import com.googlecode.prolog_cafe.exceptions.TermException;
import com.googlecode.prolog_cafe.lang.BufferingPrologControl;
import com.googlecode.prolog_cafe.lang.JavaObjectTerm;
+import com.googlecode.prolog_cafe.lang.ListTerm;
import com.googlecode.prolog_cafe.lang.Prolog;
import com.googlecode.prolog_cafe.lang.PrologClassLoader;
import com.googlecode.prolog_cafe.lang.PrologMachineCopy;
+import com.googlecode.prolog_cafe.lang.StructureTerm;
import com.googlecode.prolog_cafe.lang.SymbolTerm;
+import com.googlecode.prolog_cafe.lang.Term;
import org.eclipse.jgit.errors.LargeObjectException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
@@ -44,10 +50,7 @@
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.util.RawParseUtils;
-import java.io.File;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
import java.io.PushbackReader;
import java.io.Reader;
import java.io.StringReader;
@@ -57,6 +60,8 @@
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
@@ -96,8 +101,8 @@
}
private final boolean enableProjectRules;
- private final File cacheDir;
- private final File rulesDir;
+ private final Path cacheDir;
+ private final Path rulesDir;
private final GitRepositoryManager gitMgr;
private final DynamicSet<PredicateProvider> predicateProviders;
private final ClassLoader systemLoader;
@@ -108,7 +113,7 @@
GitRepositoryManager gm, DynamicSet<PredicateProvider> predicateProviders) {
enableProjectRules = config.getBoolean("rules", null, "enable", true);
cacheDir = site.resolve(config.getString("cache", null, "directory"));
- rulesDir = cacheDir != null ? new File(cacheDir, "rules") : null;
+ rulesDir = cacheDir != null ? cacheDir.resolve("rules") : null;
gitMgr = gm;
this.predicateProviders = predicateProviders;
@@ -153,9 +158,9 @@
return pcm;
}
- public PrologMachineCopy loadMachine(String name, InputStream in)
+ public PrologMachineCopy loadMachine(String name, Reader in)
throws CompileException {
- PrologMachineCopy pmc = consultRules(name, new InputStreamReader(in));
+ PrologMachineCopy pmc = consultRules(name, in);
if (pmc == null) {
throw new CompileException("Cannot consult rules from the stream " + name);
}
@@ -178,9 +183,9 @@
// that over dynamic consult as the bytecode will be faster.
//
if (rulesDir != null) {
- File jarFile = new File(rulesDir, "rules-" + rulesId.getName() + ".jar");
- if (jarFile.isFile()) {
- URL[] cp = new URL[] {toURL(jarFile)};
+ Path jarPath = rulesDir.resolve("rules-" + rulesId.getName() + ".jar");
+ if (Files.isRegularFile(jarPath)) {
+ URL[] cp = new URL[] {toURL(jarPath)};
return save(newEmptyMachine(new URLClassLoader(cp, systemLoader)));
}
}
@@ -204,12 +209,60 @@
SymbolTerm.intern(name), new JavaObjectTerm(in))) {
return null;
}
+ } catch (SyntaxException e) {
+ throw new CompileException(e.toString(), e);
+ } catch (TermException e) {
+ Term m = e.getMessageTerm();
+ if (m instanceof StructureTerm && "syntax_error".equals(m.name())
+ && m.arity() >= 1) {
+ StringBuilder msg = new StringBuilder();
+ if (m.arg(0) instanceof ListTerm) {
+ msg.append(Joiner.on(' ').join(((ListTerm) m.arg(0)).toJava()));
+ } else {
+ msg.append(m.arg(0).toString());
+ }
+ if (m.arity() == 2 && m.arg(1) instanceof StructureTerm
+ && "at".equals(m.arg(1).name())) {
+ Term at = m.arg(1).arg(0).dereference();
+ if (at instanceof ListTerm) {
+ msg.append(" at: ");
+ msg.append(prettyProlog(at));
+ }
+ }
+ throw new CompileException(msg.toString(), e);
+ }
+ throw new CompileException("Error while consulting rules from " + name, e);
} catch (RuntimeException e) {
throw new CompileException("Error while consulting rules from " + name, e);
}
return save(ctl);
}
+ private static String prettyProlog(Term at) {
+ StringBuilder b = new StringBuilder();
+ for (Object o : ((ListTerm) at).toJava()) {
+ if (o instanceof Term) {
+ Term t = (Term) o;
+ if (!(t instanceof StructureTerm)) {
+ b.append(t.toString()).append(' ');
+ continue;
+ }
+ switch (t.name()) {
+ case "atom":
+ SymbolTerm atom = (SymbolTerm) t.arg(0);
+ b.append(atom.toString());
+ break;
+ case "var":
+ b.append(t.arg(0).toString());
+ break;
+ }
+ } else {
+ b.append(o);
+ }
+ }
+ return b.toString().trim();
+ }
+
private String read(Project.NameKey project, ObjectId rulesId)
throws CompileException {
Repository git;
@@ -237,7 +290,6 @@
private BufferingPrologControl newEmptyMachine(ClassLoader cl) {
BufferingPrologControl ctl = new BufferingPrologControl();
- ctl.setMaxArity(PrologEnvironment.MAX_ARITY);
ctl.setMaxDatabaseSize(DB_MAX);
ctl.setPrologClassLoader(new PrologClassLoader(new PredicateClassLoader(
predicateProviders, cl)));
@@ -254,11 +306,11 @@
return ctl;
}
- private static URL toURL(File jarFile) throws CompileException {
+ private static URL toURL(Path jarPath) throws CompileException {
try {
- return jarFile.toURI().toURL();
+ return jarPath.toUri().toURL();
} catch (MalformedURLException e) {
- throw new CompileException("Cannot create URL for " + jarFile, e);
+ throw new CompileException("Cannot create URL for " + jarPath, e);
}
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/rules/StoredValue.java b/gerrit-server/src/main/java/com/google/gerrit/rules/StoredValue.java
index d454e40..27f15e6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/rules/StoredValue.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/rules/StoredValue.java
@@ -14,8 +14,8 @@
package com.google.gerrit.rules;
+import com.googlecode.prolog_cafe.exceptions.SystemException;
import com.googlecode.prolog_cafe.lang.Prolog;
-import com.googlecode.prolog_cafe.lang.SystemException;
/**
* Defines a value cached in a {@link PrologEnvironment}.
diff --git a/gerrit-server/src/main/java/com/google/gerrit/rules/StoredValues.java b/gerrit-server/src/main/java/com/google/gerrit/rules/StoredValues.java
index 6136742..c9359b4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/rules/StoredValues.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/rules/StoredValues.java
@@ -38,8 +38,8 @@
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gwtorm.server.OrmException;
+import com.googlecode.prolog_cafe.exceptions.SystemException;
import com.googlecode.prolog_cafe.lang.Prolog;
-import com.googlecode.prolog_cafe.lang.SystemException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalCopier.java b/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalCopier.java
index bd175a9..c31a411 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalCopier.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalCopier.java
@@ -142,7 +142,7 @@
private static TreeMap<Integer, PatchSet> getPatchSets(ChangeData cd)
throws OrmException {
- Collection<PatchSet> patchSets = cd.patches();
+ Collection<PatchSet> patchSets = cd.patchSets();
TreeMap<Integer, PatchSet> result = Maps.newTreeMap();
for (PatchSet ps : patchSets) {
result.put(ps.getId().get(), ps);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java
index 9faa516..305b66d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java
@@ -17,9 +17,11 @@
import static com.google.gerrit.server.change.PatchSetInserter.ValidatePolicy.RECEIVE_COMMITS;
import static com.google.gerrit.server.query.change.ChangeData.asChanges;
+import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Ordering;
import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.reviewdb.client.Change;
@@ -95,6 +97,17 @@
private static final Logger log =
LoggerFactory.getLogger(ChangeUtil.class);
+ public static final Function<PatchSet, Integer> TO_PS_ID =
+ new Function<PatchSet, Integer>() {
+ @Override
+ public Integer apply(PatchSet in) {
+ return in.getId().get();
+ }
+ };
+
+ public static final Ordering<PatchSet> PS_ID_ORDER = Ordering.natural()
+ .onResultOf(TO_PS_ID);
+
/**
* Generate a new unique identifier for change message entities.
*
@@ -104,7 +117,8 @@
* @throws OrmException the database couldn't be incremented.
*/
public static String messageUUID(ReviewDb db) throws OrmException {
- int p, s;
+ int p;
+ int s;
synchronized (uuidLock) {
if (uuidSeq == 0) {
uuidPrefix = db.nextChangeMessageId();
@@ -316,7 +330,7 @@
ins.setMessage(cmsg).insert();
try {
- RevertedSender cm = revertedSenderFactory.create(change);
+ RevertedSender cm = revertedSenderFactory.create(change.getId());
cm.setFrom(user().getAccountId());
cm.setChangeMessage(cmsg);
cm.send();
@@ -456,7 +470,7 @@
throw new IOException("Failed to delete ref " + patch.getRefName() +
" in " + repo.getDirectory() + ": " + update.getResult());
}
- gitRefUpdated.fire(change.getProject(), update);
+ gitRefUpdated.fire(change.getProject(), update, ReceiveCommand.Type.DELETE);
} finally {
repo.close();
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java b/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java
index be5e000..baba4bb 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java
@@ -14,6 +14,8 @@
package com.google.gerrit.server;
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.gerrit.common.Nullable;
@@ -37,6 +39,7 @@
import com.google.gerrit.server.config.DisableReverseDnsLookup;
import com.google.gerrit.server.group.SystemGroupBackend;
import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.OrmRuntimeException;
import com.google.gwtorm.server.ResultSet;
import com.google.inject.Inject;
import com.google.inject.OutOfScopeException;
@@ -144,13 +147,13 @@
CapabilityControl.Factory capabilityControlFactory,
final AuthConfig authConfig,
Realm realm,
- final @AnonymousCowardName String anonymousCowardName,
- final @CanonicalWebUrl Provider<String> canonicalUrl,
+ @AnonymousCowardName final String anonymousCowardName,
+ @CanonicalWebUrl final Provider<String> canonicalUrl,
final AccountCache accountCache,
final GroupBackend groupBackend,
- final @DisableReverseDnsLookup Boolean disableReverseDnsLookup,
+ @DisableReverseDnsLookup final Boolean disableReverseDnsLookup,
- final @RemotePeer Provider<SocketAddress> remotePeerProvider,
+ @RemotePeer final Provider<SocketAddress> remotePeerProvider,
final Provider<ReviewDb> dbProvider) {
this.capabilityControlFactory = capabilityControlFactory;
this.authConfig = authConfig;
@@ -327,35 +330,28 @@
@Override
public Set<Change.Id> getStarredChanges() {
if (starredChanges == null) {
- if (dbProvider == null) {
- throw new OutOfScopeException("Not in request scoped user");
- }
- Set<Change.Id> h = Sets.newHashSet();
+ checkRequestScope();
try {
- if (starredQuery != null) {
- for (StarredChange sc : starredQuery) {
- h.add(sc.getChangeId());
- }
- starredQuery = null;
- } else {
- for (StarredChange sc : dbProvider.get().starredChanges()
- .byAccount(getAccountId())) {
- h.add(sc.getChangeId());
- }
- }
- } catch (OrmException e) {
- log.warn("Cannot query starred by user changes", e);
+ starredChanges = starredChangeIds(
+ starredQuery != null ? starredQuery : starredQuery());
+ } catch (OrmException | OrmRuntimeException e) {
+ log.warn("Cannot query starred changes", e);
}
- starredChanges = Collections.unmodifiableSet(h);
}
return starredChanges;
}
+ public void clearStarredChanges() {
+ // Async query may have started before an update that the caller expects
+ // to see the results of, so we can't trust it.
+ abortStarredChanges();
+ starredChanges = null;
+ }
+
public void asyncStarredChanges() {
if (starredChanges == null && dbProvider != null) {
try {
- starredQuery =
- dbProvider.get().starredChanges().byAccount(getAccountId());
+ starredQuery = starredQuery();
} catch (OrmException e) {
log.warn("Cannot query starred by user changes", e);
starredQuery = null;
@@ -374,12 +370,31 @@
}
}
+ private void checkRequestScope() {
+ if (dbProvider == null) {
+ throw new OutOfScopeException("Not in request scoped user");
+ }
+ }
+
+ private ResultSet<StarredChange> starredQuery() throws OrmException {
+ return dbProvider.get().starredChanges().byAccount(getAccountId());
+ }
+
+ private static ImmutableSet<Change.Id> starredChangeIds(
+ Iterable<StarredChange> scs) {
+ return FluentIterable.from(scs)
+ .transform(new Function<StarredChange, Change.Id>() {
+ @Override
+ public Change.Id apply(StarredChange in) {
+ return in.getChangeId();
+ }
+ }).toSet();
+ }
+
@Override
public Collection<AccountProjectWatch> getNotificationFilters() {
if (notificationFilters == null) {
- if (dbProvider == null) {
- throw new OutOfScopeException("Not in request scoped user");
- }
+ checkRequestScope();
List<AccountProjectWatch> r;
try {
r = dbProvider.get().accountProjectWatches() //
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/PatchLineCommentsUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/PatchLineCommentsUtil.java
index d5242c2..88f034e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/PatchLineCommentsUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/PatchLineCommentsUtil.java
@@ -14,12 +14,18 @@
package com.google.gerrit.server;
+import static com.google.common.base.MoreObjects.firstNonNull;
+
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
+import com.google.common.collect.ComparisonChain;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
+import com.google.common.collect.Ordering;
+import com.google.gerrit.extensions.client.Side;
+import com.google.gerrit.extensions.common.CommentInfo;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchLineComment;
@@ -62,6 +68,47 @@
*/
@Singleton
public class PatchLineCommentsUtil {
+ public static Ordering<PatchLineComment> PLC_ORDER =
+ new Ordering<PatchLineComment>() {
+ @Override
+ public int compare(PatchLineComment c1, PatchLineComment c2) {
+ String filename1 = c1.getKey().getParentKey().get();
+ String filename2 = c2.getKey().getParentKey().get();
+ return ComparisonChain.start()
+ .compare(filename1, filename2)
+ .compare(getCommentPsId(c1).get(), getCommentPsId(c2).get())
+ .compare(c1.getSide(), c2.getSide())
+ .compare(c1.getLine(), c2.getLine())
+ .compare(c1.getWrittenOn(), c2.getWrittenOn())
+ .result();
+ }
+ };
+
+ public static final Ordering<CommentInfo> COMMENT_INFO_ORDER =
+ new Ordering<CommentInfo>() {
+ @Override
+ public int compare(CommentInfo a, CommentInfo b) {
+ return ComparisonChain.start()
+ .compare(a.path, b.path, NULLS_FIRST)
+ .compare(a.patchSet, b.patchSet, NULLS_FIRST)
+ .compare(side(a), side(b))
+ .compare(a.line, b.line, NULLS_FIRST)
+ .compare(a.id, b.id)
+ .result();
+ }
+
+ private int side(CommentInfo c) {
+ return firstNonNull(c.side, Side.REVISION).ordinal();
+ }
+ };
+
+ public static PatchSet.Id getCommentPsId(PatchLineComment plc) {
+ return plc.getKey().getParentKey().getParentKey();
+ }
+
+ private static final Ordering<Comparable<?>> NULLS_FIRST =
+ Ordering.natural().nullsFirst();
+
private final GitRepositoryManager repoManager;
private final AllUsersName allUsers;
private final DraftCommentNotes.Factory draftFactory;
@@ -106,8 +153,7 @@
notes.load();
List<PatchLineComment> comments = Lists.newArrayList();
- comments.addAll(notes.getBaseComments().values());
- comments.addAll(notes.getPatchSetComments().values());
+ comments.addAll(notes.getComments().values());
return sort(comments);
}
@@ -166,13 +212,7 @@
return sort(
db.patchComments().publishedByChangeFile(changeId, file).toList());
}
- notes.load();
- List<PatchLineComment> comments = Lists.newArrayList();
-
- addCommentsOnFile(comments, notes.getBaseComments().values(), file);
- addCommentsOnFile(comments, notes.getPatchSetComments().values(),
- file);
- return sort(comments);
+ return commentsOnFile(notes.load().getComments().values(), file);
}
public List<PatchLineComment> publishedByPatchSet(ReviewDb db,
@@ -181,11 +221,7 @@
return sort(
db.patchComments().publishedByPatchSet(psId).toList());
}
- notes.load();
- List<PatchLineComment> comments = new ArrayList<>();
- comments.addAll(notes.getPatchSetComments().get(psId));
- comments.addAll(notes.getBaseComments().get(psId));
- return sort(comments);
+ return commentsOnPatchSet(notes.load().getComments().values(), psId);
}
public List<PatchLineComment> draftByPatchSetAuthor(ReviewDb db,
@@ -195,11 +231,8 @@
return sort(
db.patchComments().draftByPatchSetAuthor(psId, author).toList());
}
-
- List<PatchLineComment> comments = Lists.newArrayList();
- comments.addAll(notes.getDraftBaseComments(author).row(psId).values());
- comments.addAll(notes.getDraftPsComments(author).row(psId).values());
- return sort(comments);
+ return commentsOnPatchSet(
+ notes.load().getDraftComments(author).values(), psId);
}
public List<PatchLineComment> draftByChangeFileAuthor(ReviewDb db,
@@ -211,12 +244,8 @@
.draftByChangeFileAuthor(notes.getChangeId(), file, author)
.toList());
}
- List<PatchLineComment> comments = Lists.newArrayList();
- addCommentsOnFile(comments, notes.getDraftBaseComments(author).values(),
- file);
- addCommentsOnFile(comments, notes.getDraftPsComments(author).values(),
- file);
- return sort(comments);
+ return commentsOnFile(
+ notes.load().getDraftComments(author).values(), file);
}
public List<PatchLineComment> draftByChangeAuthor(ReviewDb db,
@@ -233,11 +262,10 @@
in.getKey().getParentKey().getParentKey().getParentKey();
return changeId.equals(matchId);
}
- }).toSortedList(ChangeNotes.PLC_ORDER);
+ }).toSortedList(PLC_ORDER);
}
List<PatchLineComment> comments = Lists.newArrayList();
- comments.addAll(notes.getDraftBaseComments(author).values());
- comments.addAll(notes.getDraftPsComments(author).values());
+ comments.addAll(notes.getDraftComments(author).values());
return sort(comments);
}
@@ -247,9 +275,8 @@
return sort(db.patchComments().draftByAuthor(author).toList());
}
- Set<String> refNames =
- getRefNamesAllUsers(RefNames.REFS_DRAFT_COMMENTS);
-
+ // TODO(dborowitz): Just scan author space.
+ Set<String> refNames = getRefNamesAllUsers(RefNames.REFS_DRAFT_COMMENTS);
List<PatchLineComment> comments = Lists.newArrayList();
for (String refName : refNames) {
Account.Id id = Account.Id.fromRefPart(refName);
@@ -257,10 +284,8 @@
continue;
}
Change.Id changeId = Change.Id.parse(refName);
- DraftCommentNotes draftNotes =
- draftFactory.create(changeId, author).load();
- comments.addAll(draftNotes.getDraftBaseComments().values());
- comments.addAll(draftNotes.getDraftPsComments().values());
+ comments.addAll(
+ draftFactory.create(changeId, author).load().getComments().values());
}
return sort(comments);
}
@@ -297,33 +322,45 @@
db.patchComments().delete(comments);
}
- private static Collection<PatchLineComment> addCommentsOnFile(
- Collection<PatchLineComment> commentsOnFile,
+ private static List<PatchLineComment> commentsOnFile(
Collection<PatchLineComment> allComments,
String file) {
+ List<PatchLineComment> result = new ArrayList<>(allComments.size());
for (PatchLineComment c : allComments) {
String currentFilename = c.getKey().getParentKey().getFileName();
if (currentFilename.equals(file)) {
- commentsOnFile.add(c);
+ result.add(c);
}
}
- return commentsOnFile;
+ return sort(result);
}
- public static void setCommentRevId(PatchLineComment c,
+ private static List<PatchLineComment> commentsOnPatchSet(
+ Collection<PatchLineComment> allComments,
+ PatchSet.Id psId) {
+ List<PatchLineComment> result = new ArrayList<>(allComments.size());
+ for (PatchLineComment c : allComments) {
+ if (getCommentPsId(c).equals(psId)) {
+ result.add(c);
+ }
+ }
+ return sort(result);
+ }
+
+ public static RevId setCommentRevId(PatchLineComment c,
PatchListCache cache, Change change, PatchSet ps) throws OrmException {
- if (c.getRevId() != null) {
- return;
+ if (c.getRevId() == null) {
+ try {
+ // TODO(dborowitz): Bypass cache if side is REVISION.
+ PatchList patchList = cache.get(change, ps);
+ c.setRevId((c.getSide() == (short) 0)
+ ? new RevId(ObjectId.toString(patchList.getOldId()))
+ : new RevId(ObjectId.toString(patchList.getNewId())));
+ } catch (PatchListNotAvailableException e) {
+ throw new OrmException(e);
+ }
}
- PatchList patchList;
- try {
- patchList = cache.get(change, ps);
- } catch (PatchListNotAvailableException e) {
- throw new OrmException(e);
- }
- c.setRevId((c.getSide() == (short) 0)
- ? new RevId(ObjectId.toString(patchList.getOldId()))
- : new RevId(ObjectId.toString(patchList.getNewId())));
+ return c.getRevId();
}
private Set<String> getRefNamesAllUsers(String prefix) throws OrmException {
@@ -356,7 +393,7 @@
}
private static List<PatchLineComment> sort(List<PatchLineComment> comments) {
- Collections.sort(comments, ChangeNotes.PLC_ORDER);
+ Collections.sort(comments, PLC_ORDER);
return comments;
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/access/ListAccess.java b/gerrit-server/src/main/java/com/google/gerrit/server/access/ListAccess.java
index 580897f..465c9ba 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/access/ListAccess.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/access/ListAccess.java
@@ -263,7 +263,7 @@
}
}
- public class PermissionInfo {
+ public static class PermissionInfo {
public String label;
public Boolean exclusive;
public Map<String, PermissionRuleInfo> rules;
@@ -278,7 +278,7 @@
}
}
- public class PermissionRuleInfo {
+ public static class PermissionRuleInfo {
public PermissionRule.Action action;
public Boolean force;
public Integer min;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AbstractRealm.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AbstractRealm.java
index 7031672..34f83f7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AbstractRealm.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AbstractRealm.java
@@ -16,15 +16,44 @@
import com.google.common.base.Strings;
import com.google.common.collect.Sets;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Account.FieldName;
import com.google.gerrit.reviewdb.client.AccountExternalId;
import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.mail.EmailSender;
+import com.google.inject.Inject;
import java.util.Collection;
+import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
/** Basic implementation of {@link Realm}. */
public abstract class AbstractRealm implements Realm {
+ private EmailSender emailSender;
+
+ @Inject(optional = true)
+ void setEmailSender(EmailSender emailSender) {
+ this.emailSender = emailSender;
+ }
+
+ @Override
+ public Set<FieldName> getEditableFields() {
+ Set<Account.FieldName> fields = new HashSet<>();
+ for (Account.FieldName n : Account.FieldName.values()) {
+ if (allowsEdit(n)) {
+ if (n == Account.FieldName.REGISTER_NEW_EMAIL) {
+ if (emailSender != null && emailSender.isEnabled()) {
+ fields.add(n);
+ }
+ } else {
+ fields.add(n);
+ }
+ }
+ }
+ return fields;
+ }
+
@Override
public boolean hasEmailAddress(IdentifiedUser user, String email) {
for (AccountExternalId ext : user.state().getExternalIds()) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountDirectory.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountDirectory.java
index 445ac6e..b4ca530 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountDirectory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountDirectory.java
@@ -39,7 +39,7 @@
USERNAME,
/** Numeric account ID, may be deprecated. */
- ID;
+ ID
}
public abstract void fillAccountInfo(
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountsCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountsCollection.java
index efe7322..80a451a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountsCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountsCollection.java
@@ -77,9 +77,9 @@
* Parses a account ID from a request body and returns the user.
*
* @param id ID of the account, can be a string of the format
- * "Full Name <email@example.com>", just the email address, a full name
- * if it is unique, an account ID, a user name or 'self' for the
- * calling user
+ * "{@code Full Name <email@example.com>}", just the email address,
+ * a full name if it is unique, an account ID, a user name or
+ * "{@code self}" for the calling user
* @return the user, never null.
* @throws UnprocessableEntityException thrown if the account ID cannot be
* resolved or if the account is not visible to the calling user
@@ -102,9 +102,9 @@
* check whether the current user can see the account.
*
* @param id ID of the account, can be a string of the format
- * "Full Name <email@example.com>", just the email address, a full name
- * if it is unique, an account ID, a user name or 'self' for the
- * calling user
+ * "{@code Full Name <email@example.com>}", just the email address,
+ * a full name if it is unique, an account ID, a user name or
+ * "{@code self}" for the calling user
* @return the user, null if no user is found for the given account ID
* @throws AuthException thrown if 'self' is used as account ID and the
* current user is not authenticated
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/CreateGroupArgs.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/CreateGroupArgs.java
index 807eed6..9ddef3a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/CreateGroupArgs.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/CreateGroupArgs.java
@@ -25,7 +25,6 @@
public boolean visibleToAll;
public AccountGroup.Id ownerGroupId;
public Collection<? extends Account.Id> initialMembers;
- public Collection<? extends AccountGroup.UUID> initialGroups;
public AccountGroup.NameKey getGroup() {
return groupName;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetGroups.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetGroups.java
index d335add..f777145 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetGroups.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetGroups.java
@@ -16,12 +16,12 @@
import com.google.common.collect.Lists;
import com.google.gerrit.common.errors.NoSuchGroupException;
+import com.google.gerrit.extensions.common.GroupInfo;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.group.GroupJson;
-import com.google.gerrit.server.group.GroupJson.GroupInfo;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformCreateGroup.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformCreateGroup.java
deleted file mode 100644
index fd1f33e..0000000
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformCreateGroup.java
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright (C) 2011 The Android Open Source Project
-//
-// 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
-
-package com.google.gerrit.server.account;
-
-import com.google.gerrit.audit.AuditService;
-import com.google.gerrit.common.errors.NameAlreadyUsedException;
-import com.google.gerrit.common.errors.PermissionDeniedException;
-import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gerrit.reviewdb.client.AccountGroupById;
-import com.google.gerrit.reviewdb.client.AccountGroupMember;
-import com.google.gerrit.reviewdb.client.AccountGroupName;
-import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gerrit.server.GerritPersonIdent;
-import com.google.gerrit.server.IdentifiedUser;
-import com.google.gwtorm.server.OrmDuplicateKeyException;
-import com.google.gwtorm.server.OrmException;
-import com.google.inject.Inject;
-import com.google.inject.assistedinject.Assisted;
-
-import org.eclipse.jgit.lib.PersonIdent;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-public class PerformCreateGroup {
-
- public interface Factory {
- PerformCreateGroup create(CreateGroupArgs createGroupArgs);
- }
-
- private final ReviewDb db;
- private final AccountCache accountCache;
- private final GroupIncludeCache groupIncludeCache;
- private final IdentifiedUser currentUser;
- private final PersonIdent serverIdent;
- private final GroupCache groupCache;
- private final CreateGroupArgs createGroupArgs;
- private final AuditService auditService;
-
- @Inject
- PerformCreateGroup(ReviewDb db, AccountCache accountCache,
- GroupIncludeCache groupIncludeCache, IdentifiedUser currentUser,
- @GerritPersonIdent PersonIdent serverIdent, GroupCache groupCache,
- @Assisted CreateGroupArgs createGroupArgs, AuditService auditService) {
- this.db = db;
- this.accountCache = accountCache;
- this.groupIncludeCache = groupIncludeCache;
- this.currentUser = currentUser;
- this.serverIdent = serverIdent;
- this.groupCache = groupCache;
- this.createGroupArgs = createGroupArgs;
- this.auditService = auditService;
- }
-
- /**
- * Creates a new group.
-
- * @return the new group
- * @throws OrmException is thrown in case of any data store read or write
- * error
- * @throws NameAlreadyUsedException is thrown in case a group with the given
- * name already exists
- * @throws PermissionDeniedException user cannot create a group.
- */
- public AccountGroup createGroup() throws OrmException,
- NameAlreadyUsedException, PermissionDeniedException {
- if (!currentUser.getCapabilities().canCreateGroup()) {
- throw new PermissionDeniedException(String.format(
- "%s does not have \"Create Group\" capability.",
- currentUser.getUserName()));
- }
- AccountGroup.Id groupId = new AccountGroup.Id(db.nextAccountGroupId());
- AccountGroup.UUID uuid = GroupUUID.make(
- createGroupArgs.getGroupName(),
- currentUser.newCommitterIdent(
- serverIdent.getWhen(),
- serverIdent.getTimeZone()));
- AccountGroup group =
- new AccountGroup(createGroupArgs.getGroup(), groupId, uuid);
- group.setVisibleToAll(createGroupArgs.visibleToAll);
- if (createGroupArgs.ownerGroupId != null) {
- AccountGroup ownerGroup = groupCache.get(createGroupArgs.ownerGroupId);
- if (ownerGroup != null) {
- group.setOwnerGroupUUID(ownerGroup.getGroupUUID());
- }
- }
- if (createGroupArgs.groupDescription != null) {
- group.setDescription(createGroupArgs.groupDescription);
- }
- AccountGroupName gn = new AccountGroupName(group);
- // first insert the group name to validate that the group name hasn't
- // already been used to create another group
- try {
- db.accountGroupNames().insert(Collections.singleton(gn));
- } catch (OrmDuplicateKeyException e) {
- throw new NameAlreadyUsedException(createGroupArgs.getGroupName());
- }
- db.accountGroups().insert(Collections.singleton(group));
-
- addMembers(groupId, createGroupArgs.initialMembers);
-
- if (createGroupArgs.initialGroups != null) {
- addGroups(groupId, createGroupArgs.initialGroups);
- groupIncludeCache.evictSubgroupsOf(uuid);
- }
-
- groupCache.onCreateGroup(createGroupArgs.getGroup());
-
- return group;
- }
-
- private void addMembers(final AccountGroup.Id groupId,
- final Collection<? extends Account.Id> members) throws OrmException {
- List<AccountGroupMember> memberships = new ArrayList<>();
- for (Account.Id accountId : members) {
- final AccountGroupMember membership =
- new AccountGroupMember(new AccountGroupMember.Key(accountId, groupId));
- memberships.add(membership);
- }
- db.accountGroupMembers().insert(memberships);
- auditService.dispatchAddAccountsToGroup(currentUser.getAccountId(), memberships);
-
- for (Account.Id accountId : members) {
- accountCache.evict(accountId);
- }
- }
-
- private void addGroups(final AccountGroup.Id groupId,
- final Collection<? extends AccountGroup.UUID> groups) throws OrmException {
- List<AccountGroupById> includeList = new ArrayList<>();
- for (AccountGroup.UUID includeUUID : groups) {
- final AccountGroupById groupInclude =
- new AccountGroupById(new AccountGroupById.Key(groupId, includeUUID));
- includeList.add(groupInclude);
- }
- db.accountGroupById().insert(includeList);
- auditService.dispatchAddGroupsToGroup(currentUser.getAccountId(), includeList);
-
- for (AccountGroup.UUID uuid : groups) {
- groupIncludeCache.evictParentGroupsOf(uuid);
- }
- }
-}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformRenameGroup.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformRenameGroup.java
deleted file mode 100644
index 3623cc3..0000000
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformRenameGroup.java
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright (C) 2011 The Android Open Source Project
-//
-// 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
-
-package com.google.gerrit.server.account;
-
-import com.google.gerrit.common.data.GroupDetail;
-import com.google.gerrit.common.errors.InvalidNameException;
-import com.google.gerrit.common.errors.NameAlreadyUsedException;
-import com.google.gerrit.common.errors.NoSuchGroupException;
-import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gerrit.reviewdb.client.AccountGroupName;
-import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.git.RenameGroupOp;
-import com.google.gwtorm.server.OrmException;
-import com.google.inject.Inject;
-
-import java.util.Collections;
-import java.util.Date;
-import java.util.TimeZone;
-import java.util.concurrent.TimeUnit;
-
-public class PerformRenameGroup {
-
- public interface Factory {
- PerformRenameGroup create();
- }
-
- private final ReviewDb db;
- private final GroupCache groupCache;
- private final GroupControl.Factory groupControlFactory;
- private final GroupDetailFactory.Factory groupDetailFactory;
- private final RenameGroupOp.Factory renameGroupOpFactory;
- private final IdentifiedUser currentUser;
-
- @Inject
- PerformRenameGroup(final ReviewDb db, final GroupCache groupCache,
- final GroupControl.Factory groupControlFactory,
- final GroupDetailFactory.Factory groupDetailFactory,
- final RenameGroupOp.Factory renameGroupOpFactory,
- final IdentifiedUser currentUser) {
- this.db = db;
- this.groupCache = groupCache;
- this.groupControlFactory = groupControlFactory;
- this.groupDetailFactory = groupDetailFactory;
- this.renameGroupOpFactory = renameGroupOpFactory;
- this.currentUser = currentUser;
- }
-
- public GroupDetail renameGroup(final String groupName,
- final String newGroupName) throws OrmException, NameAlreadyUsedException,
- NoSuchGroupException, InvalidNameException {
- final AccountGroup.NameKey groupNameKey =
- new AccountGroup.NameKey(groupName);
- final AccountGroup group = groupCache.get(groupNameKey);
- if (group == null) {
- throw new NoSuchGroupException(groupNameKey);
- }
- return renameGroup(group.getId(), newGroupName);
- }
-
- public GroupDetail renameGroup(final AccountGroup.Id groupId,
- final String newName) throws OrmException, NameAlreadyUsedException,
- NoSuchGroupException, InvalidNameException {
- final GroupControl ctl = groupControlFactory.validateFor(groupId);
- final AccountGroup group = db.accountGroups().get(groupId);
- if (group == null || !ctl.isOwner()) {
- throw new NoSuchGroupException(groupId);
- }
- if (newName.trim().isEmpty()) {
- throw new InvalidNameException();
- }
-
- final AccountGroup.NameKey old = group.getNameKey();
- final AccountGroup.NameKey key = new AccountGroup.NameKey(newName);
-
- try {
- final AccountGroupName id = new AccountGroupName(key, groupId);
- db.accountGroupNames().insert(Collections.singleton(id));
- } catch (OrmException e) {
- AccountGroupName other = db.accountGroupNames().get(key);
- if (other != null) {
- // If we are using this identity, don't report the exception.
- //
- if (other.getId().equals(groupId)) {
- return groupDetailFactory.create(groupId).call();
- }
-
- // Otherwise, someone else has this identity.
- //
- throw new NameAlreadyUsedException(newName);
- } else {
- throw e;
- }
- }
-
- group.setNameKey(key);
- db.accountGroups().update(Collections.singleton(group));
-
- AccountGroupName priorName = db.accountGroupNames().get(old);
- if (priorName != null) {
- db.accountGroupNames().delete(Collections.singleton(priorName));
- }
-
- groupCache.evict(group);
- groupCache.evictAfterRename(old, key);
- renameGroupOpFactory.create( //
- currentUser.newCommitterIdent(new Date(), TimeZone.getDefault()), //
- group.getGroupUUID(), //
- old.get(), newName).start(0, TimeUnit.MILLISECONDS);
-
- return groupDetailFactory.create(groupId).call();
- }
-}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/Realm.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/Realm.java
index 8dd8de7..056fa85b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/Realm.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/Realm.java
@@ -24,6 +24,9 @@
/** Can the end-user modify this field of their own account? */
public boolean allowsEdit(Account.FieldName field);
+ /** Returns the account fields that the end-user can modify. */
+ public Set<Account.FieldName> getEditableFields();
+
public AuthRequest authenticate(AuthRequest who) throws AccountException;
public AuthRequest link(ReviewDb db, Account.Id to, AuthRequest who)
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/SuggestAccounts.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/SuggestAccounts.java
index 07936d9..d181c35 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/SuggestAccounts.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/SuggestAccounts.java
@@ -39,7 +39,7 @@
import java.util.List;
import java.util.Map;
-class SuggestAccounts implements RestReadView<TopLevelResource> {
+public class SuggestAccounts implements RestReadView<TopLevelResource> {
private static final int MAX_RESULTS = 100;
private static final String MAX_SUFFIX = "\u9fa5";
@@ -50,9 +50,10 @@
private final int suggestFrom;
private int limit = 10;
+ private String query;
@Option(name = "--limit", aliases = {"-n"}, metaVar = "CNT", usage = "maximum number of users to return")
- void setLimit(int n) {
+ public void setLimit(int n) {
if (n < 0) {
limit = 10;
} else if (n == 0) {
@@ -63,7 +64,9 @@
}
@Option(name = "--query", aliases = {"-q"}, metaVar = "QUERY", usage = "match users")
- private String query;
+ public void setQuery(String query) {
+ this.query = query;
+ }
@Inject
SuggestAccounts(AccountControl.Factory accountControlFactory,
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/UniversalGroupBackend.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/UniversalGroupBackend.java
index 9b32ca9..4a652b4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/UniversalGroupBackend.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/UniversalGroupBackend.java
@@ -73,6 +73,9 @@
@Override
public GroupDescription.Basic get(AccountGroup.UUID uuid) {
+ if (uuid == null) {
+ return null;
+ }
GroupBackend b = backend(uuid);
if (b == null) {
log.warn("Unknown GroupBackend for UUID: " + uuid);
@@ -121,6 +124,9 @@
@Override
public boolean contains(AccountGroup.UUID uuid) {
+ if (uuid == null) {
+ return false;
+ }
GroupMembership m = membership(uuid);
if (m == null) {
log.warn("Unknown GroupMembership for UUID: " + uuid);
@@ -134,6 +140,9 @@
Multimap<GroupMembership, AccountGroup.UUID> lookups =
ArrayListMultimap.create();
for (AccountGroup.UUID uuid : uuids) {
+ if (uuid == null) {
+ continue;
+ }
GroupMembership m = membership(uuid);
if (m == null) {
log.warn("Unknown GroupMembership for UUID: " + uuid);
@@ -161,6 +170,9 @@
Multimap<GroupMembership, AccountGroup.UUID> lookups =
ArrayListMultimap.create();
for (AccountGroup.UUID uuid : uuids) {
+ if (uuid == null) {
+ continue;
+ }
GroupMembership m = membership(uuid);
if (m == null) {
log.warn("Unknown GroupMembership for UUID: " + uuid);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/VersionedAccountPreferences.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/VersionedAccountPreferences.java
index c4d4b06..da7d141 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/VersionedAccountPreferences.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/VersionedAccountPreferences.java
@@ -27,7 +27,6 @@
/** Preferences for user accounts. */
public class VersionedAccountPreferences extends VersionedMetaData {
- private static final String REFS_USER_DEFAULT = RefNames.REFS_USER + "default";
private static final String PREFERENCES = "preferences.config";
public static VersionedAccountPreferences forUser(Account.Id id) {
@@ -35,7 +34,7 @@
}
public static VersionedAccountPreferences forDefault() {
- return new VersionedAccountPreferences(REFS_USER_DEFAULT);
+ return new VersionedAccountPreferences(RefNames.REFS_USERS_DEFAULT);
}
private final String ref;
@@ -46,7 +45,7 @@
}
public boolean isDefaults() {
- return REFS_USER_DEFAULT.equals(getRefName());
+ return RefNames.REFS_USERS_DEFAULT.equals(getRefName());
}
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/VersionedAccountQueries.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/VersionedAccountQueries.java
new file mode 100644
index 0000000..b12e7ce
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/VersionedAccountQueries.java
@@ -0,0 +1,71 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.account;
+
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.RefNames;
+import com.google.gerrit.server.git.QueryList;
+import com.google.gerrit.server.git.ValidationError;
+import com.google.gerrit.server.git.VersionedMetaData;
+
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+
+/** Named Queries for user accounts. */
+public class VersionedAccountQueries extends VersionedMetaData {
+ private static final Logger log = LoggerFactory.getLogger(VersionedAccountQueries.class);
+
+ public static VersionedAccountQueries forUser(Account.Id id) {
+ return new VersionedAccountQueries(RefNames.refsUsers(id));
+ }
+
+ private final String ref;
+ private QueryList queryList;
+
+ private VersionedAccountQueries(String ref) {
+ this.ref = ref;
+ }
+
+ @Override
+ protected String getRefName() {
+ return ref;
+ }
+
+ public QueryList getQueryList() {
+ return queryList;
+ }
+
+ @Override
+ protected void onLoad() throws IOException, ConfigInvalidException {
+ ValidationError.Sink errors = new ValidationError.Sink() {
+ @Override
+ public void error(ValidationError error) {
+ log.error("Error parsing file " + QueryList.FILE_NAME + ": " +
+ error.getMessage());
+ }
+ };
+ queryList = QueryList.parse(readUTF8(QueryList.FILE_NAME), errors);
+ }
+
+ @Override
+ protected boolean onSave(CommitBuilder commit) throws IOException,
+ ConfigInvalidException {
+ throw new UnsupportedOperationException("Cannot yet save named queries");
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/GerritApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/GerritApiImpl.java
index 5f581c3..ee7e1a5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/GerritApiImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/GerritApiImpl.java
@@ -17,22 +17,26 @@
import com.google.gerrit.extensions.api.GerritApi;
import com.google.gerrit.extensions.api.accounts.Accounts;
import com.google.gerrit.extensions.api.changes.Changes;
+import com.google.gerrit.extensions.api.groups.Groups;
import com.google.gerrit.extensions.api.projects.Projects;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@Singleton
-class GerritApiImpl extends GerritApi.NotImplemented implements GerritApi {
+class GerritApiImpl implements GerritApi {
private final Accounts accounts;
private final Changes changes;
+ private final Groups groups;
private final Projects projects;
@Inject
GerritApiImpl(Accounts accounts,
Changes changes,
+ Groups groups,
Projects projects) {
this.accounts = accounts;
this.changes = changes;
+ this.groups = groups;
this.projects = projects;
}
@@ -47,6 +51,11 @@
}
@Override
+ public Groups groups() {
+ return groups;
+ }
+
+ @Override
public Projects projects() {
return projects;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/Module.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/Module.java
index 23f4b8d..c686415 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/Module.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/Module.java
@@ -22,8 +22,9 @@
protected void configure() {
bind(GerritApi.class).to(GerritApiImpl.class);
- install(new com.google.gerrit.server.api.changes.Module());
- install(new com.google.gerrit.server.api.projects.Module());
install(new com.google.gerrit.server.api.accounts.Module());
+ install(new com.google.gerrit.server.api.changes.Module());
+ install(new com.google.gerrit.server.api.groups.Module());
+ install(new com.google.gerrit.server.api.projects.Module());
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java
index 44413b7..7051617 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java
@@ -28,7 +28,7 @@
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
-public class AccountApiImpl extends AccountApi.NotImplemented implements AccountApi {
+public class AccountApiImpl implements AccountApi {
interface Factory {
AccountApiImpl create(AccountResource account);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountsImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountsImpl.java
index 0c02c99..3f578ae 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountsImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountsImpl.java
@@ -16,6 +16,7 @@
import com.google.gerrit.extensions.api.accounts.AccountApi;
import com.google.gerrit.extensions.api.accounts.Accounts;
+import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.extensions.restapi.RestApiException;
@@ -24,24 +25,30 @@
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.AccountResource;
import com.google.gerrit.server.account.AccountsCollection;
+import com.google.gerrit.server.account.SuggestAccounts;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
+import java.util.List;
+
@Singleton
-public class AccountsImpl extends Accounts.NotImplemented implements Accounts {
+public class AccountsImpl implements Accounts {
private final AccountsCollection accounts;
private final AccountApiImpl.Factory api;
private final Provider<CurrentUser> self;
+ private final Provider<SuggestAccounts> suggestAccountsProvider;
@Inject
AccountsImpl(AccountsCollection accounts,
AccountApiImpl.Factory api,
- Provider<CurrentUser> self) {
+ Provider<CurrentUser> self,
+ Provider<SuggestAccounts> suggestAccountsProvider) {
this.accounts = accounts;
this.api = api;
this.self = self;
+ this.suggestAccountsProvider = suggestAccountsProvider;
}
@Override
@@ -61,4 +68,32 @@
}
return api.create(new AccountResource((IdentifiedUser)self.get()));
}
+
+ @Override
+ public SuggestAccountsRequest suggestAccounts() throws RestApiException {
+ return new SuggestAccountsRequest() {
+ @Override
+ public List<AccountInfo> get() throws RestApiException {
+ return AccountsImpl.this.suggestAccounts(this);
+ }
+ };
+ }
+
+ @Override
+ public SuggestAccountsRequest suggestAccounts(String query)
+ throws RestApiException {
+ return suggestAccounts().withQuery(query);
+ }
+
+ private List<AccountInfo> suggestAccounts(SuggestAccountsRequest r)
+ throws RestApiException {
+ try {
+ SuggestAccounts mySuggestAccounts = suggestAccountsProvider.get();
+ mySuggestAccounts.setQuery(r.getQuery());
+ mySuggestAccounts.setLimit(r.getLimit());
+ return mySuggestAccounts.apply(TopLevelResource.INSTANCE);
+ } catch (OrmException e) {
+ throw new RestApiException("Cannot retrieve suggested accounts", e);
+ }
+ }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
index 161461d..78b3f10 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
@@ -26,11 +26,14 @@
import com.google.gerrit.extensions.api.changes.RevisionApi;
import com.google.gerrit.extensions.client.ListChangesOption;
import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.extensions.common.CommentInfo;
import com.google.gerrit.extensions.common.EditInfo;
import com.google.gerrit.extensions.common.SuggestedReviewerInfo;
import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.change.Abandon;
import com.google.gerrit.server.change.ChangeEdits;
import com.google.gerrit.server.change.ChangeJson;
@@ -38,6 +41,8 @@
import com.google.gerrit.server.change.Check;
import com.google.gerrit.server.change.GetHashtags;
import com.google.gerrit.server.change.GetTopic;
+import com.google.gerrit.server.change.ListChangeComments;
+import com.google.gerrit.server.change.ListChangeDrafts;
import com.google.gerrit.server.change.PostHashtags;
import com.google.gerrit.server.change.PostReviewers;
import com.google.gerrit.server.change.PutTopic;
@@ -54,13 +59,15 @@
import java.io.IOException;
import java.util.EnumSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
-class ChangeApiImpl extends ChangeApi.NotImplemented implements ChangeApi {
+class ChangeApiImpl implements ChangeApi {
interface Factory {
ChangeApiImpl create(ChangeResource change);
}
+ private final Provider<CurrentUser> user;
private final Changes changeApi;
private final Revisions revisions;
private final RevisionApiImpl.Factory revisionApi;
@@ -75,11 +82,14 @@
private final Provider<ChangeJson> changeJson;
private final PostHashtags postHashtags;
private final GetHashtags getHashtags;
+ private final ListChangeComments listComments;
+ private final ListChangeDrafts listDrafts;
private final Check check;
private final ChangeEdits.Detail editDetail;
@Inject
- ChangeApiImpl(Changes changeApi,
+ ChangeApiImpl(Provider<CurrentUser> user,
+ Changes changeApi,
Revisions revisions,
RevisionApiImpl.Factory revisionApi,
Provider<SuggestReviewers> suggestReviewers,
@@ -92,9 +102,12 @@
Provider<ChangeJson> changeJson,
PostHashtags postHashtags,
GetHashtags getHashtags,
+ ListChangeComments listComments,
+ ListChangeDrafts listDrafts,
Check check,
ChangeEdits.Detail editDetail,
@Assisted ChangeResource change) {
+ this.user = user;
this.changeApi = changeApi;
this.revert = revert;
this.revisions = revisions;
@@ -108,6 +121,8 @@
this.changeJson = changeJson;
this.postHashtags = postHashtags;
this.getHashtags = getHashtags;
+ this.listComments = listComments;
+ this.listDrafts = listDrafts;
this.check = check;
this.editDetail = editDetail;
this.change = change;
@@ -244,6 +259,10 @@
public ChangeInfo get(EnumSet<ListChangesOption> s)
throws RestApiException {
try {
+ CurrentUser u = user.get();
+ if (u.isIdentifiedUser()) {
+ ((IdentifiedUser) u).clearStarredChanges();
+ }
return changeJson.get().addOptions(s).format(change);
} catch (OrmException e) {
throw new RestApiException("Cannot retrieve change", e);
@@ -289,6 +308,24 @@
}
@Override
+ public Map<String, List<CommentInfo>> comments() throws RestApiException {
+ try {
+ return listComments.apply(change);
+ } catch (OrmException e) {
+ throw new RestApiException("Cannot get comments", e);
+ }
+ }
+
+ @Override
+ public Map<String, List<CommentInfo>> drafts() throws RestApiException {
+ try {
+ return listDrafts.apply(change);
+ } catch (OrmException e) {
+ throw new RestApiException("Cannot get drafts", e);
+ }
+ }
+
+ @Override
public ChangeInfo check() throws RestApiException {
try {
return check.apply(change).value();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangesImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangesImpl.java
index 91809ec..f7705a7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangesImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangesImpl.java
@@ -24,11 +24,12 @@
import com.google.gerrit.extensions.client.ListChangesOption;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.restapi.AuthException;
-import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.TopLevelResource;
import com.google.gerrit.extensions.restapi.Url;
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.change.ChangesCollection;
import com.google.gerrit.server.change.CreateChange;
import com.google.gerrit.server.project.InvalidChangeOperationException;
@@ -43,16 +44,19 @@
@Singleton
class ChangesImpl implements Changes {
+ private final Provider<CurrentUser> user;
private final ChangesCollection changes;
private final ChangeApiImpl.Factory api;
private final CreateChange createChange;
private final Provider<QueryChanges> queryProvider;
@Inject
- ChangesImpl(ChangesCollection changes,
+ ChangesImpl(Provider<CurrentUser> user,
+ ChangesCollection changes,
ChangeApiImpl.Factory api,
CreateChange createChange,
Provider<QueryChanges> queryProvider) {
+ this.user = user;
this.changes = changes;
this.api = api;
this.createChange = createChange;
@@ -123,6 +127,10 @@
}
try {
+ CurrentUser u = user.get();
+ if (u.isIdentifiedUser()) {
+ ((IdentifiedUser) u).clearStarredChanges();
+ }
List<?> result = qc.apply(TopLevelResource.INSTANCE);
if (result.isEmpty()) {
return ImmutableList.of();
@@ -136,7 +144,7 @@
List<ChangeInfo> infos = (List<ChangeInfo>) result;
return ImmutableList.copyOf(infos);
- } catch (BadRequestException | AuthException | OrmException e) {
+ } catch (AuthException | OrmException e) {
throw new RestApiException("Cannot query changes", e);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/FileApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/FileApiImpl.java
index 42c1e23..c09890f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/FileApiImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/FileApiImpl.java
@@ -30,7 +30,7 @@
import java.io.IOException;
-class FileApiImpl extends FileApi.NotImplemented implements FileApi {
+class FileApiImpl implements FileApi {
interface Factory {
FileApiImpl create(FileResource r);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java
index c36faa2..1b420f7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java
@@ -27,6 +27,7 @@
import com.google.gerrit.extensions.api.changes.ReviewInput;
import com.google.gerrit.extensions.api.changes.RevisionApi;
import com.google.gerrit.extensions.api.changes.SubmitInput;
+import com.google.gerrit.extensions.common.ActionInfo;
import com.google.gerrit.extensions.common.CommentInfo;
import com.google.gerrit.extensions.common.FileInfo;
import com.google.gerrit.extensions.common.MergeableInfo;
@@ -40,16 +41,17 @@
import com.google.gerrit.server.change.DraftComments;
import com.google.gerrit.server.change.FileResource;
import com.google.gerrit.server.change.Files;
-import com.google.gerrit.server.change.ListComments;
-import com.google.gerrit.server.change.ListDraftComments;
+import com.google.gerrit.server.change.GetRevisionActions;
+import com.google.gerrit.server.change.ListRevisionComments;
+import com.google.gerrit.server.change.ListRevisionDrafts;
import com.google.gerrit.server.change.Mergeable;
import com.google.gerrit.server.change.PostReview;
import com.google.gerrit.server.change.PublishDraftPatchSet;
import com.google.gerrit.server.change.Rebase;
+import com.google.gerrit.server.change.RebaseChange;
import com.google.gerrit.server.change.Reviewed;
import com.google.gerrit.server.change.RevisionResource;
import com.google.gerrit.server.change.Submit;
-import com.google.gerrit.server.changedetail.RebaseChange;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -60,7 +62,7 @@
import java.util.Map;
import java.util.Set;
-class RevisionApiImpl extends RevisionApi.NotImplemented implements RevisionApi {
+class RevisionApiImpl implements RevisionApi {
interface Factory {
RevisionApiImpl create(RevisionResource r);
}
@@ -80,13 +82,14 @@
private final Provider<PostReview> review;
private final Provider<Mergeable> mergeable;
private final FileApiImpl.Factory fileApi;
- private final ListComments listComments;
- private final ListDraftComments listDrafts;
+ private final ListRevisionComments listComments;
+ private final ListRevisionDrafts listDrafts;
private final CreateDraftComment createDraft;
private final DraftComments drafts;
private final DraftApiImpl.Factory draftFactory;
private final Comments comments;
private final CommentApiImpl.Factory commentFactory;
+ private final GetRevisionActions revisionActions;
@Inject
RevisionApiImpl(Changes changes,
@@ -103,13 +106,14 @@
Provider<PostReview> review,
Provider<Mergeable> mergeable,
FileApiImpl.Factory fileApi,
- ListComments listComments,
- ListDraftComments listDrafts,
+ ListRevisionComments listComments,
+ ListRevisionDrafts listDrafts,
CreateDraftComment createDraft,
DraftComments drafts,
DraftApiImpl.Factory draftFactory,
Comments comments,
CommentApiImpl.Factory commentFactory,
+ GetRevisionActions revisionActions,
@Assisted RevisionResource r) {
this.changes = changes;
this.cherryPick = cherryPick;
@@ -132,6 +136,7 @@
this.draftFactory = draftFactory;
this.comments = comments;
this.commentFactory = commentFactory;
+ this.revisionActions = revisionActions;
this.revision = r;
}
@@ -188,7 +193,7 @@
public ChangeApi rebase(RebaseInput in) throws RestApiException {
try {
return changes.id(rebase.apply(revision, in)._number);
- } catch (OrmException | EmailException e) {
+ } catch (OrmException | EmailException | IOException e) {
throw new RestApiException("Cannot rebase ps", e);
}
}
@@ -293,6 +298,15 @@
}
@Override
+ public List<CommentInfo> commentsAsList() throws RestApiException {
+ try {
+ return listComments.getComments(revision);
+ } catch (OrmException e) {
+ throw new RestApiException("Cannot retrieve comments", e);
+ }
+ }
+
+ @Override
public Map<String, List<CommentInfo>> drafts() throws RestApiException {
try {
return listDrafts.apply(revision);
@@ -302,6 +316,15 @@
}
@Override
+ public List<CommentInfo> draftsAsList() throws RestApiException {
+ try {
+ return listDrafts.getComments(revision);
+ } catch (OrmException e) {
+ throw new RestApiException("Cannot retrieve drafts", e);
+ }
+ }
+
+ @Override
public DraftApi draft(String id) throws RestApiException {
try {
return draftFactory.create(drafts.parse(revision,
@@ -314,7 +337,11 @@
@Override
public DraftApi createDraft(DraftInput in) throws RestApiException {
try {
- return draft(createDraft.apply(revision, in).value().id);
+ String id = createDraft.apply(revision, in).value().id;
+ // Reread change to pick up new notes refs.
+ return changes.id(revision.getChange().getId().get())
+ .revision(revision.getPatchSet().getId().get())
+ .draft(id);
} catch (IOException | OrmException e) {
throw new RestApiException("Cannot create draft", e);
}
@@ -329,4 +356,9 @@
throw new RestApiException("Cannot retrieve comment", e);
}
}
+
+ @Override
+ public Map<String, ActionInfo> actions() throws RestApiException {
+ return revisionActions.apply(revision).value();
+ }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/groups/GroupApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/groups/GroupApiImpl.java
new file mode 100644
index 0000000..b7c8cd9
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/groups/GroupApiImpl.java
@@ -0,0 +1,261 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.api.groups;
+
+import com.google.gerrit.common.errors.NoSuchGroupException;
+import com.google.gerrit.extensions.api.groups.GroupApi;
+import com.google.gerrit.extensions.common.AccountInfo;
+import com.google.gerrit.extensions.common.GroupInfo;
+import com.google.gerrit.extensions.common.GroupOptionsInfo;
+import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.server.group.AddIncludedGroups;
+import com.google.gerrit.server.group.AddMembers;
+import com.google.gerrit.server.group.DeleteIncludedGroups;
+import com.google.gerrit.server.group.DeleteMembers;
+import com.google.gerrit.server.group.GetDescription;
+import com.google.gerrit.server.group.GetDetail;
+import com.google.gerrit.server.group.GetGroup;
+import com.google.gerrit.server.group.GetName;
+import com.google.gerrit.server.group.GetOptions;
+import com.google.gerrit.server.group.GetOwner;
+import com.google.gerrit.server.group.GroupResource;
+import com.google.gerrit.server.group.ListIncludedGroups;
+import com.google.gerrit.server.group.ListMembers;
+import com.google.gerrit.server.group.PutDescription;
+import com.google.gerrit.server.group.PutName;
+import com.google.gerrit.server.group.PutOptions;
+import com.google.gerrit.server.group.PutOwner;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Provider;
+import com.google.inject.assistedinject.Assisted;
+import com.google.inject.assistedinject.AssistedInject;
+
+import java.util.Arrays;
+import java.util.List;
+
+class GroupApiImpl implements GroupApi {
+ interface Factory {
+ GroupApiImpl create(GroupResource rsrc);
+ }
+
+ private final GetGroup getGroup;
+ private final GetDetail getDetail;
+ private final GetName getName;
+ private final PutName putName;
+ private final GetOwner getOwner;
+ private final PutOwner putOwner;
+ private final GetDescription getDescription;
+ private final PutDescription putDescription;
+ private final GetOptions getOptions;
+ private final PutOptions putOptions;
+ private final Provider<ListMembers> listMembers;
+ private final AddMembers addMembers;
+ private final DeleteMembers deleteMembers;
+ private final ListIncludedGroups listGroups;
+ private final AddIncludedGroups addGroups;
+ private final DeleteIncludedGroups deleteGroups;
+ private final GroupResource rsrc;
+
+ @AssistedInject
+ GroupApiImpl(
+ GetGroup getGroup,
+ GetDetail getDetail,
+ GetName getName,
+ PutName putName,
+ GetOwner getOwner,
+ PutOwner putOwner,
+ GetDescription getDescription,
+ PutDescription putDescription,
+ GetOptions getOptions,
+ PutOptions putOptions,
+ Provider<ListMembers> listMembers,
+ AddMembers addMembers,
+ DeleteMembers deleteMembers,
+ ListIncludedGroups listGroups,
+ AddIncludedGroups addGroups,
+ DeleteIncludedGroups deleteGroups,
+ @Assisted GroupResource rsrc) {
+ this.getGroup = getGroup;
+ this.getDetail = getDetail;
+ this.getName = getName;
+ this.putName = putName;
+ this.getOwner = getOwner;
+ this.putOwner = putOwner;
+ this.getDescription = getDescription;
+ this.putDescription = putDescription;
+ this.getOptions = getOptions;
+ this.putOptions = putOptions;
+ this.listMembers = listMembers;
+ this.addMembers = addMembers;
+ this.deleteMembers = deleteMembers;
+ this.listGroups = listGroups;
+ this.addGroups = addGroups;
+ this.deleteGroups = deleteGroups;
+ this.rsrc = rsrc;
+ }
+
+ @Override
+ public GroupInfo get() throws RestApiException {
+ try {
+ return getGroup.apply(rsrc);
+ } catch (OrmException e) {
+ throw new RestApiException("Cannot retrieve group", e);
+ }
+ }
+
+ @Override
+ public GroupInfo detail() throws RestApiException {
+ try {
+ return getDetail.apply(rsrc);
+ } catch (OrmException e) {
+ throw new RestApiException("Cannot retrieve group", e);
+ }
+ }
+
+ @Override
+ public String name() throws RestApiException {
+ return getName.apply(rsrc);
+ }
+
+ @Override
+ public void name(String name) throws RestApiException {
+ PutName.Input in = new PutName.Input();
+ in.name = name;
+ try {
+ putName.apply(rsrc, in);
+ } catch (NoSuchGroupException e) {
+ throw new ResourceNotFoundException(name, e);
+ } catch (OrmException e) {
+ throw new RestApiException("Cannot put group name", e);
+ }
+ }
+
+ @Override
+ public GroupInfo owner() throws RestApiException {
+ try {
+ return getOwner.apply(rsrc);
+ } catch (OrmException e) {
+ throw new RestApiException("Cannot get group owner", e);
+ }
+ }
+
+ @Override
+ public void owner(String owner) throws RestApiException {
+ PutOwner.Input in = new PutOwner.Input();
+ in.owner = owner;
+ try {
+ putOwner.apply(rsrc, in);
+ } catch (OrmException e) {
+ throw new RestApiException("Cannot put group owner", e);
+ }
+ }
+
+ @Override
+ public String description() throws RestApiException {
+ return getDescription.apply(rsrc);
+ }
+
+ @Override
+ public void description(String description) throws RestApiException {
+ PutDescription.Input in = new PutDescription.Input();
+ in.description = description;
+ try {
+ putDescription.apply(rsrc, in);
+ } catch (OrmException e) {
+ throw new RestApiException("Cannot put group description", e);
+ }
+ }
+
+ @Override
+ public GroupOptionsInfo options() throws RestApiException {
+ return getOptions.apply(rsrc);
+ }
+
+ @Override
+ public void options(GroupOptionsInfo options) throws RestApiException {
+ try {
+ putOptions.apply(rsrc, options);
+ } catch (OrmException e) {
+ throw new RestApiException("Cannot put group options", e);
+ }
+ }
+
+ @Override
+ public List<AccountInfo> members() throws RestApiException {
+ return members(false);
+ }
+
+ @Override
+ public List<AccountInfo> members(boolean recursive) throws RestApiException {
+ ListMembers list = listMembers.get();
+ list.setRecursive(recursive);
+ try {
+ return list.apply(rsrc);
+ } catch (OrmException e) {
+ throw new RestApiException("Cannot list group members", e);
+ }
+ }
+
+ @Override
+ public void addMembers(String... members) throws RestApiException {
+ try {
+ addMembers.apply(
+ rsrc, AddMembers.Input.fromMembers(Arrays.asList(members)));
+ } catch (OrmException e) {
+ throw new RestApiException("Cannot add group members", e);
+ }
+ }
+
+ @Override
+ public void removeMembers(String... members) throws RestApiException {
+ try {
+ deleteMembers.apply(
+ rsrc, AddMembers.Input.fromMembers(Arrays.asList(members)));
+ } catch (OrmException e) {
+ throw new RestApiException("Cannot remove group members", e);
+ }
+ }
+
+ @Override
+ public List<GroupInfo> includedGroups() throws RestApiException {
+ try {
+ return listGroups.apply(rsrc);
+ } catch (OrmException e) {
+ throw new RestApiException("Cannot list included groups", e);
+ }
+ }
+
+ @Override
+ public void addGroups(String... groups) throws RestApiException {
+ try {
+ addGroups.apply(
+ rsrc, AddIncludedGroups.Input.fromGroups(Arrays.asList(groups)));
+ } catch (OrmException e) {
+ throw new RestApiException("Cannot add group members", e);
+ }
+ }
+
+ @Override
+ public void removeGroups(String... groups) throws RestApiException {
+ try {
+ deleteGroups.apply(
+ rsrc, AddIncludedGroups.Input.fromGroups(Arrays.asList(groups)));
+ } catch (OrmException e) {
+ throw new RestApiException("Cannot remove group members", e);
+ }
+ }
+
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/groups/GroupsImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/groups/GroupsImpl.java
new file mode 100644
index 0000000..97ba5d3
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/groups/GroupsImpl.java
@@ -0,0 +1,147 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.api.groups;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.gerrit.server.account.CapabilityUtils.checkRequiresCapability;
+
+import com.google.gerrit.extensions.api.groups.GroupApi;
+import com.google.gerrit.extensions.api.groups.GroupInput;
+import com.google.gerrit.extensions.api.groups.Groups;
+import com.google.gerrit.extensions.common.GroupInfo;
+import com.google.gerrit.extensions.restapi.BadRequestException;
+import com.google.gerrit.extensions.restapi.IdString;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.extensions.restapi.TopLevelResource;
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.account.AccountsCollection;
+import com.google.gerrit.server.group.CreateGroup;
+import com.google.gerrit.server.group.GroupsCollection;
+import com.google.gerrit.server.group.ListGroups;
+import com.google.gerrit.server.project.ProjectsCollection;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
+import java.io.IOException;
+import java.util.SortedMap;
+
+@Singleton
+class GroupsImpl implements Groups {
+ private final AccountsCollection accounts;
+ private final GroupsCollection groups;
+ private final ProjectsCollection projects;
+ private final Provider<ListGroups> listGroups;
+ private final Provider<CurrentUser> user;
+ private final CreateGroup.Factory createGroup;
+ private final GroupApiImpl.Factory api;
+
+ @Inject
+ GroupsImpl(
+ AccountsCollection accounts,
+ GroupsCollection groups,
+ ProjectsCollection projects,
+ Provider<ListGroups> listGroups,
+ Provider<CurrentUser> user,
+ CreateGroup.Factory createGroup,
+ GroupApiImpl.Factory api) {
+ this.accounts = accounts;
+ this.groups = groups;
+ this.projects = projects;
+ this.listGroups = listGroups;
+ this.user = user;
+ this.createGroup = createGroup;
+ this.api = api;
+ }
+
+ @Override
+ public GroupApi id(String id) throws RestApiException {
+ return api.create(
+ groups.parse(TopLevelResource.INSTANCE, IdString.fromDecoded(id)));
+ }
+
+ @Override
+ public GroupApi create(String name) throws RestApiException {
+ GroupInput in = new GroupInput();
+ in.name = name;
+ return create(in);
+ }
+
+ @Override
+ public GroupApi create(GroupInput in) throws RestApiException {
+ if (checkNotNull(in, "GroupInput").name == null) {
+ throw new BadRequestException("GroupInput must specify name");
+ }
+ checkRequiresCapability(user, null, CreateGroup.class);
+ try {
+ GroupInfo info = createGroup.create(in.name)
+ .apply(TopLevelResource.INSTANCE, in);
+ return id(info.id);
+ } catch (OrmException e) {
+ throw new RestApiException("Cannot create group " + in.name, e);
+ }
+ }
+
+ @Override
+ public ListRequest list() {
+ return new ListRequest() {
+ @Override
+ public SortedMap<String, GroupInfo> getAsMap() throws RestApiException {
+ return list(this);
+ }
+ };
+ }
+
+ private SortedMap<String, GroupInfo> list(ListRequest req)
+ throws RestApiException {
+ TopLevelResource tlr = TopLevelResource.INSTANCE;
+ ListGroups list = listGroups.get();
+ list.setOptions(req.getOptions());
+
+ for (String project : req.getProjects()) {
+ try {
+ list.addProject(
+ projects.parse(tlr, IdString.fromDecoded(project)).getControl());
+ } catch (IOException e) {
+ throw new RestApiException("Error looking up project " + project, e);
+ }
+ }
+
+ for (String group : req.getGroups()) {
+ list.addGroup(groups.parse(group).getGroupUUID());
+ }
+
+ list.setVisibleToAll(req.getVisibleToAll());
+
+ if (req.getUser() != null) {
+ try {
+ list.setUser(accounts.parse(req.getUser()).getAccountId());
+ } catch (OrmException e) {
+ throw new RestApiException("Error looking up user " + req.getUser(), e);
+ }
+ }
+
+ list.setOwned(req.getOwned());
+ list.setLimit(req.getLimit());
+ list.setStart(req.getStart());
+ list.setMatchSubstring(req.getSubstring());
+ try {
+ return list.apply(tlr);
+ } catch (OrmException e) {
+ throw new RestApiException("Cannot list groups", e);
+ }
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/groups/Module.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/groups/Module.java
new file mode 100644
index 0000000..dae08cd
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/groups/Module.java
@@ -0,0 +1,27 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.api.groups;
+
+import com.google.gerrit.extensions.api.groups.Groups;
+import com.google.gerrit.server.config.FactoryModule;
+
+public class Module extends FactoryModule {
+ @Override
+ protected void configure() {
+ bind(Groups.class).to(GroupsImpl.class);
+
+ factory(GroupApiImpl.Factory.class);
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/BranchApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/BranchApiImpl.java
index f4dc67e..0bb395f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/BranchApiImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/BranchApiImpl.java
@@ -15,30 +15,41 @@
package com.google.gerrit.server.api.projects;
import com.google.gerrit.extensions.api.projects.BranchApi;
+import com.google.gerrit.extensions.api.projects.BranchInfo;
import com.google.gerrit.extensions.api.projects.BranchInput;
+import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.server.project.BranchResource;
+import com.google.gerrit.server.project.BranchesCollection;
import com.google.gerrit.server.project.CreateBranch;
+import com.google.gerrit.server.project.DeleteBranch;
import com.google.gerrit.server.project.ProjectResource;
+import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import java.io.IOException;
-public class BranchApiImpl extends BranchApi.NotImplemented implements BranchApi {
+public class BranchApiImpl implements BranchApi {
interface Factory {
BranchApiImpl create(ProjectResource project, String ref);
}
+ private final BranchesCollection branches;
private final CreateBranch.Factory createBranchFactory;
+ private final DeleteBranch deleteBranch;
private final String ref;
private final ProjectResource project;
@Inject
- BranchApiImpl(
+ BranchApiImpl(BranchesCollection branches,
CreateBranch.Factory createBranchFactory,
+ DeleteBranch deleteBranch,
@Assisted ProjectResource project,
@Assisted String ref) {
+ this.branches = branches;
this.createBranchFactory = createBranchFactory;
+ this.deleteBranch = deleteBranch;
this.project = project;
this.ref = ref;
}
@@ -55,4 +66,26 @@
throw new RestApiException("Cannot create branch", e);
}
}
+
+ @Override
+ public BranchInfo get() throws RestApiException {
+ try {
+ return resource().getBranchInfo();
+ } catch (IOException e) {
+ throw new RestApiException("Cannot read branch", e);
+ }
+ }
+
+ @Override
+ public void delete() throws RestApiException {
+ try {
+ deleteBranch.apply(resource(), new DeleteBranch.Input());
+ } catch (OrmException | IOException e) {
+ throw new RestApiException("Cannot delete branch", e);
+ }
+ }
+
+ private BranchResource resource() throws RestApiException, IOException {
+ return branches.parse(project, IdString.fromDecoded(ref));
+ }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ChildProjectApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ChildProjectApiImpl.java
new file mode 100644
index 0000000..02dc919
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ChildProjectApiImpl.java
@@ -0,0 +1,53 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.api.projects;
+
+import com.google.gerrit.extensions.api.projects.ChildProjectApi;
+import com.google.gerrit.extensions.common.ProjectInfo;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.server.project.ChildProjectResource;
+import com.google.gerrit.server.project.GetChildProject;
+import com.google.inject.Provider;
+import com.google.inject.assistedinject.Assisted;
+import com.google.inject.assistedinject.AssistedInject;
+
+public class ChildProjectApiImpl implements ChildProjectApi {
+ interface Factory {
+ ChildProjectApiImpl create(ChildProjectResource rsrc);
+ }
+
+ private final Provider<GetChildProject> getProvider;
+ private final ChildProjectResource rsrc;
+
+ @AssistedInject
+ ChildProjectApiImpl(
+ Provider<GetChildProject> getProvider,
+ @Assisted ChildProjectResource rsrc) {
+ this.getProvider = getProvider;
+ this.rsrc = rsrc;
+ }
+
+ @Override
+ public ProjectInfo get() throws RestApiException {
+ return get(false);
+ }
+
+ @Override
+ public ProjectInfo get(boolean recursive) throws RestApiException {
+ GetChildProject get = getProvider.get();
+ get.setRecursive(recursive);
+ return get.apply(rsrc);
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/Module.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/Module.java
index 0b7e258..2e6b761 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/Module.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/Module.java
@@ -24,5 +24,6 @@
factory(BranchApiImpl.Factory.class);
factory(ProjectApiImpl.Factory.class);
+ factory(ChildProjectApiImpl.Factory.class);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectApiImpl.java
index 7f73a38..84b219b5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectApiImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectApiImpl.java
@@ -14,78 +14,122 @@
package com.google.gerrit.server.api.projects;
-import com.google.common.base.Preconditions;
-import com.google.gerrit.common.errors.ProjectCreationFailedException;
+import static com.google.gerrit.server.account.CapabilityUtils.checkRequiresCapability;
+
import com.google.gerrit.extensions.api.projects.BranchApi;
+import com.google.gerrit.extensions.api.projects.BranchInfo;
+import com.google.gerrit.extensions.api.projects.ChildProjectApi;
import com.google.gerrit.extensions.api.projects.ProjectApi;
import com.google.gerrit.extensions.api.projects.ProjectInput;
+import com.google.gerrit.extensions.api.projects.PutDescriptionInput;
import com.google.gerrit.extensions.common.ProjectInfo;
import com.google.gerrit.extensions.restapi.BadRequestException;
+import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.TopLevelResource;
-import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.project.ChildProjectsCollection;
import com.google.gerrit.server.project.CreateProject;
+import com.google.gerrit.server.project.GetDescription;
+import com.google.gerrit.server.project.ListBranches;
+import com.google.gerrit.server.project.ListChildProjects;
import com.google.gerrit.server.project.ProjectJson;
import com.google.gerrit.server.project.ProjectResource;
import com.google.gerrit.server.project.ProjectsCollection;
+import com.google.gerrit.server.project.PutDescription;
import com.google.inject.Provider;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
-import java.io.IOException;
+import org.eclipse.jgit.errors.ConfigInvalidException;
-public class ProjectApiImpl extends ProjectApi.NotImplemented implements ProjectApi {
+import java.io.IOException;
+import java.util.List;
+
+public class ProjectApiImpl implements ProjectApi {
interface Factory {
ProjectApiImpl create(ProjectResource project);
ProjectApiImpl create(String name);
}
+ private final Provider<CurrentUser> user;
private final Provider<CreateProject.Factory> createProjectFactory;
private final ProjectApiImpl.Factory projectApi;
private final ProjectsCollection projects;
+ private final GetDescription getDescription;
+ private final PutDescription putDescription;
+ private final ChildProjectApiImpl.Factory childApi;
+ private final ChildProjectsCollection children;
private final ProjectResource project;
private final ProjectJson projectJson;
private final String name;
private final BranchApiImpl.Factory branchApi;
+ private final Provider<ListBranches> listBranchesProvider;
@AssistedInject
- ProjectApiImpl(Provider<CreateProject.Factory> createProjectFactory,
+ ProjectApiImpl(Provider<CurrentUser> user,
+ Provider<CreateProject.Factory> createProjectFactory,
ProjectApiImpl.Factory projectApi,
ProjectsCollection projects,
+ GetDescription getDescription,
+ PutDescription putDescription,
+ ChildProjectApiImpl.Factory childApi,
+ ChildProjectsCollection children,
ProjectJson projectJson,
BranchApiImpl.Factory branchApiFactory,
+ Provider<ListBranches> listBranchesProvider,
@Assisted ProjectResource project) {
- this(createProjectFactory, projectApi, projects, projectJson,
- branchApiFactory, project, null);
+ this(user, createProjectFactory, projectApi, projects, getDescription,
+ putDescription, childApi, children, projectJson, branchApiFactory,
+ listBranchesProvider, project, null);
}
@AssistedInject
- ProjectApiImpl(Provider<CreateProject.Factory> createProjectFactory,
+ ProjectApiImpl(Provider<CurrentUser> user,
+ Provider<CreateProject.Factory> createProjectFactory,
ProjectApiImpl.Factory projectApi,
ProjectsCollection projects,
+ GetDescription getDescription,
+ PutDescription putDescription,
+ ChildProjectApiImpl.Factory childApi,
+ ChildProjectsCollection children,
ProjectJson projectJson,
BranchApiImpl.Factory branchApiFactory,
+ Provider<ListBranches> listBranchesProvider,
@Assisted String name) {
- this(createProjectFactory, projectApi, projects, projectJson,
- branchApiFactory, null, name);
+ this(user, createProjectFactory, projectApi, projects, getDescription,
+ putDescription, childApi, children, projectJson, branchApiFactory,
+ listBranchesProvider, null, name);
}
- private ProjectApiImpl(Provider<CreateProject.Factory> createProjectFactory,
+ private ProjectApiImpl(Provider<CurrentUser> user,
+ Provider<CreateProject.Factory> createProjectFactory,
ProjectApiImpl.Factory projectApi,
ProjectsCollection projects,
+ GetDescription getDescription,
+ PutDescription putDescription,
+ ChildProjectApiImpl.Factory childApi,
+ ChildProjectsCollection children,
ProjectJson projectJson,
BranchApiImpl.Factory branchApiFactory,
+ Provider<ListBranches> listBranchesProvider,
ProjectResource project,
String name) {
+ this.user = user;
this.createProjectFactory = createProjectFactory;
this.projectApi = projectApi;
this.projects = projects;
+ this.getDescription = getDescription;
+ this.putDescription = putDescription;
+ this.childApi = childApi;
+ this.children = children;
this.projectJson = projectJson;
this.project = project;
this.name = name;
this.branchApi = branchApiFactory;
+ this.listBranchesProvider = listBranchesProvider;
}
@Override
@@ -102,24 +146,93 @@
if (in.name != null && !name.equals(in.name)) {
throw new BadRequestException("name must match input.name");
}
+ checkRequiresCapability(user, null, CreateProject.class);
createProjectFactory.get().create(name)
.apply(TopLevelResource.INSTANCE, in);
return projectApi.create(projects.parse(name));
- } catch (BadRequestException | UnprocessableEntityException
- | ResourceNotFoundException | ProjectCreationFailedException
- | IOException e) {
+ } catch (IOException | ConfigInvalidException e) {
throw new RestApiException("Cannot create project: " + e.getMessage(), e);
}
}
@Override
- public ProjectInfo get() {
- Preconditions.checkNotNull(project);
+ public ProjectInfo get() throws RestApiException {
+ if (project == null) {
+ throw new ResourceNotFoundException(name);
+ }
return projectJson.format(project);
}
@Override
- public BranchApi branch(String ref) {
- return branchApi.create(project, ref);
+ public String description() throws RestApiException {
+ return getDescription.apply(checkExists());
+ }
+
+ @Override
+ public void description(PutDescriptionInput in)
+ throws RestApiException {
+ try {
+ putDescription.apply(checkExists(), in);
+ } catch (IOException e) {
+ throw new RestApiException("Cannot put project description", e);
+ }
+ }
+
+ @Override
+ public ListBranchesRequest branches() {
+ return new ListBranchesRequest() {
+ @Override
+ public List<BranchInfo> get() throws RestApiException {
+ return listBranches(this);
+ }
+ };
+ }
+
+ private List<BranchInfo> listBranches(ListBranchesRequest request)
+ throws RestApiException {
+ ListBranches list = listBranchesProvider.get();
+ list.setLimit(request.getLimit());
+ list.setStart(request.getStart());
+ list.setMatchSubstring(request.getSubstring());
+ list.setMatchRegex(request.getRegex());
+ try {
+ return list.apply(checkExists());
+ } catch (IOException e) {
+ throw new RestApiException("Cannot list branches", e);
+ }
+ }
+
+ @Override
+ public List<ProjectInfo> children() throws RestApiException {
+ return children(false);
+ }
+
+ @Override
+ public List<ProjectInfo> children(boolean recursive) throws RestApiException {
+ ListChildProjects list = children.list();
+ list.setRecursive(recursive);
+ return list.apply(checkExists());
+ }
+
+ @Override
+ public ChildProjectApi child(String name) throws RestApiException {
+ try {
+ return childApi.create(
+ children.parse(checkExists(), IdString.fromDecoded(name)));
+ } catch (IOException e) {
+ throw new RestApiException("Cannot parse child project", e);
+ }
+ }
+
+ @Override
+ public BranchApi branch(String ref) throws ResourceNotFoundException {
+ return branchApi.create(checkExists(), ref);
+ }
+
+ private ProjectResource checkExists() throws ResourceNotFoundException {
+ if (project == null) {
+ throw new ResourceNotFoundException(name);
+ }
+ return project;
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectsImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectsImpl.java
index 86baa1e..db31d42 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectsImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectsImpl.java
@@ -14,23 +14,25 @@
package com.google.gerrit.server.api.projects;
-import com.google.common.collect.ImmutableList;
import com.google.gerrit.extensions.api.projects.ProjectApi;
+import com.google.gerrit.extensions.api.projects.ProjectInput;
import com.google.gerrit.extensions.api.projects.Projects;
import com.google.gerrit.extensions.common.ProjectInfo;
+import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.server.project.ListProjects;
+import com.google.gerrit.server.project.ListProjects.FilterType;
import com.google.gerrit.server.project.ProjectsCollection;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.io.IOException;
-import java.util.List;
+import java.util.SortedMap;
@Singleton
-class ProjectsImpl extends Projects.NotImplemented implements Projects {
+class ProjectsImpl implements Projects {
private final ProjectsCollection projects;
private final ProjectApiImpl.Factory api;
private final Provider<ListProjects> listProvider;
@@ -56,22 +58,62 @@
}
@Override
+ public ProjectApi create(String name) throws RestApiException {
+ ProjectInput in = new ProjectInput();
+ in.name = name;
+ return create(in);
+ }
+
+ @Override
+ public ProjectApi create(ProjectInput in) throws RestApiException {
+ return name(in.name).create(in);
+ }
+
+ @Override
public ListRequest list() {
return new ListRequest() {
@Override
- public List<ProjectInfo> get() throws RestApiException {
+ public SortedMap<String, ProjectInfo> getAsMap() throws RestApiException {
return list(this);
}
};
}
- private List<ProjectInfo> list(ListRequest request) throws RestApiException {
+ private SortedMap<String, ProjectInfo> list(ListRequest request)
+ throws RestApiException {
ListProjects lp = listProvider.get();
lp.setShowDescription(request.getDescription());
lp.setLimit(request.getLimit());
lp.setStart(request.getStart());
lp.setMatchPrefix(request.getPrefix());
- return ImmutableList.copyOf(lp.apply().values());
+ lp.setMatchSubstring(request.getSubstring());
+ lp.setMatchRegex(request.getRegex());
+ lp.setShowTree(request.getShowTree());
+ for (String branch : request.getBranches()) {
+ lp.addShowBranch(branch);
+ }
+
+ FilterType type;
+ switch (request.getFilterType()) {
+ case ALL:
+ type = FilterType.ALL;
+ break;
+ case CODE:
+ type = FilterType.CODE;
+ break;
+ case PARENT_CANDIDATES:
+ type = FilterType.PARENT_CANDIDATES;
+ break;
+ case PERMISSIONS:
+ type = FilterType.PERMISSIONS;
+ break;
+ default:
+ throw new BadRequestException(
+ "Unknown filter type: " + request.getFilterType());
+ }
+ lp.setFilterType(type);
+
+ return lp.apply();
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/args4j/ChangeIdHandler.java b/gerrit-server/src/main/java/com/google/gerrit/server/args4j/ChangeIdHandler.java
index 1cbab8a..00eaf94 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/args4j/ChangeIdHandler.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/args4j/ChangeIdHandler.java
@@ -57,8 +57,7 @@
try {
final Change.Key key = Change.Key.parse(tokens[2]);
final Project.NameKey project = new Project.NameKey(tokens[0]);
- final Branch.NameKey branch =
- new Branch.NameKey(project, "refs/heads/" + tokens[1]);
+ final Branch.NameKey branch = new Branch.NameKey(project, tokens[1]);
for (final ChangeData cd : queryProvider.get().byBranchKey(branch, key)) {
setter.addValue(cd.getId());
return 1;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapRealm.java b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapRealm.java
index 9060108..3607e34 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapRealm.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapRealm.java
@@ -134,7 +134,7 @@
static List<String> optionalList(final Config config,
final String name) {
- String s[] = config.getStringList("ldap", null, name);
+ String[] s = config.getStringList("ldap", null, name);
return Arrays.asList(s);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Abandon.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Abandon.java
index d0424d9..a73f8ba 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Abandon.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Abandon.java
@@ -15,7 +15,6 @@
package com.google.gerrit.server.change;
import com.google.common.base.Strings;
-import com.google.common.util.concurrent.CheckedFuture;
import com.google.gerrit.common.ChangeHooks;
import com.google.gerrit.extensions.api.changes.AbandonInput;
import com.google.gerrit.extensions.common.ChangeInfo;
@@ -123,17 +122,15 @@
}
update.commit();
- CheckedFuture<?, IOException> indexFuture =
- indexer.indexAsync(change.getId());
+ indexer.index(db, change);
try {
- ReplyToChangeSender cm = abandonedSenderFactory.create(change);
+ ReplyToChangeSender cm = abandonedSenderFactory.create(change.getId());
cm.setFrom(caller.getAccountId());
cm.setChangeMessage(message);
cm.send();
} catch (Exception e) {
log.error("Cannot email update for change " + change.getChangeId(), e);
}
- indexFuture.checkedGet();
hooks.doChangeAbandonedHook(change,
caller.getAccount(),
db.patchSets().get(change.currentPatchSetId()),
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ActionJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ActionJson.java
index df6b76e..180b9ad 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ActionJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ActionJson.java
@@ -22,7 +22,6 @@
import com.google.gerrit.extensions.webui.PrivateInternals_UiActionDescription;
import com.google.gerrit.extensions.webui.UiAction;
import com.google.gerrit.server.CurrentUser;
-import com.google.gerrit.server.changedetail.RebaseChange;
import com.google.gerrit.server.extensions.webui.UiActions;
import com.google.gerrit.server.project.ChangeControl;
import com.google.inject.Inject;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ArchiveFormat.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ArchiveFormat.java
index a5054f3..14fa7d6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ArchiveFormat.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ArchiveFormat.java
@@ -19,14 +19,14 @@
import org.eclipse.jgit.archive.Tbz2Format;
import org.eclipse.jgit.archive.TgzFormat;
import org.eclipse.jgit.archive.TxzFormat;
+import org.eclipse.jgit.archive.ZipFormat;
public enum ArchiveFormat {
TGZ("application/x-gzip", new TgzFormat()),
TAR("application/x-tar", new TarFormat()),
TBZ2("application/x-bzip2", new Tbz2Format()),
- TXZ("application/x-xz", new TxzFormat());
- // Zip is not supported because it may be interpreted by a Java plugin as a
- // valid JAR file, whose code would have access to cookies on the domain.
+ TXZ("application/x-xz", new TxzFormat()),
+ ZIP("application/x-zip", new ZipFormat());
private final ArchiveCommand.Format<?> format;
private final String mimeType;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeEdits.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeEdits.java
index 9bd625d..73f9cab 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeEdits.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeEdits.java
@@ -140,7 +140,7 @@
return deleteFileFactory.create(id.get());
}
- static class Create implements
+ public static class Create implements
RestModifyView<ChangeResource, Put.Input> {
interface Factory {
@@ -195,7 +195,7 @@
}
}
- static class DeleteFile implements
+ public static class DeleteFile implements
RestModifyView<ChangeResource, DeleteFile.Input> {
public static class Input {
}
@@ -407,7 +407,7 @@
* as reverting or restoring a file to its previous contents.
*/
@Singleton
- static class DeleteContent implements
+ public static class DeleteContent implements
RestModifyView<ChangeEditResource, DeleteContent.Input> {
public static class Input {
}
@@ -432,7 +432,7 @@
}
@Singleton
- static class Get implements RestReadView<ChangeEditResource> {
+ public static class Get implements RestReadView<ChangeEditResource> {
private final FileContentUtil fileContentUtil;
@Inject
@@ -455,7 +455,7 @@
}
@Singleton
- static class GetMeta implements RestReadView<ChangeEditResource> {
+ public static class GetMeta implements RestReadView<ChangeEditResource> {
private final WebLinks webLinks;
@Inject
@@ -481,8 +481,8 @@
return r;
}
- static class FileInfo {
- List<DiffWebLinkInfo> webLinks;
+ public static class FileInfo {
+ public List<DiffWebLinkInfo> webLinks;
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeInserter.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeInserter.java
index ff833f4..a9153d6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeInserter.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeInserter.java
@@ -33,6 +33,7 @@
import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
+import com.google.gerrit.server.git.GroupCollector;
import com.google.gerrit.server.git.WorkQueue;
import com.google.gerrit.server.index.ChangeIndexer;
import com.google.gerrit.server.mail.CreateChangeSender;
@@ -163,6 +164,11 @@
return this;
}
+ public ChangeInserter setGroups(Iterable<String> groups) {
+ patchSet.setGroups(groups);
+ return this;
+ }
+
public ChangeInserter setHashtags(Set<String> hashtags) {
this.hashtags = hashtags;
return this;
@@ -205,6 +211,9 @@
db.changes().beginTransaction(change.getId());
try {
ChangeUtil.insertAncestors(db, patchSet.getId(), commit);
+ if (patchSet.getGroups() == null) {
+ patchSet.setGroups(GroupCollector.getDefaultGroups(patchSet));
+ }
db.patchSets().insert(Collections.singleton(patchSet));
db.changes().insert(Collections.singleton(change));
LabelTypes labelTypes = projectControl.getLabelTypes();
@@ -233,10 +242,10 @@
}
CheckedFuture<?, IOException> f = indexer.indexAsync(change.getId());
-
if (!messageIsForChange()) {
commitMessageNotForChange();
}
+ f.checkedGet();
if (sendMail) {
Runnable sender = new Runnable() {
@@ -244,7 +253,7 @@
public void run() {
try {
CreateChangeSender cm =
- createChangeSenderFactory.create(change);
+ createChangeSenderFactory.create(change.getId());
cm.setFrom(change.getOwner());
cm.setPatchSet(patchSet, patchSetInfo);
cm.addReviewers(reviewers);
@@ -266,7 +275,6 @@
sender.run();
}
}
- f.checkedGet();
gitRefUpdated.fire(change.getProject(), patchSet.getRefName(),
ObjectId.zeroId(), commit);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
index 4bcc82e..28614f7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
@@ -19,6 +19,7 @@
import static com.google.gerrit.extensions.client.ListChangesOption.ALL_REVISIONS;
import static com.google.gerrit.extensions.client.ListChangesOption.CHANGE_ACTIONS;
import static com.google.gerrit.extensions.client.ListChangesOption.CHECK;
+import static com.google.gerrit.extensions.client.ListChangesOption.COMMIT_FOOTERS;
import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_ACTIONS;
import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_COMMIT;
import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_FILES;
@@ -31,12 +32,14 @@
import static com.google.gerrit.extensions.client.ListChangesOption.MESSAGES;
import static com.google.gerrit.extensions.client.ListChangesOption.REVIEWED;
import static com.google.gerrit.extensions.client.ListChangesOption.WEB_LINKS;
+import static com.google.gerrit.server.CommonConverters.toGitPerson;
import com.google.auto.value.AutoValue;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.MoreObjects;
import com.google.common.base.Optional;
+import com.google.common.base.Throwables;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.HashMultimap;
@@ -65,7 +68,6 @@
import com.google.gerrit.extensions.common.ChangeMessageInfo;
import com.google.gerrit.extensions.common.CommitInfo;
import com.google.gerrit.extensions.common.FetchInfo;
-import com.google.gerrit.extensions.common.GitPerson;
import com.google.gerrit.extensions.common.LabelInfo;
import com.google.gerrit.extensions.common.ProblemInfo;
import com.google.gerrit.extensions.common.RevisionInfo;
@@ -80,10 +82,7 @@
import com.google.gerrit.reviewdb.client.Patch;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.PatchSetApproval;
-import com.google.gerrit.reviewdb.client.PatchSetInfo;
-import com.google.gerrit.reviewdb.client.PatchSetInfo.ParentInfo;
import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.reviewdb.client.UserIdentity;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.AnonymousUser;
import com.google.gerrit.server.ChangeMessagesUtil;
@@ -92,13 +91,13 @@
import com.google.gerrit.server.PatchLineCommentsUtil;
import com.google.gerrit.server.WebLinks;
import com.google.gerrit.server.account.AccountLoader;
-import com.google.gerrit.server.changedetail.RebaseChange;
+import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.LabelNormalizer;
+import com.google.gerrit.server.git.MergeUtil;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.patch.PatchListNotAvailableException;
-import com.google.gerrit.server.patch.PatchSetInfoFactory;
-import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
import com.google.gerrit.server.project.ChangeControl;
+import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.SubmitRuleEvaluator;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.query.change.ChangeData.ChangedLines;
@@ -107,10 +106,16 @@
import com.google.inject.Inject;
import com.google.inject.Provider;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.io.IOException;
import java.sql.Timestamp;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
@@ -130,9 +135,11 @@
private final LabelNormalizer labelNormalizer;
private final Provider<CurrentUser> userProvider;
private final AnonymousUser anonymous;
+ private final GitRepositoryManager repoManager;
+ private final ProjectCache projectCache;
+ private final MergeUtil.Factory mergeUtilFactory;
private final IdentifiedUser.GenericFactory userFactory;
private final ChangeData.Factory changeDataFactory;
- private final PatchSetInfoFactory patchSetInfoFactory;
private final FileInfoJson fileInfoJson;
private final AccountLoader.Factory accountLoaderFactory;
private final DynamicMap<DownloadScheme> downloadSchemes;
@@ -154,9 +161,11 @@
LabelNormalizer ln,
Provider<CurrentUser> user,
AnonymousUser au,
+ GitRepositoryManager repoManager,
+ ProjectCache projectCache,
+ MergeUtil.Factory mergeUtilFactory,
IdentifiedUser.GenericFactory uf,
ChangeData.Factory cdf,
- PatchSetInfoFactory psi,
FileInfoJson fileInfoJson,
AccountLoader.Factory ailf,
DynamicMap<DownloadScheme> downloadSchemes,
@@ -171,9 +180,11 @@
this.labelNormalizer = ln;
this.userProvider = user;
this.anonymous = au;
- this.userFactory = uf;
this.changeDataFactory = cdf;
- this.patchSetInfoFactory = psi;
+ this.repoManager = repoManager;
+ this.userFactory = uf;
+ this.projectCache = projectCache;
+ this.mergeUtilFactory = mergeUtilFactory;
this.fileInfoJson = fileInfoJson;
this.accountLoaderFactory = ailf;
this.downloadSchemes = downloadSchemes;
@@ -238,9 +249,11 @@
ChangeInfo res = toChangeInfo(cd, reviewed, limitToPsId);
accountLoader.fill();
return res;
- } catch (OrmException | RuntimeException e) {
+ } catch (PatchListNotAvailableException | OrmException | IOException
+ | RuntimeException e) {
if (!has(CHECK)) {
- throw e;
+ Throwables.propagateIfPossible(e, OrmException.class);
+ throw new OrmException(e);
}
return checkOnly(cd);
}
@@ -298,7 +311,8 @@
if (i == null) {
try {
i = toChangeInfo(cd, reviewed, Optional.<PatchSet.Id> absent());
- } catch (OrmException | RuntimeException e) {
+ } catch (PatchListNotAvailableException | OrmException | IOException
+ | RuntimeException e) {
if (has(CHECK)) {
i = checkOnly(cd);
} else {
@@ -341,7 +355,8 @@
}
private ChangeInfo toChangeInfo(ChangeData cd, Set<Change.Id> reviewed,
- Optional<PatchSet.Id> limitToPsId) throws OrmException {
+ Optional<PatchSet.Id> limitToPsId)
+ throws PatchListNotAvailableException, OrmException, IOException {
ChangeInfo out = new ChangeInfo();
if (has(CHECK)) {
@@ -412,7 +427,7 @@
finish(out);
if (needRevisions) {
- out.revisions = revisions(ctl, cd, src);
+ out.revisions = revisions(ctl, src);
if (out.revisions != null) {
for (Map.Entry<String, RevisionInfo> entry : out.revisions.entrySet()) {
if (entry.getValue().isCurrent) {
@@ -830,14 +845,15 @@
return false;
}
- private Map<String, RevisionInfo> revisions(ChangeControl ctl, ChangeData cd,
- Map<PatchSet.Id, PatchSet> map) throws OrmException {
+ private Map<String, RevisionInfo> revisions(ChangeControl ctl,
+ Map<PatchSet.Id, PatchSet> map)
+ throws PatchListNotAvailableException, OrmException, IOException {
Map<String, RevisionInfo> res = Maps.newLinkedHashMap();
for (PatchSet in : map.values()) {
if ((has(ALL_REVISIONS)
- || in.getId().equals(cd.change().currentPatchSetId()))
+ || in.getId().equals(ctl.getChange().currentPatchSetId()))
&& ctl.isPatchVisible(in, db.get())) {
- res.put(in.getRevision().get(), toRevisionInfo(ctl, cd, in));
+ res.put(in.getRevision().get(), toRevisionInfo(ctl, in));
}
}
return res;
@@ -847,11 +863,11 @@
Optional<PatchSet.Id> limitToPsId) throws OrmException {
Collection<PatchSet> src;
if (has(ALL_REVISIONS) || has(MESSAGES)) {
- src = cd.patches();
+ src = cd.patchSets();
} else {
PatchSet ps;
if (limitToPsId.isPresent()) {
- ps = cd.patch(limitToPsId.get());
+ ps = cd.patchSet(limitToPsId.get());
if (ps == null) {
throw new OrmException("missing patch set " + limitToPsId.get());
}
@@ -871,10 +887,11 @@
return map;
}
- private RevisionInfo toRevisionInfo(ChangeControl ctl, ChangeData cd,
- PatchSet in) throws OrmException {
+ private RevisionInfo toRevisionInfo(ChangeControl ctl, PatchSet in)
+ throws PatchListNotAvailableException, OrmException, IOException {
+ Change c = ctl.getChange();
RevisionInfo out = new RevisionInfo();
- out.isCurrent = in.getId().equals(cd.change().currentPatchSetId());
+ out.isCurrent = in.getId().equals(c.currentPatchSetId());
out._number = in.getId().get();
out.ref = in.getRefName();
out.created = in.getCreatedOn();
@@ -882,21 +899,30 @@
out.draft = in.isDraft() ? true : null;
out.fetch = makeFetchMap(ctl, in);
- if (has(ALL_COMMITS) || (out.isCurrent && has(CURRENT_COMMIT))) {
- try {
- out.commit = toCommit(in, cd.change().getProject(), has(WEB_LINKS));
- } catch (PatchSetInfoNotAvailableException e) {
- throw new OrmException(e);
+ boolean setCommit = has(ALL_COMMITS)
+ || (out.isCurrent && has(CURRENT_COMMIT));
+ boolean addFooters = out.isCurrent && has(COMMIT_FOOTERS);
+ if (setCommit || addFooters) {
+ Project.NameKey project = c.getProject();
+ try (Repository repo = repoManager.openRepository(project);
+ RevWalk rw = new RevWalk(repo)) {
+ String rev = in.getRevision().get();
+ RevCommit commit = rw.parseCommit(ObjectId.fromString(rev));
+ rw.parseBody(commit);
+ if (setCommit) {
+ out.commit = toCommit(ctl, rw, commit, has(WEB_LINKS));
+ }
+ if (addFooters) {
+ out.commitWithFooters = mergeUtilFactory
+ .create(projectCache.get(project))
+ .createCherryPickCommitMessage(commit, ctl, in.getId());
+ }
}
}
if (has(ALL_FILES) || (out.isCurrent && has(CURRENT_FILES))) {
- try {
- out.files = fileInfoJson.toFileInfoMap(cd.change(), in);
- out.files.remove(Patch.COMMIT_MSG);
- } catch (PatchListNotAvailableException e) {
- throw new OrmException(e);
- }
+ out.files = fileInfoJson.toFileInfoMap(c, in);
+ out.files.remove(Patch.COMMIT_MSG);
}
if ((out.isCurrent || (out.draft != null && out.draft))
@@ -919,34 +945,35 @@
return out;
}
- CommitInfo toCommit(PatchSet in, Project.NameKey project, boolean addLinks)
- throws PatchSetInfoNotAvailableException {
- PatchSetInfo info = patchSetInfoFactory.get(db.get(), in.getId());
- CommitInfo commit = new CommitInfo();
- commit.parents = Lists.newArrayListWithCapacity(info.getParents().size());
- commit.author = toGitPerson(info.getAuthor());
- commit.committer = toGitPerson(info.getCommitter());
- commit.subject = info.getSubject();
- commit.message = info.getMessage();
+ CommitInfo toCommit(ChangeControl ctl, RevWalk rw, RevCommit commit,
+ boolean addLinks) throws IOException {
+ Project.NameKey project = ctl.getChange().getProject();
+ CommitInfo info = new CommitInfo();
+ info.parents = new ArrayList<>(commit.getParentCount());
+ info.author = toGitPerson(commit.getAuthorIdent());
+ info.committer = toGitPerson(commit.getCommitterIdent());
+ info.subject = commit.getShortMessage();
+ info.message = commit.getFullMessage();
if (addLinks) {
FluentIterable<WebLinkInfo> links =
- webLinks.getPatchSetLinks(project, in.getRevision().get());
- commit.webLinks = links.isEmpty() ? null : links.toList();
+ webLinks.getPatchSetLinks(project, commit.name());
+ info.webLinks = links.isEmpty() ? null : links.toList();
}
- for (ParentInfo parent : info.getParents()) {
+ for (RevCommit parent : commit.getParents()) {
+ rw.parseBody(parent);
CommitInfo i = new CommitInfo();
- i.commit = parent.id.get();
- i.subject = parent.shortMessage;
+ i.commit = parent.name();
+ i.subject = parent.getShortMessage();
if (addLinks) {
FluentIterable<WebLinkInfo> parentLinks =
- webLinks.getPatchSetLinks(project, parent.id.get());
+ webLinks.getPatchSetLinks(project, parent.name());
i.webLinks = parentLinks.isEmpty() ? null : parentLinks.toList();
}
- commit.parents.add(i);
+ info.parents.add(i);
}
- return commit;
+ return info;
}
private Map<String, FetchInfo> makeFetchMap(ChangeControl ctl, PatchSet in)
@@ -1002,15 +1029,6 @@
fetchInfo.commands.put(commandName, c);
}
- private static GitPerson toGitPerson(UserIdentity committer) {
- GitPerson p = new GitPerson();
- p.name = committer.getName();
- p.email = committer.getEmail();
- p.date = committer.getDate();
- p.tz = committer.getTimeZone();
- return p;
- }
-
static void finish(ChangeInfo info) {
info.id = Joiner.on('~').join(
Url.encode(info.project),
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeKind.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeKind.java
index d22d6ff..6e6f6fa 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeKind.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeKind.java
@@ -26,5 +26,5 @@
NO_CODE_CHANGE,
/** Same tree, parent tree, same commit message. */
- NO_CHANGE;
+ NO_CHANGE
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeKindCacheImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeKindCacheImpl.java
index 23039aa..8fdd445 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeKindCacheImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeKindCacheImpl.java
@@ -317,7 +317,7 @@
repo = repoManager.openRepository(change.getProject());
ChangeData cd = changeDataFactory.create(db, change);
- Collection<PatchSet> patchSetCollection = cd.patches();
+ Collection<PatchSet> patchSetCollection = cd.patchSets();
PatchSet priorPs = patch;
for (PatchSet ps : patchSetCollection) {
if (ps.getId().get() < patch.getId().get() &&
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeResource.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeResource.java
index ff4a9f7..265cb49 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeResource.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeResource.java
@@ -23,7 +23,6 @@
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.changedetail.RebaseChange;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.ProjectState;
@@ -61,18 +60,16 @@
return getControl().getNotes();
}
- @Override
- public String getETag() {
- CurrentUser user = control.getCurrentUser();
- Hasher h = Hashing.md5().newHasher()
- .putLong(getChange().getLastUpdatedOn().getTime())
+
+ // This includes all information relevant for ETag computation
+ // unrelated to the UI.
+ public void prepareETag(Hasher h, CurrentUser user) {
+ h.putLong(getChange().getLastUpdatedOn().getTime())
.putInt(getChange().getRowVersion())
- .putBoolean(user.getStarredChanges().contains(getChange().getId()))
.putInt(user.isIdentifiedUser()
? ((IdentifiedUser) user).getAccountId().get()
: 0)
.putBoolean(rebaseChange != null && rebaseChange.canRebase(this));
-
byte[] buf = new byte[20];
ObjectId noteId;
try {
@@ -87,6 +84,14 @@
for (ProjectState p : control.getProjectControl().getProjectState().tree()) {
hashObjectId(h, p.getConfig().getRevision(), buf);
}
+ }
+
+ @Override
+ public String getETag() {
+ CurrentUser user = control.getCurrentUser();
+ Hasher h = Hashing.md5().newHasher()
+ .putBoolean(user.getStarredChanges().contains(getChange().getId()));
+ prepareETag(h, user);
return h.hash().toString();
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeTriplet.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeTriplet.java
index 45bb1d4..7069e6d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeTriplet.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeTriplet.java
@@ -21,8 +21,6 @@
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Project;
-import org.eclipse.jgit.lib.Constants;
-
@AutoValue
public abstract class ChangeTriplet {
public static String format(Change change) {
@@ -53,10 +51,6 @@
String branch = Url.decode(triplet.substring(t1 + 1, t2));
String changeId = Url.decode(triplet.substring(t2 + 1));
- if (!branch.startsWith(Constants.R_REFS)) {
- branch = Constants.R_HEADS + branch;
- }
-
ChangeTriplet result = new AutoValue_ChangeTriplet(
new Branch.NameKey(new Project.NameKey(project), branch),
new Change.Key(changeId));
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangesCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangesCollection.java
index 42f16a3..6540ef2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangesCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangesCollection.java
@@ -26,7 +26,6 @@
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.CurrentUser;
-import com.google.gerrit.server.changedetail.RebaseChange;
import com.google.gerrit.server.index.ChangeIndexer;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.NoSuchChangeException;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPick.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPick.java
index efcd6d9..f4d1e0a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPick.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPick.java
@@ -102,6 +102,7 @@
return new UiAction.Description()
.setLabel("Cherry Pick")
.setTitle("Cherry pick change to a different branch")
- .setVisible(resource.getControl().getProjectControl().canUpload());
+ .setVisible(resource.getControl().getProjectControl().canUpload()
+ && resource.isCurrent());
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPickChange.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPickChange.java
index b386894..b8e1178 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPickChange.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPickChange.java
@@ -14,6 +14,7 @@
package com.google.gerrit.server.change;
+import com.google.common.base.Strings;
import com.google.gerrit.common.FooterConstants;
import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.reviewdb.client.Branch;
@@ -182,9 +183,13 @@
} else {
// Change key not found on destination branch. We can create a new
// change.
+ String newTopic = null;
+ if (!Strings.isNullOrEmpty(change.getTopic())) {
+ newTopic = change.getTopic() + "-" + newDest.getShortName();
+ }
Change newChange = createNewChange(git, revWalk, changeKey, project,
destRef, cherryPickCommit, refControl,
- identifiedUser, change.getTopic());
+ identifiedUser, newTopic);
addMessageToSourceChange(change, patch.getId(), destinationBranch,
cherryPickCommit, identifiedUser, refControl);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/CommentJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/CommentJson.java
index 4a52fc5..b155b84 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/CommentJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/CommentJson.java
@@ -14,9 +14,11 @@
package com.google.gerrit.server.change;
-import static com.google.common.base.MoreObjects.firstNonNull;
+import static com.google.gerrit.server.PatchLineCommentsUtil.COMMENT_INFO_ORDER;
+import com.google.common.base.Function;
import com.google.common.base.Strings;
+import com.google.common.collect.FluentIterable;
import com.google.gerrit.extensions.client.Comment.Range;
import com.google.gerrit.extensions.client.Side;
import com.google.gerrit.extensions.common.CommentInfo;
@@ -26,45 +28,51 @@
import com.google.gerrit.server.account.AccountLoader;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
-import com.google.inject.Singleton;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
-@Singleton
class CommentJson {
private final AccountLoader.Factory accountLoaderFactory;
+ private boolean fillAccounts = true;
+ private boolean fillPatchSet;
+
@Inject
CommentJson(AccountLoader.Factory accountLoaderFactory) {
this.accountLoaderFactory = accountLoaderFactory;
}
- CommentInfo format(PatchLineComment c) throws OrmException {
- return format(c, true);
+ CommentJson setFillAccounts(boolean fillAccounts) {
+ this.fillAccounts = fillAccounts;
+ return this;
}
- CommentInfo format(PatchLineComment c, boolean fill) throws OrmException {
+ CommentJson setFillPatchSet(boolean fillPatchSet) {
+ this.fillPatchSet = fillPatchSet;
+ return this;
+ }
+
+ CommentInfo format(PatchLineComment c) throws OrmException {
AccountLoader loader = null;
- if (fill) {
+ if (fillAccounts) {
loader = accountLoaderFactory.create(true);
}
CommentInfo commentInfo = toCommentInfo(c, loader);
- if (fill) {
+ if (fillAccounts) {
loader.fill();
}
return commentInfo;
}
- Map<String, List<CommentInfo>> format(Iterable<PatchLineComment> l,
- boolean fill) throws OrmException {
+ Map<String, List<CommentInfo>> format(Iterable<PatchLineComment> l)
+ throws OrmException {
Map<String, List<CommentInfo>> out = new TreeMap<>();
- AccountLoader accountLoader = fill
+ AccountLoader accountLoader = fillAccounts
? accountLoaderFactory.create(true)
: null;
@@ -80,20 +88,7 @@
}
for (List<CommentInfo> list : out.values()) {
- Collections.sort(list, new Comparator<CommentInfo>() {
- @Override
- public int compare(CommentInfo a, CommentInfo b) {
- int c = firstNonNull(a.side, Side.REVISION).ordinal()
- - firstNonNull(b.side, Side.REVISION).ordinal();
- if (c == 0) {
- c = firstNonNull(a.line, 0) - firstNonNull(b.line, 0);
- }
- if (c == 0) {
- c = a.id.compareTo(b.id);
- }
- return c;
- }
- });
+ Collections.sort(list, COMMENT_INFO_ORDER);
}
if (accountLoader != null) {
@@ -103,8 +98,32 @@
return out;
}
+ List<CommentInfo> formatAsList(Iterable<PatchLineComment> l)
+ throws OrmException {
+ final AccountLoader accountLoader = fillAccounts
+ ? accountLoaderFactory.create(true)
+ : null;
+ List<CommentInfo> out = FluentIterable
+ .from(l)
+ .transform(new Function<PatchLineComment, CommentInfo>() {
+ @Override
+ public CommentInfo apply(PatchLineComment c) {
+ return toCommentInfo(c, accountLoader);
+ }
+ }).toSortedList(COMMENT_INFO_ORDER);
+
+ if (accountLoader != null) {
+ accountLoader.fill();
+ }
+
+ return out;
+ }
+
private CommentInfo toCommentInfo(PatchLineComment c, AccountLoader loader) {
CommentInfo r = new CommentInfo();
+ if (fillPatchSet) {
+ r.patchSet = c.getKey().getParentKey().getParentKey().get();
+ }
r.id = Url.encode(c.getKey().get());
r.path = c.getKey().getParentKey().getFileName();
if (c.getSide() == 0) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Comments.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Comments.java
index eff408e..8f78f0e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Comments.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Comments.java
@@ -31,13 +31,13 @@
@Singleton
public class Comments implements ChildCollection<RevisionResource, CommentResource> {
private final DynamicMap<RestView<CommentResource>> views;
- private final ListComments list;
+ private final ListRevisionComments list;
private final Provider<ReviewDb> dbProvider;
private final PatchLineCommentsUtil plcUtil;
@Inject
Comments(DynamicMap<RestView<CommentResource>> views,
- ListComments list, Provider<ReviewDb> dbProvider,
+ ListRevisionComments list, Provider<ReviewDb> dbProvider,
PatchLineCommentsUtil plcUtil) {
this.views = views;
this.list = list;
@@ -51,7 +51,7 @@
}
@Override
- public ListComments list() {
+ public ListRevisionComments list() {
return list;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ConsistencyChecker.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ConsistencyChecker.java
index ee28ed2..87a1ca6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ConsistencyChecker.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ConsistencyChecker.java
@@ -14,13 +14,14 @@
package com.google.gerrit.server.change;
+import static com.google.gerrit.server.ChangeUtil.PS_ID_ORDER;
+import static com.google.gerrit.server.ChangeUtil.TO_PS_ID;
+
import com.google.auto.value.AutoValue;
-import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.MultimapBuilder;
-import com.google.common.collect.Ordering;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.api.changes.FixInput;
import com.google.gerrit.extensions.common.ProblemInfo;
@@ -210,17 +211,6 @@
}
}
- private static final Function<PatchSet, Integer> TO_PS_ID =
- new Function<PatchSet, Integer>() {
- @Override
- public Integer apply(PatchSet in) {
- return in.getId().get();
- }
- };
-
- private static final Ordering<PatchSet> PS_ID_ORDER = Ordering.natural()
- .onResultOf(TO_PS_ID);
-
private boolean checkPatchSets() {
List<PatchSet> all;
try {
@@ -307,8 +297,7 @@
return;
}
if (dest == null) {
- problem("Destination ref not found (may be new branch): "
- + change.getDest().get());
+ problem("Destination ref not found (may be new branch): " + refName);
return;
}
RevCommit tip = parseCommit(dest.getObjectId(),
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateChange.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateChange.java
index 4dffd67..ac5d3c6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateChange.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateChange.java
@@ -33,6 +33,7 @@
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.CurrentUser;
@@ -55,7 +56,6 @@
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.Config;
-import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.PersonIdent;
@@ -140,11 +140,7 @@
}
}
- String refName = input.branch;
- if (!refName.startsWith(Constants.R_REFS)) {
- refName = Constants.R_HEADS + input.branch;
- }
-
+ String refName = RefNames.fullName(input.branch);
ProjectResource rsrc = projectsCollection.parse(input.project);
Capable r = rsrc.getControl().canPushToAtLeastOneRef();
@@ -161,6 +157,7 @@
try (Repository git = gitManager.openRepository(project);
RevWalk rw = new RevWalk(git)) {
ObjectId parentCommit;
+ List<String> groups;
if (input.baseChange != null) {
List<Change> changes = changeUtil.findChanges(input.baseChange);
if (changes.size() != 1) {
@@ -176,6 +173,7 @@
new PatchSet.Id(change.getId(),
change.currentPatchSetId().get()));
parentCommit = ObjectId.fromString(ps.getRevision().get());
+ groups = ps.getGroups();
} else {
Ref destRef = git.getRef(refName);
if (destRef == null) {
@@ -183,6 +181,7 @@
"Branch %s does not exist.", refName));
}
parentCommit = destRef.getObjectId();
+ groups = null;
}
RevCommit mergeTip = rw.parseCommit(parentCommit);
@@ -212,6 +211,7 @@
change.setTopic(input.topic);
ins.setDraft(input.status != null && input.status == ChangeStatus.DRAFT);
+ ins.setGroups(groups);
ins.insert();
return Response.created(json.format(change.getId()));
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateDraftComment.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateDraftComment.java
index 36b9692..a503721 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateDraftComment.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateDraftComment.java
@@ -45,14 +45,14 @@
public class CreateDraftComment implements RestModifyView<RevisionResource, DraftInput> {
private final Provider<ReviewDb> db;
private final ChangeUpdate.Factory updateFactory;
- private final CommentJson commentJson;
+ private final Provider<CommentJson> commentJson;
private final PatchLineCommentsUtil plcUtil;
private final PatchListCache patchListCache;
@Inject
CreateDraftComment(Provider<ReviewDb> db,
ChangeUpdate.Factory updateFactory,
- CommentJson commentJson,
+ Provider<CommentJson> commentJson,
PatchLineCommentsUtil plcUtil,
PatchListCache patchListCache) {
this.db = db;
@@ -93,6 +93,6 @@
setCommentRevId(c, patchListCache, rsrc.getChange(), rsrc.getPatchSet());
plcUtil.insertComments(db.get(), update, Collections.singleton(c));
update.commit();
- return Response.created(commentJson.format(c, false));
+ return Response.created(commentJson.get().setFillAccounts(false).format(c));
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/DraftComments.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/DraftComments.java
index 7edd679..acb50ac 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/DraftComments.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/DraftComments.java
@@ -33,14 +33,14 @@
public class DraftComments implements ChildCollection<RevisionResource, DraftCommentResource> {
private final DynamicMap<RestView<DraftCommentResource>> views;
private final Provider<CurrentUser> user;
- private final ListDraftComments list;
+ private final ListRevisionDrafts list;
private final Provider<ReviewDb> dbProvider;
private final PatchLineCommentsUtil plcUtil;
@Inject
DraftComments(DynamicMap<RestView<DraftCommentResource>> views,
Provider<CurrentUser> user,
- ListDraftComments list,
+ ListRevisionDrafts list,
Provider<ReviewDb> dbProvider,
PatchLineCommentsUtil plcUtil) {
this.views = views;
@@ -56,7 +56,7 @@
}
@Override
- public ListDraftComments list() throws AuthException {
+ public ListRevisionDrafts list() throws AuthException {
checkIdentifiedUser();
return list;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/EmailReviewComments.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/EmailReviewComments.java
index 6330e34..122156b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/EmailReviewComments.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/EmailReviewComments.java
@@ -14,7 +14,8 @@
package com.google.gerrit.server.change;
-import com.google.common.collect.Lists;
+import static com.google.gerrit.server.PatchLineCommentsUtil.PLC_ORDER;
+
import com.google.gerrit.extensions.api.changes.ReviewInput.NotifyHandling;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Change;
@@ -24,7 +25,6 @@
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.git.EmailReviewCommentsExecutor;
-import com.google.gerrit.server.git.WorkQueue.Executor;
import com.google.gerrit.server.mail.CommentSender;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.util.RequestContext;
@@ -40,9 +40,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.Collections;
-import java.util.Comparator;
import java.util.List;
+import java.util.concurrent.ExecutorService;
public class EmailReviewComments implements Runnable, RequestContext {
private static final Logger log = LoggerFactory.getLogger(EmailReviewComments.class);
@@ -57,7 +56,7 @@
List<PatchLineComment> comments);
}
- private final Executor sendEmailsExecutor;
+ private final ExecutorService sendEmailsExecutor;
private final PatchSetInfoFactory patchSetInfoFactory;
private final CommentSender.Factory commentSenderFactory;
private final SchemaFactory<ReviewDb> schemaFactory;
@@ -73,7 +72,7 @@
@Inject
EmailReviewComments (
- @EmailReviewCommentsExecutor final Executor executor,
+ @EmailReviewCommentsExecutor ExecutorService executor,
PatchSetInfoFactory patchSetInfoFactory,
CommentSender.Factory commentSenderFactory,
SchemaFactory<ReviewDb> schemaFactory,
@@ -94,7 +93,7 @@
this.patchSet = patchSet;
this.authorId = authorId;
this.message = message;
- this.comments = comments;
+ this.comments = PLC_ORDER.sortedCopy(comments);
}
void sendAsync() {
@@ -103,33 +102,10 @@
@Override
public void run() {
+ RequestContext old = requestContext.setContext(this);
try {
- requestContext.setContext(this);
- comments = Lists.newArrayList(comments);
- Collections.sort(comments, new Comparator<PatchLineComment>() {
- @Override
- public int compare(PatchLineComment a, PatchLineComment b) {
- int cmp = path(a).compareTo(path(b));
- if (cmp != 0) {
- return cmp;
- }
-
- // 0 is ancestor, 1 is revision. Sort ancestor first.
- cmp = a.getSide() - b.getSide();
- if (cmp != 0) {
- return cmp;
- }
-
- return a.getLine() - b.getLine();
- }
-
- private String path(PatchLineComment c) {
- return c.getKey().getParentKey().getFileName();
- }
- });
-
- CommentSender cm = commentSenderFactory.create(notify, change);
+ CommentSender cm = commentSenderFactory.create(notify, change.getId());
cm.setFrom(authorId);
cm.setPatchSet(patchSet, patchSetInfoFactory.get(change, patchSet));
cm.setChangeMessage(message);
@@ -138,7 +114,7 @@
} catch (Exception e) {
log.error("Cannot email comments for " + patchSet.getId(), e);
} finally {
- requestContext.setContext(null);
+ requestContext.setContext(old);
if (db != null) {
db.close();
db = null;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/FileResource.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/FileResource.java
index 1662237..ca47fb9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/FileResource.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/FileResource.java
@@ -44,7 +44,7 @@
return rev.getAccountId();
}
- RevisionResource getRevision() {
+ public RevisionResource getRevision() {
return rev;
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetArchive.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetArchive.java
index 913f69e..ccc7645 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetArchive.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetArchive.java
@@ -18,16 +18,15 @@
import com.google.common.collect.ImmutableMap;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.BinaryResult;
+import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
import com.google.gerrit.extensions.restapi.RestReadView;
-import com.google.gerrit.server.config.ConfigUtil;
-import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.config.DownloadConfig;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.jgit.api.ArchiveCommand;
import org.eclipse.jgit.api.errors.GitAPIException;
-import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
@@ -36,11 +35,7 @@
import java.io.IOException;
import java.io.OutputStream;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
import java.util.HashMap;
-import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
@@ -51,33 +46,25 @@
final Set<ArchiveFormat> allowed;
@Inject
- AllowedFormats(@GerritServerConfig Config cfg) {
- Collection<ArchiveFormat> enabled;
- String v = cfg.getString("download", null, "archive");
- if (v == null) {
- enabled = Arrays.asList(ArchiveFormat.values());
- } else if (v.isEmpty() || "off".equalsIgnoreCase(v)) {
- enabled = Collections.emptyList();
- } else {
- enabled = ConfigUtil.getEnumList(cfg,
- "download", null, "archive",
- ArchiveFormat.TGZ);
- }
-
+ AllowedFormats(DownloadConfig cfg) {
Map<String, ArchiveFormat> exts = new HashMap<>();
- for (ArchiveFormat format : enabled) {
+ for (ArchiveFormat format : cfg.getArchiveFormats()) {
for (String ext : format.getSuffixes()) {
exts.put(ext, format);
}
exts.put(format.name().toLowerCase(), format);
}
extensions = ImmutableMap.copyOf(exts);
- allowed = Collections.unmodifiableSet(new LinkedHashSet<>(enabled));
+ allowed = cfg.getArchiveFormats();
}
public Set<ArchiveFormat> getAllowed() {
return allowed;
}
+
+ public ImmutableMap<String, ArchiveFormat> getExtensions() {
+ return extensions;
+ }
}
private final GitRepositoryManager repoManager;
@@ -93,8 +80,8 @@
}
@Override
- public BinaryResult apply(RevisionResource rsrc)
- throws BadRequestException, IOException {
+ public BinaryResult apply(RevisionResource rsrc) throws BadRequestException,
+ IOException, MethodNotAllowedException {
if (Strings.isNullOrEmpty(format)) {
throw new BadRequestException("format is not specified");
}
@@ -102,6 +89,9 @@
if (f == null) {
throw new BadRequestException("unknown archive format");
}
+ if (f == ArchiveFormat.ZIP) {
+ throw new MethodNotAllowedException("zip format is disabled");
+ }
boolean close = true;
final Repository repo = repoManager
.openRepository(rsrc.getControl().getProject().getNameKey());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetComment.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetComment.java
index ea84f50..d87c7eb 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetComment.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetComment.java
@@ -18,20 +18,21 @@
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
+import com.google.inject.Provider;
import com.google.inject.Singleton;
@Singleton
public class GetComment implements RestReadView<CommentResource> {
- private final CommentJson commentJson;
+ private final Provider<CommentJson> commentJson;
@Inject
- GetComment(CommentJson commentJson) {
+ GetComment(Provider<CommentJson> commentJson) {
this.commentJson = commentJson;
}
@Override
public CommentInfo apply(CommentResource rsrc) throws OrmException {
- return commentJson.format(rsrc.getComment());
+ return commentJson.get().format(rsrc.getComment());
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetCommit.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetCommit.java
index 296a262..0f0a6a2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetCommit.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetCommit.java
@@ -18,38 +18,47 @@
import com.google.gerrit.extensions.restapi.CacheControl;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestReadView;
-import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
-import com.google.gwtorm.server.OrmException;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.inject.Inject;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
import org.kohsuke.args4j.Option;
+import java.io.IOException;
import java.util.concurrent.TimeUnit;
public class GetCommit implements RestReadView<RevisionResource> {
+ private final GitRepositoryManager repoManager;
private final ChangeJson json;
@Option(name = "--links", usage = "Add weblinks")
private boolean addLinks;
@Inject
- GetCommit(ChangeJson json) {
+ GetCommit(GitRepositoryManager repoManager,
+ ChangeJson json) {
+ this.repoManager = repoManager;
this.json = json;
}
@Override
- public Response<CommitInfo> apply(RevisionResource resource)
- throws OrmException {
- try {
- Response<CommitInfo> r =
- Response.ok(json.toCommit(resource.getPatchSet(), resource
- .getChange().getProject(), addLinks));
- if (resource.isCacheable()) {
+ public Response<CommitInfo> apply(RevisionResource rsrc) throws IOException {
+ Project.NameKey p = rsrc.getChange().getProject();
+ try (Repository repo = repoManager.openRepository(p);
+ RevWalk rw = new RevWalk(repo)) {
+ String rev = rsrc.getPatchSet().getRevision().get();
+ RevCommit commit = rw.parseCommit(ObjectId.fromString(rev));
+ rw.parseBody(commit);
+ Response<CommitInfo> r = Response.ok(
+ json.toCommit(rsrc.getControl(), rw, commit, addLinks));
+ if (rsrc.isCacheable()) {
r.caching(CacheControl.PRIVATE(7, TimeUnit.DAYS));
}
return r;
- } catch (PatchSetInfoNotAvailableException e) {
- throw new OrmException(e);
}
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDiff.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDiff.java
index 8e3a5d1..eef0533 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDiff.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDiff.java
@@ -201,6 +201,7 @@
result.metaA.lines = ps.getA().size();
result.metaA.webLinks =
getFileWebLinks(state.getProject(), revA, result.metaA.name);
+ result.metaA.commitId = content.commitIdA;
}
if (ps.getDisplayMethodB() != DisplayMethod.NONE) {
@@ -211,6 +212,7 @@
result.metaB.lines = ps.getB().size();
result.metaB.webLinks =
getFileWebLinks(state.getProject(), revB, result.metaB.name);
+ result.metaB.commitId = content.commitIdB;
}
if (intraline) {
@@ -264,6 +266,8 @@
final SparseFileContent fileA;
final SparseFileContent fileB;
final boolean ignoreWS;
+ final String commitIdA;
+ final String commitIdB;
int nextA;
int nextB;
@@ -273,6 +277,8 @@
fileA = ps.getA();
fileB = ps.getB();
ignoreWS = ps.isIgnoreWhitespace();
+ commitIdA = ps.getCommitIdA();
+ commitIdB = ps.getCommitIdB();
}
void addCommon(int end) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDraftComment.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDraftComment.java
index a13ecdf..22f90c9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDraftComment.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDraftComment.java
@@ -18,20 +18,21 @@
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
+import com.google.inject.Provider;
import com.google.inject.Singleton;
@Singleton
public class GetDraftComment implements RestReadView<DraftCommentResource> {
- private final CommentJson commentJson;
+ private final Provider<CommentJson> commentJson;
@Inject
- GetDraftComment(CommentJson commentJson) {
+ GetDraftComment(Provider<CommentJson> commentJson) {
this.commentJson = commentJson;
}
@Override
public CommentInfo apply(DraftCommentResource rsrc) throws OrmException {
- return commentJson.format(rsrc.getComment());
+ return commentJson.get().format(rsrc.getComment());
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetHashtags.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetHashtags.java
index 4846c0b..d0c1e83 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetHashtags.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetHashtags.java
@@ -30,9 +30,8 @@
@Singleton
public class GetHashtags implements RestReadView<ChangeResource> {
@Override
- public Response<? extends Set<String>> apply(ChangeResource req)
+ public Response<Set<String>> apply(ChangeResource req)
throws AuthException, OrmException, IOException, BadRequestException {
-
ChangeControl control = req.getControl();
ChangeNotes notes = control.getNotes().load();
Set<String> hashtags = notes.getHashtags();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRelated.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRelated.java
index 6cdae44..df93278e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRelated.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRelated.java
@@ -14,258 +14,166 @@
package com.google.gerrit.server.change;
-import com.google.common.collect.ArrayListMultimap;
+import com.google.common.base.MoreObjects;
import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Sets;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.common.CommitInfo;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gerrit.reviewdb.client.PatchSetAncestor;
import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.CommonConverters;
-import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.project.ChangeControl;
-import com.google.gerrit.server.project.ProjectControl;
+import com.google.gerrit.server.change.WalkSorter.PatchSetData;
+import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.git.GroupCollector;
+import com.google.gerrit.server.index.ChangeField;
+import com.google.gerrit.server.index.IndexCollection;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.query.change.InternalChangeQuery;
import com.google.gwtorm.server.OrmException;
-import com.google.gwtorm.server.ResultSet;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
-import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.revwalk.RevCommit;
-import org.eclipse.jgit.revwalk.RevFlag;
-import org.eclipse.jgit.revwalk.RevSort;
-import org.eclipse.jgit.revwalk.RevWalk;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.LinkedList;
+import java.util.HashSet;
import java.util.List;
-import java.util.Map;
import java.util.Set;
@Singleton
public class GetRelated implements RestReadView<RevisionResource> {
- private static final Logger log = LoggerFactory.getLogger(GetRelated.class);
-
- private final GitRepositoryManager gitMgr;
- private final Provider<ReviewDb> dbProvider;
+ private final Provider<ReviewDb> db;
+ private final GetRelatedByAncestors byAncestors;
private final Provider<InternalChangeQuery> queryProvider;
+ private final Provider<WalkSorter> sorter;
+ private final IndexCollection indexes;
+ private final boolean byAncestorsOnly;
@Inject
- GetRelated(GitRepositoryManager gitMgr,
- Provider<ReviewDb> db,
- Provider<InternalChangeQuery> queryProvider) {
- this.gitMgr = gitMgr;
- this.dbProvider = db;
+ GetRelated(Provider<ReviewDb> db,
+ @GerritServerConfig Config cfg,
+ GetRelatedByAncestors byAncestors,
+ Provider<InternalChangeQuery> queryProvider,
+ Provider<WalkSorter> sorter,
+ IndexCollection indexes) {
+ this.db = db;
+ this.byAncestors = byAncestors;
this.queryProvider = queryProvider;
+ this.sorter = sorter;
+ this.indexes = indexes;
+ byAncestorsOnly =
+ cfg.getBoolean("change", null, "getRelatedByAncestors", false);
}
@Override
public RelatedInfo apply(RevisionResource rsrc)
throws RepositoryNotFoundException, IOException, OrmException {
- try (Repository git = gitMgr.openRepository(rsrc.getChange().getProject());
- RevWalk rw = new RevWalk(git)) {
- Ref ref = git.getRef(rsrc.getChange().getDest().get());
- RelatedInfo info = new RelatedInfo();
- info.changes = walk(rsrc, rw, ref);
- return info;
+ List<String> thisPatchSetGroups = GroupCollector.getGroups(rsrc);
+ if (byAncestorsOnly
+ || thisPatchSetGroups == null
+ || !indexes.getSearchIndex().getSchema().hasField(ChangeField.GROUP)) {
+ return byAncestors.getRelated(rsrc);
}
+ RelatedInfo relatedInfo = new RelatedInfo();
+ relatedInfo.changes = getRelated(rsrc, thisPatchSetGroups);
+ return relatedInfo;
}
- private List<ChangeAndCommit> walk(RevisionResource rsrc, RevWalk rw, Ref ref)
- throws OrmException, IOException {
- Map<Change.Id, ChangeData> changes = allOpenChanges(rsrc);
- Map<PatchSet.Id, PatchSet> patchSets = allPatchSets(rsrc, changes.values());
-
- Map<String, PatchSet> commits = Maps.newHashMap();
- for (PatchSet p : patchSets.values()) {
- commits.put(p.getRevision().get(), p);
+ private List<ChangeAndCommit> getRelated(RevisionResource rsrc,
+ List<String> thisPatchSetGroups) throws OrmException, IOException {
+ if (thisPatchSetGroups.isEmpty()) {
+ return Collections.emptyList();
}
- RevCommit rev = rw.parseCommit(ObjectId.fromString(
- rsrc.getPatchSet().getRevision().get()));
- rw.sort(RevSort.TOPO);
- rw.markStart(rev);
+ List<ChangeData> cds = queryProvider.get()
+ .enforceVisibility(true)
+ .byProjectGroups(
+ rsrc.getChange().getProject(),
+ getAllGroups(rsrc.getChange().getId()));
+ List<ChangeAndCommit> result = new ArrayList<>(cds.size());
- if (ref != null && ref.getObjectId() != null) {
- try {
- rw.markUninteresting(rw.parseCommit(ref.getObjectId()));
- } catch (IncorrectObjectTypeException notCommit) {
- // Ignore and treat as new branch.
+ PatchSet.Id editBaseId = rsrc.getEdit().isPresent()
+ ? rsrc.getEdit().get().getBasePatchSet().getId()
+ : null;
+ for (PatchSetData d : sorter.get()
+ .includePatchSets(choosePatchSets(thisPatchSetGroups, cds))
+ .setRetainBody(true)
+ .sort(cds)) {
+ PatchSet ps = d.patchSet();
+ RevCommit commit;
+ if (ps.getId().equals(editBaseId)) {
+ // Replace base of an edit with the edit itself.
+ ps = rsrc.getPatchSet();
+ commit = rsrc.getEdit().get().getEditCommit();
+ } else {
+ commit = d.commit();
}
+ result.add(new ChangeAndCommit(d.data().change(), ps, commit));
}
- Set<Change.Id> added = Sets.newHashSet();
- List<ChangeAndCommit> parents = Lists.newArrayList();
- for (RevCommit c; (c = rw.next()) != null;) {
- PatchSet p = commits.get(c.name());
- Change g = null;
- if (p != null) {
- g = changes.get(p.getId().getParentKey()).change();
- added.add(p.getId().getParentKey());
- }
- parents.add(new ChangeAndCommit(g, p, c));
- }
- List<ChangeAndCommit> list = children(rsrc, rw, changes, patchSets, added);
- list.addAll(parents);
-
- if (list.size() == 1) {
- ChangeAndCommit r = list.get(0);
- if (r.commit != null && r.commit.commit.equals(rsrc.getPatchSet().getRevision().get())) {
+ if (result.size() == 1) {
+ ChangeAndCommit r = result.get(0);
+ if (r.commit != null
+ && r.commit.commit.equals(rsrc.getPatchSet().getRevision().get())) {
return Collections.emptyList();
}
}
- return list;
+ return result;
}
- private Map<Change.Id, ChangeData> allOpenChanges(RevisionResource rsrc)
- throws OrmException {
- return ChangeData.asMap(
- queryProvider.get().byBranchOpen(rsrc.getChange().getDest()));
+ private Set<String> getAllGroups(Change.Id changeId) throws OrmException {
+ Set<String> result = new HashSet<>();
+ for (PatchSet ps : db.get().patchSets().byChange(changeId)) {
+ List<String> groups = ps.getGroups();
+ if (groups != null) {
+ result.addAll(groups);
+ }
+ }
+ return result;
}
- private Map<PatchSet.Id, PatchSet> allPatchSets(RevisionResource rsrc,
- Collection<ChangeData> cds) throws OrmException {
- Map<PatchSet.Id, PatchSet> r =
- Maps.newHashMapWithExpectedSize(cds.size() * 2);
+ private static Set<PatchSet.Id> choosePatchSets(List<String> groups,
+ List<ChangeData> cds) throws OrmException {
+ // Prefer the latest patch set matching at least one group from this
+ // revision; otherwise, just use the latest patch set overall.
+ Set<PatchSet.Id> result = new HashSet<>();
for (ChangeData cd : cds) {
- for (PatchSet p : cd.patches()) {
- r.put(p.getId(), p);
+ Collection<PatchSet> patchSets = cd.patchSets();
+ List<PatchSet> sameGroup = new ArrayList<>(patchSets.size());
+ for (PatchSet ps : patchSets) {
+ if (hasAnyGroup(ps, groups)) {
+ sameGroup.add(ps);
+ }
}
+ result.add(ChangeUtil.PS_ID_ORDER.max(
+ !sameGroup.isEmpty() ? sameGroup : patchSets).getId());
}
-
- if (rsrc.getEdit().isPresent()) {
- r.put(rsrc.getPatchSet().getId(), rsrc.getPatchSet());
- }
- return r;
+ return result;
}
- private List<ChangeAndCommit> children(RevisionResource rsrc, RevWalk rw,
- Map<Change.Id, ChangeData> changes, Map<PatchSet.Id, PatchSet> patchSets,
- Set<Change.Id> added)
- throws OrmException, IOException {
- // children is a map of parent commit name to PatchSet built on it.
- Multimap<String, PatchSet.Id> children = allChildren(changes.keySet());
-
- RevFlag seenCommit = rw.newFlag("seenCommit");
- LinkedList<String> q = Lists.newLinkedList();
- seedQueue(rsrc, rw, seenCommit, patchSets, q);
-
- ProjectControl projectCtl = rsrc.getControl().getProjectControl();
- Set<Change.Id> seenChange = Sets.newHashSet();
- List<ChangeAndCommit> graph = Lists.newArrayList();
- while (!q.isEmpty()) {
- String id = q.remove();
-
- // For every matching change find the most recent patch set.
- Map<Change.Id, PatchSet.Id> matches = Maps.newHashMap();
- for (PatchSet.Id psId : children.get(id)) {
- PatchSet.Id e = matches.get(psId.getParentKey());
- if ((e == null || e.get() < psId.get())
- && isVisible(projectCtl, changes, patchSets, psId)) {
- matches.put(psId.getParentKey(), psId);
- }
- }
-
- for (Map.Entry<Change.Id, PatchSet.Id> e : matches.entrySet()) {
- ChangeData cd = changes.get(e.getKey());
- PatchSet ps = patchSets.get(e.getValue());
- if (cd == null || ps == null || !seenChange.add(e.getKey())) {
- continue;
- }
-
- RevCommit c = rw.parseCommit(ObjectId.fromString(
- ps.getRevision().get()));
- if (!c.has(seenCommit)) {
- c.add(seenCommit);
- q.addFirst(ps.getRevision().get());
- if (added.add(ps.getId().getParentKey())) {
- rw.parseBody(c);
- graph.add(new ChangeAndCommit(cd.change(), ps, c));
- }
- }
- }
+ private static boolean hasAnyGroup(PatchSet ps, List<String> groups) {
+ if (ps.getGroups() == null) {
+ return false;
}
- Collections.reverse(graph);
- return graph;
- }
-
- private boolean isVisible(ProjectControl projectCtl,
- Map<Change.Id, ChangeData> changes,
- Map<PatchSet.Id, PatchSet> patchSets,
- PatchSet.Id psId) throws OrmException {
- ChangeData cd = changes.get(psId.getParentKey());
- PatchSet ps = patchSets.get(psId);
- if (cd != null && ps != null) {
- // Related changes are in the same project, so reuse the existing
- // ProjectControl.
- ChangeControl ctl = projectCtl.controlFor(cd.change());
- return ctl.isVisible(dbProvider.get())
- && ctl.isPatchVisible(ps, dbProvider.get());
+ // Expected size of each list is 1, so nested linear search is fine.
+ for (String g1 : ps.getGroups()) {
+ for (String g2 : groups) {
+ if (g1.equals(g2)) {
+ return true;
+ }
+ }
}
return false;
}
- private void seedQueue(RevisionResource rsrc, RevWalk rw,
- RevFlag seenCommit, Map<PatchSet.Id, PatchSet> patchSets,
- LinkedList<String> q) throws IOException {
- RevCommit tip = rw.parseCommit(ObjectId.fromString(
- rsrc.getPatchSet().getRevision().get()));
- tip.add(seenCommit);
- q.add(tip.name());
-
- Change.Id cId = rsrc.getChange().getId();
- for (PatchSet p : patchSets.values()) {
- if (cId.equals(p.getId().getParentKey())) {
- try {
- RevCommit c = rw.parseCommit(ObjectId.fromString(
- p.getRevision().get()));
- if (!c.has(seenCommit)) {
- c.add(seenCommit);
- q.add(c.name());
- }
- } catch (IOException e) {
- log.warn(String.format(
- "Cannot read patch set %d of %d",
- p.getPatchSetId(), cId.get()), e);
- }
- }
- }
- }
-
- private Multimap<String, PatchSet.Id> allChildren(Collection<Change.Id> ids)
- throws OrmException {
- ReviewDb db = dbProvider.get();
- List<ResultSet<PatchSetAncestor>> t =
- Lists.newArrayListWithCapacity(ids.size());
- for (Change.Id id : ids) {
- t.add(db.patchSetAncestors().byChange(id));
- }
-
- Multimap<String, PatchSet.Id> r = ArrayListMultimap.create();
- for (ResultSet<PatchSetAncestor> rs : t) {
- for (PatchSetAncestor a : rs) {
- r.put(a.getAncestorRevision().get(), a.getPatchSet());
- }
- }
- return r;
- }
-
public static class RelatedInfo {
public List<ChangeAndCommit> changes;
}
@@ -277,6 +185,9 @@
public Integer _revisionNumber;
public Integer _currentRevisionNumber;
+ public ChangeAndCommit() {
+ }
+
ChangeAndCommit(@Nullable Change change, @Nullable PatchSet ps, RevCommit c) {
if (change != null) {
changeId = change.getKey().get();
@@ -297,5 +208,28 @@
commit.author = CommonConverters.toGitPerson(c.getAuthorIdent());
commit.subject = c.getShortMessage();
}
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("changeId", changeId)
+ .add("commit", toString(commit))
+ .add("_changeNumber", _changeNumber)
+ .add("_revisionNumber", _revisionNumber)
+ .add("_currentRevisionNumber", _currentRevisionNumber)
+ .toString();
+ }
+
+ private static String toString(CommitInfo commit) {
+ return MoreObjects.toStringHelper(commit)
+ .add("commit", commit.commit)
+ .add("parent", commit.parents)
+ .add("author", commit.author)
+ .add("committer", commit.committer)
+ .add("subject", commit.subject)
+ .add("message", commit.message)
+ .add("webLinks", commit.webLinks)
+ .toString();
+ }
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRelatedByAncestors.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRelatedByAncestors.java
new file mode 100644
index 0000000..119de7e
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRelatedByAncestors.java
@@ -0,0 +1,266 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.change;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSetAncestor;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.change.GetRelated.ChangeAndCommit;
+import com.google.gerrit.server.change.GetRelated.RelatedInfo;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.project.ChangeControl;
+import com.google.gerrit.server.project.ProjectControl;
+import com.google.gerrit.server.query.change.ChangeData;
+import com.google.gerrit.server.query.change.InternalChangeQuery;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.ResultSet;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevFlag;
+import org.eclipse.jgit.revwalk.RevSort;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/** Implementation of {@link GetRelated} using {@link PatchSetAncestor}s. */
+class GetRelatedByAncestors {
+ private static final Logger log = LoggerFactory.getLogger(GetRelated.class);
+
+ private final GitRepositoryManager gitMgr;
+ private final Provider<ReviewDb> dbProvider;
+ private final Provider<InternalChangeQuery> queryProvider;
+
+ @Inject
+ GetRelatedByAncestors(GitRepositoryManager gitMgr,
+ Provider<ReviewDb> db,
+ Provider<InternalChangeQuery> queryProvider) {
+ this.gitMgr = gitMgr;
+ this.dbProvider = db;
+ this.queryProvider = queryProvider;
+ }
+
+ public RelatedInfo getRelated(RevisionResource rsrc)
+ throws RepositoryNotFoundException, IOException, OrmException {
+ try (Repository git = gitMgr.openRepository(rsrc.getChange().getProject());
+ RevWalk rw = new RevWalk(git)) {
+ Ref ref = git.getRef(rsrc.getChange().getDest().get());
+ RelatedInfo info = new RelatedInfo();
+ info.changes = walk(rsrc, rw, ref);
+ return info;
+ }
+ }
+
+ private List<ChangeAndCommit> walk(RevisionResource rsrc, RevWalk rw, Ref ref)
+ throws OrmException, IOException {
+ Map<Change.Id, ChangeData> changes = allOpenChanges(rsrc);
+ Map<PatchSet.Id, PatchSet> patchSets = allPatchSets(rsrc, changes.values());
+
+ Map<String, PatchSet> commits = Maps.newHashMap();
+ for (PatchSet p : patchSets.values()) {
+ commits.put(p.getRevision().get(), p);
+ }
+
+ RevCommit rev = rw.parseCommit(ObjectId.fromString(
+ rsrc.getPatchSet().getRevision().get()));
+ rw.sort(RevSort.TOPO);
+ rw.markStart(rev);
+
+ if (ref != null && ref.getObjectId() != null) {
+ try {
+ rw.markUninteresting(rw.parseCommit(ref.getObjectId()));
+ } catch (IncorrectObjectTypeException notCommit) {
+ // Ignore and treat as new branch.
+ }
+ }
+
+ Set<Change.Id> added = Sets.newHashSet();
+ List<ChangeAndCommit> parents = Lists.newArrayList();
+ for (RevCommit c; (c = rw.next()) != null;) {
+ PatchSet p = commits.get(c.name());
+ Change g = null;
+ if (p != null) {
+ g = changes.get(p.getId().getParentKey()).change();
+ added.add(p.getId().getParentKey());
+ }
+ parents.add(new ChangeAndCommit(g, p, c));
+ }
+ List<ChangeAndCommit> list = children(rsrc, rw, changes, patchSets, added);
+ list.addAll(parents);
+
+ if (list.size() == 1) {
+ ChangeAndCommit r = list.get(0);
+ if (r.commit != null && r.commit.commit.equals(rsrc.getPatchSet().getRevision().get())) {
+ return Collections.emptyList();
+ }
+ }
+ return list;
+ }
+
+ private Map<Change.Id, ChangeData> allOpenChanges(RevisionResource rsrc)
+ throws OrmException {
+ return ChangeData.asMap(
+ queryProvider.get().byBranchOpen(rsrc.getChange().getDest()));
+ }
+
+ private Map<PatchSet.Id, PatchSet> allPatchSets(RevisionResource rsrc,
+ Collection<ChangeData> cds) throws OrmException {
+ Map<PatchSet.Id, PatchSet> r =
+ Maps.newHashMapWithExpectedSize(cds.size() * 2);
+ for (ChangeData cd : cds) {
+ for (PatchSet p : cd.patchSets()) {
+ r.put(p.getId(), p);
+ }
+ }
+
+ if (rsrc.getEdit().isPresent()) {
+ r.put(rsrc.getPatchSet().getId(), rsrc.getPatchSet());
+ }
+ return r;
+ }
+
+ private List<ChangeAndCommit> children(RevisionResource rsrc, RevWalk rw,
+ Map<Change.Id, ChangeData> changes, Map<PatchSet.Id, PatchSet> patchSets,
+ Set<Change.Id> added)
+ throws OrmException, IOException {
+ // children is a map of parent commit name to PatchSet built on it.
+ Multimap<String, PatchSet.Id> children = allChildren(changes.keySet());
+
+ RevFlag seenCommit = rw.newFlag("seenCommit");
+ LinkedList<String> q = Lists.newLinkedList();
+ seedQueue(rsrc, rw, seenCommit, patchSets, q);
+
+ ProjectControl projectCtl = rsrc.getControl().getProjectControl();
+ Set<Change.Id> seenChange = Sets.newHashSet();
+ List<ChangeAndCommit> graph = Lists.newArrayList();
+ while (!q.isEmpty()) {
+ String id = q.remove();
+
+ // For every matching change find the most recent patch set.
+ Map<Change.Id, PatchSet.Id> matches = Maps.newHashMap();
+ for (PatchSet.Id psId : children.get(id)) {
+ PatchSet.Id e = matches.get(psId.getParentKey());
+ if ((e == null || e.get() < psId.get())
+ && isVisible(projectCtl, changes, patchSets, psId)) {
+ matches.put(psId.getParentKey(), psId);
+ }
+ }
+
+ for (Map.Entry<Change.Id, PatchSet.Id> e : matches.entrySet()) {
+ ChangeData cd = changes.get(e.getKey());
+ PatchSet ps = patchSets.get(e.getValue());
+ if (cd == null || ps == null || !seenChange.add(e.getKey())) {
+ continue;
+ }
+
+ RevCommit c = rw.parseCommit(ObjectId.fromString(
+ ps.getRevision().get()));
+ if (!c.has(seenCommit)) {
+ c.add(seenCommit);
+ q.addFirst(ps.getRevision().get());
+ if (added.add(ps.getId().getParentKey())) {
+ rw.parseBody(c);
+ graph.add(new ChangeAndCommit(cd.change(), ps, c));
+ }
+ }
+ }
+ }
+ Collections.reverse(graph);
+ return graph;
+ }
+
+ private boolean isVisible(ProjectControl projectCtl,
+ Map<Change.Id, ChangeData> changes,
+ Map<PatchSet.Id, PatchSet> patchSets,
+ PatchSet.Id psId) throws OrmException {
+ ChangeData cd = changes.get(psId.getParentKey());
+ PatchSet ps = patchSets.get(psId);
+ if (cd != null && ps != null) {
+ // Related changes are in the same project, so reuse the existing
+ // ProjectControl.
+ ChangeControl ctl = projectCtl.controlFor(cd.change());
+ return ctl.isVisible(dbProvider.get())
+ && ctl.isPatchVisible(ps, dbProvider.get());
+ }
+ return false;
+ }
+
+ private void seedQueue(RevisionResource rsrc, RevWalk rw,
+ RevFlag seenCommit, Map<PatchSet.Id, PatchSet> patchSets,
+ LinkedList<String> q) throws IOException {
+ RevCommit tip = rw.parseCommit(ObjectId.fromString(
+ rsrc.getPatchSet().getRevision().get()));
+ tip.add(seenCommit);
+ q.add(tip.name());
+
+ Change.Id cId = rsrc.getChange().getId();
+ for (PatchSet p : patchSets.values()) {
+ if (cId.equals(p.getId().getParentKey())) {
+ try {
+ RevCommit c = rw.parseCommit(ObjectId.fromString(
+ p.getRevision().get()));
+ if (!c.has(seenCommit)) {
+ c.add(seenCommit);
+ q.add(c.name());
+ }
+ } catch (IOException e) {
+ log.warn(String.format(
+ "Cannot read patch set %d of %d",
+ p.getPatchSetId(), cId.get()), e);
+ }
+ }
+ }
+ }
+
+ private Multimap<String, PatchSet.Id> allChildren(Collection<Change.Id> ids)
+ throws OrmException {
+ ReviewDb db = dbProvider.get();
+ List<ResultSet<PatchSetAncestor>> t =
+ Lists.newArrayListWithCapacity(ids.size());
+ for (Change.Id id : ids) {
+ t.add(db.patchSetAncestors().byChange(id));
+ }
+
+ Multimap<String, PatchSet.Id> r = ArrayListMultimap.create();
+ for (ResultSet<PatchSetAncestor> rs : t) {
+ for (PatchSetAncestor a : rs) {
+ r.put(a.getAncestorRevision().get(), a.getPatchSet());
+ }
+ }
+ return r;
+ }
+
+
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRevisionActions.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRevisionActions.java
index d58c8d2..3ae6f6c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRevisionActions.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRevisionActions.java
@@ -14,22 +14,65 @@
package com.google.gerrit.server.change;
+import com.google.common.base.Strings;
+import com.google.common.hash.Hasher;
+import com.google.common.hash.Hashing;
+import com.google.gerrit.extensions.common.ActionInfo;
+import com.google.gerrit.extensions.restapi.ETagView;
import com.google.gerrit.extensions.restapi.Response;
-import com.google.gerrit.extensions.restapi.RestReadView;
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.query.change.ChangeData;
+import com.google.gerrit.server.query.change.InternalChangeQuery;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.OrmRuntimeException;
import com.google.inject.Inject;
+import com.google.inject.Provider;
import com.google.inject.Singleton;
-@Singleton
-public class GetRevisionActions implements RestReadView<RevisionResource> {
- private final ActionJson delegate;
+import org.eclipse.jgit.lib.Config;
+import java.util.Map;
+
+@Singleton
+public class GetRevisionActions implements ETagView<RevisionResource> {
+ private final ActionJson delegate;
+ private final Provider<InternalChangeQuery> queryProvider;
+ private final Config config;
+ private final RebaseChange rebaseChange;
@Inject
- GetRevisionActions(ActionJson delegate) {
+ GetRevisionActions(
+ ActionJson delegate,
+ Provider<InternalChangeQuery> queryProvider,
+ @GerritServerConfig Config config,
+ RebaseChange rebaseChange) {
this.delegate = delegate;
+ this.queryProvider = queryProvider;
+ this.config = config;
+ this.rebaseChange = rebaseChange;
}
@Override
- public Object apply(RevisionResource rsrc) {
+ public Response<Map<String, ActionInfo>> apply(RevisionResource rsrc) {
return Response.withMustRevalidate(delegate.format(rsrc));
}
+
+ @Override
+ public String getETag(RevisionResource rsrc) {
+ String topic = rsrc.getChange().getTopic();
+ if (!Submit.wholeTopicEnabled(config)
+ || Strings.isNullOrEmpty(topic)) {
+ return rsrc.getETag();
+ }
+ Hasher h = Hashing.md5().newHasher();
+ CurrentUser user = rsrc.getControl().getCurrentUser();
+ try {
+ for (ChangeData c : queryProvider.get().byTopicOpen(topic)) {
+ new ChangeResource(c.changeControl(), rebaseChange).prepareETag(h, user);
+ }
+ } catch (OrmException e){
+ throw new OrmRuntimeException(e);
+ }
+ return h.hash().toString();
+ }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ListChangeComments.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ListChangeComments.java
new file mode 100644
index 0000000..97befa0
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ListChangeComments.java
@@ -0,0 +1,58 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.change;
+
+import com.google.gerrit.extensions.common.CommentInfo;
+import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.RestReadView;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.PatchLineCommentsUtil;
+import com.google.gerrit.server.query.change.ChangeData;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
+import java.util.List;
+import java.util.Map;
+
+@Singleton
+public class ListChangeComments implements RestReadView<ChangeResource> {
+ private final Provider<ReviewDb> db;
+ private final ChangeData.Factory changeDataFactory;
+ private final Provider<CommentJson> commentJson;
+ private final PatchLineCommentsUtil plcUtil;
+
+ @Inject
+ ListChangeComments(Provider<ReviewDb> db,
+ ChangeData.Factory changeDataFactory,
+ Provider<CommentJson> commentJson,
+ PatchLineCommentsUtil plcUtil) {
+ this.db = db;
+ this.changeDataFactory = changeDataFactory;
+ this.commentJson = commentJson;
+ this.plcUtil = plcUtil;
+ }
+
+ @Override
+ public Map<String, List<CommentInfo>> apply(
+ ChangeResource rsrc) throws AuthException, OrmException {
+ ChangeData cd = changeDataFactory.create(db.get(), rsrc.getControl());
+ return commentJson.get()
+ .setFillAccounts(true)
+ .setFillPatchSet(true)
+ .format(plcUtil.publishedByChange(db.get(), cd.notes()));
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ListChangeDrafts.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ListChangeDrafts.java
new file mode 100644
index 0000000..2b5d7d9
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ListChangeDrafts.java
@@ -0,0 +1,66 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.change;
+
+import com.google.gerrit.extensions.common.CommentInfo;
+import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.RestReadView;
+import com.google.gerrit.reviewdb.client.PatchLineComment;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.PatchLineCommentsUtil;
+import com.google.gerrit.server.query.change.ChangeData;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
+import java.util.List;
+import java.util.Map;
+
+@Singleton
+public class ListChangeDrafts implements RestReadView<ChangeResource> {
+ private final Provider<ReviewDb> db;
+ private final ChangeData.Factory changeDataFactory;
+ private final Provider<CommentJson> commentJson;
+ private final PatchLineCommentsUtil plcUtil;
+
+ @Inject
+ ListChangeDrafts(Provider<ReviewDb> db,
+ ChangeData.Factory changeDataFactory,
+ Provider<CommentJson> commentJson,
+ PatchLineCommentsUtil plcUtil) {
+ this.db = db;
+ this.changeDataFactory = changeDataFactory;
+ this.commentJson = commentJson;
+ this.plcUtil = plcUtil;
+ }
+
+ @Override
+ public Map<String, List<CommentInfo>> apply(
+ ChangeResource rsrc) throws AuthException, OrmException {
+ if (!rsrc.getControl().getCurrentUser().isIdentifiedUser()) {
+ throw new AuthException("Authentication required");
+ }
+ IdentifiedUser user = (IdentifiedUser) rsrc.getControl().getCurrentUser();
+ ChangeData cd = changeDataFactory.create(db.get(), rsrc.getControl());
+ List<PatchLineComment> drafts =
+ plcUtil.draftByChangeAuthor(db.get(), cd.notes(), user.getAccountId());
+ return commentJson.get()
+ .setFillAccounts(false)
+ .setFillPatchSet(true)
+ .format(drafts);
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ListComments.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ListRevisionComments.java
similarity index 90%
rename from gerrit-server/src/main/java/com/google/gerrit/server/change/ListComments.java
rename to gerrit-server/src/main/java/com/google/gerrit/server/change/ListRevisionComments.java
index b50e243..2392781 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ListComments.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ListRevisionComments.java
@@ -24,10 +24,10 @@
import com.google.inject.Singleton;
@Singleton
-public class ListComments extends ListDraftComments {
+public class ListRevisionComments extends ListRevisionDrafts {
@Inject
- ListComments(Provider<ReviewDb> db,
- CommentJson commentJson,
+ ListRevisionComments(Provider<ReviewDb> db,
+ Provider<CommentJson> commentJson,
PatchLineCommentsUtil plcUtil) {
super(db, commentJson, plcUtil);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ListDraftComments.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ListRevisionDrafts.java
similarity index 76%
rename from gerrit-server/src/main/java/com/google/gerrit/server/change/ListDraftComments.java
rename to gerrit-server/src/main/java/com/google/gerrit/server/change/ListRevisionDrafts.java
index 3375cba..ef12b2a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ListDraftComments.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ListRevisionDrafts.java
@@ -28,14 +28,14 @@
import java.util.Map;
@Singleton
-public class ListDraftComments implements RestReadView<RevisionResource> {
+public class ListRevisionDrafts implements RestReadView<RevisionResource> {
protected final Provider<ReviewDb> db;
- protected CommentJson commentJson;
+ protected final Provider<CommentJson> commentJson;
protected final PatchLineCommentsUtil plcUtil;
@Inject
- ListDraftComments(Provider<ReviewDb> db,
- CommentJson commentJson,
+ ListRevisionDrafts(Provider<ReviewDb> db,
+ Provider<CommentJson> commentJson,
PatchLineCommentsUtil plcUtil) {
this.db = db;
this.commentJson = commentJson;
@@ -55,6 +55,15 @@
@Override
public Map<String, List<CommentInfo>> apply(RevisionResource rsrc)
throws OrmException {
- return commentJson.format(listComments(rsrc), includeAuthorInfo());
+ return commentJson.get()
+ .setFillAccounts(includeAuthorInfo())
+ .format(listComments(rsrc));
+ }
+
+ public List<CommentInfo> getComments(RevisionResource rsrc)
+ throws OrmException {
+ return commentJson.get()
+ .setFillAccounts(includeAuthorInfo())
+ .formatAsList(listComments(rsrc));
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java
index d0e4c99..b73af931 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java
@@ -52,6 +52,8 @@
get(CHANGE_KIND, "topic").to(GetTopic.class);
get(CHANGE_KIND, "in").to(IncludedIn.class);
get(CHANGE_KIND, "hashtags").to(GetHashtags.class);
+ get(CHANGE_KIND, "comments").to(ListChangeComments.class);
+ get(CHANGE_KIND, "drafts").to(ListChangeDrafts.class);
get(CHANGE_KIND, "check").to(Check.class);
post(CHANGE_KIND, "check").to(Check.class);
put(CHANGE_KIND, "topic").to(PutTopic.class);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java
index baddd40..db9c6d0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java
@@ -35,6 +35,7 @@
import com.google.gerrit.server.events.CommitReceivedEvent;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.BanCommit;
+import com.google.gerrit.server.git.GroupCollector;
import com.google.gerrit.server.git.validators.CommitValidationException;
import com.google.gerrit.server.git.validators.CommitValidators;
import com.google.gerrit.server.index.ChangeIndexer;
@@ -108,6 +109,7 @@
private SshInfo sshInfo;
private ValidatePolicy validatePolicy = ValidatePolicy.GERRIT;
private boolean draft;
+ private Iterable<String> groups;
private boolean runHooks;
private boolean sendMail;
private Account.Id uploader;
@@ -200,6 +202,11 @@
return this;
}
+ public PatchSetInserter setGroups(Iterable<String> groups) {
+ this.groups = groups;
+ return this;
+ }
+
public PatchSetInserter setRunHooks(boolean runHooks) {
this.runHooks = runHooks;
return this;
@@ -239,12 +246,18 @@
db.changes().beginTransaction(c.getId());
try {
- if (!db.changes().get(c.getId()).getStatus().isOpen()) {
+ updatedChange = db.changes().get(c.getId());
+ if (!updatedChange.getStatus().isOpen()) {
throw new InvalidChangeOperationException(String.format(
"Change %s is closed", c.getId()));
}
ChangeUtil.insertAncestors(db, patchSet.getId(), commit);
+ if (groups != null) {
+ patchSet.setGroups(groups);
+ } else {
+ patchSet.setGroups(GroupCollector.getCurrentGroups(db, c));
+ }
db.patchSets().insert(Collections.singleton(patchSet));
SetMultimap<ReviewerState, Account.Id> oldReviewers = sendMail
@@ -293,7 +306,7 @@
try {
PatchSetInfo info = patchSetInfoFactory.get(commit, patchSet.getId());
ReplacePatchSetSender cm =
- replacePatchSetFactory.create(updatedChange);
+ replacePatchSetFactory.create(c.getId());
cm.setFrom(user.getAccountId());
cm.setPatchSet(patchSet, info);
cm.setChangeMessage(changeMessage);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PostHashtags.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PostHashtags.java
index 6638f91..62520f4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PostHashtags.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PostHashtags.java
@@ -20,6 +20,7 @@
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView;
+import com.google.gerrit.extensions.webui.UiAction;
import com.google.gerrit.server.validators.ValidationException;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
@@ -29,7 +30,8 @@
import java.util.Set;
@Singleton
-public class PostHashtags implements RestModifyView<ChangeResource, HashtagsInput> {
+public class PostHashtags implements RestModifyView<ChangeResource, HashtagsInput>,
+ UiAction<ChangeResource>{
private HashtagsUtil hashtagsUtil;
@Inject
@@ -38,12 +40,12 @@
}
@Override
- public Response<? extends Set<String>> apply(ChangeResource req, HashtagsInput input)
+ public Response<Set<String>> apply(ChangeResource req, HashtagsInput input)
throws AuthException, OrmException, IOException, BadRequestException,
ResourceConflictException {
try {
- return Response.ok(hashtagsUtil.setHashtags(
+ return Response.<Set<String>> ok(hashtagsUtil.setHashtags(
req.getControl(), input, true, true));
} catch (IllegalArgumentException e) {
throw new BadRequestException(e.getMessage());
@@ -51,4 +53,11 @@
throw new ResourceConflictException(e.getMessage());
}
}
-}
+
+ @Override
+ public UiAction.Description getDescription(ChangeResource resource) {
+ return new UiAction.Description()
+ .setLabel("Edit Hashtags")
+ .setVisible(resource.getControl().canEditHashtags());
+ }
+}
\ No newline at end of file
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java
index 8e989b6..e10077a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java
@@ -22,8 +22,6 @@
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
-import com.google.common.util.concurrent.CheckedFuture;
-import com.google.common.util.concurrent.Futures;
import com.google.gerrit.common.ChangeHooks;
import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.common.data.LabelType;
@@ -180,11 +178,8 @@
db.get().rollback();
}
- CheckedFuture<?, IOException> indexWrite;
if (dirty) {
- indexWrite = indexer.indexAsync(change.getId());
- } else {
- indexWrite = Futures.<Void, IOException> immediateCheckedFuture(null);
+ indexer.index(db.get(), change);
}
if (message != null && input.notify.compareTo(NotifyHandling.NONE) > 0) {
email.create(
@@ -198,7 +193,6 @@
Output output = new Output();
output.labels = input.labels;
- indexWrite.checkedGet();
if (message != null) {
fireCommentAddedHook(revision);
}
@@ -351,7 +345,11 @@
Map<String, PatchLineComment> drafts = Collections.emptyMap();
if (!in.isEmpty() || draftsHandling != DraftHandling.KEEP) {
- drafts = scanDraftComments(rsrc);
+ if (draftsHandling == DraftHandling.PUBLISH_ALL_REVISIONS) {
+ drafts = changeDrafts(rsrc);
+ } else {
+ drafts = patchSetDrafts(rsrc);
+ }
}
List<PatchLineComment> del = Lists.newArrayList();
@@ -376,8 +374,7 @@
e.setStatus(PatchLineComment.Status.PUBLISHED);
e.setWrittenOn(timestamp);
e.setSide(c.side == Side.PARENT ? (short) 0 : (short) 1);
- setCommentRevId(e, patchListCache, rsrc.getChange(),
- rsrc.getPatchSet());
+ setCommentRevId(e, patchListCache, rsrc.getChange(), rsrc.getPatchSet());
e.setMessage(c.message);
if (c.range != null) {
e.setRange(new CommentRange(
@@ -399,11 +396,11 @@
del.addAll(drafts.values());
break;
case PUBLISH:
+ case PUBLISH_ALL_REVISIONS:
for (PatchLineComment e : drafts.values()) {
e.setStatus(PatchLineComment.Status.PUBLISHED);
e.setWrittenOn(timestamp);
- setCommentRevId(e, patchListCache, rsrc.getChange(),
- rsrc.getPatchSet());
+ setCommentRevId(e, patchListCache, rsrc.getChange(), rsrc.getPatchSet());
ups.add(e);
}
break;
@@ -414,8 +411,18 @@
return !del.isEmpty() || !ups.isEmpty();
}
- private Map<String, PatchLineComment> scanDraftComments(
- RevisionResource rsrc) throws OrmException {
+ private Map<String, PatchLineComment> changeDrafts(RevisionResource rsrc)
+ throws OrmException {
+ Map<String, PatchLineComment> drafts = Maps.newHashMap();
+ for (PatchLineComment c : plcUtil.draftByChangeAuthor(
+ db.get(), rsrc.getNotes(), rsrc.getAccountId())) {
+ drafts.put(c.getKey().get(), c);
+ }
+ return drafts;
+ }
+
+ private Map<String, PatchLineComment> patchSetDrafts(RevisionResource rsrc)
+ throws OrmException {
Map<String, PatchLineComment> drafts = Maps.newHashMap();
for (PatchLineComment c : plcUtil.draftByPatchSetAuthor(db.get(),
rsrc.getPatchSet().getId(), rsrc.getAccountId(), rsrc.getNotes())) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReviewers.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReviewers.java
index ecfb43c..fc27010 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReviewers.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReviewers.java
@@ -255,8 +255,8 @@
ImmutableList.of(psa)));
}
accountLoaderFactory.create(true).fill(result.reviewers);
- emailReviewers(rsrc.getChange(), added);
indexFuture.checkedGet();
+ emailReviewers(rsrc.getChange(), added);
if (!added.isEmpty()) {
PatchSet patchSet = dbProvider.get().patchSets().get(rsrc.getChange().currentPatchSetId());
for (PatchSetApproval psa : added) {
@@ -283,7 +283,7 @@
}
if (!toMail.isEmpty()) {
try {
- AddReviewerSender cm = addReviewerSenderFactory.create(change);
+ AddReviewerSender cm = addReviewerSenderFactory.create(change.getId());
cm.setFrom(identifiedUser.getAccountId());
cm.addReviewers(toMail);
cm.send();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PublishDraftPatchSet.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PublishDraftPatchSet.java
index 9f77f0e..dd9a44d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PublishDraftPatchSet.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PublishDraftPatchSet.java
@@ -14,7 +14,6 @@
package com.google.gerrit.server.change;
-import com.google.common.util.concurrent.CheckedFuture;
import com.google.gerrit.common.ChangeHooks;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
@@ -82,13 +81,11 @@
if (!updatedPatchSet.isDraft()
|| updatedChange.getStatus() == Change.Status.NEW) {
- CheckedFuture<?, IOException> indexFuture =
- indexer.indexAsync(updatedChange.getId());
+ indexer.index(dbProvider.get(), updatedChange);
sender.send(rsrc.getNotes(), update,
rsrc.getChange().getStatus() == Change.Status.DRAFT,
rsrc.getUser(), updatedChange, updatedPatchSet,
rsrc.getControl().getLabelTypes());
- indexFuture.checkedGet();
hooks.doDraftPublishedHook(updatedChange, updatedPatchSet,
dbProvider.get());
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PutDraftComment.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PutDraftComment.java
index 2a0bcb3..a4a5e16 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PutDraftComment.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PutDraftComment.java
@@ -45,7 +45,7 @@
private final DeleteDraftComment delete;
private final PatchLineCommentsUtil plcUtil;
private final ChangeUpdate.Factory updateFactory;
- private final CommentJson commentJson;
+ private final Provider<CommentJson> commentJson;
private final PatchListCache patchListCache;
@Inject
@@ -53,7 +53,7 @@
DeleteDraftComment delete,
PatchLineCommentsUtil plcUtil,
ChangeUpdate.Factory updateFactory,
- CommentJson commentJson,
+ Provider<CommentJson> commentJson,
PatchListCache patchListCache) {
this.db = db;
this.delete = delete;
@@ -96,14 +96,13 @@
Collections.singleton(update(c, in)));
} else {
if (c.getRevId() == null) {
- setCommentRevId(c, patchListCache, rsrc.getChange(),
- rsrc.getPatchSet());
+ setCommentRevId(c, patchListCache, rsrc.getChange(), rsrc.getPatchSet());
}
plcUtil.updateComments(db.get(), update,
Collections.singleton(update(c, in)));
}
update.commit();
- return Response.ok(commentJson.format(c, false));
+ return Response.ok(commentJson.get().setFillAccounts(false).format(c));
}
private PatchLineComment update(PatchLineComment e, DraftInput in) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Rebase.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Rebase.java
index d2afd9a..5aacef7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Rebase.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Rebase.java
@@ -14,6 +14,7 @@
package com.google.gerrit.server.change;
+import com.google.common.primitives.Ints;
import com.google.gerrit.common.errors.EmailException;
import com.google.gerrit.extensions.api.changes.RebaseInput;
import com.google.gerrit.extensions.client.ListChangesOption;
@@ -26,10 +27,10 @@
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Change.Status;
import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gerrit.reviewdb.client.PatchSetAncestor;
+import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RevId;
import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gerrit.server.changedetail.RebaseChange;
+import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.InvalidChangeOperationException;
import com.google.gerrit.server.project.NoSuchChangeException;
@@ -38,27 +39,32 @@
import com.google.inject.Provider;
import com.google.inject.Singleton;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
-import java.util.ArrayList;
-
@Singleton
public class Rebase implements RestModifyView<RevisionResource, RebaseInput>,
UiAction<RevisionResource> {
- private static final Logger log =
- LoggerFactory.getLogger(Rebase.class);
+ private static final Logger log = LoggerFactory.getLogger(Rebase.class);
+ private final GitRepositoryManager repoManager;
private final Provider<RebaseChange> rebaseChange;
private final ChangeJson json;
private final Provider<ReviewDb> dbProvider;
@Inject
- public Rebase(Provider<RebaseChange> rebaseChange, ChangeJson json,
+ public Rebase(GitRepositoryManager repoManager,
+ Provider<RebaseChange> rebaseChange,
+ ChangeJson json,
Provider<ReviewDb> dbProvider) {
+ this.repoManager = repoManager;
this.rebaseChange = rebaseChange;
this.json = json
.addOption(ListChangesOption.CURRENT_REVISION)
@@ -69,68 +75,24 @@
@Override
public ChangeInfo apply(RevisionResource rsrc, RebaseInput input)
throws AuthException, ResourceNotFoundException,
- ResourceConflictException, EmailException, OrmException {
+ ResourceConflictException, EmailException, OrmException, IOException {
ChangeControl control = rsrc.getControl();
Change change = rsrc.getChange();
- if (!control.canRebase()) {
- throw new AuthException("rebase not permitted");
- } else if (!change.getStatus().isOpen()) {
- throw new ResourceConflictException("change is "
- + change.getStatus().name().toLowerCase());
- } else if (!hasOneParent(rsrc.getPatchSet().getId())) {
- throw new ResourceConflictException(
- "cannot rebase merge commits or commit with no ancestor");
- }
-
- String baseRev = null;
- if (input != null && input.base != null) {
- String base = input.base.trim();
- do {
- if (base.equals("")) {
- // remove existing dependency to other patch set
- baseRev = change.getDest().get();
- break;
- }
-
- ReviewDb db = dbProvider.get();
- PatchSet basePatchSet = parseBase(base);
- if (basePatchSet == null) {
- throw new ResourceConflictException("base revision is missing: " + base);
- } else if (!rsrc.getControl().isPatchVisible(basePatchSet, db)) {
- throw new AuthException("base revision not accessible: " + base);
- } else if (change.getId().equals(basePatchSet.getId().getParentKey())) {
- throw new ResourceConflictException("cannot depend on self");
- }
-
- Change baseChange = db.changes().get(basePatchSet.getId().getParentKey());
- if (baseChange != null) {
- if (!baseChange.getProject().equals(change.getProject())) {
- throw new ResourceConflictException("base change is in wrong project: "
- + baseChange.getProject());
- } else if (!baseChange.getDest().equals(change.getDest())) {
- throw new ResourceConflictException("base change is targetting wrong branch: "
- + baseChange.getDest());
- } else if (baseChange.getStatus() == Status.ABANDONED) {
- throw new ResourceConflictException("base change is abandoned: "
- + baseChange.getKey());
- } else if (isDescendantOf(baseChange.getId(), rsrc.getPatchSet().getRevision())) {
- throw new ResourceConflictException("base change " + baseChange.getKey()
- + " is a descendant of the current "
- + " change - recursion not allowed");
- }
- baseRev = basePatchSet.getRevision().get();
- break;
- }
- } while (false); // just wanted to use the break statement
- }
-
- try {
- rebaseChange.get().rebase(change, rsrc.getPatchSet().getId(),
- rsrc.getUser(), baseRev);
+ try (Repository repo = repoManager.openRepository(change.getProject());
+ RevWalk rw = new RevWalk(repo)) {
+ if (!control.canRebase()) {
+ throw new AuthException("rebase not permitted");
+ } else if (!change.getStatus().isOpen()) {
+ throw new ResourceConflictException("change is "
+ + change.getStatus().name().toLowerCase());
+ } else if (!hasOneParent(rw, rsrc.getPatchSet())) {
+ throw new ResourceConflictException(
+ "cannot rebase merge commits or commit with no ancestor");
+ }
+ rebaseChange.get().rebase(repo, rw, change, rsrc.getPatchSet().getId(),
+ rsrc.getUser(), findBaseRev(rw, rsrc, input));
} catch (InvalidChangeOperationException e) {
throw new ResourceConflictException(e.getMessage());
- } catch (IOException e) {
- throw new ResourceConflictException(e.getMessage());
} catch (NoSuchChangeException e) {
throw new ResourceNotFoundException(change.getId().toString());
}
@@ -138,88 +100,118 @@
return json.format(change.getId());
}
- private boolean isDescendantOf(Change.Id child, RevId ancestor)
- throws OrmException {
- ReviewDb db = dbProvider.get();
-
- ArrayList<RevId> parents = new ArrayList<>();
- parents.add(ancestor);
- while (!parents.isEmpty()) {
- RevId parent = parents.remove(0);
- // get direct descendants of change
- for (PatchSetAncestor desc : db.patchSetAncestors().descendantsOf(parent)) {
- PatchSet descPatchSet = db.patchSets().get(desc.getPatchSet());
- Change.Id descChangeId = descPatchSet.getId().getParentKey();
- if (child.equals(descChangeId)) {
- PatchSet.Id descCurrentPatchSetId =
- db.changes().get(descChangeId).currentPatchSetId();
- // it's only bad if the descendant patch set is current
- return descPatchSet.getId().equals(descCurrentPatchSetId);
- } else {
- // process indirect descendants as well
- parents.add(descPatchSet.getRevision());
- }
- }
+ private String findBaseRev(RevWalk rw, RevisionResource rsrc,
+ RebaseInput input) throws AuthException, ResourceConflictException,
+ OrmException, IOException {
+ if (input == null || input.base == null) {
+ return null;
}
- return false;
+ Change change = rsrc.getChange();
+ String base = input.base.trim();
+ if (base.equals("")) {
+ // remove existing dependency to other patch set
+ return change.getDest().get();
+ }
+
+ ReviewDb db = dbProvider.get();
+ PatchSet basePatchSet = parseBase(base);
+ if (basePatchSet == null) {
+ throw new ResourceConflictException("base revision is missing: " + base);
+ } else if (!rsrc.getControl().isPatchVisible(basePatchSet, db)) {
+ throw new AuthException("base revision not accessible: " + base);
+ } else if (change.getId().equals(basePatchSet.getId().getParentKey())) {
+ throw new ResourceConflictException("cannot depend on self");
+ }
+
+ Change baseChange = db.changes().get(basePatchSet.getId().getParentKey());
+ if (baseChange == null) {
+ return null;
+ }
+ if (!baseChange.getProject().equals(change.getProject())) {
+ throw new ResourceConflictException(
+ "base change is in wrong project: " + baseChange.getProject());
+ } else if (!baseChange.getDest().equals(change.getDest())) {
+ throw new ResourceConflictException(
+ "base change is targeting wrong branch: " + baseChange.getDest());
+ } else if (baseChange.getStatus() == Status.ABANDONED) {
+ throw new ResourceConflictException(
+ "base change is abandoned: " + baseChange.getKey());
+ } else if (isMergedInto(rw, rsrc.getPatchSet(), basePatchSet)) {
+ throw new ResourceConflictException(
+ "base change " + baseChange.getKey()
+ + " is a descendant of the current change - recursion not allowed");
+ }
+ return basePatchSet.getRevision().get();
}
- private PatchSet parseBase(final String base) throws OrmException {
+ private boolean isMergedInto(RevWalk rw, PatchSet base, PatchSet tip)
+ throws IOException {
+ ObjectId baseId = ObjectId.fromString(base.getRevision().get());
+ ObjectId tipId = ObjectId.fromString(tip.getRevision().get());
+ return rw.isMergedInto(rw.parseCommit(baseId), rw.parseCommit(tipId));
+ }
+
+ private PatchSet parseBase(String base) throws OrmException {
ReviewDb db = dbProvider.get();
PatchSet.Id basePatchSetId = PatchSet.Id.fromRef(base);
if (basePatchSetId != null) {
- // try parsing the base as a ref string
+ // Try parsing the base as a ref string.
return db.patchSets().get(basePatchSetId);
}
- // try parsing base as a change number (assume current patch set)
+ // Try parsing base as a change number (assume current patch set).
PatchSet basePatchSet = null;
- try {
- Change.Id baseChangeId = Change.Id.parse(base);
- if (baseChangeId != null) {
- for (PatchSet ps : db.patchSets().byChange(baseChangeId)) {
- if (basePatchSet == null || basePatchSet.getId().get() < ps.getId().get()){
- basePatchSet = ps;
- }
- }
- }
- } catch (NumberFormatException e) { // probably a SHA1
- }
-
- // try parsing as SHA1
- if (basePatchSet == null) {
- for (PatchSet ps : db.patchSets().byRevision(new RevId(base))) {
- if (basePatchSet == null || basePatchSet.getId().get() < ps.getId().get()) {
+ Integer baseChangeId = Ints.tryParse(base);
+ if (baseChangeId != null) {
+ for (PatchSet ps : db.patchSets().byChange(new Change.Id(baseChangeId))) {
+ if (basePatchSet == null
+ || basePatchSet.getId().get() < ps.getId().get()) {
basePatchSet = ps;
}
}
+ if (basePatchSet != null) {
+ return basePatchSet;
+ }
}
+ // Try parsing as SHA-1.
+ for (PatchSet ps : db.patchSets().byRevision(new RevId(base))) {
+ if (basePatchSet == null
+ || basePatchSet.getId().get() < ps.getId().get()) {
+ basePatchSet = ps;
+ }
+ }
return basePatchSet;
}
- private boolean hasOneParent(final PatchSet.Id patchSetId) {
- try {
- // prevent rebase of exotic changes (merge commit, no ancestor).
- return (dbProvider.get().patchSetAncestors()
- .ancestorsOf(patchSetId).toList().size() == 1);
- } catch (OrmException e) {
- log.error("Failed to get ancestors of patch set "
- + patchSetId.toRefName(), e);
- return false;
- }
+ private boolean hasOneParent(RevWalk rw, PatchSet ps) throws IOException {
+ // Prevent rebase of exotic changes (merge commit, no ancestor).
+ RevCommit c = rw.parseCommit(ObjectId.fromString(ps.getRevision().get()));
+ return c.getParentCount() == 1;
}
@Override
public UiAction.Description getDescription(RevisionResource resource) {
+ Project.NameKey project = resource.getChange().getProject();
+ boolean visible = resource.getChange().getStatus().isOpen()
+ && resource.isCurrent()
+ && resource.getControl().canRebase();
+ if (visible) {
+ try (Repository repo = repoManager.openRepository(project);
+ RevWalk rw = new RevWalk(repo)) {
+ visible = hasOneParent(rw, resource.getPatchSet());
+ } catch (IOException e) {
+ log.error("Failed to get ancestors of patch set "
+ + resource.getPatchSet().getId(), e);
+ visible = false;
+ }
+ }
UiAction.Description descr = new UiAction.Description()
.setLabel("Rebase")
.setTitle("Rebase onto tip of branch or parent change")
- .setVisible(resource.getChange().getStatus().isOpen()
- && resource.getControl().canRebase()
- && hasOneParent(resource.getPatchSet().getId()));
+ .setVisible(visible);
if (descr.isVisible()) {
// Disable the rebase button in the RebaseDialog if
// the change cannot be rebased.
@@ -240,7 +232,7 @@
@Override
public ChangeInfo apply(ChangeResource rsrc, RebaseInput input)
throws AuthException, ResourceNotFoundException,
- ResourceConflictException, EmailException, OrmException {
+ ResourceConflictException, EmailException, OrmException, IOException {
PatchSet ps =
rebase.dbProvider.get().patchSets()
.get(rsrc.getChange().currentPatchSetId());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/RebaseChange.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/RebaseChange.java
new file mode 100644
index 0000000..96b513e
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/RebaseChange.java
@@ -0,0 +1,387 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.change;
+
+import com.google.gerrit.common.TimeUtil;
+import com.google.gerrit.common.errors.EmailException;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Change.Status;
+import com.google.gerrit.reviewdb.client.ChangeMessage;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.RevId;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.ChangeUtil;
+import com.google.gerrit.server.GerritPersonIdent;
+import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.change.PatchSetInserter.ValidatePolicy;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.git.MergeConflictException;
+import com.google.gerrit.server.git.MergeUtil;
+import com.google.gerrit.server.project.ChangeControl;
+import com.google.gerrit.server.project.InvalidChangeOperationException;
+import com.google.gerrit.server.project.NoSuchChangeException;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.merge.ThreeWayMerger;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.TimeZone;
+
+@Singleton
+public class RebaseChange {
+ private static final Logger log = LoggerFactory.getLogger(RebaseChange.class);
+
+ private final ChangeControl.GenericFactory changeControlFactory;
+ private final Provider<ReviewDb> db;
+ private final GitRepositoryManager gitManager;
+ private final TimeZone serverTimeZone;
+ private final MergeUtil.Factory mergeUtilFactory;
+ private final PatchSetInserter.Factory patchSetInserterFactory;
+
+ @Inject
+ RebaseChange(ChangeControl.GenericFactory changeControlFactory,
+ Provider<ReviewDb> db,
+ @GerritPersonIdent PersonIdent myIdent,
+ GitRepositoryManager gitManager,
+ MergeUtil.Factory mergeUtilFactory,
+ PatchSetInserter.Factory patchSetInserterFactory) {
+ this.changeControlFactory = changeControlFactory;
+ this.db = db;
+ this.gitManager = gitManager;
+ this.serverTimeZone = myIdent.getTimeZone();
+ this.mergeUtilFactory = mergeUtilFactory;
+ this.patchSetInserterFactory = patchSetInserterFactory;
+ }
+
+ /**
+ * Rebase the change of the given patch set.
+ * <p>
+ * It is verified that the current user is allowed to do the rebase.
+ * <p>
+ * If the patch set has no dependency to an open change, then the change is
+ * rebased on the tip of the destination branch.
+ * <p>
+ * If the patch set depends on an open change, it is rebased on the latest
+ * patch set of this change.
+ * <p>
+ * The rebased commit is added as new patch set to the change.
+ * <p>
+ * E-mail notification and triggering of hooks happens for the creation of the
+ * new patch set.
+ *
+ * @param git the repository.
+ * @param rw the RevWalk.
+ * @param change the change to rebase.
+ * @param patchSetId the patch set ID to rebase.
+ * @param uploader the user that creates the rebased patch set.
+ * @param newBaseRev the commit that should be the new base.
+ * @throws NoSuchChangeException if the change to which the patch set belongs
+ * does not exist or is not visible to the user.
+ * @throws EmailException if sending the e-mail to notify about the new patch
+ * set fails.
+ * @throws OrmException if accessing the database fails.
+ * @throws IOException if accessing the repository fails.
+ * @throws InvalidChangeOperationException if rebase is not possible or not
+ * allowed.
+ */
+ public void rebase(Repository git, RevWalk rw, Change change,
+ PatchSet.Id patchSetId, IdentifiedUser uploader, String newBaseRev)
+ throws NoSuchChangeException, EmailException, OrmException, IOException,
+ InvalidChangeOperationException {
+ Change.Id changeId = patchSetId.getParentKey();
+ ChangeControl changeControl =
+ changeControlFactory.validateFor(change, uploader);
+ if (!changeControl.canRebase()) {
+ throw new InvalidChangeOperationException("Cannot rebase: New patch sets"
+ + " are not allowed to be added to change: " + changeId);
+ }
+ try (ObjectInserter inserter = git.newObjectInserter()) {
+ String baseRev = newBaseRev;
+ if (baseRev == null) {
+ baseRev = findBaseRevision(
+ patchSetId, db.get(), change.getDest(), git, rw);
+ }
+ ObjectId baseObjectId = git.resolve(baseRev);
+ if (baseObjectId == null) {
+ throw new InvalidChangeOperationException(
+ "Cannot rebase: Failed to resolve baseRev: " + baseRev);
+ }
+ RevCommit baseCommit = rw.parseCommit(baseObjectId);
+
+ PersonIdent committerIdent =
+ uploader.newCommitterIdent(TimeUtil.nowTs(), serverTimeZone);
+
+ rebase(git, rw, inserter, change, patchSetId,
+ uploader, baseCommit, mergeUtilFactory.create(
+ changeControl.getProjectControl().getProjectState(), true),
+ committerIdent, true, ValidatePolicy.GERRIT);
+ } catch (MergeConflictException e) {
+ throw new IOException(e.getMessage());
+ }
+ }
+
+ /**
+ * Find the commit onto which a patch set should be rebased.
+ * <p>
+ * This is defined as the latest patch set of the change corresponding to
+ * this commit's parent, or the destination branch tip in the case where the
+ * parent's change is merged.
+ *
+ * @param patchSetId patch set ID for which the new base commit should be
+ * found.
+ * @param db the ReviewDb.
+ * @param destBranch the destination branch.
+ * @param git the repository.
+ * @param rw the RevWalk.
+ * @return the commit onto which the patch set should be rebased.
+ * @throws InvalidChangeOperationException if rebase is not possible or not
+ * allowed.
+ * @throws IOException if accessing the repository fails.
+ * @throws OrmException if accessing the database fails.
+ */
+ private static String findBaseRevision(PatchSet.Id patchSetId,
+ ReviewDb db, Branch.NameKey destBranch, Repository git, RevWalk rw)
+ throws InvalidChangeOperationException, IOException, OrmException {
+ String baseRev = null;
+
+ PatchSet patchSet = db.patchSets().get(patchSetId);
+ if (patchSet == null) {
+ throw new InvalidChangeOperationException(
+ "Patch set " + patchSetId + " not found");
+ }
+ RevCommit commit = rw.parseCommit(
+ ObjectId.fromString(patchSet.getRevision().get()));
+
+ if (commit.getParentCount() > 1) {
+ throw new InvalidChangeOperationException(
+ "Cannot rebase a change with multiple parents.");
+ } else if (commit.getParentCount() == 0) {
+ throw new InvalidChangeOperationException(
+ "Cannot rebase a change without any parents"
+ + " (is this the initial commit?).");
+ }
+
+ RevId parentRev = new RevId(commit.getParent(0).name());
+
+ for (PatchSet depPatchSet : db.patchSets().byRevision(parentRev)) {
+ Change.Id depChangeId = depPatchSet.getId().getParentKey();
+ Change depChange = db.changes().get(depChangeId);
+ if (!depChange.getDest().equals(destBranch)) {
+ continue;
+ }
+
+ if (depChange.getStatus() == Status.ABANDONED) {
+ throw new InvalidChangeOperationException(
+ "Cannot rebase a change with an abandoned parent: "
+ + depChange.getKey());
+ }
+
+ if (depChange.getStatus().isOpen()) {
+ if (depPatchSet.getId().equals(depChange.currentPatchSetId())) {
+ throw new InvalidChangeOperationException(
+ "Change is already based on the latest patch set of the"
+ + " dependent change.");
+ }
+ PatchSet latestDepPatchSet =
+ db.patchSets().get(depChange.currentPatchSetId());
+ baseRev = latestDepPatchSet.getRevision().get();
+ }
+ break;
+ }
+
+ if (baseRev == null) {
+ // We are dependent on a merged PatchSet or have no PatchSet
+ // dependencies at all.
+ Ref destRef = git.getRef(destBranch.get());
+ if (destRef == null) {
+ throw new InvalidChangeOperationException(
+ "The destination branch does not exist: " + destBranch.get());
+ }
+ baseRev = destRef.getObjectId().getName();
+ if (baseRev.equals(parentRev.get())) {
+ throw new InvalidChangeOperationException(
+ "Change is already up to date.");
+ }
+ }
+ return baseRev;
+ }
+
+ /**
+ * Rebase the change of the given patch set on the given base commit.
+ * <p>
+ * The rebased commit is added as new patch set to the change.
+ * <p>
+ * E-mail notification and triggering of hooks is only done for the creation
+ * of the new patch set if {@code sendEmail} and {@code runHooks} are true,
+ * respectively.
+ *
+ * @param git the repository.
+ * @param inserter the object inserter.
+ * @param change the change to rebase.
+ * @param patchSetId the patch set ID to rebase.
+ * @param uploader the user that creates the rebased patch set.
+ * @param baseCommit the commit that should be the new base.
+ * @param mergeUtil merge utilities for the destination project.
+ * @param committerIdent the committer's identity.
+ * @param runHooks if hooks should be run for the new patch set.
+ * @param validate if commit validation should be run for the new patch set.
+ * @param rw the RevWalk.
+ * @return the new patch set, which is based on the given base commit.
+ * @throws NoSuchChangeException if the change to which the patch set belongs
+ * does not exist or is not visible to the user.
+ * @throws OrmException if accessing the database fails.
+ * @throws IOException if rebase is not possible.
+ * @throws InvalidChangeOperationException if rebase is not possible or not
+ * allowed.
+ */
+ public PatchSet rebase(Repository git, RevWalk rw,
+ ObjectInserter inserter, Change change, PatchSet.Id patchSetId,
+ IdentifiedUser uploader, RevCommit baseCommit, MergeUtil mergeUtil,
+ PersonIdent committerIdent, boolean runHooks, ValidatePolicy validate)
+ throws NoSuchChangeException, OrmException, IOException,
+ InvalidChangeOperationException, MergeConflictException {
+ if (!change.currentPatchSetId().equals(patchSetId)) {
+ throw new InvalidChangeOperationException("patch set is not current");
+ }
+ PatchSet originalPatchSet = db.get().patchSets().get(patchSetId);
+
+ RevCommit rebasedCommit;
+ ObjectId oldId = ObjectId.fromString(originalPatchSet.getRevision().get());
+ ObjectId newId = rebaseCommit(git, inserter, rw.parseCommit(oldId),
+ baseCommit, mergeUtil, committerIdent);
+
+ rebasedCommit = rw.parseCommit(newId);
+
+ ChangeControl changeControl =
+ changeControlFactory.validateFor(change, uploader);
+
+ PatchSetInserter patchSetInserter = patchSetInserterFactory
+ .create(git, rw, changeControl, rebasedCommit)
+ .setValidatePolicy(validate)
+ .setDraft(originalPatchSet.isDraft())
+ .setUploader(uploader.getAccountId())
+ .setSendMail(false)
+ .setRunHooks(runHooks);
+
+ PatchSet.Id newPatchSetId = patchSetInserter.getPatchSetId();
+ ChangeMessage cmsg = new ChangeMessage(
+ new ChangeMessage.Key(change.getId(),
+ ChangeUtil.messageUUID(db.get())), uploader.getAccountId(),
+ TimeUtil.nowTs(), patchSetId);
+
+ cmsg.setMessage("Patch Set " + newPatchSetId.get()
+ + ": Patch Set " + patchSetId.get() + " was rebased");
+
+ Change newChange = patchSetInserter
+ .setMessage(cmsg)
+ .insert();
+
+ return db.get().patchSets().get(newChange.currentPatchSetId());
+ }
+
+ /**
+ * Rebase a commit.
+ *
+ * @param git repository to find commits in.
+ * @param inserter inserter to handle new trees and blobs.
+ * @param original the commit to rebase.
+ * @param base base to rebase against.
+ * @param mergeUtil merge utilities for the destination project.
+ * @param committerIdent committer identity.
+ * @return the id of the rebased commit.
+ * @throws MergeConflictException the rebase failed due to a merge conflict.
+ * @throws IOException the merge failed for another reason.
+ */
+ private ObjectId rebaseCommit(Repository git, ObjectInserter inserter,
+ RevCommit original, RevCommit base, MergeUtil mergeUtil,
+ PersonIdent committerIdent) throws MergeConflictException, IOException,
+ InvalidChangeOperationException {
+ RevCommit parentCommit = original.getParent(0);
+
+ if (base.equals(parentCommit)) {
+ throw new InvalidChangeOperationException(
+ "Change is already up to date.");
+ }
+
+ ThreeWayMerger merger = mergeUtil.newThreeWayMerger(git, inserter);
+ merger.setBase(parentCommit);
+ merger.merge(original, base);
+
+ if (merger.getResultTreeId() == null) {
+ throw new MergeConflictException(
+ "The change could not be rebased due to a conflict during merge.");
+ }
+
+ CommitBuilder cb = new CommitBuilder();
+ cb.setTreeId(merger.getResultTreeId());
+ cb.setParentId(base);
+ cb.setAuthor(original.getAuthorIdent());
+ cb.setMessage(original.getFullMessage());
+ cb.setCommitter(committerIdent);
+ ObjectId objectId = inserter.insert(cb);
+ inserter.flush();
+ return objectId;
+ }
+
+ public boolean canRebase(ChangeResource r) {
+ Change c = r.getChange();
+ return canRebase(c.getProject(), c.currentPatchSetId(), c.getDest());
+ }
+
+ public boolean canRebase(RevisionResource r) {
+ return canRebase(r.getChange().getProject(),
+ r.getPatchSet().getId(), r.getChange().getDest());
+ }
+
+ public boolean canRebase(Project.NameKey project, PatchSet.Id patchSetId,
+ Branch.NameKey branch) {
+ Repository git;
+ try {
+ git = gitManager.openRepository(project);
+ } catch (RepositoryNotFoundException err) {
+ return false;
+ } catch (IOException err) {
+ return false;
+ }
+ try (RevWalk rw = new RevWalk(git)) {
+ findBaseRevision(patchSetId, db.get(), branch, git, rw);
+ return true;
+ } catch (InvalidChangeOperationException e) {
+ return false;
+ } catch (OrmException | IOException e) {
+ log.warn("Error checking if patch set " + patchSetId + " on " + branch
+ + " can be rebased", e);
+ return false;
+ } finally {
+ git.close();
+ }
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Restore.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Restore.java
index cce362a..46d73d7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Restore.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Restore.java
@@ -15,7 +15,6 @@
package com.google.gerrit.server.change;
import com.google.common.base.Strings;
-import com.google.common.util.concurrent.CheckedFuture;
import com.google.gerrit.common.ChangeHooks;
import com.google.gerrit.extensions.api.changes.RestoreInput;
import com.google.gerrit.extensions.common.ChangeInfo;
@@ -122,17 +121,16 @@
}
update.commit();
- CheckedFuture<?, IOException> f = indexer.indexAsync(change.getId());
+ indexer.index(db, change);
try {
- ReplyToChangeSender cm = restoredSenderFactory.create(change);
+ ReplyToChangeSender cm = restoredSenderFactory.create(change.getId());
cm.setFrom(caller.getAccountId());
cm.setChangeMessage(message);
cm.send();
} catch (Exception e) {
log.error("Cannot email update for change " + change.getChangeId(), e);
}
- f.checkedGet();
hooks.doChangeRestoredHook(change,
caller.getAccount(),
db.patchSets().get(change.currentPatchSetId()),
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerSuggestionCache.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerSuggestionCache.java
index c4c9186..9e243b0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerSuggestionCache.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerSuggestionCache.java
@@ -49,7 +49,6 @@
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.RAMDirectory;
-import org.apache.lucene.util.Version;
import org.eclipse.jgit.lib.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -63,8 +62,8 @@
/**
* The suggest oracle may be called many times in rapid succession during the
* course of one operation.
- * It would be easy to have a simple Cache<Boolean, List<Account>> with a short
- * expiration time of 30s.
+ * It would be easy to have a simple {@code Cache<Boolean, List<Account>>}
+ * with a short expiration time of 30s.
* Cache only has a single key we're just using Cache for the expiration behavior.
*/
@Singleton
@@ -147,9 +146,7 @@
private IndexSearcher index() throws IOException, OrmException {
RAMDirectory idx = new RAMDirectory();
- @SuppressWarnings("deprecation")
IndexWriterConfig config = new IndexWriterConfig(
- Version.LUCENE_4_10_1,
new StandardAnalyzer(CharArraySet.EMPTY_SET));
config.setOpenMode(OpenMode.CREATE);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/RevisionResource.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/RevisionResource.java
index e58d1a1..538f36b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/RevisionResource.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/RevisionResource.java
@@ -92,7 +92,7 @@
return this;
}
- Optional<ChangeEdit> getEdit() {
+ public Optional<ChangeEdit> getEdit() {
return edit;
}
@@ -104,4 +104,8 @@
}
return s;
}
+
+ public boolean isCurrent() {
+ return ps.getId().equals(getChange().currentPatchSetId());
+ }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java
index 5f67e6e..109d96f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java
@@ -99,6 +99,10 @@
"Other changes in this topic are not ready";
private static final String BLOCKED_HIDDEN_TOPIC_TOOLTIP =
"Other hidden changes in this topic are not ready";
+ private static final String CLICK_FAILURE_OTHER_TOOLTIP =
+ "Clicking the button would fail for other changes in the topic";
+ private static final String CLICK_FAILURE_TOOLTIP =
+ "Clicking the button would fail.";
public enum Status {
SUBMITTED, MERGED
@@ -169,7 +173,7 @@
this.titlePattern = new ParameterizedString(MoreObjects.firstNonNull(
cfg.getString("change", null, "submitTooltip"),
DEFAULT_TOOLTIP));
- submitWholeTopic = cfg.getBoolean("change", null, "submitWholeTopic" , false);
+ submitWholeTopic = wholeTopicEnabled(cfg);
this.submitTopicLabel = MoreObjects.firstNonNull(
Strings.emptyToNull(cfg.getString("change", null, "submitTopicLabel")),
"Submit whole topic");
@@ -206,17 +210,19 @@
rsrc.getPatchSet().getRevision().get()));
}
- change = submit(rsrc, caller, false);
- if (change == null) {
- throw new ResourceConflictException("change is "
- + status(dbProvider.get().changes().get(rsrc.getChange().getId())));
- }
+ List<Change> submittedChanges = submit(rsrc, caller, false);
if (input.waitForMerge) {
- mergeQueue.merge(change.getDest());
+ for (Change c : submittedChanges) {
+ // TODO(sbeller): We should make schedule return a Future, then we
+ // could do these all in parallel and still block until they're done.
+ mergeQueue.merge(c.getDest());
+ }
change = dbProvider.get().changes().get(change.getId());
} else {
- mergeQueue.schedule(change.getDest());
+ for (Change c : submittedChanges) {
+ mergeQueue.schedule(c.getDest());
+ }
}
if (change == null) {
@@ -239,14 +245,15 @@
}
/**
- * @param changes list of changes to be submitted at once
+ * @param changeList list of changes to be submitted at once
* @param identifiedUser the user who is checking to submit
* @return a reason why any of the changes is not submittable or null
*/
- private String problemsForSubmittingChanges(List<ChangeData> changes,
+ private String problemsForSubmittingChanges(
+ List<ChangeData> changeList,
IdentifiedUser identifiedUser) {
- for (ChangeData c : changes) {
- try {
+ try {
+ for (ChangeData c : changeList) {
ChangeControl changeControl = c.changeControl().forUser(
identifiedUser);
if (!changeControl.isVisible(dbProvider.get())) {
@@ -255,13 +262,26 @@
if (!changeControl.canSubmit()) {
return BLOCKED_TOPIC_TOOLTIP;
}
+ // Recheck mergeability rather than using value stored in the index,
+ // which may be stale.
+ // TODO(dborowitz): This is ugly; consider providing a way to not read
+ // stored fields from the index in the first place.
+ c.setMergeable(null);
+ Boolean mergeable = c.isMergeable();
+ if (mergeable == null) {
+ log.error("Ephemeral error checking if change is submittable");
+ return CLICK_FAILURE_TOOLTIP;
+ }
+ if (!mergeable) {
+ return CLICK_FAILURE_OTHER_TOOLTIP;
+ }
checkSubmitRule(c, c.currentPatchSet(), false);
- } catch (OrmException e) {
- log.error("Error checking if change is submittable", e);
- throw new OrmRuntimeException(e);
- } catch (ResourceConflictException e) {
- return BLOCKED_TOPIC_TOOLTIP;
}
+ } catch (ResourceConflictException e) {
+ return BLOCKED_TOPIC_TOOLTIP;
+ } catch (OrmException e) {
+ log.error("Error checking if change is submittable", e);
+ throw new OrmRuntimeException("Could not determine problems for the change", e);
}
return null;
}
@@ -274,12 +294,16 @@
&& resource.getChange().getStatus().isOpen()
&& resource.getPatchSet().getId().equals(current)
&& resource.getControl().canSubmit();
-
ReviewDb db = dbProvider.get();
ChangeData cd = changeDataFactory.create(db, resource.getControl());
- if (problemsForSubmittingChanges(Arrays.asList(cd), resource.getUser())
- != null) {
+
+ try {
+ checkSubmitRule(cd, cd.currentPatchSet(), false);
+ } catch (ResourceConflictException e) {
visible = false;
+ } catch (OrmException e) {
+ log.error("Error checking if change is submittable", e);
+ throw new OrmRuntimeException("Could not determine problems for the change", e);
}
if (!visible) {
@@ -288,13 +312,21 @@
.setTitle("")
.setVisible(false);
}
+
+ Boolean enabled;
+ try {
+ enabled = cd.isMergeable();
+ } catch (OrmException e) {
+ throw new OrmRuntimeException("Could not determine mergeability", e);
+ }
+
+ List<ChangeData> changesByTopic = null;
if (submitWholeTopic && !Strings.isNullOrEmpty(topic)) {
- List<ChangeData> changesByTopic = null;
- try {
- changesByTopic = queryProvider.get().byTopicOpen(topic);
- } catch (OrmException e) {
- throw new OrmRuntimeException(e);
- }
+ changesByTopic = getChangesByTopic(topic);
+ }
+ if (submitWholeTopic
+ && !Strings.isNullOrEmpty(topic)
+ && changesByTopic.size() > 1) {
Map<String, String> params = ImmutableMap.of(
"topicSize", String.valueOf(changesByTopic.size()));
String topicProblems = problemsForSubmittingChanges(changesByTopic,
@@ -311,7 +343,7 @@
.setTitle(Strings.emptyToNull(
submitTopicTooltip.replace(params)))
.setVisible(true)
- .setEnabled(true);
+ .setEnabled(Boolean.TRUE.equals(enabled));
}
} else {
RevId revId = resource.getPatchSet().getRevision();
@@ -322,7 +354,8 @@
return new UiAction.Description()
.setLabel(label)
.setTitle(Strings.emptyToNull(titlePattern.replace(params)))
- .setVisible(true);
+ .setVisible(true)
+ .setEnabled(Boolean.TRUE.equals(enabled));
}
}
@@ -345,9 +378,10 @@
.orNull();
}
- private Change submitToDatabase(ReviewDb db, Change.Id changeId,
- final Timestamp timestamp) throws OrmException {
- return db.changes().atomicUpdate(changeId,
+ private Change submitToDatabase(final ReviewDb db, final Change.Id changeId,
+ final Timestamp timestamp) throws OrmException,
+ ResourceConflictException {
+ Change ret = db.changes().atomicUpdate(changeId,
new AtomicUpdate<Change>() {
@Override
public Change update(Change change) {
@@ -359,6 +393,12 @@
return null;
}
});
+ if (ret != null) {
+ return ret;
+ } else {
+ throw new ResourceConflictException("change " + changeId + " is "
+ + status(db.changes().get(changeId)));
+ }
}
private Change submitThisChange(RevisionResource rsrc, IdentifiedUser caller,
@@ -376,13 +416,11 @@
db.changes().beginTransaction(change.getId());
try {
- BatchMetaDataUpdate batch = approve(rsrc, update, caller, timestamp);
+ BatchMetaDataUpdate batch = approve(rsrc.getPatchSet().getId(),
+ cd.changeControl(), update, caller, timestamp);
// Write update commit after all normalized label commits.
batch.write(update, new CommitBuilder());
change = submitToDatabase(db, change.getId(), timestamp);
- if (change == null) {
- return null;
- }
db.commit();
} finally {
db.rollback();
@@ -391,7 +429,7 @@
return change;
}
- private Change submitWholeTopic(RevisionResource rsrc, IdentifiedUser caller,
+ private List<Change> submitWholeTopic(RevisionResource rsrc, IdentifiedUser caller,
boolean force, String topic) throws ResourceConflictException, OrmException,
IOException {
Preconditions.checkNotNull(topic);
@@ -415,45 +453,45 @@
db.changes().beginTransaction(change.getId());
try {
- BatchMetaDataUpdate batch = approve(rsrc, update, caller, timestamp);
- // Write update commit after all normalized label commits.
- batch.write(update, new CommitBuilder());
-
for (ChangeData c : changesByTopic) {
- if (submitToDatabase(db, c.getId(), timestamp) == null) {
- return null;
- }
+ BatchMetaDataUpdate batch = approve(c.currentPatchSet().getId(),
+ c.changeControl(), update, caller, timestamp);
+ // Write update commit after all normalized label commits.
+ batch.write(update, new CommitBuilder());
+ submitToDatabase(db, c.getId(), timestamp);
}
db.commit();
} finally {
db.rollback();
}
List<Change.Id> ids = new ArrayList<>(changesByTopic.size());
+ List<Change> ret = new ArrayList<>(changesByTopic.size());
for (ChangeData c : changesByTopic) {
ids.add(c.getId());
+ ret.add(c.change());
}
indexer.indexAsync(ids).checkedGet();
- return change;
+
+ return ret;
}
- public Change submit(RevisionResource rsrc, IdentifiedUser caller,
+ public List<Change> submit(RevisionResource rsrc, IdentifiedUser caller,
boolean force) throws ResourceConflictException, OrmException,
IOException {
String topic = rsrc.getChange().getTopic();
if (submitWholeTopic && !Strings.isNullOrEmpty(topic)) {
return submitWholeTopic(rsrc, caller, force, topic);
} else {
- return submitThisChange(rsrc, caller, force);
+ return Arrays.asList(submitThisChange(rsrc, caller, force));
}
}
- private BatchMetaDataUpdate approve(RevisionResource rsrc,
+ private BatchMetaDataUpdate approve(PatchSet.Id psId, ChangeControl control,
ChangeUpdate update, IdentifiedUser caller, Timestamp timestamp)
throws OrmException {
- PatchSet.Id psId = rsrc.getPatchSet().getId();
Map<PatchSetApproval.Key, PatchSetApproval> byKey = Maps.newHashMap();
for (PatchSetApproval psa :
- approvalsUtil.byPatchSet(dbProvider.get(), rsrc.getControl(), psId)) {
+ approvalsUtil.byPatchSet(dbProvider.get(), control, psId)) {
if (!byKey.containsKey(psa.getKey())) {
byKey.put(psa.getKey(), psa);
}
@@ -464,7 +502,7 @@
|| !submit.getAccountId().equals(caller.getAccountId())) {
submit = new PatchSetApproval(
new PatchSetApproval.Key(
- rsrc.getPatchSet().getId(),
+ psId,
caller.getAccountId(),
LabelId.SUBMIT),
(short) 1, TimeUtil.nowTs());
@@ -479,7 +517,7 @@
// was added. So we need to make sure votes are accurate now. This way if
// permissions get modified in the future, historical records stay accurate.
LabelNormalizer.Result normalized =
- labelNormalizer.normalize(rsrc.getControl(), byKey.values());
+ labelNormalizer.normalize(control, byKey.values());
// TODO(dborowitz): Don't use a label in notedb; just check when status
// change happened.
@@ -489,13 +527,13 @@
dbProvider.get().patchSetApprovals().delete(normalized.deleted());
try {
- return saveToBatch(rsrc, update, normalized, timestamp);
+ return saveToBatch(control, update, normalized, timestamp);
} catch (IOException e) {
throw new OrmException(e);
}
}
- private BatchMetaDataUpdate saveToBatch(RevisionResource rsrc,
+ private BatchMetaDataUpdate saveToBatch(ChangeControl ctl,
ChangeUpdate callerUpdate, LabelNormalizer.Result normalized,
Timestamp timestamp) throws IOException {
Table<Account.Id, String, Optional<Short>> byUser = HashBasedTable.create();
@@ -507,7 +545,6 @@
byUser.put(psa.getAccountId(), psa.getLabel(), Optional.<Short> absent());
}
- ChangeControl ctl = rsrc.getControl();
BatchMetaDataUpdate batch = callerUpdate.openUpdate();
for (Account.Id accountId : byUser.rowKeySet()) {
if (!accountId.equals(callerUpdate.getUser().getAccountId())) {
@@ -654,6 +691,18 @@
return new RevisionResource(changes.parse(target), rsrc.getPatchSet());
}
+ static boolean wholeTopicEnabled(Config config) {
+ return config.getBoolean("change", null, "submitWholeTopic" , false);
+ }
+
+ private List<ChangeData> getChangesByTopic(String topic) {
+ try {
+ return queryProvider.get().byTopicOpen(topic);
+ } catch (OrmException e) {
+ throw new OrmRuntimeException(e);
+ }
+ }
+
public static class CurrentRevision implements
RestModifyView<ChangeResource, SubmitInput> {
private final Provider<ReviewDb> dbProvider;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/TestSubmitRule.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/TestSubmitRule.java
index d3c4132..31e34cf 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/TestSubmitRule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/TestSubmitRule.java
@@ -106,7 +106,7 @@
Map<String, None> need;
Map<String, AccountInfo> may;
Map<String, None> impossible;
- Integer prologReductionCount;
+ Long prologReductionCount;
Record(SubmitRecord r, AccountLoader accounts) {
this.status = r.status;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/WalkSorter.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/WalkSorter.java
new file mode 100644
index 0000000..0ccf991
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/WalkSorter.java
@@ -0,0 +1,203 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.change;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Ordering;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.query.change.ChangeData;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevSort;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Helper to sort {@link ChangeData}s based on {@link RevWalk} ordering.
+ * <p>
+ * Split changes by project, and map each change to a single commit based on the
+ * latest patch set. The set of patch sets considered may be limited by calling
+ * {@link #includePatchSets(Iterable)}. Perform a standard {@link RevWalk} on
+ * each project repository, and record the order in which each change's commit
+ * is seen.
+ * <p>
+ * Once an order within each project is determined, groups of changes are sorted
+ * based on the project name. This is slightly more stable than sorting on
+ * something like the commit or change timestamp, as it will not unexpectedly
+ * reorder large groups of changes on subsequent calls if one of the changes was
+ * updated.
+ */
+class WalkSorter {
+ private static final Logger log =
+ LoggerFactory.getLogger(WalkSorter.class);
+
+ private static final Ordering<List<PatchSetData>> PROJECT_LIST_SORTER =
+ Ordering.natural().nullsFirst()
+ .onResultOf(
+ new Function<List<PatchSetData>, Project.NameKey>() {
+ @Override
+ public Project.NameKey apply(List<PatchSetData> in) {
+ if (in == null || in.isEmpty()) {
+ return null;
+ }
+ try {
+ return in.get(0).data().change().getProject();
+ } catch (OrmException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ });
+
+ private final GitRepositoryManager repoManager;
+ private final Set<PatchSet.Id> includePatchSets;
+ private boolean retainBody;
+
+ @Inject
+ WalkSorter(GitRepositoryManager repoManager) {
+ this.repoManager = repoManager;
+ includePatchSets = new HashSet<>();
+ }
+
+ public WalkSorter includePatchSets(Iterable<PatchSet.Id> patchSets) {
+ Iterables.addAll(includePatchSets, patchSets);
+ return this;
+ }
+
+ public WalkSorter setRetainBody(boolean retainBody) {
+ this.retainBody = retainBody;
+ return this;
+ }
+
+ public Iterable<PatchSetData> sort(Iterable<ChangeData> in)
+ throws OrmException, IOException {
+ Multimap<Project.NameKey, ChangeData> byProject =
+ ArrayListMultimap.create();
+ for (ChangeData cd : in) {
+ byProject.put(cd.change().getProject(), cd);
+ }
+
+ List<List<PatchSetData>> sortedByProject =
+ new ArrayList<>(byProject.keySet().size());
+ for (Map.Entry<Project.NameKey, Collection<ChangeData>> e
+ : byProject.asMap().entrySet()) {
+ sortedByProject.add(sortProject(e.getKey(), e.getValue()));
+ }
+ Collections.sort(sortedByProject, PROJECT_LIST_SORTER);
+ return Iterables.concat(sortedByProject);
+ }
+
+ private List<PatchSetData> sortProject(Project.NameKey project,
+ Collection<ChangeData> in) throws OrmException, IOException {
+ try (Repository repo = repoManager.openRepository(project);
+ RevWalk rw = new RevWalk(repo)) {
+ rw.setRetainBody(retainBody);
+ rw.sort(RevSort.TOPO);
+ Multimap<RevCommit, PatchSetData> byCommit = byCommit(rw, in);
+ if (byCommit.isEmpty()) {
+ return ImmutableList.of();
+ }
+
+ // Walk from all patch set SHA-1s, and terminate as soon as we've found
+ // everything we're looking for. This is equivalent to just sorting the
+ // list of commits by the RevWalk's configured order.
+ for (RevCommit c : byCommit.keySet()) {
+ rw.markStart(c);
+ }
+
+ int expected = byCommit.keySet().size();
+ int found = 0;
+ RevCommit c;
+ List<PatchSetData> result = new ArrayList<>(expected);
+ while (found < expected && (c = rw.next()) != null) {
+ Collection<PatchSetData> psds = byCommit.get(c);
+ if (!psds.isEmpty()) {
+ found++;
+ for (PatchSetData psd : psds) {
+ result.add(psd);
+ }
+ }
+ }
+ return result;
+ }
+ }
+
+ private Multimap<RevCommit, PatchSetData> byCommit(RevWalk rw,
+ Collection<ChangeData> in) throws OrmException, IOException {
+ Multimap<RevCommit, PatchSetData> byCommit =
+ ArrayListMultimap.create(in.size(), 1);
+ for (ChangeData cd : in) {
+ PatchSet maxPs = null;
+ for (PatchSet ps : cd.patchSets()) {
+ if (shouldInclude(ps)
+ && (maxPs == null || ps.getId().get() > maxPs.getId().get())) {
+ maxPs = ps;
+ }
+ }
+ if (maxPs == null) {
+ continue; // No patch sets matched.
+ }
+ ObjectId id = ObjectId.fromString(maxPs.getRevision().get());
+ try {
+ RevCommit c = rw.parseCommit(id);
+ byCommit.put(c, PatchSetData.create(cd, maxPs, c));
+ } catch (MissingObjectException | IncorrectObjectTypeException e) {
+ log.warn(
+ "missing commit " + id.name() + " for patch set " + maxPs.getId(),
+ e);
+ }
+ }
+ return byCommit;
+ }
+
+ private boolean shouldInclude(PatchSet ps) {
+ return includePatchSets.isEmpty() || includePatchSets.contains(ps.getId());
+ }
+
+ @AutoValue
+ static abstract class PatchSetData {
+ @VisibleForTesting
+ static PatchSetData create(ChangeData cd, PatchSet ps, RevCommit commit) {
+ return new AutoValue_WalkSorter_PatchSetData(cd, ps, commit);
+ }
+
+ abstract ChangeData data();
+ abstract PatchSet patchSet();
+ abstract RevCommit commit();
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java
deleted file mode 100644
index 67e70c1..0000000
--- a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java
+++ /dev/null
@@ -1,399 +0,0 @@
-// Copyright (C) 2012 The Android Open Source Project
-//
-// 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.
-
-package com.google.gerrit.server.changedetail;
-
-import com.google.gerrit.common.TimeUtil;
-import com.google.gerrit.common.errors.EmailException;
-import com.google.gerrit.reviewdb.client.Branch;
-import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.reviewdb.client.Change.Status;
-import com.google.gerrit.reviewdb.client.ChangeMessage;
-import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gerrit.reviewdb.client.PatchSetAncestor;
-import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.reviewdb.client.RevId;
-import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gerrit.server.ChangeUtil;
-import com.google.gerrit.server.GerritPersonIdent;
-import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.change.ChangeResource;
-import com.google.gerrit.server.change.PatchSetInserter;
-import com.google.gerrit.server.change.PatchSetInserter.ValidatePolicy;
-import com.google.gerrit.server.change.RevisionResource;
-import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.git.MergeConflictException;
-import com.google.gerrit.server.git.MergeUtil;
-import com.google.gerrit.server.project.ChangeControl;
-import com.google.gerrit.server.project.InvalidChangeOperationException;
-import com.google.gerrit.server.project.NoSuchChangeException;
-import com.google.gwtorm.server.OrmException;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import com.google.inject.Singleton;
-
-import org.eclipse.jgit.errors.RepositoryNotFoundException;
-import org.eclipse.jgit.lib.CommitBuilder;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.ObjectInserter;
-import org.eclipse.jgit.lib.PersonIdent;
-import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.merge.ThreeWayMerger;
-import org.eclipse.jgit.revwalk.RevCommit;
-import org.eclipse.jgit.revwalk.RevWalk;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.TimeZone;
-
-@Singleton
-public class RebaseChange {
- private final ChangeControl.GenericFactory changeControlFactory;
- private final Provider<ReviewDb> db;
- private final GitRepositoryManager gitManager;
- private final TimeZone serverTimeZone;
- private final MergeUtil.Factory mergeUtilFactory;
- private final PatchSetInserter.Factory patchSetInserterFactory;
-
- @Inject
- RebaseChange(final ChangeControl.GenericFactory changeControlFactory,
- final Provider<ReviewDb> db,
- @GerritPersonIdent final PersonIdent myIdent,
- final GitRepositoryManager gitManager,
- final MergeUtil.Factory mergeUtilFactory,
- final PatchSetInserter.Factory patchSetInserterFactory) {
- this.changeControlFactory = changeControlFactory;
- this.db = db;
- this.gitManager = gitManager;
- this.serverTimeZone = myIdent.getTimeZone();
- this.mergeUtilFactory = mergeUtilFactory;
- this.patchSetInserterFactory = patchSetInserterFactory;
- }
-
- /**
- * Rebases the change of the given patch set.
- *
- * It is verified that the current user is allowed to do the rebase.
- *
- * If the patch set has no dependency to an open change, then the change is
- * rebased on the tip of the destination branch.
- *
- * If the patch set depends on an open change, it is rebased on the latest
- * patch set of this change.
- *
- * The rebased commit is added as new patch set to the change.
- *
- * E-mail notification and triggering of hooks happens for the creation of the
- * new patch set.
- *
- * @param change the change to perform the rebase for
- * @param patchSetId the id of the patch set
- * @param uploader the user that creates the rebased patch set
- * @param newBaseRev the commit that should be the new base
- * @throws NoSuchChangeException thrown if the change to which the patch set
- * belongs does not exist or is not visible to the user
- * @throws EmailException thrown if sending the e-mail to notify about the new
- * patch set fails
- * @throws OrmException thrown in case accessing the database fails
- * @throws IOException thrown if rebase is not possible or not needed
- * @throws InvalidChangeOperationException thrown if rebase is not allowed
- */
- public void rebase(Change change, PatchSet.Id patchSetId, final IdentifiedUser uploader,
- final String newBaseRev) throws NoSuchChangeException, EmailException, OrmException,
- IOException, InvalidChangeOperationException {
- final Change.Id changeId = patchSetId.getParentKey();
- final ChangeControl changeControl =
- changeControlFactory.validateFor(change, uploader);
- if (!changeControl.canRebase()) {
- throw new InvalidChangeOperationException(
- "Cannot rebase: New patch sets are not allowed to be added to change: "
- + changeId.toString());
- }
- try (Repository git = gitManager.openRepository(change.getProject());
- RevWalk rw = new RevWalk(git);
- ObjectInserter inserter = git.newObjectInserter()) {
- String baseRev = newBaseRev;
- if (baseRev == null) {
- baseRev = findBaseRevision(patchSetId, db.get(),
- change.getDest(), git, null, null, null);
- }
- ObjectId baseObjectId = git.resolve(baseRev);
- if (baseObjectId == null) {
- throw new InvalidChangeOperationException(
- "Cannot rebase: Failed to resolve baseRev: " + baseRev);
- }
- final RevCommit baseCommit = rw.parseCommit(baseObjectId);
-
- PersonIdent committerIdent =
- uploader.newCommitterIdent(TimeUtil.nowTs(),
- serverTimeZone);
-
- rebase(git, rw, inserter, patchSetId, change,
- uploader, baseCommit, mergeUtilFactory.create(
- changeControl.getProjectControl().getProjectState(), true),
- committerIdent, true, ValidatePolicy.GERRIT);
- } catch (MergeConflictException e) {
- throw new IOException(e.getMessage());
- }
- }
-
- /**
- * Finds the revision of commit on which the given patch set should be based.
- *
- * @param patchSetId the id of the patch set for which the new base commit
- * should be found
- * @param db the ReviewDb
- * @param destBranch the destination branch
- * @param git the repository
- * @param patchSetAncestors the original PatchSetAncestor of the given patch
- * set that should be based
- * @param depPatchSetList the original patch set list on which the rebased
- * patch set depends
- * @param depChangeList the original change list on whose patch set the
- * rebased patch set depends
- * @return the revision of commit on which the given patch set should be based
- * @throws IOException thrown if rebase is not possible or not needed
- * @throws OrmException thrown in case accessing the database fails
- */
- private static String findBaseRevision(final PatchSet.Id patchSetId,
- final ReviewDb db, final Branch.NameKey destBranch, final Repository git,
- List<PatchSetAncestor> patchSetAncestors, List<PatchSet> depPatchSetList,
- List<Change> depChangeList) throws IOException, OrmException {
-
- String baseRev = null;
-
- if (patchSetAncestors == null) {
- patchSetAncestors =
- db.patchSetAncestors().ancestorsOf(patchSetId).toList();
- }
-
- if (patchSetAncestors.size() > 1) {
- throw new IOException(
- "Cannot rebase a change with multiple parents. Parent commits: "
- + patchSetAncestors.toString());
- }
- if (patchSetAncestors.size() == 0) {
- throw new IOException(
- "Cannot rebase a change without any parents (is this the initial commit?).");
- }
-
- RevId ancestorRev = patchSetAncestors.get(0).getAncestorRevision();
- if (depPatchSetList == null || depPatchSetList.size() != 1 ||
- !depPatchSetList.get(0).getRevision().equals(ancestorRev)) {
- depPatchSetList = db.patchSets().byRevision(ancestorRev).toList();
- }
-
- for (PatchSet depPatchSet : depPatchSetList) {
-
- Change.Id depChangeId = depPatchSet.getId().getParentKey();
- Change depChange;
- if (depChangeList == null || depChangeList.size() != 1 ||
- !depChangeList.get(0).getId().equals(depChangeId)) {
- depChange = db.changes().get(depChangeId);
- } else {
- depChange = depChangeList.get(0);
- }
- if (!depChange.getDest().equals(destBranch)) {
- continue;
- }
-
- if (depChange.getStatus() == Status.ABANDONED) {
- throw new IOException("Cannot rebase a change with an abandoned parent: "
- + depChange.getKey().toString());
- }
-
- if (depChange.getStatus().isOpen()) {
- if (depPatchSet.getId().equals(depChange.currentPatchSetId())) {
- throw new IOException(
- "Change is already based on the latest patch set of the dependent change.");
- }
- PatchSet latestDepPatchSet =
- db.patchSets().get(depChange.currentPatchSetId());
- baseRev = latestDepPatchSet.getRevision().get();
- }
- break;
- }
-
- if (baseRev == null) {
- // We are dependent on a merged PatchSet or have no PatchSet
- // dependencies at all.
- Ref destRef = git.getRef(destBranch.get());
- if (destRef == null) {
- throw new IOException(
- "The destination branch does not exist: "
- + destBranch.get());
- }
- baseRev = destRef.getObjectId().getName();
- if (baseRev.equals(ancestorRev.get())) {
- throw new IOException("Change is already up to date.");
- }
- }
- return baseRev;
- }
-
- /**
- * Rebases the change of the given patch set on the given base commit.
- *
- * The rebased commit is added as new patch set to the change.
- *
- * E-mail notification and triggering of hooks is only done for the creation of
- * the new patch set if `sendEmail` and `runHooks` are set to true.
- *
- * @param git the repository
- * @param revWalk the RevWalk
- * @param inserter the object inserter
- * @param patchSetId the id of the patch set
- * @param change the change that should be rebased
- * @param uploader the user that creates the rebased patch set
- * @param baseCommit the commit that should be the new base
- * @param mergeUtil merge utilities for the destination project
- * @param committerIdent the committer's identity
- * @param runHooks if hooks should be run for the new patch set
- * @param validate if commit validation should be run for the new patch set
- * @return the new patch set which is based on the given base commit
- * @throws NoSuchChangeException thrown if the change to which the patch set
- * belongs does not exist or is not visible to the user
- * @throws OrmException thrown in case accessing the database fails
- * @throws IOException thrown if rebase is not possible or not needed
- * @throws InvalidChangeOperationException thrown if rebase is not allowed
- */
- public PatchSet rebase(final Repository git, final RevWalk revWalk,
- final ObjectInserter inserter, final PatchSet.Id patchSetId,
- final Change change, final IdentifiedUser uploader, final RevCommit baseCommit,
- final MergeUtil mergeUtil, PersonIdent committerIdent,
- boolean runHooks, ValidatePolicy validate)
- throws NoSuchChangeException,
- OrmException, IOException, InvalidChangeOperationException,
- MergeConflictException {
- if (!change.currentPatchSetId().equals(patchSetId)) {
- throw new InvalidChangeOperationException("patch set is not current");
- }
- final PatchSet originalPatchSet = db.get().patchSets().get(patchSetId);
-
- final RevCommit rebasedCommit;
- ObjectId oldId = ObjectId.fromString(originalPatchSet.getRevision().get());
- ObjectId newId = rebaseCommit(git, inserter, revWalk.parseCommit(oldId),
- baseCommit, mergeUtil, committerIdent);
-
- rebasedCommit = revWalk.parseCommit(newId);
-
- final ChangeControl changeControl =
- changeControlFactory.validateFor(change, uploader);
-
- PatchSetInserter patchSetInserter = patchSetInserterFactory
- .create(git, revWalk, changeControl, rebasedCommit)
- .setValidatePolicy(validate)
- .setDraft(originalPatchSet.isDraft())
- .setUploader(uploader.getAccountId())
- .setSendMail(false)
- .setRunHooks(runHooks);
-
- final PatchSet.Id newPatchSetId = patchSetInserter.getPatchSetId();
- final ChangeMessage cmsg = new ChangeMessage(
- new ChangeMessage.Key(change.getId(),
- ChangeUtil.messageUUID(db.get())), uploader.getAccountId(),
- TimeUtil.nowTs(), patchSetId);
-
- cmsg.setMessage("Patch Set " + newPatchSetId.get()
- + ": Patch Set " + patchSetId.get() + " was rebased");
-
- Change newChange = patchSetInserter
- .setMessage(cmsg)
- .insert();
-
- return db.get().patchSets().get(newChange.currentPatchSetId());
- }
-
- /**
- * Rebase a commit.
- *
- * @param git repository to find commits in.
- * @param inserter inserter to handle new trees and blobs.
- * @param original the commit to rebase.
- * @param base base to rebase against.
- * @param mergeUtil merge utilities for the destination project.
- * @param committerIdent committer identity.
- * @return the id of the rebased commit.
- * @throws MergeConflictException the rebase failed due to a merge conflict.
- * @throws IOException the merge failed for another reason.
- */
- private ObjectId rebaseCommit(Repository git, ObjectInserter inserter,
- RevCommit original, RevCommit base, MergeUtil mergeUtil,
- PersonIdent committerIdent) throws MergeConflictException, IOException {
- RevCommit parentCommit = original.getParent(0);
-
- if (base.equals(parentCommit)) {
- throw new IOException("Change is already up to date.");
- }
-
- ThreeWayMerger merger = mergeUtil.newThreeWayMerger(git, inserter);
- merger.setBase(parentCommit);
- merger.merge(original, base);
-
- if (merger.getResultTreeId() == null) {
- throw new MergeConflictException(
- "The change could not be rebased due to a conflict during merge.");
- }
-
- CommitBuilder cb = new CommitBuilder();
- cb.setTreeId(merger.getResultTreeId());
- cb.setParentId(base);
- cb.setAuthor(original.getAuthorIdent());
- cb.setMessage(original.getFullMessage());
- cb.setCommitter(committerIdent);
- ObjectId objectId = inserter.insert(cb);
- inserter.flush();
- return objectId;
- }
-
- public boolean canRebase(ChangeResource r) {
- Change c = r.getChange();
- return canRebase(c.getProject(), c.currentPatchSetId(), c.getDest());
- }
-
- public boolean canRebase(RevisionResource r) {
- return canRebase(r.getChange().getProject(),
- r.getPatchSet().getId(), r.getChange().getDest());
- }
-
- public boolean canRebase(Project.NameKey project,
- PatchSet.Id patchSetId, Branch.NameKey branch) {
- Repository git;
- try {
- git = gitManager.openRepository(project);
- } catch (RepositoryNotFoundException err) {
- return false;
- } catch (IOException err) {
- return false;
- }
- try {
- findBaseRevision(
- patchSetId,
- db.get(),
- branch,
- git,
- null,
- null,
- null);
- return true;
- } catch (IOException e) {
- return false;
- } catch (OrmException e) {
- return false;
- } finally {
- git.close();
- }
- }
-}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfig.java
index d7138b3..abcd441 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfig.java
@@ -44,6 +44,7 @@
private final boolean enableRunAs;
private final boolean userNameToLowerCase;
private final boolean gitBasicAuth;
+ private final boolean useContributorAgreements;
private final String loginUrl;
private final String logoutUrl;
private final String openIdSsoUrl;
@@ -75,6 +76,8 @@
trustContainerAuth = cfg.getBoolean("auth", "trustContainerAuth", false);
enableRunAs = cfg.getBoolean("auth", null, "enableRunAs", true);
gitBasicAuth = cfg.getBoolean("auth", "gitBasicAuth", false);
+ useContributorAgreements =
+ cfg.getBoolean("auth", "contributoragreements", false);
userNameToLowerCase = cfg.getBoolean("auth", "userNameToLowerCase", false);
@@ -194,6 +197,11 @@
return gitBasicAuth;
}
+ /** Whether contributor agreements are used. */
+ public boolean isUseContributorAgreements() {
+ return useContributorAgreements;
+ }
+
public boolean isIdentityTrustable(final Collection<AccountExternalId> ids) {
switch (getAuthType()) {
case DEVELOPMENT_BECOME_ANY_ACCOUNT:
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/DownloadConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/DownloadConfig.java
index 2d9f21a..4986989 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/DownloadConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/DownloadConfig.java
@@ -16,12 +16,14 @@
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadCommand;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadScheme;
+import com.google.gerrit.server.change.ArchiveFormat;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.jgit.lib.Config;
import java.util.Collections;
+import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -31,6 +33,7 @@
public class DownloadConfig {
private final Set<DownloadScheme> downloadSchemes;
private final Set<DownloadCommand> downloadCommands;
+ private final Set<ArchiveFormat> archiveFormats;
@Inject
DownloadConfig(@GerritServerConfig final Config cfg) {
@@ -45,6 +48,17 @@
DownloadCommand.DEFAULT_DOWNLOADS);
downloadCommands =
Collections.unmodifiableSet(new HashSet<>(allCommands));
+
+ String v = cfg.getString("download", null, "archive");
+ if (v == null) {
+ archiveFormats = EnumSet.allOf(ArchiveFormat.class);
+ } else if (v.isEmpty() || "off".equalsIgnoreCase(v)) {
+ archiveFormats = Collections.emptySet();
+ } else {
+ archiveFormats = new HashSet<>(ConfigUtil.getEnumList(cfg,
+ "download", null, "archive",
+ ArchiveFormat.TGZ));
+ }
}
/** Scheme used to download. */
@@ -56,4 +70,9 @@
public Set<DownloadCommand> getDownloadCommands() {
return downloadCommands;
}
+
+ /** Archive formats for downloading. */
+ public Set<ArchiveFormat> getArchiveFormats() {
+ return archiveFormats;
+ }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GcConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GcConfig.java
index 54096bb..572b56e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GcConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GcConfig.java
@@ -23,14 +23,19 @@
@Singleton
public class GcConfig {
private final ScheduleConfig scheduleConfig;
+ private final boolean aggressive;
@Inject
GcConfig(@GerritServerConfig Config cfg) {
scheduleConfig = new ScheduleConfig(cfg, ConfigConstants.CONFIG_GC_SECTION);
+ aggressive = cfg.getBoolean(ConfigConstants.CONFIG_GC_SECTION, "aggressive", false);
}
public ScheduleConfig getScheduleConfig() {
return scheduleConfig;
}
+ public boolean isAggressive() {
+ return aggressive;
+ }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
index 7bdccaa..8e9d7e8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
@@ -22,6 +22,7 @@
import com.google.gerrit.extensions.config.CapabilityDefinition;
import com.google.gerrit.extensions.config.DownloadCommand;
import com.google.gerrit.extensions.config.DownloadScheme;
+import com.google.gerrit.extensions.events.GarbageCollectorListener;
import com.google.gerrit.extensions.events.GitReferenceUpdatedListener;
import com.google.gerrit.extensions.events.HeadUpdatedListener;
import com.google.gerrit.extensions.events.LifecycleListener;
@@ -38,7 +39,6 @@
import com.google.gerrit.extensions.webui.PatchSetWebLink;
import com.google.gerrit.extensions.webui.ProjectWebLink;
import com.google.gerrit.extensions.webui.TopMenu;
-import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.rules.PrologModule;
import com.google.gerrit.rules.RulesCache;
import com.google.gerrit.server.AnonymousUser;
@@ -63,8 +63,6 @@
import com.google.gerrit.server.account.GroupIncludeCacheImpl;
import com.google.gerrit.server.account.GroupInfoCacheFactory;
import com.google.gerrit.server.account.GroupMembers;
-import com.google.gerrit.server.account.PerformCreateGroup;
-import com.google.gerrit.server.account.PerformRenameGroup;
import com.google.gerrit.server.auth.AuthBackend;
import com.google.gerrit.server.auth.UniversalAuthBackend;
import com.google.gerrit.server.avatar.AvatarProvider;
@@ -113,7 +111,6 @@
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.CommentLinkInfo;
import com.google.gerrit.server.project.CommentLinkProvider;
-import com.google.gerrit.server.project.PerformCreateProject;
import com.google.gerrit.server.project.PermissionCollection;
import com.google.gerrit.server.project.ProjectCacheImpl;
import com.google.gerrit.server.project.ProjectControl;
@@ -125,6 +122,7 @@
import com.google.gerrit.server.ssh.SshAddressesModule;
import com.google.gerrit.server.tools.ToolsCatalog;
import com.google.gerrit.server.util.IdGenerator;
+import com.google.gerrit.server.util.SubmoduleSectionParser;
import com.google.gerrit.server.util.ThreadLocalRequestContext;
import com.google.gerrit.server.validators.GroupCreationValidationListener;
import com.google.gerrit.server.validators.HashtagValidationListener;
@@ -139,7 +137,6 @@
import org.eclipse.jgit.transport.PreUploadHook;
import java.util.List;
-import java.util.Set;
/** Starts global state with standard dependencies. */
@@ -195,21 +192,17 @@
factory(MergeFailSender.Factory.class);
factory(MergeUtil.Factory.class);
factory(PatchScriptFactory.Factory.class);
- factory(PerformCreateGroup.Factory.class);
- factory(PerformRenameGroup.Factory.class);
factory(PluginUser.Factory.class);
factory(ProjectNode.Factory.class);
factory(ProjectState.Factory.class);
factory(RegisterNewEmailSender.Factory.class);
factory(ReplacePatchSetSender.Factory.class);
- factory(PerformCreateProject.Factory.class);
bind(PermissionCollection.Factory.class);
bind(AccountVisibility.class)
.toProvider(AccountVisibilityProvider.class)
.in(SINGLETON);
- bind(new TypeLiteral<Set<AccountGroup.UUID>>() {})
- .annotatedWith(ProjectOwnerGroups.class)
- .toProvider(ProjectOwnerGroupsProvider.class).in(SINGLETON);
+ factory(ProjectOwnerGroupsProvider.Factory.class);
+ bind(RepositoryConfig.class);
bind(AuthBackend.class).to(UniversalAuthBackend.class).in(SINGLETON);
DynamicSet.setOf(binder(), AuthBackend.class);
@@ -261,6 +254,7 @@
DynamicSet.setOf(binder(), PreUploadHook.class);
DynamicSet.setOf(binder(), NewProjectCreatedListener.class);
DynamicSet.setOf(binder(), ProjectDeletedListener.class);
+ DynamicSet.setOf(binder(), GarbageCollectorListener.class);
DynamicSet.setOf(binder(), HeadUpdatedListener.class);
DynamicSet.setOf(binder(), UsageDataPublishedListener.class);
DynamicSet.bind(binder(), GitReferenceUpdatedListener.class).to(ReindexAfterUpdate.class);
@@ -297,6 +291,7 @@
factory(MergeValidators.Factory.class);
factory(ProjectConfigValidator.Factory.class);
factory(NotesBranchUtil.Factory.class);
+ factory(SubmoduleSectionParser.Factory.class);
bind(AccountManager.class);
bind(ChangeUserName.CurrentUser.class);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerConfigModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerConfigModule.java
index 89331fd..281600d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerConfigModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerConfigModule.java
@@ -29,12 +29,12 @@
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.util.FS;
-import java.io.File;
import java.io.IOException;
+import java.nio.file.Path;
/** Creates {@link GerritServerConfig}. */
public class GerritServerConfigModule extends AbstractModule {
- public static String getSecureStoreClassName(final File sitePath) {
+ public static String getSecureStoreClassName(final Path sitePath) {
if (sitePath != null) {
return getSecureStoreFromGerritConfig(sitePath);
}
@@ -43,17 +43,17 @@
return nullToDefault(secureStoreProperty);
}
- private static String getSecureStoreFromGerritConfig(final File sitePath) {
+ private static String getSecureStoreFromGerritConfig(final Path sitePath) {
AbstractModule m = new AbstractModule() {
@Override
protected void configure() {
- bind(File.class).annotatedWith(SitePath.class).toInstance(sitePath);
+ bind(Path.class).annotatedWith(SitePath.class).toInstance(sitePath);
bind(SitePaths.class);
}
};
Injector injector = Guice.createInjector(m);
SitePaths site = injector.getInstance(SitePaths.class);
- FileBasedConfig cfg = new FileBasedConfig(site.gerrit_config, FS.DETECTED);
+ FileBasedConfig cfg = new FileBasedConfig(site.gerrit_config.toFile(), FS.DETECTED);
if (!cfg.getFile().exists()) {
return DefaultSecureStore.class.getName();
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerConfigProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerConfigProvider.java
index aa699c5..4b1236b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerConfigProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerConfigProvider.java
@@ -44,10 +44,11 @@
@Override
public Config get() {
- FileBasedConfig cfg = new FileBasedConfig(site.gerrit_config, FS.DETECTED);
+ FileBasedConfig cfg =
+ new FileBasedConfig(site.gerrit_config.toFile(), FS.DETECTED);
if (!cfg.getFile().exists()) {
- log.info("No " + site.gerrit_config.getAbsolutePath()
+ log.info("No " + site.gerrit_config.toAbsolutePath()
+ "; assuming defaults");
return new GerritConfig(cfg, secureStore);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GetServerInfo.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GetServerInfo.java
new file mode 100644
index 0000000..fe81dfd
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GetServerInfo.java
@@ -0,0 +1,176 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.config;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+import com.google.gerrit.extensions.config.DownloadCommand;
+import com.google.gerrit.extensions.config.DownloadScheme;
+import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.extensions.restapi.RestReadView;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AuthType;
+import com.google.gerrit.server.account.Realm;
+import com.google.gerrit.server.change.ArchiveFormat;
+import com.google.inject.Inject;
+
+import org.eclipse.jgit.lib.Config;
+
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+public class GetServerInfo implements RestReadView<ConfigResource> {
+ private final Config config;
+ private final AuthConfig authConfig;
+ private final Realm realm;
+ private final DownloadConfig downloadConfig;
+ private final DynamicMap<DownloadScheme> downloadSchemes;
+ private final DynamicMap<DownloadCommand> downloadCommands;
+ private final AllProjectsName allProjectsName;
+ private final AllUsersName allUsersName;
+
+ @Inject
+ public GetServerInfo(
+ @GerritServerConfig Config config,
+ AuthConfig authConfig,
+ Realm realm,
+ DownloadConfig downloadConfig,
+ DynamicMap<DownloadScheme> downloadSchemes,
+ DynamicMap<DownloadCommand> downloadCommands,
+ AllProjectsName allProjectsName,
+ AllUsersName allUsersName) {
+ this.config = config;
+ this.authConfig = authConfig;
+ this.realm = realm;
+ this.downloadConfig = downloadConfig;
+ this.downloadSchemes = downloadSchemes;
+ this.downloadCommands = downloadCommands;
+ this.allProjectsName = allProjectsName;
+ this.allUsersName = allUsersName;
+ }
+
+ @Override
+ public ServerInfo apply(ConfigResource rsrc) throws MalformedURLException {
+ ServerInfo info = new ServerInfo();
+ info.auth = new AuthInfo(authConfig, realm);
+ info.contactStore = getContactStoreInfo();
+ info.download =
+ new DownloadInfo(downloadConfig, downloadSchemes, downloadCommands);
+ info.gerrit = new GerritInfo(allProjectsName, allUsersName);
+ return info;
+ }
+
+ private ContactStoreInfo getContactStoreInfo() {
+ String url = config.getString("contactstore", null, "url");
+ if (url == null) {
+ return null;
+ }
+
+ ContactStoreInfo contactStore = new ContactStoreInfo();
+ contactStore.url = url;
+ return contactStore;
+ }
+
+ private static Boolean toBoolean(boolean v) {
+ return v ? v : null;
+ }
+
+ public static class ServerInfo {
+ public AuthInfo auth;
+ public ContactStoreInfo contactStore;
+ public DownloadInfo download;
+ public GerritInfo gerrit;
+ }
+
+ public static class AuthInfo {
+ public AuthType authType;
+ public Boolean useContributorAgreements;
+ public List<Account.FieldName> editableAccountFields;
+
+ public AuthInfo(AuthConfig cfg, Realm realm) {
+ authType = cfg.getAuthType();
+ useContributorAgreements = toBoolean(cfg.isUseContributorAgreements());
+ editableAccountFields = new ArrayList<>(realm.getEditableFields());
+ }
+ }
+
+ public static class ContactStoreInfo {
+ public String url;
+ }
+
+ public static class DownloadInfo {
+ public Map<String, DownloadSchemeInfo> schemes;
+ public List<String> archives;
+
+ public DownloadInfo(DownloadConfig downloadConfig,
+ DynamicMap<DownloadScheme> downloadSchemes,
+ DynamicMap<DownloadCommand> downloadCommands) {
+ schemes = new HashMap<>();
+ for (DynamicMap.Entry<DownloadScheme> e : downloadSchemes) {
+ DownloadScheme scheme = e.getProvider().get();
+ if (scheme.isEnabled() && scheme.getUrl("${project}") != null) {
+ schemes.put(e.getExportName(),
+ new DownloadSchemeInfo(scheme, downloadCommands));
+ }
+ }
+ archives =
+ Lists.transform(new ArrayList<>(downloadConfig.getArchiveFormats()),
+ new Function<ArchiveFormat, String>() {
+ @Override
+ public String apply(ArchiveFormat archiveFormat) {
+ return archiveFormat.name().toLowerCase(Locale.US);
+ }
+ });
+ }
+ }
+
+ public static class DownloadSchemeInfo {
+ public String url;
+ public Boolean isAuthRequired;
+ public Boolean isAuthSupported;
+ public Map<String, String> commands;
+
+ public DownloadSchemeInfo(DownloadScheme scheme,
+ DynamicMap<DownloadCommand> downloadCommands) {
+ url = scheme.getUrl("${project}");
+ isAuthRequired = toBoolean(scheme.isAuthRequired());
+ isAuthSupported = toBoolean(scheme.isAuthSupported());
+
+ commands = new HashMap<>();
+ for (DynamicMap.Entry<DownloadCommand> e : downloadCommands) {
+ String commandName = e.getExportName();
+ DownloadCommand command = e.getProvider().get();
+ String c = command.getCommand(scheme, "${project}", "${ref}");
+ if (c != null) {
+ commands.put(commandName, c);
+ }
+ }
+ }
+ }
+
+ public static class GerritInfo {
+ public String allProjects;
+ public String allUsers;
+
+ public GerritInfo(AllProjectsName allProjectsName, AllUsersName allUsersName) {
+ allProjects = allProjectsName.get();
+ allUsers = allUsersName.get();
+ }
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GetSummary.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GetSummary.java
index 9aa8590..2d19f65 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GetSummary.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GetSummary.java
@@ -24,7 +24,6 @@
import org.eclipse.jgit.internal.storage.file.WindowCacheStatAccessor;
import org.kohsuke.args4j.Option;
-import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
@@ -33,6 +32,8 @@
import java.lang.management.ThreadMXBean;
import java.net.InetAddress;
import java.net.UnknownHostException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
@@ -43,7 +44,7 @@
public class GetSummary implements RestReadView<ConfigResource> {
private final WorkQueue workQueue;
- private final File sitePath;
+ private final Path sitePath;
@Option(name = "--gc", usage = "perform Java GC before retrieving memory stats")
private boolean gc;
@@ -62,7 +63,7 @@
}
@Inject
- public GetSummary(WorkQueue workQueue, @SitePath File sitePath) {
+ public GetSummary(WorkQueue workQueue, @SitePath Path sitePath) {
this.workQueue = workQueue;
this.sitePath = sitePath;
}
@@ -88,7 +89,9 @@
private TaskSummaryInfo getTaskSummary() {
Collection<Task<?>> pending = workQueue.getTasks();
int tasksTotal = pending.size();
- int tasksRunning = 0, tasksReady = 0, tasksSleeping = 0;
+ int tasksRunning = 0;
+ int tasksReady = 0;
+ int tasksSleeping = 0;
for (Task<?> task : pending) {
switch (task.getState()) {
case RUNNING: tasksRunning++; break;
@@ -186,7 +189,8 @@
} catch (UnknownHostException e) {
}
- jvmSummary.currentWorkingDirectory = path(new File(".").getAbsoluteFile().getParentFile());
+ jvmSummary.currentWorkingDirectory =
+ path(Paths.get(".").toAbsolutePath().getParent());
jvmSummary.site = path(sitePath);
return jvmSummary;
}
@@ -210,11 +214,11 @@
return String.format("%1$6.2f%2$s", value, suffix).trim();
}
- private static String path(File file) {
+ private static String path(Path path) {
try {
- return file.getCanonicalPath();
+ return path.toRealPath().normalize().toString();
} catch (IOException err) {
- return file.getAbsolutePath();
+ return path.toAbsolutePath().normalize().toString();
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitReceivePackGroupsProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitReceivePackGroupsProvider.java
index 5e2f71f..5dd2784 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitReceivePackGroupsProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitReceivePackGroupsProvider.java
@@ -30,7 +30,8 @@
@GerritServerConfig Config config,
ThreadLocalRequestContext threadContext,
ServerRequestContext serverCtx) {
- super(gb, config, threadContext, serverCtx, "receive", null, "allowGroup");
+ super(gb, threadContext, serverCtx, config.getStringList("receive", null,
+ "allowGroup"));
// If no group was set, default to "registered users"
//
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitUploadPackGroupsProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitUploadPackGroupsProvider.java
index 79cfd88..545f48b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitUploadPackGroupsProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitUploadPackGroupsProvider.java
@@ -29,7 +29,8 @@
@GerritServerConfig Config config,
ThreadLocalRequestContext threadContext,
ServerRequestContext serverCtx) {
- super(gb, config, threadContext, serverCtx, "upload", null, "allowGroup");
+ super(gb, threadContext, serverCtx, config.getStringList("upload", null,
+ "allowGroup"));
// If no group was set, default to "registered users" and "anonymous"
//
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GroupSetProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GroupSetProvider.java
index 5c3ec39..9e55a7f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GroupSetProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GroupSetProvider.java
@@ -25,7 +25,6 @@
import com.google.inject.Inject;
import com.google.inject.Provider;
-import org.eclipse.jgit.lib.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -40,13 +39,10 @@
@Inject
protected GroupSetProvider(GroupBackend groupBackend,
- @GerritServerConfig Config config,
ThreadLocalRequestContext threadContext,
- ServerRequestContext serverCtx, String section,
- String subsection, String name) {
+ ServerRequestContext serverCtx, String[] groupNames) {
RequestContext ctx = threadContext.setContext(serverCtx);
try {
- String[] groupNames = config.getStringList(section, subsection, name);
ImmutableSet.Builder<AccountGroup.UUID> builder = ImmutableSet.builder();
for (String n : groupNames) {
GroupReference g = GroupBackends.findBestSuggestion(groupBackend, n);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/ListCaches.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/ListCaches.java
index df6d86b..006419b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/ListCaches.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/ListCaches.java
@@ -41,7 +41,7 @@
private final DynamicMap<Cache<?, ?>> cacheMap;
public static enum OutputFormat {
- LIST, TEXT_LIST;
+ LIST, TEXT_LIST
}
@Option(name = "--format", usage = "output format")
@@ -85,7 +85,7 @@
}
public enum CacheType {
- MEM, DISK;
+ MEM, DISK
}
public static class CacheInfo {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/Module.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/Module.java
index 64848ba..31fdc1e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/Module.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/Module.java
@@ -35,6 +35,7 @@
delete(TASK_KIND).to(DeleteTask.class);
child(CONFIG_KIND, "top-menus").to(TopMenuCollection.class);
get(CONFIG_KIND, "version").to(GetVersion.class);
+ get(CONFIG_KIND, "info").to(GetServerInfo.class);
get(CONFIG_KIND, "preferences").to(GetPreferences.class);
put(CONFIG_KIND, "preferences").to(SetPreferences.class);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/PluginConfigFactory.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/PluginConfigFactory.java
index 76f5323..a437085 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/PluginConfigFactory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/PluginConfigFactory.java
@@ -35,6 +35,7 @@
import java.io.File;
import java.io.IOException;
+import java.nio.file.Path;
import java.util.Map;
@Singleton
@@ -61,7 +62,7 @@
this.projectStateFactory = projectStateFactory;
this.pluginConfigs = Maps.newHashMap();
- this.cfgSnapshot = FileSnapshot.save(site.gerrit_config);
+ this.cfgSnapshot = FileSnapshot.save(site.gerrit_config.toFile());
this.cfg = cfgProvider.get();
}
@@ -103,8 +104,9 @@
* @return the plugin configuration from the 'gerrit.config' file
*/
public PluginConfig getFromGerritConfig(String pluginName, boolean refresh) {
- if (refresh && cfgSnapshot.isModified(site.gerrit_config)) {
- cfgSnapshot = FileSnapshot.save(site.gerrit_config);
+ File configFile = site.gerrit_config.toFile();
+ if (refresh && cfgSnapshot.isModified(configFile)) {
+ cfgSnapshot = FileSnapshot.save(configFile);
cfg = cfgProvider.get();
}
return new PluginConfig(pluginName, cfg);
@@ -237,33 +239,35 @@
/**
* Returns the configuration for the specified plugin that is stored in the
- * plugin configuration file 'etc/<plugin-name>.config'.
+ * plugin configuration file '{@code etc/<plugin-name>.config}'.
*
* The plugin configuration is only loaded once and is then cached.
*
* @param pluginName the name of the plugin for which the configuration should
* be returned
- * @return the plugin configuration from the 'etc/<plugin-name>.config' file
+ * @return the plugin configuration from the
+ * '{@code etc/<plugin-name>.config}' file
*/
public synchronized Config getGlobalPluginConfig(String pluginName) {
if (pluginConfigs.containsKey(pluginName)) {
return pluginConfigs.get(pluginName);
}
- File pluginConfigFile = new File(site.etc_dir, pluginName + ".config");
- FileBasedConfig cfg = new FileBasedConfig(pluginConfigFile, FS.DETECTED);
+ Path pluginConfigFile = site.etc_dir.resolve(pluginName + ".config");
+ FileBasedConfig cfg =
+ new FileBasedConfig(pluginConfigFile.toFile(), FS.DETECTED);
pluginConfigs.put(pluginName, cfg);
if (!cfg.getFile().exists()) {
- log.info("No " + pluginConfigFile.getAbsolutePath() + "; assuming defaults");
+ log.info("No " + pluginConfigFile.toAbsolutePath() + "; assuming defaults");
return cfg;
}
try {
cfg.load();
} catch (IOException e) {
- log.warn("Failed to load " + pluginConfigFile.getAbsolutePath(), e);
+ log.warn("Failed to load " + pluginConfigFile.toAbsolutePath(), e);
} catch (ConfigInvalidException e) {
- log.warn("Failed to load " + pluginConfigFile.getAbsolutePath(), e);
+ log.warn("Failed to load " + pluginConfigFile.toAbsolutePath(), e);
}
return cfg;
@@ -271,15 +275,15 @@
/**
* Returns the configuration for the specified plugin that is stored in the
- * '<plugin-name>.config' file in the 'refs/meta/config' branch of the
- * specified project.
+ * '{@code <plugin-name>.config}' file in the 'refs/meta/config' branch of
+ * the specified project.
*
* @param projectName the name of the project for which the plugin
* configuration should be returned
* @param pluginName the name of the plugin for which the configuration should
* be returned
- * @return the plugin configuration from the '<plugin-name>.config' file of
- * the specified project
+ * @return the plugin configuration from the '{@code <plugin-name>.config}'
+ * file of the specified project
* @throws NoSuchProjectException thrown if the specified project does not
* exist
*/
@@ -290,15 +294,15 @@
/**
* Returns the configuration for the specified plugin that is stored in the
- * '<plugin-name>.config' file in the 'refs/meta/config' branch of the
- * specified project.
+ * '{@code <plugin-name>.config}' file in the 'refs/meta/config' branch of
+ * the specified project.
*
* @param projectState the project for which the plugin configuration should
* be returned
* @param pluginName the name of the plugin for which the configuration should
* be returned
- * @return the plugin configuration from the '<plugin-name>.config' file of
- * the specified project
+ * @return the plugin configuration from the '{@code <plugin-name>.config}'
+ * file of the specified project
*/
public Config getProjectPluginConfig(ProjectState projectState,
String pluginName) {
@@ -307,10 +311,10 @@
/**
* Returns the configuration for the specified plugin that is stored in the
- * '<plugin-name>.config' file in the 'refs/meta/config' branch of the
- * specified project. Parameters which are not set in the
- * '<plugin-name>.config' of this project are inherited from the parent
- * project's '<plugin-name>.config' files.
+ * '{@code <plugin-name>.config}' file in the 'refs/meta/config' branch of
+ * the specified project. Parameters which are not set in the
+ * '{@code <plugin-name>.config}' of this project are inherited from the
+ * parent project's '{@code <plugin-name>.config}' files.
*
* E.g.: child project: [mySection "mySubsection"] myKey = childValue
*
@@ -324,9 +328,9 @@
* configuration should be returned
* @param pluginName the name of the plugin for which the configuration should
* be returned
- * @return the plugin configuration from the '<plugin-name>.config' file of
- * the specified project with inheriting non-set parameters from the
- * parent projects
+ * @return the plugin configuration from the '{@code <plugin-name>.config}'
+ * file of the specified project with inheriting non-set parameters
+ * from the parent projects
* @throws NoSuchProjectException thrown if the specified project does not
* exist
*/
@@ -337,10 +341,10 @@
/**
* Returns the configuration for the specified plugin that is stored in the
- * '<plugin-name>.config' file in the 'refs/meta/config' branch of the
- * specified project. Parameters which are not set in the
- * '<plugin-name>.config' of this project are inherited from the parent
- * project's '<plugin-name>.config' files.
+ * '{@code <plugin-name>.config}' file in the 'refs/meta/config' branch of
+ * the specified project. Parameters which are not set in the
+ * '{@code <plugin-name>.config}' of this project are inherited from the
+ * parent project's '{@code <plugin-name>.config}' files.
*
* E.g.: child project: [mySection "mySubsection"] myKey = childValue
*
@@ -354,9 +358,9 @@
* be returned
* @param pluginName the name of the plugin for which the configuration should
* be returned
- * @return the plugin configuration from the '<plugin-name>.config' file of
- * the specified project with inheriting non-set parameters from the
- * parent projects
+ * @return the plugin configuration from the '{@code <plugin-name>.config}'
+ * file of the specified project with inheriting non-set parameters
+ * from the parent projects
*/
public Config getProjectPluginConfigWithInheritance(ProjectState projectState,
String pluginName) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/PostCaches.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/PostCaches.java
index 7302ea1..2bbb731 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/PostCaches.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/PostCaches.java
@@ -52,7 +52,7 @@
}
public static enum Operation {
- FLUSH_ALL, FLUSH;
+ FLUSH_ALL, FLUSH
}
private final DynamicMap<Cache<?, ?>> cacheMap;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroups.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroups.java
deleted file mode 100644
index 876c51f..0000000
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroups.java
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (C) 2010 The Android Open Source Project
-//
-// 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.
-
-package com.google.gerrit.server.config;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import com.google.inject.BindingAnnotation;
-
-import java.lang.annotation.Retention;
-
-/**
- * Marker on a {@code Set<AccountGroup.Id>} for the configured groups which
- * should become owners of a created project.
- */
-@Retention(RUNTIME)
-@BindingAnnotation
-public @interface ProjectOwnerGroups {
-}
\ No newline at end of file
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroupsProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroupsProvider.java
index 0189de3..23615d6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroupsProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroupsProvider.java
@@ -14,30 +14,37 @@
package com.google.gerrit.server.config;
+import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.account.GroupBackend;
import com.google.gerrit.server.util.ServerRequestContext;
import com.google.gerrit.server.util.ThreadLocalRequestContext;
-import com.google.inject.Inject;
-
-import org.eclipse.jgit.lib.Config;
+import com.google.inject.assistedinject.Assisted;
+import com.google.inject.assistedinject.AssistedInject;
/**
* Provider of the group(s) which should become owners of a newly created
- * project. Currently only supports {@code ownerGroup} declarations in the
- * {@code "*"} repository, like so:
+ * project. The only matching patterns supported are exact match or wildcard
+ * matching which can be specified by ending the name with a {@code *}.
*
* <pre>
* [repository "*"]
* ownerGroup = Registered Users
* ownerGroup = Administrators
+ * [repository "project/*"]
+ * ownerGroup = Administrators
* </pre>
*/
public class ProjectOwnerGroupsProvider extends GroupSetProvider {
- @Inject
+
+ public interface Factory {
+ public ProjectOwnerGroupsProvider create(Project.NameKey project);
+ }
+
+ @AssistedInject
public ProjectOwnerGroupsProvider(GroupBackend gb,
- @GerritServerConfig final Config config,
- ThreadLocalRequestContext context,
- ServerRequestContext serverCtx) {
- super(gb, config, context, serverCtx, "repository", "*", "ownerGroup");
+ ThreadLocalRequestContext context, ServerRequestContext serverCtx,
+ RepositoryConfig repositoryCfg,
+ @Assisted Project.NameKey project) {
+ super(gb, context, serverCtx, repositoryCfg.getOwnerGroups(project));
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/RepositoryConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/RepositoryConfig.java
new file mode 100644
index 0000000..c34b8a6
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/RepositoryConfig.java
@@ -0,0 +1,85 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.config;
+
+import com.google.gerrit.extensions.client.SubmitType;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+import org.eclipse.jgit.lib.Config;
+
+@Singleton
+public class RepositoryConfig {
+
+ static final String SECTION_NAME = "repository";
+ static final String OWNER_GROUP_NAME = "ownerGroup";
+ static final String DEFAULT_SUBMIT_TYPE_NAME = "defaultSubmitType";
+
+ private final Config cfg;
+
+ @Inject
+ public RepositoryConfig(@GerritServerConfig Config cfg) {
+ this.cfg = cfg;
+ }
+
+ public SubmitType getDefaultSubmitType(Project.NameKey project) {
+ return cfg.getEnum(SECTION_NAME, findSubSection(project.get()),
+ DEFAULT_SUBMIT_TYPE_NAME, SubmitType.MERGE_IF_NECESSARY);
+ }
+
+ public String[] getOwnerGroups(Project.NameKey project) {
+ return cfg.getStringList(SECTION_NAME, findSubSection(project.get()),
+ OWNER_GROUP_NAME);
+ }
+
+ /**
+ * Find the subSection to get repository configuration from.
+ * <p>
+ * SubSection can use the * pattern so if project name matches more than one
+ * section, return the more precise one. E.g if the following subSections are
+ * defined:
+ *
+ * <pre>
+ * [repository "somePath/*"]
+ * name = value
+ * [repository "somePath/somePath/*"]
+ * name = value
+ * </pre>
+ *
+ * and this method is called with "somePath/somePath/someProject" as project
+ * name, it will return the subSection "somePath/somePath/*"
+ *
+ * @param project Name of the project
+ * @return the name of the subSection, null if none is found
+ */
+ private String findSubSection(String project) {
+ String subSectionFound = null;
+ for (String subSection : cfg.getSubsections(SECTION_NAME)) {
+ if (isMatch(subSection, project)
+ && (subSectionFound == null || subSectionFound.length() < subSection
+ .length())) {
+ subSectionFound = subSection;
+ }
+ }
+ return subSectionFound;
+ }
+
+ private boolean isMatch(String subSection, String project) {
+ return project.equals(subSection)
+ || (subSection.endsWith("*") && project.startsWith(subSection
+ .substring(0, subSection.length() - 1)));
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/SitePaths.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/SitePaths.java
index fbff7c4..a6a3e53 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/SitePaths.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/SitePaths.java
@@ -14,12 +14,15 @@
package com.google.gerrit.server.config;
+import com.google.common.collect.Iterables;
import com.google.inject.Inject;
import com.google.inject.Singleton;
-import java.io.File;
-import java.io.FileNotFoundException;
import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
/** Important paths within a {@link SitePath}. */
@Singleton
@@ -28,88 +31,84 @@
public static final String HEADER_FILENAME = "GerritSiteHeader.html";
public static final String FOOTER_FILENAME = "GerritSiteFooter.html";
- public final File site_path;
- public final File bin_dir;
- public final File etc_dir;
- public final File lib_dir;
- public final File tmp_dir;
- public final File logs_dir;
- public final File plugins_dir;
- public final File data_dir;
- public final File mail_dir;
- public final File hooks_dir;
- public final File static_dir;
- public final File themes_dir;
- public final File index_dir;
+ public final Path site_path;
+ public final Path bin_dir;
+ public final Path etc_dir;
+ public final Path lib_dir;
+ public final Path tmp_dir;
+ public final Path logs_dir;
+ public final Path plugins_dir;
+ public final Path data_dir;
+ public final Path mail_dir;
+ public final Path hooks_dir;
+ public final Path static_dir;
+ public final Path themes_dir;
+ public final Path index_dir;
- public final File gerrit_sh;
- public final File gerrit_war;
+ public final Path gerrit_sh;
+ public final Path gerrit_war;
- public final File gerrit_config;
- public final File secure_config;
- public final File contact_information_pub;
+ public final Path gerrit_config;
+ public final Path secure_config;
+ public final Path contact_information_pub;
- public final File ssl_keystore;
- public final File ssh_key;
- public final File ssh_rsa;
- public final File ssh_dsa;
- public final File peer_keys;
+ public final Path ssl_keystore;
+ public final Path ssh_key;
+ public final Path ssh_rsa;
+ public final Path ssh_dsa;
+ public final Path peer_keys;
- public final File site_css;
- public final File site_header;
- public final File site_footer;
- public final File site_gitweb;
+ public final Path site_css;
+ public final Path site_header;
+ public final Path site_footer;
+ public final Path site_gitweb;
/** {@code true} if {@link #site_path} has not been initialized. */
public final boolean isNew;
@Inject
- public SitePaths(final @SitePath File sitePath) throws FileNotFoundException {
+ public SitePaths(@SitePath Path sitePath) throws IOException {
site_path = sitePath;
+ Path p = sitePath;
- bin_dir = new File(site_path, "bin");
- etc_dir = new File(site_path, "etc");
- lib_dir = new File(site_path, "lib");
- tmp_dir = new File(site_path, "tmp");
- plugins_dir = new File(site_path, "plugins");
- data_dir = new File(site_path, "data");
- logs_dir = new File(site_path, "logs");
- mail_dir = new File(etc_dir, "mail");
- hooks_dir = new File(site_path, "hooks");
- static_dir = new File(site_path, "static");
- themes_dir = new File(site_path, "themes");
- index_dir = new File(site_path, "index");
+ bin_dir = p.resolve("bin");
+ etc_dir = p.resolve("etc");
+ lib_dir = p.resolve("lib");
+ tmp_dir = p.resolve("tmp");
+ plugins_dir = p.resolve("plugins");
+ data_dir = p.resolve("data");
+ logs_dir = p.resolve("logs");
+ mail_dir = etc_dir.resolve("mail");
+ hooks_dir = p.resolve("hooks");
+ static_dir = p.resolve("static");
+ themes_dir = p.resolve("themes");
+ index_dir = p.resolve("index");
- gerrit_sh = new File(bin_dir, "gerrit.sh");
- gerrit_war = new File(bin_dir, "gerrit.war");
+ gerrit_sh = bin_dir.resolve("gerrit.sh");
+ gerrit_war = bin_dir.resolve("gerrit.war");
- gerrit_config = new File(etc_dir, "gerrit.config");
- secure_config = new File(etc_dir, "secure.config");
- contact_information_pub = new File(etc_dir, "contact_information.pub");
+ gerrit_config = etc_dir.resolve("gerrit.config");
+ secure_config = etc_dir.resolve("secure.config");
+ contact_information_pub = etc_dir.resolve("contact_information.pub");
- ssl_keystore = new File(etc_dir, "keystore");
- ssh_key = new File(etc_dir, "ssh_host_key");
- ssh_rsa = new File(etc_dir, "ssh_host_rsa_key");
- ssh_dsa = new File(etc_dir, "ssh_host_dsa_key");
- peer_keys = new File(etc_dir, "peer_keys");
+ ssl_keystore = etc_dir.resolve("keystore");
+ ssh_key = etc_dir.resolve("ssh_host_key");
+ ssh_rsa = etc_dir.resolve("ssh_host_rsa_key");
+ ssh_dsa = etc_dir.resolve("ssh_host_dsa_key");
+ peer_keys = etc_dir.resolve("peer_keys");
- site_css = new File(etc_dir, CSS_FILENAME);
- site_header = new File(etc_dir, HEADER_FILENAME);
- site_footer = new File(etc_dir, FOOTER_FILENAME);
- site_gitweb = new File(etc_dir, "gitweb_config.perl");
+ site_css = etc_dir.resolve(CSS_FILENAME);
+ site_header = etc_dir.resolve(HEADER_FILENAME);
+ site_footer = etc_dir.resolve(FOOTER_FILENAME);
+ site_gitweb = etc_dir.resolve("gitweb_config.perl");
- if (site_path.exists()) {
- final String[] contents = site_path.list();
- if (contents != null) {
- isNew = contents.length == 0;
- } else if (site_path.isDirectory()) {
- throw new FileNotFoundException("Cannot access " + site_path);
- } else {
- throw new FileNotFoundException("Not a directory: " + site_path);
- }
- } else {
+ boolean isNew;
+ try (DirectoryStream<Path> files = Files.newDirectoryStream(site_path)) {
+ isNew = Iterables.isEmpty(files);
+ } catch (NoSuchFileException e) {
isNew = true;
}
+ this.isNew = isNew;
}
/**
@@ -120,16 +119,13 @@
* @param path the path string to resolve. May be null.
* @return the resolved path; null if {@code path} was null or empty.
*/
- public File resolve(final String path) {
+ public Path resolve(String path) {
if (path != null && !path.isEmpty()) {
- File loc = new File(path);
- if (!loc.isAbsolute()) {
- loc = new File(site_path, path);
- }
+ Path loc = site_path.resolve(path).normalize();
try {
- return loc.getCanonicalFile();
+ return loc.toRealPath();
} catch (IOException e) {
- return loc.getAbsoluteFile();
+ return loc.toAbsolutePath();
}
}
return null;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/contact/ContactStoreModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/contact/ContactStoreModule.java
index 6b195de..f6e08b8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/contact/ContactStoreModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/contact/ContactStoreModule.java
@@ -28,11 +28,12 @@
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.util.StringUtils;
-import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.security.Security;
/** Creates the {@link ContactStore} based on the configuration. */
@@ -46,7 +47,7 @@
public ContactStore provideContactStore(@GerritServerConfig final Config config,
final SitePaths site, final SchemaFactory<ReviewDb> schema,
final ContactStoreConnection.Factory connFactory) {
- final String url = config.getString("contactstore", null, "url");
+ String url = config.getString("contactstore", null, "url");
if (StringUtils.isEmptyOrNull(url)) {
return new NoContactStore();
}
@@ -56,18 +57,18 @@
+ " needed to encrypt contact information");
}
- final URL storeUrl;
+ URL storeUrl;
try {
storeUrl = new URL(url);
} catch (MalformedURLException e) {
throw new ProvisionException("Invalid contactstore.url: " + url, e);
}
- final String storeAPPSEC = config.getString("contactstore", null, "appsec");
- final File pubkey = site.contact_information_pub;
- if (!pubkey.exists()) {
+ String storeAPPSEC = config.getString("contactstore", null, "appsec");
+ Path pubkey = site.contact_information_pub;
+ if (!Files.exists(pubkey)) {
throw new ProvisionException("PGP public key file \""
- + pubkey.getAbsolutePath() + "\" not found");
+ + pubkey.toAbsolutePath() + "\" not found");
}
return new EncryptedContactStore(storeUrl, storeAPPSEC, pubkey, schema,
connFactory);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/contact/EncryptedContactStore.java b/gerrit-server/src/main/java/com/google/gerrit/server/contact/EncryptedContactStore.java
index 4048748..fedc909 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/contact/EncryptedContactStore.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/contact/EncryptedContactStore.java
@@ -45,12 +45,12 @@
import org.slf4j.LoggerFactory;
import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.sql.Timestamp;
@@ -74,7 +74,7 @@
private final ContactStoreConnection.Factory connFactory;
EncryptedContactStore(final URL storeUrl, final String storeAPPSEC,
- final File pubKey, final SchemaFactory<ReviewDb> schema,
+ final Path pubKey, final SchemaFactory<ReviewDb> schema,
final ContactStoreConnection.Factory connFactory) {
this.storeUrl = storeUrl;
this.storeAPPSEC = storeAPPSEC;
@@ -106,8 +106,8 @@
return true;
}
- private static PGPPublicKeyRingCollection readPubRing(final File pub) {
- try (InputStream fin = new FileInputStream(pub);
+ private static PGPPublicKeyRingCollection readPubRing(Path pub) {
+ try (InputStream fin = Files.newInputStream(pub);
InputStream in = PGPUtil.getDecoderStream(fin)) {
return new BcPGPPublicKeyRingCollection(in);
} catch (IOException | PGPException e) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditModifier.java b/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditModifier.java
index 67de914..70107c2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditModifier.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditModifier.java
@@ -389,7 +389,7 @@
private static ObjectId writeNewTree(TreeOperation op, RevWalk rw,
ObjectInserter ins, RevCommit prevEdit, ObjectReader reader,
String fileName, @Nullable String newFile,
- final @Nullable ObjectId content) throws IOException {
+ @Nullable final ObjectId content) throws IOException {
DirCache newTree = readTree(reader, prevEdit);
DirCacheEditor dce = newTree.editor();
switch (op) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditUtil.java
index 0a65527..79c6593 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditUtil.java
@@ -183,8 +183,8 @@
checkArgument(pos > 0, "invalid edit ref: %s", ref.getName());
String psId = ref.getName().substring(pos + 1);
return db.get().patchSets().get(new PatchSet.Id(
- change.getId(), Integer.valueOf(psId)));
- } catch (OrmException e) {
+ change.getId(), Integer.parseInt(psId)));
+ } catch (OrmException | NumberFormatException e) {
throw new IOException(e);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/events/ChangeEvent.java b/gerrit-server/src/main/java/com/google/gerrit/server/events/ChangeEvent.java
index 9a5ad82..f083b7a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/events/ChangeEvent.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/events/ChangeEvent.java
@@ -14,10 +14,9 @@
package com.google.gerrit.server.events;
-import static org.eclipse.jgit.lib.Constants.R_HEADS;
-
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.server.data.ChangeAttribute;
public abstract class ChangeEvent extends RefEvent {
@@ -34,7 +33,7 @@
@Override
public String getRefName() {
- return R_HEADS + change.branch;
+ return RefNames.fullName(change.branch);
}
public Change.Key getChangeKey() {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/events/EventFactory.java b/gerrit-server/src/main/java/com/google/gerrit/server/events/EventFactory.java
index f0c0bc1..4a61e3e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/events/EventFactory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/events/EventFactory.java
@@ -151,7 +151,7 @@
ru.newRev = newId != null ? newId.getName() : ObjectId.zeroId().getName();
ru.oldRev = oldId != null ? oldId.getName() : ObjectId.zeroId().getName();
ru.project = refName.getParentKey().get();
- ru.refName = refName.getShortName();
+ ru.refName = refName.get();
return ru;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/events/EventTypes.java b/gerrit-server/src/main/java/com/google/gerrit/server/events/EventTypes.java
index 908fd0a..9b37c38 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/events/EventTypes.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/events/EventTypes.java
@@ -35,6 +35,7 @@
registerClass(new ReviewerAddedEvent());
registerClass(new PatchSetCreatedEvent());
registerClass(new TopicChangedEvent());
+ registerClass(new ProjectCreatedEvent());
}
/** Register an event.
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/events/ProjectCreatedEvent.java b/gerrit-server/src/main/java/com/google/gerrit/server/events/ProjectCreatedEvent.java
new file mode 100644
index 0000000..c1534df
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/events/ProjectCreatedEvent.java
@@ -0,0 +1,35 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.events;
+
+import com.google.gerrit.reviewdb.client.Project;
+
+public class ProjectCreatedEvent extends ProjectEvent {
+ public String projectName;
+ public String headName;
+
+ public ProjectCreatedEvent() {
+ super("project-created");
+ }
+
+ @Override
+ public Project.NameKey getProjectNameKey() {
+ return new Project.NameKey(projectName);
+ }
+
+ public String getHeadName() {
+ return headName;
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/GitReferenceUpdated.java b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/GitReferenceUpdated.java
index 5327448..7eef0ee 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/GitReferenceUpdated.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/GitReferenceUpdated.java
@@ -46,16 +46,22 @@
this.listeners = listeners;
}
- public void fire(Project.NameKey project, RefUpdate refUpdate) {
+ public void fire(Project.NameKey project, RefUpdate refUpdate,
+ ReceiveCommand.Type type) {
fire(project, refUpdate.getName(), refUpdate.getOldObjectId(),
- refUpdate.getNewObjectId());
+ refUpdate.getNewObjectId(), type);
}
- public void fire(Project.NameKey project, String ref,
- ObjectId oldObjectId, ObjectId newObjectId) {
+ public void fire(Project.NameKey project, RefUpdate refUpdate) {
+ fire(project, refUpdate.getName(), refUpdate.getOldObjectId(),
+ refUpdate.getNewObjectId(), ReceiveCommand.Type.UPDATE);
+ }
+
+ public void fire(Project.NameKey project, String ref, ObjectId oldObjectId,
+ ObjectId newObjectId, ReceiveCommand.Type type) {
ObjectId o = oldObjectId != null ? oldObjectId : ObjectId.zeroId();
ObjectId n = newObjectId != null ? newObjectId : ObjectId.zeroId();
- Event event = new Event(project, ref, o.name(), n.name());
+ Event event = new Event(project, ref, o.name(), n.name(), type);
for (GitReferenceUpdatedListener l : listeners) {
try {
l.onGitReferenceUpdated(event);
@@ -65,10 +71,19 @@
}
}
+ public void fire(Project.NameKey project, String ref, ObjectId oldObjectId,
+ ObjectId newObjectId) {
+ fire(project, ref, oldObjectId, newObjectId, ReceiveCommand.Type.UPDATE);
+ }
+
+ public void fire(Project.NameKey project, ReceiveCommand cmd) {
+ fire(project, cmd.getRefName(), cmd.getOldId(), cmd.getNewId(), cmd.getType());
+ }
+
public void fire(Project.NameKey project, BatchRefUpdate batchRefUpdate) {
for (ReceiveCommand cmd : batchRefUpdate.getCommands()) {
if (cmd.getResult() == ReceiveCommand.Result.OK) {
- fire(project, cmd.getRefName(), cmd.getOldId(), cmd.getNewId());
+ fire(project, cmd);
}
}
}
@@ -78,13 +93,16 @@
private final String ref;
private final String oldObjectId;
private final String newObjectId;
+ private final ReceiveCommand.Type type;
Event(Project.NameKey project, String ref,
- String oldObjectId, String newObjectId) {
+ String oldObjectId, String newObjectId,
+ ReceiveCommand.Type type) {
this.projectName = project.get();
this.ref = ref;
this.oldObjectId = oldObjectId;
this.newObjectId = newObjectId;
+ this.type = type;
}
@Override
@@ -108,6 +126,21 @@
}
@Override
+ public boolean isCreate() {
+ return type == ReceiveCommand.Type.CREATE;
+ }
+
+ @Override
+ public boolean isDelete() {
+ return type == ReceiveCommand.Type.DELETE;
+ }
+
+ @Override
+ public boolean isNonFastForward() {
+ return type == ReceiveCommand.Type.UPDATE_NONFASTFORWARD;
+ }
+
+ @Override
public String toString() {
return String.format("%s[%s,%s: %s -> %s]", getClass().getSimpleName(),
projectName, ref, oldObjectId, newObjectId);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/BranchOrderSection.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/BranchOrderSection.java
index c447d31..f044342 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/BranchOrderSection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/BranchOrderSection.java
@@ -15,8 +15,7 @@
package com.google.gerrit.server.git;
import com.google.common.collect.ImmutableList;
-
-import org.eclipse.jgit.lib.Constants;
+import com.google.gerrit.reviewdb.client.RefNames;
import java.util.List;
@@ -35,22 +34,14 @@
} else {
ImmutableList.Builder<String> builder = ImmutableList.builder();
for (String b : order) {
- builder.add(fullName(b));
+ builder.add(RefNames.fullName(b));
}
this.order = builder.build();
}
}
- private static String fullName(String branch) {
- if (branch.startsWith(Constants.R_HEADS)) {
- return branch;
- } else {
- return Constants.R_HEADS + branch;
- }
- }
-
public List<String> getMoreStable(String branch) {
- int i = order.indexOf(fullName(branch));
+ int i = order.indexOf(RefNames.fullName(branch));
if (0 <= i) {
return order.subList(i + 1, order.size());
} else {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/GarbageCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/GarbageCollection.java
index 24af14d..a915a79 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/GarbageCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/GarbageCollection.java
@@ -16,7 +16,11 @@
import com.google.common.collect.Sets;
import com.google.gerrit.common.data.GarbageCollectionResult;
+import com.google.gerrit.extensions.events.GarbageCollectorListener;
+import com.google.gerrit.extensions.events.GarbageCollectorListener.Event;
+import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.config.GcConfig;
import com.google.inject.Inject;
import org.eclipse.jgit.api.GarbageCollectCommand;
@@ -46,15 +50,21 @@
private final GitRepositoryManager repoManager;
private final GarbageCollectionQueue gcQueue;
+ private final GcConfig gcConfig;
+ private final DynamicSet<GarbageCollectorListener> listeners;
public interface Factory {
GarbageCollection create();
}
@Inject
- GarbageCollection(GitRepositoryManager repoManager, GarbageCollectionQueue gcQueue) {
+ GarbageCollection(GitRepositoryManager repoManager,
+ GarbageCollectionQueue gcQueue, GcConfig config,
+ DynamicSet<GarbageCollectorListener> listeners) {
this.repoManager = repoManager;
this.gcQueue = gcQueue;
+ this.gcConfig = config;
+ this.listeners = listeners;
}
public GarbageCollectionResult run(List<Project.NameKey> projectNames) {
@@ -63,6 +73,11 @@
public GarbageCollectionResult run(List<Project.NameKey> projectNames,
PrintWriter writer) {
+ return run(projectNames, gcConfig.isAggressive(), writer);
+ }
+
+ public GarbageCollectionResult run(List<Project.NameKey> projectNames,
+ boolean aggressive, PrintWriter writer) {
GarbageCollectionResult result = new GarbageCollectionResult();
Set<Project.NameKey> projectsToGc = gcQueue.addAll(projectNames);
for (Project.NameKey projectName : Sets.difference(
@@ -74,15 +89,17 @@
Repository repo = null;
try {
repo = repoManager.openRepository(p);
- logGcConfiguration(p, repo);
+ logGcConfiguration(p, repo, aggressive);
print(writer, "collecting garbage for \"" + p + "\":\n");
GarbageCollectCommand gc = Git.wrap(repo).gc();
+ gc.setAggressive(aggressive);
logGcInfo(p, "before:", gc.getStatistics());
gc.setProgressMonitor(writer != null ? new TextProgressMonitor(writer)
: NullProgressMonitor.INSTANCE);
Properties statistics = gc.call();
logGcInfo(p, "after: ", statistics);
print(writer, "done.\n\n");
+ fire(p, statistics);
} catch (RepositoryNotFoundException e) {
logGcError(writer, p, e);
result.addError(new GarbageCollectionResult.Error(
@@ -102,6 +119,27 @@
return result;
}
+ private void fire(final Project.NameKey p, final Properties statistics) {
+ Event event = new GarbageCollectorListener.Event() {
+ @Override
+ public String getProjectName() {
+ return p.get();
+ }
+
+ @Override
+ public Properties getStatistics() {
+ return statistics;
+ }
+ };
+ for (GarbageCollectorListener l : listeners) {
+ try {
+ l.onGarbageCollected(event);
+ } catch (RuntimeException e) {
+ log.warn("Failure in GarbageCollectorListener", e);
+ }
+ }
+ }
+
private static void logGcInfo(Project.NameKey projectName, String msg) {
logGcInfo(projectName, msg, null);
}
@@ -123,9 +161,10 @@
}
private static void logGcConfiguration(Project.NameKey projectName,
- Repository repo) {
+ Repository repo, boolean aggressive) {
StringBuilder b = new StringBuilder();
Config cfg = repo.getConfig();
+ b.append("gc.aggressive=").append(aggressive).append("; ");
b.append(formatConfigValues(cfg, ConfigConstants.CONFIG_GC_SECTION, null));
for (String subsection : cfg.getSubsections(ConfigConstants.CONFIG_GC_SECTION)) {
b.append(formatConfigValues(cfg, ConfigConstants.CONFIG_GC_SECTION,
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/GarbageCollectionLogFile.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/GarbageCollectionLogFile.java
index 2b0d3e9..b2a4311 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/GarbageCollectionLogFile.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/GarbageCollectionLogFile.java
@@ -23,7 +23,7 @@
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
-import java.io.File;
+import java.nio.file.Path;
public class GarbageCollectionLogFile implements LifecycleListener {
@@ -43,7 +43,7 @@
LogManager.getLogger(GarbageCollection.LOG_NAME).removeAllAppenders();
}
- private static void initLogSystem(File logdir) {
+ private static void initLogSystem(Path logdir) {
Logger gcLogger = LogManager.getLogger(GarbageCollection.LOG_NAME);
gcLogger.removeAllAppenders();
gcLogger.addAppender(SystemLog.createAppender(logdir,
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/GroupCollector.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/GroupCollector.java
new file mode 100644
index 0000000..51125b4
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/GroupCollector.java
@@ -0,0 +1,303 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.git;
+
+import static com.google.common.base.Preconditions.checkState;
+import static org.eclipse.jgit.revwalk.RevFlag.UNINTERESTING;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.ListMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.MultimapBuilder;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.change.RevisionResource;
+import com.google.gwtorm.server.OrmException;
+
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayDeque;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * Helper for assigning groups to commits during {@link ReceiveCommits}.
+ * <p>
+ * For each commit encountered along a walk between the branch tip and the tip
+ * of the push, the group of a commit is defined as follows:
+ * <ul>
+ * <li>If the commit is an existing patch set of a change, the group is read
+ * from the group field in the corresponding {@link PatchSet} record.</li>
+ * <li>If all of a commit's parents are merged into the branch, then its group
+ * is its own SHA-1.</li>
+ * <li>If the commit has a single parent that is not yet merged into the
+ * branch, then its group is the same as the parent's group.<li>
+ * <li>For a merge commit, choose a parent and use that parent's group. If one
+ * of the parents has a group from a patch set, use that group, otherwise, use
+ * the group from the first parent. In addition to setting this merge commit's
+ * group, use the chosen group for all commits that would otherwise use a
+ * group from the parents that were not chosen.</li>
+ * <li>If a merge commit has multiple parents whose group comes from separate
+ * patch sets, concatenate the groups from those parents together. This
+ * indicates two side branches were pushed separately, followed by the merge.
+ * <li>
+ * </ul>
+ * <p>
+ * Callers must call {@link #visit(RevCommit)} on all commits between the
+ * current branch tip and the tip of a push, in reverse topo order (parents
+ * before children). Once all commits have been visited, call {@link
+ * #getGroups()} for the result.
+ */
+public class GroupCollector {
+ private static final Logger log =
+ LoggerFactory.getLogger(GroupCollector.class);
+
+ public static List<String> getCurrentGroups(ReviewDb db, Change c)
+ throws OrmException {
+ PatchSet ps = db.patchSets().get(c.currentPatchSetId());
+ return ps != null ? ps.getGroups() : null;
+ }
+
+ public static List<String> getDefaultGroups(PatchSet ps) {
+ return ImmutableList.of(ps.getRevision().get());
+ }
+
+ public static List<String> getGroups(RevisionResource rsrc) {
+ if (rsrc.getEdit().isPresent()) {
+ // Groups for an edit are just the base revision's groups, since they have
+ // the same parent.
+ return rsrc.getEdit().get().getBasePatchSet().getGroups();
+ }
+ return rsrc.getPatchSet().getGroups();
+ }
+
+ private static interface Lookup {
+ List<String> lookup(PatchSet.Id psId) throws OrmException;
+ }
+
+ private final Multimap<ObjectId, PatchSet.Id> patchSetsBySha;
+ private final Multimap<ObjectId, String> groups;
+ private final SetMultimap<String, String> groupAliases;
+ private final Lookup groupLookup;
+
+ private boolean done;
+
+ private GroupCollector(
+ Multimap<ObjectId, PatchSet.Id> patchSetsBySha,
+ Lookup groupLookup) {
+ this.patchSetsBySha = patchSetsBySha;
+ this.groupLookup = groupLookup;
+ groups = ArrayListMultimap.create();
+ groupAliases = HashMultimap.create();
+ }
+
+ public GroupCollector(
+ Multimap<ObjectId, Ref> changeRefsById,
+ final ReviewDb db) {
+ this(
+ Multimaps.transformValues(
+ changeRefsById,
+ new Function<Ref, PatchSet.Id>() {
+ @Override
+ public PatchSet.Id apply(Ref in) {
+ return PatchSet.Id.fromRef(in.getName());
+ }
+ }),
+ new Lookup() {
+ @Override
+ public List<String> lookup(PatchSet.Id psId) throws OrmException {
+ PatchSet ps = db.patchSets().get(psId);
+ return ps != null ? ps.getGroups() : null;
+ }
+ });
+ }
+
+ @VisibleForTesting
+ GroupCollector(
+ Multimap<ObjectId, PatchSet.Id> patchSetsBySha,
+ final ListMultimap<PatchSet.Id, String> groupLookup) {
+ this(
+ patchSetsBySha,
+ new Lookup() {
+ @Override
+ public List<String> lookup(PatchSet.Id psId) {
+ List<String> groups = groupLookup.get(psId);
+ return !groups.isEmpty() ? groups : null;
+ }
+ });
+ }
+
+ public void visit(RevCommit c) {
+ checkState(!done, "visit() called after getGroups()");
+ Set<RevCommit> interestingParents = getInterestingParents(c);
+
+ if (interestingParents.size() == 0) {
+ // All parents are uninteresting: treat this commit as the root of a new
+ // group of related changes.
+ groups.put(c, c.name());
+ return;
+ } else if (interestingParents.size() == 1) {
+ // Only one parent is new in this push. If it is the only parent, just use
+ // that parent's group. If there are multiple parents, perhaps this commit
+ // is a merge of a side branch. This commit belongs in that parent's group
+ // in that case.
+ groups.putAll(c, groups.get(interestingParents.iterator().next()));
+ return;
+ }
+
+ // Multiple parents, merging at least two branches containing new commits in
+ // this push.
+ Set<String> thisCommitGroups = new TreeSet<>();
+ Set<String> parentGroupsNewInThisPush =
+ Sets.newLinkedHashSetWithExpectedSize(interestingParents.size());
+ for (RevCommit p : interestingParents) {
+ Collection<String> parentGroups = groups.get(p);
+ if (parentGroups.isEmpty()) {
+ throw new IllegalStateException(String.format(
+ "no group assigned to parent %s of commit %s", p.name(), c.name()));
+ }
+
+ for (String parentGroup : parentGroups) {
+ if (isGroupFromExistingPatchSet(p, parentGroup)) {
+ // This parent's group is from an existing patch set, i.e. the parent
+ // not new in this push. Use this group for the commit.
+ thisCommitGroups.add(parentGroup);
+ } else {
+ // This parent's group is new in this push.
+ parentGroupsNewInThisPush.add(parentGroup);
+ }
+ }
+ }
+
+ Iterable<String> toAlias;
+ if (thisCommitGroups.isEmpty()) {
+ // All parent groups were new in this push. Pick the first one and alias
+ // other parents' groups to this first parent.
+ String firstParentGroup = parentGroupsNewInThisPush.iterator().next();
+ thisCommitGroups = ImmutableSet.of(firstParentGroup);
+ toAlias = Iterables.skip(parentGroupsNewInThisPush, 1);
+ } else {
+ // For each parent group that was new in this push, alias it to the actual
+ // computed group(s) for this commit.
+ toAlias = parentGroupsNewInThisPush;
+ }
+ groups.putAll(c, thisCommitGroups);
+ for (String pg : toAlias) {
+ groupAliases.putAll(pg, thisCommitGroups);
+ }
+ }
+
+ public SetMultimap<ObjectId, String> getGroups() throws OrmException {
+ done = true;
+ SetMultimap<ObjectId, String> result = MultimapBuilder
+ .hashKeys(groups.keySet().size())
+ .treeSetValues()
+ .build();
+ for (Map.Entry<ObjectId, Collection<String>> e
+ : groups.asMap().entrySet()) {
+ ObjectId id = e.getKey();
+ result.putAll(id.copy(), resolveGroups(id, e.getValue()));
+ }
+ return result;
+ }
+
+ private Set<RevCommit> getInterestingParents(RevCommit commit) {
+ Set<RevCommit> result =
+ Sets.newLinkedHashSetWithExpectedSize(commit.getParentCount());
+ for (RevCommit p : commit.getParents()) {
+ if (!p.has(UNINTERESTING)) {
+ result.add(p);
+ }
+ }
+ return result;
+ }
+
+ private boolean isGroupFromExistingPatchSet(RevCommit commit, String group) {
+ ObjectId id = parseGroup(commit, group);
+ return id != null && patchSetsBySha.containsKey(id);
+ }
+
+ private Set<String> resolveGroups(ObjectId forCommit,
+ Collection<String> candidates) throws OrmException {
+ Set<String> actual = Sets.newTreeSet();
+ Set<String> done = Sets.newHashSetWithExpectedSize(candidates.size());
+ Set<String> seen = Sets.newHashSetWithExpectedSize(candidates.size());
+ Deque<String> todo = new ArrayDeque<>(candidates);
+ // BFS through all aliases to find groups that are not aliased to anything
+ // else.
+ while (!todo.isEmpty()) {
+ String g = todo.removeFirst();
+ if (!seen.add(g)) {
+ continue;
+ }
+ Set<String> aliases = groupAliases.get(g);
+ if (aliases.isEmpty()) {
+ if (!done.contains(g)) {
+ Iterables.addAll(actual, resolveGroup(forCommit, g));
+ done.add(g);
+ }
+ } else {
+ todo.addAll(aliases);
+ }
+ }
+ return actual;
+ }
+
+ private ObjectId parseGroup(ObjectId forCommit, String group) {
+ try {
+ return ObjectId.fromString(group);
+ } catch (IllegalArgumentException e) {
+ // Shouldn't happen; some sort of corruption or manual tinkering?
+ log.warn("group for commit {} is not a SHA-1: {}",
+ forCommit.name(), group);
+ return null;
+ }
+ }
+
+ private Iterable<String> resolveGroup(ObjectId forCommit, String group)
+ throws OrmException {
+ ObjectId id = parseGroup(forCommit, group);
+ if (id != null) {
+ PatchSet.Id psId = Iterables.getFirst(patchSetsBySha.get(id), null);
+ if (psId != null) {
+ List<String> groups = groupLookup.lookup(psId);
+ // Group for existing patch set may be missing, e.g. if group has not
+ // been migrated yet.
+ if (groups != null && !groups.isEmpty()) {
+ return groups;
+ }
+ }
+ }
+ return ImmutableList.of(group);
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/GroupList.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/GroupList.java
index 29948c2..d07572b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/GroupList.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/GroupList.java
@@ -18,18 +18,15 @@
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroup.UUID;
-import java.io.BufferedReader;
import java.io.IOException;
-import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
-public class GroupList {
+public class GroupList extends TabFile {
public static final String FILE_NAME = "groups";
private final Map<AccountGroup.UUID, GroupReference> byUUID;
@@ -37,24 +34,14 @@
this.byUUID = byUUID;
}
- public static GroupList parse(String text, ValidationError.Sink errors) throws IOException {
- Map<AccountGroup.UUID, GroupReference> groupsByUUID = new HashMap<>();
-
- BufferedReader br = new BufferedReader(new StringReader(text));
- String s;
- for (int lineNumber = 1; (s = br.readLine()) != null; lineNumber++) {
- if (s.isEmpty() || s.startsWith("#")) {
- continue;
- }
-
- int tab = s.indexOf('\t');
- if (tab < 0) {
- errors.error(new ValidationError(FILE_NAME, lineNumber, "missing tab delimiter"));
- continue;
- }
-
- AccountGroup.UUID uuid = new AccountGroup.UUID(s.substring(0, tab).trim());
- String name = s.substring(tab + 1).trim();
+ public static GroupList parse(String text, ValidationError.Sink errors)
+ throws IOException {
+ List<Row> rows = parse(text, FILE_NAME, errors);
+ Map<AccountGroup.UUID, GroupReference> groupsByUUID =
+ new HashMap<>(rows.size());
+ for(Row row : rows) {
+ AccountGroup.UUID uuid = new AccountGroup.UUID(row.left);
+ String name = row.right;
GroupReference ref = new GroupReference(uuid, name);
groupsByUUID.put(uuid, ref);
@@ -90,49 +77,19 @@
byUUID.put(uuid, reference);
}
- private static String pad(int len, String src) {
- if (len <= src.length()) {
- return src;
- }
-
- StringBuilder r = new StringBuilder(len);
- r.append(src);
- while (r.length() < len) {
- r.append(' ');
- }
- return r.toString();
- }
-
- private static <T extends Comparable<? super T>> List<T> sort(Collection<T> m) {
- ArrayList<T> r = new ArrayList<>(m);
- Collections.sort(r);
- return r;
- }
-
public String asText() {
if (byUUID.isEmpty()) {
return null;
}
- final int uuidLen = 40;
- StringBuilder buf = new StringBuilder();
- buf.append(pad(uuidLen, "# UUID"));
- buf.append('\t');
- buf.append("Group Name");
- buf.append('\n');
-
- buf.append('#');
- buf.append('\n');
-
+ List<Row> rows = new ArrayList<>(byUUID.size());
for (GroupReference g : sort(byUUID.values())) {
if (g.getUUID() != null && g.getName() != null) {
- buf.append(pad(uuidLen, g.getUUID().get()));
- buf.append('\t');
- buf.append(g.getName());
- buf.append('\n');
+ rows.add(new Row(g.getUUID().get(), g.getName()));
}
}
- return buf.toString();
+
+ return asText("UUID", "Group Name", rows);
}
public void retainUUIDs(Collection<AccountGroup.UUID> toBeRetained) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/InsertException.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/InsertException.java
index 575ad52..cf18de0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/InsertException.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/InsertException.java
@@ -1,16 +1,16 @@
-//Copyright (C) 2014 The Android Open Source Project
+// Copyright (C) 2014 The Android Open Source Project
//
-//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
+// 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
+// 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.
+// 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.
package com.google.gerrit.server.git;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
index 633c3bb..717b393 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
@@ -51,7 +51,14 @@
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.nio.file.FileVisitOption;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collections;
+import java.util.EnumSet;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.locks.Lock;
@@ -128,8 +135,8 @@
}
}
- private final File basePath;
- private final File noteDbPath;
+ private final Path basePath;
+ private final Path noteDbPath;
private final Lock namesUpdateLock;
private volatile SortedSet<Project.NameKey> names;
@@ -153,7 +160,7 @@
}
/** @return base directory under which all projects are stored. */
- public File getBasePath() {
+ public Path getBasePath() {
return basePath;
}
@@ -163,12 +170,12 @@
return openRepository(basePath, name);
}
- private Repository openRepository(File path, Project.NameKey name)
+ private Repository openRepository(Path path, Project.NameKey name)
throws RepositoryNotFoundException {
if (isUnreasonableName(name)) {
throw new RepositoryNotFoundException("Invalid name: " + name);
}
- File gitDir = new File(path, name.get());
+ File gitDir = path.resolve(name.get()).toFile();
if (!names.contains(name)) {
// The this.names list does not hold the project-name but it can still exist
// on disk; for instance when the project has been created directly on the
@@ -214,13 +221,13 @@
return repo;
}
- private Repository createRepository(File path, Project.NameKey name)
+ private Repository createRepository(Path path, Project.NameKey name)
throws RepositoryNotFoundException, RepositoryCaseMismatchException {
if (isUnreasonableName(name)) {
throw new RepositoryNotFoundException("Invalid name: " + name);
}
- File dir = FileKey.resolve(new File(path, name.get()), FS.DETECTED);
+ File dir = FileKey.resolve(path.resolve(name.get()).toFile(), FS.DETECTED);
FileKey loc;
if (dir != null) {
// Already exists on disk, use the repository we found.
@@ -235,7 +242,7 @@
// of the repository name, so prefer the standard bare name.
//
String n = name.get() + Constants.DOT_GIT_EXT;
- loc = FileKey.exact(new File(path, n), FS.DETECTED);
+ loc = FileKey.exact(path.resolve(n).toFile(), FS.DETECTED);
}
try {
@@ -366,28 +373,25 @@
private boolean isUnreasonableName(final Project.NameKey nameKey) {
final String name = nameKey.get();
- if (name.length() == 0) return true; // no empty paths
- if (name.charAt(name.length() -1) == '/') return true; // no suffix
-
- if (name.indexOf('\\') >= 0) return true; // no windows/dos style paths
- if (name.charAt(0) == '/') return true; // no absolute paths
- if (new File(name).isAbsolute()) return true; // no absolute paths
-
- if (name.startsWith("../")) return true; // no "l../etc/passwd"
- if (name.contains("/../")) return true; // no "foo/../etc/passwd"
- if (name.contains("/./")) return true; // "foo/./foo" is insane to ask
- if (name.contains("//")) return true; // windows UNC path can be "//..."
- if (name.contains("?")) return true; // common unix wildcard
- if (name.contains("%")) return true; // wildcard or string parameter
- if (name.contains("*")) return true; // wildcard
- if (name.contains(":")) return true; // Could be used for absolute paths in windows?
- if (name.contains("<")) return true; // redirect input
- if (name.contains(">")) return true; // redirect output
- if (name.contains("|")) return true; // pipe
- if (name.contains("$")) return true; // dollar sign
- if (name.contains("\r")) return true; // carriage return
-
- return false; // is a reasonable name
+ return name.length() == 0 // no empty paths
+ || name.charAt(name.length() -1) == '/' // no suffix
+ || name.indexOf('\\') >= 0 // no windows/dos style paths
+ || name.charAt(0) == '/' // no absolute paths
+ || new File(name).isAbsolute() // no absolute paths
+ || name.startsWith("../") // no "l../etc/passwd"
+ || name.contains("/../") // no "foo/../etc/passwd"
+ || name.contains("/./") // "foo/./foo" is insane to ask
+ || name.contains("//") // windows UNC path can be "//..."
+ || name.contains(".git/") // no path segments that end with '.git' as "foo.git/bar"
+ || name.contains("?") // common unix wildcard
+ || name.contains("%") // wildcard or string parameter
+ || name.contains("*") // wildcard
+ || name.contains(":") // Could be used for absolute paths in windows?
+ || name.contains("<") // redirect input
+ || name.contains(">") // redirect output
+ || name.contains("|") // pipe
+ || name.contains("$") // dollar sign
+ || name.contains("\r"); // carriage return
}
@Override
@@ -397,51 +401,59 @@
// scanning the filesystem. Don't rely on the cached names collection.
namesUpdateLock.lock();
try {
- SortedSet<Project.NameKey> n = new TreeSet<>();
- scanProjects(basePath, "", n);
- names = Collections.unmodifiableSortedSet(n);
- return n;
+ ProjectVisitor visitor = new ProjectVisitor();
+ try {
+ Files.walkFileTree(basePath, EnumSet.of(FileVisitOption.FOLLOW_LINKS),
+ Integer.MAX_VALUE, visitor);
+ } catch (IOException e) {
+ log.error("Error walking repository tree " + basePath.toAbsolutePath(),
+ e);
+ }
+ return Collections.unmodifiableSortedSet(visitor.found);
} finally {
namesUpdateLock.unlock();
}
}
- private void scanProjects(final File dir, final String prefix,
- final SortedSet<Project.NameKey> names) {
- final File[] ls = dir.listFiles();
- if (ls == null) {
- return;
+ private class ProjectVisitor extends SimpleFileVisitor<Path> {
+ private final SortedSet<Project.NameKey> found = new TreeSet<>();
+
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir,
+ BasicFileAttributes attrs) throws IOException {
+ if (!dir.equals(basePath) && isRepo(dir)) {
+ addProject(dir);
+ return FileVisitResult.SKIP_SUBTREE;
+ }
+ return FileVisitResult.CONTINUE;
}
- for (File f : ls) {
- String fileName = f.getName();
- if (fileName.equals(Constants.DOT_GIT)) {
- // Skip repositories named only `.git`
- } else if (FileKey.isGitRepository(f, FS.DETECTED)) {
- Project.NameKey nameKey = getProjectName(prefix, fileName);
- if (isUnreasonableName(nameKey)) {
- log.warn("Ignoring unreasonably named repository " + f.getAbsolutePath());
- } else {
- names.add(nameKey);
- }
+ private boolean isRepo(Path p) {
+ String name = p.getFileName().toString();
+ return !name.equals(Constants.DOT_GIT)
+ && name.endsWith(Constants.DOT_GIT_EXT);
+ }
- } else if (f.isDirectory()) {
- scanProjects(f, prefix + f.getName() + "/", names);
+ private void addProject(Path p) {
+ Project.NameKey nameKey = getProjectName(p);
+ if (isUnreasonableName(nameKey)) {
+ log.warn(
+ "Ignoring unreasonably named repository " + p.toAbsolutePath());
+ } else {
+ found.add(nameKey);
}
}
- }
- private Project.NameKey getProjectName(final String prefix,
- final String fileName) {
- final String projectName;
- if (fileName.endsWith(Constants.DOT_GIT_EXT)) {
- int newLen = fileName.length() - Constants.DOT_GIT_EXT.length();
- projectName = prefix + fileName.substring(0, newLen);
-
- } else {
- projectName = prefix + fileName;
+ private Project.NameKey getProjectName(Path p) {
+ String projectName = basePath.relativize(p).toString();
+ if (File.separatorChar != '/') {
+ projectName = projectName.replace(File.separatorChar, '/');
+ }
+ if (projectName.endsWith(Constants.DOT_GIT_EXT)) {
+ int newLen = projectName.length() - Constants.DOT_GIT_EXT.length();
+ projectName = projectName.substring(0, newLen);
+ }
+ return new Project.NameKey(projectName);
}
-
- return new Project.NameKey(projectName);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
index 05e864b..96207fa 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
@@ -24,7 +24,6 @@
import com.google.common.collect.Iterables;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
-import com.google.common.util.concurrent.CheckedFuture;
import com.google.gerrit.common.ChangeHooks;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.TimeUtil;
@@ -814,6 +813,19 @@
potentiallyStillSubmittable.add(commit);
break;
+ case REVISION_GONE:
+ logDebug("Commit not found for change {}", c.getId());
+ ChangeMessage msg = new ChangeMessage(
+ new ChangeMessage.Key(
+ c.getId(),
+ ChangeUtil.messageUUID(db)),
+ null,
+ TimeUtil.nowTs(),
+ c.currentPatchSetId());
+ msg.setMessage("Failed to read commit for this patch set");
+ sendMergeFail(commit.notes(), msg, false);
+ break;
+
default:
setNew(commit,
message(c, "Unspecified merge failure: " + s.name()));
@@ -1032,7 +1044,7 @@
}
try {
- MergedSender cm = mergedSenderFactory.create(changeControl(c));
+ MergedSender cm = mergedSenderFactory.create(c.getId());
if (from != null) {
cm.setFrom(from.getAccountId());
}
@@ -1174,12 +1186,7 @@
update.commit();
}
- CheckedFuture<?, IOException> indexFuture;
- if (change != null) {
- indexFuture = indexer.indexAsync(change.getId());
- } else {
- indexFuture = null;
- }
+ indexer.index(db, change);
final PatchSetApproval from = submitter;
workQueue.getDefaultQueue()
.submit(requestScopePropagator.wrap(new Runnable() {
@@ -1199,7 +1206,7 @@
}
try {
- MergeFailSender cm = mergeFailSenderFactory.create(c);
+ MergeFailSender cm = mergeFailSenderFactory.create(c.getId());
if (from != null) {
cm.setFrom(from.getAccountId());
}
@@ -1217,14 +1224,6 @@
}
}));
- if (indexFuture != null) {
- try {
- indexFuture.checkedGet();
- } catch (IOException e) {
- logError("Failed to index new change message", e);
- }
- }
-
if (submitter != null) {
try {
hooks.doMergeFailedHook(c,
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeTip.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeTip.java
index ba92651..27fb7f2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeTip.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeTip.java
@@ -15,6 +15,7 @@
package com.google.gerrit.server.git;
import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.Maps;
import com.google.gerrit.common.Nullable;
@@ -44,8 +45,8 @@
*/
public MergeTip(@Nullable CodeReviewCommit initial,
Collection<CodeReviewCommit> toMerge) {
- checkArgument(toMerge != null && !toMerge.isEmpty(),
- "toMerge may not be null or empty: %s", toMerge);
+ checkNotNull(toMerge, "toMerge may not be null");
+ checkArgument(!toMerge.isEmpty(), "toMerge may not be empty");
this.mergeResults = Maps.newHashMap();
this.branchTip = initial;
// Assume fast-forward merge until opposite is proven.
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeUtil.java
index 295ad52..da38a58 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeUtil.java
@@ -25,13 +25,16 @@
import com.google.gerrit.common.data.LabelType;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.LabelId;
+import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.PatchSetApproval;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.ApprovalsUtil;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.config.CanonicalWebUrl;
import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.ProjectState;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Provider;
@@ -195,7 +198,9 @@
}
}
- public String createCherryPickCommitMessage(final CodeReviewCommit n) {
+ public String createCherryPickCommitMessage(RevCommit n, ChangeControl ctl,
+ PatchSet.Id psId) {
+ Change c = ctl.getChange();
final List<FooterLine> footers = n.getFooterLines();
final StringBuilder msgbuf = new StringBuilder();
msgbuf.append(n.getFullMessage());
@@ -215,16 +220,16 @@
msgbuf.append('\n');
}
- if (!contains(footers, FooterConstants.CHANGE_ID, n.change().getKey().get())) {
+ if (!contains(footers, FooterConstants.CHANGE_ID, c.getKey().get())) {
msgbuf.append(FooterConstants.CHANGE_ID.getName());
msgbuf.append(": ");
- msgbuf.append(n.change().getKey().get());
+ msgbuf.append(c.getKey().get());
msgbuf.append('\n');
}
final String siteUrl = urlProvider.get();
if (siteUrl != null) {
- final String url = siteUrl + n.getPatchsetId().getParentKey().get();
+ final String url = siteUrl + c.getId().get();
if (!contains(footers, FooterConstants.REVIEWED_ON, url)) {
msgbuf.append(FooterConstants.REVIEWED_ON.getName());
msgbuf.append(": ");
@@ -235,7 +240,7 @@
PatchSetApproval submitAudit = null;
- for (final PatchSetApproval a : safeGetApprovals(n)) {
+ for (final PatchSetApproval a : safeGetApprovals(ctl, psId)) {
if (a.getValue() <= 0) {
// Negative votes aren't counted.
continue;
@@ -301,6 +306,10 @@
return msgbuf.toString();
}
+ public String createCherryPickCommitMessage(final CodeReviewCommit n) {
+ return createCherryPickCommitMessage(n, n.getControl(), n.getPatchsetId());
+ }
+
private static boolean isCodeReview(LabelId id) {
return "Code-Review".equalsIgnoreCase(id.get());
}
@@ -309,11 +318,12 @@
return "Verified".equalsIgnoreCase(id.get());
}
- private Iterable<PatchSetApproval> safeGetApprovals(CodeReviewCommit n) {
+ private Iterable<PatchSetApproval> safeGetApprovals(
+ ChangeControl ctl, PatchSet.Id psId) {
try {
- return approvalsUtil.byPatchSet(db.get(), n.getControl(), n.getPatchsetId());
+ return approvalsUtil.byPatchSet(db.get(), ctl, psId);
} catch (OrmException e) {
- log.error("Can't read approval records for " + n.getPatchsetId(), e);
+ log.error("Can't read approval records for " + psId, e);
return Collections.emptyList();
}
}
@@ -667,7 +677,7 @@
}
@Override
- public void release() {
+ public void close() {
}
});
return (ThreeWayMerger) m;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MetaDataUpdate.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MetaDataUpdate.java
index c71c94f..840b167 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MetaDataUpdate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MetaDataUpdate.java
@@ -148,6 +148,7 @@
private final BatchRefUpdate batch;
private final CommitBuilder commit;
private boolean allowEmpty;
+ private boolean insertChangeId;
@AssistedInject
public MetaDataUpdate(GitReferenceUpdated gitRefUpdated,
@@ -180,6 +181,10 @@
this.allowEmpty = allowEmpty;
}
+ public void setInsertChangeId(boolean insertChangeId) {
+ this.insertChangeId = insertChangeId;
+ }
+
/** @return batch in which to run the update, or {@code null} for no batch. */
BatchRefUpdate getBatch() {
return batch;
@@ -202,6 +207,10 @@
return allowEmpty;
}
+ boolean insertChangeId() {
+ return insertChangeId;
+ }
+
public CommitBuilder getCommitBuilder() {
return commit;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
index 020c94a..99e61d6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
@@ -305,6 +305,10 @@
return notifySections.values();
}
+ public void putNotifyConfig(String name, NotifyConfig nc) {
+ notifySections.put(name, nc);
+ }
+
public Map<String, LabelType> getLabelSections() {
return labelSections;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/QueryList.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/QueryList.java
new file mode 100644
index 0000000..0df866d
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/QueryList.java
@@ -0,0 +1,41 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.git;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+public class QueryList extends TabFile {
+ public static final String FILE_NAME = "queries";
+ protected final Map<String, String> queriesByName;
+
+ private QueryList(List<Row> queriesByName) {
+ this.queriesByName = toMap(queriesByName);
+ }
+
+ public static QueryList parse(String text, ValidationError.Sink errors)
+ throws IOException {
+ return new QueryList(parse(text, FILE_NAME, errors));
+ }
+
+ public String getQuery(String name) {
+ return queriesByName.get(name);
+ }
+
+ public String asText() {
+ return asText("Name", "Query", queriesByName);
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
index f83bab6..464e267 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
@@ -44,6 +44,7 @@
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
import com.google.common.collect.Ordering;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Sets;
@@ -641,8 +642,7 @@
// We only fire gitRefUpdated for direct refs updates.
// Events for change refs are fired when they are created.
//
- gitRefUpdated.fire(project.getNameKey(), c.getRefName(),
- c.getOldId(), c.getNewId());
+ gitRefUpdated.fire(project.getNameKey(), c);
hooks.doRefUpdatedHook(
new Branch.NameKey(project.getNameKey(), c.getRefName()),
c.getOldId(),
@@ -1468,6 +1468,10 @@
private void selectNewAndReplacedChangesFromMagicBranch() {
newChanges = Lists.newArrayList();
final RevWalk walk = rp.getRevWalk();
+
+ Set<ObjectId> existing = changeRefsById().keySet();
+ GroupCollector groupCollector = new GroupCollector(refsById, db);
+
walk.reset();
walk.sort(RevSort.TOPO);
walk.sort(RevSort.REVERSE, true);
@@ -1487,7 +1491,6 @@
magicBranch.ctl != null ? magicBranch.ctl.getRefName() : null);
}
- Set<ObjectId> existing = changeRefsById().keySet();
List<ChangeLookup> pending = Lists.newArrayList();
final Set<Change.Key> newChangeIds = new HashSet<>();
final int maxBatchChanges =
@@ -1497,7 +1500,17 @@
if (c == null) {
break;
}
+ groupCollector.visit(c);
if (existing.contains(c)) { // Commit is already tracked.
+ // TODO(dborowitz): Corner case where an existing commit might need a
+ // new group:
+ // Let A<-B<-C, then:
+ // 1. Push A to refs/heads/master
+ // 2. Push B to refs/for/master
+ // 3. Force push A~ to refs/heads/master
+ // 4. Push C to refs/for/master.
+ // B will be in existing so we aren't replacing the patch set. It used
+ // to have its own group, but now needs to to be changed to A's group.
continue;
}
@@ -1606,8 +1619,20 @@
reject(magicBranch.cmd, "edit is not supported for new changes");
return;
}
- for (CreateRequest create : newChanges) {
- batch.addCommand(create.cmd);
+
+ try {
+ Multimap<ObjectId, String> groups = groupCollector.getGroups();
+ for (CreateRequest create : newChanges) {
+ batch.addCommand(create.cmd);
+ create.groups = groups.get(create.commit);
+ }
+ for (ReplaceRequest replace : replaceByChange.values()) {
+ replace.groups = groups.get(replace.newCommit);
+ }
+ } catch (OrmException e) {
+ log.error("Error collecting groups for changes", e);
+ reject(magicBranch.cmd, "internal server error");
+ return;
}
}
@@ -1647,6 +1672,7 @@
final ReceiveCommand cmd;
final ChangeInserter ins;
boolean created;
+ Collection<String> groups;
CreateRequest(RefControl ctl, RevCommit c, Change.Key changeKey)
throws OrmException {
@@ -1691,7 +1717,7 @@
}
private void insertChange(ReviewDb db) throws OrmException, IOException {
- final PatchSet ps = ins.getPatchSet();
+ final PatchSet ps = ins.setGroups(groups).getPatchSet();
final Account.Id me = currentUser.getAccountId();
final List<FooterLine> footerLines = commit.getFooterLines();
final MailRecipients recipients = new MailRecipients();
@@ -1729,18 +1755,15 @@
throws OrmException, IOException {
Submit submit = submitProvider.get();
RevisionResource rsrc = new RevisionResource(changes.parse(changeCtl), ps);
- Change c;
+ List<Change> changes;
try {
// Force submit even if submit rule evaluation fails.
- c = submit.submit(rsrc, currentUser, true);
+ changes = submit.submit(rsrc, currentUser, true);
} catch (ResourceConflictException e) {
throw new IOException(e);
}
- if (c == null) {
- addError("Submitting change " + changeCtl.getChange().getChangeId()
- + " failed.");
- } else {
- addMessage("");
+ addMessage("");
+ for (Change c : changes) {
mergeQueue.merge(c.getDest());
c = db.changes().get(c.getId());
switch (c.getStatus()) {
@@ -1849,6 +1872,7 @@
String mergedIntoRef;
boolean skip;
private PatchSet.Id priorPatchSet;
+ Collection<String> groups;
ReplaceRequest(final Change.Id toChange, final RevCommit newCommit,
final ReceiveCommand cmd, final boolean checkMergedInto) {
@@ -2024,6 +2048,7 @@
newPatchSet.setCreatedOn(TimeUtil.nowTs());
newPatchSet.setUploader(currentUser.getAccountId());
newPatchSet.setRevision(toRevId(newCommit));
+ newPatchSet.setGroups(groups);
if (magicBranch != null && magicBranch.draft) {
newPatchSet.setDraft(true);
}
@@ -2128,6 +2153,9 @@
}
ChangeUtil.insertAncestors(db, newPatchSet.getId(), newCommit);
+ if (newPatchSet.getGroups() == null) {
+ newPatchSet.setGroups(GroupCollector.getCurrentGroups(db, change));
+ }
db.patchSets().insert(Collections.singleton(newPatchSet));
if (checkMergedInto) {
@@ -2210,7 +2238,7 @@
if (cmd.getResult() == NOT_ATTEMPTED) {
cmd.execute(rp);
}
- CheckedFuture<?, IOException> f = indexer.indexAsync(change.getId());
+ indexer.index(db, change);
if (changeKind != ChangeKind.TRIVIAL_REBASE) {
workQueue.getDefaultQueue()
.submit(requestScopePropagator.wrap(new Runnable() {
@@ -2218,7 +2246,7 @@
public void run() {
try {
ReplacePatchSetSender cm =
- replacePatchSetFactory.create(change);
+ replacePatchSetFactory.create(change.getId());
cm.setFrom(me);
cm.setPatchSet(newPatchSet, info);
cm.setChangeMessage(msg);
@@ -2239,7 +2267,6 @@
}
}));
}
- f.checkedGet();
gitRefUpdated.fire(project.getNameKey(), newPatchSet.getRefName(),
ObjectId.zeroId(), newCommit);
@@ -2372,9 +2399,12 @@
walk.reset();
walk.sort(RevSort.NONE);
try {
- walk.markStart(walk.parseCommit(cmd.getNewId()));
+ RevObject parsedObject = walk.parseAny(cmd.getNewId());
+ if (!(parsedObject instanceof RevCommit)) {
+ return;
+ }
+ walk.markStart((RevCommit)parsedObject);
markHeadsAsUninteresting(walk, cmd.getRefName());
-
Set<ObjectId> existing = changeRefsById().keySet();
for (RevCommit c; (c = walk.next()) != null;) {
if (existing.contains(c)) {
@@ -2598,12 +2628,13 @@
}
private void sendMergedEmail(final ReplaceRequest result) {
+ final Change.Id id = result.change.getId();
workQueue.getDefaultQueue()
.submit(requestScopePropagator.wrap(new Runnable() {
@Override
public void run() {
try {
- final MergedSender cm = mergedSenderFactory.create(result.changeCtl);
+ final MergedSender cm = mergedSenderFactory.create(id);
cm.setFrom(currentUser.getAccountId());
cm.setPatchSet(result.newPatchSet, result.info);
cm.send();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsAdvertiseRefsHook.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsAdvertiseRefsHook.java
index 7095552..b2d3632 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsAdvertiseRefsHook.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsAdvertiseRefsHook.java
@@ -154,9 +154,10 @@
RevCommit c;
try {
while ((c = rw.next()) != null && toInclude.size() < max) {
- if (alreadySending.contains(c)) {
- } else if (toInclude.contains(c)) {
- } else if (c.getParentCount() > 1) {
+ if (alreadySending.contains(c)
+ || toInclude.contains(c)
+ || c.getParentCount() > 1) {
+ // Do nothing
} else if (toInclude.size() < base) {
toInclude.add(c);
} else {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsExecutorModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsExecutorModule.java
index 25fbfb9..365000b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsExecutorModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsExecutorModule.java
@@ -25,6 +25,7 @@
import org.eclipse.jgit.lib.Config;
import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@@ -48,9 +49,12 @@
@Provides
@Singleton
@EmailReviewCommentsExecutor
- public WorkQueue.Executor createEmailReviewCommentsExecutor(
+ public ExecutorService createEmailReviewCommentsExecutor(
@GerritServerConfig Config config, WorkQueue queues) {
int poolSize = config.getInt("sendemail", null, "threadPoolSize", 1);
+ if (poolSize == 0) {
+ return MoreExecutors.newDirectExecutorService();
+ }
return queues.createQueue(poolSize, "EmailReviewComments");
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java
index 3cf9fed..0f66da4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java
@@ -16,6 +16,7 @@
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
import com.google.gerrit.common.ChangeHooks;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.reviewdb.client.Account;
@@ -61,6 +62,7 @@
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -93,17 +95,25 @@
private final Set<Branch.NameKey> updatedSubscribers;
private final Account account;
private final ChangeHooks changeHooks;
+ private final SubmoduleSectionParser.Factory subSecParserFactory;
@Inject
- public SubmoduleOp(@Assisted final Branch.NameKey destBranch,
- @Assisted RevCommit mergeTip, @Assisted RevWalk rw,
- @CanonicalWebUrl @Nullable final Provider<String> urlProvider,
- final SchemaFactory<ReviewDb> sf, @Assisted Repository db,
- @Assisted Project destProject, @Assisted List<Change> submitted,
- @Assisted final Map<Change.Id, CodeReviewCommit> commits,
- @GerritPersonIdent final PersonIdent myIdent,
- GitRepositoryManager repoManager, GitReferenceUpdated gitRefUpdated,
- @Nullable @Assisted Account account, ChangeHooks changeHooks) {
+ public SubmoduleOp(@Assisted Branch.NameKey destBranch,
+ @Assisted RevCommit mergeTip,
+ @Assisted RevWalk rw,
+ @CanonicalWebUrl @Nullable Provider<String> urlProvider,
+ SchemaFactory<ReviewDb> sf,
+ @Assisted Repository db,
+ @Assisted Project destProject,
+ @Assisted List<Change> submitted,
+ @Assisted Map<Change.Id,
+ CodeReviewCommit> commits,
+ @GerritPersonIdent PersonIdent myIdent,
+ GitRepositoryManager repoManager,
+ GitReferenceUpdated gitRefUpdated,
+ @Nullable @Assisted Account account,
+ ChangeHooks changeHooks,
+ SubmoduleSectionParser.Factory subSecParserFactory) {
this.destBranch = destBranch;
this.mergeTip = mergeTip;
this.rw = rw;
@@ -118,6 +128,7 @@
this.gitRefUpdated = gitRefUpdated;
this.account = account;
this.changeHooks = changeHooks;
+ this.subSecParserFactory = subSecParserFactory;
updatedSubscribers = new HashSet<>();
}
@@ -128,7 +139,7 @@
updateSubmoduleSubscriptions();
updateSuperProjects(destBranch, rw, mergeTip.getId().toObjectId(), null);
- } catch (OrmException e) {
+ } catch (OrmException | IOException e) {
throw new SubmoduleException("Cannot open database", e);
} finally {
if (schema != null) {
@@ -145,42 +156,47 @@
}
try {
- final TreeWalk tw = TreeWalk.forPath(db, GIT_MODULES, mergeTip.getTree());
- if (tw != null
- && (FileMode.REGULAR_FILE.equals(tw.getRawMode(0)) || FileMode.EXECUTABLE_FILE
- .equals(tw.getRawMode(0)))) {
+ Set<SubmoduleSubscription> oldSubscriptions =
+ Sets.newHashSet(schema.submoduleSubscriptions()
+ .bySuperProject(destBranch));
+ Set<SubmoduleSubscription> newSubscriptions;
+ TreeWalk tw = TreeWalk.forPath(db, GIT_MODULES, mergeTip.getTree());
+ if (tw != null
+ && (FileMode.REGULAR_FILE.equals(tw.getRawMode(0)) ||
+ FileMode.EXECUTABLE_FILE.equals(tw.getRawMode(0)))) {
BlobBasedConfig bbc =
new BlobBasedConfig(null, db, mergeTip, GIT_MODULES);
- final String thisServer = new URI(urlProvider.get()).getHost();
+ String thisServer = new URI(urlProvider.get()).getHost();
- final Branch.NameKey target =
+ Branch.NameKey target =
new Branch.NameKey(new Project.NameKey(destProject.getName()),
destBranch.get());
- final Set<SubmoduleSubscription> oldSubscriptions =
- new HashSet<>(schema.submoduleSubscriptions()
- .bySuperProject(destBranch).toList());
- final List<SubmoduleSubscription> newSubscriptions =
- new SubmoduleSectionParser(bbc, thisServer, target, repoManager)
- .parseAllSections();
+ newSubscriptions = subSecParserFactory.create(bbc, thisServer, target)
+ .parseAllSections();
+ } else {
+ newSubscriptions = Collections.emptySet();
+ }
- final Set<SubmoduleSubscription> alreadySubscribeds = new HashSet<>();
- for (SubmoduleSubscription s : newSubscriptions) {
- if (oldSubscriptions.contains(s)) {
- alreadySubscribeds.add(s);
- }
+ Set<SubmoduleSubscription> alreadySubscribeds = new HashSet<>();
+ for (SubmoduleSubscription s : newSubscriptions) {
+ if (oldSubscriptions.contains(s)) {
+ alreadySubscribeds.add(s);
}
+ }
- oldSubscriptions.removeAll(newSubscriptions);
- newSubscriptions.removeAll(alreadySubscribeds);
+ oldSubscriptions.removeAll(newSubscriptions);
+ newSubscriptions.removeAll(alreadySubscribeds);
- if (!oldSubscriptions.isEmpty()) {
- schema.submoduleSubscriptions().delete(oldSubscriptions);
- }
+ if (!oldSubscriptions.isEmpty()) {
+ schema.submoduleSubscriptions().delete(oldSubscriptions);
+ }
+ if (!newSubscriptions.isEmpty()) {
schema.submoduleSubscriptions().insert(newSubscriptions);
}
+
} catch (OrmException e) {
logAndThrowSubmoduleException(
"Database problem at update of subscriptions table from "
@@ -201,7 +217,8 @@
}
private void updateSuperProjects(final Branch.NameKey updatedBranch, RevWalk myRw,
- final ObjectId mergedCommit, final String msg) throws SubmoduleException {
+ final ObjectId mergedCommit, final String msg) throws SubmoduleException,
+ IOException {
try {
final List<SubmoduleSubscription> subscribers =
schema.submoduleSubscriptions().bySubmodule(updatedBranch).toList();
@@ -227,6 +244,7 @@
&& (c.getStatusCode() == CommitMergeStatus.CLEAN_MERGE
|| c.getStatusCode() == CommitMergeStatus.CLEAN_PICK
|| c.getStatusCode() == CommitMergeStatus.CLEAN_REBASE)) {
+ myRw.parseBody(c);
sb.append("\n")
.append(c.getFullMessage());
}
@@ -278,8 +296,7 @@
throws SubmoduleException {
PersonIdent author = null;
- final StringBuilder msgbuf = new StringBuilder();
- msgbuf.append("Updated " + subscriber.getParentKey().get());
+ final StringBuilder msgbuf = new StringBuilder("Updated git submodules\n");
Repository pdb = null;
RevWalk recRw = null;
@@ -351,6 +368,7 @@
commit.setCommitter(myIdent);
commit.setMessage(msgbuf.toString());
oi.insert(commit);
+ oi.flush();
ObjectId commitId = oi.idFor(Constants.OBJ_COMMIT, commit.build());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/TabFile.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/TabFile.java
new file mode 100644
index 0000000..74d8f2d
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/TabFile.java
@@ -0,0 +1,129 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.git;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class TabFile {
+ protected static class Row {
+ public String left;
+ public String right;
+
+ public Row(String left, String right) {
+ this.left = left;
+ this.right = right;
+ }
+ }
+
+ protected static List<Row> parse(String text, String filename,
+ ValidationError.Sink errors) throws IOException {
+ List<Row> rows = new ArrayList<>();
+ BufferedReader br = new BufferedReader(new StringReader(text));
+ String s;
+ for (int lineNumber = 1; (s = br.readLine()) != null; lineNumber++) {
+ if (s.isEmpty() || s.startsWith("#")) {
+ continue;
+ }
+
+ int tab = s.indexOf('\t');
+ if (tab < 0) {
+ errors.error(new ValidationError(filename, lineNumber,
+ "missing tab delimiter"));
+ continue;
+ }
+
+ rows.add(new Row(s.substring(0, tab).trim(),
+ s.substring(tab + 1).trim()));
+ }
+ return rows;
+ }
+
+ protected static Map<String, String> toMap(List<Row> rows) {
+ Map<String, String> map = new HashMap<>(rows.size());
+ for (Row row : rows) {
+ map.put(row.left, row.right);
+ }
+ return map;
+ }
+
+ protected static String asText(String left, String right,
+ Map<String, String> entries) {
+ if (entries.isEmpty()) {
+ return null;
+ }
+
+ List<Row> rows = new ArrayList<>(entries.size());
+ for (String key : sort(entries.keySet())) {
+ rows.add(new Row(key, entries.get(key)));
+ }
+ return asText(left, right, rows);
+ }
+
+ protected static String asText(String left, String right, List<Row> rows) {
+ if (rows.isEmpty()) {
+ return null;
+ }
+
+ left = "# " + left;
+ int leftLen = left.length();
+ for (Row row : rows) {
+ leftLen = Math.max(leftLen, row.left.length());
+ }
+
+ StringBuilder buf = new StringBuilder();
+ buf.append(pad(leftLen, left));
+ buf.append('\t');
+ buf.append(right);
+ buf.append('\n');
+
+ buf.append('#');
+ buf.append('\n');
+
+ for (Row row : rows) {
+ buf.append(pad(leftLen, row.left));
+ buf.append('\t');
+ buf.append(row.right);
+ buf.append('\n');
+ }
+ return buf.toString();
+ }
+
+ protected static <T extends Comparable<? super T>> List<T> sort(Collection<T> m) {
+ ArrayList<T> r = new ArrayList<>(m);
+ Collections.sort(r);
+ return r;
+ }
+
+ protected static String pad(int len, String src) {
+ if (len <= src.length()) {
+ return src;
+ }
+
+ StringBuilder r = new StringBuilder(len);
+ r.append(src);
+ while (r.length() < len) {
+ r.append(' ');
+ }
+ return r.toString();
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/VersionedMetaData.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/VersionedMetaData.java
index b905f67..37df726 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/VersionedMetaData.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/VersionedMetaData.java
@@ -43,6 +43,7 @@
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.ReceiveCommand;
import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.util.ChangeIdUtil;
import org.eclipse.jgit.util.RawParseUtils;
import java.io.BufferedReader;
@@ -271,6 +272,14 @@
commit.addParentId(src);
}
+ if (update.insertChangeId()) {
+ ObjectId id =
+ ChangeIdUtil.computeChangeId(res, getRevision(),
+ commit.getAuthor(), commit.getCommitter(),
+ commit.getMessage());
+ commit.setMessage(ChangeIdUtil.insertId(commit.getMessage(), id));
+ }
+
src = inserter.insert(commit);
srcTree = res;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java
index ca9b992..4a8163b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java
@@ -110,8 +110,8 @@
return defaultQueue;
}
- /** Create a new executor queue with one thread. */
- public Executor createQueue(final int poolsize, final String prefix) {
+ /** Create a new executor queue. */
+ public Executor createQueue(int poolsize, String prefix) {
final Executor r = new Executor(poolsize, prefix);
r.setContinueExistingPeriodicTasksAfterShutdownPolicy(false);
r.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
@@ -303,11 +303,9 @@
final long delay = getDelay(TimeUnit.MILLISECONDS);
if (delay <= 0) {
return State.READY;
- } else if (0 < delay) {
+ } else {
return State.SLEEPING;
}
-
- return State.OTHER;
}
public Date getStartTime() {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/CherryPick.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/CherryPick.java
index 60af3003..2d229a9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/CherryPick.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/CherryPick.java
@@ -27,6 +27,7 @@
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.CodeReviewCommit;
import com.google.gerrit.server.git.CommitMergeStatus;
+import com.google.gerrit.server.git.GroupCollector;
import com.google.gerrit.server.git.MergeConflictException;
import com.google.gerrit.server.git.MergeException;
import com.google.gerrit.server.git.MergeIdenticalTreeException;
@@ -186,6 +187,7 @@
args.db.changes().beginTransaction(n.change().getId());
try {
insertAncestors(args.db, ps.getId(), newCommit);
+ ps.setGroups(GroupCollector.getCurrentGroups(args.db, n.change()));
args.db.patchSets().insert(Collections.singleton(ps));
n.change()
.setCurrentPatchSet(patchSetInfoFactory.get(newCommit, ps.getId()));
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/RebaseIfNecessary.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/RebaseIfNecessary.java
index acd32c7..dd981ad 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/RebaseIfNecessary.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/RebaseIfNecessary.java
@@ -20,7 +20,7 @@
import com.google.gerrit.reviewdb.client.PatchSetApproval;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.change.PatchSetInserter.ValidatePolicy;
-import com.google.gerrit.server.changedetail.RebaseChange;
+import com.google.gerrit.server.change.RebaseChange;
import com.google.gerrit.server.git.CodeReviewCommit;
import com.google.gerrit.server.git.CommitMergeStatus;
import com.google.gerrit.server.git.MergeConflictException;
@@ -89,7 +89,7 @@
.getSubmitter(n).getAccountId());
PatchSet newPatchSet =
rebaseChange.rebase(args.repo, args.rw, args.inserter,
- n.getPatchsetId(), n.change(), uploader,
+ n.change(), n.getPatchsetId(), uploader,
mergeTip.getCurrentTip(), args.mergeUtil,
args.serverIdent.get(), false, ValidatePolicy.NONE);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/SubmitStrategyFactory.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/SubmitStrategyFactory.java
index ac65f8d..ffe351b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/SubmitStrategyFactory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/SubmitStrategyFactory.java
@@ -20,7 +20,7 @@
import com.google.gerrit.server.ApprovalsUtil;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.changedetail.RebaseChange;
+import com.google.gerrit.server.change.RebaseChange;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.MergeException;
import com.google.gerrit.server.git.MergeUtil;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/validators/CommitValidators.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/validators/CommitValidators.java
index d030a55..d8c3303 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/validators/CommitValidators.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/validators/CommitValidators.java
@@ -222,7 +222,7 @@
sb.append("ERROR: ").append(errMsg);
if (c.getFullMessage().indexOf(changeId) >= 0) {
- String lines[] = c.getFullMessage().trim().split("\n");
+ String[] lines = c.getFullMessage().trim().split("\n");
String lastLine = lines.length > 0 ? lines[lines.length - 1] : "";
if (lastLine.indexOf(changeId) == -1) {
@@ -387,7 +387,9 @@
final ProjectControl projectControl = refControl.getProjectControl();
if (projectControl.getProjectState().isUseSignedOffBy()) {
- boolean sboAuthor = false, sboCommitter = false, sboMe = false;
+ boolean sboAuthor = false;
+ boolean sboCommitter = false;
+ boolean sboMe = false;
for (final FooterLine footer : receiveEvent.commit.getFooterLines()) {
if (footer.matches(FooterKey.SIGNED_OFF_BY)) {
final String e = footer.getEmailAddress();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/AddIncludedGroups.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/AddIncludedGroups.java
index 9a3f02f..f3fb2a9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/AddIncludedGroups.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/AddIncludedGroups.java
@@ -20,6 +20,7 @@
import com.google.common.collect.Maps;
import com.google.gerrit.audit.AuditService;
import com.google.gerrit.common.data.GroupDescription;
+import com.google.gerrit.extensions.common.GroupInfo;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.DefaultInput;
import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
@@ -33,7 +34,6 @@
import com.google.gerrit.server.account.GroupControl;
import com.google.gerrit.server.account.GroupIncludeCache;
import com.google.gerrit.server.group.AddIncludedGroups.Input;
-import com.google.gerrit.server.group.GroupJson.GroupInfo;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/AddMembers.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/AddMembers.java
index 5c7fcbc..134d31c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/AddMembers.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/AddMembers.java
@@ -45,8 +45,11 @@
import com.google.inject.Provider;
import com.google.inject.Singleton;
+import java.util.Collection;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
@Singleton
public class AddMembers implements RestModifyView<GroupResource, Input> {
@@ -75,6 +78,7 @@
}
}
+ private final Provider<IdentifiedUser> self;
private final AccountManager accountManager;
private final AuthType authType;
private final AccountsCollection accounts;
@@ -85,7 +89,8 @@
private final AuditService auditService;
@Inject
- AddMembers(AccountManager accountManager,
+ AddMembers(Provider<IdentifiedUser> self,
+ AccountManager accountManager,
AuthConfig authConfig,
AccountsCollection accounts,
AccountResolver accountResolver,
@@ -93,6 +98,7 @@
AccountLoader.Factory infoFactory,
Provider<ReviewDb> db,
AuditService auditService) {
+ this.self = self;
this.accountManager = accountManager;
this.auditService = auditService;
this.authType = authConfig.getAuthType();
@@ -114,11 +120,8 @@
input = Input.init(input);
GroupControl control = resource.getControl();
- Map<Account.Id, AccountGroupMember> newAccountGroupMembers = Maps.newHashMap();
- List<AccountInfo> result = Lists.newLinkedList();
- Account.Id me = ((IdentifiedUser) control.getCurrentUser()).getAccountId();
- AccountLoader loader = infoFactory.create(true);
+ Set<Account.Id> newMemberIds = new HashSet<>();
for (String nameOrEmail : input.members) {
Account a = findAccount(nameOrEmail);
if (!a.isActive()) {
@@ -129,27 +132,11 @@
if (!control.canAddMember()) {
throw new AuthException("Cannot add member: " + a.getFullName());
}
-
- if (!newAccountGroupMembers.containsKey(a.getId())) {
- AccountGroupMember.Key key =
- new AccountGroupMember.Key(a.getId(), internalGroup.getId());
- AccountGroupMember m = db.get().accountGroupMembers().get(key);
- if (m == null) {
- m = new AccountGroupMember(key);
- newAccountGroupMembers.put(m.getAccountId(), m);
- }
- }
- result.add(loader.get(a.getId()));
+ newMemberIds.add(a.getId());
}
- auditService.dispatchAddAccountsToGroup(me, newAccountGroupMembers.values());
- db.get().accountGroupMembers().insert(newAccountGroupMembers.values());
- for (AccountGroupMember m : newAccountGroupMembers.values()) {
- accountCache.evict(m.getAccountId());
- }
-
- loader.fill();
- return result;
+ addMembers(internalGroup.getId(), newMemberIds);
+ return toAccountInfoList(newMemberIds);
}
private Account findAccount(String nameOrEmail) throws AuthException,
@@ -177,6 +164,29 @@
}
}
+ public void addMembers(AccountGroup.Id groupId,
+ Collection<? extends Account.Id> newMemberIds) throws OrmException {
+ Map<Account.Id, AccountGroupMember> newAccountGroupMembers = Maps.newHashMap();
+ for (Account.Id accId : newMemberIds) {
+ if (!newAccountGroupMembers.containsKey(accId)) {
+ AccountGroupMember.Key key =
+ new AccountGroupMember.Key(accId, groupId);
+ AccountGroupMember m = db.get().accountGroupMembers().get(key);
+ if (m == null) {
+ m = new AccountGroupMember(key);
+ newAccountGroupMembers.put(m.getAccountId(), m);
+ }
+ }
+ }
+
+ auditService.dispatchAddAccountsToGroup(self.get().getAccountId(),
+ newAccountGroupMembers.values());
+ db.get().accountGroupMembers().insert(newAccountGroupMembers.values());
+ for (AccountGroupMember m : newAccountGroupMembers.values()) {
+ accountCache.evict(m.getAccountId());
+ }
+ }
+
private Account createAccountByLdap(String user) {
if (!user.matches(Account.USER_NAME_PATTERN)) {
return null;
@@ -192,6 +202,17 @@
}
}
+ private List<AccountInfo> toAccountInfoList(Set<Account.Id> accountIds)
+ throws OrmException {
+ List<AccountInfo> result = Lists.newLinkedList();
+ AccountLoader loader = infoFactory.create(true);
+ for (Account.Id accId : accountIds) {
+ result.add(loader.get(accId));
+ }
+ loader.fill();
+ return result;
+ }
+
static class PutMember implements RestModifyView<GroupResource, PutMember.Input> {
static class Input {
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/CreateGroup.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/CreateGroup.java
index cb80702..0986584 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/CreateGroup.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/CreateGroup.java
@@ -19,9 +19,9 @@
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.common.data.GroupDescription;
import com.google.gerrit.common.data.GroupDescriptions;
-import com.google.gerrit.common.errors.NameAlreadyUsedException;
-import com.google.gerrit.common.errors.PermissionDeniedException;
import com.google.gerrit.extensions.annotations.RequiresCapability;
+import com.google.gerrit.extensions.api.groups.GroupInput;
+import com.google.gerrit.extensions.common.GroupInfo;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
@@ -32,100 +32,102 @@
import com.google.gerrit.extensions.restapi.Url;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupName;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.CreateGroupArgs;
-import com.google.gerrit.server.account.PerformCreateGroup;
+import com.google.gerrit.server.account.GroupCache;
+import com.google.gerrit.server.account.GroupUUID;
import com.google.gerrit.server.config.GerritServerConfig;
-import com.google.gerrit.server.group.CreateGroup.Input;
-import com.google.gerrit.server.group.GroupJson.GroupInfo;
import com.google.gerrit.server.validators.GroupCreationValidationListener;
import com.google.gerrit.server.validators.ValidationException;
+import com.google.gwtorm.server.OrmDuplicateKeyException;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.assistedinject.Assisted;
import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.PersonIdent;
import java.util.Collections;
@RequiresCapability(GlobalCapability.CREATE_GROUP)
-public class CreateGroup implements RestModifyView<TopLevelResource, Input> {
- public static class Input {
- public String name;
- public String description;
- public Boolean visibleToAll;
- public String ownerId;
- }
-
+public class CreateGroup implements RestModifyView<TopLevelResource, GroupInput> {
public static interface Factory {
CreateGroup create(@Assisted String name);
}
private final Provider<IdentifiedUser> self;
+ private final PersonIdent serverIdent;
+ private final ReviewDb db;
+ private final GroupCache groupCache;
private final GroupsCollection groups;
- private final PerformCreateGroup.Factory op;
private final GroupJson json;
private final DynamicSet<GroupCreationValidationListener> groupCreationValidationListeners;
+ private final AddMembers addMembers;
private final boolean defaultVisibleToAll;
private final String name;
@Inject
- CreateGroup(Provider<IdentifiedUser> self, GroupsCollection groups,
- PerformCreateGroup.Factory performCreateGroupFactory, GroupJson json,
+ CreateGroup(
+ Provider<IdentifiedUser> self,
+ @GerritPersonIdent PersonIdent serverIdent,
+ ReviewDb db,
+ GroupCache groupCache,
+ GroupsCollection groups,
+ GroupJson json,
DynamicSet<GroupCreationValidationListener> groupCreationValidationListeners,
- @GerritServerConfig Config cfg, @Assisted String name) {
+ AddMembers addMembers,
+ @GerritServerConfig Config cfg,
+ @Assisted String name) {
this.self = self;
+ this.serverIdent = serverIdent;
+ this.db = db;
+ this.groupCache = groupCache;
this.groups = groups;
- this.op = performCreateGroupFactory;
this.json = json;
this.groupCreationValidationListeners = groupCreationValidationListeners;
+ this.addMembers = addMembers;
this.defaultVisibleToAll = cfg.getBoolean("groups", "newGroupsVisibleToAll", false);
this.name = name;
}
@Override
- public GroupInfo apply(TopLevelResource resource, Input input)
+ public GroupInfo apply(TopLevelResource resource, GroupInput input)
throws AuthException, BadRequestException, UnprocessableEntityException,
ResourceConflictException, OrmException {
if (input == null) {
- input = new Input();
+ input = new GroupInput();
}
if (input.name != null && !name.equals(input.name)) {
throw new BadRequestException("name must match URL");
}
AccountGroup.Id ownerId = owner(input);
- AccountGroup group;
- try {
- CreateGroupArgs args = new CreateGroupArgs();
- args.setGroupName(name);
- args.groupDescription = Strings.emptyToNull(input.description);
- args.visibleToAll = MoreObjects.firstNonNull(input.visibleToAll,
- defaultVisibleToAll);
- args.ownerGroupId = ownerId;
- args.initialMembers = ownerId == null
- ? Collections.singleton(self.get().getAccountId())
- : Collections.<Account.Id> emptySet();
+ CreateGroupArgs args = new CreateGroupArgs();
+ args.setGroupName(name);
+ args.groupDescription = Strings.emptyToNull(input.description);
+ args.visibleToAll = MoreObjects.firstNonNull(input.visibleToAll,
+ defaultVisibleToAll);
+ args.ownerGroupId = ownerId;
+ args.initialMembers = ownerId == null
+ ? Collections.singleton(self.get().getAccountId())
+ : Collections.<Account.Id> emptySet();
- for (GroupCreationValidationListener l : groupCreationValidationListeners) {
- try {
- l.validateNewGroup(args);
- } catch (ValidationException e) {
- throw new ResourceConflictException(e.getMessage(), e);
- }
+ for (GroupCreationValidationListener l : groupCreationValidationListeners) {
+ try {
+ l.validateNewGroup(args);
+ } catch (ValidationException e) {
+ throw new ResourceConflictException(e.getMessage(), e);
}
-
- group = op.create(args).createGroup();
- } catch (PermissionDeniedException e) {
- throw new AuthException(e.getMessage());
- } catch (NameAlreadyUsedException e) {
- throw new ResourceConflictException(e.getMessage());
}
- return json.format(GroupDescriptions.forAccountGroup(group));
+
+ return json.format(GroupDescriptions.forAccountGroup(createGroup(args)));
}
- private AccountGroup.Id owner(Input input)
+ private AccountGroup.Id owner(GroupInput input)
throws UnprocessableEntityException {
if (input.ownerId != null) {
GroupDescription.Basic d = groups.parseInternal(Url.decode(input.ownerId));
@@ -133,4 +135,42 @@
}
return null;
}
+
+ private AccountGroup createGroup(CreateGroupArgs createGroupArgs)
+ throws OrmException, ResourceConflictException {
+ AccountGroup.Id groupId = new AccountGroup.Id(db.nextAccountGroupId());
+ AccountGroup.UUID uuid =
+ GroupUUID.make(
+ createGroupArgs.getGroupName(),
+ self.get().newCommitterIdent(serverIdent.getWhen(),
+ serverIdent.getTimeZone()));
+ AccountGroup group =
+ new AccountGroup(createGroupArgs.getGroup(), groupId, uuid);
+ group.setVisibleToAll(createGroupArgs.visibleToAll);
+ if (createGroupArgs.ownerGroupId != null) {
+ AccountGroup ownerGroup = groupCache.get(createGroupArgs.ownerGroupId);
+ if (ownerGroup != null) {
+ group.setOwnerGroupUUID(ownerGroup.getGroupUUID());
+ }
+ }
+ if (createGroupArgs.groupDescription != null) {
+ group.setDescription(createGroupArgs.groupDescription);
+ }
+ AccountGroupName gn = new AccountGroupName(group);
+ // first insert the group name to validate that the group name hasn't
+ // already been used to create another group
+ try {
+ db.accountGroupNames().insert(Collections.singleton(gn));
+ } catch (OrmDuplicateKeyException e) {
+ throw new ResourceConflictException("group '"
+ + createGroupArgs.getGroupName() + "' already exists");
+ }
+ db.accountGroups().insert(Collections.singleton(group));
+
+ addMembers.addMembers(groupId, createGroupArgs.initialMembers);
+
+ groupCache.onCreateGroup(createGroupArgs.getGroup());
+
+ return group;
+ }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetDescription.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetDescription.java
index 8c804dd..6900b83 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetDescription.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetDescription.java
@@ -21,7 +21,7 @@
import com.google.inject.Singleton;
@Singleton
-class GetDescription implements RestReadView<GroupResource> {
+public class GetDescription implements RestReadView<GroupResource> {
@Override
public String apply(GroupResource resource) throws MethodNotAllowedException {
AccountGroup group = resource.toAccountGroup();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetDetail.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetDetail.java
index 936798d..615c862 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetDetail.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetDetail.java
@@ -14,9 +14,9 @@
package com.google.gerrit.server.group;
-import com.google.gerrit.common.groups.ListGroupsOption;
+import com.google.gerrit.extensions.client.ListGroupsOption;
+import com.google.gerrit.extensions.common.GroupInfo;
import com.google.gerrit.extensions.restapi.RestReadView;
-import com.google.gerrit.server.group.GroupJson.GroupInfo;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetGroup.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetGroup.java
index 95042a2..03c6d6c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetGroup.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetGroup.java
@@ -14,14 +14,14 @@
package com.google.gerrit.server.group;
+import com.google.gerrit.extensions.common.GroupInfo;
import com.google.gerrit.extensions.restapi.RestReadView;
-import com.google.gerrit.server.group.GroupJson.GroupInfo;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@Singleton
-class GetGroup implements RestReadView<GroupResource> {
+public class GetGroup implements RestReadView<GroupResource> {
private final GroupJson json;
@Inject
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetIncludedGroup.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetIncludedGroup.java
index 5d3853e..dbc2e0c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetIncludedGroup.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetIncludedGroup.java
@@ -14,8 +14,8 @@
package com.google.gerrit.server.group;
+import com.google.gerrit.extensions.common.GroupInfo;
import com.google.gerrit.extensions.restapi.RestReadView;
-import com.google.gerrit.server.group.GroupJson.GroupInfo;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetOptions.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetOptions.java
index 5d1ede0..7b55666 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetOptions.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetOptions.java
@@ -14,6 +14,7 @@
package com.google.gerrit.server.group;
+import com.google.gerrit.extensions.common.GroupOptionsInfo;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.inject.Singleton;
@@ -22,6 +23,6 @@
@Override
public GroupOptionsInfo apply(GroupResource resource) {
- return new GroupOptionsInfo(resource.getGroup());
+ return GroupJson.createOptions(resource.getGroup());
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetOwner.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetOwner.java
index 5fc62c6..464be18 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetOwner.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetOwner.java
@@ -15,12 +15,12 @@
package com.google.gerrit.server.group;
import com.google.gerrit.common.errors.NoSuchGroupException;
+import com.google.gerrit.extensions.common.GroupInfo;
import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.account.GroupControl;
-import com.google.gerrit.server.group.GroupJson.GroupInfo;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/GroupJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/GroupJson.java
index 96b4234..8f339de 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/GroupJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/GroupJson.java
@@ -14,14 +14,15 @@
package com.google.gerrit.server.group;
-import static com.google.gerrit.common.groups.ListGroupsOption.INCLUDES;
-import static com.google.gerrit.common.groups.ListGroupsOption.MEMBERS;
+import static com.google.gerrit.extensions.client.ListGroupsOption.INCLUDES;
+import static com.google.gerrit.extensions.client.ListGroupsOption.MEMBERS;
import com.google.common.base.Strings;
import com.google.gerrit.common.data.GroupDescription;
import com.google.gerrit.common.data.GroupDescriptions;
-import com.google.gerrit.common.groups.ListGroupsOption;
-import com.google.gerrit.extensions.common.AccountInfo;
+import com.google.gerrit.extensions.client.ListGroupsOption;
+import com.google.gerrit.extensions.common.GroupInfo;
+import com.google.gerrit.extensions.common.GroupOptionsInfo;
import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
import com.google.gerrit.extensions.restapi.Url;
import com.google.gerrit.reviewdb.client.AccountGroup;
@@ -33,9 +34,17 @@
import java.util.Collection;
import java.util.EnumSet;
-import java.util.List;
public class GroupJson {
+ public static GroupOptionsInfo createOptions(GroupDescription.Basic group) {
+ GroupOptionsInfo options = new GroupOptionsInfo();
+ AccountGroup ag = GroupDescriptions.toAccountGroup(group);
+ if (ag != null && ag.isVisibleToAll()) {
+ options.visibleToAll = true;
+ }
+ return options;
+ }
+
private final GroupBackend groupBackend;
private final GroupControl.Factory groupControlFactory;
private final Provider<ListMembers> listMembers;
@@ -86,7 +95,7 @@
info.id = Url.encode(group.getGroupUUID().get());
info.name = Strings.emptyToNull(group.getName());
info.url = Strings.emptyToNull(group.getUrl());
- info.options = new GroupOptionsInfo(group);
+ info.options = createOptions(group);
AccountGroup g = GroupDescriptions.toAccountGroup(group);
if (g != null) {
@@ -125,24 +134,4 @@
throw new IllegalStateException(e);
}
}
-
- public static class GroupInfo extends GroupBaseInfo {
- public String url;
- public GroupOptionsInfo options;
-
- // These fields are only supplied for internal groups.
- public String description;
- public Integer groupId;
- public String owner;
- public String ownerId;
-
- // These fields are only supplied for internal groups, but only if requested
- public List<AccountInfo> members;
- public List<GroupInfo> includes;
- }
-
- public static class GroupBaseInfo {
- public String id;
- public String name;
- }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/GroupOptionsInfo.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/GroupOptionsInfo.java
deleted file mode 100644
index 6be92d1..0000000
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/GroupOptionsInfo.java
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (C) 2013 The Android Open Source Project
-//
-// 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.
-
-package com.google.gerrit.server.group;
-
-import com.google.gerrit.common.data.GroupDescription;
-import com.google.gerrit.common.data.GroupDescriptions;
-import com.google.gerrit.reviewdb.client.AccountGroup;
-
-public class GroupOptionsInfo {
- public Boolean visibleToAll;
-
- public GroupOptionsInfo(GroupDescription.Basic group) {
- AccountGroup ag = GroupDescriptions.toAccountGroup(group);
- visibleToAll = ag != null && ag.isVisibleToAll() ? true : null;
- }
-
- public GroupOptionsInfo(AccountGroup group) {
- visibleToAll = group.isVisibleToAll() ? true : null;
- }
-}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java
index 40d0420..bf5193f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java
@@ -22,22 +22,20 @@
import com.google.gerrit.common.data.GroupDescriptions;
import com.google.gerrit.common.data.GroupReference;
import com.google.gerrit.common.errors.NoSuchGroupException;
-import com.google.gerrit.common.groups.ListGroupsOption;
+import com.google.gerrit.extensions.client.ListGroupsOption;
+import com.google.gerrit.extensions.common.GroupInfo;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.extensions.restapi.TopLevelResource;
import com.google.gerrit.extensions.restapi.Url;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.OutputFormat;
import com.google.gerrit.server.account.AccountResource;
import com.google.gerrit.server.account.GetGroups;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.account.GroupComparator;
import com.google.gerrit.server.account.GroupControl;
-import com.google.gerrit.server.group.GroupJson.GroupInfo;
import com.google.gerrit.server.project.ProjectControl;
-import com.google.gson.reflect.TypeToken;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -51,53 +49,80 @@
import java.util.Locale;
import java.util.Map;
import java.util.Set;
+import java.util.SortedMap;
/** List groups visible to the calling user. */
public class ListGroups implements RestReadView<TopLevelResource> {
protected final GroupCache groupCache;
+ private final List<ProjectControl> projects = new ArrayList<>();
+ private final Set<AccountGroup.UUID> groupsToInspect = Sets.newHashSet();
private final GroupControl.Factory groupControlFactory;
private final GroupControl.GenericFactory genericGroupControlFactory;
private final Provider<IdentifiedUser> identifiedUser;
private final IdentifiedUser.GenericFactory userFactory;
private final Provider<GetGroups> accountGetGroups;
private final GroupJson json;
- private EnumSet<ListGroupsOption> options;
+
+ private EnumSet<ListGroupsOption> options =
+ EnumSet.noneOf(ListGroupsOption.class);
+ private boolean visibleToAll;
+ private Account.Id user;
+ private boolean owned;
+ private int limit;
+ private int start;
+ private String matchSubstring;
@Option(name = "--project", aliases = {"-p"},
usage = "projects for which the groups should be listed")
- private final List<ProjectControl> projects = new ArrayList<>();
+ public void addProject(ProjectControl project) {
+ projects.add(project);
+ }
- @Option(name = "--visible-to-all", usage = "to list only groups that are visible to all registered users")
- private boolean visibleToAll;
+ @Option(name = "--visible-to-all",
+ usage = "to list only groups that are visible to all registered users")
+ public void setVisibleToAll(boolean visibleToAll) {
+ this.visibleToAll = visibleToAll;
+ }
@Option(name = "--user", aliases = {"-u"},
usage = "user for which the groups should be listed")
- private Account.Id user;
+ public void setUser(Account.Id user) {
+ this.user = user;
+ }
- @Option(name = "--owned", usage = "to list only groups that are owned by the specified user"
- + " or by the calling user if no user was specifed")
- private boolean owned;
-
- private Set<AccountGroup.UUID> groupsToInspect = Sets.newHashSet();
+ @Option(name = "--owned", usage = "to list only groups that are owned by the"
+ + " specified user or by the calling user if no user was specifed")
+ public void setOwned(boolean owned) {
+ this.owned = owned;
+ }
@Option(name = "-q", usage = "group to inspect")
- void addGroup(final AccountGroup.UUID id) {
+ public void addGroup(AccountGroup.UUID id) {
groupsToInspect.add(id);
}
- @Option(name = "--limit", aliases = {"-n"}, metaVar = "CNT", usage = "maximum number of groups to list")
- private int limit;
+ @Option(name = "--limit", aliases = {"-n"}, metaVar = "CNT",
+ usage = "maximum number of groups to list")
+ public void setLimit(int limit) {
+ this.limit = limit;
+ }
- @Option(name = "--start", aliases = {"-S"}, metaVar = "CNT", usage = "number of groups to skip")
- private int start;
+ @Option(name = "--start", aliases = {"-S"}, metaVar = "CNT",
+ usage = "number of groups to skip")
+ public void setStart(int start) {
+ this.start = start;
+ }
- @Option(name = "--match", aliases = {"-m"}, metaVar = "MATCH", usage = "match group substring")
- private String matchSubstring;
+ @Option(name = "--match", aliases = {"-m"}, metaVar = "MATCH",
+ usage = "match group substring")
+ public void setMatchSubstring(String matchSubstring) {
+ this.matchSubstring = matchSubstring;
+ }
@Option(name = "-o", usage = "Output options per group")
- public void addOption(ListGroupsOption o) {
+ void addOption(ListGroupsOption o) {
options.add(o);
}
@@ -120,7 +145,10 @@
this.userFactory = userFactory;
this.accountGetGroups = accountGetGroups;
this.json = json;
- this.options = EnumSet.noneOf(ListGroupsOption.class);
+ }
+
+ public void setOptions(EnumSet<ListGroupsOption> options) {
+ this.options = options;
}
public Account.Id getUser() {
@@ -132,16 +160,16 @@
}
@Override
- public Object apply(TopLevelResource resource) throws OrmException {
- final Map<String, GroupInfo> output = Maps.newTreeMap();
+ public SortedMap<String, GroupInfo> apply(TopLevelResource resource)
+ throws OrmException {
+ SortedMap<String, GroupInfo> output = Maps.newTreeMap();
for (GroupInfo info : get()) {
output.put(MoreObjects.firstNonNull(
info.name,
"Group " + Url.decode(info.id)), info);
info.name = null;
}
- return OutputFormat.JSON.newGson().toJsonTree(output,
- new TypeToken<Map<String, GroupInfo>>() {}.getType());
+ return output;
}
public List<GroupInfo> get() throws OrmException {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/ListIncludedGroups.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/ListIncludedGroups.java
index 671486c..8e22ef9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/ListIncludedGroups.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/ListIncludedGroups.java
@@ -18,12 +18,12 @@
import com.google.common.collect.Lists;
import com.google.gerrit.common.errors.NoSuchGroupException;
+import com.google.gerrit.extensions.common.GroupInfo;
import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.reviewdb.client.AccountGroupById;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.account.GroupControl;
-import com.google.gerrit.server.group.GroupJson.GroupInfo;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/PutGroup.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/PutGroup.java
index 9768270..abaa317 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/PutGroup.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/PutGroup.java
@@ -14,16 +14,16 @@
package com.google.gerrit.server.group;
+import com.google.gerrit.extensions.api.groups.GroupInput;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView;
-import com.google.gerrit.server.group.CreateGroup.Input;
import com.google.inject.Singleton;
@Singleton
-public class PutGroup implements RestModifyView<GroupResource, Input> {
+public class PutGroup implements RestModifyView<GroupResource, GroupInput> {
@Override
- public Response<?> apply(GroupResource resource, Input input)
+ public Response<?> apply(GroupResource resource, GroupInput input)
throws ResourceConflictException {
throw new ResourceConflictException("Group already exists");
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/PutName.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/PutName.java
index 6d980ae..ba28cd1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/PutName.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/PutName.java
@@ -15,8 +15,7 @@
package com.google.gerrit.server.group;
import com.google.common.base.Strings;
-import com.google.gerrit.common.errors.InvalidNameException;
-import com.google.gerrit.common.errors.NameAlreadyUsedException;
+import com.google.gerrit.common.data.GroupDetail;
import com.google.gerrit.common.errors.NoSuchGroupException;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
@@ -25,12 +24,24 @@
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestModifyView;
-import com.google.gerrit.server.account.PerformRenameGroup;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupName;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.account.GroupCache;
+import com.google.gerrit.server.account.GroupDetailFactory;
+import com.google.gerrit.server.git.RenameGroupOp;
import com.google.gerrit.server.group.PutName.Input;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
+import com.google.inject.Provider;
import com.google.inject.Singleton;
+import java.util.Collections;
+import java.util.Date;
+import java.util.TimeZone;
+import java.util.concurrent.TimeUnit;
+
@Singleton
public class PutName implements RestModifyView<GroupResource, Input> {
public static class Input {
@@ -38,39 +49,92 @@
public String name;
}
- private final PerformRenameGroup.Factory performRenameGroupFactory;
+ private final Provider<ReviewDb> db;
+ private final GroupCache groupCache;
+ private final GroupDetailFactory.Factory groupDetailFactory;
+ private final RenameGroupOp.Factory renameGroupOpFactory;
+ private final Provider<IdentifiedUser> currentUser;
@Inject
- PutName(PerformRenameGroup.Factory performRenameGroupFactory) {
- this.performRenameGroupFactory = performRenameGroupFactory;
+ PutName(Provider<ReviewDb> db,
+ GroupCache groupCache,
+ GroupDetailFactory.Factory groupDetailFactory,
+ RenameGroupOp.Factory renameGroupOpFactory,
+ Provider<IdentifiedUser> currentUser) {
+ this.db = db;
+ this.groupCache = groupCache;
+ this.groupDetailFactory = groupDetailFactory;
+ this.renameGroupOpFactory = renameGroupOpFactory;
+ this.currentUser = currentUser;
}
@Override
- public String apply(GroupResource resource, Input input)
+ public String apply(GroupResource rsrc, Input input)
throws MethodNotAllowedException, AuthException, BadRequestException,
- ResourceNotFoundException, ResourceConflictException, OrmException {
- if (resource.toAccountGroup() == null) {
+ ResourceNotFoundException, ResourceConflictException, OrmException,
+ NoSuchGroupException {
+ if (rsrc.toAccountGroup() == null) {
throw new MethodNotAllowedException();
- } else if (!resource.getControl().isOwner()) {
+ } else if (!rsrc.getControl().isOwner()) {
throw new AuthException("Not group owner");
} else if (input == null || Strings.isNullOrEmpty(input.name)) {
throw new BadRequestException("name is required");
}
+ String newName = input.name.trim();
+ if (newName.isEmpty()) {
+ throw new BadRequestException("name is required");
+ }
- final String newName = input.name.trim();
- if (resource.toAccountGroup().getName().equals(newName)) {
+ if (rsrc.toAccountGroup().getName().equals(newName)) {
return newName;
}
+ return renameGroup(rsrc.toAccountGroup(), newName).group.getName();
+ }
+
+ private GroupDetail renameGroup(AccountGroup group, String newName)
+ throws ResourceConflictException, OrmException,
+ NoSuchGroupException {
+ AccountGroup.Id groupId = group.getId();
+ AccountGroup.NameKey old = group.getNameKey();
+ AccountGroup.NameKey key = new AccountGroup.NameKey(newName);
+
try {
- return performRenameGroupFactory.create().renameGroup(
- resource.toAccountGroup().getId(), newName).group.getName();
- } catch (NoSuchGroupException e) {
- throw new ResourceNotFoundException();
- } catch (InvalidNameException e) {
- throw new BadRequestException(e.getMessage());
- } catch (NameAlreadyUsedException e) {
- throw new ResourceConflictException(e.getMessage());
+ AccountGroupName id = new AccountGroupName(key, groupId);
+ db.get().accountGroupNames().insert(Collections.singleton(id));
+ } catch (OrmException e) {
+ AccountGroupName other = db.get().accountGroupNames().get(key);
+ if (other != null) {
+ // If we are using this identity, don't report the exception.
+ //
+ if (other.getId().equals(groupId)) {
+ return groupDetailFactory.create(groupId).call();
+ }
+
+ // Otherwise, someone else has this identity.
+ //
+ throw new ResourceConflictException("group with name " + newName
+ + "already exists");
+ } else {
+ throw e;
+ }
}
+
+ group.setNameKey(key);
+ db.get().accountGroups().update(Collections.singleton(group));
+
+ AccountGroupName priorName = db.get().accountGroupNames().get(old);
+ if (priorName != null) {
+ db.get().accountGroupNames().delete(Collections.singleton(priorName));
+ }
+
+ groupCache.evict(group);
+ groupCache.evictAfterRename(old, key);
+ renameGroupOpFactory.create(
+ currentUser.get().newCommitterIdent(new Date(), TimeZone.getDefault()),
+ group.getGroupUUID(),
+ old.get(), newName).start(0, TimeUnit.MILLISECONDS);
+
+ return groupDetailFactory.create(groupId).call();
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/PutOptions.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/PutOptions.java
index 6ed6703..5788503 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/PutOptions.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/PutOptions.java
@@ -14,6 +14,7 @@
package com.google.gerrit.server.group;
+import com.google.gerrit.extensions.common.GroupOptionsInfo;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
@@ -22,7 +23,6 @@
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.account.GroupCache;
-import com.google.gerrit.server.group.PutOptions.Input;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -31,11 +31,8 @@
import java.util.Collections;
@Singleton
-public class PutOptions implements RestModifyView<GroupResource, Input> {
- public static class Input {
- public Boolean visibleToAll;
- }
-
+public class PutOptions
+ implements RestModifyView<GroupResource, GroupOptionsInfo> {
private final GroupCache groupCache;
private final Provider<ReviewDb> db;
@@ -46,7 +43,7 @@
}
@Override
- public GroupOptionsInfo apply(GroupResource resource, Input input)
+ public GroupOptionsInfo apply(GroupResource resource, GroupOptionsInfo input)
throws MethodNotAllowedException, AuthException, BadRequestException,
ResourceNotFoundException, OrmException {
if (resource.toAccountGroup() == null) {
@@ -72,6 +69,10 @@
db.get().accountGroups().update(Collections.singleton(group));
groupCache.evict(group);
- return new GroupOptionsInfo(group);
+ GroupOptionsInfo options = new GroupOptionsInfo();
+ if (group.isVisibleToAll()) {
+ options.visibleToAll = true;
+ }
+ return options;
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/PutOwner.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/PutOwner.java
index 11d34ab..b88ead5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/PutOwner.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/PutOwner.java
@@ -16,6 +16,7 @@
import com.google.common.base.Strings;
import com.google.gerrit.common.data.GroupDescription;
+import com.google.gerrit.extensions.common.GroupInfo;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.DefaultInput;
@@ -26,7 +27,6 @@
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.account.GroupCache;
-import com.google.gerrit.server.group.GroupJson.GroupInfo;
import com.google.gerrit.server.group.PutOwner.Input;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeField.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeField.java
index 2993739..ebbc951 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeField.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeField.java
@@ -44,6 +44,7 @@
import java.io.IOException;
import java.sql.Timestamp;
import java.util.Collection;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -54,6 +55,10 @@
* {@link ChangeQueryBuilder} for querying that field, and a method on
* {@link ChangeData} used for populating the corresponding document fields in
* the secondary index.
+ * <p>
+ * Field names are all lowercase alphanumeric plus underscore; index
+ * implementations may create unambiguous derived field names containing other
+ * characters.
*/
public class ChangeField {
/** Legacy change ID. */
@@ -141,18 +146,26 @@
}
};
+ @Deprecated
/** Topic, a short annotation on the branch. */
- public static final FieldDef<ChangeData, String> TOPIC =
+ public static final FieldDef<ChangeData, String> LEGACY_TOPIC =
new FieldDef.Single<ChangeData, String>(
"topic2", FieldType.EXACT, false) {
@Override
public String get(ChangeData input, FillArgs args)
throws OrmException {
- Change c = input.change();
- if (c == null) {
- return null;
- }
- return firstNonNull(c.getTopic(), "");
+ return getTopic(input);
+ }
+ };
+
+ /** Topic, a short annotation on the branch. */
+ public static final FieldDef<ChangeData, String> TOPIC =
+ new FieldDef.Single<ChangeData, String>(
+ "topic3", FieldType.PREFIX, false) {
+ @Override
+ public String get(ChangeData input, FillArgs args)
+ throws OrmException {
+ return getTopic(input);
}
};
@@ -253,7 +266,7 @@
throws OrmException {
Change c = input.change();
if (c == null) {
- return null;
+ return ImmutableSet.of();
}
Set<Integer> r = Sets.newHashSet();
if (!args.allowsDrafts && c.getStatus() == Change.Status.DRAFT) {
@@ -274,7 +287,7 @@
public Iterable<String> get(ChangeData input, FillArgs args)
throws OrmException {
Set<String> revisions = Sets.newHashSet();
- for (PatchSet ps : input.patches()) {
+ for (PatchSet ps : input.patchSets()) {
if (ps.getRevision() != null) {
revisions.add(ps.getRevision().get());
}
@@ -293,7 +306,7 @@
try {
List<FooterLine> footers = input.commitFooters();
if (footers == null) {
- return null;
+ return ImmutableSet.of();
}
return Sets.newHashSet(
args.trackingFooters.extract(footers).values());
@@ -498,6 +511,71 @@
}
};
+ /** Users who have commented on this change. */
+ public static final FieldDef<ChangeData, Iterable<Integer>> COMMENTBY =
+ new FieldDef.Repeatable<ChangeData, Integer>(
+ ChangeQueryBuilder.FIELD_COMMENTBY, FieldType.INTEGER, false) {
+ @Override
+ public Iterable<Integer> get(ChangeData input, FillArgs args)
+ throws OrmException {
+ Set<Integer> r = new HashSet<>();
+ for (ChangeMessage m : input.messages()) {
+ if (m.getAuthor() != null) {
+ r.add(m.getAuthor().get());
+ }
+ }
+ for (PatchLineComment c : input.publishedComments()) {
+ r.add(c.getAuthor().get());
+ }
+ return r;
+ }
+ };
+
+ /** Opaque group identifiers for this change's patch sets. */
+ public static final FieldDef<ChangeData, Iterable<String>> GROUP =
+ new FieldDef.Repeatable<ChangeData, String>(
+ "group", FieldType.EXACT, false) {
+ @Override
+ public Iterable<String> get(ChangeData input, FillArgs args)
+ throws OrmException {
+ Set<String> r = Sets.newHashSetWithExpectedSize(1);
+ for (PatchSet ps : input.patchSets()) {
+ List<String> groups = ps.getGroups();
+ if (groups != null) {
+ r.addAll(groups);
+ }
+ }
+ return r;
+ }
+ };
+
+ public static class PatchSetProtoField
+ extends FieldDef.Repeatable<ChangeData, byte[]> {
+ public static final ProtobufCodec<PatchSet> CODEC =
+ CodecFactory.encoder(PatchSet.class);
+
+ private PatchSetProtoField() {
+ super("_patch_set", FieldType.STORED_ONLY, true);
+ }
+
+ @Override
+ public Iterable<byte[]> get(ChangeData input, FieldDef.FillArgs args)
+ throws OrmException {
+ return toProtos(CODEC, input.patchSets());
+ }
+ }
+
+ /** Serialized patch set object, used for pre-populating results. */
+ public static final PatchSetProtoField PATCH_SET = new PatchSetProtoField();
+
+ private static String getTopic(ChangeData input) throws OrmException {
+ Change c = input.change();
+ if (c == null) {
+ return null;
+ }
+ return firstNonNull(c.getTopic(), "");
+ }
+
private static <T> List<byte[]> toProtos(ProtobufCodec<T> codec, Collection<T> objs)
throws OrmException {
List<byte[]> result = Lists.newArrayListWithCapacity(objs.size());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeSchemas.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeSchemas.java
index 05bf9bd..b6b702c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeSchemas.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeSchemas.java
@@ -38,7 +38,7 @@
ChangeField.PROJECT,
ChangeField.PROJECTS,
ChangeField.REF,
- ChangeField.TOPIC,
+ ChangeField.LEGACY_TOPIC,
ChangeField.UPDATED,
ChangeField.FILE_PART,
ChangeField.PATH,
@@ -68,7 +68,7 @@
ChangeField.PROJECT,
ChangeField.PROJECTS,
ChangeField.REF,
- ChangeField.TOPIC,
+ ChangeField.LEGACY_TOPIC,
ChangeField.UPDATED,
ChangeField.FILE_PART,
ChangeField.PATH,
@@ -88,6 +88,7 @@
ChangeField.DELTA,
ChangeField.HASHTAG);
+ @SuppressWarnings("deprecation")
static final Schema<ChangeData> V14 = schema(
ChangeField.LEGACY_ID,
ChangeField.ID,
@@ -95,6 +96,62 @@
ChangeField.PROJECT,
ChangeField.PROJECTS,
ChangeField.REF,
+ ChangeField.LEGACY_TOPIC,
+ ChangeField.UPDATED,
+ ChangeField.FILE_PART,
+ ChangeField.PATH,
+ ChangeField.OWNER,
+ ChangeField.REVIEWER,
+ ChangeField.COMMIT,
+ ChangeField.TR,
+ ChangeField.LABEL,
+ ChangeField.REVIEWED,
+ ChangeField.COMMIT_MESSAGE,
+ ChangeField.COMMENT,
+ ChangeField.CHANGE,
+ ChangeField.APPROVAL,
+ ChangeField.MERGEABLE,
+ ChangeField.ADDED,
+ ChangeField.DELETED,
+ ChangeField.DELTA,
+ ChangeField.HASHTAG);
+
+ @SuppressWarnings("deprecation")
+ static final Schema<ChangeData> V15 = schema(
+ ChangeField.LEGACY_ID,
+ ChangeField.ID,
+ ChangeField.STATUS,
+ ChangeField.PROJECT,
+ ChangeField.PROJECTS,
+ ChangeField.REF,
+ ChangeField.LEGACY_TOPIC,
+ ChangeField.UPDATED,
+ ChangeField.FILE_PART,
+ ChangeField.PATH,
+ ChangeField.OWNER,
+ ChangeField.REVIEWER,
+ ChangeField.COMMIT,
+ ChangeField.TR,
+ ChangeField.LABEL,
+ ChangeField.REVIEWED,
+ ChangeField.COMMIT_MESSAGE,
+ ChangeField.COMMENT,
+ ChangeField.CHANGE,
+ ChangeField.APPROVAL,
+ ChangeField.MERGEABLE,
+ ChangeField.ADDED,
+ ChangeField.DELETED,
+ ChangeField.DELTA,
+ ChangeField.HASHTAG,
+ ChangeField.COMMENTBY);
+
+ static final Schema<ChangeData> V16 = schema(
+ ChangeField.LEGACY_ID,
+ ChangeField.ID,
+ ChangeField.STATUS,
+ ChangeField.PROJECT,
+ ChangeField.PROJECTS,
+ ChangeField.REF,
ChangeField.TOPIC,
ChangeField.UPDATED,
ChangeField.FILE_PART,
@@ -113,7 +170,67 @@
ChangeField.ADDED,
ChangeField.DELETED,
ChangeField.DELTA,
- ChangeField.HASHTAG);
+ ChangeField.HASHTAG,
+ ChangeField.COMMENTBY);
+
+ static final Schema<ChangeData> V17 = schema(
+ ChangeField.LEGACY_ID,
+ ChangeField.ID,
+ ChangeField.STATUS,
+ ChangeField.PROJECT,
+ ChangeField.PROJECTS,
+ ChangeField.REF,
+ ChangeField.TOPIC,
+ ChangeField.UPDATED,
+ ChangeField.FILE_PART,
+ ChangeField.PATH,
+ ChangeField.OWNER,
+ ChangeField.REVIEWER,
+ ChangeField.COMMIT,
+ ChangeField.TR,
+ ChangeField.LABEL,
+ ChangeField.REVIEWED,
+ ChangeField.COMMIT_MESSAGE,
+ ChangeField.COMMENT,
+ ChangeField.CHANGE,
+ ChangeField.APPROVAL,
+ ChangeField.MERGEABLE,
+ ChangeField.ADDED,
+ ChangeField.DELETED,
+ ChangeField.DELTA,
+ ChangeField.HASHTAG,
+ ChangeField.COMMENTBY,
+ ChangeField.PATCH_SET);
+
+ static final Schema<ChangeData> V18 = schema(
+ ChangeField.LEGACY_ID,
+ ChangeField.ID,
+ ChangeField.STATUS,
+ ChangeField.PROJECT,
+ ChangeField.PROJECTS,
+ ChangeField.REF,
+ ChangeField.TOPIC,
+ ChangeField.UPDATED,
+ ChangeField.FILE_PART,
+ ChangeField.PATH,
+ ChangeField.OWNER,
+ ChangeField.REVIEWER,
+ ChangeField.COMMIT,
+ ChangeField.TR,
+ ChangeField.LABEL,
+ ChangeField.REVIEWED,
+ ChangeField.COMMIT_MESSAGE,
+ ChangeField.COMMENT,
+ ChangeField.CHANGE,
+ ChangeField.APPROVAL,
+ ChangeField.MERGEABLE,
+ ChangeField.ADDED,
+ ChangeField.DELETED,
+ ChangeField.DELTA,
+ ChangeField.HASHTAG,
+ ChangeField.COMMENTBY,
+ ChangeField.PATCH_SET,
+ ChangeField.GROUP);
private static Schema<ChangeData> schema(Collection<FieldDef<ChangeData, ?>> fields) {
return new Schema<>(ImmutableList.copyOf(fields));
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/FieldDef.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/FieldDef.java
index 557faeb..cf3fd09 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/FieldDef.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/FieldDef.java
@@ -14,6 +14,9 @@
package com.google.gerrit.server.index;
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.base.CharMatcher;
import com.google.common.base.Preconditions;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.TrackingFooters;
@@ -78,11 +81,17 @@
private final boolean stored;
private FieldDef(String name, FieldType<?> type, boolean stored) {
- this.name = name;
+ this.name = checkName(name);
this.type = type;
this.stored = stored;
}
+ private static String checkName(String name) {
+ CharMatcher m = CharMatcher.anyOf("abcdefghijklmnopqrstuvwxyz0123456789_");
+ checkArgument(m.matchesAllOf(name), "illegal field name: %s", name);
+ return name;
+ }
+
/** @return name of the field. */
public final String getName() {
return name;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/FieldType.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/FieldType.java
index dce8a20..89dc808 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/FieldType.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/FieldType.java
@@ -65,4 +65,8 @@
public String toString() {
return name;
}
+
+ public static IllegalArgumentException badFieldType(FieldType<?> t) {
+ return new IllegalArgumentException("unknown index field type " + t);
+ }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexConfig.java
index 1857e55..08f4748 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexConfig.java
@@ -18,6 +18,8 @@
import com.google.auto.value.AutoValue;
+import org.eclipse.jgit.lib.Config;
+
/**
* Implementation-specific configuration for secondary indexes.
* <p>
@@ -28,13 +30,30 @@
@AutoValue
public abstract class IndexConfig {
public static IndexConfig createDefault() {
- return create(Integer.MAX_VALUE);
+ return create(0, 0);
}
- public static IndexConfig create(int maxLimit) {
- checkArgument(maxLimit > 0, "maxLimit must be positive: %s", maxLimit);
- return new AutoValue_IndexConfig(maxLimit);
+ public static IndexConfig fromConfig(Config cfg) {
+ return create(
+ cfg.getInt("index", null, "maxLimit", 0),
+ cfg.getInt("index", null, "maxPages", 0));
+ }
+
+ public static IndexConfig create(int maxLimit, int maxPages) {
+ return new AutoValue_IndexConfig(
+ checkLimit(maxLimit, "maxLimit"),
+ checkLimit(maxPages, "maxPages"));
+ }
+
+ private static int checkLimit(int limit, String name) {
+ if (limit == 0) {
+ return Integer.MAX_VALUE;
+ }
+ checkArgument(limit > 0, "%s must be positive: %s", name, limit);
+ return limit;
}
public abstract int maxLimit();
+
+ public abstract int maxPages();
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/AbandonedSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/AbandonedSender.java
index adcf242..409c155 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/AbandonedSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/AbandonedSender.java
@@ -17,6 +17,7 @@
import com.google.gerrit.common.errors.EmailException;
import com.google.gerrit.reviewdb.client.AccountProjectWatch.NotifyType;
import com.google.gerrit.reviewdb.client.Change;
+import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
@@ -25,12 +26,13 @@
public static interface Factory extends
ReplyToChangeSender.Factory<AbandonedSender> {
@Override
- AbandonedSender create(Change change);
+ AbandonedSender create(Change.Id change);
}
@Inject
- public AbandonedSender(EmailArguments ea, @Assisted Change c) {
- super(ea, c, "abandon");
+ public AbandonedSender(EmailArguments ea, @Assisted Change.Id id)
+ throws OrmException {
+ super(ea, "abandon", newChangeData(ea, id));
}
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/AddReviewerSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/AddReviewerSender.java
index c181a9c..7a6d204 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/AddReviewerSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/AddReviewerSender.java
@@ -16,18 +16,20 @@
import com.google.gerrit.common.errors.EmailException;
import com.google.gerrit.reviewdb.client.Change;
+import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
/** Asks a user to review a change. */
public class AddReviewerSender extends NewChangeSender {
public static interface Factory {
- AddReviewerSender create(Change change);
+ AddReviewerSender create(Change.Id id);
}
@Inject
- public AddReviewerSender(EmailArguments ea, @Assisted Change c) {
- super(ea, c);
+ public AddReviewerSender(EmailArguments ea, @Assisted Change.Id id)
+ throws OrmException {
+ super(ea, newChangeData(ea, id));
}
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java
index ac23455..689c596 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java
@@ -55,6 +55,10 @@
public abstract class ChangeEmail extends NotificationEmail {
private static final Logger log = LoggerFactory.getLogger(ChangeEmail.class);
+ protected static ChangeData newChangeData(EmailArguments ea, Change.Id id) {
+ return ea.changeDataFactory.create(ea.db.get(), id);
+ }
+
protected final Change change;
protected final ChangeData changeData;
protected PatchSet patchSet;
@@ -65,10 +69,11 @@
protected Set<Account.Id> authors;
protected boolean emailOnlyAuthors;
- protected ChangeEmail(EmailArguments ea, Change c, String mc) {
- super(ea, mc, c.getProject(), c.getDest());
- change = c;
- changeData = ea.changeDataFactory.create(ea.db.get(), c);
+ protected ChangeEmail(EmailArguments ea, String mc, ChangeData cd)
+ throws OrmException {
+ super(ea, mc, cd.change().getDest());
+ changeData = cd;
+ change = cd.change();
emailOnlyAuthors = false;
}
@@ -305,7 +310,8 @@
@Override
protected final Watchers getWatchers(NotifyType type) throws OrmException {
- ProjectWatch watch = new ProjectWatch(args, project, projectState, changeData);
+ ProjectWatch watch = new ProjectWatch(
+ args, branch.getParentKey(), projectState, changeData);
return watch.getWatchers(type);
}
@@ -379,6 +385,8 @@
return args.settings.includeDiff;
}
+ private static int HEAP_EST_SIZE = 32 * 1024;
+
/** Show patch set as unified difference. */
public String getUnifiedDiff() {
PatchList patchList;
@@ -394,8 +402,9 @@
return "";
}
+ int maxSize = args.settings.maximumDiffSize;
TemporaryBuffer.Heap buf =
- new TemporaryBuffer.Heap(args.settings.maximumDiffSize);
+ new TemporaryBuffer.Heap(Math.min(HEAP_EST_SIZE, maxSize), maxSize);
try (DiffFormatter fmt = new DiffFormatter(buf)) {
Repository git;
try {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java
index b587791..8147cff 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java
@@ -14,6 +14,8 @@
package com.google.gerrit.server.mail;
+import static com.google.gerrit.server.PatchLineCommentsUtil.getCommentPsId;
+
import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.common.collect.Ordering;
@@ -50,7 +52,7 @@
.getLogger(CommentSender.class);
public static interface Factory {
- public CommentSender create(NotifyHandling notify, Change change);
+ public CommentSender create(NotifyHandling notify, Change.Id id);
}
private final NotifyHandling notify;
@@ -59,10 +61,10 @@
@Inject
public CommentSender(EmailArguments ea,
+ PatchLineCommentsUtil plcUtil,
@Assisted NotifyHandling notify,
- @Assisted Change c,
- PatchLineCommentsUtil plcUtil) {
- super(ea, c, "comment");
+ @Assisted Change.Id id) throws OrmException {
+ super(ea, "comment", newChangeData(ea, id));
this.notify = notify;
this.plcUtil = plcUtil;
}
@@ -175,7 +177,8 @@
short side = comment.getSide();
CommentRange range = comment.getRange();
if (range != null) {
- String prefix = String.format("Line %d: ", range.getStartLine());
+ String prefix = "PS" + getCommentPsId(comment).get()
+ + ", Line " + range.getStartLine() + ": ";
for (int n = range.getStartLine(); n <= range.getEndLine(); n++) {
out.append(n == range.getStartLine()
? prefix
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/CreateChangeSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/CreateChangeSender.java
index f570ac8..29895d9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/CreateChangeSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/CreateChangeSender.java
@@ -33,12 +33,13 @@
LoggerFactory.getLogger(CreateChangeSender.class);
public static interface Factory {
- public CreateChangeSender create(Change change);
+ public CreateChangeSender create(Change.Id id);
}
@Inject
- public CreateChangeSender(EmailArguments ea, @Assisted Change c) {
- super(ea, c);
+ public CreateChangeSender(EmailArguments ea, @Assisted Change.Id id)
+ throws OrmException {
+ super(ea, newChangeData(ea, id));
}
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailHeader.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailHeader.java
index 46e151b..592fbb0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailHeader.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailHeader.java
@@ -14,6 +14,8 @@
package com.google.gerrit.server.mail;
+import com.google.common.base.MoreObjects;
+
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
@@ -23,6 +25,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
+import java.util.Objects;
public abstract class EmailHeader {
public abstract boolean isEmpty();
@@ -30,7 +33,7 @@
public abstract void write(Writer w) throws IOException;
public static class String extends EmailHeader {
- private java.lang.String value;
+ private final java.lang.String value;
public String(java.lang.String v) {
value = v;
@@ -53,6 +56,22 @@
w.write(value);
}
}
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(value);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return (o instanceof String)
+ && Objects.equals(value, ((String) o).value);
+ }
+
+ @Override
+ public java.lang.String toString() {
+ return MoreObjects.toStringHelper(this).addValue(value).toString();
+ }
}
static boolean needsQuotedPrintable(java.lang.String value) {
@@ -113,7 +132,7 @@
}
public static class Date extends EmailHeader {
- private java.util.Date value;
+ private final java.util.Date value;
public Date(java.util.Date v) {
value = v;
@@ -135,6 +154,22 @@
fmt = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.ENGLISH);
w.write(fmt.format(value));
}
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(value);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return (o instanceof Date)
+ && Objects.equals(value, ((Date) o).value);
+ }
+
+ @Override
+ public java.lang.String toString() {
+ return MoreObjects.toStringHelper(this).addValue(value).toString();
+ }
}
public static class AddressList extends EmailHeader {
@@ -191,5 +226,21 @@
needComma = true;
}
}
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(list);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return (o instanceof AddressList)
+ && Objects.equals(list, ((AddressList) o).list);
+ }
+
+ @Override
+ public java.lang.String toString() {
+ return MoreObjects.toStringHelper(this).addValue(list).toString();
+ }
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/FromAddressGeneratorProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/FromAddressGeneratorProvider.java
index 058bbc8..51f7ad1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/FromAddressGeneratorProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/FromAddressGeneratorProvider.java
@@ -41,7 +41,7 @@
@Inject
FromAddressGeneratorProvider(@GerritServerConfig final Config cfg,
- final @AnonymousCowardName String anonymousCowardName,
+ @AnonymousCowardName final String anonymousCowardName,
@GerritPersonIdent final PersonIdent myIdent,
final AccountCache accountCache) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergeFailSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergeFailSender.java
index 3a5f7eb..ba75723 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergeFailSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergeFailSender.java
@@ -16,18 +16,20 @@
import com.google.gerrit.common.errors.EmailException;
import com.google.gerrit.reviewdb.client.Change;
+import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
/** Send notice about a change failing to merged. */
public class MergeFailSender extends ReplyToChangeSender {
public static interface Factory {
- public MergeFailSender create(Change change);
+ public MergeFailSender create(Change.Id id);
}
@Inject
- public MergeFailSender(EmailArguments ea, @Assisted Change c) {
- super(ea, c, "merge-failed");
+ public MergeFailSender(EmailArguments ea, @Assisted Change.Id id)
+ throws OrmException {
+ super(ea, "merge-failed", newChangeData(ea, id));
}
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergedSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergedSender.java
index 5cb1ba1..7fbcf8d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergedSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergedSender.java
@@ -22,8 +22,8 @@
import com.google.gerrit.common.errors.EmailException;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountProjectWatch.NotifyType;
+import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSetApproval;
-import com.google.gerrit.server.project.ChangeControl;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
@@ -31,15 +31,16 @@
/** Send notice about a change successfully merged. */
public class MergedSender extends ReplyToChangeSender {
public static interface Factory {
- public MergedSender create(ChangeControl change);
+ public MergedSender create(Change.Id id);
}
private final LabelTypes labelTypes;
@Inject
- public MergedSender(EmailArguments ea, @Assisted ChangeControl c) {
- super(ea, c.getChange(), "merged");
- labelTypes = c.getLabelTypes();
+ public MergedSender(EmailArguments ea, @Assisted Change.Id id)
+ throws OrmException {
+ super(ea, "merged", newChangeData(ea, id));
+ labelTypes = changeData.changeControl().getLabelTypes();
}
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/NewChangeSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/NewChangeSender.java
index 0dbcbe0..e18c7e5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/NewChangeSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/NewChangeSender.java
@@ -16,7 +16,8 @@
import com.google.gerrit.common.errors.EmailException;
import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.server.query.change.ChangeData;
+import com.google.gwtorm.server.OrmException;
import java.util.ArrayList;
import java.util.Collection;
@@ -29,8 +30,9 @@
private final Set<Account.Id> reviewers = new HashSet<>();
private final Set<Account.Id> extraCC = new HashSet<>();
- protected NewChangeSender(EmailArguments ea, Change c) {
- super(ea, c, "newchange");
+ protected NewChangeSender(EmailArguments ea, ChangeData cd)
+ throws OrmException {
+ super(ea, "newchange", cd);
}
public void addReviewers(final Collection<Account.Id> cc) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/NotificationEmail.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/NotificationEmail.java
index f0c43d3..de338ec 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/NotificationEmail.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/NotificationEmail.java
@@ -19,7 +19,6 @@
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountProjectWatch.NotifyType;
import com.google.gerrit.reviewdb.client.Branch;
-import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.mail.ProjectWatch.Watchers;
import com.google.gwtorm.server.OrmException;
@@ -33,14 +32,11 @@
private static final Logger log =
LoggerFactory.getLogger(NotificationEmail.class);
- protected Project.NameKey project;
protected Branch.NameKey branch;
protected NotificationEmail(EmailArguments ea,
- String mc, Project.NameKey project, Branch.NameKey branch) {
+ String mc, Branch.NameKey branch) {
super(ea, mc);
-
- this.project = project;
this.branch = branch;
}
@@ -104,7 +100,7 @@
@Override
protected void setupVelocityContext() {
super.setupVelocityContext();
- velocityContext.put("projectName", project.get());
+ velocityContext.put("projectName", branch.getParentKey().get());
velocityContext.put("branch", branch);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/PatchSetNotificationSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/PatchSetNotificationSender.java
index 53efa1e..80a5d24 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/PatchSetNotificationSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/PatchSetNotificationSender.java
@@ -100,7 +100,8 @@
updatedPatchSet, info, recipients.getReviewers(),
Collections.<Account.Id> emptySet());
try {
- CreateChangeSender cm = createChangeSenderFactory.create(updatedChange);
+ CreateChangeSender cm =
+ createChangeSenderFactory.create(updatedChange.getId());
cm.setFrom(me);
cm.setPatchSet(updatedPatchSet, info);
cm.addReviewers(recipients.getReviewers());
@@ -119,7 +120,8 @@
updatedPatchSet.getCreatedOn(), updatedPatchSet.getId());
msg.setMessage("Uploaded patch set " + updatedPatchSet.getPatchSetId() + ".");
try {
- ReplacePatchSetSender cm = replacePatchSetFactory.create(updatedChange);
+ ReplacePatchSetSender cm =
+ replacePatchSetFactory.create(updatedChange.getId());
cm.setFrom(me);
cm.setPatchSet(updatedPatchSet, info);
cm.setChangeMessage(msg);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ProjectWatch.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ProjectWatch.java
index 63709c6..95b0219 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ProjectWatch.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ProjectWatch.java
@@ -87,10 +87,9 @@
try {
add(matching, nc);
} catch (QueryParseException e) {
- log.warn(String.format(
- "Project %s has invalid notify %s filter \"%s\"",
+ log.warn("Project {} has invalid notify {} filter \"{}\": {}",
state.getProject().getName(), nc.getName(),
- nc.getFilter()), e);
+ nc.getFilter(), e.getMessage());
}
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplacePatchSetSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplacePatchSetSender.java
index 8412d22..05c7933 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplacePatchSetSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplacePatchSetSender.java
@@ -18,6 +18,7 @@
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountProjectWatch.NotifyType;
import com.google.gerrit.reviewdb.client.Change;
+import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
@@ -30,15 +31,16 @@
/** Send notice of new patch sets for reviewers. */
public class ReplacePatchSetSender extends ReplyToChangeSender {
public static interface Factory {
- public ReplacePatchSetSender create(Change change);
+ public ReplacePatchSetSender create(Change.Id id);
}
private final Set<Account.Id> reviewers = new HashSet<>();
private final Set<Account.Id> extraCC = new HashSet<>();
@Inject
- public ReplacePatchSetSender(EmailArguments ea, @Assisted Change c) {
- super(ea, c, "newpatchset");
+ public ReplacePatchSetSender(EmailArguments ea, @Assisted Change.Id id)
+ throws OrmException {
+ super(ea, "newpatchset", newChangeData(ea, id));
}
public void addReviewers(final Collection<Account.Id> cc) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplyToChangeSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplyToChangeSender.java
index 42ac917..62a6c72 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplyToChangeSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplyToChangeSender.java
@@ -16,15 +16,18 @@
import com.google.gerrit.common.errors.EmailException;
import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.server.query.change.ChangeData;
+import com.google.gwtorm.server.OrmException;
/** Alert a user to a reply to a change, usually commentary made during review. */
public abstract class ReplyToChangeSender extends ChangeEmail {
public static interface Factory<T extends ReplyToChangeSender> {
- public T create(Change change);
+ public T create(Change.Id id);
}
- protected ReplyToChangeSender(EmailArguments ea, Change c, String mc) {
- super(ea, c, mc);
+ protected ReplyToChangeSender(EmailArguments ea, String mc, ChangeData cd)
+ throws OrmException {
+ super(ea, mc, cd);
}
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/RestoredSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/RestoredSender.java
index 4f65ab4..a43c7b6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/RestoredSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/RestoredSender.java
@@ -17,6 +17,7 @@
import com.google.gerrit.common.errors.EmailException;
import com.google.gerrit.reviewdb.client.AccountProjectWatch.NotifyType;
import com.google.gerrit.reviewdb.client.Change;
+import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
@@ -25,12 +26,13 @@
public static interface Factory extends
ReplyToChangeSender.Factory<RestoredSender> {
@Override
- RestoredSender create(Change change);
+ RestoredSender create(Change.Id id);
}
@Inject
- public RestoredSender(EmailArguments ea, @Assisted Change c) {
- super(ea, c, "restore");
+ public RestoredSender(EmailArguments ea, @Assisted Change.Id id)
+ throws OrmException {
+ super(ea, "restore", newChangeData(ea, id));
}
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/RevertedSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/RevertedSender.java
index d1389fb..dda68ab 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/RevertedSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/RevertedSender.java
@@ -17,18 +17,20 @@
import com.google.gerrit.common.errors.EmailException;
import com.google.gerrit.reviewdb.client.AccountProjectWatch.NotifyType;
import com.google.gerrit.reviewdb.client.Change;
+import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
/** Send notice about a change being reverted. */
public class RevertedSender extends ReplyToChangeSender {
public static interface Factory {
- RevertedSender create(Change change);
+ RevertedSender create(Change.Id id);
}
@Inject
- public RevertedSender(EmailArguments ea, @Assisted Change c) {
- super(ea, c, "revert");
+ public RevertedSender(EmailArguments ea, @Assisted Change.Id id)
+ throws OrmException {
+ super(ea, "revert", newChangeData(ea, id));
}
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/VelocityRuntimeProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/VelocityRuntimeProvider.java
index ace1f5b..101aaac 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/VelocityRuntimeProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/VelocityRuntimeProvider.java
@@ -26,6 +26,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.nio.file.Files;
import java.util.Properties;
/** Configures Velocity template engine for sending email. */
@@ -49,10 +50,11 @@
p.setProperty(RuntimeConstants.RUNTIME_REFERENCES_STRICT, "true");
p.setProperty("runtime.log.logsystem.log4j.category", "velocity");
- if (site.mail_dir.isDirectory()) {
+ if (Files.isDirectory(site.mail_dir)) {
p.setProperty(rl, "file, class");
p.setProperty("file." + rl + ".class", pkg + ".FileResourceLoader");
- p.setProperty("file." + rl + ".path", site.mail_dir.getAbsolutePath());
+ p.setProperty("file." + rl + ".path",
+ site.mail_dir.toAbsolutePath().toString());
p.setProperty("class." + rl + ".class", pkg + ".ClasspathResourceLoader");
} else {
p.setProperty(rl, "class");
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeDraftUpdate.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeDraftUpdate.java
index 3b51bb4..47c1731 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeDraftUpdate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeDraftUpdate.java
@@ -16,14 +16,14 @@
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
-import static com.google.gerrit.server.notedb.CommentsInNotesUtil.getCommentPsId;
+import static com.google.gerrit.server.notedb.CommentsInNotesUtil.addCommentToMap;
+import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
-import com.google.common.collect.Table;
+import com.google.common.collect.Sets;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.PatchLineComment;
import com.google.gerrit.reviewdb.client.PatchLineComment.Status;
-import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.reviewdb.client.RevId;
@@ -46,8 +46,12 @@
import org.eclipse.jgit.revwalk.RevCommit;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Date;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@@ -165,11 +169,6 @@
}
private void verifyComment(PatchLineComment comment) {
- checkState(psId != null,
- "setPatchSetId must be called first");
- checkArgument(getCommentPsId(comment).equals(psId),
- "Comment on %s does not match configured patch set %s",
- getCommentPsId(comment), psId);
if (migration.writeChanges()) {
checkArgument(comment.getRevId() != null);
}
@@ -190,76 +189,55 @@
noteMap = NoteMap.newEmptyMap();
}
- Table<PatchSet.Id, String, PatchLineComment> baseDrafts =
- draftNotes.getDraftBaseComments();
- Table<PatchSet.Id, String, PatchLineComment> psDrafts =
- draftNotes.getDraftPsComments();
+ Map<RevId, List<PatchLineComment>> allComments = new HashMap<>();
- boolean draftsEmpty = baseDrafts.isEmpty() && psDrafts.isEmpty();
-
- // There is no need to rewrite the note for one of the sides of the patch
- // set if all of the modifications were made to the comments of one side,
- // so we set these flags to potentially save that extra work.
- boolean baseSideChanged = false;
- boolean revisionSideChanged = false;
-
- // We must define these RevIds so that if this update deletes all
- // remaining comments on a given side, then we can remove that note.
- // However, if this update doesn't delete any comments, it is okay for these
- // to be null because they won't be used.
- RevId baseRevId = null;
- RevId psRevId = null;
-
+ boolean hasComments = false;
+ int n = deleteComments.size() + upsertComments.size();
+ Set<RevId> updatedRevs = Sets.newHashSetWithExpectedSize(n);
+ Set<PatchLineComment.Key> updatedKeys = Sets.newHashSetWithExpectedSize(n);
for (PatchLineComment c : deleteComments) {
- if (c.getSide() == (short) 0) {
- baseSideChanged = true;
- baseRevId = c.getRevId();
- baseDrafts.remove(psId, c.getKey().get());
- } else {
- revisionSideChanged = true;
- psRevId = c.getRevId();
- psDrafts.remove(psId, c.getKey().get());
- }
+ allComments.put(c.getRevId(), new ArrayList<PatchLineComment>());
+ updatedRevs.add(c.getRevId());
+ updatedKeys.add(c.getKey());
}
for (PatchLineComment c : upsertComments) {
- if (c.getSide() == (short) 0) {
- baseSideChanged = true;
- baseDrafts.put(psId, c.getKey().get(), c);
- } else {
- revisionSideChanged = true;
- psDrafts.put(psId, c.getKey().get(), c);
+ hasComments = true;
+ addCommentToMap(allComments, c);
+ updatedRevs.add(c.getRevId());
+ updatedKeys.add(c.getKey());
+ }
+
+ // Re-add old comments for updated revisions so the new note contents
+ // includes both old and new comments merged in the right order.
+ //
+ // writeCommentsToNoteMap doesn't touch notes for SHA-1s that are not
+ // mentioned in the input map, so by omitting comments for those revisions,
+ // we avoid the work of having to re-serialize identical comment data for
+ // those revisions.
+ ListMultimap<RevId, PatchLineComment> existing =
+ draftNotes.getComments();
+ for (Map.Entry<RevId, PatchLineComment> e : existing.entries()) {
+ PatchLineComment c = e.getValue();
+ if (updatedRevs.contains(c.getRevId())
+ && !updatedKeys.contains(c.getKey())) {
+ hasComments = true;
+ addCommentToMap(allComments, e.getValue());
}
}
- List<PatchLineComment> newBaseDrafts =
- Lists.newArrayList(baseDrafts.row(psId).values());
- List<PatchLineComment> newPsDrafts =
- Lists.newArrayList(psDrafts.row(psId).values());
+ // If we touched every revision and there are no comments left, set the flag
+ // for the caller to delete the entire ref.
+ boolean touchedAllRevs = updatedRevs.equals(existing.keySet());
+ if (touchedAllRevs && !hasComments) {
+ removedAllComments.set(touchedAllRevs && !hasComments);
+ return null;
+ }
- updateNoteMap(baseSideChanged, noteMap, newBaseDrafts,
- baseRevId);
- updateNoteMap(revisionSideChanged, noteMap, newPsDrafts,
- psRevId);
-
- removedAllComments.set(
- baseDrafts.isEmpty() && psDrafts.isEmpty() && !draftsEmpty);
-
+ commentsUtil.writeCommentsToNoteMap(noteMap, allComments, inserter);
return noteMap.writeTree(inserter);
}
- private void updateNoteMap(boolean changed, NoteMap noteMap,
- List<PatchLineComment> comments, RevId commitId)
- throws IOException {
- if (changed) {
- if (comments.isEmpty()) {
- commentsUtil.removeNote(noteMap, commitId);
- } else {
- commentsUtil.writeCommentsToNoteMap(noteMap, comments, inserter);
- }
- }
- }
-
public RevCommit commit() throws IOException {
BatchMetaDataUpdate batch = openUpdate();
try {
@@ -279,13 +257,11 @@
if (migration.writeChanges()) {
AtomicBoolean removedAllComments = new AtomicBoolean();
ObjectId treeId = storeCommentsInNotes(removedAllComments);
- if (treeId != null) {
- if (removedAllComments.get()) {
- batch.removeRef(getRefName());
- } else {
- builder.setTreeId(treeId);
- batch.write(builder);
- }
+ if (removedAllComments.get()) {
+ batch.removeRef(getRefName());
+ } else if (treeId != null) {
+ builder.setTreeId(treeId);
+ batch.write(builder);
}
}
}
@@ -308,7 +284,7 @@
}
commit.setAuthor(newIdent(getUser().getAccount(), when));
commit.setCommitter(new PersonIdent(serverIdent, when));
- commit.setMessage(String.format("Comment on patch set %d", psId.get()));
+ commit.setMessage("Update draft comments");
return true;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotes.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotes.java
index 8cb72e9..063ff5a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotes.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotes.java
@@ -15,18 +15,15 @@
package com.google.gerrit.server.notedb;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.GERRIT_PLACEHOLDER_HOST;
-import static com.google.gerrit.server.notedb.CommentsInNotesUtil.getCommentPsId;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
-import com.google.common.collect.ComparisonChain;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Ordering;
-import com.google.common.collect.Table;
import com.google.common.primitives.Ints;
import com.google.gerrit.common.data.SubmitRecord;
import com.google.gerrit.reviewdb.client.Account;
@@ -36,6 +33,7 @@
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.PatchSetApproval;
import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.RevId;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.AllUsersNameProvider;
import com.google.gerrit.server.git.GitRepositoryManager;
@@ -52,8 +50,6 @@
import java.io.IOException;
import java.sql.Timestamp;
-import java.util.Comparator;
-import java.util.List;
import java.util.Map;
/** View of a single {@link Change} based on the log of its notes branch. */
@@ -76,20 +72,6 @@
}
});
- public static Comparator<PatchLineComment> PLC_ORDER =
- new Comparator<PatchLineComment>() {
- @Override
- public int compare(PatchLineComment c1, PatchLineComment c2) {
- String filename1 = c1.getKey().getParentKey().get();
- String filename2 = c2.getKey().getParentKey().get();
- return ComparisonChain.start()
- .compare(filename1, filename2)
- .compare(c1.getLine(), c2.getLine())
- .compare(c1.getWrittenOn(), c2.getWrittenOn())
- .result();
- }
- };
-
public static ConfigInvalidException parseException(Change.Id changeId,
String fmt, Object... args) {
return new ConfigInvalidException("Change " + changeId + ": "
@@ -138,8 +120,7 @@
private ImmutableList<Account.Id> allPastReviewers;
private ImmutableList<SubmitRecord> submitRecords;
private ImmutableListMultimap<PatchSet.Id, ChangeMessage> changeMessages;
- private ImmutableListMultimap<PatchSet.Id, PatchLineComment> commentsForBase;
- private ImmutableListMultimap<PatchSet.Id, PatchLineComment> commentsForPS;
+ private ImmutableListMultimap<RevId, PatchLineComment> comments;
private ImmutableSet<String> hashtags;
NoteMap noteMap;
@@ -194,28 +175,15 @@
return changeMessages;
}
- /** @return inline comments on each patchset's base (side == 0). */
- public ImmutableListMultimap<PatchSet.Id, PatchLineComment>
- getBaseComments() {
- return commentsForBase;
+ /** @return inline comments on each revision. */
+ public ImmutableListMultimap<RevId, PatchLineComment> getComments() {
+ return comments;
}
- /** @return inline comments on each patchset (side == 1). */
- public ImmutableListMultimap<PatchSet.Id, PatchLineComment>
- getPatchSetComments() {
- return commentsForPS;
- }
-
- public Table<PatchSet.Id, String, PatchLineComment> getDraftBaseComments(
+ public ImmutableListMultimap<RevId, PatchLineComment> getDraftComments(
Account.Id author) throws OrmException {
loadDraftComments(author);
- return draftCommentNotes.getDraftBaseComments();
- }
-
- public Table<PatchSet.Id, String, PatchLineComment> getDraftPsComments(
- Account.Id author) throws OrmException {
- loadDraftComments(author);
- return draftCommentNotes.getDraftPsComments();
+ return draftCommentNotes.getComments();
}
/**
@@ -234,6 +202,11 @@
}
}
+ @VisibleForTesting
+ DraftCommentNotes getDraftCommentNotes() {
+ return draftCommentNotes;
+ }
+
public boolean containsComment(PatchLineComment c) throws OrmException {
if (containsCommentPublished(c)) {
return true;
@@ -243,11 +216,7 @@
}
public boolean containsCommentPublished(PatchLineComment c) {
- PatchSet.Id psId = getCommentPsId(c);
- List<PatchLineComment> list = (c.getSide() == (short) 0)
- ? getBaseComments().get(psId)
- : getPatchSetComments().get(psId);
- for (PatchLineComment l : list) {
+ for (PatchLineComment l : getComments().values()) {
if (c.getKey().equals(l.getKey())) {
return true;
}
@@ -282,8 +251,7 @@
}
approvals = parser.buildApprovals();
changeMessages = parser.buildMessages();
- commentsForBase = ImmutableListMultimap.copyOf(parser.commentsForBase);
- commentsForPS = ImmutableListMultimap.copyOf(parser.commentsForPs);
+ comments = ImmutableListMultimap.copyOf(parser.comments);
noteMap = parser.commentNoteMap;
if (parser.hashtags != null) {
@@ -310,8 +278,7 @@
reviewers = ImmutableSetMultimap.of();
submitRecords = ImmutableList.of();
changeMessages = ImmutableListMultimap.of();
- commentsForBase = ImmutableListMultimap.of();
- commentsForPS = ImmutableListMultimap.of();
+ comments = ImmutableListMultimap.of();
hashtags = ImmutableSet.of();
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotesParser.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotesParser.java
index b5b3c74..6f8cb2b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotesParser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotesParser.java
@@ -44,6 +44,7 @@
import com.google.gerrit.reviewdb.client.PatchLineComment;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.RevId;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.util.LabelVote;
@@ -72,8 +73,7 @@
final Map<Account.Id, ReviewerState> reviewers;
final List<Account.Id> allPastReviewers;
final List<SubmitRecord> submitRecords;
- final Multimap<PatchSet.Id, PatchLineComment> commentsForPs;
- final Multimap<PatchSet.Id, PatchLineComment> commentsForBase;
+ final Multimap<RevId, PatchLineComment> comments;
NoteMap commentNoteMap;
Change.Status status;
Set<String> hashtags;
@@ -99,8 +99,7 @@
allPastReviewers = Lists.newArrayList();
submitRecords = Lists.newArrayListWithExpectedSize(1);
changeMessages = LinkedListMultimap.create();
- commentsForPs = ArrayListMultimap.create();
- commentsForBase = ArrayListMultimap.create();
+ comments = ArrayListMultimap.create();
}
@Override
@@ -275,7 +274,7 @@
throws IOException, ConfigInvalidException {
commentNoteMap = CommentsInNotesUtil.parseCommentsFromNotes(repo,
ChangeNoteUtil.changeRefName(changeId), walk, changeId,
- commentsForBase, commentsForPs, PatchLineComment.Status.PUBLISHED);
+ comments, PatchLineComment.Status.PUBLISHED);
}
private void parseApproval(PatchSet.Id psId, Account.Id accountId,
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeRebuilder.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeRebuilder.java
index 76dfdc8..d715947 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeRebuilder.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeRebuilder.java
@@ -16,7 +16,6 @@
import static com.google.common.base.Preconditions.checkState;
import static com.google.gerrit.server.PatchLineCommentsUtil.setCommentRevId;
-import static com.google.gerrit.server.notedb.CommentsInNotesUtil.getCommentPsId;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ArrayListMultimap;
@@ -33,6 +32,7 @@
import com.google.gerrit.reviewdb.client.PatchSetApproval;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.PatchLineCommentsUtil;
import com.google.gerrit.server.git.VersionedMetaData.BatchMetaDataUpdate;
import com.google.gerrit.server.patch.PatchListCache;
import com.google.gerrit.server.project.ChangeControl;
@@ -306,7 +306,7 @@
PatchLineCommentEvent(PatchLineComment c, Change change, PatchSet ps,
PatchListCache cache) {
- super(getCommentPsId(c), c.getAuthor(), c.getWrittenOn());
+ super(PatchLineCommentsUtil.getCommentPsId(c), c.getAuthor(), c.getWrittenOn());
this.c = c;
this.change = change;
this.ps = ps;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeUpdate.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeUpdate.java
index 7302425..43c232b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeUpdate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeUpdate.java
@@ -20,7 +20,7 @@
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_PATCH_SET;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_STATUS;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_SUBMITTED_WITH;
-import static com.google.gerrit.server.notedb.CommentsInNotesUtil.getCommentPsId;
+import static com.google.gerrit.server.notedb.CommentsInNotesUtil.addCommentToMap;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
@@ -28,14 +28,13 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
-import com.google.common.collect.Multimap;
import com.google.gerrit.common.data.SubmitRecord;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchLineComment;
import com.google.gerrit.reviewdb.client.PatchLineComment.Status;
-import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.RevId;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.config.AnonymousCowardName;
@@ -57,6 +56,7 @@
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
@@ -91,8 +91,7 @@
private String subject;
private List<SubmitRecord> submitRecords;
private final CommentsInNotesUtil commentsUtil;
- private List<PatchLineComment> commentsForBase;
- private List<PatchLineComment> commentsForPs;
+ private List<PatchLineComment> comments;
private Set<String> hashtags;
private String changeMessage;
private ChangeNotes notes;
@@ -161,8 +160,7 @@
this.commentsUtil = commentsUtil;
this.approvals = Maps.newTreeMap(labelNameComparator);
this.reviewers = Maps.newLinkedHashMap();
- this.commentsForPs = Lists.newArrayList();
- this.commentsForBase = Lists.newArrayList();
+ this.comments = Lists.newArrayList();
}
public void setStatus(Change.Status status) {
@@ -238,15 +236,11 @@
"A comment already exists with the same key as the following comment,"
+ " so we cannot insert this comment: %s", c);
}
- if (c.getSide() == 0) {
- commentsForBase.add(c);
- } else {
- commentsForPs.add(c);
- }
+ comments.add(c);
}
private void insertDraftComment(PatchLineComment c) throws OrmException {
- createDraftUpdateIfNull(c);
+ createDraftUpdateIfNull();
draftUpdate.insertComment(c);
}
@@ -263,15 +257,11 @@
checkArgument(!notes.containsCommentPublished(c),
"Cannot update a comment that has already been published and saved");
}
- if (c.getSide() == 0) {
- commentsForBase.add(c);
- } else {
- commentsForPs.add(c);
- }
+ comments.add(c);
}
private void upsertDraftComment(PatchLineComment c) {
- createDraftUpdateIfNull(c);
+ createDraftUpdateIfNull();
draftUpdate.upsertComment(c);
}
@@ -286,46 +276,32 @@
checkArgument(!notes.containsCommentPublished(c),
"Cannot update a comment that has already been published and saved");
}
- if (c.getSide() == 0) {
- commentsForBase.add(c);
- } else {
- commentsForPs.add(c);
- }
+ comments.add(c);
}
private void updateDraftComment(PatchLineComment c) throws OrmException {
- createDraftUpdateIfNull(c);
+ createDraftUpdateIfNull();
draftUpdate.updateComment(c);
}
private void deleteDraftComment(PatchLineComment c) throws OrmException {
- createDraftUpdateIfNull(c);
+ createDraftUpdateIfNull();
draftUpdate.deleteComment(c);
}
private void deleteDraftCommentIfPresent(PatchLineComment c)
throws OrmException {
- createDraftUpdateIfNull(c);
+ createDraftUpdateIfNull();
draftUpdate.deleteCommentIfPresent(c);
}
- private void createDraftUpdateIfNull(PatchLineComment c) {
+ private void createDraftUpdateIfNull() {
if (draftUpdate == null) {
draftUpdate = draftUpdateFactory.create(ctl, when);
- if (psId != null) {
- draftUpdate.setPatchSetId(psId);
- } else {
- draftUpdate.setPatchSetId(getCommentPsId(c));
- }
}
}
private void verifyComment(PatchLineComment c) {
- checkArgument(psId != null,
- "setPatchSetId must be called first");
- checkArgument(getCommentPsId(c).equals(psId),
- "Comment on %s doesn't match previous patch set %s",
- getCommentPsId(c), psId);
checkArgument(c.getRevId() != null);
checkArgument(c.getStatus() == Status.PUBLISHED,
"Cannot add a draft comment to a ChangeUpdate. Use a ChangeDraftUpdate"
@@ -356,31 +332,23 @@
if (noteMap == null) {
noteMap = NoteMap.newEmptyMap();
}
- if (commentsForPs.isEmpty() && commentsForBase.isEmpty()) {
+ if (comments.isEmpty()) {
return null;
}
- Multimap<PatchSet.Id, PatchLineComment> allCommentsOnBases =
- notes.getBaseComments();
- Multimap<PatchSet.Id, PatchLineComment> allCommentsOnPs =
- notes.getPatchSetComments();
-
- // This writes all comments for the base of this PS to the note map.
- if (!commentsForBase.isEmpty()) {
- List<PatchLineComment> baseCommentsForThisPs =
- new ArrayList<>(allCommentsOnBases.get(psId));
- baseCommentsForThisPs.addAll(commentsForBase);
- commentsUtil.writeCommentsToNoteMap(noteMap, baseCommentsForThisPs,
- inserter);
+ Map<RevId, List<PatchLineComment>> allComments = Maps.newHashMap();
+ for (Map.Entry<RevId, Collection<PatchLineComment>> e
+ : notes.getComments().asMap().entrySet()) {
+ List<PatchLineComment> comments = new ArrayList<>();
+ for (PatchLineComment c : e.getValue()) {
+ comments.add(c);
+ }
+ allComments.put(e.getKey(), comments);
}
-
- // This write all comments for this PS to the note map.
- if (!commentsForPs.isEmpty()) {
- List<PatchLineComment> commentsForThisPs =
- new ArrayList<>(allCommentsOnPs.get(psId));
- commentsForThisPs.addAll(commentsForPs);
- commentsUtil.writeCommentsToNoteMap(noteMap, commentsForThisPs, inserter);
+ for (PatchLineComment c : comments) {
+ addCommentToMap(allComments, c);
}
+ commentsUtil.writeCommentsToNoteMap(noteMap, allComments, inserter);
return noteMap.writeTree(inserter);
}
@@ -504,8 +472,7 @@
private boolean isEmpty() {
return approvals.isEmpty()
&& changeMessage == null
- && commentsForBase.isEmpty()
- && commentsForPs.isEmpty()
+ && comments.isEmpty()
&& reviewers.isEmpty()
&& status == null
&& subject == null
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/CommentsInNotesUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/CommentsInNotesUtil.java
index f3e03c0..149325d9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/CommentsInNotesUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/CommentsInNotesUtil.java
@@ -15,6 +15,7 @@
package com.google.gerrit.server.notedb;
import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.gerrit.server.PatchLineCommentsUtil.PLC_ORDER;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.GERRIT_PLACEHOLDER_HOST;
import static com.google.gerrit.server.notedb.ChangeNotes.parseException;
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -33,6 +34,7 @@
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.RevId;
import com.google.gerrit.server.GerritPersonIdent;
+import com.google.gerrit.server.PatchLineCommentsUtil;
import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.config.AnonymousCowardName;
import com.google.inject.Inject;
@@ -63,9 +65,11 @@
import java.nio.charset.Charset;
import java.sql.Timestamp;
import java.text.ParseException;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
+import java.util.Map;
/**
* Utility functions to parse PatchLineComments out of a note byte array and
@@ -86,8 +90,7 @@
public static NoteMap parseCommentsFromNotes(Repository repo, String refName,
RevWalk walk, Change.Id changeId,
- Multimap<PatchSet.Id, PatchLineComment> commentsForBase,
- Multimap<PatchSet.Id, PatchLineComment> commentsForPs,
+ Multimap<RevId, PatchLineComment> comments,
Status status)
throws IOException, ConfigInvalidException {
Ref ref = repo.getRef(refName);
@@ -99,20 +102,14 @@
RevCommit commit = walk.parseCommit(ref.getObjectId());
NoteMap noteMap = NoteMap.read(reader, commit);
- for (Note note: noteMap) {
+ for (Note note : noteMap) {
byte[] bytes =
reader.open(note.getData(), OBJ_BLOB).getCachedBytes(MAX_NOTE_SZ);
List<PatchLineComment> result = parseNote(bytes, changeId, status);
if (result == null || result.isEmpty()) {
continue;
}
- PatchSet.Id psId = result.get(0).getKey().getParentKey().getParentKey();
- short side = result.get(0).getSide();
- if (side == 0) {
- commentsForBase.putAll(psId, result);
- } else {
- commentsForPs.putAll(psId, result);
- }
+ comments.putAll(new RevId(note.name()), result);
}
return noteMap;
}
@@ -152,10 +149,6 @@
return dateFormatter.formatDate(newIdent);
}
- public static PatchSet.Id getCommentPsId(PatchLineComment plc) {
- return plc.getKey().getParentKey().getParentKey();
- }
-
private static PatchLineComment parseComment(byte[] note, MutableInteger curr,
String currentFileName, PatchSet.Id psId, RevId revId, boolean isForBase,
Charset enc, Status status)
@@ -449,7 +442,7 @@
PatchLineComment first = comments.get(0);
short side = first.getSide();
- PatchSet.Id psId = getCommentPsId(first);
+ PatchSet.Id psId = PatchLineCommentsUtil.getCommentPsId(first);
appendHeaderField(writer, side == 0
? BASE_PATCH_SET
: PATCH_SET,
@@ -459,7 +452,7 @@
String currentFilename = null;
for (PatchLineComment c : comments) {
- PatchSet.Id currentPsId = getCommentPsId(c);
+ PatchSet.Id currentPsId = PatchLineCommentsUtil.getCommentPsId(c);
checkArgument(psId.equals(currentPsId),
"All comments being added must all have the same PatchSet.Id. The"
+ "comment below does not have the same PatchSet.Id as the others "
@@ -524,19 +517,47 @@
return buf.toByteArray();
}
+ /**
+ * Write comments for multiple revisions to a note map.
+ * <p>
+ * Mutates the map in-place. only notes for SHA-1s found as keys in the map
+ * are modified; all other notes are left untouched.
+ *
+ * @param noteMap note map to modify.
+ * @param allComments map of revision to all comments for that revision;
+ * callers are responsible for reading the original comments and applying
+ * any changes. Differs from a multimap in that present-but-empty values
+ * are significant, and indicate the note for that SHA-1 should be
+ * deleted.
+ * @param inserter object inserter for writing notes.
+ * @throws IOException if an error occurred.
+ */
public void writeCommentsToNoteMap(NoteMap noteMap,
- List<PatchLineComment> allComments, ObjectInserter inserter)
- throws IOException {
- checkArgument(!allComments.isEmpty(),
- "No comments to write; to delete, use removeNoteFromNoteMap().");
- ObjectId commit =
- ObjectId.fromString(allComments.get(0).getRevId().get());
- Collections.sort(allComments, ChangeNotes.PLC_ORDER);
- noteMap.set(commit, inserter.insert(OBJ_BLOB, buildNote(allComments)));
+ Map<RevId, List<PatchLineComment>> allComments, ObjectInserter inserter)
+ throws IOException {
+ for (Map.Entry<RevId, List<PatchLineComment>> e : allComments.entrySet()) {
+ List<PatchLineComment> comments = e.getValue();
+ ObjectId commit = ObjectId.fromString(e.getKey().get());
+ if (comments.isEmpty()) {
+ noteMap.remove(commit);
+ continue;
+ }
+ Collections.sort(comments, PLC_ORDER);
+ // We allow comments for multiple commits to be written in the same
+ // update, even though the rest of the metadata update is associated with
+ // a single patch set.
+ noteMap.set(commit, inserter.insert(OBJ_BLOB, buildNote(comments)));
+ }
}
- public void removeNote(NoteMap noteMap, RevId commitId)
- throws IOException {
- noteMap.remove(ObjectId.fromString(commitId.get()));
+ static void addCommentToMap(Map<RevId, List<PatchLineComment>> map,
+ PatchLineComment c) {
+ List<PatchLineComment> list = map.get(c.getRevId());
+ if (list == null) {
+ list = new ArrayList<>();
+ map.put(c.getRevId(), list);
+ }
+ list.add(c);
}
+
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/DraftCommentNotes.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/DraftCommentNotes.java
index 20d6c4a..a02c24d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/DraftCommentNotes.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/DraftCommentNotes.java
@@ -14,18 +14,14 @@
package com.google.gerrit.server.notedb;
-import static com.google.gerrit.server.notedb.CommentsInNotesUtil.getCommentPsId;
-
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.HashBasedTable;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Table;
+import com.google.common.collect.ImmutableListMultimap;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchLineComment;
-import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames;
+import com.google.gerrit.reviewdb.client.RevId;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.AllUsersNameProvider;
import com.google.gerrit.server.git.GitRepositoryManager;
@@ -70,8 +66,7 @@
private final AllUsersName draftsProject;
private final Account.Id author;
- private final Table<PatchSet.Id, String, PatchLineComment> draftBaseComments;
- private final Table<PatchSet.Id, String, PatchLineComment> draftPsComments;
+ private ImmutableListMultimap<RevId, PatchLineComment> comments;
private NoteMap noteMap;
DraftCommentNotes(GitRepositoryManager repoManager, NotesMigration migration,
@@ -79,9 +74,6 @@
super(repoManager, migration, changeId);
this.draftsProject = draftsProject;
this.author = author;
-
- this.draftBaseComments = HashBasedTable.create();
- this.draftPsComments = HashBasedTable.create();
}
public NoteMap getNoteMap() {
@@ -92,32 +84,18 @@
return author;
}
- /**
- * @return a defensive copy of the table containing all draft comments
- * on this change with side == 0. The row key is the comment's PatchSet.Id,
- * the column key is the comment's UUID, and the value is the comment.
- */
- public Table<PatchSet.Id, String, PatchLineComment>
- getDraftBaseComments() {
- return HashBasedTable.create(draftBaseComments);
- }
-
- /**
- * @return a defensive copy of the table containing all draft comments
- * on this change with side == 1. The row key is the comment's PatchSet.Id,
- * the column key is the comment's UUID, and the value is the comment.
- */
- public Table<PatchSet.Id, String, PatchLineComment>
- getDraftPsComments() {
- return HashBasedTable.create(draftPsComments);
+ public ImmutableListMultimap<RevId, PatchLineComment> getComments() {
+ // TODO(dborowitz): Defensive copy?
+ return comments;
}
public boolean containsComment(PatchLineComment c) {
- Table<PatchSet.Id, String, PatchLineComment> t =
- c.getSide() == (short) 0
- ? getDraftBaseComments()
- : getDraftPsComments();
- return t.contains(getCommentPsId(c), c.getKey().get());
+ for (PatchLineComment existing : comments.values()) {
+ if (c.getKey().equals(existing.getKey())) {
+ return true;
+ }
+ }
+ return false;
}
@Override
@@ -129,6 +107,7 @@
protected void onLoad() throws IOException, ConfigInvalidException {
ObjectId rev = getRevision();
if (rev == null) {
+ loadDefaults();
return;
}
@@ -137,8 +116,7 @@
getChangeId(), walk, rev, repoManager, draftsProject, author)) {
parser.parseDraftComments();
- buildCommentTable(draftBaseComments, parser.draftBaseComments);
- buildCommentTable(draftPsComments, parser.draftPsComments);
+ comments = ImmutableListMultimap.copyOf(parser.comments);
noteMap = parser.noteMap;
}
}
@@ -152,20 +130,11 @@
@Override
protected void loadDefaults() {
- // Do nothing; tables are final and initialized in constructor.
+ comments = ImmutableListMultimap.of();
}
@Override
protected Project.NameKey getProjectName() {
return draftsProject;
}
-
- private void buildCommentTable(
- Table<PatchSet.Id, String, PatchLineComment> commentTable,
- Multimap<PatchSet.Id, PatchLineComment> allComments) {
- for (PatchLineComment c : allComments.values()) {
- commentTable.put(getCommentPsId(c), c.getKey().get(), c);
- }
- }
-
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/DraftCommentNotesParser.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/DraftCommentNotesParser.java
index 4b3fbdf..ef8683f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/DraftCommentNotesParser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/DraftCommentNotesParser.java
@@ -19,8 +19,8 @@
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchLineComment;
-import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.RefNames;
+import com.google.gerrit.reviewdb.client.RevId;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.git.GitRepositoryManager;
@@ -34,8 +34,7 @@
import java.io.IOException;
class DraftCommentNotesParser implements AutoCloseable {
- final Multimap<PatchSet.Id, PatchLineComment> draftBaseComments;
- final Multimap<PatchSet.Id, PatchLineComment> draftPsComments;
+ final Multimap<RevId, PatchLineComment> comments;
NoteMap noteMap;
private final Change.Id changeId;
@@ -53,8 +52,7 @@
this.repo = repoManager.openMetadataRepository(draftsProject);
this.author = author;
- draftBaseComments = ArrayListMultimap.create();
- draftPsComments = ArrayListMultimap.create();
+ comments = ArrayListMultimap.create();
}
@Override
@@ -66,7 +64,6 @@
walk.markStart(walk.parseCommit(tip));
noteMap = CommentsInNotesUtil.parseCommentsFromNotes(repo,
RefNames.refsDraftComments(author, changeId),
- walk, changeId, draftBaseComments,
- draftPsComments, PatchLineComment.Status.DRAFT);
+ walk, changeId, comments, PatchLineComment.Status.DRAFT);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListLoader.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListLoader.java
index 40a51aa..b8caa62 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListLoader.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListLoader.java
@@ -87,6 +87,7 @@
private final ExecutorService diffExecutor;
private final long timeoutMillis;
+
@Inject
PatchListLoader(GitRepositoryManager mgr,
PatchListCache plc,
@@ -337,7 +338,7 @@
}
@Override
- public void release() {
+ public void close() {
}
});
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptBuilder.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
index ea427eb..5b70730 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
@@ -177,7 +177,7 @@
boolean hugeFile = false;
if (a.mode == FileMode.GITLINK || b.mode == FileMode.GITLINK) {
-
+ // Do nothing
} else if (a.src == b.src && a.size() <= context
&& content.getEdits().isEmpty()) {
// Odd special case; the files are identical (100% rename or copy)
@@ -214,7 +214,9 @@
a.displayMethod, b.displayMethod, a.mimeType.toString(),
b.mimeType.toString(), comments, history, hugeFile,
intralineDifferenceIsPossible, intralineFailure, intralineTimeout,
- content.getPatchType() == Patch.PatchType.BINARY);
+ content.getPatchType() == Patch.PatchType.BINARY,
+ aId == null ? null : aId.getName(),
+ bId == null ? null : bId.getName());
}
private static boolean isModify(PatchListEntry content) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/CleanupHandle.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/CleanupHandle.java
index 593f2c9..9827812 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/CleanupHandle.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/CleanupHandle.java
@@ -14,17 +14,17 @@
package com.google.gerrit.server.plugins;
-import java.io.File;
import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.jar.JarFile;
class CleanupHandle {
- private final File tmpFile;
+ private final Path tmp;
private final JarFile jarFile;
- CleanupHandle(File tmpFile,
- JarFile jarFile) {
- this.tmpFile = tmpFile;
+ CleanupHandle(Path tmp, JarFile jarFile) {
+ this.tmp = tmp;
this.jarFile = jarFile;
}
@@ -34,12 +34,13 @@
} catch (IOException err) {
PluginLoader.log.error("Cannot close " + jarFile.getName(), err);
}
- if (!tmpFile.delete() && tmpFile.exists()) {
- PluginLoader.log.warn("Cannot delete " + tmpFile.getAbsolutePath()
- + ", retrying to delete it on termination of the virtual machine");
- tmpFile.deleteOnExit();
- } else {
- PluginLoader.log.info("Cleaned plugin " + tmpFile.getName());
+ try {
+ Files.deleteIfExists(tmp);
+ PluginLoader.log.info("Cleaned plugin " + tmp.getFileName());
+ } catch (IOException e) {
+ PluginLoader.log.warn("Cannot delete " + tmp.toAbsolutePath()
+ + ", retrying to delete it on termination of the virtual machine", e);
+ tmp.toFile().deleteOnExit();
}
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/CopyConfigModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/CopyConfigModule.java
index 7252617..1d4233a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/CopyConfigModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/CopyConfigModule.java
@@ -33,7 +33,7 @@
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.PersonIdent;
-import java.io.File;
+import java.nio.file.Path;
/**
* Copies critical objects from the {@code dbInjector} into a plugin.
@@ -47,11 +47,11 @@
class CopyConfigModule extends AbstractModule {
@Inject
@SitePath
- private File sitePath;
+ private Path sitePath;
@Provides
@SitePath
- File getSitePath() {
+ Path getSitePath() {
return sitePath;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/JarPluginProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/JarPluginProvider.java
index 3406080..926ef44 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/JarPluginProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/JarPluginProvider.java
@@ -24,13 +24,14 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
@@ -43,7 +44,7 @@
static final String JAR_EXTENSION = ".jar";
static final Logger log = LoggerFactory.getLogger(JarPluginProvider.class);
- private final File tmpDir;
+ private final Path tmpDir;
@Inject
JarPluginProvider(SitePaths sitePaths) {
@@ -51,42 +52,42 @@
}
@Override
- public boolean handles(File srcFile) {
- String fileName = srcFile.getName();
+ public boolean handles(Path srcPath) {
+ String fileName = srcPath.getFileName().toString();
return fileName.endsWith(JAR_EXTENSION)
|| fileName.endsWith(JAR_EXTENSION + ".disabled");
}
@Override
- public String getPluginName(File srcFile) {
+ public String getPluginName(Path srcPath) {
try {
- return MoreObjects.firstNonNull(getJarPluginName(srcFile),
- PluginLoader.nameOf(srcFile));
+ return MoreObjects.firstNonNull(getJarPluginName(srcPath),
+ PluginLoader.nameOf(srcPath));
} catch (IOException e) {
- throw new IllegalArgumentException("Invalid plugin file " + srcFile
+ throw new IllegalArgumentException("Invalid plugin file " + srcPath
+ ": cannot get plugin name", e);
}
}
- public static String getJarPluginName(File srcFile) throws IOException {
- try (JarFile jarFile = new JarFile(srcFile)) {
+ public static String getJarPluginName(Path srcPath) throws IOException {
+ try (JarFile jarFile = new JarFile(srcPath.toFile())) {
return jarFile.getManifest().getMainAttributes()
.getValue("Gerrit-PluginName");
}
}
@Override
- public ServerPlugin get(File srcFile, FileSnapshot snapshot,
+ public ServerPlugin get(Path srcPath, FileSnapshot snapshot,
PluginDescription description) throws InvalidPluginException {
try {
- String name = getPluginName(srcFile);
- String extension = getExtension(srcFile);
- try (FileInputStream in = new FileInputStream(srcFile)) {
- File tmp = asTemp(in, tempNameFor(name), extension, tmpDir);
- return loadJarPlugin(name, srcFile, snapshot, tmp, description);
+ String name = getPluginName(srcPath);
+ String extension = getExtension(srcPath);
+ try (InputStream in = Files.newInputStream(srcPath)) {
+ Path tmp = asTemp(in, tempNameFor(name), extension, tmpDir);
+ return loadJarPlugin(name, srcPath, snapshot, tmp, description);
}
} catch (IOException e) {
- throw new InvalidPluginException("Cannot load Jar plugin " + srcFile, e);
+ throw new InvalidPluginException("Cannot load Jar plugin " + srcPath, e);
}
}
@@ -95,8 +96,8 @@
return "gerrit";
}
- private static String getExtension(File file) {
- return getExtension(file.getName());
+ private static String getExtension(Path path) {
+ return getExtension(path.getFileName().toString());
}
private static String getExtension(String name) {
@@ -109,18 +110,18 @@
return PLUGIN_TMP_PREFIX + name + "_" + fmt.format(new Date()) + "_";
}
- public static File storeInTemp(String pluginName, InputStream in,
+ public static Path storeInTemp(String pluginName, InputStream in,
SitePaths sitePaths) throws IOException {
- if (!sitePaths.tmp_dir.exists()) {
- sitePaths.tmp_dir.mkdirs();
+ if (!Files.exists(sitePaths.tmp_dir)) {
+ Files.createDirectories(sitePaths.tmp_dir);
}
return asTemp(in, tempNameFor(pluginName), ".jar", sitePaths.tmp_dir);
}
- private ServerPlugin loadJarPlugin(String name, File srcJar,
- FileSnapshot snapshot, File tmp, PluginDescription description)
+ private ServerPlugin loadJarPlugin(String name, Path srcJar,
+ FileSnapshot snapshot, Path tmp, PluginDescription description)
throws IOException, InvalidPluginException, MalformedURLException {
- JarFile jarFile = new JarFile(tmp);
+ JarFile jarFile = new JarFile(tmp.toFile());
boolean keep = false;
try {
Manifest manifest = jarFile.getManifest();
@@ -129,24 +130,22 @@
List<URL> urls = new ArrayList<>(2);
String overlay = System.getProperty("gerrit.plugin-classes");
if (overlay != null) {
- File classes = new File(new File(new File(overlay), name), "main");
- if (classes.isDirectory()) {
- log.info(String.format("plugin %s: including %s", name,
- classes.getPath()));
- urls.add(classes.toURI().toURL());
+ Path classes = Paths.get(overlay).resolve(name).resolve("main");
+ if (Files.isDirectory(classes)) {
+ log.info(String.format("plugin %s: including %s", name, classes));
+ urls.add(classes.toUri().toURL());
}
}
- urls.add(tmp.toURI().toURL());
+ urls.add(tmp.toUri().toURL());
ClassLoader pluginLoader =
new URLClassLoader(urls.toArray(new URL[urls.size()]),
PluginLoader.parentFor(type));
JarScanner jarScanner = createJarScanner(tmp);
- ServerPlugin plugin =
- new ServerPlugin(name, description.canonicalUrl, description.user,
- srcJar, snapshot, jarScanner, description.dataDir,
- pluginLoader);
+ ServerPlugin plugin = new ServerPlugin(name, description.canonicalUrl,
+ description.user, srcJar, snapshot, jarScanner,
+ description.dataDir, pluginLoader);
plugin.setCleanupHandle(new CleanupHandle(tmp, jarFile));
keep = true;
return plugin;
@@ -157,7 +156,7 @@
}
}
- private JarScanner createJarScanner(File srcJar)
+ private JarScanner createJarScanner(Path srcJar)
throws InvalidPluginException {
try {
return new JarScanner(srcJar);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/JarScanner.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/JarScanner.java
index a8600fe..0f4aa6c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/JarScanner.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/JarScanner.java
@@ -39,10 +39,10 @@
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
-import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -69,8 +69,8 @@
private final JarFile jarFile;
- public JarScanner(File srcFile) throws IOException {
- this.jarFile = new JarFile(srcFile);
+ public JarScanner(Path src) throws IOException {
+ this.jarFile = new JarFile(src.toFile());
}
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/JsPlugin.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/JsPlugin.java
index 63f69b5..8da8cc1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/JsPlugin.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/JsPlugin.java
@@ -27,12 +27,12 @@
import org.eclipse.jgit.internal.storage.file.FileSnapshot;
-import java.io.File;
+import java.nio.file.Path;
class JsPlugin extends Plugin {
private Injector httpInjector;
- JsPlugin(String name, File srcFile, PluginUser pluginUser,
+ JsPlugin(String name, Path srcFile, PluginUser pluginUser,
FileSnapshot snapshot) {
super(name, srcFile, pluginUser, snapshot, ApiType.JS);
}
@@ -40,7 +40,7 @@
@Override
@Nullable
public String getVersion() {
- String fileName = getSrcFile().getName();
+ String fileName = getSrcFile().getFileName().toString();
int firstDash = fileName.indexOf("-");
if (firstDash > 0) {
return fileName.substring(firstDash + 1, fileName.lastIndexOf(".js"));
@@ -51,7 +51,7 @@
@Override
public void start(PluginGuiceEnvironment env) throws Exception {
manager = new LifecycleManager();
- String fileName = getSrcFile().getName();
+ String fileName = getSrcFile().getFileName().toString();
httpInjector =
Guice.createInjector(new StandaloneJsPluginModule(getName(), fileName));
manager.start();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ListPlugins.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ListPlugins.java
index 54f05f0..1d717ef 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ListPlugins.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ListPlugins.java
@@ -90,7 +90,7 @@
stdout.format("%-30s %-10s %-8s %s\n", p.getName(),
Strings.nullToEmpty(info.version),
p.isDisabled() ? "DISABLED" : "ENABLED",
- p.getSrcFile().getName());
+ p.getSrcFile().getFileName());
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/MultipleProvidersForPluginException.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/MultipleProvidersForPluginException.java
index 82a6ad9..cf38310 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/MultipleProvidersForPluginException.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/MultipleProvidersForPluginException.java
@@ -18,14 +18,14 @@
import com.google.common.base.Joiner;
import com.google.common.collect.Iterables;
-import java.io.File;
+import java.nio.file.Path;
class MultipleProvidersForPluginException extends IllegalArgumentException {
private static final long serialVersionUID = 1L;
- MultipleProvidersForPluginException(File pluginSrcFile,
+ MultipleProvidersForPluginException(Path pluginSrcPath,
Iterable<ServerPluginProvider> providersHandlers) {
- super(pluginSrcFile.getAbsolutePath()
+ super(pluginSrcPath.toAbsolutePath()
+ " is claimed to be handled by more than one plugin provider: "
+ providersListToString(providersHandlers));
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/Plugin.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/Plugin.java
index b227909..6b84c21 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/Plugin.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/Plugin.java
@@ -14,6 +14,8 @@
package com.google.gerrit.server.plugins;
+import static com.google.gerrit.common.FileUtil.lastModified;
+
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.gerrit.common.Nullable;
@@ -25,7 +27,7 @@
import org.eclipse.jgit.internal.storage.file.FileSnapshot;
-import java.io.File;
+import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.jar.Attributes;
@@ -67,7 +69,7 @@
}
private final String name;
- private final File srcFile;
+ private final Path srcFile;
private final ApiType apiType;
private final boolean disabled;
private final CacheKey cacheKey;
@@ -80,17 +82,17 @@
private List<ReloadableRegistrationHandle<?>> reloadableHandles;
public Plugin(String name,
- File srcFile,
+ Path srcPath,
PluginUser pluginUser,
FileSnapshot snapshot,
ApiType apiType) {
this.name = name;
- this.srcFile = srcFile;
+ this.srcFile = srcPath;
this.apiType = apiType;
this.snapshot = snapshot;
this.pluginUser = pluginUser;
this.cacheKey = new Plugin.CacheKey(name);
- this.disabled = srcFile.getName().endsWith(".disabled");
+ this.disabled = srcPath.getFileName().toString().endsWith(".disabled");
}
public CleanupHandle getCleanupHandle() {
@@ -105,7 +107,7 @@
return pluginUser;
}
- public File getSrcFile() {
+ public Path getSrcFile() {
return srcFile;
}
@@ -168,7 +170,7 @@
abstract boolean canReload();
- boolean isModified(File jar) {
- return snapshot.lastModified() != jar.lastModified();
+ boolean isModified(Path jar) {
+ return snapshot.lastModified() != lastModified(jar);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginContentScanner.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginContentScanner.java
index 0228509..1d9cd0e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginContentScanner.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginContentScanner.java
@@ -11,14 +11,15 @@
// 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.
+
package com.google.gerrit.server.plugins;
import com.google.common.base.Optional;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
+import java.nio.file.NoSuchFileException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Map;
@@ -57,7 +58,7 @@
@Override
public InputStream getInputStream(PluginEntry entry) throws IOException {
- throw new FileNotFoundException("Empty plugin");
+ throw new NoSuchFileException("Empty plugin");
}
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginEntry.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginEntry.java
index 7242e98..74ded73 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginEntry.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginEntry.java
@@ -23,7 +23,7 @@
* Plugin static resource entry
*
* Bean representing a static resource inside a plugin.
- * All static resources are available at <plugin web url>/static
+ * All static resources are available at {@code <plugin web url>/static}
* and served by the HttpPluginServlet.
*/
public class PluginEntry {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginGuiceEnvironment.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginGuiceEnvironment.java
index 3fbbfa9..2887a00 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginGuiceEnvironment.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginGuiceEnvironment.java
@@ -518,10 +518,12 @@
bindings.remove(Key.get(Injector.class));
bindings.remove(Key.get(java.util.logging.Logger.class));
- final @Nullable Binding<HttpServletRequest> requestBinding =
+ @Nullable
+ final Binding<HttpServletRequest> requestBinding =
src.getExistingBinding(Key.get(HttpServletRequest.class));
- final @Nullable Binding<HttpServletResponse> responseBinding =
+ @Nullable
+ final Binding<HttpServletResponse> responseBinding =
src.getExistingBinding(Key.get(HttpServletResponse.class));
return new AbstractModule() {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginLoader.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginLoader.java
index b51359d..4e651c2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginLoader.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginLoader.java
@@ -18,6 +18,8 @@
import com.google.common.base.Joiner;
import com.google.common.base.MoreObjects;
import com.google.common.base.Predicate;
+import com.google.common.collect.ComparisonChain;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Lists;
@@ -25,6 +27,7 @@
import com.google.common.collect.Multimap;
import com.google.common.collect.Queues;
import com.google.common.collect.Sets;
+import com.google.common.io.ByteStreams;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.extensions.systemstatus.ServerInformation;
@@ -45,14 +48,15 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.File;
-import java.io.FileFilter;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.AbstractMap;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
@@ -71,13 +75,13 @@
static final String PLUGIN_TMP_PREFIX = "plugin_";
static final Logger log = LoggerFactory.getLogger(PluginLoader.class);
- public String getPluginName(File srcFile) {
- return MoreObjects.firstNonNull(getGerritPluginName(srcFile),
- nameOf(srcFile));
+ public String getPluginName(Path srcPath) {
+ return MoreObjects.firstNonNull(getGerritPluginName(srcPath),
+ nameOf(srcPath));
}
- private final File pluginsDir;
- private final File dataDir;
+ private final Path pluginsDir;
+ private final Path dataDir;
private final PluginGuiceEnvironment env;
private final ServerInformationImpl srvInfoImpl;
private final PluginUser.Factory pluginUserFactory;
@@ -158,7 +162,7 @@
checkRemoteInstall();
String fileName = originalName;
- File tmp = asTemp(in, ".next_" + fileName + "_", ".tmp", pluginsDir);
+ Path tmp = asTemp(in, ".next_" + fileName + "_", ".tmp", pluginsDir);
String name = MoreObjects.firstNonNull(getGerritPluginName(tmp),
nameOf(fileName));
if (!originalName.equals(name)) {
@@ -168,26 +172,26 @@
}
String fileExtension = getExtension(fileName);
- File dst = new File(pluginsDir, name + fileExtension);
+ Path dst = pluginsDir.resolve(name + fileExtension);
synchronized (this) {
Plugin active = running.get(name);
if (active != null) {
- fileName = active.getSrcFile().getName();
+ fileName = active.getSrcFile().getFileName().toString();
log.info(String.format("Replacing plugin %s", active.getName()));
- File old = new File(pluginsDir, ".last_" + fileName);
- old.delete();
- active.getSrcFile().renameTo(old);
+ Path old = pluginsDir.resolve(".last_" + fileName);
+ Files.deleteIfExists(old);
+ Files.move(active.getSrcFile(), old);
}
- new File(pluginsDir, fileName + ".disabled").delete();
- tmp.renameTo(dst);
+ Files.deleteIfExists(pluginsDir.resolve(fileName + ".disabled"));
+ Files.move(tmp, dst);
try {
Plugin plugin = runPlugin(name, dst, active);
if (active == null) {
log.info(String.format("Installed plugin %s", plugin.getName()));
}
} catch (PluginInstallException e) {
- dst.delete();
+ Files.deleteIfExists(dst);
throw e;
}
@@ -195,21 +199,17 @@
}
}
- static File asTemp(InputStream in, String prefix, String suffix, File dir)
+ static Path asTemp(InputStream in, String prefix, String suffix, Path dir)
throws IOException {
- File tmp = File.createTempFile(prefix, suffix, dir);
+ Path tmp = Files.createTempFile(dir, prefix, suffix);
boolean keep = false;
- try (FileOutputStream out = new FileOutputStream(tmp)) {
- byte[] data = new byte[8192];
- int n;
- while ((n = in.read(data)) > 0) {
- out.write(data, 0, n);
- }
+ try (OutputStream out = Files.newOutputStream(tmp)) {
+ ByteStreams.copy(in, out);
keep = true;
return tmp;
} finally {
if (!keep) {
- tmp.delete();
+ Files.delete(tmp);
}
}
}
@@ -217,7 +217,8 @@
private synchronized void unloadPlugin(Plugin plugin) {
persistentCacheFactory.onStop(plugin);
String name = plugin.getName();
- log.info(String.format("Unloading plugin %s", name));
+ log.info(String.format("Unloading plugin %s, version %s",
+ name, plugin.getVersion()));
plugin.stop(env);
env.onStopPlugin(plugin);
running.remove(name);
@@ -240,12 +241,21 @@
}
log.info(String.format("Disabling plugin %s", active.getName()));
- File off = new File(active.getSrcFile() + ".disabled");
- active.getSrcFile().renameTo(off);
+ Path off = active.getSrcFile().resolveSibling(
+ active.getSrcFile().getFileName() + ".disabled");
+ try {
+ Files.move(active.getSrcFile(), off);
+ } catch (IOException e) {
+ log.error("Failed to disable plugin", e);
+ // In theory we could still unload the plugin even if the rename
+ // failed. However, it would be reloaded on the next server startup,
+ // which is probably not what the user expects.
+ continue;
+ }
unloadPlugin(active);
try {
- FileSnapshot snapshot = FileSnapshot.save(off);
+ FileSnapshot snapshot = FileSnapshot.save(off.toFile());
Plugin offPlugin = loadPlugin(name, off, snapshot);
disabled.put(name, offPlugin);
} catch (Throwable e) {
@@ -274,13 +284,17 @@
}
log.info(String.format("Enabling plugin %s", name));
- String n = off.getSrcFile().getName();
+ String n = off.getSrcFile().toFile().getName();
if (n.endsWith(".disabled")) {
n = n.substring(0, n.lastIndexOf('.'));
}
- File on = new File(pluginsDir, n);
- off.getSrcFile().renameTo(on);
-
+ Path on = pluginsDir.resolve(n);
+ try {
+ Files.move(off.getSrcFile(), on);
+ } catch (IOException e) {
+ log.error("Failed to move plugin " + name + " into place", e);
+ continue;
+ }
disabled.remove(name);
runPlugin(name, on, null);
}
@@ -290,7 +304,7 @@
@Override
public synchronized void start() {
- log.info("Loading plugins from " + pluginsDir.getAbsolutePath());
+ log.info("Loading plugins from " + pluginsDir.toAbsolutePath());
srvInfoImpl.state = ServerInformation.State.STARTUP;
rescan();
srvInfoImpl.state = ServerInformation.State.RUNNING;
@@ -342,7 +356,9 @@
String name = active.getName();
try {
log.info(String.format("Reloading plugin %s", name));
- runPlugin(name, active.getSrcFile(), active);
+ Plugin newPlugin = runPlugin(name, active.getSrcFile(), active);
+ log.info(String.format("Reloaded plugin %s, version %s",
+ newPlugin.getName(), newPlugin.getVersion()));
} catch (PluginInstallException e) {
log.warn(String.format("Cannot reload plugin %s", name), e.getCause());
throw e;
@@ -354,42 +370,42 @@
}
public synchronized void rescan() {
- Multimap<String, File> pluginsFiles = prunePlugins(pluginsDir);
+ Multimap<String, Path> pluginsFiles = prunePlugins(pluginsDir);
if (pluginsFiles.isEmpty()) {
return;
}
syncDisabledPlugins(pluginsFiles);
- Map<String, File> activePlugins = filterDisabled(pluginsFiles);
- for (Map.Entry<String, File> entry : jarsFirstSortedPluginsSet(activePlugins)) {
+ Map<String, Path> activePlugins = filterDisabled(pluginsFiles);
+ for (Map.Entry<String, Path> entry : jarsFirstSortedPluginsSet(activePlugins)) {
String name = entry.getKey();
- File file = entry.getValue();
- String fileName = file.getName();
- if (!isJsPlugin(fileName) && !serverPluginFactory.handles(file)) {
+ Path path = entry.getValue();
+ String fileName = path.getFileName().toString();
+ if (!isJsPlugin(fileName) && !serverPluginFactory.handles(path)) {
log.warn("No Plugin provider was found that handles this file format: {}", fileName);
continue;
}
FileSnapshot brokenTime = broken.get(name);
- if (brokenTime != null && !brokenTime.isModified(file)) {
+ if (brokenTime != null && !brokenTime.isModified(path.toFile())) {
continue;
}
Plugin active = running.get(name);
- if (active != null && !active.isModified(file)) {
+ if (active != null && !active.isModified(path)) {
continue;
}
if (active != null) {
- log.info(String.format("Reloading plugin %s, version %s",
- active.getName(), active.getVersion()));
+ log.info(String.format("Reloading plugin %s", active.getName()));
}
try {
- Plugin loadedPlugin = runPlugin(name, file, active);
- if (active == null && !loadedPlugin.isDisabled()) {
- log.info(String.format("Loaded plugin %s, version %s",
+ Plugin loadedPlugin = runPlugin(name, path, active);
+ if (!loadedPlugin.isDisabled()) {
+ log.info(String.format("%s plugin %s, version %s",
+ active == null ? "Loaded" : "Reloaded",
loadedPlugin.getName(), loadedPlugin.getVersion()));
}
} catch (PluginInstallException e) {
@@ -400,31 +416,32 @@
cleanInBackground();
}
- private void addAllEntries(Map<String, File> from,
- TreeSet<Entry<String, File>> to) {
- Iterator<Entry<String, File>> it = from.entrySet().iterator();
+ private void addAllEntries(Map<String, Path> from,
+ TreeSet<Entry<String, Path>> to) {
+ Iterator<Entry<String, Path>> it = from.entrySet().iterator();
while (it.hasNext()) {
- Entry<String,File> entry = it.next();
+ Entry<String,Path> entry = it.next();
to.add(new AbstractMap.SimpleImmutableEntry<>(
entry.getKey(), entry.getValue()));
}
}
- private TreeSet<Entry<String, File>> jarsFirstSortedPluginsSet(
- Map<String, File> activePlugins) {
- TreeSet<Entry<String, File>> sortedPlugins =
- Sets.newTreeSet(new Comparator<Entry<String, File>>() {
+ private TreeSet<Entry<String, Path>> jarsFirstSortedPluginsSet(
+ Map<String, Path> activePlugins) {
+ TreeSet<Entry<String, Path>> sortedPlugins =
+ Sets.newTreeSet(new Comparator<Entry<String, Path>>() {
@Override
- public int compare(Entry<String, File> entry1,
- Entry<String, File> entry2) {
- String file1 = entry1.getValue().getName();
- String file2 = entry2.getValue().getName();
- int cmp = file1.compareTo(file2);
- if (file1.endsWith(".jar")) {
- return (file2.endsWith(".jar") ? cmp : -1);
- } else {
- return (file2.endsWith(".jar") ? +1 : cmp);
- }
+ public int compare(Entry<String, Path> e1, Entry<String, Path> e2) {
+ Path n1 = e1.getValue().getFileName();
+ Path n2 = e2.getValue().getFileName();
+ return ComparisonChain.start()
+ .compareTrueFirst(isJar(n1), isJar(n2))
+ .compare(n1, n2)
+ .result();
+ }
+
+ private boolean isJar(Path n1) {
+ return n1.toString().endsWith(".jar");
}
});
@@ -432,14 +449,14 @@
return sortedPlugins;
}
- private void syncDisabledPlugins(Multimap<String, File> jars) {
+ private void syncDisabledPlugins(Multimap<String, Path> jars) {
stopRemovedPlugins(jars);
dropRemovedDisabledPlugins(jars);
}
- private Plugin runPlugin(String name, File plugin, Plugin oldPlugin)
+ private Plugin runPlugin(String name, Path plugin, Plugin oldPlugin)
throws PluginInstallException {
- FileSnapshot snapshot = FileSnapshot.save(plugin);
+ FileSnapshot snapshot = FileSnapshot.save(plugin.toFile());
try {
Plugin newPlugin = loadPlugin(name, plugin, snapshot);
if (newPlugin.getCleanupHandle() != null) {
@@ -479,11 +496,11 @@
}
}
- private void stopRemovedPlugins(Multimap<String, File> jars) {
+ private void stopRemovedPlugins(Multimap<String, Path> jars) {
Set<String> unload = Sets.newHashSet(running.keySet());
- for (Map.Entry<String, Collection<File>> entry : jars.asMap().entrySet()) {
- for (File file : entry.getValue()) {
- if (!file.getName().endsWith(".disabled")) {
+ for (Map.Entry<String, Collection<Path>> entry : jars.asMap().entrySet()) {
+ for (Path path : entry.getValue()) {
+ if (!path.getFileName().toString().endsWith(".disabled")) {
unload.remove(entry.getKey());
}
}
@@ -493,11 +510,11 @@
}
}
- private void dropRemovedDisabledPlugins(Multimap<String, File> jars) {
+ private void dropRemovedDisabledPlugins(Multimap<String, Path> jars) {
Set<String> unload = Sets.newHashSet(disabled.keySet());
- for (Map.Entry<String, Collection<File>> entry : jars.asMap().entrySet()) {
- for (File file : entry.getValue()) {
- if (file.getName().endsWith(".disabled")) {
+ for (Map.Entry<String, Collection<Path>> entry : jars.asMap().entrySet()) {
+ for (Path path : entry.getValue()) {
+ if (path.getFileName().toString().endsWith(".disabled")) {
unload.remove(entry.getKey());
}
}
@@ -528,8 +545,8 @@
}
}
- public static String nameOf(File plugin) {
- return nameOf(plugin.getName());
+ public static String nameOf(Path plugin) {
+ return nameOf(plugin.getFileName().toString());
}
private static String nameOf(String name) {
@@ -545,21 +562,21 @@
return 0 < ext ? name.substring(ext) : "";
}
- private Plugin loadPlugin(String name, File srcPlugin, FileSnapshot snapshot)
+ private Plugin loadPlugin(String name, Path srcPlugin, FileSnapshot snapshot)
throws InvalidPluginException {
- String pluginName = srcPlugin.getName();
+ String pluginName = srcPlugin.getFileName().toString();
if (isJsPlugin(pluginName)) {
return loadJsPlugin(name, srcPlugin, snapshot);
} else if (serverPluginFactory.handles(srcPlugin)) {
return loadServerPlugin(srcPlugin, snapshot);
} else {
throw new InvalidPluginException(String.format(
- "Unsupported plugin type: %s", srcPlugin.getName()));
+ "Unsupported plugin type: %s", srcPlugin.getFileName()));
}
}
- private File getPluginDataDir(String name) {
- return new File(dataDir, name);
+ private Path getPluginDataDir(String name) {
+ return dataDir.resolve(name);
}
private String getPluginCanonicalWebUrl(String name) {
@@ -569,11 +586,11 @@
return url;
}
- private Plugin loadJsPlugin(String name, File srcJar, FileSnapshot snapshot) {
+ private Plugin loadJsPlugin(String name, Path srcJar, FileSnapshot snapshot) {
return new JsPlugin(name, srcJar, pluginUserFactory.create(name), snapshot);
}
- private ServerPlugin loadServerPlugin(File scriptFile,
+ private ServerPlugin loadServerPlugin(Path scriptFile,
FileSnapshot snapshot) throws InvalidPluginException {
String name = serverPluginFactory.getPluginName(scriptFile);
return serverPluginFactory.get(scriptFile, snapshot, new PluginDescription(
@@ -597,15 +614,15 @@
// Only one active plugin per plugin name can exist for each plugin name.
// Filter out disabled plugins and transform the multimap to a map
- private static Map<String, File> filterDisabled(
- Multimap<String, File> pluginFiles) {
- Map<String, File> activePlugins = Maps.newHashMapWithExpectedSize(
- pluginFiles.keys().size());
- for (String name : pluginFiles.keys()) {
- for (File pluginFile : pluginFiles.asMap().get(name)) {
- if (!pluginFile.getName().endsWith(".disabled")) {
+ private static Map<String, Path> filterDisabled(
+ Multimap<String, Path> pluginPaths) {
+ Map<String, Path> activePlugins = Maps.newHashMapWithExpectedSize(
+ pluginPaths.keys().size());
+ for (String name : pluginPaths.keys()) {
+ for (Path pluginPath : pluginPaths.asMap().get(name)) {
+ if (!pluginPath.getFileName().toString().endsWith(".disabled")) {
assert(!activePlugins.containsKey(name));
- activePlugins.put(name, pluginFile);
+ activePlugins.put(name, pluginPath);
}
}
}
@@ -621,37 +638,40 @@
//
// NOTE: Bear in mind that the plugin name can be reassigned after load by the
// Server plugin provider.
- public Multimap<String, File> prunePlugins(File pluginsDir) {
- List<File> pluginFiles = scanFilesInPluginsDirectory(pluginsDir);
- Multimap<String, File> map;
- map = asMultimap(pluginFiles);
+ public Multimap<String, Path> prunePlugins(Path pluginsDir) {
+ List<Path> pluginPaths = scanPathsInPluginsDirectory(pluginsDir);
+ Multimap<String, Path> map;
+ map = asMultimap(pluginPaths);
for (String plugin : map.keySet()) {
- Collection<File> files = map.asMap().get(plugin);
+ Collection<Path> files = map.asMap().get(plugin);
if (files.size() == 1) {
continue;
}
// retrieve enabled plugins
- Iterable<File> enabled = filterDisabledPlugins(
- files);
+ Iterable<Path> enabled = filterDisabledPlugins(files);
// If we have only one (the winner) plugin, nothing to do
if (!Iterables.skip(enabled, 1).iterator().hasNext()) {
continue;
}
- File winner = Iterables.getFirst(enabled, null);
+ Path winner = Iterables.getFirst(enabled, null);
assert(winner != null);
// Disable all loser plugins by renaming their file names to
// "file.disabled" and replace the disabled files in the multimap.
- Collection<File> elementsToRemove = Lists.newArrayList();
- Collection<File> elementsToAdd = Lists.newArrayList();
- for (File loser : Iterables.skip(enabled, 1)) {
+ Collection<Path> elementsToRemove = Lists.newArrayList();
+ Collection<Path> elementsToAdd = Lists.newArrayList();
+ for (Path loser : Iterables.skip(enabled, 1)) {
log.warn(String.format("Plugin <%s> was disabled, because"
+ " another plugin <%s>"
+ " with the same name <%s> already exists",
loser, winner, plugin));
- File disabledPlugin = new File(loser + ".disabled");
+ Path disabledPlugin = Paths.get(loser + ".disabled");
elementsToAdd.add(disabledPlugin);
elementsToRemove.add(loser);
- loser.renameTo(disabledPlugin);
+ try {
+ Files.move(loser, disabledPlugin);
+ } catch (IOException e) {
+ log.warn("Failed to fully disable plugin " + loser, e);
+ }
}
Iterables.removeAll(files, elementsToRemove);
Iterables.addAll(files, elementsToAdd);
@@ -659,50 +679,52 @@
return map;
}
- private List<File> scanFilesInPluginsDirectory(File pluginsDir) {
- if (pluginsDir == null || !pluginsDir.exists()) {
+ private List<Path> scanPathsInPluginsDirectory(Path pluginsDir) {
+ if (pluginsDir == null || !Files.exists(pluginsDir)) {
return Collections.emptyList();
}
- File[] matches = pluginsDir.listFiles(new FileFilter() {
+ DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<Path>() {
@Override
- public boolean accept(File pathname) {
- String n = pathname.getName();
+ public boolean accept(Path entry) throws IOException {
+ String n = entry.getFileName().toString();
return !n.startsWith(".last_")
&& !n.startsWith(".next_");
}
- });
- if (matches == null) {
- log.error("Cannot list " + pluginsDir.getAbsolutePath());
- return Collections.emptyList();
+ };
+ try (DirectoryStream<Path> files
+ = Files.newDirectoryStream(pluginsDir, filter)) {
+ return ImmutableList.copyOf(files);
+ } catch (IOException e) {
+ log.error("Cannot list " + pluginsDir.toAbsolutePath(), e);
+ return ImmutableList.of();
}
- return Arrays.asList(matches);
}
- private static Iterable<File> filterDisabledPlugins(
- Collection<File> files) {
- return Iterables.filter(files, new Predicate<File>() {
+ private static Iterable<Path> filterDisabledPlugins(
+ Collection<Path> paths) {
+ return Iterables.filter(paths, new Predicate<Path>() {
@Override
- public boolean apply(File file) {
- return !file.getName().endsWith(".disabled");
+ public boolean apply(Path p) {
+ return !p.getFileName().toString().endsWith(".disabled");
}
});
}
- public String getGerritPluginName(File srcFile) {
- String fileName = srcFile.getName();
+ public String getGerritPluginName(Path srcPath) {
+ String fileName = srcPath.getFileName().toString();
if (isJsPlugin(fileName)) {
return fileName.substring(0, fileName.length() - 3);
}
- if (serverPluginFactory.handles(srcFile)) {
- return serverPluginFactory.getPluginName(srcFile);
+ if (serverPluginFactory.handles(srcPath)) {
+ return serverPluginFactory.getPluginName(srcPath);
}
return null;
}
- private Multimap<String, File> asMultimap(List<File> plugins) {
- Multimap<String, File> map = LinkedHashMultimap.create();
- for (File srcFile : plugins) {
- map.put(getPluginName(srcFile), srcFile);
+ private Multimap<String, Path> asMultimap(List<Path> plugins) {
+ Multimap<String, Path> map = LinkedHashMultimap.create();
+ for (Path srcPath : plugins) {
+ map.put(getPluginName(srcPath), srcPath);
}
return map;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ServerPlugin.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ServerPlugin.java
index 0b037fb..28d57b2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ServerPlugin.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ServerPlugin.java
@@ -17,25 +17,19 @@
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.gerrit.common.Nullable;
-import com.google.gerrit.extensions.annotations.PluginCanonicalWebUrl;
-import com.google.gerrit.extensions.annotations.PluginData;
-import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.extensions.registration.RegistrationHandle;
import com.google.gerrit.extensions.registration.ReloadableRegistrationHandle;
import com.google.gerrit.lifecycle.LifecycleManager;
import com.google.gerrit.server.PluginUser;
import com.google.gerrit.server.util.RequestContext;
-import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
-import com.google.inject.Provider;
-import com.google.inject.ProvisionException;
import org.eclipse.jgit.internal.storage.file.FileSnapshot;
-import java.io.File;
import java.io.IOException;
+import java.nio.file.Path;
import java.util.List;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
@@ -59,7 +53,7 @@
private final Manifest manifest;
private final PluginContentScanner scanner;
- private final File dataDir;
+ private final Path dataDir;
private final String pluginCanonicalWebUrl;
private final ClassLoader classLoader;
private Class<? extends Module> sysModule;
@@ -75,12 +69,13 @@
public ServerPlugin(String name,
String pluginCanonicalWebUrl,
PluginUser pluginUser,
- File srcJar,
+ Path srcJar,
FileSnapshot snapshot,
PluginContentScanner scanner,
- File dataDir,
+ Path dataDir,
ClassLoader classLoader) throws InvalidPluginException {
- super(name, srcJar, pluginUser, snapshot, Plugin.getApiType(getPluginManifest(scanner)));
+ super(name, srcJar, pluginUser, snapshot,
+ Plugin.getApiType(getPluginManifest(scanner)));
this.pluginCanonicalWebUrl = pluginCanonicalWebUrl;
this.scanner = scanner;
this.dataDir = dataDir;
@@ -127,10 +122,18 @@
return (Class<? extends Module>) clazz;
}
- File getSrcJar() {
+ Path getSrcJar() {
return getSrcFile();
}
+ Path getDataDir() {
+ return dataDir;
+ }
+
+ String getPluginCanonicalWebUrl() {
+ return pluginCanonicalWebUrl;
+ }
+
private static Manifest getPluginManifest(PluginContentScanner scanner)
throws InvalidPluginException {
try {
@@ -229,45 +232,11 @@
}
private Injector newRootInjector(final PluginGuiceEnvironment env) {
- List<Module> modules = Lists.newArrayListWithCapacity(4);
+ List<Module> modules = Lists.newArrayListWithCapacity(2);
if (getApiType() == ApiType.PLUGIN) {
modules.add(env.getSysModule());
}
- modules.add(new AbstractModule() {
- @Override
- protected void configure() {
- bind(PluginUser.class).toInstance(getPluginUser());
- bind(String.class)
- .annotatedWith(PluginName.class)
- .toInstance(getName());
- bind(String.class)
- .annotatedWith(PluginCanonicalWebUrl.class)
- .toInstance(pluginCanonicalWebUrl);
-
- bind(File.class)
- .annotatedWith(PluginData.class)
- .toProvider(new Provider<File>() {
- private volatile boolean ready;
-
- @Override
- public File get() {
- if (!ready) {
- synchronized (dataDir) {
- if (!ready) {
- if (!dataDir.exists() && !dataDir.mkdirs()) {
- throw new ProvisionException(String.format(
- "Cannot create %s for plugin %s",
- dataDir.getAbsolutePath(), getName()));
- }
- ready = true;
- }
- }
- }
- return dataDir;
- }
- });
- }
- });
+ modules.add(new ServerPluginInfoModule(this));
return Guice.createInjector(modules);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ServerPluginInfoModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ServerPluginInfoModule.java
new file mode 100644
index 0000000..b0e9453
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ServerPluginInfoModule.java
@@ -0,0 +1,77 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.plugins;
+
+import com.google.gerrit.extensions.annotations.PluginCanonicalWebUrl;
+import com.google.gerrit.extensions.annotations.PluginData;
+import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.gerrit.server.PluginUser;
+import com.google.inject.AbstractModule;
+import com.google.inject.Provides;
+import com.google.inject.ProvisionException;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+class ServerPluginInfoModule extends AbstractModule {
+ private final ServerPlugin plugin;
+ private final Path dataDir;
+
+ private volatile boolean ready;
+
+ ServerPluginInfoModule(ServerPlugin plugin) {
+ this.plugin = plugin;
+ this.dataDir = plugin.getDataDir();
+ }
+
+ @Override
+ protected void configure() {
+ bind(PluginUser.class).toInstance(plugin.getPluginUser());
+ bind(String.class)
+ .annotatedWith(PluginName.class)
+ .toInstance(plugin.getName());
+ bind(String.class)
+ .annotatedWith(PluginCanonicalWebUrl.class)
+ .toInstance(plugin.getPluginCanonicalWebUrl());
+ }
+
+ @Provides
+ @PluginData
+ Path getPluginData() {
+ if (!ready) {
+ synchronized (dataDir) {
+ if (!ready) {
+ try {
+ Files.createDirectories(dataDir);
+ } catch (IOException e) {
+ throw new ProvisionException(String.format(
+ "Cannot create %s for plugin %s",
+ dataDir.toAbsolutePath(), plugin.getName()), e);
+ }
+ ready = true;
+ }
+ }
+ }
+ return dataDir;
+ }
+
+ @Provides
+ @PluginData
+ File getPluginDataAsFile(@PluginData Path pluginData) {
+ return pluginData.toFile();
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ServerPluginProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ServerPluginProvider.java
index 37fed9b..bc2432b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ServerPluginProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ServerPluginProvider.java
@@ -19,7 +19,7 @@
import org.eclipse.jgit.internal.storage.file.FileSnapshot;
-import java.io.File;
+import java.nio.file.Path;
/**
* Provider of one Server plugin from one external file
@@ -40,7 +40,7 @@
public class PluginDescription {
public final PluginUser user;
public final String canonicalUrl;
- public final File dataDir;
+ public final Path dataDir;
/**
* Creates a new PluginDescription for ServerPluginProvider.
@@ -49,7 +49,7 @@
* @param canonicalUrl plugin root Web URL
* @param dataDir directory for plugin data
*/
- public PluginDescription(PluginUser user, String canonicalUrl, File dataDir) {
+ public PluginDescription(PluginUser user, String canonicalUrl, Path dataDir) {
this.user = user;
this.canonicalUrl = canonicalUrl;
this.dataDir = dataDir;
@@ -59,39 +59,39 @@
/**
* Declares the availability to manage an external file or directory
*
- * @param srcFile the external file or directory
+ * @param srcPath the external file or directory
* @return true if file or directory can be loaded into a Server Plugin
*/
- boolean handles(File srcFile);
+ boolean handles(Path srcPath);
/**
* Returns the plugin name of an external file or directory
*
- * Should be called only if {@link #handles(File) handles(srcFile)}
+ * Should be called only if {@link #handles(Path) handles(srcFile)}
* returns true and thus srcFile is a supported plugin format.
* An IllegalArgumentException is thrown otherwise as srcFile
* is not a valid file format for extracting its plugin name.
*
- * @param srcFile external file or directory
+ * @param srcPath external file or directory
* @return plugin name
*/
- String getPluginName(File srcFile);
+ String getPluginName(Path srcPath);
/**
* Loads an external file or directory into a Server plugin.
*
- * Should be called only if {@link #handles(File) handles(srcFile)}
+ * Should be called only if {@link #handles(Path) handles(srcFile)}
* returns true and thus srcFile is a supported plugin format.
* An IllegalArgumentException is thrown otherwise as srcFile
* is not a valid file format for extracting its plugin name.
*
- * @param srcFile external file or directory
+ * @param srcPath external file or directory
* @param snapshot snapshot of the external file
* @param pluginDescriptor descriptor of the ServerPlugin to load
* @throws InvalidPluginException if plugin is supposed to be handled
* but cannot be loaded for any other reason
*/
- ServerPlugin get(File srcFile, FileSnapshot snapshot,
+ ServerPlugin get(Path srcPath, FileSnapshot snapshot,
PluginDescription pluginDescriptor) throws InvalidPluginException;
/**
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/UniversalServerPluginProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/UniversalServerPluginProvider.java
index 0e8bd87..afdc5b3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/UniversalServerPluginProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/UniversalServerPluginProvider.java
@@ -22,7 +22,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.File;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
@@ -38,27 +38,26 @@
}
@Override
- public ServerPlugin get(File srcFile, FileSnapshot snapshot,
+ public ServerPlugin get(Path srcPath, FileSnapshot snapshot,
PluginDescription pluginDescription) throws InvalidPluginException {
- return providerOf(srcFile).get(srcFile, snapshot, pluginDescription);
+ return providerOf(srcPath).get(srcPath, snapshot, pluginDescription);
}
@Override
- public String getPluginName(File srcFile) {
- return providerOf(srcFile).getPluginName(srcFile);
+ public String getPluginName(Path srcPath) {
+ return providerOf(srcPath).getPluginName(srcPath);
}
@Override
- public boolean handles(File srcFile) {
- List<ServerPluginProvider> providers =
- providersForHandlingPlugin(srcFile);
+ public boolean handles(Path srcPath) {
+ List<ServerPluginProvider> providers = providersForHandlingPlugin(srcPath);
switch (providers.size()) {
case 1:
return true;
case 0:
return false;
default:
- throw new MultipleProvidersForPluginException(srcFile, providers);
+ throw new MultipleProvidersForPluginException(srcPath, providers);
}
}
@@ -67,27 +66,27 @@
return "gerrit";
}
- private ServerPluginProvider providerOf(File srcFile) {
+ private ServerPluginProvider providerOf(Path srcPath) {
List<ServerPluginProvider> providers =
- providersForHandlingPlugin(srcFile);
+ providersForHandlingPlugin(srcPath);
switch (providers.size()) {
case 1:
return providers.get(0);
case 0:
throw new IllegalArgumentException(
"No ServerPluginProvider found/loaded to handle plugin file "
- + srcFile.getAbsolutePath());
+ + srcPath.toAbsolutePath());
default:
- throw new MultipleProvidersForPluginException(srcFile, providers);
+ throw new MultipleProvidersForPluginException(srcPath, providers);
}
}
private List<ServerPluginProvider> providersForHandlingPlugin(
- final File srcFile) {
+ final Path srcPath) {
List<ServerPluginProvider> providers = new ArrayList<>();
for (ServerPluginProvider serverPluginProvider : serverPluginProviders) {
- boolean handles = serverPluginProvider.handles(srcFile);
- log.debug("File {} handled by {} ? => {}", srcFile,
+ boolean handles = serverPluginProvider.handles(srcPath);
+ log.debug("File {} handled by {} ? => {}", srcPath,
serverPluginProvider.getProviderPluginName(), handles);
if (handles) {
providers.add(serverPluginProvider);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/BranchResource.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/BranchResource.java
index 98531ce..7168b1b2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/BranchResource.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/BranchResource.java
@@ -14,9 +14,9 @@
package com.google.gerrit.server.project;
+import com.google.gerrit.extensions.api.projects.BranchInfo;
import com.google.gerrit.extensions.restapi.RestView;
import com.google.gerrit.reviewdb.client.Branch;
-import com.google.gerrit.server.project.ListBranches.BranchInfo;
import com.google.inject.TypeLiteral;
public class BranchResource extends ProjectResource {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/BranchesCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/BranchesCollection.java
index e96d3a5..41d4920 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/BranchesCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/BranchesCollection.java
@@ -14,6 +14,7 @@
package com.google.gerrit.server.project;
+import com.google.gerrit.extensions.api.projects.BranchInfo;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.AcceptsCreate;
import com.google.gerrit.extensions.restapi.BadRequestException;
@@ -21,7 +22,7 @@
import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestView;
-import com.google.gerrit.server.project.ListBranches.BranchInfo;
+import com.google.gerrit.reviewdb.client.RefNames;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@@ -56,9 +57,8 @@
public BranchResource parse(ProjectResource parent, IdString id)
throws ResourceNotFoundException, IOException, BadRequestException {
String branchName = id.get();
- if (!branchName.startsWith(Constants.R_REFS)
- && !branchName.equals(Constants.HEAD)) {
- branchName = Constants.R_HEADS + branchName;
+ if (!branchName.equals(Constants.HEAD)) {
+ branchName = RefNames.fullName(branchName);
}
List<BranchInfo> branches = list.get().apply(parent);
for (BranchInfo b : branches) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ChildProjectResource.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ChildProjectResource.java
index f68acdd..4257825 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ChildProjectResource.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ChildProjectResource.java
@@ -15,28 +15,34 @@
package com.google.gerrit.server.project;
import com.google.common.collect.Iterables;
+import com.google.gerrit.extensions.restapi.RestResource;
import com.google.gerrit.extensions.restapi.RestView;
import com.google.inject.TypeLiteral;
-public class ChildProjectResource extends ProjectResource {
+public class ChildProjectResource implements RestResource {
public static final TypeLiteral<RestView<ChildProjectResource>> CHILD_PROJECT_KIND =
new TypeLiteral<RestView<ChildProjectResource>>() {};
+ private final ProjectResource parent;
private final ProjectControl child;
- public ChildProjectResource(ProjectResource project, ProjectControl child) {
- super(project);
+ public ChildProjectResource(ProjectResource parent, ProjectControl child) {
+ this.parent = parent;
this.child = child;
}
+ public ProjectResource getParent() {
+ return parent;
+ }
+
public ProjectControl getChild() {
return child;
}
public boolean isDirectChild() {
- ProjectState parent =
+ ProjectState firstParent =
Iterables.getFirst(child.getProjectState().parents(), null);
- return parent != null
- && getNameKey().equals(parent.getProject().getNameKey());
+ return firstParent != null
+ && parent.getNameKey().equals(firstParent.getProject().getNameKey());
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ChildProjectsCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ChildProjectsCollection.java
index ca98cf6..faba87a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ChildProjectsCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ChildProjectsCollection.java
@@ -44,7 +44,7 @@
}
@Override
- public RestView<ProjectResource> list() throws ResourceNotFoundException,
+ public ListChildProjects list() throws ResourceNotFoundException,
AuthException {
return list.get();
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java
index ac40df0..cb94063 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java
@@ -17,6 +17,7 @@
import com.google.common.collect.Iterables;
import com.google.gerrit.common.ChangeHooks;
import com.google.gerrit.common.errors.InvalidRevisionException;
+import com.google.gerrit.extensions.api.projects.BranchInfo;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.DefaultInput;
@@ -30,7 +31,6 @@
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.project.CreateBranch.Input;
-import com.google.gerrit.server.project.ListBranches.BranchInfo;
import com.google.gerrit.server.util.MagicBranch;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -48,6 +48,7 @@
import org.eclipse.jgit.revwalk.ObjectWalk;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.ReceiveCommand;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -105,9 +106,7 @@
while (ref.startsWith("/")) {
ref = ref.substring(1);
}
- if (!ref.startsWith(Constants.R_REFS)) {
- ref = Constants.R_HEADS + ref;
- }
+ ref = RefNames.fullName(ref);
if (!Repository.isValidRefName(ref)) {
throw new BadRequestException("invalid branch name \"" + ref + "\"");
}
@@ -151,7 +150,7 @@
case FAST_FORWARD:
case NEW:
case NO_CHANGE:
- referenceUpdated.fire(name.getParentKey(), u);
+ referenceUpdated.fire(name.getParentKey(), u, ReceiveCommand.Type.CREATE);
hooks.doRefUpdatedHook(name, u, identifiedUser.get().getAccount());
break;
case LOCK_FAILURE:
@@ -174,7 +173,11 @@
}
}
- return new BranchInfo(ref, revid.getName(), refControl.canDelete());
+ BranchInfo info = new BranchInfo();
+ info.ref = ref;
+ info.revision = revid.getName();
+ info.canDelete = refControl.canDelete() ? true : null;
+ return info;
} catch (IOException err) {
log.error("Cannot create branch \"" + name + "\"", err);
throw err;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateProject.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateProject.java
index b0ac201..0abffde 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateProject.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateProject.java
@@ -17,13 +17,19 @@
import com.google.common.base.MoreObjects;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
+import com.google.gerrit.common.ProjectUtil;
+import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.GlobalCapability;
-import com.google.gerrit.common.errors.ProjectCreationFailedException;
+import com.google.gerrit.common.data.GroupDescription;
+import com.google.gerrit.common.data.GroupReference;
+import com.google.gerrit.common.data.Permission;
+import com.google.gerrit.common.data.PermissionRule;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.extensions.api.projects.ProjectInput;
import com.google.gerrit.extensions.client.InheritableBoolean;
import com.google.gerrit.extensions.client.SubmitType;
import com.google.gerrit.extensions.common.ProjectInfo;
+import com.google.gerrit.extensions.events.NewProjectCreatedListener;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
@@ -34,8 +40,17 @@
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.GerritPersonIdent;
+import com.google.gerrit.server.account.GroupBackend;
+import com.google.gerrit.server.config.ProjectOwnerGroupsProvider;
+import com.google.gerrit.server.config.RepositoryConfig;
+import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.ProjectConfig;
+import com.google.gerrit.server.git.RepositoryCaseMismatchException;
import com.google.gerrit.server.group.GroupsCollection;
import com.google.gerrit.server.validators.ProjectCreationValidationListener;
import com.google.gerrit.server.validators.ValidationException;
@@ -44,8 +59,22 @@
import com.google.inject.assistedinject.Assisted;
import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.RefUpdate.Result;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.ReceiveCommand;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
@RequiresCapability(GlobalCapability.CREATE_PROJECT)
@@ -54,40 +83,68 @@
CreateProject create(String name);
}
- private final PerformCreateProject.Factory createProjectFactory;
+ private static final Logger log = LoggerFactory
+ .getLogger(CreateProject.class);
+
private final Provider<ProjectsCollection> projectsCollection;
private final Provider<GroupsCollection> groupsCollection;
private final DynamicSet<ProjectCreationValidationListener> projectCreationValidationListeners;
private final ProjectJson json;
private final ProjectControl.GenericFactory projectControlFactory;
+ private final GitRepositoryManager repoManager;
+ private final DynamicSet<NewProjectCreatedListener> createdListener;
+ private final ProjectCache projectCache;
+ private final GroupBackend groupBackend;
+ private final ProjectOwnerGroupsProvider.Factory projectOwnerGroups;
+ private final MetaDataUpdate.User metaDataUpdateFactory;
+ private final GitReferenceUpdated referenceUpdated;
+ private final RepositoryConfig repositoryCfg;
+ private final PersonIdent serverIdent;
private final Provider<CurrentUser> currentUser;
private final Provider<PutConfig> putConfig;
private final String name;
@Inject
- CreateProject(PerformCreateProject.Factory performCreateProjectFactory,
- Provider<ProjectsCollection> projectsCollection,
+ CreateProject(Provider<ProjectsCollection> projectsCollection,
Provider<GroupsCollection> groupsCollection, ProjectJson json,
DynamicSet<ProjectCreationValidationListener> projectCreationValidationListeners,
ProjectControl.GenericFactory projectControlFactory,
- Provider<CurrentUser> currentUser, Provider<PutConfig> putConfig,
+ GitRepositoryManager repoManager,
+ DynamicSet<NewProjectCreatedListener> createdListener,
+ ProjectCache projectCache,
+ GroupBackend groupBackend,
+ ProjectOwnerGroupsProvider.Factory projectOwnerGroups,
+ MetaDataUpdate.User metaDataUpdateFactory,
+ GitReferenceUpdated referenceUpdated,
+ RepositoryConfig repositoryCfg,
+ @GerritPersonIdent PersonIdent serverIdent,
+ Provider<CurrentUser> currentUser,
+ Provider<PutConfig> putConfig,
@Assisted String name) {
- this.createProjectFactory = performCreateProjectFactory;
this.projectsCollection = projectsCollection;
this.groupsCollection = groupsCollection;
this.projectCreationValidationListeners = projectCreationValidationListeners;
this.json = json;
this.projectControlFactory = projectControlFactory;
+ this.repoManager = repoManager;
+ this.createdListener = createdListener;
+ this.projectCache = projectCache;
+ this.groupBackend = groupBackend;
+ this.projectOwnerGroups = projectOwnerGroups;
+ this.metaDataUpdateFactory = metaDataUpdateFactory;
+ this.referenceUpdated = referenceUpdated;
+ this.repositoryCfg = repositoryCfg;
+ this.serverIdent = serverIdent;
this.currentUser = currentUser;
this.putConfig = putConfig;
this.name = name;
}
@Override
- public Response<ProjectInfo> apply(TopLevelResource resource, ProjectInput input)
- throws BadRequestException, UnprocessableEntityException,
- ResourceConflictException, ProjectCreationFailedException,
- ResourceNotFoundException, IOException {
+ public Response<ProjectInfo> apply(TopLevelResource resource,
+ ProjectInput input) throws BadRequestException,
+ UnprocessableEntityException, ResourceConflictException,
+ ResourceNotFoundException, IOException, ConfigInvalidException {
if (input == null) {
input = new ProjectInput();
}
@@ -95,8 +152,9 @@
throw new BadRequestException("name must match URL");
}
- final CreateProjectArgs args = new CreateProjectArgs();
- args.setProjectName(name);
+ CreateProjectArgs args = new CreateProjectArgs();
+ args.setProjectName(ProjectUtil.stripGitSuffix(name));
+
if (!Strings.isNullOrEmpty(input.parent)) {
args.newParent = projectsCollection.get().parse(input.parent).getControl();
}
@@ -104,14 +162,16 @@
args.permissionsOnly = input.permissionsOnly;
args.projectDescription = Strings.emptyToNull(input.description);
args.submitType = input.submitType;
- args.branch = input.branches;
- if (input.owners != null) {
- List<AccountGroup.UUID> ownerIds =
- Lists.newArrayListWithCapacity(input.owners.size());
+ args.branch = normalizeBranchNames(input.branches);
+ if (input.owners == null || input.owners.isEmpty()) {
+ args.ownerIds =
+ new ArrayList<>(projectOwnerGroups.create(args.getProject()).get());
+ } else {
+ args.ownerIds =
+ Lists.newArrayListWithCapacity(input.owners.size());
for (String owner : input.owners) {
- ownerIds.add(groupsCollection.get().parse(owner).getGroupUUID());
+ args.ownerIds.add(groupsCollection.get().parse(owner).getGroupUUID());
}
- args.ownerIds = ownerIds;
}
args.contributorAgreements =
MoreObjects.firstNonNull(input.useContributorAgreements,
@@ -144,7 +204,7 @@
}
}
- Project p = createProjectFactory.create(args).createProject();
+ Project p = createProject(args);
if (input.pluginConfigValues != null) {
try {
@@ -160,4 +220,181 @@
return Response.created(json.format(p));
}
+
+ public Project createProject(CreateProjectArgs args)
+ throws BadRequestException, ResourceConflictException, IOException,
+ ConfigInvalidException {
+ final Project.NameKey nameKey = args.getProject();
+ try {
+ final String head =
+ args.permissionsOnly ? RefNames.REFS_CONFIG
+ : args.branch.get(0);
+ Repository repo = repoManager.createRepository(nameKey);
+ try {
+ NewProjectCreatedListener.Event event = new NewProjectCreatedListener.Event() {
+ @Override
+ public String getProjectName() {
+ return nameKey.get();
+ }
+
+ @Override
+ public String getHeadName() {
+ return head;
+ }
+ };
+ for (NewProjectCreatedListener l : createdListener) {
+ try {
+ l.onNewProjectCreated(event);
+ } catch (RuntimeException e) {
+ log.warn("Failure in NewProjectCreatedListener", e);
+ }
+ }
+
+ RefUpdate u = repo.updateRef(Constants.HEAD);
+ u.disableRefLog();
+ u.link(head);
+
+ createProjectConfig(args);
+
+ if (!args.permissionsOnly
+ && args.createEmptyCommit) {
+ createEmptyCommits(repo, nameKey, args.branch);
+ }
+
+ return projectCache.get(nameKey).getProject();
+ } finally {
+ repo.close();
+ }
+ } catch (RepositoryCaseMismatchException e) {
+ throw new ResourceConflictException("Cannot create " + nameKey.get()
+ + " because the name is already occupied by another project."
+ + " The other project has the same name, only spelled in a"
+ + " different case.");
+ } catch (RepositoryNotFoundException badName) {
+ throw new BadRequestException("invalid project name: " + nameKey);
+ } catch (IllegalStateException err) {
+ try {
+ Repository repo = repoManager.openRepository(nameKey);
+ try {
+ if (repo.getObjectDatabase().exists()) {
+ throw new ResourceConflictException("project \"" + nameKey + "\" exists");
+ }
+ throw err;
+ } finally {
+ repo.close();
+ }
+ } catch (IOException ioErr) {
+ String msg = "Cannot create " + nameKey;
+ log.error(msg, err);
+ throw ioErr;
+ }
+ } catch (ConfigInvalidException e) {
+ String msg = "Cannot create " + nameKey;
+ log.error(msg, e);
+ throw e;
+ }
+ }
+
+ private void createProjectConfig(CreateProjectArgs args) throws IOException, ConfigInvalidException {
+ MetaDataUpdate md =
+ metaDataUpdateFactory.create(args.getProject());
+ try {
+ ProjectConfig config = ProjectConfig.read(md);
+ config.load(md);
+
+ Project newProject = config.getProject();
+ newProject.setDescription(args.projectDescription);
+ newProject.setSubmitType(MoreObjects.firstNonNull(args.submitType,
+ repositoryCfg.getDefaultSubmitType(args.getProject())));
+ newProject
+ .setUseContributorAgreements(args.contributorAgreements);
+ newProject.setUseSignedOffBy(args.signedOffBy);
+ newProject.setUseContentMerge(args.contentMerge);
+ newProject.setCreateNewChangeForAllNotInTarget(args.newChangeForAllNotInTarget);
+ newProject.setRequireChangeID(args.changeIdRequired);
+ newProject.setMaxObjectSizeLimit(args.maxObjectSizeLimit);
+ if (args.newParent != null) {
+ newProject.setParentName(args.newParent.getProject()
+ .getNameKey());
+ }
+
+ if (!args.ownerIds.isEmpty()) {
+ AccessSection all =
+ config.getAccessSection(AccessSection.ALL, true);
+ for (AccountGroup.UUID ownerId : args.ownerIds) {
+ GroupDescription.Basic g = groupBackend.get(ownerId);
+ if (g != null) {
+ GroupReference group = config.resolve(GroupReference.forGroup(g));
+ all.getPermission(Permission.OWNER, true).add(
+ new PermissionRule(group));
+ }
+ }
+ }
+
+ md.setMessage("Created project\n");
+ config.commit(md);
+ } finally {
+ md.close();
+ }
+ projectCache.onCreateProject(args.getProject());
+ repoManager.setProjectDescription(args.getProject(),
+ args.projectDescription);
+ }
+
+ private List<String> normalizeBranchNames(List<String> branches)
+ throws BadRequestException {
+ if (branches == null || branches.isEmpty()) {
+ return Collections.singletonList(Constants.R_HEADS + Constants.MASTER);
+ }
+
+ List<String> normalizedBranches = new ArrayList<>();
+ for (String branch : branches) {
+ while (branch.startsWith("/")) {
+ branch = branch.substring(1);
+ }
+ branch = RefNames.fullName(branch);
+ if (!Repository.isValidRefName(branch)) {
+ throw new BadRequestException(String.format(
+ "Branch \"%s\" is not a valid name.", branch));
+ }
+ if (!normalizedBranches.contains(branch)) {
+ normalizedBranches.add(branch);
+ }
+ }
+ return normalizedBranches;
+ }
+
+ private void createEmptyCommits(Repository repo, Project.NameKey project,
+ List<String> refs) throws IOException {
+ try (ObjectInserter oi = repo.newObjectInserter()) {
+ CommitBuilder cb = new CommitBuilder();
+ cb.setTreeId(oi.insert(Constants.OBJ_TREE, new byte[] {}));
+ cb.setAuthor(metaDataUpdateFactory.getUserPersonIdent());
+ cb.setCommitter(serverIdent);
+ cb.setMessage("Initial empty repository\n");
+
+ ObjectId id = oi.insert(cb);
+ oi.flush();
+
+ for (String ref : refs) {
+ RefUpdate ru = repo.updateRef(ref);
+ ru.setNewObjectId(id);
+ Result result = ru.update();
+ switch (result) {
+ case NEW:
+ referenceUpdated.fire(project, ru, ReceiveCommand.Type.CREATE);
+ break;
+ default: {
+ throw new IOException(String.format(
+ "Failed to create ref \"%s\": %s", ref, result.name()));
+ }
+ }
+ }
+ } catch (IOException e) {
+ log.error(
+ "Cannot create empty commit for "
+ + project.get(), e);
+ throw e;
+ }
+ }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranch.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranch.java
index 4aba333..202dc0e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranch.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranch.java
@@ -35,6 +35,7 @@
import org.eclipse.jgit.errors.LockFailedException;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.ReceiveCommand;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -46,7 +47,7 @@
private static final int MAX_LOCK_FAILURE_CALLS = 10;
private static final long SLEEP_ON_LOCK_FAILURE_MS = 15;
- static class Input {
+ public static class Input {
}
private final Provider<IdentifiedUser> identifiedUser;
@@ -113,7 +114,7 @@
case NO_CHANGE:
case FAST_FORWARD:
case FORCED:
- referenceUpdated.fire(rsrc.getNameKey(), u);
+ referenceUpdated.fire(rsrc.getNameKey(), u, ReceiveCommand.Type.DELETE);
hooks.doRefUpdatedHook(rsrc.getBranchKey(), u, identifiedUser.get().getAccount());
ResultSet<SubmoduleSubscription> submoduleSubscriptions =
dbProvider.get().submoduleSubscriptions().bySuperProject(rsrc.getBranchKey());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranches.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranches.java
index d6e93f0..fc34917 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranches.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranches.java
@@ -165,8 +165,7 @@
private void postDeletion(ProjectResource project, ReceiveCommand cmd)
throws OrmException {
- referenceUpdated.fire(project.getNameKey(), cmd.getRefName(),
- cmd.getOldId(), cmd.getNewId());
+ referenceUpdated.fire(project.getNameKey(), cmd);
Branch.NameKey branchKey =
new Branch.NameKey(project.getNameKey(), cmd.getRefName());
hooks.doRefUpdatedHook(branchKey, cmd.getOldId(), cmd.getNewId(),
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteDashboard.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteDashboard.java
index b525399..7702b7d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteDashboard.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteDashboard.java
@@ -22,7 +22,6 @@
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.server.project.DashboardsCollection.DashboardInfo;
-import com.google.gerrit.server.project.DeleteDashboard.Input;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@@ -30,11 +29,7 @@
import java.io.IOException;
@Singleton
-class DeleteDashboard implements RestModifyView<DashboardResource, Input> {
- static class Input {
- String commitMessage;
- }
-
+class DeleteDashboard implements RestModifyView<DashboardResource, SetDashboard.Input> {
private final Provider<SetDefaultDashboard> defaultSetter;
@Inject
@@ -43,7 +38,7 @@
}
@Override
- public Response<DashboardInfo> apply(DashboardResource resource, Input input)
+ public Response<DashboardInfo> apply(DashboardResource resource, SetDashboard.Input input)
throws AuthException, BadRequestException, ResourceConflictException,
ResourceNotFoundException, MethodNotAllowedException, IOException {
if (resource.isProjectDefault()) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/GarbageCollect.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/GarbageCollect.java
index fe1086b..a5a96b1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/GarbageCollect.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/GarbageCollect.java
@@ -41,6 +41,7 @@
UiAction<ProjectResource> {
public static class Input {
public boolean showProgress;
+ public boolean aggressive;
}
private final boolean canGC;
@@ -68,8 +69,10 @@
}
};
try {
- GarbageCollectionResult result = garbageCollectionFactory.create().run(
- Collections.singletonList(rsrc.getNameKey()), input.showProgress ? writer : null);
+ GarbageCollectionResult result =
+ garbageCollectionFactory.create().run(
+ Collections.singletonList(rsrc.getNameKey()), input.aggressive,
+ input.showProgress ? writer : null);
String msg = "Garbage collection completed successfully.";
if (result.hasErrors()) {
for (GarbageCollectionResult.Error e : result.getErrors()) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetBranch.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetBranch.java
index 59b15d8..78878a7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetBranch.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetBranch.java
@@ -14,8 +14,8 @@
package com.google.gerrit.server.project;
+import com.google.gerrit.extensions.api.projects.BranchInfo;
import com.google.gerrit.extensions.restapi.RestReadView;
-import com.google.gerrit.server.project.ListBranches.BranchInfo;
import com.google.inject.Singleton;
@Singleton
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetChildProject.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetChildProject.java
index 815653f..7737d8c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetChildProject.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetChildProject.java
@@ -23,9 +23,12 @@
public class GetChildProject implements RestReadView<ChildProjectResource> {
@Option(name = "--recursive", usage = "to list child projects recursively")
- private boolean recursive;
+ public void setRecursive(boolean recursive) {
+ this.recursive = recursive;
+ }
private final ProjectJson json;
+ private boolean recursive;
@Inject
GetChildProject(ProjectJson json) {
@@ -38,6 +41,6 @@
if (recursive || rsrc.isDirectChild()) {
return json.format(rsrc.getChild().getProject());
}
- throw new ResourceNotFoundException(rsrc.getName());
+ throw new ResourceNotFoundException(rsrc.getChild().getProject().getName());
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetDescription.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetDescription.java
index 5241c69..bace0a8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetDescription.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetDescription.java
@@ -20,7 +20,7 @@
import com.google.inject.Singleton;
@Singleton
-class GetDescription implements RestReadView<ProjectResource> {
+public class GetDescription implements RestReadView<ProjectResource> {
@Override
public String apply(ProjectResource resource) {
Project project = resource.getControl().getProject();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ListBranches.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ListBranches.java
index a8eda97..8195c2a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ListBranches.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ListBranches.java
@@ -15,10 +15,11 @@
package com.google.gerrit.server.project;
import com.google.common.base.Predicate;
+import com.google.common.base.Strings;
+import com.google.common.collect.ComparisonChain;
import com.google.common.collect.FluentIterable;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
+import com.google.gerrit.extensions.api.projects.BranchInfo;
import com.google.gerrit.extensions.common.ActionInfo;
import com.google.gerrit.extensions.common.WebLinkInfo;
import com.google.gerrit.extensions.registration.DynamicMap;
@@ -45,11 +46,11 @@
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
-import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
@@ -59,15 +60,28 @@
private final WebLinks webLinks;
@Option(name = "--limit", aliases = {"-n"}, metaVar = "CNT", usage = "maximum number of branches to list")
- private int limit;
+ public void setLimit(int limit) {
+ this.limit = limit;
+ }
@Option(name = "--start", aliases = {"-s"}, metaVar = "CNT", usage = "number of branches to skip")
- private int start;
+ public void setStart(int start) {
+ this.start = start;
+ }
@Option(name = "--match", aliases = {"-m"}, metaVar = "MATCH", usage = "match branches substring")
- private String matchSubstring;
+ public void setMatchSubstring(String matchSubstring) {
+ this.matchSubstring = matchSubstring;
+ }
@Option(name = "--regex", aliases = {"-r"}, metaVar = "REGEX", usage = "match branches regex")
+ public void setMatchRegex(String matchRegex) {
+ this.matchRegex = matchRegex;
+ }
+
+ private int limit;
+ private int start;
+ private String matchSubstring;
private String matchRegex;
@Inject
@@ -82,171 +96,163 @@
@Override
public List<BranchInfo> apply(ProjectResource rsrc)
throws ResourceNotFoundException, IOException, BadRequestException {
- List<BranchInfo> branches = Lists.newArrayList();
+ FluentIterable<BranchInfo> branches = allBranches(rsrc);
+ branches = filterBranches(branches);
+ if (start > 0) {
+ branches = branches.skip(start);
+ }
+ if (limit > 0) {
+ branches = branches.limit(limit);
+ }
+ return branches.toList();
+ }
- BranchInfo headBranch = null;
- BranchInfo configBranch = null;
- final Set<String> targets = Sets.newHashSet();
-
- final Repository db;
- try {
- db = repoManager.openRepository(rsrc.getNameKey());
+ private FluentIterable<BranchInfo> allBranches(ProjectResource rsrc)
+ throws IOException, ResourceNotFoundException {
+ List<Ref> refs;
+ try (Repository db = repoManager.openRepository(rsrc.getNameKey())) {
+ Collection<Ref> heads =
+ db.getRefDatabase().getRefs(Constants.R_HEADS).values();
+ refs = new ArrayList<>(heads.size() + 3);
+ refs.addAll(heads);
+ addRef(db, refs, Constants.HEAD);
+ addRef(db, refs, RefNames.REFS_CONFIG);
+ addRef(db, refs, RefNames.REFS_USERS_DEFAULT);
} catch (RepositoryNotFoundException noGitRepository) {
throw new ResourceNotFoundException();
}
- try {
- List<Ref> refs =
- new ArrayList<>(db.getRefDatabase().getRefs(Constants.R_HEADS)
- .values());
-
- try {
- Ref head = db.getRef(Constants.HEAD);
- if (head != null) {
- refs.add(head);
- }
- } catch (IOException e) {
- // Ignore the failure reading HEAD.
- }
- try {
- Ref config = db.getRef(RefNames.REFS_CONFIG);
- if (config != null) {
- refs.add(config);
- }
- } catch (IOException e) {
- // Ignore the failure reading refs/meta/config.
- }
-
- for (Ref ref : refs) {
- if (ref.isSymbolic()) {
- targets.add(ref.getTarget().getName());
- }
+ Set<String> targets = Sets.newHashSetWithExpectedSize(1);
+ for (Ref ref : refs) {
+ if (ref.isSymbolic()) {
+ targets.add(ref.getTarget().getName());
}
+ }
- for (Ref ref : refs) {
- if (ref.isSymbolic()) {
- // A symbolic reference to another branch, instead of
- // showing the resolved value, show the name it references.
- //
- String target = ref.getTarget().getName();
- RefControl targetRefControl = rsrc.getControl().controlForRef(target);
- if (!targetRefControl.isVisible()) {
- continue;
- }
- if (target.startsWith(Constants.R_HEADS)) {
- target = target.substring(Constants.R_HEADS.length());
- }
-
- BranchInfo b = new BranchInfo(ref.getName(), target, false);
-
- if (Constants.HEAD.equals(ref.getName())) {
- headBranch = b;
- } else {
- b.setCanDelete(targetRefControl.canDelete());
- branches.add(b);
- }
+ List<BranchInfo> branches = new ArrayList<>(refs.size());
+ for (Ref ref : refs) {
+ if (ref.isSymbolic()) {
+ // A symbolic reference to another branch, instead of
+ // showing the resolved value, show the name it references.
+ //
+ String target = ref.getTarget().getName();
+ RefControl targetRefControl = rsrc.getControl().controlForRef(target);
+ if (!targetRefControl.isVisible()) {
continue;
}
-
- final RefControl refControl = rsrc.getControl().controlForRef(ref.getName());
- if (refControl.isVisible()) {
- if (RefNames.REFS_CONFIG.equals(ref.getName())) {
- configBranch = createBranchInfo(ref, refControl, targets);
- } else {
- branches.add(createBranchInfo(ref, refControl, targets));
- }
+ if (target.startsWith(Constants.R_HEADS)) {
+ target = target.substring(Constants.R_HEADS.length());
}
- }
- } finally {
- db.close();
- }
- Collections.sort(branches, new Comparator<BranchInfo>() {
- @Override
- public int compare(final BranchInfo a, final BranchInfo b) {
- return a.ref.compareTo(b.ref);
- }
- });
- if (configBranch != null) {
- branches.add(0, configBranch);
- }
- if (headBranch != null) {
- branches.add(0, headBranch);
- }
- List<BranchInfo> filteredBranches;
- if ((matchSubstring != null && !matchSubstring.isEmpty())
- || (matchRegex != null && !matchRegex.isEmpty())) {
- filteredBranches = filterBranches(branches);
- } else {
- filteredBranches = branches;
- }
- if (!filteredBranches.isEmpty()) {
- int end = filteredBranches.size();
- if (limit > 0 && start + limit < end) {
- end = start + limit;
+ BranchInfo b = new BranchInfo();
+ b.ref = ref.getName();
+ b.revision = target;
+ branches.add(b);
+
+ if (!Constants.HEAD.equals(ref.getName())) {
+ b.canDelete = targetRefControl.canDelete() ? true : null;
+ }
+ continue;
}
- if (start <= end) {
- filteredBranches = filteredBranches.subList(start, end);
- } else {
- filteredBranches = Collections.emptyList();
+
+ RefControl refControl = rsrc.getControl().controlForRef(ref.getName());
+ if (refControl.isVisible()) {
+ branches.add(createBranchInfo(ref, refControl, targets));
}
}
- return filteredBranches;
+ Collections.sort(branches, new BranchComparator());
+ return FluentIterable.from(branches);
}
- private List<BranchInfo> filterBranches(List<BranchInfo> branches)
- throws BadRequestException {
- if (matchSubstring != null) {
- return Lists.newArrayList(Iterables.filter(branches,
- new Predicate<BranchInfo>() {
- @Override
- public boolean apply(BranchInfo in) {
- if (!in.ref.startsWith(Constants.R_HEADS)){
- return in.ref.toLowerCase(Locale.US).contains(
- matchSubstring.toLowerCase(Locale.US));
- } else {
- return in.ref.substring(Constants.R_HEADS.length())
- .toLowerCase(Locale.US)
- .contains(matchSubstring.toLowerCase(Locale.US));
- }
- }
- }));
- } else if (matchRegex != null) {
- if (matchRegex.startsWith("^")) {
- matchRegex = matchRegex.substring(1);
- if (matchRegex.endsWith("$") && !matchRegex.endsWith("\\$")) {
- matchRegex = matchRegex.substring(0, matchRegex.length() - 1);
- }
- }
- if (matchRegex.equals(".*")) {
- return branches;
- }
- try {
- final RunAutomaton a =
- new RunAutomaton(new RegExp(matchRegex).toAutomaton());
- return Lists.newArrayList(Iterables.filter(
- branches, new Predicate<BranchInfo>() {
- @Override
- public boolean apply(BranchInfo in) {
- if (!in.ref.startsWith(Constants.R_HEADS)){
- return a.run(in.ref);
- } else {
- return a.run(in.ref.substring(Constants.R_HEADS.length()));
- }
- }
- }));
- } catch (IllegalArgumentException e) {
- throw new BadRequestException(e.getMessage());
- }
+ private static class BranchComparator implements Comparator<BranchInfo> {
+ @Override
+ public int compare(BranchInfo a, BranchInfo b) {
+ return ComparisonChain.start()
+ .compareTrueFirst(isHead(a), isHead(b))
+ .compareTrueFirst(isConfig(a), isConfig(b))
+ .compare(a.ref, b.ref)
+ .result();
+ }
+
+ private static boolean isHead(BranchInfo i) {
+ return Constants.HEAD.equals(i.ref);
+ }
+
+ private static boolean isConfig(BranchInfo i) {
+ return RefNames.REFS_CONFIG.equals(i.ref);
+ }
+ }
+
+ private static void addRef(Repository db, List<Ref> refs, String name)
+ throws IOException {
+ Ref ref = db.getRef(name);
+ if (ref != null) {
+ refs.add(ref);
+ }
+ }
+
+ private FluentIterable<BranchInfo> filterBranches(
+ FluentIterable<BranchInfo> branches) throws BadRequestException {
+ if (!Strings.isNullOrEmpty(matchSubstring)) {
+ branches = branches.filter(new SubstringPredicate(matchSubstring));
+ } else if (!Strings.isNullOrEmpty(matchRegex)) {
+ branches = branches.filter(new RegexPredicate(matchRegex));
}
return branches;
}
+ private static class SubstringPredicate implements Predicate<BranchInfo> {
+ private final String substring;
+
+ private SubstringPredicate(String substring) {
+ this.substring = substring.toLowerCase(Locale.US);
+ }
+
+ @Override
+ public boolean apply(BranchInfo in) {
+ String ref = in.ref;
+ if (ref.startsWith(Constants.R_HEADS)) {
+ ref = ref.substring(Constants.R_HEADS.length());
+ }
+ ref = ref.toLowerCase(Locale.US);
+ return ref.contains(substring);
+ }
+ }
+
+ private static class RegexPredicate implements Predicate<BranchInfo> {
+ private final RunAutomaton a;
+
+ private RegexPredicate(String regex) throws BadRequestException {
+ if (regex.startsWith("^")) {
+ regex = regex.substring(1);
+ if (regex.endsWith("$") && !regex.endsWith("\\$")) {
+ regex = regex.substring(0, regex.length() - 1);
+ }
+ }
+ try {
+ a = new RunAutomaton(new RegExp(regex).toAutomaton());
+ } catch (IllegalArgumentException e) {
+ throw new BadRequestException(e.getMessage());
+ }
+ }
+
+ @Override
+ public boolean apply(BranchInfo in) {
+ if (!in.ref.startsWith(Constants.R_HEADS)){
+ return a.run(in.ref);
+ } else {
+ return a.run(in.ref.substring(Constants.R_HEADS.length()));
+ }
+ }
+ }
+
private BranchInfo createBranchInfo(Ref ref, RefControl refControl,
Set<String> targets) {
- BranchInfo info = new BranchInfo(ref.getName(),
- ref.getObjectId() != null ? ref.getObjectId().name() : null,
- !targets.contains(ref.getName()) && refControl.canDelete());
+ BranchInfo info = new BranchInfo();
+ info.ref = ref.getName();
+ info.revision = ref.getObjectId() != null ? ref.getObjectId().name() : null;
+ info.canDelete = !targets.contains(ref.getName()) && refControl.canDelete()
+ ? true : null;
for (UiAction.Description d : UiActions.from(
branchViews,
new BranchResource(refControl.getProjectControl(), info),
@@ -262,22 +268,4 @@
info.webLinks = links.isEmpty() ? null : links.toList();
return info;
}
-
- public static class BranchInfo {
- public String ref;
- public String revision;
- public Boolean canDelete;
- public Map<String, ActionInfo> actions;
- public List<WebLinkInfo> webLinks;
-
- public BranchInfo(String ref, String revision, boolean canDelete) {
- this.ref = ref;
- this.revision = revision;
- this.canDelete = canDelete;
- }
-
- void setCanDelete(boolean canDelete) {
- this.canDelete = canDelete ? true : null;
- }
- }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java
index a9851e4..2d8757e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java
@@ -66,6 +66,7 @@
import java.util.Locale;
import java.util.Map;
import java.util.Set;
+import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
@@ -236,12 +237,12 @@
return apply();
}
- public Map<String, ProjectInfo> apply() throws BadRequestException {
+ public SortedMap<String, ProjectInfo> apply() throws BadRequestException {
format = OutputFormat.JSON;
return display(null);
}
- public Map<String, ProjectInfo> display(OutputStream displayOutputStream)
+ public SortedMap<String, ProjectInfo> display(OutputStream displayOutputStream)
throws BadRequestException {
PrintWriter stdout = null;
if (displayOutputStream != null) {
@@ -255,7 +256,7 @@
int foundIndex = 0;
int found = 0;
- Map<String, ProjectInfo> output = Maps.newTreeMap();
+ TreeMap<String, ProjectInfo> output = Maps.newTreeMap();
Map<String, String> hiddenNames = Maps.newHashMap();
Set<String> rejected = new HashSet<>();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/PerformCreateProject.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/PerformCreateProject.java
deleted file mode 100644
index 689920b..0000000
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/PerformCreateProject.java
+++ /dev/null
@@ -1,304 +0,0 @@
-// Copyright (C) 2011 The Android Open Source Project
-//
-// 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
-
-package com.google.gerrit.server.project;
-
-import com.google.common.base.MoreObjects;
-import com.google.gerrit.common.ProjectUtil;
-import com.google.gerrit.common.data.AccessSection;
-import com.google.gerrit.common.data.GroupDescription;
-import com.google.gerrit.common.data.GroupReference;
-import com.google.gerrit.common.data.Permission;
-import com.google.gerrit.common.data.PermissionRule;
-import com.google.gerrit.common.errors.ProjectCreationFailedException;
-import com.google.gerrit.extensions.client.SubmitType;
-import com.google.gerrit.extensions.events.NewProjectCreatedListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
-import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.reviewdb.client.RefNames;
-import com.google.gerrit.server.GerritPersonIdent;
-import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.account.GroupBackend;
-import com.google.gerrit.server.config.GerritServerConfig;
-import com.google.gerrit.server.config.ProjectOwnerGroups;
-import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
-import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.git.MetaDataUpdate;
-import com.google.gerrit.server.git.ProjectConfig;
-import com.google.gerrit.server.git.RepositoryCaseMismatchException;
-import com.google.inject.Inject;
-import com.google.inject.assistedinject.Assisted;
-
-import org.eclipse.jgit.errors.ConfigInvalidException;
-import org.eclipse.jgit.errors.RepositoryNotFoundException;
-import org.eclipse.jgit.lib.CommitBuilder;
-import org.eclipse.jgit.lib.Config;
-import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.ObjectInserter;
-import org.eclipse.jgit.lib.PersonIdent;
-import org.eclipse.jgit.lib.RefUpdate;
-import org.eclipse.jgit.lib.RefUpdate.Result;
-import org.eclipse.jgit.lib.Repository;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-
-
-/** Common class that holds the code to create projects */
-public class PerformCreateProject {
- private static final Logger log = LoggerFactory
- .getLogger(PerformCreateProject.class);
-
- public interface Factory {
- PerformCreateProject create(CreateProjectArgs createProjectArgs);
- }
-
- private final Config cfg;
- private final Set<AccountGroup.UUID> projectOwnerGroups;
- private final IdentifiedUser currentUser;
- private final GitRepositoryManager repoManager;
- private final GitReferenceUpdated referenceUpdated;
- private final DynamicSet<NewProjectCreatedListener> createdListener;
- private final PersonIdent serverIdent;
- private final CreateProjectArgs createProjectArgs;
- private final ProjectCache projectCache;
- private final GroupBackend groupBackend;
- private final MetaDataUpdate.User metaDataUpdateFactory;
-
- @Inject
- PerformCreateProject(@GerritServerConfig Config cfg,
- @ProjectOwnerGroups Set<AccountGroup.UUID> pOwnerGroups,
- IdentifiedUser identifiedUser, GitRepositoryManager gitRepoManager,
- GitReferenceUpdated referenceUpdated,
- DynamicSet<NewProjectCreatedListener> createdListener,
- @GerritPersonIdent PersonIdent personIdent, GroupBackend groupBackend,
- MetaDataUpdate.User metaDataUpdateFactory,
- @Assisted CreateProjectArgs createPArgs, ProjectCache pCache) {
- this.cfg = cfg;
- this.projectOwnerGroups = pOwnerGroups;
- this.currentUser = identifiedUser;
- this.repoManager = gitRepoManager;
- this.referenceUpdated = referenceUpdated;
- this.createdListener = createdListener;
- this.serverIdent = personIdent;
- this.createProjectArgs = createPArgs;
- this.projectCache = pCache;
- this.groupBackend = groupBackend;
- this.metaDataUpdateFactory = metaDataUpdateFactory;
- }
-
- public Project createProject() throws ProjectCreationFailedException {
- validateParameters();
- final Project.NameKey nameKey = createProjectArgs.getProject();
- try {
- final String head =
- createProjectArgs.permissionsOnly ? RefNames.REFS_CONFIG
- : createProjectArgs.branch.get(0);
- final Repository repo = repoManager.createRepository(nameKey);
- try {
- NewProjectCreatedListener.Event event = new NewProjectCreatedListener.Event() {
- @Override
- public String getProjectName() {
- return nameKey.get();
- }
-
- @Override
- public String getHeadName() {
- return head;
- }
- };
- for (NewProjectCreatedListener l : createdListener) {
- try {
- l.onNewProjectCreated(event);
- } catch (RuntimeException e) {
- log.warn("Failure in NewProjectCreatedListener", e);
- }
- }
-
- final RefUpdate u = repo.updateRef(Constants.HEAD);
- u.disableRefLog();
- u.link(head);
-
- createProjectConfig();
-
- if (!createProjectArgs.permissionsOnly
- && createProjectArgs.createEmptyCommit) {
- createEmptyCommits(repo, nameKey, createProjectArgs.branch);
- }
-
- return projectCache.get(nameKey).getProject();
- } finally {
- repo.close();
- }
- } catch (RepositoryCaseMismatchException e) {
- throw new ProjectCreationFailedException("Cannot create " + nameKey.get()
- + " because the name is already occupied by another project."
- + " The other project has the same name, only spelled in a"
- + " different case.", e);
- } catch (RepositoryNotFoundException badName) {
- throw new ProjectCreationFailedException("Cannot create " + nameKey, badName);
- } catch (IllegalStateException err) {
- try {
- final Repository repo = repoManager.openRepository(nameKey);
- try {
- if (repo.getObjectDatabase().exists()) {
- throw new ProjectCreationFailedException("project \"" + nameKey + "\" exists");
- }
- throw err;
- } finally {
- repo.close();
- }
- } catch (IOException ioErr) {
- final String msg = "Cannot create " + nameKey;
- log.error(msg, err);
- throw new ProjectCreationFailedException(msg, ioErr);
- }
- } catch (Exception e) {
- final String msg = "Cannot create " + nameKey;
- log.error(msg, e);
- throw new ProjectCreationFailedException(msg, e);
- }
- }
-
- private void createProjectConfig() throws IOException, ConfigInvalidException {
- final MetaDataUpdate md =
- metaDataUpdateFactory.create(createProjectArgs.getProject());
- try {
- final ProjectConfig config = ProjectConfig.read(md);
- config.load(md);
-
- Project newProject = config.getProject();
- newProject.setDescription(createProjectArgs.projectDescription);
- newProject.setSubmitType(MoreObjects.firstNonNull(createProjectArgs.submitType,
- cfg.getEnum("repository", "*", "defaultSubmitType", SubmitType.MERGE_IF_NECESSARY)));
- newProject
- .setUseContributorAgreements(createProjectArgs.contributorAgreements);
- newProject.setUseSignedOffBy(createProjectArgs.signedOffBy);
- newProject.setUseContentMerge(createProjectArgs.contentMerge);
- newProject.setCreateNewChangeForAllNotInTarget(createProjectArgs.newChangeForAllNotInTarget);
- newProject.setRequireChangeID(createProjectArgs.changeIdRequired);
- newProject.setMaxObjectSizeLimit(createProjectArgs.maxObjectSizeLimit);
- if (createProjectArgs.newParent != null) {
- newProject.setParentName(createProjectArgs.newParent.getProject()
- .getNameKey());
- }
-
- if (!createProjectArgs.ownerIds.isEmpty()) {
- final AccessSection all =
- config.getAccessSection(AccessSection.ALL, true);
- for (AccountGroup.UUID ownerId : createProjectArgs.ownerIds) {
- GroupDescription.Basic g = groupBackend.get(ownerId);
- if (g != null) {
- GroupReference group = config.resolve(GroupReference.forGroup(g));
- all.getPermission(Permission.OWNER, true).add(
- new PermissionRule(group));
- }
- }
- }
-
- md.setMessage("Created project\n");
- config.commit(md);
- } finally {
- md.close();
- }
- projectCache.onCreateProject(createProjectArgs.getProject());
- repoManager.setProjectDescription(createProjectArgs.getProject(),
- createProjectArgs.projectDescription);
- }
-
- private void validateParameters() throws ProjectCreationFailedException {
- if (createProjectArgs.getProjectName() == null
- || createProjectArgs.getProjectName().isEmpty()) {
- throw new ProjectCreationFailedException("Project name is required");
- }
-
- String nameWithoutSuffix = ProjectUtil.stripGitSuffix(createProjectArgs.getProjectName());
- createProjectArgs.setProjectName(nameWithoutSuffix);
-
- if (!currentUser.getCapabilities().canCreateProject()) {
- throw new ProjectCreationFailedException(String.format(
- "%s does not have \"Create Project\" capability.",
- currentUser.getUserName()));
- }
-
- if (createProjectArgs.ownerIds == null
- || createProjectArgs.ownerIds.isEmpty()) {
- createProjectArgs.ownerIds = new ArrayList<>(projectOwnerGroups);
- }
-
- List<String> transformedBranches = new ArrayList<>();
- if (createProjectArgs.branch == null ||
- createProjectArgs.branch.isEmpty()) {
- createProjectArgs.branch = Collections.singletonList(Constants.MASTER);
- }
- for (String branch : createProjectArgs.branch) {
- while (branch.startsWith("/")) {
- branch = branch.substring(1);
- }
- if (!branch.startsWith(Constants.R_HEADS)) {
- branch = Constants.R_HEADS + branch;
- }
- if (!Repository.isValidRefName(branch)) {
- throw new ProjectCreationFailedException(String.format(
- "Branch \"%s\" is not a valid name.", branch));
- }
- if (!transformedBranches.contains(branch)) {
- transformedBranches.add(branch);
- }
- }
- createProjectArgs.branch = transformedBranches;
- }
-
- private void createEmptyCommits(final Repository repo,
- final Project.NameKey project, final List<String> refs)
- throws IOException {
- try (ObjectInserter oi = repo.newObjectInserter()) {
- CommitBuilder cb = new CommitBuilder();
- cb.setTreeId(oi.insert(Constants.OBJ_TREE, new byte[] {}));
- cb.setAuthor(metaDataUpdateFactory.getUserPersonIdent());
- cb.setCommitter(serverIdent);
- cb.setMessage("Initial empty repository\n");
-
- ObjectId id = oi.insert(cb);
- oi.flush();
-
- for (String ref : refs) {
- RefUpdate ru = repo.updateRef(ref);
- ru.setNewObjectId(id);
- final Result result = ru.update();
- switch (result) {
- case NEW:
- referenceUpdated.fire(project, ru);
- break;
- default: {
- throw new IOException(String.format(
- "Failed to create ref \"%s\": %s", ref, result.name()));
- }
- }
- }
- } catch (IOException e) {
- log.error(
- "Cannot create empty commit for "
- + createProjectArgs.getProjectName(), e);
- throw e;
- }
- }
-}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
index 558b572..10b64a0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
@@ -22,7 +22,6 @@
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
-import com.google.common.io.Files;
import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.GroupReference;
import com.google.gerrit.common.data.LabelType;
@@ -46,7 +45,7 @@
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
-import com.googlecode.prolog_cafe.compiler.CompileException;
+import com.googlecode.prolog_cafe.exceptions.CompileException;
import com.googlecode.prolog_cafe.lang.PrologMachineCopy;
import org.eclipse.jgit.errors.ConfigInvalidException;
@@ -55,9 +54,10 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.File;
import java.io.IOException;
-import java.io.InputStream;
+import java.io.Reader;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -205,10 +205,10 @@
* read the provided input stream.
*
* @param name a name of the input stream. Could be any name.
- * @param in InputStream to read prolog rules from
+ * @param in stream to read prolog rules from
* @throws CompileException
*/
- public PrologEnvironment newPrologEnvironment(String name, InputStream in)
+ public PrologEnvironment newPrologEnvironment(String name, Reader in)
throws CompileException {
PrologMachineCopy pmc = rulesCache.loadMachine(name, in);
return envFactory.create(pmc);
@@ -488,25 +488,25 @@
private ThemeInfo loadTheme() {
String name = getConfig().getProject().getName();
- File dir = new File(sitePaths.themes_dir, name);
- if (!dir.exists()) {
+ Path dir = sitePaths.themes_dir.resolve(name);
+ if (!Files.exists(dir)) {
return ThemeInfo.INHERIT;
- } else if (!dir.isDirectory()) {
+ } else if (!Files.isDirectory(dir)) {
log.warn("Bad theme for {}: not a directory", name);
return ThemeInfo.INHERIT;
}
try {
- return new ThemeInfo(readFile(new File(dir, SitePaths.CSS_FILENAME)),
- readFile(new File(dir, SitePaths.HEADER_FILENAME)),
- readFile(new File(dir, SitePaths.FOOTER_FILENAME)));
+ return new ThemeInfo(readFile(dir.resolve(SitePaths.CSS_FILENAME)),
+ readFile(dir.resolve(SitePaths.HEADER_FILENAME)),
+ readFile(dir.resolve(SitePaths.FOOTER_FILENAME)));
} catch (IOException e) {
log.error("Error reading theme for " + name, e);
return ThemeInfo.INHERIT;
}
}
- private String readFile(File f) throws IOException {
- return f.exists() ? Files.toString(f, UTF_8) : null;
+ private String readFile(Path p) throws IOException {
+ return Files.exists(p) ? new String(Files.readAllBytes(p), UTF_8) : null;
}
private boolean getInheritableBoolean(Function<Project, InheritableBoolean> func) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/PutDescription.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/PutDescription.java
index 536bfa7..1d7c724 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/PutDescription.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/PutDescription.java
@@ -17,8 +17,8 @@
import com.google.common.base.MoreObjects;
import com.google.common.base.Strings;
import com.google.gerrit.common.ChangeHooks;
+import com.google.gerrit.extensions.api.projects.PutDescriptionInput;
import com.google.gerrit.extensions.restapi.AuthException;
-import com.google.gerrit.extensions.restapi.DefaultInput;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.Response;
@@ -30,7 +30,6 @@
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.ProjectConfig;
-import com.google.gerrit.server.project.PutDescription.Input;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -42,13 +41,7 @@
import java.util.Objects;
@Singleton
-class PutDescription implements RestModifyView<ProjectResource, Input> {
- static class Input {
- @DefaultInput
- String description;
- String commitMessage;
- }
-
+public class PutDescription implements RestModifyView<ProjectResource, PutDescriptionInput> {
private final ProjectCache cache;
private final MetaDataUpdate.Server updateFactory;
private final GitRepositoryManager gitMgr;
@@ -66,11 +59,11 @@
}
@Override
- public Response<String> apply(ProjectResource resource, Input input)
- throws AuthException, ResourceConflictException,
- ResourceNotFoundException, IOException {
+ public Response<String> apply(ProjectResource resource,
+ PutDescriptionInput input) throws AuthException,
+ ResourceConflictException, ResourceNotFoundException, IOException {
if (input == null) {
- input = new Input(); // Delete would set description to null.
+ input = new PutDescriptionInput(); // Delete would set description to null.
}
ProjectControl ctl = resource.getControl();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
index 71c3104..e507de7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
@@ -259,6 +259,7 @@
switch (getCurrentUser().getAccessPath()) {
case REST_API:
case JSON_RPC:
+ case UNKNOWN:
owner = isOwner();
admin = getCurrentUser().getCapabilities().canAdministrateServer();
break;
@@ -364,18 +365,13 @@
}
switch (getCurrentUser().getAccessPath()) {
- case REST_API:
- case JSON_RPC:
- case SSH_COMMAND:
- return getCurrentUser().getCapabilities().canAdministrateServer()
- || (isOwner() && !isForceBlocked(Permission.PUSH))
- || canPushWithForce();
-
case GIT:
return canPushWithForce();
default:
- return false;
+ return getCurrentUser().getCapabilities().canAdministrateServer()
+ || (isOwner() && !isForceBlocked(Permission.PUSH))
+ || canPushWithForce();
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/SectionSortCache.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/SectionSortCache.java
index 9009aad..7b6b5c8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/SectionSortCache.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/SectionSortCache.java
@@ -86,7 +86,7 @@
Collections.sort(sections, new MostSpecificComparator(ref));
- int srcIdx[];
+ int[] srcIdx;
if (isIdentityTransform(sections, srcMap)) {
srcIdx = null;
} else {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/SetHead.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/SetHead.java
index 77c221c..07c0162 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/SetHead.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/SetHead.java
@@ -23,6 +23,7 @@
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
+import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.project.SetHead.Input;
@@ -43,9 +44,9 @@
public class SetHead implements RestModifyView<ProjectResource, Input> {
private static final Logger log = LoggerFactory.getLogger(SetHead.class);
- static class Input {
+ public static class Input {
@DefaultInput
- String ref;
+ public String ref;
}
private final GitRepositoryManager repoManager;
@@ -71,10 +72,7 @@
if (input == null || Strings.isNullOrEmpty(input.ref)) {
throw new BadRequestException("ref required");
}
- String ref = input.ref;
- if (!ref.startsWith(Constants.R_REFS)) {
- ref = Constants.R_HEADS + ref;
- }
+ String ref = RefNames.fullName(input.ref);
Repository repo = null;
try {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
index 4df9831..e8e29c1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
@@ -16,7 +16,6 @@
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
-import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.collect.Lists;
import com.google.gerrit.common.Nullable;
@@ -27,13 +26,13 @@
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.rules.PrologEnvironment;
-import com.google.gerrit.rules.ReductionLimitException;
import com.google.gerrit.rules.StoredValues;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gwtorm.server.OrmException;
-import com.googlecode.prolog_cafe.compiler.CompileException;
+import com.googlecode.prolog_cafe.exceptions.CompileException;
+import com.googlecode.prolog_cafe.exceptions.ReductionLimitException;
import com.googlecode.prolog_cafe.lang.IntegerTerm;
import com.googlecode.prolog_cafe.lang.ListTerm;
import com.googlecode.prolog_cafe.lang.Prolog;
@@ -45,7 +44,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.ByteArrayInputStream;
+import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -107,7 +106,7 @@
private boolean skipFilters;
private String rule;
private boolean logErrors = true;
- private int reductionsConsumed;
+ private long reductionsConsumed;
private Term submitRule;
@@ -185,7 +184,7 @@
}
/** @return Prolog reductions consumed during evaluation. */
- public int getReductionsConsumed() {
+ public long getReductionsConsumed() {
return reductionsConsumed;
}
@@ -270,7 +269,7 @@
SubmitRecord rec = new SubmitRecord();
out.add(rec);
- if (!submitRecord.isStructure() || 1 != submitRecord.arity()) {
+ if (!(submitRecord instanceof StructureTerm) || 1 != submitRecord.arity()) {
return invalidResult(submitRule, submitRecord);
}
@@ -289,14 +288,16 @@
//
submitRecord = submitRecord.arg(0);
- if (!submitRecord.isStructure()) {
+ if (!(submitRecord instanceof StructureTerm)) {
return invalidResult(submitRule, submitRecord);
}
rec.labels = new ArrayList<>(submitRecord.arity());
for (Term state : ((StructureTerm) submitRecord).args()) {
- if (!state.isStructure() || 2 != state.arity() || !"label".equals(state.name())) {
+ if (!(state instanceof StructureTerm)
+ || 2 != state.arity()
+ || !"label".equals(state.name())) {
return invalidResult(submitRule, submitRecord);
}
@@ -414,7 +415,7 @@
}
Term typeTerm = results.get(0);
- if (!typeTerm.isSymbol()) {
+ if (!(typeTerm instanceof SymbolTerm)) {
return typeError("Submit rule '" + getSubmitRule() + "' for change "
+ cd.getId() + " of " + getProjectName()
+ " did not return a symbol.");
@@ -485,9 +486,9 @@
resultsTerm, env, filterRuleLocatorName, filterRuleWrapperName);
}
List<Term> r;
- if (resultsTerm.isList()) {
+ if (resultsTerm instanceof ListTerm) {
r = Lists.newArrayList();
- for (Term t = resultsTerm; t.isList();) {
+ for (Term t = resultsTerm; t instanceof ListTerm;) {
ListTerm l = (ListTerm) t;
r.add(l.car().dereference());
t = l.cdr().dereference();
@@ -510,12 +511,20 @@
if (rule == null) {
env = projectState.newPrologEnvironment();
} else {
- env = projectState.newPrologEnvironment(
- "stdin", new ByteArrayInputStream(rule.getBytes(UTF_8)));
+ env = projectState.newPrologEnvironment("stdin", new StringReader(rule));
}
} catch (CompileException err) {
- throw new RuleEvalException("Cannot consult rules.pl for "
- + getProjectName(), err);
+ String msg;
+ if (rule == null && control.getProjectControl().isOwner()) {
+ msg = String.format(
+ "Cannot load rules.pl for %s: %s",
+ getProjectName(), err.getMessage());
+ } else if (rule != null) {
+ msg = err.getMessage();
+ } else {
+ msg = String.format("Cannot load rules.pl for %s", getProjectName());
+ }
+ throw new RuleEvalException(msg, err);
}
env.set(StoredValues.REVIEW_DB, cd.db());
env.set(StoredValues.CHANGE_DATA, cd);
@@ -578,7 +587,7 @@
private void appliedBy(SubmitRecord.Label label, Term status)
throws UserTermExpected {
- if (status.isStructure() && status.arity() == 1) {
+ if (status instanceof StructureTerm && status.arity() == 1) {
Term who = status.arg(0);
if (isUser(who)) {
label.appliedBy = new Account.Id(((IntegerTerm) who.arg(0)).intValue());
@@ -589,10 +598,10 @@
}
private static boolean isUser(Term who) {
- return who.isStructure()
+ return who instanceof StructureTerm
&& who.arity() == 1
&& who.name().equals("user")
- && who.arg(0).isInteger();
+ && who.arg(0) instanceof IntegerTerm;
}
public Term getSubmitRule() {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/IntPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/IntPredicate.java
index e3750fa..d336bb5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/IntPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/IntPredicate.java
@@ -39,8 +39,9 @@
@Override
public boolean equals(final Object other) {
- if (other == null)
+ if (other == null) {
return false;
+ }
if (getClass() == other.getClass()) {
final IntPredicate<?> p = (IntPredicate<?>) other;
return getOperator().equals(p.getOperator())
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/NotPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/NotPredicate.java
index 6a9a877..248fb9c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/NotPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/NotPredicate.java
@@ -74,8 +74,9 @@
@Override
public boolean equals(final Object other) {
- if (other == null)
+ if (other == null) {
return false;
+ }
return getClass() == other.getClass()
&& getChildren().equals(((Predicate<?>) other).getChildren());
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/OperatorPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/OperatorPredicate.java
index 899fc3b..87460d2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/OperatorPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/OperatorPredicate.java
@@ -50,8 +50,9 @@
@Override
public boolean equals(final Object other) {
- if (other == null)
+ if (other == null) {
return false;
+ }
if (getClass() == other.getClass()) {
final OperatorPredicate<?> p = (OperatorPredicate<?>) other;
return getOperator().equals(p.getOperator())
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/OrPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/OrPredicate.java
index 845c805..2432a41 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/OrPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/OrPredicate.java
@@ -92,8 +92,9 @@
@Override
public boolean equals(final Object other) {
- if (other == null)
+ if (other == null) {
return false;
+ }
return getClass() == other.getClass()
&& getChildren().equals(((Predicate<?>) other).getChildren());
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/QueryBuilder.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/QueryBuilder.java
index bd1fa0c..b3c6aeb 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/QueryBuilder.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/QueryBuilder.java
@@ -370,9 +370,6 @@
} catch (IllegalAccessException e) {
throw error("Error in operator " + name + ":" + value, e);
} catch (InvocationTargetException e) {
- if (e.getCause() instanceof QueryParseException) {
- throw (QueryParseException) e.getCause();
- }
throw error("Error in operator " + name + ":" + value, e.getCause());
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/VariablePredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/VariablePredicate.java
index d6d0f9c..e298e5f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/VariablePredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/VariablePredicate.java
@@ -81,8 +81,9 @@
@Override
public boolean equals(final Object other) {
- if (other == null)
+ if (other == null) {
return false;
+ }
if (getClass() == other.getClass()) {
final VariablePredicate<?> v = (VariablePredicate<?>) other;
return getName().equals(v.getName())
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/WildPatternPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/WildPatternPredicate.java
index 48f3898..981051b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/WildPatternPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/WildPatternPredicate.java
@@ -45,8 +45,9 @@
@Override
public boolean equals(final Object other) {
- if (other == null)
+ if (other == null) {
return false;
+ }
if (getClass() == other.getClass()) {
final WildPatternPredicate<?> p = (WildPatternPredicate<?>) other;
return getOperator().equals(p.getOperator());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/BasicChangeRewrites.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/BasicChangeRewrites.java
index 1053d92..d167860 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/BasicChangeRewrites.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/BasicChangeRewrites.java
@@ -29,7 +29,7 @@
new InvalidProvider<InternalChangeQuery>(),
new InvalidProvider<ChangeQueryRewriter>(),
null, null, null, null, null, null, null, null, null, null, null,
- null, null, null, null, null, null, null, null));
+ null, null, null, null, null, null, null, null, null));
private static final QueryRewriter.Definition<ChangeData, BasicChangeRewrites> mydef =
new QueryRewriter.Definition<>(BasicChangeRewrites.class, BUILDER);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
index e4e94a1..5c023e2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
@@ -119,7 +119,7 @@
public static void ensureAllPatchSetsLoaded(Iterable<ChangeData> changes)
throws OrmException {
for (ChangeData cd : changes) {
- cd.patches();
+ cd.patchSets();
}
}
@@ -127,7 +127,7 @@
throws OrmException {
Map<PatchSet.Id, ChangeData> missing = Maps.newHashMap();
for (ChangeData cd : changes) {
- if (cd.currentPatchSet == null && cd.patches == null) {
+ if (cd.currentPatchSet == null && cd.patchSets == null) {
missing.put(cd.change().currentPatchSetId(), cd);
}
}
@@ -172,12 +172,13 @@
/**
* Create an instance for testing only.
* <p>
- * Attempting to lazy load data will fail with NPEs.
+ * Attempting to lazy load data will fail with NPEs. Callers may consider
+ * manually setting fields that can be set.
*
* @param id change ID
* @return instance for testing.
*/
- static ChangeData createForTest(Change.Id id, int currentPatchSetId) {
+ public static ChangeData createForTest(Change.Id id, int currentPatchSetId) {
ChangeData cd = new ChangeData(null, null, null, null, null, null, null,
null, null, null, null, null, null, id);
cd.currentPatchSet = new PatchSet(new PatchSet.Id(id, currentPatchSetId));
@@ -204,7 +205,7 @@
private String commitMessage;
private List<FooterLine> commitFooters;
private PatchSet currentPatchSet;
- private Collection<PatchSet> patches;
+ private Collection<PatchSet> patchSets;
private ListMultimap<PatchSet.Id, PatchSetApproval> allApprovals;
private List<PatchSetApproval> currentApprovals;
private Map<Integer, List<String>> files = new HashMap<>();
@@ -450,6 +451,10 @@
return change;
}
+ public void setChange(Change c) {
+ change = c;
+ }
+
public Change reloadChange() throws OrmException {
change = db.changes().get(legacyId);
return change;
@@ -468,7 +473,7 @@
if (c == null) {
return null;
}
- for (PatchSet p : patches()) {
+ for (PatchSet p : patchSets()) {
if (p.getId().equals(c.currentPatchSetId())) {
currentPatchSet = p;
return p;
@@ -536,23 +541,28 @@
* @return patches for the change.
* @throws OrmException an error occurred reading the database.
*/
- public Collection<PatchSet> patches()
+ public Collection<PatchSet> patchSets()
throws OrmException {
- if (patches == null) {
- patches = db.patchSets().byChange(legacyId).toList();
+ if (patchSets == null) {
+ patchSets = db.patchSets().byChange(legacyId).toList();
}
- return patches;
+ return patchSets;
+ }
+
+ public void setPatchSets(Collection<PatchSet> patchSets) {
+ this.currentPatchSet = null;
+ this.patchSets = patchSets;
}
/**
- * @return patch with the given ID, or null if it does not exist.
+ * @return patch set with the given ID, or null if it does not exist.
* @throws OrmException an error occurred reading the database.
*/
- public PatchSet patch(PatchSet.Id psId) throws OrmException {
+ public PatchSet patchSet(PatchSet.Id psId) throws OrmException {
if (currentPatchSet != null && currentPatchSet.getId().equals(psId)) {
return currentPatchSet;
}
- for (PatchSet ps : patches()) {
+ for (PatchSet ps : patchSets()) {
if (ps.getId().equals(psId)) {
return ps;
}
@@ -602,7 +612,7 @@
return submitRecords;
}
- public void setMergeable(boolean mergeable) {
+ public void setMergeable(Boolean mergeable) {
this.mergeable = mergeable;
}
@@ -619,9 +629,7 @@
if (ps == null || !changeControl().isPatchVisible(ps, db)) {
return null;
}
- Repository repo = null;
- try {
- repo = repoManager.openRepository(c.getProject());
+ try (Repository repo = repoManager.openRepository(c.getProject())) {
Ref ref = repo.getRef(c.getDest().get());
SubmitTypeRecord rec = new SubmitRuleEvaluator(this)
.getSubmitType();
@@ -637,10 +645,6 @@
ref, rec.type, mergeStrategy, c.getDest(), repo, db);
} catch (IOException e) {
throw new OrmException(e);
- } finally {
- if (repo != null) {
- repo.close();
- }
}
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
index c9d7e6c..e64b53f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
@@ -19,13 +19,12 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
import com.google.common.collect.Lists;
-import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.data.GroupReference;
import com.google.gerrit.common.errors.NotSignedInException;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
@@ -34,8 +33,11 @@
import com.google.gerrit.server.account.CapabilityControl;
import com.google.gerrit.server.account.GroupBackend;
import com.google.gerrit.server.account.GroupBackends;
+import com.google.gerrit.server.account.VersionedAccountQueries;
import com.google.gerrit.server.change.ChangeTriplet;
import com.google.gerrit.server.config.AllProjectsName;
+import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.config.AllUsersNameProvider;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.TrackingFooters;
import com.google.gerrit.server.git.GitRepositoryManager;
@@ -57,9 +59,13 @@
import com.google.inject.ProvisionException;
import com.google.inject.util.Providers;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.AbbreviatedObjectId;
import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.Repository;
+import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@@ -88,6 +94,7 @@
public static final String FIELD_BRANCH = "branch";
public static final String FIELD_CHANGE = "change";
public static final String FIELD_COMMENT = "comment";
+ public static final String FIELD_COMMENTBY = "commentby";
public static final String FIELD_COMMIT = "commit";
public static final String FIELD_CONFLICTS = "conflicts";
public static final String FIELD_DELETED = "deleted";
@@ -107,6 +114,7 @@
public static final String FIELD_PATH = "path";
public static final String FIELD_PROJECT = "project";
public static final String FIELD_PROJECTS = "projects";
+ public static final String FIELD_QUERY = "query";
public static final String FIELD_REF = "ref";
public static final String FIELD_REVIEWER = "reviewer";
public static final String FIELD_REVIEWERIN = "reviewerin";
@@ -138,15 +146,16 @@
final AccountResolver accountResolver;
final GroupBackend groupBackend;
final AllProjectsName allProjectsName;
+ final AllUsersNameProvider allUsersName;
final PatchListCache patchListCache;
final GitRepositoryManager repoManager;
final ProjectCache projectCache;
final Provider<ListChildProjects> listChildProjects;
- final IndexCollection indexes;
final SubmitStrategyFactory submitStrategyFactory;
final ConflictsCache conflictsCache;
final TrackingFooters trackingFooters;
final boolean allowsDrafts;
+ final ChangeIndex index;
private final Provider<CurrentUser> self;
@@ -165,6 +174,7 @@
AccountResolver accountResolver,
GroupBackend groupBackend,
AllProjectsName allProjectsName,
+ AllUsersNameProvider allUsersName,
PatchListCache patchListCache,
GitRepositoryManager repoManager,
ProjectCache projectCache,
@@ -177,10 +187,11 @@
this(db, queryProvider, rewriter, userFactory, self,
capabilityControlFactory, changeControlGenericFactory,
changeDataFactory, fillArgs, plcUtil, accountResolver, groupBackend,
- allProjectsName, patchListCache, repoManager, projectCache,
- listChildProjects, indexes, submitStrategyFactory, conflictsCache,
- trackingFooters,
- cfg == null ? true : cfg.getBoolean("change", "allowDrafts", true));
+ allProjectsName, allUsersName, patchListCache, repoManager,
+ projectCache, listChildProjects, submitStrategyFactory,
+ conflictsCache, trackingFooters,
+ cfg == null ? true : cfg.getBoolean("change", "allowDrafts", true),
+ indexes != null ? indexes.getSearchIndex() : null);
}
private Arguments(
@@ -197,15 +208,16 @@
AccountResolver accountResolver,
GroupBackend groupBackend,
AllProjectsName allProjectsName,
+ AllUsersNameProvider allUsersName,
PatchListCache patchListCache,
GitRepositoryManager repoManager,
ProjectCache projectCache,
Provider<ListChildProjects> listChildProjects,
- IndexCollection indexes,
SubmitStrategyFactory submitStrategyFactory,
ConflictsCache conflictsCache,
TrackingFooters trackingFooters,
- boolean allowsDrafts) {
+ boolean allowsDrafts,
+ ChangeIndex index) {
this.db = db;
this.queryProvider = queryProvider;
this.rewriter = rewriter;
@@ -219,15 +231,16 @@
this.accountResolver = accountResolver;
this.groupBackend = groupBackend;
this.allProjectsName = allProjectsName;
+ this.allUsersName = allUsersName;
this.patchListCache = patchListCache;
this.repoManager = repoManager;
this.projectCache = projectCache;
this.listChildProjects = listChildProjects;
- this.indexes = indexes;
this.submitStrategyFactory = submitStrategyFactory;
this.conflictsCache = conflictsCache;
this.trackingFooters = trackingFooters;
this.allowsDrafts = allowsDrafts;
+ this.index = index;
}
Arguments asUser(CurrentUser otherUser) {
@@ -235,9 +248,9 @@
Providers.of(otherUser),
capabilityControlFactory, changeControlGenericFactory,
changeDataFactory, fillArgs, plcUtil, accountResolver, groupBackend,
- allProjectsName, patchListCache, repoManager, projectCache,
- listChildProjects, indexes, submitStrategyFactory, conflictsCache,
- trackingFooters, allowsDrafts);
+ allProjectsName, allUsersName, patchListCache, repoManager,
+ projectCache, listChildProjects, submitStrategyFactory,
+ conflictsCache, trackingFooters, allowsDrafts, index);
}
Arguments asUser(Account.Id otherId) {
@@ -272,6 +285,10 @@
throw new QueryParseException(NotSignedInException.MESSAGE, e);
}
}
+
+ Schema<ChangeData> getSchema() {
+ return index != null ? index.getSchema() : null;
+ }
}
private final Arguments args;
@@ -339,8 +356,7 @@
@Operator
public Predicate<ChangeData> comment(String value) {
- ChangeIndex index = args.indexes.getSearchIndex();
- return new CommentPredicate(index, value);
+ return new CommentPredicate(args.index, value);
}
@Operator
@@ -396,7 +412,7 @@
}
if ("mergeable".equalsIgnoreCase(value)) {
- return new IsMergeablePredicate(schema(args.indexes), args.fillArgs);
+ return new IsMergeablePredicate(args.getSchema(), args.fillArgs);
}
try {
@@ -426,8 +442,9 @@
@Operator
public Predicate<ChangeData> project(String name) {
- if (name.startsWith("^"))
+ if (name.startsWith("^")) {
return new RegexProjectPredicate(name);
+ }
return new ProjectPredicate(name);
}
@@ -444,15 +461,10 @@
@Operator
public Predicate<ChangeData> branch(String name) {
- if (name.startsWith("^"))
- return ref("^" + branchToRef(name.substring(1)));
- return ref(branchToRef(name));
- }
-
- private static String branchToRef(String name) {
- if (!name.startsWith(Branch.R_HEADS))
- return Branch.R_HEADS + name;
- return name;
+ if (name.startsWith("^")) {
+ return ref("^" + RefNames.fullName(name.substring(1)));
+ }
+ return ref(RefNames.fullName(name));
}
@Operator
@@ -462,15 +474,17 @@
@Operator
public Predicate<ChangeData> topic(String name) {
- if (name.startsWith("^"))
- return new RegexTopicPredicate(name);
- return new TopicPredicate(name);
+ if (name.startsWith("^")) {
+ return new RegexTopicPredicate(args.getSchema(), name);
+ }
+ return new TopicPredicate(args.getSchema(), name);
}
@Operator
public Predicate<ChangeData> ref(String ref) {
- if (ref.startsWith("^"))
+ if (ref.startsWith("^")) {
return new RegexRefPredicate(ref);
+ }
return new RefPredicate(ref);
}
@@ -553,8 +567,7 @@
@Operator
public Predicate<ChangeData> message(String text) {
- ChangeIndex index = args.indexes.getSearchIndex();
- return new MessagePredicate(index, text);
+ return new MessagePredicate(args.index, text);
}
@Operator
@@ -659,9 +672,12 @@
@Operator
public Predicate<ChangeData> owner(String who) throws QueryParseException,
OrmException {
- Set<Account.Id> m = parseAccount(who);
- List<OwnerPredicate> p = Lists.newArrayListWithCapacity(m.size());
- for (Account.Id id : m) {
+ return owner(parseAccount(who));
+ }
+
+ private Predicate<ChangeData> owner(Set<Account.Id> who) {
+ List<OwnerPredicate> p = Lists.newArrayListWithCapacity(who.size());
+ for (Account.Id id : who) {
p.add(new OwnerPredicate(id));
}
return Predicate.or(p);
@@ -743,6 +759,46 @@
return new DeltaPredicate(value);
}
+ @Operator
+ public Predicate<ChangeData> commentby(String who)
+ throws QueryParseException, OrmException {
+ return commentby(parseAccount(who));
+ }
+
+ private Predicate<ChangeData> commentby(Set<Account.Id> who) {
+ List<CommentByPredicate> p = Lists.newArrayListWithCapacity(who.size());
+ for (Account.Id id : who) {
+ p.add(new CommentByPredicate(id));
+ }
+ return Predicate.or(p);
+ }
+
+ @Operator
+ public Predicate<ChangeData> from(String who)
+ throws QueryParseException, OrmException {
+ Set<Account.Id> ownerIds = parseAccount(who);
+ return Predicate.or(owner(ownerIds), commentby(ownerIds));
+ }
+
+ @Operator
+ public Predicate<ChangeData> query(String name) throws QueryParseException {
+ AllUsersName allUsers = args.allUsersName.get();
+ try (Repository git = args.repoManager.openRepository(allUsers)) {
+ VersionedAccountQueries q = VersionedAccountQueries.forUser(self());
+ q.load(git);
+ String query = q.getQueryList().getQuery(name);
+ if (query != null) {
+ return parse(query);
+ }
+ } catch (RepositoryNotFoundException e) {
+ throw new QueryParseException("Unknown named query (no " +
+ allUsers.get() +" repo): " + name, e);
+ } catch (IOException | ConfigInvalidException e) {
+ throw new QueryParseException("Error parsing named query: " + name, e);
+ }
+ throw new QueryParseException("Unknown named query: " + name);
+ }
+
@Override
protected Predicate<ChangeData> defaultField(String query) throws QueryParseException {
if (query.startsWith("refs/")) {
@@ -834,9 +890,4 @@
private Account.Id self() throws QueryParseException {
return args.getIdentifiedUser().getAccountId();
}
-
- private static Schema<ChangeData> schema(@Nullable IndexCollection indexes) {
- ChangeIndex index = indexes != null ? indexes.getSearchIndex() : null;
- return index != null ? index.getSchema() : null;
- }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommentByPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommentByPredicate.java
new file mode 100644
index 0000000..dee7086
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommentByPredicate.java
@@ -0,0 +1,57 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.query.change;
+
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.ChangeMessage;
+import com.google.gerrit.reviewdb.client.PatchLineComment;
+import com.google.gerrit.server.index.ChangeField;
+import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gwtorm.server.OrmException;
+
+import java.util.Objects;
+
+class CommentByPredicate extends IndexPredicate<ChangeData> {
+ private final Account.Id id;
+
+ CommentByPredicate(Account.Id id) {
+ super(ChangeField.COMMENTBY, id.toString());
+ this.id = id;
+ }
+
+ Account.Id getAccountId() {
+ return id;
+ }
+
+ @Override
+ public boolean match(ChangeData cd) throws OrmException {
+ for (ChangeMessage m : cd.messages()) {
+ if (Objects.equals(m.getAuthor(), id)) {
+ return true;
+ }
+ }
+ for (PatchLineComment c : cd.publishedComments()) {
+ if (Objects.equals(c.getAuthor(), id)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public int getCost() {
+ return 1;
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommitPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommitPredicate.java
index 14daa4d..3dd7c61 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommitPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommitPredicate.java
@@ -32,7 +32,7 @@
@Override
public boolean match(final ChangeData object) throws OrmException {
- for (PatchSet p : object.patches()) {
+ for (PatchSet p : object.patchSets()) {
if (p.getRevision() != null && p.getRevision().get() != null) {
final ObjectId id = ObjectId.fromString(p.getRevision().get());
if (abbrevId.prefixCompare(id) == 0) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsFilePredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsFilePredicate.java
index e5fc51d..a21c590 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsFilePredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsFilePredicate.java
@@ -24,8 +24,7 @@
static Predicate<ChangeData> create(Arguments args, String value) {
Predicate<ChangeData> eqPath =
new EqualsPathPredicate(ChangeQueryBuilder.FIELD_FILE, value);
- if (!args.indexes.getSearchIndex().getSchema().getFields().containsKey(
- ChangeField.FILE_PART.getName())) {
+ if (!args.getSchema().hasField(ChangeField.FILE_PART)) {
return eqPath;
}
return Predicate.or(eqPath, new EqualsFilePredicate(value));
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/GroupPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/GroupPredicate.java
new file mode 100644
index 0000000..235d64e
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/GroupPredicate.java
@@ -0,0 +1,44 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.query.change;
+
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.server.index.ChangeField;
+import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gwtorm.server.OrmException;
+
+import java.util.List;
+
+class GroupPredicate extends IndexPredicate<ChangeData> {
+ GroupPredicate(String group) {
+ super(ChangeField.GROUP, group);
+ }
+
+ @Override
+ public boolean match(ChangeData cd) throws OrmException {
+ for (PatchSet ps : cd.patchSets()) {
+ List<String> groups = ps.getGroups();
+ if (groups != null && groups.contains(getValue())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public int getCost() {
+ return 1;
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/InternalChangeQuery.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/InternalChangeQuery.java
index e08847a..15b1d8c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/InternalChangeQuery.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/InternalChangeQuery.java
@@ -15,16 +15,26 @@
package com.google.gerrit.server.query.change;
import static com.google.gerrit.server.query.Predicate.and;
+import static com.google.gerrit.server.query.Predicate.or;
import static com.google.gerrit.server.query.change.ChangeStatusPredicate.open;
+import com.google.gerrit.common.Nullable;
import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.index.ChangeIndex;
+import com.google.gerrit.server.index.IndexCollection;
+import com.google.gerrit.server.index.Schema;
import com.google.gerrit.server.query.Predicate;
import com.google.gerrit.server.query.QueryParseException;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
+import org.eclipse.jgit.lib.AbbreviatedObjectId;
+import org.eclipse.jgit.lib.ObjectId;
+
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
/**
@@ -52,15 +62,18 @@
return new ChangeStatusPredicate(status);
}
- private static Predicate<ChangeData> topic(String topic) {
- return new TopicPredicate(topic);
+ private static Predicate<ChangeData> commit(AbbreviatedObjectId id) {
+ return new CommitPredicate(id);
}
private final QueryProcessor qp;
+ private final IndexCollection indexes;
@Inject
- InternalChangeQuery(QueryProcessor queryProcessor) {
+ InternalChangeQuery(QueryProcessor queryProcessor,
+ IndexCollection indexes) {
qp = queryProcessor.enforceVisibility(false);
+ this.indexes = indexes;
}
public InternalChangeQuery setLimit(int n) {
@@ -73,6 +86,10 @@
return this;
}
+ private Predicate<ChangeData> topic(String topic) {
+ return new TopicPredicate(schema(indexes), topic);
+ }
+
public List<ChangeData> byKey(Change.Key key) throws OrmException {
return byKeyPrefix(key.get());
}
@@ -123,6 +140,23 @@
return query(and(topic(topic), open()));
}
+ public List<ChangeData> byCommitPrefix(String prefix) throws OrmException {
+ return query(commit(AbbreviatedObjectId.fromString(prefix)));
+ }
+
+ public List<ChangeData> byCommit(ObjectId id) throws OrmException {
+ return query(commit(AbbreviatedObjectId.fromObjectId(id)));
+ }
+
+ public List<ChangeData> byProjectGroups(Project.NameKey project,
+ Collection<String> groups) throws OrmException {
+ List<GroupPredicate> groupPredicates = new ArrayList<>(groups.size());
+ for (String g : groups) {
+ groupPredicates.add(new GroupPredicate(g));
+ }
+ return query(and(project(project), or(groupPredicates)));
+ }
+
private List<ChangeData> query(Predicate<ChangeData> p) throws OrmException {
try {
return qp.queryChanges(p).changes();
@@ -130,4 +164,9 @@
throw new OrmException(e);
}
}
+
+ private static Schema<ChangeData> schema(@Nullable IndexCollection indexes) {
+ ChangeIndex index = indexes != null ? indexes.getSearchIndex() : null;
+ return index != null ? index.getSchema() : null;
+ }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OutputStreamQuery.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OutputStreamQuery.java
index 222c2bb..f73e0e4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OutputStreamQuery.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OutputStreamQuery.java
@@ -209,11 +209,11 @@
if (includePatchSets) {
if (includeFiles) {
- eventFactory.addPatchSets(c, d.patches(),
+ eventFactory.addPatchSets(c, d.patchSets(),
includeApprovals ? d.approvals().asMap() : null,
includeFiles, d.change(), labelTypes);
} else {
- eventFactory.addPatchSets(c, d.patches(),
+ eventFactory.addPatchSets(c, d.patchSets(),
includeApprovals ? d.approvals().asMap() : null,
labelTypes);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java
index 51d971d..6068dd0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java
@@ -132,6 +132,13 @@
if (limit == getBackendSupportedLimit()) {
limit--;
}
+
+ int page = (start / limit) + 1;
+ if (page > indexConfig.maxPages()) {
+ throw new QueryParseException(
+ "Cannot go beyond page " + indexConfig.maxPages() + "of results");
+ }
+
Predicate<ChangeData> s = queryRewriter.rewrite(q, start, limit + 1);
if (!(s instanceof ChangeDataSource)) {
q = Predicate.and(open(), q);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexTopicPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexTopicPredicate.java
index 3a9604f..7d5f1dc 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexTopicPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexTopicPredicate.java
@@ -15,8 +15,8 @@
package com.google.gerrit.server.query.change;
import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.server.index.ChangeField;
import com.google.gerrit.server.index.RegexPredicate;
+import com.google.gerrit.server.index.Schema;
import com.google.gwtorm.server.OrmException;
import dk.brics.automaton.RegExp;
@@ -25,8 +25,8 @@
class RegexTopicPredicate extends RegexPredicate<ChangeData> {
private final RunAutomaton pattern;
- RegexTopicPredicate(String re) {
- super(ChangeField.TOPIC, re);
+ RegexTopicPredicate(Schema<ChangeData> schema, String re) {
+ super(TopicPredicate.topicField(schema), re);
if (re.startsWith("^")) {
re = re.substring(1);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RevWalkPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RevWalkPredicate.java
deleted file mode 100644
index 0947fae..0000000
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RevWalkPredicate.java
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright (C) 2013 The Android Open Source Project
-//
-// 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.
-
-package com.google.gerrit.server.query.change;
-
-import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.reviewdb.client.RevId;
-import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.query.OperatorPredicate;
-import com.google.gwtorm.server.OrmException;
-import com.google.inject.Provider;
-
-import org.eclipse.jgit.errors.RepositoryNotFoundException;
-import org.eclipse.jgit.lib.AnyObjectId;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.revwalk.RevWalk;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-
-/**
- * Predicate which creates Repository, RevWalk objects and properly
- * closes them. Git based operators should extend this predicate.
- *
- */
-public abstract class RevWalkPredicate extends OperatorPredicate<ChangeData> {
- private static final Logger log =
- LoggerFactory.getLogger(RevWalkPredicate.class);
-
- public static class Arguments {
- public final PatchSet patchSet;
- public final RevId revision;
- public final AnyObjectId objectId;
- public final Change change;
- public final Project.NameKey projectName;
-
- public Arguments(PatchSet patchSet,
- RevId revision,
- AnyObjectId objectId,
- Change change,
- Project.NameKey projectName) {
- this.patchSet = patchSet;
- this.revision = revision;
- this.objectId = objectId;
- this.change = change;
- this.projectName = projectName;
- }
- }
-
- public final Provider<ReviewDb> db;
- public final GitRepositoryManager repoManager;
-
- public RevWalkPredicate(Provider<ReviewDb> db,
- GitRepositoryManager repoManager, String operator, String ref) {
- super(operator, ref);
- this.db = db;
- this.repoManager = repoManager;
- }
-
- @Override
- public boolean match(ChangeData object) throws OrmException {
- final PatchSet patchSet = object.currentPatchSet();
- if (patchSet == null) {
- return false;
- }
-
- final RevId revision = patchSet.getRevision();
- if (revision == null) {
- return false;
- }
-
- final AnyObjectId objectId = ObjectId.fromString(revision.get());
- if (objectId == null) {
- return false;
- }
-
- Change change = object.change();
- if (change == null) {
- return false;
- }
-
- final Project.NameKey projectName = change.getProject();
- if (projectName == null) {
- return false;
- }
-
- Arguments args = new Arguments(patchSet, revision, objectId, change, projectName);
-
- try (Repository repo = repoManager.openRepository(projectName);
- RevWalk rw = new RevWalk(repo)) {
- return match(repo, rw, args);
- } catch (RepositoryNotFoundException e) {
- log.error("Repository \"" + projectName.get() + "\" unknown.", e);
- } catch (IOException e) {
- log.error(projectName.get() + " cannot be read as a repository", e);
- }
- return false;
- }
-
- public abstract boolean match(Repository repo, RevWalk rw, Arguments args);
-}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/TopicPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/TopicPredicate.java
index 07a6714..7196c9f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/TopicPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/TopicPredicate.java
@@ -18,12 +18,26 @@
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.server.index.ChangeField;
+import com.google.gerrit.server.index.FieldDef;
import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.Schema;
import com.google.gwtorm.server.OrmException;
class TopicPredicate extends IndexPredicate<ChangeData> {
- TopicPredicate(String topic) {
- super(ChangeField.TOPIC, topic);
+ @SuppressWarnings("deprecation")
+ static FieldDef<ChangeData, ?> topicField(Schema<ChangeData> schema) {
+ if (schema == null) {
+ return ChangeField.LEGACY_TOPIC;
+ }
+ FieldDef<ChangeData, ?> f = schema.getFields().get(TOPIC.getName());
+ if (f != null) {
+ return f;
+ }
+ return schema.getFields().get(ChangeField.LEGACY_TOPIC.getName());
+ }
+
+ TopicPredicate(Schema<ChangeData> schema, String topic) {
+ super(topicField(schema), topic);
}
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/AclUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/AclUtil.java
new file mode 100644
index 0000000..ced8cd0
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/AclUtil.java
@@ -0,0 +1,59 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.schema;
+
+import com.google.gerrit.common.data.AccessSection;
+import com.google.gerrit.common.data.GroupReference;
+import com.google.gerrit.common.data.LabelType;
+import com.google.gerrit.common.data.Permission;
+import com.google.gerrit.common.data.PermissionRule;
+import com.google.gerrit.server.git.ProjectConfig;
+
+public class AclUtil {
+ public static void grant(ProjectConfig config, AccessSection section,
+ String permission, GroupReference... groupList) {
+ grant(config, section, permission, false, groupList);
+ }
+
+ public static void grant(ProjectConfig config, AccessSection section,
+ String permission, boolean force, GroupReference... groupList) {
+ Permission p = section.getPermission(permission, true);
+ for (GroupReference group : groupList) {
+ if (group != null) {
+ PermissionRule r = rule(config, group);
+ r.setForce(force);
+ p.add(r);
+ }
+ }
+ }
+
+ public static void grant(ProjectConfig config,
+ AccessSection section, LabelType type,
+ int min, int max, GroupReference... groupList) {
+ String name = Permission.LABEL + type.getName();
+ Permission p = section.getPermission(name, true);
+ for (GroupReference group : groupList) {
+ if (group != null) {
+ PermissionRule r = rule(config, group);
+ r.setRange(min, max);
+ p.add(r);
+ }
+ }
+ }
+
+ public static PermissionRule rule(ProjectConfig config, GroupReference group) {
+ return new PermissionRule(config.resolve(group));
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/AllProjectsCreator.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/AllProjectsCreator.java
index 1eefbf9..1198176 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/AllProjectsCreator.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/AllProjectsCreator.java
@@ -17,6 +17,8 @@
import static com.google.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS;
import static com.google.gerrit.server.group.SystemGroupBackend.PROJECT_OWNERS;
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
+import static com.google.gerrit.server.schema.AclUtil.grant;
+import static com.google.gerrit.server.schema.AclUtil.rule;
import com.google.common.base.MoreObjects;
import com.google.common.base.Strings;
@@ -183,41 +185,6 @@
config.commitToNewRef(md, RefNames.REFS_CONFIG);
}
- private void grant(ProjectConfig config, AccessSection section,
- String permission, GroupReference... groupList) {
- grant(config, section, permission, false, groupList);
- }
-
- private void grant(ProjectConfig config, AccessSection section,
- String permission, boolean force, GroupReference... groupList) {
- Permission p = section.getPermission(permission, true);
- for (GroupReference group : groupList) {
- if (group != null) {
- PermissionRule r = rule(config, group);
- r.setForce(force);
- p.add(r);
- }
- }
- }
-
- private void grant(ProjectConfig config,
- AccessSection section, LabelType type,
- int min, int max, GroupReference... groupList) {
- String name = Permission.LABEL + type.getName();
- Permission p = section.getPermission(name, true);
- for (GroupReference group : groupList) {
- if (group != null) {
- PermissionRule r = rule(config, group);
- r.setRange(min, max);
- p.add(r);
- }
- }
- }
-
- private PermissionRule rule(ProjectConfig config, GroupReference group) {
- return new PermissionRule(config.resolve(group));
- }
-
public static LabelType initCodeReviewLabel(ProjectConfig c) {
LabelType type = new LabelType("Code-Review", ImmutableList.of(
new LabelValue((short) 2, "Looks good to me, approved"),
@@ -226,6 +193,7 @@
new LabelValue((short) -1, "I would prefer this is not merged as is"),
new LabelValue((short) -2, "This shall not be merged")));
type.setCopyMinScore(true);
+ type.setCopyAllScoresOnTrivialRebase(true);
c.getLabelSections().put(type.getName(), type);
return type;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/AllUsersCreator.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/AllUsersCreator.java
index fda5306..3fa7986 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/AllUsersCreator.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/AllUsersCreator.java
@@ -14,8 +14,11 @@
package com.google.gerrit.server.schema;
+import static com.google.gerrit.server.schema.AclUtil.grant;
+
import com.google.gerrit.common.Version;
import com.google.gerrit.common.data.AccessSection;
+import com.google.gerrit.common.data.GroupReference;
import com.google.gerrit.common.data.Permission;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames;
@@ -40,6 +43,8 @@
private final AllUsersName allUsersName;
private final PersonIdent serverUser;
+ private GroupReference admin;
+
@Inject
AllUsersCreator(
GitRepositoryManager mgr,
@@ -50,6 +55,11 @@
this.serverUser = serverUser;
}
+ public AllUsersCreator setAdministrators(GroupReference admin) {
+ this.admin = admin;
+ return this;
+ }
+
public void create() throws IOException, ConfigInvalidException {
Repository git = null;
try {
@@ -84,8 +94,17 @@
Project project = config.getProject();
project.setDescription("Individual user settings and preferences.");
- AccessSection all = config.getAccessSection(RefNames.REFS_USER + "*", true);
+ AccessSection all = config.getAccessSection(RefNames.REFS_USERS + "*", true);
all.getPermission(Permission.READ, true).setExclusiveGroup(true);
+
+ AccessSection defaults = config.getAccessSection(RefNames.REFS_USERS_DEFAULT, true);
+ defaults.getPermission(Permission.READ, true).setExclusiveGroup(true);
+ grant(config, defaults, Permission.READ, admin);
+ defaults.getPermission(Permission.PUSH, true).setExclusiveGroup(true);
+ grant(config, defaults, Permission.PUSH, admin);
+ defaults.getPermission(Permission.CREATE, true).setExclusiveGroup(true);
+ grant(config, defaults, Permission.CREATE, admin);
+
config.commit(md);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/H2.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/H2.java
index f43530f..66f2f1d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/H2.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/H2.java
@@ -20,9 +20,6 @@
import org.eclipse.jgit.lib.Config;
-import java.io.File;
-import java.io.IOException;
-
class H2 extends BaseDataSourceType {
protected final Config cfg;
@@ -41,12 +38,6 @@
if (database == null || database.isEmpty()) {
database = "db/ReviewDB";
}
- File db = site.resolve(database);
- try {
- db = db.getCanonicalFile();
- } catch (IOException e) {
- db = db.getAbsoluteFile();
- }
- return "jdbc:h2:" + db.toURI().toString();
+ return "jdbc:h2:" + site.resolve(database).toUri().toString();
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaCreator.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaCreator.java
index daf1d4d..2581d56 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaCreator.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaCreator.java
@@ -32,14 +32,15 @@
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.PersonIdent;
-import java.io.File;
import java.io.IOException;
+import java.nio.file.Path;
import java.util.Collections;
/** Creates the current database schema and populates initial code rows. */
public class SchemaCreator {
- private final @SitePath
- File site_path;
+ @SitePath
+ private final
+ Path site_path;
private final AllProjectsCreator allProjectsCreator;
private final AllUsersCreator allUsersCreator;
@@ -58,7 +59,7 @@
this(site.site_path, ap, auc, au, dst);
}
- public SchemaCreator(@SitePath File site,
+ public SchemaCreator(@SitePath Path site,
AllProjectsCreator ap,
AllUsersCreator auc,
@GerritPersonIdent PersonIdent au,
@@ -86,7 +87,9 @@
.setAdministrators(GroupReference.forGroup(admin))
.setBatchUsers(GroupReference.forGroup(batch))
.create();
- allUsersCreator.create();
+ allUsersCreator
+ .setAdministrators(GroupReference.forGroup(admin))
+ .create();
dataSourceType.getIndexScript().run(db);
}
@@ -117,9 +120,9 @@
final SystemConfig s = SystemConfig.create();
try {
- s.sitePath = site_path.getCanonicalPath();
+ s.sitePath = site_path.toRealPath().normalize().toString();
} catch (IOException e) {
- s.sitePath = site_path.getAbsolutePath();
+ s.sitePath = site_path.toAbsolutePath().normalize().toString();
}
c.systemConfig().insert(Collections.singleton(s));
return s;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaUpdater.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaUpdater.java
index 2b9d4b4..fe5b992 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaUpdater.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaUpdater.java
@@ -131,9 +131,9 @@
throw new OrmException("No record in system_config table");
}
try {
- sc.sitePath = site.site_path.getCanonicalPath();
+ sc.sitePath = site.site_path.toRealPath().normalize().toString();
} catch (IOException e) {
- sc.sitePath = site.site_path.getAbsolutePath();
+ sc.sitePath = site.site_path.toAbsolutePath().normalize().toString();
}
db.systemConfig().update(Collections.singleton(sc));
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersion.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersion.java
index 945baa8..c1be4f8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersion.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersion.java
@@ -32,7 +32,7 @@
/** A version of the database schema. */
public abstract class SchemaVersion {
/** The current schema version. */
- public static final Class<Schema_107> C = Schema_107.class;
+ public static final Class<Schema_108> C = Schema_108.class;
public static int getBinaryVersion() {
return guessVersion(C);
@@ -49,8 +49,9 @@
public static int guessVersion(Class<?> c) {
String n = c.getName();
n = n.substring(n.lastIndexOf('_') + 1);
- while (n.startsWith("0"))
+ while (n.startsWith("0")) {
n = n.substring(1);
+ }
return Integer.parseInt(n);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersionCheck.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersionCheck.java
index 591601d..c809af4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersionCheck.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersionCheck.java
@@ -58,14 +58,14 @@
throw new ProvisionException("Schema not yet initialized."
+ " Run init to initialize the schema:\n"
+ "$ java -jar gerrit.war init -d "
- + site.site_path.getAbsolutePath());
+ + site.site_path.toAbsolutePath());
}
if (currentVer.versionNbr < expectedVer) {
throw new ProvisionException("Unsupported schema version "
+ currentVer.versionNbr + "; expected schema version " + expectedVer
+ ". Run init to upgrade:\n"
- + "$ java -jar " + site.gerrit_war.getAbsolutePath() + " init -d "
- + site.site_path.getAbsolutePath());
+ + "$ java -jar " + site.gerrit_war.toAbsolutePath() + " init -d "
+ + site.site_path.toAbsolutePath());
} else if (currentVer.versionNbr > expectedVer) {
throw new ProvisionException("Unsupported schema version "
+ currentVer.versionNbr + "; expected schema version " + expectedVer
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_108.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_108.java
new file mode 100644
index 0000000..8cbf119
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_108.java
@@ -0,0 +1,161 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.schema;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.SetMultimap;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.RefNames;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.git.GroupCollector;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefDatabase;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevObject;
+import org.eclipse.jgit.revwalk.RevSort;
+import org.eclipse.jgit.revwalk.RevWalk;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+public class Schema_108 extends SchemaVersion {
+ private final GitRepositoryManager repoManager;
+
+ @Inject
+ Schema_108(Provider<Schema_107> prior,
+ GitRepositoryManager repoManager) {
+ super(prior);
+ this.repoManager = repoManager;
+ }
+
+ @Override
+ protected void migrateData(ReviewDb db, UpdateUI ui) throws OrmException {
+ ui.message("Listing all changes ...");
+ SetMultimap<Project.NameKey, Change.Id> openByProject =
+ getOpenChangesByProject(db);
+ ui.message("done");
+
+ ui.message("Updating groups for open changes ...");
+ int i = 0;
+ for (Map.Entry<Project.NameKey, Collection<Change.Id>> e
+ : openByProject.asMap().entrySet()) {
+ try (Repository repo = repoManager.openRepository(e.getKey());
+ RevWalk rw = new RevWalk(repo)) {
+ updateProjectGroups(db, repo, rw, (Set<Change.Id>) e.getValue());
+ } catch (IOException err) {
+ throw new OrmException(err);
+ }
+ if (++i % 100 == 0) {
+ ui.message(" done " + i + " projects ...");
+ }
+ }
+ ui.message("done");
+ }
+
+ private static void updateProjectGroups(ReviewDb db, Repository repo,
+ RevWalk rw, Set<Change.Id> changes) throws OrmException, IOException {
+ // Match sorting in ReceiveCommits.
+ rw.reset();
+ rw.sort(RevSort.TOPO);
+ rw.sort(RevSort.REVERSE, true);
+
+ RefDatabase refdb = repo.getRefDatabase();
+ for (Ref ref : refdb.getRefs(Constants.R_HEADS).values()) {
+ RevCommit c = maybeParseCommit(rw, ref.getObjectId());
+ if (c != null) {
+ rw.markUninteresting(c);
+ }
+ }
+
+ Multimap<ObjectId, Ref> changeRefsBySha = ArrayListMultimap.create();
+ Multimap<ObjectId, PatchSet.Id> patchSetsBySha = ArrayListMultimap.create();
+ for (Ref ref : refdb.getRefs(RefNames.REFS_CHANGES).values()) {
+ ObjectId id = ref.getObjectId();
+ if (ref.getObjectId() == null) {
+ continue;
+ }
+ id = id.copy();
+ changeRefsBySha.put(id, ref);
+ PatchSet.Id psId = PatchSet.Id.fromRef(ref.getName());
+ if (psId != null && changes.contains(psId.getParentKey())) {
+ patchSetsBySha.put(id, psId);
+ RevCommit c = maybeParseCommit(rw, id);
+ if (c != null) {
+ rw.markStart(c);
+ }
+ }
+ }
+
+ GroupCollector collector = new GroupCollector(changeRefsBySha, db);
+ RevCommit c;
+ while ((c = rw.next()) != null) {
+ collector.visit(c);
+ }
+
+ updateGroups(db, collector, patchSetsBySha);
+ }
+
+ private static void updateGroups(ReviewDb db, GroupCollector collector,
+ Multimap<ObjectId, PatchSet.Id> patchSetsBySha) throws OrmException {
+ Map<PatchSet.Id, PatchSet> patchSets =
+ db.patchSets().toMap(db.patchSets().get(patchSetsBySha.values()));
+ for (Map.Entry<ObjectId, Collection<String>> e
+ : collector.getGroups().asMap().entrySet()) {
+ for (PatchSet.Id psId : patchSetsBySha.get(e.getKey())) {
+ PatchSet ps = patchSets.get(psId);
+ if (ps != null) {
+ ps.setGroups(e.getValue());
+ }
+ }
+ }
+
+ db.patchSets().update(patchSets.values());
+ }
+
+ private SetMultimap<Project.NameKey, Change.Id> getOpenChangesByProject(
+ ReviewDb db) throws OrmException {
+ SetMultimap<Project.NameKey, Change.Id> openByProject =
+ HashMultimap.create();
+ for (Change c : db.changes().all()) {
+ if (c.getStatus().isOpen()) {
+ openByProject.put(c.getProject(), c.getId());
+ }
+ }
+ return openByProject;
+ }
+
+ private static RevCommit maybeParseCommit(RevWalk rw, ObjectId id)
+ throws IOException {
+ if (id == null) {
+ return null;
+ }
+ RevObject obj = rw.parseAny(id);
+ return (obj instanceof RevCommit) ? (RevCommit) obj : null;
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/securestore/DefaultSecureStore.java b/gerrit-server/src/main/java/com/google/gerrit/server/securestore/DefaultSecureStore.java
index b852217..7665c64 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/securestore/DefaultSecureStore.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/securestore/DefaultSecureStore.java
@@ -26,6 +26,7 @@
import java.io.File;
import java.io.IOException;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
@@ -35,8 +36,8 @@
@Inject
DefaultSecureStore(SitePaths site) {
- File secureConfig = new File(site.etc_dir, "secure.config");
- sec = new FileBasedConfig(secureConfig, FS.DETECTED);
+ Path secureConfig = site.etc_dir.resolve("secure.config");
+ sec = new FileBasedConfig(secureConfig.toFile(), FS.DETECTED);
try {
sec.load();
} catch (Exception e) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/securestore/SecureStoreProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/securestore/SecureStoreProvider.java
index e830590..99127d8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/securestore/SecureStoreProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/securestore/SecureStoreProvider.java
@@ -26,14 +26,14 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.File;
+import java.nio.file.Path;
@Singleton
public class SecureStoreProvider implements Provider<SecureStore> {
private static final Logger log = LoggerFactory
.getLogger(SecureStoreProvider.class);
- private final File libdir;
+ private final Path libdir;
private final Injector injector;
private final String className;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/util/RangeUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/util/RangeUtil.java
index 5c5e2f9..92873d3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/util/RangeUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/util/RangeUtil.java
@@ -46,7 +46,7 @@
/**
* Determine the range of values being requested in the given query.
*
- * @param rangeQuery the raw query, e.g. "added:>12345"
+ * @param rangeQuery the raw query, e.g. "{@code added:>12345}"
* @param minValue the minimum possible value for the field, inclusive
* @param maxValue the maximum possible value for the field, inclusive
* @return the calculated {@link Range}, or null if the query is invalid
@@ -83,7 +83,8 @@
*/
public static Range getRange(
String prefix, String test, int queryInt, int minValue, int maxValue) {
- int min, max;
+ int min;
+ int max;
switch (test) {
case "=":
default:
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/util/RegexListSearcher.java b/gerrit-server/src/main/java/com/google/gerrit/server/util/RegexListSearcher.java
index 4b0fd35..0a99a8a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/util/RegexListSearcher.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/util/RegexListSearcher.java
@@ -75,7 +75,8 @@
public Iterable<T> search(List<T> list) {
checkNotNull(list);
- int begin, end;
+ int begin;
+ int end;
if (0 < prefixLen) {
// Assumes many consecutive elements may have the same prefix, so the cost
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/util/SubmoduleSectionParser.java b/gerrit-server/src/main/java/com/google/gerrit/server/util/SubmoduleSectionParser.java
index 8970425..195a3e0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/util/SubmoduleSectionParser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/util/SubmoduleSectionParser.java
@@ -14,18 +14,20 @@
package com.google.gerrit.server.util;
+import com.google.common.collect.Sets;
import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.SubmoduleSubscription;
-import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.project.ProjectCache;
+import com.google.inject.Inject;
+import com.google.inject.assistedinject.Assisted;
import org.eclipse.jgit.lib.BlobBasedConfig;
import org.eclipse.jgit.lib.Constants;
import java.net.URI;
import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Set;
/**
* It parses from a configuration file submodule sections.
@@ -45,22 +47,30 @@
* </pre>
*/
public class SubmoduleSectionParser {
+
+ public interface Factory {
+ SubmoduleSectionParser create(BlobBasedConfig bbc, String thisServer,
+ Branch.NameKey superProjectBranch);
+ }
+
+ private final ProjectCache projectCache;
private final BlobBasedConfig bbc;
private final String thisServer;
private final Branch.NameKey superProjectBranch;
- private final GitRepositoryManager repoManager;
- public SubmoduleSectionParser(final BlobBasedConfig bbc,
- final String thisServer, final Branch.NameKey superProjectBranch,
- final GitRepositoryManager repoManager) {
+ @Inject
+ public SubmoduleSectionParser(ProjectCache projectCache,
+ @Assisted BlobBasedConfig bbc,
+ @Assisted String thisServer,
+ @Assisted Branch.NameKey superProjectBranch) {
+ this.projectCache = projectCache;
this.bbc = bbc;
this.thisServer = thisServer;
this.superProjectBranch = superProjectBranch;
- this.repoManager = repoManager;
}
- public List<SubmoduleSubscription> parseAllSections() {
- List<SubmoduleSubscription> parsedSubscriptions = new ArrayList<>();
+ public Set<SubmoduleSubscription> parseAllSections() {
+ Set<SubmoduleSubscription> parsedSubscriptions = Sets.newHashSet();
for (final String id : bbc.getSubsections("submodule")) {
final SubmoduleSubscription subscription = parse(id);
if (subscription != null) {
@@ -91,8 +101,6 @@
// Subscription really related to this running server.
if (branch.equals(".")) {
branch = superProjectBranch.get();
- } else if (!branch.startsWith(Constants.R_REFS)) {
- branch = Constants.R_HEADS + branch;
}
final String urlExtractedPath = new URI(url).getPath();
@@ -106,12 +114,10 @@
projectName = projectName.substring(0, //
projectName.length() - Constants.DOT_GIT_EXT.length());
}
-
- if (repoManager.list().contains(new Project.NameKey(projectName))) {
- return new SubmoduleSubscription(
- superProjectBranch,
- new Branch.NameKey(new Project.NameKey(projectName), branch),
- path);
+ Project.NameKey projectKey = new Project.NameKey(projectName);
+ if (projectCache.get(projectKey) != null) {
+ return new SubmoduleSubscription(superProjectBranch,
+ new Branch.NameKey(projectKey, branch), path);
}
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/util/SystemLog.java b/gerrit-server/src/main/java/com/google/gerrit/server/util/SystemLog.java
index cf7f11f..32cdca5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/util/SystemLog.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/util/SystemLog.java
@@ -33,8 +33,8 @@
import org.eclipse.jgit.lib.Config;
import org.slf4j.LoggerFactory;
-import java.io.File;
import java.io.IOException;
+import java.nio.file.Path;
@Singleton
public class SystemLog {
@@ -56,12 +56,12 @@
return Strings.isNullOrEmpty(System.getProperty(LOG4J_CONFIGURATION));
}
- public static Appender createAppender(File logdir, String name, Layout layout) {
+ public static Appender createAppender(Path logdir, String name, Layout layout) {
final DailyRollingFileAppender dst = new DailyRollingFileAppender();
dst.setName(name);
dst.setLayout(layout);
dst.setEncoding("UTF-8");
- dst.setFile(new File(resolve(logdir), name).getPath());
+ dst.setFile(resolve(logdir).resolve(name).toString());
dst.setImmediateFlush(true);
dst.setAppend(true);
dst.setErrorHandler(new DieErrorHandler());
@@ -91,11 +91,11 @@
return async;
}
- private static File resolve(final File logs_dir) {
+ private static Path resolve(Path p) {
try {
- return logs_dir.getCanonicalFile();
+ return p.toRealPath().normalize();
} catch (IOException e) {
- return logs_dir.getAbsoluteFile();
+ return p.toAbsolutePath().normalize();
}
}
diff --git a/gerrit-server/src/main/java/gerrit/AbstractCommitUserIdentityPredicate.java b/gerrit-server/src/main/java/gerrit/AbstractCommitUserIdentityPredicate.java
index 606e883..32713d1 100644
--- a/gerrit-server/src/main/java/gerrit/AbstractCommitUserIdentityPredicate.java
+++ b/gerrit-server/src/main/java/gerrit/AbstractCommitUserIdentityPredicate.java
@@ -17,11 +17,11 @@
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.UserIdentity;
+import com.googlecode.prolog_cafe.exceptions.PrologException;
import com.googlecode.prolog_cafe.lang.IntegerTerm;
import com.googlecode.prolog_cafe.lang.Operation;
import com.googlecode.prolog_cafe.lang.Predicate;
import com.googlecode.prolog_cafe.lang.Prolog;
-import com.googlecode.prolog_cafe.lang.PrologException;
import com.googlecode.prolog_cafe.lang.StructureTerm;
import com.googlecode.prolog_cafe.lang.SymbolTerm;
import com.googlecode.prolog_cafe.lang.Term;
diff --git a/gerrit-server/src/main/java/gerrit/PRED__load_commit_labels_1.java b/gerrit-server/src/main/java/gerrit/PRED__load_commit_labels_1.java
index f0806a5..b9b6c5a 100644
--- a/gerrit-server/src/main/java/gerrit/PRED__load_commit_labels_1.java
+++ b/gerrit-server/src/main/java/gerrit/PRED__load_commit_labels_1.java
@@ -9,13 +9,13 @@
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gwtorm.server.OrmException;
+import com.googlecode.prolog_cafe.exceptions.JavaException;
+import com.googlecode.prolog_cafe.exceptions.PrologException;
import com.googlecode.prolog_cafe.lang.IntegerTerm;
-import com.googlecode.prolog_cafe.lang.JavaException;
import com.googlecode.prolog_cafe.lang.ListTerm;
import com.googlecode.prolog_cafe.lang.Operation;
import com.googlecode.prolog_cafe.lang.Predicate;
import com.googlecode.prolog_cafe.lang.Prolog;
-import com.googlecode.prolog_cafe.lang.PrologException;
import com.googlecode.prolog_cafe.lang.StructureTerm;
import com.googlecode.prolog_cafe.lang.SymbolTerm;
import com.googlecode.prolog_cafe.lang.Term;
diff --git a/gerrit-server/src/main/java/gerrit/PRED__user_label_range_4.java b/gerrit-server/src/main/java/gerrit/PRED__user_label_range_4.java
index a955307..8efc2f1 100644
--- a/gerrit-server/src/main/java/gerrit/PRED__user_label_range_4.java
+++ b/gerrit-server/src/main/java/gerrit/PRED__user_label_range_4.java
@@ -20,15 +20,17 @@
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.project.ChangeControl;
-import com.googlecode.prolog_cafe.lang.IllegalTypeException;
+import com.googlecode.prolog_cafe.exceptions.IllegalTypeException;
+import com.googlecode.prolog_cafe.exceptions.PInstantiationException;
+import com.googlecode.prolog_cafe.exceptions.PrologException;
import com.googlecode.prolog_cafe.lang.IntegerTerm;
import com.googlecode.prolog_cafe.lang.JavaObjectTerm;
import com.googlecode.prolog_cafe.lang.Operation;
-import com.googlecode.prolog_cafe.lang.PInstantiationException;
import com.googlecode.prolog_cafe.lang.Predicate;
import com.googlecode.prolog_cafe.lang.Prolog;
-import com.googlecode.prolog_cafe.lang.PrologException;
+import com.googlecode.prolog_cafe.lang.SymbolTerm;
import com.googlecode.prolog_cafe.lang.Term;
+import com.googlecode.prolog_cafe.lang.VariableTerm;
/**
* Resolves the valid range for a label on a CurrentUser.
@@ -54,18 +56,18 @@
Term a3 = arg3.dereference();
Term a4 = arg4.dereference();
- if (a1.isVariable()) {
+ if (a1 instanceof VariableTerm) {
throw new PInstantiationException(this, 1);
}
- if (!a1.isSymbol()) {
+ if (!(a1 instanceof SymbolTerm)) {
throw new IllegalTypeException(this, 1, "atom", a1);
}
String label = a1.name();
- if (a2.isVariable()) {
+ if (a2 instanceof VariableTerm) {
throw new PInstantiationException(this, 2);
}
- if (!a2.isJavaObject() || !a2.convertible(CurrentUser.class)) {
+ if (!(a2 instanceof JavaObjectTerm) || !a2.convertible(CurrentUser.class)) {
throw new IllegalTypeException(this, 2, "CurrentUser)", a2);
}
CurrentUser user = (CurrentUser) ((JavaObjectTerm) a2).object();
diff --git a/gerrit-server/src/main/java/gerrit/PRED_change_branch_1.java b/gerrit-server/src/main/java/gerrit/PRED_change_branch_1.java
index b835b34..ee5bdc9 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_change_branch_1.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_change_branch_1.java
@@ -17,10 +17,10 @@
import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.rules.StoredValues;
+import com.googlecode.prolog_cafe.exceptions.PrologException;
import com.googlecode.prolog_cafe.lang.Operation;
import com.googlecode.prolog_cafe.lang.Predicate;
import com.googlecode.prolog_cafe.lang.Prolog;
-import com.googlecode.prolog_cafe.lang.PrologException;
import com.googlecode.prolog_cafe.lang.SymbolTerm;
import com.googlecode.prolog_cafe.lang.Term;
diff --git a/gerrit-server/src/main/java/gerrit/PRED_change_owner_1.java b/gerrit-server/src/main/java/gerrit/PRED_change_owner_1.java
index 51502f8..b56b036 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_change_owner_1.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_change_owner_1.java
@@ -17,11 +17,11 @@
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.rules.StoredValues;
+import com.googlecode.prolog_cafe.exceptions.PrologException;
import com.googlecode.prolog_cafe.lang.IntegerTerm;
import com.googlecode.prolog_cafe.lang.Operation;
import com.googlecode.prolog_cafe.lang.Predicate;
import com.googlecode.prolog_cafe.lang.Prolog;
-import com.googlecode.prolog_cafe.lang.PrologException;
import com.googlecode.prolog_cafe.lang.StructureTerm;
import com.googlecode.prolog_cafe.lang.SymbolTerm;
import com.googlecode.prolog_cafe.lang.Term;
diff --git a/gerrit-server/src/main/java/gerrit/PRED_change_project_1.java b/gerrit-server/src/main/java/gerrit/PRED_change_project_1.java
index 29c6704..e131605 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_change_project_1.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_change_project_1.java
@@ -17,10 +17,10 @@
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.rules.StoredValues;
+import com.googlecode.prolog_cafe.exceptions.PrologException;
import com.googlecode.prolog_cafe.lang.Operation;
import com.googlecode.prolog_cafe.lang.Predicate;
import com.googlecode.prolog_cafe.lang.Prolog;
-import com.googlecode.prolog_cafe.lang.PrologException;
import com.googlecode.prolog_cafe.lang.SymbolTerm;
import com.googlecode.prolog_cafe.lang.Term;
diff --git a/gerrit-server/src/main/java/gerrit/PRED_change_topic_1.java b/gerrit-server/src/main/java/gerrit/PRED_change_topic_1.java
index 7ba648f..d1a91d9 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_change_topic_1.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_change_topic_1.java
@@ -17,10 +17,10 @@
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.rules.StoredValues;
+import com.googlecode.prolog_cafe.exceptions.PrologException;
import com.googlecode.prolog_cafe.lang.Operation;
import com.googlecode.prolog_cafe.lang.Predicate;
import com.googlecode.prolog_cafe.lang.Prolog;
-import com.googlecode.prolog_cafe.lang.PrologException;
import com.googlecode.prolog_cafe.lang.SymbolTerm;
import com.googlecode.prolog_cafe.lang.Term;
diff --git a/gerrit-server/src/main/java/gerrit/PRED_commit_author_3.java b/gerrit-server/src/main/java/gerrit/PRED_commit_author_3.java
index 3700909..59c4c18 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_commit_author_3.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_commit_author_3.java
@@ -18,9 +18,9 @@
import com.google.gerrit.reviewdb.client.UserIdentity;
import com.google.gerrit.rules.StoredValues;
+import com.googlecode.prolog_cafe.exceptions.PrologException;
import com.googlecode.prolog_cafe.lang.Operation;
import com.googlecode.prolog_cafe.lang.Prolog;
-import com.googlecode.prolog_cafe.lang.PrologException;
import com.googlecode.prolog_cafe.lang.Term;
public class PRED_commit_author_3 extends AbstractCommitUserIdentityPredicate {
diff --git a/gerrit-server/src/main/java/gerrit/PRED_commit_committer_3.java b/gerrit-server/src/main/java/gerrit/PRED_commit_committer_3.java
index 64823df..77a668b 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_commit_committer_3.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_commit_committer_3.java
@@ -18,9 +18,9 @@
import com.google.gerrit.reviewdb.client.UserIdentity;
import com.google.gerrit.rules.StoredValues;
+import com.googlecode.prolog_cafe.exceptions.PrologException;
import com.googlecode.prolog_cafe.lang.Operation;
import com.googlecode.prolog_cafe.lang.Prolog;
-import com.googlecode.prolog_cafe.lang.PrologException;
import com.googlecode.prolog_cafe.lang.Term;
public class PRED_commit_committer_3 extends AbstractCommitUserIdentityPredicate {
diff --git a/gerrit-server/src/main/java/gerrit/PRED_commit_delta_4.java b/gerrit-server/src/main/java/gerrit/PRED_commit_delta_4.java
index 51a871c..893c5bc 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_commit_delta_4.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_commit_delta_4.java
@@ -19,15 +19,16 @@
import com.google.gerrit.server.patch.PatchList;
import com.google.gerrit.server.patch.PatchListEntry;
-import com.googlecode.prolog_cafe.lang.IllegalTypeException;
+import com.googlecode.prolog_cafe.exceptions.IllegalTypeException;
+import com.googlecode.prolog_cafe.exceptions.PInstantiationException;
+import com.googlecode.prolog_cafe.exceptions.PrologException;
import com.googlecode.prolog_cafe.lang.JavaObjectTerm;
import com.googlecode.prolog_cafe.lang.Operation;
-import com.googlecode.prolog_cafe.lang.PInstantiationException;
import com.googlecode.prolog_cafe.lang.Predicate;
import com.googlecode.prolog_cafe.lang.Prolog;
-import com.googlecode.prolog_cafe.lang.PrologException;
import com.googlecode.prolog_cafe.lang.SymbolTerm;
import com.googlecode.prolog_cafe.lang.Term;
+import com.googlecode.prolog_cafe.lang.VariableTerm;
import java.util.Iterator;
import java.util.regex.Pattern;
@@ -66,22 +67,22 @@
engine.setB0();
Term a1 = arg1.dereference();
- if (a1.isVariable()) {
+ if (a1 instanceof VariableTerm) {
throw new PInstantiationException(this, 1);
}
- if (!a1.isSymbol()) {
+ if (!(a1 instanceof SymbolTerm)) {
throw new IllegalTypeException(this, 1, "symbol", a1);
}
Pattern regex = Pattern.compile(a1.name());
- engine.areg1 = new JavaObjectTerm(regex);
- engine.areg2 = arg2;
- engine.areg3 = arg3;
- engine.areg4 = arg4;
+ engine.r1 = new JavaObjectTerm(regex);
+ engine.r2 = arg2;
+ engine.r3 = arg3;
+ engine.r4 = arg4;
PatchList pl = StoredValues.PATCH_LIST.get(engine);
Iterator<PatchListEntry> iter = pl.getPatches().iterator();
- engine.areg5 = new JavaObjectTerm(iter);
+ engine.r5 = new JavaObjectTerm(iter);
return engine.jtry5(commit_delta_check, commit_delta_next);
}
@@ -89,11 +90,11 @@
private static final class PRED_commit_delta_check extends Operation {
@Override
public Operation exec(Prolog engine) {
- Term a1 = engine.areg1;
- Term a2 = engine.areg2;
- Term a3 = engine.areg3;
- Term a4 = engine.areg4;
- Term a5 = engine.areg5;
+ Term a1 = engine.r1;
+ Term a2 = engine.r2;
+ Term a3 = engine.r3;
+ Term a4 = engine.r4;
+ Term a5 = engine.r5;
Pattern regex = (Pattern)((JavaObjectTerm)a1).object();
@SuppressWarnings("unchecked")
@@ -144,7 +145,7 @@
private static final class PRED_commit_delta_empty extends Operation {
@Override
public Operation exec(Prolog engine) {
- Term a5 = engine.areg5;
+ Term a5 = engine.r5;
@SuppressWarnings("unchecked")
Iterator<PatchListEntry> iter =
diff --git a/gerrit-server/src/main/java/gerrit/PRED_commit_edits_2.java b/gerrit-server/src/main/java/gerrit/PRED_commit_edits_2.java
index 509faf0..c97a964 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_commit_edits_2.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_commit_edits_2.java
@@ -19,14 +19,16 @@
import com.google.gerrit.server.patch.PatchListEntry;
import com.google.gerrit.server.patch.Text;
-import com.googlecode.prolog_cafe.lang.IllegalTypeException;
-import com.googlecode.prolog_cafe.lang.JavaException;
+import com.googlecode.prolog_cafe.exceptions.IllegalTypeException;
+import com.googlecode.prolog_cafe.exceptions.JavaException;
+import com.googlecode.prolog_cafe.exceptions.PInstantiationException;
+import com.googlecode.prolog_cafe.exceptions.PrologException;
import com.googlecode.prolog_cafe.lang.Operation;
-import com.googlecode.prolog_cafe.lang.PInstantiationException;
import com.googlecode.prolog_cafe.lang.Predicate;
import com.googlecode.prolog_cafe.lang.Prolog;
-import com.googlecode.prolog_cafe.lang.PrologException;
+import com.googlecode.prolog_cafe.lang.SymbolTerm;
import com.googlecode.prolog_cafe.lang.Term;
+import com.googlecode.prolog_cafe.lang.VariableTerm;
import org.eclipse.jgit.diff.Edit;
import org.eclipse.jgit.errors.CorruptObjectException;
@@ -134,10 +136,10 @@
}
private Pattern getRegexParameter(Term term) {
- if (term.isVariable()) {
+ if (term instanceof VariableTerm) {
throw new PInstantiationException(this, 1);
}
- if (!term.isSymbol()) {
+ if (!(term instanceof SymbolTerm)) {
throw new IllegalTypeException(this, 1, "symbol", term);
}
return Pattern.compile(term.name(), Pattern.MULTILINE);
diff --git a/gerrit-server/src/main/java/gerrit/PRED_commit_message_1.java b/gerrit-server/src/main/java/gerrit/PRED_commit_message_1.java
index e2eb6b1..6e1dc91 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_commit_message_1.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_commit_message_1.java
@@ -17,10 +17,10 @@
import com.google.gerrit.reviewdb.client.PatchSetInfo;
import com.google.gerrit.rules.StoredValues;
+import com.googlecode.prolog_cafe.exceptions.PrologException;
import com.googlecode.prolog_cafe.lang.Operation;
import com.googlecode.prolog_cafe.lang.Predicate;
import com.googlecode.prolog_cafe.lang.Prolog;
-import com.googlecode.prolog_cafe.lang.PrologException;
import com.googlecode.prolog_cafe.lang.SymbolTerm;
import com.googlecode.prolog_cafe.lang.Term;
diff --git a/gerrit-server/src/main/java/gerrit/PRED_commit_stats_3.java b/gerrit-server/src/main/java/gerrit/PRED_commit_stats_3.java
index 83878be..4f665ee 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_commit_stats_3.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_commit_stats_3.java
@@ -17,11 +17,11 @@
import com.google.gerrit.rules.StoredValues;
import com.google.gerrit.server.patch.PatchList;
+import com.googlecode.prolog_cafe.exceptions.PrologException;
import com.googlecode.prolog_cafe.lang.IntegerTerm;
import com.googlecode.prolog_cafe.lang.Operation;
import com.googlecode.prolog_cafe.lang.Predicate;
import com.googlecode.prolog_cafe.lang.Prolog;
-import com.googlecode.prolog_cafe.lang.PrologException;
import com.googlecode.prolog_cafe.lang.Term;
/**
diff --git a/gerrit-server/src/main/java/gerrit/PRED_current_user_1.java b/gerrit-server/src/main/java/gerrit/PRED_current_user_1.java
index 6d0dd0f..a63b1e7 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_current_user_1.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_current_user_1.java
@@ -21,12 +21,12 @@
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.PeerDaemonUser;
-import com.googlecode.prolog_cafe.lang.EvaluationException;
+import com.googlecode.prolog_cafe.exceptions.EvaluationException;
+import com.googlecode.prolog_cafe.exceptions.PrologException;
import com.googlecode.prolog_cafe.lang.IntegerTerm;
import com.googlecode.prolog_cafe.lang.Operation;
import com.googlecode.prolog_cafe.lang.Predicate;
import com.googlecode.prolog_cafe.lang.Prolog;
-import com.googlecode.prolog_cafe.lang.PrologException;
import com.googlecode.prolog_cafe.lang.StructureTerm;
import com.googlecode.prolog_cafe.lang.SymbolTerm;
import com.googlecode.prolog_cafe.lang.Term;
diff --git a/gerrit-server/src/main/java/gerrit/PRED_current_user_2.java b/gerrit-server/src/main/java/gerrit/PRED_current_user_2.java
index 62fe075..3ee8d82 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_current_user_2.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_current_user_2.java
@@ -24,17 +24,18 @@
import com.google.gerrit.server.IdentifiedUser;
import com.google.inject.util.Providers;
-import com.googlecode.prolog_cafe.lang.IllegalTypeException;
+import com.googlecode.prolog_cafe.exceptions.IllegalTypeException;
+import com.googlecode.prolog_cafe.exceptions.PInstantiationException;
+import com.googlecode.prolog_cafe.exceptions.PrologException;
import com.googlecode.prolog_cafe.lang.IntegerTerm;
import com.googlecode.prolog_cafe.lang.JavaObjectTerm;
import com.googlecode.prolog_cafe.lang.Operation;
-import com.googlecode.prolog_cafe.lang.PInstantiationException;
import com.googlecode.prolog_cafe.lang.Predicate;
import com.googlecode.prolog_cafe.lang.Prolog;
-import com.googlecode.prolog_cafe.lang.PrologException;
import com.googlecode.prolog_cafe.lang.StructureTerm;
import com.googlecode.prolog_cafe.lang.SymbolTerm;
import com.googlecode.prolog_cafe.lang.Term;
+import com.googlecode.prolog_cafe.lang.VariableTerm;
import java.util.Map;
@@ -64,7 +65,7 @@
Term a1 = arg1.dereference();
Term a2 = arg2.dereference();
- if (a1.isVariable()) {
+ if (a1 instanceof VariableTerm) {
throw new PInstantiationException(this, 1);
}
@@ -76,7 +77,7 @@
}
public Term createUser(Prolog engine, Term key) {
- if (!key.isStructure()
+ if (!(key instanceof StructureTerm)
|| key.arity() != 1
|| !((StructureTerm) key).functor().equals(user)) {
throw new IllegalTypeException(this, 1, "user(int)", key);
@@ -84,7 +85,7 @@
Term idTerm = key.arg(0);
CurrentUser user;
- if (idTerm.isInteger()) {
+ if (idTerm instanceof IntegerTerm) {
Map<Account.Id, IdentifiedUser> cache = StoredValues.USERS.get(engine);
Account.Id accountId = new Account.Id(((IntegerTerm) idTerm).intValue());
user = cache.get(accountId);
diff --git a/gerrit-server/src/main/java/gerrit/PRED_get_legacy_label_types_1.java b/gerrit-server/src/main/java/gerrit/PRED_get_legacy_label_types_1.java
index 698c11c..f93e424 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_get_legacy_label_types_1.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_get_legacy_label_types_1.java
@@ -18,12 +18,12 @@
import com.google.gerrit.common.data.LabelValue;
import com.google.gerrit.rules.StoredValues;
+import com.googlecode.prolog_cafe.exceptions.PrologException;
import com.googlecode.prolog_cafe.lang.IntegerTerm;
import com.googlecode.prolog_cafe.lang.ListTerm;
import com.googlecode.prolog_cafe.lang.Operation;
import com.googlecode.prolog_cafe.lang.Predicate;
import com.googlecode.prolog_cafe.lang.Prolog;
-import com.googlecode.prolog_cafe.lang.PrologException;
import com.googlecode.prolog_cafe.lang.StructureTerm;
import com.googlecode.prolog_cafe.lang.SymbolTerm;
import com.googlecode.prolog_cafe.lang.Term;
diff --git a/gerrit-server/src/main/java/gerrit/PRED_project_default_submit_type_1.java b/gerrit-server/src/main/java/gerrit/PRED_project_default_submit_type_1.java
index 824c6ef..b1a8a74 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_project_default_submit_type_1.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_project_default_submit_type_1.java
@@ -18,10 +18,10 @@
import com.google.gerrit.rules.StoredValues;
import com.google.gerrit.server.project.ChangeControl;
+import com.googlecode.prolog_cafe.exceptions.PrologException;
import com.googlecode.prolog_cafe.lang.Operation;
import com.googlecode.prolog_cafe.lang.Predicate;
import com.googlecode.prolog_cafe.lang.Prolog;
-import com.googlecode.prolog_cafe.lang.PrologException;
import com.googlecode.prolog_cafe.lang.SymbolTerm;
import com.googlecode.prolog_cafe.lang.Term;
diff --git a/gerrit-server/src/main/resources/com/google/gerrit/server/mime/mime-types.properties b/gerrit-server/src/main/resources/com/google/gerrit/server/mime/mime-types.properties
index 3d8d271..2646fd0 100644
--- a/gerrit-server/src/main/resources/com/google/gerrit/server/mime/mime-types.properties
+++ b/gerrit-server/src/main/resources/com/google/gerrit/server/mime/mime-types.properties
@@ -33,6 +33,7 @@
pig = text/x-pig
pl = text/x-perl
pm = text/x-perl
+pp = text/x-puppet
project.config = text/x-ini
properties = text/x-ini
py = text/x-python
diff --git a/gerrit-server/src/test/java/com/google/gerrit/rules/GerritCommonTest.java b/gerrit-server/src/test/java/com/google/gerrit/rules/GerritCommonTest.java
index f5dca09..74ab572 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/rules/GerritCommonTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/rules/GerritCommonTest.java
@@ -33,7 +33,8 @@
import com.google.gerrit.testutil.InMemoryRepositoryManager;
import com.google.inject.AbstractModule;
-import com.googlecode.prolog_cafe.compiler.CompileException;
+import com.googlecode.prolog_cafe.exceptions.CompileException;
+import com.googlecode.prolog_cafe.exceptions.ReductionLimitException;
import com.googlecode.prolog_cafe.lang.JavaObjectTerm;
import com.googlecode.prolog_cafe.lang.Prolog;
import com.googlecode.prolog_cafe.lang.StructureTerm;
@@ -112,7 +113,6 @@
public void testReductionLimit() throws CompileException {
PrologEnvironment env = envFactory.create(machine);
setUpEnvironment(env);
- env.setEnabled(Prolog.Feature.IO, true);
String script = "loopy :- b(5).\n"
+ "b(N) :- N > 0, !, S = N - 1, b(S).\n"
diff --git a/gerrit-server/src/test/java/com/google/gerrit/rules/PrologTestCase.java b/gerrit-server/src/test/java/com/google/gerrit/rules/PrologTestCase.java
index aaab173..027d043 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/rules/PrologTestCase.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/rules/PrologTestCase.java
@@ -22,7 +22,7 @@
import com.google.inject.Guice;
import com.google.inject.Module;
-import com.googlecode.prolog_cafe.compiler.CompileException;
+import com.googlecode.prolog_cafe.exceptions.CompileException;
import com.googlecode.prolog_cafe.lang.BufferingPrologControl;
import com.googlecode.prolog_cafe.lang.JavaObjectTerm;
import com.googlecode.prolog_cafe.lang.Prolog;
@@ -185,8 +185,8 @@
private Term removePackage(Term test) {
Term name = test;
- if (name.isStructure() && ":".equals(((StructureTerm) name).name())) {
- name = ((StructureTerm) name).args()[1];
+ if (name instanceof StructureTerm && ":".equals(name.name())) {
+ name = name.arg(1);
}
return name;
}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/change/CommentsTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/change/CommentsTest.java
index 8bedd17..a437477 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/change/CommentsTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/change/CommentsTest.java
@@ -106,7 +106,8 @@
public Config config;
@ConfigSuite.Config
- public static @GerritServerConfig Config noteDbEnabled() {
+ @GerritServerConfig
+ public static Config noteDbEnabled() {
return NotesMigration.allEnabledConfig();
}
@@ -240,24 +241,23 @@
plc1 = newPatchLineComment(psId1, "Comment1", null,
"FileOne.txt", Side.REVISION, 3, ownerId, timeBase,
"First Comment", new CommentRange(1, 2, 3, 4));
- plc1.setRevId(new RevId("ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD"));
+ plc1.setRevId(new RevId("abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"));
plc2 = newPatchLineComment(psId1, "Comment2", "Comment1",
"FileOne.txt", Side.REVISION, 3, otherUserId, timeBase + 1000,
"Reply to First Comment", new CommentRange(1, 2, 3, 4));
- plc2.setRevId(new RevId("ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD"));
+ plc2.setRevId(new RevId("abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"));
plc3 = newPatchLineComment(psId1, "Comment3", "Comment1",
"FileOne.txt", Side.PARENT, 3, ownerId, timeBase + 2000,
"First Parent Comment", new CommentRange(1, 2, 3, 4));
- plc3.setRevId(new RevId("CDEFCDEFCDEFCDEFCDEFCDEFCDEFCDEFCDEFCDEF"));
+ plc3.setRevId(new RevId("cdefcdefcdefcdefcdefcdefcdefcdefcdefcdef"));
plc4 = newPatchLineComment(psId2, "Comment4", null, "FileOne.txt",
Side.REVISION, 3, ownerId, timeBase + 3000, "Second Comment",
new CommentRange(1, 2, 3, 4), Status.DRAFT);
- plc4.setRevId(new RevId("BCDEBCDEBCDEBCDEBCDEBCDEBCDEBCDEBCDEBCDE"));
+ plc4.setRevId(new RevId("bcdebcdebcdebcdebcdebcdebcdebcdebcdebcde"));
plc5 = newPatchLineComment(psId2, "Comment5", null, "FileOne.txt",
Side.REVISION, 5, ownerId, timeBase + 4000, "Third Comment",
new CommentRange(3, 4, 5, 6), Status.DRAFT);
- plc5.setRevId(new RevId("BCDEBCDEBCDEBCDEBCDEBCDEBCDEBCDEBCDEBCDE"));
- plc5.setRevId(new RevId("BCDEBCDEBCDEBCDEBCDEBCDEBCDEBCDEBCDEBCDE"));
+ plc5.setRevId(new RevId("bcdebcdebcdebcdebcdebcdebcdebcdebcdebcde"));
plc6 = newPatchLineComment(psId3, "Comment6", null, "FileOne.txt",
Side.REVISION, 5, ownerId, timeBase + 5000, "Sixth Comment",
new CommentRange(3, 4, 5, 6), Status.DRAFT);
@@ -371,7 +371,7 @@
@Test
public void testPatchLineCommentsUtilByCommentStatus() throws OrmException {
assertThat(plcUtil.publishedByChange(db, revRes2.getNotes()))
- .containsExactly(plc1, plc2, plc3).inOrder();
+ .containsExactly(plc3, plc1, plc2).inOrder();
assertThat(plcUtil.draftByChange(db, revRes2.getNotes()))
.containsExactly(plc4, plc5).inOrder();
}
@@ -422,7 +422,7 @@
private void assertCommentMap(Map<String, List<CommentInfo>> actual,
Map<String, ? extends List<PatchLineComment>> expected,
boolean isPublished) {
- assertThat((Iterable<?>)actual.keySet()).containsExactlyElementsIn(expected.keySet());
+ assertThat(actual.keySet()).containsExactlyElementsIn(expected.keySet());
for (Map.Entry<String, List<CommentInfo>> entry : actual.entrySet()) {
List<CommentInfo> actualList = entry.getValue();
List<PatchLineComment> expectedList = expected.get(entry.getKey());
@@ -443,7 +443,7 @@
assertThat(new Account.Id(ci.author._accountId))
.isEqualTo(plc.getAuthor());
}
- assertThat((int) ci.line).isEqualTo(plc.getLine());
+ assertThat(ci.line).isEqualTo(plc.getLine());
assertThat(MoreObjects.firstNonNull(ci.side, Side.REVISION))
.isEqualTo(plc.getSide() == 0 ? Side.PARENT : Side.REVISION);
assertThat(TimeUtil.roundToSecond(ci.updated))
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/change/ConsistencyCheckerTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/change/ConsistencyCheckerTest.java
index 358620f..8caba88 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/change/ConsistencyCheckerTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/change/ConsistencyCheckerTest.java
@@ -25,6 +25,7 @@
import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.extensions.api.changes.FixInput;
import com.google.gerrit.extensions.common.ProblemInfo;
+import com.google.gerrit.lifecycle.LifecycleManager;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
@@ -36,10 +37,10 @@
import com.google.gerrit.testutil.FakeAccountByEmailCache;
import com.google.gerrit.testutil.InMemoryDatabase;
import com.google.gerrit.testutil.InMemoryRepositoryManager;
+import com.google.gerrit.testutil.InMemoryRepositoryManager.Repo;
import com.google.gerrit.testutil.TestChanges;
import com.google.inject.util.Providers;
-import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
@@ -52,12 +53,13 @@
import java.util.List;
public class ConsistencyCheckerTest {
+ private LifecycleManager lifecycle;
private InMemoryDatabase schemaFactory;
private ReviewDb db;
private InMemoryRepositoryManager repoManager;
private ConsistencyChecker checker;
- private TestRepository<InMemoryRepository> repo;
+ private TestRepository<Repo> repo;
private Project.NameKey project;
private Account.Id userId;
private RevCommit tip;
@@ -65,7 +67,9 @@
@Before
public void setUp() throws Exception {
FakeAccountByEmailCache accountCache = new FakeAccountByEmailCache();
- schemaFactory = InMemoryDatabase.newDatabase();
+ lifecycle = new LifecycleManager();
+ schemaFactory = InMemoryDatabase.newDatabase(lifecycle);
+ lifecycle.start();
schemaFactory.create();
db = schemaFactory.open();
repoManager = new InMemoryRepositoryManager();
@@ -88,6 +92,9 @@
if (db != null) {
db.close();
}
+ if (lifecycle != null) {
+ lifecycle.stop();
+ }
if (schemaFactory != null) {
InMemoryDatabase.drop(schemaFactory);
}
@@ -335,7 +342,8 @@
@Test
public void missingDestRef() throws Exception {
- RefUpdate ru = repo.getRepository().updateRef("refs/heads/master");
+ String ref = "refs/heads/master";
+ RefUpdate ru = repo.getRepository().updateRef(ref);
ru.setForceUpdate(true);
assertThat(ru.delete()).isEqualTo(RefUpdate.Result.FORCED);
Change c = insertChange();
@@ -344,7 +352,7 @@
updatePatchSetRef(ps);
db.patchSets().insert(singleton(ps));
- assertProblems(c, "Destination ref not found (may be new branch): master");
+ assertProblems(c, "Destination ref not found (may be new branch): " + ref);
}
@Test
@@ -356,7 +364,8 @@
assertProblems(c,
"Patch set 1 (" + rev + ") is not merged into destination ref"
- + " master (" + tip.name() + "), but change status is MERGED");
+ + " refs/heads/master (" + tip.name()
+ + "), but change status is MERGED");
}
@Test
@@ -370,7 +379,8 @@
assertProblems(c,
"Patch set 1 (" + commit.name() + ") is merged into destination ref"
- + " master (" + commit.name() + "), but change status is NEW");
+ + " refs/heads/master (" + commit.name()
+ + "), but change status is NEW");
}
@Test
@@ -387,7 +397,8 @@
ProblemInfo p = problems.get(0);
assertThat(p.message).isEqualTo(
"Patch set 1 (" + commit.name() + ") is merged into destination ref"
- + " master (" + commit.name() + "), but change status is NEW");
+ + " refs/heads/master (" + commit.name()
+ + "), but change status is NEW");
assertThat(p.status).isEqualTo(ProblemInfo.Status.FIXED);
assertThat(p.outcome).isEqualTo("Marked change as merged");
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/change/HashtagsTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/change/HashtagsTest.java
index d5b722c..6100ffd 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/change/HashtagsTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/change/HashtagsTest.java
@@ -23,45 +23,45 @@
public class HashtagsTest {
@Test
public void emptyCommitMessage() throws Exception {
- assertThat((Iterable<?>)HashtagsUtil.extractTags("")).isEmpty();
+ assertThat(HashtagsUtil.extractTags("")).isEmpty();
}
@Test
public void nullCommitMessage() throws Exception {
- assertThat((Iterable<?>)HashtagsUtil.extractTags(null)).isEmpty();
+ assertThat(HashtagsUtil.extractTags(null)).isEmpty();
}
@Test
public void noHashtags() throws Exception {
String commitMessage = "Subject\n\nLine 1\n\nLine 2";
- assertThat((Iterable<?>)HashtagsUtil.extractTags(commitMessage)).isEmpty();
+ assertThat(HashtagsUtil.extractTags(commitMessage)).isEmpty();
}
@Test
public void singleHashtag() throws Exception {
String commitMessage = "#Subject\n\nLine 1\n\nLine 2";
- assertThat((Iterable<?>)HashtagsUtil.extractTags(commitMessage))
+ assertThat(HashtagsUtil.extractTags(commitMessage))
.containsExactlyElementsIn(Sets.newHashSet("Subject"));
}
@Test
public void singleHashtagNumeric() throws Exception {
String commitMessage = "Subject\n\n#123\n\nLine 2";
- assertThat((Iterable<?>)HashtagsUtil.extractTags(commitMessage))
+ assertThat(HashtagsUtil.extractTags(commitMessage))
.containsExactlyElementsIn(Sets.newHashSet("123"));
}
@Test
public void multipleHashtags() throws Exception {
String commitMessage = "#Subject\n\n#Hashtag\n\nLine 2";
- assertThat((Iterable<?>)HashtagsUtil.extractTags(commitMessage))
+ assertThat(HashtagsUtil.extractTags(commitMessage))
.containsExactlyElementsIn(Sets.newHashSet("Subject", "Hashtag"));
}
@Test
public void repeatedHashtag() throws Exception {
String commitMessage = "#Subject\n\n#Hashtag1\n\n#Hashtag2\n\n#Hashtag1";
- assertThat((Iterable<?>)HashtagsUtil.extractTags(commitMessage))
+ assertThat(HashtagsUtil.extractTags(commitMessage))
.containsExactlyElementsIn(
Sets.newHashSet("Subject", "Hashtag1", "Hashtag2"));
}
@@ -69,21 +69,21 @@
@Test
public void multipleHashtagsNoSpaces() throws Exception {
String commitMessage = "Subject\n\n#Hashtag1#Hashtag2";
- assertThat((Iterable<?>)HashtagsUtil.extractTags(commitMessage))
+ assertThat(HashtagsUtil.extractTags(commitMessage))
.containsExactlyElementsIn(Sets.newHashSet("Hashtag1"));
}
@Test
public void hyphenatedHashtag() throws Exception {
String commitMessage = "Subject\n\n#Hyphenated-Hashtag";
- assertThat((Iterable<?>)HashtagsUtil.extractTags(commitMessage))
+ assertThat(HashtagsUtil.extractTags(commitMessage))
.containsExactlyElementsIn(Sets.newHashSet("Hyphenated-Hashtag"));
}
@Test
public void underscoredHashtag() throws Exception {
String commitMessage = "Subject\n\n#Underscored_Hashtag";
- assertThat((Iterable<?>)HashtagsUtil.extractTags(commitMessage))
+ assertThat(HashtagsUtil.extractTags(commitMessage))
.containsExactlyElementsIn(Sets.newHashSet("Underscored_Hashtag"));
}
@@ -91,7 +91,7 @@
public void hashtagsWithAccentedCharacters() throws Exception {
String commitMessage = "Jag #måste #öva på min #Svenska!\n\n"
+ "Jag behöver en #läkare.";
- assertThat((Iterable<?>)HashtagsUtil.extractTags(commitMessage))
+ assertThat(HashtagsUtil.extractTags(commitMessage))
.containsExactlyElementsIn(
Sets.newHashSet("måste", "öva", "Svenska", "läkare"));
}
@@ -99,6 +99,6 @@
@Test
public void hashWithoutHashtag() throws Exception {
String commitMessage = "Subject\n\n# Text";
- assertThat((Iterable<?>)HashtagsUtil.extractTags(commitMessage)).isEmpty();
+ assertThat(HashtagsUtil.extractTags(commitMessage)).isEmpty();
}
}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/change/WalkSorterTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/change/WalkSorterTest.java
new file mode 100644
index 0000000..7b7983c
--- /dev/null
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/change/WalkSorterTest.java
@@ -0,0 +1,267 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.change;
+
+import static com.google.common.collect.Collections2.permutations;
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.RevId;
+import com.google.gerrit.server.change.WalkSorter.PatchSetData;
+import com.google.gerrit.server.query.change.ChangeData;
+import com.google.gerrit.testutil.InMemoryRepositoryManager;
+import com.google.gerrit.testutil.InMemoryRepositoryManager.Repo;
+import com.google.gerrit.testutil.TestChanges;
+import com.google.gwtorm.client.KeyUtil;
+import com.google.gwtorm.server.StandardKeyEncoder;
+
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class WalkSorterTest {
+ static {
+ KeyUtil.setEncoderImpl(new StandardKeyEncoder());
+ }
+
+ private Account.Id userId;
+ private InMemoryRepositoryManager repoManager;
+
+ @Before
+ public void setUp() {
+ userId = new Account.Id(1);
+ repoManager = new InMemoryRepositoryManager();
+ }
+
+ @Test
+ public void seriesOfChanges() throws Exception {
+ TestRepository<Repo> p = newRepo("p");
+ RevCommit c1_1 = p.commit().create();
+ RevCommit c2_1 = p.commit().parent(c1_1).create();
+ RevCommit c3_1 = p.commit().parent(c2_1).create();
+
+ ChangeData cd1 = newChange(p, c1_1);
+ ChangeData cd2 = newChange(p, c2_1);
+ ChangeData cd3 = newChange(p, c3_1);
+
+ List<ChangeData> changes = ImmutableList.of(cd1, cd2, cd3);
+ WalkSorter sorter = new WalkSorter(repoManager);
+
+ assertSorted(sorter, changes, ImmutableList.of(
+ patchSetData(cd3, c3_1),
+ patchSetData(cd2, c2_1),
+ patchSetData(cd1, c1_1)));
+
+ // Add new patch sets whose commits are in reverse order, so output is in
+ // reverse order.
+ RevCommit c3_2 = p.commit().create();
+ RevCommit c2_2 = p.commit().parent(c3_2).create();
+ RevCommit c1_2 = p.commit().parent(c2_2).create();
+
+ addPatchSet(cd1, c1_2);
+ addPatchSet(cd2, c2_2);
+ addPatchSet(cd3, c3_2);
+
+ assertSorted(sorter, changes, ImmutableList.of(
+ patchSetData(cd1, c1_2),
+ patchSetData(cd2, c2_2),
+ patchSetData(cd3, c3_2)));
+ }
+
+ @Test
+ public void seriesOfChangesAtSameTimestamp() throws Exception {
+ TestRepository<Repo> p = newRepo("p");
+ RevCommit c1 = p.commit().tick(0).create();
+ RevCommit c2 = p.commit().tick(0).parent(c1).create();
+ RevCommit c3 = p.commit().tick(0).parent(c2).create();
+ RevCommit c4 = p.commit().tick(0).parent(c3).create();
+
+ RevWalk rw = p.getRevWalk();
+ rw.parseCommit(c1);
+ assertThat(rw.parseCommit(c2).getCommitTime())
+ .isEqualTo(c1.getCommitTime());
+ assertThat(rw.parseCommit(c3).getCommitTime())
+ .isEqualTo(c1.getCommitTime());
+ assertThat(rw.parseCommit(c4).getCommitTime())
+ .isEqualTo(c1.getCommitTime());
+
+ ChangeData cd1 = newChange(p, c1);
+ ChangeData cd2 = newChange(p, c2);
+ ChangeData cd3 = newChange(p, c3);
+ ChangeData cd4 = newChange(p, c4);
+
+ List<ChangeData> changes = ImmutableList.of(cd1, cd2, cd3, cd4);
+ WalkSorter sorter = new WalkSorter(repoManager);
+
+ assertSorted(sorter, changes, ImmutableList.of(
+ patchSetData(cd4, c4),
+ patchSetData(cd3, c3),
+ patchSetData(cd2, c2),
+ patchSetData(cd1, c1)));
+ }
+
+ @Test
+ public void projectsSortedByName() throws Exception {
+ TestRepository<Repo> pa = newRepo("a");
+ TestRepository<Repo> pb = newRepo("b");
+ RevCommit c1 = pa.commit().create();
+ RevCommit c2 = pb.commit().create();
+ RevCommit c3 = pa.commit().parent(c1).create();
+ RevCommit c4 = pb.commit().parent(c2).create();
+
+ ChangeData cd1 = newChange(pa, c1);
+ ChangeData cd2 = newChange(pb, c2);
+ ChangeData cd3 = newChange(pa, c3);
+ ChangeData cd4 = newChange(pb, c4);
+
+ assertSorted(
+ new WalkSorter(repoManager),
+ ImmutableList.of(cd1, cd2, cd3, cd4),
+ ImmutableList.of(
+ patchSetData(cd3, c3),
+ patchSetData(cd1, c1),
+ patchSetData(cd4, c4),
+ patchSetData(cd2, c2)));
+ }
+
+ @Test
+ public void restrictToPatchSets() throws Exception {
+ TestRepository<Repo> p = newRepo("p");
+ RevCommit c1_1 = p.commit().create();
+ RevCommit c2_1 = p.commit().parent(c1_1).create();
+
+ ChangeData cd1 = newChange(p, c1_1);
+ ChangeData cd2 = newChange(p, c2_1);
+
+ // Add new patch sets whose commits are in reverse order.
+ RevCommit c2_2 = p.commit().create();
+ RevCommit c1_2 = p.commit().parent(c2_2).create();
+
+ addPatchSet(cd1, c1_2);
+ addPatchSet(cd2, c2_2);
+
+ List<ChangeData> changes = ImmutableList.of(cd1, cd2);
+ WalkSorter sorter = new WalkSorter(repoManager);
+
+ assertSorted(sorter, changes, ImmutableList.of(
+ patchSetData(cd1, c1_2),
+ patchSetData(cd2, c2_2)));
+
+ // If we restrict to PS1 of each change, the sorter uses that commit.
+ sorter.includePatchSets(ImmutableSet.of(
+ new PatchSet.Id(cd1.getId(), 1),
+ new PatchSet.Id(cd2.getId(), 1)));
+ assertSorted(sorter, changes, ImmutableList.of(
+ patchSetData(cd2, 1, c2_1),
+ patchSetData(cd1, 1, c1_1)));
+ }
+
+ @Test
+ public void restrictToPatchSetsOmittingWholeProject() throws Exception {
+ TestRepository<Repo> pa = newRepo("a");
+ TestRepository<Repo> pb = newRepo("b");
+ RevCommit c1 = pa.commit().create();
+ RevCommit c2 = pa.commit().create();
+
+ ChangeData cd1 = newChange(pa, c1);
+ ChangeData cd2 = newChange(pb, c2);
+
+ List<ChangeData> changes = ImmutableList.of(cd1, cd2);
+ WalkSorter sorter = new WalkSorter(repoManager)
+ .includePatchSets(ImmutableSet.of(cd1.currentPatchSet().getId()));
+
+ assertSorted(sorter, changes, ImmutableList.of(patchSetData(cd1, c1)));
+ }
+
+ @Test
+ public void retainBody() throws Exception {
+ TestRepository<Repo> p = newRepo("p");
+ RevCommit c = p.commit().message("message").create();
+ ChangeData cd = newChange(p, c);
+
+ List<ChangeData> changes = ImmutableList.of(cd);
+ RevCommit actual = new WalkSorter(repoManager)
+ .setRetainBody(true)
+ .sort(changes)
+ .iterator().next()
+ .commit();
+ assertThat(actual.getRawBuffer()).isNotNull();
+ assertThat(actual.getShortMessage()).isEqualTo("message");
+
+ actual = new WalkSorter(repoManager)
+ .setRetainBody(false)
+ .sort(changes)
+ .iterator().next()
+ .commit();
+ assertThat(actual.getRawBuffer()).isNull();
+ }
+
+ private ChangeData newChange(TestRepository<Repo> tr, ObjectId id)
+ throws Exception {
+ Project.NameKey project = tr.getRepository().getDescription().getProject();
+ Change c = TestChanges.newChange(project, userId);
+ ChangeData cd = ChangeData.createForTest(c.getId(), 1);
+ cd.setChange(c);
+ cd.currentPatchSet().setRevision(new RevId(id.name()));
+ cd.setPatchSets(ImmutableList.of(cd.currentPatchSet()));
+ return cd;
+ }
+
+ private PatchSet addPatchSet(ChangeData cd, ObjectId id) throws Exception {
+ TestChanges.incrementPatchSet(cd.change());
+ PatchSet ps = new PatchSet(cd.change().currentPatchSetId());
+ ps.setRevision(new RevId(id.name()));
+ List<PatchSet> patchSets = new ArrayList<>(cd.patchSets());
+ patchSets.add(ps);
+ cd.setPatchSets(patchSets);
+ return ps;
+ }
+
+ private TestRepository<Repo> newRepo(String name)
+ throws Exception {
+ return new TestRepository<>(
+ repoManager.createRepository(new Project.NameKey(name)));
+ }
+
+ private static PatchSetData patchSetData(ChangeData cd, RevCommit commit)
+ throws Exception {
+ return PatchSetData.create(cd, cd.currentPatchSet(), commit);
+ }
+
+ private static PatchSetData patchSetData(ChangeData cd, int psId,
+ RevCommit commit) throws Exception {
+ return PatchSetData.create(
+ cd, cd.patchSet(new PatchSet.Id(cd.getId(), psId)), commit);
+ }
+
+ private static void assertSorted(WalkSorter sorter, List<ChangeData> changes,
+ List<PatchSetData> expected) throws Exception {
+ for (List<ChangeData> list : permutations(changes)) {
+ assertThat(sorter.sort(list))
+ .containsExactlyElementsIn(expected).inOrder();
+ }
+ }
+}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/config/RepositoryConfigTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/config/RepositoryConfigTest.java
new file mode 100644
index 0000000..1fb6d81
--- /dev/null
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/config/RepositoryConfigTest.java
@@ -0,0 +1,147 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.config;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.Lists;
+import com.google.gerrit.extensions.client.SubmitType;
+import com.google.gerrit.reviewdb.client.Project.NameKey;
+
+import org.eclipse.jgit.lib.Config;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.List;
+
+public class RepositoryConfigTest {
+
+ private Config cfg;
+ private RepositoryConfig repoCfg;
+
+ @Before
+ public void setUp() throws Exception {
+ cfg = new Config();
+ repoCfg = new RepositoryConfig(cfg);
+ }
+
+ @Test
+ public void testDefaultSubmitTypeWhenNotConfigured() {
+ assertThat(repoCfg.getDefaultSubmitType(new NameKey("someProject")))
+ .isEqualTo(SubmitType.MERGE_IF_NECESSARY);
+ }
+
+ @Test
+ public void testDefaultSubmitTypeForStarFilter() {
+ configureDefaultSubmitType("*", SubmitType.CHERRY_PICK);
+ assertThat(repoCfg.getDefaultSubmitType(new NameKey("someProject")))
+ .isEqualTo(SubmitType.CHERRY_PICK);
+
+ configureDefaultSubmitType("*", SubmitType.FAST_FORWARD_ONLY);
+ assertThat(repoCfg.getDefaultSubmitType(new NameKey("someProject")))
+ .isEqualTo(SubmitType.FAST_FORWARD_ONLY);
+
+ configureDefaultSubmitType("*", SubmitType.REBASE_IF_NECESSARY);
+ assertThat(repoCfg.getDefaultSubmitType(new NameKey("someProject")))
+ .isEqualTo(SubmitType.REBASE_IF_NECESSARY);
+ }
+
+ @Test
+ public void testDefaultSubmitTypeForSpecificFilter() {
+ configureDefaultSubmitType("someProject", SubmitType.CHERRY_PICK);
+ assertThat(repoCfg.getDefaultSubmitType(new NameKey("someOtherProject")))
+ .isEqualTo(SubmitType.MERGE_IF_NECESSARY);
+ assertThat(repoCfg.getDefaultSubmitType(new NameKey("someProject")))
+ .isEqualTo(SubmitType.CHERRY_PICK);
+ }
+
+ @Test
+ public void testDefaultSubmitTypeForStartWithFilter() {
+ configureDefaultSubmitType("somePath/somePath/*",
+ SubmitType.REBASE_IF_NECESSARY);
+ configureDefaultSubmitType("somePath/*", SubmitType.CHERRY_PICK);
+ configureDefaultSubmitType("*", SubmitType.MERGE_ALWAYS);
+
+ assertThat(repoCfg.getDefaultSubmitType(new NameKey("someProject")))
+ .isEqualTo(SubmitType.MERGE_ALWAYS);
+
+ assertThat(
+ repoCfg.getDefaultSubmitType(new NameKey("somePath/someProject")))
+ .isEqualTo(SubmitType.CHERRY_PICK);
+
+ assertThat(
+ repoCfg.getDefaultSubmitType(new NameKey(
+ "somePath/somePath/someProject"))).isEqualTo(
+ SubmitType.REBASE_IF_NECESSARY);
+ }
+
+ private void configureDefaultSubmitType(String projectFilter,
+ SubmitType submitType) {
+ cfg.setString(RepositoryConfig.SECTION_NAME, projectFilter,
+ RepositoryConfig.DEFAULT_SUBMIT_TYPE_NAME, submitType.toString());
+ }
+
+ @Test
+ public void testOwnerGroupsWhenNotConfigured() {
+ assertThat(repoCfg.getOwnerGroups(new NameKey("someProject"))).isEqualTo(
+ new String[] {});
+ }
+
+ @Test
+ public void testOwnerGroupsForStarFilter() {
+ String[] ownerGroups = new String[] {"group1", "group2"};
+ configureOwnerGroups("*", Lists.newArrayList(ownerGroups));
+ assertThat(repoCfg.getOwnerGroups(new NameKey("someProject"))).isEqualTo(
+ ownerGroups);
+ }
+
+ @Test
+ public void testOwnerGroupsForSpecificFilter() {
+ String[] ownerGroups = new String[] {"group1", "group2"};
+ configureOwnerGroups("someProject", Lists.newArrayList(ownerGroups));
+ assertThat(repoCfg.getOwnerGroups(new NameKey("someOtherProject")))
+ .isEqualTo(new String[] {});
+ assertThat(repoCfg.getOwnerGroups(new NameKey("someProject"))).isEqualTo(
+ ownerGroups);
+ }
+
+ @Test
+ public void testOwnerGroupsForStartWithFilter() {
+ String[] ownerGroups1 = new String[] {"group1"};
+ String[] ownerGroups2 = new String[] {"group2"};
+ String[] ownerGroups3 = new String[] {"group3"};
+
+ configureOwnerGroups("*", Lists.newArrayList(ownerGroups1));
+ configureOwnerGroups("somePath/*", Lists.newArrayList(ownerGroups2));
+ configureOwnerGroups("somePath/somePath/*",
+ Lists.newArrayList(ownerGroups3));
+
+ assertThat(repoCfg.getOwnerGroups(new NameKey("someProject"))).isEqualTo(
+ ownerGroups1);
+
+ assertThat(repoCfg.getOwnerGroups(new NameKey("somePath/someProject")))
+ .isEqualTo(ownerGroups2);
+
+ assertThat(
+ repoCfg.getOwnerGroups(new NameKey("somePath/somePath/someProject")))
+ .isEqualTo(ownerGroups3);
+ }
+
+ private void configureOwnerGroups(String projectFilter,
+ List<String> ownerGroups) {
+ cfg.setStringList(RepositoryConfig.SECTION_NAME, projectFilter,
+ RepositoryConfig.OWNER_GROUP_NAME, ownerGroups);
+ }
+}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/config/SitePathsTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/config/SitePathsTest.java
index 5fdecf0..5533d53 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/config/SitePathsTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/config/SitePathsTest.java
@@ -25,88 +25,89 @@
import org.junit.Test;
-import java.io.File;
-import java.io.FileNotFoundException;
import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.NotDirectoryException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
public class SitePathsTest {
@Test
public void testCreate_NotExisting() throws IOException {
- final File root = random();
+ final Path root = random();
final SitePaths site = new SitePaths(root);
assertTrue(site.isNew);
assertEquals(root, site.site_path);
- assertEquals(new File(root, "etc"), site.etc_dir);
+ assertEquals(root.resolve("etc"), site.etc_dir);
}
@Test
public void testCreate_Empty() throws IOException {
- final File root = random();
+ final Path root = random();
try {
- assertTrue(root.mkdir());
+ Files.createDirectory(root);
final SitePaths site = new SitePaths(root);
assertTrue(site.isNew);
assertEquals(root, site.site_path);
} finally {
- root.delete();
+ Files.delete(root);
}
}
@Test
public void testCreate_NonEmpty() throws IOException {
- final File root = random();
- final File txt = new File(root, "test.txt");
+ final Path root = random();
+ final Path txt = root.resolve("test.txt");
try {
- assertTrue(root.mkdir());
- assertTrue(txt.createNewFile());
+ Files.createDirectory(root);
+ Files.createFile(txt);
final SitePaths site = new SitePaths(root);
assertFalse(site.isNew);
assertEquals(root, site.site_path);
} finally {
- txt.delete();
- root.delete();
+ Files.delete(txt);
+ Files.delete(root);
}
}
@Test
public void testCreate_NotDirectory() throws IOException {
- final File root = random();
+ final Path root = random();
try {
- assertTrue(root.createNewFile());
+ Files.createFile(root);
try {
new SitePaths(root);
fail("Did not throw exception");
- } catch (FileNotFoundException e) {
- assertEquals("Not a directory: " + root.getPath(), e.getMessage());
+ } catch (NotDirectoryException e) {
+ // Expected.
}
} finally {
- root.delete();
+ Files.delete(root);
}
}
@Test
public void testResolve() throws IOException {
- final File root = random();
+ final Path root = random();
final SitePaths site = new SitePaths(root);
assertNull(site.resolve(null));
assertNull(site.resolve(""));
assertNotNull(site.resolve("a"));
- assertEquals(new File(root, "a").getCanonicalFile(), site.resolve("a"));
+ assertEquals(root.resolve("a").toAbsolutePath().normalize(),
+ site.resolve("a"));
final String pfx = HostPlatform.isWin32() ? "C:/" : "/";
assertNotNull(site.resolve(pfx + "a"));
- assertEquals(new File(pfx + "a").getCanonicalFile(), site.resolve(pfx + "a"));
+ assertEquals(Paths.get(pfx + "a"), site.resolve(pfx + "a"));
}
- private static File random() throws IOException {
- File tmp = File.createTempFile("gerrit_test_", "_site");
- if (!tmp.delete()) {
- throw new IOException("Cannot create " + tmp.getPath());
- }
+ private static Path random() throws IOException {
+ Path tmp = Files.createTempFile("gerrit_test_", "_site");
+ Files.deleteIfExists(tmp);
return tmp;
}
}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/git/GroupCollectorTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/git/GroupCollectorTest.java
new file mode 100644
index 0000000..ba0599d
--- /dev/null
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/git/GroupCollectorTest.java
@@ -0,0 +1,365 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.git;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableListMultimap;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimap;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+
+import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
+import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevSort;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.junit.Before;
+import org.junit.Test;
+
+public class GroupCollectorTest {
+ private TestRepository<?> tr;
+
+ @Before
+ public void setUp() throws Exception {
+ tr = new TestRepository<>(
+ new InMemoryRepository(new DfsRepositoryDescription("repo")));
+ }
+
+ @Test
+ public void commitWhoseParentIsUninterestingGetsNewGroup() throws Exception {
+ RevCommit branchTip = tr.commit().create();
+ RevCommit a = tr.commit().parent(branchTip).create();
+
+ Multimap<ObjectId, String> groups = collectGroups(
+ newWalk(a, branchTip),
+ patchSets(),
+ groups());
+
+ assertThat(groups).containsEntry(a, a.name());
+ }
+
+ @Test
+ public void commitWhoseParentIsNewPatchSetGetsParentsGroup()
+ throws Exception {
+ RevCommit branchTip = tr.commit().create();
+ RevCommit a = tr.commit().parent(branchTip).create();
+ RevCommit b = tr.commit().parent(a).create();
+
+ Multimap<ObjectId, String> groups = collectGroups(
+ newWalk(b, branchTip),
+ patchSets(),
+ groups());
+
+ assertThat(groups).containsEntry(a, a.name());
+ assertThat(groups).containsEntry(b, a.name());
+ }
+
+ @Test
+ public void commitWhoseParentIsExistingPatchSetGetsParentsGroup()
+ throws Exception {
+ RevCommit branchTip = tr.commit().create();
+ RevCommit a = tr.commit().parent(branchTip).create();
+ RevCommit b = tr.commit().parent(a).create();
+
+ String group = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
+ Multimap<ObjectId, String> groups = collectGroups(
+ newWalk(b, branchTip),
+ patchSets().put(a, psId(1, 1)),
+ groups().put(psId(1, 1), group));
+
+ assertThat(groups).containsEntry(a, group);
+ assertThat(groups).containsEntry(b, group);
+ }
+
+ @Test
+ public void commitWhoseParentIsExistingPatchSetWithNoGroup()
+ throws Exception {
+ RevCommit branchTip = tr.commit().create();
+ RevCommit a = tr.commit().parent(branchTip).create();
+ RevCommit b = tr.commit().parent(a).create();
+
+ Multimap<ObjectId, String> groups = collectGroups(
+ newWalk(b, branchTip),
+ patchSets().put(a, psId(1, 1)),
+ groups());
+
+ assertThat(groups).containsEntry(a, a.name());
+ assertThat(groups).containsEntry(b, a.name());
+ }
+
+ @Test
+ public void mergeCommitAndNewParentsAllGetSameGroup() throws Exception {
+ RevCommit branchTip = tr.commit().create();
+ RevCommit a = tr.commit().parent(branchTip).create();
+ RevCommit b = tr.commit().parent(branchTip).create();
+ RevCommit m = tr.commit().parent(a).parent(b).create();
+
+ Multimap<ObjectId, String> groups = collectGroups(
+ newWalk(m, branchTip),
+ patchSets(),
+ groups());
+
+ assertThat(groups).containsEntry(a, a.name());
+ assertThat(groups).containsEntry(b, a.name());
+ assertThat(groups).containsEntry(m, a.name());
+ }
+
+ @Test
+ public void mergeCommitWhereOneParentHasExistingGroup() throws Exception {
+ RevCommit branchTip = tr.commit().create();
+ RevCommit a = tr.commit().parent(branchTip).create();
+ RevCommit b = tr.commit().parent(branchTip).create();
+ RevCommit m = tr.commit().parent(a).parent(b).create();
+
+ String group = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
+ Multimap<ObjectId, String> groups = collectGroups(
+ newWalk(m, branchTip),
+ patchSets().put(b, psId(1, 1)),
+ groups().put(psId(1, 1), group));
+
+ // Merge commit and other parent get the existing group.
+ assertThat(groups).containsEntry(a, group);
+ assertThat(groups).containsEntry(b, group);
+ assertThat(groups).containsEntry(m, group);
+ }
+
+ @Test
+ public void mergeCommitWhereBothParentsHaveDifferentGroups()
+ throws Exception {
+ RevCommit branchTip = tr.commit().create();
+ RevCommit a = tr.commit().parent(branchTip).create();
+ RevCommit b = tr.commit().parent(branchTip).create();
+ RevCommit m = tr.commit().parent(a).parent(b).create();
+
+ String group1 = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
+ String group2 = "1234567812345678123456781234567812345678";
+ Multimap<ObjectId, String> groups = collectGroups(
+ newWalk(m, branchTip),
+ patchSets()
+ .put(a, psId(1, 1))
+ .put(b, psId(2, 1)),
+ groups()
+ .put(psId(1, 1), group1)
+ .put(psId(2, 1), group2));
+
+ assertThat(groups).containsEntry(a, group1);
+ assertThat(groups).containsEntry(b, group2);
+ // Merge commit gets joined group of parents.
+ assertThat(groups.asMap())
+ .containsEntry(m, ImmutableSet.of(group1, group2));
+ }
+
+ @Test
+ public void mergeCommitMergesGroupsFromParent() throws Exception {
+ RevCommit branchTip = tr.commit().create();
+ RevCommit a = tr.commit().parent(branchTip).create();
+ RevCommit b = tr.commit().parent(branchTip).create();
+ RevCommit m = tr.commit().parent(a).parent(b).create();
+
+ String group1 = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
+ String group2a = "1234567812345678123456781234567812345678";
+ String group2b = "ef123456ef123456ef123456ef123456ef123456";
+ Multimap<ObjectId, String> groups = collectGroups(
+ newWalk(m, branchTip),
+ patchSets()
+ .put(a, psId(1, 1))
+ .put(b, psId(2, 1)),
+ groups()
+ .put(psId(1, 1), group1)
+ .put(psId(2, 1), group2a)
+ .put(psId(2, 1), group2b));
+
+ assertThat(groups).containsEntry(a, group1);
+ assertThat(groups.asMap())
+ .containsEntry(b, ImmutableSet.of(group2a, group2b));
+ // Joined parent groups are split and resorted.
+ assertThat(groups.asMap())
+ .containsEntry(m, ImmutableSet.of(group1, group2a, group2b));
+ }
+
+ @Test
+ public void mergeCommitWithOneUninterestingParentAndOtherParentIsExisting()
+ throws Exception {
+ RevCommit branchTip = tr.commit().create();
+ RevCommit a = tr.commit().parent(branchTip).create();
+ RevCommit m = tr.commit().parent(branchTip).parent(a).create();
+
+ String group = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
+ Multimap<ObjectId, String> groups = collectGroups(
+ newWalk(m, branchTip),
+ patchSets().put(a, psId(1, 1)),
+ groups().put(psId(1, 1), group));
+
+ assertThat(groups).containsEntry(a, group);
+ assertThat(groups).containsEntry(m, group);
+ }
+
+ @Test
+ public void mergeCommitWithOneUninterestingParentAndOtherParentIsNew()
+ throws Exception {
+ RevCommit branchTip = tr.commit().create();
+ RevCommit a = tr.commit().parent(branchTip).create();
+ RevCommit m = tr.commit().parent(branchTip).parent(a).create();
+
+ Multimap<ObjectId, String> groups = collectGroups(
+ newWalk(m, branchTip),
+ patchSets(),
+ groups());
+
+ assertThat(groups).containsEntry(a, a.name());
+ assertThat(groups).containsEntry(m, a.name());
+ }
+
+ @Test
+ public void multipleMergeCommitsInHistoryAllResolveToSameGroup()
+ throws Exception {
+ RevCommit branchTip = tr.commit().create();
+ RevCommit a = tr.commit().parent(branchTip).create();
+ RevCommit b = tr.commit().parent(branchTip).create();
+ RevCommit c = tr.commit().parent(branchTip).create();
+ RevCommit m1 = tr.commit().parent(b).parent(c).create();
+ RevCommit m2 = tr.commit().parent(a).parent(m1).create();
+
+ Multimap<ObjectId, String> groups = collectGroups(
+ newWalk(m2, branchTip),
+ patchSets(),
+ groups());
+
+ assertThat(groups).containsEntry(a, a.name());
+ assertThat(groups).containsEntry(b, a.name());
+ assertThat(groups).containsEntry(c, a.name());
+ assertThat(groups).containsEntry(m1, a.name());
+ assertThat(groups).containsEntry(m2, a.name());
+ }
+
+ @Test
+ public void mergeCommitWithDuplicatedParentGetsParentsGroup()
+ throws Exception {
+ RevCommit branchTip = tr.commit().create();
+ RevCommit a = tr.commit().parent(branchTip).create();
+ RevCommit m = tr.commit().parent(a).parent(a).create();
+ tr.getRevWalk().parseBody(m);
+ assertThat(m.getParentCount()).isEqualTo(2);
+ assertThat(m.getParent(0)).isEqualTo(m.getParent(1));
+
+ Multimap<ObjectId, String> groups = collectGroups(
+ newWalk(m, branchTip),
+ patchSets(),
+ groups());
+
+ assertThat(groups).containsEntry(a, a.name());
+ assertThat(groups).containsEntry(m, a.name());
+ }
+
+ @Test
+ public void mergeCommitWithOneNewParentAndTwoExistingPatchSets()
+ throws Exception {
+ RevCommit branchTip = tr.commit().create();
+ RevCommit a = tr.commit().parent(branchTip).create();
+ RevCommit b = tr.commit().parent(branchTip).create();
+ RevCommit c = tr.commit().parent(b).create();
+ RevCommit m = tr.commit().parent(a).parent(c).create();
+
+ String group1 = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
+ String group2 = "1234567812345678123456781234567812345678";
+ Multimap<ObjectId, String> groups = collectGroups(
+ newWalk(m, branchTip),
+ patchSets()
+ .put(a, psId(1, 1))
+ .put(b, psId(2, 1)),
+ groups()
+ .put(psId(1, 1), group1)
+ .put(psId(2, 1), group2));
+
+ assertThat(groups).containsEntry(a, group1);
+ assertThat(groups).containsEntry(b, group2);
+ assertThat(groups).containsEntry(c, group2);
+ assertThat(groups.asMap())
+ .containsEntry(m, ImmutableSet.of(group1, group2));
+ }
+
+ @Test
+ public void collectGroupsForMultipleTipsInParallel() throws Exception {
+ RevCommit branchTip = tr.commit().create();
+ RevCommit a = tr.commit().parent(branchTip).create();
+ RevCommit b = tr.commit().parent(a).create();
+ RevCommit c = tr.commit().parent(branchTip).create();
+ RevCommit d = tr.commit().parent(c).create();
+
+ RevWalk rw = newWalk(b, branchTip);
+ rw.markStart(rw.parseCommit(d));
+ // Schema upgrade case: all commits are existing patch sets, but none have
+ // groups assigned yet.
+ Multimap<ObjectId, String> groups = collectGroups(
+ rw,
+ patchSets()
+ .put(branchTip, psId(1, 1))
+ .put(a, psId(2, 1))
+ .put(b, psId(3, 1))
+ .put(c, psId(4, 1))
+ .put(d, psId(5, 1)),
+ groups());
+
+ assertThat(groups).containsEntry(a, a.name());
+ assertThat(groups).containsEntry(b, a.name());
+ assertThat(groups).containsEntry(c, c.name());
+ assertThat(groups).containsEntry(d, c.name());
+ }
+
+ // TODO(dborowitz): Tests for octopus merges.
+
+ private static PatchSet.Id psId(int c, int p) {
+ return new PatchSet.Id(new Change.Id(c), p);
+ }
+
+ private RevWalk newWalk(ObjectId start, ObjectId branchTip) throws Exception {
+ // Match RevWalk conditions from ReceiveCommits.
+ RevWalk rw = new RevWalk(tr.getRepository());
+ rw.sort(RevSort.TOPO);
+ rw.sort(RevSort.REVERSE, true);
+ rw.markStart(rw.parseCommit(start));
+ rw.markUninteresting(rw.parseCommit(branchTip));
+ return rw;
+ }
+
+ private static Multimap<ObjectId, String> collectGroups(
+ RevWalk rw,
+ ImmutableMultimap.Builder<ObjectId, PatchSet.Id> patchSetsBySha,
+ ImmutableListMultimap.Builder<PatchSet.Id, String> groupLookup)
+ throws Exception {
+ GroupCollector gc =
+ new GroupCollector(patchSetsBySha.build(), groupLookup.build());
+ RevCommit c;
+ while ((c = rw.next()) != null) {
+ gc.visit(c);
+ }
+ return gc.getGroups();
+ }
+
+ // Helper methods for constructing various map arguments, to avoid lots of
+ // type specifications.
+ private static ImmutableMultimap.Builder<ObjectId, PatchSet.Id> patchSets() {
+ return ImmutableMultimap.builder();
+ }
+
+ private static ImmutableListMultimap.Builder<PatchSet.Id, String> groups() {
+ return ImmutableListMultimap.builder();
+ }
+}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/git/GroupListTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/git/GroupListTest.java
index e741a91c..fde86a5 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/git/GroupListTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/git/GroupListTest.java
@@ -118,4 +118,8 @@
"ebe31c01aec2c9ac3b3c03e87a47450829ff4310")));
}
+ @Test
+ public void testAsText() throws Exception {
+ assertTrue(TEXT.equals(groupList.asText()));
+ }
}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/git/LabelNormalizerTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/git/LabelNormalizerTest.java
index 78a4c5c..181ba15 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/git/LabelNormalizerTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/git/LabelNormalizerTest.java
@@ -46,6 +46,7 @@
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
+import com.google.inject.util.Providers;
import org.eclipse.jgit.lib.Repository;
import org.junit.After;
@@ -59,7 +60,7 @@
@Inject private AccountManager accountManager;
@Inject private AllProjectsName allProjects;
@Inject private GitRepositoryManager repoManager;
- @Inject private IdentifiedUser.RequestFactory userFactory;
+ @Inject private IdentifiedUser.GenericFactory userFactory;
@Inject private InMemoryDatabase schemaFactory;
@Inject private LabelNormalizer norm;
@Inject private MetaDataUpdate.User metaDataUpdateFactory;
@@ -84,7 +85,7 @@
schemaCreator.create(db);
userId = accountManager.authenticate(AuthRequest.forUser("user"))
.getAccountId();
- user = userFactory.create(userId);
+ user = userFactory.create(Providers.of(db), userId);
configureProject();
setUpChange();
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java
new file mode 100644
index 0000000..ca154b1
--- /dev/null
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java
@@ -0,0 +1,233 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.git;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.config.SitePaths;
+import com.google.gerrit.server.notedb.NotesMigration;
+import com.google.gerrit.testutil.TempFileUtil;
+import com.google.gwtorm.client.KeyUtil;
+import com.google.gwtorm.server.StandardKeyEncoder;
+
+import org.easymock.EasyMockSupport;
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.RepositoryCache;
+import org.eclipse.jgit.lib.RepositoryCache.FileKey;
+import org.eclipse.jgit.util.FS;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+public class LocalDiskRepositoryManagerTest extends EasyMockSupport {
+
+ static {
+ KeyUtil.setEncoderImpl(new StandardKeyEncoder());
+ }
+
+ private Config cfg;
+ private SitePaths site;
+ private LocalDiskRepositoryManager repoManager;
+
+ @Before
+ public void setUp() throws Exception {
+ site = new SitePaths(TempFileUtil.createTempDirectory().toPath());
+ site.resolve("git").toFile().mkdir();
+ cfg = new Config();
+ cfg.setString("gerrit", null, "basePath", "git");
+ repoManager =
+ new LocalDiskRepositoryManager(site, cfg,
+ createNiceMock(NotesMigration.class));
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testThatNullBasePathThrowsAnException() {
+ new LocalDiskRepositoryManager(site, new Config(),
+ createNiceMock(NotesMigration.class));
+ }
+
+ @Test
+ public void testProjectCreation() throws Exception {
+ Project.NameKey projectA = new Project.NameKey("projectA");
+ try (Repository repo = repoManager.createRepository(projectA)) {
+ assertThat(repo).isNotNull();
+ }
+ try (Repository repo = repoManager.openRepository(projectA)) {
+ assertThat(repo).isNotNull();
+ }
+ assertThat(repoManager.list()).containsExactly(projectA);
+ }
+
+ @Test(expected = RepositoryNotFoundException.class)
+ public void testProjectCreationWithEmptyName() throws Exception {
+ repoManager.createRepository(new Project.NameKey(""));
+ }
+
+ @Test(expected = RepositoryNotFoundException.class)
+ public void testProjectCreationWithTrailingSlash() throws Exception {
+ repoManager.createRepository(new Project.NameKey("projectA/"));
+ }
+
+ @Test(expected = RepositoryNotFoundException.class)
+ public void testProjectCreationWithBackSlash() throws Exception {
+ repoManager.createRepository(new Project.NameKey("a\\projectA"));
+ }
+
+ @Test(expected = RepositoryNotFoundException.class)
+ public void testProjectCreationAbsolutePath() throws Exception {
+ repoManager.createRepository(new Project.NameKey("/projectA"));
+ }
+
+ @Test(expected = RepositoryNotFoundException.class)
+ public void testProjectCreationStartingWithDotDot() throws Exception {
+ repoManager.createRepository(new Project.NameKey("../projectA"));
+ }
+
+ @Test(expected = RepositoryNotFoundException.class)
+ public void testProjectCreationContainsDotDot() throws Exception {
+ repoManager.createRepository(new Project.NameKey("a/../projectA"));
+ }
+
+ @Test(expected = RepositoryNotFoundException.class)
+ public void testProjectCreationDotPathSegment() throws Exception {
+ repoManager.createRepository(new Project.NameKey("a/./projectA"));
+ }
+
+ @Test(expected = RepositoryNotFoundException.class)
+ public void testProjectCreationWithTwoSlashes() throws Exception {
+ repoManager.createRepository(new Project.NameKey("a//projectA"));
+ }
+
+ @Test(expected = RepositoryNotFoundException.class)
+ public void testProjectCreationWithPathSegmentEndingByDotGit()
+ throws Exception {
+ repoManager.createRepository(new Project.NameKey("a/b.git/projectA"));
+ }
+
+ @Test(expected = RepositoryNotFoundException.class)
+ public void testProjectCreationWithQuestionMark() throws Exception {
+ repoManager.createRepository(new Project.NameKey("project?A"));
+ }
+
+ @Test(expected = RepositoryNotFoundException.class)
+ public void testProjectCreationWithPercentageSign() throws Exception {
+ repoManager.createRepository(new Project.NameKey("project%A"));
+ }
+
+ @Test(expected = RepositoryNotFoundException.class)
+ public void testProjectCreationWithWidlcard() throws Exception {
+ repoManager.createRepository(new Project.NameKey("project*A"));
+ }
+
+ @Test(expected = RepositoryNotFoundException.class)
+ public void testProjectCreationWithColon() throws Exception {
+ repoManager.createRepository(new Project.NameKey("project:A"));
+ }
+
+ @Test(expected = RepositoryNotFoundException.class)
+ public void testProjectCreationWithLessThatSign() throws Exception {
+ repoManager.createRepository(new Project.NameKey("project<A"));
+ }
+
+ @Test(expected = RepositoryNotFoundException.class)
+ public void testProjectCreationWithGreaterThatSign() throws Exception {
+ repoManager.createRepository(new Project.NameKey("project>A"));
+ }
+
+ @Test(expected = RepositoryNotFoundException.class)
+ public void testProjectCreationWithPipe() throws Exception {
+ repoManager.createRepository(new Project.NameKey("project|A"));
+ }
+
+ @Test(expected = RepositoryNotFoundException.class)
+ public void testProjectCreationWithDollarSign() throws Exception {
+ repoManager.createRepository(new Project.NameKey("project$A"));
+ }
+
+ @Test(expected = RepositoryNotFoundException.class)
+ public void testProjectCreationWithCarriageReturn() throws Exception {
+ repoManager.createRepository(new Project.NameKey("project\\rA"));
+ }
+
+ @Test
+ public void testOpenRepositoryCreatedDirectlyOnDisk() throws Exception {
+ createRepository(repoManager.getBasePath(), "projectA");
+ Project.NameKey projectA = new Project.NameKey("projectA");
+ try (Repository repo = repoManager.openRepository(projectA)) {
+ assertThat(repo).isNotNull();
+ }
+ assertThat(repoManager.list()).containsExactly(projectA);
+ }
+
+ @Test(expected = RepositoryNotFoundException.class)
+ public void testOpenRepositoryInvalidName() throws Exception {
+ repoManager.openRepository(new Project.NameKey("project%?|<>A"));
+ }
+
+ @Test
+ public void testList() throws Exception {
+ Project.NameKey projectA = new Project.NameKey("projectA");
+ createRepository(repoManager.getBasePath(), projectA.get());
+
+ Project.NameKey projectB = new Project.NameKey("path/projectB");
+ createRepository(repoManager.getBasePath(), projectB.get());
+
+ Project.NameKey projectC = new Project.NameKey("anotherPath/path/projectC");
+ createRepository(repoManager.getBasePath(), projectC.get());
+ // create an invalid git repo named only .git
+ repoManager.getBasePath().resolve(".git").toFile().mkdir();
+ // create an invalid repo name
+ createRepository(repoManager.getBasePath(), "project?A");
+ assertThat(repoManager.list())
+ .containsExactly(projectA, projectB, projectC);
+ }
+
+ @Test
+ public void testGetSetProjectDescription() throws Exception {
+ Project.NameKey projectA = new Project.NameKey("projectA");
+ try (Repository repo = repoManager.createRepository(projectA)) {
+ assertThat(repo).isNotNull();
+ }
+
+ assertThat(repoManager.getProjectDescription(projectA)).isNull();
+ repoManager.setProjectDescription(projectA, "projectA description");
+ assertThat(repoManager.getProjectDescription(projectA)).isEqualTo(
+ "projectA description");
+
+ repoManager.setProjectDescription(projectA, "");
+ assertThat(repoManager.getProjectDescription(projectA)).isNull();
+ }
+
+ @Test(expected = RepositoryNotFoundException.class)
+ public void testGetProjectDescriptionFromUnexistingRepository()
+ throws Exception {
+ repoManager.getProjectDescription(new Project.NameKey("projectA"));
+ }
+
+ private void createRepository(Path directory, String projectName)
+ throws IOException {
+ String n = projectName + Constants.DOT_GIT_EXT;
+ FileKey loc = FileKey.exact(directory.resolve(n).toFile(), FS.DETECTED);
+ try (Repository db = RepositoryCache.open(loc, false)) {
+ db.create(true /* bare */);
+ }
+ }
+}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/git/QueryListTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/git/QueryListTest.java
new file mode 100644
index 0000000..d022d3e
--- /dev/null
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/git/QueryListTest.java
@@ -0,0 +1,121 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.git;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.easymock.EasyMock.createNiceMock;
+import static org.easymock.EasyMock.replay;
+
+import junit.framework.TestCase;
+
+import org.junit.Test;
+
+import java.io.IOException;
+
+public class QueryListTest extends TestCase {
+ public static final String Q_P = "project:foo";
+ public static final String Q_B = "branch:bar";
+ public static final String Q_COMPLEX = "branch:bar AND peers:'is:open\t'";
+
+ public static final String N_FOO = "foo";
+ public static final String N_BAR = "bar";
+
+ public static final String L_FOO = N_FOO + "\t" + Q_P + "\n";
+ public static final String L_BAR = N_BAR + "\t" + Q_B + "\n";
+ public static final String L_FOO_PROP = N_FOO + " \t" + Q_P + "\n";
+ public static final String L_BAR_PROP = N_BAR + " \t" + Q_B + "\n";
+ public static final String L_FOO_PAD_F = " " + N_FOO + "\t" + Q_P + "\n";
+ public static final String L_FOO_PAD_E = N_FOO + " \t" + Q_P + "\n";
+ public static final String L_BAR_PAD_F = N_BAR + "\t " + Q_B + "\n";
+ public static final String L_BAR_PAD_E = N_BAR + "\t" + Q_B + " \n";
+ public static final String L_COMPLEX = N_FOO + "\t" + Q_COMPLEX + "\t \n";
+ public static final String L_BAD = N_FOO + "\n";
+
+ public static final String HEADER = "# Name\tQuery\n";
+ public static final String C1 = "# A Simple Comment\n";
+ public static final String C2 = "# Comment with a tab\t and multi # # #\n";
+
+ public static final String F_SIMPLE = L_FOO + L_BAR;
+ public static final String F_PROPER = L_BAR_PROP + L_FOO_PROP; // alpha order
+ public static final String F_PAD_F = L_FOO_PAD_F + L_BAR_PAD_F;
+ public static final String F_PAD_E = L_FOO_PAD_E + L_BAR_PAD_E;
+
+ @Test
+ public void testParseSimple() throws Exception {
+ QueryList ql = QueryList.parse(F_SIMPLE, null);
+ assertThat(ql.getQuery(N_FOO)).isEqualTo(Q_P);
+ assertThat(ql.getQuery(N_BAR)).isEqualTo(Q_B);
+ }
+
+ @Test
+ public void testParseWHeader() throws Exception {
+ QueryList ql = QueryList.parse(HEADER + F_SIMPLE, null);
+ assertThat(ql.getQuery(N_FOO)).isEqualTo(Q_P);
+ assertThat(ql.getQuery(N_BAR)).isEqualTo(Q_B);
+ }
+
+ @Test
+ public void testParseWComments() throws Exception {
+ QueryList ql = QueryList.parse(C1 + F_SIMPLE + C2, null);
+ assertThat(ql.getQuery(N_FOO)).isEqualTo(Q_P);
+ assertThat(ql.getQuery(N_BAR)).isEqualTo(Q_B);
+ }
+
+ @Test
+ public void testParseFooComment() throws Exception {
+ QueryList ql = QueryList.parse("#" + L_FOO + L_BAR, null);
+ assertThat(ql.getQuery(N_FOO)).isNull();
+ assertThat(ql.getQuery(N_BAR)).isEqualTo(Q_B);
+ }
+
+ @Test
+ public void testParsePaddedFronts() throws Exception {
+ QueryList ql = QueryList.parse(F_PAD_F, null);
+ assertThat(ql.getQuery(N_FOO)).isEqualTo(Q_P);
+ assertThat(ql.getQuery(N_BAR)).isEqualTo(Q_B);
+ }
+
+ @Test
+ public void testParsePaddedEnds() throws Exception {
+ QueryList ql = QueryList.parse(F_PAD_E, null);
+ assertThat(ql.getQuery(N_FOO)).isEqualTo(Q_P);
+ assertThat(ql.getQuery(N_BAR)).isEqualTo(Q_B);
+ }
+
+ @Test
+ public void testParseComplex() throws Exception {
+ QueryList ql = QueryList.parse(L_COMPLEX, null);
+ assertThat(ql.getQuery(N_FOO)).isEqualTo(Q_COMPLEX);
+ }
+
+ @Test(expected = IOException.class)
+ public void testParseBad() throws Exception {
+ ValidationError.Sink sink = createNiceMock(ValidationError.Sink.class);
+ replay(sink);
+ QueryList.parse(L_BAD, sink);
+ }
+
+ @Test
+ public void testAsText() throws Exception {
+ String expectedText = HEADER + "#\n" + F_PROPER;
+ QueryList ql = QueryList.parse(F_SIMPLE, null);
+ String asText = ql.asText();
+ assertThat(asText).isEqualTo(expectedText);
+
+ ql = QueryList.parse(asText, null);
+ asText = ql.asText();
+ assertThat(asText).isEqualTo(expectedText);
+ }
+}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/git/SubmoduleOpTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/git/SubmoduleOpTest.java
deleted file mode 100644
index c2f3f6f..0000000
--- a/gerrit-server/src/test/java/com/google/gerrit/server/git/SubmoduleOpTest.java
+++ /dev/null
@@ -1,1017 +0,0 @@
-// Copyright (C) 2011 The Android Open Source Project
-//
-// 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.
-
-package com.google.gerrit.server.git;
-
-import static org.easymock.EasyMock.anyObject;
-import static org.easymock.EasyMock.capture;
-import static org.easymock.EasyMock.eq;
-import static org.easymock.EasyMock.expect;
-import static org.junit.Assert.assertEquals;
-
-import com.google.gerrit.common.ChangeHooks;
-import com.google.gerrit.common.TimeUtil;
-import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.reviewdb.client.Branch;
-import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.reviewdb.client.SubmoduleSubscription;
-import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gerrit.reviewdb.server.SubmoduleSubscriptionAccess;
-import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
-import com.google.gwtorm.client.KeyUtil;
-import com.google.gwtorm.server.ListResultSet;
-import com.google.gwtorm.server.ResultSet;
-import com.google.gwtorm.server.SchemaFactory;
-import com.google.gwtorm.server.StandardKeyEncoder;
-import com.google.inject.Provider;
-
-import org.easymock.Capture;
-import org.easymock.EasyMock;
-import org.easymock.IMocksControl;
-import org.eclipse.jgit.api.Git;
-import org.eclipse.jgit.dircache.DirCacheBuilder;
-import org.eclipse.jgit.dircache.DirCacheEntry;
-import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
-import org.eclipse.jgit.lib.AnyObjectId;
-import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.FileMode;
-import org.eclipse.jgit.lib.ObjectInserter;
-import org.eclipse.jgit.lib.PersonIdent;
-import org.eclipse.jgit.lib.RefUpdate;
-import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.revwalk.RevCommit;
-import org.eclipse.jgit.revwalk.RevWalk;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-public class SubmoduleOpTest extends LocalDiskRepositoryTestCase {
- static {
- KeyUtil.setEncoderImpl(new StandardKeyEncoder());
- }
-
- private static final String newLine = System.getProperty("line.separator");
-
- private IMocksControl mockMaker;
- private SchemaFactory<ReviewDb> schemaFactory;
- private SubmoduleSubscriptionAccess subscriptions;
- private ReviewDb schema;
- private Provider<String> urlProvider;
- private GitRepositoryManager repoManager;
- private GitReferenceUpdated gitRefUpdated;
- private ChangeHooks changeHooks;
-
- @SuppressWarnings("unchecked")
- @Override
- @Before
- public void setUp() throws Exception {
- super.setUp();
-
- mockMaker = EasyMock.createStrictControl();
- schemaFactory = mockMaker.createMock(SchemaFactory.class);
- schema = mockMaker.createMock(ReviewDb.class);
- subscriptions = mockMaker.createMock(SubmoduleSubscriptionAccess.class);
- urlProvider = mockMaker.createMock(Provider.class);
- repoManager = mockMaker.createMock(GitRepositoryManager.class);
- gitRefUpdated = mockMaker.createMock(GitReferenceUpdated.class);
- changeHooks = mockMaker.createMock(ChangeHooks.class);
- }
-
- private void doReplay() {
- mockMaker.replay();
- }
-
- private void doVerify() {
- mockMaker.verify();
- }
-
- /**
- * It tests Submodule.update in the scenario a merged commit is an empty one
- * (it does not have a .gitmodules file) and the project the commit was merged
- * is not a submodule of other project.
- *
- * @throws Exception If an exception occurs.
- */
- @Test
- public void testEmptyCommit() throws Exception {
- expect(schemaFactory.open()).andReturn(schema);
-
- try (Repository realDb = createWorkRepository()) {
- // TODO(dborowitz): Use try/finally when this doesn't double-close the repo.
- @SuppressWarnings("resource")
- final Git git = new Git(realDb);
-
- final RevCommit mergeTip = git.commit().setMessage("test").call();
-
- final Branch.NameKey branchNameKey =
- new Branch.NameKey(new Project.NameKey("test-project"), "test-branch");
-
- expect(urlProvider.get()).andReturn("http://localhost:8080");
-
- expect(schema.submoduleSubscriptions()).andReturn(subscriptions);
- final ResultSet<SubmoduleSubscription> emptySubscriptions =
- new ListResultSet<>(new ArrayList<SubmoduleSubscription>());
- expect(subscriptions.bySubmodule(branchNameKey)).andReturn(
- emptySubscriptions);
-
- schema.close();
-
- doReplay();
-
- final SubmoduleOp submoduleOp =
- new SubmoduleOp(branchNameKey, mergeTip, new RevWalk(realDb), urlProvider,
- schemaFactory, realDb, null, new ArrayList<Change>(), null, null,
- null, null, null, null);
-
- submoduleOp.update();
-
- doVerify();
- }
- }
-
- /**
- * It tests SubmoduleOp.update in a scenario considering:
- * <ul>
- * <li>no subscriptions existing to destination project</li>
- * <li>a commit is merged to "dest-project"</li>
- * <li>commit contains .gitmodules file with content</li>
- * </ul>
- *
- * <pre>
- * [submodule "source"]
- * path = source
- * url = http://localhost:8080/source
- * branch = .
- * </pre>
- * <p>
- * It expects to insert a new row in subscriptions table. The row inserted
- * specifies:
- * <ul>
- * <li>target "dest-project" on branch "refs/heads/master"</li>
- * <li>source "a" on branch "refs/heads/master"</li>
- * <li>path "a"</li>
- * </ul>
- * </p>
- *
- * @throws Exception If an exception occurs.
- */
- @Test
- public void testNewSubscriptionToDotBranchValue() throws Exception {
- doOneSubscriptionInsert(buildSubmoduleSection("source", "source",
- "http://localhost:8080/source", ".").toString(), "refs/heads/master");
-
- doVerify();
- }
-
- /**
- * It tests SubmoduleOp.update in a scenario considering:
- * <ul>
- * <li>no subscriptions existing to destination project</li>
- * <li>a commit is merged to "dest-project"</li>
- * <li>commit contains .gitmodules file with content</li>
- * </ul>
- *
- * <pre>
- * [submodule "source"]
- * path = source
- * url = http://localhost:8080/source
- * branch = refs/heads/master
- * </pre>
- *
- * <p>
- * It expects to insert a new row in subscriptions table. The row inserted
- * specifies:
- * <ul>
- * <li>target "dest-project" on branch "refs/heads/master"</li>
- * <li>source "source" on branch "refs/heads/master"</li>
- * <li>path "source"</li>
- * </ul>
- * </p>
- *
- * @throws Exception If an exception occurs.
- */
- @Test
- public void testNewSubscriptionToSameBranch() throws Exception {
- doOneSubscriptionInsert(buildSubmoduleSection("source", "source",
- "http://localhost:8080/source", "refs/heads/master").toString(),
- "refs/heads/master");
-
- doVerify();
- }
-
- /**
- * It tests SubmoduleOp.update in a scenario considering:
- * <ul>
- * <li>no subscriptions existing to destination project</li>
- * <li>a commit is merged to "dest-project"</li>
- * <li>commit contains .gitmodules file with content</li>
- * </ul>
- *
- * <pre>
- * [submodule "source"]
- * path = source
- * url = http://localhost:8080/source
- * branch = refs/heads/test
- * </pre>
- * <p>
- * It expects to insert a new row in subscriptions table. The row inserted
- * specifies:
- * <ul>
- * <li>target "dest-project" on branch "refs/heads/master"</li>
- * <li>source "source" on branch "refs/heads/test"</li>
- * <li>path "source"</li>
- * </ul>
- * </p>
- *
- * @throws Exception If an exception occurs.
- */
- @Test
- public void testNewSubscriptionToDifferentBranch() throws Exception {
- doOneSubscriptionInsert(buildSubmoduleSection("source", "source",
- "http://localhost:8080/source", "refs/heads/test").toString(),
- "refs/heads/test");
-
- doVerify();
- }
-
- /**
- * It tests SubmoduleOp.update in a scenario considering:
- * <ul>
- * <li>no subscriptions existing to destination project</li>
- * <li>a commit is merged to "dest-project" in "refs/heads/master" branch</li>
- * <li>commit contains .gitmodules file with content</li>
- * </ul>
- *
- * <pre>
- * [submodule "source-a"]
- * path = source-a
- * url = http://localhost:8080/source-a
- * branch = .
- *
- * [submodule "source-b"]
- * path = source-b
- * url = http://localhost:8080/source-b
- * branch = .
- * </pre>
- * <p>
- * It expects to insert new rows in subscriptions table. The rows inserted
- * specifies:
- * <ul>
- * <li>target "dest-project" on branch "refs/heads/master"</li>
- * <li>source "source-a" on branch "refs/heads/master" with "source-a" path</li>
- * <li>source "source-b" on branch "refs/heads/master" with "source-b" path</li>
- * </ul>
- * </p>
- *
- * @throws Exception If an exception occurs.
- */
- @Test
- public void testNewSubscriptionsWithDotBranchValue() throws Exception {
- final StringBuilder sb =
- buildSubmoduleSection("source-a", "source-a",
- "http://localhost:8080/source-a", ".");
- sb.append(buildSubmoduleSection("source-b", "source-b",
- "http://localhost:8080/source-b", "."));
-
- final Branch.NameKey mergedBranch =
- new Branch.NameKey(new Project.NameKey("dest-project"),
- "refs/heads/master");
-
- List<SubmoduleSubscription> subscriptionsToInsert = new ArrayList<>();
- subscriptionsToInsert
- .add(new SubmoduleSubscription(mergedBranch, new Branch.NameKey(
- new Project.NameKey("source-a"), "refs/heads/master"), "source-a"));
- subscriptionsToInsert
- .add(new SubmoduleSubscription(mergedBranch, new Branch.NameKey(
- new Project.NameKey("source-b"), "refs/heads/master"), "source-b"));
-
- doOnlySubscriptionInserts(sb.toString(), mergedBranch,
- subscriptionsToInsert);
-
- doVerify();
- }
-
- /**
- * It tests SubmoduleOp.update in a scenario considering:
- * <ul>
- * <li>no subscriptions existing to destination project</li>
- * <li>a commit is merged to "dest-project" in "refs/heads/master" branch</li>
- * <li>commit contains .gitmodules file with content</li>
- * </ul>
- *
- * <pre>
- * [submodule "source-a"]
- * path = source-a
- * url = http://localhost:8080/source-a
- * branch = .
- *
- * [submodule "source-b"]
- * path = source-b
- * url = http://localhost:8080/source-b
- * branch = refs/heads/master
- * </pre>
- * <p>
- * It expects to insert new rows in subscriptions table. The rows inserted
- * specifies:
- * <ul>
- * <li>target "dest-project" on branch "refs/heads/master"</li>
- * <li>source "source-a" on branch "refs/heads/master" with "source-a" path</li>
- * <li>source "source-b" on branch "refs/heads/master" with "source-b" path</li>
- * </ul>
- * </p>
- *
- * @throws Exception If an exception occurs.
- */
- @Test
- public void testNewSubscriptionsDotAndSameBranchValues() throws Exception {
- final StringBuilder sb =
- buildSubmoduleSection("source-a", "source-a",
- "http://localhost:8080/source-a", ".");
- sb.append(buildSubmoduleSection("source-b", "source-b",
- "http://localhost:8080/source-b", "refs/heads/master"));
-
- final Branch.NameKey mergedBranch =
- new Branch.NameKey(new Project.NameKey("dest-project"),
- "refs/heads/master");
-
- List<SubmoduleSubscription> subscriptionsToInsert = new ArrayList<>();
- subscriptionsToInsert
- .add(new SubmoduleSubscription(mergedBranch, new Branch.NameKey(
- new Project.NameKey("source-a"), "refs/heads/master"), "source-a"));
- subscriptionsToInsert
- .add(new SubmoduleSubscription(mergedBranch, new Branch.NameKey(
- new Project.NameKey("source-b"), "refs/heads/master"), "source-b"));
-
- doOnlySubscriptionInserts(sb.toString(), mergedBranch,
- subscriptionsToInsert);
-
- doVerify();
- }
-
- /**
- * It tests SubmoduleOp.update in a scenario considering:
- * <ul>
- * <li>no subscriptions existing to destination project</li>
- * <li>a commit is merged to "dest-project" in "refs/heads/master" branch</li>
- * <li>commit contains .gitmodules file with content</li>
- *
- * <pre>
- * [submodule "source-a"]
- * path = source-a
- * url = http://localhost:8080/source-a
- * branch = refs/heads/test-a
- *
- * [submodule "source-b"]
- * path = source-b
- * url = http://localhost:8080/source-b
- * branch = refs/heads/test-b
- * </pre>
- *
- * <p>
- * It expects to insert new rows in subscriptions table. The rows inserted
- * specifies:
- * <ul>
- * <li>target "dest-project" on branch "refs/heads/master"</li>
- * <li>source "source-a" on branch "refs/heads/test-a" with "source-a" path</li>
- * <li>source "source-b" on branch "refs/heads/test-b" with "source-b" path</li>
- * </ul>
- * </p>
- *
- * @throws Exception If an exception occurs.
- */
- @Test
- public void testNewSubscriptionsSpecificBranchValues() throws Exception {
- final StringBuilder sb =
- buildSubmoduleSection("source-a", "source-a",
- "http://localhost:8080/source-a", "refs/heads/test-a");
- sb.append(buildSubmoduleSection("source-b", "source-b",
- "http://localhost:8080/source-b", "refs/heads/test-b"));
-
- final Branch.NameKey mergedBranch =
- new Branch.NameKey(new Project.NameKey("dest-project"),
- "refs/heads/master");
-
- List<SubmoduleSubscription> subscriptionsToInsert = new ArrayList<>();
- subscriptionsToInsert
- .add(new SubmoduleSubscription(mergedBranch, new Branch.NameKey(
- new Project.NameKey("source-a"), "refs/heads/test-a"), "source-a"));
- subscriptionsToInsert
- .add(new SubmoduleSubscription(mergedBranch, new Branch.NameKey(
- new Project.NameKey("source-b"), "refs/heads/test-b"), "source-b"));
-
- doOnlySubscriptionInserts(sb.toString(), mergedBranch,
- subscriptionsToInsert);
-
- doVerify();
- }
-
- /**
- * It tests SubmoduleOp.update in a scenario considering:
- * <ul>
- * <li>one subscription existing to destination project/branch</li>
- * <li>a commit is merged to "dest-project" in "refs/heads/master" branch</li>
- * <li>commit contains .gitmodules file with content</li>
- * </ul>
- *
- * <pre>
- * [submodule "source"]
- * path = source
- * url = http://localhost:8080/source
- * branch = refs/heads/master
- * </pre>
- * <p>
- * It expects to insert a new row in subscriptions table. The rows inserted
- * specifies:
- * <ul>
- * <li>target "dest-project" on branch "refs/heads/master"</li>
- * <li>source "source" on branch "refs/heads/master" with "source" path</li>
- * </ul>
- * </p>
- * <p>
- * It also expects to remove the row in subscriptions table specifying another
- * project/branch subscribed to merged branch. This one to be removed is:
- * <ul>
- * <li>target "dest-project" on branch "refs/heads/master"</li>
- * <li>source "old-source" on branch "refs/heads/master" with "old-source"
- * path</li>
- * </ul>
- * </p>
- *
- * @throws Exception If an exception occurs.
- */
- @Test
- public void testSubscriptionsInsertOneRemoveOne() throws Exception {
- final Branch.NameKey mergedBranch =
- new Branch.NameKey(new Project.NameKey("dest-project"),
- "refs/heads/master");
-
- List<SubmoduleSubscription> subscriptionsToInsert = new ArrayList<>();
- subscriptionsToInsert.add(new SubmoduleSubscription(mergedBranch,
- new Branch.NameKey(new Project.NameKey("source"), "refs/heads/master"),
- "source"));
-
- List<SubmoduleSubscription> oldOnesToMergedBranch = new ArrayList<>();
- oldOnesToMergedBranch.add(new SubmoduleSubscription(mergedBranch,
- new Branch.NameKey(new Project.NameKey("old-source"),
- "refs/heads/master"), "old-source"));
-
- doOnlySubscriptionTableOperations(buildSubmoduleSection("source", "source",
- "http://localhost:8080/source", "refs/heads/master").toString(),
- mergedBranch, subscriptionsToInsert, oldOnesToMergedBranch);
-
- doVerify();
- }
-
- /**
- * It tests SubmoduleOp.update in a scenario considering:
- * <ul>
- * <li>one subscription existing to destination project/branch with a source
- * called old on refs/heads/master branch</li>
- * <li>a commit is merged to "dest-project" in "refs/heads/master" branch</li>
- * <li>
- * commit contains .gitmodules file with content</li>
- * </ul>
- *
- * <pre>
- * [submodule "new"]
- * path = new
- * url = http://localhost:8080/new
- * branch = refs/heads/master
- *
- * [submodule "old"]
- * path = old
- * url = http://localhost:8080/old
- * branch = refs/heads/master
- * </pre>
- * <p>
- * It expects to insert a new row in subscriptions table. It should not remove
- * any row. The rows inserted specifies:
- * <ul>
- * <li>target "dest-project" on branch "refs/heads/master"</li>
- * <li>source "new" on branch "refs/heads/master" with "new" path</li>
- * </ul>
- * </p>
- *
- * @throws Exception If an exception occurs.
- */
- @Test
- public void testSubscriptionAddedAndMantainPreviousOne() throws Exception {
- final StringBuilder sb =
- buildSubmoduleSection("new", "new", "http://localhost:8080/new",
- "refs/heads/master");
- sb.append(buildSubmoduleSection("old", "old", "http://localhost:8080/old",
- "refs/heads/master"));
-
- final Branch.NameKey mergedBranch =
- new Branch.NameKey(new Project.NameKey("dest-project"),
- "refs/heads/master");
-
- final SubmoduleSubscription old =
- new SubmoduleSubscription(mergedBranch, new Branch.NameKey(new Project.NameKey(
- "old"), "refs/heads/master"), "old");
-
- List<SubmoduleSubscription> extractedsubscriptions = new ArrayList<>();
- extractedsubscriptions.add(new SubmoduleSubscription(mergedBranch,
- new Branch.NameKey(new Project.NameKey("new"), "refs/heads/master"),
- "new"));
- extractedsubscriptions.add(old);
-
- List<SubmoduleSubscription> oldOnesToMergedBranch = new ArrayList<>();
- oldOnesToMergedBranch.add(old);
-
- doOnlySubscriptionTableOperations(sb.toString(), mergedBranch,
- extractedsubscriptions, oldOnesToMergedBranch);
-
- doVerify();
- }
-
- /**
- * It tests SubmoduleOp.update in a scenario considering an empty .gitmodules
- * file is part of a commit to a destination project/branch having two sources
- * subscribed.
- * <p>
- * It expects to remove the subscriptions to destination project/branch.
- * </p>
- *
- * @throws Exception If an exception occurs.
- */
- @Test
- public void testRemoveSubscriptions() throws Exception {
- final Branch.NameKey mergedBranch =
- new Branch.NameKey(new Project.NameKey("dest-project"),
- "refs/heads/master");
-
- List<SubmoduleSubscription> extractedsubscriptions = new ArrayList<>();
- List<SubmoduleSubscription> oldOnesToMergedBranch = new ArrayList<>();
- oldOnesToMergedBranch
- .add(new SubmoduleSubscription(mergedBranch, new Branch.NameKey(
- new Project.NameKey("source-a"), "refs/heads/master"), "source-a"));
- oldOnesToMergedBranch
- .add(new SubmoduleSubscription(mergedBranch, new Branch.NameKey(
- new Project.NameKey("source-b"), "refs/heads/master"), "source-b"));
-
- doOnlySubscriptionTableOperations("", mergedBranch, extractedsubscriptions,
- oldOnesToMergedBranch);
- }
-
- /**
- * It tests SubmoduleOp.update in a scenario considering no .gitmodules file
- * in a merged commit to a destination project/branch that is a source one to
- * one called "target-project".
- * <p>
- * It expects to update the git link called "source-project" to be in target
- * repository.
- * </p>
- *
- * @throws Exception If an exception occurs.
- */
- @Test
- public void testOneSubscriberToUpdate() throws Exception {
- expect(schemaFactory.open()).andReturn(schema);
-
- try (Repository sourceRepository = createWorkRepository();
- Repository targetRepository = createWorkRepository()) {
- // TODO(dborowitz): Use try/finally when this doesn't double-close the repo.
- @SuppressWarnings("resource")
- final Git sourceGit = new Git(sourceRepository);
- // TODO(dborowitz): Use try/finally when this doesn't double-close the repo.
- @SuppressWarnings("resource")
- final Git targetGit = new Git(targetRepository);
-
- addRegularFileToIndex("file.txt", "test content", sourceRepository);
-
- final RevCommit sourceMergeTip =
- sourceGit.commit().setMessage("test").call();
-
- final Branch.NameKey sourceBranchNameKey =
- new Branch.NameKey(new Project.NameKey("source-project"),
- "refs/heads/master");
-
- final CodeReviewCommit codeReviewCommit =
- new CodeReviewCommit(sourceMergeTip.toObjectId());
- final Change submittedChange = new Change(
- new Change.Key(sourceMergeTip.toObjectId().getName()), new Change.Id(1),
- new Account.Id(1), sourceBranchNameKey, TimeUtil.nowTs());
-
- final Map<Change.Id, CodeReviewCommit> mergedCommits = new HashMap<>();
- mergedCommits.put(submittedChange.getId(), codeReviewCommit);
-
- final List<Change> submitted = new ArrayList<>();
- submitted.add(submittedChange);
-
- addGitLinkToIndex("a", sourceMergeTip.copy(), targetRepository);
-
- targetGit.commit().setMessage("test").call();
-
- final Branch.NameKey targetBranchNameKey =
- new Branch.NameKey(new Project.NameKey("target-project"),
- sourceBranchNameKey.get());
-
- expect(urlProvider.get()).andReturn("http://localhost:8080");
-
- expect(schema.submoduleSubscriptions()).andReturn(subscriptions);
- final ResultSet<SubmoduleSubscription> subscribers =
- new ListResultSet<>(Collections
- .singletonList(new SubmoduleSubscription(targetBranchNameKey,
- sourceBranchNameKey, "source-project")));
- expect(subscriptions.bySubmodule(sourceBranchNameKey)).andReturn(
- subscribers);
-
- expect(repoManager.openRepository(targetBranchNameKey.getParentKey()))
- .andReturn(targetRepository).anyTimes();
-
- Capture<RefUpdate> ruCapture = new Capture<>();
- gitRefUpdated.fire(eq(targetBranchNameKey.getParentKey()),
- capture(ruCapture));
- changeHooks.doRefUpdatedHook(eq(targetBranchNameKey),
- anyObject(RefUpdate.class), EasyMock.<Account>isNull());
-
- expect(schema.submoduleSubscriptions()).andReturn(subscriptions);
- final ResultSet<SubmoduleSubscription> emptySubscriptions =
- new ListResultSet<>(new ArrayList<SubmoduleSubscription>());
- expect(subscriptions.bySubmodule(targetBranchNameKey)).andReturn(
- emptySubscriptions);
-
- schema.close();
-
- final PersonIdent myIdent =
- new PersonIdent("test-user", "test-user@email.com");
-
- doReplay();
-
- final SubmoduleOp submoduleOp =
- new SubmoduleOp(sourceBranchNameKey, sourceMergeTip, new RevWalk(
- sourceRepository), urlProvider, schemaFactory, sourceRepository,
- new Project(sourceBranchNameKey.getParentKey()), submitted,
- mergedCommits, myIdent, repoManager, gitRefUpdated, null,
- changeHooks);
-
- submoduleOp.update();
-
- doVerify();
- RefUpdate ru = ruCapture.getValue();
- assertEquals(ru.getName(), targetBranchNameKey.get());
- }
- }
-
- /**
- * It tests SubmoduleOp.update in a scenario considering established circular
- * reference in submodule_subscriptions table.
- * <p>
- * In the tested scenario there is no .gitmodules file in a merged commit to a
- * destination project/branch that is a source one to one called
- * "target-project".
- * <p>
- * submodule_subscriptions table will be incorrect due source appearing as a
- * subscriber or target-project: according to database target-project has as
- * source the source-project, and source-project has as source the
- * target-project.
- * <p>
- * It expects to update the git link called "source-project" to be in target
- * repository and ignoring the incorrect row in database establishing the
- * circular reference.
- * </p>
- *
- * @throws Exception If an exception occurs.
- */
- @Test
- public void testAvoidingCircularReference() throws Exception {
- expect(schemaFactory.open()).andReturn(schema);
-
- try (Repository sourceRepository = createWorkRepository();
- Repository targetRepository = createWorkRepository()) {
- // TODO(dborowitz): Use try/finally when this doesn't double-close the repo.
- @SuppressWarnings("resource")
- final Git sourceGit = new Git(sourceRepository);
- // TODO(dborowitz): Use try/finally when this doesn't double-close the repo.
- @SuppressWarnings("resource")
- final Git targetGit = new Git(targetRepository);
-
- addRegularFileToIndex("file.txt", "test content", sourceRepository);
-
- final RevCommit sourceMergeTip =
- sourceGit.commit().setMessage("test").call();
-
- final Branch.NameKey sourceBranchNameKey =
- new Branch.NameKey(new Project.NameKey("source-project"),
- "refs/heads/master");
-
- final CodeReviewCommit codeReviewCommit =
- new CodeReviewCommit(sourceMergeTip.toObjectId());
- final Change submittedChange = new Change(
- new Change.Key(sourceMergeTip.toObjectId().getName()), new Change.Id(1),
- new Account.Id(1), sourceBranchNameKey, TimeUtil.nowTs());
-
- final Map<Change.Id, CodeReviewCommit> mergedCommits = new HashMap<>();
- mergedCommits.put(submittedChange.getId(), codeReviewCommit);
-
- final List<Change> submitted = new ArrayList<>();
- submitted.add(submittedChange);
-
- addGitLinkToIndex("a", sourceMergeTip.copy(), targetRepository);
-
- targetGit.commit().setMessage("test").call();
-
- final Branch.NameKey targetBranchNameKey =
- new Branch.NameKey(new Project.NameKey("target-project"),
- sourceBranchNameKey.get());
-
- expect(urlProvider.get()).andReturn("http://localhost:8080");
-
- expect(schema.submoduleSubscriptions()).andReturn(subscriptions);
- final ResultSet<SubmoduleSubscription> subscribers =
- new ListResultSet<>(Collections
- .singletonList(new SubmoduleSubscription(targetBranchNameKey,
- sourceBranchNameKey, "source-project")));
- expect(subscriptions.bySubmodule(sourceBranchNameKey)).andReturn(
- subscribers);
-
- expect(repoManager.openRepository(targetBranchNameKey.getParentKey()))
- .andReturn(targetRepository).anyTimes();
-
- Capture<RefUpdate> ruCapture = new Capture<>();
- gitRefUpdated.fire(eq(targetBranchNameKey.getParentKey()),
- capture(ruCapture));
- changeHooks.doRefUpdatedHook(eq(targetBranchNameKey),
- anyObject(RefUpdate.class), EasyMock.<Account>isNull());
-
- expect(schema.submoduleSubscriptions()).andReturn(subscriptions);
- final ResultSet<SubmoduleSubscription> incorrectSubscriptions =
- new ListResultSet<>(Collections
- .singletonList(new SubmoduleSubscription(sourceBranchNameKey,
- targetBranchNameKey, "target-project")));
- expect(subscriptions.bySubmodule(targetBranchNameKey)).andReturn(
- incorrectSubscriptions);
-
- schema.close();
-
- final PersonIdent myIdent =
- new PersonIdent("test-user", "test-user@email.com");
-
- doReplay();
-
- final SubmoduleOp submoduleOp =
- new SubmoduleOp(sourceBranchNameKey, sourceMergeTip, new RevWalk(
- sourceRepository), urlProvider, schemaFactory, sourceRepository,
- new Project(sourceBranchNameKey.getParentKey()), submitted,
- mergedCommits, myIdent, repoManager, gitRefUpdated, null, changeHooks);
-
- submoduleOp.update();
-
- doVerify();
- RefUpdate ru = ruCapture.getValue();
- assertEquals(ru.getName(), targetBranchNameKey.get());
- }
- }
-
- /**
- * It calls SubmoduleOp.update considering only one insert on Subscriptions
- * table.
- * <p>
- * It considers a commit containing a .gitmodules file was merged in
- * refs/heads/master of a dest-project.
- * </p>
- * <p>
- * The .gitmodules file content should indicate a source project called
- * "source".
- * </p>
- *
- * @param gitModulesFileContent The .gitmodules file content. During the test
- * this file is created, so the commit containing it.
- * @param sourceBranchName The branch name of source project "pointed by"
- * .gitmodules file.
- * @throws Exception If an exception occurs.
- */
- private void doOneSubscriptionInsert(final String gitModulesFileContent,
- final String sourceBranchName) throws Exception {
- final Branch.NameKey mergedBranch =
- new Branch.NameKey(new Project.NameKey("dest-project"),
- "refs/heads/master");
-
- List<SubmoduleSubscription> subscriptionsToInsert = new ArrayList<>();
- subscriptionsToInsert.add(new SubmoduleSubscription(mergedBranch,
- new Branch.NameKey(new Project.NameKey("source"), sourceBranchName),
- "source"));
-
- doOnlySubscriptionInserts(gitModulesFileContent, mergedBranch,
- subscriptionsToInsert);
- }
-
- /**
- * It calls SubmoduleOp.update method considering scenario only inserting new
- * subscriptions.
- * <p>
- * In this test a commit is created and considered merged to
- * {@code mergedBranch} branch.
- * </p>
- * <p>
- * The destination project the commit was merged is not considered to be a
- * source of another project (no subscribers found to this project).
- * </p>
- *
- * @param gitModulesFileContent The .gitmodules file content.
- * @param mergedBranch The {@code Branch.NameKey} instance representing the
- * project/branch the commit was merged.
- * @param extractedSubscriptions The subscription rows extracted from
- * gitmodules file.
- * @throws Exception If an exception occurs.
- */
- private void doOnlySubscriptionInserts(final String gitModulesFileContent,
- final Branch.NameKey mergedBranch,
- final List<SubmoduleSubscription> extractedSubscriptions) throws Exception {
- doOnlySubscriptionTableOperations(gitModulesFileContent, mergedBranch,
- extractedSubscriptions, new ArrayList<SubmoduleSubscription>());
- }
-
- /**
- * It calls SubmoduleOp.update method considering scenario only updating
- * Subscriptions table.
- * <p>
- * In this test a commit is created and considered merged to
- * {@code mergedBranch} branch.
- * </p>
- * <p>
- * The destination project the commit was merged is not considered to be a
- * source of another project (no subscribers found to this project).
- * </p>
- *
- * @param gitModulesFileContent The .gitmodules file content.
- * @param mergedBranch The {@code Branch.NameKey} instance representing the
- * project/branch the commit was merged.
- * @param extractedSubscriptions The subscription rows extracted from
- * gitmodules file.
- * @param previousSubscriptions The subscription rows to be considering as
- * existing and pointing as target to the {@code mergedBranch}
- * before updating the table.
- * @throws Exception If an exception occurs.
- */
- private void doOnlySubscriptionTableOperations(
- final String gitModulesFileContent, final Branch.NameKey mergedBranch,
- final List<SubmoduleSubscription> extractedSubscriptions,
- final List<SubmoduleSubscription> previousSubscriptions) throws Exception {
- expect(schemaFactory.open()).andReturn(schema);
-
- try (Repository realDb = createWorkRepository()) {
- // TODO(dborowitz): Use try/finally when this doesn't double-close the repo.
- @SuppressWarnings("resource")
- final Git git = new Git(realDb);
-
- addRegularFileToIndex(".gitmodules", gitModulesFileContent, realDb);
-
- final RevCommit mergeTip = git.commit().setMessage("test").call();
-
- expect(urlProvider.get()).andReturn("http://localhost:8080").times(2);
-
- expect(schema.submoduleSubscriptions()).andReturn(subscriptions);
- expect(subscriptions.bySuperProject(mergedBranch)).andReturn(
- new ListResultSet<>(previousSubscriptions));
-
- SortedSet<Project.NameKey> existingProjects = new TreeSet<>();
-
- for (SubmoduleSubscription extracted : extractedSubscriptions) {
- existingProjects.add(extracted.getSubmodule().getParentKey());
- }
-
- for (int index = 0; index < extractedSubscriptions.size(); index++) {
- expect(repoManager.list()).andReturn(existingProjects);
- }
-
- final Set<SubmoduleSubscription> alreadySubscribeds = new HashSet<>();
- for (SubmoduleSubscription s : extractedSubscriptions) {
- if (previousSubscriptions.contains(s)) {
- alreadySubscribeds.add(s);
- }
- }
-
- final Set<SubmoduleSubscription> subscriptionsToRemove =
- new HashSet<>(previousSubscriptions);
- final List<SubmoduleSubscription> subscriptionsToInsert =
- new ArrayList<>(extractedSubscriptions);
-
- subscriptionsToRemove.removeAll(subscriptionsToInsert);
- subscriptionsToInsert.removeAll(alreadySubscribeds);
-
- if (!subscriptionsToRemove.isEmpty()) {
- expect(schema.submoduleSubscriptions()).andReturn(subscriptions);
- subscriptions.delete(subscriptionsToRemove);
- }
-
- expect(schema.submoduleSubscriptions()).andReturn(subscriptions);
- subscriptions.insert(subscriptionsToInsert);
-
- expect(schema.submoduleSubscriptions()).andReturn(subscriptions);
- expect(subscriptions.bySubmodule(mergedBranch)).andReturn(
- new ListResultSet<>(new ArrayList<SubmoduleSubscription>()));
-
- schema.close();
-
- doReplay();
-
- final SubmoduleOp submoduleOp =
- new SubmoduleOp(mergedBranch, mergeTip, new RevWalk(realDb),
- urlProvider, schemaFactory, realDb, new Project(mergedBranch
- .getParentKey()), new ArrayList<Change>(), null, null,
- repoManager, null, null, null);
-
- submoduleOp.update();
- }
- }
-
- /**
- * It creates and adds a regular file to git index of a repository.
- *
- * @param fileName The file name.
- * @param content File content.
- * @param repository The Repository instance.
- * @throws IOException If an I/O exception occurs.
- */
- private void addRegularFileToIndex(final String fileName,
- final String content, final Repository repository) throws IOException {
- final ObjectInserter oi = repository.newObjectInserter();
- AnyObjectId objectId =
- oi.insert(Constants.OBJ_BLOB, Constants.encode(content));
- oi.flush();
- addEntryToIndex(fileName, FileMode.REGULAR_FILE, objectId, repository);
- }
-
- /**
- * It creates and adds a git link to git index of a repository.
- *
- * @param fileName The file name.
- * @param objectId The sha-1 value of git link.
- * @param repository The Repository instance.
- * @throws IOException If an I/O exception occurs.
- */
- private void addGitLinkToIndex(final String fileName,
- final AnyObjectId objectId, final Repository repository)
- throws IOException {
- addEntryToIndex(fileName, FileMode.GITLINK, objectId, repository);
- }
-
- /**
- * It adds an entry to index.
- *
- * @param path The entry path.
- * @param fileMode The entry file mode.
- * @param objectId The ObjectId value of the entry.
- * @param repository The repository instance.
- * @throws IOException If an I/O exception occurs.
- */
- private void addEntryToIndex(final String path, final FileMode fileMode,
- final AnyObjectId objectId, final Repository repository)
- throws IOException {
- final DirCacheEntry e = new DirCacheEntry(path);
- e.setFileMode(fileMode);
- e.setObjectId(objectId);
-
- final DirCacheBuilder dirCacheBuilder = repository.lockDirCache().builder();
- dirCacheBuilder.add(e);
- dirCacheBuilder.commit();
- }
-
- private static StringBuilder buildSubmoduleSection(final String name,
- final String path, final String url, final String branch) {
- final StringBuilder sb = new StringBuilder();
-
- sb.append("[submodule \"");
- sb.append(name);
- sb.append("\"]");
- sb.append(newLine);
-
- sb.append("\tpath = ");
- sb.append(path);
- sb.append(newLine);
-
- sb.append("\turl = ");
- sb.append(url);
- sb.append(newLine);
-
- sb.append("\tbranch = ");
- sb.append(branch);
- sb.append(newLine);
-
- return sb;
- }
-}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/index/FakeQueryBuilder.java b/gerrit-server/src/test/java/com/google/gerrit/server/index/FakeQueryBuilder.java
index c9a2056..0c8625d 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/index/FakeQueryBuilder.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/index/FakeQueryBuilder.java
@@ -27,7 +27,7 @@
FakeQueryBuilder.class),
new ChangeQueryBuilder.Arguments(null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null,
- indexes, null, null, null, null));
+ null, indexes, null, null, null, null));
}
@Operator
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/ioutil/ColumnFormatterTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/ioutil/ColumnFormatterTest.java
index 02d0582..fa4ac0e 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/ioutil/ColumnFormatterTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/ioutil/ColumnFormatterTest.java
@@ -25,7 +25,7 @@
* Holds an in-memory {@link java.io.PrintWriter} object and allows
* comparisons of its contents to a supplied string via an assert statement.
*/
- class PrintWriterComparator {
+ static class PrintWriterComparator {
private PrintWriter printWriter;
private StringWriter stringWriter;
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/AbstractChangeNotesTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/AbstractChangeNotesTest.java
index 1308723..108c20f 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/AbstractChangeNotesTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/AbstractChangeNotesTest.java
@@ -203,16 +203,16 @@
return label;
}
- protected PatchLineComment newPublishedPatchLineComment(PatchSet.Id psId,
+ protected PatchLineComment newPublishedComment(PatchSet.Id psId,
String filename, String UUID, CommentRange range, int line,
IdentifiedUser commenter, String parentUUID, Timestamp t,
String message, short side, String commitSHA1) {
- return newPatchLineComment(psId, filename, UUID, range, line, commenter,
+ return newComment(psId, filename, UUID, range, line, commenter,
parentUUID, t, message, side, commitSHA1,
PatchLineComment.Status.PUBLISHED);
}
- protected PatchLineComment newPatchLineComment(PatchSet.Id psId,
+ protected PatchLineComment newComment(PatchSet.Id psId,
String filename, String UUID, CommentRange range, int line,
IdentifiedUser commenter, String parentUUID, Timestamp t,
String message, short side, String commitSHA1,
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeNotesTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeNotesTest.java
index aea966a..6067442 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeNotesTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeNotesTest.java
@@ -14,23 +14,19 @@
package com.google.gerrit.server.notedb;
+import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.server.notedb.ReviewerState.CC;
import static com.google.gerrit.server.notedb.ReviewerState.REVIEWER;
import static com.google.gerrit.testutil.TestChanges.incrementPatchSet;
import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
+import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Iterables;
-import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
-import com.google.common.collect.Multimap;
import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.common.data.SubmitRecord;
import com.google.gerrit.reviewdb.client.Account;
@@ -41,8 +37,8 @@
import com.google.gerrit.reviewdb.client.PatchLineComment.Status;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.RevId;
import com.google.gerrit.server.git.VersionedMetaData.BatchMetaDataUpdate;
-import com.google.gwtorm.server.OrmException;
import org.eclipse.jgit.lib.BatchRefUpdate;
import org.eclipse.jgit.lib.CommitBuilder;
@@ -50,12 +46,12 @@
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.notes.Note;
+import org.eclipse.jgit.notes.NoteMap;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.ReceiveCommand;
import org.junit.Test;
-import java.io.IOException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.LinkedHashSet;
@@ -71,22 +67,23 @@
update.commit();
ChangeNotes notes = newNotes(c);
- assertEquals(1, notes.getApprovals().keySet().size());
+ assertThat(notes.getApprovals().keySet())
+ .containsExactly(c.currentPatchSetId());
List<PatchSetApproval> psas =
notes.getApprovals().get(c.currentPatchSetId());
- assertEquals(2, psas.size());
+ assertThat(psas).hasSize(2);
- assertEquals(c.currentPatchSetId(), psas.get(0).getPatchSetId());
- assertEquals(1, psas.get(0).getAccountId().get());
- assertEquals("Code-Review", psas.get(0).getLabel());
- assertEquals((short) -1, psas.get(0).getValue());
- assertEquals(truncate(after(c, 1000)), psas.get(0).getGranted());
+ assertThat(psas.get(0).getPatchSetId()).isEqualTo(c.currentPatchSetId());
+ assertThat(psas.get(0).getAccountId().get()).isEqualTo(1);
+ assertThat(psas.get(0).getLabel()).isEqualTo("Code-Review");
+ assertThat(psas.get(0).getValue()).isEqualTo((short) -1);
+ assertThat(psas.get(0).getGranted()).isEqualTo(truncate(after(c, 1000)));
- assertEquals(c.currentPatchSetId(), psas.get(1).getPatchSetId());
- assertEquals(1, psas.get(1).getAccountId().get());
- assertEquals("Verified", psas.get(1).getLabel());
- assertEquals((short) 1, psas.get(1).getValue());
- assertEquals(psas.get(0).getGranted(), psas.get(1).getGranted());
+ assertThat(psas.get(1).getPatchSetId()).isEqualTo(c.currentPatchSetId());
+ assertThat(psas.get(1).getAccountId().get()).isEqualTo(1);
+ assertThat(psas.get(1).getLabel()).isEqualTo("Verified");
+ assertThat(psas.get(1).getValue()).isEqualTo((short) 1);
+ assertThat(psas.get(1).getGranted()).isEqualTo(psas.get(0).getGranted());
}
@Test
@@ -105,21 +102,21 @@
ChangeNotes notes = newNotes(c);
ListMultimap<PatchSet.Id, PatchSetApproval> psas = notes.getApprovals();
- assertEquals(2, notes.getApprovals().keySet().size());
+ assertThat(psas).hasSize(2);
PatchSetApproval psa1 = Iterables.getOnlyElement(psas.get(ps1));
- assertEquals(ps1, psa1.getPatchSetId());
- assertEquals(1, psa1.getAccountId().get());
- assertEquals("Code-Review", psa1.getLabel());
- assertEquals((short) -1, psa1.getValue());
- assertEquals(truncate(after(c, 1000)), psa1.getGranted());
+ assertThat(psa1.getPatchSetId()).isEqualTo(ps1);
+ assertThat(psa1.getAccountId().get()).isEqualTo(1);
+ assertThat(psa1.getLabel()).isEqualTo("Code-Review");
+ assertThat(psa1.getValue()).isEqualTo((short) -1);
+ assertThat(psa1.getGranted()).isEqualTo(truncate(after(c, 1000)));
PatchSetApproval psa2 = Iterables.getOnlyElement(psas.get(ps2));
- assertEquals(ps2, psa2.getPatchSetId());
- assertEquals(1, psa2.getAccountId().get());
- assertEquals("Code-Review", psa2.getLabel());
- assertEquals((short) +1, psa2.getValue());
- assertEquals(truncate(after(c, 2000)), psa2.getGranted());
+ assertThat(psa2.getPatchSetId()).isEqualTo(ps2);
+ assertThat(psa2.getAccountId().get()).isEqualTo(1);
+ assertThat(psa2.getLabel()).isEqualTo("Code-Review");
+ assertThat(psa2.getValue()).isEqualTo((short) +1);
+ assertThat(psa2.getGranted()).isEqualTo(truncate(after(c, 2000)));
}
@Test
@@ -132,8 +129,8 @@
ChangeNotes notes = newNotes(c);
PatchSetApproval psa = Iterables.getOnlyElement(
notes.getApprovals().get(c.currentPatchSetId()));
- assertEquals("Code-Review", psa.getLabel());
- assertEquals((short) -1, psa.getValue());
+ assertThat(psa.getLabel()).isEqualTo("Code-Review");
+ assertThat(psa.getValue()).isEqualTo((short) -1);
update = newUpdate(c, changeOwner);
update.putApproval("Code-Review", (short) 1);
@@ -142,8 +139,8 @@
notes = newNotes(c);
psa = Iterables.getOnlyElement(
notes.getApprovals().get(c.currentPatchSetId()));
- assertEquals("Code-Review", psa.getLabel());
- assertEquals((short) 1, psa.getValue());
+ assertThat(psa.getLabel()).isEqualTo("Code-Review");
+ assertThat(psa.getValue()).isEqualTo((short) 1);
}
@Test
@@ -158,22 +155,23 @@
update.commit();
ChangeNotes notes = newNotes(c);
- assertEquals(1, notes.getApprovals().keySet().size());
+ assertThat(notes.getApprovals().keySet())
+ .containsExactly(c.currentPatchSetId());
List<PatchSetApproval> psas =
notes.getApprovals().get(c.currentPatchSetId());
- assertEquals(2, psas.size());
+ assertThat(psas).hasSize(2);
- assertEquals(c.currentPatchSetId(), psas.get(0).getPatchSetId());
- assertEquals(1, psas.get(0).getAccountId().get());
- assertEquals("Code-Review", psas.get(0).getLabel());
- assertEquals((short) -1, psas.get(0).getValue());
- assertEquals(truncate(after(c, 1000)), psas.get(0).getGranted());
+ assertThat(psas.get(0).getPatchSetId()).isEqualTo(c.currentPatchSetId());
+ assertThat(psas.get(0).getAccountId().get()).isEqualTo(1);
+ assertThat(psas.get(0).getLabel()).isEqualTo("Code-Review");
+ assertThat(psas.get(0).getValue()).isEqualTo((short) -1);
+ assertThat(psas.get(0).getGranted()).isEqualTo(truncate(after(c, 1000)));
- assertEquals(c.currentPatchSetId(), psas.get(1).getPatchSetId());
- assertEquals(2, psas.get(1).getAccountId().get());
- assertEquals("Code-Review", psas.get(1).getLabel());
- assertEquals((short) 1, psas.get(1).getValue());
- assertEquals(truncate(after(c, 2000)), psas.get(1).getGranted());
+ assertThat(psas.get(1).getPatchSetId()).isEqualTo(c.currentPatchSetId());
+ assertThat(psas.get(1).getAccountId().get()).isEqualTo(2);
+ assertThat(psas.get(1).getLabel()).isEqualTo("Code-Review");
+ assertThat(psas.get(1).getValue()).isEqualTo((short) 1);
+ assertThat(psas.get(1).getGranted()).isEqualTo(truncate(after(c, 2000)));
}
@Test
@@ -186,16 +184,16 @@
ChangeNotes notes = newNotes(c);
PatchSetApproval psa = Iterables.getOnlyElement(
notes.getApprovals().get(c.currentPatchSetId()));
- assertEquals(1, psa.getAccountId().get());
- assertEquals("Not-For-Long", psa.getLabel());
- assertEquals((short) 1, psa.getValue());
+ assertThat(psa.getAccountId().get()).isEqualTo(1);
+ assertThat(psa.getLabel()).isEqualTo("Not-For-Long");
+ assertThat(psa.getValue()).isEqualTo((short) 1);
update = newUpdate(c, changeOwner);
update.removeApproval("Not-For-Long");
update.commit();
notes = newNotes(c);
- assertTrue(notes.getApprovals().isEmpty());
+ assertThat(notes.getApprovals()).isEmpty();
}
@Test
@@ -207,10 +205,10 @@
update.commit();
ChangeNotes notes = newNotes(c);
- assertEquals(ImmutableSetMultimap.of(
+ assertThat(notes.getReviewers()).isEqualTo(
+ ImmutableSetMultimap.of(
REVIEWER, new Account.Id(1),
- REVIEWER, new Account.Id(2)),
- notes.getReviewers());
+ REVIEWER, new Account.Id(2)));
}
@Test
@@ -222,10 +220,10 @@
update.commit();
ChangeNotes notes = newNotes(c);
- assertEquals(ImmutableSetMultimap.of(
- REVIEWER, new Account.Id(1),
- CC, new Account.Id(2)),
- notes.getReviewers());
+ assertThat(notes.getReviewers()).isEqualTo(
+ ImmutableSetMultimap.of(
+ REVIEWER, new Account.Id(1),
+ CC, new Account.Id(2)));
}
@Test
@@ -236,18 +234,16 @@
update.commit();
ChangeNotes notes = newNotes(c);
- assertEquals(ImmutableSetMultimap.of(
- REVIEWER, new Account.Id(2)),
- notes.getReviewers());
+ assertThat(notes.getReviewers()).isEqualTo(
+ ImmutableSetMultimap.of(REVIEWER, new Account.Id(2)));
update = newUpdate(c, otherUser);
update.putReviewer(otherUser.getAccount().getId(), CC);
update.commit();
notes = newNotes(c);
- assertEquals(ImmutableSetMultimap.of(
- CC, new Account.Id(2)),
- notes.getReviewers());
+ assertThat(notes.getReviewers()).isEqualTo(
+ ImmutableSetMultimap.of(CC, new Account.Id(2)));
}
@Test
@@ -268,9 +264,11 @@
ChangeNotes notes = newNotes(c);
List<PatchSetApproval> psas =
notes.getApprovals().get(c.currentPatchSetId());
- assertEquals(2, psas.size());
- assertEquals(changeOwner.getAccount().getId(), psas.get(0).getAccountId());
- assertEquals(otherUser.getAccount().getId(), psas.get(1).getAccountId());
+ assertThat(psas).hasSize(2);
+ assertThat(psas.get(0).getAccountId())
+ .isEqualTo(changeOwner.getAccount().getId());
+ assertThat(psas.get(1).getAccountId())
+ .isEqualTo(otherUser.getAccount().getId());
update = newUpdate(c, changeOwner);
update.removeReviewer(otherUser.getAccount().getId());
@@ -278,8 +276,9 @@
notes = newNotes(c);
psas = notes.getApprovals().get(c.currentPatchSetId());
- assertEquals(1, psas.size());
- assertEquals(changeOwner.getAccount().getId(), psas.get(0).getAccountId());
+ assertThat(psas).hasSize(1);
+ assertThat(psas.get(0).getAccountId())
+ .isEqualTo(changeOwner.getAccount().getId());
}
@Test
@@ -299,13 +298,15 @@
ChangeNotes notes = newNotes(c);
List<SubmitRecord> recs = notes.getSubmitRecords();
- assertEquals(2, recs.size());
- assertEquals(submitRecord("NOT_READY", null,
- submitLabel("Verified", "OK", changeOwner.getAccountId()),
- submitLabel("Code-Review", "NEED", null)), recs.get(0));
- assertEquals(submitRecord("NOT_READY", null,
- submitLabel("Verified", "OK", changeOwner.getAccountId()),
- submitLabel("Alternative-Code-Review", "NEED", null)), recs.get(1));
+ assertThat(recs).hasSize(2);
+ assertThat(recs.get(0)).isEqualTo(
+ submitRecord("NOT_READY", null,
+ submitLabel("Verified", "OK", changeOwner.getAccountId()),
+ submitLabel("Code-Review", "NEED", null)));
+ assertThat(recs.get(1)).isEqualTo(
+ submitRecord("NOT_READY", null,
+ submitLabel("Verified", "OK", changeOwner.getAccountId()),
+ submitLabel("Alternative-Code-Review", "NEED", null)));
}
@Test
@@ -327,16 +328,16 @@
update.commit();
ChangeNotes notes = newNotes(c);
- assertEquals(submitRecord("OK", null,
- submitLabel("Code-Review", "OK", changeOwner.getAccountId())),
- Iterables.getOnlyElement(notes.getSubmitRecords()));
+ assertThat(notes.getSubmitRecords()).containsExactly(
+ submitRecord("OK", null,
+ submitLabel("Code-Review", "OK", changeOwner.getAccountId())));
}
@Test
public void emptyChangeUpdate() throws Exception {
ChangeUpdate update = newUpdate(newChange(), changeOwner);
update.commit();
- assertNull(update.getRevision());
+ assertThat(update.getRevision()).isNull();
}
@Test
@@ -351,7 +352,7 @@
try (RevWalk walk = new RevWalk(repo)) {
RevCommit commit = walk.parseCommit(update.getRevision());
walk.parseBody(commit);
- assertTrue(commit.getFullMessage().endsWith("Hashtags: tag1,tag2\n"));
+ assertThat(commit.getFullMessage()).endsWith("Hashtags: tag1,tag2\n");
}
}
@@ -366,7 +367,7 @@
update.commit();
ChangeNotes notes = newNotes(c);
- assertEquals(hashtags, notes.getHashtags());
+ assertThat(notes.getHashtags()).isEqualTo(hashtags);
}
@Test
@@ -374,7 +375,7 @@
ChangeUpdate update = newUpdate(newChange(), changeOwner);
update.setSubject("Create change");
update.commit();
- assertNotNull(update.getRevision());
+ assertThat(update.getRevision()).isNotNull();
}
@Test
@@ -398,15 +399,17 @@
ChangeNotes notes = newNotes(c);
List<PatchSetApproval> psas =
notes.getApprovals().get(c.currentPatchSetId());
- assertEquals(2, psas.size());
+ assertThat(psas).hasSize(2);
- assertEquals(changeOwner.getAccount().getId(), psas.get(0).getAccountId());
- assertEquals("Verified", psas.get(0).getLabel());
- assertEquals((short) 1, psas.get(0).getValue());
+ assertThat(psas.get(0).getAccountId())
+ .isEqualTo(changeOwner.getAccount().getId());
+ assertThat(psas.get(0).getLabel()).isEqualTo("Verified");
+ assertThat(psas.get(0).getValue()).isEqualTo((short) 1);
- assertEquals(otherUser.getAccount().getId(), psas.get(1).getAccountId());
- assertEquals("Code-Review", psas.get(1).getLabel());
- assertEquals((short) 2, psas.get(1).getValue());
+ assertThat(psas.get(1).getAccountId())
+ .isEqualTo(otherUser.getAccount().getId());
+ assertThat(psas.get(1).getLabel()).isEqualTo("Code-Review");
+ assertThat(psas.get(1).getValue()).isEqualTo((short) 2);
}
@Test
@@ -420,7 +423,7 @@
PatchSet.Id psId = c.currentPatchSetId();
BatchRefUpdate bru = repo.getRefDatabase().newBatchUpdate();
BatchMetaDataUpdate batch = update1.openUpdateInBatch(bru);
- PatchLineComment comment1 = newPublishedPatchLineComment(psId, "file1",
+ PatchLineComment comment1 = newPublishedComment(psId, "file1",
uuid1, range1, range1.getEndLine(), otherUser, null, time1, message1,
(short) 0, "abcd1234abcd1234abcd1234abcd1234abcd1234");
update1.setPatchSetId(psId);
@@ -437,17 +440,17 @@
ChangeNotes notes = newNotes(c);
ObjectId tip = notes.getRevision();
RevCommit commitWithApprovals = rw.parseCommit(tip);
- assertNotNull(commitWithApprovals);
+ assertThat(commitWithApprovals).isNotNull();
RevCommit commitWithComments = commitWithApprovals.getParent(0);
- assertNotNull(commitWithComments);
+ assertThat(commitWithComments).isNotNull();
ChangeNotesParser notesWithComments =
new ChangeNotesParser(c, commitWithComments.copy(), rw, repoManager);
notesWithComments.parseAll();
ImmutableListMultimap<PatchSet.Id, PatchSetApproval> approvals1 =
notesWithComments.buildApprovals();
- assertEquals(0, approvals1.size());
- assertEquals(1, notesWithComments.commentsForBase.size());
+ assertThat(approvals1).isEmpty();
+ assertThat(notesWithComments.comments).hasSize(1);
notesWithComments.close();
ChangeNotesParser notesWithApprovals =
@@ -455,8 +458,8 @@
notesWithApprovals.parseAll();
ImmutableListMultimap<PatchSet.Id, PatchSetApproval> approvals2 =
notesWithApprovals.buildApprovals();
- assertEquals(1, approvals2.size());
- assertEquals(1, notesWithApprovals.commentsForBase.size());
+ assertThat(approvals2).hasSize(1);
+ assertThat(notesWithApprovals.comments).hasSize(1);
notesWithApprovals.close();
} finally {
batch.close();
@@ -481,12 +484,12 @@
batch1 = update1.openUpdateInBatch(bru);
batch1.write(update1, new CommitBuilder());
batch1.commit();
- assertNull(repo.getRef(update1.getRefName()));
+ assertThat(repo.getRef(update1.getRefName())).isNull();
batch2 = update2.openUpdateInBatch(bru);
batch2.write(update2, new CommitBuilder());
batch2.commit();
- assertNull(repo.getRef(update2.getRefName()));
+ assertThat(repo.getRef(update2.getRefName())).isNull();
} finally {
if (batch1 != null) {
batch1.close();
@@ -497,19 +500,19 @@
}
List<ReceiveCommand> cmds = bru.getCommands();
- assertEquals(2, cmds.size());
- assertEquals(update1.getRefName(), cmds.get(0).getRefName());
- assertEquals(update2.getRefName(), cmds.get(1).getRefName());
+ assertThat(cmds).hasSize(2);
+ assertThat(cmds.get(0).getRefName()).isEqualTo(update1.getRefName());
+ assertThat(cmds.get(1).getRefName()).isEqualTo(update2.getRefName());
try (RevWalk rw = new RevWalk(repo)) {
bru.execute(rw, NullProgressMonitor.INSTANCE);
}
- assertEquals(ReceiveCommand.Result.OK, cmds.get(0).getResult());
- assertEquals(ReceiveCommand.Result.OK, cmds.get(1).getResult());
+ assertThat(cmds.get(0).getResult()).isEqualTo(ReceiveCommand.Result.OK);
+ assertThat(cmds.get(1).getResult()).isEqualTo(ReceiveCommand.Result.OK);
- assertNotNull(repo.getRef(update1.getRefName()));
- assertNotNull(repo.getRef(update2.getRefName()));
+ assertThat(repo.getRef(update1.getRefName())).isNotNull();
+ assertThat(repo.getRef(update2.getRefName())).isNotNull();
}
@Test
@@ -524,14 +527,12 @@
ChangeNotes notes = newNotes(c);
ListMultimap<PatchSet.Id, ChangeMessage> changeMessages =
notes.getChangeMessages();
- assertEquals(1, changeMessages.keySet().size());
+ assertThat(changeMessages.keySet()).containsExactly(ps1);
ChangeMessage cm = Iterables.getOnlyElement(changeMessages.get(ps1));
- assertEquals("Just a little code change.\n",
- cm.getMessage());
- assertEquals(changeOwner.getAccount().getId(),
- cm.getAuthor());
- assertEquals(ps1, cm.getPatchSetId());
+ assertThat(cm.getMessage()).isEqualTo("Just a little code change.\n");
+ assertThat(cm.getAuthor()).isEqualTo(changeOwner.getAccount().getId());
+ assertThat(cm.getPatchSetId()).isEqualTo(ps1);
}
@Test
@@ -542,9 +543,7 @@
update.commit();
ChangeNotes notes = newNotes(c);
- ListMultimap<PatchSet.Id, ChangeMessage> changeMessages =
- notes.getChangeMessages();
- assertEquals(0, changeMessages.keySet().size());
+ assertThat(notes.getChangeMessages()).isEmpty();
}
@Test
@@ -559,11 +558,11 @@
ChangeNotes notes = newNotes(c);
ListMultimap<PatchSet.Id, ChangeMessage> changeMessages =
notes.getChangeMessages();
- assertEquals(1, changeMessages.keySet().size());
+ assertThat(changeMessages).hasSize(1);
ChangeMessage cm1 = Iterables.getOnlyElement(changeMessages.get(ps1));
- assertEquals("Testing trailing double newline\n" + "\n", cm1.getMessage());
- assertEquals(changeOwner.getAccount().getId(), cm1.getAuthor());
+ assertThat(cm1.getMessage()).isEqualTo("Testing trailing double newline\n" + "\n");
+ assertThat(cm1.getAuthor()).isEqualTo(changeOwner.getAccount().getId());
}
@Test
@@ -581,15 +580,15 @@
ChangeNotes notes = newNotes(c);
ListMultimap<PatchSet.Id, ChangeMessage> changeMessages =
notes.getChangeMessages();
- assertEquals(1, changeMessages.keySet().size());
+ assertThat(changeMessages).hasSize(1);
ChangeMessage cm1 = Iterables.getOnlyElement(changeMessages.get(ps1));
- assertEquals("Testing paragraph 1\n"
+ assertThat(cm1.getMessage()).isEqualTo("Testing paragraph 1\n"
+ "\n"
+ "Testing paragraph 2\n"
+ "\n"
- + "Testing paragraph 3", cm1.getMessage());
- assertEquals(changeOwner.getAccount().getId(), cm1.getAuthor());
+ + "Testing paragraph 3");
+ assertThat(cm1.getAuthor()).isEqualTo(changeOwner.getAccount().getId());
}
@Test
@@ -611,20 +610,19 @@
ChangeNotes notes = newNotes(c);
ListMultimap<PatchSet.Id, ChangeMessage> changeMessages =
notes.getChangeMessages();
- assertEquals(2, changeMessages.keySet().size());
+ assertThat(changeMessages).hasSize(2);
ChangeMessage cm1 = Iterables.getOnlyElement(changeMessages.get(ps1));
- assertEquals("This is the change message for the first PS.",
- cm1.getMessage());
- assertEquals(changeOwner.getAccount().getId(),
- cm1.getAuthor());
+ assertThat(cm1.getMessage())
+ .isEqualTo("This is the change message for the first PS.");
+ assertThat(cm1.getAuthor()).isEqualTo(changeOwner.getAccount().getId());
ChangeMessage cm2 = Iterables.getOnlyElement(changeMessages.get(ps2));
- assertEquals(ps1, cm1.getPatchSetId());
- assertEquals("This is the change message for the second PS.",
- cm2.getMessage());
- assertEquals(changeOwner.getAccount().getId(), cm2.getAuthor());
- assertEquals(ps2, cm2.getPatchSetId());
+ assertThat(cm1.getPatchSetId()).isEqualTo(ps1);
+ assertThat(cm2.getMessage())
+ .isEqualTo("This is the change message for the second PS.");
+ assertThat(cm2.getAuthor()).isEqualTo(changeOwner.getAccount().getId());
+ assertThat(cm2.getPatchSetId()).isEqualTo(ps2);
}
@Test
@@ -645,20 +643,18 @@
ChangeNotes notes = newNotes(c);
ListMultimap<PatchSet.Id, ChangeMessage> changeMessages =
notes.getChangeMessages();
- assertEquals(1, changeMessages.keySet().size());
+ assertThat(changeMessages.keySet()).hasSize(1);
List<ChangeMessage> cm = changeMessages.get(ps1);
- assertEquals(2, cm.size());
- assertEquals("First change message.\n",
- cm.get(0).getMessage());
- assertEquals(changeOwner.getAccount().getId(),
- cm.get(0).getAuthor());
- assertEquals(ps1, cm.get(0).getPatchSetId());
- assertEquals("Second change message.\n",
- cm.get(1).getMessage());
- assertEquals(changeOwner.getAccount().getId(),
- cm.get(1).getAuthor());
- assertEquals(ps1, cm.get(1).getPatchSetId());
+ assertThat(cm).hasSize(2);
+ assertThat(cm.get(0).getMessage()).isEqualTo("First change message.\n");
+ assertThat(cm.get(0).getAuthor())
+ .isEqualTo(changeOwner.getAccount().getId());
+ assertThat(cm.get(0).getPatchSetId()).isEqualTo(ps1);
+ assertThat(cm.get(1).getMessage()).isEqualTo("Second change message.\n");
+ assertThat(cm.get(1).getAuthor())
+ .isEqualTo(changeOwner.getAccount().getId());
+ assertThat(cm.get(1).getPatchSetId()).isEqualTo(ps1);
}
@Test
@@ -677,7 +673,7 @@
Timestamp time3 = TimeUtil.nowTs();
PatchSet.Id psId = c.currentPatchSetId();
- PatchLineComment comment1 = newPublishedPatchLineComment(psId, "file1",
+ PatchLineComment comment1 = newPublishedComment(psId, "file1",
uuid1, range1, range1.getEndLine(), otherUser, null, time1, message1,
(short) 1, "abcd1234abcd1234abcd1234abcd1234abcd1234");
update.setPatchSetId(psId);
@@ -686,7 +682,7 @@
update = newUpdate(c, otherUser);
CommentRange range2 = new CommentRange(2, 1, 3, 1);
- PatchLineComment comment2 = newPublishedPatchLineComment(psId, "file1",
+ PatchLineComment comment2 = newPublishedComment(psId, "file1",
uuid2, range2, range2.getEndLine(), otherUser, null, time2, message2,
(short) 1, "abcd1234abcd1234abcd1234abcd1234abcd1234");
update.setPatchSetId(psId);
@@ -695,7 +691,7 @@
update = newUpdate(c, otherUser);
CommentRange range3 = new CommentRange(3, 1, 4, 1);
- PatchLineComment comment3 = newPublishedPatchLineComment(psId, "file2",
+ PatchLineComment comment3 = newPublishedComment(psId, "file2",
uuid3, range3, range3.getEndLine(), otherUser, null, time3, message3,
(short) 1, "abcd1234abcd1234abcd1234abcd1234abcd1234");
update.setPatchSetId(psId);
@@ -713,7 +709,7 @@
walk.getObjectReader().open(
note.getData(), Constants.OBJ_BLOB).getBytes();
String noteString = new String(bytes, UTF_8);
- assertEquals("Patch-set: 1\n"
+ assertThat(noteString).isEqualTo("Patch-set: 1\n"
+ "Revision: abcd1234abcd1234abcd1234abcd1234abcd1234\n"
+ "File: file1\n"
+ "\n"
@@ -739,8 +735,7 @@
+ "UUID: uuid3\n"
+ "Bytes: 9\n"
+ "comment 3\n"
- + "\n",
- noteString);
+ + "\n");
}
}
@@ -757,7 +752,7 @@
Timestamp time2 = TimeUtil.nowTs();
PatchSet.Id psId = c.currentPatchSetId();
- PatchLineComment comment1 = newPublishedPatchLineComment(psId, "file1",
+ PatchLineComment comment1 = newPublishedComment(psId, "file1",
uuid1, range1, range1.getEndLine(), otherUser, null, time1, message1,
(short) 0, "abcd1234abcd1234abcd1234abcd1234abcd1234");
update.setPatchSetId(psId);
@@ -766,7 +761,7 @@
update = newUpdate(c, otherUser);
CommentRange range2 = new CommentRange(2, 1, 3, 1);
- PatchLineComment comment2 = newPublishedPatchLineComment(psId, "file1",
+ PatchLineComment comment2 = newPublishedComment(psId, "file1",
uuid2, range2, range2.getEndLine(), otherUser, null, time2, message2,
(short) 0, "abcd1234abcd1234abcd1234abcd1234abcd1234");
update.setPatchSetId(psId);
@@ -784,7 +779,7 @@
walk.getObjectReader().open(
note.getData(), Constants.OBJ_BLOB).getBytes();
String noteString = new String(bytes, UTF_8);
- assertEquals("Base-for-patch-set: 1\n"
+ assertThat(noteString).isEqualTo("Base-for-patch-set: 1\n"
+ "Revision: abcd1234abcd1234abcd1234abcd1234abcd1234\n"
+ "File: file1\n"
+ "\n"
@@ -801,8 +796,7 @@
+ "UUID: uuid2\n"
+ "Bytes: 9\n"
+ "comment 2\n"
- + "\n",
- noteString);
+ + "\n");
}
}
@@ -813,6 +807,8 @@
ChangeUpdate update = newUpdate(c, otherUser);
String uuid1 = "uuid1";
String uuid2 = "uuid2";
+ String rev1 = "abcd1234abcd1234abcd1234abcd1234abcd1234";
+ String rev2 = "abcd4567abcd4567abcd4567abcd4567abcd4567";
String messageForBase = "comment for base";
String messageForPS = "comment for ps";
CommentRange range = new CommentRange(1, 1, 2, 1);
@@ -820,34 +816,26 @@
PatchSet.Id psId = c.currentPatchSetId();
PatchLineComment commentForBase =
- newPublishedPatchLineComment(psId, "filename", uuid1,
+ newPublishedComment(psId, "filename", uuid1,
range, range.getEndLine(), otherUser, null, now, messageForBase,
- (short) 0, "abcd1234abcd1234abcd1234abcd1234abcd1234");
+ (short) 0, rev1);
update.setPatchSetId(psId);
update.upsertComment(commentForBase);
update.commit();
update = newUpdate(c, otherUser);
PatchLineComment commentForPS =
- newPublishedPatchLineComment(psId, "filename", uuid2,
+ newPublishedComment(psId, "filename", uuid2,
range, range.getEndLine(), otherUser, null, now, messageForPS,
- (short) 1, "abcd4567abcd4567abcd4567abcd4567abcd4567");
+ (short) 1, rev2);
update.setPatchSetId(psId);
update.upsertComment(commentForPS);
update.commit();
- ChangeNotes notes = newNotes(c);
- Multimap<PatchSet.Id, PatchLineComment> commentsForBase =
- notes.getBaseComments();
- Multimap<PatchSet.Id, PatchLineComment> commentsForPS =
- notes.getPatchSetComments();
- assertEquals(commentsForBase.size(), 1);
- assertEquals(commentsForPS.size(), 1);
-
- assertEquals(commentForBase,
- Iterables.getOnlyElement(commentsForBase.get(psId)));
- assertEquals(commentForPS,
- Iterables.getOnlyElement(commentsForPS.get(psId)));
+ assertThat(newNotes(c).getComments()).containsExactly(
+ ImmutableMultimap.of(
+ new RevId(rev1), commentForBase,
+ new RevId(rev2), commentForPS));
}
@Test
@@ -855,6 +843,7 @@
Change c = newChange();
String uuid1 = "uuid1";
String uuid2 = "uuid2";
+ String rev = "abcd1234abcd1234abcd1234abcd1234abcd1234";
CommentRange range = new CommentRange(1, 1, 2, 1);
PatchSet.Id psId = c.currentPatchSetId();
String filename = "filename";
@@ -863,37 +852,25 @@
ChangeUpdate update = newUpdate(c, otherUser);
Timestamp timeForComment1 = TimeUtil.nowTs();
Timestamp timeForComment2 = TimeUtil.nowTs();
- PatchLineComment comment1 = newPublishedPatchLineComment(psId, filename,
+ PatchLineComment comment1 = newPublishedComment(psId, filename,
uuid1, range, range.getEndLine(), otherUser, null, timeForComment1,
- "comment 1", side, "abcd1234abcd1234abcd1234abcd1234abcd1234");
+ "comment 1", side, rev);
update.setPatchSetId(psId);
update.upsertComment(comment1);
update.commit();
update = newUpdate(c, otherUser);
- PatchLineComment comment2 = newPublishedPatchLineComment(psId, filename,
+ PatchLineComment comment2 = newPublishedComment(psId, filename,
uuid2, range, range.getEndLine(), otherUser, null, timeForComment2,
- "comment 2", side, "abcd1234abcd1234abcd1234abcd1234abcd1234");
+ "comment 2", side, rev);
update.setPatchSetId(psId);
update.upsertComment(comment2);
update.commit();
- ChangeNotes notes = newNotes(c);
- Multimap<PatchSet.Id, PatchLineComment> commentsForBase =
- notes.getBaseComments();
- Multimap<PatchSet.Id, PatchLineComment> commentsForPS =
- notes.getPatchSetComments();
- assertEquals(commentsForBase.size(), 0);
- assertEquals(commentsForPS.size(), 2);
-
- ImmutableList<PatchLineComment> commentsForThisPS =
- (ImmutableList<PatchLineComment>) commentsForPS.get(psId);
- assertEquals(commentsForThisPS.size(), 2);
- PatchLineComment commentFromNotes1 = commentsForThisPS.get(0);
- PatchLineComment commentFromNotes2 = commentsForThisPS.get(1);
-
- assertEquals(comment1, commentFromNotes1);
- assertEquals(comment2, commentFromNotes2);
+ assertThat(newNotes(c).getComments()).containsExactly(
+ ImmutableMultimap.of(
+ new RevId(rev), comment1,
+ new RevId(rev), comment2)).inOrder();
}
@Test
@@ -901,6 +878,7 @@
throws Exception {
Change c = newChange();
String uuid = "uuid";
+ String rev = "abcd1234abcd1234abcd1234abcd1234abcd1234";
CommentRange range = new CommentRange(1, 1, 2, 1);
PatchSet.Id psId = c.currentPatchSetId();
String filename1 = "filename1";
@@ -909,43 +887,33 @@
ChangeUpdate update = newUpdate(c, otherUser);
Timestamp now = TimeUtil.nowTs();
- PatchLineComment comment1 = newPublishedPatchLineComment(psId, filename1,
+ PatchLineComment comment1 = newPublishedComment(psId, filename1,
uuid, range, range.getEndLine(), otherUser, null, now, "comment 1",
- side, "abcd1234abcd1234abcd1234abcd1234abcd1234");
+ side, rev);
update.setPatchSetId(psId);
update.upsertComment(comment1);
update.commit();
update = newUpdate(c, otherUser);
- PatchLineComment comment2 = newPublishedPatchLineComment(psId, filename2,
+ PatchLineComment comment2 = newPublishedComment(psId, filename2,
uuid, range, range.getEndLine(), otherUser, null, now, "comment 2",
- side, "abcd1234abcd1234abcd1234abcd1234abcd1234");
+ side, rev);
update.setPatchSetId(psId);
update.upsertComment(comment2);
update.commit();
- ChangeNotes notes = newNotes(c);
- Multimap<PatchSet.Id, PatchLineComment> commentsForBase =
- notes.getBaseComments();
- Multimap<PatchSet.Id, PatchLineComment> commentsForPS =
- notes.getPatchSetComments();
- assertEquals(commentsForBase.size(), 0);
- assertEquals(commentsForPS.size(), 2);
-
- ImmutableList<PatchLineComment> commentsForThisPS =
- (ImmutableList<PatchLineComment>) commentsForPS.get(psId);
- assertEquals(commentsForThisPS.size(), 2);
- PatchLineComment commentFromNotes1 = commentsForThisPS.get(0);
- PatchLineComment commentFromNotes2 = commentsForThisPS.get(1);
-
- assertEquals(comment1, commentFromNotes1);
- assertEquals(comment2, commentFromNotes2);
+ assertThat(newNotes(c).getComments()).containsExactly(
+ ImmutableMultimap.of(
+ new RevId(rev), comment1,
+ new RevId(rev), comment2)).inOrder();
}
@Test
public void patchLineCommentMultiplePatchsets() throws Exception {
Change c = newChange();
String uuid = "uuid";
+ String rev1 = "abcd1234abcd1234abcd1234abcd1234abcd1234";
+ String rev2 = "abcd4567abcd4567abcd4567abcd4567abcd4567";
CommentRange range = new CommentRange(1, 1, 2, 1);
PatchSet.Id ps1 = c.currentPatchSetId();
String filename = "filename1";
@@ -953,9 +921,9 @@
ChangeUpdate update = newUpdate(c, otherUser);
Timestamp now = TimeUtil.nowTs();
- PatchLineComment comment1 = newPublishedPatchLineComment(ps1, filename,
+ PatchLineComment comment1 = newPublishedComment(ps1, filename,
uuid, range, range.getEndLine(), otherUser, null, now, "comment on ps1",
- side, "abcd1234abcd1234abcd1234abcd1234abcd1234");
+ side, rev1);
update.setPatchSetId(ps1);
update.upsertComment(comment1);
update.commit();
@@ -965,37 +933,24 @@
update = newUpdate(c, otherUser);
now = TimeUtil.nowTs();
- PatchLineComment comment2 = newPublishedPatchLineComment(ps2, filename,
+ PatchLineComment comment2 = newPublishedComment(ps2, filename,
uuid, range, range.getEndLine(), otherUser, null, now, "comment on ps2",
- side, "abcd4567abcd4567abcd4567abcd4567abcd4567");
+ side, rev2);
update.setPatchSetId(ps2);
update.upsertComment(comment2);
update.commit();
- ChangeNotes notes = newNotes(c);
- LinkedListMultimap<PatchSet.Id, PatchLineComment> commentsForBase =
- LinkedListMultimap.create(notes.getBaseComments());
- LinkedListMultimap<PatchSet.Id, PatchLineComment> commentsForPS =
- LinkedListMultimap.create(notes.getPatchSetComments());
- assertEquals(commentsForBase.keys().size(), 0);
- assertEquals(commentsForPS.values().size(), 2);
-
- List<PatchLineComment> commentsForPS1 = commentsForPS.get(ps1);
- assertEquals(commentsForPS1.size(), 1);
- PatchLineComment commentFromPs1 = commentsForPS1.get(0);
-
- List<PatchLineComment> commentsForPS2 = commentsForPS.get(ps2);
- assertEquals(commentsForPS2.size(), 1);
- PatchLineComment commentFromPs2 = commentsForPS2.get(0);
-
- assertEquals(comment1, commentFromPs1);
- assertEquals(comment2, commentFromPs2);
+ assertThat(newNotes(c).getComments()).containsExactly(
+ ImmutableMultimap.of(
+ new RevId(rev1), comment1,
+ new RevId(rev2), comment2));
}
@Test
public void patchLineCommentSingleDraftToPublished() throws Exception {
Change c = newChange();
String uuid = "uuid";
+ String rev = "abcd4567abcd4567abcd4567abcd4567abcd4567";
CommentRange range = new CommentRange(1, 1, 2, 1);
PatchSet.Id ps1 = c.currentPatchSetId();
String filename = "filename1";
@@ -1003,16 +958,17 @@
ChangeUpdate update = newUpdate(c, otherUser);
Timestamp now = TimeUtil.nowTs();
- PatchLineComment comment1 = newPatchLineComment(ps1, filename, uuid,
- range, range.getEndLine(), otherUser, null, now, "comment on ps1", side,
- "abcd4567abcd4567abcd4567abcd4567abcd4567", Status.DRAFT);
+ PatchLineComment comment1 = newComment(ps1, filename, uuid, range,
+ range.getEndLine(), otherUser, null, now, "comment on ps1", side,
+ rev, Status.DRAFT);
update.setPatchSetId(ps1);
update.insertComment(comment1);
update.commit();
ChangeNotes notes = newNotes(c);
- assertEquals(1, notes.getDraftPsComments(otherUserId).values().size());
- assertEquals(0, notes.getDraftBaseComments(otherUserId).values().size());
+ assertThat(notes.getDraftComments(otherUserId)).containsExactly(
+ ImmutableMultimap.of(new RevId(rev), comment1));
+ assertThat(notes.getComments()).isEmpty();
comment1.setStatus(Status.PUBLISHED);
update = newUpdate(c, otherUser);
@@ -1021,49 +977,44 @@
update.commit();
notes = newNotes(c);
-
- assertTrue(notes.getDraftPsComments(otherUserId).values().isEmpty());
- assertTrue(notes.getDraftBaseComments(otherUserId).values().isEmpty());
-
- assertTrue(notes.getBaseComments().values().isEmpty());
- PatchLineComment commentFromNotes =
- Iterables.getOnlyElement(notes.getPatchSetComments().values());
- assertEquals(comment1, commentFromNotes);
+ assertThat(notes.getDraftComments(otherUserId)).isEmpty();
+ assertThat(notes.getComments()).containsExactly(
+ ImmutableMultimap.of(new RevId(rev), comment1));
}
@Test
public void patchLineCommentMultipleDraftsSameSidePublishOne()
- throws OrmException, IOException {
+ throws Exception {
Change c = newChange();
String uuid1 = "uuid1";
String uuid2 = "uuid2";
+ String rev = "abcd4567abcd4567abcd4567abcd4567abcd4567";
CommentRange range1 = new CommentRange(1, 1, 2, 2);
CommentRange range2 = new CommentRange(2, 2, 3, 3);
String filename = "filename1";
short side = (short) 1;
Timestamp now = TimeUtil.nowTs();
- String commitSHA1 = "abcd4567abcd4567abcd4567abcd4567abcd4567";
PatchSet.Id psId = c.currentPatchSetId();
// Write two drafts on the same side of one patch set.
ChangeUpdate update = newUpdate(c, otherUser);
update.setPatchSetId(psId);
- PatchLineComment comment1 = newPatchLineComment(psId, filename, uuid1,
+ PatchLineComment comment1 = newComment(psId, filename, uuid1,
range1, range1.getEndLine(), otherUser, null, now, "comment on ps1",
- side, commitSHA1, Status.DRAFT);
- PatchLineComment comment2 = newPatchLineComment(psId, filename, uuid2,
+ side, rev, Status.DRAFT);
+ PatchLineComment comment2 = newComment(psId, filename, uuid2,
range2, range2.getEndLine(), otherUser, null, now, "other on ps1",
- side, commitSHA1, Status.DRAFT);
+ side, rev, Status.DRAFT);
update.insertComment(comment1);
update.insertComment(comment2);
update.commit();
ChangeNotes notes = newNotes(c);
- assertTrue(notes.getDraftBaseComments(otherUserId).values().isEmpty());
- assertEquals(2, notes.getDraftPsComments(otherUserId).values().size());
-
- assertTrue(notes.getDraftPsComments(otherUserId).containsValue(comment1));
- assertTrue(notes.getDraftPsComments(otherUserId).containsValue(comment2));
+ assertThat(notes.getDraftComments(otherUserId)).containsExactly(
+ ImmutableMultimap.of(
+ new RevId(rev), comment1,
+ new RevId(rev), comment2)).inOrder();
+ assertThat(notes.getComments()).isEmpty();
// Publish first draft.
update = newUpdate(c, otherUser);
@@ -1073,54 +1024,46 @@
update.commit();
notes = newNotes(c);
- assertEquals(comment1,
- Iterables.getOnlyElement(notes.getPatchSetComments().get(psId)));
- assertEquals(comment2,
- Iterables.getOnlyElement(
- notes.getDraftPsComments(otherUserId).values()));
-
- assertTrue(notes.getBaseComments().values().isEmpty());
- assertTrue(notes.getDraftBaseComments(otherUserId).values().isEmpty());
+ assertThat(notes.getDraftComments(otherUserId)).containsExactly(
+ ImmutableMultimap.of(new RevId(rev), comment2));
+ assertThat(notes.getComments()).containsExactly(
+ ImmutableMultimap.of(new RevId(rev), comment1));
}
@Test
public void patchLineCommentsMultipleDraftsBothSidesPublishAll()
- throws OrmException, IOException {
+ throws Exception {
Change c = newChange();
String uuid1 = "uuid1";
String uuid2 = "uuid2";
+ String rev1 = "abcd1234abcd1234abcd1234abcd1234abcd1234";
+ String rev2 = "abcd4567abcd4567abcd4567abcd4567abcd4567";
CommentRange range1 = new CommentRange(1, 1, 2, 2);
CommentRange range2 = new CommentRange(2, 2, 3, 3);
String filename = "filename1";
Timestamp now = TimeUtil.nowTs();
- String commitSHA1 = "abcd4567abcd4567abcd4567abcd4567abcd4567";
- String baseSHA1 = "abcd1234abcd1234abcd1234abcd1234abcd1234";
PatchSet.Id psId = c.currentPatchSetId();
// Write two drafts, one on each side of the patchset.
ChangeUpdate update = newUpdate(c, otherUser);
update.setPatchSetId(psId);
- PatchLineComment baseComment = newPatchLineComment(psId, filename, uuid1,
+ PatchLineComment baseComment = newComment(psId, filename, uuid1,
range1, range1.getEndLine(), otherUser, null, now, "comment on base",
- (short) 0, baseSHA1, Status.DRAFT);
- PatchLineComment psComment = newPatchLineComment(psId, filename, uuid2,
+ (short) 0, rev1, Status.DRAFT);
+ PatchLineComment psComment = newComment(psId, filename, uuid2,
range2, range2.getEndLine(), otherUser, null, now, "comment on ps",
- (short) 1, commitSHA1, Status.DRAFT);
+ (short) 1, rev2, Status.DRAFT);
update.insertComment(baseComment);
update.insertComment(psComment);
update.commit();
ChangeNotes notes = newNotes(c);
- PatchLineComment baseDraftCommentFromNotes =
- Iterables.getOnlyElement(
- notes.getDraftBaseComments(otherUserId).values());
- PatchLineComment psDraftCommentFromNotes =
- Iterables.getOnlyElement(
- notes.getDraftPsComments(otherUserId).values());
-
- assertEquals(baseComment, baseDraftCommentFromNotes);
- assertEquals(psComment, psDraftCommentFromNotes);
+ assertThat(notes.getDraftComments(otherUserId)).containsExactly(
+ ImmutableMultimap.of(
+ new RevId(rev1), baseComment,
+ new RevId(rev2), psComment));
+ assertThat(notes.getComments()).isEmpty();
// Publish both comments.
update = newUpdate(c, otherUser);
@@ -1133,17 +1076,98 @@
update.commit();
notes = newNotes(c);
+ assertThat(notes.getDraftComments(otherUserId)).isEmpty();
+ assertThat(notes.getComments()).containsExactly(
+ ImmutableMultimap.of(
+ new RevId(rev1), baseComment,
+ new RevId(rev2), psComment));
+ }
- PatchLineComment baseCommentFromNotes =
- Iterables.getOnlyElement(notes.getBaseComments().values());
- PatchLineComment psCommentFromNotes =
- Iterables.getOnlyElement(notes.getPatchSetComments().values());
+ @Test
+ public void patchLineCommentsDeleteAllDrafts() throws Exception {
+ Change c = newChange();
+ String uuid = "uuid";
+ String rev = "abcd1234abcd1234abcd1234abcd1234abcd1234";
+ ObjectId objId = ObjectId.fromString(rev);
+ CommentRange range = new CommentRange(1, 1, 2, 1);
+ PatchSet.Id psId = c.currentPatchSetId();
+ String filename = "filename";
+ short side = (short) 1;
- assertEquals(baseComment, baseCommentFromNotes);
- assertEquals(psComment, psCommentFromNotes);
+ ChangeUpdate update = newUpdate(c, otherUser);
+ Timestamp now = TimeUtil.nowTs();
+ PatchLineComment comment = newComment(psId, filename, uuid, range,
+ range.getEndLine(), otherUser, null, now, "comment on ps1", side,
+ rev, Status.DRAFT);
+ update.setPatchSetId(psId);
+ update.upsertComment(comment);
+ update.commit();
- assertTrue(notes.getDraftBaseComments(otherUserId).values().isEmpty());
- assertTrue(notes.getDraftPsComments(otherUserId).values().isEmpty());
+ ChangeNotes notes = newNotes(c);
+ assertThat(notes.getDraftComments(otherUserId)).hasSize(1);
+ assertThat(notes.getDraftCommentNotes().getNoteMap().contains(objId))
+ .isTrue();
+
+ update = newUpdate(c, otherUser);
+ now = TimeUtil.nowTs();
+ update.setPatchSetId(psId);
+ update.deleteComment(comment);
+ update.commit();
+
+ notes = newNotes(c);
+ assertThat(notes.getDraftComments(otherUserId)).isEmpty();
+ assertThat(notes.getDraftCommentNotes().getNoteMap()).isNull();
+ }
+
+ @Test
+ public void patchLineCommentsDeleteAllDraftsForOneRevision()
+ throws Exception {
+ Change c = newChange();
+ String uuid = "uuid";
+ String rev1 = "abcd1234abcd1234abcd1234abcd1234abcd1234";
+ String rev2 = "abcd4567abcd4567abcd4567abcd4567abcd4567";
+ ObjectId objId1 = ObjectId.fromString(rev1);
+ ObjectId objId2 = ObjectId.fromString(rev2);
+ CommentRange range = new CommentRange(1, 1, 2, 1);
+ PatchSet.Id ps1 = c.currentPatchSetId();
+ String filename = "filename1";
+ short side = (short) 1;
+
+ ChangeUpdate update = newUpdate(c, otherUser);
+ Timestamp now = TimeUtil.nowTs();
+ PatchLineComment comment1 = newComment(ps1, filename,
+ uuid, range, range.getEndLine(), otherUser, null, now, "comment on ps1",
+ side, rev1, Status.DRAFT);
+ update.setPatchSetId(ps1);
+ update.upsertComment(comment1);
+ update.commit();
+
+ incrementPatchSet(c);
+ PatchSet.Id ps2 = c.currentPatchSetId();
+
+ update = newUpdate(c, otherUser);
+ now = TimeUtil.nowTs();
+ PatchLineComment comment2 = newComment(ps2, filename,
+ uuid, range, range.getEndLine(), otherUser, null, now, "comment on ps2",
+ side, rev2, Status.DRAFT);
+ update.setPatchSetId(ps2);
+ update.upsertComment(comment2);
+ update.commit();
+
+ ChangeNotes notes = newNotes(c);
+ assertThat(notes.getDraftComments(otherUserId)).hasSize(2);
+
+ update = newUpdate(c, otherUser);
+ now = TimeUtil.nowTs();
+ update.setPatchSetId(ps2);
+ update.deleteComment(comment2);
+ update.commit();
+
+ notes = newNotes(c);
+ assertThat(notes.getDraftComments(otherUserId)).hasSize(1);
+ NoteMap noteMap = notes.getDraftCommentNotes().getNoteMap();
+ assertThat(noteMap.contains(objId1)).isTrue();
+ assertThat(noteMap.contains(objId2)).isFalse();
}
@Test
@@ -1151,27 +1175,20 @@
Change c = newChange();
ChangeUpdate update = newUpdate(c, otherUser);
String uuid = "uuid";
+ String rev = "abcd1234abcd1234abcd1234abcd1234abcd1234";
String messageForBase = "comment for base";
Timestamp now = TimeUtil.nowTs();
PatchSet.Id psId = c.currentPatchSetId();
- PatchLineComment commentForBase =
- newPublishedPatchLineComment(psId, "filename", uuid,
- null, 0, otherUser, null, now, messageForBase,
- (short) 0, "abcd1234abcd1234abcd1234abcd1234abcd1234");
+ PatchLineComment comment = newPublishedComment(
+ psId, "filename", uuid, null, 0, otherUser, null, now, messageForBase,
+ (short) 0, rev);
update.setPatchSetId(psId);
- update.upsertComment(commentForBase);
+ update.upsertComment(comment);
update.commit();
- ChangeNotes notes = newNotes(c);
- Multimap<PatchSet.Id, PatchLineComment> commentsForBase =
- notes.getBaseComments();
- Multimap<PatchSet.Id, PatchLineComment> commentsForPs =
- notes.getPatchSetComments();
-
- assertTrue(commentsForPs.isEmpty());
- assertEquals(commentForBase,
- Iterables.getOnlyElement(commentsForBase.get(psId)));
+ assertThat(newNotes(c).getComments()).containsExactly(
+ ImmutableMultimap.of(new RevId(rev), comment));
}
@Test
@@ -1179,26 +1196,63 @@
Change c = newChange();
ChangeUpdate update = newUpdate(c, otherUser);
String uuid = "uuid";
+ String rev = "abcd1234abcd1234abcd1234abcd1234abcd1234";
String messageForBase = "comment for base";
Timestamp now = TimeUtil.nowTs();
PatchSet.Id psId = c.currentPatchSetId();
- PatchLineComment commentForBase =
- newPublishedPatchLineComment(psId, "filename", uuid,
- null, 1, otherUser, null, now, messageForBase,
- (short) 0, "abcd1234abcd1234abcd1234abcd1234abcd1234");
+ PatchLineComment comment = newPublishedComment(
+ psId, "filename", uuid, null, 1, otherUser, null, now, messageForBase,
+ (short) 0, rev);
update.setPatchSetId(psId);
- update.upsertComment(commentForBase);
+ update.upsertComment(comment);
+ update.commit();
+
+ assertThat(newNotes(c).getComments()).containsExactly(
+ ImmutableMultimap.of(new RevId(rev), comment));
+ }
+
+ @Test
+ public void updateCommentsForMultipleRevisions() throws Exception {
+ Change c = newChange();
+ String uuid = "uuid";
+ String rev1 = "abcd1234abcd1234abcd1234abcd1234abcd1234";
+ String rev2 = "abcd4567abcd4567abcd4567abcd4567abcd4567";
+ CommentRange range = new CommentRange(1, 1, 2, 1);
+ PatchSet.Id ps1 = c.currentPatchSetId();
+ String filename = "filename1";
+ short side = (short) 1;
+
+ incrementPatchSet(c);
+ PatchSet.Id ps2 = c.currentPatchSetId();
+
+ ChangeUpdate update = newUpdate(c, otherUser);
+ update.setPatchSetId(ps2);
+ Timestamp now = TimeUtil.nowTs();
+ PatchLineComment comment1 = newComment(ps1, filename,
+ uuid, range, range.getEndLine(), otherUser, null, now, "comment on ps1",
+ side, rev1, Status.DRAFT);
+ PatchLineComment comment2 = newComment(ps2, filename,
+ uuid, range, range.getEndLine(), otherUser, null, now, "comment on ps2",
+ side, rev2, Status.DRAFT);
+ update.upsertComment(comment1);
+ update.upsertComment(comment2);
update.commit();
ChangeNotes notes = newNotes(c);
- Multimap<PatchSet.Id, PatchLineComment> commentsForBase =
- notes.getBaseComments();
- Multimap<PatchSet.Id, PatchLineComment> commentsForPs =
- notes.getPatchSetComments();
+ assertThat(notes.getDraftComments(otherUserId)).hasSize(2);
+ assertThat(notes.getComments()).isEmpty();
- assertTrue(commentsForPs.isEmpty());
- assertEquals(commentForBase,
- Iterables.getOnlyElement(commentsForBase.get(psId)));
+ update = newUpdate(c, otherUser);
+ update.setPatchSetId(ps2);
+ comment1.setStatus(Status.PUBLISHED);
+ comment2.setStatus(Status.PUBLISHED);
+ update.upsertComment(comment1);
+ update.upsertComment(comment2);
+ update.commit();
+
+ notes = newNotes(c);
+ assertThat(notes.getDraftComments(otherUserId)).isEmpty();
+ assertThat(notes.getComments()).hasSize(2);
}
}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/CommitMessageOutputTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/CommitMessageOutputTest.java
index 328509a..49b61cc 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/CommitMessageOutputTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/CommitMessageOutputTest.java
@@ -14,9 +14,9 @@
package com.google.gerrit.server.notedb;
+import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.server.notedb.ReviewerState.CC;
import static com.google.gerrit.server.notedb.ReviewerState.REVIEWER;
-import static org.junit.Assert.assertEquals;
import com.google.common.collect.ImmutableList;
import com.google.gerrit.common.TimeUtil;
@@ -43,7 +43,7 @@
update.putReviewer(changeOwner.getAccount().getId(), REVIEWER);
update.putReviewer(otherUser.getAccount().getId(), CC);
update.commit();
- assertEquals("refs/changes/01/1/meta", update.getRefName());
+ assertThat(update.getRefName()).isEqualTo("refs/changes/01/1/meta");
RevCommit commit = parseCommit(update.getRevision());
assertBodyEquals("Update patch set 1\n"
@@ -56,17 +56,18 @@
commit);
PersonIdent author = commit.getAuthorIdent();
- assertEquals("Change Owner", author.getName());
- assertEquals("1@gerrit", author.getEmailAddress());
- assertEquals(new Date(c.getCreatedOn().getTime() + 1000),
- author.getWhen());
- assertEquals(TimeZone.getTimeZone("GMT-7:00"), author.getTimeZone());
+ assertThat(author.getName()).isEqualTo("Change Owner");
+ assertThat(author.getEmailAddress()).isEqualTo("1@gerrit");
+ assertThat(author.getWhen())
+ .isEqualTo(new Date(c.getCreatedOn().getTime() + 1000));
+ assertThat(author.getTimeZone())
+ .isEqualTo(TimeZone.getTimeZone("GMT-7:00"));
PersonIdent committer = commit.getCommitterIdent();
- assertEquals("Gerrit Server", committer.getName());
- assertEquals("noreply@gerrit.com", committer.getEmailAddress());
- assertEquals(author.getWhen(), committer.getWhen());
- assertEquals(author.getTimeZone(), committer.getTimeZone());
+ assertThat(committer.getName()).isEqualTo("Gerrit Server");
+ assertThat(committer.getEmailAddress()).isEqualTo("noreply@gerrit.com");
+ assertThat(committer.getWhen()).isEqualTo(author.getWhen());
+ assertThat(committer.getTimeZone()).isEqualTo(author.getTimeZone());
}
@Test
@@ -76,7 +77,7 @@
update.setChangeMessage("Just a little code change.\n"
+ "How about a new line");
update.commit();
- assertEquals("refs/changes/01/1/meta", update.getRefName());
+ assertThat(update.getRefName()).isEqualTo("refs/changes/01/1/meta");
assertBodyEquals("Update patch set 1\n"
+ "\n"
@@ -130,17 +131,18 @@
commit);
PersonIdent author = commit.getAuthorIdent();
- assertEquals("Change Owner", author.getName());
- assertEquals("1@gerrit", author.getEmailAddress());
- assertEquals(new Date(c.getCreatedOn().getTime() + 1000),
- author.getWhen());
- assertEquals(TimeZone.getTimeZone("GMT-7:00"), author.getTimeZone());
+ assertThat(author.getName()).isEqualTo("Change Owner");
+ assertThat(author.getEmailAddress()).isEqualTo("1@gerrit");
+ assertThat(author.getWhen())
+ .isEqualTo(new Date(c.getCreatedOn().getTime() + 1000));
+ assertThat(author.getTimeZone())
+ .isEqualTo(TimeZone.getTimeZone("GMT-7:00"));
PersonIdent committer = commit.getCommitterIdent();
- assertEquals("Gerrit Server", committer.getName());
- assertEquals("noreply@gerrit.com", committer.getEmailAddress());
- assertEquals(author.getWhen(), committer.getWhen());
- assertEquals(author.getTimeZone(), committer.getTimeZone());
+ assertThat(committer.getName()).isEqualTo("Gerrit Server");
+ assertThat(committer.getEmailAddress()).isEqualTo("noreply@gerrit.com");
+ assertThat(committer.getWhen()).isEqualTo(author.getWhen());
+ assertThat(committer.getTimeZone()).isEqualTo(author.getTimeZone());
}
@Test
@@ -161,8 +163,8 @@
commit);
PersonIdent author = commit.getAuthorIdent();
- assertEquals("Anonymous Coward (3)", author.getName());
- assertEquals("3@gerrit", author.getEmailAddress());
+ assertThat(author.getName()).isEqualTo("Anonymous Coward (3)");
+ assertThat(author.getEmailAddress()).isEqualTo("3@gerrit");
}
@Test
@@ -252,6 +254,6 @@
private void assertBodyEquals(String expected, ObjectId commitId)
throws Exception {
RevCommit commit = parseCommit(commitId);
- assertEquals(expected, commit.getFullMessage());
+ assertThat(commit.getFullMessage()).isEqualTo(expected);
}
}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/project/ProjectControlTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/project/ProjectControlTest.java
index b5b321e..0bd4f51 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/project/ProjectControlTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/project/ProjectControlTest.java
@@ -36,6 +36,7 @@
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
+import com.google.inject.util.Providers;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.junit.TestRepository;
@@ -49,7 +50,7 @@
/** Unit tests for {@link ProjectControl}. */
public class ProjectControlTest {
@Inject private AccountManager accountManager;
- @Inject private IdentifiedUser.RequestFactory userFactory;
+ @Inject private IdentifiedUser.GenericFactory userFactory;
@Inject private InMemoryDatabase schemaFactory;
@Inject private InMemoryRepositoryManager repoManager;
@Inject private ProjectControl.GenericFactory projectControlFactory;
@@ -73,7 +74,7 @@
schemaCreator.create(db);
Account.Id userId = accountManager.authenticate(AuthRequest.forUser("user"))
.getAccountId();
- user = userFactory.create(userId);
+ user = userFactory.create(Providers.of(db), userId);
Project.NameKey name = new Project.NameKey("project");
InMemoryRepository inMemoryRepo = repoManager.createRepository(name);
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java
index 4c123fd..c7aabc9 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java
@@ -285,7 +285,8 @@
public void testUsernamePatternNonRegex() {
allow(local, READ, DEVS, "refs/sb/${username}/heads/*");
- ProjectControl u = util.user(local, "u", DEVS), d = util.user(local, "d", DEVS);
+ ProjectControl u = util.user(local, "u", DEVS);
+ ProjectControl d = util.user(local, "d", DEVS);
assertFalse("u can't read", u.controlForRef("refs/sb/d/heads/foobar").isVisible());
assertTrue("d can read", d.controlForRef("refs/sb/d/heads/foobar").isVisible());
}
@@ -294,7 +295,8 @@
public void testUsernamePatternWithRegex() {
allow(local, READ, DEVS, "^refs/sb/${username}/heads/.*");
- ProjectControl u = util.user(local, "d.v", DEVS), d = util.user(local, "dev", DEVS);
+ ProjectControl u = util.user(local, "d.v", DEVS);
+ ProjectControl d = util.user(local, "dev", DEVS);
assertFalse("u can't read", u.controlForRef("refs/sb/dev/heads/foobar").isVisible());
assertTrue("d can read", d.controlForRef("refs/sb/dev/heads/foobar").isVisible());
}
@@ -316,7 +318,8 @@
allow(local, READ, DEVS, "^refs/heads/.*");
allow(parent, READ, ANONYMOUS_USERS, "^refs/heads/.*-QA-.*");
- ProjectControl u = util.user(local, DEVS), d = util.user(local, DEVS);
+ ProjectControl u = util.user(local, DEVS);
+ ProjectControl d = util.user(local, DEVS);
assertTrue("u can read", u.controlForRef("refs/heads/foo-QA-bar").isVisible());
assertTrue("d can read", d.controlForRef("refs/heads/foo-QA-bar").isVisible());
}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/project/Util.java b/gerrit-server/src/test/java/com/google/gerrit/server/project/Util.java
index e39700c..32bc9c6 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/project/Util.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/project/Util.java
@@ -21,9 +21,11 @@
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Lists;
import com.google.gerrit.common.data.AccessSection;
+import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.common.data.GroupReference;
import com.google.gerrit.common.data.LabelType;
import com.google.gerrit.common.data.LabelValue;
+import com.google.gerrit.common.data.PermissionRange;
import com.google.gerrit.common.data.PermissionRule;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountProjectWatch;
@@ -81,15 +83,17 @@
import java.util.Set;
public class Util {
- public static AccountGroup.UUID ADMIN = new AccountGroup.UUID("test.admin");
- public static AccountGroup.UUID DEVS = new AccountGroup.UUID("test.devs");
+ public static final AccountGroup.UUID ADMIN = new AccountGroup.UUID("test.admin");
+ public static final AccountGroup.UUID DEVS = new AccountGroup.UUID("test.devs");
- public static final LabelType CR = category("Code-Review",
- value(2, "Looks good to me, approved"),
- value(1, "Looks good to me, but someone else must approve"),
- value(0, "No score"),
- value(-1, "I would prefer this is not merged as is"),
- value(-2, "This shall not be merged"));
+ public static final LabelType codeReview() {
+ return category("Code-Review",
+ value(2, "Looks good to me, approved"),
+ value(1, "Looks good to me, but someone else must approve"),
+ value(0, "No score"),
+ value(-1, "I would prefer this is not merged as is"),
+ value(-2, "This shall not be merged"));
+ }
public static LabelValue value(int value, String text) {
return new LabelValue((short) value, text);
@@ -138,6 +142,22 @@
project.getAccessSection(AccessSection.GLOBAL_CAPABILITIES, true)
.getPermission(capabilityName, true)
.add(rule);
+ if (GlobalCapability.hasRange(capabilityName)) {
+ PermissionRange.WithDefaults range =
+ GlobalCapability.getRange(capabilityName);
+ if (range != null) {
+ rule.setRange(range.getDefaultMin(), range.getDefaultMax());
+ }
+ }
+ return rule;
+ }
+
+ public static PermissionRule remove(ProjectConfig project,
+ String capabilityName, AccountGroup.UUID group) {
+ PermissionRule rule = newRule(project, group);
+ project.getAccessSection(AccessSection.GLOBAL_CAPABILITIES, true)
+ .getPermission(capabilityName, true)
+ .remove(rule);
return rule;
}
@@ -197,7 +217,8 @@
Repository repo = repoManager.createRepository(allProjectsName);
allProjects = new ProjectConfig(new Project.NameKey(allProjectsName.get()));
allProjects.load(repo);
- allProjects.getLabelSections().put(CR.getName(), CR);
+ LabelType cr = codeReview();
+ allProjects.getLabelSections().put(cr.getName(), cr);
add(allProjects);
} catch (IOException | ConfigInvalidException e) {
throw new RuntimeException(e);
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
index 34588fa..fd36097 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
@@ -15,7 +15,6 @@
package com.google.gerrit.server.query.change;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assert_;
import static com.google.common.truth.TruthJUnit.assume;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.concurrent.TimeUnit.HOURS;
@@ -23,7 +22,9 @@
import static java.util.concurrent.TimeUnit.MINUTES;
import static org.junit.Assert.fail;
+import com.google.common.base.Function;
import com.google.common.base.MoreObjects;
+import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@@ -32,12 +33,11 @@
import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.extensions.api.GerritApi;
+import com.google.gerrit.extensions.api.changes.Changes.QueryRequest;
import com.google.gerrit.extensions.api.changes.HashtagsInput;
import com.google.gerrit.extensions.api.changes.ReviewInput;
-import com.google.gerrit.extensions.api.projects.ProjectInput;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.restapi.BadRequestException;
-import com.google.gerrit.extensions.restapi.TopLevelResource;
import com.google.gerrit.lifecycle.LifecycleManager;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Branch;
@@ -51,11 +51,7 @@
import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.change.ChangeInserter;
import com.google.gerrit.server.change.ChangeTriplet;
-import com.google.gerrit.server.change.ChangesCollection;
-import com.google.gerrit.server.change.PostReview;
-import com.google.gerrit.server.change.RevisionResource;
import com.google.gerrit.server.notedb.NotesMigration;
-import com.google.gerrit.server.project.CreateProject;
import com.google.gerrit.server.project.ProjectControl;
import com.google.gerrit.server.schema.SchemaCreator;
import com.google.gerrit.server.util.RequestContext;
@@ -63,12 +59,12 @@
import com.google.gerrit.testutil.ConfigSuite;
import com.google.gerrit.testutil.InMemoryDatabase;
import com.google.gerrit.testutil.InMemoryRepositoryManager;
+import com.google.gerrit.testutil.InMemoryRepositoryManager.Repo;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Provider;
import com.google.inject.util.Providers;
-import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.revwalk.RevCommit;
@@ -81,32 +77,37 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
@Ignore
@RunWith(ConfigSuite.class)
public abstract class AbstractQueryChangesTest {
- private static final TopLevelResource TLR = TopLevelResource.INSTANCE;
+ @ConfigSuite.Default
+ public static Config defaultConfig() {
+ return updateConfig(new Config());
+ }
@ConfigSuite.Config
public static Config noteDbEnabled() {
- return NotesMigration.allEnabledConfig();
+ return updateConfig(NotesMigration.allEnabledConfig());
+ }
+
+ private static Config updateConfig(Config cfg) {
+ cfg.setInt("index", null, "maxPages", 10);
+ return cfg;
}
@ConfigSuite.Parameter public Config config;
@Inject protected AccountManager accountManager;
@Inject protected ChangeInserter.Factory changeFactory;
- @Inject protected ChangesCollection changes;
- @Inject protected CreateProject.Factory projectFactory;
@Inject protected GerritApi gApi;
- @Inject protected IdentifiedUser.RequestFactory userFactory;
+ @Inject protected IdentifiedUser.GenericFactory userFactory;
@Inject protected InMemoryDatabase schemaFactory;
@Inject protected InMemoryRepositoryManager repoManager;
@Inject protected NotesMigration notesMigration;
- @Inject protected PostReview postReview;
@Inject protected ProjectControl.GenericFactory projectControlFactory;
- @Inject protected Provider<QueryChanges> queryProvider;
@Inject protected SchemaCreator schemaCreator;
@Inject protected ThreadLocalRequestContext requestContext;
@@ -122,10 +123,10 @@
@Before
public void setUpInjector() throws Exception {
- Injector injector = createInjector();
- injector.injectMembers(this);
lifecycle = new LifecycleManager();
+ Injector injector = createInjector();
lifecycle.add(injector);
+ injector.injectMembers(this);
lifecycle.start();
db = schemaFactory.open();
@@ -135,12 +136,13 @@
Account userAccount = db.accounts().get(userId);
userAccount.setPreferredEmail("user@example.com");
db.accounts().update(ImmutableList.of(userAccount));
- user = userFactory.create(userId);
+ user = userFactory.create(Providers.of(db), userId);
requestContext.setContext(newRequestContext(userAccount.getId()));
}
private RequestContext newRequestContext(Account.Id requestUserId) {
- final CurrentUser requestUser = userFactory.create(requestUserId);
+ final CurrentUser requestUser =
+ userFactory.create(Providers.of(db), requestUserId);
return new RequestContext() {
@Override
public CurrentUser getCurrentUser() {
@@ -189,58 +191,54 @@
@Test
public void byId() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, null, null).insert();
Change change2 = newChange(repo, null, null, null, null).insert();
- assertThat(query("12345")).isEmpty();
- assertResultEquals(change1, queryOne(change1.getId().get()));
- assertResultEquals(change2, queryOne(change2.getId().get()));
+ assertQuery("12345");
+ assertQuery(change1.getId().get(), change1);
+ assertQuery(change2.getId().get(), change2);
}
@Test
public void byKey() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
Change change = newChange(repo, null, null, null, null).insert();
String key = change.getKey().get();
- assertThat(query("I0000000000000000000000000000000000000000")).isEmpty();
+ assertQuery("I0000000000000000000000000000000000000000");
for (int i = 0; i <= 36; i++) {
String q = key.substring(0, 41 - i);
- assertResultEquals("result for " + q, change, queryOne(q));
+ assertQuery(q, change);
}
}
@Test
public void byTriplet() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
Change change = newChange(repo, null, null, null, "branch").insert();
String k = change.getKey().get();
- assertResultEquals(change, queryOne("repo~branch~" + k));
- assertResultEquals(change, queryOne("change:repo~branch~" + k));
- assertResultEquals(change, queryOne("repo~refs/heads/branch~" + k));
- assertResultEquals(change, queryOne("change:repo~refs/heads/branch~" + k));
- assertResultEquals(change, queryOne("repo~branch~" + k.substring(0, 10)));
- assertResultEquals(change,
- queryOne("change:repo~branch~" + k.substring(0, 10)));
+ assertQuery("repo~branch~" + k, change);
+ assertQuery("change:repo~branch~" + k, change);
+ assertQuery("repo~refs/heads/branch~" + k, change);
+ assertQuery("change:repo~refs/heads/branch~" + k, change);
+ assertQuery("repo~branch~" + k.substring(0, 10), change);
+ assertQuery("change:repo~branch~" + k.substring(0, 10), change);
- assertThat(query("foo~bar")).isEmpty();
+ assertQuery("foo~bar");
assertBadQuery("change:foo~bar");
- assertThat(query("otherrepo~branch~" + k)).isEmpty();
- assertThat(query("change:otherrepo~branch~" + k)).isEmpty();
- assertThat(query("repo~otherbranch~" + k)).isEmpty();
- assertThat(query("change:repo~otherbranch~" + k)).isEmpty();
- assertThat(query("repo~branch~I0000000000000000000000000000000000000000"))
- .isEmpty();
- assertThat(query(
- "change:repo~branch~I0000000000000000000000000000000000000000"))
- .isEmpty();
+ assertQuery("otherrepo~branch~" + k);
+ assertQuery("change:otherrepo~branch~" + k);
+ assertQuery("repo~otherbranch~" + k);
+ assertQuery("change:repo~otherbranch~" + k);
+ assertQuery("repo~branch~I0000000000000000000000000000000000000000");
+ assertQuery("change:repo~branch~I0000000000000000000000000000000000000000");
}
@Test
public void byStatus() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins1 = newChange(repo, null, null, null, null);
Change change1 = ins1.getChange();
change1.setStatus(Change.Status.NEW);
@@ -250,16 +248,16 @@
change2.setStatus(Change.Status.MERGED);
ins2.insert();
- assertResultEquals(change1, queryOne("status:new"));
- assertResultEquals(change1, queryOne("status:NEW"));
- assertResultEquals(change1, queryOne("is:new"));
- assertResultEquals(change2, queryOne("status:merged"));
- assertResultEquals(change2, queryOne("is:merged"));
+ assertQuery("status:new", change1);
+ assertQuery("status:NEW", change1);
+ assertQuery("is:new", change1);
+ assertQuery("status:merged", change2);
+ assertQuery("is:merged", change2);
}
@Test
public void byStatusOpen() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins1 = newChange(repo, null, null, null, null);
Change change1 = ins1.getChange();
change1.setStatus(Change.Status.NEW);
@@ -273,31 +271,23 @@
change3.setStatus(Change.Status.MERGED);
ins3.insert();
- List<ChangeInfo> results;
- results = query("status:open");
- assertThat(results).hasSize(2);
- assertResultEquals(change2, results.get(0));
- assertResultEquals(change1, results.get(1));
-
- assertThat(query("status:OPEN")).hasSize(2);
- assertThat(query("status:o")).hasSize(2);
- assertThat(query("status:op")).hasSize(2);
- assertThat(query("status:ope")).hasSize(2);
- assertThat(query("status:pending")).hasSize(2);
- assertThat(query("status:PENDING")).hasSize(2);
- assertThat(query("status:p")).hasSize(2);
- assertThat(query("status:pe")).hasSize(2);
- assertThat(query("status:pen")).hasSize(2);
-
- results = query("is:open");
- assertThat(results).hasSize(2);
- assertResultEquals(change2, results.get(0));
- assertResultEquals(change1, results.get(1));
+ Change[] expected = new Change[] {change2, change1};
+ assertQuery("status:open", expected);
+ assertQuery("status:OPEN", expected);
+ assertQuery("status:o", expected);
+ assertQuery("status:op", expected);
+ assertQuery("status:ope", expected);
+ assertQuery("status:pending", expected);
+ assertQuery("status:PENDING", expected);
+ assertQuery("status:p", expected);
+ assertQuery("status:pe", expected);
+ assertQuery("status:pen", expected);
+ assertQuery("is:open", expected);
}
@Test
public void byStatusClosed() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins1 = newChange(repo, null, null, null, null);
Change change1 = ins1.getChange();
change1.setStatus(Change.Status.MERGED);
@@ -311,29 +301,21 @@
change3.setStatus(Change.Status.NEW);
ins3.insert();
- List<ChangeInfo> results;
- results = query("status:closed");
- assertThat(results).hasSize(2);
- assertResultEquals(change2, results.get(0));
- assertResultEquals(change1, results.get(1));
-
- assertThat(query("status:CLOSED")).hasSize(2);
- assertThat(query("status:c")).hasSize(2);
- assertThat(query("status:cl")).hasSize(2);
- assertThat(query("status:clo")).hasSize(2);
- assertThat(query("status:clos")).hasSize(2);
- assertThat(query("status:close")).hasSize(2);
- assertThat(query("status:closed")).hasSize(2);
-
- results = query("is:closed");
- assertThat(results).hasSize(2);
- assertResultEquals(change2, results.get(0));
- assertResultEquals(change1, results.get(1));
+ Change[] expected = new Change[] {change2, change1};
+ assertQuery("status:closed", expected);
+ assertQuery("status:CLOSED", expected);
+ assertQuery("status:c", expected);
+ assertQuery("status:cl", expected);
+ assertQuery("status:clo", expected);
+ assertQuery("status:clos", expected);
+ assertQuery("status:close", expected);
+ assertQuery("status:closed", expected);
+ assertQuery("is:closed", expected);
}
@Test
public void byStatusPrefix() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins1 = newChange(repo, null, null, null, null);
Change change1 = ins1.getChange();
change1.setStatus(Change.Status.NEW);
@@ -343,109 +325,101 @@
change2.setStatus(Change.Status.MERGED);
ins2.insert();
- assertResultEquals(change1, queryOne("status:n"));
- assertResultEquals(change1, queryOne("status:ne"));
- assertResultEquals(change1, queryOne("status:new"));
- assertResultEquals(change1, queryOne("status:N"));
- assertResultEquals(change1, queryOne("status:nE"));
- assertResultEquals(change1, queryOne("status:neW"));
+ assertQuery("status:n", change1);
+ assertQuery("status:ne", change1);
+ assertQuery("status:new", change1);
+ assertQuery("status:N", change1);
+ assertQuery("status:nE", change1);
+ assertQuery("status:neW", change1);
assertBadQuery("status:nx");
assertBadQuery("status:newx");
}
@Test
public void byCommit() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins = newChange(repo, null, null, null, null);
ins.insert();
String sha = ins.getPatchSet().getRevision().get();
- assertThat(query("0000000000000000000000000000000000000000")).isEmpty();
+ assertQuery("0000000000000000000000000000000000000000");
for (int i = 0; i <= 36; i++) {
String q = sha.substring(0, 40 - i);
- assertResultEquals("result for " + q, ins.getChange(), queryOne(q));
+ assertQuery(q, ins.getChange());
}
}
@Test
public void byOwner() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, userId.get(), null).insert();
int user2 = accountManager.authenticate(AuthRequest.forUser("anotheruser"))
.getAccountId().get();
Change change2 = newChange(repo, null, null, user2, null).insert();
- assertResultEquals(change1, queryOne("owner:" + userId.get()));
- assertResultEquals(change2, queryOne("owner:" + user2));
+ assertQuery("owner:" + userId.get(), change1);
+ assertQuery("owner:" + user2, change2);
}
@Test
public void byOwnerIn() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, userId.get(), null).insert();
int user2 = accountManager.authenticate(AuthRequest.forUser("anotheruser"))
.getAccountId().get();
Change change2 = newChange(repo, null, null, user2, null).insert();
- assertResultEquals(change1, queryOne("ownerin:Administrators"));
- List<ChangeInfo> results = query("ownerin:\"Registered Users\"");
- assertThat(results).hasSize(2);
- assertResultEquals(change2, results.get(0));
- assertResultEquals(change1, results.get(1));
+ assertQuery("ownerin:Administrators", change1);
+ assertQuery("ownerin:\"Registered Users\"", change2, change1);
}
@Test
public void byProject() throws Exception {
- TestRepository<InMemoryRepository> repo1 = createProject("repo1");
- TestRepository<InMemoryRepository> repo2 = createProject("repo2");
+ TestRepository<Repo> repo1 = createProject("repo1");
+ TestRepository<Repo> repo2 = createProject("repo2");
Change change1 = newChange(repo1, null, null, null, null).insert();
Change change2 = newChange(repo2, null, null, null, null).insert();
- assertThat(query("project:foo")).isEmpty();
- assertThat(query("project:repo")).isEmpty();
- assertResultEquals(change1, queryOne("project:repo1"));
- assertResultEquals(change2, queryOne("project:repo2"));
+ assertQuery("project:foo");
+ assertQuery("project:repo");
+ assertQuery("project:repo1", change1);
+ assertQuery("project:repo2", change2);
}
@Test
public void byProjectPrefix() throws Exception {
- TestRepository<InMemoryRepository> repo1 = createProject("repo1");
- TestRepository<InMemoryRepository> repo2 = createProject("repo2");
+ TestRepository<Repo> repo1 = createProject("repo1");
+ TestRepository<Repo> repo2 = createProject("repo2");
Change change1 = newChange(repo1, null, null, null, null).insert();
Change change2 = newChange(repo2, null, null, null, null).insert();
- assertThat(query("projects:foo")).isEmpty();
- assertResultEquals(change1, queryOne("projects:repo1"));
- assertResultEquals(change2, queryOne("projects:repo2"));
-
- List<ChangeInfo> results;
- results = query("projects:repo");
- assertThat(results).hasSize(2);
- assertResultEquals(change2, results.get(0));
- assertResultEquals(change1, results.get(1));
+ assertQuery("projects:foo");
+ assertQuery("projects:repo1", change1);
+ assertQuery("projects:repo2", change2);
+ assertQuery("projects:repo", change2, change1);
}
@Test
public void byBranchAndRef() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, null, "master").insert();
Change change2 = newChange(repo, null, null, null, "branch").insert();
- assertThat(query("branch:foo")).isEmpty();
- assertResultEquals(change1, queryOne("branch:master"));
- assertResultEquals(change1, queryOne("branch:refs/heads/master"));
- assertThat(query("ref:master")).isEmpty();
- assertResultEquals(change1, queryOne("ref:refs/heads/master"));
- assertResultEquals(change1, queryOne("branch:refs/heads/master"));
- assertResultEquals(change2, queryOne("branch:branch"));
- assertResultEquals(change2, queryOne("branch:refs/heads/branch"));
- assertThat(query("ref:branch")).isEmpty();
- assertResultEquals(change2, queryOne("ref:refs/heads/branch"));
+ assertQuery("branch:foo");
+ assertQuery("branch:master", change1);
+ assertQuery("branch:refs/heads/master", change1);
+ assertQuery("ref:master");
+ assertQuery("ref:refs/heads/master", change1);
+ assertQuery("branch:refs/heads/master", change1);
+ assertQuery("branch:branch", change2);
+ assertQuery("branch:refs/heads/branch", change2);
+ assertQuery("ref:branch");
+ assertQuery("ref:refs/heads/branch", change2);
}
@Test
public void byTopic() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins1 = newChange(repo, null, null, null, null);
Change change1 = ins1.getChange();
change1.setTopic("feature1");
@@ -458,28 +432,29 @@
Change change3 = newChange(repo, null, null, null, null).insert();
- assertThat(query("topic:foo")).isEmpty();
- assertResultEquals(change1, queryOne("topic:feature1"));
- assertResultEquals(change2, queryOne("topic:feature2"));
- assertResultEquals(change3, queryOne("topic:\"\""));
+ assertQuery("topic:foo");
+ assertQuery("topic:feature1", change1);
+ assertQuery("topic:feature2", change2);
+ assertQuery("topic:feature", change2, change1);
+ assertQuery("topic:\"\"", change3, change2, change1);
}
@Test
public void byMessageExact() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
RevCommit commit1 = repo.parseBody(repo.commit().message("one").create());
Change change1 = newChange(repo, commit1, null, null, null).insert();
RevCommit commit2 = repo.parseBody(repo.commit().message("two").create());
Change change2 = newChange(repo, commit2, null, null, null).insert();
- assertThat(query("message:foo")).isEmpty();
- assertResultEquals(change1, queryOne("message:one"));
- assertResultEquals(change2, queryOne("message:two"));
+ assertQuery("message:foo");
+ assertQuery("message:one", change1);
+ assertQuery("message:two", change2);
}
@Test
public void fullTextWithNumbers() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
RevCommit commit1 =
repo.parseBody(repo.commit().message("12345 67890").create());
Change change1 = newChange(repo, commit1, null, null, null).insert();
@@ -487,65 +462,61 @@
repo.parseBody(repo.commit().message("12346 67891").create());
Change change2 = newChange(repo, commit2, null, null, null).insert();
- assertThat(query("message:1234")).isEmpty();
- assertResultEquals(change1, queryOne("message:12345"));
- assertResultEquals(change2, queryOne("message:12346"));
+ assertQuery("message:1234");
+ assertQuery("message:12345", change1);
+ assertQuery("message:12346", change2);
}
@Test
public void byLabel() throws Exception {
accountManager.authenticate(AuthRequest.forUser("anotheruser"));
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins = newChange(repo, null, null, null, null);
Change change = ins.insert();
- ReviewInput input = new ReviewInput();
- input.message = "toplevel";
- input.labels = ImmutableMap.<String, Short> of("Code-Review", (short) 1);
- postReview.apply(new RevisionResource(
- changes.parse(change.getId()), ins.getPatchSet()), input);
+ gApi.changes().id(change.getId().get()).current()
+ .review(new ReviewInput().label("Code-Review", 1));
- assertThat(query("label:Code-Review=-2")).isEmpty();
- assertThat(query("label:Code-Review-2")).isEmpty();
- assertThat(query("label:Code-Review=-1")).isEmpty();
- assertThat(query("label:Code-Review-1")).isEmpty();
- assertThat(query("label:Code-Review=0")).isEmpty();
- assertResultEquals(change, queryOne("label:Code-Review=+1"));
- assertResultEquals(change, queryOne("label:Code-Review=1"));
- assertResultEquals(change, queryOne("label:Code-Review+1"));
- assertThat(query("label:Code-Review=+2")).isEmpty();
- assertThat(query("label:Code-Review=2")).isEmpty();
- assertThat(query("label:Code-Review+2")).isEmpty();
+ assertQuery("label:Code-Review=-2");
+ assertQuery("label:Code-Review-2");
+ assertQuery("label:Code-Review=-1");
+ assertQuery("label:Code-Review-1");
+ assertQuery("label:Code-Review=0");
+ assertQuery("label:Code-Review=+1", change);
+ assertQuery("label:Code-Review=1", change);
+ assertQuery("label:Code-Review+1", change);
+ assertQuery("label:Code-Review=+2");
+ assertQuery("label:Code-Review=2");
+ assertQuery("label:Code-Review+2");
- assertResultEquals(change, queryOne("label:Code-Review>=0"));
- assertResultEquals(change, queryOne("label:Code-Review>0"));
- assertResultEquals(change, queryOne("label:Code-Review>=1"));
- assertThat(query("label:Code-Review>1")).isEmpty();
- assertThat(query("label:Code-Review>=2")).isEmpty();
+ assertQuery("label:Code-Review>=0", change);
+ assertQuery("label:Code-Review>0", change);
+ assertQuery("label:Code-Review>=1", change);
+ assertQuery("label:Code-Review>1");
+ assertQuery("label:Code-Review>=2");
- assertResultEquals(change, queryOne("label: Code-Review<=2"));
- assertResultEquals(change, queryOne("label: Code-Review<2"));
- assertResultEquals(change, queryOne("label: Code-Review<=1"));
- assertThat(query("label:Code-Review<1")).isEmpty();
- assertThat(query("label:Code-Review<=0")).isEmpty();
+ assertQuery("label: Code-Review<=2", change);
+ assertQuery("label: Code-Review<2", change);
+ assertQuery("label: Code-Review<=1", change);
+ assertQuery("label:Code-Review<1");
+ assertQuery("label:Code-Review<=0");
- assertThat(query("label:Code-Review=+1,anotheruser")).isEmpty();
- assertResultEquals(change, queryOne("label:Code-Review=+1,user"));
- assertResultEquals(change, queryOne("label:Code-Review=+1,user=user"));
- assertResultEquals(change, queryOne("label:Code-Review=+1,Administrators"));
- assertResultEquals(change, queryOne("label:Code-Review=+1,group=Administrators"));
+ assertQuery("label:Code-Review=+1,anotheruser");
+ assertQuery("label:Code-Review=+1,user", change);
+ assertQuery("label:Code-Review=+1,user=user", change);
+ assertQuery("label:Code-Review=+1,Administrators", change);
+ assertQuery("label:Code-Review=+1,group=Administrators", change);
}
@Test
public void limit() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
Change last = null;
int n = 5;
for (int i = 0; i < n; i++) {
last = newChange(repo, null, null, null, null).insert();
}
- List<ChangeInfo> results;
for (int i = 1; i <= n + 2; i++) {
int expectedSize;
Boolean expectedMoreChanges;
@@ -556,86 +527,62 @@
expectedSize = n;
expectedMoreChanges = null;
}
- results = query("status:new limit:" + i);
- String msg = "i=" + i;
- assert_().withFailureMessage(msg).that(results).hasSize(expectedSize);
- assertResultEquals(last, results.get(0));
- assert_().withFailureMessage(msg)
- .that(results.get(results.size() - 1)._moreChanges)
+ String q = "status:new limit:" + i;
+ List<ChangeInfo> results = newQuery(q).get();
+ assertThat(results).named(q).hasSize(expectedSize);
+ assertThat(results.get(results.size() - 1)._moreChanges).named(q)
.isEqualTo(expectedMoreChanges);
+ assertThat(results.get(0)._number).isEqualTo(last.getId().get());
}
}
@Test
public void start() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
List<Change> changes = Lists.newArrayList();
for (int i = 0; i < 2; i++) {
changes.add(newChange(repo, null, null, null, null).insert());
}
- QueryChanges q;
- List<ChangeInfo> results;
- results = query("status:new");
- assertThat(results).hasSize(2);
- assertResultEquals(changes.get(1), results.get(0));
- assertResultEquals(changes.get(0), results.get(1));
-
- q = newQuery("status:new");
- q.setStart(1);
- results = query(q);
- assertThat(results).hasSize(1);
- assertResultEquals(changes.get(0), results.get(0));
-
- q = newQuery("status:new");
- q.setStart(2);
- results = query(q);
- assertThat(results).isEmpty();
-
- q = newQuery("status:new");
- q.setStart(3);
- results = query(q);
- assertThat(results).isEmpty();
+ assertQuery("status:new", changes.get(1), changes.get(0));
+ assertQuery(newQuery("status:new").withStart(1), changes.get(0));
+ assertQuery(newQuery("status:new").withStart(2));
+ assertQuery(newQuery("status:new").withStart(3));
}
@Test
public void startWithLimit() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
List<Change> changes = Lists.newArrayList();
for (int i = 0; i < 3; i++) {
changes.add(newChange(repo, null, null, null, null).insert());
}
- QueryChanges q;
- List<ChangeInfo> results;
- results = query("status:new limit:2");
- assertThat(results).hasSize(2);
- assertResultEquals(changes.get(2), results.get(0));
- assertResultEquals(changes.get(1), results.get(1));
+ assertQuery("status:new limit:2", changes.get(2), changes.get(1));
+ assertQuery(
+ newQuery("status:new limit:2").withStart(1),
+ changes.get(1), changes.get(0));
+ assertQuery(newQuery("status:new limit:2").withStart(2), changes.get(0));
+ assertQuery(newQuery("status:new limit:2").withStart(3));
+ }
- q = newQuery("status:new limit:2");
- q.setStart(1);
- results = query(q);
- assertThat(results).hasSize(2);
- assertResultEquals(changes.get(1), results.get(0));
- assertResultEquals(changes.get(0), results.get(1));
+ @Test
+ public void maxPages() throws Exception {
+ TestRepository<Repo> repo = createProject("repo");
+ Change change = newChange(repo, null, null, null, null).insert();
- q = newQuery("status:new limit:2");
- q.setStart(2);
- results = query(q);
- assertThat(results).hasSize(1);
- assertResultEquals(changes.get(0), results.get(0));
-
- q = newQuery("status:new limit:2");
- q.setStart(3);
- results = query(q);
- assertThat(results).isEmpty();
+ QueryRequest query = newQuery("status:new").withLimit(10);
+ assertQuery(query, change);
+ assertQuery(query.withStart(1));
+ assertQuery(query.withStart(99));
+ assertBadQuery(query.withStart(100));
+ assertQuery(query.withLimit(100).withStart(100));
}
@Test
public void updateOrder() throws Exception {
clockStepMs = MILLISECONDS.convert(2, MINUTES);
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
List<ChangeInserter> inserters = Lists.newArrayList();
List<Change> changes = Lists.newArrayList();
for (int i = 0; i < 5; i++) {
@@ -644,93 +591,68 @@
}
for (int i : ImmutableList.of(2, 0, 1, 4, 3)) {
- ReviewInput input = new ReviewInput();
- input.message = "modifying " + i;
- postReview.apply(
- new RevisionResource(
- this.changes.parse(changes.get(i).getId()),
- inserters.get(i).getPatchSet()),
- input);
- changes.set(i, db.changes().get(changes.get(i).getId()));
+ gApi.changes().id(changes.get(i).getId().get()).current()
+ .review(new ReviewInput().message("modifying " + i));
}
- List<ChangeInfo> results = query("status:new");
- assertThat(results).hasSize(5);
- assertResultEquals(changes.get(3), results.get(0));
- assertResultEquals(changes.get(4), results.get(1));
- assertResultEquals(changes.get(1), results.get(2));
- assertResultEquals(changes.get(0), results.get(3));
- assertResultEquals(changes.get(2), results.get(4));
+ assertQuery(
+ "status:new",
+ changes.get(3),
+ changes.get(4),
+ changes.get(1),
+ changes.get(0),
+ changes.get(2));
}
@Test
public void updatedOrderWithMinuteResolution() throws Exception {
clockStepMs = MILLISECONDS.convert(2, MINUTES);
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins1 = newChange(repo, null, null, null, null);
Change change1 = ins1.insert();
Change change2 = newChange(repo, null, null, null, null).insert();
- assertThat(lastUpdatedMs(change1) < lastUpdatedMs(change2)).isTrue();
+ assertThat(lastUpdatedMs(change1)).isLessThan(lastUpdatedMs(change2));
+ assertQuery("status:new", change2, change1);
- List<ChangeInfo> results;
- results = query("status:new");
- assertThat(results).hasSize(2);
- assertResultEquals(change2, results.get(0));
- assertResultEquals(change1, results.get(1));
-
- ReviewInput input = new ReviewInput();
- input.message = "toplevel";
- postReview.apply(new RevisionResource(
- changes.parse(change1.getId()), ins1.getPatchSet()), input);
+ gApi.changes().id(change1.getId().get()).current()
+ .review(new ReviewInput());
change1 = db.changes().get(change1.getId());
- assertThat(lastUpdatedMs(change1) > lastUpdatedMs(change2)).isTrue();
- assertThat(lastUpdatedMs(change1) - lastUpdatedMs(change2)
- > MILLISECONDS.convert(1, MINUTES)).isTrue();
+ assertThat(lastUpdatedMs(change1)).isGreaterThan(lastUpdatedMs(change2));
+ assertThat(lastUpdatedMs(change1) - lastUpdatedMs(change2))
+ .isGreaterThan(MILLISECONDS.convert(1, MINUTES));
- results = query("status:new");
- assertThat(results).hasSize(2);
// change1 moved to the top.
- assertResultEquals(change1, results.get(0));
- assertResultEquals(change2, results.get(1));
+ assertQuery("status:new", change1, change2);
}
@Test
public void updatedOrderWithSubMinuteResolution() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins1 = newChange(repo, null, null, null, null);
Change change1 = ins1.insert();
Change change2 = newChange(repo, null, null, null, null).insert();
- assertThat(lastUpdatedMs(change1) < lastUpdatedMs(change2)).isTrue();
+ assertThat(lastUpdatedMs(change1)).isLessThan(lastUpdatedMs(change2));
- List<ChangeInfo> results;
- results = query("status:new");
- assertThat(results).hasSize(2);
- assertResultEquals(change2, results.get(0));
- assertResultEquals(change1, results.get(1));
+ assertQuery("status:new", change2, change1);
- ReviewInput input = new ReviewInput();
- input.message = "toplevel";
- postReview.apply(new RevisionResource(
- changes.parse(change1.getId()), ins1.getPatchSet()), input);
+ gApi.changes().id(change1.getId().get()).current()
+ .review(new ReviewInput());
change1 = db.changes().get(change1.getId());
- assertThat(lastUpdatedMs(change1) > lastUpdatedMs(change2)).isTrue();
- assertThat(lastUpdatedMs(change1) - lastUpdatedMs(change2)
- < MILLISECONDS.convert(1, MINUTES)).isTrue();
+ assertThat(lastUpdatedMs(change1)).isGreaterThan(lastUpdatedMs(change2));
+ assertThat(lastUpdatedMs(change1) - lastUpdatedMs(change2))
+ .isLessThan(MILLISECONDS.convert(1, MINUTES));
- results = query("status:new");
- assertThat(results).hasSize(2);
// change1 moved to the top.
- assertResultEquals(change1, results.get(0));
- assertResultEquals(change2, results.get(1));
+ assertQuery("status:new", change1, change2);
}
@Test
public void filterOutMoreThanOnePageOfResults() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
Change change = newChange(repo, null, null, userId.get(), null).insert();
int user2 = accountManager.authenticate(AuthRequest.forUser("anotheruser"))
.getAccountId().get();
@@ -738,88 +660,87 @@
newChange(repo, null, null, user2, null).insert();
}
- assertResultEquals(change, queryOne("status:new ownerin:Administrators"));
- assertResultEquals(change,
- queryOne("status:new ownerin:Administrators limit:2"));
+ assertQuery("status:new ownerin:Administrators", change);
+ assertQuery("status:new ownerin:Administrators limit:2", change);
}
@Test
public void filterOutAllResults() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
int user2 = accountManager.authenticate(AuthRequest.forUser("anotheruser"))
.getAccountId().get();
for (int i = 0; i < 5; i++) {
newChange(repo, null, null, user2, null).insert();
}
- assertThat(query("status:new ownerin:Administrators")).isEmpty();
- assertThat(query("status:new ownerin:Administrators limit:2")).isEmpty();
+ assertQuery("status:new ownerin:Administrators");
+ assertQuery("status:new ownerin:Administrators limit:2");
}
@Test
public void byFileExact() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
RevCommit commit = repo.parseBody(
repo.commit().message("one")
.add("dir/file1", "contents1").add("dir/file2", "contents2")
.create());
Change change = newChange(repo, commit, null, null, null).insert();
- assertThat(query("file:file")).isEmpty();
- assertResultEquals(change, queryOne("file:dir"));
- assertResultEquals(change, queryOne("file:file1"));
- assertResultEquals(change, queryOne("file:file2"));
- assertResultEquals(change, queryOne("file:dir/file1"));
- assertResultEquals(change, queryOne("file:dir/file2"));
+ assertQuery("file:file");
+ assertQuery("file:dir", change);
+ assertQuery("file:file1", change);
+ assertQuery("file:file2", change);
+ assertQuery("file:dir/file1", change);
+ assertQuery("file:dir/file2", change);
}
@Test
public void byFileRegex() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
RevCommit commit = repo.parseBody(
repo.commit().message("one")
.add("dir/file1", "contents1").add("dir/file2", "contents2")
.create());
Change change = newChange(repo, commit, null, null, null).insert();
- assertThat(query("file:.*file.*")).isEmpty();
- assertThat(query("file:^file.*")).isEmpty(); // Whole path only.
- assertResultEquals(change, queryOne("file:^dir.file.*"));
+ assertQuery("file:.*file.*");
+ assertQuery("file:^file.*"); // Whole path only.
+ assertQuery("file:^dir.file.*", change);
}
@Test
public void byPathExact() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
RevCommit commit = repo.parseBody(
repo.commit().message("one")
.add("dir/file1", "contents1").add("dir/file2", "contents2")
.create());
Change change = newChange(repo, commit, null, null, null).insert();
- assertThat(query("path:file")).isEmpty();
- assertThat(query("path:dir")).isEmpty();
- assertThat(query("path:file1")).isEmpty();
- assertThat(query("path:file2")).isEmpty();
- assertResultEquals(change, queryOne("path:dir/file1"));
- assertResultEquals(change, queryOne("path:dir/file2"));
+ assertQuery("path:file");
+ assertQuery("path:dir");
+ assertQuery("path:file1");
+ assertQuery("path:file2");
+ assertQuery("path:dir/file1", change);
+ assertQuery("path:dir/file2", change);
}
@Test
public void byPathRegex() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
RevCommit commit = repo.parseBody(
repo.commit().message("one")
.add("dir/file1", "contents1").add("dir/file2", "contents2")
.create());
Change change = newChange(repo, commit, null, null, null).insert();
- assertThat(query("path:.*file.*")).isEmpty();
- assertResultEquals(change, queryOne("path:^dir.file.*"));
+ assertQuery("path:.*file.*");
+ assertQuery("path:^dir.file.*", change);
}
@Test
public void byComment() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins = newChange(repo, null, null, null, null);
Change change = ins.insert();
@@ -830,99 +751,74 @@
comment.message = "inline";
input.comments = ImmutableMap.<String, List<ReviewInput.CommentInput>> of(
Patch.COMMIT_MSG, ImmutableList.<ReviewInput.CommentInput> of(comment));
- postReview.apply(new RevisionResource(
- changes.parse(change.getId()), ins.getPatchSet()), input);
+ gApi.changes().id(change.getId().get()).current().review(input);
- assertThat(query("comment:foo")).isEmpty();
- assertResultEquals(change, queryOne("comment:toplevel"));
- assertResultEquals(change, queryOne("comment:inline"));
+ assertQuery("comment:foo");
+ assertQuery("comment:toplevel", change);
+ assertQuery("comment:inline", change);
}
@Test
public void byAge() throws Exception {
long thirtyHours = MILLISECONDS.convert(30, HOURS);
clockStepMs = thirtyHours;
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, null, null).insert();
Change change2 = newChange(repo, null, null, null, null).insert();
clockStepMs = 0; // Queried by AgePredicate constructor.
long now = TimeUtil.nowMs();
- assertThat(lastUpdatedMs(change2) - lastUpdatedMs(change1)).isEqualTo(thirtyHours);
+ assertThat(lastUpdatedMs(change2) - lastUpdatedMs(change1))
+ .isEqualTo(thirtyHours);
assertThat(now - lastUpdatedMs(change2)).isEqualTo(thirtyHours);
assertThat(TimeUtil.nowMs()).isEqualTo(now);
- assertThat(query("-age:1d")).isEmpty();
- assertThat(query("-age:" + (30 * 60 - 1) + "m")).isEmpty();
- assertResultEquals(change2, queryOne("-age:2d"));
-
- List<ChangeInfo> results;
- results = query("-age:3d");
- assertThat(results).hasSize(2);
- assertResultEquals(change2, results.get(0));
- assertResultEquals(change1, results.get(1));
-
- assertThat(query("age:3d")).isEmpty();
- assertResultEquals(change1, queryOne("age:2d"));
-
- results = query("age:1d");
- assertThat(results).hasSize(2);
- assertResultEquals(change2, results.get(0));
- assertResultEquals(change1, results.get(1));
+ assertQuery("-age:1d");
+ assertQuery("-age:" + (30 * 60 - 1) + "m");
+ assertQuery("-age:2d", change2);
+ assertQuery("-age:3d", change2, change1);
+ assertQuery("age:3d");
+ assertQuery("age:2d", change1);
+ assertQuery("age:1d", change2, change1);
}
@Test
public void byBefore() throws Exception {
clockStepMs = MILLISECONDS.convert(30, HOURS);
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, null, null).insert();
Change change2 = newChange(repo, null, null, null, null).insert();
clockStepMs = 0;
- assertThat(query("before:2009-09-29")).isEmpty();
- assertThat(query("before:2009-09-30")).isEmpty();
- assertThat(query("before:\"2009-09-30 16:59:00 -0400\"")).isEmpty();
- assertThat(query("before:\"2009-09-30 20:59:00 -0000\"")).isEmpty();
- assertThat(query("before:\"2009-09-30 20:59:00\"")).isEmpty();
- assertResultEquals(change1,
- queryOne("before:\"2009-09-30 17:02:00 -0400\""));
- assertResultEquals(change1,
- queryOne("before:\"2009-10-01 21:02:00 -0000\""));
- assertResultEquals(change1,
- queryOne("before:\"2009-10-01 21:02:00\""));
- assertResultEquals(change1, queryOne("before:2009-10-01"));
-
- List<ChangeInfo> results;
- results = query("before:2009-10-03");
- assertThat(results).hasSize(2);
- assertResultEquals(change2, results.get(0));
- assertResultEquals(change1, results.get(1));
+ assertQuery("before:2009-09-29");
+ assertQuery("before:2009-09-30");
+ assertQuery("before:\"2009-09-30 16:59:00 -0400\"");
+ assertQuery("before:\"2009-09-30 20:59:00 -0000\"");
+ assertQuery("before:\"2009-09-30 20:59:00\"");
+ assertQuery("before:\"2009-09-30 17:02:00 -0400\"", change1);
+ assertQuery("before:\"2009-10-01 21:02:00 -0000\"", change1);
+ assertQuery("before:\"2009-10-01 21:02:00\"", change1);
+ assertQuery("before:2009-10-01", change1);
+ assertQuery("before:2009-10-03", change2, change1);
}
@Test
public void byAfter() throws Exception {
clockStepMs = MILLISECONDS.convert(30, HOURS);
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, null, null).insert();
Change change2 = newChange(repo, null, null, null, null).insert();
clockStepMs = 0;
- assertThat(query("after:2009-10-03")).isEmpty();
- assertResultEquals(change2,
- queryOne("after:\"2009-10-01 20:59:59 -0400\""));
- assertResultEquals(change2,
- queryOne("after:\"2009-10-01 20:59:59 -0000\""));
- assertResultEquals(change2, queryOne("after:2009-10-01"));
-
- List<ChangeInfo> results;
- results = query("after:2009-09-30");
- assertThat(results).hasSize(2);
- assertResultEquals(change2, results.get(0));
- assertResultEquals(change1, results.get(1));
+ assertQuery("after:2009-10-03");
+ assertQuery("after:\"2009-10-01 20:59:59 -0400\"", change2);
+ assertQuery("after:\"2009-10-01 20:59:59 -0000\"", change2);
+ assertQuery("after:2009-10-01", change2);
+ assertQuery("after:2009-09-30", change2, change1);
}
@Test
public void bySize() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
// added = 3, deleted = 0, delta = 3
RevCommit commit1 = repo.parseBody(
@@ -934,32 +830,32 @@
Change change1 = newChange(repo, commit1, null, null, null).insert();
Change change2 = newChange(repo, commit2, null, null, null).insert();
- assertThat(query("added:>4")).isEmpty();
- assertResultEquals(change1, queryOne("added:3"));
- assertResultEquals(change1, queryOne("added:>2"));
- assertResultEquals(change1, queryOne("added:>=3"));
- assertResultEquals(change2, queryOne("added:<1"));
- assertResultEquals(change2, queryOne("added:<=0"));
+ assertQuery("added:>4");
+ assertQuery("added:3", change1);
+ assertQuery("added:>2", change1);
+ assertQuery("added:>=3", change1);
+ assertQuery("added:<1", change2);
+ assertQuery("added:<=0", change2);
- assertThat(query("deleted:>3")).isEmpty();
- assertResultEquals(change2, queryOne("deleted:2"));
- assertResultEquals(change2, queryOne("deleted:>1"));
- assertResultEquals(change2, queryOne("deleted:>=2"));
- assertResultEquals(change1, queryOne("deleted:<1"));
- assertResultEquals(change1, queryOne("deleted:<=0"));
+ assertQuery("deleted:>3");
+ assertQuery("deleted:2", change2);
+ assertQuery("deleted:>1", change2);
+ assertQuery("deleted:>=2", change2);
+ assertQuery("deleted:<1", change1);
+ assertQuery("deleted:<=0", change1);
for (String str : Lists.newArrayList("delta", "size")) {
- assertThat(query(str + ":<2")).isEmpty();
- assertResultEquals(change1, queryOne(str + ":3"));
- assertResultEquals(change1, queryOne(str + ":>2"));
- assertResultEquals(change1, queryOne(str + ":>=3"));
- assertResultEquals(change2, queryOne(str + ":<3"));
- assertResultEquals(change2, queryOne(str + ":<=2"));
+ assertQuery(str + ":<2");
+ assertQuery(str + ":3", change1);
+ assertQuery(str + ":>2", change1);
+ assertQuery(str + ":>=3", change1);
+ assertQuery(str + ":<3", change2);
+ assertQuery(str + ":<=2", change2);
}
}
private List<Change> setUpHashtagChanges() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, null, null).insert();
Change change2 = newChange(repo, null, null, null, null).insert();
@@ -977,34 +873,31 @@
public void byHashtagWithNotedb() throws Exception {
assume().that(notesMigration.enabled()).isTrue();
List<Change> changes = setUpHashtagChanges();
- List<ChangeInfo> results = query("hashtag:foo");
- assertThat(results).hasSize(2);
- assertResultEquals(changes.get(1), results.get(0));
- assertResultEquals(changes.get(0), results.get(1));
- assertResultEquals(changes.get(1), queryOne("hashtag:bar"));
- assertResultEquals(changes.get(1), queryOne("hashtag:\"a tag\""));
- assertResultEquals(changes.get(1), queryOne("hashtag:\"a tag \""));
- assertResultEquals(changes.get(1), queryOne("hashtag:\" a tag \""));
- assertResultEquals(changes.get(1), queryOne("hashtag:\"#a tag\""));
- assertResultEquals(changes.get(1), queryOne("hashtag:\"# #a tag\""));
+ assertQuery("hashtag:foo", changes.get(1), changes.get(0));
+ assertQuery("hashtag:bar", changes.get(1));
+ assertQuery("hashtag:\"a tag\"", changes.get(1));
+ assertQuery("hashtag:\"a tag \"", changes.get(1));
+ assertQuery("hashtag:\" a tag \"", changes.get(1));
+ assertQuery("hashtag:\"#a tag\"", changes.get(1));
+ assertQuery("hashtag:\"# #a tag\"", changes.get(1));
}
@Test
public void byHashtagWithoutNotedb() throws Exception {
assume().that(notesMigration.enabled()).isFalse();
setUpHashtagChanges();
- assertThat(query("hashtag:foo")).isEmpty();
- assertThat(query("hashtag:bar")).isEmpty();
- assertThat(query("hashtag:\" bar \"")).isEmpty();
- assertThat(query("hashtag:\"a tag\"")).isEmpty();
- assertThat(query("hashtag:\" a tag \"")).isEmpty();
- assertThat(query("hashtag:#foo")).isEmpty();
- assertThat(query("hashtag:\"# #foo\"")).isEmpty();
+ assertQuery("hashtag:foo");
+ assertQuery("hashtag:bar");
+ assertQuery("hashtag:\" bar \"");
+ assertQuery("hashtag:\"a tag\"");
+ assertQuery("hashtag:\" a tag \"");
+ assertQuery("hashtag:#foo");
+ assertQuery("hashtag:\"# #foo\"");
}
@Test
public void byDefault() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, null, null).insert();
@@ -1023,8 +916,7 @@
ReviewInput ri4 = new ReviewInput();
ri4.message = "toplevel";
ri4.labels = ImmutableMap.<String, Short> of("Code-Review", (short) 1);
- postReview.apply(new RevisionResource(
- changes.parse(change4.getId()), ins4.getPatchSet()), ri4);
+ gApi.changes().id(change4.getId().get()).current().review(ri4);
ChangeInserter ins5 = newChange(repo, null, null, null, null);
Change change5 = ins5.getChange();
@@ -1033,24 +925,25 @@
Change change6 = newChange(repo, null, null, null, "branch6").insert();
- assertResultEquals(change1,
- queryOne(Integer.toString(change1.getId().get())));
- assertResultEquals(change1, queryOne(ChangeTriplet.format(change1)));
- assertResultEquals(change2, queryOne("foosubject"));
- assertResultEquals(change3, queryOne("Foo.java"));
- assertResultEquals(change4, queryOne("Code-Review+1"));
- assertResultEquals(change4, queryOne("toplevel"));
- assertResultEquals(change5, queryOne("feature5"));
- assertResultEquals(change6, queryOne("branch6"));
- assertResultEquals(change6, queryOne("refs/heads/branch6"));
+ assertQuery(change1.getId().get(), change1);
+ assertQuery(ChangeTriplet.format(change1), change1);
+ assertQuery("foosubject", change2);
+ assertQuery("Foo.java", change3);
+ assertQuery("Code-Review+1", change4);
+ assertQuery("toplevel", change4);
+ assertQuery("feature5", change5);
+ assertQuery("branch6", change6);
+ assertQuery("refs/heads/branch6", change6);
- assertThat(query("user@example.com")).hasSize(6);
- assertThat(query("repo")).hasSize(6);
+ Change[] expected =
+ new Change[] {change6, change5, change4, change3, change2, change1};
+ assertQuery("user@example.com", expected);
+ assertQuery("repo", expected);
}
@Test
public void implicitVisibleTo() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, userId.get(), null).insert();
ChangeInserter ins2 = newChange(repo, null, null, userId.get(), null);
Change change2 = ins2.getChange();
@@ -1058,20 +951,17 @@
ins2.insert();
String q = "project:repo";
- List<ChangeInfo> results = query(q);
- assertThat(results).hasSize(2);
- assertResultEquals(change2, results.get(0));
- assertResultEquals(change1, results.get(1));
+ assertQuery(q, change2, change1);
// Second user cannot see first user's drafts.
requestContext.setContext(newRequestContext(accountManager
.authenticate(AuthRequest.forUser("anotheruser")).getAccountId()));
- assertResultEquals(change1, queryOne(q));
+ assertQuery(q, change1);
}
@Test
public void explicitVisibleTo() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, userId.get(), null).insert();
ChangeInserter ins2 = newChange(repo, null, null, userId.get(), null);
Change change2 = ins2.getChange();
@@ -1079,20 +969,98 @@
ins2.insert();
String q = "project:repo";
- List<ChangeInfo> results = query(q);
- assertThat(results).hasSize(2);
- assertResultEquals(change2, results.get(0));
- assertResultEquals(change1, results.get(1));
+ assertQuery(q, change2, change1);
// Second user cannot see first user's drafts.
Account.Id user2 = accountManager
.authenticate(AuthRequest.forUser("anotheruser"))
.getAccountId();
- assertResultEquals(change1, queryOne(q + " visibleto:" + user2.get()));
+ assertQuery(q + " visibleto:" + user2.get(), change1);
+ }
+
+ @Test
+ public void byCommentBy() throws Exception {
+ TestRepository<Repo> repo = createProject("repo");
+ Change change1 = newChange(repo, null, null, null, null).insert();
+ Change change2 = newChange(repo, null, null, null, null).insert();
+
+ int user2 = accountManager.authenticate(AuthRequest.forUser("anotheruser"))
+ .getAccountId().get();
+
+ ReviewInput input = new ReviewInput();
+ input.message = "toplevel";
+ ReviewInput.CommentInput comment = new ReviewInput.CommentInput();
+ comment.line = 1;
+ comment.message = "inline";
+ input.comments = ImmutableMap.<String, List<ReviewInput.CommentInput>> of(
+ Patch.COMMIT_MSG, ImmutableList.<ReviewInput.CommentInput> of(comment));
+ gApi.changes().id(change1.getId().get()).current().review(input);
+
+ input = new ReviewInput();
+ input.message = "toplevel";
+ gApi.changes().id(change2.getId().get()).current().review(input);
+
+ assertQuery("commentby:" + userId.get(), change2, change1);
+ assertQuery("commentby:" + user2);
+ }
+
+ @Test
+ public void byFrom() throws Exception {
+ TestRepository<Repo> repo = createProject("repo");
+ Change change1 = newChange(repo, null, null, null, null).insert();
+
+ int user2 = accountManager.authenticate(AuthRequest.forUser("anotheruser"))
+ .getAccountId().get();
+ ChangeInserter ins2 = newChange(repo, null, null, user2, null);
+ Change change2 = ins2.insert();
+
+ ReviewInput input = new ReviewInput();
+ input.message = "toplevel";
+ ReviewInput.CommentInput comment = new ReviewInput.CommentInput();
+ comment.line = 1;
+ comment.message = "inline";
+ input.comments = ImmutableMap.<String, List<ReviewInput.CommentInput>> of(
+ Patch.COMMIT_MSG, ImmutableList.<ReviewInput.CommentInput> of(comment));
+ gApi.changes().id(change2.getId().get()).current().review(input);
+
+ assertQuery("from:" + userId.get(), change2, change1);
+ assertQuery("from:" + user2, change2);
+ }
+
+ @Test
+ public void conflicts() throws Exception {
+ TestRepository<Repo> repo = createProject("repo");
+ RevCommit commit1 = repo.parseBody(
+ repo.commit()
+ .add("file1", "contents1")
+ .add("dir/file2", "contents2")
+ .add("dir/file3", "contents3")
+ .create());
+ RevCommit commit2 = repo.parseBody(
+ repo.commit()
+ .add("file1", "contents1")
+ .create());
+ RevCommit commit3 = repo.parseBody(
+ repo.commit()
+ .add("dir/file2", "contents2 different")
+ .create());
+ RevCommit commit4 = repo.parseBody(
+ repo.commit()
+ .add("file4", "contents4")
+ .create());
+ Change change1 = newChange(repo, commit1, null, null, null).insert();
+ Change change2 = newChange(repo, commit2, null, null, null).insert();
+ Change change3 = newChange(repo, commit3, null, null, null).insert();
+ Change change4 = newChange(repo, commit4, null, null, null).insert();
+
+ assertQuery("conflicts:" + change1.getId().get(), change3);
+ assertQuery("conflicts:" + change2.getId().get());
+ assertQuery("conflicts:" + change3.getId().get(), change1);
+ assertQuery("conflicts:" + change4.getId().get());
}
protected ChangeInserter newChange(
- TestRepository<InMemoryRepository> repo,
+ TestRepository<Repo> repo,
@Nullable RevCommit commit, @Nullable String key, @Nullable Integer owner,
@Nullable String branch) throws Exception {
if (commit == null) {
@@ -1120,75 +1088,69 @@
Change change = new Change(new Change.Key(key), id, ownerId,
new Branch.NameKey(project, branch), TimeUtil.nowTs());
+ IdentifiedUser user = userFactory.create(Providers.of(db), ownerId);
return changeFactory.create(
- projectControlFactory.controlFor(project, userFactory.create(ownerId)),
+ projectControlFactory.controlFor(project, user),
change,
commit);
}
- protected void assertResultEquals(Change expected, ChangeInfo actual) {
- assertThat(actual._number).isEqualTo(expected.getId().get());
- }
-
- protected void assertResultEquals(String message, Change expected,
- ChangeInfo actual) {
- assert_().withFailureMessage(message).that(actual._number)
- .isEqualTo(expected.getId().get());
- }
-
protected void assertBadQuery(Object query) throws Exception {
+ assertBadQuery(newQuery(query));
+ }
+
+ protected void assertBadQuery(QueryRequest query) throws Exception {
try {
- query(query);
+ query.get();
fail("expected BadRequestException for query: " + query);
} catch (BadRequestException e) {
// Expected.
}
}
- protected TestRepository<InMemoryRepository> createProject(String name)
- throws Exception {
- CreateProject create = projectFactory.create(name);
- create.apply(TLR, new ProjectInput());
+ protected TestRepository<Repo> createProject(String name) throws Exception {
+ gApi.projects().create(name).get();
return new TestRepository<>(
repoManager.openRepository(new Project.NameKey(name)));
}
- protected QueryChanges newQuery(Object query) {
- QueryChanges q = queryProvider.get();
- q.addQuery(query.toString());
- return q;
+ protected QueryRequest newQuery(Object query) {
+ return gApi.changes().query(query.toString());
}
- @SuppressWarnings({"rawtypes", "unchecked"})
- protected List<ChangeInfo> query(QueryChanges q) throws Exception {
- Object result = q.apply(TLR);
- assert_()
- .withFailureMessage(
- String.format("expected List<ChangeInfo>, found %s for [%s]",
- result, q.getQuery(0))).that(result).isInstanceOf(List.class);
- List results = (List) result;
- if (!results.isEmpty()) {
- assert_()
- .withFailureMessage(
- String.format("expected ChangeInfo, found %s for [%s]", result,
- q.getQuery(0))).that(results.get(0))
- .isInstanceOf(ChangeInfo.class);
- }
- return (List<ChangeInfo>) result;
+ protected void assertQuery(Object query, Change... changes)
+ throws Exception {
+ assertQuery(newQuery(query), changes);
}
- protected List<ChangeInfo> query(Object query) throws Exception {
+ protected void assertQuery(QueryRequest query, Change... changes)
+ throws Exception {
+ assertThat(query(query)).named(query.toString())
+ .containsExactlyElementsIn(ids(changes)).inOrder();
+ }
+
+ protected List<Integer> query(Object query) throws Exception {
return query(newQuery(query));
}
- protected ChangeInfo queryOne(Object query) throws Exception {
- List<ChangeInfo> results = query(query);
- assert_()
- .withFailureMessage(
- String.format(
- "expected singleton List<ChangeInfo>, found %s for [%s]",
- results, query)).that(results).hasSize(1);
- return results.get(0);
+ protected static List<Integer> query(QueryRequest query) throws Exception {
+ return FluentIterable.from(query.get())
+ .transform(new Function<ChangeInfo, Integer>() {
+ @Override
+ public Integer apply(ChangeInfo in) {
+ return in._number;
+ }
+ }).toList();
+ }
+
+ protected static Iterable<Integer> ids(Change... changes) {
+ return FluentIterable.from(Arrays.asList(changes)).transform(
+ new Function<Change, Integer>() {
+ @Override
+ public Integer apply(Change in) {
+ return in.getId().get();
+ }
+ });
}
protected static long lastUpdatedMs(Change c) {
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/query/change/ChangeDataTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/query/change/ChangeDataTest.java
new file mode 100644
index 0000000..ca1e2b1
--- /dev/null
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/query/change/ChangeDataTest.java
@@ -0,0 +1,42 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.query.change;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.testutil.TestChanges;
+
+import org.junit.Test;
+
+public class ChangeDataTest {
+ @Test
+ public void setPatchSetsClearsCurrentPatchSet() throws Exception {
+ ChangeData cd = ChangeData.createForTest(new Change.Id(1), 1);
+ cd.setChange(TestChanges.newChange(
+ new Project.NameKey("project"), new Account.Id(1000)));
+ PatchSet curr1 = cd.currentPatchSet();
+ int currId = curr1.getId().get();
+ PatchSet ps1 = new PatchSet(new PatchSet.Id(cd.getId(), currId + 1));
+ PatchSet ps2 = new PatchSet(new PatchSet.Id(cd.getId(), currId + 2));
+ cd.setPatchSets(ImmutableList.of(ps1, ps2));
+ PatchSet curr2 = cd.currentPatchSet();
+ assertThat(curr2).isNotSameAs(curr1);
+ }
+}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/query/change/LuceneQueryChangesTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/query/change/LuceneQueryChangesTest.java
index 742c230..6122d65 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/query/change/LuceneQueryChangesTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/query/change/LuceneQueryChangesTest.java
@@ -14,14 +14,12 @@
package com.google.gerrit.server.query.change;
-import static org.junit.Assert.assertTrue;
-
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.testutil.InMemoryModule;
+import com.google.gerrit.testutil.InMemoryRepositoryManager.Repo;
import com.google.inject.Guice;
import com.google.inject.Injector;
-import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.revwalk.RevCommit;
@@ -37,7 +35,7 @@
@Test
public void fullTextWithSpecialChars() throws Exception {
- TestRepository<InMemoryRepository> repo = createProject("repo");
+ TestRepository<Repo> repo = createProject("repo");
RevCommit commit1 =
repo.parseBody(repo.commit().message("foo_bar_foo").create());
Change change1 = newChange(repo, commit1, null, null, null).insert();
@@ -45,12 +43,12 @@
repo.parseBody(repo.commit().message("one.two.three").create());
Change change2 = newChange(repo, commit2, null, null, null).insert();
- assertTrue(query("message:foo_ba").isEmpty());
- assertResultEquals(change1, queryOne("message:bar"));
- assertResultEquals(change1, queryOne("message:foo_bar"));
- assertResultEquals(change1, queryOne("message:foo bar"));
- assertResultEquals(change2, queryOne("message:two"));
- assertResultEquals(change2, queryOne("message:one.two"));
- assertResultEquals(change2, queryOne("message:one two"));
+ assertQuery("message:foo_ba");
+ assertQuery("message:bar", change1);
+ assertQuery("message:foo_bar", change1);
+ assertQuery("message:foo bar", change1);
+ assertQuery("message:two", change2);
+ assertQuery("message:one.two", change2);
+ assertQuery("message:one two", change2);
}
}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/query/change/LuceneQueryChangesV14Test.java b/gerrit-server/src/test/java/com/google/gerrit/server/query/change/LuceneQueryChangesV14Test.java
new file mode 100644
index 0000000..0feb800
--- /dev/null
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/query/change/LuceneQueryChangesV14Test.java
@@ -0,0 +1,55 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.server.query.change;
+
+import com.google.gerrit.testutil.InMemoryModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+
+import org.eclipse.jgit.lib.Config;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class LuceneQueryChangesV14Test extends LuceneQueryChangesTest {
+ @Override
+ protected Injector createInjector() {
+ Config luceneConfig = new Config(config);
+ InMemoryModule.setDefaults(luceneConfig);
+ // Latest version with a Lucene 4 index.
+ luceneConfig.setInt("index", "lucene", "testVersion", 14);
+ return Guice.createInjector(new InMemoryModule(luceneConfig));
+ }
+
+ @Override
+ @Ignore
+ @Test
+ public void byCommentBy() {
+ // Ignore.
+ }
+
+ @Override
+ @Ignore
+ @Test
+ public void byFrom() {
+ // Ignore.
+ }
+
+ @Override
+ @Ignore
+ @Test
+ public void byTopic() {
+ // Ignore.
+ }
+}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaCreatorTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaCreatorTest.java
index 0c8157d..d4398cd 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaCreatorTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaCreatorTest.java
@@ -25,6 +25,7 @@
import com.google.gerrit.common.data.LabelType;
import com.google.gerrit.common.data.LabelTypes;
import com.google.gerrit.common.data.LabelValue;
+import com.google.gerrit.lifecycle.LifecycleManager;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.ProjectConfig;
@@ -56,13 +57,20 @@
@Inject
private InMemoryDatabase db;
+ private LifecycleManager lifecycle;
+
@Before
public void setUp() throws Exception {
+ lifecycle = new LifecycleManager();
new InMemoryModule().inject(this);
+ lifecycle.start();
}
@After
public void tearDown() throws Exception {
+ if (lifecycle != null) {
+ lifecycle.stop();
+ }
InMemoryDatabase.drop(db);
}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java
index 8686fe6..7412b3f 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java
@@ -16,6 +16,7 @@
import static org.junit.Assert.assertEquals;
+import com.google.gerrit.lifecycle.LifecycleManager;
import com.google.gerrit.reviewdb.client.SystemConfig;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.GerritPersonIdent;
@@ -43,22 +44,29 @@
import org.junit.Before;
import org.junit.Test;
-import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.List;
import java.util.UUID;
public class SchemaUpdaterTest {
+ private LifecycleManager lifecycle;
private InMemoryDatabase db;
@Before
public void setUp() throws Exception {
- db = InMemoryDatabase.newDatabase();
+ lifecycle = new LifecycleManager();
+ db = InMemoryDatabase.newDatabase(lifecycle);
+ lifecycle.start();
}
@After
public void tearDown() throws Exception {
+ if (lifecycle != null) {
+ lifecycle.stop();
+ }
InMemoryDatabase.drop(db);
}
@@ -67,7 +75,7 @@
IOException {
db.create();
- final File site = new File(UUID.randomUUID().toString());
+ final Path site = Paths.get(UUID.randomUUID().toString());
final SitePaths paths = new SitePaths(site);
SchemaUpdater u = Guice.createInjector(new FactoryModule() {
@Override
@@ -129,6 +137,6 @@
db.assertSchemaVersion();
final SystemConfig sc = db.getSystemConfig();
- assertEquals(paths.site_path.getCanonicalPath(), sc.sitePath);
+ assertEquals(paths.site_path.toAbsolutePath().toString(), sc.sitePath);
}
}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/util/SubmoduleSectionParserTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/util/SubmoduleSectionParserTest.java
index d87888f..bd672f3 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/util/SubmoduleSectionParserTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/util/SubmoduleSectionParserTest.java
@@ -14,16 +14,19 @@
package com.google.gerrit.server.util;
+import static org.easymock.EasyMock.createNiceMock;
import static org.easymock.EasyMock.createStrictMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertEquals;
+import com.google.common.collect.Sets;
import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.SubmoduleSubscription;
-import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.project.ProjectCache;
+import com.google.gerrit.server.project.ProjectState;
import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
import org.eclipse.jgit.lib.BlobBasedConfig;
@@ -32,17 +35,15 @@
import org.junit.Test;
import java.net.URI;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.TreeMap;
-import java.util.TreeSet;
public class SubmoduleSectionParserTest extends LocalDiskRepositoryTestCase {
private static final String THIS_SERVER = "localhost";
- private GitRepositoryManager repoManager;
+ private ProjectCache projectCache;
private BlobBasedConfig bbc;
@Override
@@ -50,16 +51,16 @@
public void setUp() throws Exception {
super.setUp();
- repoManager = createStrictMock(GitRepositoryManager.class);
+ projectCache = createStrictMock(ProjectCache.class);
bbc = createStrictMock(BlobBasedConfig.class);
}
private void doReplay() {
- replay(repoManager, bbc);
+ replay(projectCache, bbc);
}
private void doVerify() {
- verify(repoManager, bbc);
+ verify(projectCache, bbc);
}
@Test
@@ -87,7 +88,7 @@
new Branch.NameKey(new Project.NameKey("super-project"),
"refs/heads/master");
- List<SubmoduleSubscription> expectedSubscriptions = new ArrayList<>();
+ Set<SubmoduleSubscription> expectedSubscriptions = Sets.newHashSet();
expectedSubscriptions
.add(new SubmoduleSubscription(superBranchNameKey, new Branch.NameKey(
new Project.NameKey("a"), "refs/heads/master"), "a"));
@@ -134,7 +135,7 @@
new Branch.NameKey(new Project.NameKey("super-project"),
"refs/heads/master");
- List<SubmoduleSubscription> expectedSubscriptions = new ArrayList<>();
+ Set<SubmoduleSubscription> expectedSubscriptions = Sets.newHashSet();
expectedSubscriptions
.add(new SubmoduleSubscription(superBranchNameKey, new Branch.NameKey(
new Project.NameKey("a"), "refs/heads/master"), "a"));
@@ -159,9 +160,10 @@
sectionsToReturn.put("a", new SubmoduleSection("ssh://review.source.com/a",
"a", "."));
+ Set<SubmoduleSubscription> expectedSubscriptions = Collections.emptySet();
execute(new Branch.NameKey(new Project.NameKey("super-project"),
"refs/heads/master"), sectionsToReturn, new HashMap<String, String>(),
- new ArrayList<SubmoduleSubscription>());
+ expectedSubscriptions);
}
@Test
@@ -170,9 +172,10 @@
sectionsToReturn.put("a", new SubmoduleSection("ssh://localhost/a", "a",
"."));
+ Set<SubmoduleSubscription> expectedSubscriptions = Collections.emptySet();
execute(new Branch.NameKey(new Project.NameKey("super-project"),
"refs/heads/master"), sectionsToReturn, new HashMap<String, String>(),
- new ArrayList<SubmoduleSubscription>());
+ expectedSubscriptions);
}
@Test
@@ -181,15 +184,16 @@
sectionsToReturn.put("project", new SubmoduleSection(
"ssh://localhost/company/tools/project", "project", "."));
+ Set<SubmoduleSubscription> expectedSubscriptions = Collections.emptySet();
execute(new Branch.NameKey(new Project.NameKey("super-project"),
"refs/heads/master"), sectionsToReturn, new HashMap<String, String>(),
- new ArrayList<SubmoduleSubscription>());
+ expectedSubscriptions);
}
private void execute(final Branch.NameKey superProjectBranch,
final Map<String, SubmoduleSection> sectionsToReturn,
final Map<String, String> reposToBeFound,
- final List<SubmoduleSubscription> expectedSubscriptions) throws Exception {
+ final Set<SubmoduleSubscription> expectedSubscriptions) throws Exception {
expect(bbc.getSubsections("submodule"))
.andReturn(sectionsToReturn.keySet());
@@ -214,13 +218,12 @@
projectNameCandidate.length() - Constants.DOT_GIT_EXT.length());
}
if (projectNameCandidate.equals(reposToBeFound.get(id))) {
- expect(repoManager.list()).andReturn(
- new TreeSet<>(Collections.singletonList(
- new Project.NameKey(projectNameCandidate))));
+ expect(projectCache.get(new Project.NameKey(projectNameCandidate)))
+ .andReturn(createNiceMock(ProjectState.class));
break;
} else {
- expect(repoManager.list()).andReturn(
- new TreeSet<>(Collections.<Project.NameKey> emptyList()));
+ expect(projectCache.get(new Project.NameKey(projectNameCandidate)))
+ .andReturn(null);
}
}
}
@@ -229,10 +232,10 @@
doReplay();
final SubmoduleSectionParser ssp =
- new SubmoduleSectionParser(bbc, THIS_SERVER, superProjectBranch,
- repoManager);
+ new SubmoduleSectionParser(projectCache, bbc, THIS_SERVER,
+ superProjectBranch);
- List<SubmoduleSubscription> returnedSubscriptions = ssp.parseAllSections();
+ Set<SubmoduleSubscription> returnedSubscriptions = ssp.parseAllSections();
doVerify();
diff --git a/gerrit-server/src/test/java/com/google/gerrit/testutil/ConfigSuite.java b/gerrit-server/src/test/java/com/google/gerrit/testutil/ConfigSuite.java
index 707dd12..d769bcc 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/testutil/ConfigSuite.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/testutil/ConfigSuite.java
@@ -20,6 +20,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.google.common.base.MoreObjects;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import org.junit.runner.Runner;
@@ -28,6 +29,7 @@
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
+import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
@@ -78,6 +80,9 @@
*
* Additionally, config values used by <strong>default</strong> can be set
* in a method annotated with {@code @ConfigSuite.Default}.
+ * <p>
+ * The name of the config method corresponding to the currently-running test can
+ * be stored in a field annotated with {@code @ConfigSuite.Name}.
*/
public class ConfigSuite extends Suite {
private static final String DEFAULT = "default";
@@ -97,15 +102,22 @@
public static @interface Parameter {
}
+ @Target({FIELD})
+ @Retention(RUNTIME)
+ public static @interface Name {
+ }
+
private static class ConfigRunner extends BlockJUnit4ClassRunner {
private final Method configMethod;
private final Field parameterField;
+ private final Field nameField;
private final String name;
- private ConfigRunner(Class<?> clazz, Field parameterField, String name,
- Method configMethod) throws InitializationError {
+ private ConfigRunner(Class<?> clazz, Field parameterField, Field nameField,
+ String name, Method configMethod) throws InitializationError {
super(clazz);
this.parameterField = parameterField;
+ this.nameField = nameField;
this.name = name;
this.configMethod = configMethod;
}
@@ -114,6 +126,9 @@
public Object createTest() throws Exception {
Object test = getTestClass().getJavaClass().newInstance();
parameterField.set(test, callConfigMethod(configMethod));
+ if (nameField != null) {
+ nameField.set(test, name);
+ }
return test;
}
@@ -132,15 +147,23 @@
private static List<Runner> runnersFor(Class<?> clazz) {
Method defaultConfig = getDefaultConfig(clazz);
List<Method> configs = getConfigs(clazz);
- Field field = getParameterField(clazz);
+ Field parameterField = getOnlyField(clazz, Parameter.class);
+ checkArgument(parameterField != null, "No @ConfigSuite.Field found");
+ Field nameField = getOnlyField(clazz, Name.class);
List<Runner> result = Lists.newArrayListWithCapacity(configs.size() + 1);
try {
- result.add(new ConfigRunner(clazz, field, null, defaultConfig));
+ result.add(new ConfigRunner(
+ clazz, parameterField, nameField, null, defaultConfig));
for (Method m : configs) {
- result.add(new ConfigRunner(clazz, field, m.getName(), m));
+ result.add(new ConfigRunner(
+ clazz, parameterField, nameField, m.getName(), m));
}
return result;
} catch (InitializationError e) {
+ System.err.println("Errors initializing runners:");
+ for (Throwable t : e.getCauses()) {
+ t.printStackTrace();
+ }
throw new RuntimeException(e);
}
}
@@ -191,16 +214,18 @@
}
}
- private static Field getParameterField(Class<?> clazz) {
+ private static Field getOnlyField(Class<?> clazz,
+ Class<? extends Annotation> ann) {
List<Field> fields = Lists.newArrayListWithExpectedSize(1);
for (Field f : clazz.getFields()) {
- if (f.getAnnotation(Parameter.class) != null) {
+ if (f.getAnnotation(ann) != null) {
fields.add(f);
}
}
- checkArgument(fields.size() == 1,
- "expected 1 @ConfigSuite.Parameter field, found: %s", fields);
- return fields.get(0);
+ checkArgument(fields.size() <= 1,
+ "expected 1 @ConfigSuite.%s field, found: %s",
+ ann.getSimpleName(), fields);
+ return Iterables.getFirst(fields, null);
}
public ConfigSuite(Class<?> clazz) throws InitializationError {
diff --git a/gerrit-server/src/test/java/com/google/gerrit/testutil/FakeEmailSender.java b/gerrit-server/src/test/java/com/google/gerrit/testutil/FakeEmailSender.java
new file mode 100644
index 0000000..7adf721
--- /dev/null
+++ b/gerrit-server/src/test/java/com/google/gerrit/testutil/FakeEmailSender.java
@@ -0,0 +1,134 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.testutil;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.gerrit.common.errors.EmailException;
+import com.google.gerrit.server.git.WorkQueue;
+import com.google.gerrit.server.mail.Address;
+import com.google.gerrit.server.mail.EmailHeader;
+import com.google.gerrit.server.mail.EmailSender;
+import com.google.inject.AbstractModule;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * Email sender implementation that records messages in memory.
+ * <p>
+ * This class is mostly threadsafe. The only exception is that not all {@link
+ * EmailHeader} subclasses are immutable. In particular, if a caller holds a
+ * reference to an {@code AddressList} and mutates it after sending, the message
+ * returned by {@link #getMessages()} may or may not reflect mutations.
+ */
+@Singleton
+public class FakeEmailSender implements EmailSender {
+ private static final Logger log =
+ LoggerFactory.getLogger(FakeEmailSender.class);
+
+ public static class Module extends AbstractModule {
+ @Override
+ public void configure() {
+ bind(EmailSender.class).to(FakeEmailSender.class);
+ }
+ }
+
+ @AutoValue
+ public abstract static class Message {
+ private static Message create(Address from, Collection<Address> rcpt,
+ Map<String, EmailHeader> headers, String body) {
+ return new AutoValue_FakeEmailSender_Message(from,
+ ImmutableList.copyOf(rcpt), ImmutableMap.copyOf(headers), body);
+ }
+
+ public abstract Address from();
+ public abstract ImmutableList<Address> rcpt();
+ public abstract ImmutableMap<String, EmailHeader> headers();
+ public abstract String body();
+ }
+
+ private final WorkQueue workQueue;
+ private final List<Message> messages;
+
+ @Inject
+ FakeEmailSender(WorkQueue workQueue) {
+ this.workQueue = workQueue;
+ messages = Collections.synchronizedList(new ArrayList<Message>());
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return true;
+ }
+
+ @Override
+ public boolean canEmail(String address) {
+ return true;
+ }
+
+ @Override
+ public void send(Address from, Collection<Address> rcpt,
+ Map<String, EmailHeader> headers, String body) throws EmailException {
+ messages.add(Message.create(from, rcpt, headers, body));
+ }
+
+ public ImmutableList<Message> getMessages() {
+ waitForEmails();
+ synchronized (messages) {
+ return ImmutableList.copyOf(messages);
+ }
+ }
+
+ public ImmutableList<Message> getMessages(String changeId, String type) {
+ final String idFooter = "\nGerrit-Change-Id: " + changeId + "\n";
+ final String typeFooter = "\nGerrit-MessageType: " + type + "\n";
+ return FluentIterable.from(getMessages())
+ .filter(new Predicate<Message>() {
+ @Override
+ public boolean apply(Message in) {
+ return in.body().contains(idFooter)
+ && in.body().contains(typeFooter);
+ }
+ }).toList();
+ }
+
+ private void waitForEmails() {
+ // TODO(dborowitz): This is brittle; consider forcing emails to use
+ // a single thread in tests (tricky because most callers just use the
+ // default executor).
+ for (WorkQueue.Task<?> task : workQueue.getTasks()) {
+ if (task.toString().contains("send-email")) {
+ try {
+ task.get();
+ } catch (ExecutionException | InterruptedException e) {
+ log.warn("error finishing email task", e);
+ }
+ }
+ }
+ }
+}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryDatabase.java b/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryDatabase.java
index 49fcc96..1f5b6cd 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryDatabase.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryDatabase.java
@@ -16,6 +16,7 @@
import static org.junit.Assert.assertEquals;
+import com.google.gerrit.lifecycle.LifecycleManager;
import com.google.gerrit.reviewdb.client.CurrentSchemaVersion;
import com.google.gerrit.reviewdb.client.SystemConfig;
import com.google.gerrit.reviewdb.server.ReviewDb;
@@ -27,6 +28,7 @@
import com.google.gwtorm.server.SchemaFactory;
import com.google.inject.Guice;
import com.google.inject.Inject;
+import com.google.inject.Injector;
import org.eclipse.jgit.errors.ConfigInvalidException;
@@ -46,9 +48,10 @@
* the JVM running the unit tests doesn't run out of heap space.
*/
public class InMemoryDatabase implements SchemaFactory<ReviewDb> {
- public static InMemoryDatabase newDatabase() {
- return Guice.createInjector(new InMemoryModule())
- .getInstance(InMemoryDatabase.class);
+ public static InMemoryDatabase newDatabase(LifecycleManager lifecycle) {
+ Injector injector = Guice.createInjector(new InMemoryModule());
+ lifecycle.add(injector);
+ return injector.getInstance(InMemoryDatabase.class);
}
private static int dbCnt;
diff --git a/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryModule.java b/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryModule.java
index 76af6f1..2219d28 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryModule.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryModule.java
@@ -17,7 +17,6 @@
import static com.google.common.base.Preconditions.checkState;
import static com.google.inject.Scopes.SINGLETON;
-import com.google.common.net.InetAddresses;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.gerrit.common.ChangeHooks;
import com.google.gerrit.common.DisabledChangeHooks;
@@ -25,7 +24,6 @@
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.GerritPersonIdentProvider;
-import com.google.gerrit.server.RemotePeer;
import com.google.gerrit.server.cache.h2.DefaultCacheFactory;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.AllProjectsNameProvider;
@@ -46,11 +44,9 @@
import com.google.gerrit.server.git.GarbageCollection;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.PerThreadRequestScope;
-import com.google.gerrit.server.git.WorkQueue;
import com.google.gerrit.server.index.ChangeSchemas;
import com.google.gerrit.server.index.IndexModule.IndexType;
import com.google.gerrit.server.mail.SignedTokenEmailTokenVerifier;
-import com.google.gerrit.server.mail.SmtpEmailSender;
import com.google.gerrit.server.patch.DiffExecutor;
import com.google.gerrit.server.schema.DataSourceType;
import com.google.gerrit.server.schema.SchemaCreator;
@@ -73,11 +69,10 @@
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.PersonIdent;
-import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.concurrent.ExecutorService;
public class InMemoryModule extends FactoryModule {
@@ -93,12 +88,12 @@
cfg.setString("gerrit", null, "allProjects", "Test-Projects");
cfg.setString("user", null, "name", "Gerrit Code Review");
cfg.setString("user", null, "email", "gerrit@localhost");
- cfg.setBoolean("sendemail", null, "enable", false);
cfg.setString("cache", null, "directory", null);
cfg.setString("index", null, "type", "lucene");
cfg.setBoolean("index", "lucene", "testInmemory", true);
cfg.setInt("index", "lucene", "testVersion",
ChangeSchemas.getLatest().getVersion());
+ cfg.setInt("sendemail", null, "threadPoolSize", 0);
}
private final Config cfg;
@@ -117,6 +112,13 @@
@Override
protected void configure() {
+ // Do NOT bind @RemotePeer, as it is bound in a child injector of
+ // ChangeMergeQueue (bound via GerritGlobalModule below), so there cannot be
+ // a binding in the parent injector. If you need @RemotePeer, you must bind
+ // it in a child injector of the one containing InMemoryModule. But unless
+ // you really need to test something request-scoped, you likely don't
+ // actually need it.
+
// For simplicity, don't create child injectors, just use this one to get a
// few required modules.
Injector cfgInjector = Guice.createInjector(new AbstractModule() {
@@ -132,10 +134,9 @@
bindScope(RequestScoped.class, PerThreadRequestScope.REQUEST);
- bind(File.class).annotatedWith(SitePath.class).toInstance(new File("."));
+ // TODO(dborowitz): Use jimfs.
+ bind(Path.class).annotatedWith(SitePath.class).toInstance(Paths.get("."));
bind(Config.class).annotatedWith(GerritServerConfig.class).toInstance(cfg);
- bind(SocketAddress.class).annotatedWith(RemotePeer.class).toInstance(
- new InetSocketAddress(InetAddresses.forString("127.0.0.1"), 1234));
bind(PersonIdent.class)
.annotatedWith(GerritPersonIdent.class)
.toProvider(GerritPersonIdentProvider.class);
@@ -180,7 +181,7 @@
}
});
install(new DefaultCacheFactory.Module());
- install(new SmtpEmailSender.Module());
+ install(new FakeEmailSender.Module());
install(new SignedTokenEmailTokenVerifier.Module());
IndexType indexType = null;
@@ -204,10 +205,8 @@
@Provides
@Singleton
@EmailReviewCommentsExecutor
- public WorkQueue.Executor createEmailReviewCommentsExecutor(
- @GerritServerConfig Config config, WorkQueue queues) {
- int poolSize = config.getInt("sendemail", null, "threadPoolSize", 1);
- return queues.createQueue(poolSize, "EmailReviewComments");
+ public ExecutorService createEmailReviewCommentsExecutor() {
+ return MoreExecutors.newDirectExecutorService();
}
@Provides
diff --git a/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryRepositoryManager.java b/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryRepositoryManager.java
index 0635464..ec53b29 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryRepositoryManager.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryRepositoryManager.java
@@ -35,16 +35,22 @@
return new Repo(name);
}
- private static class Description extends DfsRepositoryDescription {
+ public static class Description extends DfsRepositoryDescription {
+ private final Project.NameKey name;
private String desc;
private Description(Project.NameKey name) {
super(name.get());
+ this.name = name;
desc = "In-memory repository " + name.get();
}
+
+ public Project.NameKey getProject() {
+ return name;
+ }
}
- private static class Repo extends InMemoryRepository {
+ public static class Repo extends InMemoryRepository {
private Repo(Project.NameKey name) {
super(new Description(name));
}
@@ -58,13 +64,13 @@
private Map<String, Repo> repos = Maps.newHashMap();
@Override
- public InMemoryRepository openRepository(Project.NameKey name)
+ public synchronized Repo openRepository(Project.NameKey name)
throws RepositoryNotFoundException {
return get(name);
}
@Override
- public InMemoryRepository createRepository(Project.NameKey name)
+ public synchronized Repo createRepository(Project.NameKey name)
throws RepositoryCaseMismatchException, RepositoryNotFoundException {
Repo repo;
try {
@@ -80,13 +86,13 @@
}
@Override
- public InMemoryRepository openMetadataRepository(Project.NameKey name)
- throws RepositoryNotFoundException {
+ public synchronized Repo openMetadataRepository(
+ Project.NameKey name) throws RepositoryNotFoundException {
return openRepository(name);
}
@Override
- public SortedSet<Project.NameKey> list() {
+ public synchronized SortedSet<Project.NameKey> list() {
SortedSet<Project.NameKey> names = Sets.newTreeSet();
for (DfsRepository repo : repos.values()) {
names.add(new Project.NameKey(repo.getDescription().getRepositoryName()));
@@ -95,13 +101,14 @@
}
@Override
- public String getProjectDescription(Project.NameKey name)
+ public synchronized String getProjectDescription(Project.NameKey name)
throws RepositoryNotFoundException {
return get(name).getDescription().desc;
}
@Override
- public void setProjectDescription(Project.NameKey name, String description) {
+ public synchronized void setProjectDescription(Project.NameKey name,
+ String description) {
try {
get(name).getDescription().desc = description;
} catch (RepositoryNotFoundException e) {
@@ -109,7 +116,8 @@
}
}
- private Repo get(Project.NameKey name) throws RepositoryNotFoundException {
+ private synchronized Repo get(Project.NameKey name)
+ throws RepositoryNotFoundException {
Repo repo = repos.get(name.get().toLowerCase());
if (repo != null) {
return repo;
diff --git a/gerrit-solr/src/main/java/com/google/gerrit/solr/IndexVersionCheck.java b/gerrit-solr/src/main/java/com/google/gerrit/solr/IndexVersionCheck.java
index ddb86c3..0faa691 100644
--- a/gerrit-solr/src/main/java/com/google/gerrit/solr/IndexVersionCheck.java
+++ b/gerrit-solr/src/main/java/com/google/gerrit/solr/IndexVersionCheck.java
@@ -25,8 +25,8 @@
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.util.FS;
-import java.io.File;
import java.io.IOException;
+import java.nio.file.Path;
import java.util.Map;
class IndexVersionCheck implements LifecycleListener {
@@ -34,8 +34,8 @@
SolrChangeIndex.CHANGES_OPEN, ChangeSchemas.getLatest().getVersion(),
SolrChangeIndex.CHANGES_CLOSED, ChangeSchemas.getLatest().getVersion());
- public static File solrIndexConfig(SitePaths sitePaths) {
- return new File(sitePaths.index_dir, "gerrit_index.config");
+ public static Path solrIndexConfig(SitePaths sitePaths) {
+ return sitePaths.index_dir.resolve("gerrit_index.config");
}
private final SitePaths sitePaths;
@@ -48,9 +48,9 @@
@Override
public void start() {
// TODO Query schema version from a special meta-document
- File file = solrIndexConfig(sitePaths);
+ Path path = solrIndexConfig(sitePaths);
try {
- FileBasedConfig cfg = new FileBasedConfig(file, FS.detect());
+ FileBasedConfig cfg = new FileBasedConfig(path.toFile(), FS.detect());
cfg.load();
for (Map.Entry<String, Integer> e : SCHEMA_VERSIONS.entrySet()) {
int schemaVersion = cfg.getInt("index", e.getKey(), "schemaVersion", 0);
@@ -61,9 +61,9 @@
}
}
} catch (IOException e) {
- throw new ProvisionException("unable to read " + file);
+ throw new ProvisionException("unable to read " + path);
} catch (ConfigInvalidException e) {
- throw new ProvisionException("invalid config file " + file);
+ throw new ProvisionException("invalid config file " + path);
}
}
@@ -75,6 +75,6 @@
private final String upgrade() {
return "\nRun reindex to rebuild the index:\n"
+ "$ java -jar gerrit.war reindex -d "
- + sitePaths.site_path.getAbsolutePath();
+ + sitePaths.site_path.toAbsolutePath();
}
}
diff --git a/gerrit-solr/src/main/java/com/google/gerrit/solr/SolrChangeIndex.java b/gerrit-solr/src/main/java/com/google/gerrit/solr/SolrChangeIndex.java
index 78f5265..b9e47954 100644
--- a/gerrit-solr/src/main/java/com/google/gerrit/solr/SolrChangeIndex.java
+++ b/gerrit-solr/src/main/java/com/google/gerrit/solr/SolrChangeIndex.java
@@ -319,7 +319,7 @@
doc.addField(name, value);
}
} else {
- throw QueryBuilder.badFieldType(type);
+ throw FieldType.badFieldType(type);
}
}
@@ -327,7 +327,7 @@
public void markReady(boolean ready) throws IOException {
// TODO Move the schema version information to a special meta-document
FileBasedConfig cfg = new FileBasedConfig(
- solrIndexConfig(sitePaths),
+ solrIndexConfig(sitePaths).toFile(),
FS.detect());
for (Map.Entry<String, Integer> e : SCHEMA_VERSIONS.entrySet()) {
cfg.setInt("index", e.getKey(), "schemaVersion",
diff --git a/gerrit-solr/src/main/java/com/google/gerrit/solr/SolrIndexModule.java b/gerrit-solr/src/main/java/com/google/gerrit/solr/SolrIndexModule.java
index 38de6ee..0133e33 100644
--- a/gerrit-solr/src/main/java/com/google/gerrit/solr/SolrIndexModule.java
+++ b/gerrit-solr/src/main/java/com/google/gerrit/solr/SolrIndexModule.java
@@ -50,7 +50,6 @@
@Override
protected void configure() {
- bind(IndexConfig.class).toInstance(IndexConfig.createDefault());
install(new IndexModule(threads));
bind(ChangeIndex.class).to(SolrChangeIndex.class);
listener().to(SolrChangeIndex.class);
@@ -61,6 +60,12 @@
@Provides
@Singleton
+ IndexConfig getIndexConfig(@GerritServerConfig Config cfg) {
+ return IndexConfig.fromConfig(cfg);
+ }
+
+ @Provides
+ @Singleton
public SolrChangeIndex getChangeIndex(@GerritServerConfig Config cfg,
Provider<ReviewDb> db,
ChangeData.Factory changeDataFactory,
diff --git a/gerrit-sshd/BUCK b/gerrit-sshd/BUCK
index 4774cb3..7bee47e 100644
--- a/gerrit-sshd/BUCK
+++ b/gerrit-sshd/BUCK
@@ -28,6 +28,7 @@
'//lib/mina:core',
'//lib/mina:sshd',
'//lib/jgit:jgit',
+ '//lib/jgit:jgit-archive',
],
provided_deps = [
'//lib/bouncycastle:bcprov',
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java
index c0fd2ac..c38394a 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java
@@ -338,8 +338,7 @@
return 127;
}
- if (e instanceof UnloggedFailure) {
- } else {
+ if (!(e instanceof UnloggedFailure)) {
final StringBuilder m = new StringBuilder();
m.append("Internal server error");
if (userProvider.get().isIdentifiedUser()) {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandFactoryProvider.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandFactoryProvider.java
index 56441fba..6bd9c4c 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandFactoryProvider.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandFactoryProvider.java
@@ -263,30 +263,33 @@
switch (b) {
case '\t':
case ' ':
- if (inquote || inDblQuote)
+ if (inquote || inDblQuote) {
r.append(b);
- else if (r.length() > 0) {
+ } else if (r.length() > 0) {
list.add(r.toString());
r = new StringBuilder();
}
continue;
case '\"':
- if (inquote)
+ if (inquote) {
r.append(b);
- else
+ } else {
inDblQuote = !inDblQuote;
+ }
continue;
case '\'':
- if (inDblQuote)
+ if (inDblQuote) {
r.append(b);
- else
+ } else {
inquote = !inquote;
+ }
continue;
case '\\':
- if (inquote || ip == commandLine.length())
+ if (inquote || ip == commandLine.length()) {
r.append(b); // literal within a quote
- else
+ } else {
r.append(commandLine.charAt(ip++));
+ }
continue;
default:
r.append(b);
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DatabasePubKeyAuth.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DatabasePubKeyAuth.java
index cc7b637..e453a4b 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DatabasePubKeyAuth.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DatabasePubKeyAuth.java
@@ -14,7 +14,10 @@
package com.google.gerrit.sshd;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
import com.google.common.base.Preconditions;
+import com.google.gerrit.common.FileUtil;
import com.google.gerrit.reviewdb.client.AccountSshKey;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.PeerDaemonUser;
@@ -33,10 +36,10 @@
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
import java.security.KeyPair;
import java.security.PublicKey;
import java.util.Collection;
@@ -65,7 +68,7 @@
DatabasePubKeyAuth(final SshKeyCacheImpl skc, final SshLog l,
final IdentifiedUser.GenericFactory uf, final PeerDaemonUser.Factory pf,
final SitePaths site, final KeyPairProvider hostKeyProvider,
- final @GerritServerConfig Config cfg, final SshScope s) {
+ @GerritServerConfig final Config cfg, final SshScope s) {
sshKeyCache = skc;
sshLog = l;
userFactory = uf;
@@ -169,56 +172,50 @@
}
private static class PeerKeyCache {
- private final File path;
+ private final Path path;
private final long modified;
final Set<PublicKey> keys;
- PeerKeyCache(final File path) {
+ PeerKeyCache(Path path) {
this.path = path;
- this.modified = path.lastModified();
+ this.modified = FileUtil.lastModified(path);
this.keys = read(path);
}
- private static Set<PublicKey> read(File path) {
- try {
- final BufferedReader br = new BufferedReader(new FileReader(path));
- try {
- final Set<PublicKey> keys = new HashSet<>();
- String line;
- while ((line = br.readLine()) != null) {
- line = line.trim();
- if (line.startsWith("#") || line.isEmpty()) {
- continue;
- }
-
- try {
- byte[] bin = Base64.decodeBase64(line.getBytes("ISO-8859-1"));
- keys.add(new Buffer(bin).getRawPublicKey());
- } catch (RuntimeException e) {
- logBadKey(path, line, e);
- } catch (SshException e) {
- logBadKey(path, line, e);
- }
+ private static Set<PublicKey> read(Path path) {
+ try (BufferedReader br = Files.newBufferedReader(path, UTF_8)) {
+ final Set<PublicKey> keys = new HashSet<>();
+ String line;
+ while ((line = br.readLine()) != null) {
+ line = line.trim();
+ if (line.startsWith("#") || line.isEmpty()) {
+ continue;
}
- return Collections.unmodifiableSet(keys);
- } finally {
- br.close();
- }
- } catch (FileNotFoundException noFile) {
- return Collections.emptySet();
+ try {
+ byte[] bin = Base64.decodeBase64(line.getBytes("ISO-8859-1"));
+ keys.add(new Buffer(bin).getRawPublicKey());
+ } catch (RuntimeException e) {
+ logBadKey(path, line, e);
+ } catch (SshException e) {
+ logBadKey(path, line, e);
+ }
+ }
+ return Collections.unmodifiableSet(keys);
+ } catch (NoSuchFileException noFile) {
+ return Collections.emptySet();
} catch (IOException err) {
log.error("Cannot read " + path, err);
return Collections.emptySet();
}
}
- private static void logBadKey(File path, String line, Exception e) {
+ private static void logBadKey(Path path, String line, Exception e) {
log.warn("Invalid key in " + path + ":\n " + line, e);
}
boolean isCurrent() {
- return path.lastModified() == modified;
+ return modified == FileUtil.lastModified(path);
}
PeerKeyCache reload() {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DispatchCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DispatchCommand.java
index a7748ff..09222b7 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DispatchCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DispatchCommand.java
@@ -88,10 +88,11 @@
checkRequiresCapability(cmd);
if (cmd instanceof BaseCommand) {
final BaseCommand bc = (BaseCommand) cmd;
- if (getName().isEmpty())
+ if (getName().isEmpty()) {
bc.setName(commandName);
- else
+ } else {
bc.setName(getName() + " " + commandName);
+ }
bc.setArguments(args.toArray(new String[args.size()]));
} else if (!args.isEmpty()) {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/HostKeyProvider.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/HostKeyProvider.java
index 241f853..3e6e2f5 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/HostKeyProvider.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/HostKeyProvider.java
@@ -24,7 +24,8 @@
import org.apache.sshd.common.util.SecurityUtils;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
-import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
@@ -38,29 +39,29 @@
@Override
public KeyPairProvider get() {
- final File objKey = site.ssh_key;
- final File rsaKey = site.ssh_rsa;
- final File dsaKey = site.ssh_dsa;
+ Path objKey = site.ssh_key;
+ Path rsaKey = site.ssh_rsa;
+ Path dsaKey = site.ssh_dsa;
final List<String> stdKeys = new ArrayList<>(2);
- if (rsaKey.exists()) {
- stdKeys.add(rsaKey.getAbsolutePath());
+ if (Files.exists(rsaKey)) {
+ stdKeys.add(rsaKey.toAbsolutePath().toString());
}
- if (dsaKey.exists()) {
- stdKeys.add(dsaKey.getAbsolutePath());
+ if (Files.exists(dsaKey)) {
+ stdKeys.add(dsaKey.toAbsolutePath().toString());
}
- if (objKey.exists()) {
+ if (Files.exists(objKey)) {
if (stdKeys.isEmpty()) {
SimpleGeneratorHostKeyProvider p = new SimpleGeneratorHostKeyProvider();
- p.setPath(objKey.getAbsolutePath());
+ p.setPath(objKey.toAbsolutePath().toString());
return p;
} else {
// Both formats of host key exist, we don't know which format
// should be authoritative. Complain and abort.
//
- stdKeys.add(objKey.getAbsolutePath());
+ stdKeys.add(objKey.toAbsolutePath().toString());
throw new ProvisionException("Multiple host keys exist: " + stdKeys);
}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java
index 39eb720..33ffb47 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java
@@ -135,12 +135,14 @@
* <p>
* Versions of Git before 1.5.3 may require setting the username and port
* properties in the user's {@code ~/.ssh/config} file, and using a host
- * alias through a URL such as <code>gerrit-alias:/tools/gerrit.git:
+ * alias through a URL such as {@code gerrit-alias:/tools/gerrit.git}:
* <pre>
+ * {@code
* Host gerrit-alias
* User sop@google.com
* Hostname gerrit.com
* Port 8010
+ * }
* </pre>
*/
@Singleton
@@ -443,7 +445,8 @@
if ((n & -n) == n) {
return (int)((n * (long) next(31)) >> 31);
}
- int bits, val;
+ int bits;
+ int val;
do {
bits = next(31);
val = bits % n;
@@ -453,9 +456,9 @@
throw new IllegalArgumentException();
}
- final protected int next(int numBits) {
+ protected final int next(int numBits) {
int bytes = (numBits+7)/8;
- byte next[] = new byte[bytes];
+ byte[] next = new byte[bytes];
int ret = 0;
random.nextBytes(next);
for (int i = 0; i < bytes; i++) {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshLog.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshLog.java
index 439b8c8..4d6a790 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshLog.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshLog.java
@@ -220,7 +220,8 @@
event.setProperty(P_SESSION, id(sd.getSessionId()));
- String userName = "-", accountId = "-";
+ String userName = "-";
+ String accountId = "-";
if (user != null && user.isIdentifiedUser()) {
IdentifiedUser u = (IdentifiedUser) user;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateBranchCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateBranchCommand.java
index 55f6158..b1d09e9 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateBranchCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateBranchCommand.java
@@ -26,7 +26,7 @@
/** Create a new branch. **/
@CommandMetaData(name = "create-branch", description = "Create a new branch")
-final public class CreateBranchCommand extends SshCommand {
+public final class CreateBranchCommand extends SshCommand {
@Argument(index = 0, required = true, metaVar = "PROJECT", usage = "name of the project")
private ProjectControl project;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateGroupCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateGroupCommand.java
index 75194dc..155c2eb 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateGroupCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateGroupCommand.java
@@ -14,17 +14,22 @@
package com.google.gerrit.sshd.commands;
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
import com.google.gerrit.common.data.GlobalCapability;
-import com.google.gerrit.common.errors.NameAlreadyUsedException;
-import com.google.gerrit.common.errors.PermissionDeniedException;
import com.google.gerrit.extensions.annotations.RequiresCapability;
-import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.extensions.api.groups.GroupInput;
+import com.google.gerrit.extensions.common.GroupInfo;
+import com.google.gerrit.extensions.restapi.IdString;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.extensions.restapi.TopLevelResource;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gerrit.server.account.CreateGroupArgs;
-import com.google.gerrit.server.account.PerformCreateGroup;
-import com.google.gerrit.server.validators.GroupCreationValidationListener;
-import com.google.gerrit.server.validators.ValidationException;
+import com.google.gerrit.server.group.AddIncludedGroups;
+import com.google.gerrit.server.group.AddMembers;
+import com.google.gerrit.server.group.CreateGroup;
+import com.google.gerrit.server.group.GroupResource;
+import com.google.gerrit.server.group.GroupsCollection;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.gwtorm.server.OrmException;
@@ -71,36 +76,75 @@
}
@Inject
- private PerformCreateGroup.Factory performCreateGroupFactory;
+ private CreateGroup.Factory createGroupFactory;
@Inject
- private DynamicSet<GroupCreationValidationListener> groupCreationValidationListeners;
+ private GroupsCollection groups;
+
+ @Inject
+ private AddMembers addMembers;
+
+ @Inject
+ private AddIncludedGroups addIncludedGroups;
@Override
protected void run() throws Failure, OrmException {
try {
- CreateGroupArgs args = new CreateGroupArgs();
- args.setGroupName(groupName);
- args.groupDescription = groupDescription;
- args.visibleToAll = visibleToAll;
- args.ownerGroupId = ownerGroupId;
- args.initialMembers = initialMembers;
- args.initialGroups = initialGroups;
+ GroupResource rsrc = createGroup();
- for (GroupCreationValidationListener l : groupCreationValidationListeners) {
- try {
- l.validateNewGroup(args);
- } catch (ValidationException e) {
- die(e);
- }
+ if (!initialMembers.isEmpty()) {
+ addMembers(rsrc);
}
- performCreateGroupFactory.create(args).createGroup();
- } catch (PermissionDeniedException e) {
- throw die(e);
-
- } catch (NameAlreadyUsedException e) {
+ if (!initialGroups.isEmpty()) {
+ addIncludedGroups(rsrc);
+ }
+ } catch (RestApiException e) {
throw die(e);
}
}
+
+ private GroupResource createGroup() throws RestApiException, OrmException {
+ GroupInput input = new GroupInput();
+ input.description = groupDescription;
+ input.visibleToAll = visibleToAll;
+
+ if (ownerGroupId != null) {
+ input.ownerId = String.valueOf(ownerGroupId.get());
+ }
+
+ GroupInfo group = createGroupFactory.create(groupName)
+ .apply(TopLevelResource.INSTANCE, input);
+ return groups.parse(TopLevelResource.INSTANCE,
+ IdString.fromUrl(group.id));
+ }
+
+ private void addMembers(GroupResource rsrc) throws RestApiException,
+ OrmException {
+ AddMembers.Input input =
+ AddMembers.Input.fromMembers(FluentIterable
+ .from(initialMembers)
+ .transform(new Function<Account.Id, String>() {
+ @Override
+ public String apply(Account.Id id) {
+ return String.valueOf(id.get());
+ }
+ })
+ .toList());
+ addMembers.apply(rsrc, input);
+ }
+
+ private void addIncludedGroups(GroupResource rsrc) throws RestApiException,
+ OrmException {
+ AddIncludedGroups.Input input =
+ AddIncludedGroups.Input.fromGroups(FluentIterable.from(initialGroups)
+ .transform(new Function<AccountGroup.UUID, String>() {
+ @Override
+ public String apply(AccountGroup.UUID id) {
+ return id.get();
+ }
+ }).toList());
+
+ addIncludedGroups.apply(rsrc, input);
+ }
}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateProjectCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateProjectCommand.java
index 4e151b3..7dc558e 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateProjectCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateProjectCommand.java
@@ -109,7 +109,8 @@
requireChangeID = InheritableBoolean.TRUE;
}
- @Option(name = "--create-new-change-for-all-not-in-target", aliases = {"--ncfa"}, usage = "if a new change will be created for every commit not in target branch")
+ @Option(name = "--create-new-change-for-all-not-in-target", aliases = {"--ncfa"},
+ usage = "if a new change will be created for every commit not in target branch")
void setNewChangeForAllNotInTarget(@SuppressWarnings("unused") boolean on) {
createNewChangeForAllNotInTarget = InheritableBoolean.TRUE;
}
@@ -124,7 +125,8 @@
@Option(name = "--max-object-size-limit", usage = "max Git object size for this project")
private String maxObjectSizeLimit;
- @Option(name = "--plugin-config", usage = "plugin configuration parameter with format '<plugin-name>.<parameter-name>=<value>'")
+ @Option(name = "--plugin-config",
+ usage = "plugin configuration parameter with format '<plugin-name>.<parameter-name>=<value>'")
private List<String> pluginConfigValues;
private String projectName;
@@ -181,7 +183,7 @@
input.pluginConfigValues = parsePluginConfigValues(pluginConfigValues);
}
- gApi.projects().name(projectName).create(input);
+ gApi.projects().create(input);
} else {
List<Project.NameKey> parentCandidates =
suggestParentCandidates.getNameKeys();
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/DefaultCommandModule.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/DefaultCommandModule.java
index f75eb2b..2d071c7 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/DefaultCommandModule.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/DefaultCommandModule.java
@@ -70,15 +70,23 @@
// Honor the legacy hyphenated forms as aliases for the non-hyphenated forms
command("git-upload-pack").to(Commands.key(git, "upload-pack"));
command(git, "upload-pack").to(Upload.class);
+ command("git-upload-archive").to(Commands.key(git, "upload-archive"));
+ command(git, "upload-archive").to(UploadArchive.class);
command("suexec").to(SuExec.class);
listener().to(ShowCaches.StartupListener.class);
- // The following commands can only be ran on a server in Master mode
+ // The following commands can only be run on a server in Master mode
command(gerrit, CreateAccountCommand.class);
command(gerrit, CreateGroupCommand.class);
command(gerrit, CreateProjectCommand.class);
+ command(gerrit, SetHeadCommand.class);
command(gerrit, AdminQueryShell.class);
- if (!slaveMode) {
+ if (slaveMode) {
+ command("git-receive-pack").to(NotSupportedInSlaveModeFailureCommand.class);
+ command("gerrit-receive-pack").to(NotSupportedInSlaveModeFailureCommand.class);
+ command(git, "receive-pack").to(NotSupportedInSlaveModeFailureCommand.class);
+ command(gerrit, "test-submit").to(NotSupportedInSlaveModeFailureCommand.class);
+ } else {
command("git-receive-pack").to(Commands.key(git, "receive-pack"));
command("gerrit-receive-pack").to(Commands.key(git, "receive-pack"));
command(git, "receive-pack").to(Commands.key(gerrit, "receive-pack"));
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/GarbageCollectionCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/GarbageCollectionCommand.java
index c533f4f..d02fb4c 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/GarbageCollectionCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/GarbageCollectionCommand.java
@@ -46,6 +46,9 @@
@Option(name = "--show-progress", usage = "progress information is shown")
private boolean showProgress;
+ @Option(name = "--aggressive", usage = "run aggressive garbage collection")
+ private boolean aggressive;
+
@Argument(index = 0, required = false, multiValued = true, metaVar = "NAME",
usage = "projects for which the Git garbage collection should be run")
private List<ProjectControl> projects = new ArrayList<>();
@@ -85,7 +88,8 @@
}
GarbageCollectionResult result =
- garbageCollectionFactory.create().run(projectNames, showProgress ? stdout : null);
+ garbageCollectionFactory.create().run(projectNames, aggressive,
+ showProgress ? stdout : null);
if (result.hasErrors()) {
for (GarbageCollectionResult.Error e : result.getErrors()) {
String msg;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListGroupsCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListGroupsCommand.java
index 82ad16f..ad72b13 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListGroupsCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListGroupsCommand.java
@@ -18,6 +18,7 @@
import com.google.common.base.MoreObjects;
import com.google.common.base.Strings;
+import com.google.gerrit.extensions.common.GroupInfo;
import com.google.gerrit.extensions.restapi.Url;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.IdentifiedUser;
@@ -25,7 +26,6 @@
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.account.GroupControl;
import com.google.gerrit.server.group.GroupJson;
-import com.google.gerrit.server.group.GroupJson.GroupInfo;
import com.google.gerrit.server.group.ListGroups;
import com.google.gerrit.server.ioutil.ColumnFormatter;
import com.google.gerrit.sshd.CommandMetaData;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/LsUserRefs.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/LsUserRefs.java
index c41fcdc..15e030f 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/LsUserRefs.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/LsUserRefs.java
@@ -20,7 +20,7 @@
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.AccountResolver;
@@ -110,7 +110,7 @@
db, true).filter(repo.getRefDatabase().getRefs(ALL), false);
for (final String ref : refsMap.keySet()) {
- if (!onlyRefsHeads || ref.startsWith(Branch.R_HEADS)) {
+ if (!onlyRefsHeads || ref.startsWith(RefNames.REFS_HEADS)) {
stdout.println(ref);
}
}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/NotSupportedInSlaveModeFailureCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/NotSupportedInSlaveModeFailureCommand.java
new file mode 100644
index 0000000..39e6d4a
--- /dev/null
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/NotSupportedInSlaveModeFailureCommand.java
@@ -0,0 +1,25 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.sshd.commands;
+
+import com.google.gerrit.sshd.SshCommand;
+
+/* Failure command, that produces verbose failure message in slave mode */
+public class NotSupportedInSlaveModeFailureCommand extends SshCommand {
+ @Override
+ protected void run() throws UnloggedFailure {
+ throw die(getName() + ": is not supported in slave mode");
+ }
+}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/QueryShell.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/QueryShell.java
index 8f26bba..6a71176 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/QueryShell.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/QueryShell.java
@@ -758,7 +758,9 @@
r.append(" (");
boolean first = true;
for (String c : columns.values()) {
- if (!first) r.append(", ");
+ if (!first) {
+ r.append(", ");
+ }
r.append(c);
first = false;
}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/RenameGroupCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/RenameGroupCommand.java
index 38535a4..c8ebb6c 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/RenameGroupCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/RenameGroupCommand.java
@@ -14,10 +14,13 @@
package com.google.gerrit.sshd.commands;
-import com.google.gerrit.common.errors.InvalidNameException;
-import com.google.gerrit.common.errors.NameAlreadyUsedException;
import com.google.gerrit.common.errors.NoSuchGroupException;
-import com.google.gerrit.server.account.PerformRenameGroup;
+import com.google.gerrit.extensions.restapi.IdString;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.extensions.restapi.TopLevelResource;
+import com.google.gerrit.server.group.GroupResource;
+import com.google.gerrit.server.group.GroupsCollection;
+import com.google.gerrit.server.group.PutName;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.gwtorm.server.OrmException;
@@ -34,19 +37,20 @@
private String newGroupName;
@Inject
- private PerformRenameGroup.Factory performRenameGroupFactory;
+ private GroupsCollection groups;
+
+ @Inject
+ private PutName putName;
@Override
protected void run() throws Failure {
try {
- performRenameGroupFactory.create().renameGroup(groupName, newGroupName);
- } catch (OrmException e) {
- throw die(e);
- } catch (InvalidNameException e) {
- throw die(e);
- } catch (NameAlreadyUsedException e) {
- throw die(e);
- } catch (NoSuchGroupException e) {
+ GroupResource rsrc = groups.parse(TopLevelResource.INSTANCE,
+ IdString.fromDecoded(groupName));
+ PutName.Input input = new PutName.Input();
+ input.name = newGroupName;
+ putName.apply(rsrc, input);
+ } catch (RestApiException | OrmException | NoSuchGroupException e) {
throw die(e);
}
}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java
index 3ac72a7..bc820a4 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java
@@ -73,7 +73,9 @@
private final Set<PatchSet> patchSets = new HashSet<>();
- @Argument(index = 0, required = true, multiValued = true, metaVar = "{COMMIT | CHANGE,PATCHSET}", usage = "list of commits or patch sets to review")
+ @Argument(index = 0, required = true, multiValued = true,
+ metaVar = "{COMMIT | CHANGE,PATCHSET}",
+ usage = "list of commits or patch sets to review")
void addPatchSetId(final String token) {
try {
PatchSet ps = CommandUtils.parsePatchSet(token, db, projectControl,
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetHeadCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetHeadCommand.java
new file mode 100644
index 0000000..b1d1605
--- /dev/null
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetHeadCommand.java
@@ -0,0 +1,55 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.sshd.commands;
+
+import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
+import com.google.gerrit.server.project.ProjectControl;
+import com.google.gerrit.server.project.ProjectResource;
+import com.google.gerrit.server.project.SetHead;
+import com.google.gerrit.server.project.SetHead.Input;
+import com.google.gerrit.sshd.CommandMetaData;
+import com.google.gerrit.sshd.SshCommand;
+import com.google.inject.Inject;
+
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.Option;
+
+@CommandMetaData(name = "set-head", description = "Change HEAD reference for a project")
+public class SetHeadCommand extends SshCommand {
+
+ @Argument(index = 0, required = true, metaVar = "NAME", usage = "name of the project")
+ private ProjectControl project;
+
+ @Option(name = "--new-head", required = true, metaVar = "REF", usage = "new HEAD reference")
+ private String newHead;
+
+ private final SetHead setHead;
+
+ @Inject
+ SetHeadCommand(SetHead setHead) {
+ this.setHead = setHead;
+ }
+
+ @Override
+ protected void run() throws Exception {
+ Input input = new SetHead.Input();
+ input.ref = newHead;
+ try {
+ setHead.apply(new ProjectResource(project), input);
+ } catch (UnprocessableEntityException e) {
+ throw new UnloggedFailure("fatal: " + e.getMessage());
+ }
+ }
+}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/UploadArchive.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/UploadArchive.java
new file mode 100644
index 0000000..929f7ea
--- /dev/null
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/UploadArchive.java
@@ -0,0 +1,226 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// 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.
+
+package com.google.gerrit.sshd.commands;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.change.ArchiveFormat;
+import com.google.gerrit.server.change.GetArchive;
+import com.google.gerrit.sshd.AbstractGitCommand;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+import org.eclipse.jgit.api.ArchiveCommand;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.PacketLineIn;
+import org.eclipse.jgit.transport.PacketLineOut;
+import org.eclipse.jgit.transport.SideBandOutputStream;
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.Option;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Allows getting archives for Git repositories over SSH using the Git
+ * upload-archive protocol.
+ */
+public class UploadArchive extends AbstractGitCommand {
+ /**
+ * Options for parsing Git commands.
+ * <p>
+ * These options are not passed on command line, but received through input
+ * stream in pkt-line format.
+ */
+ static class Options {
+ @Option(name = "-f", aliases = {"--format"}, usage = "Format of the"
+ + " resulting archive: tar or zip... If this option is not given, and"
+ + " the output file is specified, the format is inferred from the"
+ + " filename if possible (e.g. writing to \"foo.zip\" makes the output"
+ + " to be in the zip format). Otherwise the output format is tar.")
+ private String format = "tar";
+
+ @Option(name = "--prefix",
+ usage = "Prepend <prefix>/ to each filename in the archive.")
+ private String prefix;
+
+ @Option(name = "-0", usage = "Store the files instead of deflating them.")
+ private boolean level0;
+ @Option(name = "-1")
+ private boolean level1;
+ @Option(name = "-2")
+ private boolean level2;
+ @Option(name = "-3")
+ private boolean level3;
+ @Option(name = "-4")
+ private boolean level4;
+ @Option(name = "-5")
+ private boolean level5;
+ @Option(name = "-6")
+ private boolean level6;
+ @Option(name = "-7")
+ private boolean level7;
+ @Option(name = "-8")
+ private boolean level8;
+ @Option(name = "-9", usage = "Highest and slowest compression level. You "
+ + "can specify any number from 1 to 9 to adjust compression speed and "
+ + "ratio.")
+ private boolean level9;
+
+ @Argument(index = 0, required = true, usage = "The tree or commit to "
+ + "produce an archive for.")
+ private String treeIsh = "master";
+
+ @Argument(index = 1, multiValued = true, usage =
+ "Without an optional path parameter, all files and subdirectories of "
+ + "the current working directory are included in the archive. If one "
+ + "or more paths are specified, only these are included.")
+ private List<String> path;
+ }
+
+ @Inject
+ private GetArchive.AllowedFormats allowedFormats;
+ @Inject
+ private Provider<ReviewDb> db;
+ private Options options = new Options();
+
+ /**
+ * Read and parse arguments from input stream.
+ * This method gets the arguments from input stream, in Pkt-line format,
+ * then parses them to fill the options object.
+ */
+ protected void readArguments() throws IOException, Failure {
+ String argCmd = "argument ";
+ List<String> args = Lists.newArrayList();
+
+ // Read arguments in Pkt-Line format
+ PacketLineIn packetIn = new PacketLineIn(in);
+ for (;;) {
+ String s = packetIn.readString();
+ if (s == PacketLineIn.END) {
+ break;
+ }
+ if (!s.startsWith(argCmd)) {
+ throw new Failure(1, "fatal: 'argument' token or flush expected");
+ }
+ String[] parts = s.substring(argCmd.length()).split("=", 2);
+ for(String p : parts) {
+ args.add(p);
+ }
+ }
+
+ try {
+ // Parse them into the 'options' field
+ CmdLineParser parser = new CmdLineParser(options);
+ parser.parseArgument(args);
+ if (options.path == null || Arrays.asList(".").equals(options.path)) {
+ options.path = Collections.emptyList();
+ }
+ } catch (CmdLineException e) {
+ throw new Failure(2, "fatal: unable to parse arguments, " + e);
+ }
+ }
+
+ @Override
+ protected void runImpl() throws IOException, Failure {
+ PacketLineOut packetOut = new PacketLineOut(out);
+ packetOut.setFlushOnEnd(true);
+ packetOut.writeString("ACK");
+ packetOut.end();
+
+ try {
+ // Parse Git arguments
+ readArguments();
+
+ ArchiveFormat f = allowedFormats.getExtensions().get("." + options.format);
+ if (f == null) {
+ throw new Failure(3, "fatal: upload-archive not permitted");
+ }
+
+ // Find out the object to get from the specified reference and paths
+ ObjectId treeId = repo.resolve(options.treeIsh);
+ if (treeId.equals(ObjectId.zeroId())) {
+ throw new Failure(4, "fatal: reference not found");
+ }
+
+ // Verify the user has permissions to read the specified reference
+ if (!projectControl.allRefsAreVisible() && !canRead(treeId)) {
+ throw new Failure(5, "fatal: cannot perform upload-archive operation");
+ }
+
+ try {
+ // The archive is sent in DATA sideband channel
+ SideBandOutputStream sidebandOut =
+ new SideBandOutputStream(SideBandOutputStream.CH_DATA,
+ SideBandOutputStream.MAX_BUF, out);
+ new ArchiveCommand(repo)
+ .setFormat(f.name())
+ .setFormatOptions(getFormatOptions(f))
+ .setTree(treeId)
+ .setPaths(options.path.toArray(new String[0]))
+ .setPrefix(options.prefix)
+ .setOutputStream(sidebandOut)
+ .call();
+ sidebandOut.flush();
+ sidebandOut.close();
+ } catch (GitAPIException e) {
+ throw new Failure(7, "fatal: git api exception, " + e);
+ }
+ } catch (Failure f) {
+ // Report the error in ERROR sideband channel
+ SideBandOutputStream sidebandError =
+ new SideBandOutputStream(SideBandOutputStream.CH_ERROR,
+ SideBandOutputStream.MAX_BUF, out);
+ sidebandError.write(f.getMessage().getBytes(UTF_8));
+ sidebandError.flush();
+ sidebandError.close();
+ throw f;
+ } finally {
+ // In any case, cleanly close the packetOut channel
+ packetOut.end();
+ }
+ }
+
+ private Map<String, Object> getFormatOptions(ArchiveFormat f) {
+ if (f == ArchiveFormat.ZIP) {
+ int value = Arrays.asList(options.level0, options.level1, options.level2,
+ options.level3, options.level4, options.level5, options.level6,
+ options.level7, options.level8, options.level9).indexOf(true);
+ if (value >= 0) {
+ return ImmutableMap.<String, Object> of(
+ "level", Integer.valueOf(value));
+ }
+ }
+ return Collections.emptyMap();
+ }
+
+ private boolean canRead(ObjectId revId) throws IOException {
+ try (RevWalk rw = new RevWalk(repo)) {
+ RevCommit commit = rw.parseCommit(revId);
+ return projectControl.canReadCommit(db.get(), rw, commit);
+ }
+ }
+}
diff --git a/gerrit-util-cli/src/main/java/com/google/gerrit/util/cli/CmdLineParser.java b/gerrit-util-cli/src/main/java/com/google/gerrit/util/cli/CmdLineParser.java
index 734b7045..e70ab72 100644
--- a/gerrit-util-cli/src/main/java/com/google/gerrit/util/cli/CmdLineParser.java
+++ b/gerrit-util-cli/src/main/java/com/google/gerrit/util/cli/CmdLineParser.java
@@ -202,8 +202,9 @@
for (int argi = 0; argi < args.length; argi++) {
final String str = args[argi];
if (str.equals("--")) {
- while (argi < args.length)
+ while (argi < args.length) {
tmp.add(args[argi++]);
+ }
break;
}
diff --git a/gerrit-util-http/src/main/java/com/google/gerrit/util/http/RequestUtil.java b/gerrit-util-http/src/main/java/com/google/gerrit/util/http/RequestUtil.java
index 922a8d5..888ad2f 100644
--- a/gerrit-util-http/src/main/java/com/google/gerrit/util/http/RequestUtil.java
+++ b/gerrit-util-http/src/main/java/com/google/gerrit/util/http/RequestUtil.java
@@ -35,6 +35,7 @@
* without decoding URL-encoded characters.
*/
public static String getEncodedPathInfo(HttpServletRequest req) {
+ // CS IGNORE LineLength FOR NEXT 3 LINES. REASON: URL.
// Based on com.google.guice.ServletDefinition$1#getPathInfo() from:
// https://github.com/google/guice/blob/41c126f99d6309886a0ded2ac729033d755e1593/extensions/servlet/src/com/google/inject/servlet/ServletDefinition.java
String servletPath = req.getServletPath();
diff --git a/gerrit-war/pom.xml b/gerrit-war/pom.xml
index 0fb1c9a..17e8286 100644
--- a/gerrit-war/pom.xml
+++ b/gerrit-war/pom.xml
@@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-war</artifactId>
- <version>2.11.1</version>
+ <version>2.12-SNAPSHOT</version>
<packaging>war</packaging>
<name>Gerrit Code Review - WAR</name>
<description>Gerrit WAR</description>
diff --git a/gerrit-war/src/main/java/com/google/gerrit/httpd/SiteInitializer.java b/gerrit-war/src/main/java/com/google/gerrit/httpd/SiteInitializer.java
index 6bbbd8f..ea4a3ea 100644
--- a/gerrit-war/src/main/java/com/google/gerrit/httpd/SiteInitializer.java
+++ b/gerrit-war/src/main/java/com/google/gerrit/httpd/SiteInitializer.java
@@ -20,7 +20,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -47,21 +48,19 @@
public void init() {
try {
if (sitePath != null) {
- File site = new File(sitePath);
- LOG.info(String.format("Initializing site at %s",
- site.getAbsolutePath()));
+ Path site = Paths.get(sitePath);
+ LOG.info("Initializing site at " + site.toRealPath().normalize());
new BaseInit(site, false, true, pluginsDistribution, pluginsToInstall).run();
return;
}
try (Connection conn = connectToDb()) {
- File site = getSiteFromReviewDb(conn);
+ Path site = getSiteFromReviewDb(conn);
if (site == null && initPath != null) {
- site = new File(initPath);
+ site = Paths.get(initPath);
}
if (site != null) {
- LOG.info(String.format("Initializing site at %s",
- site.getAbsolutePath()));
+ LOG.info("Initializing site at " + site.toRealPath().normalize());
new BaseInit(site, new ReviewDbDataSourceProvider(), false, false,
pluginsDistribution, pluginsToInstall).run();
}
@@ -76,12 +75,12 @@
return new ReviewDbDataSourceProvider().get().getConnection();
}
- private File getSiteFromReviewDb(Connection conn) {
+ private Path getSiteFromReviewDb(Connection conn) {
try (Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(
"SELECT site_path FROM system_config")) {
if (rs.next()) {
- return new File(rs.getString(1));
+ return Paths.get(rs.getString(1));
}
} catch (SQLException e) {
return null;
diff --git a/gerrit-war/src/main/java/com/google/gerrit/httpd/SitePathFromSystemConfigProvider.java b/gerrit-war/src/main/java/com/google/gerrit/httpd/SitePathFromSystemConfigProvider.java
index b97df3f..60f389e 100644
--- a/gerrit-war/src/main/java/com/google/gerrit/httpd/SitePathFromSystemConfigProvider.java
+++ b/gerrit-war/src/main/java/com/google/gerrit/httpd/SitePathFromSystemConfigProvider.java
@@ -22,12 +22,13 @@
import com.google.inject.Inject;
import com.google.inject.Provider;
-import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.List;
-/** Provides {@link java.io.File} annotated with {@link SitePath}. */
-class SitePathFromSystemConfigProvider implements Provider<File> {
- private final File path;
+/** Provides {@link Path} annotated with {@link SitePath}. */
+class SitePathFromSystemConfigProvider implements Provider<Path> {
+ private final Path path;
@Inject
SitePathFromSystemConfigProvider(SchemaFactory<ReviewDb> schemaFactory)
@@ -36,18 +37,18 @@
}
@Override
- public File get() {
+ public Path get() {
return path;
}
- private static File read(SchemaFactory<ReviewDb> schemaFactory)
+ private static Path read(SchemaFactory<ReviewDb> schemaFactory)
throws OrmException {
ReviewDb db = schemaFactory.open();
try {
List<SystemConfig> all = db.systemConfig().all().toList();
switch (all.size()) {
case 1:
- return new File(all.get(0).sitePath);
+ return Paths.get(all.get(0).sitePath);
case 0:
throw new OrmException("system_config table is empty");
default:
diff --git a/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java b/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
index b365e76..3bc8b58 100644
--- a/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
+++ b/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
@@ -82,8 +82,9 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.File;
import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -105,7 +106,7 @@
private static final Logger log =
LoggerFactory.getLogger(WebAppInitializer.class);
- private File sitePath;
+ private Path sitePath;
private Injector dbInjector;
private Injector cfgInjector;
private Injector sysInjector;
@@ -126,7 +127,7 @@
if (manager == null) {
final String path = System.getProperty("gerrit.site_path");
if (path != null) {
- sitePath = new File(path);
+ sitePath = Paths.get(path);
}
if (System.getProperty("gerrit.init") != null) {
@@ -215,7 +216,7 @@
Module sitePathModule = new AbstractModule() {
@Override
protected void configure() {
- bind(File.class).annotatedWith(SitePath.class).toInstance(sitePath);
+ bind(Path.class).annotatedWith(SitePath.class).toInstance(sitePath);
}
};
modules.add(sitePathModule);
@@ -267,7 +268,7 @@
modules.add(new AbstractModule() {
@Override
protected void configure() {
- bind(File.class).annotatedWith(SitePath.class).toProvider(
+ bind(Path.class).annotatedWith(SitePath.class).toProvider(
SitePathFromSystemConfigProvider.class).in(SINGLETON);
}
});
diff --git a/lib/BUCK b/lib/BUCK
index a880f06..d91ea26 100644
--- a/lib/BUCK
+++ b/lib/BUCK
@@ -45,8 +45,8 @@
maven_jar(
name = 'gson',
- id = 'com.google.code.gson:gson:2.1',
- sha1 = '2e66da15851f9f5b5079228f856c2f090ba98c38',
+ id = 'com.google.code.gson:gson:2.3.1',
+ sha1 = 'ecb6e1f8e4b0e84c4b886c2f14a1500caf309757',
license = 'Apache2.0',
)
@@ -188,8 +188,8 @@
maven_jar(
name = 'truth',
- id = 'com.google.truth:truth:0.25',
- sha1 = '503ba892e8482976b81eb2b2df292858fbac3782',
+ id = 'com.google.truth:truth:0.26',
+ sha1 = 'b5802815625d82f39c33219299771f3d64301b06',
license = 'DO_NOT_DISTRIBUTE',
deps = [
':guava',
diff --git a/lib/asciidoctor/java/DocIndexer.java b/lib/asciidoctor/java/DocIndexer.java
index 7eb70c1..f06c662 100644
--- a/lib/asciidoctor/java/DocIndexer.java
+++ b/lib/asciidoctor/java/DocIndexer.java
@@ -25,7 +25,6 @@
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.store.IndexInput;
import org.apache.lucene.store.RAMDirectory;
-import org.apache.lucene.util.Version;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
@@ -51,8 +50,6 @@
import java.util.zip.ZipOutputStream;
public class DocIndexer {
- @SuppressWarnings("deprecation")
- private static final Version LUCENE_VERSION = Version.LUCENE_4_10_1;
private static final Pattern SECTION_HEADER = Pattern.compile("^=+ (.*)");
@Option(name = "-o", usage = "output JAR file")
@@ -99,9 +96,9 @@
UnsupportedEncodingException, FileNotFoundException {
RAMDirectory directory = new RAMDirectory();
IndexWriterConfig config = new IndexWriterConfig(
- LUCENE_VERSION,
new StandardAnalyzer(CharArraySet.EMPTY_SET));
config.setOpenMode(OpenMode.CREATE);
+ config.setCommitOnClose(true);
IndexWriter iwriter = new IndexWriter(directory, config);
for (String inputFile : inputFiles) {
File file = new File(inputFile);
diff --git a/lib/codemirror/cm.defs b/lib/codemirror/cm.defs
index db87b25..8259252 100644
--- a/lib/codemirror/cm.defs
+++ b/lib/codemirror/cm.defs
@@ -64,6 +64,7 @@
'php',
'pig',
'properties',
+ 'puppet',
'python',
'r',
'rst',
diff --git a/lib/commons/BUCK b/lib/commons/BUCK
index 155baad..57d93b3 100644
--- a/lib/commons/BUCK
+++ b/lib/commons/BUCK
@@ -23,7 +23,6 @@
sha1 = 'ab365c96ee9bc88adcc6fa40d185c8e15a31410d',
license = 'Apache2.0',
exclude = ['META-INF/LICENSE.txt', 'META-INF/NOTICE.txt'],
- visibility = ['//lib/jgit:jgit-archive'],
)
maven_jar(
@@ -41,8 +40,8 @@
maven_jar(
name = 'lang',
- id = 'commons-lang:commons-lang:2.5',
- sha1 = 'b0236b252e86419eef20c31a44579d2aee2f0a69',
+ id = 'commons-lang:commons-lang:2.6',
+ sha1 = '0ce1edb914c94ebc388f086c6827e8bdeec71ac2',
license = 'Apache2.0',
exclude = ['META-INF/LICENSE.txt', 'META-INF/NOTICE.txt'],
)
diff --git a/lib/jgit/BUCK b/lib/jgit/BUCK
index dcefb64..9dc2e73 100644
--- a/lib/jgit/BUCK
+++ b/lib/jgit/BUCK
@@ -1,13 +1,13 @@
include_defs('//lib/maven.defs')
-REPO = MAVEN_CENTRAL # Leave here even if set to MAVEN_CENTRAL.
-VERS = '4.0.0.201505050340-m2'
+REPO = GERRIT # Leave here even if set to MAVEN_CENTRAL.
+VERS = '4.0.0.201505191015-rc1.19-g1773002'
maven_jar(
name = 'jgit',
id = 'org.eclipse.jgit:org.eclipse.jgit:' + VERS,
- bin_sha1 = '1cc3120d39ed2b55584e631634e65c5d2e6c1cf7',
- src_sha1 = '425f578cc9d5ccb8f3b050a5ab1e2d7a0becb25d',
+ bin_sha1 = '4db24b39dab8dc0e889807383728032945f461be',
+ src_sha1 = '1723a2855f50493b7c0b216aae97909a7ea59962',
license = 'jgit',
repository = REPO,
unsign = True,
@@ -22,7 +22,7 @@
maven_jar(
name = 'jgit-servlet',
id = 'org.eclipse.jgit:org.eclipse.jgit.http.server:' + VERS,
- sha1 = '2a9f55d1d92afef795542b995db6ab261007857f',
+ sha1 = '7bfdbddea56a87f3f2687ae6abf2c5bdae649f0c',
license = 'jgit',
repository = REPO,
deps = [':jgit'],
@@ -36,7 +36,7 @@
maven_jar(
name = 'jgit-archive',
id = 'org.eclipse.jgit:org.eclipse.jgit.archive:' + VERS,
- sha1 = 'ee3954753067818f8f734981a01c13ac33425f2c',
+ sha1 = '08fce6b89f6d1e78f99869d542d70899f3be9c9f',
license = 'jgit',
repository = REPO,
deps = [':jgit',
@@ -53,7 +53,7 @@
maven_jar(
name = 'junit',
id = 'org.eclipse.jgit:org.eclipse.jgit.junit:' + VERS,
- sha1 = '6cc19f8f0a1791e26d4225625ecba6a31d9b830e',
+ sha1 = 'a54c16076e6cbdb9113565a82cffa5f268ae8e3b',
license = 'DO_NOT_DISTRIBUTE',
repository = REPO,
unsign = True,
diff --git a/lib/joda/BUCK b/lib/joda/BUCK
index d45ce78..2401870 100644
--- a/lib/joda/BUCK
+++ b/lib/joda/BUCK
@@ -7,8 +7,8 @@
maven_jar(
name = 'joda-time',
- id = 'joda-time:joda-time:2.3',
- sha1 = '56498efd17752898cfcc3868c1b6211a07b12b8f',
+ id = 'joda-time:joda-time:2.7',
+ sha1 = '5599707a3eaad13e889f691b3af78c8c03842195',
deps = [':joda-convert'],
license = 'Apache2.0',
exclude = EXCLUDE,
diff --git a/lib/log/BUCK b/lib/log/BUCK
index cadc7e7..b332f20 100644
--- a/lib/log/BUCK
+++ b/lib/log/BUCK
@@ -31,3 +31,18 @@
license = 'Apache2.0',
exclude = ['META-INF/LICENSE', 'META-INF/NOTICE'],
)
+
+maven_jar(
+ name = 'jsonevent-layout',
+ id = 'net.logstash.log4j:jsonevent-layout:1.7',
+ sha1 = '507713504f0ddb75ba512f62763519c43cf46fde',
+ license = 'Apache2.0',
+ deps = [':json-smart', '//lib/commons:lang']
+)
+
+maven_jar(
+ name = 'json-smart',
+ id = 'net.minidev:json-smart:1.1.1',
+ sha1 = '24a2f903d25e004de30ac602c5b47f2d4e420a59',
+ license = 'Apache2.0',
+)
diff --git a/lib/lucene/BUCK b/lib/lucene/BUCK
index 9026f79..68d579d 100644
--- a/lib/lucene/BUCK
+++ b/lib/lucene/BUCK
@@ -1,11 +1,11 @@
include_defs('//lib/maven.defs')
-VERSION = '4.10.2'
+VERSION = '5.1.0'
maven_jar(
name = 'core',
id = 'org.apache.lucene:lucene-core:' + VERSION,
- sha1 = 'c01e3d675d277e0a93e7890d03cc3246b2cdecaa',
+ sha1 = '93e64c67106f9a50e6ea01cfcfd6ac692ab3a41a',
license = 'Apache2.0',
exclude = [
'META-INF/LICENSE.txt',
@@ -16,8 +16,33 @@
maven_jar(
name = 'analyzers-common',
id = 'org.apache.lucene:lucene-analyzers-common:' + VERSION,
- sha1 = 'f977f8c443e8f4e9d1fd7fdfda80a6cf60b3e7c2',
+ sha1 = '54770d9b792536dff25ae1d70cd8af822c0079a3',
license = 'Apache2.0',
+ deps = [':core'],
+ exclude = [
+ 'META-INF/LICENSE.txt',
+ 'META-INF/NOTICE.txt',
+ ],
+)
+
+maven_jar(
+ name = 'backward-codecs',
+ id = 'org.apache.lucene:lucene-backward-codecs:' + VERSION,
+ sha1 = '5f0c5bb10ac3facace6b314bb02a6b572795b3c9',
+ license = 'Apache2.0',
+ deps = [':core'],
+ exclude = [
+ 'META-INF/LICENSE.txt',
+ 'META-INF/NOTICE.txt',
+ ],
+)
+
+maven_jar(
+ name = 'misc',
+ id = 'org.apache.lucene:lucene-misc:' + VERSION,
+ sha1 = '3b700fa57f5d444da0e58cc1855042e6c5a18640',
+ license = 'Apache2.0',
+ deps = [':core'],
exclude = [
'META-INF/LICENSE.txt',
'META-INF/NOTICE.txt',
@@ -27,6 +52,11 @@
maven_jar(
name = 'query-parser',
id = 'org.apache.lucene:lucene-queryparser:' + VERSION,
- sha1 = 'd70f54e1060d553ba7aeb4d49a71fd0c068499e8',
+ sha1 = '53f0b3f0e700a8ec484195d3370688171e830634',
license = 'Apache2.0',
+ deps = [':core'],
+ exclude = [
+ 'META-INF/LICENSE.txt',
+ 'META-INF/NOTICE.txt',
+ ],
)
diff --git a/lib/maven.defs b/lib/maven.defs
index 4edba9c..cc45212 100644
--- a/lib/maven.defs
+++ b/lib/maven.defs
@@ -46,9 +46,14 @@
from os import path
parts = id.split(':')
- if len(parts) != 3:
- raise NameError('expected id="groupId:artifactId:version"')
- group, artifact, version = parts
+ if len(parts) not in [3, 4]:
+ raise NameError('%s:\nexpected id="groupId:artifactId:version[:classifier]"'
+ % id)
+ if len(parts) == 4:
+ group, artifact, version, classifier = parts
+ else:
+ group, artifact, version = parts
+ classifier = None
# SNAPSHOT artifacts are handled differently on Google storage bucket:
# 'SNAPSHOT' is discarded from the directory name. However on other
@@ -62,7 +67,11 @@
else:
file_version = version
+ if classifier is not None:
+ file_version += '-' + classifier
+
jar = path.join(name, artifact.lower() + '-' + file_version)
+
url = '/'.join([
repository,
group.replace('.', '/'), artifact, version,
diff --git a/lib/prolog/BUCK b/lib/prolog/BUCK
index 1f3e425..77fe5ac 100644
--- a/lib/prolog/BUCK
+++ b/lib/prolog/BUCK
@@ -1,15 +1,53 @@
include_defs('//lib/maven.defs')
+VERSION = '1.4.1'
+REPO = GERRIT
+
maven_jar(
- name = 'prolog-cafe',
- id = 'com.googlecode.prolog-cafe:PrologCafe:1.3',
- sha1 = '5e0fbf18e8c98c4113f9acc978306884a1152870',
+ name = 'runtime',
+ id = 'com.googlecode.prolog-cafe:prolog-runtime:' + VERSION,
+ sha1 = 'c5d9f92e49c485969dcd424dfc0c08125b5f8246',
license = 'prologcafe',
- repository = GERRIT,
+ repository = REPO,
+)
+
+maven_jar(
+ name = 'compiler',
+ id = 'com.googlecode.prolog-cafe:prolog-compiler:' + VERSION,
+ sha1 = 'ac24044c6ec166fdcb352b78b80d187ead3eff41',
+ license = 'prologcafe',
+ repository = REPO,
+ deps = [
+ ':io',
+ ':runtime',
+ ],
+)
+
+maven_jar(
+ name = 'io',
+ id = 'com.googlecode.prolog-cafe:prolog-io:' + VERSION,
+ sha1 = 'b072426a4b1b8af5e914026d298ee0358a8bb5aa',
+ license = 'prologcafe',
+ repository = REPO,
+ deps = [':runtime'],
+ visibility = [],
+)
+
+maven_jar(
+ name = 'cafeteria',
+ id = 'com.googlecode.prolog-cafe:prolog-cafeteria:' + VERSION,
+ sha1 = '8cbc3b0c19e7167c42d3f11667b21cb21ddec641',
+ license = 'prologcafe',
+ repository = REPO,
+ deps = [
+ ':io',
+ ':runtime',
+ ],
+ visibility = ['//gerrit-pgm:'],
)
java_binary(
- name = 'compiler',
+ name = 'compiler_bin',
main_class = 'BuckPrologCompiler',
deps = [':compiler_lib'],
visibility = ['PUBLIC'],
@@ -18,6 +56,9 @@
java_library(
name = 'compiler_lib',
srcs = ['java/BuckPrologCompiler.java'],
- deps = [':prolog-cafe'],
+ deps = [
+ ':compiler',
+ ':runtime',
+ ],
visibility = ['//tools/eclipse:classpath'],
)
diff --git a/lib/prolog/java/BuckPrologCompiler.java b/lib/prolog/java/BuckPrologCompiler.java
index 17d2d76..0cbe10e 100644
--- a/lib/prolog/java/BuckPrologCompiler.java
+++ b/lib/prolog/java/BuckPrologCompiler.java
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import com.googlecode.prolog_cafe.compiler.CompileException;
import com.googlecode.prolog_cafe.compiler.Compiler;
+import com.googlecode.prolog_cafe.exceptions.CompileException;
import java.io.File;
import java.io.FileInputStream;
@@ -63,7 +63,11 @@
private static void add(JarOutputStream out, File classes, String prefix)
throws IOException {
- for (String name : classes.list()) {
+ String[] list = classes.list();
+ if (list == null) {
+ return;
+ }
+ for (String name : list) {
File f = new File(classes, name);
if (f.isDirectory()) {
add(out, f, prefix + name + "/");
@@ -71,8 +75,7 @@
}
JarEntry e = new JarEntry(prefix + name);
- FileInputStream in = new FileInputStream(f);
- try {
+ try (FileInputStream in = new FileInputStream(f)) {
e.setTime(f.lastModified());
out.putNextEntry(e);
byte[] buf = new byte[16 << 10];
@@ -81,7 +84,6 @@
out.write(buf, 0, n);
}
} finally {
- in.close();
out.closeEntry();
}
}
diff --git a/lib/prolog/prolog.defs b/lib/prolog/prolog.defs
index d0636f5..677a9e2 100644
--- a/lib/prolog/prolog.defs
+++ b/lib/prolog/prolog.defs
@@ -19,7 +19,7 @@
visibility = []):
genrule(
name = name + '__pl2j',
- cmd = '$(exe //lib/prolog:compiler)' +
+ cmd = '$(exe //lib/prolog:compiler_bin)' +
' $TMP $OUT ' +
' '.join(srcs),
srcs = srcs,
@@ -28,7 +28,7 @@
java_library(
name = name + '__lib',
srcs = [':' + name + '__pl2j'],
- deps = ['//lib/prolog:prolog-cafe'] + deps,
+ deps = ['//lib/prolog:runtime'] + deps,
)
genrule(
name = name + '__ln',
diff --git a/plugins/commit-message-length-validator b/plugins/commit-message-length-validator
index 7923b67..8d295ed 160000
--- a/plugins/commit-message-length-validator
+++ b/plugins/commit-message-length-validator
@@ -1 +1 @@
-Subproject commit 7923b67392164dcc65ada85f723fa5111b265484
+Subproject commit 8d295ed48e8f52eef5661b6eb10d6402d197c776
diff --git a/plugins/cookbook-plugin b/plugins/cookbook-plugin
index 17b63c1..a93641d 160000
--- a/plugins/cookbook-plugin
+++ b/plugins/cookbook-plugin
@@ -1 +1 @@
-Subproject commit 17b63c160498d02fb1c511c5b43b02f538b29558
+Subproject commit a93641db50f52e24421f75671bb1d4df268dd722
diff --git a/plugins/download-commands b/plugins/download-commands
index baa09c2..1cf6921 160000
--- a/plugins/download-commands
+++ b/plugins/download-commands
@@ -1 +1 @@
-Subproject commit baa09c2e265a2b264a5fb4571e7eefda04def0c4
+Subproject commit 1cf69212a7489e88d8c73377f0f77f8a5965db75
diff --git a/plugins/replication b/plugins/replication
index 53ee1b8..f03316c 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit 53ee1b8ec4de5de4d710233eda2230b5380f1390
+Subproject commit f03316c26b5991cba96280de59a4119619a18a58
diff --git a/plugins/reviewnotes b/plugins/reviewnotes
index 603b7b3..b5c6f81 160000
--- a/plugins/reviewnotes
+++ b/plugins/reviewnotes
@@ -1 +1 @@
-Subproject commit 603b7b3885a1d2953ca891f58d2a6095e72e5313
+Subproject commit b5c6f81d979e78fbd734d946b18270ec8319eaf6
diff --git a/tools/build.defs b/tools/build.defs
index 8b858cd..da07c1e 100644
--- a/tools/build.defs
+++ b/tools/build.defs
@@ -71,8 +71,8 @@
context = [
'//gerrit-main:main_bin',
'//gerrit-war:webapp_assets',
- '//gerrit-gwtui:' + ui,
- ] + context,
+ ] + (['//gerrit-gwtui:' + ui] if ui else []) +
+ context,
docs = docs,
visibility = visibility,
)
diff --git a/tools/checkstyle.xml b/tools/checkstyle.xml
index a9f8cfe..fc94144 100644
--- a/tools/checkstyle.xml
+++ b/tools/checkstyle.xml
@@ -14,10 +14,12 @@
<property name="severity" value="warning"/>
<property name="charset" value="UTF-8"/>
<module name="TreeWalker">
+ <module name="FileContentsHolder"/>
<module name="OuterTypeFilename"/>
<module name="LineLength">
<property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
- <property name="max" value="100"/>
+ <property name="max" value="150"/>
+ <property name="tabWidth" value="2"/>
</module>
<module name="OneTopLevelClass"/>
<module name="NoLineWrap"/>
@@ -27,9 +29,8 @@
</module>
<module name="NeedBraces"/>
<module name="LeftCurly">
- <property name="maxLineLength" value="100"/>
+ <property name="maxLineLength" value="150"/>
</module>
- <module name="RightCurly"/>
<module name="RightCurly">
<property name="option" value="alone"/>
<property name="tokens" value="CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, LITERAL_DO, STATIC_INIT, INSTANCE_INIT"/>
@@ -47,8 +48,6 @@
<module name="OneStatementPerLine"/>
<module name="MultipleVariableDeclarations"/>
<module name="ArrayTypeStyle"/>
- <module name="MissingSwitchDefault"/>
- <module name="FallThrough"/>
<module name="UpperEll"/>
<module name="ModifierOrder"/>
<module name="EmptyLineSeparator">
@@ -100,4 +99,9 @@
<property name="eachLine" value="true"/>
<metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
</module>
+ <module name="SuppressWithNearbyCommentFilter">
+ <property name="commentFormat" value="CS IGNORE (\w+) FOR NEXT (\d+) LINES\. REASON\: \w+"/>
+ <property name="checkFormat" value="$1"/>
+ <property name="influenceFormat" value="$2"/>
+ </module>
</module>
diff --git a/tools/default.defs b/tools/default.defs
index 30518c4..14bc9ce 100644
--- a/tools/default.defs
+++ b/tools/default.defs
@@ -18,6 +18,7 @@
include_defs('//tools/gwt-constants.defs')
include_defs('//tools/java_doc.defs')
include_defs('//tools/java_sources.defs')
+include_defs('//tools/git.defs')
import copy
# Set defaults on java rules:
@@ -63,7 +64,8 @@
kwargs[apdk] = []
apds = kwargs.get(apdk, [])
- if AUTO_VALUE_DEP in kwargs.get('deps', []):
+ all_deps = kwargs.get('deps', []) + kwargs.get('exported_deps', [])
+ if AUTO_VALUE_DEP in all_deps:
aps.extend(AUTO_VALUE_PROCESSORS)
apds.extend(AUTO_VALUE_PROCESSOR_DEPS)
@@ -129,7 +131,7 @@
type = 'plugin',
visibility = ['PUBLIC']):
from multiprocessing import cpu_count
- mf_cmd = 'v=\$(git describe HEAD);'
+ mf_cmd = 'v=%s;' % git_describe(name)
if manifest_file:
mf_src = [manifest_file]
mf_cmd += 'sed "s:@VERSION@:$v:g" $SRCS >$OUT'
diff --git a/tools/gerrit.importorder b/tools/gerrit.importorder
index 831c5fe..398130e 100644
--- a/tools/gerrit.importorder
+++ b/tools/gerrit.importorder
@@ -1,9 +1,12 @@
#Organize Import Order
-#Wed Jan 14 10:19:45 JST 2015
-6=javax
-5=java
-4=org
-3=net
-2=junit
-1=com
-0=com.google
+#Mon Mar 23 17:27:34 PDT 2015
+9=javax
+8=java
+7=org
+6=net
+5=junit
+4=eu
+3=dk
+2=com
+1=com.google
+0=\#
diff --git a/tools/git.defs b/tools/git.defs
index c58ac88..0247e32 100644
--- a/tools/git.defs
+++ b/tools/git.defs
@@ -12,10 +12,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-def git_describe():
+def git_describe(plugin = None):
import subprocess
- cmd = ['git', 'describe', '--match', 'v[0-9].*', '--dirty']
- p = subprocess.Popen(cmd, stdout = subprocess.PIPE)
+ cmd = ['git', 'describe', '--always', '--match', 'v[0-9].*', '--dirty']
+ if not plugin or plugin == '${pluginName}':
+ p = subprocess.Popen(cmd, stdout = subprocess.PIPE)
+ else:
+ p = subprocess.Popen(cmd, stdout = subprocess.PIPE, cwd = 'plugins/%s' % plugin)
v = p.communicate()[0].strip()
r = p.returncode
if r != 0: