From 45da51aa6deb1221b986aec0e9d86675e18187fc Mon Sep 17 00:00:00 2001
From: Rhys Arkins <rhys@arkins.net>
Date: Fri, 9 Nov 2018 14:22:11 +0100
Subject: [PATCH] refactor: add cargo skeleton

Begins #1870
---
 lib/config/definitions.js                     | 23 ++++++++++++++
 lib/manager/cargo/artifacts.js                | 30 +++++++++++++++++++
 lib/manager/cargo/extract.js                  |  9 ++++++
 lib/manager/cargo/index.js                    | 14 +++++++++
 lib/manager/cargo/update.js                   |  9 ++++++
 lib/manager/index.js                          | 11 ++++++-
 .../__snapshots__/artifacts.spec.js.snap      | 10 +++++++
 test/manager/cargo/artifacts.spec.js          | 16 ++++++++++
 test/manager/cargo/extract.spec.js            | 13 ++++++++
 test/manager/cargo/update.spec.js             | 13 ++++++++
 .../extract/__snapshots__/index.spec.js.snap  |  3 ++
 11 files changed, 150 insertions(+), 1 deletion(-)
 create mode 100644 lib/manager/cargo/artifacts.js
 create mode 100644 lib/manager/cargo/extract.js
 create mode 100644 lib/manager/cargo/index.js
 create mode 100644 lib/manager/cargo/update.js
 create mode 100644 test/manager/cargo/__snapshots__/artifacts.spec.js.snap
 create mode 100644 test/manager/cargo/artifacts.spec.js
 create mode 100644 test/manager/cargo/extract.spec.js
 create mode 100644 test/manager/cargo/update.spec.js

diff --git a/lib/config/definitions.js b/lib/config/definitions.js
index db7100df41..16e58610c9 100644
--- a/lib/config/definitions.js
+++ b/lib/config/definitions.js
@@ -1005,6 +1005,29 @@ const options = [
     },
     mergeable: true,
   },
