Skip to content

Commit

Permalink
Merge branch 'main' into ropensci
Browse files Browse the repository at this point in the history
  • Loading branch information
xuanxu committed Dec 10, 2021
2 parents d32def2 + 01f28c7 commit 70e376f
Show file tree
Hide file tree
Showing 20 changed files with 216 additions and 24 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.4', '3.0.2']
ruby-version: ['2.7.5', '3.0.3']
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.0.2
3.0.3
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
source 'https://rubygems.org'

if ENV["CUSTOM_RUBY_VERSION"]
ruby ENV["CUSTOM_RUBY_VERSION"]
end

gem 'octokit'
gem 'sinatra', '2.1.0'
gem 'sinatra-contrib', '2.1.0'
Expand Down
23 changes: 22 additions & 1 deletion app/lib/github.rb
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,21 @@ def team_id(org_team_name)
end
end

# Uses the GitHub API to get a list of users in a team
def team_members(team_id_or_name)
case team_id_or_name
when Integer
team = team_id_or_name
when String
team = team_id(team_id_or_name)
else
team = nil
end

return [] if team.nil?
github_client.team_members(team).collect { |e| e.login }.compact.sort
end

# Send an invitation to a user to join an organization's team using the GitHub API
def invite_user_to_team(username, org_team_name)
username = user_login(username)
Expand Down Expand Up @@ -189,8 +204,14 @@ def trigger_workflow(repo, workflow, inputs={}, ref="main")
url = "https://api.github.com/repos/#{repo}/actions/workflows/#{workflow}/dispatches"
parameters = { inputs: inputs, ref: ref }
response = Faraday.post(url, parameters.to_json, github_headers)
response_ok = response.status.to_i == 204

unless response_ok
logger.warn("Error triggering workflow #{workflow} at #{repo}: ")
logger.warn(" Response #{response.status}: #{response.body}")
end

response.status.to_i == 204
response_ok
end

# Returns true if the user in a team member of any of the authorized teams
Expand Down
8 changes: 4 additions & 4 deletions app/lib/responder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -143,18 +143,18 @@ def required_params(*param_names)
if empty_param?(param_name)
raise "Configuration Error in #{self.class.name}: No value for #{param_name}."
else
self.class.define_method(param_name.to_s) { params[param_name].strip }
self.class.define_method(param_name.to_s) { params[param_name] }
end
end
end

# True if param's value is empty
def empty_param?(x)
return true if params[x].nil?
if params[x].is_a?(String)
params[x].strip.empty?
else
if params[x].is_a?(Hash) || params[x].is_a?(Array)
params[x].empty?
else
params[x].to_s.strip.empty?
end
end

Expand Down
2 changes: 1 addition & 1 deletion app/responders/github_action_responder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def process_message(message)
inputs = params[:inputs] || {}
inputs_from_issue = params[:data_from_issue] || []
mapping = params[:mapping] || {}
ref = params[:ref] || "main"
ref = params[:workflow_ref] || "main"
mapped_parameters = {}

inputs_from_issue.each do |input_from_issue|
Expand Down
27 changes: 27 additions & 0 deletions app/responders/list_team_members_responder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
require_relative '../lib/responder'

class ListTeamMembersResponder < Responder

keyname :list_team_members

def define_listening
required_params :command, :team_id

@event_action = "issue_comment.created"
@event_regex = /\A@#{bot_name} #{command}\.?\s*\z/i
end

def process_message(message)
team_members = team_members(params[:team_id])
heading = params[:heading].to_s
respond_template :list_team_members, { heading: heading, team_members: team_members }
end

def description
params[:description] || "Replies to '#{command}'"
end

def example_invocation
"@#{bot_name} #{command}"
end
end
8 changes: 8 additions & 0 deletions app/responses/list_team_members.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<%= heading %>

