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
data/bin/clone_repos DELETED
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
4
- require 'teachers_pet/actions/clone_repos'
5
-
6
- TeachersPet::Actions::CloneRepos.new.run
data/bin/create_repos DELETED
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
4
- require 'teachers_pet/actions/create_repos'
5
-
6
- TeachersPet::Actions::CreateRepos.new.run
data/bin/create_teams DELETED
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
4
- require 'teachers_pet/actions/create_teams'
5
-
6
- TeachersPet::Actions::CreateTeams.new.run
data/bin/fork_collab DELETED
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
4
- require 'teachers_pet/actions/fork_collab'
5
-
6
- TeachersPet::Actions::ForkCollab.new.run
data/bin/open_issue DELETED
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
4
- require 'teachers_pet/actions/open_issue'
5
-
6
- TeachersPet::Actions::OpenIssue.new.run
data/bin/push_files DELETED
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
4
- require 'teachers_pet/actions/push_files'
5
-
6
- TeachersPet::Actions::PushFiles.new.run
@@ -1,101 +0,0 @@
1
- # Author: Mike Helmick
2
- # Creates "teams" for an origanization. In this scenario - each team consists of
3
- # one student, and any instructors for the course.
4
-
5
- # The students and instructors files contain 1 userid per line.
6
- # - For teams, the students file should be "teamName studentName studentName"
7
- # We recommend that instructors also be created as students for ease of testing.
8
-
9
- $LOAD_PATH << File.join(File.dirname(__FILE__), '..', '..')
10
-
11
- require 'rubygems'
12
- require 'highline/question'
13
- require 'highline/import'
14
- require 'highline/compatibility'
15
-
16
- require 'teachers_pet/actions/base'
17
-
18
- module TeachersPet
19
- module Actions
20
- class CreateTeams < Base
21
- def read_info
22
- @organization = ask("What is the organization name?") { |q| q.default = TeachersPet::Configuration.organization }
23
- @student_file = self.get_students_file_path
24
- @instructor_file = self.get_instructors_file_path
25
- end
26
-
27
- def load_files
28
- @students = read_file(@student_file, 'Students')
29
- @instructors = read_file(@instructor_file, 'Instructors')
30
- end
31
-
32
- def create
33
- self.init_client
34
- confirm("Create teams for #{@students.size} students/teams?")
35
-
36
- existing = Hash.new
37
- teams = @client.organization_teams(@organization)
38
- teams.each { |team| existing[team[:name]] = team }
39
-
40
- puts "\nDetermining which students need teams created..."
41
- todo = Hash.new
42
- @students.keys.each do |team|
43
- if existing[team].nil?
44
- puts " -> #{team}"
45
- todo[team] = true
46
- end
47
- end
48
-
49
- if todo.empty?
50
- puts "\nAll teams exist"
51
- else
52
- puts "\nCreating team..."
53
- todo.keys.each do |team|
54
- puts " -> '#{team}' ..."
55
- @client.create_team(@organization,
56
- {
57
- :name => team,
58
- :permission => 'push'
59
- })
60
- end
61
- end
62
-
63
- puts "\nAdjusting team memberships"
64
- teams = @client.organization_teams(@organization)
65
- teams.each do |team|
66
- team_members = get_team_member_logins(team[:id])
67
- if team[:name].eql?('Owners')
68
- puts "*** OWNERS *** - Ensuring instructors are owners"
69
- @instructors.keys.each do |instructor|
70
- unless team_members.include?(instructor)
71
- @client.add_team_member(team[:id], instructor)
72
- puts " -> '#{instructor}' has been made an owner for this course"
73
- else
74
- puts " -> '#{instructor}' is already an owner"
75
- end
76
- end
77
- elsif @students.key?(team[:name])
78
- puts "Validating membership for team '#{team[:name]}'"
79
- # If there isn't a team member that is the same name as the team, and we already know
80
- # there is a student with the same name, add that student to the team.
81
- #unless team_members.include?(team[:name])
82
- @students[team[:name]].each do |student|
83
- puts " -> Adding '#{team[:name]}' to the team"
84
- @client.add_team_member(team[:id], student)
85
- end
86
- # Originally, instructors were added to the student's team, but that isn't needed
87
- # since instructors are addded to the Owners team that can see all repositories.
88
- else
89
- puts "*** Team name '#{team[:name]}' does not match any students, ignoring. ***"
90
- end
91
- end
92
- end
93
-
94
- def run
95
- self.read_info
96
- self.load_files
97
- self.create
98
- end
99
- end
100
- end
101
- end
@@ -1,44 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe TeachersPet::Actions::CloneRepos do
4
- let(:action) { TeachersPet::Actions::CloneRepos.new }
5
-
6
- def respond(question, response)
7
- action.stub(:ask).with(question).and_return(response)
8
- end
9
-
10
- before do
11
- # fallback
12
- action.stub(:ask){|question| raise("can't ask \"#{question}\"") }
13
- action.stub(:choose){ raise("can't choose()") }
14
-
15
- action.stub(:confirm)
16
- end
17
-
18
- it "runs" do
19
- respond("What repository name should be cloned for each student?", 'testrepo')
20
- respond("What is the organization name?", 'testorg')
21
- respond("What is the filename of the list of students?", students_list_fixture_path)
22
- action.stub(get_clone_method: 'https')
23
- respond("What is the organization name?", "testorg")
24
- stub_github_config
25
-
26
- request_stubs = []
27
-
28
- request_stubs << stub_get_json('https://testteacher:abc123@api.github.com/orgs/testorg',
29
- login: 'testorg',
30
- url: 'https://api.github.com/orgs/testorg'
31
- )
32
- request_stubs << stub_get_json('https://testteacher:abc123@api.github.com/orgs/testorg/teams?per_page=100', student_teams)
33
- student_usernames.each do |username|
34
- request_stubs << stub_get_json("https://testteacher:abc123@api.github.com/repos/testorg/#{username}-testrepo", {})
35
- action.should_receive(:execute).with("git clone https://www.github.com/testorg/#{username}-testrepo.git").once
36
- end
37
-
38
- action.run
39
-
40
- request_stubs.each do |request_stub|
41
- expect(request_stub).to have_been_requested.once
42
- end
43
- end
44
- end
@@ -1,65 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe TeachersPet::Actions::CreateRepos do
4
- let(:action) { TeachersPet::Actions::CreateRepos.new }
5
-
6
- before do
7
- # fallback
8
- action.stub(:ask){|question| raise("can't ask \"#{question}\"") }
9
- action.stub(:choose){ raise("can't choose()") }
10
-
11
- action.stub(:confirm)
12
- end
13
-
14
- def common_test(create_as_public)
15
- respond("What repository name should be created for each student?", 'testrepo')
16
- respond("What is the organization name?", 'testorg')
17
- respond("What is the filename of the list of students?", students_list_fixture_path)
18
- respond("What is the filename of the list of instructors?", instructors_list_fixture_path)
19
- confirm("Create repositories as public?", create_as_public)
20
- confirm("Add .gitignore and README.md files? (skip this if you are pushing starter files.)", false)
21
- mode = create_as_public ? 'public' : 'private'
22
- respond("Create 3 #{mode} repositories for students and give access to instructors?", "1")
23
- stub_github_config
24
-
25
- request_stubs = []
26
-
27
- request_stubs << stub_get_json('https://testteacher:abc123@api.github.com/orgs/testorg',
28
- login: 'testorg',
29
- url: 'https://api.github.com/orgs/testorg'
30
- )
31
- request_stubs << stub_get_json('https://testteacher:abc123@api.github.com/orgs/testorg/teams?per_page=100', student_teams)
32
- student_usernames.each do |username|
33
- # Check for the repos existing already
34
- stub_request(:get, "https://testteacher:abc123@api.github.com/repos/testorg/#{username}-testrepo").
35
- to_return(:status => 404, :body => "", :headers => {})
36
- end
37
-
38
- student_usernames.each do |username|
39
- # actually create the repo
40
- team_id = 0
41
- student_teams.each do |st|
42
- if st[:name].eql?(username)
43
- team_id = st[:id]
44
- end
45
- end
46
- stub_request(:post, "https://testteacher:abc123@api.github.com/orgs/testorg/repos").
47
- with(:body => "{\"description\":\"testrepo created for #{username}\",\"private\":#{!create_as_public},\"has_issues\":true,\"has_wiki\":false,\"has_downloads\":false,\"team_id\":#{team_id},\"auto_init\":false,\"gitignore_template\":\"\",\"name\":\"#{username}-testrepo\"}").
48
- to_return(:status => 200)
49
- end
50
-
51
- action.run
52
-
53
- request_stubs.each do |request_stub|
54
- expect(request_stub).to have_been_requested.once
55
- end
56
- end
57
-
58
- it "create repos public" do
59
- common_test(true)
60
- end
61
-
62
- it "create repos private" do
63
- common_test(false)
64
- end
65
- end
@@ -1,40 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe TeachersPet::Actions::CreateTeams do
4
- let(:action) { TeachersPet::Actions::CreateTeams.new }
5
-
6
- before do
7
- # fallback
8
- action.stub(:ask){|question| raise("can't ask \"#{question}\"") }
9
- action.stub(:choose){ raise("can't choose()") }
10
-
11
- action.stub(:confirm)
12
- end
13
-
14
- it "creates teams if none exist" do
15
- respond("What is the organization name?", 'testorg')
16
- respond("What is the filename of the list of students?", students_list_fixture_path)
17
- respond("What is the filename of the list of instructors?", instructors_list_fixture_path)
18
- stub_github_config
19
-
20
- teams_stub = stub_get_json('https://testteacher:abc123@api.github.com/orgs/testorg/teams?per_page=100', [])
21
-
22
- request_stubs = []
23
- student_usernames.each do |student|
24
- request_stubs << stub_request(:post, 'https://testteacher:abc123@api.github.com/orgs/testorg/teams').
25
- with(body: {
26
- name: student,
27
- permission: 'push'
28
- }.to_json)
29
- end
30
-
31
- action.run
32
-
33
- expect(teams_stub).to have_been_requested.twice
34
- request_stubs.each do |request_stub|
35
- expect(request_stub).to have_been_requested.once
36
- end
37
- end
38
-
39
- it "handles existing teams"
40
- end
@@ -1,71 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe TeachersPet::Actions::OpenIssue do
4
- let(:action) { TeachersPet::Actions::OpenIssue.new }
5
-
6
- before do
7
- # fallback
8
- action.stub(:ask){|question| raise("can't ask \"#{question}\"") }
9
- action.stub(:choose){ raise("can't choose()") }
10
-
11
- action.stub(:confirm)
12
- end
13
-
14
- def common_test(labels)
15
-
16
- issue_title = "Issue Test"
17
-
18
- # Respond to action prompts
19
- respond("What repository will the issue be raised in?", 'testrepo')
20
- respond("What is the organization name?", 'testorg')
21
- respond("What is the title of the issue?", 'Issue Test')
22
- respond("What is the path to the file containing the issue body?", issue_fixture_path)
23
- respond("Optionally add any labels, seperated by commas:", labels)
24
- respond("What is the filename of the list of students?", students_list_fixture_path)
25
- respond("What is the filename of the list of instructors?", instructors_list_fixture_path)
26
- respond("Create issue '#{issue_title}' in #{File.open(students_list_fixture_path).readlines.size} student repositories - 'testrepo'?", "1")
27
- stub_github_config
28
-
29
- request_stubs = []
30
-
31
- request_stubs << stub_get_json('https://testteacher:abc123@api.github.com/orgs/testorg',
32
- login: 'testorg',
33
- url: 'https://api.github.com/orgs/testorg'
34
- )
35
- request_stubs << stub_get_json('https://testteacher:abc123@api.github.com/orgs/testorg/teams?per_page=100', student_teams)
36
- student_usernames.each do |username|
37
- # Action checks that repos exist already
38
- stub_request(:get, "https://testteacher:abc123@api.github.com/repos/testorg/#{username}-testrepo").
39
- to_return(:status => 200, :body => "", :headers => {})
40
- end
41
-
42
- # create the issue in each repo
43
- student_usernames.each do |username|
44
- team_id = 0
45
- student_teams.each do |st|
46
- if st[:name].eql?(username)
47
- team_id = st[:id]
48
- end
49
- end
50
- issue_body = File.read(issue_fixture_path).gsub("\n", "\\n")
51
- labels_list = labels.split(",").map(&:strip).to_s.delete(' ')
52
- stub_request(:post, "https://testteacher:abc123@api.github.com/repos/testorg/#{username}-testrepo/issues").
53
- with(:body => "{\"labels\":#{labels_list},\"title\":\"Issue Test\",\"body\":\"#{issue_body}\"}").
54
- to_return(:status => 201)
55
- end
56
-
57
- action.run
58
-
59
- request_stubs.each do |request_stub|
60
- expect(request_stub).to have_been_requested.once
61
- end
62
- end
63
-
64
- it "open issue no labels" do
65
- common_test("")
66
- end
67
-
68
- it "open issue with labels" do
69
- common_test("bug, feature")
70
- end
71
- end