From 235951a1a2374143a747ed38388e92233b9359b8 Mon Sep 17 00:00:00 2001
From: Norbert Szulc <norbert@icetek.io>
Date: Thu, 8 Feb 2024 18:29:50 +0100
Subject: [PATCH] feat(manager/pip-compile): Create wrapper for pip
 extractPackageFile (#27154)

Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
---
 .../manager/pip-compile/extract.spec.ts       | 30 ++++++++++
 lib/modules/manager/pip-compile/extract.ts    | 55 +++++++++++++++++++
 lib/modules/manager/pip-compile/index.ts      |  2 +-
 lib/modules/manager/pip-compile/types.ts      |  6 ++
 4 files changed, 92 insertions(+), 1 deletion(-)
 create mode 100644 lib/modules/manager/pip-compile/extract.spec.ts
 create mode 100644 lib/modules/manager/pip-compile/extract.ts
 create mode 100644 lib/modules/manager/pip-compile/types.ts

diff --git a/lib/modules/manager/pip-compile/extract.spec.ts b/lib/modules/manager/pip-compile/extract.spec.ts
new file mode 100644
index 0000000000..c193da7457
--- /dev/null
+++ b/lib/modules/manager/pip-compile/extract.spec.ts
@@ -0,0 +1,30 @@
+import { Fixtures } from '../../../../test/fixtures';
+import { extractPackageFile } from '.';
+
+jest.mock('../../../util/fs');
+
+describe('modules/manager/pip-compile/extract', () => {
+  describe('extractPackageFile()', () => {
+    it('returns object for requirements.in', () => {
+      const packageFile = extractPackageFile(
+        Fixtures.get('requirementsWithHashes.txt'),
+        'requirements.in',
+        {},
+      );
+      expect(packageFile).toHaveProperty('deps');
+      expect(packageFile?.deps[0]).toHaveProperty('depName', 'attrs');
+    });
+
+    it.each([
+      'random.py',
+      'app.cfg',
+      'already_locked.txt',
+      // TODO(not7cd)
+      'pyproject.toml',
+      'setup.py',
+      'setup.cfg',
+    ])('returns null on not supported package files', (file: string) => {
+      expect(extractPackageFile('some content', file, {})).toBeNull();
+    });
+  });
+});
diff --git a/lib/modules/manager/pip-compile/extract.ts b/lib/modules/manager/pip-compile/extract.ts
new file mode 100644
index 0000000000..59c4e13340
--- /dev/null
+++ b/lib/modules/manager/pip-compile/extract.ts
@@ -0,0 +1,55 @@
+import { logger } from '../../../logger';
+import { extractPackageFile as extractRequirementsFile } from '../pip_requirements/extract';
+// TODO(not7cd): enable in the next PR, when this can be properly tested
+// import { extractPackageFile as extractSetupPyFile } from '../pip_setup';
+// import { extractPackageFile as extractSetupCfgFile } from '../setup-cfg';
+import type { ExtractConfig, PackageFileContent } from '../types';
+import type { SupportedManagers } from './types';
+
+function matchManager(filename: string): SupportedManagers | 'unknown' {
+  if (filename.endsWith('setup.py')) {
+    return 'pip_setup';
+  }
+  if (filename.endsWith('setup.cfg')) {
+    return 'setup-cfg';
+  }
+  if (filename.endsWith('pyproject.toml')) {
+    return 'pep621';
+  }
+  // naive, could be improved, maybe use pip_requirements.fileMatch
+  if (filename.endsWith('.in')) {
+    return 'pip_requirements';
+  }
+  return 'unknown';
+}
+
+export function extractPackageFile(
+  content: string,
+  packageFile: string,
+  _config: ExtractConfig,
+): PackageFileContent | null {
+  logger.trace('pip-compile.extractPackageFile()');
+  const manager = matchManager(packageFile);
+  // TODO(not7cd): extract based on manager: pep621, setuptools, identify other missing source types
+  switch (manager) {
+    // TODO(not7cd): enable in the next PR, when this can be properly tested
+    // case 'pip_setup':
+    //   return extractSetupPyFile(content, _packageFile, _config);
+    // case 'setup-cfg':
+    //   return await extractSetupCfgFile(content);
+    case 'pip_requirements':
+      return extractRequirementsFile(content);
+    case 'unknown':
+      logger.warn(
+        { packageFile },
+        `pip-compile: could not determine manager for source file, fallback to pip_requirements`,
+      );
+      return extractRequirementsFile(content);
+    default:
+      logger.warn(
+        { packageFile, manager },
+        `pip-compile: support for manager is not yet implemented`,
+      );
+      return null;
+  }
+}
diff --git a/lib/modules/manager/pip-compile/index.ts b/lib/modules/manager/pip-compile/index.ts
index 98e6160108..9fb9e6f535 100644
--- a/lib/modules/manager/pip-compile/index.ts
+++ b/lib/modules/manager/pip-compile/index.ts
@@ -2,7 +2,7 @@ import type { Category } from '../../../constants';
 import { GitTagsDatasource } from '../../datasource/git-tags';
 import { PypiDatasource } from '../../datasource/pypi';
 
-export { extractPackageFile } from '../pip_requirements/extract';
+export { extractPackageFile } from './extract';
 export { updateArtifacts } from './artifacts';
 
 export const supportsLockFileMaintenance = true;
diff --git a/lib/modules/manager/pip-compile/types.ts b/lib/modules/manager/pip-compile/types.ts
new file mode 100644
index 0000000000..b1503a685d
--- /dev/null
+++ b/lib/modules/manager/pip-compile/types.ts
@@ -0,0 +1,6 @@
+// managers supported by pip-tools Python package
+export type SupportedManagers =
+  | 'pip_requirements'
+  | 'pip_setup'
+  | 'setup-cfg'
+  | 'pep621';
-- 
GitLab