diff --git a/.all-contributorsrc b/.all-contributorsrc new file mode 100644 index 00000000..dcd84c21 --- /dev/null +++ b/.all-contributorsrc @@ -0,0 +1,23 @@ +{ + "projectName": "kcd-scripts", + "projectOwner": "kentcdodds", + "files": [ + "README.md" + ], + "imageSize": 100, + "commit": false, + "contributors": [ + { + "login": "kentcdodds", + "name": "Kent C. Dodds", + "avatar_url": "https://avatars.githubusercontent.com/u/1500684?v=3", + "profile": "https://kentcdodds.com", + "contributions": [ + "code", + "doc", + "infra", + "test" + ] + } + ] +} diff --git a/.babelrc b/.babelrc new file mode 100644 index 00000000..a699d330 --- /dev/null +++ b/.babelrc @@ -0,0 +1,13 @@ +{ + "presets": [ + ["env", { + "targets": { + "node": "4.5" + } + }] + ], + "plugins": [ + "transform-class-properties", + "transform-object-rest-spread" + ] +} diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..9c628283 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +node_modules +coverage +dist diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..3fd3cbc2 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,23 @@ +{ + "extends": [ + "kentcdodds", + "kentcdodds/jest", + "kentcdodds/prettier" + ], + "rules": { + // stuff I haven't gotten around to updating in my config + "no-unused-vars": ["error", { "argsIgnorePattern": "^_", "varsIgnorePattern": "^ignored" }], + "func-style": "off", + "no-process-exit": "off", + "import/no-dynamic-require": "off", + + // prettier does this for us + "max-len": "off", + "semi": "off", + "quotes": "off", + "comma-dangle": "off", + "no-console": "off", + "indent": "off", + "babel/object-curly-spacing": "off" + } +} diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..391f0a4e --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +* text=auto +*.js text eol=lf diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 00000000..65162e38 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,43 @@ + + +- `kcd-scripts` version: +- `node` version: +- `npm` (or `yarn`) version: + +Relevant code or config + +```javascript + +``` + +What you did: + + + +What happened: + + + +Reproduction repository: + + + +Problem description: + + + +Suggested solution: diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..e421002c --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,35 @@ + + + +**What**: + + +**Why**: + + +**How**: + + +**Checklist**: + + +- [ ] Documentation +- [ ] Tests +- [ ] Ready to be merged +- [ ] Added myself to contributors table + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..09048d22 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +node_modules +coverage +dist +.opt-in +.opt-out +.DS_Store +.eslintcache + +# these cause more harm than good +# when working with contributors +package-lock.json +yarn.lock diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..a57cc9e5 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +registry=http://registry.npmjs.org/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..6fdf7167 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,17 @@ +sudo: false +language: node_js +cache: + directories: + - node_modules +notifications: + email: false +node_js: + - '8' +script: + - npm start validate +after_success: + - npx codecov + - npm i -g semantic-release@7 && semantic-release pre && npm publish && semantic-release post +branches: + only: + - master diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..06d221aa --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,4 @@ +# CHANGELOG + +The changelog is automatically updated using [semantic-release](https://github.com/semantic-release/semantic-release). +You can see it on the [releases page](../../releases). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..cd514e9f --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,84 @@ +# Contributing + +Thanks for being willing to contribute! + +**Working on your first Pull Request?** You can learn how from this *free* series +[How to Contribute to an Open Source Project on GitHub][egghead] + +## Project setup + +1. Fork and clone the repo +2. `$ npm install` to install dependencies +3. `$ npm start validate` to validate you've got it working +4. Create a branch for your PR + +This project uses [`nps`][nps] and you can run `npm start help` to see what +scripts are available. + +> Tip: Keep your `master` branch pointing at the original repository and make +> pull requests from branches on your fork. To do this, run: +> +> ``` +> git remote add upstream https://github.com/kentcdodds/kcd-scripts.git +> git fetch upstream +> git branch --set-upstream-to=upstream/master master +> ``` +> +> This will add the original repository as a "remote" called "upstream," +> Then fetch the git information from that remote, then set your local `master` +> branch to use the upstream master branch whenever you run `git pull`. +> Then you can make all of your pull request branches based on this `master` +> branch. Whenever you want to update your version of `master`, do a regular +> `git pull`. + +## Add yourself as a contributor + +This project follows the [all contributors][all-contributors] specification. +To add yourself to the table of contributors on the README.md, please use the +automated script as part of your PR: + +```console +npm start contributors.add +``` + +Follow the prompt and commit `.all-contributorsrc` and `README.md` in the PR. +If you've already added yourself to the list and are making +a new type of contribution, you can run it again and select the added +contribution type. + +## Committing and Pushing changes + +This project uses [`semantic-release`][semantic-release] to do automatic +releases and generate a changelog based on the commit history. So we follow +[a convention][convention] for commit messages. You don't have to follow this +convention if you don't like to. Just know that when we merge your commit, we'll +probably use "Squash and Merge" so we can change the commit message :) + +Please make sure to run the tests before you commit your changes. You can run +`npm start test.update` which will update any snapshots that need updating. +Make sure to include those changes (if they exist) in your commit. + +### opt into git hooks + +There are git hooks set up with this project that are automatically installed +when you install dependencies. They're really handy, but are turned off by +default (so as to not hinder new contributors). You can opt into these by +creating a file called `.opt-in` at the root of the project and putting this +inside: + +``` +pre-commit +``` + +## Help needed + +Please checkout the [the open issues][issues] + +Also, please watch the repo and respond to questions/bug reports/feature requests! Thanks! + +[egghead]: https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github +[semantic-release]: https://npmjs.com/package/semantic-release +[convention]: https://github.com/conventional-changelog/conventional-changelog-angular/blob/ed32559941719a130bb0327f886d6a32a8cbc2ba/convention.md +[all-contributors]: https://github.com/kentcdodds/all-contributors +[issues]: https://github.com/kentcdodds/kcd-scripts/issues +[nps]: https://github.com/kentcdodds/nps diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..4c43675b --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) +Copyright (c) 2017 Kent C. Dodds + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 00000000..b200c321 --- /dev/null +++ b/README.md @@ -0,0 +1,93 @@ +
+

kcd-scripts

+ +CLI for common scripts for my projects +
+ +
+ +[![Build Status][build-badge]][build] +[![Code Coverage][coverage-badge]][coverage] +[![version][version-badge]][package] +[![downloads][downloads-badge]][npmcharts] +[![MIT License][license-badge]][LICENSE] + +[![All Contributors](https://img.shields.io/badge/all_contributors-1-orange.svg?style=flat-square)](#contributors) +[![PRs Welcome][prs-badge]][prs] +[![Code of Conduct][coc-badge]][coc] + +[![Watch on GitHub][github-watch-badge]][github-watch] +[![Star on GitHub][github-star-badge]][github-star] +[![Tweet][twitter-badge]][twitter] + +## The problem + +// TODO + +## This solution + +// TODO + +## Installation + +This module is distributed via [npm][npm] which is bundled with [node][node] and +should be installed as one of your project's `devDependencies`: + +``` +npm install --save-dev kcd-scripts +``` + +## Usage + +// TODO + +## Inspiration + +// TODO + +## Other Solutions + +I'm not aware of any, if you are please [make a pull request][prs] and add it +here! + +## Contributors + +Thanks goes to these people ([emoji key][emojis]): + + +| [
Kent C. Dodds](https://kentcdodds.com)
[💻](https://github.com/kentcdodds/kcd-scripts/commits?author=kentcdodds) [📖](https://github.com/kentcdodds/kcd-scripts/commits?author=kentcdodds) 🚇 [⚠️](https://github.com/kentcdodds/kcd-scripts/commits?author=kentcdodds) | +| :---: | + + +This project follows the [all-contributors][all-contributors] specification. +Contributions of any kind welcome! + +## LICENSE + +MIT + +[npm]: https://www.npmjs.com/ +[node]: https://nodejs.org +[build-badge]: https://img.shields.io/travis/kentcdodds/kcd-scripts.svg?style=flat-square +[build]: https://travis-ci.org/kentcdodds/kcd-scripts +[coverage-badge]: https://img.shields.io/codecov/c/github/kentcdodds/kcd-scripts.svg?style=flat-square +[coverage]: https://codecov.io/github/kentcdodds/kcd-scripts +[version-badge]: https://img.shields.io/npm/v/kcd-scripts.svg?style=flat-square +[package]: https://www.npmjs.com/package/kcd-scripts +[downloads-badge]: https://img.shields.io/npm/dm/kcd-scripts.svg?style=flat-square +[npmcharts]: http://npmcharts.com/compare/kcd-scripts +[license-badge]: https://img.shields.io/npm/l/kcd-scripts.svg?style=flat-square +[license]: https://github.com/kentcdodds/kcd-scripts/blob/master/LICENSE +[prs-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square +[prs]: http://makeapullrequest.com +[donate-badge]: https://img.shields.io/badge/$-support-green.svg?style=flat-square +[coc-badge]: https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square +[coc]: https://github.com/kentcdodds/kcd-scripts/blob/master/other/CODE_OF_CONDUCT.md +[github-watch-badge]: https://img.shields.io/github/watchers/kentcdodds/kcd-scripts.svg?style=social +[github-watch]: https://github.com/kentcdodds/kcd-scripts/watchers +[github-star-badge]: https://img.shields.io/github/stars/kentcdodds/kcd-scripts.svg?style=social +[github-star]: https://github.com/kentcdodds/kcd-scripts/stargazers +[twitter]: https://twitter.com/intent/tweet?text=Check%20out%20kcd-scripts!%20https://github.com/kentcdodds/kcd-scripts%20%F0%9F%91%8D +[twitter-badge]: https://img.shields.io/twitter/url/https/github.com/kentcdodds/kcd-scripts.svg?style=social +[emojis]: https://github.com/kentcdodds/all-contributors#emoji-key +[all-contributors]: https://github.com/kentcdodds/all-contributors diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 00000000..19758b9f --- /dev/null +++ b/jest.config.js @@ -0,0 +1 @@ +module.exports = require('./src/config/jest.config') diff --git a/kcd.config.js b/kcd.config.js new file mode 100644 index 00000000..472503fd --- /dev/null +++ b/kcd.config.js @@ -0,0 +1,10 @@ +const path = require('path') + +module.exports = { + eslint: { + extends: [path.join(__dirname, './.eslintrc')], + }, + jest: { + coverageThreshold: {}, + }, +} diff --git a/other/CODE_OF_CONDUCT.md b/other/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..a62ad9c1 --- /dev/null +++ b/other/CODE_OF_CONDUCT.md @@ -0,0 +1,87 @@ +# Contributor Covenant Code of Conduct + + + +**Table of Contents** + +- [Our Pledge](#our-pledge) +- [Our Standards](#our-standards) +- [Our Responsibilities](#our-responsibilities) +- [Scope](#scope) +- [Enforcement](#enforcement) +- [Attribution](#attribution) + + + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at kent+coc@doddsfamily.us. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/other/MAINTAINING.md b/other/MAINTAINING.md new file mode 100644 index 00000000..5232261b --- /dev/null +++ b/other/MAINTAINING.md @@ -0,0 +1,75 @@ +# Maintaining + + + +**Table of Contents** + +- [Code of Conduct](#code-of-conduct) +- [Issues](#issues) +- [Pull Requests](#pull-requests) +- [Release](#release) +- [Thanks!](#thanks) + + + +This is documentation for maintainers of this project. + +## Code of Conduct + +Please review, understand, and be an example of it. Violations of the code of conduct are +taken seriously, even (especially) for maintainers. + +## Issues + +We want to support and build the community. We do that best by helping people learn to solve +their own problems. We have an issue template and hopefully most folks follow it. If it's +not clear what the issue is, invite them to create a minimal reproduction of what they're trying +to accomplish or the bug they think they've found. + +Once it's determined that a code change is necessary, point people to +[makeapullrequest.com](http://makeapullrequest.com) and invite them to make a pull request. +If they're the one who needs the feature, they're the one who can build it. If they need +some hand holding and you have time to lend a hand, please do so. It's an investment into +another human being, and an investment into a potential maintainer. + +Remember that this is open source, so the code is not yours, it's ours. If someone needs a change +in the codebase, you don't have to make it happen yourself. Commit as much time to the project +as you want/need to. Nobody can ask any more of you than that. + +## Pull Requests + +As a maintainer, you're fine to make your branches on the main repo or on your own fork. Either +way is fine. + +When we receive a pull request, a travis build is kicked off automatically (see the `.travis.yml` +for what runs in the travis build). We avoid merging anything that breaks the travis build. + +Please review PRs and focus on the code rather than the individual. You never know when this is +someone's first ever PR and we want their experience to be as positive as possible, so be +uplifting and constructive. + +When you merge the pull request, 99% of the time you should use the +[Squash and merge](https://help.github.com/articles/merging-a-pull-request/) feature. This keeps +our git history clean, but more importantly, this allows us to make any necessary changes to the +commit message so we release what we want to release. See the next section on Releases for more +about that. + +## Release + +Our releases are automatic. They happen whenever code lands into `master`. A travis build gets +kicked off and if it's successful, a tool called +[`semantic-release`](https://github.com/semantic-release/semantic-release) is used to +automatically publish a new release to npm as well as a changelog to GitHub. It is only able to +determine the version and whether a release is necessary by the git commit messages. With this +in mind, **please brush up on [the commit message convention][commit] which drives our releases.** + +> One important note about this: Please make sure that commit messages do NOT contain the words +> "BREAKING CHANGE" in them unless we want to push a major version. I've been burned by this +> more than once where someone will include "BREAKING CHANGE: None" and it will end up releasing +> a new major version. Not a huge deal honestly, but kind of annoying... + +## Thanks! + +Thank you so much for helping to maintain this project! + +[commit]: https://github.com/conventional-changelog-archived-repos/conventional-changelog-angular/blob/ed32559941719a130bb0327f886d6a32a8cbc2ba/convention.md diff --git a/other/USERS.md b/other/USERS.md new file mode 100644 index 00000000..5432378d --- /dev/null +++ b/other/USERS.md @@ -0,0 +1,16 @@ +# Users + + + + + +If you or your company uses this project, add your name to this list! Eventually +we may have a website to showcase these (wanna build it!?) + +> No users have been added yet! + + diff --git a/other/manual-releases.md b/other/manual-releases.md new file mode 100644 index 00000000..7f85823d --- /dev/null +++ b/other/manual-releases.md @@ -0,0 +1,47 @@ +# manual-releases + + + + + +This project has an automated release set up. So things are only released when there are +useful changes in the code that justify a release. But sometimes things get messed up one way or another +and we need to trigger the release ourselves. When this happens, simply bump the number below and commit +that with the following commit message based on your needs: + +**Major** + +``` +fix(release): manually release a major version + +There was an issue with a major release, so this manual-releases.md +change is to release a new major version. + +Reference: # + +BREAKING CHANGE: +``` + +**Minor** + +``` +feat(release): manually release a minor version + +There was an issue with a minor release, so this manual-releases.md +change is to release a new minor version. + +Reference: # +``` + +**Patch** + +``` +fix(release): manually release a patch version + +There was an issue with a patch release, so this manual-releases.md +change is to release a new patch version. + +Reference: # +``` + +The number of times we've had to do a manual release is: 0 diff --git a/package-scripts.js b/package-scripts.js new file mode 100644 index 00000000..15b7d3e4 --- /dev/null +++ b/package-scripts.js @@ -0,0 +1,45 @@ +const npsUtils = require('nps-utils') + +const series = npsUtils.series +const concurrent = npsUtils.concurrent +const rimraf = npsUtils.rimraf +const crossEnv = npsUtils.crossEnv + +module.exports = { + scripts: { + contributors: { + add: { + description: 'When new people contribute to the project, run this', + script: 'all-contributors add', + }, + generate: { + description: 'Update the badge and contributors table', + script: 'all-contributors generate', + }, + }, + test: { + default: crossEnv('NODE_ENV=test jest --coverage'), + update: crossEnv('NODE_ENV=test jest --coverage --updateSnapshot'), + watch: crossEnv('NODE_ENV=test jest --watch'), + openCoverage: 'open coverage/lcov-report/index.html', + }, + build: { + description: 'delete the dist directory and run babel to build the files', + script: series( + rimraf('dist'), + 'babel --copy-files --out-dir dist --ignore __tests__ src' + ), + }, + lint: { + description: 'lint the entire project', + script: 'eslint . --cache', + }, + validate: { + description: `This runs several scripts to make sure things look good before committing or on clean install`, + script: concurrent.nps('lint', 'build', 'test'), + }, + }, + options: { + silent: false, + }, +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..ddc53819 --- /dev/null +++ b/package.json @@ -0,0 +1,66 @@ +{ + "name": "kcd-scripts", + "version": "0.0.0-semantically-released", + "description": "CLI for common scripts for my projects", + "main": "dist/index.js", + "engines": { + "node": "> 4", + "npm": "> 3" + }, + "scripts": { + "start": "nps", + "test": "node src test", + "precommit": + "lint-staged && opt --in pre-commit --exec \"npm start validate\"" + }, + "files": ["dist"], + "keywords": [], + "author": "Kent C. Dodds (http://kentcdodds.com/)", + "license": "MIT", + "dependencies": { + "all-contributors-cli": "^4.3.0", + "babel-cli": "^6.24.1", + "babel-preset-env": "^1.6.0", + "babel-jest": "^20.0.3", + "babel-plugin-transform-class-properties": "^6.24.1", + "babel-plugin-transform-object-rest-spread": "^6.23.0", + "concurrently": "^3.5.0", + "cross-spawn": "^5.1.0", + "eslint-config-kentcdodds": "^12.4.1", + "eslint": "^4.2.0", + "husky": "^0.14.3", + "jest": "^20.0.4", + "lint-staged": "^4.0.1", + "lodash": "^4.17.4", + "opt-cli": "^1.5.1", + "prettier": "^1.6.1", + "read-pkg-up": "^2.0.0", + "resolve-bin": "^0.4.0", + "rimraf": "^2.6.1" + }, + "devDependencies": { + "nps": "^5.4.0", + "nps-utils": "^1.2.0" + }, + "lint-staged": { + "*.+(js|json)": ["prettier --write", "git add"] + }, + "prettier": { + "printWidth": 80, + "tabWidth": 2, + "useTabs": false, + "semi": false, + "singleQuote": true, + "trailingComma": "es5", + "bracketSpacing": false, + "jsxBraketSameLine": false + }, + "repository": { + "type": "git", + "url": "https://github.com/kentcdodds/kcd-scripts.git" + }, + "bugs": { + "url": "https://github.com/kentcdodds/kcd-scripts/issues" + }, + "homepage": "https://github.com/kentcdodds/kcd-scripts#readme" +} diff --git a/src/__tests__/index.js b/src/__tests__/index.js new file mode 100644 index 00000000..6eb18238 --- /dev/null +++ b/src/__tests__/index.js @@ -0,0 +1 @@ +test('works', () => {}) diff --git a/src/config/eslintignore b/src/config/eslintignore new file mode 100644 index 00000000..5ab667c9 --- /dev/null +++ b/src/config/eslintignore @@ -0,0 +1,6 @@ +node_modules/ +coverage/ +dist/ +build/ +out/ +.next/ diff --git a/src/config/eslintrc.js b/src/config/eslintrc.js new file mode 100644 index 00000000..c6fdc0a1 --- /dev/null +++ b/src/config/eslintrc.js @@ -0,0 +1,41 @@ +const {applyOverrides, ifDevDep} = require('../utils') + +const config = applyOverrides({ + type: 'eslint', + config: { + extends: [ + 'kentcdodds', + ifDevDep('jest', 'kentcdodds/jest'), + ifDevDep('webpack', 'kentcdodds/webpack'), + ifDevDep('react', 'kentcdodds/jsx-a11y'), + ifDevDep('react', 'kentcdodds/react'), + ifDevDep('prettier', 'kentcdodds/prettier'), + ].filter(Boolean), + rules: { + // stuff I haven't gotten around to updating in my config + 'no-unused-vars': [ + 'error', + {argsIgnorePattern: '^_', varsIgnorePattern: '^ignored'}, + ], + 'func-style': 'off', + 'no-process-exit': 'off', + + // prettier does this for us + ...ifDevDep( + 'prettier', + { + 'max-len': 'off', + semi: 'off', + quotes: 'off', + 'comma-dangle': 'off', + 'no-console': 'off', + indent: 'off', + 'babel/object-curly-spacing': 'off', + }, + {} + ), + }, + }, +}) + +module.exports = config diff --git a/src/config/jest.config.js b/src/config/jest.config.js new file mode 100644 index 00000000..3e256282 --- /dev/null +++ b/src/config/jest.config.js @@ -0,0 +1,29 @@ +const {ifDevDep, applyOverrides} = require('../utils') + +const ignores = [ + '/node_modules/', + '/fixtures/', + '/__tests__/helpers/', + '__mocks__', +] + +const config = applyOverrides({ + type: 'jest', + config: { + testEnvironment: ifDevDep('webpack', 'jsdom', 'node'), + collectCoverageFrom: ['src/**/*.js'], + testMatch: ['**/__tests__/**/*.js'], + testPathIgnorePatterns: ignores, + coveragePathIgnorePatterns: ignores, + coverageThreshold: { + global: { + branches: 100, + functions: 100, + lines: 100, + statements: 100, + }, + }, + }, +}) + +module.exports = config diff --git a/src/config/prettierrc.js b/src/config/prettierrc.js new file mode 100644 index 00000000..d487c288 --- /dev/null +++ b/src/config/prettierrc.js @@ -0,0 +1,17 @@ +const {applyOverrides} = require('../utils') + +const config = applyOverrides({ + type: 'prettier', + config: { + printWidth: 80, + tabWidth: 2, + useTabs: false, + semi: false, + singleQuote: true, + trailingComma: 'all', + bracketSpacing: false, + jsxBraketSameLine: false, + }, +}) + +module.exports = config diff --git a/src/index.js b/src/index.js new file mode 100644 index 00000000..24b5cd1f --- /dev/null +++ b/src/index.js @@ -0,0 +1,42 @@ +#!/usr/bin/env node +const path = require('path') +const spawn = require('cross-spawn') + +function attemptResolve(...args) { + try { + return require.resolve(...args) + } catch (error) { + return null + } +} + +const [executor, ignoredBin, script, ...args] = process.argv +const relativeScriptPath = path.join(__dirname, './scripts', script) +const scriptPath = attemptResolve(relativeScriptPath) + +if (!scriptPath) { + console.log(`Unknown script "${script}".`) + console.log('Perhaps you need to update paypal-scripts?') +} + +const result = spawn.sync(executor, [scriptPath, ...args], { + stdio: 'inherit', +}) + +if (result.signal) { + if (result.signal === 'SIGKILL') { + console.log( + 'The build failed because the process exited too early. ' + + 'This probably means the system ran out of memory or someone called ' + + '`kill -9` on the process.' + ) + } else if (result.signal === 'SIGTERM') { + console.log( + 'The build failed because the process exited too early. ' + + 'Someone might have called `kill` or `killall`, or the system could ' + + 'be shutting down.' + ) + } + process.exit(1) +} +process.exit(result.status) diff --git a/src/paths.js b/src/paths.js new file mode 100644 index 00000000..8a79d73d --- /dev/null +++ b/src/paths.js @@ -0,0 +1,7 @@ +const path = require('path') +const fs = require('fs') + +const appDirectory = fs.realpathSync(process.cwd()) +const fromRoot = (...p) => path.join(appDirectory, ...p) + +module.exports = {appDirectory, fromRoot} diff --git a/src/scripts/build.js b/src/scripts/build.js new file mode 100644 index 00000000..2d89b4fb --- /dev/null +++ b/src/scripts/build.js @@ -0,0 +1,22 @@ +const resolveBin = require('resolve-bin') +const spawn = require('cross-spawn') +const rimraf = require('rimraf') +const {fromRoot} = require('../paths') + +const argv = process.argv.slice(2) + +rimraf.sync(fromRoot('dist')) + +const result = spawn.sync( + resolveBin.sync('babel-cli', {executable: 'babel'}), + // prettier-ignore + [ + '--copy-files', + '--out-dir', 'dist', + '--ignore', '__tests__,__mocks__', + 'src', + ].concat(argv), + {stdio: 'inherit'} +) + +process.exit(result) diff --git a/src/scripts/format.js b/src/scripts/format.js new file mode 100644 index 00000000..224c97f7 --- /dev/null +++ b/src/scripts/format.js @@ -0,0 +1,20 @@ +const path = require('path') +const resolveBin = require('resolve-bin') +const spawn = require('cross-spawn') + +const argv = process.argv.slice(2) + +const here = p => path.join(__dirname, p) + +const result = spawn.sync( + resolveBin.sync('prettier'), + // prettier-ignore + [ + '--write', + '--config', here('../config/prettierrc.js'), + '--ignore-path', here('../config/eslintignore'), + ].concat(argv), + {stdio: 'inherit'} +) + +process.exit(result) diff --git a/src/scripts/lint.js b/src/scripts/lint.js new file mode 100644 index 00000000..7d8505b9 --- /dev/null +++ b/src/scripts/lint.js @@ -0,0 +1,25 @@ +const path = require('path') +const resolveBin = require('resolve-bin') +const spawn = require('cross-spawn') + +const [ignoredExecutor, ignoredBin, ignoredScript, ...args] = process.argv + +const here = p => path.join(__dirname, p) + +const result = spawn.sync( + resolveBin.sync('eslint'), + // prettier-ignore + [ + '--config', here('../config/eslintrc.js'), + '--ignore-path', here('../config/eslintignore'), + '--cache', + '.', + ].concat(args), + {stdio: 'inherit'} +) + +if (result.status === 0) { + console.error(`All's good 👍`) +} + +process.exit(result.status) diff --git a/src/scripts/test.js b/src/scripts/test.js new file mode 100644 index 00000000..b9c1988b --- /dev/null +++ b/src/scripts/test.js @@ -0,0 +1,13 @@ +process.env.BABEL_ENV = 'test' +process.env.NODE_ENV = 'test' + +const jest = require('jest') + +const argv = process.argv.slice(2) + +if (!process.env.CI && !argv.includes('--coverage')) { + argv.push('--watch') +} +argv.push('--config', JSON.stringify(require('../config/jest.config'))) + +jest.run(argv) diff --git a/src/scripts/validate.js b/src/scripts/validate.js new file mode 100644 index 00000000..86e8c45f --- /dev/null +++ b/src/scripts/validate.js @@ -0,0 +1,27 @@ +const spawn = require('cross-spawn') +const {ifScript} = require('../utils') + +const scriptNames = (...scripts) => + scripts + .map(s => ifScript(s, s)) + .filter(Boolean) + .join(',') + +const result = spawn.sync( + require.resolve('concurrently'), + // prettier-ignore + [ + '--kill-others-on-fail', + '--prefix', '[{name}]', + '--names', scriptNames('build', 'lint', 'test'), + '--prefix-colors', 'bgBlue.bold,bgGreen.bold,bgOrang.bold', + ...[ + ifScript('build', 'npm run build --silent'), + ifScript('lint', 'npm run lint --silent'), + ifScript('test', 'npm run test --silent -- --coverage'), + ].filter(Boolean), + ], + {stdio: 'inherit'} +) + +process.exit(result) diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 00000000..ffdeb023 --- /dev/null +++ b/src/utils.js @@ -0,0 +1,90 @@ +const fs = require('fs') +const path = require('path') +const {mergeWith} = require('lodash') +const readPkgUp = require('read-pkg-up') + +function hasDevDependency(dep) { + return getPkgProp('devDependencies').hasOwnProperty(dep) +} + +function getPkgProp(prop) { + const {pkg} = readPkgUp.sync({cwd: process.cwd()}) + return pkg[prop] +} + +function hasScript(script) { + return getPkgProp('scripts').hasOwnProperty(script) +} + +function ifScript(script, t, f) { + return hasScript(script) ? t : f +} + +function ifDevDep(dep, t, f) { + return hasDevDependency(dep) ? t : f +} + +// this will do a deep merge of two objects +// If the object has a value that's an array, +// then the source's value will be concat-ed with it. +function mergeWithArrayConcat(object, source) { + return mergeWith(object, source, (objValue, srcValue) => { + if (Array.isArray(objValue)) { + return objValue.concat(srcValue) + } + return srcValue + }) +} + +function applyOverrides({config = {}, type}) { + config = applyOverridesToPath({ + config, + type, + overrideConfig: readUserConfig()[type], + }) + return config +} + +function readUserConfig() { + const appDirectory = fs.realpathSync(process.cwd()) + const configPath = path.resolve(path.join(appDirectory, '/kcd.config.js')) + if (fs.existsSync(configPath)) { + return require(configPath) + } else { + return {} + } +} + +// eslint-disable-next-line complexity +function applyOverridesToPath({config, type, overrideConfig}) { + if (!overrideConfig) { + return config + } + try { + if (typeof overrideConfig === 'function') { + const overrides = overrideConfig(config, process.env.NODE_ENV) + if (!overrides) { + throw new Error( + `${type} overrides function provided, but the config was not returned. You need to return the config` + ) + } + return overrides + } else if (typeof overrideConfig === 'object') { + return mergeWithArrayConcat(config, overrideConfig) + } + } catch (error) { + console.error( + `There was a problem trying to apply ${type} config overrides` + ) + throw error + } + return config +} + +module.exports = { + applyOverrides, + hasDevDependency, + ifDevDep, + hasScript, + ifScript, +}