```
<% team_members.each do |team_member| -%>
@<%= team_member %>
<% end -%>
<%= "The list is empty" if team_members.empty? -%>
```
6 changes: 3 additions & 3 deletions config/settings-production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,12 @@ buffy:
- warn_if_empty: true
- reviewers
- repourl:
- heading: Repository
- warn_if_empty: true
- heading: Repository
- warn_if_empty: true
- submission-type:
- heading: Submission Type
warn_if_empty: true
- editor
- language:
- heading: Language Code
warn_if_empty: true
warn_if_empty: true
1 change: 1 addition & 0 deletions docs/available_responders.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Buffy includes a list of Responders that can be used by configuring them in the
responders/invite
responders/set_value
responders/list_of_values
responders/list_team_members
responders/add_remove_assignee
responders/reviewer_checklist_comment
responders/add_remove_checklist
Expand Down
Binary file added docs/images/responders/list_team_members.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ We will use here [Heroku](https://www.heroku.com) as an example service to deplo
BUFFY_GH_SECRET_TOKEN: <a_random_string>
RACK_ENV: production

**2b.** You can set the Ruby version to install using the CUSTOM_RUBY_VERSION env var. Unless you need any other specific version, please add also a Config Var named CUSTOM_RUBY_VERSION with the value of the latest version listed in the [Buffy tested Ruby versions](https://github.com/openjournals/buffy/blob/main/.github/workflows/tests.yml#L10).


**3.** You can set Heroku to automatically redeploy when new commits are added. You can also add heroku as a git remote and deploy manually using

$ git push heroku main
Expand Down
4 changes: 2 additions & 2 deletions docs/responders/github_action.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ Some parameters are required for the responder to work: the `command` to invoke
:command: *Required*. The command this responder will listen to.
:workflow_repo: *Required*. The repo to run the action on, in *org/name* format.
:workflow_name: *Required*. Name of the workflow to run.
:message: An optional message to reply.
:ref: Optional. The ref for the GitHub action to use. Defaults to *main*.
:workflow_ref: Optional. The git ref for the GitHub action to use. Defaults to *main*.
:message: An optional message to reply with once the workflow is triggered.
:description: The description of the action this command runs. It will show in the help command if the responder is not hidden.
:inputs: *<Map>* An optional list of params/values to pass as inputs to the GitHub Action.
:data_from_issue: *<Array>* An optional list of fields from the body of the issue to pass as inputs to the GitHub Action.
Expand Down
48 changes: 48 additions & 0 deletions docs/responders/list_team_members.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
List team members
=================

This responder replies with a list of members from a GitHub team

## Listens to

```
@botname <command>
```

For example, if you configure the command to be _list editors_, it would respond to:
```
@botname list editors
```

## Settings key

`list_team_members`

## Params
```eval_rst
:command: The command this responder will listen to.
:team_id: The id of the GitHub team to be listed.
:heading: *Optional* Heading for the replied list.
:description: *Optional* String to show when the help command is invoked.
```

## Examples

**List editors team members with custom heading**
```yaml
...
responders:
list_team_members:
command: list editors
team_id: 3824115
heading: Current journal editors
...
```


## In action

![](../images/responders/list_team_members.png "List team members responder in action")
22 changes: 21 additions & 1 deletion spec/github_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@
end

it "should be false if API call is not successful" do
expect(Faraday).to receive(:post).and_return(double(status: 401))
expect(Faraday).to receive(:post).and_return(double(status: 401, body: "User Unauthorized"))
expect(subject.trigger_workflow("openjournals/buffy", "action.yml")).to be_falsy
end

Expand Down Expand Up @@ -392,6 +392,26 @@
end
end

describe "#team_members" do
before do
members = [double(login: "user1"), double(login: "user2")]
allow_any_instance_of(Octokit::Client).to receive(:team_members).with(1111).and_return(members)
allow(subject).to receive(:team_id).with("org/team_test").and_return(1111)
end

it "should accept a team id" do
expect(subject.team_members(1111)).to eq(["user1", "user2"])
end

it "should accept a team name" do
expect(subject.team_members("org/team_test")).to eq(["user1", "user2"])
end

it "should return empty list if the team doesn't exists" do
expect(subject.team_members(nil)).to eq([])
end
end

describe "#user_in_authorized_teams?" do
it "should return true if user is member of any authorized team" do
expect_any_instance_of(Octokit::Client).to receive(:team_member?).once.with(11, "sender").and_return(true)
Expand Down
17 changes: 9 additions & 8 deletions spec/responder_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -402,28 +402,29 @@
it "should be true when param's value is an empty string" do
subject.params = { first_name: "", last_name: " " }

expect(subject.empty_param?("first_name")).to be_truthy
expect(subject.empty_param?("last_name")).to be_truthy
expect(subject.empty_param?(:first_name)).to be_truthy
expect(subject.empty_param?(:last_name)).to be_truthy
end

it "should be true when param's value is an empty array" do
subject.params = { values: [] }

expect(subject.empty_param?("values")).to be_truthy
expect(subject.empty_param?(:values)).to be_truthy
end

it "should be true when param's value is an empty hash" do
subject.params = { values: {} }

expect(subject.empty_param?("values")).to be_truthy
expect(subject.empty_param?(:values)).to be_truthy
end

it "should be false when param's value is present" do
subject.params = { labels: ["archived", "accepted"], name: "Buffy", required: {version: "1.0"} }
subject.params = { labels: ["archived", "accepted"], name: "Buffy", required: {version: "1.0"}, id: 33}

expect(subject.empty_param?("labels")).to be_truthy
expect(subject.empty_param?("name")).to be_truthy
expect(subject.empty_param?("required")).to be_truthy
expect(subject.empty_param?(:labels)).to be_falsy
expect(subject.empty_param?(:name)).to be_falsy
expect(subject.empty_param?(:required)).to be_falsy
expect(subject.empty_param?(:id)).to be_falsy
end
end

Expand Down
2 changes: 1 addition & 1 deletion spec/responders/github_action_responder_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
end

it "should run workflow with custom inputs and params" do
@responder.params = @responder.params.merge({ ref: "v1.2.3",
@responder.params = @responder.params.merge({ workflow_ref: "v1.2.3",
data_from_issue: ["abc", "p"],
mapping: { input3: :sender, input4: "p" },
inputs: { input1: "A", input2: "B" }})
Expand Down
57 changes: 57 additions & 0 deletions spec/responders/list_team_members_responder_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
require_relative "../spec_helper.rb"

describe ListTeamMembersResponder do

subject do
described_class
end

describe "listening" do
before { @responder = subject.new({env: { bot_github_user: "botsci" }}, { command: "list editors", team_id: 12345 }) }

it "should listen to new comments" do
expect(@responder.event_action).to eq("issue_comment.created")
end

it "should define regex" do
expect(@responder.event_regex).to match("@botsci list editors")
expect(@responder.event_regex).to match("@botsci list editors.")
expect(@responder.event_regex).to match("@botsci list editors \r\n")
expect(@responder.event_regex).to_not match("```@botsci list editors")
expect(@responder.event_regex).to_not match("@botsci list editors \r\n more")
end
end

describe "#process_message" do
before do
@responder = subject.new({env: {bot_github_user: "botsci"}}, { command: "list editors", team_id: 12345 })
@team_members = ["user1", "user2"]
disable_github_calls_for(@responder)
end

it "should respond with a erb template to github" do
team_members = ["user1", "user2"]
expect(@responder).to receive(:team_members).once.with(12345).and_return(@team_members)

expected_locals = { heading: "", team_members: @team_members }
expect(@responder).to receive(:respond_template).once.with(:list_team_members, expected_locals)
@responder.process_message("@botsci list editors")
end

it "should allow to customize heading" do
@responder.params[:heading] = "Current editors"
expect(@responder).to receive(:team_members).once.with(12345).and_return(@team_members)

expected_locals = { heading: "Current editors", team_members: @team_members }
expect(@responder).to receive(:respond_template).once.with(:list_team_members, expected_locals)
@responder.process_message("@botsci list editors")
end

it "should allow to customize description" do
expect(@responder.description).to eq("Replies to 'list editors'")

@responder.params[:description] = "List current editors"
expect(@responder.description).to eq("List current editors")
end
end
end
1 change: 1 addition & 0 deletions spec/support/common_actions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def disable_github_calls_for(responder)
allow(responder).to receive(:add_assignee).and_return(true)
allow(responder).to receive(:remove_assignee).and_return(true)
allow(responder).to receive(:team_id).and_return(nil)
allow(responder).to receive(:team_members).and_return([])
allow(responder).to receive(:trigger_workflow).and_return(true)

allow(Octokit::Client).to receive(:new).and_return(Octokit::Client.new())
Expand Down
3 changes: 2 additions & 1 deletion spec/support/responder_params.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ def sample_params(responder_class)
AddAndRemoveUserChecklistResponder => { template_file: "checklist.md" },
ReviewerChecklistCommentResponder => { template_file: "checklist.md" },
GithubActionResponder => { workflow_repo: "openjournals/joss-reviews", workflow_name: "compiler", command: "generate pdf" },
InitialValuesResponder => { values: ["version", "target-repository"]}
InitialValuesResponder => { values: ["version", "target-repository"]},
ListTeamMembersResponder => { command: "list editors", team_id: 3824115 },
}

params_by_responder[responder_class] || {}
Expand Down

0 comments on commit 70e376f

Please sign in to comment.