Merge "config-mail.txt: note about necessary restart" into stable-3.4
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
index 180f2a2..c9ba093 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
@@ -175,6 +175,12 @@
import {debounce, DelayedTask} from '../../../utils/async-util';
import {Timing} from '../../../constants/reporting';
+const CHANGE_ID_ERROR = {
+ MISMATCH: 'mismatch',
+ MISSING: 'missing',
+};
+const CHANGE_ID_REGEX_PATTERN = /^(Change-Id:\s|Link:.*\/id\/)(I[0-9a-f]{8,40})/gm;
+
const MIN_LINES_FOR_COMMIT_COLLAPSE = 17;
const REVIEWERS_REGEX = /^(R|CC)=/gm;
@@ -374,6 +380,13 @@
@property({type: Number})
_lineHeight?: number;
+ @property({
+ type: String,
+ computed:
+ '_computeChangeIdCommitMessageError(_latestCommitMessage, _change)',
+ })
+ _changeIdCommitMessageError?: string;
+
@property({type: Object})
_patchRange?: ChangeViewPatchRange;
@@ -1511,6 +1524,53 @@
);
}
+ _computeChangeIdClass(displayChangeId: string) {
+ return displayChangeId === CHANGE_ID_ERROR.MISMATCH ? 'warning' : '';
+ }
+
+ _computeTitleAttributeWarning(displayChangeId: string) {
+ if (displayChangeId === CHANGE_ID_ERROR.MISMATCH) {
+ return 'Change-Id mismatch';
+ } else if (displayChangeId === CHANGE_ID_ERROR.MISSING) {
+ return 'No Change-Id in commit message';
+ }
+ return undefined;
+ }
+
+ _computeChangeIdCommitMessageError(
+ commitMessage?: string,
+ change?: ChangeInfo
+ ) {
+ if (change === undefined) {
+ return undefined;
+ }
+
+ if (!commitMessage) {
+ return CHANGE_ID_ERROR.MISSING;
+ }
+
+ // Find the last match in the commit message:
+ let changeId;
+ let changeIdArr;
+
+ while ((changeIdArr = CHANGE_ID_REGEX_PATTERN.exec(commitMessage))) {
+ changeId = changeIdArr[2];
+ }
+
+ if (changeId) {
+ // A change-id is detected in the commit message.
+
+ if (changeId === change.change_id) {
+ // The change-id found matches the real change-id.
+ return null;
+ }
+ // The change-id found does not match the change-id.
+ return CHANGE_ID_ERROR.MISMATCH;
+ }
+ // There is no change-id in the commit message.
+ return CHANGE_ID_ERROR.MISSING;
+ }
+
_computeReplyButtonLabel(
changeRecord?: ElementPropertyDeepChange<
GrChangeView,
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.ts
index cb72ba7..01045850 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.ts
@@ -91,6 +91,11 @@
background-color: var(--view-background-color);
box-shadow: var(--elevation-level-1);
}
+ .changeId {
+ color: var(--deemphasized-text-color);
+ font-family: var(--font-family);
+ margin-top: var(--spacing-l);
+ }
.changeMetadata {
/* Limit meta section to half of the screen at max */
max-width: 50%;
@@ -428,6 +433,19 @@
remove-zero-width-space=""
></gr-linked-text>
</gr-editable-content>
+ <div
+ class="changeId"
+ hidden$="[[!_changeIdCommitMessageError]]"
+ >
+ <hr />
+ Change-Id:
+ <span
+ class$="[[_computeChangeIdClass(_changeIdCommitMessageError)]]"
+ title$="[[_computeTitleAttributeWarning(_changeIdCommitMessageError)]]"
+ >
+ [[_change.change_id]]
+ </span>
+ </div>
</div>
<gr-change-summary
change-comments="[[_changeComments]]"
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
index d8aebcb..d3d424e 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
@@ -1661,6 +1661,104 @@
assert.equal(putStub.lastCall.args[1], '\n\n\n\n\n\n\n\n');
});
+ test('_computeChangeIdCommitMessageError', () => {
+ let commitMessage = 'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282483';
+ let change: ChangeInfo = {
+ ...createChangeViewChange(),
+ change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282483' as ChangeId,
+ };
+ assert.equal(
+ element._computeChangeIdCommitMessageError(commitMessage, change),
+ null
+ );
+
+ change = {
+ ...createChangeViewChange(),
+ change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282484' as ChangeId,
+ };
+ assert.equal(
+ element._computeChangeIdCommitMessageError(commitMessage, change),
+ 'mismatch'
+ );
+
+ commitMessage = 'This is the greatest change.';
+ assert.equal(
+ element._computeChangeIdCommitMessageError(commitMessage, change),
+ 'missing'
+ );
+ });
+
+ test('multiple change Ids in commit message picks last', () => {
+ const commitMessage = [
+ 'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282484',
+ 'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282483',
+ ].join('\n');
+ let change: ChangeInfo = {
+ ...createChangeViewChange(),
+ change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282483' as ChangeId,
+ };
+ assert.equal(
+ element._computeChangeIdCommitMessageError(commitMessage, change),
+ null
+ );
+ change = {
+ ...createChangeViewChange(),
+ change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282484' as ChangeId,
+ };
+ assert.equal(
+ element._computeChangeIdCommitMessageError(commitMessage, change),
+ 'mismatch'
+ );
+ });
+
+ test('does not count change Id that starts mid line', () => {
+ const commitMessage = [
+ 'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282484',
+ 'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282483',
+ ].join(' and ');
+ let change: ChangeInfo = {
+ ...createChangeViewChange(),
+ change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282484' as ChangeId,
+ };
+ assert.equal(
+ element._computeChangeIdCommitMessageError(commitMessage, change),
+ null
+ );
+ change = {
+ ...createChangeViewChange(),
+ change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282483' as ChangeId,
+ };
+ assert.equal(
+ element._computeChangeIdCommitMessageError(commitMessage, change),
+ 'mismatch'
+ );
+ });
+
+ test('_computeTitleAttributeWarning', () => {
+ let changeIdCommitMessageError = 'missing';
+ assert.equal(
+ element._computeTitleAttributeWarning(changeIdCommitMessageError),
+ 'No Change-Id in commit message'
+ );
+
+ changeIdCommitMessageError = 'mismatch';
+ assert.equal(
+ element._computeTitleAttributeWarning(changeIdCommitMessageError),
+ 'Change-Id mismatch'
+ );
+ });
+
+ test('_computeChangeIdClass', () => {
+ let changeIdCommitMessageError = 'missing';
+ assert.equal(element._computeChangeIdClass(changeIdCommitMessageError), '');
+
+ changeIdCommitMessageError = 'mismatch';
+ assert.equal(
+ element._computeChangeIdClass(changeIdCommitMessageError),
+ 'warning'
+ );
+ });
+
test('topic is coalesced to null', done => {
sinon.stub(element, '_changeChanged');
stubRestApi('getChangeDetail').returns(