Skip to content
Merged
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
25 changes: 22 additions & 3 deletions scripts/publish-npm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
import * as argparse from 'argparse';
import chalk from 'chalk';
import * as shell from 'shelljs';
import {RELEASE_UNITS, question, $, printReleaseUnit, printPhase, getReleaseBranch, checkoutReleaseBranch} from './release-util';
import {RELEASE_UNITS, question, $, printReleaseUnit, printPhase, getReleaseBranch, checkoutReleaseBranch, ALPHA_RELEASE_UNIT, TFJS_RELEASE_UNIT} from './release-util';
import * as fs from 'fs';

const TMP_DIR = '/tmp/tfjs-publish';
const BAZEL_PACKAGES = new Set([
Expand Down Expand Up @@ -55,7 +56,8 @@ async function main() {
console.log(chalk.blue(`Using release unit ${releaseUnitInt}`));
console.log();

const {name, phases} = RELEASE_UNITS[releaseUnitInt];
const releaseUnit = RELEASE_UNITS[releaseUnitInt];
const {name, phases} = releaseUnit;

phases.forEach((_, i) => printPhase(phases, i));
console.log();
Expand All @@ -69,7 +71,13 @@ async function main() {
console.log(chalk.blue(`Using phase ${phaseInt}`));
console.log();

let releaseBranch = await getReleaseBranch(name);
let releaseBranch: string;
if (releaseUnit === ALPHA_RELEASE_UNIT) {
// Alpha release unit is published with the tfjs release unit.
releaseBranch = await getReleaseBranch(TFJS_RELEASE_UNIT.name);
} else {
releaseBranch = await getReleaseBranch(name);
}
console.log();

checkoutReleaseBranch(releaseBranch, args.git_protocol, TMP_DIR);
Expand All @@ -85,6 +93,17 @@ async function main() {
const pkg = packages[i];
shell.cd(pkg);

// Check the package.json for 'link:' and 'file:' dependencies.
const packageJson = JSON.parse(fs.readFileSync('package.json')
.toString('utf8')) as {dependencies: Record<string, string>};
for (let [dep, depVersion] of Object.entries(packageJson.dependencies)) {
const start = depVersion.slice(0,5);
if (start === 'link:' || start === 'file:') {
throw new Error(`${pkg} has a '${start}' dependency on ${dep}. `
+ 'Refusing to publish.');
}
}

console.log(chalk.magenta.bold(`~~~ Preparing package ${pkg}~~~`));
console.log(chalk.magenta('~~~ Installing packages ~~~'));
// tfjs-node-gpu needs to get some files from tfjs-node.
Expand Down
56 changes: 31 additions & 25 deletions scripts/release-tfjs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import * as argparse from 'argparse';
import chalk from 'chalk';
import * as fs from 'fs';
import * as shell from 'shelljs';
import {TMP_DIR, $, question, makeReleaseDir, createPR, TFJS_RELEASE_UNIT, updateTFJSDependencyVersions} from './release-util';
import {TMP_DIR, $, question, makeReleaseDir, createPR, TFJS_RELEASE_UNIT, updateTFJSDependencyVersions, ALPHA_RELEASE_UNIT, getMinorUpdateVersion, getPatchUpdateVersion} from './release-util';

const parser = new argparse.ArgumentParser();

Expand All @@ -36,13 +36,6 @@ parser.addArgument('--git-protocol', {
help: 'Use the git protocol rather than the http protocol when cloning repos.'
});

// Computes the default updated version (does a minor version update).
function getMinorUpdateVersion(version: string): string {
const versionSplit = version.split('.');

return [versionSplit[0], +versionSplit[1] + 1, '0'].join('.');
}

async function main() {
const args = parser.parseArgs();
const urlBase = args.git_protocol ? 'git@github.com:' : 'https://github.com/';
Expand All @@ -52,11 +45,29 @@ async function main() {
// Guess release version from tfjs-core's latest version, with a minor update.
const latestVersion = $(`npm view @tensorflow/tfjs-core dist-tags.latest`);
const minorUpdateVersion = getMinorUpdateVersion(latestVersion);
let newVersion = minorUpdateVersion;
newVersion =
await question(`New version (leave empty for ${minorUpdateVersion}): `);
if (newVersion === '') {
newVersion = minorUpdateVersion;
const newVersion = await question('New version for monorepo (leave empty for '
+ `${minorUpdateVersion}): `) || minorUpdateVersion;

// Populate the versions map with new versions for monorepo packages.
const versions = new Map<string /* package name */, string /* version */>();
for (const phase of TFJS_RELEASE_UNIT.phases) {
for (const packageName of phase.packages) {
versions.set(packageName, newVersion);
}
}

// Add versions for alpha monorepo packages, which do not have the same
// version as the other monorepo packages.
for (const phase of ALPHA_RELEASE_UNIT.phases) {
for (const packageName of phase.packages) {
const latestVersion =
$(`npm view @tensorflow/${packageName} dist-tags.latest`);
const minorUpdateVersion = getPatchUpdateVersion(latestVersion);
const newVersion =
await question(`New version for alpha package ${packageName}`
+ ` (leave empty for ${minorUpdateVersion}): `) || minorUpdateVersion;
versions.set(packageName, newVersion);
}
}

// Get release candidate commit.
Expand All @@ -77,15 +88,10 @@ async function main() {
$(`git checkout -b ${releaseBranch} ${commit}`);
$(`git push origin ${releaseBranch}`);

// Update version.
const phases = TFJS_RELEASE_UNIT.phases;

for (let i = 0; i < phases.length; i++) {
const packages = phases[i].packages;
const deps = phases[i].deps || [];

for (let i = 0; i < packages.length; i++) {
const packageName = packages[i];
// Update versions in package.json files.
const phases = [...TFJS_RELEASE_UNIT.phases, ...ALPHA_RELEASE_UNIT.phases];
for (const phase of phases) {
for (const packageName of phase.packages) {
shell.cd(packageName);

// Update the version.
Expand All @@ -94,10 +100,10 @@ async function main() {
const parsedPkg = JSON.parse(`${pkg}`);

console.log(chalk.magenta.bold(`~~~ Processing ${packageName} ~~~`));
const newVersion = versions.get(packageName);
pkg = `${pkg}`.replace(
`"version": "${parsedPkg.version}"`, `"version": "${newVersion}"`);

pkg = updateTFJSDependencyVersions(deps, pkg, parsedPkg, newVersion);
`"version": "${parsedPkg.version}"`, `"version": "${newVersion}"`);
pkg = updateTFJSDependencyVersions(pkg, versions);

fs.writeFileSync(packageJsonPath, pkg);

Expand Down
109 changes: 73 additions & 36 deletions scripts/release-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ export const WASM_PHASE: Phase = {
deps: ['tfjs-core', 'tfjs-backend-cpu']
};

export const WEBGPU_PHASE: Phase = {
packages: ['tfjs-backend-webgpu'],
deps: ['tfjs-core', 'tfjs-backend-cpu'],
};

export const VIS_PHASE: Phase = {
packages: ['tfjs-vis']
};
Expand Down Expand Up @@ -133,6 +138,18 @@ export const TFJS_RELEASE_UNIT: ReleaseUnit = {
]
};

// TODO(mattsoulanille): Move WEBGPU_PHASE to TFJS_RELEASE_UNIT when webgpu
// is out of alpha.
// Alpha packages use monorepo dependencies at the latest version but are
// not yet released at the same version number as the monorepo packages.
// Use this for packages that will be a part of the monorepo in the future.
// The release script will ask for a new version for each phase, and it will
// replace 'link' dependencies with the new monorepo version.
export const ALPHA_RELEASE_UNIT: ReleaseUnit = {
name: 'alpha-monorepo-packages',
phases: [WEBGPU_PHASE],
};

export const VIS_RELEASE_UNIT: ReleaseUnit = {
name: 'vis',
phases: [VIS_PHASE]
Expand Down Expand Up @@ -160,8 +177,9 @@ export const WEBSITE_RELEASE_UNIT: ReleaseUnit = {
};

export const RELEASE_UNITS: ReleaseUnit[] = [
TFJS_RELEASE_UNIT, VIS_RELEASE_UNIT, REACT_NATIVE_RELEASE_UNIT,
TFLITE_RELEASE_UNIT, AUTOML_RELEASE_UNIT, WEBSITE_RELEASE_UNIT
TFJS_RELEASE_UNIT, ALPHA_RELEASE_UNIT, VIS_RELEASE_UNIT,
REACT_NATIVE_RELEASE_UNIT, TFLITE_RELEASE_UNIT, AUTOML_RELEASE_UNIT,
WEBSITE_RELEASE_UNIT,
];

export const TMP_DIR = '/tmp/tfjs-release';
Expand Down Expand Up @@ -275,46 +293,43 @@ export async function updateDependency(

// Update package.json dependencies of tfjs packages. This method is different
// than `updateDependency`, it does not rely on published versions, instead it
// assumes all the packages have the same version and use that to update.
// uses a map from packageName to newVersion to update the versions.
export function updateTFJSDependencyVersions(
deps: string[], pkg: string, parsedPkg: any, tfjsVersion: string): string {
console.log(chalk.magenta.bold(`~~~ Update dependency versions ~~~`));
pkg: string, versions: Map<string, string>): string {

if (deps != null) {
for (let j = 0; j < deps.length; j++) {
const dep = deps[j];

// Get the current dependency package version.
let version = '';
const depNpmName = `@tensorflow/${dep}`;
if (parsedPkg['dependencies'] != null &&
parsedPkg['dependencies'][depNpmName] != null) {
version = parsedPkg['dependencies'][depNpmName];
} else if (
parsedPkg['peerDependencies'] != null &&
parsedPkg['peerDependencies'][depNpmName] != null) {
version = parsedPkg['peerDependencies'][depNpmName];
} else if (
parsedPkg['devDependencies'] != null &&
parsedPkg['devDependencies'][depNpmName] != null) {
version = parsedPkg['devDependencies'][depNpmName];
}
if (version == null) {
throw new Error(`No dependency found for ${dep}.`);
}
console.log(chalk.magenta.bold(`~~~ Update dependency versions ~~~`));

let relaxedVersionPrefix = '';
if (version.startsWith('~') || version.startsWith('^')) {
relaxedVersionPrefix = version.substr(0, 1);
}
const versionLatest = relaxedVersionPrefix + tfjsVersion;
const parsedPkg = JSON.parse(`${pkg}`);JSON.parse(pkg);
for (const [dep, newVersion] of versions) {
// Get the current dependency package version.
let version = '';
const depNpmName = `@tensorflow/${dep}`;
if (parsedPkg['dependencies'] != null &&
parsedPkg['dependencies'][depNpmName] != null) {
version = parsedPkg['dependencies'][depNpmName];
} else if (
parsedPkg['peerDependencies'] != null &&
parsedPkg['peerDependencies'][depNpmName] != null) {
version = parsedPkg['peerDependencies'][depNpmName];
} else if (
parsedPkg['devDependencies'] != null &&
parsedPkg['devDependencies'][depNpmName] != null) {
version = parsedPkg['devDependencies'][depNpmName];
}
if (version == null) {
throw new Error(`No dependency found for ${dep}.`);
}

pkg = `${pkg}`.replace(
new RegExp(`"${depNpmName}": "${version}"`, 'g'),
`"${depNpmName}": "${versionLatest}"`);
let relaxedVersionPrefix = '';
if (version.startsWith('~') || version.startsWith('^')) {
relaxedVersionPrefix = version.substr(0, 1);
}
}
const versionLatest = relaxedVersionPrefix + newVersion;

pkg = `${pkg}`.replace(
new RegExp(`"${depNpmName}": "${version}"`, 'g'),
`"${depNpmName}": "${versionLatest}"`);
}
return pkg;
}

Expand Down Expand Up @@ -390,3 +405,25 @@ export function createPR(
$(`hub pull-request -b ${releaseBranch} -m "${message}" -l INTERNAL -o`);
console.log();
}

// Computes the default updated version (does a patch version update).
export function getPatchUpdateVersion(version: string): string {
const versionSplit = version.split('.');

// For alpha or beta version string (e.g. "0.0.1-alpha.5"), increase the
// number after alpha/beta.
if (versionSplit[2].includes('alpha') || versionSplit[2].includes('beta')) {
return [
versionSplit[0], versionSplit[1], versionSplit[2], +versionSplit[3] + 1
].join('.');
}

return [versionSplit[0], versionSplit[1], +versionSplit[2] + 1].join('.');
}

// Computes the default updated version (does a minor version update).
export function getMinorUpdateVersion(version: string): string {
const versionSplit = version.split('.');

return [versionSplit[0], +versionSplit[1] + 1, '0'].join('.');
}
27 changes: 8 additions & 19 deletions scripts/release.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import * as argparse from 'argparse';
import chalk from 'chalk';
import * as fs from 'fs';
import * as shell from 'shelljs';
import {RELEASE_UNITS, WEBSITE_RELEASE_UNIT, TMP_DIR, $, question, printReleaseUnit, printPhase, makeReleaseDir, updateDependency, prepareReleaseBuild, createPR} from './release-util';
import {RELEASE_UNITS, WEBSITE_RELEASE_UNIT, TMP_DIR, $, question, printReleaseUnit, printPhase, makeReleaseDir, updateDependency, prepareReleaseBuild, createPR, getPatchUpdateVersion, ALPHA_RELEASE_UNIT} from './release-util';
import {releaseWebsite} from './release-website';

const parser = new argparse.ArgumentParser();
Expand All @@ -40,38 +40,27 @@ parser.addArgument('--git-protocol', {
help: 'Use the git protocal rather than the http protocol when cloning repos.'
});

// Computes the default updated version (does a patch version update).
function getPatchUpdateVersion(version: string): string {
const versionSplit = version.split('.');

// For alpha or beta version string (e.g. "0.0.1-alpha.5"), increase the
// number after alpha/beta.
if (versionSplit[2].includes('alpha') || versionSplit[2].includes('beta')) {
return [
versionSplit[0], versionSplit[1], versionSplit[2], +versionSplit[3] + 1
].join('.');
}

return [versionSplit[0], versionSplit[1], +versionSplit[2] + 1].join('.');
}

async function main() {
const args = parser.parseArgs();

RELEASE_UNITS.forEach((_, i) => printReleaseUnit(i));
// The alpha release unit is released with the monorepo and should not be
// released by this script. Packages in the alpha release unit need their
// package.json dependencies rewritten.
const releaseUnits = RELEASE_UNITS.filter(r => r !== ALPHA_RELEASE_UNIT);
releaseUnits.forEach((_, i) => printReleaseUnit(i));
console.log();

const releaseUnitStr =
await question('Which release unit (leave empty for 0): ');
const releaseUnitInt = +releaseUnitStr;
if (releaseUnitInt < 0 || releaseUnitInt >= RELEASE_UNITS.length) {
if (releaseUnitInt < 0 || releaseUnitInt >= releaseUnits.length) {
console.log(chalk.red(`Invalid release unit: ${releaseUnitStr}`));
process.exit(1);
}
console.log(chalk.blue(`Using release unit ${releaseUnitInt}`));
console.log();

const releaseUnit = RELEASE_UNITS[releaseUnitInt];
const releaseUnit = releaseUnits[releaseUnitInt];
const {name, phases} = releaseUnit;

phases.forEach((_, i) => printPhase(phases, i));
Expand Down
1 change: 1 addition & 0 deletions scripts/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"downlevelIteration": true
}
}