From def2c8f518c6e70701641c5a326458a69f42a2fd Mon Sep 17 00:00:00 2001
From: Ayoub Kaanich <kayoub5@live.com>
Date: Wed, 15 Aug 2018 07:57:09 +0200
Subject: [PATCH] refactor: Prepare GitHub storage for Git storage (#2378)

Contains GitHub specific changes from #2323
---
 lib/platform/github/index.js   |  11 +-
 lib/platform/github/storage.js | 863 +++++++++++++++++----------------
 2 files changed, 459 insertions(+), 415 deletions(-)

diff --git a/lib/platform/github/index.js b/lib/platform/github/index.js
index afcbac8762..efc9dcd7c6 100644
--- a/lib/platform/github/index.js
+++ b/lib/platform/github/index.js
@@ -77,6 +77,10 @@ async function getRepos(token, endpoint) {
 }
 
 function cleanRepo() {
+  // istanbul ignore if
+  if (config.storage) {
+    config.storage.cleanRepo();
+  }
   // In theory most of this isn't necessary. In practice..
   get.reset();
   config = {};
@@ -179,7 +183,8 @@ async function initRepo({
   // This shouldn't be necessary, but occasional strange errors happened until it was added
   config.issueList = null;
   config.prList = null;
-  config.storage = new Storage(config);
+  config.storage = new Storage();
+  await config.storage.initRepo(config);
   logger.debug('Prefetching prList and fileList');
   await Promise.all([getPrList(), getFileList()]);
   if (forkMode) {
@@ -225,7 +230,7 @@ async function initRepo({
       // Wait an arbitrary 30s to hopefully give GitHub enough time for forking to complete
       await delay(30000);
     }
-    config.storage = new Storage(config);
+    await config.storage.initRepo(config);
   }
   // istanbul ignore if
   if (mirrorMode) {
@@ -334,7 +339,7 @@ async function setBaseBranch(branchName) {
     logger.debug(`Setting baseBranch to ${branchName}`);
     config.baseBranch = branchName;
     config.baseCommitSHA = null;
-    config.storage = new Storage(config);
+    config.storage.setBaseBranch(branchName);
     await getFileList(branchName);
   }
 }
diff --git a/lib/platform/github/storage.js b/lib/platform/github/storage.js
index ad9bf0baf3..a9bd11550a 100644
--- a/lib/platform/github/storage.js
+++ b/lib/platform/github/storage.js
@@ -5,472 +5,511 @@ const get = require('./gh-got-wrapper');
 const { expandError } = require('./util');
 
 class Storage {
-  constructor(config) {
+  constructor() {
     // config
-    this.config = config;
-    this.gitAuthor = config.gitAuthor;
-    this.gitPrivateKey = config.gitPrivateKey;
-    this.forkToken = config.forkToken;
-    this.repository = config.repository;
-    this.baseBranch = config.baseBranch;
+    let config = {};
     // cache
-    this.branchFiles = {};
-    this.branchList = null;
-  }
+    let branchFiles = {};
+    let branchList = null;
 
-  // Returns true if branch exists, otherwise false
-  async branchExists(branchName) {
-    if (!this.branchList) {
-      logger.debug('Retrieving branchList');
-      this.branchList = (await get(
-        `repos/${this.repository}/branches?per_page=100`,
-        {
-          paginate: true,
-        }
-      )).body.map(branch => branch.name);
-      logger.debug({ branchList: this.branchList }, 'Retrieved branchList');
+    Object.assign(this, {
+      initRepo,
+      cleanRepo,
+      branchExists,
+      commitFilesToBranch,
+      createBranch,
+      deleteBranch,
+      getAllRenovateBranches,
+      getBranchCommit,
+      getBranchLastCommitTime,
+      getCommitMessages,
+      getFile,
+      getFileList,
+      isBranchStale,
+      mergeBranch,
+      setBaseBranch,
+    });
+
+    function initRepo(args) {
+      cleanRepo();
+      config = { ...args };
     }
-    const res = this.branchList.includes(branchName);
-    logger.debug(`branchExists(${branchName})=${res}`);
-    return res;
-  }
 
-  // Get full file list
-  async getFileList(branchName) {
-    const branch = branchName || this.baseBranch;
-    if (this.branchFiles[branch]) {
-      return this.branchFiles[branch];
+    function cleanRepo() {
+      branchFiles = {};
+      branchList = null;
     }
-    try {
-      const res = await get(
-        `repos/${this.repository}/git/trees/${branch}?recursive=true`
-      );
-      if (res.body.truncated) {
-        logger.warn(
-          { repository: this.repository },
-          'repository tree is truncated'
-        );
+
+    // Returns true if branch exists, otherwise false
+    async function branchExists(branchName) {
+      if (!branchList) {
+        logger.debug('Retrieving branchList');
+        branchList = (await get(
+          `repos/${config.repository}/branches?per_page=100`,
+          {
+            paginate: true,
+          }
+        )).body.map(branch => branch.name);
+        logger.debug({ branchList }, 'Retrieved branchList');
       }
-      const fileList = res.body.tree
-        .filter(item => item.type === 'blob' && item.mode !== '120000')
-        .map(item => item.path)
-        .sort();
-      logger.debug(`Retrieved fileList with length ${fileList.length}`);
-      this.branchFiles[branch] = fileList;
-      return fileList;
-    } catch (err) /* istanbul ignore next */ {
-      if (err.statusCode === 409) {
-        logger.debug('Repository is not initiated');
-        throw new Error('uninitiated');
+      const res = branchList.includes(branchName);
+      logger.debug(`branchExists(${branchName})=${res}`);
+      return res;
+    }
+
+    function setBaseBranch(branchName) {
+      if (branchName) {
+        logger.debug(`Setting baseBranch to ${branchName}`);
+        config.baseBranch = branchName;
       }
-      logger.info(
-        { repository: this.repository },
-        'Error retrieving git tree - no files detected'
-      );
-      return [];
     }
-  }
 
-  async getAllRenovateBranches(branchPrefix) {
-    logger.trace('getAllRenovateBranches');
-    try {
-      const allBranches = (await get(
-        `repos/${this.repository}/git/refs/heads/${branchPrefix}`,
-        {
-          paginate: true,
-        }
-      )).body;
-      return allBranches.reduce((arr, branch) => {
-        if (branch.ref.startsWith(`refs/heads/${branchPrefix}`)) {
-          arr.push(branch.ref.substring('refs/heads/'.length));
-        }
-        if (
-          branchPrefix.endsWith('/') &&
-          branch.ref === `refs/heads/${branchPrefix.slice(0, -1)}`
-        ) {
+    // Get full file list
+    async function getFileList(branchName) {
+      const branch = branchName || config.baseBranch;
+      if (branchFiles[branch]) {
+        return branchFiles[branch];
+      }
+      try {
+        const res = await get(
+          `repos/${config.repository}/git/trees/${branch}?recursive=true`
+        );
+        if (res.body.truncated) {
           logger.warn(
-            `Pruning branch "${branchPrefix.slice(
-              0,
-              -1
-            )}" so that it does not block PRs`
+            { repository: config.repository },
+            'repository tree is truncated'
           );
-          arr.push(branch.ref.substring('refs/heads/'.length));
         }
-        return arr;
-      }, []);
-    } catch (err) /* istanbul ignore next */ {
-      return [];
+        const fileList = res.body.tree
+          .filter(item => item.type === 'blob' && item.mode !== '120000')
+          .map(item => item.path)
+          .sort();
+        logger.debug(`Retrieved fileList with length ${fileList.length}`);
+        branchFiles[branch] = fileList;
+        return fileList;
+      } catch (err) /* istanbul ignore next */ {
+        if (err.statusCode === 409) {
+          logger.debug('Repository is not initiated');
+          throw new Error('uninitiated');
+        }
+        logger.info(
+          { repository: config.repository },
+          'Error retrieving git tree - no files detected'
+        );
+        return [];
+      }
     }
-  }
 
-  async isBranchStale(branchName) {
-    // Check if branch's parent SHA = master SHA
-    logger.debug(`isBranchStale(${branchName})`);
-    const branchCommit = await this.getBranchCommit(branchName);
-    logger.debug(`branchCommit=${branchCommit}`);
-    const commitDetails = await getCommitDetails(this, branchCommit);
-    logger.trace({ commitDetails }, `commitDetails`);
-    const parentSha = commitDetails.parents[0].sha;
-    logger.debug(`parentSha=${parentSha}`);
-    const baseCommitSHA = await this.getBranchCommit(this.baseBranch);
-    logger.debug(`baseCommitSHA=${baseCommitSHA}`);
-    // Return true if the SHAs don't match
-    return parentSha !== baseCommitSHA;
-  }
+    async function getAllRenovateBranches(branchPrefix) {
+      logger.trace('getAllRenovateBranches');
+      try {
+        const allBranches = (await get(
+          `repos/${config.repository}/git/refs/heads/${branchPrefix}`,
+          {
+            paginate: true,
+          }
+        )).body;
+        return allBranches.reduce((arr, branch) => {
+          if (branch.ref.startsWith(`refs/heads/${branchPrefix}`)) {
+            arr.push(branch.ref.substring('refs/heads/'.length));
+          }
+          if (
+            branchPrefix.endsWith('/') &&
+            branch.ref === `refs/heads/${branchPrefix.slice(0, -1)}`
+          ) {
+            logger.warn(
+              `Pruning branch "${branchPrefix.slice(
+                0,
+                -1
+              )}" so that it does not block PRs`
+            );
+            arr.push(branch.ref.substring('refs/heads/'.length));
+          }
+          return arr;
+        }, []);
+      } catch (err) /* istanbul ignore next */ {
+        return [];
+      }
+    }
 
-  async deleteBranch(branchName) {
-    delete this.branchFiles[branchName];
-    const options = this.forkToken ? { token: this.forkToken } : undefined;
-    try {
-      await get.delete(
-        `repos/${this.repository}/git/refs/heads/${branchName}`,
-        options
-      );
-    } catch (err) /* istanbul ignore next */ {
-      if (err.message.startsWith('Reference does not exist')) {
-        logger.info({ branchName }, 'Branch to delete does not exist');
-      } else {
-        logger.warn(
-          { err, body: err.response.body, branchName },
-          'Error deleting branch'
+    async function isBranchStale(branchName) {
+      // Check if branch's parent SHA = master SHA
+      logger.debug(`isBranchStale(${branchName})`);
+      const branchCommit = await getBranchCommit(branchName);
+      logger.debug(`branchCommit=${branchCommit}`);
+      const commitDetails = await getCommitDetails(branchCommit);
+      logger.trace({ commitDetails }, `commitDetails`);
+      const parentSha = commitDetails.parents[0].sha;
+      logger.debug(`parentSha=${parentSha}`);
+      const baseCommitSHA = await getBranchCommit(config.baseBranch);
+      logger.debug(`baseCommitSHA=${baseCommitSHA}`);
+      // Return true if the SHAs don't match
+      return parentSha !== baseCommitSHA;
+    }
+
+    async function deleteBranch(branchName) {
+      delete branchFiles[branchName];
+      const options = config.forkToken
+        ? { token: config.forkToken }
+        : undefined;
+      try {
+        await get.delete(
+          `repos/${config.repository}/git/refs/heads/${branchName}`,
+          options
         );
+      } catch (err) /* istanbul ignore next */ {
+        if (err.message.startsWith('Reference does not exist')) {
+          logger.info({ branchName }, 'Branch to delete does not exist');
+        } else {
+          logger.warn(
+            { err, body: err.response.body, branchName },
+            'Error deleting branch'
+          );
+        }
       }
     }
-  }
 
-  async mergeBranch(branchName) {
-    logger.debug(`mergeBranch(${branchName})`);
-    const url = `repos/${this.repository}/git/refs/heads/${this.baseBranch}`;
-    const options = {
-      body: {
-        sha: await this.getBranchCommit(branchName),
-      },
-    };
-    try {
-      await get.patch(url, options);
-    } catch (err) {
-      logger.info(
-        expandError(err),
-        `Error pushing branch merge for ${branchName}`
-      );
-      throw new Error('Branch automerge failed');
+    async function mergeBranch(branchName) {
+      logger.debug(`mergeBranch(${branchName})`);
+      const url = `repos/${config.repository}/git/refs/heads/${
+        config.baseBranch
+      }`;
+      const options = {
+        body: {
+          sha: await getBranchCommit(branchName),
+        },
+      };
+      try {
+        await get.patch(url, options);
+      } catch (err) {
+        logger.info(
+          expandError(err),
+          `Error pushing branch merge for ${branchName}`
+        );
+        throw new Error('Branch automerge failed');
+      }
+      // Delete branch
+      await deleteBranch(branchName);
     }
-    // Delete branch
-    await this.deleteBranch(branchName);
-  }
 
-  async getBranchLastCommitTime(branchName) {
-    try {
-      const res = await get(
-        `repos/${this.repository}/commits?sha=${branchName}`
-      );
-      return new Date(res.body[0].commit.committer.date);
-    } catch (err) {
-      logger.error(expandError(err), `getBranchLastCommitTime error`);
-      return new Date();
+    async function getBranchLastCommitTime(branchName) {
+      try {
+        const res = await get(
+          `repos/${config.repository}/commits?sha=${branchName}`
+        );
+        return new Date(res.body[0].commit.committer.date);
+      } catch (err) {
+        logger.error(expandError(err), `getBranchLastCommitTime error`);
+        return new Date();
+      }
     }
-  }
 
-  // Generic File operations
+    // Generic File operations
 
-  async getFile(filePath, branchName) {
-    logger.trace(`getFile(filePath=${filePath}, branchName=${branchName})`);
-    const branchFiles = await this.getFileList(branchName);
-    if (!branchFiles.includes(filePath)) {
-      return null;
-    }
-    let res;
-    try {
-      res = await get(
-        `repos/${this.repository}/contents/${encodeURI(
-          filePath
-        )}?ref=${branchName || this.baseBranch}`
-      );
-    } catch (error) {
-      if (error.statusCode === 404) {
-        // If file not found, then return null JSON
-        logger.info({ filePath, branchName }, 'getFile 404');
+    async function getFile(filePath, branchName) {
+      logger.trace(`getFile(filePath=${filePath}, branchName=${branchName})`);
+      if (!(await getFileList(branchName)).includes(filePath)) {
         return null;
       }
-      if (
-        error.statusCode === 403 &&
-        error.message &&
-        error.message.startsWith('This API returns blobs up to 1 MB in size')
-      ) {
-        logger.info('Large file');
-        // istanbul ignore if
-        if (branchName && branchName !== this.baseBranch) {
-          logger.info('Cannot retrieve large files from non-master branch');
-          return null;
-        }
-        // istanbul ignore if
-        if (path.dirname(filePath) !== '.') {
-          logger.info('Cannot retrieve large files from non-root directories');
+      let res;
+      try {
+        res = await get(
+          `repos/${config.repository}/contents/${encodeURI(
+            filePath
+          )}?ref=${branchName || config.baseBranch}`
+        );
+      } catch (error) {
+        if (error.statusCode === 404) {
+          // If file not found, then return null JSON
+          logger.info({ filePath, branchName }, 'getFile 404');
           return null;
         }
-        const treeUrl = `repos/${this.repository}/git/trees/${this.baseBranch}`;
-        const baseName = path.basename(filePath);
-        let fileSha;
-        (await get(treeUrl)).body.tree.forEach(file => {
-          if (file.path === baseName) {
-            fileSha = file.sha;
+        if (
+          error.statusCode === 403 &&
+          error.message &&
+          error.message.startsWith('This API returns blobs up to 1 MB in size')
+        ) {
+          logger.info('Large file');
+          // istanbul ignore if
+          if (branchName && branchName !== config.baseBranch) {
+            logger.info('Cannot retrieve large files from non-master branch');
+            return null;
           }
-        });
-        if (!fileSha) {
-          logger.warn('Could not locate file blob');
+          // istanbul ignore if
+          if (path.dirname(filePath) !== '.') {
+            logger.info(
+              'Cannot retrieve large files from non-root directories'
+            );
+            return null;
+          }
+          const treeUrl = `repos/${config.repository}/git/trees/${
+            config.baseBranch
+          }`;
+          const baseName = path.basename(filePath);
+          let fileSha;
+          (await get(treeUrl)).body.tree.forEach(file => {
+            if (file.path === baseName) {
+              fileSha = file.sha;
+            }
+          });
+          if (!fileSha) {
+            logger.warn('Could not locate file blob');
+            throw error;
+          }
+          res = await get(`repos/${config.repository}/git/blobs/${fileSha}`);
+        } else {
+          // Propagate if it's any other error
           throw error;
         }
-        res = await get(`repos/${this.repository}/git/blobs/${fileSha}`);
-      } else {
-        // Propagate if it's any other error
-        throw error;
       }
+      if (res && res.body.content) {
+        return Buffer.from(res.body.content, 'base64').toString();
+      }
+      return null;
     }
-    if (res && res.body.content) {
-      return Buffer.from(res.body.content, 'base64').toString();
-    }
-    return null;
-  }
 
-  // Add a new commit, create branch if not existing
-  async commitFilesToBranch(
-    branchName,
-    files,
-    message,
-    parentBranch = this.baseBranch
-  ) {
-    logger.debug(
-      `commitFilesToBranch('${branchName}', files, message, '${parentBranch})'`
-    );
-    delete this.branchFiles[branchName];
-    const parentCommit = await this.getBranchCommit(parentBranch);
-    const parentTree = await getCommitTree(this, parentCommit);
-    const fileBlobs = [];
-    // Create blobs
-    for (const file of files) {
-      const blob = await createBlob(this, file.contents);
-      fileBlobs.push({
-        name: file.name,
-        blob,
-      });
-    }
-    // Create tree
-    const tree = await createTree(this, parentTree, fileBlobs);
-    const commit = await createCommit(this, parentCommit, tree, message);
-    const isBranchExisting = await this.branchExists(branchName);
-    try {
-      if (isBranchExisting) {
-        await updateBranch(this, branchName, commit);
-      } else {
-        await this.createBranch(branchName, commit);
+    // Add a new commit, create branch if not existing
+    async function commitFilesToBranch(
+      branchName,
+      files,
+      message,
+      parentBranch = config.baseBranch
+    ) {
+      logger.debug(
+        `commitFilesToBranch('${branchName}', files, message, '${parentBranch})'`
+      );
+      delete branchFiles[branchName];
+      const parentCommit = await getBranchCommit(parentBranch);
+      const parentTree = await getCommitTree(parentCommit);
+      const fileBlobs = [];
+      // Create blobs
+      for (const file of files) {
+        const blob = await createBlob(file.contents);
+        fileBlobs.push({
+          name: file.name,
+          blob,
+        });
+      }
+      // Create tree
+      const tree = await createTree(parentTree, fileBlobs);
+      const commit = await createCommit(parentCommit, tree, message);
+      const isBranchExisting = await branchExists(branchName);
+      try {
+        if (isBranchExisting) {
+          await updateBranch(branchName, commit);
+        } else {
+          await createBranch(branchName, commit);
+        }
+      } catch (err) /* istanbul ignore next */ {
+        logger.debug({
+          files: files.filter(
+            file =>
+              !file.name.endsWith('package-lock.json') &&
+              !file.name.endsWith('npm-shrinkwrap.json') &&
+              !file.name.endsWith('yarn.lock')
+          ),
+        });
+        throw err;
       }
-    } catch (err) /* istanbul ignore next */ {
-      logger.debug({
-        files: files.filter(
-          file =>
-            !file.name.endsWith('package-lock.json') &&
-            !file.name.endsWith('npm-shrinkwrap.json') &&
-            !file.name.endsWith('yarn.lock')
-        ),
-      });
-      throw err;
     }
-  }
 
-  // Internal branch operations
+    // Internal branch operations
 
-  // Creates a new branch with provided commit
-  async createBranch(branchName, sha) {
-    logger.debug(`createBranch(${branchName})`);
-    const options = {
-      body: {
-        ref: `refs/heads/${branchName}`,
-        sha,
-      },
-    };
-    // istanbul ignore if
-    if (this.forkToken) {
-      options.token = this.forkToken;
-    }
-    try {
+    // Creates a new branch with provided commit
+    async function createBranch(branchName, sha) {
+      logger.debug(`createBranch(${branchName})`);
+      const options = {
+        body: {
+          ref: `refs/heads/${branchName}`,
+          sha,
+        },
+      };
       // istanbul ignore if
-      if (branchName.includes('/')) {
-        const [blockingBranch] = branchName.split('/');
-        if (await this.branchExists(blockingBranch)) {
-          logger.warn({ blockingBranch }, 'Deleting blocking branch');
-          await this.deleteBranch(blockingBranch);
+      if (config.forkToken) {
+        options.token = config.forkToken;
+      }
+      try {
+        // istanbul ignore if
+        if (branchName.includes('/')) {
+          const [blockingBranch] = branchName.split('/');
+          if (await branchExists(blockingBranch)) {
+            logger.warn({ blockingBranch }, 'Deleting blocking branch');
+            await deleteBranch(blockingBranch);
+          }
+        }
+        logger.debug({ options, branchName }, 'Creating branch');
+        await get.post(`repos/${config.repository}/git/refs`, options);
+        branchList.push(branchName);
+        logger.debug('Created branch');
+      } catch (err) /* istanbul ignore next */ {
+        const headers = err.response.req.getHeaders();
+        delete headers.token;
+        logger.warn(
+          {
+            err,
+            message: err.message,
+            responseBody: err.response.body,
+            headers,
+            options,
+          },
+          'Error creating branch'
+        );
+        if (err.statusCode === 422) {
+          throw new Error('repository-changed');
         }
+        throw err;
       }
-      logger.debug({ options, branchName }, 'Creating branch');
-      await get.post(`repos/${this.repository}/git/refs`, options);
-      this.branchList.push(branchName);
-      logger.debug('Created branch');
-    } catch (err) /* istanbul ignore next */ {
-      const headers = err.response.req.getHeaders();
-      delete headers.token;
-      logger.warn(
-        {
-          err,
-          message: err.message,
-          responseBody: err.response.body,
-          headers,
-          options,
-        },
-        'Error creating branch'
+    }
+
+    // Return the commit SHA for a branch
+    async function getBranchCommit(branchName) {
+      const res = await get(
+        `repos/${config.repository}/git/refs/heads/${branchName}`
       );
-      if (err.statusCode === 422) {
-        throw new Error('repository-changed');
-      }
-      throw err;
+      return res.body.object.sha;
     }
-  }
 
-  // Return the commit SHA for a branch
-  async getBranchCommit(branchName) {
-    const res = await get(
-      `repos/${this.repository}/git/refs/heads/${branchName}`
-    );
-    return res.body.object.sha;
-  }
+    async function getCommitMessages() {
+      logger.debug('getCommitMessages');
+      const res = await get(`repos/${config.repository}/commits`);
+      return res.body.map(commit => commit.commit.message);
+    }
 
-  async getCommitMessages() {
-    logger.debug('getCommitMessages');
-    const res = await get(`repos/${this.repository}/commits`);
-    return res.body.map(commit => commit.commit.message);
-  }
-}
+    // Internal: Updates an existing branch to new commit sha
+    async function updateBranch(branchName, commit) {
+      logger.debug(`Updating branch ${branchName} with commit ${commit}`);
+      const options = {
+        body: {
+          sha: commit,
+          force: true,
+        },
+      };
+      // istanbul ignore if
+      if (config.forkToken) {
+        options.token = config.forkToken;
+      }
+      try {
+        await get.patch(
+          `repos/${config.repository}/git/refs/heads/${branchName}`,
+          options
+        );
+      } catch (err) /* istanbul ignore next */ {
+        if (err.statusCode === 422) {
+          logger.info(expandError(err), 'Branch no longer exists - exiting');
+          throw new Error('repository-changed');
+        }
+        throw err;
+      }
+    }
+    // Low-level commit operations
 
-// Internal: Updates an existing branch to new commit sha
-async function updateBranch(self, branchName, commit) {
-  logger.debug(`Updating branch ${branchName} with commit ${commit}`);
-  const options = {
-    body: {
-      sha: commit,
-      force: true,
-    },
-  };
-  // istanbul ignore if
-  if (self.forkToken) {
-    options.token = self.forkToken;
-  }
-  try {
-    await get.patch(
-      `repos/${self.repository}/git/refs/heads/${branchName}`,
-      options
-    );
-  } catch (err) /* istanbul ignore next */ {
-    if (err.statusCode === 422) {
-      logger.info(expandError(err), 'Branch no longer exists - exiting');
-      throw new Error('repository-changed');
+    // Create a blob with fileContents and return sha
+    async function createBlob(fileContents) {
+      logger.debug('Creating blob');
+      const options = {
+        body: {
+          encoding: 'base64',
+          content: Buffer.from(fileContents).toString('base64'),
+        },
+      };
+      // istanbul ignore if
+      if (config.forkToken) {
+        options.token = config.forkToken;
+      }
+      return (await get.post(`repos/${config.repository}/git/blobs`, options))
+        .body.sha;
     }
-    throw err;
-  }
-}
-// Low-level commit operations
 
-// Create a blob with fileContents and return sha
-async function createBlob(self, fileContents) {
-  logger.debug('Creating blob');
-  const options = {
-    body: {
-      encoding: 'base64',
-      content: Buffer.from(fileContents).toString('base64'),
-    },
-  };
-  // istanbul ignore if
-  if (self.forkToken) {
-    options.token = self.forkToken;
-  }
-  return (await get.post(`repos/${self.repository}/git/blobs`, options)).body
-    .sha;
-}
+    // Return the tree SHA for a commit
+    async function getCommitTree(commit) {
+      logger.debug(`getCommitTree(${commit})`);
+      return (await get(`repos/${config.repository}/git/commits/${commit}`))
+        .body.tree.sha;
+    }
 
-// Return the tree SHA for a commit
-async function getCommitTree(self, commit) {
-  logger.debug(`getCommitTree(${commit})`);
-  return (await get(`repos/${self.repository}/git/commits/${commit}`)).body.tree
-    .sha;
-}
+    // Create a tree and return SHA
+    async function createTree(baseTree, files) {
+      logger.debug(`createTree(${baseTree}, files)`);
+      const body = {
+        base_tree: baseTree,
+        tree: [],
+      };
+      files.forEach(file => {
+        body.tree.push({
+          path: file.name,
+          mode: '100644',
+          type: 'blob',
+          sha: file.blob,
+        });
+      });
+      logger.trace({ body }, 'createTree body');
+      const options = { body };
+      // istanbul ignore if
+      if (config.forkToken) {
+        options.token = config.forkToken;
+      }
+      return (await get.post(`repos/${config.repository}/git/trees`, options))
+        .body.sha;
+    }
 
-// Create a tree and return SHA
-async function createTree(self, baseTree, files) {
-  logger.debug(`createTree(${baseTree}, files)`);
-  const body = {
-    base_tree: baseTree,
-    tree: [],
-  };
-  files.forEach(file => {
-    body.tree.push({
-      path: file.name,
-      mode: '100644',
-      type: 'blob',
-      sha: file.blob,
-    });
-  });
-  logger.trace({ body }, 'createTree body');
-  const options = { body };
-  // istanbul ignore if
-  if (self.forkToken) {
-    options.token = self.forkToken;
-  }
-  return (await get.post(`repos/${self.repository}/git/trees`, options)).body
-    .sha;
-}
+    // Create a commit and return commit SHA
+    async function createCommit(parent, tree, message) {
+      logger.debug(`createCommit(${parent}, ${tree}, ${message})`);
+      const { gitAuthor, gitPrivateKey } = config;
+      const now = moment();
+      let author;
+      if (gitAuthor) {
+        logger.trace('Setting gitAuthor');
+        author = {
+          name: gitAuthor.name,
+          email: gitAuthor.address,
+          date: now.format(),
+        };
+      }
+      const body = {
+        message,
+        parents: [parent],
+        tree,
+      };
+      if (author) {
+        body.author = author;
+        // istanbul ignore if
+        if (gitPrivateKey) {
+          logger.debug('Found gitPrivateKey');
+          const privKeyObj = openpgp.key.readArmored(gitPrivateKey).keys[0];
+          const commit = `tree ${tree}\nparent ${parent}\nauthor ${
+            author.name
+          } <${author.email}> ${now.format('X ZZ')}\ncommitter ${
+            author.name
+          } <${author.email}> ${now.format('X ZZ')}\n\n${message}`;
+          const { signature } = await openpgp.sign({
+            data: openpgp.util.str2Uint8Array(commit),
+            privateKeys: privKeyObj,
+            detached: true,
+            armor: true,
+          });
+          body.signature = signature;
+        }
+      }
+      const options = {
+        body,
+      };
+      // istanbul ignore if
+      if (config.forkToken) {
+        options.token = config.forkToken;
+      }
+      return (await get.post(`repos/${config.repository}/git/commits`, options))
+        .body.sha;
+    }
 
-// Create a commit and return commit SHA
-async function createCommit(self, parent, tree, message) {
-  logger.debug(`createCommit(${parent}, ${tree}, ${message})`);
-  const { gitAuthor, gitPrivateKey } = self;
-  const now = moment();
-  let author;
-  if (gitAuthor) {
-    logger.trace('Setting gitAuthor');
-    author = {
-      name: gitAuthor.name,
-      email: gitAuthor.address,
-      date: now.format(),
-    };
-  }
-  const body = {
-    message,
-    parents: [parent],
-    tree,
-  };
-  if (author) {
-    body.author = author;
-    // istanbul ignore if
-    if (gitPrivateKey) {
-      logger.debug('Found gitPrivateKey');
-      const privKeyObj = openpgp.key.readArmored(gitPrivateKey).keys[0];
-      const commit = `tree ${tree}\nparent ${parent}\nauthor ${author.name} <${
-        author.email
-      }> ${now.format('X ZZ')}\ncommitter ${author.name} <${
-        author.email
-      }> ${now.format('X ZZ')}\n\n${message}`;
-      const { signature } = await openpgp.sign({
-        data: openpgp.util.str2Uint8Array(commit),
-        privateKeys: privKeyObj,
-        detached: true,
-        armor: true,
-      });
-      body.signature = signature;
+    async function getCommitDetails(commit) {
+      logger.debug(`getCommitDetails(${commit})`);
+      const results = await get(
+        `repos/${config.repository}/git/commits/${commit}`
+      );
+      return results.body;
     }
   }
-  const options = {
-    body,
-  };
-  // istanbul ignore if
-  if (self.forkToken) {
-    options.token = self.forkToken;
-  }
-  return (await get.post(`repos/${self.repository}/git/commits`, options)).body
-    .sha;
-}
-
-async function getCommitDetails(self, commit) {
-  logger.debug(`getCommitDetails(${commit})`);
-  const results = await get(`repos/${self.repository}/git/commits/${commit}`);
-  return results.body;
 }
 
 module.exports = Storage;
-- 
GitLab