├── .gitignore ├── package.json ├── README.md ├── docs └── api.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "octokit-create-new-file", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "doc": "documentation build -f md -o ./docs/api.md", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "documentation": "^12.1.4", 15 | "jest": "^25.1.0", 16 | "standard": "^14.3.1" 17 | }, 18 | "dependencies": { 19 | "slugify": "^1.4.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # octokit-create-new-file 2 | 3 | Creates a new file on a new branch and opens a new pull request. 4 | 5 | ## Usage 6 | 7 | ```js 8 | const createNewFile = require('octokit-create-new-file') 9 | const newPr = await createNewFile(octokit, { 10 | pr: { 11 | title: 'This is a new pull request', 12 | body: 'An extended description about this pull request.' 13 | }, 14 | repo: { 15 | owner: 'Example', 16 | repo: 'Name' 17 | }, 18 | commitMessage: 'Create a new file', 19 | file: { 20 | path: 'new-file.md', 21 | content: 'This is the content of the new file.' 22 | } 23 | }) 24 | 25 | console.log(newPr) 26 | // { number: 1, title: 'Example' } 27 | ``` 28 | 29 | ##### [See the full API docs here](./docs/api.md) -------------------------------------------------------------------------------- /docs/api.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | - [createNewFile][1] 6 | - [Parameters][2] 7 | - [Options][3] 8 | - [Properties][4] 9 | 10 | ## createNewFile 11 | 12 | Create a new file on a new branch and open a pull request 13 | 14 | ### Parameters 15 | 16 | - `octokit` **[object][5]** Octokit object 17 | - `opts` **[Options][6]** 18 | 19 | Returns **[Promise][7]<[Object][5]>** 20 | 21 | ## Options 22 | 23 | Type: [Object][5] 24 | 25 | ### Properties 26 | 27 | - `pr` **[Object][5]** Pull Request object 28 | - `pr.title` **[string][8]** Title of the new Pull Request 29 | - `pr.body` **[string][8]?** Body of the new Pull Request 30 | - `pr.branch` **[string][8]?** Name of the new branch to create. Defaults to `create-{{ file.path }}` 31 | - `pr.base` **[string][8]?** Name of the base branch to use 32 | - `commitMessage` **[string][8]?** Commit message 33 | - `repo` **[Object][5]** Repository object 34 | - `repo.owner` **[string][8]** Repository owner 35 | - `repo.repo` **[string][8]** Repository name 36 | - `file` **[Object][5]** File object 37 | - `file.path` **[string][8]** File path 38 | - `file.content` **[string][8]** File content 39 | - `file.encoding` **[string][8]?** File encoding, either `base64` or `utf8` 40 | 41 | [1]: #createnewfile 42 | 43 | [2]: #parameters 44 | 45 | [3]: #options 46 | 47 | [4]: #properties 48 | 49 | [5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object 50 | 51 | [6]: #options 52 | 53 | [7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise 54 | 55 | [8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String 56 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const slugify = require('slugify') 2 | 3 | /** 4 | * Create a new file on a new branch and open a pull request 5 | * 6 | * @param {object} octokit - Octokit object 7 | * @param {Options} opts 8 | * @returns {Promise} 9 | */ 10 | async function createNewFile (octokit, opts) { 11 | const branchName = opts.pr.branch || `create-${slugify(opts.file.path, { lower: true })}` 12 | 13 | // Get the current "master" reference, to get the current master's sha 14 | const sha = await octokit.gitdata.getReference({ 15 | ...opts.repo, 16 | ref: `heads/${opts.branch || 'master'}` 17 | }) 18 | 19 | // Get the tree associated with master, and the content 20 | // of the template file to open the PR with. 21 | const tree = await octokit.gitdata.getTree({ 22 | ...opts.repo, 23 | tree_sha: sha.data.object.sha 24 | }) 25 | 26 | // Create a new blob with the existing template content 27 | const blob = await octokit.gitdata.createBlob({ 28 | content: opts.file.content, 29 | encoding: opts.file.encoding || 'utf8' 30 | }) 31 | 32 | const newTree = await octokit.gitdata.createTree({ 33 | ...opts.repo, 34 | tree: [{ 35 | path: opts.file.path, 36 | sha: blob.data.sha, 37 | mode: '100644', 38 | type: 'blob' 39 | }], 40 | base_tree: tree.data.sha 41 | }) 42 | 43 | // Create a commit and a reference using the new tree 44 | const newCommit = await octokit.gitdata.createCommit({ 45 | ...opts.repo, 46 | message: opts.commitMessage || `Create ${opts.file.path}`, 47 | parents: [sha.data.object.sha], 48 | tree: newTree.data.sha 49 | }) 50 | 51 | await octokit.gitdata.createReference({ 52 | ref: `refs/heads/${branchName}`, 53 | sha: newCommit.data.sha 54 | }) 55 | 56 | const pr = await octokit.pullRequests.create({ 57 | ...opts.repo, 58 | title: opts.pr.title || `Create ${opts.file.path}`, 59 | body: opts.pr.body, 60 | head: branchName, 61 | base: opts.pr.base || 'master' 62 | }) 63 | 64 | return pr.data 65 | } 66 | 67 | /** 68 | * @typedef {Object} Options 69 | * @property {Object} pr - Pull Request object 70 | * @property {string} pr.title - Title of the new Pull Request 71 | * @property {string} [pr.body] - Body of the new Pull Request 72 | * @property {string} [pr.branch] - Name of the new branch to create. Defaults to `create-{{ file.path }}` 73 | * @property {string} [pr.base='master'] - Name of the base branch to use 74 | * @property {string} [commitMessage] - Commit message 75 | * @property {Object} repo - Repository object 76 | * @property {string} repo.owner - Repository owner 77 | * @property {string} repo.repo - Repository name 78 | * @property {Object} file - File object 79 | * @property {string} file.path - File path 80 | * @property {string} file.content - File content 81 | * @property {string} [file.encoding='utf8'] - File encoding, either `base64` or `utf8` 82 | */ 83 | 84 | module.exports = createNewFile 85 | --------------------------------------------------------------------------------