Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const pathToPackage = argv.pathToPackage || `${pathToRoot}/package.json`;
const info = helpers.getPackageInfo(pathToPackage);

const pathToPlist = argv.pathToPlist || `${pathToRoot}/ios/${info.name}/Info.plist`;
const pathToPbxproj = argv.pathToPbxproj || `${pathToRoot}/ios/${info.name}.xcodeproj/project.pbxproj`;
const pathToGradle = argv.pathToGradle || `${pathToRoot}/android/app/build.gradle`;
// handle case of several plist files
const pathsToPlists = Array.isArray(pathToPlist) ? pathToPlist : [pathToPlist];
Expand All @@ -27,7 +28,7 @@ let patch = helpers.version(versions[2], argv.patch, argv.major || argv.minor);
const version = `${major}.${minor}.${patch}`;

// getting next build number
const buildCurrent = helpers.getBuildNumberFromPlist(pathsToPlists[0]);
const buildCurrent = helpers.getMaximumBuildNumber(pathsToPlists[0], pathToPbxproj);
const build = buildCurrent + 1;

// getting commit message
Expand Down Expand Up @@ -73,7 +74,7 @@ const update = chain.then(() => {
log.info('Updating version in xcode project...', 1);

pathsToPlists.forEach(pathToPlist => {
helpers.changeVersionAndBuildInPlist(pathToPlist, version, build);
helpers.changeVersionAndBuildInPlist(pathToPlist, version, build, pathToPbxproj);
});
log.success(`Version and build number in ios project (plist file) changed.`, 2);
}).then(() => {
Expand All @@ -96,7 +97,8 @@ const commit = update.then(() => {
return helpers.commitVersionIncrease(version, message, [
pathToPackage,
...pathsToPlists,
pathToGradle
pathToGradle,
pathToPbxproj
]).then(() => {
log.success(`Commit with files added. Run "git push".`, 1);
});
Expand Down
91 changes: 81 additions & 10 deletions lib/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,31 +19,102 @@ module.exports = {
return flag ? value + 1 : value;
},

replacePlaceholdersFromPbxproj(string, pathToPbxproj) {
const pbxProjContent = fs.readFileSync(pathToPbxproj, 'utf8');

// Convert to set and back to remove duplicates, since replaceAll will replace all instances of a placeholder
const placeholders = [...new Set(string.match(/\$\([^)]*\)/))];
for (let placeholder of placeholders) {
// Slice to remove $( and )
const regex = new RegExp(`${placeholder.slice(2,-1)}\\s*=\\s*([^;]+);`);
const match = pbxProjContent.match(regex);
if (match) string = string.replaceAll(placeholder, match[1]);
}

return string;
},

getPackageInfo(pathToFile) {
return JSON.parse(fs.readFileSync(pathToFile, 'utf8'));
},

getBuildNumberFromPlist(pathToPlist) {
getMaximumBuildNumber(pathToPlist, pathToPbxproj = null) {
const buildNumbers = [];
buildNumbers.push(this.getBuildNumberFromPlist(pathToPlist, pathToPbxproj));

return Math.max(...buildNumbers);
},

matchPlistBuildNumber(content) {
return content.match(/(<key>CFBundleVersion<\/key>\s+<string>)(.*)(<\/string>)/)[2];
},

matchPlistVersionNumber(content) {
return content.match(/(<key>CFBundleShortVersionString<\/key>\s+<string>)(.*)(<\/string>)/)[2];
},

getBuildNumberFromPlist(pathToPlist, pathToPbxproj = null) {
const content = fs.readFileSync(pathToPlist, 'utf8');
const match = content.match(/(<key>CFBundleVersion<\/key>\s+<string>)([\d\.]+)(<\/string>)/);
if (match && match[2]) {
return parseInt(match[2]);
const match = this.matchPlistBuildNumber(content);
if (match) {
let result = match;
if (pathToPbxproj) result = this.replacePlaceholdersFromPbxproj(match, pathToPbxproj);
return parseInt(result);
}

return 1;
},

setBuildSetting(content, key, newValue) {
// Escape key in case it ever contains regex characters
const escapedKey = key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');

const regex = new RegExp(`(${escapedKey}\\s*=\\s*)([^;]*)(;)`, 'g');

return content.replaceAll(regex, (_, prefix, _oldValue, suffix) => {
return `${prefix}${newValue}${suffix}`;
});
},

changeVersionInPackage(pathToFile, version) {
let packageContent = fs.readFileSync(pathToFile, 'utf8');
packageContent = packageContent.replace(/("version":\s*")([\d\.]+)(")/g, `$1${version}$3`);
fs.writeFileSync(pathToFile, packageContent, 'utf8');
},

changeVersionAndBuildInPlist(pathToFile, version, build) {
let content = fs.readFileSync(pathToFile, 'utf8');
content = content.replace(/(<key>CFBundleShortVersionString<\/key>\s*<string>)([\d\.]+)(<\/string>)/g, `$1${version}$3`);
content = content.replace(/(<key>CFBundleVersion<\/key>\s+<string>)([\d\.]+)(<\/string>)/g, `$1${build}$3`);
fs.writeFileSync(pathToFile, content, 'utf8');
isSingleVariableRef(str) {
return /^\$\([^)]+\)$/.test(str);
},

changeVersionAndBuildInPlist(pathToPlist, version, build, pathToPbxproj = null) {
let plistContent = fs.readFileSync(pathToPlist, 'utf8');
let pbxProjContent = null;
const rawBuildNumber = this.matchPlistBuildNumber(plistContent);
const rawVersion = this.matchPlistVersionNumber(plistContent);

if (pathToPbxproj) {
pbxProjContent = fs.readFileSync(pathToPbxproj, 'utf8');
}

if (!isNaN(parseInt(rawBuildNumber))) {
plistContent = plistContent.replace(/(<key>CFBundleVersion<\/key>\s+<string>)([\d\.]+)(<\/string>)/g, `$1${build}$3`);
}
else if (this.isSingleVariableRef(rawBuildNumber) && pathToPbxproj) {
pbxProjContent = this.setBuildSetting(pbxProjContent, rawBuildNumber.slice(2, -1), build);
} else {
throw new Error('Build number in plist is not a single variable nor a number. Unsure how to proceed, bailing out');
}

if (!rawVersion.split('.').some(part => !isNaN(parseInt(part))) && rawVersion.split('.').length === 3) {
plistContent = plistContent.replace(/(<key>CFBundleShortVersionString<\/key>\s*<string>)([\d\.]+)(<\/string>)/g, `$1${version}$3`);
} else if (this.isSingleVariableRef(rawVersion) && pathToPbxproj) {
pbxProjContent = this.setBuildSetting(pbxProjContent, rawVersion.slice(2, -1), version);
} else {
throw new Error('Version number in plist is not a single variable nor a number. Unsure how to proceed, bailing out');
}

fs.writeFileSync(pathToPlist, plistContent, 'utf8');
if (pathToPbxproj) fs.writeFileSync(pathToPbxproj, pbxProjContent, 'utf8');
},

changeVersionAndBuildInGradle(pathToFile, version, build) {
Expand All @@ -55,7 +126,7 @@ module.exports = {

commitVersionIncrease(version, message, pathsToAdd = []) {
return new Promise((resolve, reject) => {
exec(`git add ${pathsToAdd.join(' ')} && git commit -m '${message}' && git tag -a v${version} -m '${message}'`, error => {
exec(`git add ${pathsToAdd.join(' ')} && git commit -m "${message}" && git tag -a v${version} -m "${message}"`, error => {
if (error) {
reject(error);
return;
Expand Down