Skip to content

Commit

Permalink
Merge branch 'main' into resciencec
Browse files Browse the repository at this point in the history
  • Loading branch information
xuanxu committed May 19, 2023
2 parents 7f73755 + 937107d commit 4f03e8b
Show file tree
Hide file tree
Showing 11 changed files with 113 additions and 57 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
continue-on-error: ${{ matrix.failure-allowed }}
strategy:
matrix:
ruby-version: ['2.7.7', '3.0.5', '3.1.3', '3.2.1']
ruby-version: ['2.7.8', '3.0.6', '3.1.4', '3.2.2']
failure-allowed: [false]
include:
- ruby-version: 'truffleruby'
Expand Down
2 changes: 1 addition & 1 deletion .ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.2.1
3.2.2
30 changes: 15 additions & 15 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
GEM
remote: https://rubygems.org/
specs:
addressable (2.8.1)
addressable (2.8.4)
public_suffix (>= 2.0.2, < 6.0)
bibtex-ruby (6.0.0)
latex-decode (~> 0.0)
cgi (0.3.6)
charlock_holmes (0.7.7)
chronic (0.10.2)
concurrent-ruby (1.2.2)
connection_pool (2.3.0)
connection_pool (2.4.0)
crack (0.4.5)
rexml
diff-lcs (1.5.0)
Expand Down Expand Up @@ -39,28 +39,28 @@ GEM
rugged (>= 0.24, < 2.0)
thor (>= 0.19, < 2.0)
mini_mime (1.1.2)
mini_portile2 (2.8.1)
mini_portile2 (2.8.2)
multi_json (1.15.0)
mustermann (3.0.0)
ruby2_keywords (~> 0.0.1)
nio4r (2.5.8)
nokogiri (1.14.2)
nio4r (2.5.9)
nokogiri (1.14.3)
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
octokit (6.1.0)
octokit (6.1.1)
faraday (>= 1, < 3)
sawyer (~> 0.9)
openssl (3.1.0)
public_suffix (5.0.1)
puma (6.1.1)
puma (6.2.2)
nio4r (~> 2.0)
racc (1.6.2)
rack (2.2.6.4)
rack (2.2.7)
rack-protection (3.0.5)
rack
rack-test (2.1.0)
rack (>= 1.3)
redis-client (0.14.0)
redis-client (0.14.1)
connection_pool
reverse_markdown (2.1.1)
nokogiri
Expand All @@ -69,17 +69,17 @@ GEM
rspec-core (~> 3.12.0)
rspec-expectations (~> 3.12.0)
rspec-mocks (~> 3.12.0)
rspec-core (3.12.1)
rspec-core (3.12.2)
rspec-support (~> 3.12.0)
rspec-expectations (3.12.2)
rspec-expectations (3.12.3)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
rspec-mocks (3.12.4)
rspec-mocks (3.12.5)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
rspec-support (3.12.0)
ruby2_keywords (0.0.5)
rugged (1.6.2)
rugged (1.6.3)
sawyer (0.9.2)
addressable (>= 2.3.5)
faraday (>= 0.17.3, < 3)
Expand All @@ -89,11 +89,11 @@ GEM
multi_json (~> 1.15)
rexml (~> 3.2, >= 3.2.5)
thor (~> 1.2, >= 1.2.1)
sidekiq (7.0.7)
sidekiq (7.1.0)
concurrent-ruby (< 2)
connection_pool (>= 2.3.0)
rack (>= 2.2.4)
redis-client (>= 0.11.0)
redis-client (>= 0.14.0)
sinatra (3.0.5)
mustermann (~> 3.0)
rack (~> 2.2, >= 2.2.4)
Expand Down
2 changes: 1 addition & 1 deletion app/lib/responder_registry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def self.available_responders
responder_class = Object.const_get(name)
available_responders[responder_class.key] = responder_class
rescue NameError => err
logger.warn("There is a mismatch in a Responder class name/module: #{err.message}")
Logger.new(STDOUT).warn("There is a mismatch in a Responder class name/module: #{err.message}")
end
end

Expand Down
13 changes: 7 additions & 6 deletions app/responders/reminders_responder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,20 @@ def process_message(message)

human = "@#{user_login(context.sender)}" if human == "me"

unless targets.include?(human)
unless targets.include?(human.downcase)
respond("#{human} doesn't seem to be a reviewer or author for this submission.")
return false
end

schedule_at = target_time(size, unit)

