Merge "Update Bazel version to 7.6.1"
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
index 0393242..46da136 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
@@ -1375,26 +1375,18 @@
   }
 
   async showRevertDialog() {
-    const change = this.change;
-    if (!change) return;
-    const query = `submissionid: "${change.submission_id}"`;
-    /* A chromium plugin expects that the modifyRevertMsg hook will only
-    be called after the revert button is pressed, hence we populate the
-    revert dialog after revert button is pressed. */
-    const [changes, validationOptions] = await Promise.all([
-      this.restApiService.getChanges(0, query),
-      this.restApiService.getValidationOptions(this.change!._number),
-    ]);
-    if (!changes) {
+    if (!this.change) return;
+    assertIsDefined(this.confirmRevertDialog, 'confirmRevertDialog');
+    if (
+      !(await this.confirmRevertDialog.populate(
+        this.change,
+        this.commitMessage
+      ))
+    ) {
+      // This indicates error in REST response that will show error dialog, no
+      // need to open revert dialog.
       return;
     }
-    assertIsDefined(this.confirmRevertDialog, 'confirmRevertDialog');
-    this.confirmRevertDialog.populate(
-      change,
-      validationOptions,
-      this.commitMessage,
-      changes.length
-    );
     this.showActionDialog(this.confirmRevertDialog);
   }
 
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.ts b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.ts
index ed4c9c5..7131586 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.ts
@@ -55,10 +55,7 @@
 import {GrConfirmRebaseDialog} from '../gr-confirm-rebase-dialog/gr-confirm-rebase-dialog';
 import {GrConfirmMoveDialog} from '../gr-confirm-move-dialog/gr-confirm-move-dialog';
 import {GrConfirmAbandonDialog} from '../gr-confirm-abandon-dialog/gr-confirm-abandon-dialog';
-import {
-  GrConfirmRevertDialog,
-  RevertType,
-} from '../gr-confirm-revert-dialog/gr-confirm-revert-dialog';
+import {GrConfirmRevertDialog} from '../gr-confirm-revert-dialog/gr-confirm-revert-dialog';
 import {testResolver} from '../../../test/common-test-setup';
 import {storageServiceToken} from '../../../services/storage/gr-storage_impl';
 import {pluginLoaderToken} from '../../shared/gr-js-api-interface/gr-plugin-loader';
@@ -66,7 +63,6 @@
   ChangeModel,
   changeModelToken,
 } from '../../../models/change/change-model';
-import {assertIsDefined} from '../../../utils/common-util';
 import {GrAutogrowTextarea} from '../../shared/gr-autogrow-textarea/gr-autogrow-textarea';
 
 // TODO(dhruvsri): remove use of _populateRevertMessage as it's private
@@ -2619,45 +2615,6 @@
           });
         });
 
-        test('sends validation options when opening revert dialog', async () => {
-          sinon.stub(element, 'handleAction');
-          const fireActionStub = sinon.stub(element, 'fireAction');
-          element.actions = {
-            revert: {
-              method: HttpMethod.POST,
-              label: 'Revert',
-              title: 'Revert the change',
-              enabled: true,
-            },
-          };
-          const confirmRevertDialog = query<GrConfirmRevertDialog>(
-            element,
-            '#confirmRevertDialog'
-          );
-          assertIsDefined(confirmRevertDialog, 'confirmDialog');
-          const populateRevertDialogStub = sinon.stub(
-            confirmRevertDialog,
-            'populate'
-          );
-          await element.showRevertDialog();
-          await waitUntil(() => !!populateRevertDialogStub.called);
-          assert.deepEqual(populateRevertDialogStub.lastCall.args[1], {
-            validation_options: [{name: 'o1', description: 'option 1'}],
-          });
-
-          element.handleRevertDialogConfirm(
-            new CustomEvent('confirm', {
-              detail: {
-                revertType: RevertType.REVERT_SINGLE_CHANGE,
-                message: 'revert this change',
-              },
-            })
-          );
-          await waitUntil(() => !!fireActionStub.called);
-
-          assert.deepEqual(fireActionStub.lastCall.args[0], '/revert');
-        });
-
         suite('multiple changes revert', () => {
           let showActionDialogStub: sinon.SinonStub;
           let setUrlStub: sinon.SinonStub;
diff --git a/polygerrit-ui/app/elements/change/gr-change-autocomplete/gr-change-autocomplete.ts b/polygerrit-ui/app/elements/change/gr-change-autocomplete/gr-change-autocomplete.ts
index fb20cf3..5c1ca29 100644
--- a/polygerrit-ui/app/elements/change/gr-change-autocomplete/gr-change-autocomplete.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-autocomplete/gr-change-autocomplete.ts
@@ -79,7 +79,7 @@
         /* changeNumber=*/ 450,
         'is:open -age:90d',
         /* offset=*/ undefined,
-        /* options=*/ undefined,
+        /* options=*/ '0',
         throwingErrorCallback
       );
       if (!res) {
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 0409f80..20bfeec 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
@@ -727,7 +727,7 @@
       change.labels = {};
       element.change = change;
 
-      changeModel.setState({
+      changeModel.updateState({
         loadingStatus: LoadingStatus.LOADED,
         change,
       });
@@ -1424,7 +1424,7 @@
         changeNum: TEST_NUMERIC_CHANGE_ID,
         repo: TEST_PROJECT_NAME,
       };
-      changeModel.setState({
+      changeModel.updateState({
         loadingStatus: LoadingStatus.LOADED,
         change: {
           ...createChangeViewChange(),
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_test.ts b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_test.ts
index 30cf475..eac869d 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_test.ts
@@ -131,7 +131,7 @@
       element.branch = 'test' as BranchName;
       await element.updateComplete;
       changeModel = testResolver(changeModelToken);
-      changeModel.setState({
+      changeModel.updateState({
         loadingStatus: LoadingStatus.LOADED,
         change,
       });
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.ts
index 52ae1c2..26aefd5 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.ts
@@ -26,6 +26,7 @@
 import {GrAutogrowTextarea} from '../../shared/gr-autogrow-textarea/gr-autogrow-textarea';
 import '@material/web/radio/radio';
 import {materialStyles} from '../../../styles/gr-material-styles';
+import {getAppContext} from '../../../services/app-context';
 
 const ERR_COMMIT_NOT_FOUND = 'Unable to find the commit hash of this change.';
 const SPECIFY_REASON_STRING = '<MUST SPECIFY REASON HERE>';
@@ -83,6 +84,8 @@
 
   private readonly getPluginLoader = resolve(this, pluginLoaderToken);
 
+  private readonly restApiService = getAppContext().restApiService;
+
   static override get styles() {
     return [
       formStyles,
@@ -222,13 +225,31 @@
     );
   }
 
-  populate(
+  /**
+   * Fetches required information and populates the dialog message.
+   *
+   * Returns `false` if the dialog shouldn't be shown.
+   */
+  async populate(
     change: ParsedChangeInfo,
-    validationOptions: ValidationOptionsInfo | undefined,
-    commitMessage: string,
-    changesCount: number
-  ) {
-    this.changesCount = changesCount;
+    commitMessage: string
+  ): Promise<boolean> {
+    const query = `submissionid: "${change.submission_id}"`;
+    /* A chromium plugin expects that the modifyRevertMsg hook will only
+    be called after the revert button is pressed, hence we populate the
+    revert dialog after revert button is pressed. */
+    const [changes, validationOptions] = await Promise.all([
+      // Specify options 0 to explicitly not request any additional information,
+      // as opposed to using default, since we only care about number of
+      // changes.
+      this.restApiService.getChanges(0, query, undefined, /* options=*/ '0'),
+      this.restApiService.getValidationOptions(change._number),
+    ]);
+    if (!changes) {
+      return false;
+    }
+
+    this.changesCount = changes.length;
     this.validationOptions = validationOptions;
     // The option to revert a single change is always available
     this.populateRevertSingleChangeMessage(
@@ -237,6 +258,7 @@
       change.current_revision
     );
     this.populateRevertSubmissionMessage(change, commitMessage);
+    return true;
   }
 
   populateRevertSingleChangeMessage(
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_test.ts b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_test.ts
index 7077099..acdb84b 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_test.ts
@@ -6,10 +6,21 @@
 import * as sinon from 'sinon';
 import {assert, fixture, html} from '@open-wc/testing';
 import '../../../test/common-test-setup';
-import {createParsedChange} from '../../../test/test-data-generators';
-import {ChangeSubmissionId, CommitId} from '../../../types/common';
+import {
+  createChange,
+  createParsedChange,
+} from '../../../test/test-data-generators';
+import {
+  ChangeId,
+  ChangeSubmissionId,
+  CommitId,
+  TopicName,
+  ValidationOptionsInfo,
+} from '../../../types/common';
 import './gr-confirm-revert-dialog';
 import {GrConfirmRevertDialog} from './gr-confirm-revert-dialog';
+import {stubRestApi} from '../../../test/test-utils';
+import {ParsedChangeInfo} from '../../../types/types';
 
 suite('gr-confirm-revert-dialog tests', () => {
   let element: GrConfirmRevertDialog;
@@ -129,4 +140,44 @@
       'Reverted changes: /q/submissionid:5545\n';
     assert.equal(element.message, expected);
   });
+
+  suite('populate tests', () => {
+    let change: ParsedChangeInfo;
+
+    setup(async () => {
+      change = {
+        ...createParsedChange(),
+        submission_id: '5545' as ChangeSubmissionId,
+        current_revision: 'abcd123' as CommitId,
+      };
+      stubRestApi('getChanges').returns(
+        Promise.resolve([
+          {
+            ...createChange(),
+            change_id: '12345678901234' as ChangeId,
+            topic: 'T' as TopicName,
+            subject: 'random',
+          },
+          {
+            ...createChange(),
+            change_id: '23456' as ChangeId,
+            topic: 'T' as TopicName,
+            subject: 'a'.repeat(100),
+          },
+        ])
+      );
+      stubRestApi('getValidationOptions').returns(
+        Promise.resolve({
+          validation_options: [{name: 'o1', description: 'option 1'}],
+        } as ValidationOptionsInfo)
+      );
+    });
+
+    test('validation options are fetched when populating revert dialog', async () => {
+      await element.populate(change, 'commit message');
+      assert.deepEqual(element.validationOptions, {
+        validation_options: [{name: 'o1', description: 'option 1'}],
+      });
+    });
+  });
 });
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
index 04c8618..88e029a 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
@@ -1615,6 +1615,10 @@
         );
         if (reloadRequired) {
           fireReload(this);
+        } else {
+          // Only reload submittability if the full reload is not triggered, to
+          // avoid duplicate requests.
+          this.getChangeModel().reloadSubmittability();
         }
 
         this.patchsetLevelDraftMessage = '';
diff --git a/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements.ts b/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements.ts
index 377a649..5972b41 100644
--- a/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements.ts
+++ b/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements.ts
@@ -13,7 +13,7 @@
 import '../../checks/gr-checks-chip-for-label';
 import {css, html, LitElement, nothing, TemplateResult} from 'lit';
 import {customElement, property, state} from 'lit/decorators.js';
-import {ParsedChangeInfo} from '../../../types/types';
+import {LoadingStatus, ParsedChangeInfo} from '../../../types/types';
 import {repeat} from 'lit/directives/repeat.js';
 import {
   AccountInfo,
@@ -49,6 +49,7 @@
 import {subscribe} from '../../lit/subscription-controller';
 import {when} from 'lit/directives/when.js';
 import {spinnerStyles} from '../../../styles/gr-spinner-styles';
+import {changeModelToken} from '../../../models/change/change-model';
 
 /**
  * @attr {Boolean} suppress-title - hide titles, currently for hovercard view
@@ -73,6 +74,9 @@
   @state()
   runs: CheckRun[] = [];
 
+  @state()
+  requirementsLoading?: boolean;
+
   static override get styles() {
     return [
       fontStyles,
@@ -147,6 +151,8 @@
 
   private readonly getChecksModel = resolve(this, checksModelToken);
 
+  private readonly getChangeModel = resolve(this, changeModelToken);
+
   constructor() {
     super();
     subscribe(
@@ -154,6 +160,11 @@
       () => this.getChecksModel().allRunsLatestPatchsetLatestAttempt$,
       x => (this.runs = x)
     );
+    subscribe(
+      this,
+      () => this.getChangeModel().submittabilityLoadingStatus$,
+      x => (this.requirementsLoading = x === LoadingStatus.LOADING)
+    );
   }
 
   override render() {
@@ -173,7 +184,7 @@
       >
         Submit Requirements
         ${when(
-          submit_requirements.length === 0,
+          this.requirementsLoading,
           () =>
             html`<span
               class="loadingSpin"
diff --git a/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements_test.ts b/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements_test.ts
index aee2017..8f55c29 100644
--- a/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements_test.ts
@@ -72,6 +72,7 @@
         submittable: false,
       },
       loadingStatus: LoadingStatus.LOADED,
+      submittabilityLoadingStatus: LoadingStatus.LOADED,
     });
     element = await fixture<GrSubmitRequirements>(
       html`<gr-submit-requirements
@@ -138,6 +139,32 @@
     );
   });
 
+  test('renders loading', async () => {
+    element.requirementsLoading = true;
+    element.change = {
+      ...element.change,
+      submit_requirements: undefined,
+    } as ParsedChangeInfo;
+    await element.updateComplete;
+    assert.shadowDom.equal(
+      element,
+      /* HTML */ `
+        <h3 class="heading-3 metadata-title" id="submit-requirements-caption">
+          Submit Requirements
+          <span
+            class="loadingSpin"
+            title="Submit Requirements status is being updated"
+          >
+          </span>
+        </h3>
+        <h3 class="heading-3 metadata-title">Label Votes</h3>
+        <section class="trigger-votes">
+          <gr-trigger-vote> </gr-trigger-vote>
+        </section>
+      `
+    );
+  });
+
   suite('votes-cell', () => {
     setup(async () => {
       element.disableEndpoints = true;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.ts b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.ts
index 4881f49..ca12afd 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.ts
@@ -1380,7 +1380,7 @@
         };
         userModel.setDiffPreferences(diffPreferences);
         viewModel.updateState({diffView: {path: 'wheatley.md'}});
-        changeModel.setState({
+        changeModel.updateState({
           change: createParsedChange(),
           reviewedFiles: [],
           loadingStatus: LoadingStatus.LOADED,
@@ -1412,7 +1412,7 @@
       };
       userModel.setDiffPreferences(diffPreferences);
       viewModel.updateState({diffView: {path: 'wheatley.md'}});
-      changeModel.setState({
+      changeModel.updateState({
         change: createParsedChange(),
         reviewedFiles: [],
         loadingStatus: LoadingStatus.LOADED,
@@ -1433,7 +1433,7 @@
         basePatchNum: PARENT,
         diffView: {path: '/COMMIT_MSG'},
       });
-      changeModel.setState({
+      changeModel.updateState({
         change: createParsedChange(),
         reviewedFiles: [],
         loadingStatus: LoadingStatus.LOADED,
diff --git a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
index 2bf84fe..0a14ef7 100644
--- a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
+++ b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
@@ -170,11 +170,12 @@
           //     [/?#]           //   Start with one of / ? #
           //     [^\s'"]*        //   Followed by some chars that are not whitespace,
           //                     //   ' or " (to not grab trailing quotes)
+          //     (?<![.,])       //   and not ending with '.' or ','
           //   )                 // End path/query/fragment group
           // )                   // End capture group 1
           // (?=\s|$|[)'"!?.,])  // Ensure the match is followed by whitespace,
           //                     // end of line, or one of ) ' " ! ? . ,
-          match: `(?<=\\s|^|[('":[])((?:[\\w-]+\\.)+(?:${TLD_REGEX})(?=.*?/)(?:[/?#][^\\s'"]*))(?=\\s|$|[)'"!?.,])`,
+          match: `(?<=\\s|^|[('":[])((?:[\\w-]+\\.)+(?:${TLD_REGEX})(?=.*?/)(?:[/?#][^\\s'"]*(?<![.,])))(?=\\s|$|[)'"!?.,])`,
           // Prepend http:// for the link href otherwise it will be treated as
           // a relative URL.
           link: 'http://$1',
diff --git a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.ts b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.ts
index 113a6cd..2085cc7 100644
--- a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.ts
@@ -264,6 +264,15 @@
         }
       };
 
+      const getLinkifiedUrl = async (url: string) => {
+        element.content = url;
+        await element.updateComplete;
+        const a = query<HTMLElement>(element, 'a');
+
+        assert.isDefined<HTMLElement | undefined>(a);
+        return a.innerText;
+      };
+
       await checkLinking('http://www.google.com');
       await checkLinking('https://www.google.com');
       await checkLinking('https://www.google.com/');
@@ -271,6 +280,10 @@
       await checkLinking('https://www.google.com/asdf-');
       await checkLinking('https://www.google.com/asdf-');
       await checkLinking('https://www.google.com/asdf)');
+      assert.equal(
+        await getLinkifiedUrl('hello gerrit.com/asdf,'),
+        'gerrit.com/asdf'
+      );
       // matches & part as well, even we first linkify and then htmlEscape
       await checkLinking(
         'https://google.com/traces/list?project=gerrit&tid=123'
diff --git a/polygerrit-ui/app/models/change/change-model.ts b/polygerrit-ui/app/models/change/change-model.ts
index a71d225..db2fda3 100644
--- a/polygerrit-ui/app/models/change/change-model.ts
+++ b/polygerrit-ui/app/models/change/change-model.ts
@@ -102,6 +102,7 @@
    * Corresponding values in `change` are always kept in sync.
    */
   submittabilityInfo?: SubmittabilityInfo;
+  submittabilityLoadingStatus: LoadingStatus;
   /**
    * The list of reviewed files, kept in the model because we want changes made
    * in one view to reflect on other views without re-rendering the other views.
@@ -338,6 +339,7 @@
 // Use DeepReadOnly?
 const initialState: ChangeState = {
   loadingStatus: LoadingStatus.NOT_LOADED,
+  submittabilityLoadingStatus: LoadingStatus.NOT_LOADED,
 };
 
 export const changeModelToken = define<ChangeModel>('change-model');
@@ -373,6 +375,11 @@
     changeState => changeState.submittabilityInfo
   );
 
+  public readonly submittabilityLoadingStatus$ = select(
+    this.state$,
+    changeState => changeState.submittabilityLoadingStatus
+  );
+
   public readonly submittable$ = select(
     this.state$,
     changeState => changeState.submittabilityInfo?.submittable
@@ -827,8 +834,14 @@
           if (!changeNum) {
             // On change reload changeNum is set to undefined to reset change
             // state. We propagate undefined and reset the state in this case.
+            this.updateState({
+              submittabilityLoadingStatus: LoadingStatus.NOT_LOADED,
+            });
             return of(undefined);
           }
+          this.updateState({
+            submittabilityLoadingStatus: LoadingStatus.LOADING,
+          });
           return from(this.restApiService.getSubmittabilityInfo(changeNum));
         })
       )
@@ -840,6 +853,9 @@
             KnownExperimentId.ASYNC_SUBMIT_REQUIREMENTS
           )
         ) {
+          this.updateState({
+            submittabilityLoadingStatus: LoadingStatus.NOT_LOADED,
+          });
           return;
         }
         const change = fillFromSubmittabilityInfo(
@@ -849,6 +865,9 @@
         this.updateState({
           change,
           submittabilityInfo,
+          submittabilityLoadingStatus: submittabilityInfo
+            ? LoadingStatus.LOADED
+            : LoadingStatus.NOT_LOADED,
         });
       });
   }
diff --git a/polygerrit-ui/app/services/gr-rest-api/gr-rest-api-impl.ts b/polygerrit-ui/app/services/gr-rest-api/gr-rest-api-impl.ts
index 553000b..aae54ad 100644
--- a/polygerrit-ui/app/services/gr-rest-api/gr-rest-api-impl.ts
+++ b/polygerrit-ui/app/services/gr-rest-api/gr-rest-api-impl.ts
@@ -2383,10 +2383,12 @@
       'DETAILED_ACCOUNTS',
       'MESSAGES',
       'REVIEWER_UPDATES',
-      'SUBMITTABLE',
       'SKIP_DIFFSTAT',
-      'SUBMIT_REQUIREMENTS',
     ];
+    if (!this.flags.isEnabled(KnownExperimentId.ASYNC_SUBMIT_REQUIREMENTS)) {
+      options.push('SUBMITTABLE');
+      options.push('SUBMIT_REQUIREMENTS');
+    }
     return options;
   }
 
diff --git a/tools/nongoogle.bzl b/tools/nongoogle.bzl
index 11125d7..4fdc091 100644
--- a/tools/nongoogle.bzl
+++ b/tools/nongoogle.bzl
@@ -186,8 +186,8 @@
 
     maven_jar(
         name = "commons-io",
-        artifact = "commons-io:commons-io:2.18.0",
-        sha1 = "44084ef756763795b31c578403dd028ff4a22950",
+        artifact = "commons-io:commons-io:2.20.0",
+        sha1 = "36f3474daec2849c149e877614e7f979b2082cd2",
     )
 
     # Google internal dependencies: these are developed at Google, so there is