+  {
+    name: 'rust',
+    releaseStatus: 'unpublished',
+    description: 'Configuration option for Rust package management.',
+    stage: 'package',
+    type: 'json',
+    default: {},
+    mergeable: true,
+    cli: false,
+  },
+  {
+    name: 'cargo',
+    releaseStatus: 'unpublished',
+    description: 'Configuration object for Cargo crate renovation.',
+    stage: 'repository',
+    type: 'json',
+    default: {
+      enabled: false,
+      commitMessageTopic: 'Rust crate {{depName}}',
+      managerBranchPrefix: 'rust-',
+    },
+    mergeable: true,
+  },
   {
     name: 'supportPolicy',
     description:
diff --git a/lib/manager/cargo/artifacts.js b/lib/manager/cargo/artifacts.js
new file mode 100644
index 0000000000..60d8326a0e
--- /dev/null
+++ b/lib/manager/cargo/artifacts.js
@@ -0,0 +1,30 @@
+module.exports = {
+  getArtifacts,
+};
+
+async function getArtifacts(
+  cargoTomlFileName,
+  updatedDeps,
+  newCargoTomlContent,
+  config
+) {
+  await logger.debug({ config }, `cargo.getArtifacts(${cargoTomlFileName})`);
+  let cargoLockFileName;
+  try {
+    cargoLockFileName = cargoTomlFileName.replace(/\.toml$/, '.lock');
+    logger.debug('Updating ' + cargoLockFileName);
+    // TODO: Update cargo lock file
+    return null;
+  } catch (err) {
+    logger.warn(
+      { err, message: err.message },
+      'Failed to update Cargo lock file'
+    );
+    return {
+      lockFileError: {
+        lockFile: cargoLockFileName,
+        stderr: err.message,
+      },
+    };
+  }
+}
diff --git a/lib/manager/cargo/extract.js b/lib/manager/cargo/extract.js
new file mode 100644
index 0000000000..8ec60ac244
--- /dev/null
+++ b/lib/manager/cargo/extract.js
@@ -0,0 +1,9 @@
+module.exports = {
+  extractPackageFile,
+};
+
+function extractPackageFile(content, fileName) {
+  logger.trace(`cargo.extractPackageFile(${fileName})`);
+  // TODO: Extract cargo.toml dependencies
+  return null;
+}
diff --git a/lib/manager/cargo/index.js b/lib/manager/cargo/index.js
new file mode 100644
index 0000000000..161560073d
--- /dev/null
+++ b/lib/manager/cargo/index.js
@@ -0,0 +1,14 @@
+const { extractPackageFile } = require('./extract');
+const { updateDependency } = require('./update');
+const { getArtifacts } = require('./artifacts');
+
+const language = 'rust';
+
+module.exports = {
+  extractPackageFile,
+  getArtifacts,
+  language,
+  updateDependency,
+  // TODO: support this
+  // supportsLockFileMaintenance: true,
+};
diff --git a/lib/manager/cargo/update.js b/lib/manager/cargo/update.js
new file mode 100644
index 0000000000..3c3fb715ae
--- /dev/null
+++ b/lib/manager/cargo/update.js
@@ -0,0 +1,9 @@
+module.exports = {
+  updateDependency,
+};
+
+function updateDependency(currentFileContent, upgrade) {
+  logger.debug({ config: upgrade }, 'cargo.updateDependency()');
+  // TODO
+  return currentFileContent;
+}
diff --git a/lib/manager/index.js b/lib/manager/index.js
index cecc51d102..433e1ccf3c 100644
--- a/lib/manager/index.js
+++ b/lib/manager/index.js
@@ -1,6 +1,7 @@
 const managerList = [
   'bazel',
   'buildkite',
+  'cargo',
   'circleci',
   'composer',
   'docker-compose',
@@ -23,7 +24,15 @@ for (const manager of managerList) {
   managers[manager] = require(`./${manager}`);
 }
 
-const languageList = ['docker', 'golang', 'js', 'node', 'php', 'python'];
+const languageList = [
+  'docker',
+  'golang',
+  'js',
+  'node',
+  'php',
+  'python',
+  'rust',
+];
 
 const get = (manager, name) => managers[manager][name];
 const getLanguageList = () => languageList;
diff --git a/test/manager/cargo/__snapshots__/artifacts.spec.js.snap b/test/manager/cargo/__snapshots__/artifacts.spec.js.snap
new file mode 100644
index 0000000000..9ab65d6d65
--- /dev/null
+++ b/test/manager/cargo/__snapshots__/artifacts.spec.js.snap
@@ -0,0 +1,10 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`cargo.getArtifacts() catches errors 1`] = `
+Object {
+  "lockFileError": Object {
+    "lockFile": undefined,
+    "stderr": "Cannot read property 'replace' of undefined",
+  },
+}
+`;
diff --git a/test/manager/cargo/artifacts.spec.js b/test/manager/cargo/artifacts.spec.js
new file mode 100644
index 0000000000..3c3a9ef6fb
--- /dev/null
+++ b/test/manager/cargo/artifacts.spec.js
@@ -0,0 +1,16 @@
+const cargo = require('../../../lib/manager/cargo/artifacts');
+
+let config;
+
+describe('cargo.getArtifacts()', () => {
+  beforeEach(() => {
+    jest.resetAllMocks();
+    config = {};
+  });
+  it('returns null by default', async () => {
+    expect(await cargo.getArtifacts('cargo.toml', [], '', config)).toBeNull();
+  });
+  it('catches errors', async () => {
+    expect(await cargo.getArtifacts()).toMatchSnapshot();
+  });
+});
diff --git a/test/manager/cargo/extract.spec.js b/test/manager/cargo/extract.spec.js
new file mode 100644
index 0000000000..a4d7baf917
--- /dev/null
+++ b/test/manager/cargo/extract.spec.js
@@ -0,0 +1,13 @@
+const { extractPackageFile } = require('../../../lib/manager/cargo/extract');
+
+describe('lib/manager/cargo/extract', () => {
+  describe('extractPackageFile()', () => {
+    let config;
+    beforeEach(() => {
+      config = {};
+    });
+    it('returns null for empty', () => {
+      expect(extractPackageFile('nothing here', config)).toBe(null);
+    });
+  });
+});
diff --git a/test/manager/cargo/update.spec.js b/test/manager/cargo/update.spec.js
new file mode 100644
index 0000000000..148c248410
--- /dev/null
+++ b/test/manager/cargo/update.spec.js
@@ -0,0 +1,13 @@
+const { updateDependency } = require('../../../lib/manager/cargo/update');
+
+describe('lib/manager/cargo/update', () => {
+  describe('updateDependency()', () => {
+    let config;
+    beforeEach(() => {
+      config = {};
+    });
+    it('returns same', () => {
+      expect(updateDependency('abc', config)).toEqual('abc');
+    });
+  });
+});
diff --git a/test/workers/repository/extract/__snapshots__/index.spec.js.snap b/test/workers/repository/extract/__snapshots__/index.spec.js.snap
index 47c8d589f6..81f621ea2c 100644
--- a/test/workers/repository/extract/__snapshots__/index.spec.js.snap
+++ b/test/workers/repository/extract/__snapshots__/index.spec.js.snap
@@ -8,6 +8,9 @@ Object {
   "buildkite": Array [
     Object {},
   ],
+  "cargo": Array [
+    Object {},
+  ],
   "circleci": Array [
     Object {},
   ],
-- 
GitLab