if schedule_at
if user_login(human) == user_login(context.sender)
if user_login(human).downcase == user_login(context.sender).downcase
human = "@#{user_login(context.sender)}"
msg = ":wave: #{human}, please take a look at the state of the submission (this is an automated reminder)."
AsyncMessageWorker.perform_at(schedule_at, serializable(locals), msg)
else
ReviewReminderWorker.perform_at(schedule_at, serializable(locals), human, authors_list.include?(human))
ReviewReminderWorker.perform_at(schedule_at, serializable(locals), human, authors_list.include?(human.downcase))
end
respond("Reminder set for #{human} in #{size} #{unit}")
else
Expand All @@ -38,16 +39,16 @@ def process_message(message)
end

def targets
(authors_list + reviewers_list + ["@#{user_login(context.sender)}"]).uniq
(authors_list + reviewers_list + ["@#{user_login(context.sender).downcase}"]).uniq
end

def reviewers_list
@reviewers_list ||= reviewers_value.inject([]) {|re, value| re + read_value_from_body(value).split(",").map(&:strip)}
@reviewers_list ||= reviewers_value.inject([]) {|re, value| re + read_value_from_body(value).split(",").map(&:strip).map(&:downcase)}
@reviewers_list.compact.uniq
end

def authors_list
@authors_list ||= authors_value.inject([]) {|au, value| au + read_value_from_body(value).split(",").map(&:strip)}
@authors_list ||= authors_value.inject([]) {|au, value| au + read_value_from_body(value).split(",").map(&:strip).map(&:downcase)}
@authors_list.compact.uniq
end

Expand Down
4 changes: 2 additions & 2 deletions app/responders/reviewer_checklist_comment_responder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def process_message(message)
end

def sender_in_reviewers_list?
reviewers.include?("@#{context.sender}")
reviewers.include?("@#{context.sender.downcase}")
end

def update_checklists_links
Expand All @@ -38,7 +38,7 @@ def update_checklists_links
end

def reviewers
@reviewers ||= read_value_from_body("reviewers-list").split(",").map(&:strip)
@reviewers ||= read_value_from_body("reviewers-list").split(",").map(&:strip).map(&:downcase)
end

def checklists_mapping
Expand Down
32 changes: 17 additions & 15 deletions docs/installation.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
Installation
============

