Skip to content

Commit 1f4c649

Browse files
authored
Merge pull request #7 from stovmascript/next
Next
2 parents 366291f + d343a5b commit 1f4c649

File tree

5 files changed

+209
-97
lines changed

5 files changed

+209
-97
lines changed

README.md

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@
22

33
Seamlessly shadows the behaviour of [`npm version`](https://docs.npmjs.com/cli/version).
44

5+
## Prerequisites (iOS only)
6+
7+
- Xcode Command Line Tools (`xcode-select --install`)
8+
9+
## Project setup (iOS only)
10+
11+
Open your Xcode project and under "Build Settings -> Versioning -> Current Project Version", set the value to your current `CFBundleVersion` ("General -> Identity -> Build").
12+
13+
---
14+
515
## npm-scripts hook (automatic method)
616

717
### Setup
@@ -39,7 +49,7 @@ react-native-version will then update your `android/` and `ios/` code and automa
3949
npm install -g react-native-version
4050
```
4151

42-
### Example
52+
### Example usage
4353

4454
```shell
4555
cd AwesomeProject/
@@ -54,8 +64,9 @@ react-native-version
5464
-a, --amend Amend the previous commit. This is done automatically when react-native-version is run from the "postversion" npm script. Use "--never-amend" if you never want to amend.
5565
-A, --never-amend Never amend the previous commit
5666
-b, --increment-build Only increment build number
57-
-d, --android [path] Path to your "app/build.gradle" file
58-
-i, --ios [path] Path to your "Info.plist" file
67+
-d, --android [path] Path to your "android/app/build.gradle" file
68+
-i, --ios [path] Path to your "ios/" folder
69+
-r, --reset-build Reset build number back to "1" (iOS only). Unlike Android's "versionCode", iOS doesn't require you to bump the "CFBundleVersion", as long as "CFBundleShortVersionString" changes. To make it consistent across platforms, react-native-version bumps both by default. You can use this option if you prefer to reset the build number after every version change. If you then need to push another build under the same version, you can use "-bt ios".
5970
-t, --target <platforms> Only version specified platforms, eg. "--target android,ios"
6071
```
6172

@@ -88,7 +99,29 @@ RNV=android react-native-version --target ios
8899
```
89100
:rage1: :speak_no_evil:
90101

102+
## API
103+
104+
```javascript
105+
import { version } from 'react-native-version';
106+
107+
version({
108+
amend: true,
109+
resetBuild: true,
110+
// ...
111+
});
112+
```
113+
114+
### Methods
115+
116+
#### version(program)
117+
Versions your app.
118+
119+
| Param | Type | Description |
120+
| --- | --- | --- |
121+
| program | <code>object</code> | commander/CLI-style options, camelCased |
122+
91123
## See also
92124

125+
- [agvtool](https://developer.apple.com/library/content/qa/qa1827/_index.html)
93126
- [npm-version](https://docs.npmjs.com/cli/version)
94127
- [Semantic Versioning (semver)](http://semver.org/)

cli.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/usr/bin/env node
2+
3+
const list = require('./utils').list;
4+
const pkg = require('./package');
5+
const program = require('commander');
6+
const rnv = require('./');
7+
8+
const defaults = rnv.getDefaults();
9+
10+
program
11+
/* eslint-disable max-len */
12+
.option('-a, --amend', 'Amend the previous commit. This is done automatically when ' + pkg.name + ' is run from the "postversion" npm script. Use "--never-amend" if you never want to amend.')
13+
.option('-A, --never-amend', 'Never amend the previous commit')
14+
.option('-b, --increment-build', 'Only increment build number')
15+
.option('-d, --android [path]', 'Path to your "android/app/build.gradle" file', defaults.android)
16+
.option('-i, --ios [path]', 'Path to your "ios/" folder', defaults.ios)
17+
.option('-r, --reset-build', 'Reset build number back to "1" (iOS only). Unlike Android\'s "versionCode", iOS doesn\'t require you to bump the "CFBundleVersion", as long as "CFBundleShortVersionString" changes. To make it consistent across platforms, ' + pkg.name + ' bumps both by default. You can use this option if you prefer to reset the build number after every version change. If you then need to push another build under the same version, you can use "-bt ios".')
18+
.option('-t, --target <platforms>', 'Only version specified platforms, eg. "--target android,ios"', list)
19+
/* eslint-enable max-len */
20+
.parse(process.argv);
21+
22+
rnv.version(program);

index.js

Lines changed: 131 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,111 +1,153 @@
1-
#!/usr/bin/env node
2-
31
const chalk = require('chalk');
42
const child = require('child_process');
53
const fs = require('fs');
4+
const list = require('./utils').list;
65
const path = require('path');
7-
const pkg = require('./package');
8-
const plist = require('simple-plist');
9-
const program = require('commander');
106

117
const cwd = process.cwd();
128

139
const appPkg = require(path.join(cwd, 'package.json'));
1410

15-
/**
16-
* Splits list items in comma-separated lists
17-
* @param {string} val comma-separated list
18-
* @return {array} list items
19-
*/
20-
function list(val) {
21-
return val.split(',');
22-
}
11+
const env = {
12+
target: process.env.RNV && list(process.env.RNV)
13+
};
2314

24-
program
25-
/* eslint-disable max-len */
26-
.option('-a, --amend', 'Amend the previous commit. This is done automatically when ' + pkg.name + ' is run from the "postversion" npm script. Use "--never-amend" if you never want to amend.')
27-
.option('-A, --never-amend', 'Never amend the previous commit')
28-
.option('-b, --increment-build', 'Only increment build number')
29-
.option('-d, --android [path]', 'Path to your "app/build.gradle" file', path.join(cwd, 'android/app/build.gradle'))
30-
.option('-i, --ios [path]', 'Path to your "Info.plist" file', path.join(cwd, 'ios', appPkg.name, 'Info.plist'))
31-
.option('-t, --target <platforms>', 'Only version specified platforms, eg. "--target android,ios"', list)
32-
/* eslint-enable max-len */
33-
.parse(process.argv);
15+
const defaults = {
16+
android: path.join(cwd, 'android/app/build.gradle'),
17+
ios: path.join(cwd, 'ios')
18+
};
3419

3520
/**
36-
* Amends previous commit with changed gradle and plist files
21+
* Versions your app.
22+
* @param {object} program commander/CLI-style options, camelCased
3723
*/
38-
function amend() {
39-
if (
40-
program.amend
41-
|| process.env.npm_lifecycle_event === 'postversion' && !program.neverAmend
42-
|| !program.incrementBuild
43-
) {
44-
child.spawnSync('git', ['add', program.android, program.ios]);
45-
child.execSync('git commit --amend --no-edit');
46-
}
47-
}
48-
49-
const env = {
50-
target: process.env.RNV && list(process.env.RNV)
51-
};
24+
function version(program) {
25+
program.android = program.android || defaults.android;
26+
program.ios = program.ios || defaults.ios;
27+
28+
const targets = []
29+
.concat(program.target, env.target)
30+
.filter(function(target) {
31+
return typeof target !== 'undefined';
32+
});
5233

53-
const targets = []
54-
.concat(program.target, env.target)
55-
.filter(function(target) {
56-
return typeof target !== 'undefined';
57-
});
58-
59-
if (!targets.length || targets.indexOf('android') > -1) {
60-
fs.stat(program.android, function(err, stats) {
61-
if (err) {
62-
console.log(chalk.red('No file found at ' + program.android));
63-
console.log(chalk.yellow('Use the "--android" option to specify the path manually'));
64-
program.outputHelp();
65-
} else {
66-
const androidFile = fs.readFileSync(program.android, 'utf8');
67-
var newAndroidFile = androidFile;
68-
69-
if (!program.incrementBuild) {
70-
newAndroidFile = newAndroidFile.replace(
71-
/versionName "(.*)"/, 'versionName "' + appPkg.version + '"'
72-
);
73-
}
74-
75-
newAndroidFile = newAndroidFile.replace(/versionCode (\d+)/, function(match, cg1) {
76-
const newVersionCodeNumber = parseInt(cg1, 10) + 1;
77-
return 'versionCode ' + newVersionCodeNumber;
34+
const android = new Promise(function(resolve) {
35+
if (!targets.length || targets.indexOf('android') > -1) {
36+
fs.stat(program.android, function(err) {
37+
if (err) {
38+
console.log(chalk.red('No gradle file found at ' + program.android));
39+
40+
console.log(chalk.yellow(
41+
'Use the "--android" option to specify the path manually'
42+
));
43+
44+
program.outputHelp();
45+
} else {
46+
const androidFile = fs.readFileSync(program.android, 'utf8');
47+
var newAndroidFile = androidFile;
48+
49+
if (!program.incrementBuild) {
50+
newAndroidFile = newAndroidFile.replace(
51+
/versionName "(.*)"/, 'versionName "' + appPkg.version + '"'
52+
);
53+
}
54+
55+
newAndroidFile = newAndroidFile
56+
.replace(/versionCode (\d+)/, function(match, cg1) {
57+
const newVersionCodeNumber = parseInt(cg1, 10) + 1;
58+
return 'versionCode ' + newVersionCodeNumber;
59+
});
60+
61+
fs.writeFileSync(program.android, newAndroidFile);
62+
resolve();
63+
}
7864
});
65+
}
66+
});
7967

80-
fs.writeFileSync(program.android, newAndroidFile);
81-
amend();
68+
const ios = new Promise(function(resolve) {
69+
if (!targets.length || targets.indexOf('ios') > -1) {
70+
fs.stat(program.ios, function(err) {
71+
if (err) {
72+
console.log(chalk.red('No project folder found at ' + program.ios));
73+
74+
console.log(chalk.yellow(
75+
'Use the "--ios" option to specify the path manually'
76+
));
77+
78+
program.outputHelp();
79+
} else {
80+
try {
81+
child.execSync('xcode-select --print-path', {
82+
stdio: ['ignore', 'ignore', 'pipe']
83+
});
84+
} catch (err) {
85+
console.log(chalk.red(err));
86+
87+
console.log(chalk.yellow(
88+
'Looks like Xcode Command Line Tools aren\'t installed'
89+
));
90+
91+
console.log('');
92+
console.log(' Install:');
93+
console.log('');
94+
console.log(' $ xcode-select --install');
95+
console.log('');
96+
process.exit(1);
97+
}
98+
99+
const agvtoolOpts = {
100+
cwd: program.ios
101+
};
102+
103+
try {
104+
child.execSync('agvtool what-version', agvtoolOpts);
105+
} catch (err) {
106+
console.log(chalk.red(err.stdout));
107+
process.exit(1);
108+
}
109+
110+
if (!program.incrementBuild) {
111+
child.spawnSync(
112+
'agvtool', ['new-marketing-version', appPkg.version], agvtoolOpts
113+
);
114+
}
115+
116+
if (program.resetBuild) {
117+
child.execSync('agvtool new-version -all 1', agvtoolOpts);
118+
} else {
119+
child.execSync('agvtool next-version -all', agvtoolOpts);
120+
}
121+
122+
resolve();
123+
}
124+
});
82125
}
83126
});
84-
}
85127

86-
if (!targets.length || targets.indexOf('ios') > -1) {
87-
fs.stat(program.ios, function(err, stats) {
88-
if (err) {
89-
console.log(chalk.red('No file found at ' + program.ios));
90-
console.log(chalk.yellow('Use the "--ios" option to specify the path manually'));
91-
program.outputHelp();
92-
} else {
93-
const iosFile = plist.readFileSync(program.ios);
94-
95-
if (program.incrementBuild) {
96-
iosFile.CFBundleVersion = String(parseInt(iosFile.CFBundleVersion, 10) + 1);
97-
} else {
98-
iosFile.CFBundleShortVersionString = appPkg.version;
99-
iosFile.CFBundleVersion = String(1);
100-
}
101-
102-
plist.writeFileSync(program.ios, iosFile);
103-
104-
if (process.platform === 'darwin') {
105-
child.execSync('plutil -convert xml1 ' + program.ios);
106-
}
107-
108-
amend();
128+
Promise
129+
.all([android, ios])
130+
.then(function() {
131+
if (
132+
program.amend
133+
|| process.env.npm_lifecycle_event === 'postversion' && !program.neverAmend
134+
) {
135+
child.spawnSync('git', ['add', program.android, program.ios]);
136+
child.execSync('git commit --amend --no-edit');
109137
}
110138
});
111139
}
140+
141+
module.exports = {
142+
143+
/**
144+
* Returns default values for some options, namely android/ios file/folder paths
145+
* @return {object} defaults
146+
*/
147+
getDefaults: function() {
148+
return defaults;
149+
},
150+
151+
version: version
152+
153+
};

package.json

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@
66
"license": "MIT",
77
"main": "index.js",
88
"bin": {
9-
"react-native-version": "index.js"
9+
"react-native-version": "cli.js"
1010
},
1111
"dependencies": {
1212
"chalk": "^1.1.3",
13-
"commander": "^2.9.0",
14-
"simple-plist": "^0.1.4"
13+
"commander": "^2.9.0"
1514
},
1615
"devDependencies": {
1716
"eslint": "^3.4.0",
18-
"eslint-config-google": "^0.6.0"
17+
"eslint-config-google": "^0.6.0",
18+
"jsdoc-to-markdown": "^1.3.7"
1919
},
2020
"homepage": "https://github.com/stovmascript/react-native-version#readme",
2121
"repository": {
@@ -38,5 +38,8 @@
3838
"version",
3939
"versionCode",
4040
"versionName"
41-
]
41+
],
42+
"scripts": {
43+
"docs": "jsdoc2md -d 4 index.js"
44+
}
4245
}

utils.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module.exports = {
2+
3+
/**
4+
* Splits list items in comma-separated lists
5+
* @param {string} val comma-separated list
6+
* @return {array} list items
7+
*/
8+
list: function(val) {
9+
return val.split(',');
10+
}
11+
12+
};

0 commit comments

Comments
 (0)