Skip to content

Commit 0e9ba46

Browse files
committed
Merge branch 'develop' of https://github.com/stdlib-js/stdlib into develop
2 parents 65b1756 + 62a5c3a commit 0e9ba46

File tree

92 files changed

+1547
-997
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+1547
-997
lines changed

.github/workflows/scripts/generate_pr_commit_message

Lines changed: 101 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,23 @@ on_error() {
5656
exit "$1"
5757
}
5858

59+
# Resolves a name and email using .mailmap via git check-mailmap, falling back to the provided values if no match is found.
60+
#
61+
# $1 - name
62+
# $2 - email
63+
resolve_name_email() {
64+
local name="$1"
65+
local email="$2"
66+
local resolved
67+
68+
resolved=$(git check-mailmap "$name <$email>" 2>/dev/null)
69+
if [ -n "$resolved" ]; then
70+
echo "$resolved"
71+
else
72+
echo "$name <$email>"
73+
fi
74+
}
75+
5976
# Resolves GitHub handle to name and email using .mailmap.
6077
#
6178
# $1 - GitHub handle
@@ -76,24 +93,47 @@ resolve_user() {
7693
fi
7794
}
7895

79-
# Makes authenticated GitHub API requests.
96+
# Makes GitHub API requests.
8097
#
8198
# $1 - HTTP method (GET or POST)
8299
# $2 - API endpoint
83-
# $3 - Data for POST requests
100+
# $3 - data for POST requests
84101
github_api() {
85102
local method="$1"
86103
local endpoint="$2"
87104
local data="$3"
88105

89-
if [ "$method" == "GET" ]; then
90-
curl -s -H "Authorization: token $GITHUB_TOKEN" "$GITHUB_API_URL$endpoint"
91-
elif [ "$method" == "POST" ]; then
92-
curl -s -X POST -H "Authorization: token $GITHUB_TOKEN" -H "Content-Type: application/json" -d "$data" "$GITHUB_API_URL$endpoint"
93-
else
94-
echo "Invalid HTTP method: $method"
95-
on_error 1
106+
# Initialize an array to hold curl headers:
107+
local headers=()
108+
109+
# If GITHUB_TOKEN is set, add the Authorization header:
110+
if [ -n "$GITHUB_TOKEN" ]; then
111+
headers+=("-H" "Authorization: token $GITHUB_TOKEN")
96112
fi
113+
114+
# Determine the HTTP method and construct the curl command accordingly...
115+
case "$method" in
116+
GET)
117+
curl -s "${headers[@]}" "$GITHUB_API_URL$endpoint"
118+
;;
119+
POST)
120+
# For POST requests, always set the Content-Type header>
121+
headers+=("-H" "Content-Type: application/json")
122+
123+
# If data is provided, include it in the request:
124+
if [ -n "$data" ]; then
125+
curl -s -X POST "${headers[@]}" -d "$data" "$GITHUB_API_URL$endpoint"
126+
else
127+
# Handle cases where POST data is required but not provided:
128+
echo "POST request requires data."
129+
on_error 1
130+
fi
131+
;;
132+
*)
133+
echo "Invalid HTTP method: $method"
134+
on_error 1
135+
;;
136+
esac
97137
}
98138

