Add labels to the settings web interface
This new form allows project owners to configure the behavior of their
labels: what function should be used to allow/block submission, if the
change owner can self-approve his change, and when the votes should be
copied.
Change-Id: I180de2b6c3c5decf8192e84d960c37a861d9240a
diff --git a/gr-simple-submit-rules-label-config/gr-simple-submit-rules-label-config.html b/gr-simple-submit-rules-label-config/gr-simple-submit-rules-label-config.html
new file mode 100644
index 0000000..79bc203
--- /dev/null
+++ b/gr-simple-submit-rules-label-config/gr-simple-submit-rules-label-config.html
@@ -0,0 +1,219 @@
+<!--
+@license
+Copyright (C) 2018 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.
+-->
+<!-- TODO(maximeg) Import the web components when this issue is solved:
+ https://bugs.chromium.org/p/gerrit/issues/detail?id=8096 -->
+
+<dom-module id="gr-simple-submit-rules-label-config">
+ <template>
+ <style include="shared-styles"></style>
+ <style include="gr-form-styles"></style>
+ <style>
+ :host {
+ border: 1px solid var(--border-color);
+ display: block;
+ margin-bottom: 1em;
+ padding: 1em 1em;
+ }
+
+ fieldset {
+ border: 1px solid var(--border-color);
+ }
+ </style>
+
+ <main class="gr-form-styles">
+ <h3 id="options">Label [[labelName]]</h3>
+
+ <fieldset id="simple-submit-rules">
+
+ <section>
+ <span class="title">Should a vote with the maximum value be required?</span>
+ <span class="value">
+ <input id="maxVoteRequired"
+ type="checkbox"
+ checked="{{_maxVoteRequired::change}}"
+ disabled$="[[readOnly]]">
+ </span>
+ </section>
+
+ <section>
+ <span class="title">Should votes with the lowest value block submission?</span>
+ <span class="value">
+ <input id="negativeBlocks"
+ type="checkbox"
+ checked="{{_negativeBlocks::change}}"
+ disabled$="[[readOnly]]">
+ </span>
+ </section>
+
+ <section>
+ <span class="title">(Expert users) Function name</span>
+ <span class="value">
+ <gr-select id="functionName"
+ bind-value="{{_labelConfig.function}}">
+ <select disabled$="[[readOnly]]">
+ <option value="MaxNoBlock">MaxNoBlock</option>
+ <option value="MaxWithBlock">MaxWithBlock</option>
+ <option value="AnyWithBlock">AnyWithBlock</option>
+ <option value="NoBlock">NoBlock</option>
+ <option value="NoOp">NoOp</option>
+ </select>
+ </gr-select>
+ </span>
+ </section>
+
+ <section>
+ <span class="title">Allow approval by the change owner</span>
+ <span class="value">
+ <input id="allowUnresolvedComments"
+ type="checkbox"
+ checked="{{_labelConfig.ignore_self_approval::change}}"
+ disabled$="[[readOnly]]">
+ </span>
+ </section>
+ </fieldset>
+
+ <fieldset>
+ <section>
+ <span class="title">
+ When a new patchset is uploaded, Gerrit should copy votes ...
+ </span>
+ </section>
+
+ <!-- copyMinScore -->
+ <section>
+ <span class="title">
+ <gr-tooltip-content class="draftTooltip"
+ has-tooltip
+ title="Should votes of the minimal value be kept?"
+ max-width="20em"
+ show-icon>
+ with minimal value
+ </gr-tooltip-content>
+ </span>
+ <span class="value">
+ <input id="copyMinScore"
+ type="checkbox"
+ checked="{{_copyScores.copyMinScore::change}}"
+ disabled$="[[readOnly]]">
+ </span>
+ </section>
+
+ <!-- copyMaxScore -->
+ <section>
+ <span class="title">
+ <gr-tooltip-content class="draftTooltip"
+ has-tooltip
+ title="Should votes of the maximal value be kept?"
+ max-width="20em"
+ show-icon>
+ with maximal value
+ </gr-tooltip-content>
+ </span>
+ <span class="value">
+ <input id="copyMaxScore"
+ type="checkbox"
+ checked="{{_copyScores.copyMaxScore::change}}"
+ disabled$="[[readOnly]]">
+ </span>
+ </section>
+
+ <!-- copyAllScoresOnTrivialRebase -->
+ <section>
+ <span class="title">
+ <gr-tooltip-content class="draftTooltip"
+ has-tooltip
+ title="Should votes be kept when a trivial rebase
+ is done (same commit message and content, different parent)?"
+ max-width="20em"
+ show-icon>
+ on trivial rebase
+ </gr-tooltip-content>
+ </span>
+ <span class="value">
+ <input id="copyAllScoresOnTrivialRebase"
+ type="checkbox"
+ checked="{{_copyScores.copyAllScoresOnTrivialRebase::change}}"
+ disabled$="[[readOnly]]">
+ </span>
+ </section>
+
+ <!-- copyAllScoresIfNoCodeChange -->
+ <section>
+ <span class="title">
+ <gr-tooltip-content class="draftTooltip"
+ has-tooltip
+ title="Should votes be kept when the commit message is modified?
+ Changing the parent or changing files invalidates this."
+ max-width="20em"
+ show-icon>
+ when only the commit message is modified
+ </gr-tooltip-content>
+ </span>
+ <span class="value">
+ <input id="copyAllScoresIfNoCodeChange"
+ type="checkbox"
+ checked="{{_copyScores.copyAllScoresIfNoCodeChange::change}}"
+ disabled$="[[readOnly]]">
+ </span>
+ </section>
+
+ <!-- copyAllScoresIfNoChange -->
+ <section>
+ <span class="title">
+ <gr-tooltip-content class="draftTooltip"
+ has-tooltip
+ title="Should votes be kept when the commit metadata (author, commit
+ date) are modified? Changing anything else from the commit
+ (message, content, parent) invalidates this."
+ max-width="20em"
+ show-icon>
+ when only commit metatada are modified
+ </gr-tooltip-content>
+ </span>
+ <span class="value">
+ <input id="copyAllScoresIfNoChange"
+ type="checkbox"
+ checked="{{_copyScores.copyAllScoresIfNoChange::change}}"
+ disabled$="[[readOnly]]">
+ </span>
+ </section>
+
+ <!-- copyAllScoresOnMergeFirstParentUpdate -->
+ <section>
+ <span class="title">
+ <gr-tooltip-content class="draftTooltip"
+ has-tooltip
+ title="Only applies to Merge commits. Should votes be kept when the
+ destination commit of a merge commit is changed?"
+ max-width="20em"
+ show-icon>
+ on rebased merge commits
+ </gr-tooltip-content>
+ </span>
+ <span class="value">
+ <input id="copyAllScoresOnMergeFirstParentUpdate"
+ type="checkbox"
+ checked="{{_copyScores.copyAllScoresOnMergeFirstParentUpdate::change}}"
+ disabled$="[[readOnly]]">
+ </span>
+ </section>
+
+ </fieldset>
+ </main>
+ </template>
+ <script src="./gr-simple-submit-rules-label-config.js"></script>
+</dom-module>
diff --git a/gr-simple-submit-rules-label-config/gr-simple-submit-rules-label-config.js b/gr-simple-submit-rules-label-config/gr-simple-submit-rules-label-config.js
new file mode 100644
index 0000000..7e11c39
--- /dev/null
+++ b/gr-simple-submit-rules-label-config/gr-simple-submit-rules-label-config.js
@@ -0,0 +1,133 @@
+/**
+ * @license
+ * Copyright (C) 2018 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.
+ */
+
+(function () {
+ 'use strict';
+
+ const COPY_SCORES = [
+ 'copyMinScore',
+ 'copyMaxScore',
+ 'copyAllScoresOnTrivialRebase',
+ 'copyAllScoresIfNoCodeChange',
+ 'copyAllScoresIfNoChange',
+ 'copyAllScoresOnMergeFirstParentUpdate'
+ ];
+
+ Polymer({
+ is: 'gr-simple-submit-rules-label-config',
+
+ properties: {
+ labelName: String,
+ /** @type {?} */
+ repoConfig: {
+ type: Object,
+ notify: true,
+ },
+ readOnly: Boolean,
+ // The two "_updating" booleans are there to prevent an infinite loop:
+ // when the user changes a value, we update another value and this
+ // update in turn triggers the function again.
+ _updatingFunction: {
+ type: Boolean,
+ value: false
+ },
+ _updatingCopyScores: {
+ type: Boolean,
+ value: false
+ },
+ _labelConfig: {
+ type: Object,
+ computed: '_computeLabelConfig(repoConfig.labels, labelName)'
+ },
+ _copyScores: {
+ type: Object,
+ value: {},
+ },
+ _negativeBlocks: Boolean,
+ _maxVoteRequired: Boolean,
+ },
+
+ observers: [
+ '_observeFunctionChange(_labelConfig.function)',
+ '_observeFunctionDescriptorChange(_negativeBlocks, _maxVoteRequired)',
+ '_observeCopyScoresChange(_labelConfig.copy_scores)',
+ '_observeCopyScoresChangeInUi(_copyScores.*)',
+ ],
+
+ _observeFunctionDescriptorChange(negativeBlocks, maxVoteRequired) {
+ if (this._labelConfig === undefined) { return; }
+ if (this._updatingFunction) { return; }
+ this._updatingFunction = true;
+ let fName = '';
+
+ if (maxVoteRequired) {
+ fName = negativeBlocks ? 'MaxWithBlock' : 'MaxNoBlock';
+ } else {
+ fName = negativeBlocks ? 'AnyWithBlock' : 'NoBlock';
+ }
+ this.set('_labelConfig.function', fName);
+
+ this._updatingFunction = false;
+ },
+
+ _observeFunctionChange(_function) {
+ if (this._updatingFunction) { return; }
+ this._updatingFunction = true;
+
+ this._negativeBlocks = _function.indexOf('WithBlock') !== -1;
+ this._maxVoteRequired = _function.indexOf('Max') !== -1;
+
+ this._updatingFunction = false;
+ },
+
+ _computeLabelConfig(labels, labelName) {
+ this.linkPaths(['repoConfig.labels', labelName], '_labelConfig');
+ this.linkPaths('_labelConfig', ['repoConfig.labels', labelName]);
+ return labels[this.labelName] || {};
+ },
+
+ _observeCopyScoresChange() {
+ if (this._updatingCopyScores) { return; }
+ this._updatingCopyScores = true;
+
+ for (let key of COPY_SCORES) {
+ this.set(['_copyScores', key], false);
+ }
+ for (let value of this._labelConfig.copy_scores) {
+ this.set(['_copyScores', value], true);
+ }
+
+ this._updatingCopyScores = false;
+ },
+
+ _observeCopyScoresChangeInUi() {
+ if (this._updatingCopyScores) { return; }
+ this._updatingCopyScores = true;
+
+
+ let newCopyScores = [];
+ for (let key in this._copyScores) {
+ if (this._copyScores[key]) {
+ newCopyScores.push(key);
+ }
+ }
+ this.set('_labelConfig.copy_scores', newCopyScores);
+
+ this._updatingCopyScores = false;
+ },
+ });
+})();
diff --git a/gr-simple-submit-rules-label-config/gr-simple-submit-rules-label-config_test.html b/gr-simple-submit-rules-label-config/gr-simple-submit-rules-label-config_test.html
new file mode 100644
index 0000000..97408cf
--- /dev/null
+++ b/gr-simple-submit-rules-label-config/gr-simple-submit-rules-label-config_test.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<!--
+@license
+Copyright (C) 2016 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.
+-->
+<meta name="viewport"
+ content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+<title>gr-simple-submit-rules-label-config</title>
+
+<script src="../../../polygerrit-ui/app/bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
+<script src="../../../polygerrit-ui/app/bower_components/web-component-tester/browser.js"></script>
+<link rel="import"
+ href="../../../polygerrit-ui/app/test/common-test-setup.html" />
+<!-- TODO(maximeg) find if there is a better way to do this, like .. not in tests -->
+<link rel="import"
+ href="../../../polygerrit-ui/app/elements/shared/gr-select/gr-select.html" />
+<link rel="import"
+ href="../../../polygerrit-ui/app/styles/shared-styles.html" />
+<link rel="import"
+ href="../../../polygerrit-ui/app/styles/gr-form-styles.html" />
+
+<link rel="import"
+ href="gr-simple-submit-rules-label-config.html">
+
+<script>void (0);</script>
+
+<test-fixture id="basic">
+ <template>
+ <gr-simple-submit-rules-label-config label-name="Verified"
+ repo-config='{"labels": {"Verified": {"function": "MaxNoBlock", "copy_scores": []}}}'
+ readOnly="false">
+ </gr-simple-submit-rules-label-config>
+ </template>
+</test-fixture>
+
+<script>
+ const COPY_SCORES = [
+ 'copyMinScore',
+ 'copyMaxScore',
+ 'copyAllScoresOnTrivialRebase',
+ 'copyAllScoresIfNoCodeChange',
+ 'copyAllScoresIfNoChange',
+ 'copyAllScoresOnMergeFirstParentUpdate'
+ ];
+
+ suite('gr-simple-submit-rules-label-config tests', () => {
+ let element;
+ let sandbox;
+
+ setup(() => {
+ sandbox = sinon.sandbox.create();
+
+ element = fixture('basic');
+ });
+
+ teardown(() => {
+ sandbox.restore();
+ });
+
+ test('section title is correct', () => {
+ assert.equal(element.$$('#options').innerText.indexOf('Label Verified'), 0);
+ });
+
+ // The following tests check that changing the function name (from the REST API)
+ // has an impact on the displayed settings
+ test('function "MaxWithBlock" is properly mapped to UI', done => {
+ element.set('_labelConfig.function', 'MaxWithBlock');
+
+ flush(function () {
+ assert.ok(element.$$('#negativeBlocks').checked);
+ assert.ok(element.$$('#maxVoteRequired').checked);
+ assert.equal(element.$$('#functionName select').value, 'MaxWithBlock');
+ done();
+ });
+ });
+
+ test('function "MaxNoBlock" is properly mapped to UI', done => {
+ element.set('_labelConfig.function', 'MaxNoBlock');
+
+ flush(function () {
+ assert.equal(element.$$('#negativeBlocks').checked, false);
+ assert.ok(element.$$('#maxVoteRequired').checked);
+ assert.equal(element.$$('#functionName select').value, 'MaxNoBlock');
+ done();
+ });
+ });
+
+ test('function "NoBlock" is properly mapped to UI', done => {
+ element.set('_labelConfig.function', 'NoBlock');
+
+ flush(function () {
+ assert.equal(element.$$('#negativeBlocks').checked, false);
+ assert.equal(element.$$('#maxVoteRequired').checked, false);
+ assert.equal(element.$$('#functionName select').value, 'NoBlock');
+ done();
+ });
+ });
+
+ test('function "AnyWithBlock" is properly mapped to UI', done => {
+ element.set('_labelConfig.function', 'AnyWithBlock');
+
+ flush(function () {
+ assert.ok(element.$$('#negativeBlocks').checked);
+ assert.equal(element.$$('#maxVoteRequired').checked, false);
+ assert.equal(element.$$('#functionName select').value, 'AnyWithBlock');
+ done();
+ });
+ });
+
+ // The following tests check that changing the function from the UI has a
+ // visible impact on the easy checkboxes options, while keeping the function
+ // name intact.
+ test('picking function "MaxWithBlock" correctly updates the UI', done => {
+ element.$$('#functionName select').value = 'MaxWithBlock';
+ element.$$('#functionName').dispatchEvent(new Event('change'));
+
+ flush(function () {
+ assert.ok(element.$$('#negativeBlocks').checked);
+ assert.ok(element.$$('#maxVoteRequired').checked);
+ assert.equal(element.$$('#functionName select').value, 'MaxWithBlock');
+ done();
+ });
+ });
+
+ test('picking function "NoBlock" correctly updates the UI', done => {
+ element.$$('#functionName select').value = 'NoBlock';
+ element.$$('#functionName').dispatchEvent(new Event('change'));
+
+ flush(function () {
+ assert.equal(element.$$('#negativeBlocks').checked, false);
+ assert.equal(element.$$('#maxVoteRequired').checked, false);
+ assert.equal(element.$$('#functionName select').value, 'NoBlock');
+ done();
+ });
+ });
+
+ test('picking function "AnyWithBlock" correctly updates the UI', done => {
+ element.$$('#functionName select').value = 'AnyWithBlock';
+ element.$$('#functionName').dispatchEvent(new Event('change'));
+
+ flush(function () {
+ assert.ok(element.$$('#negativeBlocks').checked);
+ assert.equal(element.$$('#maxVoteRequired').checked, false);
+ assert.equal(element.$$('#functionName select').value, 'AnyWithBlock');
+ done();
+ });
+ });
+
+ test('picking function "MaxNoBlock" correctly updates the UI', done => {
+ element.$$('#functionName select').value = 'MaxNoBlock';
+ element.$$('#functionName').dispatchEvent(new Event('change'));
+
+ flush(function () {
+ assert.equal(element.$$('#negativeBlocks').checked, false);
+ assert.ok(element.$$('#maxVoteRequired').checked);
+ assert.equal(element.$$('#functionName select').value, 'MaxNoBlock');
+ done();
+ });
+ });
+
+ // The following tests check that the easy way to define the function
+ // ("negative blocks?" and "max vote required?") maps to the right function,
+ // without impacting the user choices.
+ test('function "MaxWithBlock" is properly suggested from UI', done => {
+ element.$$('#negativeBlocks').checked = true;
+ element.$$('#negativeBlocks').dispatchEvent(new Event('change'));
+
+ element.$$('#maxVoteRequired').checked = 'true';
+ element.$$('#maxVoteRequired').dispatchEvent(new Event('change'));
+
+ flush(function () {
+ assert.ok(element.$$('#negativeBlocks').checked);
+ assert.ok(element.$$('#maxVoteRequired').checked);
+ assert.equal(element.$$('#functionName select').value, 'MaxWithBlock');
+ done();
+ });
+ });
+
+ test('function "NoBlock" is properly suggested from UI', done => {
+ element.$$('#negativeBlocks').checked = false;
+ element.$$('#negativeBlocks').dispatchEvent(new Event('change'));
+
+ element.$$('#maxVoteRequired').checked = false;
+ element.$$('#maxVoteRequired').dispatchEvent(new Event('change'));
+
+ flush(function () {
+ assert.equal(element.$$('#negativeBlocks').checked, false);
+ assert.equal(element.$$('#maxVoteRequired').checked, false);
+ assert.equal(element.$$('#functionName select').value, 'NoBlock');
+ done();
+ });
+ });
+
+ test('function "AnyWithBlock" is properly suggested from UI', done => {
+ element.$$('#negativeBlocks').checked = true;
+ element.$$('#negativeBlocks').dispatchEvent(new Event('change'));
+
+ element.$$('#maxVoteRequired').checked = false;
+ element.$$('#maxVoteRequired').dispatchEvent(new Event('change'));
+
+ flush(function () {
+ assert.ok(element.$$('#negativeBlocks').checked);
+ assert.equal(element.$$('#maxVoteRequired').checked, false);
+ assert.equal(element.$$('#functionName select').value, 'AnyWithBlock');
+ done();
+ });
+ });
+
+ test('function "MaxNoBlock" is properly suggested from UI', done => {
+ element.$$('#negativeBlocks').checked = false;
+
+ element.$$('#maxVoteRequired').checked = 'true';
+ element.$$('#maxVoteRequired').dispatchEvent(new Event('change'));
+
+ flush(function () {
+ assert.equal(element.$$('#negativeBlocks').checked, false);
+ assert.ok(element.$$('#maxVoteRequired').checked);
+ assert.equal(element.$$('#functionName select').value, 'MaxNoBlock');
+ done();
+ });
+ });
+
+ // The following tests check that "copy scores" are correctly mapped *to* and
+ // *from* the UI, for the two possible boolean values.
+ for (let copyScoreName of COPY_SCORES) {
+ let elName = '#' + copyScoreName;
+
+ test('copyScore.' + copyScoreName + ' [false] is reflected *in* the UI', () => {
+ assert.equal(element.$$(elName).checked, false);
+ });
+
+ test('copyScore.' + copyScoreName + ' [true] is reflected in the UI', done => {
+ element.set('_labelConfig.copy_scores', [copyScoreName]);
+
+ flush(function () {
+ assert.ok(element.$$(elName).checked);
+ done();
+ });
+ });
+ }
+
+
+ for (let copyScoreName of COPY_SCORES) {
+ let elName = '#' + copyScoreName;
+
+ test('copyScore.' + copyScoreName + ' is reflected *from* the UI', done => {
+ element.$$(elName).checked = 'true';
+ element.$$(elName).dispatchEvent(new Event('change'));
+
+ flush(function () {
+ assert.deepEqual(element.repoConfig.labels.Verified.copy_scores, [copyScoreName]);
+ done();
+ });
+ });
+ }
+
+ });
+</script>
diff --git a/gr-simple-submit-rules-repo-config/gr-simple-submit-rules-repo-config.html b/gr-simple-submit-rules-repo-config/gr-simple-submit-rules-repo-config.html
index 44e3db1..23cc805 100644
--- a/gr-simple-submit-rules-repo-config/gr-simple-submit-rules-repo-config.html
+++ b/gr-simple-submit-rules-repo-config/gr-simple-submit-rules-repo-config.html
@@ -15,6 +15,11 @@
limitations under the License.
-->
+<link rel="import"
+ href="../gr-simple-submit-rules-label-config/gr-simple-submit-rules-label-config.html">
+<!-- TODO(maximeg) Import the web components when this issue is solved:
+ https://bugs.chromium.org/p/gerrit/issues/detail?id=8096 -->
+
<dom-module id="gr-simple-submit-rules-repo-config">
<template>
<style include="shared-styles"></style>
@@ -36,6 +41,18 @@
</gr-select>
</span>
</section>
+
+ <template is="dom-repeat"
+ id="allLabels"
+ items="[[_labels]]"
+ initial-count="5"
+ target-framerate="60">
+ <gr-simple-submit-rules-label-config mutable-data
+ label-name="[[item]]"
+ repo-config="{{_repoConfig}}"
+ read-only="[[_readOnly]]">
+ </gr-simple-submit-rules-label-config>
+ </template>
</fieldset>
<gr-button on-tap="_handleSaveRepoConfig"
diff --git a/gr-simple-submit-rules-repo-config/gr-simple-submit-rules-repo-config.js b/gr-simple-submit-rules-repo-config/gr-simple-submit-rules-repo-config.js
index c9daafe..f745939 100644
--- a/gr-simple-submit-rules-repo-config/gr-simple-submit-rules-repo-config.js
+++ b/gr-simple-submit-rules-repo-config/gr-simple-submit-rules-repo-config.js
@@ -33,7 +33,12 @@
value: true,
},
_restApi: Object,
- },
+ _labels: {
+ type: Array,
+ value() { return []; },
+ computed: '_computeLabelNames(_repoConfig.*)',
+ },
+ },
observers: [
'_handleConfigChanged(_repoConfig.*)',
@@ -75,7 +80,7 @@
promises.push(this._pluginRestApi().get(this._endpointUrl())
.then(config => {
if (!config) { return; }
- this._repoConfig = config;
+ this.set('_repoConfig', config);
this._loading = false;
}));
@@ -120,5 +125,12 @@
return this._pluginRestApi().get('/access/?project=' + encodeURIComponent(repoName));
},
+ _computeLabelNames() {
+ if (this._repoConfig && this._repoConfig.labels) {
+ return Object.keys(this._repoConfig.labels);
+ }
+ return [];
+ },
+
});
})();
diff --git a/gr-simple-submit-rules-repo-config/gr-simple-submit-rules-repo-config_test.html b/gr-simple-submit-rules-repo-config/gr-simple-submit-rules-repo-config_test.html
index 4e35e86..f71b6f7 100644
--- a/gr-simple-submit-rules-repo-config/gr-simple-submit-rules-repo-config_test.html
+++ b/gr-simple-submit-rules-repo-config/gr-simple-submit-rules-repo-config_test.html
@@ -60,6 +60,7 @@
comments: {
block_if_unresolved_comments: false,
},
+ labels: {},
});
},
getLoggedIn() { return Promise.resolve(true); },
@@ -98,6 +99,42 @@
assert.equal(unresolvedCommentsEl.disabled, true);
});
+ test('adds a label element', done => {
+ element.set(['_repoConfig', 'labels', 'Verified'], {
+ function: 'MaxNoBlock',
+ copy_scores: []
+ });
+ flush(function () {
+ let labelItems = element.querySelectorAll('gr-simple-submit-rules-label-config');
+ assert.ok(labelItems);
+ assert.equal(labelItems.length, 1);
+
+ let labelEl = labelItems[0];
+ assert.ok(labelEl);
+ assert.equal(labelEl.labelName, 'Verified');
+ assert.equal(labelEl.readOnly, false);
+ done();
+ });
+ });
+
+ test('adds two labels elements', done => {
+ element.set(['_repoConfig', 'labels', 'Verified'], {
+ function: 'MaxNoBlock',
+ copy_scores: []
+ });
+
+ element.set(['_repoConfig', 'labels', 'Code-Review'], {
+ function: 'MaxNoBlock',
+ copy_scores: []
+ });
+
+ flush(function () {
+ let labelItems = element.querySelectorAll('gr-simple-submit-rules-label-config');
+ assert.equal(labelItems.length, 2);
+ done();
+ });
+ });
+
test('unresolved comment uses the repoConfig value (false)', done => {
element.set('_repoConfig.comments.block_if_unresolved_comments', false);
diff --git a/tests.html b/tests.html
index e4dbfc4..32c3317 100644
--- a/tests.html
+++ b/tests.html
@@ -11,6 +11,7 @@
<script>
WCT.loadSuites([
'gr-simple-submit-rules-repo-config/gr-simple-submit-rules-repo-config_test.html',
+ 'gr-simple-submit-rules-label-config/gr-simple-submit-rules-label-config_test.html'
]);
</script>
</body>