mirror of
https://github.com/material-components/material-web.git
synced 2024-10-27 14:07:17 +03:00
286d4733ce
These are WIP. Some known issues: * select, chips, and textfield ripple not working * many tests to be added * some elements tbd, including e.g. top-app-bar and drawer
224 lines
8.1 KiB
JavaScript
224 lines
8.1 KiB
JavaScript
/**
|
|
* Copyright 2016 Google Inc. All Rights Reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/**
|
|
* @fileoverview Collects updated packages and compares them with commit messages whose scope corresponds
|
|
* to them between the previous release and HEAD. It then analyzes each commit message to determine the most
|
|
* appropriate version to update each component to. For example, say there have been 4 commits for drawer
|
|
* since the previous release, from most -> least recent:
|
|
*
|
|
* - feat(drawer): Add some functionality
|
|
* - docs(drawer): Update README
|
|
* - refactor(drawer): Change some functionality
|
|
*
|
|
* BREAKING CHANGE: Something was removed / modified as part of the API.
|
|
* - fix(drawer): Fix bug
|
|
*
|
|
* This script will determine that the *major* version should be bumped, due to the breaking
|
|
* change between the last release and now. If the 2nd commit was removed, it would have determined
|
|
* that the *minor* version should be bumped, since it is a more significant change than the fix. Note that
|
|
* the docs(*) commit would not cause any change, since a documentation change does not constitute a version
|
|
* bump.
|
|
*
|
|
* This script will output each package which has deemed to have been changed, along with its new version
|
|
* and the commit that caused it to change. It will also output the new version for the 'material-components-web'
|
|
* package based off the most significant change type within the subpackages. Additionally, it will write the
|
|
* component/version info to a human-readable text file .new-versions.log within the script's CWD.
|
|
*
|
|
* Caveats:
|
|
* 1) This is to be used as an AID, not as a replacement for human verification.
|
|
* 2) This assumes there is at least one tag in the repo. If not, it will not work.
|
|
*
|
|
* NOTE: This script is no longer used since we switched to lerna fixed mode. It may prove useful again if we switch
|
|
* back to independent mode in the future.
|
|
*/
|
|
|
|
const childProcess = require('child_process');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const AsciiTable = require('ascii-table');
|
|
const CliTable = require('cli-table');
|
|
const semver = require('semver');
|
|
|
|
const getUpdatedPkgs = require('./lib/get-updated-pkgs');
|
|
|
|
const MAGICAL_DELIMITER = `__ENDCOMMIT_${Date.now()}__`;
|
|
const COMMIT_MSG_RE = /^(feat|fix|docs|style|refactor|perf|test|chore)\((.+)\):/;
|
|
const BREAKING_CHANGE_RE = /^BREAKING\sCHANGE:/;
|
|
const GIT_LOG_CMD = `git log --format='%B${MAGICAL_DELIMITER}' $(git rev-list --tags --max-count=1)..HEAD`;
|
|
const PKGS_PATH = path.resolve(__dirname, '../packages');
|
|
const VersionType = {
|
|
MAJOR: 'major',
|
|
MINOR: 'minor',
|
|
PATCH: 'patch',
|
|
};
|
|
|
|
const updatedPkgs = getUpdatedPkgs();
|
|
if (!updatedPkgs.length) {
|
|
console.log('No packages to update');
|
|
process.exit(0);
|
|
}
|
|
|
|
const commitMatches = childProcess
|
|
.execSync(GIT_LOG_CMD)
|
|
.toString()
|
|
.split(MAGICAL_DELIMITER)
|
|
.map((c) => {
|
|
const trimmedCommit = c.trim();
|
|
const m = trimmedCommit.match(COMMIT_MSG_RE);
|
|
return m && {
|
|
commit: trimmedCommit,
|
|
type: m[1],
|
|
scope: m[2],
|
|
hasBreakingChange: trimmedCommit.split('\n').some((l) => BREAKING_CHANGE_RE.test(l)),
|
|
};
|
|
})
|
|
.filter((info) => Boolean(info) && affectsPackage(info.scope));
|
|
const componentPkgs = updatedPkgs.filter(({name}) => name.indexOf('@material') === 0);
|
|
const mdcPkg = updatedPkgs.find(({name}) => name === 'material-components-web');
|
|
const newPkgVersions = collectNewPkgVersions(componentPkgs, commitMatches);
|
|
const newMDCVersion = Object.assign(collectMDCVersion(mdcPkg, newPkgVersions), {
|
|
name: 'material-components-web',
|
|
causedByCommit: 'N/A',
|
|
});
|
|
|
|
const allPkgVersions = [newMDCVersion].concat(newPkgVersions);
|
|
writeSummaryToScreen(allPkgVersions);
|
|
writeSummaryToFile(allPkgVersions);
|
|
|
|
function affectsPackage(commitScope) {
|
|
return fs.existsSync(path.join(PKGS_PATH, `mdc-${commitScope}`));
|
|
}
|
|
|
|
function collectNewPkgVersions(updatedPkgs, commitInfos) {
|
|
return updatedPkgs.map((p) => {
|
|
const {version, changeType, causedByCommit} = determineVersion(p, commitInfos);
|
|
return {
|
|
name: p.name,
|
|
version,
|
|
changeType,
|
|
causedByCommit,
|
|
};
|
|
});
|
|
}
|
|
|
|
function determineVersion(pkg, commitInfos) {
|
|
const currentVersion = semver.valid(pkg.version);
|
|
if (!currentVersion) {
|
|
throw new Error(
|
|
`Invalid semver version ${pkg.version} for ${pkg.name}. This MUST be fixed before release.`
|
|
);
|
|
}
|
|
|
|
return commitInfos.reduce(pickBestVersionInfo(pkg), {
|
|
version: semver.inc(currentVersion, 'patch'),
|
|
changeType: 'patch',
|
|
causedByCommit: '(dependency update - part of packages to be updated but no explicit commits referencing it)',
|
|
});
|
|
}
|
|
|
|
function pickBestVersionInfo(pkg) {
|
|
return (currentBest, commitInfo) => {
|
|
const {version, changeType} = currentBest;
|
|
const pkgComponent = pkg.name.split('/')[1];
|
|
if (commitInfo.scope !== pkgComponent) {
|
|
return currentBest;
|
|
}
|
|
|
|
let possibleNewChangeType = changeType;
|
|
if (commitInfo.hasBreakingChange) {
|
|
possibleNewChangeType = semver.major(pkg.version) === 0 ? VersionType.MINOR : VersionType.MAJOR;
|
|
} else if (commitInfo.type === 'feat') {
|
|
possibleNewChangeType = VersionType.MINOR;
|
|
} else if (commitInfo.type === 'docs') {
|
|
// docs would not cause any change, so it should not put its commit message as reason of version bump.
|
|
return currentBest;
|
|
} else {
|
|
// fix, style (refers to coding style), refactor (non-breaking change), chore, ...
|
|
possibleNewChangeType = VersionType.PATCH;
|
|
}
|
|
// Note that we assume that pkg.version is valid by the time we get here.
|
|
const possibleNewVersion = possibleNewChangeType ?
|
|
semver.inc(pkg.version, possibleNewChangeType) : pkg.version;
|
|
|
|
if (semver.gt(version, possibleNewVersion)) {
|
|
return currentBest;
|
|
}
|
|
return {
|
|
version: possibleNewVersion,
|
|
changeType: possibleNewChangeType,
|
|
causedByCommit: commitInfo.commit,
|
|
};
|
|
};
|
|
}
|
|
|
|
function collectMDCVersion(mdcPkg, newPkgVersions) {
|
|
const currentVersion = semver.valid(mdcPkg.version);
|
|
if (!currentVersion) {
|
|
throw new Error(
|
|
`Invalid material-components-web version ${mdcPkg.version}. This MUST change before release.`
|
|
);
|
|
}
|
|
const changeTypes = new Set(newPkgVersions.map(({changeType}) => changeType));
|
|
const versionRanks = {
|
|
[VersionType.PATCH]: 0,
|
|
[VersionType.MINOR]: 1,
|
|
[VersionType.MAJOR]: 2,
|
|
};
|
|
const overallChangeTypes = [...changeTypes]
|
|
.sort((ct1, ct2) => versionRanks[ct1] - versionRanks[ct2]);
|
|
const overallChangeType = overallChangeTypes.pop();
|
|
return {
|
|
version: semver.inc(currentVersion, overallChangeType) || '(no update needed)',
|
|
changeType: overallChangeType,
|
|
};
|
|
}
|
|
|
|
function writeSummary(pkgVersions, performWrite) {
|
|
const title = 'New Package Versions';
|
|
const headers = ['Package', 'Version', 'Change Type', 'Associated Commit Subject'];
|
|
const rows = pkgVersions.map(({name, version, changeType, causedByCommit}) => [
|
|
name, version, changeType, causedByCommit.split('\n').shift(),
|
|
]);
|
|
|
|
performWrite(title, headers, rows);
|
|
}
|
|
|
|
function writeSummaryToScreen(pkgVersions) {
|
|
writeSummary(pkgVersions, (title, headers, rows) => {
|
|
const table = new CliTable({
|
|
head: headers,
|
|
});
|
|
table.push(...rows);
|
|
console.log(`*** ${title} ***`);
|
|
console.log(table.toString());
|
|
});
|
|
}
|
|
|
|
function writeSummaryToFile(pkgVersions) {
|
|
writeSummary(pkgVersions, (title, headers, rows) => {
|
|
const table = AsciiTable.factory({
|
|
title,
|
|
heading: headers,
|
|
rows,
|
|
});
|
|
const outFile = path.join(process.cwd(), '.new-versions.log');
|
|
fs.writeFileSync(outFile, table.toString());
|
|
console.log(`*** New Version Data written to ${outFile} ***`);
|
|
});
|
|
}
|