diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..dce2110 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,52 @@ +on: [pull_request] + +jobs: + check: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v4 + with: + fetch-depth: '0' + show-progress: 'false' + - uses: actions/cache@v4 + with: + path: /root/.jbang + key: $-jbang-$ + restore-keys: | + $-jbang- + - name: jbang + uses: jbangdev/jbang-action@v0.115.0 + with: + script: gcl.java + env: + GITHUB_OAUTH: ${{ secrets.GITHUB_TOKEN }} + lint: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v4 + with: + show-progress: 'false' + - name: markdownlint + uses: DavidAnson/markdownlint-cli2-action@v16 + with: + globs: | + *.md + - name: Lint CHANGELOG.md + run: | + # Install jbang + curl -Ls https://sh.jbang.dev | bash -s - app setup + export PATH=$PATH:$HOME/.jbang/bin + + # run heylogs verification + jbang com.github.nbbrd.heylogs:heylogs-cli:0.7.2:bin check CHANGELOG.md > heylogs.txt || true + + # improve output + sed -i 's/all-h2-contain-a-version/all-h2-contain-a-version (ignored)/' heylogs.txt + + cat heylogs.txt + + # exit 1 in case of error + # We have 1 "valid" issue in CHANGELOG.md + grep -q "2 problems" heylogs.txt || exit 1 diff --git a/.markdownlint.yml b/.markdownlint.yml new file mode 100644 index 0000000..1d77064 --- /dev/null +++ b/.markdownlint.yml @@ -0,0 +1,4 @@ +default: true + +# allow arbitrary line length +MD013: false diff --git a/CHANGELOG.md b/CHANGELOG.md index d43974a..970baa6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). -## 2024-04-25 +## [2024-04-25] ### Added @@ -20,11 +20,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Commits without any pull request number are also analyzed. - Fixed typo in parameter `--login-mapping`. +- Handling of ignored users. ### Removed - Removed some hard-coded JabRef defaults (such as ignored users). -## 2024-04-09 +## [2024-04-09] Initial release. + +[2024-04-25]: https://github.com/koppor/github-contributors-list/compare/2024-04-09...2024-04-25 +[2024-04-09]: https://github.com/koppor/github-contributors-list/releases/tag/2024-04-09 diff --git a/README.md b/README.md index a686ec5..be34b4f 100644 --- a/README.md +++ b/README.md @@ -22,13 +22,13 @@ See for real-wor 3. `cd` to the repository you want to analyze. 4. `jbang gcl@koppor/github-contributors-list` -``` -Usage: jbang gcl.java [-lhV] [--startrevision=] - [--endrevision=] [--owner=] - [--repo=] [--cols=] [--filter=]... +```terminal +Usage: jbang gcl@koppor/github-contributors-list [-lhV] [--startrevision=] + [--endrevision=] [--repository=] + [--cols=] [--filter=]... [--filter-emails=]... [-m=]... - - The path to the git repository to analyse. + [] + [] The path to the git repository to analyse. --cols= Number of columns --endrevision= The last revision to check (tag or commit id). @@ -40,11 +40,12 @@ Usage: jbang gcl.java [-lhV] [--startrevision=] -h, --help Show this help message and exit. -l, --[no-]github-lookup Should calls be made to GitHub's API for user information - -m, --lgin-mapping= + -m, --login-mapping= Mapping of GitHub logins to names. Format: name=login - --owner= The GitHub owner of the repository - --repo= The GitHub repository name + --repository= + The GitHub repository in the form + owner/repostiory. E.g., JabRef/jabref --startrevision= The first revision to check (tag or commit id). Excluded. @@ -55,7 +56,9 @@ At the end, non-found committers are listed. The format is ` `. Example: - Anish.Pal https://github.com/JabRef/jabref/pull/10829 https://github.com/JabRef/jabref/pull/10829/commits/d2d84923df2c6c7d59559da8d583ae17dc803c3d +```text +Anish.Pal https://github.com/JabRef/jabref/pull/10829 https://github.com/JabRef/jabref/pull/10829/commits/d2d84923df2c6c7d59559da8d583ae17dc803c3d +``` With that information, one can create a mapping from the committer name to the GitHub username. In this case: `Anish.Pal=pal-anish` diff --git a/gcl.java b/gcl.java index 0ddc0b6..957cfce 100755 --- a/gcl.java +++ b/gcl.java @@ -76,7 +76,7 @@ public class gcl implements Callable { private static final Pattern numberAtEnd = Pattern.compile(".*\\(#(\\d+)\\)$"); private static final Pattern mergeCommit = Pattern.compile("^Merge pull request #(\\d+) from.*"); - @Parameters(index = "0", description = "The path to the git repository to analyse.") + @Parameters(index = "0", arity = "0..1", description = "The path to the git repository to analyse.") private Path repositoryPath = Path.of("."); @Option(names = "--startrevision", description = "The first revision to check (tag or commit id). Excluded.") @@ -126,6 +126,10 @@ public class gcl implements Callable { private static final String githubUsersEmailSuffix = "@users.noreply.github.com"; private record Contributor(String name, String url, String avatarUrl) implements Serializable { + public String getUserId() { + // Example: https://github.com/LoayGhreeb, then userId is LoeyGhreeb + return url.substring(url.lastIndexOf('/') + 1); + } } private record CoAuthor(String name, String email) { @@ -136,7 +140,7 @@ public CoAuthor(String line) { } } - private SortedSet contributors = new TreeSet<>((a, b) -> String.CASE_INSENSITIVE_ORDER.compare(a.name,b.name)); + private SortedSet contributors = new TreeSet<>((a, b) -> String.CASE_INSENSITIVE_ORDER.compare(a.name, b.name)); private SortedSet fallbacks = new TreeSet<>(); @@ -179,15 +183,32 @@ public Integer call() throws Exception { Git git = Git.open(repositoryPath.toFile()); Repository repository = git.getRepository(); RevWalk revWalk = new RevWalk(repository)) { + String remoteOriginUrl = "n/a"; if (!hasRepository) { // Source: https://stackoverflow.com/a/38062680/873282 - ownerRepository = git.getRepository().getConfig().getString("remote", "origin", "url"); - ownerRepository = ownerRepository.substring(ownerRepository.indexOf(':') + 1, ownerRepository.lastIndexOf('.')); + remoteOriginUrl = git.getRepository().getConfig().getString("remote", "origin", "url"); + if (remoteOriginUrl.startsWith("git@")) { + ownerRepository = remoteOriginUrl.substring(remoteOriginUrl.indexOf(':') + 1, remoteOriginUrl.lastIndexOf('.')); + } else { + ownerRepository = remoteOriginUrl.substring(remoteOriginUrl.indexOf("github.com/") + "github.com/".length()); + if (ownerRepository.endsWith(".git")) { + ownerRepository = ownerRepository.substring(0, ownerRepository.length() - ".git".length()); + } + } } Logger.info("Connecting to {}...", ownerRepository); GitHub gitHub = GitHub.connect(); - GHRepository gitHubRepository = gitHub.getRepository(ownerRepository); + GHRepository gitHubRepository; + try { + gitHubRepository = gitHub.getRepository(ownerRepository); + } catch (IllegalArgumentException e) { + Logger.error("Error in repository reference {}", ownerRepository); + if (!hasRepository) { + Logger.error("It was automatically derived from {}", remoteOriginUrl); + } + return 1; + } MVMap emailToContributor = store.openMap("emailToContributor"); MVMap loginToContributor = store.openMap("loginToContributor"); @@ -472,13 +493,15 @@ private Optional lookupContributorData(MVMap e Contributor contributor = emailToContributor.get(email); if (contributor != null) { - // Example: Store "LoyGhreeb" https://github.com/LoayGhreeb in userId - String userId = contributor.url.substring(contributor.url.lastIndexOf('/') + 1); + // We already know this email, just check whether we ignore this one + String userId = contributor.getUserId(); if (ignoredUsers.contains(userId)) { Logger.trace("Ignored because of userId {}: {}", userId, coAuthor); return Optional.empty(); } + return Optional.of(contributor); } + if (!ghLookup) { Logger.trace("Online lookup disabled. Using {} as fallback.", coAuthor.name); fallbacks.add(coAuthor.name);