Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/util-git-info/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ yarn-error.log*
misc
old

tests/result.json

# TypeScript generated types
types/

# Runtime data
pids
*.pid
Expand Down
189 changes: 155 additions & 34 deletions packages/util-git-info/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ npm install git-er-done

## Usage

### Basic Usage

```js
const { gitDetails } = require('git-er-done')

// Git commit ref / branch to check against. Default is 'master'
const GIT_COMMIT_REF = '9f63b23ec99e36a176d73909fc67a39dc3bd56b7'

gitData({
gitDetails({
base: GIT_COMMIT_REF,
}).then((git) => {
/* git data returns
Expand All @@ -29,55 +30,175 @@ gitData({
createdFiles: [ Array of created files ],
deletedFiles: [ Array of deleted files ],
commits: [ Array of commits ],
linesOfCode: [AsyncFunction: linesOfCode]
lastCommit: { Object with last commit info },
linesOfCode: [AsyncFunction: linesOfCode],
dir: String path to git repo
}
*/

if (modifiedFiles.length) {
if (git.modifiedFiles.length) {
// Some files have changed
}

if (createdFiles.length) {
if (git.createdFiles.length) {
// Some files have been created
}

if (deletedFiles.length) {
if (git.deletedFiles.length) {
// Some files have been deleted
}
})
```

/* Using fileMatch function */
const srcCode = git.fileMatch('src/**/*.js')
/* srcCode is object
{
modified: true,
created: true,
deleted: true,
edited: true,
getKeyedPaths: [Function: getKeyedPaths]
}
*/
if (srcCode.edited) {
console.log('srcCode has been edited')
// Do stuff because src edited
}
### Using without options

const mdFiles = git.fileMatch('**/*.md')
if (mdFiles.edited) {
// Do stuff because markdown files are changed
}
You can call `gitDetails()` without any options to get info from the current HEAD:

const mdFilesData = mdFiles.getKeyedPaths()
/* mdFilesData is full information on the files in the sub path that changed
{
modified: [ Array of modified files ],
created: [ Array of created files ],
deleted:[ Array of deleted files ],
edited: [ Array of edited files ]
}
*/
```js
const { gitDetails } = require('git-er-done')

const git = await gitDetails()
console.log('Modified files:', git.modifiedFiles)
console.log('Created files:', git.createdFiles)
console.log('Deleted files:', git.deletedFiles)
```

### Getting Lines of Code Changed

```js
const { gitDetails } = require('git-er-done')

const git = await gitDetails({
base: 'main',
head: 'feature-branch'
})

const totalLines = await git.linesOfCode()
console.log(`Total lines changed: ${totalLines}`)
```

### Working with Commit Information

Access detailed commit information including author, committer, and subject:

```js
const { gitDetails } = require('git-er-done')

const git = await gitDetails({ base: 'main' })

//... Etc. GIT ER DONE
// Access commits array
git.commits.forEach((commit) => {
console.log('SHA:', commit.sha)
console.log('Author:', commit.author.name, commit.author.email)
console.log('Committer:', commit.committer.name)
console.log('Subject:', commit.subject)
console.log('Sanitized Subject:', commit.sanitizedSubject)
console.log('---')
})

// Access the last commit
console.log('Last commit:', git.lastCommit)
```

### Using fileMatch with Patterns

Use glob patterns to match specific files. You can also use negation patterns:

```js
const { gitDetails } = require('git-er-done')

const git = await gitDetails({ base: 'main' })

// Simple pattern matching
const srcCode = git.fileMatch('src/**/*.js')
/* srcCode returns object with:
{
modified: Boolean,
modifiedFiles: Array,
created: Boolean,
createdFiles: Array,
deleted: Boolean,
deletedFiles: Array,
edited: Boolean,
editedFiles: Array
}
*/

if (srcCode.edited) {
console.log('Source code has been edited')
console.log('Modified files:', srcCode.modifiedFiles)
console.log('Created files:', srcCode.createdFiles)
}

// Match with negation - find all JSON files except package.json
const jsonFiles = git.fileMatch('**/**.json', '!**/package.json')
if (jsonFiles.modified) {
console.log('Non-package JSON files modified:', jsonFiles.modifiedFiles)
}
if (jsonFiles.created) {
console.log('Non-package JSON files created:', jsonFiles.createdFiles)
}

// Check markdown files
const mdFiles = git.fileMatch('**/*.md')
if (mdFiles.edited) {
// Do stuff because markdown files are changed
console.log('All markdown changes:', mdFiles.editedFiles)
}
```

### Getting Detailed File Information

The `fileMatch` function returns detailed information about matched files:

```js
const { gitDetails } = require('git-er-done')

const git = await gitDetails({ base: 'main' })

const testFiles = git.fileMatch('**/*.test.js')

// Access individual arrays
console.log('Modified test files:', testFiles.modifiedFiles)
console.log('Created test files:', testFiles.createdFiles)
console.log('Deleted test files:', testFiles.deletedFiles)
console.log('All edited test files:', testFiles.editedFiles)

// Check if any test files changed
if (testFiles.edited) {
console.log('Tests have been modified - run test suite')
}

## Examples

Check out the [`examples`](./examples) directory for more use cases:

### Basic Examples
- [`get-git-data.js`](./examples/get-git-data.js) - Get basic git information between commits
- [`get-all-commits.js`](./examples/get-all-commits.js) - Retrieve and display all commits
- [`get-git-files.js`](./examples/get-git-files.js) - Get list of all git-tracked files
- [`get-specific-commit-info.js`](./examples/get-specific-commit-info.js) - Get detailed information about a specific commit

### File Change Detection
- [`detect-file-changes.js`](./examples/detect-file-changes.js) - Detect specific file changes between commits
- [`file-match-patterns.js`](./examples/file-match-patterns.js) - Comprehensive guide to file matching patterns

### Statistics & Analysis
- [`get-lines-of-code-changed.js`](./examples/get-lines-of-code-changed.js) - Calculate lines of code changed
- [`branch-comparison.js`](./examples/branch-comparison.js) - Compare two branches with detailed statistics

### Automation & CI/CD
- [`check-config-changes.js`](./examples/check-config-changes.js) - Detect configuration file changes for CI/CD pipelines
- [`code-review-helper.js`](./examples/code-review-helper.js) - Automated code review checklist and suggestions
- [`monorepo-package-detection.js`](./examples/monorepo-package-detection.js) - Detect which packages changed in a monorepo
- [`generate-release-notes.js`](./examples/generate-release-notes.js) - Auto-generate release notes from commits

Run any example:

```bash
node examples/get-git-data.js
node examples/code-review-helper.js
node examples/monorepo-package-detection.js
```

## Prior art
Expand Down
109 changes: 109 additions & 0 deletions packages/util-git-info/examples/branch-comparison.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
const { gitDetails } = require('../src')

async function compareBranches() {
const branch1 = 'main'
const branch2 = 'HEAD'

console.log(`🔍 Comparing ${branch1}...${branch2}\n`)
console.log('═══════════════════════════════════════\n')

let gitInfo
try {
gitInfo = await gitDetails({
base: branch1,
head: branch2
})
} catch (err) {
console.log('Error getting git info')
console.log(err)
return
}

// Commits
console.log(`📝 Commits: ${gitInfo.commits.length}\n`)
if (gitInfo.commits.length > 0) {
const recentCommits = gitInfo.commits.slice(0, 5)
console.log('Recent commits:')
recentCommits.forEach(commit => {
console.log(` ${commit.abbreviatedCommitHash} - ${commit.subject}`)
console.log(` ${commit.author.name} (${commit.author.date})\n`)
})

if (gitInfo.commits.length > 5) {
console.log(` ... and ${gitInfo.commits.length - 5} more commits\n`)
}
}

// Contributors
const contributors = new Map()
gitInfo.commits.forEach(commit => {
const name = commit.author.name
contributors.set(name, (contributors.get(name) || 0) + 1)
})

console.log('👥 Contributors:\n')
Array.from(contributors.entries())
.sort((a, b) => b[1] - a[1])
.forEach(([name, count]) => {
console.log(` ${name}: ${count} commit${count > 1 ? 's' : ''}`)
})
console.log()

// File changes
console.log('📊 File Changes:\n')
console.log(` Modified: ${gitInfo.modifiedFiles.length}`)
console.log(` Created: ${gitInfo.createdFiles.length}`)
console.log(` Deleted: ${gitInfo.deletedFiles.length}`)

const totalLines = await gitInfo.linesOfCode()
console.log(` Lines changed: ${totalLines}`)
console.log()

// File type breakdown
const getExtension = (file) => {
const match = file.match(/\.([^.]+)$/)
return match ? match[1] : 'no extension'
}

const allFiles = [
...gitInfo.modifiedFiles,
...gitInfo.createdFiles,
...gitInfo.deletedFiles
]

const fileTypes = {}
allFiles.forEach(file => {
const ext = getExtension(file)
fileTypes[ext] = (fileTypes[ext] || 0) + 1
})

console.log('📁 File Types:\n')
Object.entries(fileTypes)
.sort((a, b) => b[1] - a[1])
.forEach(([ext, count]) => {
console.log(` .${ext}: ${count} file${count > 1 ? 's' : ''}`)
})
console.log()

// Notable changes
console.log('🔍 Notable Changes:\n')

const tests = gitInfo.fileMatch(['**/*.test.js', '**/*.test.ts', '**/*.spec.js'])
if (tests.edited) {
console.log(` ✅ ${tests.editedFiles.length} test file${tests.editedFiles.length > 1 ? 's' : ''} changed`)
}

const docs = gitInfo.fileMatch('**/*.md')
if (docs.edited) {
console.log(` 📝 ${docs.editedFiles.length} documentation file${docs.editedFiles.length > 1 ? 's' : ''} changed`)
}

const configs = gitInfo.fileMatch(['**/package.json', '**/*.config.js', '**/tsconfig.json'])
if (configs.edited) {
console.log(` ⚙️ ${configs.editedFiles.length} config file${configs.editedFiles.length > 1 ? 's' : ''} changed`)
}

console.log('\n═══════════════════════════════════════')
}

compareBranches()
Loading