├── .github ├── dependabot.yml └── workflows │ └── test-and-release.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── commit-stream.js ├── package.json └── test.js /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: 'github-actions' 4 | directory: '/' 5 | schedule: 6 | interval: 'daily' 7 | commit-message: 8 | prefix: 'chore' 9 | include: 'scope' 10 | - package-ecosystem: 'npm' 11 | directory: '/' 12 | schedule: 13 | interval: 'daily' 14 | commit-message: 15 | prefix: 'chore' 16 | include: 'scope' 17 | -------------------------------------------------------------------------------- /.github/workflows/test-and-release.yml: -------------------------------------------------------------------------------- 1 | name: Test & Maybe Release 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | strategy: 8 | fail-fast: false 9 | matrix: 10 | node: [16.x, 18.x, lts/*, current] 11 | os: [macos-latest, ubuntu-latest, windows-latest] 12 | runs-on: ${{ matrix.os }} 13 | steps: 14 | - name: Checkout Repository 15 | uses: actions/checkout@v3 16 | with: 17 | fetch-depth: 0 18 | - name: Use Node.js ${{ matrix.node }} 19 | uses: actions/setup-node@v3.6.0 20 | with: 21 | node-version: ${{ matrix.node }} 22 | - name: Install Dependencies 23 | run: | 24 | npm install --no-progress 25 | - name: Run tests 26 | run: | 27 | npm config set script-shell bash 28 | npm run test:ci 29 | release: 30 | name: Release 31 | permissions: 32 | contents: write 33 | needs: test 34 | runs-on: ubuntu-latest 35 | if: github.event_name == 'push' && github.ref == 'refs/heads/main' 36 | steps: 37 | - name: Checkout 38 | uses: actions/checkout@v3 39 | with: 40 | fetch-depth: 0 41 | - name: Setup Node.js 42 | uses: actions/setup-node@v3.6.0 43 | with: 44 | node-version: lts/* 45 | - name: Install dependencies 46 | run: | 47 | npm install --no-progress --no-package-lock --no-save 48 | - name: Build 49 | run: | 50 | npm run build 51 | - name: Install plugins 52 | run: | 53 | npm install \ 54 | @semantic-release/commit-analyzer \ 55 | conventional-changelog-conventionalcommits \ 56 | @semantic-release/release-notes-generator \ 57 | @semantic-release/npm \ 58 | @semantic-release/github \ 59 | @semantic-release/git \ 60 | @semantic-release/changelog \ 61 | --no-progress --no-package-lock --no-save 62 | - name: Release 63 | env: 64 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 65 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 66 | run: npx semantic-release 67 | 68 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [2.2.0](https://github.com/nodejs/commit-stream/compare/v2.1.0...v2.2.0) (2024-11-27) 2 | 3 | ### Features 4 | 5 | * add cveId support ([6c82ccd](https://github.com/nodejs/commit-stream/commit/6c82ccd24e44167433126ba2bf4e95c8c4f41297)) 6 | 7 | ### Bug Fixes 8 | 9 | * add permissions: write to create release action ([776bc30](https://github.com/nodejs/commit-stream/commit/776bc302aebaef471870b56586572225325af238)) 10 | 11 | ### Tests 12 | 13 | * add CVE-ID test ([0748578](https://github.com/nodejs/commit-stream/commit/0748578e475534d96be8e4b9f306f5d84c7e383a)) 14 | * fix sha cve id pr ([670b4ab](https://github.com/nodejs/commit-stream/commit/670b4abd056ca4099e8dcb02d31504a857db991c)) 15 | 16 | ## [2.1.0](https://github.com/rvagg/commit-stream/compare/v2.0.1...v2.1.0) (2023-05-16) 17 | 18 | 19 | ### Features 20 | 21 | * add support for green-button merges ([9e87160](https://github.com/rvagg/commit-stream/commit/9e87160f261d67ea0a3a6c4a02136b5c50ecfa42)) 22 | 23 | ## [2.0.1](https://github.com/rvagg/commit-stream/compare/v2.0.0...v2.0.1) (2023-04-04) 24 | 25 | 26 | ### Trivial Changes 27 | 28 | * **deps:** bump actions/setup-node from 3.5.1 to 3.6.0 ([d4c0cac](https://github.com/rvagg/commit-stream/commit/d4c0cacb25482c5e16523fab70ec90b30fde42d9)) 29 | 30 | ## [2.0.0](https://github.com/rvagg/commit-stream/compare/v1.0.2...v2.0.0) (2023-04-04) 31 | 32 | 33 | ### ⚠ BREAKING CHANGES 34 | 35 | * refactor, format, and update 36 | 37 | ### Features 38 | 39 | * refactor, format, and update ([4fbc36a](https://github.com/rvagg/commit-stream/commit/4fbc36ae62345b86d6573786d05c50e880a1ff45)) 40 | 41 | 42 | ### Bug Fixes 43 | 44 | * check for and handle process erorrs ([f3db5f7](https://github.com/rvagg/commit-stream/commit/f3db5f7bea4c115d2057e1f4920b59d061d48339)) 45 | * full-depth checkout to make tests work ([2c69ecd](https://github.com/rvagg/commit-stream/commit/2c69ecd878de30273c3b8c31df5d84f1bcd6f7d5)) 46 | * release from main, not master ([2f458df](https://github.com/rvagg/commit-stream/commit/2f458dfd0eb330b66b2f8b4f83fe2b3176fe5e52)) 47 | * use pipeline to catch errors ([090d127](https://github.com/rvagg/commit-stream/commit/090d127f5238d67de258b90e03fd2402c270aabb)) 48 | 49 | 50 | ### Trivial Changes 51 | 52 | * **ci:** add auto-release ([5ca9a54](https://github.com/rvagg/commit-stream/commit/5ca9a5436f19e85a2dcbbf16305e970521171dc8)) 53 | * update strip-ansi to 6.x ([#5](https://github.com/rvagg/commit-stream/issues/5)) ([b232087](https://github.com/rvagg/commit-stream/commit/b23208796d7e3fd08b36f6106aa7f027aa827137)) 54 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | ## Copyright (c) 2015 Rod Vagg 4 | 5 | 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: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | 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. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # commit-stream 2 | 3 | **Turn a `git log` into a stream of commit objects** 4 | 5 | [![npm](https://nodei.co/npm/commit-stream.png?downloads=true&downloadRank=true)](https://nodei.co/npm/commit-stream/) 6 | [![npm](https://nodei.co/npm-dl/commit-stream.png?months=6&height=3)](https://nodei.co/npm/commit-stream/) 7 | 8 | ## API 9 | 10 | **`commitStream([defaultGithubUser, defaultGithubProject])`** 11 | 12 | Returns an object stream that you can pipe a stream of newlines from the output of `git log` to. The output of the stream is a series of objects, each representing a commit from the log.` 13 | 14 | Intended to be used on a standard log format (not a simplified one using one of the simplifying `--format` options) but it will also process change stats if you `git log --stat`. 15 | 16 | Typical usage: 17 | 18 | ```js 19 | import { spawn } from 'node:child_process' 20 | import split2 from 'split2' 21 | import listStream from 'list-stream' 22 | 23 | spawn('bash', ['-c', 'git log']) 24 | .stdout.pipe(split2()) // break up by newline characters 25 | .pipe(commitStream('rvagg', 'commit-stream')) 26 | .pipe(listStream.obj(onCommitList)) 27 | 28 | function onCommitList (err, list) { 29 | // list is an array of objects 30 | } 31 | ``` 32 | 33 | Commit object properties: 34 | 35 | - `sha`: the full commit sha 36 | - `author`: an object representing the author of the commit 37 | - `name`: the name of the committer 38 | - `email`: the email of the committer 39 | - `authors`: a list of such objects representing the authors of the commit, supporting multiple authors through `Co-authored-by:` 40 | - `authorDate`: a string representing the date of the original commit by the author (never change) 41 | - `commitDate`: a string representing the date of the last change of the commit 42 | - `summary`: the one-line summary of the commit 43 | - `description`: the free-form text content of the summary, minus specific metadata lines 44 | - `reviewers`: an array containing objects with `name` and `email` properties if the commit metadata contains reviewers in a `Reviewed-By: Foo Bar ` format. 45 | - `changes`: if `--stat` data is included in the git log, an object containing change stats: 46 | - `files`: the number of files changed 47 | - `insertions`: the number of new lines inserted 48 | - `deletions`: the number of old lines removed 49 | - `prUrl`: a URL pointing to a pull-request where this change was made if the commit metadata contains a `PR-URL: https://github.com/user/project/pull/XX` line. Note that whatever proceeds the `PR-URL: ` string will be collected in this property; one exception being that if a shortened `#XX` version is found and you have supplied `defaultGitHubUser` and `defaultGitHubProject` arguments to the constructor then a full GitHub pull-request will be reconstituted in its place. 50 | - `ghUser`, `ghProject`, `ghIssue`: if a proper GitHub pull request is found for the `prUrl` property (including shortened `#XX` ones), these properties will be added to point to the original user, project and issue (pull-request) for this change, as extracted from the URL. Also, if a commit message line ends with ` (#XX)` as is done with green-button merges, this will be used. 51 | 52 | ## License 53 | 54 | **commit-stream** is Copyright (c) 2015 Rod Vagg [@rvagg](https://twitter.com/rvagg) and licenced under the MIT licence. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE.md file for more details. 55 | -------------------------------------------------------------------------------- /commit-stream.js: -------------------------------------------------------------------------------- 1 | import through2 from 'through2' 2 | import stripAnsi from 'strip-ansi' 3 | 4 | export default function commitStream (ghUser, ghProject) { 5 | let commit 6 | 7 | return through2.obj(onLine, onEnd) 8 | 9 | function addLine (line) { 10 | line = stripAnsi(line) 11 | 12 | if (line.length === 0) return 13 | 14 | let old, m 15 | 16 | if (/^commit \w+$/.test(line)) { 17 | old = commit 18 | commit = { sha: line.split(' ')[1] } 19 | } else if ((m = line.match(/^CommitDate:\s+(.*)$/)) !== null) { 20 | if (commit === undefined || commit === null) { 21 | throw new Error('Something unexpected occurred') 22 | } 23 | commit.commitDate = m[1].trim() 24 | } else if ( 25 | (m = line.match( 26 | /^\s*(?:Author|Co[- ]?authored[- ]?by):?\s*([^<]+) <([^>]+)>\s*$/i 27 | )) !== null 28 | ) { 29 | if (commit === undefined || commit === null) { 30 | throw new Error('Something unexpected occurred') 31 | } 32 | if (commit.authors === undefined || commit.authors === null) { 33 | commit.authors = [] 34 | } 35 | commit.authors.push({ name: m[1], email: m[2] }) 36 | } else if ((m = line.match(/^(?:AuthorDate|Date):\s+(.*)$/)) !== null) { 37 | if (commit === undefined || commit === null) { 38 | throw new Error('Something unexpected occurred') 39 | } 40 | commit.authorDate = m[1].trim() 41 | } else if ( 42 | (m = line.match(/^\s+Reviewed[- ]?By:?\s*([^<]+) <([^>]+)>\s*$/i)) !== 43 | null 44 | ) { 45 | if (commit.reviewers === undefined || commit.reviewers === null) { 46 | commit.reviewers = [] 47 | } 48 | commit.reviewers.push({ name: m[1], email: m[2] }) 49 | } else if ((m = line.match(/\bCVE-ID:\s+(CVE-\d{4}-\d{5})\b/)) !== null) { 50 | commit.cveId = m[1]; 51 | } else if ((m = line.match(/^\s+PR(?:[- ]?URL)?:?\s*(.+)\s*$/) || line.match(/\(#(\d+)\)$/)) !== null) { 52 | commit.prUrl = m[1] 53 | if ( 54 | typeof ghUser === 'string' && 55 | ghUser.length !== 0 && 56 | typeof ghProject === 'string' && 57 | ghProject.length !== 0 && 58 | (m = commit.prUrl.match(/^\s*#?(\d+)\s*$/)) !== null 59 | ) { 60 | commit.prUrl = `https://github.com/${ghUser}/${ghProject}/pull/${m[1]}` 61 | } 62 | if ( 63 | (m = commit.prUrl.match( 64 | /^(https?:\/\/.+\/([^/]+)\/([^/]+))\/\w+\/(\d+)(\/)?$/i 65 | )) !== null 66 | ) { 67 | commit.ghIssue = parseInt(m[4]) 68 | commit.ghUser = m[2] 69 | commit.ghProject = m[3] 70 | } 71 | if ((m = line.match(/^ {4}(.*)\s\(#\d+\)$/)) && !commit.summary) { 72 | commit.summary = m[1] 73 | } 74 | } else if (/^ {4}/.test(line) && (line = line.trim()).length !== 0) { 75 | if (commit.summary === undefined || commit.summary === null) { 76 | commit.summary = line 77 | } else { 78 | if (commit.description === undefined || commit.description === null) { 79 | commit.description = [] 80 | } 81 | commit.description.push(line) 82 | } 83 | } else if ( 84 | /^ [^ ]/.test(line) && 85 | (line = line.trim()).length !== 0 && 86 | (m = line.match( 87 | /^(\d+) files? changed(?:, (\d+) insertions?\(\+\))?(?:, (\d+) deletions?\(-\))?/ 88 | )) !== null 89 | ) { 90 | commit.changes = { 91 | files: parseInt(m[1]), 92 | insertions: parseInt(m[2] ?? 0), 93 | deletions: parseInt(m[3] ?? 0) 94 | } 95 | } 96 | 97 | return old 98 | } 99 | 100 | function onLine (line, _, callback) { 101 | const commit = addLine(line) 102 | 103 | if (commit?.authors?.length > 0) { 104 | commit.author = commit.authors[0] 105 | 106 | this.push(commit) 107 | } 108 | 109 | callback() 110 | } 111 | 112 | function onEnd (callback) { 113 | if (commit?.authors?.length > 0) { 114 | commit.author = commit.authors[0] 115 | 116 | this.push(commit) 117 | } 118 | 119 | callback() 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "commit-stream", 3 | "version": "2.2.0", 4 | "description": "Turn a `git log` into a stream of commit objects", 5 | "main": "commit-stream.js", 6 | "type": "module", 7 | "scripts": { 8 | "build": "true", 9 | "test:ci": "npm run test", 10 | "test": "node test.js" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/nodejs/commit-stream.git" 15 | }, 16 | "author": "Rod (http://r.va.gg/)", 17 | "license": "MIT", 18 | "bugs": { 19 | "url": "https://github.com/nodejs/commit-stream/issues" 20 | }, 21 | "homepage": "https://github.com/nodejs/commit-stream", 22 | "devDependencies": { 23 | "bl": "^6.0.1", 24 | "list-stream": "^2.1.0", 25 | "readable-stream": "^4.3.0", 26 | "split2": "^4.2.0", 27 | "tape": "^5.6.3" 28 | }, 29 | "dependencies": { 30 | "strip-ansi": "^7.0.1", 31 | "through2": "^4.0.2" 32 | }, 33 | "release": { 34 | "branches": [ 35 | "main" 36 | ], 37 | "plugins": [ 38 | [ 39 | "@semantic-release/commit-analyzer", 40 | { 41 | "preset": "conventionalcommits", 42 | "releaseRules": [ 43 | { 44 | "breaking": true, 45 | "release": "major" 46 | }, 47 | { 48 | "revert": true, 49 | "release": "patch" 50 | }, 51 | { 52 | "type": "feat", 53 | "release": "minor" 54 | }, 55 | { 56 | "type": "fix", 57 | "release": "patch" 58 | }, 59 | { 60 | "type": "chore", 61 | "release": "patch" 62 | }, 63 | { 64 | "type": "docs", 65 | "release": "patch" 66 | }, 67 | { 68 | "type": "test", 69 | "release": "patch" 70 | }, 71 | { 72 | "scope": "no-release", 73 | "release": false 74 | } 75 | ] 76 | } 77 | ], 78 | [ 79 | "@semantic-release/release-notes-generator", 80 | { 81 | "preset": "conventionalcommits", 82 | "presetConfig": { 83 | "types": [ 84 | { 85 | "type": "feat", 86 | "section": "Features" 87 | }, 88 | { 89 | "type": "fix", 90 | "section": "Bug Fixes" 91 | }, 92 | { 93 | "type": "chore", 94 | "section": "Trivial Changes" 95 | }, 96 | { 97 | "type": "docs", 98 | "section": "Trivial Changes" 99 | }, 100 | { 101 | "type": "test", 102 | "section": "Tests" 103 | } 104 | ] 105 | } 106 | } 107 | ], 108 | "@semantic-release/changelog", 109 | "@semantic-release/npm", 110 | "@semantic-release/github", 111 | "@semantic-release/git" 112 | ] 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | import commitStream from './commit-stream.js' 2 | import { spawn, exec } from 'node:child_process' 3 | import test from 'tape' 4 | import split2 from 'split2' 5 | import listStream from 'list-stream' 6 | import { pipeline } from 'readable-stream' 7 | import bl from 'bl' 8 | 9 | function gitToList (t, gitCmd, user, repo, callback) { 10 | if (typeof user === 'function') { 11 | callback = user 12 | user = undefined 13 | repo = undefined 14 | } 15 | const child = spawn('bash', ['-c', gitCmd]) 16 | child.stderr.pipe(bl((_, out) => { 17 | t.strictEqual(out.toString(), '') 18 | })) 19 | child.on('error', (err) => { 20 | t.error(err, 'error from child') 21 | }) 22 | child.on('close', (code) => { 23 | t.strictEqual(code, 0, 'exit code zero') 24 | setImmediate(t.end.bind(t)) 25 | }) 26 | pipeline( 27 | child.stdout, 28 | split2(), 29 | commitStream(user, repo), 30 | listStream.obj(callback), 31 | () => {} 32 | ) 33 | } 34 | 35 | test('git is runnable', (t) => { 36 | exec('git version', (error, stdout, stderr) => { 37 | if (error) { 38 | t.fail(`command failed: ${error}`) 39 | } else if (stderr) { 40 | t.fail(`command output to stderr: ${stderr}`) 41 | } else { 42 | t.match(stdout, /^git version 2/) 43 | } 44 | t.end() 45 | }) 46 | }) 47 | 48 | test('current plain commit log', (t) => { 49 | gitToList(t, 'git log', (err, list) => { 50 | t.error(err, 'no error') 51 | 52 | t.ok(list?.length > 0, 'got a list') 53 | if (!list || !list.length) { 54 | return 55 | } 56 | 57 | t.deepEqual( 58 | list[list.length - 9], 59 | { 60 | author: { email: 'ralphtheninja@riseup.net', name: 'Lars-Magnus Skog' }, 61 | authors: [ 62 | { email: 'ralphtheninja@riseup.net', name: 'Lars-Magnus Skog' } 63 | ], 64 | authorDate: 'Tue Feb 9 15:46:46 2016 +0100', 65 | description: [ 66 | 'Fixes: https://github.com/rvagg/changelog-maker/issues/35' 67 | ], 68 | ghIssue: 1, 69 | ghProject: 'commit-stream', 70 | ghUser: 'rvagg', 71 | prUrl: 'https://github.com/rvagg/commit-stream/pull/1', 72 | sha: '1bcfd072fd74399808fbcd5cf31ce5342dd6d70c', 73 | summary: 'process: this should not match PR-URL', 74 | reviewers: [{ email: 'rod@vagg.org', name: 'Rod Vagg' }] 75 | }, 76 | 'got correct ninth commit' 77 | ) 78 | 79 | t.deepEqual( 80 | list[list.length - 4], 81 | { 82 | author: { email: 'rod@vagg.org', name: 'Rod Vagg' }, 83 | authors: [{ email: 'rod@vagg.org', name: 'Rod Vagg' }], 84 | authorDate: 'Fri Apr 17 11:16:51 2015 +1000', 85 | sha: 'f92b93c3c7175b07f847dd45058b121cea6b3a20', 86 | summary: 'deleted package.json line' 87 | }, 88 | 'got correct fourth commit' 89 | ) 90 | 91 | t.deepEqual( 92 | list[list.length - 3], 93 | { 94 | author: { email: 'rod@vagg.org', name: 'Rod Vagg' }, 95 | authors: [{ email: 'rod@vagg.org', name: 'Rod Vagg' }], 96 | authorDate: 'Fri Apr 17 11:13:06 2015 +1000', 97 | description: ['comment', 'Reviewed-By: Nobody'], 98 | sha: 'db34ce2af09a6a9fb70241d43965a2bc48b90b4c', 99 | summary: 'squished package.json' 100 | }, 101 | 'got correct third commit' 102 | ) 103 | 104 | t.deepEqual( 105 | list[list.length - 2], 106 | { 107 | author: { email: 'rod@vagg.org', name: 'Rod Vagg' }, 108 | authors: [{ email: 'rod@vagg.org', name: 'Rod Vagg' }], 109 | authorDate: 'Fri Apr 17 10:52:16 2015 +1000', 110 | description: [ 111 | 'Some extra summary information here', 112 | 'newline', 113 | 'Fixes: https://github.com/rvagg/commit-stream/issues/0' 114 | ], 115 | ghIssue: 0, 116 | ghProject: 'commit-stream', 117 | ghUser: 'rvagg', 118 | prUrl: 'https://github.com/rvagg/commit-stream/pulls/0', 119 | reviewers: [{ email: 'roger@vagg.org', name: 'Roger Vagg' }], 120 | sha: '6275758f597ae579202fbe4eccca1407f2c67ac1', 121 | summary: 'added test.js' 122 | }, 123 | 'got correct second commit' 124 | ) 125 | 126 | t.deepEqual( 127 | list[list.length - 1], 128 | { 129 | sha: 'd94841274e2979e7758413a0f48fa37560d0dde6', 130 | authorDate: 'Thu Apr 16 20:49:21 2015 +1000', 131 | author: { name: 'Rod Vagg', email: 'rod@vagg.org' }, 132 | authors: [{ email: 'rod@vagg.org', name: 'Rod Vagg' }], 133 | summary: 'make it so' 134 | }, 135 | 'got correct first commit' 136 | ) 137 | 138 | t.deepEqual( 139 | list[list.length - 16], 140 | { 141 | sha: list[list.length - 16]?.sha, // unknown at time of writing :) 142 | authorDate: 'Tue Jun 12 23:41:35 2018 +0200', 143 | author: { name: 'Anna Henningsen', email: 'anna@addaleax.net' }, 144 | authors: [ 145 | { name: 'Anna Henningsen', email: 'anna@addaleax.net' }, 146 | { name: 'nobody', email: 'nobody@nowhere' } 147 | ], 148 | summary: 'add support for co-authored-by' 149 | }, 150 | 'got correct co-authored-by commit' 151 | ) 152 | }) 153 | }) 154 | 155 | test('current commit log with changes', (t) => { 156 | gitToList(t, 'git log --stat', (err, list) => { 157 | t.error(err, 'no errors') 158 | 159 | t.ok(list?.length > 0, 'got a list') 160 | if (!list || !list.length) { 161 | return 162 | } 163 | 164 | t.deepEqual( 165 | list[list.length - 4]?.changes, 166 | { 167 | files: 1, 168 | insertions: 0, 169 | deletions: 1 170 | }, 171 | 'got correct second commit changes' 172 | ) 173 | 174 | t.deepEqual( 175 | list[list.length - 3]?.changes, 176 | { 177 | files: 1, 178 | insertions: 1, 179 | deletions: 28 180 | }, 181 | 'got correct second commit changes' 182 | ) 183 | 184 | t.deepEqual( 185 | list[list.length - 2]?.changes, 186 | { 187 | files: 1, 188 | insertions: 49, 189 | deletions: 0 190 | }, 191 | 'got correct second commit changes' 192 | ) 193 | 194 | t.deepEqual( 195 | list[list.length - 1]?.changes, 196 | { 197 | files: 1, 198 | insertions: 28, 199 | deletions: 0 200 | }, 201 | 'got correct first commit changes' 202 | ) 203 | }) 204 | }) 205 | 206 | test('current commit log with ghUser and ghRepo passed', function (t) { 207 | gitToList(t, 'git log', 'rvagg', 'commit-stream', function (err, list) { 208 | t.error(err, 'no error') 209 | 210 | t.ok(list && list.length > 1, 'got a list') 211 | 212 | t.deepEqual(list[list.length - 18], { 213 | sha: 'b23208796d7e3fd08b36f6106aa7f027aa827137', 214 | authors: [ 215 | { name: 'Rich Trott', email: 'rtrott@gmail.com' } 216 | ], 217 | authorDate: 'Mon Oct 11 19:29:18 2021 -0700', 218 | prUrl: 'https://github.com/rvagg/commit-stream/pull/5', 219 | ghIssue: 5, 220 | ghUser: 'rvagg', 221 | ghProject: 'commit-stream', 222 | author: { name: 'Rich Trott', email: 'rtrott@gmail.com' }, 223 | summary: 'chore: update strip-ansi to 6.x' 224 | }, 'got correct pr url for green-button merge') 225 | }) 226 | }) 227 | 228 | test('cve id', function (t) { 229 | gitToList(t, 'git log', 'rvagg', 'commit-stream', function (err, list) { 230 | t.error(err, 'no error') 231 | 232 | t.ok(list && list.length > 1, 'got a list') 233 | 234 | t.deepEqual(list[list.length - 30], { 235 | sha: '6c82ccd24e44167433126ba2bf4e95c8c4f41297', 236 | authors: [ 237 | { name: 'RafaelGSS', email: 'rafael.nunu@hotmail.com' } 238 | ], 239 | authorDate: 'Fri Nov 22 00:19:29 2024 -0300', 240 | author: { name: 'RafaelGSS', email: 'rafael.nunu@hotmail.com' }, 241 | summary: 'feat: add cveId support', 242 | cveId: 'CVE-2024-12345' 243 | }, 'got correct pr url for green-button merge') 244 | }) 245 | }) 246 | --------------------------------------------------------------------------------