Skip to content

GitHub PR Comment notification doesn't work when source branch comes from a fork #384

@Artmorse

Description

@Artmorse

Context

I've configured an ApplicationSet with a Pull Request Generator to generate Applications on the repository PR labeled with preview. I've also configured GitHub notifications to create pr comments when the app is synced.


Everything is working fine for the PR where the source branch originates from the repository itself, but it's not working when the base branch comes from a fork.

Bug reproduction

I was able to verify that PRs coming from the fork weren’t working compared to the others by creating 2 PRs, one based on a repository branch and the second one based on a fork branch.

I was able to verify that bad behavior by triggering notifications using the command below ⬇️

kubectl exec $(kubectl get pods -l app.kubernetes.io/name=argocd-server --sort-by=.metadata.creationTimestamp -o jsonpath='{.items[0].metadata.name}') -n argocd -- argocd admin notifications template notify app-sync-succeeded my-application --recipient github:""
ArgoCD Notifications configuration 🔧
The trigger.on-sync-succeeded configuration
template.app-sync-succeeded: | message: | {{if eq .serviceType "slack"}}:white_check_mark:{{end}} Application {{.app.metadata.name}} has been successfully synced at {{.app.status.operationState.finishedAt}}. Sync operation details are available at: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}. github: repoURLPath: "{{.app.spec.source.repoURL}}" revisionPath: "{{index .app.metadata.labels \"custom.argoproj.io/head_sha\"}}" pullRequestComment: content: | :green_circle: Application **{{.app.metadata.name}}** has been successfully *synced* at {{.app.status.operationState.startedAt}}. {{- if .app.status.summary.externalURLs }} {{- range .app.status.summary.externalURLs }} :arrow_right: :globe_with_meridians: {{ . }} {{- end }} {{- else }} :warning: :globe_with_meridians: No external URLs found. {{- end }} :worm: See the details in [ArgoCD]({{.context.argocdUrl}}/applications/{{.app.metadata.name}}).
The trigger.on-sync-succeeded configuration
trigger.on-sync-succeeded: | - description: Application syncing has succeeded send: - app-sync-succeeded when: app.status.operationState != nil and app.status.operationState.phase in ['Succeeded']

Note

If the two PRs share the same branch (i.e., the same HEAD commit), you'll notice that triggering the notification on the second PR (the one with the fork branch as the source) results in the message being created on the other PR.

On the example below, the PR based on the repository branch is 1522, and the one based on the fork branch is 1355.
Image

Investigation

In the case where I've a single PR based on a fork branch.

The request on the upstream repository /repos/$YOUR_REPOSITORY_OWNER/$YOUR_REPOSITORY_NAME/commits/$YOUR_COMMIT_ID/pulls returns nothing.

Running the same request on the fork /repos/$YOUR_FORK_REPOSITORY_OWNER/$YOUR_REPOSITORY_NAME/commits/$YOUR_COMMIT_ID/pulls returns a 404. Probably because of the scope of the ArgoCD GitHub App.

🚀 The issue seems to come from the first GitHub request!
The requests return nothing but a PR based on a fork branch exists with the passed commit ID.

I tried rerunning it locally using the same GitHub App and reached the same conclusion.

# Get the installation ID
curl --request GET \
--url "https://api.github.com/app/installations" \
--header "Accept: application/vnd.github+json" \
--header "Authorization: Bearer $YOUR_BEARER" \
--header "X-GitHub-Api-Version: 2022-11-28" | jq '[.[].id]'

# Get an access token
curl --request POST --url "https://api.github.com/app/installations/$YOUR_INSTALLATION_ID/access_tokens" \
--header "Accept: application/vnd.github+json" \
--header "Authorization: Bearer $YOUR_BEARER" \
--header "X-GitHub-Api-Version: 2022-11-28" | jq '.token'

curl --request GET \
--url "https://api.github.com/repos/$YOUR_REPOSITORY_OWNER/$YOUR_REPOSITORY_NAME/commits/$YOUR_COMMIT_ID/pulls" \
--header "Accept: application/vnd.github+json" \
--header "Authorization: token $YOUR_ACCESS_TOKEN" \
--header "X-GitHub-Api-Version: 2022-11-28" | jq

Solution proposal

We could loop over all the PRs and retrieve the latest commit ID to verify if it matches our.

The big stop for this approach is the number of requests sent to GitHub.

#!/bin/bash

# === Configuration ===
GITHUB_TOKEN="$YOUR_ACCESS_TOKEN"
REPO_OWNER="$YOUR_REPOSITORY_OWNER"
REPO_NAME="$YOUR_REPOSITORY_NAME"
COMMIT_SHA="$YOUR_COMMIT_ID"

# === Script ===
API_URL="https://api.github.com"
PER_PAGE=100
PAGE=1
FOUND=0

echo "🔍 Searching PRs in $REPO_OWNER/$REPO_NAME for commit $COMMIT_SHA"

while : ; do
  PRS=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
              "$API_URL/repos/$REPO_OWNER/$REPO_NAME/pulls?state=all&per_page=$PER_PAGE&page=$PAGE")

  PR_COUNT=$(echo "$PRS" | jq length)
  if [[ "$PR_COUNT" -eq 0 ]]; then
    break
  fi

  for pr_number in $(echo "$PRS" | jq -r '.[].number'); do
    echo "🔄 Checking PR #$pr_number"

    COMMITS=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
                   "$API_URL/repos/$REPO_OWNER/$REPO_NAME/pulls/$pr_number/commits")

    if echo "$COMMITS" | jq -r '.[-1].sha' | grep -q "$COMMIT_SHA"; then
      echo "✅ Found commit $COMMIT_SHA in PR #$pr_number"
      FOUND=1
    fi
  done

  ((PAGE++))
done

if [[ "$FOUND" -eq 0 ]]; then
  echo "❌ No PR found containing commit $COMMIT_SHA"
fi

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions