Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update check-cla to customize which CLA repo to use #91

Merged
merged 30 commits into from
Apr 27, 2023
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
ee9d811
Update check-cla to customize which CLA repo
kenodegard Apr 3, 2023
ec9f0b4
Adds set-commit-status action
kenodegard Apr 4, 2023
a3dded4
Update READMEs and descriptions
kenodegard Apr 4, 2023
6c83ecc
Use JavaScript, not TypeScript
kenodegard Apr 4, 2023
2b2d732
Don't need to authenticate Octokit object
kenodegard Apr 4, 2023
5361102
Remove redundant debug statements
kenodegard Apr 4, 2023
528c212
Dumb JS split
kenodegard Apr 4, 2023
83dab52
Flatten await and keep try-catch simple
kenodegard Apr 4, 2023
b3b9940
Set author/committer and delete branch on merge
kenodegard Apr 4, 2023
1542cb4
debugging
kenodegard Apr 4, 2023
261fc09
Remove unused sha and labels
kenodegard Apr 5, 2023
1928626
Update ids
kenodegard Apr 5, 2023
00ae91f
Allow custom author/committer
kenodegard Apr 5, 2023
8eee82e
Fix json formatting, update PR url
kenodegard Apr 5, 2023
4729d17
Fix inputs
kenodegard Apr 5, 2023
b2db323
Fallback sha
kenodegard Apr 5, 2023
9bdcc51
debugging comment payload
kenodegard Apr 5, 2023
43ec963
Remove temporary raw const
kenodegard Apr 5, 2023
d8454ec
Optional react to comment
kenodegard Apr 5, 2023
8ee0ba0
Add token to reaction
kenodegard Apr 5, 2023
5ab5369
Replace rocket with eyes
kenodegard Apr 5, 2023
ebb06e5
Reduce noise
kenodegard Apr 5, 2023
a4ac617
Include classic PAT instructions
kenodegard Apr 5, 2023
4f67ffb
GFM
kenodegard Apr 5, 2023
d66d4eb
Extract PR number for sticky comment
kenodegard Apr 5, 2023
71c4f55
Support both PRs and "issues"
kenodegard Apr 5, 2023
6146699
Extract metadata whether triggered as a PR or "issue" comment
kenodegard Apr 5, 2023
5616a98
Group metadata steps
kenodegard Apr 5, 2023
3c9f741
Update comments and step names
kenodegard Apr 5, 2023
ae8e19e
Use correct url
kenodegard Apr 5, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 28 additions & 16 deletions check-cla/README.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,55 @@
# Check CLA (Contributor License Agreement)

This is a custom GitHub action to be used in the conda GitHub organization
for checking the conda contributor license agreement.
A custom GitHub action to be used in the conda GitHub organization for checking the
conda contributor license agreement.

## GitHub Action Usage

In your GitHub repository include the action in your workflows:

```yaml
name: Contributor license agreement (CLA)
name: Check CLA

on:
issue_comment:
types:
- created
pull_request_target:
types:
- reopened
- opened
- synchronize
jezdez marked this conversation as resolved.
Show resolved Hide resolved

jobs:
check:
if: >-
!github.event.repository.fork
&& (
(
github.event.comment.body == '@conda-bot check'
&& github.event.issue.pull_request
|| github.event_name == 'pull_request_target'
)
runs-on: ubuntu-latest
steps:
- name: Check CLA
uses: conda/actions/check-cla
- uses: conda/actions/check-cla
with:
# [required]
# label to add when actor has signed the CLA
label: cla-signed
# A token with ability to comment, label, and modify the commit status
# (`pull_request: write` and `statuses: write`)
# (default: secrets.GITHUB_TOKEN)
token:
# [required]
# Label to apply to contributor's PR once CLA is singed
label:

# Upstream repository in which to create PR
# (default: conda/infrastructure)
cla_repo:
# Path to the CLA signees file within the provided `cla_repo`
# (default: .clabot)
cla_path:

# Fork of cla_repo in which to create branch
# (default: conda-bot/infrastructure)
cla_fork:
# [required]
# the GitHub Personal Access Token to comment and label with
token: ${{ secrets.CLA_ACTION_TOKEN }}
# Token for opening singee PR in the provided `cla_repo`
cla_token:
# Git-format author/committer to use for pull request commits
# (default: Conda Bot <[email protected]>)
cla_author:
```
181 changes: 103 additions & 78 deletions check-cla/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,161 +3,186 @@ name: CLA check
description: Reacts to new PRs and check if the contributor has previously signed the conda contributor license agreement (CLA).
inputs:
token:
description: Token for commenting and labeling on contributor's PR
required: true
infrastructure_token:
description: Token for opening singee PR in conda/infrastructure
description: 'A token with ability to comment, label, and modify the commit status (`pull_request: write` and `statuses: write`)'
default: ${{ github.token }}
required: true
label:
description: Label to apply to contributor's PR once CLA is singed
required: true
cla_repo:
description: Upstream repository in which to create PR
default: conda/infrastructure
cla_path:
description: Path to the CLA signees file within the provided `cla_repo`
default: .clabot
cla_fork:
description: Fork of `cla_repo` in which to create branch
default: conda-bot/infrastructure
cla_token:
description: Token for opening singee PR in `cla_fork`
required: true
cla_author:
description: Git-format author/committer to use for pull request commits
default: Conda Bot <[email protected]>

