Skip to content

Commit

Permalink
Merge pull request #119 from rkotze/repo-author-list
Browse files Browse the repository at this point in the history
Git mob core extract the list of contributors and filter by author name or email.
  • Loading branch information
rkotze authored Nov 19, 2023
2 parents 190715a + 0a8b186 commit aac614b
Show file tree
Hide file tree
Showing 14 changed files with 236 additions and 142 deletions.
15 changes: 14 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,27 @@ Follows [Semantic Versioning](https://semver.org/).

### Added

-- `git suggest-coauthors <name or email>` can filter by author name or email. Addresses [issue 90](https://github.com/rkotze/git-mob/issues/90)

### Refactored

- Remove legacy git-message API and replace it with git-mob-core `git-message` API
- Remove legacy git-add-coauthor API and replace it with git-mob-core `saveNewCoAuthors`
- Remove legacy git-suggest-coauthor API and replace it with git-mob-core `repoAuthorList`
- Migrated `git-suggest-coauthors` to TypeScript

## git-mob-core next

### Added

- Added `repoAuthorList` which will list all contributors from a repo
- Added filter to `repoAuthorList` which uses `--author` flag from `git shortlog`.

### Refactored

- Add new co-author module migrated to TypeScript and tested
- Change to async `topLevelDirectory`, `insideWorkTree` - may not be needed in future versions
- Resolve-git-message-path migrated to TypeScript
- `resolve-git-message-path` migrated to TypeScript
- Changed to async `resolveGitMessagePath`, `setCommitTemplate`

## git-mob 3.0.0
Expand Down
2 changes: 1 addition & 1 deletion packages/git-mob-core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ fetchGitHubAuthors(userNames: string[], userAgent: string): <Promise<Author[]>>
pathToCoAuthors(): <Promise<string>>
getConfig(prop: string): string | undefined
updateConfig(prop: string, value: string): void
repoAuthorList(authorFilter?: string): Promise<Author[] | undefined>
gitMobConfig = {
localTemplate(): <Promise<boolean>>,
fetchFromGitHub(): <Promise<boolean>>,
Expand All @@ -39,7 +40,6 @@ gitRevParse = {
insideWorkTree(): <Promise<string>>,
topLevelDirectory(): <Promise<boolean>>,
};
class Author
```

## Author class
Expand Down
5 changes: 0 additions & 5 deletions packages/git-mob-core/src/commands.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { silentRun } from './silent-run.js';
import { execCommand } from './git-mob-api/exec-command.js';

function handleResponse(query) {
try {
Expand Down Expand Up @@ -59,10 +58,6 @@ function removeGitMobSection() {
return silentRun(`git config --global --remove-section git-mob`);
}

export async function getRepoAuthors() {
return execCommand('git shortlog -sen HEAD');
}

export const config = {
getAll,
get,
Expand Down
9 changes: 9 additions & 0 deletions packages/git-mob-core/src/git-mob-api/exec-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,12 @@ export async function setConfig(key: string, value: string) {
throw new Error(`Git mob core setConfig: ${message}`);
}
}

export async function getRepoAuthors(authorFilter?: string) {
let repoAuthorQuery = 'git shortlog -seni HEAD';
if (authorFilter) {
repoAuthorQuery += ` --author="${authorFilter}"`;
}

return execCommand(repoAuthorQuery);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import os from 'node:os';
import { getRepoAuthors } from '../exec-command';
import { Author } from '../author';
import { repoAuthorList } from './repo-author-list';

jest.mock('../exec-command');
const mockedGetRepoAuthors = jest.mocked(getRepoAuthors);

describe('Extract repository authors', function () {
it('Given a list of authors extract the name and email', async function () {
mockedGetRepoAuthors.mockResolvedValueOnce(
` 33\tRichard Kotze <rkotze@email.com>${os.EOL} 53\tTony Stark <tony@stark.com>`
);
const listOfAuthors = await repoAuthorList();
expect(listOfAuthors).toEqual([
new Author('rkrk', 'Richard Kotze', 'rkotze@email.com'),
new Author('tsto', 'Tony Stark', 'tony@stark.com'),
]);
});

it('author has one name', async function () {
mockedGetRepoAuthors.mockResolvedValueOnce(
` 33\tRichard <rkotze@email.com>${os.EOL} 53\tTony Stark <tony@stark.com>`
);
const listOfAuthors = await repoAuthorList();
expect(listOfAuthors).toEqual([
new Author('rrk', 'Richard', 'rkotze@email.com'),
new Author('tsto', 'Tony Stark', 'tony@stark.com'),
]);
});

it('author uses a private GitHub email', async function () {
mockedGetRepoAuthors.mockResolvedValueOnce(
` 33\tRichard <rkotze@email.com>${os.EOL} 53\tTony Stark <20342323+tony[bot]@users.noreply.github.com>`
);
const listOfAuthors = await repoAuthorList();
expect(listOfAuthors).toEqual([
new Author('rrk', 'Richard', 'rkotze@email.com'),
new Author(
'ts20',
'Tony Stark',
'20342323+tony[bot]@users.noreply.github.com'
),
]);
});

it('only one author on repository', async function () {
mockedGetRepoAuthors.mockResolvedValueOnce(
` 33\tRichard Kotze <rkotze@email.com>`
);
const listOfAuthors = await repoAuthorList();
expect(listOfAuthors).toEqual([
new Author('rkrk', 'Richard Kotze', 'rkotze@email.com'),
]);
});

it('author has special characters in name', async function () {
mockedGetRepoAuthors.mockResolvedValueOnce(
` 33\tRic<C4><8D>rd Kotze <rkotze@email.com>`
);
const listOfAuthors = await repoAuthorList();
expect(listOfAuthors).toEqual([
new Author('rkrk', 'Ric<C4><8D>rd Kotze', 'rkotze@email.com'),
]);
});

it('exclude if fails to match author pattern in list', async function () {
mockedGetRepoAuthors.mockResolvedValueOnce(
` 33\tRichard Kotze <rkotze.email.com`
);
const listOfAuthors = await repoAuthorList();
expect(listOfAuthors).toEqual(undefined);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { EOL } from 'node:os';
import { Author } from '../author';
import { getRepoAuthors } from '../exec-command';

export async function repoAuthorList(
authorFilter?: string
): Promise<Author[] | undefined> {
const repoAuthorsString = await getRepoAuthors(authorFilter);
const splitEndOfLine = repoAuthorsString.split(EOL);
const authorList = splitEndOfLine
.map(createRepoAuthor)
.filter(author => author !== undefined) as Author[];

if (authorList.length > 0) return authorList;
}

function createRepoAuthor(authorString: string) {
const regexList = /\d+\t(.+)\s<(.+)>/;
const authorArray = regexList.exec(authorString);
if (authorArray !== null) {
const [, name, email] = authorArray;
return new Author(genKey(name, email), name, email);
}
}

function genKey(name: string, email: string) {
const nameInitials = name
.toLowerCase()
.split(' ')
.reduce(function (acc, cur) {
return acc + cur[0];
}, '');

const domainFirstTwoLetters = email.slice(0, 2);
return nameInitials + domainFirstTwoLetters;
}
1 change: 1 addition & 0 deletions packages/git-mob-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ export const gitRevParse = {
};

export { saveNewCoAuthors } from './git-mob-api/manage-authors/add-new-coauthor.js';
export { repoAuthorList } from './git-mob-api/git-authors/repo-author-list.js';
export { pathToCoAuthors } from './git-mob-api/git-authors/index.js';
export { fetchGitHubAuthors } from './git-mob-api/git-authors/fetch-github-authors.js';
export { getConfig, updateConfig } from './config-manager.js';
Expand Down
11 changes: 6 additions & 5 deletions packages/git-mob/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ _Add co-authors to commits_ when you collaborate on code. Use when pairing with
- [Add co-author](#add-co-author)
- [Delete co-author](#delete-co-author)
- [Edit co-author](#edit-co-author)
- [Suggest co-authors base on current repo](#suggest-co-authors-base-on-current-repo)
- [Suggest co-authors](#suggest-co-authors)
- [Help](#help)
- [Add initials of current mob to your prompt](#add-initials-of-current-mob-to-your-prompt)
- [Bash](#bash)
Expand Down Expand Up @@ -242,13 +242,14 @@ $ git edit-coauthor bb --name="Barry Butterworth"
$ git edit-coauthor bb --email="barry@butterworth.org"
```
### Suggest co-authors base on current repo
### Suggest co-authors
Suggest some co-authors to add based on existing committers to your
current repo
Suggest co-authors to save based on contributors to the current Git repo.
Optional author filter by name or email.
```
$ git suggest-coauthors
$ git suggest-coauthors <name or email>
```
### Help
Expand Down
12 changes: 0 additions & 12 deletions packages/git-mob/src/git-commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,15 +129,6 @@ function topLevelDirectory() {
return silentRun('git rev-parse --show-toplevel').stdout.trim();
}

/**
* Returns a list of the existing authors for the git repository
* including their names and email addresses
* @returns {string} of output from git command
*/
function shortLogAuthorSummary() {
return silentRun('git shortlog --summary --email --number HEAD').stdout.trim();
}

function getTemplatePath() {
return get('commit.template');
}
Expand Down Expand Up @@ -182,6 +173,3 @@ export const revParse = {
insideWorkTree,
topLevelDirectory,
};
export const authors = {
shortLogAuthorSummary,
};
98 changes: 0 additions & 98 deletions packages/git-mob/src/git-suggest-coauthors.js

This file was deleted.

18 changes: 0 additions & 18 deletions packages/git-mob/src/git-suggest-coauthors.spec.js

This file was deleted.

26 changes: 26 additions & 0 deletions packages/git-mob/src/git-suggest-coauthors.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { EOL } from 'node:os';
import test from 'ava';
import { exec } from '../test-helpers/index.js';

test('Suggests coauthors using repo contributors', t => {
const { stdout } = exec('git suggest-coauthors');

t.regex(stdout, /Here are some suggestions/);
t.regex(stdout, /git add-coauthor rkri "Richard Kotze" richkotze@outlook.com/);
t.regex(stdout, /Paste any line above/);
});

test('Filter suggestions of coauthors', t => {
const { stdout } = exec('git suggest-coauthors dennis i');

t.regex(stdout, /git add-coauthor diid "Dennis Ideler" ideler.dennis@gmail.com/);
t.is(stdout.split(EOL).filter(a => a.includes('git add-coauthor')).length, 2);
});

test('Prints help message', t => {
const { stdout } = exec('git suggest-coauthors -h');

t.regex(stdout, /usage/i);
t.regex(stdout, /options/i);
t.regex(stdout, /example/i);
});
Loading

0 comments on commit aac614b

Please sign in to comment.