@sentry/junior-github 0.92.0 → 0.92.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +120 -20
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -910,10 +910,39 @@ function actorEmail(actor) {
910
910
  const email = cleanIdentityPart(actor?.email);
911
911
  return /^[^\s@<>]+@[^\s@<>]+\.[^\s@<>]+$/.test(email) ? email : void 0;
912
912
  }
913
- function isGitCommitCommand(command) {
914
- return /(?:^|[\s;|&])git(?:\s+(?:-C\s+\S+|-c\s+\S+|--git-dir(?:=\S+|\s+\S+)|--work-tree(?:=\S+|\s+\S+)|--namespace(?:=\S+|\s+\S+)))*\s+commit(?:\s|$)/.test(
915
- command
916
- );
913
+ function actorIdentityKey(actor) {
914
+ if (actor.platform === "system") {
915
+ return `system ${actor.name}`;
916
+ }
917
+ return actor.platform === "slack" ? `slack ${actor.teamId} ${actor.userId}` : `${actor.platform} ${actor.userId}`;
918
+ }
919
+ function additionalActorCoauthorTrailers(args) {
920
+ if (!args.actors || args.actors.length === 0) {
921
+ return [];
922
+ }
923
+ const runActorKey = args.runActor ? actorIdentityKey(args.runActor) : void 0;
924
+ const seenEmails = /* @__PURE__ */ new Set([args.botEmail.toLowerCase()]);
925
+ if (args.authorEmail) {
926
+ seenEmails.add(args.authorEmail.toLowerCase());
927
+ }
928
+ const trailers = [];
929
+ for (const candidate of args.actors) {
930
+ if (runActorKey && actorIdentityKey(candidate) === runActorKey) {
931
+ continue;
932
+ }
933
+ const name = actorName(candidate);
934
+ const email = actorEmail(candidate);
935
+ if (!name || !email) {
936
+ continue;
937
+ }
938
+ const emailKey = email.toLowerCase();
939
+ if (seenEmails.has(emailKey)) {
940
+ continue;
941
+ }
942
+ seenEmails.add(emailKey);
943
+ trailers.push(`Co-Authored-By: ${name} <${email}>`);
944
+ }
945
+ return trailers;
917
946
  }
918
947
  function prepareCommitMsgHook() {
919
948
  return `#!/usr/bin/env bash
@@ -939,12 +968,86 @@ if [ -z "\${JUNIOR_GIT_COAUTHOR_NAME:-}" ] || [ -z "\${JUNIOR_GIT_COAUTHOR_EMAIL
939
968
  exit 1
940
969
  fi
941
970
 
942
- trailer="Co-Authored-By: $JUNIOR_GIT_COAUTHOR_NAME <$JUNIOR_GIT_COAUTHOR_EMAIL>"
943
- if grep -Fqx "$trailer" "$message_file"; then
971
+ # Git and GitHub only interpret the final contiguous paragraph as the trailer
972
+ # block, so all missing trailers are collected and appended as one block:
973
+ # actor trailers in order, Junior's agent trailer last.
974
+ desired_trailers=""
975
+ add_trailer() {
976
+ desired_trailers="$desired_trailers$1"$'\\n'
977
+ }
978
+
979
+ if [ -n "\${JUNIOR_GIT_ACTOR_COAUTHOR_TRAILERS:-}" ]; then
980
+ while IFS= read -r actor_trailer; do
981
+ if [ -n "$actor_trailer" ]; then
982
+ add_trailer "$actor_trailer"
983
+ fi
984
+ done <<< "$JUNIOR_GIT_ACTOR_COAUTHOR_TRAILERS"
985
+ fi
986
+
987
+ add_trailer "Co-Authored-By: $JUNIOR_GIT_COAUTHOR_NAME <$JUNIOR_GIT_COAUTHOR_EMAIL>"
988
+
989
+ final_trailer_block=$(awk '
990
+ { lines[NR] = $0 }
991
+ END {
992
+ line = NR
993
+ while (line > 0 && lines[line] == "") {
994
+ line--
995
+ }
996
+ if (line == 0) {
997
+ exit 0
998
+ }
999
+ start = line
1000
+ while (start > 0 && lines[start] != "") {
1001
+ start--
1002
+ }
1003
+ for (i = start + 1; i <= line; i++) {
1004
+ if (lines[i] !~ /^[[:alnum:]-]+: .+/) {
1005
+ exit 0
1006
+ }
1007
+ }
1008
+ for (i = start + 1; i <= line; i++) {
1009
+ print lines[i]
1010
+ }
1011
+ }
1012
+ ' "$message_file")
1013
+
1014
+ missing_trailers=""
1015
+ collect_missing_trailer() {
1016
+ if ! printf '%s\\n' "$final_trailer_block" | grep -Fqx -- "$1"; then
1017
+ missing_trailers="\${missing_trailers}\${1}"$'\\n'
1018
+ fi
1019
+ }
1020
+
1021
+ while IFS= read -r desired_trailer; do
1022
+ if [ -n "$desired_trailer" ]; then
1023
+ collect_missing_trailer "$desired_trailer"
1024
+ fi
1025
+ done <<< "$desired_trailers"
1026
+
1027
+ if [ -z "$missing_trailers" ]; then
944
1028
  exit 0
945
1029
  fi
946
1030
 
947
- printf '\\n%s\\n' "$trailer" >> "$message_file"
1031
+ if [ -n "$(tail -c 1 "$message_file")" ]; then
1032
+ printf '\\n' >> "$message_file"
1033
+ fi
1034
+
1035
+ # When the message already ends with Junior's bot trailer, insert missing
1036
+ # actor trailers before it so the bot trailer stays last.
1037
+ last_line=$(tail -n 1 "$message_file")
1038
+ bot_trailer="Co-Authored-By: $JUNIOR_GIT_COAUTHOR_NAME <$JUNIOR_GIT_COAUTHOR_EMAIL>"
1039
+ if [ "$last_line" = "$bot_trailer" ]; then
1040
+ tmp_file=$(mktemp)
1041
+ trap 'rm -f "$tmp_file"' EXIT
1042
+ sed '$d' "$message_file" > "$tmp_file"
1043
+ printf '%s' "$missing_trailers" >> "$tmp_file"
1044
+ printf '%s\\n' "$bot_trailer" >> "$tmp_file"
1045
+ cat "$tmp_file" > "$message_file"
1046
+ elif [ -n "$final_trailer_block" ]; then
1047
+ printf '%s' "$missing_trailers" >> "$message_file"
1048
+ else
1049
+ printf '\\n%s' "$missing_trailers" >> "$message_file"
1050
+ fi
948
1051
  `;
949
1052
  }
950
1053
  async function configureGit(ctx, key, value) {
@@ -1825,26 +1928,13 @@ function githubPlugin(options = {}) {
1825
1928
  if (ctx.tool.name !== "bash") {
1826
1929
  return;
1827
1930
  }
1828
- const command = typeof ctx.tool.input === "object" && ctx.tool.input && "command" in ctx.tool.input ? String(ctx.tool.input.command ?? "") : "";
1829
1931
  const botName = readEnv(botNameEnv);
1830
1932
  const botEmail = readEnv(botEmailEnv);
1831
- if ((!botName || !botEmail) && isGitCommitCommand(command)) {
1832
- ctx.decision.deny(
1833
- `Junior GitHub plugin is misconfigured: host env vars ${botNameEnv} and ${botEmailEnv} are missing. This is an internal deployment configuration error; do not set them in the sandbox.`
1834
- );
1835
- return;
1836
- }
1837
1933
  if (!botName || !botEmail) {
1838
1934
  return;
1839
1935
  }
1840
1936
  const authorName = actorName(ctx.actor);
1841
1937
  const authorEmail = actorEmail(ctx.actor);
1842
- if ((!authorName || !authorEmail) && isGitCommitCommand(command)) {
1843
- ctx.decision.deny(
1844
- "Junior GitHub plugin could not determine a resolved actor name and email for commit attribution. This is an internal request-context error; do not set author env vars manually."
1845
- );
1846
- return;
1847
- }
1848
1938
  if (authorName && authorEmail) {
1849
1939
  ctx.env.set("GIT_AUTHOR_NAME", authorName);
1850
1940
  ctx.env.set("GIT_AUTHOR_EMAIL", authorEmail);
@@ -1855,6 +1945,16 @@ function githubPlugin(options = {}) {
1855
1945
  ctx.env.set("GIT_COMMITTER_EMAIL", botEmail);
1856
1946
  ctx.env.set("JUNIOR_GIT_COAUTHOR_NAME", botName);
1857
1947
  ctx.env.set("JUNIOR_GIT_COAUTHOR_EMAIL", botEmail);
1948
+ const actorTrailers = additionalActorCoauthorTrailers({
1949
+ actors: ctx.actors,
1950
+ authorEmail,
1951
+ botEmail,
1952
+ runActor: ctx.actor
1953
+ });
1954
+ ctx.env.set(
1955
+ "JUNIOR_GIT_ACTOR_COAUTHOR_TRAILERS",
1956
+ actorTrailers.join("\n")
1957
+ );
1858
1958
  },
1859
1959
  grantForEgress(ctx) {
1860
1960
  return githubGrantForEgress(ctx);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/junior-github",
3
- "version": "0.92.0",
3
+ "version": "0.92.1",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -25,7 +25,7 @@
25
25
  "dependencies": {
26
26
  "@sinclair/typebox": "^0.34.49",
27
27
  "zod": "^4.4.3",
28
- "@sentry/junior-plugin-api": "0.92.0"
28
+ "@sentry/junior-plugin-api": "0.92.1"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@types/node": "^25.9.1",