Skip to content

Commit

Permalink
refactor: increase usability and other minor changes (#21)
Browse files Browse the repository at this point in the history
* documentation: update multiple manifest references in scripts

* fix: throw semantic release error for unwritable manifests

* chore: add log to confirm completion

* documentation: use new travis badge that works

This change is done for the travis-ci.com migration, its further described over here badges/shields#1711.

Fixes #7

* documentation: update multiple manifest references in scripts

* fix: throw semantic release error for unwritable manifests

* chore: add log to confirm completion

* documentation: use new travis badge that works

This change is done for the travis-ci.com migration, its further described over here badges/shields#1711.

Fixes #7

* fix: add missing manifest identification for write errors

* refactor: remove some duplicate code reported by code climate

* chore: use spammy behavior for codecov

This helps making the PR more understandable when fixing multiple issues.
  • Loading branch information
byCedric authored Jul 11, 2018
1 parent 729baeb commit 49e29b1
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 32 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Expo - Semantic Release

[![Latest Release](https://img.shields.io/github/release/byCedric/semantic-release-expo/all.svg?style=flat-square)](https://github.com/byCedric/semantic-release-expo/releases)
[![Build Status](https://img.shields.io/travis/byCedric/semantic-release-expo/master.svg?style=flat-square)](https://travis-ci.com/byCedric/semantic-release-expo)
[![Build Status](https://img.shields.io/travis/com/byCedric/semantic-release-expo/master.svg?style=flat-square)](https://travis-ci.com/byCedric/semantic-release-expo)
[![Codecov coverage](https://img.shields.io/codecov/c/github/byCedric/semantic-release-expo.svg?style=flat-square)](https://codecov.io/gh/byCedric/semantic-release-expo)
[![Code Climate grade](https://img.shields.io/codeclimate/maintainability/byCedric/semantic-release-expo.svg?style=flat-square)](https://codeclimate.com/github/byCedric/semantic-release-expo)

Expand Down
2 changes: 1 addition & 1 deletion codecov.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
comment:
layout: "reach, diff, flags, files"
behavior: default
behavior: spammy
require_changes: false
require_base: false
require_head: true
10 changes: 10 additions & 0 deletions src/expo.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { readFile, readJson, writeJson } from 'fs-extra';
import * as detectIndent from 'detect-indent';
import * as detectNewline from 'detect-newline';
import { Context } from './types';

/**
* A manifest-light definition to use for typehinting.
Expand Down Expand Up @@ -40,6 +41,15 @@ export const DEFAULT_INDENT = ' ';
*/
export const DEFAULT_NEWLINE = '\n';

/**
* Log information about the manifest which is related to the error.
*/
export function logManifestFromError(context: Context, error: any) {
if (error && error.expo) {
context.logger.log('Error encountered for %s manifest %s', 'Expo', error.expo);
}
}

/**
* Read the Expo manifest content and return the parsed JSON.
*/
Expand Down
20 changes: 17 additions & 3 deletions src/scripts/prepare.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { getManifestFiles } from '../config';
import { readManifests, writeManifest } from '../expo';
import { readManifests, writeManifest, logManifestFromError } from '../expo';
import { SemanticMethod } from '../types';
import bumpVersions from '../version-bumpers';

const SemanticReleaseError = require('@semantic-release/error');

/**
* Prepare the new release by updating the manifest.
* Prepare the new release by updating all manifests.
* This should update at least the `version` using the next release version name.
* It should also update the version code and build number when available.
*/
Expand All @@ -21,7 +23,19 @@ const prepare: SemanticMethod = async (config, context) => {
})
));

await Promise.all(writes);
try {
await Promise.all(writes);
} catch (error) {
logManifestFromError(context, error);

throw new SemanticReleaseError(
'Could not write Expo manifest(s)',
'EWRITEEXPOMANIFEST',
error.message
);
}

context.logger.log('Updated all %s manifests!', writes.length);
};

export default prepare;
14 changes: 8 additions & 6 deletions src/scripts/verify-conditions.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { getManifestFiles, inheritPrepareConfig } from '../config';
import { readManifests } from '../expo';
import { readManifests, logManifestFromError } from '../expo';
import { SemanticMethod } from '../types';

const SemanticReleaseError = require('@semantic-release/error');

/**
* Verify the configuration of this plugin.
* This checks if an Expo `app.json` can be found.
* This checks if all Expo manifests are readable.
*/
const verifyConditions: SemanticMethod = async (config, context) => {
const verifyConfig = inheritPrepareConfig(config, context);
Expand All @@ -16,11 +16,13 @@ const verifyConditions: SemanticMethod = async (config, context) => {
meta => context.logger.log('Found %s manifest for %s in %s', 'Expo', meta.manifest.name, meta.filename)
);
} catch (error) {
if (error.expo) {
context.logger.log('Error encountered for %s manifest %s', 'Expo', error.expo);
}
logManifestFromError(context, error);

throw new SemanticReleaseError('Could not load Expo manifest(s).', 'EINVALIDEXPOMANIFEST', error.message);
throw new SemanticReleaseError(
'Could not load Expo manifest(s).',
'EINVALIDEXPOMANIFEST',
error.message
);
}
};

Expand Down
26 changes: 26 additions & 0 deletions test/expo.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ import {
MANIFEST_FILE,
DEFAULT_INDENT,
DEFAULT_NEWLINE,
logManifestFromError,
readManifest,
readManifests,
writeManifest,
getPlatforms,
getAndroidPlatform,
getIosPlatform,
} from '../src/expo';
import { createContext } from './factory';

describe('expo', () => {
describe('constants', () => {
Expand All @@ -27,6 +29,30 @@ describe('expo', () => {
it('has line feed as default new line', () => expect(DEFAULT_NEWLINE).toBe('\n'));
});

describe('#logManifestFromError', () => {
it('does not log anything for normal errors', () => {
const context = createContext();

logManifestFromError(context, new Error());

expect((context.logger.log as jest.Mock).mock.calls).toHaveLength(0);
});

it('does log for errors related to manifest errors', () => {
const context = createContext();
const error = new Error() as any;
error.expo = 'app.production.json';

logManifestFromError(context, error);

expect(context.logger.log).toBeCalledWith(
'Error encountered for %s manifest %s',
'Expo',
'app.production.json',
);
});
});

describe('#readManifest', () => {
it('reads the manifest file', async () => {
readFile.mockResolvedValue('{ "expo": { "name": "test" } }');
Expand Down
32 changes: 32 additions & 0 deletions test/factory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Context } from '../src/types';

/**
* Create a simple context logger with mock methods.
*/
export function createContextLogger() {
return {
log: jest.fn(),
error: jest.fn(),
};
}

/**
* Create a simple context object with logger.
*/
export function createContext(): Context {
return { logger: createContextLogger() };
}

/**
* Create a context with logger and default options.
*/
export function createContextWithOptions(): Context {
return {
logger: createContextLogger(),
options: {
branch: 'master',
repositoryUrl: 'https://github.com/bycedric/semantic-release-expo',
tagFormat: '${version}',
},
};
}
6 changes: 2 additions & 4 deletions test/scripts/prepare.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,19 @@ jest.doMock('../../src/expo', () => ({ readManifests, writeManifest, MANIFEST_FI
jest.doMock('../../src/version-bumpers', () => ({ default: bumpVersions }));

import prepare from '../../src/scripts/prepare';
import { createContextLogger } from '../factory';

describe('scripts/prepare', () => {
it('reads and writes manifests with new version bumped', async () => {
const config = {};
const context = {
logger: createContextLogger(),
nextRelease: {
version: '0.2.1',
gitTag: 'v0.2.1',
gitHead: 'abc12',
notes: 'Testing a new version',
},
logger: {
log: jest.fn(),
error: jest.fn(),
},
};

const oldManifest = { name: 'test', version: '0.2.0' };
Expand Down
24 changes: 7 additions & 17 deletions test/scripts/verify-conditions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,19 @@ const readManifests = jest.fn();
jest.doMock('../../src/expo', () => ({ readManifests, MANIFEST_FILE: 'app.json' }));

import verifyConditions from '../../src/scripts/verify-conditions';
import { createContextWithOptions } from '../factory';

const SemanticReleaseError = require('@semantic-release/error');

describe('scripts/verify-conditions', () => {
const createContextWithPrepare = (prepare?: any) => ({
options: {
prepare,
branch: 'master',
repositoryUrl: 'https://github.com/bycedric/semantic-release-expo',
tagFormat: '${version}',
},
logger: {
log: jest.fn(),
error: jest.fn(),
},
});

it('reads manifest and logs name', async () => {
const context = createContextWithOptions();
const config = {
manifests: [
'app.json',
'app.staging.json',
],
};
const context = createContextWithPrepare();

const firstMeta = {
filename: 'app.json',
Expand Down Expand Up @@ -65,7 +53,7 @@ describe('scripts/verify-conditions', () => {

it('throws when read manifest failed', async () => {
const config = {};
const context = createContextWithPrepare();
const context = createContextWithOptions();

readManifests.mockRejectedValue(new Error());

Expand All @@ -75,11 +63,13 @@ describe('scripts/verify-conditions', () => {
it('inherits prepare configration without verify conditions configuration', async () => {
const config = {};
const manifests = ['app.production.json', 'app.staging.json'];
const context = createContextWithPrepare([
const context = createContextWithOptions();

context.options!.prepare = [
{ path: '@semantic-release/changelog' },
{ path: '@semantic-release/npm' },
{ path: 'semantic-release-expo', manifests },
]);
];

const firstMeta = {
filename: 'app.production.json',
Expand Down

0 comments on commit 49e29b1

Please sign in to comment.