Merge branch 'szzh' of http://repository.trustie.net/xianbo/trustie2 into szzh
Conflicts: db/schema.rbdev_xiangzheng
commit
61dc979ee4
@ -0,0 +1,259 @@
|
||||
#coding=utf-8
|
||||
|
||||
require 'redmine/scm/adapters/git_adapter'
|
||||
|
||||
class Repository::Gitlab < Repository
|
||||
|
||||
attr_protected :root_url
|
||||
validates_presence_of :url
|
||||
|
||||
def self.human_attribute_name(attribute_key_name, *args)
|
||||
attr_name = attribute_key_name.to_s
|
||||
if attr_name == "url"
|
||||
attr_name = "path_to_repository"
|
||||
end
|
||||
super(attr_name, *args)
|
||||
end
|
||||
|
||||
def self.scm_adapter_class
|
||||
Redmine::Scm::Adapters::GitlabAdapter
|
||||
end
|
||||
|
||||
def self.scm_name
|
||||
'Gitlab'
|
||||
end
|
||||
|
||||
def commits(authors, start_date, end_date, branch='master')
|
||||
scm.commits(authors, start_date, end_date,branch).map {|commit|
|
||||
[commit[:author], commit[:num]]
|
||||
}
|
||||
end
|
||||
|
||||
def report_last_commit
|
||||
extra_report_last_commit
|
||||
end
|
||||
|
||||
def extra_report_last_commit
|
||||
return false if extra_info.nil?
|
||||
v = extra_info["extra_report_last_commit"]
|
||||
return false if v.nil?
|
||||
v.to_s != '0'
|
||||
end
|
||||
|
||||
def supports_directory_revisions?
|
||||
true
|
||||
end
|
||||
|
||||
def supports_revision_graph?
|
||||
true
|
||||
end
|
||||
|
||||
def repo_log_encoding
|
||||
'UTF-8'
|
||||
end
|
||||
|
||||
# Returns the identifier for the given git changeset
|
||||
def self.changeset_identifier(changeset)
|
||||
changeset.scmid
|
||||
end
|
||||
|
||||
# Returns the readable identifier for the given git changeset
|
||||
def self.format_changeset_identifier(changeset)
|
||||
changeset.revision[0, 8]
|
||||
end
|
||||
|
||||
def branches
|
||||
scm.branches
|
||||
end
|
||||
|
||||
def tags
|
||||
scm.tags
|
||||
end
|
||||
|
||||
def default_branch
|
||||
scm.default_branch
|
||||
rescue Exception => e
|
||||
logger.error "git: error during get default branch: #{e.message}"
|
||||
nil
|
||||
end
|
||||
|
||||
def find_changeset_by_name(name)
|
||||
if name.present?
|
||||
changesets.where(:revision => name.to_s).first ||
|
||||
changesets.where('scmid LIKE ?', "#{name}%").first
|
||||
end
|
||||
end
|
||||
|
||||
def entries(path=nil, identifier=nil)
|
||||
entries = scm.entries(path, identifier, :report_last_commit => extra_report_last_commit)
|
||||
load_entries_changesets(entries)
|
||||
entries
|
||||
end
|
||||
|
||||
# With SCMs that have a sequential commit numbering,
|
||||
# such as Subversion and Mercurial,
|
||||
# Redmine is able to be clever and only fetch changesets
|
||||
# going forward from the most recent one it knows about.
|
||||
#
|
||||
# However, Git does not have a sequential commit numbering.
|
||||
#
|
||||
# In order to fetch only new adding revisions,
|
||||
# Redmine needs to save "heads".
|
||||
#
|
||||
# In Git and Mercurial, revisions are not in date order.
|
||||
# Redmine Mercurial fixed issues.
|
||||
# * Redmine Takes Too Long On Large Mercurial Repository
|
||||
# http://www.redmine.org/issues/3449
|
||||
# * Sorting for changesets might go wrong on Mercurial repos
|
||||
# http://www.redmine.org/issues/3567
|
||||
#
|
||||
# Database revision column is text, so Redmine can not sort by revision.
|
||||
# Mercurial has revision number, and revision number guarantees revision order.
|
||||
# Redmine Mercurial model stored revisions ordered by database id to database.
|
||||
# So, Redmine Mercurial model can use correct ordering revisions.
|
||||
#
|
||||
# Redmine Mercurial adapter uses "hg log -r 0:tip --limit 10"
|
||||
# to get limited revisions from old to new.
|
||||
# But, Git 1.7.3.4 does not support --reverse with -n or --skip.
|
||||
#
|
||||
# The repository can still be fully reloaded by calling #clear_changesets
|
||||
# before fetching changesets (eg. for offline resync)
|
||||
def fetch_changesets
|
||||
scm_brs = branches
|
||||
return if scm_brs.nil? || scm_brs.empty?
|
||||
|
||||
h1 = extra_info || {}
|
||||
h = h1.dup
|
||||
repo_heads = scm_brs.map{ |br| br.scmid }
|
||||
h["heads"] ||= []
|
||||
prev_db_heads = h["heads"].dup
|
||||
if prev_db_heads.empty?
|
||||
prev_db_heads += heads_from_branches_hash
|
||||
end
|
||||
return if prev_db_heads.sort == repo_heads.sort
|
||||
|
||||
h["db_consistent"] ||= {}
|
||||
if changesets.count == 0
|
||||
h["db_consistent"]["ordering"] = 1
|
||||
merge_extra_info(h)
|
||||
self.save
|
||||
elsif ! h["db_consistent"].has_key?("ordering")
|
||||
h["db_consistent"]["ordering"] = 0
|
||||
merge_extra_info(h)
|
||||
self.save
|
||||
end
|
||||
save_revisions(prev_db_heads, repo_heads)
|
||||
end
|
||||
|
||||
def save_revisions(prev_db_heads, repo_heads)
|
||||
h = {}
|
||||
opts = {}
|
||||
opts[:reverse] = true
|
||||
opts[:excludes] = prev_db_heads
|
||||
opts[:includes] = repo_heads
|
||||
|
||||
revisions = scm.revisions('', nil, nil, opts)
|
||||
return if revisions.blank?
|
||||
|
||||
# Make the search for existing revisions in the database in a more sufficient manner
|
||||
#
|
||||
# Git branch is the reference to the specific revision.
|
||||
# Git can *delete* remote branch and *re-push* branch.
|
||||
#
|
||||
# $ git push remote :branch
|
||||
# $ git push remote branch
|
||||
#
|
||||
# After deleting branch, revisions remain in repository until "git gc".
|
||||
# On git 1.7.2.3, default pruning date is 2 weeks.
|
||||
# So, "git log --not deleted_branch_head_revision" return code is 0.
|
||||
#
|
||||
# After re-pushing branch, "git log" returns revisions which are saved in database.
|
||||
# So, Redmine needs to scan revisions and database every time.
|
||||
#
|
||||
# This is replacing the one-after-one queries.
|
||||
# Find all revisions, that are in the database, and then remove them from the revision array.
|
||||
# Then later we won't need any conditions for db existence.
|
||||
# Query for several revisions at once, and remove them from the revisions array, if they are there.
|
||||
# Do this in chunks, to avoid eventual memory problems (in case of tens of thousands of commits).
|
||||
# If there are no revisions (because the original code's algorithm filtered them),
|
||||
# then this part will be stepped over.
|
||||
# We make queries, just if there is any revision.
|
||||
limit = 100
|
||||
offset = 0
|
||||
revisions_copy = revisions.clone # revisions will change
|
||||
while offset < revisions_copy.size
|
||||
recent_changesets_slice = changesets.find(
|
||||
:all,
|
||||
:conditions => [
|
||||
'scmid IN (?)',
|
||||
revisions_copy.slice(offset, limit).map{|x| x.scmid}
|
||||
]
|
||||
)
|
||||
# Subtract revisions that redmine already knows about
|
||||
recent_revisions = recent_changesets_slice.map{|c| c.scmid}
|
||||
revisions.reject!{|r| recent_revisions.include?(r.scmid)}
|
||||
offset += limit
|
||||
end
|
||||
|
||||
revisions.each do |rev|
|
||||
transaction do
|
||||
# There is no search in the db for this revision, because above we ensured,
|
||||
# that it's not in the db.
|
||||
save_revision(rev)
|
||||
end
|
||||
end
|
||||
h["heads"] = repo_heads.dup
|
||||
merge_extra_info(h)
|
||||
self.save
|
||||
end
|
||||
private :save_revisions
|
||||
|
||||
def save_revision(rev)
|
||||
parents = (rev.parents || []).collect{|rp| find_changeset_by_name(rp)}.compact
|
||||
changeset = Changeset.create(
|
||||
:repository => self,
|
||||
:revision => rev.identifier,
|
||||
:scmid => rev.scmid,
|
||||
:committer => rev.author,
|
||||
:committed_on => rev.time,
|
||||
:comments => rev.message,
|
||||
:parents => parents
|
||||
)
|
||||
unless changeset.new_record?
|
||||
rev.paths.each { |change| changeset.create_change(change) }
|
||||
end
|
||||
changeset
|
||||
end
|
||||
private :save_revision
|
||||
|
||||
def heads_from_branches_hash
|
||||
h1 = extra_info || {}
|
||||
h = h1.dup
|
||||
h["branches"] ||= {}
|
||||
h['branches'].map{|br, hs| hs['last_scmid']}
|
||||
end
|
||||
|
||||
def latest_changesets(path,rev,limit=10)
|
||||
revisions = scm.revisions(path, nil, rev, :limit => limit, :all => false)
|
||||
return [] if revisions.nil? || revisions.empty?
|
||||
|
||||
changesets.find(
|
||||
:all,
|
||||
:conditions => [
|
||||
"scmid IN (?)",
|
||||
revisions.map!{|c| c.scmid}
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def clear_extra_info_of_changesets
|
||||
return if extra_info.nil?
|
||||
v = extra_info["extra_report_last_commit"]
|
||||
write_attribute(:extra_info, nil)
|
||||
h = {}
|
||||
h["extra_report_last_commit"] = v
|
||||
merge_extra_info(h)
|
||||
self.save
|
||||
end
|
||||
private :clear_extra_info_of_changesets
|
||||
end
|
@ -1,2 +1,7 @@
|
||||
<% if @in_user_center%>
|
||||
$("#user_activity_<%= @user_activity_id%>").replaceWith("<%= escape_javascript(render :partial => 'users/user_blog', :locals => {:activity => @article,:user_activity_id =>@user_activity_id}) %>");
|
||||
init_activity_KindEditor_data(<%= @user_activity_id%>,"","87%");
|
||||
<% else%>
|
||||
$("#user_activity_<%= @user_activity_id%>").replaceWith("<%= escape_javascript(render :partial => 'blogs/article', :locals => {:activity => @article,:user_activity_id =>@user_activity_id,:first_user_activity =>@first_user_activity,:page => @page}) %>");
|
||||
init_activity_KindEditor_data(<%= @user_activity_id%>,"","87%");
|
||||
init_activity_KindEditor_data(<%= @user_activity_id%>,"","87%");
|
||||
<% end %>
|
@ -1,6 +1,10 @@
|
||||
$('#ajax-modal').html('<%= escape_javascript(render :partial => 'homework_common/set_evalutation_att') %>');
|
||||
var datepickerOptions={dateFormat: 'yy-mm-dd', firstDay: 0, showOn: 'button', buttonImageOnly: true, buttonImage: '/images/public_icon.png', showButtonPanel: true, showWeek: true, showOtherMonths: true, selectOtherMonths: true};
|
||||
showModal('ajax-modal', '350px');
|
||||
$('#ajax-modal').siblings().remove();
|
||||
$('#ajax-modal').before("<span style='float: right;cursor:pointer;'>" +
|
||||
"<a href='javascript:' onclick='clickCanel();'><img src='/images/bid/close.png' width='26px' height='26px' /></a></span>");
|
||||
$('#ajax-modal').parent().css("top","25%").css("left","35%").css("position","fixed");
|
||||
$('#ajax-modal').parent().css("top","25%").css("left","35%").css("position","fixed");
|
||||
$(function() { $('#evaluation_start_time').datepicker(datepickerOptions);
|
||||
$('#evaluation_end_time').datepicker(datepickerOptions);
|
||||
});
|
@ -1,32 +1,13 @@
|
||||
<%= link_to @repository.identifier.present? ? h(@repository.identifier) : 'root',
|
||||
{:action => 'show', :id => @project,
|
||||
:repository_id => @repository.identifier_param,
|
||||
:path => nil, :rev => @rev },
|
||||
:class=>"fl c_blue f14 fb" %>
|
||||
<%
|
||||
dirs = path.split('/')
|
||||
if 'file' == kind
|
||||
filename = dirs.pop
|
||||
end
|
||||
link_path = ''
|
||||
dirs.each do |dir|
|
||||
next if dir.blank?
|
||||
link_path << '/' unless link_path.empty?
|
||||
link_path << "#{dir}"
|
||||
%>
|
||||
/ <%= link_to h(dir), :action => 'show', :id => @project, :repository_id => @repository.identifier_param,
|
||||
:path => to_path_param(link_path), :rev => @rev %>
|
||||
<% end %>
|
||||
<% if filename %>
|
||||
/ <%= link_to h(filename),
|
||||
:action => 'changes', :id => @project, :repository_id => @repository.identifier_param,
|
||||
:path => to_path_param("#{link_path}/#{filename}"), :rev => @rev %>
|
||||
<% end %>
|
||||
<%
|
||||
# @rev is revsion or Git and Mercurial branch or tag.
|
||||
# For Mercurial *tip*, @rev and @changeset are nil.
|
||||
rev_text = @changeset.nil? ? @rev : format_revision(@changeset)
|
||||
%>
|
||||
<p class="fl f14 fb c_grey02"><%= "@ #{h rev_text}" unless rev_text.blank? %></p>
|
||||
<div class="git_usr_title">
|
||||
<span><%= link_to @repository.identifier.present? ? h(@repository.identifier) : 'root',
|
||||
{:action => 'show', :id => @project,
|
||||
:repository_id => @repository.identifier_param,
|
||||
:path => nil, :rev => @rev },
|
||||
:class => "repository-title-dec"
|
||||
%>
|
||||
/
|
||||
<%=link_to @project.owner, user_path(@project.owner), :class => "repository-title-dec" %>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<% html_title(with_leading_slash(path)) -%>
|
||||
|
@ -1,34 +1,33 @@
|
||||
<% content_for :header_tags do %>
|
||||
<%= javascript_include_tag 'repository_navigation' %>
|
||||
<% end %>
|
||||
<a href="javascript:void(0);" class="pic_stats fl ml20 mt3"></a>
|
||||
<%= link_to l(:label_statistics),
|
||||
<!--<a href="javascript:void(0);" class="pic_stats fl ml20 mt3"></a>-->
|
||||
<%#= link_to l(:label_statistics),
|
||||
{:action => 'stats', :id => @project, :repository_id => @repository.identifier_param},
|
||||
:class => 'mt3 c_blue fl' if @repository.supports_all_revisions? %>
|
||||
<div class="repositorytitle mr15">
|
||||
<% content_for :header_tags do %>
|
||||
<%= javascript_include_tag 'repository_navigation' %>
|
||||
<% end %>
|
||||
|
||||
<%= form_tag({:action => controller.action_name,
|
||||
:id => @project,
|
||||
:repository_id => @repository.identifier_param,
|
||||
:path => to_path_param(@path),
|
||||
:rev => nil},
|
||||
{:method => :get, :id => 'revision_selector', :class => "fl c_grey02 ml5"}) do -%>
|
||||
<!-- Branches Dropdown -->
|
||||
<% if !@repository.branches.nil? && @repository.branches.length > 0 -%>
|
||||
| <%= l(:label_branch) %>:
|
||||
<%= select_tag :branch,
|
||||
options_for_select([''] + @repository.branches, @rev),
|
||||
:id => 'branch' %>
|
||||
<% end -%>
|
||||
|
||||
<% if !@repository.tags.nil? && @repository.tags.length > 0 -%>
|
||||
| <%= l(:label_tag) %>:
|
||||
<%= select_tag :tag,
|
||||
options_for_select([''] + @repository.tags, @rev),
|
||||
:id => 'tag' %>
|
||||
<% end -%>
|
||||
|
||||
<% if @repository.supports_all_revisions? %>
|
||||
| <%= l(:label_revision) %>:
|
||||
<%= text_field_tag 'rev', @rev, :size => 8 %>
|
||||
<% end %>
|
||||
<% end -%>
|
||||
<%= form_tag({:action => controller.action_name,
|
||||
:id => @project,
|
||||
:repository_id => @repository.identifier_param,
|
||||
:path => to_path_param(@path),
|
||||
:rev => nil},
|
||||
{:method => :get, :id => 'revision_selector'}) do -%>
|
||||
<!-- Branches Dropdown -->
|
||||
<% if !@repository.branches.nil? && @repository.branches.length > 0 -%>
|
||||
<%= l(:label_branch) %>:
|
||||
<%= select_tag :branch, options_for_select([''] + @repository.branches, @rev), :id => 'branch' %>
|
||||
<% end -%>
|
||||
|
||||
<% if !@repository.tags.nil? && @repository.tags.length > 0 -%>
|
||||
<%= select_tag :tag, options_for_select([''] + @repository.tags, @rev), :id => 'tag', :style=>" display:none" %>
|
||||
<% end -%>
|
||||
|
||||
<% if @repository.supports_all_revisions? %>
|
||||
<%= hidden_field_tag 'rev', @rev, :size => 8 %>
|
||||
<% end %>
|
||||
<% end -%>
|
||||
|
||||
</div>
|
||||
|
@ -0,0 +1,37 @@
|
||||
<div class="overall-summary overall-summary-bottomless">
|
||||
|
||||
<div class="stats-switcher-viewport js-stats-switcher-viewport">
|
||||
<div class="stats-switcher-wrapper">
|
||||
<ul class="numbers-summary">
|
||||
<li class="commits">
|
||||
<a data-pjax="" href="/redmine/redmine/commits/0.6-stable">
|
||||
<span class="octicon octicon-history"></span>
|
||||
<span class="num text-emphasized">
|
||||
<%=link_to @changesets.count, {:action => 'changes', :path => to_path_param(@path), :id => @project, :repository_id => @repository.identifier_param, :rev => @rev}, :class => "num text-emphasized c_blue" %>
|
||||
</span>
|
||||
commits
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<span class="octicon image-type"></span>
|
||||
<span class="num text-emphasized" style="color: #269AC9">
|
||||
<%= @repository.branches.count %>
|
||||
</span>
|
||||
branches
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<span class="octicon octicon-organization"></span>
|
||||
<span class="num text-emphasized">
|
||||
<%=link_to @repository.committers.count, committers_repository_path(@repository), :class => "c_blue" %>
|
||||
</span>
|
||||
contributors
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
@ -0,0 +1,12 @@
|
||||
<div class="repository-update-dec">
|
||||
<p class="c_orange">
|
||||
<%= l(:label_repository_migrate_dec) %>
|
||||
</p>
|
||||
<%= form_for(@repository, url: to_gitlab_project_repository_path(@project, @repository)) do |f| %>
|
||||
<input type="text" name="repo_name"/>
|
||||
<button type="submit">转换到新版本</button>
|
||||
<% end %>
|
||||
<span class="c_grey">
|
||||
<%= l(:label_repository_name_dec) %>
|
||||
</span>
|
||||
</div>
|
@ -1,66 +1,9 @@
|
||||
<%= form_for('new_form',:url => {:controller => 'student_work',:action => 'set_score_rule',:homework => homework.id},:method => "post") do |f|%>
|
||||
<% if student_path %>
|
||||
<%=hidden_field_tag 'student_path', params[:student_path], :value => student_path %>
|
||||
<% end %>
|
||||
<div class="markPopup" id="popbox02">
|
||||
<span class="uploadText">评分设置</span>
|
||||
<div class="mt15">
|
||||
<span class="f14 fontGrey3 mr10">迟交扣分</span>
|
||||
<input type="text" name="late_penalty" id="late_penalty_num" placeholder="请输入0-50数值" class=" markInput" value="<%= homework.late_penalty%>" onkeyup="check_late_penalty('late_penalty_num')"/>
|
||||
</div>
|
||||
<div>
|
||||
<span class="f14 fontGrey3 mr10">缺评扣分</span>
|
||||
<input type="text" name="absence_penalty" id="absence_penalty_num" placeholder="请输入0-50数值" class="markInput" value="<%= homework.homework_detail_manual.absence_penalty%>" onkeyup="check_late_penalty('absence_penalty_num')"/>
|
||||
</div>
|
||||
|
||||
<% if homework.homework_type == 2%>
|
||||
<div>
|
||||
<span class="f14 fontGrey3 mr10">系统评分</span>
|
||||
<%= select_tag :sy_proportion,options_for_select(ta_proportion_option,homework.homework_detail_programing.ta_proportion), {:class => "markPercentage"} %>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$("#sy_proportion").change(function(){
|
||||
var ta_proportion = 100 - parseInt($("#sy_proportion").val() * 100);
|
||||
$("#ta_proportion").replaceWith(build_selector(ta_proportion));
|
||||
$("#student_proportion").val("0%");
|
||||
});
|
||||
|
||||
$("#ta_proportion").live("change",function(){
|
||||
var ta_proportion = 100 - parseInt($("#sy_proportion").val() * 100) - parseInt($("#ta_proportion").val() * 100);
|
||||
$("#student_proportion").val(ta_proportion + "%");
|
||||
});
|
||||
</script>
|
||||
<% else%>
|
||||
<script>
|
||||
$("#ta_proportion").change(function(){
|
||||
var ta_proportion = $("#ta_proportion").val();
|
||||
$("#student_proportion").val((100 - parseInt(ta_proportion * 100)) + "%");
|
||||
});
|
||||
</script>
|
||||
<% end%>
|
||||
|
||||
<div>
|
||||
<span class="f14 fontGrey3 mr10">教辅评分</span>
|
||||
<%= select_tag :ta_proportion,options_for_select(ta_proportion_option_to(100-(homework.homework_detail_programing ? homework.homework_detail_programing.ta_proportion * 100 : 0).to_i),homework.homework_detail_manual.ta_proportion), {:class => "markPercentage"} %>
|
||||
</div>
|
||||
<div>
|
||||
<span class="f14 fontGrey3 mr10">学生匿评</span>
|
||||
<input type="text" id="student_proportion" value="<%= (100 - homework.homework_detail_manual.ta_proportion * 100).to_i - (homework.homework_detail_programing ? homework.homework_detail_programing.ta_proportion * 100 : 0).to_i%>%" class="markPercentage" readonly>
|
||||
</div>
|
||||
<div class="mb20">
|
||||
<span class="f14 fontGrey3 mr10">教师优先</span>
|
||||
<input type="checkbox" name="teacher_priority" <%= homework.teacher_priority == 1 ? 'checked' : ''%>/>
|
||||
<span class="f12 c_red ml10">教师评分为最终评分</span>
|
||||
</div>
|
||||
<div>
|
||||
<div class="courseSendSubmit">
|
||||
<a href="javascript:void(0);" class="sendSourceText" onclick="$('#ajax-modal').find('form').submit();">确定</a>
|
||||
</div>
|
||||
<div class="courseSendCancel">
|
||||
<a href="javascript:void(0);" class="sendSourceText linkGrey6" onclick="clickCanel();">取消</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
<% end%>
|
||||
<% if student_path%>
|
||||
<%= form_for('new_form',:url => {:controller => 'student_work',:action => 'set_score_rule',:homework => homework.id,:student_path => student_path},:method => "post") do |f|%>
|
||||
<% render :partial => 'student_work/set_score_rule_detail', :locals => {:homework => homework, :f => f}%>
|
||||
<% end%>
|
||||
<% else %>
|
||||
<%= form_for('new_form',:url => {:controller => 'student_work',:action => 'set_score_rule',:homework => homework.id,:user_activity_id=>user_activity_id,:is_in_course=>is_in_course},:method => "post",:remote => true) do |f|%>
|
||||
<% render :partial => 'student_work/set_score_rule_detail', :locals => {:homework => homework, :f => f}%>
|
||||
<% end%>
|
||||
<% end %>
|
@ -0,0 +1,61 @@
|
||||
<div class="markPopup" id="popbox02">
|
||||
<span class="uploadText">评分设置</span>
|
||||
<div class="mt15">
|
||||
<span class="f14 fontGrey3 mr10">迟交扣分</span>
|
||||
<input type="text" name="late_penalty" id="late_penalty_num" placeholder="请输入0-50数值" class=" markInput" value="<%= homework.late_penalty%>" onkeyup="check_late_penalty('late_penalty_num')"/>
|
||||
</div>
|
||||
<div>
|
||||
<span class="f14 fontGrey3 mr10">缺评扣分</span>
|
||||
<input type="text" name="absence_penalty" id="absence_penalty_num" placeholder="请输入0-50数值" class="markInput" value="<%= homework.homework_detail_manual.absence_penalty%>" onkeyup="check_late_penalty('absence_penalty_num')"/>
|
||||
</div>
|
||||
|
||||
<% if homework.homework_type == 2%>
|
||||
<div>
|
||||
<span class="f14 fontGrey3 mr10">系统评分</span>
|
||||
<%= select_tag :sy_proportion,options_for_select(ta_proportion_option,homework.homework_detail_programing.ta_proportion), {:class => "markPercentage"} %>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$("#sy_proportion").change(function(){
|
||||
var ta_proportion = 100 - parseInt($("#sy_proportion").val() * 100);
|
||||
$("#ta_proportion").replaceWith(build_selector(ta_proportion));
|
||||
$("#student_proportion").val("0%");
|
||||
});
|
||||
|
||||
$("#ta_proportion").live("change",function(){
|
||||
var ta_proportion = 100 - parseInt($("#sy_proportion").val() * 100) - parseInt($("#ta_proportion").val() * 100);
|
||||
$("#student_proportion").val(ta_proportion + "%");
|
||||
});
|
||||
</script>
|
||||
<% else%>
|
||||
<script>
|
||||
$("#ta_proportion").change(function(){
|
||||
var ta_proportion = $("#ta_proportion").val();
|
||||
$("#student_proportion").val((100 - parseInt(ta_proportion * 100)) + "%");
|
||||
});
|
||||
</script>
|
||||
<% end%>
|
||||
|
||||
<div>
|
||||
<span class="f14 fontGrey3 mr10">教辅评分</span>
|
||||
<%= select_tag :ta_proportion,options_for_select(ta_proportion_option_to(100-(homework.homework_detail_programing ? homework.homework_detail_programing.ta_proportion * 100 : 0).to_i),homework.homework_detail_manual.ta_proportion), {:class => "markPercentage"} %>
|
||||
</div>
|
||||
<div>
|
||||
<span class="f14 fontGrey3 mr10">学生匿评</span>
|
||||
<input type="text" id="student_proportion" value="<%= (100 - homework.homework_detail_manual.ta_proportion * 100).to_i - (homework.homework_detail_programing ? homework.homework_detail_programing.ta_proportion * 100 : 0).to_i%>%" class="markPercentage" readonly>
|
||||
</div>
|
||||
<div class="mb20">
|
||||
<span class="f14 fontGrey3 mr10">教师优先</span>
|
||||
<input type="checkbox" name="teacher_priority" <%= homework.teacher_priority == 1 ? 'checked' : ''%>/>
|
||||
<span class="f12 c_red ml10">教师评分为最终评分</span>
|
||||
</div>
|
||||
<div>
|
||||
<div class="courseSendSubmit">
|
||||
<a href="javascript:void(0);" class="sendSourceText" onclick="$('#ajax-modal').find('form').submit();">确定</a>
|
||||
</div>
|
||||
<div class="courseSendCancel">
|
||||
<a href="javascript:void(0);" class="sendSourceText linkGrey6" onclick="clickCanel();">取消</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
@ -0,0 +1,8 @@
|
||||
clickCanel();
|
||||
<% if @user_activity_id %>
|
||||
$("#user_activity_<%= @user_activity_id%>").replaceWith("<%= escape_javascript(render :partial => 'users/course_homework', :locals => {:activity => @homework,:user_activity_id =>@user_activity_id}) %>");
|
||||
init_activity_KindEditor_data(<%= @user_activity_id%>,"","87%");
|
||||
<% else %>
|
||||
$("#homework_common_<%= @homework.id %>").replaceWith("<%= escape_javascript(render :partial => 'users/user_homework_detail', :locals => {:homework_common => @homework,:is_in_course => @is_in_course}) %>");
|
||||
init_activity_KindEditor_data(<%= @homework.id%>,"","87%");
|
||||
<% end %>
|
@ -0,0 +1,9 @@
|
||||
Gitlab.configure do |config|
|
||||
# config.endpoint = 'http://192.168.41.130:3000/trustie/api/v3' # API endpoint URL, default: ENV['GITLAB_API_ENDPOINT']
|
||||
# config.private_token = 'cK15gUDwvt8EEkzwQ_63' # user's private token, default: ENV['GITLAB_API_PRIVATE_TOKEN']
|
||||
config.endpoint = 'http://git.trustie.net/trustie/api/v3' # API endpoint URL, default: ENV['GITLAB_API_ENDPOINT']
|
||||
config.private_token = 'fPc_gBmEiSANve8TCfxW' # user's private token, default: ENV['GITLAB_API_PRIVATE_TOKEN']
|
||||
# Optional
|
||||
# config.user_agent = 'Custom User Agent' # user agent, default: 'Gitlab Ruby Gem [version]'
|
||||
# config.sudo = 'user' # username for sudo mode, default: nil
|
||||
end
|
@ -0,0 +1,5 @@
|
||||
class AddGitlabUserIdToUsers < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :users, :gid, :integer
|
||||
end
|
||||
end
|
@ -0,0 +1,5 @@
|
||||
class AddGpidToProject < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :projects, :gpid, :integer
|
||||
end
|
||||
end
|
@ -0,0 +1,4 @@
|
||||
source 'https://rubygems.org'
|
||||
|
||||
# Specify your gem's dependencies in gitlab.gemspec
|
||||
gemspec
|
@ -0,0 +1,24 @@
|
||||
Copyright (c) 2012-2014 Nihad Abbasov <mail@narkoz.me>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
@ -0,0 +1,121 @@
|
||||
# Gitlab
|
||||
|
||||
[](http://travis-ci.org/NARKOZ/gitlab)
|
||||
|
||||
[website](http://narkoz.github.io/gitlab) |
|
||||
[documentation](http://rubydoc.info/gems/gitlab/frames)
|
||||
|
||||
Gitlab is a Ruby wrapper and CLI for the [GitLab API](https://github.com/gitlabhq/gitlabhq/tree/master/doc/api#gitlab-api).
|
||||
|
||||
## Installation
|
||||
|
||||
Install it from rubygems:
|
||||
|
||||
```sh
|
||||
gem install gitlab
|
||||
```
|
||||
|
||||
Or add to a Gemfile:
|
||||
|
||||
```ruby
|
||||
gem 'gitlab'
|
||||
# gem 'gitlab', :git => 'git://github.com/NARKOZ/gitlab.git'
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Configuration example:
|
||||
|
||||
```ruby
|
||||
Gitlab.configure do |config|
|
||||
config.endpoint = 'https://example.net/api/v3' # API endpoint URL, default: ENV['GITLAB_API_ENDPOINT']
|
||||
config.private_token = 'qEsq1pt6HJPaNciie3MG' # user's private token, default: ENV['GITLAB_API_PRIVATE_TOKEN']
|
||||
# Optional
|
||||
# config.user_agent = 'Custom User Agent' # user agent, default: 'Gitlab Ruby Gem [version]'
|
||||
# config.sudo = 'user' # username for sudo mode, default: nil
|
||||
end
|
||||
```
|
||||
|
||||
(Note: If you are using Gitlab.com's hosted service, your endpoint will be `https://gitlab.com/api/v3`)
|
||||
|
||||
Usage examples:
|
||||
|
||||
```ruby
|
||||
# set an API endpoint
|
||||
Gitlab.endpoint = 'http://example.net/api/v3'
|
||||
# => "http://example.net/api/v3"
|
||||
|
||||
# set a user private token
|
||||
Gitlab.private_token = 'qEsq1pt6HJPaNciie3MG'
|
||||
# => "qEsq1pt6HJPaNciie3MG"
|
||||
|
||||
# list projects
|
||||
Gitlab.projects(:per_page => 5)
|
||||
# => [#<Gitlab::ObjectifiedHash:0x000000023326e0 @data={"id"=>1, "code"=>"brute", "name"=>"Brute", "description"=>nil, "path"=>"brute", "default_branch"=>nil, "owner"=>#<Gitlab::ObjectifiedHash:0x00000002331600 @data={"id"=>1, "email"=>"john@example.com", "name"=>"John Smith", "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}>, "private"=>true, "issues_enabled"=>true, "merge_requests_enabled"=>true, "wall_enabled"=>true, "wiki_enabled"=>true, "created_at"=>"2012-09-17T09:41:56Z"}>, #<Gitlab::ObjectifiedHash:0x000000023450d8 @data={"id"=>2, "code"=>"mozart", "name"=>"Mozart", "description"=>nil, "path"=>"mozart", "default_branch"=>nil, "owner"=>#<Gitlab::ObjectifiedHash:0x00000002344ca0 @data={"id"=>1, "email"=>"john@example.com", "name"=>"John Smith", "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}>, "private"=>true, "issues_enabled"=>true, "merge_requests_enabled"=>true, "wall_enabled"=>true, "wiki_enabled"=>true, "created_at"=>"2012-09-17T09:41:57Z"}>, #<Gitlab::ObjectifiedHash:0x00000002344958 @data={"id"=>3, "code"=>"gitlab", "name"=>"Gitlab", "description"=>nil, "path"=>"gitlab", "default_branch"=>nil, "owner"=>#<Gitlab::ObjectifiedHash:0x000000023447a0 @data={"id"=>1, "email"=>"john@example.com", "name"=>"John Smith", "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}>, "private"=>true, "issues_enabled"=>true, "merge_requests_enabled"=>true, "wall_enabled"=>true, "wiki_enabled"=>true, "created_at"=>"2012-09-17T09:41:58Z"}>]
|
||||
|
||||
# initialize a new client
|
||||
g = Gitlab.client(:endpoint => 'https://api.example.com', :private_token => 'qEsq1pt6HJPaNciie3MG')
|
||||
# => #<Gitlab::Client:0x00000001e62408 @endpoint="https://api.example.com", @private_token="qEsq1pt6HJPaNciie3MG", @user_agent="Gitlab Ruby Gem 2.0.0">
|
||||
|
||||
# get a user
|
||||
user = g.user
|
||||
# => #<Gitlab::ObjectifiedHash:0x00000002217990 @data={"id"=>1, "email"=>"john@example.com", "name"=>"John Smith", "bio"=>nil, "skype"=>"", "linkedin"=>"", "twitter"=>"john", "dark_scheme"=>false, "theme_id"=>1, "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}>
|
||||
|
||||
# get a user's email
|
||||
user.email
|
||||
# => "john@example.com"
|
||||
|
||||
# set a sudo mode to perform API calls as another user
|
||||
Gitlab.sudo = 'other_user'
|
||||
# => "other_user"
|
||||
|
||||
# disable a sudo mode
|
||||
Gitlab.sudo = nil
|
||||
# => nil
|
||||
```
|
||||
|
||||
For more information, refer to [documentation](http://rubydoc.info/gems/gitlab/frames).
|
||||
|
||||
## CLI
|
||||
|
||||
Usage examples:
|
||||
|
||||
```sh
|
||||
# list users
|
||||
gitlab users
|
||||
|
||||
# get current user
|
||||
gitlab user
|
||||
|
||||
# get a user
|
||||
gitlab user 2
|
||||
|
||||
# filter output
|
||||
gitlab user --only=id,username
|
||||
|
||||
gitlab user --except=email,bio
|
||||
```
|
||||
|
||||
## CLI Shell
|
||||
|
||||
Usage examples:
|
||||
|
||||
```sh
|
||||
# start shell session
|
||||
gitlab shell
|
||||
|
||||
# list available commands
|
||||
gitlab> help
|
||||
|
||||
# list groups
|
||||
gitlab> groups
|
||||
|
||||
# protect a branch
|
||||
gitlab> protect_branch 1 master
|
||||
```
|
||||
|
||||
For more information, refer to [website](http://narkoz.github.io/gitlab).
|
||||
|
||||
## License
|
||||
|
||||
Released under the BSD 2-clause license. See LICENSE.txt for details.
|
@ -0,0 +1,9 @@
|
||||
require "bundler/gem_tasks"
|
||||
|
||||
require 'rspec/core/rake_task'
|
||||
RSpec::Core::RakeTask.new(:spec) do |spec|
|
||||
spec.pattern = FileList['spec/**/*_spec.rb']
|
||||
spec.rspec_opts = ['--color', '--format d']
|
||||
end
|
||||
|
||||
task :default => :spec
|
@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
$:.unshift File.expand_path('../../lib', __FILE__)
|
||||
|
||||
require 'gitlab/cli'
|
||||
|
||||
Gitlab::CLI.start(ARGV)
|
@ -0,0 +1,26 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
lib = File.expand_path('../lib', __FILE__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
require 'gitlab/version'
|
||||
|
||||
Gem::Specification.new do |gem|
|
||||
gem.name = "gitlab"
|
||||
gem.version = Gitlab::VERSION
|
||||
gem.authors = ["Nihad Abbasov"]
|
||||
gem.email = ["mail@narkoz.me"]
|
||||
gem.description = %q{Ruby client and CLI for GitLab API}
|
||||
gem.summary = %q{A Ruby wrapper and CLI for the GitLab API}
|
||||
gem.homepage = "https://github.com/narkoz/gitlab"
|
||||
|
||||
gem.files = `git ls-files`.split($/)
|
||||
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
||||
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
||||
gem.require_paths = ["lib"]
|
||||
|
||||
gem.add_runtime_dependency 'httparty'
|
||||
gem.add_runtime_dependency 'terminal-table'
|
||||
|
||||
gem.add_development_dependency 'rake'
|
||||
gem.add_development_dependency 'rspec'
|
||||
gem.add_development_dependency 'webmock'
|
||||
end
|
@ -0,0 +1,37 @@
|
||||
require 'gitlab/version'
|
||||
require 'gitlab/objectified_hash'
|
||||
require 'gitlab/configuration'
|
||||
require 'gitlab/error'
|
||||
require 'gitlab/request'
|
||||
require 'gitlab/api'
|
||||
require 'gitlab/client'
|
||||
|
||||
module Gitlab
|
||||
extend Configuration
|
||||
|
||||
# Alias for Gitlab::Client.new
|
||||
#
|
||||
# @return [Gitlab::Client]
|
||||
def self.client(options={})
|
||||
Gitlab::Client.new(options)
|
||||
end
|
||||
|
||||
# Delegate to Gitlab::Client
|
||||
def self.method_missing(method, *args, &block)
|
||||
return super unless client.respond_to?(method)
|
||||
client.send(method, *args, &block)
|
||||
end
|
||||
|
||||
# Delegate to Gitlab::Client
|
||||
def self.respond_to?(method)
|
||||
return client.respond_to?(method) || super
|
||||
end
|
||||
|
||||
# Returns an unsorted array of available client methods.
|
||||
#
|
||||
# @return [Array<Symbol>]
|
||||
def self.actions
|
||||
hidden = /endpoint|private_token|user_agent|sudo|get|post|put|\Adelete\z|validate|set_request_defaults/
|
||||
(Gitlab::Client.instance_methods - Object.methods).reject {|e| e[hidden]}
|
||||
end
|
||||
end
|
@ -0,0 +1,17 @@
|
||||
module Gitlab
|
||||
# @private
|
||||
class API < Request
|
||||
# @private
|
||||
attr_accessor(*Configuration::VALID_OPTIONS_KEYS)
|
||||
|
||||
# Creates a new API.
|
||||
# @raise [Error:MissingCredentials]
|
||||
def initialize(options={})
|
||||
options = Gitlab.options.merge(options)
|
||||
Configuration::VALID_OPTIONS_KEYS.each do |key|
|
||||
send("#{key}=", options[key])
|
||||
end
|
||||
set_request_defaults @endpoint, @private_token, @sudo
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,47 @@
|
||||
require 'gitlab'
|
||||
require 'terminal-table/import'
|
||||
require_relative 'cli_helpers'
|
||||
require_relative 'shell'
|
||||
|
||||
class Gitlab::CLI
|
||||
extend Helpers
|
||||
|
||||
def self.start(args)
|
||||
command = args.shift.strip rescue 'help'
|
||||
run(command, args)
|
||||
end
|
||||
|
||||
def self.run(cmd, args=[])
|
||||
case cmd
|
||||
when 'help'
|
||||
puts actions_table
|
||||
when 'info'
|
||||
endpoint = Gitlab.endpoint ? Gitlab.endpoint : 'not set'
|
||||
private_token = Gitlab.private_token ? Gitlab.private_token : 'not set'
|
||||
puts "Gitlab endpoint is #{endpoint}"
|
||||
puts "Gitlab private token is #{private_token}"
|
||||
puts "Ruby Version is #{RUBY_VERSION}"
|
||||
puts "Gitlab Ruby Gem #{Gitlab::VERSION}"
|
||||
when '-v', '--version'
|
||||
puts "Gitlab Ruby Gem #{Gitlab::VERSION}"
|
||||
when 'shell'
|
||||
Gitlab::Shell.start
|
||||
else
|
||||
unless valid_command?(cmd)
|
||||
puts "Unknown command. Run `gitlab help` for a list of available commands."
|
||||
exit(1)
|
||||
end
|
||||
|
||||
if args.any? && (args.last.start_with?('--only=') || args.last.start_with?('--except='))
|
||||
command_args = args[0..-2]
|
||||
else
|
||||
command_args = args
|
||||
end
|
||||
|
||||
confirm_command(cmd)
|
||||
|
||||
data = gitlab_helper(cmd, command_args) { exit(1) }
|
||||
output_table(cmd, args, data)
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,175 @@
|
||||
class Gitlab::CLI
|
||||
# Defines methods related to CLI output and formatting.
|
||||
module Helpers
|
||||
extend self
|
||||
|
||||
# Returns filtered required fields.
|
||||
#
|
||||
# @return [Array]
|
||||
def required_fields(args)
|
||||
if args.any? && args.last.start_with?('--only=')
|
||||
args.last.gsub('--only=', '').split(',')
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
# Returns filtered excluded fields.
|
||||
#
|
||||
# @return [Array]
|
||||
def excluded_fields(args)
|
||||
if args.any? && args.last.start_with?('--except=')
|
||||
args.last.gsub('--except=', '').split(',')
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
# Confirms command is valid.
|
||||
#
|
||||
# @return [Boolean]
|
||||
def valid_command?(cmd)
|
||||
command = cmd.is_a?(Symbol) ? cmd : cmd.to_sym
|
||||
Gitlab.actions.include?(command)
|
||||
end
|
||||
|
||||
# Confirms command with a desctructive action.
|
||||
#
|
||||
# @return [String]
|
||||
def confirm_command(cmd)
|
||||
if cmd.start_with?('remove_') || cmd.start_with?('delete_')
|
||||
puts "Are you sure? (y/n)"
|
||||
if %w(y yes).include?($stdin.gets.to_s.strip.downcase)
|
||||
puts 'Proceeding..'
|
||||
else
|
||||
puts 'Command aborted.'
|
||||
exit(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Table with available commands.
|
||||
#
|
||||
# @return [String]
|
||||
def actions_table
|
||||
client = Gitlab::Client.new(endpoint: '')
|
||||
actions = Gitlab.actions
|
||||
methods = []
|
||||
|
||||
actions.each do |action|
|
||||
methods << {
|
||||
name: action,
|
||||
owner: client.method(action).owner.to_s.gsub('Gitlab::Client::', '')
|
||||
}
|
||||
end
|
||||
|
||||
owners = methods.map {|m| m[:owner]}.uniq.sort
|
||||
methods_c = methods.group_by {|m| m[:owner]}
|
||||
methods_c = methods_c.map {|_, v| [_, v.sort_by {|hv| hv[:name]}] }
|
||||
methods_c = Hash[methods_c.sort_by(&:first).map {|k, v| [k, v]}]
|
||||
max_column_length = methods_c.values.max_by(&:size).size
|
||||
|
||||
rows = max_column_length.times.map do |i|
|
||||
methods_c.keys.map do |key|
|
||||
methods_c[key][i] ? methods_c[key][i][:name] : ''
|
||||
end
|
||||
end
|
||||
|
||||
table do |t|
|
||||
t.title = "Available commands (#{actions.size} total)"
|
||||
t.headings = owners
|
||||
|
||||
rows.each do |row|
|
||||
t.add_row row
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Decides which table to use.
|
||||
#
|
||||
# @return [String]
|
||||
def output_table(cmd, args, data)
|
||||
case data
|
||||
when Gitlab::ObjectifiedHash
|
||||
puts single_record_table(data, cmd, args)
|
||||
when Array
|
||||
puts multiple_record_table(data, cmd, args)
|
||||
else
|
||||
puts data.inspect
|
||||
end
|
||||
end
|
||||
|
||||
# Table for a single record.
|
||||
#
|
||||
# @return [String]
|
||||
def single_record_table(data, cmd, args)
|
||||
hash = data.to_h
|
||||
keys = hash.keys.sort {|x, y| x.to_s <=> y.to_s }
|
||||
keys = keys & required_fields(args) if required_fields(args).any?
|
||||
keys = keys - excluded_fields(args)
|
||||
|
||||
table do |t|
|
||||
t.title = "Gitlab.#{cmd} #{args.join(', ')}"
|
||||
|
||||
keys.each_with_index do |key, index|
|
||||
case value = hash[key]
|
||||
when Hash
|
||||
value = 'Hash'
|
||||
when nil
|
||||
value = 'null'
|
||||
end
|
||||
|
||||
t.add_row [key, value]
|
||||
t.add_separator unless keys.size - 1 == index
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Table for multiple records.
|
||||
#
|
||||
# @return [String]
|
||||
def multiple_record_table(data, cmd, args)
|
||||
return 'No data' if data.empty?
|
||||
|
||||
arr = data.map(&:to_h)
|
||||
keys = arr.first.keys.sort {|x, y| x.to_s <=> y.to_s }
|
||||
keys = keys & required_fields(args) if required_fields(args).any?
|
||||
keys = keys - excluded_fields(args)
|
||||
|
||||
table do |t|
|
||||
t.title = "Gitlab.#{cmd} #{args.join(', ')}"
|
||||
t.headings = keys
|
||||
|
||||
arr.each_with_index do |hash, index|
|
||||
values = []
|
||||
|
||||
keys.each do |key|
|
||||
case value = hash[key]
|
||||
when Hash
|
||||
value = 'Hash'
|
||||
when nil
|
||||
value = 'null'
|
||||
end
|
||||
|
||||
values << value
|
||||
end
|
||||
|
||||
t.add_row values
|
||||
t.add_separator unless arr.size - 1 == index
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Helper function to call Gitlab commands with args.
|
||||
def gitlab_helper(cmd, args=[])
|
||||
begin
|
||||
data = args.any? ? Gitlab.send(cmd, *args) : Gitlab.send(cmd)
|
||||
rescue => e
|
||||
puts e.message
|
||||
yield if block_given?
|
||||
end
|
||||
|
||||
data
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,18 @@
|
||||
module Gitlab
|
||||
# Wrapper for the Gitlab REST API.
|
||||
class Client < API
|
||||
Dir[File.expand_path('../client/*.rb', __FILE__)].each {|f| require f}
|
||||
|
||||
include Branches
|
||||
include Groups
|
||||
include Issues
|
||||
include MergeRequests
|
||||
include Milestones
|
||||
include Notes
|
||||
include Projects
|
||||
include Repositories
|
||||
include Snippets
|
||||
include SystemHooks
|
||||
include Users
|
||||
end
|
||||
end
|
@ -0,0 +1,79 @@
|
||||
class Gitlab::Client
|
||||
# Defines methods related to repositories.
|
||||
module Branches
|
||||
# Gets a list of project repositiory branches.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.branches(42)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def branches(project, options={})
|
||||
get("/projects/#{project}/repository/branches", :query => options)
|
||||
end
|
||||
alias_method :repo_branches, :branches
|
||||
|
||||
# Gets information about a repository branch.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.branch(3, 'api')
|
||||
# Gitlab.repo_branch(5, 'master')
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [String] branch The name of the branch.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def branch(project, branch)
|
||||
get("/projects/#{project}/repository/branches/#{branch}")
|
||||
end
|
||||
|
||||
alias_method :repo_branch, :branch
|
||||
|
||||
# Protects a repository branch.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.protect_branch(3, 'api')
|
||||
# Gitlab.repo_protect_branch(5, 'master')
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [String] branch The name of the branch.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def protect_branch(project, branch)
|
||||
put("/projects/#{project}/repository/branches/#{branch}/protect")
|
||||
end
|
||||
alias_method :repo_protect_branch, :protect_branch
|
||||
|
||||
# Unprotects a repository branch.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.unprotect_branch(3, 'api')
|
||||
# Gitlab.repo_unprotect_branch(5, 'master')
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [String] branch The name of the branch.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def unprotect_branch(project, branch)
|
||||
put("/projects/#{project}/repository/branches/#{branch}/unprotect")
|
||||
end
|
||||
alias_method :repo_unprotect_branch, :unprotect_branch
|
||||
|
||||
# Creates a repository branch. Requires Gitlab >= 6.8.x
|
||||
#
|
||||
# @example
|
||||
# Gitlab.create_branch(3, 'api')
|
||||
# Gitlab.repo_create_branch(5, 'master')
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [String] branch The name of the new branch.
|
||||
# @param [String] ref Create branch from commit sha or existing branch
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def create_branch(project, branch, ref)
|
||||
post("/projects/#{project}/repository/branches",:body => {:branch_name => branch, :ref => ref})
|
||||
end
|
||||
alias_method :repo_create_branch, :create_branch
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -0,0 +1,88 @@
|
||||
class Gitlab::Client
|
||||
# Defines methods related to groups.
|
||||
module Groups
|
||||
# Gets a list of groups.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.groups
|
||||
# Gitlab.groups(:per_page => 40)
|
||||
#
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def groups(options={})
|
||||
get("/groups", :query => options)
|
||||
end
|
||||
|
||||
# Gets a single group.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.group(42)
|
||||
#
|
||||
# @param [Integer] id The ID of a group.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def group(id)
|
||||
get("/groups/#{id}")
|
||||
end
|
||||
|
||||
# Creates a new group.
|
||||
#
|
||||
# @param [String] name The name of a group.
|
||||
# @param [String] path The path of a group.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created group.
|
||||
def create_group(name, path)
|
||||
body = {:name => name, :path => path}
|
||||
post("/groups", :body => body)
|
||||
end
|
||||
|
||||
# Get a list of group members.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.group_members(1)
|
||||
# Gitlab.group_members(1, :per_page => 40)
|
||||
#
|
||||
# @param [Integer] id The ID of a group.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def group_members(id, options={})
|
||||
get("/groups/#{id}/members", :query => options)
|
||||
end
|
||||
|
||||
# Adds a user to group.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.add_group_member(1, 2, 40)
|
||||
#
|
||||
# @param [Integer] team_id The group id to add a member to.
|
||||
# @param [Integer] user_id The user id of the user to add to the team.
|
||||
# @param [Integer] access_level Project access level.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about added team member.
|
||||
def add_group_member(team_id, user_id, access_level)
|
||||
post("/groups/#{team_id}/members", :body => {:user_id => user_id, :access_level => access_level})
|
||||
end
|
||||
|
||||
# Removes user from user group.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.remove_group_member(1, 2)
|
||||
#
|
||||
# @param [Integer] team_id The group ID.
|
||||
# @param [Integer] user_id The ID of a user.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about removed team member.
|
||||
def remove_group_member(team_id, user_id)
|
||||
delete("/groups/#{team_id}/members/#{user_id}")
|
||||
end
|
||||
|
||||
# Transfers a project to a group
|
||||
#
|
||||
# @param [Integer] id The ID of a group.
|
||||
# @param [Integer] project_id The ID of a project.
|
||||
def transfer_project_to_group(id, project_id)
|
||||
body = {:id => id, :project_id => project_id}
|
||||
post("/groups/#{id}/projects/#{project_id}", :body => body)
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,92 @@
|
||||
class Gitlab::Client
|
||||
# Defines methods related to issues.
|
||||
module Issues
|
||||
# Gets a list of user's issues.
|
||||
# Will return a list of project's issues if project ID passed.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.issues
|
||||
# Gitlab.issues(5)
|
||||
# Gitlab.issues(:per_page => 40)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def issues(project=nil, options={})
|
||||
if project.to_i.zero?
|
||||
get("/issues", :query => options)
|
||||
else
|
||||
get("/projects/#{project}/issues", :query => options)
|
||||
end
|
||||
end
|
||||
|
||||
# Gets a single issue.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.issue(5, 42)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of an issue.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def issue(project, id)
|
||||
get("/projects/#{project}/issues/#{id}")
|
||||
end
|
||||
|
||||
# Creates a new issue.
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [String] title The title of an issue.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [String] :description The description of an issue.
|
||||
# @option options [Integer] :assignee_id The ID of a user to assign issue.
|
||||
# @option options [Integer] :milestone_id The ID of a milestone to assign issue.
|
||||
# @option options [String] :labels Comma-separated label names for an issue.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created issue.
|
||||
def create_issue(project, title, options={})
|
||||
body = {:title => title}.merge(options)
|
||||
post("/projects/#{project}/issues", :body => body)
|
||||
end
|
||||
|
||||
# Updates an issue.
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of an issue.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [String] :title The title of an issue.
|
||||
# @option options [String] :description The description of an issue.
|
||||
# @option options [Integer] :assignee_id The ID of a user to assign issue.
|
||||
# @option options [Integer] :milestone_id The ID of a milestone to assign issue.
|
||||
# @option options [String] :labels Comma-separated label names for an issue.
|
||||
# @option options [String] :state_event The state event of an issue ('close' or 'reopen').
|
||||
# @return [Gitlab::ObjectifiedHash] Information about updated issue.
|
||||
def edit_issue(project, id, options={})
|
||||
put("/projects/#{project}/issues/#{id}", :body => options)
|
||||
end
|
||||
|
||||
# Closes an issue.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.close_issue(3, 42)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of an issue.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about closed issue.
|
||||
def close_issue(project, id)
|
||||
put("/projects/#{project}/issues/#{id}", :body => {:state_event => 'close'})
|
||||
end
|
||||
|
||||
# Reopens an issue.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.reopen_issue(3, 42)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of an issue.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about reopened issue.
|
||||
def reopen_issue(project, id)
|
||||
put("/projects/#{project}/issues/#{id}", :body => {:state_event => 'reopen'})
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,107 @@
|
||||
class Gitlab::Client
|
||||
# Defines methods related to merge requests.
|
||||
module MergeRequests
|
||||
# Gets a list of project merge requests.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.merge_requests(5)
|
||||
# Gitlab.merge_requests(:per_page => 40)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def merge_requests(project, options={})
|
||||
get("/projects/#{project}/merge_requests", :query => options)
|
||||
end
|
||||
|
||||
# Gets a single merge request.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.merge_request(5, 36)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of a merge request.
|
||||
# @return <Gitlab::ObjectifiedHash]
|
||||
def merge_request(project, id)
|
||||
get("/projects/#{project}/merge_request/#{id}")
|
||||
end
|
||||
|
||||
# Creates a merge request.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.create_merge_request(5, 'New merge request',
|
||||
# :source_branch => 'source_branch', :target_branch => 'target_branch')
|
||||
# Gitlab.create_merge_request(5, 'New merge request',
|
||||
# :source_branch => 'source_branch', :target_branch => 'target_branch', :assignee_id => 42)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [String] title The title of a merge request.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [String] :source_branch (required) The source branch name.
|
||||
# @option options [String] :target_branch (required) The target branch name.
|
||||
# @option options [Integer] :assignee_id (optional) The ID of a user to assign merge request.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created merge request.
|
||||
def create_merge_request(project, title, options={})
|
||||
check_attributes!(options, [:source_branch, :target_branch])
|
||||
|
||||
body = {:title => title}.merge(options)
|
||||
post("/projects/#{project}/merge_requests", :body => body)
|
||||
end
|
||||
|
||||
# Updates a merge request.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.update_merge_request(5, 42, :title => 'New title')
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of a merge request.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [String] :title The title of a merge request.
|
||||
# @option options [String] :source_branch The source branch name.
|
||||
# @option options [String] :target_branch The target branch name.
|
||||
# @option options [Integer] :assignee_id The ID of a user to assign merge request.
|
||||
# @option options [String] :state_event New state (close|reopen|merge).
|
||||
# @return [Gitlab::ObjectifiedHash] Information about updated merge request.
|
||||
def update_merge_request(project, id, options={})
|
||||
put("/projects/#{project}/merge_request/#{id}", :body => options)
|
||||
end
|
||||
|
||||
# Adds a comment to a merge request.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.create_merge_request_comment(5, 1, "Awesome merge!")
|
||||
# Gitlab.create_merge_request_comment('gitlab', 1, "Awesome merge!")
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of a merge request.
|
||||
# @param [String] note The content of a comment.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created merge request comment.
|
||||
def create_merge_request_comment(project, id, note)
|
||||
post("/projects/#{project}/merge_request/#{id}/comments", :body => {:note => note})
|
||||
end
|
||||
|
||||
# Gets the comments on a merge request.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.merge_request_comments(5, 1)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of a merge request.
|
||||
# @return [Gitlab::ObjectifiedHash] The merge request's comments.
|
||||
def merge_request_comments(project, id)
|
||||
get("/projects/#{project}/merge_request/#{id}/comments")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_attributes!(options, attrs)
|
||||
attrs.each do |attr|
|
||||
unless options.has_key?(attr) || options.has_key?(attr.to_s)
|
||||
raise Gitlab::Error::MissingAttributes.new("Missing '#{attr}' parameter")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,57 @@
|
||||
class Gitlab::Client
|
||||
# Defines methods related to milestones.
|
||||
module Milestones
|
||||
# Gets a list of project's milestones.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.milestones(5)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def milestones(project, options={})
|
||||
get("/projects/#{project}/milestones", :query => options)
|
||||
end
|
||||
|
||||
# Gets a single milestone.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.milestone(5, 36)
|
||||
#
|
||||
# @param [Integer, String] project The ID of a project.
|
||||
# @param [Integer] id The ID of a milestone.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def milestone(project, id)
|
||||
get("/projects/#{project}/milestones/#{id}")
|
||||
end
|
||||
|
||||
# Creates a new milestone.
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [String] title The title of a milestone.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [String] :description The description of a milestone.
|
||||
# @option options [String] :due_date The due date of a milestone.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created milestone.
|
||||
def create_milestone(project, title, options={})
|
||||
body = {:title => title}.merge(options)
|
||||
post("/projects/#{project}/milestones", :body => body)
|
||||
end
|
||||
|
||||
# Updates a milestone.
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of a milestone.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [String] :title The title of a milestone.
|
||||
# @option options [String] :description The description of a milestone.
|
||||
# @option options [String] :due_date The due date of a milestone.
|
||||
# @option options [String] :state_event The state of a milestone ('close' or 'activate').
|
||||
# @return [Gitlab::ObjectifiedHash] Information about updated milestone.
|
||||
def edit_milestone(project, id, options={})
|
||||
put("/projects/#{project}/milestones/#{id}", :body => options)
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,106 @@
|
||||
class Gitlab::Client
|
||||
# Defines methods related to notes.
|
||||
module Notes
|
||||
# Gets a list of projects notes.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.notes(5)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def notes(project)
|
||||
get("/projects/#{project}/notes")
|
||||
end
|
||||
|
||||
# Gets a list of notes for a issue.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.issue_notes(5, 10)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] issue The ID of an issue.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def issue_notes(project, issue)
|
||||
get("/projects/#{project}/issues/#{issue}/notes")
|
||||
end
|
||||
|
||||
# Gets a list of notes for a snippet.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.snippet_notes(5, 1)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] snippet The ID of a snippet.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def snippet_notes(project, snippet)
|
||||
get("/projects/#{project}/snippets/#{snippet}/notes")
|
||||
end
|
||||
|
||||
# Gets a single wall note.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.note(5, 15)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of a note.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def note(project, id)
|
||||
get("/projects/#{project}/notes/#{id}")
|
||||
end
|
||||
|
||||
# Gets a single issue note.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.issue_note(5, 10, 1)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] issue The ID of an issue.
|
||||
# @param [Integer] id The ID of a note.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def issue_note(project, issue, id)
|
||||
get("/projects/#{project}/issues/#{issue}/notes/#{id}")
|
||||
end
|
||||
|
||||
# Gets a single snippet note.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.snippet_note(5, 11, 3)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] snippet The ID of a snippet.
|
||||
# @param [Integer] id The ID of an note.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def snippet_note(project, snippet, id)
|
||||
get("/projects/#{project}/snippets/#{snippet}/notes/#{id}")
|
||||
end
|
||||
|
||||
# Creates a new wall note.
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [String] body The body of a note.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created note.
|
||||
def create_note(project, body)
|
||||
post("/projects/#{project}/notes", :body => {:body => body})
|
||||
end
|
||||
|
||||
# Creates a new issue note.
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] issue The ID of an issue.
|
||||
# @param [String] body The body of a note.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created note.
|
||||
def create_issue_note(project, issue, body)
|
||||
post("/projects/#{project}/issues/#{issue}/notes", :body => {:body => body})
|
||||
end
|
||||
|
||||
# Creates a new snippet note.
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] snippet The ID of a snippet.
|
||||
# @param [String] body The body of a note.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created note.
|
||||
def create_snippet_note(project, snippet, body)
|
||||
post("/projects/#{project}/snippets/#{snippet}/notes", :body => {:body => body})
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,300 @@
|
||||
class Gitlab::Client
|
||||
# Defines methods related to projects.
|
||||
module Projects
|
||||
# Gets a list of projects owned by the authenticated user.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.projects
|
||||
#
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @option options [String] :scope Scope of projects. 'owned' for list of projects owned by the authenticated user, 'all' to get all projects (admin only)
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def projects(options={})
|
||||
if (options[:scope])
|
||||
get("/projects/#{options[:scope]}", :query => options)
|
||||
else
|
||||
get("/projects", :query => options)
|
||||
end
|
||||
end
|
||||
|
||||
# Gets information about a project.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.project(3)
|
||||
# Gitlab.project('gitlab')
|
||||
#
|
||||
# @param [Integer, String] id The ID or name of a project.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def project(id)
|
||||
get("/projects/#{id}")
|
||||
end
|
||||
|
||||
# Gets a list of project events.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.project_events(42)
|
||||
# Gitlab.project_events('gitlab')
|
||||
#
|
||||
# @param [Integer, String] project The ID or name of a project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def project_events(project, options={})
|
||||
get("/projects/#{project}/events", :query => options)
|
||||
end
|
||||
|
||||
# Creates a new project.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.create_project('gitlab')
|
||||
# Gitlab.create_project('viking', :description => 'Awesome project')
|
||||
# Gitlab.create_project('Red', :wall_enabled => false)
|
||||
#
|
||||
# @param [String] name The name of a project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [String] :description The description of a project.
|
||||
# @option options [String] :default_branch The default branch of a project.
|
||||
# @option options [String] :group_id The group in which to create a project.
|
||||
# @option options [String] :namespace_id The namespace in which to create a project.
|
||||
# @option options [Boolean] :wiki_enabled The wiki integration for a project (0 = false, 1 = true).
|
||||
# @option options [Boolean] :wall_enabled The wall functionality for a project (0 = false, 1 = true).
|
||||
# @option options [Boolean] :issues_enabled The issues integration for a project (0 = false, 1 = true).
|
||||
# @option options [Boolean] :snippets_enabled The snippets integration for a project (0 = false, 1 = true).
|
||||
# @option options [Boolean] :merge_requests_enabled The merge requests functionality for a project (0 = false, 1 = true).
|
||||
# @option options [Boolean] :public The setting for making a project public (0 = false, 1 = true).
|
||||
# @option options [Integer] :user_id The user/owner id of a project.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created project.
|
||||
def create_project(name, options={})
|
||||
url = options[:user_id] ? "/projects/user/#{options[:user_id]}" : "/projects"
|
||||
post(url, :body => {:name => name}.merge(options))
|
||||
end
|
||||
|
||||
# Deletes a project.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.delete_project(4)
|
||||
#
|
||||
# @param [Integer, String] id The ID or name of a project.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about deleted project.
|
||||
def delete_project(id)
|
||||
delete("/projects/#{id}")
|
||||
end
|
||||
|
||||
# Gets a list of project team members.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.team_members(42)
|
||||
# Gitlab.team_members('gitlab')
|
||||
#
|
||||
# @param [Integer, String] project The ID or name of a project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [String] :query The search query.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def team_members(project, options={})
|
||||
get("/projects/#{project}/members", :query => options)
|
||||
end
|
||||
|
||||
# Gets a project team member.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.team_member('gitlab', 2)
|
||||
#
|
||||
# @param [Integer, String] project The ID or name of a project.
|
||||
# @param [Integer] id The ID of a project team member.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def team_member(project, id)
|
||||
get("/projects/#{project}/members/#{id}")
|
||||
end
|
||||
|
||||
# Adds a user to project team.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.add_team_member('gitlab', 2, 40)
|
||||
#
|
||||
# @param [Integer, String] project The ID or name of a project.
|
||||
# @param [Integer] id The ID of a user.
|
||||
# @param [Integer] access_level The access level to project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about added team member.
|
||||
def add_team_member(project, id, access_level)
|
||||
post("/projects/#{project}/members", :body => {:user_id => id, :access_level => access_level})
|
||||
end
|
||||
|
||||
# Updates a team member's project access level.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.edit_team_member('gitlab', 3, 20)
|
||||
#
|
||||
# @param [Integer, String] project The ID or name of a project.
|
||||
# @param [Integer] id The ID of a user.
|
||||
# @param [Integer] access_level The access level to project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>] Information about updated team member.
|
||||
def edit_team_member(project, id, access_level)
|
||||
put("/projects/#{project}/members/#{id}", :body => {:access_level => access_level})
|
||||
end
|
||||
|
||||
# Removes a user from project team.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.remove_team_member('gitlab', 2)
|
||||
#
|
||||
# @param [Integer, String] project The ID or name of a project.
|
||||
# @param [Integer] id The ID of a user.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about removed team member.
|
||||
def remove_team_member(project, id)
|
||||
delete("/projects/#{project}/members/#{id}")
|
||||
end
|
||||
|
||||
# Gets a list of project hooks.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.project_hooks(42)
|
||||
# Gitlab.project_hooks('gitlab')
|
||||
#
|
||||
# @param [Integer, String] project The ID or name of a project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def project_hooks(project, options={})
|
||||
get("/projects/#{project}/hooks", :query => options)
|
||||
end
|
||||
|
||||
# Gets a project hook.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.project_hook(42, 5)
|
||||
# Gitlab.project_hook('gitlab', 5)
|
||||
#
|
||||
# @param [Integer, String] project The ID or name of a project.
|
||||
# @param [Integer] id The ID of a hook.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def project_hook(project, id)
|
||||
get("/projects/#{project}/hooks/#{id}")
|
||||
end
|
||||
|
||||
# Adds a new hook to the project.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.add_project_hook(42, 'https://api.example.net/v1/webhooks/ci')
|
||||
#
|
||||
# @param [Integer, String] project The ID or name of a project.
|
||||
# @param [String] url The hook URL.
|
||||
# @param [Hash] options Events list (`{push_events: true, merge_requests_events: false}`).
|
||||
# @return [Gitlab::ObjectifiedHash] Information about added hook.
|
||||
def add_project_hook(project, url, options = {})
|
||||
available_events = [:push_events, :merge_requests_events, :issues_events]
|
||||
passed_events = available_events.select { |event| options[event] }
|
||||
events = Hash[passed_events.map { |event| [event, options[event]] }]
|
||||
|
||||
post("/projects/#{project}/hooks", :body => {:url => url}.merge(events))
|
||||
end
|
||||
|
||||
# Updates a project hook URL.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.edit_project_hook(42, 1, 'https://api.example.net/v1/webhooks/ci')
|
||||
#
|
||||
# @param [Integer, String] project The ID or name of a project.
|
||||
# @param [Integer] id The ID of the hook.
|
||||
# @param [String] url The hook URL.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about updated hook.
|
||||
def edit_project_hook(project, id, url)
|
||||
put("/projects/#{project}/hooks/#{id}", :body => {:url => url})
|
||||
end
|
||||
|
||||
# Deletes a hook from project.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.delete_project_hook('gitlab', 4)
|
||||
#
|
||||
# @param [Integer, String] project The ID or name of a project.
|
||||
# @param [String] id The ID of the hook.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about deleted hook.
|
||||
def delete_project_hook(project, id)
|
||||
delete("/projects/#{project}/hooks/#{id}")
|
||||
end
|
||||
|
||||
# Mark this project as forked from the other
|
||||
#
|
||||
# @example
|
||||
# Gitlab.make_forked(42, 24)
|
||||
#
|
||||
# @param [Integer, String] project The ID or name of a project.
|
||||
# @param [Integer] id The ID of the project it is forked from.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about the forked project.
|
||||
def make_forked_from(project, id)
|
||||
post("/projects/#{project}/fork/#{id}")
|
||||
end
|
||||
|
||||
# Remove a forked_from relationship for a project.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.remove_forked(42)
|
||||
#
|
||||
# @param [Integer, String] project The ID or name of a project.
|
||||
# @param [Integer] project The ID of the project it is forked from
|
||||
# @return [Gitlab::ObjectifiedHash] Information about the forked project.
|
||||
def remove_forked(project)
|
||||
delete("/projects/#{project}/fork")
|
||||
end
|
||||
|
||||
# Gets a project deploy keys.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.deploy_keys(42)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def deploy_keys(project, options={})
|
||||
get("/projects/#{project}/keys", :query => options)
|
||||
end
|
||||
|
||||
# Gets a single project deploy key.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.deploy_key(42, 1)
|
||||
#
|
||||
# @param [Integer, String] project The ID of a project.
|
||||
# @param [Integer] id The ID of a deploy key.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def deploy_key(project, id)
|
||||
get("/projects/#{project}/keys/#{id}")
|
||||
end
|
||||
|
||||
# Creates a new deploy key.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.create_deploy_key(42, 'My Key', 'Key contents')
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [String] title The title of a deploy key.
|
||||
# @param [String] key The content of a deploy key.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created deploy key.
|
||||
def create_deploy_key(project, title, key)
|
||||
post("/projects/#{project}/keys", body: {title: title, key: key})
|
||||
end
|
||||
|
||||
# Deletes a deploy key from project.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.delete_deploy_key(42, 1)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of a deploy key.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about deleted deploy key.
|
||||
def delete_deploy_key(project, id)
|
||||
delete("/projects/#{project}/keys/#{id}")
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,89 @@
|
||||
class Gitlab::Client
|
||||
# Defines methods related to repositories.
|
||||
module Repositories
|
||||
|
||||
def trees(project, options={})
|
||||
get "/projects/#{project}/repository/tree", query: options
|
||||
end
|
||||
alias_method :repo_trees, :trees
|
||||
|
||||
def files(project, file_path, ref)
|
||||
get "/projects/#{project}/repository/files", query: {file_path: file_path, ref: ref}
|
||||
end
|
||||
alias_method :repo_files, :files
|
||||
|
||||
# Gets a list of project repository tags.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.tags(42)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def tags(project, options={})
|
||||
get("/projects/#{project}/repository/tags", :query => options)
|
||||
end
|
||||
alias_method :repo_tags, :tags
|
||||
|
||||
# Creates a new project repository tag.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.create_tag(42,'new_tag','master')
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [String] tag_name The name of the new tag.
|
||||
# @param [String] ref The ref (commit sha, branch name, or another tag) the tag will point to.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def create_tag(project, tag_name, ref)
|
||||
post("/projects/#{project}/repository/tags", body: {tag_name: tag_name, ref: ref})
|
||||
end
|
||||
alias_method :repo_create_tag, :create_tag
|
||||
|
||||
# Gets a list of project commits.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.commits('viking')
|
||||
# Gitlab.repo_commits('gitlab', :ref_name => 'api')
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [String] :ref_name The branch or tag name of a project repository.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def commits(project, options={})
|
||||
get("/projects/#{project}/repository/commits", :query => options)
|
||||
end
|
||||
alias_method :repo_commits, :commits
|
||||
|
||||
# Gets a specific commit identified by the commit hash or name of a branch or tag.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.commit(42, '6104942438c14ec7bd21c6cd5bd995272b3faff6')
|
||||
# Gitlab.repo_commit(3, 'ed899a2f4b50b4370feeea94676502b42383c746')
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [String] sha The commit hash or name of a repository branch or tag
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def commit(project, sha)
|
||||
get("/projects/#{project}/repository/commits/#{sha}")
|
||||
end
|
||||
alias_method :repo_commit, :commit
|
||||
|
||||
# Get the diff of a commit in a project.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.commit_diff(42, '6104942438c14ec7bd21c6cd5bd995272b3faff6')
|
||||
# Gitlab.repo_commit_diff(3, 'ed899a2f4b50b4370feeea94676502b42383c746')
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [String] sha The name of a repository branch or tag or if not given the default branch.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def commit_diff(project, sha)
|
||||
get("/projects/#{project}/repository/commits/#{sha}/diff")
|
||||
end
|
||||
alias_method :repo_commit_diff, :commit_diff
|
||||
end
|
||||
end
|
@ -0,0 +1,86 @@
|
||||
class Gitlab::Client
|
||||
# Defines methods related to snippets.
|
||||
module Snippets
|
||||
# Gets a list of project's snippets.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.snippets(42)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def snippets(project, options={})
|
||||
get("/projects/#{project}/snippets", :query => options)
|
||||
end
|
||||
|
||||
# Gets information about a snippet.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.snippet(2, 14)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of a snippet.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def snippet(project, id)
|
||||
get("/projects/#{project}/snippets/#{id}")
|
||||
end
|
||||
|
||||
# Creates a new snippet.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.create_snippet(42, {:title => 'REST', :file_name => 'api.rb', :code => 'some code'})
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [String] :title (required) The title of a snippet.
|
||||
# @option options [String] :file_name (required) The name of a snippet file.
|
||||
# @option options [String] :code (required) The content of a snippet.
|
||||
# @option options [String] :lifetime (optional) The expiration date of a snippet.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created snippet.
|
||||
def create_snippet(project, options={})
|
||||
check_attributes!(options, [:title, :file_name, :code])
|
||||
post("/projects/#{project}/snippets", :body => options)
|
||||
end
|
||||
|
||||
# Updates a snippet.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.edit_snippet(42, 34, :file_name => 'README.txt')
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of a snippet.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [String] :title The title of a snippet.
|
||||
# @option options [String] :file_name The name of a snippet file.
|
||||
# @option options [String] :code The content of a snippet.
|
||||
# @option options [String] :lifetime The expiration date of a snippet.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about updated snippet.
|
||||
def edit_snippet(project, id, options={})
|
||||
put("/projects/#{project}/snippets/#{id}", :body => options)
|
||||
end
|
||||
|
||||
# Deletes a snippet.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.delete_snippet(2, 14)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of a snippet.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about deleted snippet.
|
||||
def delete_snippet(project, id)
|
||||
delete("/projects/#{project}/snippets/#{id}")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_attributes!(options, attrs)
|
||||
attrs.each do |attr|
|
||||
unless options.has_key?(attr) || options.has_key?(attr.to_s)
|
||||
raise Gitlab::Error::MissingAttributes.new("Missing '#{attr}' parameter")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,58 @@
|
||||
class Gitlab::Client
|
||||
# Defines methods related to system hooks.
|
||||
module SystemHooks
|
||||
# Gets a list of system hooks.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.hooks
|
||||
# Gitlab.system_hooks
|
||||
#
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def hooks(options={})
|
||||
get("/hooks", query: options)
|
||||
end
|
||||
alias_method :system_hooks, :hooks
|
||||
|
||||
# Adds a new system hook.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.add_hook('http://example.com/hook')
|
||||
# Gitlab.add_system_hook('https://api.example.net/v1/hook')
|
||||
#
|
||||
# @param [String] url The hook URL.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def add_hook(url)
|
||||
post("/hooks", :body => {:url => url})
|
||||
end
|
||||
alias_method :add_system_hook, :add_hook
|
||||
|
||||
# Tests a system hook.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.hook(3)
|
||||
# Gitlab.system_hook(12)
|
||||
#
|
||||
# @param [Integer] id The ID of a system hook.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def hook(id)
|
||||
get("/hooks/#{id}")
|
||||
end
|
||||
alias_method :system_hook, :hook
|
||||
|
||||
# Deletes a new system hook.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.delete_hook(3)
|
||||
# Gitlab.delete_system_hook(12)
|
||||
#
|
||||
# @param [Integer] id The ID of a system hook.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def delete_hook(id)
|
||||
delete("/hooks/#{id}")
|
||||
end
|
||||
alias_method :delete_system_hook, :delete_hook
|
||||
end
|
||||
end
|
@ -0,0 +1,123 @@
|
||||
class Gitlab::Client
|
||||
# Defines methods related to users.
|
||||
module Users
|
||||
# Gets a list of users.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.users
|
||||
#
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def users(options={})
|
||||
get("/users", :query => options)
|
||||
end
|
||||
|
||||
# Gets information about a user.
|
||||
# Will return information about an authorized user if no ID passed.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.user
|
||||
# Gitlab.user(2)
|
||||
#
|
||||
# @param [Integer] id The ID of a user.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def user(id=nil)
|
||||
id.to_i.zero? ? get("/user") : get("/users/#{id}")
|
||||
end
|
||||
|
||||
# Creates a new user.
|
||||
# Requires authentication from an admin account.
|
||||
#
|
||||
# @param [String] email The email of a user.
|
||||
# @param [String] password The password of a user.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [String] :name The name of a user. Defaults to email.
|
||||
# @option options [String] :skype The skype of a user.
|
||||
# @option options [String] :linkedin The linkedin of a user.
|
||||
# @option options [String] :twitter The twitter of a user.
|
||||
# @option options [Integer] :projects_limit The limit of projects for a user.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created user.
|
||||
def create_user(email, password, options={})
|
||||
body = {:email => email, :password => password, :name => email}.merge(options)
|
||||
post("/users", :body => body)
|
||||
end
|
||||
|
||||
# Updates a user.
|
||||
#
|
||||
# @param [Integer] id The ID of a user.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [String] email The email of a user.
|
||||
# @option options [String] password The password of a user.
|
||||
# @option options [String] :name The name of a user. Defaults to email.
|
||||
# @option options [String] :skype The skype of a user.
|
||||
# @option options [String] :linkedin The linkedin of a user.
|
||||
# @option options [String] :twitter The twitter of a user.
|
||||
# @option options [Integer] :projects_limit The limit of projects for a user.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created user.
|
||||
def edit_user(user_id, options={})
|
||||
put("/users/#{user_id}", :body => options)
|
||||
end
|
||||
|
||||
# Creates a new user session.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.session('jack@example.com', 'secret12345')
|
||||
#
|
||||
# @param [String] email The email of a user.
|
||||
# @param [String] password The password of a user.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
# @note This method doesn't require private_token to be set.
|
||||
def session(email, password)
|
||||
post("/session", :body => {:email => email, :password => password})
|
||||
end
|
||||
|
||||
# Gets a list of user's SSH keys.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.ssh_keys
|
||||
#
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def ssh_keys(options={})
|
||||
get("/user/keys", :query => options)
|
||||
end
|
||||
|
||||
# Gets information about SSH key.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.ssh_key(1)
|
||||
#
|
||||
# @param [Integer] id The ID of a user's SSH key.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def ssh_key(id)
|
||||
get("/user/keys/#{id}")
|
||||
end
|
||||
|
||||
# Creates a new SSH key.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.create_ssh_key('key title', 'key body')
|
||||
#
|
||||
# @param [String] title The title of an SSH key.
|
||||
# @param [String] key The SSH key body.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created SSH key.
|
||||
def create_ssh_key(title, key)
|
||||
post("/user/keys", :body => {:title => title, :key => key})
|
||||
end
|
||||
|
||||
# Deletes an SSH key.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.delete_ssh_key(1)
|
||||
#
|
||||
# @param [Integer] id The ID of a user's SSH key.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about deleted SSH key.
|
||||
def delete_ssh_key(id)
|
||||
delete("/user/keys/#{id}")
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,39 @@
|
||||
module Gitlab
|
||||
# Defines constants and methods related to configuration.
|
||||
module Configuration
|
||||
# An array of valid keys in the options hash when configuring a Gitlab::API.
|
||||
VALID_OPTIONS_KEYS = [:endpoint, :private_token, :user_agent, :sudo, :httparty].freeze
|
||||
|
||||
# The user agent that will be sent to the API endpoint if none is set.
|
||||
DEFAULT_USER_AGENT = "Gitlab Ruby Gem #{Gitlab::VERSION}".freeze
|
||||
|
||||
# @private
|
||||
attr_accessor(*VALID_OPTIONS_KEYS)
|
||||
|
||||
# Sets all configuration options to their default values
|
||||
# when this module is extended.
|
||||
def self.extended(base)
|
||||
base.reset
|
||||
end
|
||||
|
||||
# Convenience method to allow configuration options to be set in a block.
|
||||
def configure
|
||||
yield self
|
||||
end
|
||||
|
||||
# Creates a hash of options and their values.
|
||||
def options
|
||||
VALID_OPTIONS_KEYS.inject({}) do |option, key|
|
||||
option.merge!(key => send(key))
|
||||
end
|
||||
end
|
||||
|
||||
# Resets all configuration options to the defaults.
|
||||
def reset
|
||||
self.endpoint = ENV['GITLAB_API_ENDPOINT']
|
||||
self.private_token = ENV['GITLAB_API_PRIVATE_TOKEN']
|
||||
self.sudo = nil
|
||||
self.user_agent = DEFAULT_USER_AGENT
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,42 @@
|
||||
module Gitlab
|
||||
module Error
|
||||
# Custom error class for rescuing from all Gitlab errors.
|
||||
class Error < StandardError; end
|
||||
|
||||
# Raise when attributes are missing.
|
||||
class MissingAttributes < Error; end
|
||||
|
||||
# Raised when API endpoint credentials not configured.
|
||||
class MissingCredentials < Error; end
|
||||
|
||||
# Raised when impossible to parse response body.
|
||||
class Parsing < Error; end
|
||||
|
||||
# Raised when API endpoint returns the HTTP status code 400.
|
||||
class BadRequest < Error; end
|
||||
|
||||
# Raised when API endpoint returns the HTTP status code 401.
|
||||
class Unauthorized < Error; end
|
||||
|
||||
# Raised when API endpoint returns the HTTP status code 403.
|
||||
class Forbidden < Error; end
|
||||
|
||||
# Raised when API endpoint returns the HTTP status code 404.
|
||||
class NotFound < Error; end
|
||||
|
||||
# Raised when API endpoint returns the HTTP status code 405.
|
||||
class MethodNotAllowed < Error; end
|
||||
|
||||
# Raised when API endpoint returns the HTTP status code 409.
|
||||
class Conflict < Error; end
|
||||
|
||||
# Raised when API endpoint returns the HTTP status code 500.
|
||||
class InternalServerError < Error; end
|
||||
|
||||
# Raised when API endpoint returns the HTTP status code 502.
|
||||
class BadGateway < Error; end
|
||||
|
||||
# Raised when API endpoint returns the HTTP status code 503.
|
||||
class ServiceUnavailable < Error; end
|
||||
end
|
||||
end
|
@ -0,0 +1,44 @@
|
||||
require 'gitlab'
|
||||
require 'gitlab/cli_helpers'
|
||||
|
||||
module Gitlab::Help
|
||||
extend Gitlab::CLI::Helpers
|
||||
|
||||
def self.get_help(methods,cmd=nil)
|
||||
help = ''
|
||||
|
||||
if cmd.nil? || cmd == 'help'
|
||||
help = actions_table
|
||||
else
|
||||
ri_cmd = `which ri`.chomp
|
||||
|
||||
if $? == 0
|
||||
namespace = methods.select {|m| m[:name] === cmd }.map {|m| m[:owner]+'.'+m[:name] }.shift
|
||||
|
||||
if namespace
|
||||
begin
|
||||
ri_output = `#{ri_cmd} -T #{namespace} 2>&1`.chomp
|
||||
|
||||
if $? == 0
|
||||
ri_output.gsub!(/#{cmd}\((.*?)\)/, cmd+' \1')
|
||||
ri_output.gsub!(/Gitlab\./, 'gitlab> ')
|
||||
ri_output.gsub!(/Gitlab\..+$/, '')
|
||||
ri_output.gsub!(/\,\s?/, ' ')
|
||||
help = ri_output
|
||||
else
|
||||
help = "Ri docs not found for #{namespace}, please install the docs to use 'help'"
|
||||
end
|
||||
rescue => e
|
||||
puts e.message
|
||||
end
|
||||
else
|
||||
help = "Unknown command: #{cmd}"
|
||||
end
|
||||
else
|
||||
help = "'ri' tool not found in your PATH, please install it to use the help."
|
||||
end
|
||||
end
|
||||
|
||||
puts help
|
||||
end
|
||||
end
|
@ -0,0 +1,24 @@
|
||||
module Gitlab
|
||||
# Converts hashes to the objects.
|
||||
class ObjectifiedHash
|
||||
# Creates a new ObjectifiedHash object.
|
||||
def initialize(hash)
|
||||
@hash = hash
|
||||
@data = hash.inject({}) do |data, (key,value)|
|
||||
value = ObjectifiedHash.new(value) if value.is_a? Hash
|
||||
data[key.to_s] = value
|
||||
data
|
||||
end
|
||||
end
|
||||
|
||||
def to_hash
|
||||
@hash
|
||||
end
|
||||
alias_method :to_h, :to_hash
|
||||
|
||||
# Delegate to ObjectifiedHash.
|
||||
def method_missing(key)
|
||||
@data.key?(key.to_s) ? @data[key.to_s] : nil
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,113 @@
|
||||
require 'httparty'
|
||||
require 'json'
|
||||
|
||||
module Gitlab
|
||||
# @private
|
||||
class Request
|
||||
include HTTParty
|
||||
format :json
|
||||
headers 'Accept' => 'application/json'
|
||||
parser Proc.new { |body, _| parse(body) }
|
||||
|
||||
attr_accessor :private_token
|
||||
|
||||
# Converts the response body to an ObjectifiedHash.
|
||||
def self.parse(body)
|
||||
body = decode(body)
|
||||
|
||||
if body.is_a? Hash
|
||||
ObjectifiedHash.new body
|
||||
elsif body.is_a? Array
|
||||
body.collect! { |e| ObjectifiedHash.new(e) }
|
||||
else
|
||||
raise Error::Parsing.new "Couldn't parse a response body"
|
||||
end
|
||||
end
|
||||
|
||||
# Decodes a JSON response into Ruby object.
|
||||
def self.decode(response)
|
||||
begin
|
||||
JSON.load response
|
||||
rescue JSON::ParserError
|
||||
raise Error::Parsing.new "The response is not a valid JSON"
|
||||
end
|
||||
end
|
||||
|
||||
def get(path, options={})
|
||||
set_httparty_config(options)
|
||||
set_private_token_header(options)
|
||||
validate self.class.get(path, options)
|
||||
end
|
||||
|
||||
def post(path, options={})
|
||||
set_httparty_config(options)
|
||||
set_private_token_header(options, path)
|
||||
validate self.class.post(path, options)
|
||||
end
|
||||
|
||||
def put(path, options={})
|
||||
set_httparty_config(options)
|
||||
set_private_token_header(options)
|
||||
validate self.class.put(path, options)
|
||||
end
|
||||
|
||||
def delete(path, options={})
|
||||
set_httparty_config(options)
|
||||
set_private_token_header(options)
|
||||
validate self.class.delete(path, options)
|
||||
end
|
||||
|
||||
# Checks the response code for common errors.
|
||||
# Returns parsed response for successful requests.
|
||||
def validate(response)
|
||||
case response.code
|
||||
when 400; raise Error::BadRequest.new error_message(response)
|
||||
when 401; raise Error::Unauthorized.new error_message(response)
|
||||
when 403; raise Error::Forbidden.new error_message(response)
|
||||
when 404; raise Error::NotFound.new error_message(response)
|
||||
when 405; raise Error::MethodNotAllowed.new error_message(response)
|
||||
when 409; raise Error::Conflict.new error_message(response)
|
||||
when 500; raise Error::InternalServerError.new error_message(response)
|
||||
when 502; raise Error::BadGateway.new error_message(response)
|
||||
when 503; raise Error::ServiceUnavailable.new error_message(response)
|
||||
end
|
||||
|
||||
response.parsed_response
|
||||
end
|
||||
|
||||
# Sets a base_uri and default_params for requests.
|
||||
# @raise [Error::MissingCredentials] if endpoint not set.
|
||||
def set_request_defaults(endpoint, private_token, sudo=nil)
|
||||
raise Error::MissingCredentials.new("Please set an endpoint to API") unless endpoint
|
||||
@private_token = private_token
|
||||
|
||||
self.class.base_uri endpoint
|
||||
self.class.default_params :sudo => sudo
|
||||
self.class.default_params.delete(:sudo) if sudo.nil?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Sets a PRIVATE-TOKEN header for requests.
|
||||
# @raise [Error::MissingCredentials] if private_token not set.
|
||||
def set_private_token_header(options, path=nil)
|
||||
unless path == '/session'
|
||||
raise Error::MissingCredentials.new("Please set a private_token for user") unless @private_token
|
||||
options[:headers] = {'PRIVATE-TOKEN' => @private_token}
|
||||
end
|
||||
end
|
||||
|
||||
# Set HTTParty configuration
|
||||
# @see https://github.com/jnunemaker/httparty
|
||||
def set_httparty_config(options)
|
||||
if self.httparty
|
||||
options.merge!(self.httparty)
|
||||
end
|
||||
end
|
||||
|
||||
def error_message(response)
|
||||
"Server responded with code #{response.code}, message: #{response.parsed_response.message}. " \
|
||||
"Request URI: #{response.request.base_uri}#{response.request.path}"
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,51 @@
|
||||
require 'gitlab'
|
||||
require 'gitlab/help'
|
||||
require 'gitlab/cli_helpers'
|
||||
require 'readline'
|
||||
|
||||
class Gitlab::Shell
|
||||
extend Gitlab::CLI::Helpers
|
||||
|
||||
def self.start
|
||||
actions = Gitlab.actions
|
||||
|
||||
comp = proc { |s| actions.map(&:to_s).grep(/^#{Regexp.escape(s)}/) }
|
||||
|
||||
Readline.completion_proc = comp
|
||||
Readline.completion_append_character = ' '
|
||||
|
||||
client = Gitlab::Client.new(endpoint: '')
|
||||
|
||||
while buf = Readline.readline('gitlab> ', true)
|
||||
next if buf.nil? || buf.empty?
|
||||
break if buf == 'exit'
|
||||
|
||||
buf = buf.scan(/["][^"]+["]|\S+/).map { |word| word.gsub(/^['"]|['"]$/,'') }
|
||||
cmd = buf.shift
|
||||
args = buf.count > 0 ? buf : []
|
||||
|
||||
if cmd == 'help'
|
||||
methods = []
|
||||
|
||||
actions.each do |action|
|
||||
methods << {
|
||||
name: action.to_s,
|
||||
owner: client.method(action).owner.to_s
|
||||
}
|
||||
end
|
||||
|
||||
args[0].nil? ? Gitlab::Help.get_help(methods) : Gitlab::Help.get_help(methods, args[0])
|
||||
next
|
||||
end
|
||||
|
||||
data = if actions.include?(cmd.to_sym)
|
||||
confirm_command(cmd)
|
||||
gitlab_helper(cmd, args)
|
||||
else
|
||||
"'#{cmd}' is not a valid command. See the 'help' for a list of valid commands."
|
||||
end
|
||||
|
||||
output_table(cmd, args, data)
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,3 @@
|
||||
module Gitlab
|
||||
VERSION = "3.2.0"
|
||||
end
|
@ -0,0 +1 @@
|
||||
{"name":"api","commit":{"id":"f7dd067490fe57505f7226c3b54d3127d2f7fd46","parents":[{"id":"949b1df930bedace1dbd755aaa4a82e8c451a616"}],"tree":"f8c4b21c036339f92fcc5482aa28a41250553b27","message":"API: expose issues project id","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-07-25T04:22:21-07:00","committed_date":"2012-07-25T04:22:21-07:00"},"protected": true}
|
@ -0,0 +1 @@
|
||||
[{"name":"api","commit":{"id":"f7dd067490fe57505f7226c3b54d3127d2f7fd46","parents":[{"id":"949b1df930bedace1dbd755aaa4a82e8c451a616"}],"tree":"f8c4b21c036339f92fcc5482aa28a41250553b27","message":"API: expose issues project id","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-07-25T04:22:21-07:00","committed_date":"2012-07-25T04:22:21-07:00"}},{"name":"dashboard-feed","commit":{"id":"f8f6ff065eccc6ede4d35ed87a09bb962b84ca25","parents":[{"id":"2cf8010792c3075824ee27d0f037aeb178cbbf7e"}],"tree":"e17f2157143d550891d4669c10b7446e4739bc6d","message":"add projects atom feed","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-05-31T23:42:02-07:00","committed_date":"2012-05-31T23:42:02-07:00"}},{"name":"master","commit":{"id":"2cf8010792c3075824ee27d0f037aeb178cbbf7e","parents":[{"id":"af226ae9c9af406c8a0e0bbdf364563495c2f432"},{"id":"e851cb07762aa464aae10e8b4b28de87c1a6f925"}],"tree":"6c6845838039f01723d91f395a1d2fa1dcc82522","message":"Merge pull request #868 from SaitoWu/bugfix/encoding\n\nBugfix/encoding","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-05-30T00:24:43-07:00","committed_date":"2012-05-30T00:24:43-07:00"}},{"name":"preview_notes","commit":{"id":"3749e0d99ac6bfbc65889b1b7a5310e14e7fe89a","parents":[{"id":"2483181f2c3d4ea7d2c68147b19bc07fc3937b0c"}],"tree":"f8c56161b0d6561568f088df9961362eb1ece88b","message":"pass project_id to notes preview path","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-08-09T23:46:27-07:00","committed_date":"2012-08-09T23:46:27-07:00"}},{"name":"refactoring","commit":{"id":"7c7761099cae83f59fe5780340e100be890847b2","parents":[{"id":"058d80b3363dd4fc4417ca4f60f76119188a2470"}],"tree":"d7d4a94c700dc0e84ee943019213d2358a49c413","message":"fix deprecation warnings","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-05-29T07:16:28-07:00","committed_date":"2012-05-29T07:16:28-07:00"}}]
|
@ -0,0 +1 @@
|
||||
{"note":"Cool Merge Request!","author":{"id":1,"username":"jsmith","email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-07-11T01:32:18Z"}}
|
@ -0,0 +1 @@
|
||||
{"name":"api","commit":{ "id":"f7dd067490fe57505f7226c3b54d3127d2f7fd46","message":"API: expose issues project id","parent_ids":["949b1df930bedace1dbd755aaa4a82e8c451a616"],"authored_date":"2012-07-25T04:22:21-07:00","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","committed_date":"2012-07-25T04:22:21-07:00","committer_name":"Nihad Abbasov","committer_email":"narkoz.2008@gmail.com"},"protected": false}
|
@ -0,0 +1 @@
|
||||
{"id":2,"target_branch":"master","source_branch":"api","project_id":3,"title":"New feature","closed":false,"merged":false,"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-10-19T05:56:05Z"},"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-10-19T05:56:14Z"}}
|
@ -0,0 +1 @@
|
||||
{"message": "409 Already exists"}
|
@ -0,0 +1,60 @@
|
||||
{"id": 10, "name": "GitLab-Group", "path": "gitlab-group", "owner_id": 6, "projects": [
|
||||
{
|
||||
"id": 9,
|
||||
"name": "mojito",
|
||||
"description": null,
|
||||
"default_branch": "master",
|
||||
"owner": {
|
||||
"id": 6,
|
||||
"username": "jose",
|
||||
"email": "jose@abc.com",
|
||||
"name": "Jose Jose",
|
||||
"blocked": false,
|
||||
"created_at": "2013-02-06T06:54:06Z"
|
||||
},
|
||||
"path": "mojito",
|
||||
"path_with_namespace": "gitlab-group/mojito",
|
||||
"issues_enabled": true,
|
||||
"merge_requests_enabled": true,
|
||||
"wall_enabled": true,
|
||||
"wiki_enabled": true,
|
||||
"created_at": "2013-02-06T16:59:15Z",
|
||||
"namespace": {
|
||||
"created_at": "2013-02-06T16:58:22Z",
|
||||
"id": 10,
|
||||
"name": "GitLab-Group",
|
||||
"owner_id": 6,
|
||||
"path": "gitlab-group",
|
||||
"updated_at": "2013-02-06T16:58:22Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"name": "gitlabhq",
|
||||
"description": null,
|
||||
"default_branch": null,
|
||||
"owner": {
|
||||
"id": 6,
|
||||
"username": "randx",
|
||||
"email": "randx@github.com",
|
||||
"name": "Dmitry Z",
|
||||
"blocked": false,
|
||||
"created_at": "2013-02-06T06:54:06Z"
|
||||
},
|
||||
"path": "gitlabhq",
|
||||
"path_with_namespace": "gitlab-group/gitlabhq",
|
||||
"issues_enabled": true,
|
||||
"merge_requests_enabled": true,
|
||||
"wall_enabled": true,
|
||||
"wiki_enabled": true,
|
||||
"created_at": "2013-02-06T17:02:31Z",
|
||||
"namespace": {
|
||||
"created_at": "2013-02-06T16:58:22Z",
|
||||
"id": 10,
|
||||
"name": "GitLab-Group",
|
||||
"owner_id": 6,
|
||||
"path": "gitlab-group",
|
||||
"updated_at": "2013-02-06T16:58:22Z"
|
||||
}
|
||||
}
|
||||
]}
|
@ -0,0 +1 @@
|
||||
{"id":3,"name":"Gitlab-Group","path":"gitlab-group","owner_id":1}
|
@ -0,0 +1 @@
|
||||
{"id":2,"username":"jsmith","email":"jsmith@local.host","name":"John Smith","state":"active","created_at":"2013-09-04T18:15:30Z","access_level":10}
|
@ -0,0 +1 @@
|
||||
{"created_at":"2013-09-04T18:18:15Z","group_access":10,"group_id":3,"id":2,"notification_level":3,"updated_at":"2013-09-04T18:18:15Z","user_id":2}
|
@ -0,0 +1 @@
|
||||
[{"id":1,"username":"eraymond","email":"eraymond@local.host","name":"Edward Raymond","state":"active","created_at":"2013-08-30T16:16:22Z","access_level":50},{"id":1,"username":"jsmith","email":"jsmith@local.host","name":"John Smith","state":"active","created_at":"2013-08-30T16:16:22Z","access_level":50}]
|
@ -0,0 +1,2 @@
|
||||
[{"id": 3,"name": "ThreeGroup","path": "threegroup","owner_id": 1},{"id": 5,"name": "Five-Group","path": "five-group","owner_id": 2},{"id": 8,"name": "Eight Group","path": "eight-group","owner_id": 6}
|
||||
]
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue