diff --git a/lib/manager/homebrew/update.ts b/lib/manager/homebrew/update.ts index eaf80631b087d5c236ceb65bbff24fa7dc31ba3b..1508b324e6a84e1006460bbf973e87c1d336f199 100644 --- a/lib/manager/homebrew/update.ts +++ b/lib/manager/homebrew/update.ts @@ -1,4 +1,4 @@ -import { createHash } from 'crypto'; +import { fromStream } from 'hasha'; import { coerce } from 'semver'; import { parseUrlPath } from './extract'; import { skip, isSpace, removeComments } from './util'; @@ -13,12 +13,10 @@ export async function updateDependency( ): Promise<string> { logger.trace('updateDependency()'); /* - 1. Update url field - 2. Update sha256 field + 1. Update url field 2. Update sha256 field */ let newContent = content; let newUrl: string; - let file: string; // Example urls: // "https://github.com/bazelbuild/bazel-watcher/archive/v0.8.2.tar.gz" // "https://github.com/aide/aide/releases/download/v0.16.1/aide-0.16.1.tar.gz" @@ -29,22 +27,25 @@ export async function updateDependency( ); return content; } + let newSha256; try { newUrl = `https://github.com/${upgrade.managerData.ownerName}/${ upgrade.managerData.repoName }/releases/download/${upgrade.newValue}/${ upgrade.managerData.repoName }-${coerce(upgrade.newValue)}.tar.gz`; - file = (await got(newUrl, { - encoding: null, - })).body; + newSha256 = await fromStream(got.stream(newUrl), { + algorithm: 'sha256', + }); } catch (errOuter) { logger.debug( `Failed to download release download for ${upgrade.depName} - trying archive instead` ); try { newUrl = `https://github.com/${upgrade.managerData.ownerName}/${upgrade.managerData.repoName}/archive/${upgrade.newValue}.tar.gz`; - file = (await got(newUrl, { encoding: null })).body; + newSha256 = await fromStream(got.stream(newUrl), { + algorithm: 'sha256', + }); } catch (errInner) { logger.debug( `Failed to download archive download for ${upgrade.depName} - update failed` @@ -52,6 +53,12 @@ export async function updateDependency( return content; } } + if (!newSha256) { + logger.debug( + `Failed to generate new sha256 for ${upgrade.depName} - update failed` + ); + return content; + } const newParsedUrlPath = parseUrlPath(newUrl); if (!newParsedUrlPath) { logger.debug(`Failed to update url for dependency ${upgrade.depName}`); @@ -61,14 +68,6 @@ export async function updateDependency( logger.debug(`Failed to update url for dependency ${upgrade.depName}`); return content; } - let newSha256; - try { - newSha256 = createHash('sha256') - .update(file) - .digest('hex'); - } catch (err) /* istanbul ignore next */ { - logger.warn({ err }, 'Failed to generate new sha256 for homebrew'); - } newContent = updateUrl(content, upgrade.managerData.url, newUrl); if (!newContent) { logger.debug(`Failed to update url for dependency ${upgrade.depName}`); diff --git a/test/manager/homebrew/__snapshots__/update.spec.ts.snap b/test/manager/homebrew/__snapshots__/update.spec.ts.snap index c307d2d924d56960b4a46a04cb32e122f499e964..e673acfcb3da977f12d3cf758bb5e581b11bbe89 100644 --- a/test/manager/homebrew/__snapshots__/update.spec.ts.snap +++ b/test/manager/homebrew/__snapshots__/update.spec.ts.snap @@ -1,5 +1,68 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`manager/homebrew/update returns unchanged content if both got requests fail 1`] = ` +"=begin + url \\"https://github.com/aide/aide/releases/download/v0.16.1/aide-0.16.1.tar.gz\\" + sha256 \\"0f2b7cecc70c1a27d35c06c98804fcdb9f326630de5d035afc447122186010b7\\" +=end +# url \\"https://github.com/aide/aide/releases/download/v0.16.1/aide-0.16.1.tar.gz\\" +# sha256 \\"0f2b7cecc70c1a27d35c06c98804fcdb9f326630de5d035afc447122186010b7\\" + +$sha256 = \\"0f2b7cecc70c1a27d35c06c98804fcdb9f326630de5d035afc447122186010b7\\" +class Aide < Formula + desc \\"File and directory integrity checker\\" + homepage \\"https://aide.github.io/\\" + url \\"https://github.com/aide/aide/releases/download/v0.16.1/aide-0.16.1.tar.gz\\" + sha256 \\"0f2b7cecc70c1a27d35c06c98804fcdb9f326630de5d035afc447122186010b7\\" + + bottle do + cellar :any + sha256 \\"53b1dfabc76d6e54db56ec24f7f91b6cc9dcdd18210d17d2df92f86225fb9c9f\\" => :mojave + sha256 \\"79a2d4ce92526516891c844a4852161d39421f9dc31d2eba5ea0e48d79496053\\" => :high_sierra + sha256 \\"b626fcf7e52a0ea66fbed58bdc00cb08484f7bce8e84e61edf6740fbad7fabc5\\" => :sierra + end + + head do + url \\"https://github.com/aide/aide.git\\" + depends_on \\"autoconf\\" => :build + depends_on \\"automake\\" => :build + end + + depends_on \\"libgcrypt\\" + depends_on \\"libgpg-error\\" + depends_on \\"pcre\\" + + def install + system \\"sh\\", \\"./autogen.sh\\" if build.head? + + system \\"./configure\\", \\"--disable-lfs\\", + \\"--disable-static\\", + \\"--with-curl\\", + \\"--with-zlib\\", + \\"--sysconfdir=#{etc}\\", + \\"--prefix=#{prefix}\\" + + system \\"make\\", \\"install\\" + end + + test do + (testpath/\\"aide.conf\\").write <<~EOS + database = file:/var/lib/aide/aide.db + database_out = file:/var/lib/aide/aide.db.new + database_new = file:/var/lib/aide/aide.db.new + gzip_dbout = yes + summarize_changes = yes + grouped = yes + verbose = 7 + database_attrs = sha256 + /etc p+i+u+g+sha256 + EOS + system \\"#{bin}/aide\\", \\"--config-check\\", \\"-c\\", \\"aide.conf\\" + end +end +" +`; + exports[`manager/homebrew/update updates "archive" github dependency 1`] = ` "# Copyright 2018 The Bazel Authors. All rights reserved. # @@ -30,7 +93,7 @@ class Ibazel < Formula # To generate run: # curl https://codeload.github.com/bazelbuild/bazel-watcher/tar.gz/v0.8.2 | sha256sum - sha256 '9c96cc68155bd283282123413ecaafe52b12ea5f2585c3c383ce6141f779a58f' + sha256 'new_hash_value' bottle :unneeded @@ -64,7 +127,7 @@ class Aide < Formula desc \\"File and directory integrity checker\\" homepage \\"https://aide.github.io/\\" url \\"https://github.com/aide/aide/releases/download/v0.17.7/aide-0.17.7.tar.gz\\" - sha256 \\"337c78a56c8dde1a42eb767bf89f16eb3ee4207e4817954899a3f0f293c6ad6b\\" + sha256 \\"new_hash_value\\" bottle do cellar :any diff --git a/test/manager/homebrew/update.spec.ts b/test/manager/homebrew/update.spec.ts index 597d758673843a21272b5f4263b870a4f1245344..85bc3b79a4b0757bd143b6593675c4351c47976b 100644 --- a/test/manager/homebrew/update.spec.ts +++ b/test/manager/homebrew/update.spec.ts @@ -1,10 +1,11 @@ import fs from 'fs'; +import { fromStream as _fromStream } from 'hasha'; import { updateDependency } from '../../../lib/manager/homebrew/update'; -import _got from '../../../lib/util/got'; +jest.mock('hasha'); jest.mock('../../../lib/util/got'); -const got: any = _got; +const fromStream: jest.Mock<Promise<string>> = _fromStream as any; const aide = fs.readFileSync('test/manager/homebrew/_fixtures/aide.rb', 'utf8'); const ibazel = fs.readFileSync( @@ -30,7 +31,7 @@ describe('manager/homebrew/update', () => { }, newValue: 'v0.17.7', }; - got.mockReturnValueOnce({ body: 'some_content_1' }); + fromStream.mockResolvedValueOnce('new_hash_value'); const newContent = await updateDependency(aide, upgrade); expect(newContent).not.toBeNull(); expect(newContent).not.toBe(aide); @@ -50,13 +51,13 @@ describe('manager/homebrew/update', () => { }, newValue: 'v0.9.3', }; - got.mockReturnValueOnce({ body: 'some_content_2' }); + fromStream.mockResolvedValueOnce('new_hash_value'); const newContent = await updateDependency(ibazel, upgrade); expect(newContent).not.toBeNull(); expect(newContent).not.toBe(ibazel); expect(newContent).toMatchSnapshot(); }); - it('returns unchanged content if got function throws errors', async () => { + it('returns unchanged content if fromStream promise rejects', async () => { const upgrade = { currentValue: 'v0.8.2', depName: 'Ibazel', @@ -70,9 +71,7 @@ describe('manager/homebrew/update', () => { }, newValue: 'v0.9.3', }; - got.mockImplementationOnce(() => { - throw new Error('Request failed'); - }); + fromStream.mockRejectedValueOnce('Request failed'); const newContent = await updateDependency(ibazel, upgrade); expect(newContent).not.toBeNull(); expect(newContent).toBe(ibazel); @@ -91,9 +90,7 @@ describe('manager/homebrew/update', () => { }, newValue: 'v0.9.3', }; - got.mockImplementationOnce(() => { - return { body: 'some_content' }; - }); + fromStream.mockResolvedValueOnce('some_content'); const newContent = await updateDependency(content, upgrade); expect(newContent).not.toBeNull(); expect(newContent).toBe(content); @@ -113,13 +110,9 @@ describe('manager/homebrew/update', () => { }, newValue: 'v0.9.3', }; - got - .mockImplementationOnce(() => { - throw Error('Request failed'); - }) - .mockImplementationOnce(() => { - return { body: 'some_content' }; - }); + fromStream + .mockRejectedValueOnce('Request failed') + .mockResolvedValueOnce('some_content'); const newContent = await updateDependency(content, upgrade); expect(newContent).not.toBeNull(); expect(newContent).toBe(content); @@ -139,13 +132,9 @@ describe('manager/homebrew/update', () => { }, newValue: 'v0.9.3', }; - got - .mockImplementationOnce(() => { - throw Error('Request failed'); - }) - .mockImplementationOnce(() => { - return { body: 'some_content' }; - }); + fromStream + .mockRejectedValueOnce('Request failed') + .mockResolvedValueOnce('some_content'); const newContent = await updateDependency(content, upgrade); expect(newContent).not.toBeNull(); expect(newContent).toBe(content); @@ -172,9 +161,7 @@ describe('manager/homebrew/update', () => { }, newValue: 'v0.9.3', }; - got.mockImplementationOnce(() => { - return { body: 'some_content' }; - }); + fromStream.mockResolvedValueOnce('some_content'); const newContent = await updateDependency(content, upgrade); expect(newContent).not.toBeNull(); expect(newContent).toBe(content); @@ -200,9 +187,7 @@ describe('manager/homebrew/update', () => { }, newValue: 'v0.9.3', }; - got.mockImplementationOnce(() => { - return { body: 'some_content' }; - }); + fromStream.mockResolvedValueOnce('some_content'); const newContent = await updateDependency(content, upgrade); expect(newContent).not.toBeNull(); expect(newContent).toBe(content); @@ -229,9 +214,7 @@ describe('manager/homebrew/update', () => { }, newValue: 'v0.9.3', }; - got.mockImplementationOnce(() => { - return { body: 'some_content' }; - }); + fromStream.mockResolvedValueOnce('some_content'); const newContent = await updateDependency(content, upgrade); expect(newContent).not.toBeNull(); expect(newContent).toBe(content); @@ -257,11 +240,31 @@ describe('manager/homebrew/update', () => { }, newValue: 'v0.9.3', }; - got.mockImplementationOnce(() => { - return { body: 'some_content' }; - }); + fromStream.mockResolvedValueOnce('some_content'); const newContent = await updateDependency(content, upgrade); expect(newContent).not.toBeNull(); expect(newContent).toBe(content); }); + it('returns unchanged content if both got requests fail', async () => { + const upgrade = { + currentValue: 'v0.16.1', + depName: 'Aide', + managerData: { + ownerName: 'aide', + repoName: 'aide', + sha256: + '0f2b7cecc70c1a27d35c06c98804fcdb9f326630de5d035afc447122186010b7', + url: + 'https://github.com/aide/aide/releases/download/v0.16.1/aide-0.16.1.tar.gz', + }, + newValue: 'v0.17.7', + }; + fromStream + .mockRejectedValueOnce('Request failed.') + .mockRejectedValueOnce('Request failed.'); + const newContent = await updateDependency(aide, upgrade); + expect(newContent).not.toBeNull(); + expect(newContent).toBe(aide); + expect(newContent).toMatchSnapshot(); + }); });