Merge "Fix account visibility bypass and PII leak in QueryAccounts"
diff --git a/Documentation/cmd-show-caches.txt b/Documentation/cmd-show-caches.txt
index 92e8963..ceca34b 100644
--- a/Documentation/cmd-show-caches.txt
+++ b/Documentation/cmd-show-caches.txt
@@ -8,6 +8,7 @@
--
_ssh_ -p <port> <host> _gerrit show-caches_
[--show-jvm]
+ [--include-diskstats]
[--cache <NAME> ...]
--
@@ -25,6 +26,9 @@
operating system, and other details about the environment
that Gerrit Code Review is running in.
+--include-diskstats::
+ Include disk stat collection for persistent caches.
+
--show-threads::
Show detailed counts for Gerrit specific threads.
diff --git a/Documentation/rest-api-config.txt b/Documentation/rest-api-config.txt
index b86d732..f7e477d 100644
--- a/Documentation/rest-api-config.txt
+++ b/Documentation/rest-api-config.txt
@@ -330,11 +330,25 @@
The entries in the map are sorted by cache name.
+.Query Options
+[options="header",cols="1,3"]
+|===
+|Field Name |Description
+|`include-diskstats` |If `true`, disk stat collection is included for persistent caches.
+|===
+
.Request
----
GET /config/server/caches/ HTTP/1.0
----
+To include disk stats for persistent caches:
+
+.Request
+----
+ GET /config/server/caches/?include-diskstats=true HTTP/1.0
+----
+
.Response
----
HTTP/1.1 200 OK
diff --git a/contrib/maintenance/gerrit/site.py b/contrib/maintenance/gerrit/site.py
index faf6c02..450acaa 100644
--- a/contrib/maintenance/gerrit/site.py
+++ b/contrib/maintenance/gerrit/site.py
@@ -37,11 +37,11 @@
) as cfg:
config_base_path = cfg.get("gerrit", None, "basePath", "git")
if os.path.isabs(config_base_path):
- self.basePath = config_base_path
+ self.base_path = config_base_path
else:
- self.basePath = os.path.join(self.path, config_base_path)
+ self.base_path = os.path.join(self.path, config_base_path)
- return self.basePath
+ return self.base_path
def get_projects(self, excludes=None):
for current, dirs, _ in os.walk(self.get_base_path(), topdown=True):
diff --git a/java/com/google/gerrit/pgm/Reindex.java b/java/com/google/gerrit/pgm/Reindex.java
index 7c0f258..0964dae 100644
--- a/java/com/google/gerrit/pgm/Reindex.java
+++ b/java/com/google/gerrit/pgm/Reindex.java
@@ -315,7 +315,7 @@
new CacheDisplay(
sw,
StreamSupport.stream(cacheMap.spliterator(), false)
- .map(e -> CacheInfoFactory.create(e.getExportName(), e.get()))
+ .map(e -> CacheInfoFactory.create(e.getExportName(), e.get(), true))
.collect(Collectors.toList()))
.displayCaches();
System.out.print(sw.toString());
diff --git a/java/com/google/gerrit/server/cache/CacheInfoFactory.java b/java/com/google/gerrit/server/cache/CacheInfoFactory.java
index dafa186..48122db 100644
--- a/java/com/google/gerrit/server/cache/CacheInfoFactory.java
+++ b/java/com/google/gerrit/server/cache/CacheInfoFactory.java
@@ -24,11 +24,11 @@
public class CacheInfoFactory {
- public static CacheInfo create(Cache<?, ?> cache) {
- return create(null, cache);
+ public static CacheInfo create(Cache<?, ?> cache, boolean includeDiskStats) {
+ return create(null, cache, includeDiskStats);
}
- public static CacheInfo create(String name, Cache<?, ?> cache) {
+ public static CacheInfo create(String name, Cache<?, ?> cache, boolean includeDiskStats) {
CacheInfo cacheInfo = new CacheInfo();
cacheInfo.name = name;
@@ -44,10 +44,12 @@
if (cache instanceof PersistentCache) {
cacheInfo.type = CacheType.DISK;
- PersistentCache.DiskStats diskStats = ((PersistentCache) cache).diskStats();
- cacheInfo.entries.setDisk(diskStats.size());
- cacheInfo.entries.setSpace(diskStats.space());
- cacheInfo.hitRatio.setDisk(diskStats.hitCount(), diskStats.requestCount());
+ if (includeDiskStats) {
+ PersistentCache.DiskStats diskStats = ((PersistentCache) cache).diskStats();
+ cacheInfo.entries.setDisk(diskStats.size());
+ cacheInfo.entries.setSpace(diskStats.space());
+ cacheInfo.hitRatio.setDisk(diskStats.hitCount(), diskStats.requestCount());
+ }
} else {
cacheInfo.type = CacheType.MEM;
}
diff --git a/java/com/google/gerrit/server/restapi/config/GetCache.java b/java/com/google/gerrit/server/restapi/config/GetCache.java
index 23615fa..0f06128 100644
--- a/java/com/google/gerrit/server/restapi/config/GetCache.java
+++ b/java/com/google/gerrit/server/restapi/config/GetCache.java
@@ -26,6 +26,6 @@
@Override
public Response<CacheInfo> apply(CacheResource rsrc) {
- return Response.ok(CacheInfoFactory.create(rsrc.getName(), rsrc.getCache()));
+ return Response.ok(CacheInfoFactory.create(rsrc.getName(), rsrc.getCache(), true));
}
}
diff --git a/java/com/google/gerrit/server/restapi/config/ListCaches.java b/java/com/google/gerrit/server/restapi/config/ListCaches.java
index 2856d83..6411615 100644
--- a/java/com/google/gerrit/server/restapi/config/ListCaches.java
+++ b/java/com/google/gerrit/server/restapi/config/ListCaches.java
@@ -51,26 +51,33 @@
@Option(name = "--format", usage = "output format")
private OutputFormat format;
+ @Option(
+ name = "--include-diskstats",
+ usage = "if set, disk stat collection is included for persistent caches")
+ private boolean includeDiskStats;
+
public ListCaches setFormat(OutputFormat format) {
this.format = format;
return this;
}
+ public ListCaches setIncludeDiskStats(boolean includeDiskStats) {
+ this.includeDiskStats = includeDiskStats;
+ return this;
+ }
+
@Inject
public ListCaches(DynamicMap<Cache<?, ?>> cacheMap) {
this.cacheMap = cacheMap;
}
- public Map<String, CacheInfo> getCacheInfos() {
- return getCacheInfos(name -> true);
- }
-
- public Map<String, CacheInfo> getCacheInfos(Predicate<String> nameFilter) {
+ public Map<String, CacheInfo> getCacheInfos(
+ Predicate<String> nameFilter, boolean includeDiskStats) {
Map<String, CacheInfo> cacheInfos = new TreeMap<>();
for (Extension<Cache<?, ?>> e : cacheMap) {
String name = cacheNameOf(e.getPluginName(), e.getExportName());
if (nameFilter.test(name)) {
- cacheInfos.put(name, CacheInfoFactory.create(e.getProvider().get()));
+ cacheInfos.put(name, CacheInfoFactory.create(e.getProvider().get(), includeDiskStats));
}
}
return cacheInfos;
@@ -79,7 +86,7 @@
@Override
public Response<Object> apply(ConfigResource rsrc) {
if (format == null) {
- return Response.ok(getCacheInfos());
+ return Response.ok(getCacheInfos(name -> true, includeDiskStats));
}
Stream<String> cacheNames =
Streams.stream(cacheMap)
diff --git a/java/com/google/gerrit/sshd/commands/ShowCaches.java b/java/com/google/gerrit/sshd/commands/ShowCaches.java
index 71e5bd1..bf7c154 100644
--- a/java/com/google/gerrit/sshd/commands/ShowCaches.java
+++ b/java/com/google/gerrit/sshd/commands/ShowCaches.java
@@ -85,6 +85,11 @@
private boolean showThreads;
@Option(
+ name = "--include-diskstats",
+ usage = "include disk stat collection for persistent caches")
+ private boolean includeDiskStats;
+
+ @Option(
name = "--cache",
usage = "show the named cache; may be supplied more than once",
metaVar = "NAME")
@@ -166,11 +171,13 @@
private Collection<CacheInfo> getCaches() {
Map<String, CacheInfo> selected;
if (caches.isEmpty()) {
- selected = listCaches.getCacheInfos();
+ selected = listCaches.getCacheInfos(name -> true, includeDiskStats);
} else {
Set<String> filter =
caches.stream().map(n -> n.toLowerCase(Locale.US)).collect(Collectors.toSet());
- selected = listCaches.getCacheInfos(n -> filter.contains(n.toLowerCase(Locale.US)));
+ selected =
+ listCaches.getCacheInfos(
+ n -> filter.contains(n.toLowerCase(Locale.US)), includeDiskStats);
}
for (Map.Entry<String, CacheInfo> entry : selected.entrySet()) {
CacheInfo cache = entry.getValue();
diff --git a/javatests/com/google/gerrit/acceptance/rest/config/ListCachesIT.java b/javatests/com/google/gerrit/acceptance/rest/config/ListCachesIT.java
index a987225..7f2e39e 100644
--- a/javatests/com/google/gerrit/acceptance/rest/config/ListCachesIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/config/ListCachesIT.java
@@ -21,6 +21,7 @@
import com.google.common.io.BaseEncoding;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.acceptance.UseLocalDisk;
import com.google.gerrit.extensions.common.CacheInfo;
import com.google.gson.reflect.TypeToken;
import java.util.Arrays;
@@ -88,4 +89,36 @@
public void listCaches_BadRequest() throws Exception {
adminRestSession.get("/config/server/caches/?format=NONSENSE").assertBadRequest();
}
+
+ @Test
+ public void listCaches_withoutIncludeDiskStats_memCacheUnaffected() throws Exception {
+ RestResponse r = adminRestSession.get("/config/server/caches/");
+ r.assertOK();
+ Map<String, CacheInfo> result =
+ newGson().fromJson(r.getReader(), new TypeToken<Map<String, CacheInfo>>() {}.getType());
+
+ assertThat(result).containsKey("accounts");
+ CacheInfo accountsCacheInfo = result.get("accounts");
+ assertThat(accountsCacheInfo.type).isEqualTo(CacheInfo.CacheType.MEM);
+ assertThat(accountsCacheInfo.entries.mem).isAtLeast(1L);
+ assertThat(accountsCacheInfo.hitRatio.mem).isAtLeast(0);
+
+ assertThat(accountsCacheInfo.entries.disk).isNull();
+ assertThat(accountsCacheInfo.hitRatio.disk).isNull();
+ }
+
+ @Test
+ @UseLocalDisk
+ public void listCaches_withIncludeDiskStats_diskCacheHasDiskStats() throws Exception {
+ RestResponse r = adminRestSession.get("/config/server/caches/?include-diskstats=true");
+ r.assertOK();
+ Map<String, CacheInfo> result =
+ newGson().fromJson(r.getReader(), new TypeToken<Map<String, CacheInfo>>() {}.getType());
+
+ assertThat(result).containsKey("accounts");
+ CacheInfo accountsInfo = result.get("accounts");
+ assertThat(accountsInfo.type).isEqualTo(CacheInfo.CacheType.DISK);
+ assertThat(accountsInfo.entries.mem).isNotNull();
+ assertThat(accountsInfo.entries.disk).isNotNull();
+ }
}
diff --git a/plugins/replication b/plugins/replication
index 0f4eec7..54898d7 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit 0f4eec70496e7589dba4d7e432deb427c22b6069
+Subproject commit 54898d71ffa30bcdaa0f37f968efb0985d9bca64
diff --git a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts
index bfdde07..a9284c5 100644
--- a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts
+++ b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts
@@ -29,7 +29,11 @@
import {subscribe} from '../../lit/subscription-controller';
import {assert} from '../../../utils/common-util';
import {resolve} from '../../../models/dependency';
-import {createChangeUrl} from '../../../models/views/change';
+import {
+ changeViewModelToken,
+ createApplyFixUrl,
+} from '../../../models/views/change';
+
import {GrDialog} from '../../shared/gr-dialog/gr-dialog';
import {userModelToken} from '../../../models/user/user-model';
import {modalStyles} from '../../../styles/gr-modal-styles';
@@ -114,6 +118,8 @@
private readonly getNavigation = resolve(this, navigationToken);
+ private readonly getViewModel = resolve(this, changeViewModelToken);
+
private readonly reporting = getAppContext().reportingService;
private readonly syntaxLayer = new GrSyntaxLayerWorker(
@@ -481,16 +487,22 @@
});
}
if (res?.ok) {
+ const currentChildView = this.getViewModel().getState()?.childView;
+ const filePath =
+ fixSuggestion.replacements[0]?.path ??
+ this.currentPreviews[0]?.filepath;
this.getNavigation().setUrl(
- createChangeUrl({
+ createApplyFixUrl({
change,
- patchNum: EDIT,
basePatchNum: patchNum as BasePatchSetNum,
forceReload: !this.hasEdit,
+ filePath,
+ currentChildView,
})
);
this.close(true);
}
+
this.isApplyFixLoading = false;
}
}
diff --git a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.ts b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.ts
index 1d35430..21ce8ed 100644
--- a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.ts
+++ b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.ts
@@ -14,12 +14,15 @@
import {GrApplyFixDialog} from './gr-apply-fix-dialog';
import {PatchSetNum, PatchSetNumber} from '../../../types/common';
import {
+ createChangeViewState,
+ createDiffViewState,
createFixSuggestionInfo,
createParsedChange,
createRange,
createRevisions,
getCurrentRevision,
} from '../../../test/test-data-generators';
+import {changeViewModelToken} from '../../../models/views/change';
import {createDefaultDiffPrefs} from '../../../constants/constants';
import {OpenFixPreviewEventDetail} from '../../../types/events';
import {GrButton} from '../../shared/gr-button/gr-button';
@@ -227,4 +230,70 @@
'/c/test-project/+/42/2..edit?forceReload=true'
);
});
+
+ suite('handleApplyFix navigation', () => {
+ setup(() => {
+ stubRestApi('applyFixSuggestion').returns(
+ Promise.resolve(new Response(null, {status: 200}))
+ );
+ });
+
+ test('navigates to createDiffUrl when in Diff View', async () => {
+ testResolver(changeViewModelToken).setState(createDiffViewState());
+ const fixDetail: OpenFixPreviewEventDetail = {
+ patchNum: 2 as PatchSetNum,
+ fixSuggestions: [
+ {
+ ...createFixSuggestionInfo('fix_1'),
+ replacements: [
+ {
+ path: 'file1.txt',
+ replacement: 'new content',
+ range: createRange(),
+ },
+ ],
+ },
+ ],
+ onCloseFixPreviewCallbacks: [],
+ };
+ await open(fixDetail);
+
+ await element.handleApplyFix(new CustomEvent('confirm'));
+
+ assert.isTrue(setUrlStub.calledOnce);
+ assert.equal(
+ setUrlStub.lastCall.firstArg,
+ '/c/test-project/+/42/2..edit/file1.txt?forceReload=true'
+ );
+ });
+
+ test('navigates to createChangeUrl when in Change View', async () => {
+ testResolver(changeViewModelToken).setState(createChangeViewState());
+ const fixDetail: OpenFixPreviewEventDetail = {
+ patchNum: 2 as PatchSetNum,
+ fixSuggestions: [
+ {
+ ...createFixSuggestionInfo('fix_1'),
+ replacements: [
+ {
+ path: 'file1.txt',
+ replacement: 'new content',
+ range: createRange(),
+ },
+ ],
+ },
+ ],
+ onCloseFixPreviewCallbacks: [],
+ };
+ await open(fixDetail);
+
+ await element.handleApplyFix(new CustomEvent('confirm'));
+
+ assert.isTrue(setUrlStub.calledOnce);
+ assert.equal(
+ setUrlStub.lastCall.firstArg,
+ '/c/test-project/+/42/2..edit?forceReload=true'
+ );
+ });
+ });
});
diff --git a/polygerrit-ui/app/elements/shared/gr-suggestion-diff-preview/gr-suggestion-diff-preview.ts b/polygerrit-ui/app/elements/shared/gr-suggestion-diff-preview/gr-suggestion-diff-preview.ts
index 72e0905..0b46706 100644
--- a/polygerrit-ui/app/elements/shared/gr-suggestion-diff-preview/gr-suggestion-diff-preview.ts
+++ b/polygerrit-ui/app/elements/shared/gr-suggestion-diff-preview/gr-suggestion-diff-preview.ts
@@ -30,7 +30,11 @@
import {navigationToken} from '../../core/gr-navigation/gr-navigation';
import {fire, fireError} from '../../../utils/event-util';
import {Timing} from '../../../constants/reporting';
-import {createChangeUrl} from '../../../models/views/change';
+import {
+ changeViewModelToken,
+ createApplyFixUrl,
+} from '../../../models/views/change';
+
import {getFileExtension} from '../../../utils/file-util';
import {throwingErrorCallback} from '../gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper';
import {ReportSource} from '../../../services/suggestions/suggestions-service';
@@ -128,6 +132,8 @@
private readonly getNavigation = resolve(this, navigationToken);
+ private readonly getViewModel = resolve(this, changeViewModelToken);
+
private readonly syntaxLayer = new GrSyntaxLayerWorker(
resolve(this, highlightServiceToken),
() => getAppContext().reportingService
@@ -391,16 +397,23 @@
// basePatchNum is from comment patchset and comment cannot be created
// in EDIT. RevisionPatchset without EDIT is PatchSetNumber
if (res?.ok && basePatchNum !== undefined && basePatchNum !== EDIT) {
+ const currentChildView = this.getViewModel().getState()?.childView;
+ const filePath =
+ fixSuggestion.replacements[0]?.path ?? this.preview?.filepath;
this.getNavigation().setUrl(
- createChangeUrl({
+ createApplyFixUrl({
changeNum,
repo: this.repo!,
- patchNum: EDIT,
basePatchNum: basePatchNum as PatchSetNumber,
forceReload: !this.hasEdit,
+ filePath,
+ currentChildView,
})
);
- fire(this, 'reload-diff', {path: fixSuggestion.replacements[0].path});
+
+ if (filePath) {
+ fire(this, 'reload-diff', {path: filePath});
+ }
fire(this, 'apply-user-suggestion', {
fixSuggestion: fixSuggestion.description.includes(
ReportSource.GET_AI_FIX_FOR_COMMENT
diff --git a/polygerrit-ui/app/elements/shared/gr-suggestion-diff-preview/gr-suggestion-diff-preview_test.ts b/polygerrit-ui/app/elements/shared/gr-suggestion-diff-preview/gr-suggestion-diff-preview_test.ts
index 742900f..da0220c 100644
--- a/polygerrit-ui/app/elements/shared/gr-suggestion-diff-preview/gr-suggestion-diff-preview_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-suggestion-diff-preview/gr-suggestion-diff-preview_test.ts
@@ -17,8 +17,21 @@
} from '../../../test/test-data-generators';
import {getAppContext} from '../../../services/app-context';
import {GrSuggestionDiffPreview} from './gr-suggestion-diff-preview';
-import {stubFlags} from '../../../test/test-utils';
-import {NumericChangeId, RevisionPatchSetNum} from '../../../api/rest-api';
+import * as sinon from 'sinon';
+import {navigationToken} from '../../core/gr-navigation/gr-navigation';
+import {stubFlags, stubRestApi} from '../../../test/test-utils';
+import {
+ NumericChangeId,
+ RepoName,
+ RevisionPatchSetNum,
+} from '../../../api/rest-api';
+import {changeViewModelToken} from '../../../models/views/change';
+import {
+ createChangeViewState,
+ createDiffViewState,
+ createRange,
+} from '../../../test/test-data-generators';
+import {testResolver} from '../../../test/common-test-setup';
suite('gr-suggestion-diff-preview tests', () => {
let element: GrSuggestionDiffPreview;
@@ -121,4 +134,53 @@
{ignoreAttributes: ['style']}
);
});
+
+ suite('applyFix navigation', () => {
+ let setUrlStub: sinon.SinonStub;
+
+ setup(() => {
+ setUrlStub = sinon.stub(testResolver(navigationToken), 'setUrl');
+ stubRestApi('applyFixSuggestion').returns(
+ Promise.resolve(new Response(null, {status: 200}))
+ );
+ element.changeNum = 42 as NumericChangeId;
+ element.repo = 'test-project' as RepoName;
+ element.patchSet = 1 as RevisionPatchSetNum;
+
+ element.fixSuggestionInfo = {
+ ...createFixSuggestionInfo(),
+ replacements: [
+ {
+ path: 'foo/bar.ts',
+ replacement: 'new content',
+ range: createRange(),
+ },
+ ],
+ };
+ });
+
+ test('navigates to createDiffUrl when in Diff View', async () => {
+ testResolver(changeViewModelToken).setState(createDiffViewState());
+
+ await element.applyFix();
+
+ assert.isTrue(setUrlStub.calledOnce);
+ assert.equal(
+ setUrlStub.lastCall.firstArg,
+ '/c/test-project/+/42/1..edit/foo/bar.ts?forceReload=true'
+ );
+ });
+
+ test('navigates to createChangeUrl when in Change View', async () => {
+ testResolver(changeViewModelToken).setState(createChangeViewState());
+
+ await element.applyFix();
+
+ assert.isTrue(setUrlStub.calledOnce);
+ assert.equal(
+ setUrlStub.lastCall.firstArg,
+ '/c/test-project/+/42/1..edit?forceReload=true'
+ );
+ });
+ });
});
diff --git a/polygerrit-ui/app/models/views/change.ts b/polygerrit-ui/app/models/views/change.ts
index 03c944f..0ee5e99 100644
--- a/polygerrit-ui/app/models/views/change.ts
+++ b/polygerrit-ui/app/models/views/change.ts
@@ -253,6 +253,9 @@
) {
params.push(`checksPatchset=${state.checksPatchset}`);
}
+ if (state.forceReload) {
+ params.push('forceReload=true');
+ }
if (params.length > 0) {
queryParams = '?' + params.join('&');
}
@@ -285,6 +288,26 @@
return `${createChangeUrlCommon(state)}${path},edit${suffix}`;
}
+export function createApplyFixUrl(
+ obj: (CreateChangeUrlObject | Omit<ChangeViewState, 'view' | 'childView'>) & {
+ filePath?: string;
+ currentChildView?: ChangeChildView;
+ }
+): string {
+ const {filePath, currentChildView, ...restObj} = obj;
+ if (currentChildView === ChangeChildView.DIFF && filePath) {
+ return createDiffUrl({
+ ...restObj,
+ patchNum: EDIT,
+ diffView: {path: filePath},
+ });
+ }
+ return createChangeUrl({
+ ...restObj,
+ patchNum: EDIT,
+ });
+}
+
/**
* The shared part of creating a change URL between OVERVIEW, DIFF and EDIT
* child views.
diff --git a/polygerrit-ui/app/models/views/change_test.ts b/polygerrit-ui/app/models/views/change_test.ts
index e05adb6..8bebe21 100644
--- a/polygerrit-ui/app/models/views/change_test.ts
+++ b/polygerrit-ui/app/models/views/change_test.ts
@@ -6,10 +6,13 @@
import {assert} from '@open-wc/testing';
import {
BasePatchSetNum,
+ EDIT,
+ NumericChangeId,
PatchSetNumber,
RepoName,
RevisionPatchSetNum,
} from '../../api/rest-api';
+
import '../../test/common-test-setup';
import {
createChangeViewState,
@@ -17,7 +20,9 @@
createEditViewState,
} from '../../test/test-data-generators';
import {
+ ChangeChildView,
ChangeViewState,
+ createApplyFixUrl,
createChangeUrl,
createDiffUrl,
createEditUrl,
@@ -114,6 +119,14 @@
);
});
+ test('forceReload', () => {
+ params.forceReload = true;
+ assert.equal(
+ createDiffUrl(params),
+ '/c/test-project/+/42/12/x%252By/path.cpp?forceReload=true'
+ );
+ });
+
test('base patchset', () => {
params.basePatchNum = 6 as BasePatchSetNum;
assert.equal(
@@ -186,4 +199,36 @@
assert.equal(createEditUrl(params).substring(0, 5), '/base');
window.CANONICAL_PATH = undefined;
});
+
+ suite('createApplyFixUrl', () => {
+ test('Diff View context', () => {
+ assert.equal(
+ createApplyFixUrl({
+ changeNum: 42 as NumericChangeId,
+ repo: 'test-project' as RepoName,
+ patchNum: EDIT,
+ basePatchNum: 1 as BasePatchSetNum,
+ forceReload: true,
+ filePath: 'foo/bar.ts',
+ currentChildView: ChangeChildView.DIFF,
+ }),
+ '/c/test-project/+/42/1..edit/foo/bar.ts?forceReload=true'
+ );
+ });
+
+ test('Overview context', () => {
+ assert.equal(
+ createApplyFixUrl({
+ changeNum: 42 as NumericChangeId,
+ repo: 'test-project' as RepoName,
+ patchNum: EDIT,
+ basePatchNum: 1 as BasePatchSetNum,
+ forceReload: true,
+ filePath: 'foo/bar.ts',
+ currentChildView: ChangeChildView.OVERVIEW,
+ }),
+ '/c/test-project/+/42/1..edit?forceReload=true'
+ );
+ });
+ });
});
diff --git a/resources/com/google/gerrit/server/mime/mime-types.properties b/resources/com/google/gerrit/server/mime/mime-types.properties
index 66f21b9..f557cfd 100644
--- a/resources/com/google/gerrit/server/mime/mime-types.properties
+++ b/resources/com/google/gerrit/server/mime/mime-types.properties
@@ -244,6 +244,7 @@
svg = application/xml
svh = text/x-systemverilog
swift = text/x-swift
+tada = text/x-python
tcl = text/x-tcl
tex = text/x-latex
text = text/plain