teachers_pet 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +7 -0
  3. data/Guardfile +3 -1
  4. data/README.md +53 -28
  5. data/Rakefile +1 -1
  6. data/bin/teachers_pet +4 -0
  7. data/lib/teachers_pet.rb +4 -1
  8. data/lib/teachers_pet/actions/add_to_team.rb +31 -0
  9. data/lib/teachers_pet/actions/base.rb +36 -111
  10. data/lib/teachers_pet/actions/clone_repos.rb +9 -36
  11. data/lib/teachers_pet/actions/create_repos.rb +16 -39
  12. data/lib/teachers_pet/actions/create_student_teams.rb +35 -0
  13. data/lib/teachers_pet/actions/fork_collab.rb +4 -19
  14. data/lib/teachers_pet/actions/open_issue.rb +17 -32
  15. data/lib/teachers_pet/actions/push_files.rb +8 -22
  16. data/lib/teachers_pet/cli.rb +22 -0
  17. data/lib/teachers_pet/client_decorator.rb +59 -0
  18. data/lib/teachers_pet/commands/add_to_team.rb +12 -0
  19. data/lib/teachers_pet/commands/clone_repos.rb +15 -0
  20. data/lib/teachers_pet/commands/create_repos.rb +15 -0
  21. data/lib/teachers_pet/commands/create_student_teams.rb +13 -0
  22. data/lib/teachers_pet/commands/fork_collab.rb +12 -0
  23. data/lib/teachers_pet/commands/open_issue.rb +18 -0
  24. data/lib/teachers_pet/commands/push_files.rb +15 -0
  25. data/lib/teachers_pet/configuration.rb +0 -13
  26. data/lib/teachers_pet/version.rb +1 -1
  27. data/spec/actions/base_spec.rb +13 -0
  28. data/spec/cli_spec.rb +17 -0
  29. data/spec/commands/add_to_team_spec.rb +43 -0
  30. data/spec/commands/clone_repos_spec.rb +33 -0
  31. data/spec/commands/create_repos_spec.rb +55 -0
  32. data/spec/commands/create_student_teams_spec.rb +90 -0
  33. data/spec/commands/fork_collab_spec.rb +95 -0
  34. data/spec/commands/open_issue_spec.rb +63 -0
  35. data/spec/commands/push_files_spec.rb +33 -0
  36. data/spec/fixtures/empty +0 -0
  37. data/spec/fixtures/teams +1 -0
  38. data/spec/spec_helper.rb +13 -53
  39. data/spec/support/command_helpers.rb +11 -0
  40. data/spec/support/common_helpers.rb +52 -0
  41. data/teachers_pet.gemspec +6 -2
  42. metadata +89 -29
  43. data/bin/clone_repos +0 -6
  44. data/bin/create_repos +0 -6
  45. data/bin/create_teams +0 -6
  46. data/bin/fork_collab +0 -6
  47. data/bin/open_issue +0 -6
  48. data/bin/push_files +0 -6
  49. data/lib/teachers_pet/actions/create_teams.rb +0 -101
  50. data/spec/actions/clone_repos_spec.rb +0 -44
  51. data/spec/actions/create_repos_spec.rb +0 -65
  52. data/spec/actions/create_teams_spec.rb +0 -40
  53. data/spec/actions/open_issue_spec.rb +0 -71
@@ -0,0 +1,13 @@
1
+ module TeachersPet
2
+ class Cli
3
+ option :organization, required: true
4
+
5
+ students_option
6
+ common_options
7
+
8
+ desc 'create_student_teams', "Create teams for each student (or student group), and a team for all the instructors."
9
+ def create_student_teams
10
+ TeachersPet::Actions::CreateStudentTeams.new(options).run
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ module TeachersPet
2
+ class Cli
3
+ option :repository, required: true, banner: 'OWNER/REPO'
4
+ option :dry_run, type: :boolean, default: false
5
+ common_options
6
+
7
+ desc "fork_collab", "Give collaborator access to everyone who has forked a particular repository."
8
+ def fork_collab
9
+ TeachersPet::Actions::ForkCollab.new(options).run
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,18 @@
1
+ module TeachersPet
2
+ class Cli
3
+ option :organization, required: true
4
+ option :repository, required: true
5
+
6
+ option :title, desc: "The title of the issue to be created"
7
+ option :body, banner: 'PATH', desc: "The path to the file containing the issue body (.txt or .md)"
8
+ option :labels, banner: 'LABEL1,LABEL2'
9
+
10
+ students_option
11
+ common_options
12
+
13
+ desc "open_issue", "Opens a single issue in each repository in the organization."
14
+ def open_issue
15
+ TeachersPet::Actions::OpenIssue.new(options).run
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,15 @@
1
+ module TeachersPet
2
+ class Cli
3
+ option :organization, required: true
4
+ option :repository, required: true
5
+
6
+ students_option
7
+ common_options
8
+ option :ssh, banner: 'HOST', default: TeachersPet::Configuration.sshEndpoint
9
+
10
+ desc 'push_files', "Run this command from a local Git repository to push the files up to the specified repository for each student. It will add a remote that is the name of each student team to your repository."
11
+ def push_files
12
+ TeachersPet::Actions::PushFiles.new(options).run
13
+ end
14
+ end
15
+ end
@@ -19,13 +19,6 @@ module TeachersPet
19
19
  @@WEB_ENDPOINT
