diff --git a/src/__tests__/fixtures/invalid-version-file/lib/test-gem/version.rb b/src/__tests__/fixtures/invalid-version-file/lib/test-gem/version.rb new file mode 100644 index 0000000..a17bd89 --- /dev/null +++ b/src/__tests__/fixtures/invalid-version-file/lib/test-gem/version.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +module TestGem + SOME_CONST = '1.1.2' +end diff --git a/src/__tests__/fixtures/invalid-version-file/test-gem.gemspec b/src/__tests__/fixtures/invalid-version-file/test-gem.gemspec new file mode 100644 index 0000000..fe80e19 --- /dev/null +++ b/src/__tests__/fixtures/invalid-version-file/test-gem.gemspec @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +lib = File.expand_path('lib', __dir__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) + +require 'test-gem/version' + +Gem::Specification.new do |spec| + spec.name = 'a-test-gem' + spec.version = TestGem::SOME_CONST + spec.authors = ['Rylan Collins'] + spec.summary = 'A gem for testing' +end diff --git a/src/__tests__/fixtures/prerelease/lib/test-gem/version.rb b/src/__tests__/fixtures/prerelease/lib/test-gem/version.rb new file mode 100644 index 0000000..09bdedd --- /dev/null +++ b/src/__tests__/fixtures/prerelease/lib/test-gem/version.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +module TestGem + VERSION = '0.1.0.alpha.1' +end diff --git a/src/__tests__/fixtures/prerelease/test-gem.gemspec b/src/__tests__/fixtures/prerelease/test-gem.gemspec new file mode 100644 index 0000000..e7e46ab --- /dev/null +++ b/src/__tests__/fixtures/prerelease/test-gem.gemspec @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +lib = File.expand_path('lib', __dir__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) + +require 'test-gem/version' + +Gem::Specification.new do |spec| + spec.name = 'a-test-gem' + spec.version = TestGem::VERSION + spec.authors = ['Rylan Collins'] + spec.summary = 'A gem for testing' +end diff --git a/src/__tests__/prepare.test.js b/src/__tests__/prepare.test.js index 2b7c71f..6cc55aa 100644 --- a/src/__tests__/prepare.test.js +++ b/src/__tests__/prepare.test.js @@ -44,6 +44,23 @@ end `); }); +describe('when the version.rb contains a prerelease version', () => { + it('writes the new version to the version.rb file', async () => { + await prepare( + {}, + { ...context, nextRelease: { version: '1.0.0-alpha.1' } }, + { versionFile, gemspec, gemName }, + ); + const versionContents = await readFile(path.resolve(cwd, versionFile), 'utf8'); + expect(versionContents).toEqual(`# frozen_string_literal: true + +module TestGem + VERSION = '1.0.0-alpha.1' +end +`); + }); +}); + describe('when updateGemfileLock is set to `true`', () => { it('runs `bundle install`', async () => { await writeFile(path.resolve(cwd, 'Gemfile'), "source 'https://rubygems.org'\ngemspec", 'utf8'); diff --git a/src/__tests__/verifyConditions.test.js b/src/__tests__/verifyConditions.test.js index 5774c8e..83b07af 100644 --- a/src/__tests__/verifyConditions.test.js +++ b/src/__tests__/verifyConditions.test.js @@ -66,6 +66,17 @@ describe('when there is no version file', () => { }); }); +describe('when no version can be found in the version file', () => { + it('throws an error', async () => { + const cwd = path.resolve(__dirname, './fixtures/invalid-version-file'); + await expect( + verifyConditions({}, { cwd, env: defaultEnv }, { credentialsFile }), + ).rejects.toThrow( + /^Couldn't find a valid version constant defined in `lib\/test-gem\/version.rb`.$/, + ); + }); +}); + it('creates the credentials file', async () => { await verifyConditions({}, { cwd: validCwd, env: defaultEnv }, { credentialsFile }); const credentialsContents = await readFile(credentialsFile, 'utf8'); diff --git a/src/common.js b/src/common.js new file mode 100644 index 0000000..8b3219b --- /dev/null +++ b/src/common.js @@ -0,0 +1,2 @@ +// taken from https://github.com/svenfuchs/gem-release/blob/0f5f2382ef960d40169400a8aa25085cd37d26b0/lib/gem/release/files/version.rb#L7 +module.exports.VERSION_REGEX = /(VERSION\s*=\s*['"])(?:(?!"|').)*(['"])/; diff --git a/src/prepare.js b/src/prepare.js index d13ba08..b6500c2 100644 --- a/src/prepare.js +++ b/src/prepare.js @@ -1,16 +1,13 @@ const { readFile, writeFile } = require('fs').promises; const path = require('path'); const execa = require('execa'); +const { VERSION_REGEX } = require('./common'); const writeVersion = async ({ versionFile, nextVersion, logger, cwd }) => { const fullVersionPath = path.resolve(cwd, versionFile); const versionContents = await readFile(fullVersionPath, 'utf8'); - const newContents = versionContents.replace( - /(VERSION = ['"])[0-9.]*(['"])/, - `$1${nextVersion}$2`, - ); + const newContents = versionContents.replace(VERSION_REGEX, `$1${nextVersion}$2`); logger.log('Writing version %s to `%s`', nextVersion, versionFile); - // TODO: Check to insure the contents changed. Or, maybe verify the format of the version in verify? await writeFile(fullVersionPath, newContents, 'utf8'); }; diff --git a/src/verifyConditions.js b/src/verifyConditions.js index 3b6117a..d001e01 100644 --- a/src/verifyConditions.js +++ b/src/verifyConditions.js @@ -1,10 +1,11 @@ // const verifyConditions = require('./src/verify'); const util = require('util'); const execa = require('execa'); -const { writeFile } = require('fs').promises; +const path = require('path'); +const { writeFile, readFile } = require('fs').promises; const SemanticReleaseError = require('@semantic-release/error'); - const glob = util.promisify(require('glob')); +const { VERSION_REGEX } = require('./common'); const loadGemspec = async cwd => { const gemspecs = await glob('*.gemspec', { cwd }); @@ -23,7 +24,6 @@ Please follow the "[Make your own gem guide](https://guides.rubygems.org/make-yo const [gemspec] = gemspecs; let gemName = null; try { - // TODO: Use cwd here instead of the full path? const { stdout } = await execa( 'ruby', ['-e', `puts Gem::Specification.load('${gemspec}').name`], @@ -55,8 +55,7 @@ Please make sure to add a valid \`name\` for your gem in your \`.gemspec\`. return { name: gemName, gemspec }; }; -const findVersionFile = async cwd => { - // TODO: Should we verify that we can find the version here? +const verifyVersionFile = async cwd => { const versionFiles = await glob('lib/**/version.rb', { cwd }); if (versionFiles.length !== 1) { throw new SemanticReleaseError( @@ -69,7 +68,21 @@ Please create a \`version.rb\` file with a defined \`VERSION\` constant in your ); } - return versionFiles[0]; + const [versionFile] = versionFiles; + const fullVersionPath = path.resolve(cwd, versionFile); + const versionContents = await readFile(fullVersionPath, 'utf8'); + if (!VERSION_REGEX.test(versionContents)) { + throw new SemanticReleaseError( + `Couldn't find a valid version constant defined in \`${versionFile}\`.`, + 'EINVALIDVERSIONFILE', + `Your \`version.rb\` file must define a \`VERSION\` constant. + +Please define your gem's version a string constant named \`VERSION\` inside your \`version.rb\` file. + `, + ); + } + + return versionFile; }; const verifyApiKey = async ({ env, credentialsFile }) => { @@ -105,7 +118,7 @@ module.exports = async function verify(pluginConfig, { env, cwd }, { credentials const { name, gemspec } = await loadGemspec(cwd); // - Locate version file - const versionFile = await findVersionFile(cwd); + const versionFile = await verifyVersionFile(cwd); // - Verify env var await verifyApiKey({ env, cwd, credentialsFile });