99139
# Main execution sequence.
@@ -103,6 +143,10 @@ main() {
103143
pr_title=$(echo "$pr_details" | jq -r '.title')
104144
pr_body=$(echo "$pr_details" | jq -r '.body // ""')
105145
pr_url=$(echo "$pr_details" | jq -r '.html_url')
146+
pr_author_login=$(echo "$pr_details" | jq -r '.user.login')
147+
148+
# Resolve the PR author's name and email using .mailmap:
149+
pr_author_resolved=$(resolve_user "$pr_author_login")
106150

107151
# Extract reviewers:
108152
pr_reviews=$(github_api "GET" "/repos/$REPO_OWNER/$REPO_NAME/pulls/$pr_number/reviews")
@@ -111,8 +155,51 @@ main() {
111155
# Fetch commits in the PR:
112156
pr_commits=$(github_api "GET" "/repos/$REPO_OWNER/$REPO_NAME/pulls/$pr_number/commits")
113157

114-
# Extract co-authors from commits:
115-
co_authors=$(echo "$pr_commits" | jq -r '.[].commit.message' | grep -Eio "Co-authored-by:.*" | sort -u)
158+
# Extract co-authors from commit messages:
159+
processed_co_authors=""
160+
while IFS= read -r co_author_line; do
161+
name_email=$(echo "$co_author_line" | sed -E 's/Co-authored-by:[[:space:]]*(.*)/\1/')
162+
name=$(echo "$name_email" | sed -E 's/^(.*)<.*>$/\1/' | xargs)
163+
email=$(echo "$name_email" | sed -E 's/^.*<(.*)>$/\1/' | xargs)
164+
resolved_author=$(resolve_name_email "$name" "$email")
165+
166+
processed_co_authors+="Co-authored-by: $resolved_author"$'\n'
167+
done <<< "$co_authors"
168+
169+
# Extract commit authors:
170+
authors_info=$(echo "$pr_commits" | jq -r '.[] | .commit.author | "\(.name) <\(.email)>"' | sort -u | sed '/^ *<.*>/d' | sed '/^$/d')
171+
172+
# Process commit authors:
173+
commit_authors=""
174+
while IFS= read -r author_line; do
175+
# Skip empty lines:
176+
if [ -z "$author_line" ]; then
177+
continue
178+
fi
179+
180+
# Extract name and email:
181+
name=$(echo "$author_line" | sed -E 's/^(.*)<.*>$/\1/' | xargs)
182+
email=$(echo "$author_line" | sed -E 's/^.*<(.*)>$/\1/' | xargs)
183+
184+
# Resolve name and email using .mailmap:
185+
resolved_author=$(resolve_name_email "$name" "$email")
186+
187+
# Skip if the resolved author matches the resolved PR author:
188+
if [ "$resolved_author" == "$pr_author_resolved" ]; then
189+
continue
190+
fi
191+
192+
commit_authors+="$resolved_author"$'\n'
193+
done <<< "$authors_info"
194+
195+
# Remove any empty lines and duplicates:
196+
commit_authors=$(echo "$commit_authors" | sort -u | sed '/^$/d')
197+
198+
# Prefix with 'Co-authored-by: ':
199+
commit_authors_formatted=$(echo "$commit_authors" | sed 's/^/Co-authored-by: /' | sort -u)
200+
201+
# Combine co-authors and commit authors:
202+
all_co_authors=$(echo -e "$co_authors\n$commit_authors_formatted" | sort -u | sed '/^$/d')
116203

117204
# Extract 'Signed-off-by' lines from commits:
118205
signed_off_bys=$(echo "$pr_commits" | jq -r '.[].commit.message' | grep -Eio 'Signed-off-by:.*' | sort -u)
@@ -124,6 +211,7 @@ main() {
124211

125212
# GitHub-supported closing keywords:
126213
closing_keywords=("close" "closes" "closed" "fix" "fixes" "fixed" "resolve" "resolves" "resolved")
214+
127215
# Create a regex pattern from the keywords:
128216
keywords_pattern=$(IFS='|'; echo "${closing_keywords[*]}")
129217

@@ -148,8 +236,8 @@ main() {
148236
commit_body+="\n$ref_issues"
149237
fi
150238
commit_body+="\n"
151-
if [ -n "$co_authors" ]; then
152-
commit_body+="\n$co_authors"
239+
if [ -n "$all_co_authors" ]; then
240+
commit_body+="\n$all_co_authors"
153241
fi
154242
for reviewer in $reviewers; do
155243
resolved_reviewer=$(resolve_user "$reviewer")

.mailmap

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ Chinmay Joshi <[email protected]> Chinmay J
3636

3737
# D
3838

39+
40+
Debashis Maharana <[email protected]> DebashisMaharana
41+
3942
4043
Dorrin Sotoudeh <[email protected]> dorrin-sot
4144

CONTRIBUTORS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Christopher Dambamuromo <[email protected]>
2121
2222
Daniel Killenberger <[email protected]>
2323
Daniel Yu <[email protected]>
24-
DebashisMaharana <[email protected].com>
24+
Debashis Maharana <debashismaharana7854@gmail.com>
2525
Dominik Moritz <[email protected]>
2626
Dorrin Sotoudeh <[email protected]>
2727
EuniceSim142 <[email protected]>

lib/node_modules/@stdlib/_tools/changelog/generate/lib/format_contributors.js

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020

2121
// MODULES //
2222

23+
var join = require( 'path' ).join;
24+
var spawn = require( 'child_process' ).spawnSync; // eslint-disable-line node/no-sync
25+
var logger = require( 'debug' );
2326
var contains = require( '@stdlib/assert/contains' );
2427
var replace = require( '@stdlib/string/replace' );
2528
var map = require( '@stdlib/utils/map' );
@@ -31,11 +34,32 @@ var EXCLUDED_CONTRIBUTORS = require( './excluded_contributors.json' );
3134

3235
// VARIABLES //
3336

37+
var debug = logger( 'changelog:generate:format-contributors' );
3438
var RE_CO_AUTHORED_BY = /co-authored-by/i;
39+
var RESOLVE_NAME_EMAIL_CMD = join( __dirname, '..', 'scripts', 'resolve_name_email.sh' );
3540

3641

3742
// FUNCTIONS //
3843

44+
/**
45+
* Resolves a Git user name and email address according to the .mailmap file.
46+
*
47+
* @private
48+
* @param {string} pair - name and email pair
49+
* @returns {string} canonical name and email address if found, otherwise the original input
50+
*/
51+
function resolveNameEmailPair( pair ) {
52+
try {
53+
debug( 'Attempting to resolve name and email: %s.', pair );
54+
return spawn( RESOLVE_NAME_EMAIL_CMD, [ pair ], {
55+
'stdio': [ 'pipe', 'pipe', 'ignore' ] // stdin, stdout, stderr
56+
}).stdout.toString();
57+
} catch ( err ) {
58+
debug( 'Encountered an error resolving name and email: %s.', err.message );
59+
return pair;
60+
}
61+
}
62+
3963
/**
4064
* Extracts a list of contributors from a list of commits.
4165
*
@@ -66,7 +90,8 @@ function extractContributors( commits ) {
6690
if (
6791
RE_CO_AUTHORED_BY.test( mention.action )
6892
) {
69-
author = replace( mention.ref, /\s*<[^>]+>\s*/, '' );
93+
author = resolveNameEmailPair( mention.ref );
94+
author = replace( author, /\s*<[^>]+>\s*/, '' );
7095
if (
7196
!contains( out, author ) &&
7297
!contains( EXCLUDED_CONTRIBUTORS, author )
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#!/usr/bin/env bash
2+
#
3+
# @license Apache-2.0
4+
#
5+
# Copyright (c) 2024 The Stdlib Authors.
6+
#
7+
# Licensed under the Apache License, Version 2.0 (the "License");
8+
# you may not use this file except in compliance with the License.
9+
# You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing, software
14+
# distributed under the License is distributed on an "AS IS" BASIS,
15+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
# See the License for the specific language governing permissions and
17+
# limitations under the License.
18+
19+
# Script for resolving a name and email using .mailmap via `git check-mailmap`.
20+
#
21+
# Usage: resolve-mailmap.sh "name <email>"
22+
#
23+
# Arguments:
24+
#
25+
# name_email The name and email pair in the format "name <email>"
26+
#
27+
28+
if [ -z "$1" ]; then
29+
echo "Error: must provide a name and email in the format \"name <email>\"." >&2
30+
exit 1
31+
fi
32+
33+
name_email="$1"
34+
35+
resolved=$(git check-mailmap "$name_email" 2>/dev/null)
36+
if [ -n "$resolved" ]; then
37+
echo "$resolved"
38+
else
39+
echo "$name_email"
40+
fi

lib/node_modules/@stdlib/array/base/cuany-by-right/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,13 @@ The function supports the following parameters:
116116
<!-- eslint no-undef: "error" -->
117117

118118
```javascript
119+
var bernoulli = require( '@stdlib/random/array/bernoulli' );
120+
var cuanyByRight = require( '@stdlib/array/base/cuany-by-right' );
121+
119122
function isPositive( value ) {
120123
return ( value > 0 );
121124
}
122125

123-
var bernoulli = require( '@stdlib/random/array/bernoulli' );
124-
var cuanyByRight = require( '@stdlib/array/base/cuany-by-right' );
125-
126126
// Create an array of random values:
127127
var x = bernoulli( 10, 0.1 );
128128
console.log( x );

lib/node_modules/@stdlib/array/base/cuany-by/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,13 @@ The function supports the following parameters:
116116
<!-- eslint no-undef: "error" -->
117117

118118
```javascript
119+
var bernoulli = require( '@stdlib/random/array/bernoulli' );
120+
var cuanyBy = require( '@stdlib/array/base/cuany-by' );
121+
119122
function isPositive( value ) {
120123
return ( value > 0 );
121124
}
122125

123-
var bernoulli = require( '@stdlib/random/array/bernoulli' );
124-
var cuanyBy = require( '@stdlib/array/base/cuany-by' );
125-
126126
// Create an array of random values:
127127
var x = bernoulli( 10, 0.1 );
128128
console.log( x );

lib/node_modules/@stdlib/array/base/cuany-by/benchmark/benchmark.assign.length.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ var bench = require( '@stdlib/bench' );
2424
var pow = require( '@stdlib/math/base/special/pow' );
2525
var isArray = require( '@stdlib/assert/is-array' );
2626
var filled = require( '@stdlib/array/base/filled' );
27-
var isPositiveInteger = require( '@stdlib/assert/is-positive-integer' );
27+
var isPositiveInteger = require( '@stdlib/assert/is-positive-integer' ).isPrimitive;
2828
var pkg = require( './../package.json' ).name;
2929
var cuanyBy = require( './../lib' );
3030

@@ -39,7 +39,7 @@ var cuanyBy = require( './../lib' );
3939
* @returns {Function} benchmark function
4040
*/
4141
function createBenchmark( len ) {
42-
var x = filled( 1.5, len );
42+
var x = filled( 0, len );
4343
return benchmark;
4444

4545
/**

lib/node_modules/@stdlib/array/base/cuany-by/benchmark/benchmark.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
var bench = require( '@stdlib/bench' );
2424
var isArray = require( '@stdlib/assert/is-array' );
25-
var isPositiveInteger = require( '@stdlib/assert/is-positive-integer' );
25+
var isPositiveInteger = require( '@stdlib/assert/is-positive-integer' ).isPrimitive;
2626
var pkg = require( './../package.json' ).name;
2727
var cuanyBy = require( './../lib' );
2828

lib/node_modules/@stdlib/array/base/cuany-by/benchmark/benchmark.length.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ var bench = require( '@stdlib/bench' );
2424
var pow = require( '@stdlib/math/base/special/pow' );
2525
var isArray = require( '@stdlib/assert/is-array' );
2626
var filled = require( '@stdlib/array/base/filled' );
27-
var isPositiveInteger = require( '@stdlib/assert/is-positive-integer' );
27+
var isPositiveInteger = require( '@stdlib/assert/is-positive-integer' ).isPrimitive;
2828
var pkg = require( '@stdlib/array/base/cuany-by/package.json' ).name;
2929
var cuanyBy = require( '@stdlib/array/base/cuany-by/lib' );
3030

0 commit comments

Comments
 (0)