20
20
  end
21
21
 
22
- # The name of your organization
23
- @@ORGANIZATION = 'edugit-test'
24
-
25
- def self.organization
26
- @@ORGANIZATION
27
- end
28
-
29
22
  # The name fo the file that contains the team definitions / students
30
23
  @@STUDENTS_FILE = './students'
31
24
 
@@ -33,12 +26,6 @@ module TeachersPet
33
26
  @@STUDENTS_FILE
34
27
  end
35
28
 
36
- # The name of the file that contains the GitHub usernames of the instructors
37
- @@INSTRUCTORS_FILE = './instructors'
38
-
39
- def self.instructorsFile
40
- @@INSTRUCTORS_FILE
41
- end
42
29
 
43
30
  # github.com - set to 'github.com'
44
31
  # GitHub Enterprise - 'yourserver.com'
@@ -1,3 +1,3 @@
1
1
  module TeachersPet
2
- VERSION = '0.2.0'
2
+ VERSION = '0.3.0'
3
3
  end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe TeachersPet::Actions::Base do
4
+ describe '#read_file' do
5
+ it "returns a hash of usernames by team name" do
6
+ action = TeachersPet::Actions::Base.new
7
+ result = action.read_file(fixture_path('teams'))
8
+ expect(result).to eq(
9
+ 'studentteam1' => %w(teststudent1 teststudent2)
10
+ )
11
+ end
12
+ end
13
+ end
data/spec/cli_spec.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe TeachersPet::Cli do
4
+ include CommandHelpers
5
+
6
+ it "throws an error for unsupported options" do
7
+ # ...using an arbirtrary command
8
+
9
+ # Make sure it short-circuits
10
+ expect(TeachersPet::Actions::CreateStudentTeams).to_not receive(:new)
11
+
12
+ output = capture(:stderr) {
13
+ TeachersPet::Cli.start(%w(create_student_teams --organization testorg --unsupported-option))
14
+ }
15
+ expect(output).to include('--unsupported-option')
16
+ end
17
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'add_to_team' do
4
+ include CommandHelpers
5
+
6
+ it "adds users to the team matching the filename" do
7
+ request_stubs = []
8
+
9
+ request_stubs << stub_get_json('https://testteacher:abc123@api.github.com/orgs/testorg/teams?per_page=100', [
10
+ {
11
+ id: 101,
12
+ name: 'instructors'
13
+ }
14
+ ])
15
+
16
+ users = instructor_usernames
17
+ request_stubs << stub_get_json('https://testteacher:abc123@api.github.com/teams/101/members?per_page=100', [
18
+ {
19
+ login: users.first
20
+ }
21
+ ])
22
+
23
+ users[1..-1].each do |instructor|
24
+ request_stubs << stub_request(:put, "https://testteacher:abc123@api.github.com/teams/101/members/#{instructor}")
25
+ end
26
+
27
+ teachers_pet(:add_to_team,
28
+ organization: 'testorg',
29
+ members: instructors_list_fixture_path,
30
+
31
+ username: 'testteacher',
32
+ password: 'abc123'
33
+ )
34
+
35
+ request_stubs.each do |request_stub|
36
+ expect(request_stub).to have_been_requested.once
37
+ end
38
+ end
39
+
40
+ it "creates the team if it doesn't already exist"
41
+
42
+ it "treats the team names case-insensitively"
43
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'clone_repos' do
4
+ include CommandHelpers
5
+
6
+ it "runs" do
7
+ request_stubs = []
8
+
9
+ request_stubs << stub_get_json('https://testteacher:abc123@api.github.com/orgs/testorg',
10
+ login: 'testorg',
11
+ url: 'https://api.github.com/orgs/testorg'
12
+ )
13
+ request_stubs << stub_get_json('https://testteacher:abc123@api.github.com/orgs/testorg/teams?per_page=100', student_teams)
14
+ student_usernames.each do |username|
15
+ request_stubs << stub_get_json("https://testteacher:abc123@api.github.com/repos/testorg/#{username}-testrepo", {})
16
+ expect_any_instance_of(TeachersPet::Actions::CloneRepos).to receive(:execute).with("git clone https://www.github.com/testorg/#{username}-testrepo.git").once
17
+ end
18
+
19
+ teachers_pet(:clone_repos,
20
+ repository: 'testrepo',
21
+ organization: 'testorg',
22
+
23
+ students: students_list_fixture_path,
24
+
25
+ username: 'testteacher',
26
+ password: 'abc123'
27
+ )
28
+
29
+ request_stubs.each do |request_stub|
30
+ expect(request_stub).to have_been_requested.once
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'create_repos' do
4
+ include CommandHelpers
5
+
6
+ def common_test(create_as_public)
7
+ request_stubs = []
8
+
9
+ request_stubs << stub_get_json('https://testteacher:abc123@api.github.com/orgs/testorg',
10
+ login: 'testorg',
11
+ url: 'https://api.github.com/orgs/testorg'
12
+ )
13
+ request_stubs << stub_get_json('https://testteacher:abc123@api.github.com/orgs/testorg/teams?per_page=100', student_teams)
14
+ student_usernames.each do |username|
15
+ # Check for the repos existing already
16
+ stub_request(:get, "https://testteacher:abc123@api.github.com/repos/testorg/#{username}-testrepo").
17
+ to_return(status: 404)
18
+ end
19
+
20
+ student_usernames.each do |username|
21
+ # actually create the repo
22
+ team_id = 0
23
+ student_teams.each do |st|
24
+ if st[:name].eql?(username)
25
+ team_id = st[:id]
26
+ end
27
+ end
28
+ stub_request(:post, "https://testteacher:abc123@api.github.com/orgs/testorg/repos").
29
+ with(body: "{\"description\":\"testrepo created for #{username}\",\"private\":#{!create_as_public},\"has_issues\":true,\"has_wiki\":false,\"has_downloads\":false,\"team_id\":#{team_id},\"name\":\"#{username}-testrepo\"}")
30
+ end
31
+
32
+ teachers_pet(:create_repos,
33
+ repository: 'testrepo',
34
+ organization: 'testorg',
35
+ public: create_as_public,
36
+
37
+ students: students_list_fixture_path,
38
+
39
+ username: 'testteacher',
40
+ password: 'abc123'
41
+ )
42
+
43
+ request_stubs.each do |request_stub|
44
+ expect(request_stub).to have_been_requested.once
45
+ end
46
+ end
47
+
48
+ it "create repos public" do
49
+ common_test(true)
50
+ end
51
+
52
+ it "create repos private" do
53
+ common_test(false)
54
+ end
55
+ end
@@ -0,0 +1,90 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'create_student_teams' do
4
+ include CommandHelpers
5
+
6
+ def stub_owners_only
7
+ stub_get_json('https://testteacher:abc123@api.github.com/orgs/testorg/teams?per_page=100', [
8
+ {
9
+ id: 101,
10
+ name: 'Owners'
11
+ }
12
+ ])
13
+ end
14
+
15
+ it "creates one team per student" do
16
+ request_stubs = []
17
+ request_stubs << stub_owners_only
18
+
19
+ student_usernames.each_with_index do |student, i|
20
+ # Creates team
21
+ request_stubs << stub_request(:post, 'https://testteacher:abc123@api.github.com/orgs/testorg/teams').
22
+ with(body: {
23
+ name: student,
24
+ permission: 'push'
25
+ }.to_json).to_return(body: {
26
+ id: i,
27
+ name: student
28
+ })
29
+
30
+ # Checks for existing team members
31
+ # TODO No need to retrieve members for a new team
32
+ request_stubs << stub_get_json("https://testteacher:abc123@api.github.com/teams/#{i}/members?per_page=100", [])
33
+
34
+ # Add student to their team
35
+ request_stubs << stub_request(:put, "https://testteacher:abc123@api.github.com/teams/#{i}/members/#{student}")
36
+ end
37
+
38
+ teachers_pet(:create_student_teams,
39
+ organization: 'testorg',
40
+
41
+ students: students_list_fixture_path,
42
+ instructors: empty_list_fixture_path,
43
+
44
+ username: 'testteacher',
45
+ password: 'abc123'
46
+ )
47
+
48
+ request_stubs.each do |request_stub|
49
+ expect(request_stub).to have_been_requested.once
50
+ end
51
+ end
52
+
53
+ it "creates teams for groups of students" do
54
+ request_stubs = []
55
+ stub_owners_only
56
+
57
+ # Creates team
58
+ request_stubs << stub_request(:post, 'https://testteacher:abc123@api.github.com/orgs/testorg/teams').
59
+ with(body: {
60
+ name: 'studentteam1',
61
+ permission: 'push'
62
+ }.to_json).to_return(body: {
63
+ id: 1,
64
+ name: 'studentteam1'
65
+ })
66
+
67
+ # Checks for existing team members
68
+ # TODO No need to retrieve members for a new team
69
+ request_stubs << stub_get_json('https://testteacher:abc123@api.github.com/teams/1/members?per_page=100', [])
70
+
71
+ %w(teststudent1 teststudent2).each do |student|
72
+ # Add student to their team
73
+ request_stubs << stub_request(:put, "https://testteacher:abc123@api.github.com/teams/1/members/#{student}")
74
+ end
75
+
76
+ teachers_pet(:create_student_teams,
77
+ organization: 'testorg',
78
+
79
+ students: fixture_path('teams'),
80
+ instructors: empty_list_fixture_path,
81
+
82
+ username: 'testteacher',
83
+ password: 'abc123'
84
+ )
85
+
86
+ request_stubs.each do |request_stub|
87
+ expect(request_stub).to have_been_requested.once
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,95 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'fork_collab' do
4
+ include CommandHelpers
5
+
6
+ context 'through CLI' do
7
+ it "requires the repository be specified" do
8
+ expect {
9
+ teachers_pet(:fork_collab)
10
+ }.to raise_error(Thor::RequiredArgumentMissingError, /--repository/)
11
+ end
12
+
13
+ it "passes the options to the action" do
14
+ expect_to_be_run_with(TeachersPet::Actions::ForkCollab,
15
+ 'api' => 'https://api.github.com/',
16
+ 'dry_run' => false,
17
+ 'password' => 'abc123',
18
+ 'repository' => 'testorg/testrepo',
19
+ 'username' => ENV['USER'],
20
+ 'web' => 'https://www.github.com/'
21
+ )
22
+ teachers_pet(:fork_collab, repository: 'testorg/testrepo', password: 'abc123')
23
+ end
24
+
25
+ it "succeeds for basic auth" do
26
+ request_stubs = []
27
+ request_stubs << stub_get_json('https://testteacher:abc123@api.github.com/repos/testorg/testrepo/forks?per_page=100', [
28
+ {
29
+ owner: {
30
+ login: 'teststudent',
31
+ type: 'User'
32
+ }
33
+ }
34
+ ])
35
+ request_stubs << stub_request(:put, 'https://testteacher:abc123@api.github.com/repos/testorg/testrepo/collaborators/teststudent')
36
+
37
+ teachers_pet(:fork_collab,
38
+ repository: 'testorg/testrepo',
39
+ username: 'testteacher',
40
+ password: 'abc123'
41
+ )
42
+
43
+ request_stubs.each do |request_stub|
44
+ expect(request_stub).to have_been_requested.once
45
+ end
46
+ end
47
+
48
+ it "succeeds for OAuth" do
49
+ request_stubs = []
50
+ request_stubs << stub_get_json('https://api.github.com/repos/testorg/testrepo/forks?per_page=100', [
51
+ {
52
+ owner: {
53
+ login: 'teststudent',
54
+ type: 'User'
55
+ }
56
+ }
57
+ ]).with(headers: {'Authorization' => 'token tokentokentoken'})
58
+
59
+ request_stubs << stub_request(:put, 'https://api.github.com/repos/testorg/testrepo/collaborators/teststudent').
60
+ with(headers: {'Authorization' => 'token tokentokentoken'})
61
+
62
+ teachers_pet(:fork_collab,
63
+ repository: 'testorg/testrepo',
64
+ token: 'tokentokentoken'
65
+ )
66
+
67
+ request_stubs.each do |request_stub|
68
+ expect(request_stub).to have_been_requested.once
69
+ end
70
+ end
71
+
72
+ it "prints the users on a dry run" do
73
+ request_stub = stub_get_json('https://testteacher:abc123@api.github.com/repos/testorg/testrepo/forks?per_page=100', [
74
+ {
75
+ owner: {
76
+ login: 'teststudent',
77
+ type: 'User'
78
+ }
79
+ }
80
+ ])
81
+
82
+ output = capture(:stdout) do
83
+ teachers_pet(:fork_collab,
84
+ repository: 'testorg/testrepo',
85
+ username: 'testteacher',
86
+ password: 'abc123',
87
+ dry_run: true
88
+ )
89
+ end
90
+
91
+ expect(output).to include('teststudent')
92
+ expect(request_stub).to have_been_requested.once
93
+ end
94
+ end
95
+ end