diff --git a/action.yml b/action.yml index e0f24e6..5cd4d37 100644 --- a/action.yml +++ b/action.yml @@ -2,13 +2,25 @@ name: Sponsor Labeler author: Daniel Cazzulino description: | A GitHub Action that labels issues and pull requests if - the creator is a sponsor. + the creator is a sponsor (directly or indirectly via org or contributions). inputs: label: - description: The label to apply to the issue or pull request. Defaults to "sponsor 💜". + description: The default sponsor label to apply to the issue or pull request. Defaults to "sponsor 💜". required: false default: 'sponsor 💜' + contrib-label: + description: The label to apply to the issue or pull request for past contributors. Defaults to "sponsor 💚". + required: false + default: 'sponsor 💚' + silver-label: + description: The label to apply when sponsor amount is above the silver-amount. Defaults to "sponsor 🤍". + required: false + default: 'sponsor 🤍' + silver-amount: + description: Sponsors over this amount are labeled with silver-label instead. Defaults to 50. + required: false + default: 50 gold-label: description: The label to apply when sponsor amount is above the gold-amount. Defaults to "sponsor 💛". required: false @@ -39,11 +51,14 @@ runs: - run: echo "${{ github.action_path }}" >> $GITHUB_PATH shell: bash - name: 💜 sponsor - if: ${{ !endsWith(github.event.sender.login, '[bot]') }} + if: ${{ !endsWith(github.event.sender.login, '[bot]') && github.event.sender.login != inputs.sponsorable }} shell: pwsh env: SPONSORABLE: ${{ inputs.sponsorable }} SPONSOR_LABEL: ${{ inputs.label }} + SPONSOR_CONTRIB_LABEL: ${{ inputs.contrib-label }} + SPONSOR_SILVER_LABEL: ${{ inputs.silver-label }} + SPONSOR_SILVER_AMOUNT: ${{ inputs.silver-amount }} SPONSOR_GOLD_LABEL: ${{ inputs.gold-label }} SPONSOR_GOLD_AMOUNT: ${{ inputs.gold-amount }} SPONSOR_SENDER_LOGIN: ${{ github.event.sender.login }} diff --git a/sponsor-labeler.ps1 b/sponsor-labeler.ps1 index 463b5f7..821dd26 100644 --- a/sponsor-labeler.ps1 +++ b/sponsor-labeler.ps1 @@ -1,6 +1,56 @@ $verbose = [bool]::Parse($env:SPONSOR_VERBOSE ?? "false") -$query = gh api graphql --paginate -f owner=$env:SPONSORABLE -f query=' +# ensure labels exist +gh label create "$env:SPONSOR_LABEL" -c '#D4C5F9' -d 'Sponsor' || & { $global:LASTEXITCODE=0 } +gh label create "$env:SPONSOR_CONTRIB_LABEL" -c '#BFFFD3' -d 'Sponsor via contributions' || & { $global:LASTEXITCODE=0 } +gh label create "$env:SPONSOR_SILVER_LABEL" -c '#C0C0C0' -d 'Silver Sponsor' || & { $global:LASTEXITCODE=0 } +gh label create "$env:SPONSOR_GOLD_LABEL" -c '#FEF2C0' -d 'Gold Sponsor' || & { $global:LASTEXITCODE=0 } + +$team = gh api graphql -f query=' +query { + viewer { + organizations(first: 100) { + nodes { + login + isVerified + email + websiteUrl + } + } + } +}' --jq "[.data.viewer.organizations.nodes.[] | select(.login == `"$env:SPONSORABLE`")]" || $(throw "Failed to query GH GraphQL API") + +if ($team -ne $null) { + Write-Output "User $env:SPONSOR_SENDER_LOGIN belongs to the $env:SPONSORABLE organization." + return +} + +$owners = gh api graphql --paginate -f login=$env:SPONSOR_SENDER_LOGIN -f query=' +query($login: String!, $endCursor: String) { + user(login: $login) { + repositoriesContributedTo(first: 5, includeUserRepositories: true, contributionTypes: [COMMIT], after: $endCursor) { + nodes { + nameWithOwner, + owner { + login + } + } + pageInfo { + hasNextPage + endCursor + } + } + } +}' --jq '[.data.user.repositoriesContributedTo.nodes.[].owner.login]' | jq -s 'flatten | unique' || $(throw "Failed to query GH GraphQL API") + +if (($owners | jq ".[] | select(. == `"$env:SPONSORABLE`")") -ne $null) { + Write-Output "User $env:SPONSOR_SENDER_LOGIN is considered an implicit sponsor as a former contributor to the organization." + Write-Output "Adding $env:SPONSOR_CONTRIB_LABEL label to #$env:SPONSOR_ISSUE." + gh issue edit $env:SPONSOR_ISSUE --add-label "$env:SPONSOR_CONTRIB_LABEL" + return +} + +$sponsor = gh api graphql --paginate -f owner=$env:SPONSORABLE -f query=' query($owner: String!, $endCursor: String) { organization (login: $owner) { sponsorshipsAsMaintainer (first: 100, after: $endCursor) { @@ -15,16 +65,10 @@ query($owner: String!, $endCursor: String) { } } } -' || $(throw "Failed to query GH GraphQL API") - -$sponsor = $query | - ConvertFrom-Json | - select @{ Name='nodes'; Expression={$_.data.organization.sponsorshipsAsMaintainer.nodes}} | - select -ExpandProperty nodes | - where { $_.sponsorEntity.id -eq $env:SPONSOR_SENDER_ID } - +' --jq ".data.organization.sponsorshipsAsMaintainer.nodes | map(select(.sponsorEntity.id == `"$env:SPONSOR_SENDER_ID`")) | .[]" || $(throw "Failed to query GH GraphQL API") + if ($sponsor -ne $null) { - $amount = select -ExpandProperty tier | select -ExpandProperty monthlyPriceInDollars + $amount = $sponsor | jq '.tier.monthlyPriceInDollars' if ($amount -eq $null) { # We have a sponsor, but we might not be able to get the tier amount if token # isn't owner of the sponsorable. Asume regular sponsors in that case. @@ -35,7 +79,7 @@ if ($sponsor -ne $null) { if ($null -eq $amount) { # Try again with the organizations the user belongs to. - $user = gh api graphql --paginate -f user=$env:SPONSOR_SENDER_LOGIN -f query=' + $userorgs = gh api graphql --paginate -f user=$env:SPONSOR_SENDER_LOGIN -f query=' query ($user: String!, $endCursor: String) { user(login: $user) { organizations(first: 100, after: $endCursor) { @@ -43,13 +87,7 @@ query ($user: String!, $endCursor: String) { } } } -' || $(throw "Failed to query GH GraphQL API") - - $userorgs = $user | - ConvertFrom-Json | - select @{ Name='nodes'; Expression={$_.data.user.organizations.nodes}} | - select -ExpandProperty nodes | - select -ExpandProperty id +' --jq '[.data.user.organizations.nodes.[].id]' || $(throw "Failed to query GH GraphQL API") $orgs = gh api graphql --paginate -f owner=$env:SPONSORABLE -f query=' query($owner: String!, $endCursor: String) { @@ -65,21 +103,15 @@ query ($user: String!, $endCursor: String) { } } } - ' || $(throw "Failed to query GH GraphQL API") + ' --jq '[.data.organization.sponsorshipsAsMaintainer.nodes[] | select(.sponsorEntity | has("id"))]' || $(throw "Failed to query GH GraphQL API") - $sponsor = $orgs | - ConvertFrom-Json | - select @{ Name='nodes'; Expression={$_.data.organization.sponsorshipsAsMaintainer.nodes}} | - select -ExpandProperty nodes | - where { $_.sponsorEntity.id -in $userorgs } + $sponsors = $orgs | jq "[.[] | select(.sponsorEntity.id as `$id | $userorgs | index(`$id))]" - if ($sponsor -ne $null) { - $amount = select -ExpandProperty tier | - sort-object -Property monthlyPriceInDollars -Descending | - select -ExpandProperty monthlyPriceInDollars -First 1 + if (($sponsors | convertfrom-json | measure).count -ne 0) { + $amount = $sponsors | jq '[.[] | .tier.monthlyPriceInDollars | select(. != null)] | sort' | select -last 1 if ($amount -eq $null) { - # We have a sponsor, but we might not be able to get the tier amount if token + # We have at least one sponsor, but we might not be able to get the tier amount if token # isn't owner of the sponsorable. Asume regular sponsors in that case. $amount = 1 Write-Warning "Sponsor tier couldn't be read. Make sure token belongs to an owner of $env:SPONSORABLE." @@ -112,12 +144,19 @@ query ($user: String!, $endCursor: String) { Write-Output "User $env:SPONSOR_SENDER_LOGIN is a direct sponsor of $env:SPONSORABLE." } -# ensure labels exist -gh label create "$env:SPONSOR_GOLD_LABEL" -c '#FEF2C0' -d 'Gold Sponsor' || & { $global:LASTEXITCODE=0 } -gh label create "$env:SPONSOR_LABEL" -c '#D4C5F9' -d 'Sponsor' || & { $global:LASTEXITCODE=0 } + $gold = [int]$env:SPONSOR_GOLD_AMOUNT -$label = if ([int]$amount -ge $gold) { $env:SPONSOR_GOLD_LABEL } else { $env:SPONSOR_LABEL } +$silver = [int]$env:SPONSOR_SILVER_AMOUNT +$label = if ([int]$amount -ge $gold) { + $env:SPONSOR_GOLD_LABEL + } else { + if ([int]$amount -ge $silver) { + $env:SPONSOR_SILVER_LABEL + } else { + $env:SPONSOR_LABEL + } + } Write-Output "Adding $label label to #$env:SPONSOR_ISSUE." gh issue edit $env:SPONSOR_ISSUE --add-label "$label" \ No newline at end of file