From 4cc31070b1f58380cf818b347b8fa1364409f41f Mon Sep 17 00:00:00 2001
From: Miles Budnek <miles.budnek@fortra.com>
Date: Tue, 3 Sep 2024 13:25:13 -0400
Subject: [PATCH] feat(workers/repository): Update package files in the same
 order they're extracted (#28671)

Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
Co-authored-by: Rhys Arkins <rhys@arkins.net>
---
 .../update/branch/get-updated.spec.ts         | 51 +++++++++++++++++++
 .../repository/update/branch/get-updated.ts   | 23 +++++++++
 2 files changed, 74 insertions(+)

diff --git a/lib/workers/repository/update/branch/get-updated.spec.ts b/lib/workers/repository/update/branch/get-updated.spec.ts
index cdb22fd082..08a037138a 100644
--- a/lib/workers/repository/update/branch/get-updated.spec.ts
+++ b/lib/workers/repository/update/branch/get-updated.spec.ts
@@ -9,6 +9,7 @@ import * as _gomod from '../../../../modules/manager/gomod';
 import * as _helmv3 from '../../../../modules/manager/helmv3';
 import * as _npm from '../../../../modules/manager/npm';
 import * as _pep621 from '../../../../modules/manager/pep621';
+import * as _pipCompile from '../../../../modules/manager/pip-compile';
 import * as _poetry from '../../../../modules/manager/poetry';
 import type { PackageFile } from '../../../../modules/manager/types';
 import type { BranchConfig, BranchUpgradeConfig } from '../../../types';
@@ -24,6 +25,7 @@ const npm = mocked(_npm);
 const batectWrapper = mocked(_batectWrapper);
 const autoReplace = mocked(_autoReplace);
 const pep621 = mocked(_pep621);
+const pipCompile = mocked(_pipCompile);
 const poetry = mocked(_poetry);
 
 jest.mock('../../../../modules/manager/bundler');
@@ -34,6 +36,7 @@ jest.mock('../../../../modules/manager/git-submodules');
 jest.mock('../../../../modules/manager/gomod', () => mockDeep());
 jest.mock('../../../../modules/manager/batect-wrapper');
 jest.mock('../../../../modules/manager/pep621');
+jest.mock('../../../../modules/manager/pip-compile');
 jest.mock('../../../../modules/manager/poetry');
 jest.mock('../../../../util/git');
 jest.mock('./auto-replace');
@@ -867,6 +870,54 @@ describe('workers/repository/update/branch/get-updated', () => {
           );
         });
       });
+
+      it('passes package files to updateArtifacts in the same order they were returned by the manager', async () => {
+        config.upgrades.push({
+          packageFile: 'requirements-dev.in',
+          manager: 'pip-compile',
+          updateType: 'replacement',
+          depName: 'awscli',
+          currentValue: '==1.32.86',
+          newVersion: '1.32.92',
+          branchName: 'renovate/aws-packages',
+        });
+        config.upgrades.push({
+          packageFile: 'requirements.in',
+          manager: 'pip-compile',
+          updateType: 'replacement',
+          depName: 'botocore',
+          currentValue: '==1.34.86',
+          newVersion: '1.34.92',
+          branchName: 'renovate/aws-packages',
+        });
+        config.packageFiles = {
+          'pip-compile': [
+            {
+              packageFile: 'requirement.in',
+              deps: [],
+            },
+            {
+              packageFile: 'requirements-dev.in',
+              deps: [],
+            },
+          ],
+        };
+
+        pipCompile.updateArtifacts.mockResolvedValue([]);
+        autoReplace.doAutoReplace.mockResolvedValue('new content');
+
+        await getUpdatedPackageFiles(config);
+
+        expect(pipCompile.updateArtifacts).toHaveBeenCalledTimes(2);
+        expect(pipCompile.updateArtifacts).toHaveBeenNthCalledWith(
+          1,
+          expect.objectContaining({ packageFileName: 'requirements.in' }),
+        );
+        expect(pipCompile.updateArtifacts).toHaveBeenNthCalledWith(
+          2,
+          expect.objectContaining({ packageFileName: 'requirements-dev.in' }),
+        );
+      });
     });
   });
 });
diff --git a/lib/workers/repository/update/branch/get-updated.ts b/lib/workers/repository/update/branch/get-updated.ts
index 0b226224fd..59bdac1e42 100644
--- a/lib/workers/repository/update/branch/get-updated.ts
+++ b/lib/workers/repository/update/branch/get-updated.ts
@@ -40,6 +40,26 @@ async function getFileContent(
   return fileContent;
 }
 
+function sortPackageFiles(
+  config: BranchConfig,
+  manager: string,
+  packageFiles: FilePath[],
+): void {
+  const managerPackageFiles = config.packageFiles?.[manager];
+  if (!managerPackageFiles) {
+    return;
+  }
+  packageFiles.sort((lhs, rhs) => {
+    const lhsIndex = managerPackageFiles.findIndex(
+      (entry) => entry.packageFile === lhs.path,
+    );
+    const rhsIndex = managerPackageFiles.findIndex(
+      (entry) => entry.packageFile === rhs.path,
+    );
+    return lhsIndex - rhsIndex;
+  });
+}
+
 function hasAny(set: Set<string>, targets: Iterable<string>): boolean {
   for (const target of targets) {
     if (set.has(target)) {
@@ -334,6 +354,7 @@ export async function getUpdatedPackageFiles(
         updatedPackageFiles,
         managerPackageFiles[manager],
       );
+      sortPackageFiles(config, manager, packageFilesForManager);
       for (const packageFile of packageFilesForManager) {
         const updatedDeps = packageFileUpdatedDeps[packageFile.path];
         const results = await managerUpdateArtifacts(manager, {
@@ -374,6 +395,7 @@ export async function getUpdatedPackageFiles(
         nonUpdatedPackageFiles,
         managerPackageFiles[manager],
       );
+      sortPackageFiles(config, manager, packageFilesForManager);
       for (const packageFile of packageFilesForManager) {
         const updatedDeps = packageFileUpdatedDeps[packageFile.path];
         const results = await managerUpdateArtifacts(manager, {
@@ -416,6 +438,7 @@ export async function getUpdatedPackageFiles(
           lockFileMaintenancePackageFiles,
           managerPackageFiles[manager],
         );
+        sortPackageFiles(config, manager, packageFilesForManager);
         for (const packageFile of packageFilesForManager) {
           const contents =
             updatedFileContents[packageFile.path] ||
-- 
GitLab