diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 8ce0abc990c..d189a503397 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -9,11 +9,14 @@ Thanks for your interest in plotly.js! ### Features, Bug fixes, and others: Before opening a pull request, developer should: +1. make sure they are not on the `master` branch of their fork as using `master` for a pull request would make it difficult to fetch `upstream` changes. +2. fetch latest changes from `upstream/master` into your fork i.e. `origin/master` then pull `origin/master` from you local `master`. +3. then `git rebase master` their local dev branch off the latest `master` which should be sync with `upstream/master` at this time. +4. make sure to **not** `git add` the `dist/` folder (the `dist/` is updated only on version bumps). +5. make sure to commit changes to the `package-lock.json` file (if any new dependency required). +6. provide a title and write an overview of what the PR attempts to do with a link to the issue they are trying to address. +7. select the _Allow edits from maintainers_ option (see this [article](https://help.github.com/articles/allowing-changes-to-a-pull-request-branch-created-from-a-fork/) for more details). -- `git rebase` their local branch off the latest `master`, -- make sure to **not** `git add` the `dist/` folder (the `dist/` is updated only on version bumps), -- make sure to commit changes to the `package-lock.json` file (if any new dependency required), -- write an overview of what the PR attempts to do, -- select the _Allow edits from maintainers_ option (see this [article](https://help.github.com/articles/allowing-changes-to-a-pull-request-branch-created-from-a-fork/) for more details). - -Note that it is forbidden to force push (i.e. `git push -f`) to remote branches associated with opened pull requests. Force pushes make it hard for maintainers to keep track of updates. Therefore, if required, please `git merge master` into your PR branch instead of `git rebase master`. +After opening a pull request, developer: + - should create a new small markdown log file using the PR number e.g. `1010_fix.md` or `1010_add.md` inside `draftlogs` folder as described in this [README](https://github.com/plotly/plotly.js/blob/master/draftlogs/README.md), commit it and push. + - should **not** force push (i.e. `git push -f`) to remote branches associated with opened pull requests. Force pushes make it hard for maintainers to keep track of updates. Therefore, if required, please fetch `upstream/master` and "merge" with master instead of "rebase". diff --git a/draftlogs/5779_fix.md b/draftlogs/5779_fix.md new file mode 100644 index 00000000000..c45f560f477 --- /dev/null +++ b/draftlogs/5779_fix.md @@ -0,0 +1,2 @@ + - Improve README for ES6 module import [[#5779](https://github.com/plotly/plotly.js/pull/5779)], + with thanks to @andreafonso for the contribution! diff --git a/draftlogs/README.md b/draftlogs/README.md new file mode 100644 index 00000000000..5ae928cb0cc --- /dev/null +++ b/draftlogs/README.md @@ -0,0 +1,22 @@ +## Directory of draft logs to help prepare the upcoming [CHANGELOG](https://github.com/plotly/plotly.js/blob/master/CHANGELOG.md) + +Every pull request should add at least one markdown file to this directory. +The filename must start with a number, preferably the PR number, followed by one of these: +1. `_fix.md` to propose a bug fix +2. `_add.md` to propose new features +3. `_remove.md` to propose a feature removal +4. `_change.md` to propose a minor/major change +5. `_deprecate.md` to propose a feature be deprecated + +If your PR falls into more than one category - for example adding a new feature and changing an existing feature - you should include each in a separate file. + +### Example filename and content for PR numbered 5546 for adding a new feature +- filename: `5546_add.md` +- content: +``` + - Add `icicle` trace type [[#5546](https://github.com/plotly/plotly.js/pull/5546)] +``` +which would render + - Add `icicle` trace type [[#5546](https://github.com/plotly/plotly.js/pull/5546)] + +> Please start your single-line or multiple lined message with a verb. You could basically use the PR description while providing a link to the PR similar to the above example is appreciated too. diff --git a/package.json b/package.json index 27688415040..4c23b2d0f1a 100644 --- a/package.json +++ b/package.json @@ -27,8 +27,11 @@ "stats": "node tasks/stats.js", "find-strings": "node tasks/find_locale_strings.js", "preprocess": "node tasks/preprocess.js", - "build": "node tasks/empty_dist.js && npm run preprocess && npm run find-strings && npm run bundle && npm run extra-bundles && npm run stats", - "cibuild": "node tasks/empty_dist.js && npm run preprocess && node tasks/cibundle.js", + "use-draftlogs": "node tasks/use_draftlogs.js", + "empty-draftlogs": "node tasks/empty_draftlogs.js", + "empty-dist": "node tasks/empty_dist.js", + "build": "npm run empty-dist && npm run preprocess && npm run find-strings && npm run bundle && npm run extra-bundles && npm run stats", + "cibuild": "npm run empty-dist && npm run preprocess && node tasks/cibundle.js", "watch": "node tasks/watch.js", "lint": "eslint --version && eslint .", "lint-fix": "eslint . --fix || true", diff --git a/tasks/empty_dist.js b/tasks/empty_dist.js index 7302f41448c..8d8350f1f26 100644 --- a/tasks/empty_dist.js +++ b/tasks/empty_dist.js @@ -1,36 +1,13 @@ -var path = require('path'); -var fs = require('fs-extra'); -var common = require('./util/common'); var constants = require('./util/constants'); +var makeEmptyDirectory = require('./util/make_empty_directory'); +var emptyDir = makeEmptyDirectory.emptyDir; +var makeDir = makeEmptyDirectory.makeDir; var dist = constants.pathToDist; // dist var distTopojson = constants.pathToTopojsonDist; // dist/topojson + // main emptyDir(distTopojson); emptyDir(dist); makeDir(dist); makeDir(distTopojson); - -function emptyDir(dir) { - if(common.doesDirExist(dir)) { - console.log('empty ' + dir); - try { - var allFiles = fs.readdirSync(dir); - allFiles.forEach(function(file) { - // remove file - fs.unlinkSync(path.join(dir, file)); - }); - - fs.rmdirSync(dir); - } catch(err) { - console.error(err); - } - } -} - -function makeDir(dir) { - if(!common.doesDirExist(dir)) { - // create folder - fs.mkdirSync(dir); - } -} diff --git a/tasks/empty_draftlogs.js b/tasks/empty_draftlogs.js new file mode 100644 index 00000000000..1ddd5484c14 --- /dev/null +++ b/tasks/empty_draftlogs.js @@ -0,0 +1,18 @@ +var constants = require('./util/constants'); +var makeEmptyDirectory = require('./util/make_empty_directory'); +var emptyDir = makeEmptyDirectory.emptyDir; +var makeDir = makeEmptyDirectory.makeDir; + +var pathToDraftlogs = constants.pathToDraftlogs; + +var chZero = '0'.charCodeAt(0); +var chNine = '9'.charCodeAt(0); + +function startsWithNumber(v) { + var ch = v.charCodeAt(0); + return chZero <= ch && ch <= chNine; +} + +// main +emptyDir(pathToDraftlogs, { filter: startsWithNumber }); +makeDir(pathToDraftlogs); diff --git a/tasks/use_draftlogs.js b/tasks/use_draftlogs.js new file mode 100644 index 00000000000..d0ac292b002 --- /dev/null +++ b/tasks/use_draftlogs.js @@ -0,0 +1,86 @@ +var fs = require('fs'); +var path = require('path'); +var constants = require('./util/constants'); + +var pathToDraftlogs = constants.pathToDraftlogs; +var pathToChangelog = constants.pathToChangelog; + +var chZero = '0'.charCodeAt(0); +var chNine = '9'.charCodeAt(0); + +function startsWithNumber(v) { + var ch = v.charCodeAt(0); + return chZero <= ch && ch <= chNine; +} + +var allLogs = fs.readdirSync(pathToDraftlogs).filter(startsWithNumber); + +var len = allLogs.length; +if(!len) return; + +var writeAfterMe = 'where X.Y.Z is the semver of most recent plotly.js release.'; +var changelog = fs.readFileSync(pathToChangelog).toString().split(writeAfterMe); +var head = changelog[0]; +var foot = changelog[1]; + +var all = { + Added: [], + Removed: [], + Deprecated: [], + Changed: [], + Fixed: [] +}; + +var ENTER = '\n'; + +var skippedFiles = []; +for(var i = 0; i < len; i++) { + var filename = allLogs[i]; + var message = fs.readFileSync(path.join(pathToDraftlogs, filename), { encoding: 'utf-8' }).toString(); + // trim empty lines + message = message.split(ENTER).filter(function(e) { return !!e; }).join(ENTER); + + if(filename.endsWith('_add.md')) { + all.Added.push(message); + } else if(filename.endsWith('_remove.md')) { + all.Removed.push(message); + } else if(filename.endsWith('_deprecate.md')) { + all.Deprecated.push(message); + } else if(filename.endsWith('_change.md')) { + all.Changed.push(message); + } else if(filename.endsWith('_fix.md')) { + all.Fixed.push(message); + } else { + skippedFiles.push(filename); + } +} + +var draftNewChangelog = [ + head + writeAfterMe, + '', + '## [X.Y.Z] -- UNRELEASED' +]; + +var append = function(key) { + var newMessages = all[key]; + if(!newMessages.length) return; + draftNewChangelog.push(''); + draftNewChangelog.push('### ' + key); + draftNewChangelog.push(newMessages.join(ENTER)); +}; + +append('Added'); +append('Removed'); +append('Deprecated'); +append('Changed'); +append('Fixed'); + +draftNewChangelog.push(foot); + +fs.writeFileSync(pathToChangelog, draftNewChangelog.join(ENTER), { encoding: 'utf-8' }); + +if(skippedFiles.length) { + throw JSON.stringify({ + 'skippedFiles': skippedFiles + }, null, 2); +} diff --git a/tasks/util/constants.js b/tasks/util/constants.js index 98508b8c18f..dbc873daabb 100644 --- a/tasks/util/constants.js +++ b/tasks/util/constants.js @@ -7,6 +7,7 @@ var pathToSrc = path.join(pathToRoot, 'src/'); var pathToLib = path.join(pathToRoot, 'lib/'); var pathToImageTest = path.join(pathToRoot, 'test/image'); var pathToStrictD3Module = path.join(pathToRoot, 'test/strict-d3.js'); +var pathToDraftlogs = path.join(pathToRoot, 'draftlogs/'); var pathToDist = path.join(pathToRoot, 'dist/'); var pathToBuild = path.join(pathToRoot, 'build/'); @@ -168,6 +169,8 @@ module.exports = { pathToLib: pathToLib, pathToBuild: pathToBuild, pathToDist: pathToDist, + pathToDraftlogs: pathToDraftlogs, + pathToChangelog: path.join(pathToRoot, 'CHANGELOG.md'), partialBundleTraces: partialBundleTraces, diff --git a/tasks/util/make_empty_directory.js b/tasks/util/make_empty_directory.js new file mode 100644 index 00000000000..cf34b0bce71 --- /dev/null +++ b/tasks/util/make_empty_directory.js @@ -0,0 +1,40 @@ +var path = require('path'); +var fs = require('fs-extra'); +var common = require('./common'); + +module.exports = { + emptyDir: emptyDir, + makeDir: makeDir +}; + +function emptyDir(dir, opts) { + if(common.doesDirExist(dir)) { + console.log('empty ' + dir); + try { + var allFiles = fs.readdirSync(dir); + var hasFilter = false; + if(opts && opts.filter) { + hasFilter = true; + allFiles = allFiles.filter(opts.filter); + } + + allFiles.forEach(function(file) { + // remove file + fs.unlinkSync(path.join(dir, file)); + }); + + if(!hasFilter) { + fs.rmdirSync(dir); + } + } catch(err) { + console.error(err); + } + } +} + +function makeDir(dir) { + if(!common.doesDirExist(dir)) { + // create folder + fs.mkdirSync(dir); + } +}