├── README.md ├── src ├── load-gitignores.js ├── index.js └── get-gitignore.js ├── tests └── index.js ├── package.json ├── LICENSE ├── .gitignore └── CODE_OF_CONDUCT.md /README.md: -------------------------------------------------------------------------------- 1 | # goops 2 | goops is a command line tool that adds a .gitignore file to your current 3 | working directory. It's a little more helpful than that though, goops will 4 | analyze the files in your directory and determine the best .gitignore for 5 | your project based on a simple heuristic or offer you a list of potential 6 | .gitignore files to choose from. 7 | 8 | ## Installation 9 | 10 | ``` 11 | npm install --global goops 12 | ``` 13 | 14 | ## Usage 15 | ![goops demo](https://cloud.githubusercontent.com/assets/1857993/23940333/80b2c4ac-0932-11e7-9f5c-b10791fc9f35.gif) 16 | -------------------------------------------------------------------------------- /src/load-gitignores.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const gitignore = require('gitignore'); 5 | const path = require('path'); 6 | 7 | const ignores = path.join(__dirname, '/../gitignores'); 8 | 9 | gitignore.getTypes(function(error, types) { 10 | if (error) return console.log(error); 11 | 12 | types.map(function(type) { 13 | gitignore.writeFile({ 14 | type: type, 15 | file: fs.createWriteStream(path.join(ignores, type + '.gitignore')) 16 | }, function(error) { 17 | if (error) return console.log(error); 18 | }); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | 'use strict'; 3 | 4 | const fs = require('fs'); 5 | const path = require('path'); 6 | const getGitIgnore = require('./get-gitignore'); 7 | 8 | const cwd = process.cwd(); 9 | 10 | const contents = fs.readdirSync(cwd).map(function(element) { 11 | if (fs.statSync(path.join(cwd, element)).isDirectory()) { 12 | return element + '/'; 13 | } else { 14 | return element; 15 | } 16 | }); 17 | 18 | const gitignoresArray = getGitIgnore(contents); 19 | const filePath = path.join(cwd, '/.gitignore'); 20 | 21 | gitignoresArray.forEach((element, index) => { 22 | const gitignore = path.join(__dirname, '/../gitignores', element); 23 | fs.createReadStream(gitignore).pipe(fs.createWriteStream(filePath, { flags: 'a' })); 24 | }) 25 | -------------------------------------------------------------------------------- /tests/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const chai = require('chai'); 4 | const expect = chai.expect; 5 | const getGitIgnore = require('../src/get-gitignore'); 6 | 7 | // sample project contents fixtures 8 | const npmContents = ['src/', 'node_modules/', 'package.json', '.env', '.npm']; 9 | const pythonContents = ['src/', 'main.pyc', 'wheels/']; 10 | const combinedContents = npmContents.concat(pythonContents); 11 | 12 | describe('getGitIgnore', function() { 13 | it('gets the right .gitignore for a probable Node project', function() { 14 | expect(getGitIgnore(npmContents)).to.contain('Node.gitignore'); 15 | }); 16 | it('gets the right .gitignore for a probable Python project', function() { 17 | expect(getGitIgnore(pythonContents)).to.contain('Python.gitignore'); 18 | }); 19 | it('gets a .gitignore for project with Node and Python', function() { 20 | expect(getGitIgnore(combinedContents, true)).to.eql(['Node.gitignore', 'Python.gitignore']); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "goops", 3 | "version": "1.0.1", 4 | "description": "A CLI tool that automatically generates a gitignore for a project", 5 | "bin": { 6 | "goops": "src/index.js" 7 | }, 8 | "scripts": { 9 | "test": "mocha tests", 10 | "postinstall": "mkdir -p gitignores && node src/load-gitignores.js" 11 | }, 12 | "main": "src/index.js", 13 | "keywords": [ 14 | "git", 15 | "command line tool", 16 | "developer experience" 17 | ], 18 | "bugs": { 19 | "url": "https://github.com/captainsafia/goops/issues" 20 | }, 21 | "repository": { 22 | "type": "git", 23 | "url": "https://github.com/captainsafia/goops" 24 | }, 25 | "author": "Safia Abdalla (http://safia.rocks/)", 26 | "license": "MIT", 27 | "dependencies": { 28 | "gitignore": "^0.6.0", 29 | "lodash.pickby": "^4.6.0", 30 | "minimatch": "^3.0.3", 31 | "readline-sync": "^1.4.6" 32 | }, 33 | "devDependencies": { 34 | "chai": "^3.5.0", 35 | "mocha": "^3.2.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Safia Abdalla 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | gitignores/ 61 | -------------------------------------------------------------------------------- /src/get-gitignore.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | const readline = require('readline-sync'); 6 | 7 | const minimatch = require('minimatch'); 8 | const pickBy = require('lodash.pickby'); 9 | 10 | const ignores = path.join(__dirname, '/../gitignores/'); 11 | const gitignores = fs.readdirSync(ignores); 12 | 13 | function applies(gitignore, contents) { 14 | const data = fs.readFileSync(path.join(ignores, gitignore)); 15 | const ignored = data.toString().split("\n").filter(function(ignored) { 16 | return !ignored.startsWith('#') && !ignored.startsWith('!'); 17 | }); 18 | 19 | let count = 0; 20 | const ignoredGlobs = ignored.map(function(line) { 21 | return contents.map(function(element) { 22 | if (minimatch(element, line)) count++; 23 | }); 24 | }); 25 | 26 | return count; 27 | } 28 | 29 | function getGitIgnore(contents, selectAll = false) { 30 | const ignored = {}; 31 | const relevantGitignores = []; // used to return an array of gitignores push into the local .gitignore 32 | 33 | gitignores.map(function(gitignore) { 34 | ignored[gitignore] = applies(gitignore, contents); 35 | }); 36 | 37 | const sorted = Object.keys(ignored).sort(function(a, b) { 38 | return ignored[b] - ignored[a]; 39 | }); 40 | 41 | 42 | const counts = Object.keys(ignored).reduce(function(count, value) { 43 | return count + (ignored[value] === ignored[sorted[0]]); 44 | }, 0); 45 | 46 | if (counts > 1) { 47 | const filtered = Object.keys(pickBy(ignored, function(value, key) { 48 | return value === ignored[sorted[0]]; 49 | })); 50 | 51 | // if selectAll is true we'll skip the option display and just return all the options 52 | if (selectAll) { 53 | return filtered; 54 | } 55 | 56 | console.log('Multiple possible options found! Please select one or more options from the list.'); 57 | 58 | filtered.forEach(function(element, index) { 59 | console.log((index + 1) + '. ' + element); 60 | }); 61 | 62 | const selectAllNumber = filtered.length + 1; 63 | console.log(`${selectAllNumber}. Select All`); 64 | 65 | const selectionResponse = readline.question('Enter a number or separate multiple options with a comma (e.g. 1, 2, 3): '); 66 | const selectionsArray = selectionResponse.replace(' ', ',').split(',').filter(el => el.length > 0); 67 | 68 | // if the number for the select all option is listed, return everything 69 | if (selectionsArray.indexOf(selectAllNumber.toString()) !== -1) { 70 | return filtered; // returns an array of all the options 71 | }; 72 | 73 | selectionsArray.forEach(selectionNumber => { 74 | relevantGitignores.push(filtered[selectionNumber - 1]); 75 | }) 76 | return relevantGitignores; 77 | } 78 | 79 | relevantGitignores.push(sorted[0]); 80 | return relevantGitignores; 81 | } 82 | 83 | module.exports = getGitIgnore; 84 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at safia@safia.rocks. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [http://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: http://contributor-covenant.org 74 | [version]: http://contributor-covenant.org/version/1/4/ 75 | --------------------------------------------------------------------------------