|
#!/usr/bin/env node |
|
|
|
const { execSync } = require("child_process"); |
|
const { readFileSync } = require("fs"); |
|
const { resolve } = require("path"); |
|
|
|
/* CONSTANTS */ |
|
const ROOT_DIR = resolve(__dirname, "../../.."); |
|
|
|
/* HELPERS */ |
|
const exec = (command, options = {}) => |
|
execSync( |
|
command, |
|
{ |
|
encoding: "utf-8", |
|
cwd: ROOT_DIR, |
|
...options |
|
} |
|
); |
|
|
|
const getPaths = (name) => |
|
exec(`find node_modules -type d -name "${name}"`) |
|
.split("\n") |
|
.filter((s) => s.length > 0); |
|
|
|
const getPackageNameFromPath = (path) => { |
|
const endOfPath = path.split('node_modules/').slice(-1)[0]; |
|
const segments = endOfPath.split("/"); |
|
|
|
if (segments[0].startsWith("@")) { |
|
return segments.slice(0, 2).join("/"); |
|
} |
|
|
|
return segments[0]; |
|
}; |
|
|
|
const getPotentiallyNestedPackagePath = (path) => { |
|
const potentiallyNestedPath = path.split(/(node_modules\/)/).slice(0, -1); |
|
|
|
const packageName = getPackageNameFromPath(path); |
|
|
|
return [...potentiallyNestedPath, packageName].join(""); |
|
}; |
|
|
|
const getNativePackagePaths = () => { |
|
const paths = getPaths("android").concat(getPaths("ios")); |
|
|
|
const packagePaths = paths.map((path) => |
|
getPotentiallyNestedPackagePath(path) |
|
); |
|
|
|
return Array.from(new Set(packagePaths)); // Return a unique array |
|
}; |
|
|
|
const getVersions = (packagePaths) => |
|
Object.fromEntries( |
|
packagePaths.reduce((acc, path) => { |
|
const packageJsonFilename = resolve(path, "package.json"); |
|
const packageJsonContents = readFileSync(packageJsonFilename, { encoding: "utf8" }); |
|
const packageInfo = JSON.parse(packageJsonContents); |
|
|
|
const { version } = packageInfo; |
|
const packageName = getPackageNameFromPath(path);; |
|
|
|
acc.push([packageName, version]); |
|
return acc; |
|
}, []).sort((a, b) => a[0] > b[0] ? 1 : -1) // Sort by package name |
|
); |
|
|
|
const checkout = (ref) => { |
|
console.info(`➡️ Switching to ${ref}`); |
|
exec(`git checkout ${ref}`); |
|
}; |
|
|
|
const cleanup = () => { |
|
console.info("➡️ Removing node_modules/"); |
|
exec('rm -rf node_modules'); |
|
}; |
|
|
|
const installProdDeps = () => { |
|
console.info("➡️ Installing production dependencies"); |
|
exec("yarn install --production"); |
|
}; |
|
|
|
const getNativePackageVersions = () => { |
|
console.info("➡️ Finding native dependencies"); |
|
const nativePackagePaths = getNativePackagePaths(); |
|
const packagesWithVersions = getVersions(nativePackagePaths); |
|
return packagesWithVersions; |
|
}; |
|
|
|
const setup = (ref) => { |
|
checkout(ref); |
|
cleanup(); |
|
installProdDeps(); |
|
}; |
|
|
|
/* MAIN */ |
|
const main = () => { |
|
const { SOURCE_REF, TARGET_REF } = process.env; |
|
if (!SOURCE_REF || !TARGET_REF) { |
|
console.error('ERROR: Must provide SOURCE_REF and TARGET_REF in env.') |
|
process.exit(1); |
|
} |
|
|
|
setup(SOURCE_REF); |
|
const sourcePackageVersions = getNativePackageVersions(); |
|
|
|
setup(TARGET_REF); |
|
const targetPackageVersions = getNativePackageVersions(); |
|
|
|
console.info("➡️ Comparing"); |
|
|
|
let noChanges = true; |
|
Object.entries(sourcePackageVersions).forEach(([package, version]) => { |
|
if (!targetPackageVersions[package]) { |
|
console.info(`❌ Package removed: ${package}`); |
|
noChanges = false; |
|
} else if (targetPackageVersions[package] !== version) { |
|
console.info(`🚀 Package version changed: ${package} (${version} -> ${targetPackageVersions[package]})`); |
|
noChanges = false; |
|
} |
|
}); |
|
|
|
Object.entries(targetPackageVersions).forEach(([package]) => { |
|
if (!sourcePackageVersions[package]) { |
|
console.info(`✅ Package added: ${package}`); |
|
noChanges = false; |
|
} |
|
}); |
|
|
|
return noChanges; |
|
}; |
|
|
|
if (require.main === module) { |
|
const noChanges = main(); |
|
process.exit(noChanges ? 0 : 1); // Exit w/ non-zero code if there are changes to native packages |
|
} |