runs:
using: composite
steps:
- name: Get PR metadata
id: pr
# if triggered by a comment, leave a reaction
- name: Comment Reaction
uses: peter-evans/[email protected]
if: github.event_name == 'issue_comment'
with:
token: ${{ inputs.token }}
comment-id: ${{ github.event.comment.id }}
reactions: eyes
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaves a reaction on the @conda-bot check so we know the workflow is running (otherwise theres no indication the bot is working on it)


# has_label
- name: Get PR labels
id: labels
uses: actions/github-script@v6
with:
script: |
const { owner, repo, number } = context.issue;
const pullRequest = await github.rest.pulls.get({
owner,
repo,
pull_number: number,
core.debug(`owner: ${owner}`);
core.debug(`repo: ${repo}`);
core.debug(`number: ${number}`);

const raw = await github.rest.pulls.get({
owner: owner,
repo: repo,
pull_number: number
});
console.log(pullRequest);
const sha = pullRequest.data.head.sha;
console.log(sha);
core.setOutput('sha', sha);

const labels = pullRequest.data.labels.map(label => label.name)
console.log(labels);
core.setOutput('labels', labels);
const labels = raw.data.labels.map(label => label.name)
core.debug(`labels: ${labels}`);

const hasLabel = labels.includes('${{ inputs.label }}')
console.log(hasLabel);
core.setOutput('hasLabel', hasLabel);
const has_label = labels.includes('${{ inputs.label }}')
core.setOutput('has_label', has_label);
core.debug(`has_label: ${has_label}`);
kenodegard marked this conversation as resolved.
Show resolved Hide resolved

# commit status → pending
- name: Set commit status with pending
uses: dholth/github-status-action@runs-using-node16
uses: conda/actions/set-commit-status@customize-cla-repo
with:
authToken: ${{ inputs.token }}
token: ${{ inputs.token }}
context: CLA check
description: Checking conda CLA...
state: pending
sha: ${{ steps.pr.outputs.sha || github.sha }}
description: Checking conda CLA...

# has_signed
- name: Check if current actor has signed
uses: actions/github-script@v6
id: contributors
with:
github-token: ${{ inputs.token }}
script: |
console.log(context);
const getContributors = async () => {
try {
const results = (
await github.rest.repos.getContent({
owner: 'conda',
repo: 'infrastructure',
path: '.clabot'
})
);
return JSON.parse(Buffer.from(results.data.content, results.data.encoding).toString('utf-8')).contributors;
} catch (err) {
core.error(`Could not retrieve contributors, returning undefined. Reason: ${err}`)
return undefined;
}
}
const contributors = await getContributors();
console.log(contributors);
const pull_request = (context.payload.issue || context.payload.pull_request || context.payload);
const creator = pull_request.user.login;
console.log(creator);
const hasSigned = contributors.includes(creator);
console.log(hasSigned);
core.setOutput('contributors', contributors);
core.setOutput('hasSigned', hasSigned);
const { owner, repo } = context.issue;
core.debug(`owner: ${owner}`);
core.debug(`repo: ${repo}`);

const { content, encoding } = (await github.rest.repos.getContent({
owner: owner,
repo: repo,
path: '${{ inputs.cla_path }}'
})).data;
const contributors = JSON.parse(
Buffer.from(content, encoding).toString('utf-8')
).contributors;
core.debug(`contributors: ${contributors}`);

const creator = (
context.payload.issue
|| context.payload.pull_request
|| context.payload
).user.login;
core.debug(`creator: ${creator}`);

const has_signed = contributors.includes(creator);
core.setOutput('has_signed', has_signed);
core.debug(`has_signed: ${has_signed}`);

kenodegard marked this conversation as resolved.
Show resolved Hide resolved
# add [cla-signed] label if actor has already signed
- name: Add label
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add this to a separate javascript file? This is started to get long enough to warrant that, imo.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Specifying these JS blocks in separate files requires:

steps:
  - uses: actions/checkout@v3
  - uses: actions/github-script@v6
    with:
      script: |
        const script = require('./path/to/script.js')
        await script({github, context, core})

My problem with this is the checkout step which will make it harder to version our actions.

There's an open request for something better: actions/github-script#326

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a common pattern for actions to include all JS inlined, even if it's not great, let's follow that for now

uses: actions-ecosystem/[email protected]
if: steps.contributors.outputs.hasSigned == 'true' && steps.pr.outputs.hasLabel == 'false'
if: steps.contributors.outputs.has_signed == 'true' && steps.labels.outputs.has_label == 'false'
with:
github_token: ${{ inputs.token }}
labels: ${{ inputs.label }}

# remove [cla-signed] label if actor has not signed yet
- name: Remove label
uses: actions-ecosystem/[email protected]
if: steps.contributors.outputs.hasSigned == 'false' && steps.pr.outputs.hasLabel == 'true'
if: steps.contributors.outputs.has_signed == 'false' && steps.labels.outputs.has_label == 'true'
with:
github_token: ${{ inputs.token }}
labels: ${{ inputs.label }}

# checkout conda/infrastructure to update .clabot
# checkout cla_repo to update cla_path
- uses: actions/checkout@v3
if: steps.contributors.outputs.hasSigned == 'false'
if: steps.contributors.outputs.has_signed == 'false'
with:
repository: conda/infrastructure
repository: ${{ inputs.cla_repo }}

# update .clabot
# update cla_path
- shell: python
if: steps.contributors.outputs.hasSigned == 'false'
if: steps.contributors.outputs.has_signed == 'false'
run: |
import json
from pathlib import Path

path = Path(".clabot")
clabot = json.loads(path.read_text())
clabot["contributors"].append("${{ github.actor }}")
clabot["contributors"].sort()
path.write_text(json.dumps(clabot))
path = Path("${{ inputs.cla_path }}")
signees = json.loads(path.read_text())
signees["contributors"].append("${{ github.actor }}")
signees["contributors"].sort()
path.write_text(json.dumps(signees, indent=2))

# create PR
- uses: peter-evans/create-pull-request@v4
id: cla-pr
if: steps.contributors.outputs.hasSigned == 'false'
id: pull
if: steps.contributors.outputs.has_signed == 'false'
with:
token: ${{ inputs.infrastructure_token }}
push-to-fork: ${{ inputs.cla_fork }}
token: ${{ inputs.cla_token }}
branch: cla-${{ github.actor }}
delete-branch: true
commit-message: Adding CLA singee ${{ github.actor }}
author: ${{ inputs.cla_author }}
committer: ${{ inputs.cla_author }}
title: Adding CLA singee ${{ github.actor }}
body: |
Adding CLA signee @${{ github.actor }}

Xref ${{ github.event.pull_request.url }}
Xref ${{ github.event.pull_request.html_url }}

# create sticky comment if not signed
- name: Create comment
uses: marocchino/sticky-pull-request-comment@v2
if: steps.contributors.outputs.hasSigned == 'false'
if: steps.contributors.outputs.has_signed == 'false'
with:
number: context.issue.number
message: |
We require contributors to sign our [Contributor License Agreement](https://conda.io/en/latest/contributing.html#conda-contributor-license-agreement) and we don't have one on file for @${{ github.event.pull_request.user.login }}.

In order for us to review and merge your code, please e-sign the [Contributor License Agreement PDF](https://conda.io/en/latest/contributing.html#conda-contributor-license-agreement). We then need to manually verify your signature, merge the PR (${{ steps.cla-pr.outputs.pull-request-url }}), and ping the bot to refresh the PR.
In order for us to review and merge your code, please e-sign the [Contributor License Agreement PDF](https://conda.io/en/latest/contributing.html#conda-contributor-license-agreement). We then need to manually verify your signature, merge the PR (${{ steps.pull.outputs.pull-request-url }}), and ping the bot to refresh the PR.
GITHUB_TOKEN: ${{ inputs.token }}

# commit status → error
- name: Set commit status to error
if: steps.contributors.outputs.hasSigned == 'false'
uses: dholth/github-status-action@runs-using-node16
if: steps.contributors.outputs.has_signed == 'false'
uses: conda/actions/set-commit-status@customize-cla-repo
with:
authToken: ${{ inputs.token }}
token: ${{ inputs.token }}
context: CLA check
description: Please follow the details link to sign the conda CLA. →
state: error
sha: ${{ steps.pr.outputs.sha || github.sha }}
description: Please follow the details link to sign the conda CLA. →
target_url: https://conda.io/en/latest/contributing.html#conda-contributor-license-agreement

# commit status → success
- name: Set commit status to success
if: steps.contributors.outputs.hasSigned == 'true'
uses: dholth/github-status-action@runs-using-node16
if: steps.contributors.outputs.has_signed == 'true'
uses: conda/actions/set-commit-status@customize-cla-repo
with:
authToken: ${{ inputs.token }}
token: ${{ inputs.token }}
context: CLA check
description: CLA signed, thank you!
state: success
sha: ${{ steps.pr.outputs.sha || github.sha }}
description: CLA signed, thank you!
42 changes: 42 additions & 0 deletions set-commit-status/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Set Commit Status

A custom GitHub action to be used in the conda GitHub organization to set a commit
status.

## GitHub Action Usage

In your GitHub repository include the action in your workflows:

```yaml
name: Set Commit Status

on: pull_request_target

jobs:
pending:
# need write access for statuses to succeed
permissions:
statuses: write

steps:
- uses: conda/actions/set-commit-status
with:
# [required]
# A token with the ability to modify the commit status
# (`statuses: write`)
# (default: secrets.GITHUB_TOKEN)
token:

# [required]
# The name of the commit status
context:
# [required]
# The commit status to set; either success, error, failure, or pending
state:

# A short text explaining the commit status
# (default: '')
description:
# URL/URI linking to further details
target_url:
```
Loading