Buffy works listening to events received from GitHub and deciding if/how to reply by passing the received payload to different Responders.
You can fork Buffy and configure the responders you want to use for any specific repository. There is no need for the Buffy fork to be located in the same GitHub user/organization as the repo where it will be used. To have Buffy ready and listening to events you can install it locally or deploy it to a server or service platform.
You'll need the following components:
Buffy functions by monitoring events that are sent from a GitHub repository (e.g., openjournals/joss-reviews). Based on the information in these events, Buffy determines whether and how to respond by passing the event data to different [Responders](https://api.rubyonrails.org/v4.1/classes/ActionController/Responder.html).

- A GitHub user to use as the bot with admin permissions on the target repo (usually a member of the organization owning the repo).
You can fork Buffy and configure the responders you want to use for a particular repository, and the fork doesn't necessarily
need to be hosted under the same GitHub user or organization (as the repository where it will be used). For Buffy to be operational, it must be running either through a local installation or deployment to a platform. The following components are necessary for this setup:

- A GitHub user with administrative permissions on the target repository (typically a member of the organization that owns the repository) is required to act as the bot.
- An instance of Buffy running
- A webhook configured in the GitHub repo's settings to send events to Buffy
- A webhook configured in the settings of the GitHub repository that will send events to Buffy (e.g., a `reviews` repository).

### Create the bot GitHub user

This will be the user responding to commands in the reviews repo.
This will be the "user" responding to the commands issued from a reviews repository.

**1.** [Sign up at GitHub](https://github.com/join) and create the bot user:

Expand Down Expand Up @@ -40,13 +41,13 @@ Some applications and services must be available to use by Buffy:

#### Deployment

We will use here [Heroku](https://www.heroku.com) as an example service to deploy Buffy but you can use any other server or platform.
As an example, we will use [Heroku](https://www.heroku.com) to deploy Buffy. However, any other server or platform can also be used.

**1.** Create a new app in heroku linked to the url of your fork of Buffy. Automatically Heroku will use the `heroku/ruby` buildpack.
**1.** To begin, create a new app in Heroku linked to the URL of your Buffy fork. Heroku will automatically use the `heroku/ruby` buildpack.

- To process background jobs Buffy needs `redis` installed, several add-ons providing it are available: Heroku Redis, RedisGreen, Redis To Go, etc.
- To install the `cloc` dependency there's a buildpack for Heroku available [here](https://github.com/openjournals/heroku-buildpack-cloc).
- Gitinspector can be installed [using npm](https://www.npmjs.com/package/gitinspector). To do so in Heroku, the `heroku/nodejs` buildpack can be added.
- To process background jobs, Buffy needs a `redis` add-on, such as Heroku Redis or RedisGreen etc.
- You can use [this Heroku buildpack](https://github.com/openjournals/heroku-buildpack-cloc) to install the `cloc` dependency.
- You can install Gitinspector using npm by following the instructions [here](https://www.npmjs.com/package/gitinspector). If you plan to deploy to Heroku, you can add the `heroku/nodejs` buildpack to your app.

**2.** In the app settings add the following Config Vars:

Expand All @@ -64,23 +65,24 @@ We will use here [Heroku](https://www.heroku.com) as an example service to deplo

There are detailed instructions in the Deploy section of your Heroku app.

**4.** You should now have a public URL with Buffy running. You can test that pointing your browser to `/status`, like for example: `https://your-new-buffy-deploy.herokuapp.com/status` It should return a simple *up and running* message.
**4.** At this point, you should have a public URL pointing to your new Buffy app! To confirm this, you can test it by visiting https://your-new-buffy-deploy.herokuapp.com/status. On success, you should see a basic (*up and running*) message confirming that Buffy is up and running.


### Configure a webhook to send events from GitHub to Buffy

**1.** Go to the settings page of the repository where you want to use buffy. Add a new webhook.
**1.** Navigate to the settings page of the repository that Buffy will be listening to and add a new webhook.

![Add webhook](./images/new_webhook.png "Add webhook")

**2.** Configure the new webhook with:
**2.** Set up the new webhook with the following configuration:

Payload URL: /dispatch path at your public buffy url
Content type: application/json
Secret: The BUFFY_GH_SECRET_TOKEN you configured in the previous step

Select individual events to trigger: **issue comments** and **issues**

![New webhook](./images/webhook.png "New webhook")


If everything went well you should have now your bot responding on the reviews issues. Try `@botname help` for example.
Assuming everything went smoothly, your Buffy instance should now be responding to review issues. You can test this by sending the `@botname help` command from a reviews issue to verify that the bot is functioning as expected.
39 changes: 23 additions & 16 deletions docs/responders/github_action.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
GitHub Action
=============

This responder triggers workflow run on a GitHub Action using the GitHub API. Optionally if the call is successful (not the result of the workflow run but the call to trigger it) a reply message can be posted as a comment in the issue.
This `buffy` responder dispatches an event to trigger a GitHub Action workflow in a repository, where the workflow is defined by a `.github/workflows/*.yaml` file. If desired, upon a successful event dispatch to trigger the workflow (not the outcome of the workflow run), a reply message can be posted as a comment in the (corresponding review) issue.
Allows [labeling](../labeling).

## Listens to
Expand All @@ -17,7 +17,7 @@ For example, if you configure the command to be _compile pdf_, it will respond t

## Requirements

Some parameters are required for the responder to work: the `command` to invoke it, and the `workflow_repo` and `workflow_name` values to identify the action to run. All can be set using the settings YAML file.
Some parameters are required for the responder to work: the `command` to invoke it, and the `workflow_repo` and `workflow_name` values to identify the action to run. All can be set using the respective settings YAML file (e.g., `buffy/config/settings-<environment>.yml`).

## Settings key

Expand Down Expand Up @@ -54,22 +54,29 @@ If you want to run multiple responders, use an array of these subparams.
## Examples

**A complete example:**

The following snippet sets up `buffy` to react to a `@editorialbot generate pdf` command issued during a `joss` review:

```yaml
...
github_action:
only: editors
command: compile pdf
description: Generates a PDF based on the paper.md file in the repository
workflow_repo: openjournals/reviews
workflow_name: compile-pdf.yml
inputs:
file: paper.md
data-from-issue:
- branch
- target_repository
mapping:
repository: target_repository
number: issue_id
- draft_paper:
command: generate pdf
workflow_repo: openjournals/joss-papers
workflow_name: draft-paper.yml
workflow_ref: master
description: Generates the pdf paper
data_from_issue:
- branch
- target-repository
- issue_id
mapping:
repository_url: target-repository
...
```
Once the responder is invoked it triggers the _compile-pdf.yml_ workflow on the _openjournals/reviews_ repository passing to it the _file_, _repository_, _branch_ and _number_ inputs.

Once invoked, this `github_action` responder triggers the [_draft-paper_](https://github.com/openjournals/joss-papers/blob/main/.github/workflows/draft-paper.yml) workflow on the [_openjournals/joss-papers_](https://github.com/openjournals/joss-papers) repository (see the [actions tab](https://github.com/openjournals/joss-papers/actions)).

The `data_from_issue` field lists the values of _branch_, _target-repository_, and _issue-id_ (which `buffy` fetches from a review issue body) that serve as input arguments for this action. The optional `mapping` field indicates that the value _target-repository_ is mapped to the _repository_url_ variable.

For additional use cases, please refer to the complete [`settings-production.yml`](https://github.com/openjournals/buffy/blob/joss/config/settings-production.yml) file located under the `joss` branch of `buffy`.
1 change: 1 addition & 0 deletions spec/responder_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,7 @@
end

it "should do nothing if no external service config present" do
expect(ExternalServiceWorker).to_not receive(:perform_async)
expect { @responder.process_external_service({}, {}) }.to_not change(ExternalServiceWorker.jobs, :size)
expect { @responder.process_external_service("", {}) }.to_not change(ExternalServiceWorker.jobs, :size)
expect { @responder.process_external_service(nil, {}) }.to_not change(ExternalServiceWorker.jobs, :size)
Expand Down
33 changes: 33 additions & 0 deletions spec/responders/reminders_responder_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,19 @@
@responder.process_message(msg)
end

it "should be case insensitive with the editor's GitHub handles" do
msg = "@botsci remind @eDItoR21 in 5 weeks"
@responder.match_data = @responder.event_regex.match(msg)
in_five_weeks = Chronic.parse("in 5 weeks")
expect(@responder).to receive(:target_time).with("5", "weeks").and_return(in_five_weeks)
expected_msg = ":wave: @editor21, please take a look at the state of the submission (this is an automated reminder)."
expect(AsyncMessageWorker).to receive(:perform_at).with(in_five_weeks, @responder.locals, expected_msg)
expect(ReviewReminderWorker).to_not receive(:perform_at)
expect(@responder).to receive(:respond).with("Reminder set for @editor21 in 5 weeks")

@responder.process_message(msg)
end

it "should respond success message and schedule worker run for 'me'" do
msg = "@botsci remind me in 15 days"
@responder.match_data = @responder.event_regex.match(msg)
Expand Down Expand Up @@ -88,6 +101,26 @@
expect(ReviewReminderWorker).to receive(:perform_at).with(in_four_days, @responder.locals, "@author", true)
@responder.process_message(msg)
end

it "should be case insensitive with the reviewers GitHub handles" do
msg = "@botsci remind @ReVieWEr42 in 3 weeks"
@responder.match_data = @responder.event_regex.match(msg)
expect(ReviewReminderWorker).to receive(:perform_at)
expect(@responder).to receive(:respond).with("Reminder set for @ReVieWEr42 in 3 weeks")

@responder.process_message(msg)
end

it "should be case insensitive with the authors GitHub handles" do
msg = "@botsci remind @AUTHor in 4 days"
@responder.match_data = @responder.event_regex.match(msg)

in_four_days = Chronic.parse("in 4 days")
expect(@responder).to receive(:target_time).with("4", "days").and_return(in_four_days)

expect(ReviewReminderWorker).to receive(:perform_at).with(in_four_days, @responder.locals, "@AUTHor", true)
@responder.process_message(msg)
end
end

describe "configurable targets" do
Expand Down
12 changes: 12 additions & 0 deletions spec/responders/reviewer_checklist_comment_responder_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,18 @@
@responder.process_message(@msg)
end

it "should be case insensitive for the reviewer's username" do
@responder.context[:sender] = "ReVIEwer1"

expected_locals = { issue_id: 5, issue_author: "opener", bot_name: "botsci", repo: "openjournals/buffy", sender: "ReVIEwer1" }
expected_checklist = "Checklist for @ReVIEwer1 \n[] A"

expect(@responder).to receive(:render_external_template).with("checklist.md", expected_locals).and_return(expected_checklist)
expect(@responder).to receive(:update_comment).with(111222, expected_checklist)
expect(@responder).to_not receive(:respond)
@responder.process_message(@msg)
end

it "should not add user checklist if sender is not a reviewer" do
@responder.context[:sender] = "nonreviewer"

Expand Down

0 comments on commit 4f03e8b

Please sign in to comment.