Commit ed4fbcf6b004bacfe9ad3c99296d543921c477ed
Merge branch 'master' into fix_project_access_notification
5.01 KB
4.95 KB
3.22 KB
3.61 KB
4.64 KB
4.04 KB
3.08 KB
3.77 KB
4.15 KB
4.37 KB
4.62 KB
3.41 KB
4.63 KB
6.9 KB
5.33 KB
3.62 KB
4.37 KB
6.52 KB
3.01 KB
4.92 KB
2.78 KB
5.5 KB
4.98 KB
4.24 KB
3.11 KB
3.1 KB
3.53 KB
2.94 KB
2.87 KB
3.13 KB
3.44 KB
3.44 KB
2.97 KB
3.26 KB
3.26 KB
2.95 KB
3.63 KB
3 KB
3.46 KB
3.12 KB
3.15 KB
3.16 KB
1.37 KB
4.71 KB
6.59 KB
2.87 KB
5.9 KB
3.98 KB
2.95 KB
5.78 KB
4.36 KB
3.87 KB
2.9 KB
3.42 KB
2.25 KB
1.79 KB
4.56 KB
3.82 KB
1.35 KB
5.45 KB
2.4 KB
4.15 KB
5.89 KB
6.24 KB
3.13 KB
2.72 KB
3.72 KB
5.43 KB
5.95 KB
6.44 KB
5.13 KB
2.7 KB
4.75 KB
5.6 KB
6.33 KB
4.61 KB
3.8 KB
4.76 KB
5.28 KB
2.31 KB
3.79 KB
2.3 KB
1.3 KB
4.13 KB
3.66 KB
4.97 KB
3.99 KB
4 KB
5.07 KB
4.73 KB
3.74 KB
5.09 KB
5.91 KB
4.59 KB
3.09 KB
6.39 KB
3.25 KB
6.75 KB
5.02 KB
4.09 KB
6.33 KB
5.81 KB
6.07 KB
8.32 KB
5.02 KB
2.63 KB
4.02 KB
5.81 KB
4.38 KB
4.88 KB
3.75 KB
3.97 KB
1.64 KB
1.96 KB
2.95 KB
4.4 KB
5.99 KB
2.85 KB
3.94 KB
4.38 KB
4.55 KB
5.26 KB
4.4 KB
5.02 KB
4.56 KB
4.18 KB
3.66 KB
5.75 KB
5.85 KB
5.59 KB
6.56 KB
4.23 KB
2.84 KB
2.87 KB
1.64 KB
5.47 KB
7.01 KB
5.74 KB
3.89 KB
3.38 KB
5.13 KB
4.61 KB
4.54 KB
3.49 KB
4.57 KB
4.21 KB
3.75 KB
3.41 KB
6.94 KB
4.09 KB
4.55 KB
2.53 KB
2.53 KB
2.8 KB
2.53 KB
2.79 KB
2.45 KB
2.73 KB
2.78 KB
2.53 KB
2.79 KB
2.43 KB
2.67 KB
2.56 KB
2.78 KB
2.56 KB
2.77 KB
2.52 KB
2.67 KB
2.55 KB
2.75 KB
2.54 KB
2.78 KB
2.43 KB
2.68 KB
4.73 KB
5.57 KB
3.78 KB
3.77 KB
1.65 KB
3.55 KB
2.88 KB
4.21 KB
5.83 KB
3.69 KB
1.67 KB
5.39 KB
5.72 KB
4.77 KB
3.61 KB
6.05 KB
3.98 KB
7.96 KB
4.08 KB
6.97 KB
1.54 KB
6.54 KB
7.44 KB
7.2 KB
7.05 KB
5.61 KB
5.18 KB
2.59 KB
5.98 KB
3.92 KB
5.52 KB
5.57 KB
6.53 KB
6.09 KB
5.29 KB
1.23 KB
1.91 KB
5.21 KB
5.67 KB
3.81 KB
4.78 KB
3.65 KB
7.73 KB
4.34 KB
5.33 KB
5.32 KB
2.91 KB
2.58 KB
7.2 KB
5.04 KB
5.56 KB
2.72 KB
4.65 KB
2.97 KB
6.13 KB
5.15 KB
5.81 KB
5.79 KB
4.51 KB
6.97 KB
4.24 KB
3.23 KB
5.09 KB
7.64 KB
6.58 KB
3.55 KB
5.02 KB
3.2 KB
6.83 KB
2.08 KB
4.23 KB
4.65 KB
7 KB
6.87 KB
7.13 KB
5.09 KB
4.56 KB
3.75 KB
3.21 KB
3.92 KB
2.75 KB
4.97 KB
2.63 KB
1.44 KB
1.62 KB
4.2 KB
3.85 KB
5.3 KB
4.7 KB
4.81 KB
1.15 KB
4.81 KB
4.29 KB
4.76 KB
5.43 KB
4.78 KB
7.04 KB
3.03 KB
4.54 KB
5.47 KB
1.12 KB
1.49 KB
6.07 KB
3.92 KB
1.16 KB
3.79 KB
4.75 KB
6.12 KB
5.83 KB
4.18 KB
4.61 KB
5.68 KB
4.37 KB
5.74 KB
3.51 KB
5.98 KB
4.91 KB
3.14 KB
3.35 KB
5.71 KB
4.51 KB
6.55 KB
3.52 KB
4.97 KB
3.1 KB
5.85 KB
3.32 KB
3.52 KB
7.37 KB
6.25 KB
4.71 KB
4.2 KB
6.31 KB
7.05 KB
2.89 KB
5.76 KB
4.74 KB
4.2 KB
4.41 KB
6.55 KB
5.87 KB
6.17 KB
5.7 KB
4.77 KB
1.3 KB
1.02 KB
3.46 KB
5.3 KB
6.06 KB
4.97 KB
4.33 KB
1.12 KB
1.03 KB
5.59 KB
3.5 KB
4.28 KB
3.09 KB
6.93 KB
5.57 KB
3.58 KB
7.05 KB
4.06 KB
5.32 KB
4.64 KB
3.65 KB
5.51 KB
5.79 KB
1.87 KB
6.4 KB
3.22 KB
3.42 KB
5.62 KB
6.03 KB
3.96 KB
6.12 KB
2.86 KB
1.08 KB
340 Bytes
1.38 KB
1.28 KB
197 Bytes
591 Bytes
315 Bytes
4 KB
5.75 KB
8.13 KB
3.96 KB
4.45 KB
2.45 KB
5.69 KB
5.71 KB
4.47 KB
5.77 KB
4.77 KB
5 KB
3.46 KB
4.39 KB
3.43 KB
1.42 KB
5.34 KB
4.5 KB
3.81 KB
3.02 KB
6.48 KB
3.61 KB
2.15 KB
6.45 KB
3.58 KB
6.84 KB
2.81 KB
3.42 KB
3.41 KB
3.97 KB
5.5 KB
3.99 KB
4.82 KB
5.04 KB
6.98 KB
3.39 KB
6.19 KB
7.02 KB
2.76 KB
3.37 KB
4 KB
4.82 KB
6.13 KB
6.64 KB
5.43 KB
5.63 KB
5.55 KB
2.79 KB
4.99 KB
4.53 KB
3.7 KB
3.81 KB
6.03 KB
4.23 KB
6.2 KB
5.44 KB
5.78 KB
3.93 KB
3.33 KB
3.69 KB
5.91 KB
4.8 KB
5.26 KB
4.13 KB
3.7 KB
2.59 KB
3.65 KB
3.3 KB
3.59 KB
4.85 KB
5.64 KB
3.34 KB
5.86 KB
5.8 KB
2.41 KB
2.44 KB
4.63 KB
2.97 KB
3.54 KB
3.23 KB
4.1 KB
4.26 KB
4.47 KB
3.03 KB
5.88 KB
5.2 KB
6.38 KB
4.64 KB
4.35 KB
5.11 KB
5.89 KB
5.4 KB
4.57 KB
8.04 KB
4.83 KB
3.29 KB
3.03 KB
3.32 KB
3.59 KB
4.04 KB
5.74 KB
3.04 KB
5.46 KB
3.44 KB
7.41 KB
5.37 KB
4.86 KB
5.22 KB
4.21 KB
3.46 KB
4.07 KB
4.89 KB
9.29 KB
4.3 KB
7.27 KB
6.47 KB
3.99 KB
3.99 KB
2.12 KB
4.56 KB
4.77 KB
1.9 KB
3.11 KB
1.54 KB
6.48 KB
5.68 KB
3.89 KB
6.27 KB
5.97 KB
3.76 KB
4.73 KB
3.83 KB
5.25 KB
6.59 KB
5.08 KB
4.1 KB
3.69 KB
5.8 KB
5.53 KB
3.43 KB
3.21 KB
6.87 KB
4.96 KB
4.62 KB
5.36 KB
4.11 KB
5.08 KB
3.62 KB
5.89 KB
5.2 KB
1.5 KB
2.12 KB
2.48 KB
3.42 KB
5.64 KB
3.84 KB
5.64 KB
5.41 KB
5.04 KB
4.06 KB
4.49 KB
7.35 KB
6.58 KB
5.84 KB
1.76 KB
7.29 KB
5.18 KB
5.55 KB
6.14 KB
2.76 KB
4.19 KB
4.83 KB
4.33 KB
4.97 KB
3.6 KB
5.94 KB
2.13 KB
3.64 KB
3.93 KB
3.58 KB
4.7 KB
2.5 KB
3.01 KB
2.62 KB
5.06 KB
3.92 KB
2.41 KB
5.78 KB
6.77 KB
4.83 KB
4.35 KB
4.63 KB
4.94 KB
6.14 KB
5.39 KB
4.71 KB
6.47 KB
5.3 KB
5.37 KB
5.86 KB
4.68 KB
4.65 KB
4.9 KB
5.5 KB
4.35 KB
5.15 KB
4.96 KB
3.15 KB
3.01 KB
3.01 KB
3.35 KB
3.11 KB
3.27 KB
6.69 KB
4.64 KB
5.02 KB
4.71 KB
3.31 KB
3.84 KB
4.58 KB
4.1 KB
4.14 KB
4.8 KB
6.06 KB
7.73 KB
4.72 KB
4.19 KB
4.92 KB
3.7 KB
4 KB
1.67 KB
5.54 KB
4.41 KB
4.62 KB
6.01 KB
2.15 KB
5.28 KB
1.06 KB
1.07 KB
1.09 KB
1.24 KB
3.56 KB
5.19 KB
6.03 KB
5.25 KB
6.38 KB
6.42 KB
5.31 KB
3.62 KB
4.18 KB
3.85 KB
1.58 KB
5.33 KB
5.52 KB
3.92 KB
4.19 KB
4.04 KB
5.34 KB
2.98 KB
5.45 KB
4.54 KB
5.28 KB
7.6 KB
6.11 KB
5.11 KB
5.26 KB
5.03 KB
6.02 KB
4.1 KB
6.46 KB
1.89 KB
5.31 KB
3.83 KB
7.6 KB
3.06 KB
3.14 KB
5.57 KB
3.47 KB
4.4 KB
3.74 KB
4.95 KB
3.88 KB
6.12 KB
4.75 KB
5.24 KB
4.15 KB
5.32 KB
5.61 KB
3.75 KB
4.46 KB
6.33 KB
6.68 KB
6.59 KB
5.92 KB
5.24 KB
6.67 KB
2.21 KB
2.98 KB
5.77 KB
4.62 KB
5 KB
4.13 KB
9.13 KB
4.57 KB
4.64 KB
4.69 KB
7.41 KB
3.16 KB
3.7 KB
4.75 KB
4.07 KB
2.37 KB
5.7 KB
4.5 KB
1.85 KB
1.9 KB
2.01 KB
2.11 KB
5.75 KB
5.97 KB
5.66 KB
5.94 KB
7.02 KB
5.18 KB
5.92 KB
2.81 KB
6.5 KB
3.97 KB
5.23 KB
5.5 KB
4.55 KB
5.58 KB
4.76 KB
1.87 KB
4.16 KB
4.91 KB
4.25 KB
1.68 KB
6.79 KB
5.56 KB
2.16 KB
5.84 KB
5.05 KB
2.08 KB
3.43 KB
9.13 KB
3.54 KB
3.97 KB
4.26 KB
4.72 KB
5.93 KB
5.04 KB
5.24 KB
3.74 KB
5.35 KB
7.77 KB
6.41 KB
5.61 KB
3.71 KB
3.82 KB
6.44 KB
6.11 KB
5.13 KB
1016 Bytes
3.84 KB
5.45 KB
4.67 KB
6.37 KB
5.55 KB
4.28 KB
5.31 KB
2.97 KB
5.81 KB
4.31 KB
6.49 KB
4.62 KB
3.66 KB
5.81 KB
5.37 KB
1.95 KB
3.24 KB
5.84 KB
4.38 KB
2.52 KB
3.67 KB
4.95 KB
4.96 KB
3.02 KB
5.91 KB
5.61 KB
6.03 KB
842 Bytes
1.69 KB
4.69 KB
5.61 KB
5.65 KB
3.58 KB
3.7 KB
2.94 KB
5.54 KB
3.46 KB
3.81 KB
4.7 KB
4.75 KB
1.37 KB
2.64 KB
4.72 KB
6.02 KB
4.33 KB
4.79 KB
5.39 KB
4.09 KB
5.71 KB
3.63 KB
4.27 KB
4.57 KB
5.92 KB
5.21 KB
5.12 KB
4.21 KB
3.44 KB
3.48 KB
6.83 KB
7.45 KB
4.43 KB
3.8 KB
3.33 KB
4.01 KB
2.94 KB
3.12 KB
4.32 KB
3.85 KB
2.98 KB
5.05 KB
4.08 KB
5.76 KB
4.63 KB
5.19 KB
5.59 KB
3.47 KB
3.63 KB
6.14 KB
4.56 KB
3.34 KB
3.07 KB
3.81 KB
4.97 KB
4.84 KB
4.9 KB
4.75 KB
6.02 KB
3.34 KB
2.41 KB
5.75 KB
6.36 KB
3.1 KB
5.07 KB
4.66 KB
5.37 KB
4.93 KB
872 Bytes
6.05 KB
6.3 KB
3.99 KB
6.13 KB
5.71 KB
4.82 KB
5.89 KB
4.13 KB
2.45 KB
4.29 KB
1.38 KB
3.41 KB
3.08 KB
5.13 KB
5.87 KB
4.73 KB
6.73 KB
3.98 KB
7.91 KB
3.8 KB
2.71 KB
2 KB
4.31 KB
4.87 KB
5.75 KB
2.18 KB
3.51 KB
1.98 KB
... | ... | @@ -1,11 +0,0 @@ |
1 | -$(document).ready(function(){ | |
2 | - $('input#user_force_random_password').on('change', function(elem) { | |
3 | - var elems = $('#user_password, #user_password_confirmation'); | |
4 | - | |
5 | - if ($(this).attr('checked')) { | |
6 | - elems.val('').attr('disabled', true); | |
7 | - } else { | |
8 | - elems.removeAttr('disabled'); | |
9 | - } | |
10 | - }); | |
11 | -}); |
... | ... | @@ -17,134 +17,3 @@ |
17 | 17 | //= require raphael |
18 | 18 | //= require branch-graph |
19 | 19 | //= require_tree . |
20 | - | |
21 | -$(document).ready(function(){ | |
22 | - | |
23 | - $(".one_click_select").live("click", function(){ | |
24 | - $(this).select(); | |
25 | - }); | |
26 | - | |
27 | - $('body').on('ajax:complete, ajax:beforeSend, submit', 'form', function(e){ | |
28 | - var buttons = $('[type="submit"]', this); | |
29 | - switch( e.type ){ | |
30 | - case 'ajax:beforeSend': | |
31 | - case 'submit': | |
32 | - buttons.attr('disabled', 'disabled'); | |
33 | - break; | |
34 | - case ' ajax:complete': | |
35 | - default: | |
36 | - buttons.removeAttr('disabled'); | |
37 | - break; | |
38 | - } | |
39 | - }) | |
40 | - | |
41 | - $(".account-box").mouseenter(showMenu); | |
42 | - $(".account-box").mouseleave(resetMenu); | |
43 | - | |
44 | - $("#projects-list .project").live('click', function(e){ | |
45 | - if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") { | |
46 | - location.href = $(this).attr("url"); | |
47 | - e.stopPropagation(); | |
48 | - return false; | |
49 | - } | |
50 | - }); | |
51 | - | |
52 | - /** | |
53 | - * Focus search field by pressing 's' key | |
54 | - */ | |
55 | - $(document).keypress(function(e) { | |
56 | - if( $(e.target).is(":input") ) return; | |
57 | - switch(e.which) { | |
58 | - case 115: focusSearch(); | |
59 | - e.preventDefault(); | |
60 | - } | |
61 | - }); | |
62 | - | |
63 | - /** | |
64 | - * Commit show suppressed diff | |
65 | - * | |
66 | - */ | |
67 | - $(".supp_diff_link").bind("click", function() { | |
68 | - showDiff(this); | |
69 | - }); | |
70 | - | |
71 | - /** | |
72 | - * Note markdown preview | |
73 | - * | |
74 | - */ | |
75 | - $(document).on('click', '#preview-link', function(e) { | |
76 | - $('#preview-note').text('Loading...'); | |
77 | - | |
78 | - var previewLinkText = ($(this).text() == 'Preview' ? 'Edit' : 'Preview'); | |
79 | - $(this).text(previewLinkText); | |
80 | - | |
81 | - var note = $('#note_note').val(); | |
82 | - if (note.trim().length === 0) { note = 'Nothing to preview'; } | |
83 | - $.post($(this).attr('href'), {note: note}, function(data) { | |
84 | - $('#preview-note').html(data); | |
85 | - }); | |
86 | - | |
87 | - $('#preview-note, #note_note').toggle(); | |
88 | - e.preventDefault(); | |
89 | - }); | |
90 | -}); | |
91 | - | |
92 | -function focusSearch() { | |
93 | - $("#search").focus(); | |
94 | -} | |
95 | - | |
96 | -function updatePage(data){ | |
97 | - $.ajax({type: "GET", url: location.href, data: data, dataType: "script"}); | |
98 | -} | |
99 | - | |
100 | -function showMenu() { | |
101 | - $(this).toggleClass('hover'); | |
102 | -} | |
103 | - | |
104 | -function resetMenu() { | |
105 | - $(this).removeClass("hover"); | |
106 | -} | |
107 | - | |
108 | -function slugify(text) { | |
109 | - return text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase(); | |
110 | -} | |
111 | - | |
112 | -function showDiff(link) { | |
113 | - $(link).next('table').show(); | |
114 | - $(link).remove(); | |
115 | -} | |
116 | - | |
117 | -(function($){ | |
118 | - var _chosen = $.fn.chosen; | |
119 | - $.fn.extend({ | |
120 | - chosen: function(options) { | |
121 | - var default_options = {'search_contains' : 'true'}; | |
122 | - $.extend(default_options, options); | |
123 | - return _chosen.apply(this, [default_options]); | |
124 | - }}) | |
125 | -})(jQuery); | |
126 | - | |
127 | - | |
128 | -function ajaxGet(url) { | |
129 | - $.ajax({type: "GET", url: url, dataType: "script"}); | |
130 | -} | |
131 | - | |
132 | -/** | |
133 | - * Disable button if text field is empty | |
134 | - */ | |
135 | -function disableButtonIfEmtpyField(field_selector, button_selector) { | |
136 | - field = $(field_selector); | |
137 | - if(field.val() == "") { | |
138 | - field.closest("form").find(button_selector).attr("disabled", "disabled").addClass("disabled"); | |
139 | - } | |
140 | - | |
141 | - field.on('keyup', function(){ | |
142 | - var field = $(this); | |
143 | - var closest_submit = field.closest("form").find(button_selector); | |
144 | - if(field.val() == "") { | |
145 | - closest_submit.attr("disabled", "disabled").addClass("disabled"); | |
146 | - } else { | |
147 | - closest_submit.removeAttr("disabled").removeClass("disabled"); | |
148 | - } | |
149 | - }) | |
150 | -} | ... | ... |
... | ... | @@ -1,10 +0,0 @@ |
1 | -function initGraphNav() { | |
2 | - $(".graph svg").css("position", "relative"); | |
3 | - $("body").bind("keyup", function(e) { | |
4 | - if(e.keyCode == 37) { // left | |
5 | - $(".graph svg").animate({ left: "+=400" }); | |
6 | - } else if(e.keyCode == 39) { // right | |
7 | - $(".graph svg").animate({ left: "-=400" }); | |
8 | - } | |
9 | - }); | |
10 | -} |
... | ... | @@ -0,0 +1,10 @@ |
1 | +initGraphNav = -> | |
2 | + $('.graph svg').css 'position', 'relative' | |
3 | + | |
4 | + $('body').bind 'keyup', (e) -> | |
5 | + if e.keyCode is 37 # left | |
6 | + $('.graph svg').animate left: '+=400' | |
7 | + else if e.keyCode is 39 # right | |
8 | + $('.graph svg').animate left: '-=400' | |
9 | + | |
10 | +window.initGraphNav = initGraphNav | ... | ... |
... | ... | @@ -0,0 +1,130 @@ |
1 | +$(document).ready(function(){ | |
2 | + | |
3 | + $(".one_click_select").live("click", function(){ | |
4 | + $(this).select(); | |
5 | + }); | |
6 | + | |
7 | + $('body').on('ajax:complete, ajax:beforeSend, submit', 'form', function(e){ | |
8 | + var buttons = $('[type="submit"]', this); | |
9 | + switch( e.type ){ | |
10 | + case 'ajax:beforeSend': | |
11 | + case 'submit': | |
12 | + buttons.attr('disabled', 'disabled'); | |
13 | + break; | |
14 | + case ' ajax:complete': | |
15 | + default: | |
16 | + buttons.removeAttr('disabled'); | |
17 | + break; | |
18 | + } | |
19 | + }) | |
20 | + | |
21 | + $(".account-box").mouseenter(showMenu); | |
22 | + $(".account-box").mouseleave(resetMenu); | |
23 | + | |
24 | + $("#projects-list .project").live('click', function(e){ | |
25 | + if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") { | |
26 | + location.href = $(this).attr("url"); | |
27 | + e.stopPropagation(); | |
28 | + return false; | |
29 | + } | |
30 | + }); | |
31 | + | |
32 | + /** | |
33 | + * Focus search field by pressing 's' key | |
34 | + */ | |
35 | + $(document).keypress(function(e) { | |
36 | + if( $(e.target).is(":input") ) return; | |
37 | + switch(e.which) { | |
38 | + case 115: focusSearch(); | |
39 | + e.preventDefault(); | |
40 | + } | |
41 | + }); | |
42 | + | |
43 | + /** | |
44 | + * Commit show suppressed diff | |
45 | + * | |
46 | + */ | |
47 | + $(".supp_diff_link").bind("click", function() { | |
48 | + showDiff(this); | |
49 | + }); | |
50 | + | |
51 | + /** | |
52 | + * Note markdown preview | |
53 | + * | |
54 | + */ | |
55 | + $(document).on('click', '#preview-link', function(e) { | |
56 | + $('#preview-note').text('Loading...'); | |
57 | + | |
58 | + var previewLinkText = ($(this).text() == 'Preview' ? 'Edit' : 'Preview'); | |
59 | + $(this).text(previewLinkText); | |
60 | + | |
61 | + var note = $('#note_note').val(); | |
62 | + if (note.trim().length === 0) { note = 'Nothing to preview'; } | |
63 | + $.post($(this).attr('href'), {note: note}, function(data) { | |
64 | + $('#preview-note').html(data); | |
65 | + }); | |
66 | + | |
67 | + $('#preview-note, #note_note').toggle(); | |
68 | + e.preventDefault(); | |
69 | + }); | |
70 | +}); | |
71 | + | |
72 | +function focusSearch() { | |
73 | + $("#search").focus(); | |
74 | +} | |
75 | + | |
76 | +function updatePage(data){ | |
77 | + $.ajax({type: "GET", url: location.href, data: data, dataType: "script"}); | |
78 | +} | |
79 | + | |
80 | +function showMenu() { | |
81 | + $(this).toggleClass('hover'); | |
82 | +} | |
83 | + | |
84 | +function resetMenu() { | |
85 | + $(this).removeClass("hover"); | |
86 | +} | |
87 | + | |
88 | +function slugify(text) { | |
89 | + return text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase(); | |
90 | +} | |
91 | + | |
92 | +function showDiff(link) { | |
93 | + $(link).next('table').show(); | |
94 | + $(link).remove(); | |
95 | +} | |
96 | + | |
97 | +(function($){ | |
98 | + var _chosen = $.fn.chosen; | |
99 | + $.fn.extend({ | |
100 | + chosen: function(options) { | |
101 | + var default_options = {'search_contains' : 'true'}; | |
102 | + $.extend(default_options, options); | |
103 | + return _chosen.apply(this, [default_options]); | |
104 | + }}) | |
105 | +})(jQuery); | |
106 | + | |
107 | + | |
108 | +function ajaxGet(url) { | |
109 | + $.ajax({type: "GET", url: url, dataType: "script"}); | |
110 | +} | |
111 | + | |
112 | +/** | |
113 | + * Disable button if text field is empty | |
114 | + */ | |
115 | +function disableButtonIfEmtpyField(field_selector, button_selector) { | |
116 | + field = $(field_selector); | |
117 | + if(field.val() == "") { | |
118 | + field.closest("form").find(button_selector).attr("disabled", "disabled").addClass("disabled"); | |
119 | + } | |
120 | + | |
121 | + field.on('keyup', function(){ | |
122 | + var field = $(this); | |
123 | + var closest_submit = field.closest("form").find(button_selector); | |
124 | + if(field.val() == "") { | |
125 | + closest_submit.attr("disabled", "disabled").addClass("disabled"); | |
126 | + } else { | |
127 | + closest_submit.removeAttr("disabled").removeClass("disabled"); | |
128 | + } | |
129 | + }) | |
130 | +} | ... | ... |
... | ... | @@ -1,16 +0,0 @@ |
1 | -function Projects() { | |
2 | - $("#project_name").live("change", function(){ | |
3 | - var slug = slugify($(this).val()); | |
4 | - $("#project_code").val(slug); | |
5 | - $("#project_path").val(slug); | |
6 | - }); | |
7 | - | |
8 | - $('.new_project, .edit_project').live('ajax:before', function() { | |
9 | - $('.project_new_holder, .project_edit_holder').hide(); | |
10 | - $('.save-project-loader').show(); | |
11 | - }); | |
12 | - | |
13 | - $('form #project_default_branch').chosen(); | |
14 | - | |
15 | - disableButtonIfEmtpyField("#project_name", ".project-submit") | |
16 | -} |
... | ... | @@ -0,0 +1,20 @@ |
1 | +window.Projects = -> | |
2 | + $('#project_name').on 'change', -> | |
3 | + slug = slugify $(@).val() | |
4 | + $('#project_code, #project_path').val slug | |
5 | + | |
6 | + $('.new_project, .edit_project').on 'ajax:before', -> | |
7 | + $('.project_new_holder, .project_edit_holder').hide() | |
8 | + $('.save-project-loader').show() | |
9 | + | |
10 | + $('form #project_default_branch').chosen() | |
11 | + disableButtonIfEmtpyField '#project_name', '.project-submit' | |
12 | + | |
13 | +# Git clone panel switcher | |
14 | +$ -> | |
15 | + scope = $ '.project_clone_holder' | |
16 | + if scope.length > 0 | |
17 | + $('a, button', scope).click -> | |
18 | + $('a, button', scope).removeClass 'active' | |
19 | + $(@).addClass 'active' | |
20 | + $('#project_clone', scope).val $(@).data 'clone' | ... | ... |
1 | 1 | .btn { |
2 | - background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #f7f7f7), to(#d5d5d5)); | |
3 | - background-image: -webkit-linear-gradient(#f7f7f7 7.6%, #d5d5d5); | |
4 | - background-image: -moz-linear-gradient(#f7f7f7 7.6%, #d5d5d5); | |
5 | - background-image: -o-linear-gradient(#f7f7f7 7.6%, #d5d5d5); | |
2 | + @include bg-gradient(#f7f7f7, #d5d5d5); | |
6 | 3 | border-color:#aaa; |
7 | 4 | &:hover { |
8 | 5 | @include bg-gray-gradient; |
... | ... | @@ -12,10 +9,8 @@ |
12 | 9 | |
13 | 10 | &.primary { |
14 | 11 | background:#2a79A3; |
12 | + @include bg-gradient(#47A7b7, #2585b5); | |
15 | 13 | border-color: #2A79A3; |
16 | - background-image: -webkit-linear-gradient(#47A7b7 7.6%, #2585b5); | |
17 | - background-image: -moz-linear-gradient(#47A7b7 7.6%, #2585b5); | |
18 | - background-image: -o-linear-gradient(#47A7b7 7.6%, #2585b5); | |
19 | 14 | color:#fff; |
20 | 15 | text-shadow: 0 1px 1px #268; |
21 | 16 | &:hover { |
... | ... | @@ -30,16 +25,11 @@ |
30 | 25 | } |
31 | 26 | |
32 | 27 | &.success { |
33 | - border-color: #4A4; | |
34 | - background-image: -webkit-linear-gradient(#82D482 7.6%, #22B442); | |
35 | - background-image: -moz-linear-gradient(#82D482 7.6%, #22B442); | |
36 | - background-image: -o-linear-gradient(#82D482 7.6%, #22B442); | |
37 | - color: #fff; | |
38 | - text-shadow: 0 1px 1px #141; | |
28 | + @extend .btn-success; | |
39 | 29 | |
40 | 30 | &:hover { |
41 | - background: #6C6; | |
42 | - color: #fff; | |
31 | + @extend .btn-success; | |
32 | + background: #51a351; | |
43 | 33 | } |
44 | 34 | |
45 | 35 | &.disabled { |
... | ... | @@ -62,10 +52,8 @@ |
62 | 52 | padding-right:30px; |
63 | 53 | } |
64 | 54 | |
65 | - &.danger, | |
66 | - &.btn-danger { | |
67 | - color:#fff; | |
68 | - background: #DA4E49; | |
55 | + &.danger { | |
56 | + @extend .btn-danger; | |
69 | 57 | border-color: #BD362F; |
70 | 58 | |
71 | 59 | &:hover { | ... | ... |
... | ... | @@ -3,13 +3,13 @@ |
3 | 3 | * |
4 | 4 | */ |
5 | 5 | .file_holder { |
6 | - border:1px solid #CCC; | |
6 | + border:1px solid #BBB; | |
7 | 7 | margin-bottom:1em; |
8 | 8 | @include solid_shade; |
9 | 9 | |
10 | 10 | .file_title { |
11 | 11 | border-bottom: 1px solid #bbb; |
12 | - @include bg-gray-gradient; | |
12 | + @include bg-dark-gray-gradient; | |
13 | 13 | margin: 0; |
14 | 14 | font-weight: normal; |
15 | 15 | font-weight: bold; | ... | ... |
1 | -table.highlighttable | |
2 | -{ | |
1 | +table.highlighttable { | |
3 | 2 | margin:0px; |
4 | 3 | padding:0px; |
5 | 4 | font-size:12px; |
6 | 5 | table-layout:fixed; |
7 | 6 | background: #EEE; |
7 | + box-shadow: none; | |
8 | + border: none; | |
9 | + td.linenos { | |
10 | + background:#eee; | |
11 | + border-left:none; | |
12 | + } | |
13 | + td.code { | |
14 | + border-right:none; | |
15 | + } | |
8 | 16 | } |
9 | 17 | |
18 | + | |
10 | 19 | td.code, |
11 | 20 | td.linenos{ |
12 | 21 | padding:0; | ... | ... |
1 | 1 | @import "bootstrap"; |
2 | 2 | @import "bootstrap-responsive"; |
3 | 3 | |
4 | -/** GITLAB colors **/ | |
4 | +/** GitLab colors **/ | |
5 | 5 | $link_color:#3A89A3; |
6 | 6 | $blue_link: #2fa0bb; |
7 | 7 | $style_color: #474d57; |
8 | 8 | $hover: #fdf5d9; |
9 | 9 | |
10 | -/** GITLAB Fonts **/ | |
10 | +/** GitLab Fonts **/ | |
11 | 11 | @font-face { font-family: Korolev; src: url('korolev-medium-compressed.otf'); } |
12 | 12 | |
13 | 13 | /** MIXINS **/ |
... | ... | @@ -56,6 +56,13 @@ $hover: #fdf5d9; |
56 | 56 | border-radius: $radius; |
57 | 57 | } |
58 | 58 | |
59 | +@mixin bg-gradient($from, $to) { | |
60 | + background-image: -webkit-gradient(linear, 0 0, 0 100%, from($from), to($to)); | |
61 | + background-image: -webkit-linear-gradient($from, $to); | |
62 | + background-image: -moz-linear-gradient($from, $to); | |
63 | + background-image: -o-linear-gradient($from, $to); | |
64 | +} | |
65 | + | |
59 | 66 | @mixin bg-gray-gradient { |
60 | 67 | background:#eee; |
61 | 68 | background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf)); |
... | ... | @@ -106,9 +113,9 @@ $hover: #fdf5d9; |
106 | 113 | @import "themes/ui_modern.scss"; |
107 | 114 | |
108 | 115 | /** |
109 | - * Gitlab bootstrap. | |
116 | + * GitLab bootstrap. | |
110 | 117 | * Overrides some styles of twitter bootstrap. |
111 | - * Also give some common classes for gitlab app | |
118 | + * Also give some common classes for GitLab app | |
112 | 119 | */ |
113 | 120 | @import "gitlab_bootstrap/common.scss"; |
114 | 121 | @import "gitlab_bootstrap/typography.scss"; | ... | ... |
... | ... | @@ -22,7 +22,7 @@ header { |
22 | 22 | * |
23 | 23 | */ |
24 | 24 | .app_logo { |
25 | - width:230px; | |
25 | + width:200px; | |
26 | 26 | float:left; |
27 | 27 | position:relative; |
28 | 28 | top:-5px; |
... | ... | @@ -31,7 +31,7 @@ header { |
31 | 31 | |
32 | 32 | h1 { |
33 | 33 | padding-top: 5px; |
34 | - width:102px; | |
34 | + width:90px; | |
35 | 35 | background: url('logo_dark.png') no-repeat 0px -3px; |
36 | 36 | float:left; |
37 | 37 | margin-left:5px; | ... | ... |
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | * Main Menu of Application |
3 | 3 | * |
4 | 4 | */ |
5 | -ul.main_menu { | |
5 | +ul.main_menu { | |
6 | 6 | border-radius: 4px; |
7 | 7 | margin: auto; |
8 | 8 | margin:30px 0; |
... | ... | @@ -12,7 +12,7 @@ ul.main_menu { |
12 | 12 | position:relative; |
13 | 13 | overflow:hidden; |
14 | 14 | @include shade; |
15 | - .count { | |
15 | + .count { | |
16 | 16 | position: relative; |
17 | 17 | top: -1px; |
18 | 18 | display: inline-block; |
... | ... | @@ -29,12 +29,12 @@ ul.main_menu { |
29 | 29 | border-radius: 8px; |
30 | 30 | -moz-border-radius: 8px; |
31 | 31 | } |
32 | - .label { | |
32 | + .label { | |
33 | 33 | background:$hover; |
34 | 34 | text-shadow:none; |
35 | 35 | color:$style_color; |
36 | 36 | } |
37 | - li { | |
37 | + li { | |
38 | 38 | list-style-type: none; |
39 | 39 | margin: 0; |
40 | 40 | display: table-cell; |
... | ... | @@ -43,7 +43,7 @@ ul.main_menu { |
43 | 43 | border-left: 1px solid #EEE; |
44 | 44 | border-bottom:2px solid #CFCFCF; |
45 | 45 | |
46 | - &:first-child{ | |
46 | + &:first-child{ | |
47 | 47 | -webkit-border-top-left-radius: 4px; |
48 | 48 | -webkit-border-bottom-left-radius: 4px; |
49 | 49 | -moz-border-radius-topleft: 4px; |
... | ... | @@ -53,31 +53,31 @@ ul.main_menu { |
53 | 53 | border-left: 0; |
54 | 54 | } |
55 | 55 | |
56 | - &.current { | |
56 | + &.current { | |
57 | 57 | background-color:#D5D5D5; |
58 | - border-bottom: 2px solid $style_color; | |
58 | + border-bottom: 1px solid #AAA; | |
59 | 59 | border-right: 1px solid #BBB; |
60 | 60 | border-left: 1px solid #BBB; |
61 | 61 | border-radius: 0 0 1px 1px; |
62 | - &:first-child{ | |
62 | + &:first-child{ | |
63 | 63 | border-bottom:none; |
64 | 64 | border-left:none; |
65 | 65 | } |
66 | 66 | } |
67 | 67 | |
68 | - &.home { | |
69 | - a { | |
68 | + &.home { | |
69 | + a { | |
70 | 70 | background: url(home_icon.PNG) no-repeat center center; |
71 | 71 | text-indent:-9999px; |
72 | 72 | min-width:20px; |
73 | - img { | |
73 | + img { | |
74 | 74 | position:relative; |
75 | 75 | top:4px; |
76 | 76 | } |
77 | 77 | } |
78 | 78 | } |
79 | 79 | } |
80 | - a { | |
80 | + a { | |
81 | 81 | display: block; |
82 | 82 | text-align: center; |
83 | 83 | font-weight:bold; | ... | ... |
... | ... | @@ -75,17 +75,21 @@ |
75 | 75 | padding: 4px 7px; |
76 | 76 | border: 1px solid #CCC; |
77 | 77 | margin-bottom:5px; |
78 | - input[type=text] { | |
78 | +} | |
79 | + | |
80 | +.project_clone_holder { | |
81 | + input[type="text"] { | |
79 | 82 | border: 1px solid #BBB; |
83 | + box-shadow: none; | |
80 | 84 | } |
81 | 85 | } |
82 | 86 | |
83 | -.save-project-loader { | |
84 | - img { | |
87 | +.save-project-loader { | |
88 | + img { | |
85 | 89 | margin-top:50px; |
86 | 90 | margin-bottom:50px; |
87 | 91 | } |
88 | - h3 { | |
92 | + h3 { | |
89 | 93 | @extend .page_title; |
90 | 94 | } |
91 | 95 | ... | ... |
... | ... | @@ -120,22 +120,12 @@ class ApplicationController < ActionController::Base |
120 | 120 | end |
121 | 121 | end |
122 | 122 | |
123 | - def load_refs | |
124 | - if params[:ref].blank? | |
125 | - @branch = params[:branch].blank? ? nil : params[:branch] | |
126 | - @tag = params[:tag].blank? ? nil : params[:tag] | |
127 | - @ref = @branch || @tag || @project.try(:default_branch) || Repository.default_ref | |
128 | - else | |
129 | - @ref = params[:ref] | |
130 | - end | |
131 | - end | |
132 | - | |
133 | 123 | def render_404 |
134 | 124 | render file: File.join(Rails.root, "public", "404"), layout: false, status: "404" |
135 | 125 | end |
136 | 126 | |
137 | 127 | def require_non_empty_project |
138 | - redirect_to @project unless @project.repo_exists? && @project.has_commits? | |
128 | + redirect_to @project if @project.empty_repo? | |
139 | 129 | end |
140 | 130 | |
141 | 131 | def no_cache_headers | ... | ... |
... | ... | @@ -59,12 +59,19 @@ class CommitsController < ApplicationController |
59 | 59 | |
60 | 60 | def patch |
61 | 61 | @commit = project.commit(params[:id]) |
62 | - | |
62 | + | |
63 | 63 | send_data( |
64 | 64 | @commit.to_patch, |
65 | 65 | type: "text/plain", |
66 | 66 | disposition: 'attachment', |
67 | - filename: (@commit.id.to_s + ".patch") | |
67 | + filename: "#{@commit.id.patch}" | |
68 | 68 | ) |
69 | 69 | end |
70 | + | |
71 | + protected | |
72 | + | |
73 | + def load_refs | |
74 | + @ref ||= params[:ref].presence || params[:branch].presence || params[:tag].presence | |
75 | + @ref ||= @ref || @project.try(:default_branch) || 'master' | |
76 | + end | |
70 | 77 | end | ... | ... |
... | ... | @@ -50,7 +50,7 @@ class ProjectsController < ApplicationController |
50 | 50 | |
51 | 51 | respond_to do |format| |
52 | 52 | format.html do |
53 | - if @project.repo_exists? && @project.has_commits? | |
53 | + unless @project.empty_repo? | |
54 | 54 | @last_push = current_user.recent_push(@project.id) |
55 | 55 | render :show |
56 | 56 | else | ... | ... |
1 | 1 | module GitlabMarkdownHelper |
2 | - # Replaces references (i.e. @abc, #123, !456, ...) in the text with links to | |
3 | - # the appropriate items in Gitlab. | |
4 | - # | |
5 | - # text - the source text | |
6 | - # html_options - extra options for the reference links as given to link_to | |
7 | - # | |
8 | - # note: reference links will only be generated if @project is set | |
9 | - # | |
10 | - # see Gitlab::Markdown for details on the supported syntax | |
11 | - def gfm(text, html_options = {}) | |
12 | - return text if text.nil? | |
13 | - return text if @project.nil? | |
14 | - | |
15 | - # Extract pre blocks so they are not altered | |
16 | - # from http://github.github.com/github-flavored-markdown/ | |
17 | - extractions = {} | |
18 | - text.gsub!(%r{<pre>.*?</pre>|<code>.*?</code>}m) do |match| | |
19 | - md5 = Digest::MD5.hexdigest(match) | |
20 | - extractions[md5] = match | |
21 | - "{gfm-extraction-#{md5}}" | |
22 | - end | |
23 | - | |
24 | - # TODO: add popups with additional information | |
25 | - | |
26 | - parser = Gitlab::Markdown.new(@project, html_options) | |
27 | - text = parser.parse(text) | |
28 | - | |
29 | - # Insert pre block extractions | |
30 | - text.gsub!(/\{gfm-extraction-(\h{32})\}/) do | |
31 | - extractions[$1] | |
32 | - end | |
33 | - | |
34 | - sanitize text.html_safe, attributes: ActionView::Base.sanitized_allowed_attributes + %w(id class ) | |
35 | - end | |
2 | + include Gitlab::Markdown | |
36 | 3 | |
37 | 4 | # Use this in places where you would normally use link_to(gfm(...), ...). |
38 | 5 | # | ... | ... |
... | ... | @@ -111,18 +111,18 @@ class Notify < ActionMailer::Base |
111 | 111 | # Examples |
112 | 112 | # |
113 | 113 | # >> subject('Lorem ipsum') |
114 | - # => "gitlab | Lorem ipsum" | |
114 | + # => "GitLab | Lorem ipsum" | |
115 | 115 | # |
116 | 116 | # # Automatically inserts Project name when @project is set |
117 | 117 | # >> @project = Project.last |
118 | 118 | # => #<Project id: 1, name: "Ruby on Rails", path: "ruby_on_rails", ...> |
119 | 119 | # >> subject('Lorem ipsum') |
120 | - # => "gitlab | Lorem ipsum | Ruby on Rails" | |
120 | + # => "GitLab | Lorem ipsum | Ruby on Rails" | |
121 | 121 | # |
122 | 122 | # # Accepts multiple arguments |
123 | 123 | # >> subject('Lorem ipsum', 'Dolor sit amet') |
124 | - # => "gitlab | Lorem ipsum | Dolor sit amet" | |
124 | + # => "GitLab | Lorem ipsum | Dolor sit amet" | |
125 | 125 | def subject(*extra) |
126 | - "gitlab | " << extra.join(' | ') << (@project ? " | #{@project.name}" : "") | |
126 | + "GitLab | " << extra.join(' | ') << (@project ? " | #{@project.name}" : "") | |
127 | 127 | end |
128 | 128 | end | ... | ... |
... | ... | @@ -103,7 +103,7 @@ class Note < ActiveRecord::Base |
103 | 103 | # Returns true if this is an upvote note, |
104 | 104 | # otherwise false is returned |
105 | 105 | def upvote? |
106 | - note =~ /^\+1/ ? true : false | |
106 | + note.start_with?('+1') || note.start_with?(':+1:') | |
107 | 107 | end |
108 | 108 | end |
109 | 109 | # == Schema Information | ... | ... |
... | ... | @@ -104,6 +104,8 @@ class Project < ActiveRecord::Base |
104 | 104 | length: { within: 1..255 } |
105 | 105 | |
106 | 106 | validates :owner, presence: true |
107 | + validates :issues_enabled, :wall_enabled, :merge_requests_enabled, | |
108 | + :wiki_enabled, inclusion: { in: [true, false] } | |
107 | 109 | validate :check_limit |
108 | 110 | validate :repo_name |
109 | 111 | |
... | ... | @@ -187,7 +189,7 @@ end |
187 | 189 | # private_flag :boolean(1) default(TRUE), not null |
188 | 190 | # code :string(255) |
189 | 191 | # owner_id :integer(4) |
190 | -# default_branch :string(255) default("master"), not null | |
192 | +# default_branch :string(255) | |
191 | 193 | # issues_enabled :boolean(1) default(TRUE), not null |
192 | 194 | # wall_enabled :boolean(1) default(TRUE), not null |
193 | 195 | # merge_requests_enabled :boolean(1) default(TRUE), not null | ... | ... |
... | ... | @@ -14,7 +14,7 @@ class UsersProject < ActiveRecord::Base |
14 | 14 | after_save :update_repository |
15 | 15 | after_destroy :update_repository |
16 | 16 | |
17 | - validates_uniqueness_of :user_id, scope: [:project_id] | |
17 | + validates_uniqueness_of :user_id, scope: [:project_id], message: "already exists in project" | |
18 | 18 | validates_presence_of :user_id |
19 | 19 | validates_presence_of :project_id |
20 | 20 | |
... | ... | @@ -48,10 +48,10 @@ class UsersProject < ActiveRecord::Base |
48 | 48 | |
49 | 49 | def self.access_roles |
50 | 50 | { |
51 | - "Guest" => GUEST, | |
52 | - "Reporter" => REPORTER, | |
51 | + "Guest" => GUEST, | |
52 | + "Reporter" => REPORTER, | |
53 | 53 | "Developer" => DEVELOPER, |
54 | - "Master" => MASTER | |
54 | + "Master" => MASTER | |
55 | 55 | } |
56 | 56 | end |
57 | 57 | ... | ... |
1 | -module Account | |
1 | +module Account | |
2 | + # Returns a string for use as a Gitolite user identifier | |
3 | + # | |
4 | + # Note that Gitolite 2.x requires the following pattern for users: | |
5 | + # | |
6 | + # ^@?[0-9a-zA-Z][0-9a-zA-Z._\@+-]*$ | |
2 | 7 | def identifier |
3 | - email.gsub /[^[:alnum:]]/, "_" | |
8 | + # Replace non-word chars with underscores, then make sure it starts with | |
9 | + # valid chars | |
10 | + email.gsub(/\W/, '_').gsub(/\A([\W\_])+/, '') | |
4 | 11 | end |
5 | 12 | |
6 | 13 | def is_admin? | ... | ... |
1 | +# Includes methods for handling Git Push events | |
2 | +# | |
3 | +# Triggered by PostReceive job | |
1 | 4 | module PushObserver |
2 | 5 | def observe_push(oldrev, newrev, ref, user) |
3 | 6 | data = post_receive_data(oldrev, newrev, ref, user) |
... | ... | @@ -84,11 +87,10 @@ module PushObserver |
84 | 87 | data |
85 | 88 | end |
86 | 89 | |
87 | - | |
88 | - # This method will be called after each post receive | |
89 | - # and only if user present in gitlab. | |
90 | - # All callbacks for post receive should be placed here | |
90 | + # This method will be called after each post receive and only if the provided | |
91 | + # user is present in GitLab. | |
91 | 92 | # |
93 | + # All callbacks for post receive should be placed here. | |
92 | 94 | def trigger_post_receive(oldrev, newrev, ref, user) |
93 | 95 | # Create push event |
94 | 96 | self.observe_push(oldrev, newrev, ref, user) |
... | ... | @@ -101,5 +103,11 @@ module PushObserver |
101 | 103 | |
102 | 104 | # Create satellite |
103 | 105 | self.satellite.create unless self.satellite.exists? |
106 | + | |
107 | + # Discover the default branch, but only if it hasn't already been set to | |
108 | + # something else | |
109 | + if default_branch.nil? | |
110 | + update_attributes(default_branch: discover_default_branch) | |
111 | + end | |
104 | 112 | end |
105 | 113 | end | ... | ... |
... | ... | @@ -8,6 +8,10 @@ module Repository |
8 | 8 | false |
9 | 9 | end |
10 | 10 | |
11 | + def empty_repo? | |
12 | + !repo_exists? || !has_commits? | |
13 | + end | |
14 | + | |
11 | 15 | def commit(commit_id = nil) |
12 | 16 | Commit.find_or_first(repo, commit_id, root_ref) |
13 | 17 | end |
... | ... | @@ -38,7 +42,7 @@ module Repository |
38 | 42 | |
39 | 43 | def has_post_receive_file? |
40 | 44 | hook_file = File.join(path_to_repo, 'hooks', 'post-receive') |
41 | - File.exists?(hook_file) | |
45 | + File.exists?(hook_file) | |
42 | 46 | end |
43 | 47 | |
44 | 48 | def tags |
... | ... | @@ -67,7 +71,7 @@ module Repository |
67 | 71 | |
68 | 72 | def repo_exists? |
69 | 73 | @repo_exists ||= (repo && !repo.branches.empty?) |
70 | - rescue | |
74 | + rescue | |
71 | 75 | @repo_exists = false |
72 | 76 | end |
73 | 77 | |
... | ... | @@ -90,24 +94,42 @@ module Repository |
90 | 94 | end.sort_by(&:name) |
91 | 95 | end |
92 | 96 | |
97 | + # Discovers the default branch based on the repository's available branches | |
98 | + # | |
99 | + # - If no branches are present, returns nil | |
100 | + # - If one branch is present, returns its name | |
101 | + # - If two or more branches are present, returns the one that has a name | |
102 | + # matching root_ref (default_branch or 'master' if default_branch is nil) | |
103 | + def discover_default_branch | |
104 | + branches = heads.collect(&:name) | |
105 | + | |
106 | + if branches.length == 0 | |
107 | + nil | |
108 | + elsif branches.length == 1 | |
109 | + branches.first | |
110 | + else | |
111 | + branches.select { |v| v == root_ref }.first | |
112 | + end | |
113 | + end | |
114 | + | |
93 | 115 | def has_commits? |
94 | 116 | !!commit |
95 | 117 | end |
96 | 118 | |
97 | - def root_ref | |
119 | + def root_ref | |
98 | 120 | default_branch || "master" |
99 | 121 | end |
100 | 122 | |
101 | - def root_ref? branch | |
123 | + def root_ref?(branch) | |
102 | 124 | root_ref == branch |
103 | 125 | end |
104 | 126 | |
105 | 127 | # Archive Project to .tar.gz |
106 | 128 | # |
107 | - # Already packed repo archives stored at | |
129 | + # Already packed repo archives stored at | |
108 | 130 | # app_root/tmp/repositories/project_name/project_name-commit-id.tag.gz |
109 | 131 | # |
110 | - def archive_repo ref | |
132 | + def archive_repo(ref) | |
111 | 133 | ref = ref || self.root_ref |
112 | 134 | commit = self.commit(ref) |
113 | 135 | return nil unless commit |
... | ... | @@ -134,6 +156,6 @@ module Repository |
134 | 156 | end |
135 | 157 | |
136 | 158 | def http_url_to_repo |
137 | - http_url = [Gitlab.config.url, "/", path, ".git"].join() | |
159 | + http_url = [Gitlab.config.url, "/", path, ".git"].join('') | |
138 | 160 | end |
139 | 161 | end | ... | ... |
... | ... | @@ -11,8 +11,13 @@ |
11 | 11 | .input= f.text_field :title |
12 | 12 | .clearfix |
13 | 13 | = f.label :key |
14 | - .input= f.text_area :key, class: "xlarge" | |
14 | + .input | |
15 | + = f.text_area :key, class: [:xxlarge, :thin_area] | |
16 | + %p.hint | |
17 | + Paste a machine public key here. Read more about how generate it | |
18 | + = link_to "here", help_ssh_path | |
19 | + | |
15 | 20 | .actions |
16 | - = f.submit 'Save', class: "primary btn" | |
17 | - = link_to "Cancel", project_deploy_keys_path(@project), class: "btn" | |
21 | + = f.submit 'Save', class: "save-btn btn" | |
22 | + = link_to "Cancel", project_deploy_keys_path(@project), class: "btn cancel-btn" | |
18 | 23 | ... | ... |
1 | 1 | = render "repositories/head" |
2 | -- if can? current_user, :admin_project, @project | |
3 | - .alert-message.block-message | |
4 | - Deploy keys allow read-only access to repository. | |
2 | + | |
3 | +%p.slead | |
4 | + Deploy keys allow read-only access to repository. It matches perfectly for CI, staging or production servers. | |
5 | + | |
6 | + - if can? current_user, :admin_project, @project | |
5 | 7 | = link_to new_project_deploy_key_path(@project), class: "btn small", title: "New Deploy Key" do |
6 | 8 | Add Deploy Key |
7 | - | |
8 | 9 | - if @keys.any? |
9 | 10 | %table |
11 | + %thead | |
12 | + %tr | |
13 | + %th Keys | |
14 | + %th | |
15 | + %th | |
10 | 16 | - @keys.each do |key| |
11 | 17 | = render(partial: 'show', locals: {key: key}) | ... | ... |
1 | 1 | = render "repositories/head" |
2 | -%h3= @key.title | |
2 | +%h3.page_title | |
3 | + Deploy key: | |
4 | + = @key.title | |
5 | + %small | |
6 | + created at | |
7 | + = @key.created_at.stamp("Aug 21, 2011") | |
8 | +.back_link | |
9 | + = link_to project_deploy_keys_path(@project) do | |
10 | + ← To keys list | |
3 | 11 | %hr |
4 | 12 | %pre= @key.key |
5 | -.actions | |
13 | +.right | |
6 | 14 | = link_to 'Remove', project_deploy_key_path(@key.project, @key), confirm: 'Are you sure?', method: :delete, class: "danger btn delete-key" |
7 | - .clear | ... | ... |
1 | -%h3.page_title Gitlab Flavored Markdown | |
1 | +%h3.page_title GitLab Flavored Markdown | |
2 | 2 | .back_link |
3 | 3 | = link_to help_path do |
4 | 4 | ← to index |
... | ... | @@ -7,7 +7,7 @@ |
7 | 7 | .row |
8 | 8 | .span8 |
9 | 9 | %p |
10 | - For Gitlab we developed something we call "Gitlab Flavored Markdown" (GFM). | |
10 | + For GitLab we developed something we call "GitLab Flavored Markdown" (GFM). | |
11 | 11 | It extends the standard Markdown in a few significant ways adds some useful functionality. |
12 | 12 | |
13 | 13 | %p You can use GFM in: |
... | ... | @@ -62,7 +62,7 @@ |
62 | 62 | %p becomes |
63 | 63 | = markdown %Q{```ruby\nrequire 'redcarpet'\nmarkdown = Redcarpet.new("Hello World!")\nputs markdown.to_html\n```} |
64 | 64 | |
65 | - %h4 Special Gitlab references | |
65 | + %h4 Special GitLab references | |
66 | 66 | |
67 | 67 | %p |
68 | 68 | GFM recognizes special references. |
... | ... | @@ -90,12 +90,11 @@ |
90 | 90 | -# this example will only be shown if the user has a project with at least one issue |
91 | 91 | - if @project = current_user.projects.first |
92 | 92 | - if issue = @project.issues.first |
93 | - %p For example in your #{link_to @project.name, project_path(@project)} project something like | |
93 | + %p For example in your #{link_to @project.name, project_path(@project)} project, writing: | |
94 | 94 | %pre= "This is related to ##{issue.id}. @#{current_user.name} is working on solving it." |
95 | - %p becomes | |
96 | - = markdown "This is related to ##{issue.id}. @#{current_user.name} is working on solving it." | |
97 | - | |
98 | - | |
95 | + %p becomes: | |
96 | + %pre= gfm "This is related to ##{issue.id}. @#{current_user.name} is working on solving it." | |
97 | + - @project = nil # Prevent this from bubbling up to page title | |
99 | 98 | |
100 | 99 | .span4.right |
101 | 100 | .alert.alert-info | ... | ... |
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 | %hr |
6 | 6 | |
7 | 7 | %p.slead |
8 | - SSH key allows you to establish a secure connection between your computer and Gitlab | |
8 | + SSH key allows you to establish a secure connection between your computer and GitLab | |
9 | 9 | |
10 | 10 | %p.slead |
11 | 11 | To generate a new SSH key just open your terminal and use code below. |
... | ... | @@ -17,7 +17,7 @@ |
17 | 17 | \# Generating public/private rsa key pair... |
18 | 18 | |
19 | 19 | %p.slead |
20 | - Next just use code below to dump your public key and add to GITLAB SSH Keys | |
20 | + Next just use code below to dump your public key and add to GitLab SSH Keys | |
21 | 21 | |
22 | 22 | %pre.dark |
23 | 23 | cat ~/.ssh/id_rsa.pub | ... | ... |
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 | %hr |
6 | 6 | |
7 | 7 | %p.slead |
8 | - Your Gitlab instance can perform HTTP POST request on next event: create_project, delete_project, create_user, delete_user, change_team_member. | |
8 | + Your GitLab instance can perform HTTP POST request on next event: create_project, delete_project, create_user, delete_user, change_team_member. | |
9 | 9 | %br |
10 | 10 | System Hooks can be used for logging or change information in LDAP server. |
11 | 11 | %br | ... | ... |
... | ... | @@ -5,11 +5,11 @@ |
5 | 5 | %hr |
6 | 6 | |
7 | 7 | %p.slead |
8 | - Every Gitlab project can trigger a web server whenever the repo is pushed to. | |
8 | + Every GitLab project can trigger a web server whenever the repo is pushed to. | |
9 | 9 | %br |
10 | 10 | Web Hooks can be used to update an external issue tracker, trigger CI builds, update a backup mirror, or even deploy to your production server. |
11 | 11 | %br |
12 | - GITLAB will send POST request with commits information on every push. | |
12 | + GitLab will send POST request with commits information on every push. | |
13 | 13 | %h5 Hooks request example: |
14 | 14 | = render "hooks/data_ex" |
15 | 15 | ... | ... |
... | ... | @@ -38,7 +38,7 @@ |
38 | 38 | = f.label :description, "Details" |
39 | 39 | .input |
40 | 40 | = f.text_area :description, maxlength: 2000, class: "xxlarge", rows: 14 |
41 | - %p.hint Issues are parsed with #{link_to "Gitlab Flavored Markdown", help_markdown_path, target: '_blank'}. | |
41 | + %p.hint Issues are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}. | |
42 | 42 | |
43 | 43 | |
44 | 44 | .actions | ... | ... |
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | %head |
3 | 3 | %meta{content: "text/html; charset=utf-8", "http-equiv" => "Content-Type"} |
4 | 4 | %title |
5 | - gitlabhq | |
5 | + GitLab | |
6 | 6 | :css |
7 | 7 | .header h1 {color: #BBBBBB !important; font: bold 32px Helvetica, Arial, sans-serif; margin: 0; padding: 0; line-height: 40px;} |
8 | 8 | .header p {color: #c6c6c6; font: normal 12px Helvetica, Arial, sans-serif; margin: 0; padding: 0; line-height: 18px;} |
... | ... | @@ -21,7 +21,7 @@ |
21 | 21 | \ |
22 | 22 | %td{align: "left", style: "padding: 18px 0 10px;", width: "580"} |
23 | 23 | %h1{style: "color: #BBBBBB; font: normal 32px Helvetica, Arial, sans-serif; margin: 0; padding: 0; line-height: 40px;"} |
24 | - gitlab | |
24 | + GITLAB | |
25 | 25 | - if @project |
26 | 26 | | #{@project.name} |
27 | 27 | %table{align: "center", bgcolor: "#fff", border: "0", cellpadding: "0", cellspacing: "0", style: "font-family: Helvetica, Arial, sans-serif; background: #fff;", width: "600"} | ... | ... |
... | ... | @@ -22,7 +22,7 @@ |
22 | 22 | = f.label :description, "Description", class: "control-label" |
23 | 23 | .controls |
24 | 24 | = f.text_area :description, maxlength: 2000, class: "input-xlarge", rows: 10 |
25 | - %p.hint Milestones are parsed with #{link_to "Gitlab Flavored Markdown", help_markdown_path, target: '_blank'}. | |
25 | + %p.hint Milestones are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}. | |
26 | 26 | .span6 |
27 | 27 | .control-group |
28 | 28 | = f.label :due_date, "Due Date", class: "control-label" | ... | ... |
... | ... | @@ -11,7 +11,7 @@ |
11 | 11 | = f.text_area :note, size: 255, class: 'note-text' |
12 | 12 | #preview-note.preview_note.hide |
13 | 13 | .hint |
14 | - .right Comments are parsed with #{link_to "Gitlab Flavored Markdown", help_markdown_path, target: '_blank'}. | |
14 | + .right Comments are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}. | |
15 | 15 | .clearfix |
16 | 16 | |
17 | 17 | .row.note_advanced_opts.hide | ... | ... |
... | ... | @@ -6,7 +6,7 @@ |
6 | 6 | %h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} |
7 | 7 | Hi #{@user['name']}! |
8 | 8 | %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} |
9 | - Administrator created account for you. Now you are a member of company gitlab application. | |
9 | + Administrator created account for you. Now you are a member of company GitLab application. | |
10 | 10 | %td{style: "font-size: 1px; line-height: 1px;", width: "21"} |
11 | 11 | %tr |
12 | 12 | %td{style: "font-size: 1px; line-height: 1px;", width: "21"} | ... | ... |
... | ... | @@ -3,19 +3,19 @@ |
3 | 3 | .span7 |
4 | 4 | .form-horizontal |
5 | 5 | .input-prepend.project_clone_holder |
6 | - = link_to "SSH", "#", class: "btn small active", :"data-clone" => @project.ssh_url_to_repo | |
7 | - = link_to "HTTP", "#", class: "btn small", :"data-clone" => @project.http_url_to_repo | |
6 | + %button{class: "btn small active", :"data-clone" => @project.ssh_url_to_repo} SSH | |
7 | + %button{class: "btn small", :"data-clone" => @project.http_url_to_repo} HTTP | |
8 | 8 | = text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select span5" |
9 | 9 | .span4.right |
10 | 10 | .right |
11 | - - if can? current_user, :download_code, @project | |
12 | - = link_to archive_project_repository_path(@project), class: "btn small grouped" do | |
13 | - %i.icon-download-alt | |
14 | - Download | |
15 | - - if @project.merge_requests_enabled && can?(current_user, :write_merge_request, @project) | |
16 | - = link_to new_project_merge_request_path(@project), title: "New Merge Request", class: "btn small grouped" do | |
17 | - Merge Request | |
18 | - - if @project.issues_enabled && can?(current_user, :write_issue, @project) | |
19 | - = link_to new_project_issue_path(@project), title: "New Issue", class: "btn small grouped" do | |
20 | - Issue | |
21 | - | |
11 | + - unless @project.empty_repo? | |
12 | + - if can? current_user, :download_code, @project | |
13 | + = link_to archive_project_repository_path(@project), class: "btn small grouped" do | |
14 | + %i.icon-download-alt | |
15 | + Download | |
16 | + - if @project.merge_requests_enabled && can?(current_user, :write_merge_request, @project) | |
17 | + = link_to new_project_merge_request_path(@project), title: "New Merge Request", class: "btn small grouped" do | |
18 | + Merge Request | |
19 | + - if @project.issues_enabled && can?(current_user, :write_issue, @project) | |
20 | + = link_to new_project_issue_path(@project), title: "New Issue", class: "btn small grouped" do | |
21 | + Issue | ... | ... |
... | ... | @@ -1,23 +0,0 @@ |
1 | -%h5.title | |
2 | - = @project.name | |
3 | -%br | |
4 | -%div | |
5 | - %a.btn.info{href: tree_project_ref_path(@project, @project.root_ref)} Browse code | |
6 | - | |
7 | - %a.btn{href: project_commits_path(@project)} Commits | |
8 | - %strong.right | |
9 | - = link_to project_path(@project) do | |
10 | - Switch to project → | |
11 | -%br | |
12 | -.alert-message.block-message.warning | |
13 | - .input | |
14 | - .input-prepend | |
15 | - %span.add-on git clone | |
16 | - = text_field_tag :project_clone, @project.url_to_repo, class: "xlarge one_click_select git_clone_url" | |
17 | - | |
18 | -= simple_format @project.description | |
19 | -- unless @events.blank? | |
20 | - %h4.middle_title Recent Activity | |
21 | - .content_list= render @events | |
22 | - | |
23 | - |
1 | 1 | = render 'shared/no_ssh' |
2 | -.project_clone_panel | |
3 | - .row | |
4 | - .span7 | |
5 | - .form-horizontal | |
6 | - .input-prepend.project_clone_holder | |
7 | - = link_to "SSH", "#", class: "btn small active", :"data-clone" => @project.ssh_url_to_repo | |
8 | - = link_to "HTTP", "#", class: "btn small", :"data-clone" => @project.http_url_to_repo | |
9 | - = text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select span5" | |
2 | += render 'clone_panel' | |
3 | + | |
10 | 4 | %div.git-empty |
11 | 5 | %h4 Git global setup: |
12 | 6 | %pre.dark |
... | ... | @@ -36,16 +30,3 @@ |
36 | 30 | - if can? current_user, :admin_project, @project |
37 | 31 | .prepend-top-20 |
38 | 32 | = link_to 'Remove project', @project, confirm: 'Are you sure?', method: :delete, class: "btn danger right" |
39 | - | |
40 | - | |
41 | - | |
42 | -:javascript | |
43 | - $(function(){ | |
44 | - var link_sel = ".project_clone_holder a"; | |
45 | - $(link_sel).bind("click", function() { | |
46 | - $(link_sel).removeClass("active"); | |
47 | - $(this).addClass("active"); | |
48 | - $("#project_clone").val($(this).attr("data-clone")); | |
49 | - }) | |
50 | - }) | |
51 | - | ... | ... |
... | ... | @@ -2,13 +2,3 @@ |
2 | 2 | = render 'clone_panel' |
3 | 3 | = render "events/event_last_push", event: @last_push |
4 | 4 | .content_list= render @events |
5 | - | |
6 | -:javascript | |
7 | - $(function(){ | |
8 | - var link_sel = ".project_clone_holder a"; | |
9 | - $(link_sel).bind("click", function() { | |
10 | - $(link_sel).removeClass("active"); | |
11 | - $(this).addClass("active"); | |
12 | - $("#project_clone").val($(this).attr("data-clone")); | |
13 | - }) | |
14 | - }) | ... | ... |
... | ... | @@ -7,4 +7,8 @@ |
7 | 7 | %li{class: "#{'active' if (controller.controller_name == "refs") }"} |
8 | 8 | = link_to tree_project_ref_path(@project, @ref) do |
9 | 9 | Source |
10 | - | |
10 | + %li.right | |
11 | + .input-prepend.project_clone_holder | |
12 | + %button{class: "btn small active", :"data-clone" => @project.ssh_url_to_repo} SSH | |
13 | + %button{class: "btn small", :"data-clone" => @project.http_url_to_repo} HTTP | |
14 | + = text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select span5" | ... | ... |
... | ... | @@ -3,7 +3,7 @@ |
3 | 3 | |
4 | 4 | .team_member_show |
5 | 5 | - if can? current_user, :admin_project, @project |
6 | - = link_to 'Remove from team', project_team_member_path(project_id: @project, id: @team_member.id), confirm: 'Are you sure?', method: :delete, class: "right btn btn-danger" | |
6 | + = link_to 'Remove from team', project_team_member_path(project_id: @project, id: @team_member.id), confirm: 'Are you sure?', method: :delete, class: "right btn danger" | |
7 | 7 | .profile_avatar_holder |
8 | 8 | = image_tag gravatar_icon(user.email, 60), class: "borders" |
9 | 9 | %h3 | ... | ... |
... | ... | @@ -14,7 +14,7 @@ |
14 | 14 | .middle_box_content |
15 | 15 | .input |
16 | 16 | %span.cgray |
17 | - Wiki content is parsed with #{link_to "Gitlab Flavored Markdown", help_markdown_path, target: '_blank'}. | |
17 | + Wiki content is parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}. | |
18 | 18 | To link to a (new) page you can just type |
19 | 19 | %code [Link Title](page-slug) |
20 | 20 | \. | ... | ... |
... | ... | @@ -50,10 +50,6 @@ Gitlab::Application.routes.draw do |
50 | 50 | end |
51 | 51 | end |
52 | 52 | resources :team_members, :only => [:edit, :update, :destroy] |
53 | - get 'mailer/preview_note' | |
54 | - get 'mailer/preview_user_new' | |
55 | - get 'mailer/preview_issue_new' | |
56 | - | |
57 | 53 | resources :hooks, :only => [:index, :create, :destroy] do |
58 | 54 | get :test |
59 | 55 | end | ... | ... |
... | ... | @@ -0,0 +1,12 @@ |
1 | +class SetDefaultBranchDefaultToNil < ActiveRecord::Migration | |
2 | + def up | |
3 | + # Set the default_branch to allow nil, and default it to nil | |
4 | + change_column_null(:projects, :default_branch, true) | |
5 | + change_column_default(:projects, :default_branch, nil) | |
6 | + end | |
7 | + | |
8 | + def down | |
9 | + change_column_null(:projects, :default_branch, false) | |
10 | + change_column_default(:projects, :default_branch, 'master') | |
11 | + end | |
12 | +end | ... | ... |
... | ... | @@ -11,7 +11,7 @@ |
11 | 11 | # |
12 | 12 | # It's strongly recommended to check this file into your version control system. |
13 | 13 | |
14 | -ActiveRecord::Schema.define(:version => 20120729131232) do | |
14 | +ActiveRecord::Schema.define(:version => 20120905043334) do | |
15 | 15 | |
16 | 16 | create_table "events", :force => true do |t| |
17 | 17 | t.string "target_type" |
... | ... | @@ -98,16 +98,16 @@ ActiveRecord::Schema.define(:version => 20120729131232) do |
98 | 98 | t.string "name" |
99 | 99 | t.string "path" |
100 | 100 | t.text "description" |
101 | - t.datetime "created_at", :null => false | |
102 | - t.datetime "updated_at", :null => false | |
103 | - t.boolean "private_flag", :default => true, :null => false | |
101 | + t.datetime "created_at", :null => false | |
102 | + t.datetime "updated_at", :null => false | |
103 | + t.boolean "private_flag", :default => true, :null => false | |
104 | 104 | t.string "code" |
105 | 105 | t.integer "owner_id" |
106 | - t.string "default_branch", :default => "master", :null => false | |
107 | - t.boolean "issues_enabled", :default => true, :null => false | |
108 | - t.boolean "wall_enabled", :default => true, :null => false | |
109 | - t.boolean "merge_requests_enabled", :default => true, :null => false | |
110 | - t.boolean "wiki_enabled", :default => true, :null => false | |
106 | + t.string "default_branch" | |
107 | + t.boolean "issues_enabled", :default => true, :null => false | |
108 | + t.boolean "wall_enabled", :default => true, :null => false | |
109 | + t.boolean "merge_requests_enabled", :default => true, :null => false | |
110 | + t.boolean "wiki_enabled", :default => true, :null => false | |
111 | 111 | end |
112 | 112 | |
113 | 113 | create_table "protected_branches", :force => true do |t| | ... | ... |
1 | -# Gitlab API | |
1 | +# GitLab API | |
2 | 2 | |
3 | -All API requests require authentication. You need to pass `private_token` parameter to authenticate. | |
3 | +All API requests require authentication. You need to pass a `private_token` parameter to authenticate. You can find or reset your private token in your profile. | |
4 | 4 | |
5 | -To get or reset your token visit your profile. | |
6 | - | |
7 | -If no or invalid `private_token` provided error message will be returned with status code 401: | |
5 | +If no, or an invalid, `private_token` is provided then an error message will be returned with status code 401: | |
8 | 6 | |
9 | 7 | ```json |
10 | 8 | { |
... | ... | @@ -12,10 +10,9 @@ If no or invalid `private_token` provided error message will be returned with st |
12 | 10 | } |
13 | 11 | ``` |
14 | 12 | |
15 | -API requests should be prefixed with `api` and the API version. | |
16 | -API version is equal to Gitlab major version number and defined in `lib/api.rb`. | |
13 | +API requests should be prefixed with `api` and the API version. The API version is equal to the GitLab major version number, which is defined in `lib/api.rb`. | |
17 | 14 | |
18 | -Example of valid API request: | |
15 | +Example of a valid API request: | |
19 | 16 | |
20 | 17 | ``` |
21 | 18 | GET http://example.com/api/v2/projects?private_token=QVy1PB7sTxfy4pqfZM1U | ... | ... |
1 | 1 | ## List projects |
2 | 2 | |
3 | -Get a list of authenticated user's projects. | |
3 | +Get a list of projects owned by the authenticated user. | |
4 | 4 | |
5 | 5 | ``` |
6 | 6 | GET /projects |
... | ... | @@ -55,7 +55,7 @@ GET /projects |
55 | 55 | |
56 | 56 | ## Single project |
57 | 57 | |
58 | -Get an authenticated user's project. | |
58 | +Get a specific project, identified by project ID, which is owned by the authentication user. | |
59 | 59 | |
60 | 60 | ``` |
61 | 61 | GET /projects/:id |
... | ... | @@ -102,6 +102,12 @@ Parameters: |
102 | 102 | + `name` (required) - new project name |
103 | 103 | + `code` (optional) - new project code, uses project name if not set |
104 | 104 | + `path` (optional) - new project path, uses project name if not set |
105 | ++ `description (optional) - short project description | |
106 | ++ `default_branch` (optional) - 'master' by default | |
107 | ++ `issues_enabled` (optional) - enabled by default | |
108 | ++ `wall_enabled` (optional) - enabled by default | |
109 | ++ `merge_requests_enabled` (optional) - enabled by default | |
110 | ++ `wiki_enabled` (optional) - enabled by default | |
105 | 111 | |
106 | 112 | Will return created project with status `201 Created` on success, or `404 Not |
107 | 113 | found` on fail. |
... | ... | @@ -109,7 +115,7 @@ found` on fail. |
109 | 115 | |
110 | 116 | ## Project repository branches |
111 | 117 | |
112 | -Get a list of project repository branches sorted by name alphabetically. | |
118 | +Get a list of repository branches from a project, sorted by name alphabetically. | |
113 | 119 | |
114 | 120 | ``` |
115 | 121 | GET /projects/:id/repository/branches |
... | ... | @@ -186,7 +192,7 @@ Parameters: |
186 | 192 | |
187 | 193 | ## Project repository tags |
188 | 194 | |
189 | -Get a list of project repository tags sorted by name in reverse alphabetical order. | |
195 | +Get a list of repository tags from a project, sorted by name in reverse alphabetical order. | |
190 | 196 | |
191 | 197 | ``` |
192 | 198 | GET /projects/:id/repository/tags |
... | ... | @@ -237,3 +243,4 @@ Parameters: |
237 | 243 | + `filepath` (required) - The path the file |
238 | 244 | |
239 | 245 | Will return the raw file contents. |
246 | + | ... | ... |
... | ... | @@ -1,45 +0,0 @@ |
1 | -#!/bin/sh | |
2 | - | |
3 | -sudo apt-get update | |
4 | -sudo apt-get upgrade | |
5 | - | |
6 | -sudo DEBIAN_FRONTEND='noninteractive' apt-get install -y postfix-policyd-spf-python # Install postfix without prompting. | |
7 | -sudo apt-get install -y git git-core wget curl gcc checkinstall libxml2-dev libxslt-dev sqlite3 libsqlite3-dev libcurl4-openssl-dev libreadline-gplv2-dev libc6-dev libssl-dev libmysql++-dev make build-essential zlib1g-dev libicu-dev redis-server openssh-server python-dev python-pip libyaml-dev | |
8 | - | |
9 | -wget http://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.3-p194.tar.gz | |
10 | -tar xfvz ruby-1.9.3-p194.tar.gz | |
11 | -cd ruby-1.9.3-p194 | |
12 | -./configure | |
13 | -make | |
14 | -sudo make install | |
15 | - | |
16 | -sudo adduser \ | |
17 | - --system \ | |
18 | - --shell /bin/sh \ | |
19 | - --gecos 'git version control' \ | |
20 | - --group \ | |
21 | - --disabled-password \ | |
22 | - --home /home/git \ | |
23 | - git | |
24 | - | |
25 | -sudo adduser --disabled-login --gecos 'gitlab system' gitlab | |
26 | - | |
27 | -sudo usermod -a -G git gitlab | |
28 | - | |
29 | -sudo -H -u gitlab ssh-keygen -q -N '' -t rsa -f /home/gitlab/.ssh/id_rsa | |
30 | - | |
31 | -cd /home/git | |
32 | -sudo -H -u git git clone git://github.com/gitlabhq/gitolite /home/git/gitolite | |
33 | - | |
34 | -sudo -u git -H sh -c "PATH=/home/git/bin:$PATH; /home/git/gitolite/src/gl-system-install" | |
35 | -sudo cp /home/gitlab/.ssh/id_rsa.pub /home/git/gitlab.pub | |
36 | -sudo chmod 777 /home/git/gitlab.pub | |
37 | - | |
38 | -sudo -u git -H sed -i 's/0077/0007/g' /home/git/share/gitolite/conf/example.gitolite.rc | |
39 | -sudo -u git -H sh -c "PATH=/home/git/bin:$PATH; gl-setup -q /home/git/gitlab.pub" | |
40 | - | |
41 | -sudo chmod -R g+rwX /home/git/repositories/ | |
42 | -sudo chown -R git:git /home/git/repositories/ | |
43 | - | |
44 | -sudo -u gitlab -H git clone git@localhost:gitolite-admin.git /tmp/gitolite-admin | |
45 | -sudo rm -rf /tmp/gitolite-admin |
... | ... | @@ -20,7 +20,7 @@ You might have some luck using these, but no guarantees: |
20 | 20 | - MacOS X |
21 | 21 | - FreeBSD |
22 | 22 | |
23 | -Gitlab does **not** run on Windows and we have no plans of making Gitlab compatible. | |
23 | +GitLab does **not** run on Windows and we have no plans of making GitLab compatible. | |
24 | 24 | |
25 | 25 | ## This installation guide created for Debian/Ubuntu and properly tested. |
26 | 26 | |
... | ... | @@ -28,40 +28,44 @@ The installation consists of 6 steps: |
28 | 28 | |
29 | 29 | 1. Install packages / dependencies |
30 | 30 | 2. Install ruby |
31 | -3. Install gitolite | |
32 | -4. Install and configure Gitlab. | |
31 | +3. Install Gitolite | |
32 | +4. Install and configure GitLab. | |
33 | 33 | 5. Start the web front-end |
34 | 34 | 6. Start a Resque worker (for background processing) |
35 | 35 | |
36 | 36 | ### IMPORTANT |
37 | 37 | |
38 | -Please make sure you have followed all the steps below before posting to the mailinglist with installation and configuration questions. | |
38 | +Please make sure you have followed all the steps below before posting to the mailing list with installation and configuration questions. | |
39 | 39 | |
40 | -Only create a Github Issue if you want a specific part of this installation guide updated. | |
40 | +Only create a GitHub Issue if you want a specific part of this installation guide updated. | |
41 | 41 | |
42 | 42 | Also read the [Read this before you submit an issue](https://github.com/gitlabhq/gitlabhq/wiki/Read-this-before-you-submit-an-issue) wiki page. |
43 | 43 | |
44 | 44 | > - - - |
45 | -> First 3 steps can be easily skipped with simply install script: | |
45 | +> The first 3 steps of this guide can be easily skipped by executing an install script: | |
46 | 46 | > |
47 | 47 | > # Install curl and sudo |
48 | 48 | > apt-get install curl sudo |
49 | 49 | > |
50 | 50 | > # 3 steps in 1 command :) |
51 | -> curl https://raw.github.com/gitlabhq/gitlabhq/master/doc/debian_ubuntu.sh | sh | |
51 | +> curl https://raw.github.com/gitlabhq/gitlab-recipes/master/install/debian_ubuntu.sh | sh | |
52 | 52 | > |
53 | -> Now you can go to step 4" | |
53 | +> Now you can go to [Step 4](#4-install-gitlab-and-configuration-check-status-configuration) | |
54 | 54 | > |
55 | -> Or if you are installing on Amazon Web Services using Ubuntu 12.04 you can do all steps (1 to 6) at once with: | |
55 | +> Or if you are installing on Amazon Web Services using Ubuntu 12.04 you can do all steps (1 to 6) at once with: | |
56 | 56 | > |
57 | -> curl https://raw.github.com/gitlabhq/gitlabhq/master/lib/support/aws/debian_ubuntu_aws.sh | sh | |
57 | +> curl https://raw.github.com/gitlabhq/gitlab-recipes/master/install/debian_ubuntu_aws.sh | sh | |
58 | 58 | > |
59 | -> for more detailed instructions read the HOWTO section of [the script](https://github.com/gitlabhq/gitlabhq/blob/master/lib/support/aws/debian_ubuntu_aws.sh) | |
59 | +> for more detailed instructions read the HOWTO section of [the script](https://github.com/gitlabhq/gitlab-recipes/blob/master/install/debian_ubuntu_aws.sh) | |
60 | 60 | > - - - |
61 | 61 | |
62 | 62 | # 1. Install packages |
63 | 63 | |
64 | -*Keep in mind that `sudo` is not installed for debian by default. You should install it with as root:* **apt-get update && apt-get upgrade && apt-get install sudo** | |
64 | +*Keep in mind that `sudo` is not installed on Debian by default. You should install it as root:* | |
65 | + | |
66 | + apt-get update && apt-get upgrade && apt-get install sudo | |
67 | + | |
68 | +Now install the required packages: | |
65 | 69 | |
66 | 70 | sudo apt-get update |
67 | 71 | sudo apt-get upgrade |
... | ... | @@ -71,16 +75,16 @@ Also read the [Read this before you submit an issue](https://github.com/gitlabhq |
71 | 75 | # If you want to use MySQL: |
72 | 76 | sudo apt-get install -y mysql-server mysql-client libmysqlclient-dev |
73 | 77 | |
74 | -# 2. Install ruby | |
78 | +# 2. Install Ruby | |
75 | 79 | |
76 | - wget http://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.2-p290.tar.gz | |
77 | - tar xzfv ruby-1.9.2-p290.tar.gz | |
78 | - cd ruby-1.9.2-p290 | |
80 | + wget http://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.3-p194.tar.gz | |
81 | + tar xfvz ruby-1.9.3-p194.tar.gz | |
82 | + cd ruby-1.9.3-p194 | |
79 | 83 | ./configure |
80 | 84 | make |
81 | 85 | sudo make install |
82 | 86 | |
83 | -# 3. Install gitolite | |
87 | +# 3. Install Gitolite | |
84 | 88 | |
85 | 89 | Create user for git: |
86 | 90 | |
... | ... | @@ -93,12 +97,12 @@ Create user for git: |
93 | 97 | --home /home/git \ |
94 | 98 | git |
95 | 99 | |
96 | -Create user for gitlab: | |
100 | +Create user for GitLab: | |
97 | 101 | |
98 | 102 | # ubuntu/debian |
99 | 103 | sudo adduser --disabled-login --gecos 'gitlab system' gitlab |
100 | 104 | |
101 | -Add your user to git group: | |
105 | +Add your user to the `git` group: | |
102 | 106 | |
103 | 107 | sudo usermod -a -G git gitlab |
104 | 108 | |
... | ... | @@ -106,10 +110,10 @@ Generate key: |
106 | 110 | |
107 | 111 | sudo -H -u gitlab ssh-keygen -q -N '' -t rsa -f /home/gitlab/.ssh/id_rsa |
108 | 112 | |
109 | -Get gitolite source code: | |
113 | +Clone GitLab's fork of the Gitolite source code: | |
110 | 114 | |
111 | 115 | cd /home/git |
112 | - sudo -H -u git git clone git://github.com/gitlabhq/gitolite /home/git/gitolite | |
116 | + sudo -H -u git git clone https://github.com/gitlabhq/gitolite.git /home/git/gitolite | |
113 | 117 | |
114 | 118 | Setup: |
115 | 119 | |
... | ... | @@ -135,23 +139,23 @@ Permissions: |
135 | 139 | # if succeed you can remove it |
136 | 140 | sudo rm -rf /tmp/gitolite-admin |
137 | 141 | |
138 | -**IMPORTANT! If you cant clone `gitolite-admin` repository - DONT PROCEED INSTALLATION** | |
142 | +**IMPORTANT! If you can't clone `gitolite-admin` repository - DO NOT PROCEED WITH INSTALLATION** | |
143 | +Check the [Trouble Shooting Guide](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Trouble-Shooting-Guide) | |
144 | +and ensure you have followed all of the above steps carefully. | |
139 | 145 | |
140 | -# 4. Install gitlab and configuration. Check status configuration. | |
146 | +# 4. Clone GitLab source and install prerequisites | |
141 | 147 | |
142 | 148 | sudo gem install charlock_holmes --version '0.6.8' |
143 | 149 | sudo pip install pygments |
144 | 150 | sudo gem install bundler |
145 | 151 | cd /home/gitlab |
146 | - sudo -H -u gitlab git clone -b stable git://github.com/gitlabhq/gitlabhq.git gitlab | |
152 | + sudo -H -u gitlab git clone -b stable https://github.com/gitlabhq/gitlabhq.git gitlab | |
147 | 153 | cd gitlab |
148 | 154 | |
149 | - sudo -u gitlab mkdir tmp | |
150 | - | |
151 | 155 | # Rename config files |
152 | 156 | sudo -u gitlab cp config/gitlab.yml.example config/gitlab.yml |
153 | 157 | |
154 | -#### Select db you want to use | |
158 | +#### Select the database you want to use | |
155 | 159 | |
156 | 160 | # SQLite |
157 | 161 | sudo -u gitlab cp config/database.yml.sqlite config/database.yml |
... | ... | @@ -163,7 +167,7 @@ Permissions: |
163 | 167 | # Login to MySQL |
164 | 168 | $ mysql -u root -p |
165 | 169 | |
166 | - # Create the gitlabhq production database | |
170 | + # Create the GitLab production database | |
167 | 171 | mysql> CREATE DATABASE IF NOT EXISTS `gitlabhq_production` DEFAULT CHARACTER SET `utf8` COLLATE `utf8_unicode_ci`; |
168 | 172 | |
169 | 173 | # Create the MySQL User change $password to a real password |
... | ... | @@ -179,15 +183,17 @@ Permissions: |
179 | 183 | |
180 | 184 | sudo -u gitlab -H bundle install --without development test --deployment |
181 | 185 | |
182 | -#### Setup DB | |
186 | +#### Setup database | |
183 | 187 | |
184 | 188 | sudo -u gitlab bundle exec rake gitlab:app:setup RAILS_ENV=production |
185 | 189 | |
186 | -#### Setup gitlab hooks | |
190 | +#### Setup GitLab hooks | |
187 | 191 | |
188 | 192 | sudo cp ./lib/hooks/post-receive /home/git/share/gitolite/hooks/common/post-receive |
189 | 193 | sudo chown git:git /home/git/share/gitolite/hooks/common/post-receive |
190 | 194 | |
195 | +#### Check application status | |
196 | + | |
191 | 197 | Checking status: |
192 | 198 | |
193 | 199 | sudo -u gitlab bundle exec rake gitlab:app:status RAILS_ENV=production |
... | ... | @@ -208,9 +214,9 @@ Checking status: |
208 | 214 | UMASK for .gitolite.rc is 0007? ............YES |
209 | 215 | /home/git/share/gitolite/hooks/common/post-receive exists? ............YES |
210 | 216 | |
211 | -If you got all YES - congrats! You can go to next step. | |
217 | +If you got all YES - congratulations! You can go to the next step. | |
212 | 218 | |
213 | -# 5. Server up | |
219 | +# 5. Start the web server | |
214 | 220 | |
215 | 221 | Application can be started with next command: |
216 | 222 | |
... | ... | @@ -225,12 +231,12 @@ You can login via web using admin generated with setup: |
225 | 231 | admin@local.host |
226 | 232 | 5iveL!fe |
227 | 233 | |
228 | -# 6. Run resque process (for processing queue). | |
234 | +# 6. Run Resque process (for processing job queue). | |
229 | 235 | |
230 | 236 | # Manually |
231 | 237 | sudo -u gitlab bundle exec rake environment resque:work QUEUE=* RAILS_ENV=production BACKGROUND=yes |
232 | 238 | |
233 | - # Gitlab start script | |
239 | + # GitLab start script | |
234 | 240 | sudo -u gitlab ./resque.sh |
235 | 241 | # if you run this as root /home/gitlab/gitlab/tmp/pids/resque_worker.pid will be owned by root |
236 | 242 | # causing the resque worker not to start via init script on next boot/service restart |
... | ... | @@ -240,19 +246,19 @@ You can login via web using admin generated with setup: |
240 | 246 | |
241 | 247 | # Nginx && Unicorn |
242 | 248 | |
243 | -### Install Nginx | |
244 | - | |
245 | - sudo apt-get install nginx | |
246 | - | |
247 | -## Unicorn | |
249 | +## 1. Unicorn | |
248 | 250 | |
249 | 251 | cd /home/gitlab/gitlab |
250 | 252 | sudo -u gitlab cp config/unicorn.rb.orig config/unicorn.rb |
251 | 253 | sudo -u gitlab bundle exec unicorn_rails -c config/unicorn.rb -E production -D |
252 | 254 | |
253 | -Add gitlab to nginx sites & change with your host specific settings | |
255 | +## 2. Nginx | |
256 | + | |
257 | + # Install first | |
258 | + sudo apt-get install nginx | |
254 | 259 | |
255 | - sudo cp /home/gitlab/gitlab/lib/support/nginx-gitlab /etc/nginx/sites-available/gitlab | |
260 | + # Add GitLab to nginx sites & change with your host specific settings | |
261 | + sudo wget https://raw.github.com/gitlabhq/gitlab-recipes/master/nginx/gitlab -P /etc/nginx/sites-available/ | |
256 | 262 | sudo ln -s /etc/nginx/sites-available/gitlab /etc/nginx/sites-enabled/gitlab |
257 | 263 | |
258 | 264 | # Change **YOUR_SERVER_IP** and **YOUR_SERVER_FQDN** |
... | ... | @@ -260,22 +266,21 @@ Add gitlab to nginx sites & change with your host specific settings |
260 | 266 | # of the host serving GitLab. |
261 | 267 | sudo vim /etc/nginx/sites-enabled/gitlab |
262 | 268 | |
263 | -Restart nginx: | |
264 | 269 | |
270 | + # Restart nginx: | |
265 | 271 | /etc/init.d/nginx restart |
266 | 272 | |
267 | -Create init script in /etc/init.d/gitlab: | |
268 | - | |
269 | - cp /home/gitlab/gitlab/lib/support/init-gitlab /etc/init.d/gitlab | |
273 | +## 3. Init script | |
270 | 274 | |
271 | -Adding permission: | |
275 | +Create init script in /etc/init.d/gitlab: | |
272 | 276 | |
277 | + sudo wget https://raw.github.com/gitlabhq/gitlab-recipes/master/init.d/gitlab -P /etc/init.d/ | |
273 | 278 | sudo chmod +x /etc/init.d/gitlab |
274 | 279 | |
275 | -Gitlab autostart: | |
280 | +GitLab autostart: | |
276 | 281 | |
277 | 282 | sudo update-rc.d gitlab defaults |
278 | 283 | |
279 | -Now you can start/restart/stop gitlab like: | |
284 | +Now you can start/restart/stop GitLab like: | |
280 | 285 | |
281 | 286 | sudo /etc/init.d/gitlab restart | ... | ... |
... | ... | @@ -4,7 +4,7 @@ Feature: Issues |
4 | 4 | And I own project "Shop" |
5 | 5 | And project "Shop" have "Release 0.4" open issue |
6 | 6 | And project "Shop" have "Release 0.3" closed issue |
7 | - And I visit project "Shop" issues page | |
7 | + And I visit project "Shop" issues page | |
8 | 8 | |
9 | 9 | Scenario: I should see open issues |
10 | 10 | Given I should see "Release 0.4" in issues |
... | ... | @@ -36,3 +36,31 @@ Feature: Issues |
36 | 36 | Given I visit issue page "Release 0.4" |
37 | 37 | And I leave a comment like "XML attached" |
38 | 38 | Then I should see comment "XML attached" |
39 | + | |
40 | + @javascript | |
41 | + Scenario: I search issue | |
42 | + Given I fill in issue search with "Release" | |
43 | + Then I should see "Release 0.4" in issues | |
44 | + And I should not see "Release 0.3" in issues | |
45 | + | |
46 | + @javascript | |
47 | + Scenario: I search issue that not exist | |
48 | + Given I fill in issue search with "Bug" | |
49 | + Then I should not see "Release 0.4" in issues | |
50 | + And I should not see "Release 0.3" in issues | |
51 | + | |
52 | + | |
53 | + @javascript | |
54 | + Scenario: I search all issues | |
55 | + Given I click link "All" | |
56 | + And I fill in issue search with "0.3" | |
57 | + Then I should see "Release 0.3" in issues | |
58 | + And I should not see "Release 0.4" in issues | |
59 | + | |
60 | + @javascript | |
61 | + Scenario: I clear search | |
62 | + Given I click link "All" | |
63 | + And I fill in issue search with "Something" | |
64 | + And I fill in issue search with "" | |
65 | + Then I should see "Release 0.4" in issues | |
66 | + And I should see "Release 0.3" in issues | ... | ... |
... | ... | @@ -0,0 +1,21 @@ |
1 | +include LoginHelpers | |
2 | + | |
3 | +Given /^I signin as a user$/ do | |
4 | + login_as :user | |
5 | +end | |
6 | + | |
7 | +When /^I click link "(.*?)"$/ do |link| | |
8 | + click_link link | |
9 | +end | |
10 | + | |
11 | +When /^I click button "(.*?)"$/ do |button| | |
12 | + click_button button | |
13 | +end | |
14 | + | |
15 | +When /^I fill in "(.*?)" with "(.*?)"$/ do |field, value| | |
16 | + fill_in field, :with => value | |
17 | +end | |
18 | + | |
19 | +Given /^show me page$/ do | |
20 | + save_and_open_page | |
21 | +end | ... | ... |
1 | -Given /^I visit dashboard page$/ do | |
2 | - visit dashboard_path | |
3 | -end | |
4 | - | |
5 | 1 | Then /^I should see "(.*?)" link$/ do |arg1| |
6 | 2 | page.should have_link(arg1) |
7 | 3 | end |
... | ... | @@ -51,10 +47,10 @@ Then /^I click "(.*?)" link$/ do |arg1| |
51 | 47 | end |
52 | 48 | |
53 | 49 | Then /^I see prefilled new Merge Request page$/ do |
54 | - current_path.should == new_project_merge_request_path(@project) | |
55 | - find("#merge_request_source_branch").value.should == "new_design" | |
56 | - find("#merge_request_target_branch").value.should == "master" | |
57 | - find("#merge_request_title").value.should == "New Design" | |
50 | + current_path.should == new_project_merge_request_path(@project) | |
51 | + find("#merge_request_source_branch").value.should == "new_design" | |
52 | + find("#merge_request_target_branch").value.should == "master" | |
53 | + find("#merge_request_title").value.should == "New Design" | |
58 | 54 | end |
59 | 55 | |
60 | 56 | Given /^I visit dashboard search page$/ do |
... | ... | @@ -66,10 +62,6 @@ Given /^I search for "(.*?)"$/ do |arg1| |
66 | 62 | click_button "Search" |
67 | 63 | end |
68 | 64 | |
69 | -Given /^I visit dashboard issues page$/ do | |
70 | - visit dashboard_issues_path | |
71 | -end | |
72 | - | |
73 | 65 | Then /^I should see issues assigned to me$/ do |
74 | 66 | issues = @user.issues |
75 | 67 | issues.each do |issue| |
... | ... | @@ -78,10 +70,6 @@ Then /^I should see issues assigned to me$/ do |
78 | 70 | end |
79 | 71 | end |
80 | 72 | |
81 | -Given /^I visit dashboard merge requests page$/ do | |
82 | - visit dashboard_merge_requests_path | |
83 | -end | |
84 | - | |
85 | 73 | Then /^I should see my merge requests$/ do |
86 | 74 | merge_requests = @user.merge_requests |
87 | 75 | merge_requests.each do |mr| | ... | ... |
1 | -Given /^I visit profile page$/ do | |
2 | - visit profile_path | |
3 | -end | |
4 | - | |
5 | 1 | Then /^I should see my profile info$/ do |
6 | 2 | page.should have_content "Profile" |
7 | 3 | page.should have_content @user.name |
8 | 4 | page.should have_content @user.email |
9 | 5 | end |
10 | 6 | |
11 | -Given /^I visit profile password page$/ do | |
12 | - visit profile_password_path | |
13 | -end | |
14 | - | |
15 | 7 | Then /^I change my password$/ do |
16 | 8 | fill_in "user_password", :with => "222333" |
17 | 9 | fill_in "user_password_confirmation", :with => "222333" |
... | ... | @@ -22,10 +14,6 @@ Then /^I should be redirected to sign in page$/ do |
22 | 14 | current_path.should == new_user_session_path |
23 | 15 | end |
24 | 16 | |
25 | -Given /^I visit profile token page$/ do | |
26 | - visit profile_token_path | |
27 | -end | |
28 | - | |
29 | 17 | Then /^I reset my token$/ do |
30 | 18 | @old_token = @user.private_token |
31 | 19 | click_button "Reset" | ... | ... |
1 | -Given /^I visit project source page$/ do | |
2 | - visit tree_project_ref_path(@project, @project.root_ref) | |
3 | -end | |
4 | - | |
5 | 1 | Then /^I should see files from repository$/ do |
6 | 2 | page.should have_content("app") |
7 | 3 | page.should have_content("History") |
8 | 4 | page.should have_content("Gemfile") |
9 | 5 | end |
10 | 6 | |
11 | -Given /^I visit project source page for "(.*?)"$/ do |arg1| | |
12 | - visit tree_project_ref_path(@project, arg1) | |
13 | -end | |
14 | - | |
15 | 7 | Then /^I should see files from repository for "(.*?)"$/ do |arg1| |
16 | 8 | current_path.should == tree_project_ref_path(@project, arg1) |
17 | 9 | page.should have_content("app") |
... | ... | @@ -31,10 +23,6 @@ Given /^I click on raw button$/ do |
31 | 23 | click_link "raw" |
32 | 24 | end |
33 | 25 | |
34 | -Given /^I visit blob file from repo$/ do | |
35 | - visit tree_project_ref_path(@project, ValidCommit::ID, :path => ValidCommit::BLOB_FILE_PATH) | |
36 | -end | |
37 | - | |
38 | 26 | Then /^I should see raw file content$/ do |
39 | 27 | page.source.should == ValidCommit::BLOB_FILE |
40 | 28 | end | ... | ... |
1 | -Given /^I visit project commits page$/ do | |
2 | - visit project_commits_path(@project) | |
3 | -end | |
4 | - | |
5 | 1 | Then /^I see project commits$/ do |
6 | 2 | current_path.should == project_commits_path(@project) |
7 | 3 | |
... | ... | @@ -23,19 +19,11 @@ Then /^I see commits atom feed$/ do |
23 | 19 | page.body.should have_selector("entry summary", :text => commit.description) |
24 | 20 | end |
25 | 21 | |
26 | -Given /^I click on commit link$/ do | |
27 | - visit project_commit_path(@project, ValidCommit::ID) | |
28 | -end | |
29 | - | |
30 | 22 | Then /^I see commit info$/ do |
31 | 23 | page.should have_content ValidCommit::MESSAGE |
32 | 24 | page.should have_content "Showing 1 changed file" |
33 | 25 | end |
34 | 26 | |
35 | -Given /^I visit compare refs page$/ do | |
36 | - visit compare_project_commits_path(@project) | |
37 | -end | |
38 | - | |
39 | 27 | Given /^I fill compare fields with refs$/ do |
40 | 28 | fill_in "from", :with => "master" |
41 | 29 | fill_in "to", :with => "stable" |
... | ... | @@ -48,18 +36,6 @@ Given /^I see compared refs$/ do |
48 | 36 | page.should have_content "Showing 73 changed files" |
49 | 37 | end |
50 | 38 | |
51 | -Given /^I visit project branches page$/ do | |
52 | - visit branches_project_repository_path(@project) | |
53 | -end | |
54 | - | |
55 | -Given /^I visit project commit page$/ do | |
56 | - visit project_commit_path(@project, ValidCommit::ID) | |
57 | -end | |
58 | - | |
59 | -Given /^I visit project tags page$/ do | |
60 | - visit tags_project_repository_path(@project) | |
61 | -end | |
62 | - | |
63 | 39 | Then /^I should see "(.*?)" recent branches list$/ do |arg1| |
64 | 40 | page.should have_content("Branches") |
65 | 41 | page.should have_content("master") |
... | ... | @@ -76,7 +52,7 @@ Then /^I should see "(.*?)" all tags list$/ do |arg1| |
76 | 52 | end |
77 | 53 | |
78 | 54 | Then /^I should see "(.*?)" protected branches list$/ do |arg1| |
79 | - within "table" do | |
55 | + within "table" do | |
80 | 56 | page.should have_content "stable" |
81 | 57 | page.should_not have_content "master" |
82 | 58 | end | ... | ... |
... | ... | @@ -8,16 +8,12 @@ Given /^project "(.*?)" have "(.*?)" closed issue$/ do |arg1, arg2| |
8 | 8 | Factory.create(:issue, :title => arg2, :project => project, :author => project.users.first, :closed => true) |
9 | 9 | end |
10 | 10 | |
11 | -Given /^I visit project "(.*?)" issues page$/ do |arg1| | |
12 | - visit project_issues_path(Project.find_by_name(arg1)) | |
13 | -end | |
14 | - | |
15 | 11 | Given /^I should see "(.*?)" in issues$/ do |arg1| |
16 | - page.should have_content arg1 | |
12 | + page.should have_content arg1 | |
17 | 13 | end |
18 | 14 | |
19 | 15 | Given /^I should not see "(.*?)" in issues$/ do |arg1| |
20 | - page.should_not have_content arg1 | |
16 | + page.should_not have_content arg1 | |
21 | 17 | end |
22 | 18 | |
23 | 19 | Then /^I should see issue "(.*?)"$/ do |arg1| |
... | ... | @@ -27,11 +23,6 @@ Then /^I should see issue "(.*?)"$/ do |arg1| |
27 | 23 | page.should have_content issue.project.name |
28 | 24 | end |
29 | 25 | |
30 | -Given /^I visit issue page "(.*?)"$/ do |arg1| | |
31 | - issue = Issue.find_by_title(arg1) | |
32 | - visit project_issue_path(issue.project, issue) | |
33 | -end | |
34 | - | |
35 | 26 | Given /^I submit new issue "(.*?)"$/ do |arg1| |
36 | 27 | fill_in "issue_title", with: arg1 |
37 | 28 | click_button "Submit new issue" |
... | ... | @@ -51,7 +42,16 @@ Given /^I visit project "(.*?)" labels page$/ do |arg1| |
51 | 42 | end |
52 | 43 | |
53 | 44 | Then /^I should see label "(.*?)"$/ do |arg1| |
54 | - within ".labels-table" do | |
45 | + within ".labels-table" do | |
55 | 46 | page.should have_content arg1 |
56 | 47 | end |
57 | 48 | end |
49 | + | |
50 | +Given /^I fill in issue search with "(.*?)"$/ do |arg1| | |
51 | + # Because fill_in, with: "" triggers nothing | |
52 | + # we need to trigger a keyup event | |
53 | + if arg1 == '' | |
54 | + page.execute_script("$('.issue_search').val('').keyup();"); | |
55 | + end | |
56 | + fill_in 'issue_search', with: arg1 | |
57 | +end | ... | ... |
... | ... | @@ -8,21 +8,17 @@ Given /^project "(.*?)" have "(.*?)" closed merge request$/ do |arg1, arg2| |
8 | 8 | Factory.create(:merge_request, :title => arg2, :project => project, :author => project.users.first, :closed => true) |
9 | 9 | end |
10 | 10 | |
11 | -Given /^I visit project "(.*?)" merge requests page$/ do |arg1| | |
12 | - visit project_merge_requests_path(Project.find_by_name(arg1)) | |
13 | -end | |
14 | - | |
15 | 11 | Then /^I should see "(.*?)" in merge requests$/ do |arg1| |
16 | - page.should have_content arg1 | |
12 | + page.should have_content arg1 | |
17 | 13 | end |
18 | 14 | |
19 | 15 | Then /^I should not see "(.*?)" in merge requests$/ do |arg1| |
20 | - page.should_not have_content arg1 | |
16 | + page.should_not have_content arg1 | |
21 | 17 | end |
22 | 18 | |
23 | 19 | Then /^I should see merge request "(.*?)"$/ do |arg1| |
24 | 20 | merge_request = MergeRequest.find_by_title(arg1) |
25 | - page.should have_content(merge_request.title[0..10]) | |
21 | + page.should have_content(merge_request.title[0..10]) | |
26 | 22 | page.should have_content(merge_request.target_branch) |
27 | 23 | page.should have_content(merge_request.source_branch) |
28 | 24 | end |
... | ... | @@ -34,11 +30,6 @@ Given /^I submit new merge request "(.*?)"$/ do |arg1| |
34 | 30 | click_button "Save" |
35 | 31 | end |
36 | 32 | |
37 | -Given /^I visit merge request page "(.*?)"$/ do |arg1| | |
38 | - mr = MergeRequest.find_by_title(arg1) | |
39 | - visit project_merge_request_path(mr.project, mr) | |
40 | -end | |
41 | - | |
42 | 33 | Then /^I should see closed merge request "(.*?)"$/ do |arg1| |
43 | 34 | mr = MergeRequest.find_by_title(arg1) |
44 | 35 | mr.closed.should be_true | ... | ... |
... | ... | @@ -12,11 +12,6 @@ Given /^project "(.*?)" has milestone "(.*?)"$/ do |arg1, arg2| |
12 | 12 | end |
13 | 13 | end |
14 | 14 | |
15 | -Given /^I visit project "(.*?)" milestones page$/ do |arg1| | |
16 | - @project = Project.find_by_name(arg1) | |
17 | - visit project_milestones_path(@project) | |
18 | -end | |
19 | - | |
20 | 15 | Then /^I should see active milestones$/ do |
21 | 16 | milestone = @project.milestones.first |
22 | 17 | page.should have_content(milestone.title[0..10]) | ... | ... |
... | ... | @@ -8,10 +8,6 @@ Given /^"(.*?)" is "(.*?)" developer$/ do |arg1, arg2| |
8 | 8 | project.add_access(user, :write) |
9 | 9 | end |
10 | 10 | |
11 | -Given /^I visit project "(.*?)" team page$/ do |arg1| | |
12 | - visit team_project_path(Project.find_by_name(arg1)) | |
13 | -end | |
14 | - | |
15 | 11 | Then /^I should be able to see myself in team$/ do |
16 | 12 | page.should have_content(@user.name) |
17 | 13 | page.should have_content(@user.email) |
... | ... | @@ -23,13 +19,9 @@ Then /^I should see "(.*?)" in team list$/ do |arg1| |
23 | 19 | page.should have_content(user.email) |
24 | 20 | end |
25 | 21 | |
26 | -Given /^I click link "(.*?)"$/ do |arg1| | |
27 | - click_link arg1 | |
28 | -end | |
29 | - | |
30 | 22 | Given /^I select "(.*?)" as "(.*?)"$/ do |arg1, arg2| |
31 | 23 | user = User.find_by_name(arg1) |
32 | - within "#new_team_member" do | |
24 | + within "#new_team_member" do | |
33 | 25 | select user.name, :from => "team_member_user_id" |
34 | 26 | select arg2, :from => "team_member_project_access" |
35 | 27 | end |
... | ... | @@ -44,7 +36,7 @@ end |
44 | 36 | |
45 | 37 | Given /^I change "(.*?)" role to "(.*?)"$/ do |arg1, arg2| |
46 | 38 | user = User.find_by_name(arg1) |
47 | - within ".user_#{user.id}" do | |
39 | + within ".user_#{user.id}" do | |
48 | 40 | select arg2, :from => "team_member_project_access" |
49 | 41 | end |
50 | 42 | end | ... | ... |
1 | -include LoginHelpers | |
2 | - | |
3 | -Given /^I signin as a user$/ do | |
4 | - login_as :user | |
5 | -end | |
6 | - | |
7 | 1 | When /^I visit new project page$/ do |
8 | 2 | visit new_project_path |
9 | 3 | end |
... | ... | @@ -65,10 +59,6 @@ Given /^I visit project "(.*?)" network page$/ do |arg1| |
65 | 59 | visit graph_project_path(project) |
66 | 60 | end |
67 | 61 | |
68 | -Given /^show me page$/ do | |
69 | - save_and_open_page | |
70 | -end | |
71 | - | |
72 | 62 | Given /^page should have network graph$/ do |
73 | 63 | page.should have_content "Project Network Graph" |
74 | 64 | within ".graph" do | ... | ... |
... | ... | @@ -0,0 +1,91 @@ |
1 | +Given /^I visit project "(.*?)" issues page$/ do |arg1| | |
2 | + visit project_issues_path(Project.find_by_name(arg1)) | |
3 | +end | |
4 | + | |
5 | +Given /^I visit issue page "(.*?)"$/ do |arg1| | |
6 | + issue = Issue.find_by_title(arg1) | |
7 | + visit project_issue_path(issue.project, issue) | |
8 | +end | |
9 | + | |
10 | +Given /^I visit project "(.*?)" merge requests page$/ do |arg1| | |
11 | + visit project_merge_requests_path(Project.find_by_name(arg1)) | |
12 | +end | |
13 | + | |
14 | +Given /^I visit merge request page "(.*?)"$/ do |arg1| | |
15 | + mr = MergeRequest.find_by_title(arg1) | |
16 | + visit project_merge_request_path(mr.project, mr) | |
17 | +end | |
18 | + | |
19 | +Given /^I visit project "(.*?)" milestones page$/ do |arg1| | |
20 | + @project = Project.find_by_name(arg1) | |
21 | + visit project_milestones_path(@project) | |
22 | +end | |
23 | + | |
24 | +Given /^I visit project commits page$/ do | |
25 | + visit project_commits_path(@project) | |
26 | +end | |
27 | + | |
28 | +Given /^I visit compare refs page$/ do | |
29 | + visit compare_project_commits_path(@project) | |
30 | +end | |
31 | + | |
32 | +Given /^I visit project branches page$/ do | |
33 | + visit branches_project_repository_path(@project) | |
34 | +end | |
35 | + | |
36 | +Given /^I visit project commit page$/ do | |
37 | + visit project_commit_path(@project, ValidCommit::ID) | |
38 | +end | |
39 | + | |
40 | +Given /^I visit project tags page$/ do | |
41 | + visit tags_project_repository_path(@project) | |
42 | +end | |
43 | + | |
44 | +Given /^I click on commit link$/ do | |
45 | + visit project_commit_path(@project, ValidCommit::ID) | |
46 | +end | |
47 | + | |
48 | +Given /^I visit project source page$/ do | |
49 | + visit tree_project_ref_path(@project, @project.root_ref) | |
50 | +end | |
51 | + | |
52 | +Given /^I visit project source page for "(.*?)"$/ do |arg1| | |
53 | + visit tree_project_ref_path(@project, arg1) | |
54 | +end | |
55 | + | |
56 | +Given /^I visit blob file from repo$/ do | |
57 | + visit tree_project_ref_path(@project, ValidCommit::ID, :path => ValidCommit::BLOB_FILE_PATH) | |
58 | +end | |
59 | + | |
60 | +Given /^I visit project "(.*?)" team page$/ do |arg1| | |
61 | + visit team_project_path(Project.find_by_name(arg1)) | |
62 | +end | |
63 | + | |
64 | +Given /^I visit project wiki page$/ do | |
65 | + visit project_wiki_path(@project, :index) | |
66 | +end | |
67 | + | |
68 | +Given /^I visit profile page$/ do | |
69 | + visit profile_path | |
70 | +end | |
71 | + | |
72 | +Given /^I visit profile token page$/ do | |
73 | + visit profile_token_path | |
74 | +end | |
75 | + | |
76 | +Given /^I visit profile password page$/ do | |
77 | + visit profile_password_path | |
78 | +end | |
79 | + | |
80 | +Given /^I visit dashboard page$/ do | |
81 | + visit dashboard_path | |
82 | +end | |
83 | + | |
84 | +Given /^I visit dashboard issues page$/ do | |
85 | + visit dashboard_issues_path | |
86 | +end | |
87 | + | |
88 | +Given /^I visit dashboard merge requests page$/ do | |
89 | + visit dashboard_merge_requests_path | |
90 | +end | |
91 | + | ... | ... |
... | ... | @@ -29,14 +29,24 @@ module Gitlab |
29 | 29 | # name (required) - name for new project |
30 | 30 | # code (optional) - code for new project, uses project name if not set |
31 | 31 | # path (optional) - path for new project, uses project name if not set |
32 | + # description (optional) - short project description | |
33 | + # default_branch (optional) - 'master' by default | |
34 | + # issues_enabled (optional) - enabled by default | |
35 | + # wall_enabled (optional) - enabled by default | |
36 | + # merge_requests_enabled (optional) - enabled by default | |
37 | + # wiki_enabled (optional) - enabled by default | |
32 | 38 | # Example Request |
33 | 39 | # POST /projects |
34 | 40 | post do |
35 | - project = {} | |
36 | - project[:name] = params[:name] | |
37 | - project[:code] = params[:code] || project[:name] | |
38 | - project[:path] = params[:path] || project[:name] | |
39 | - @project = Project.create_by_user(project, current_user) | |
41 | + params[:code] ||= params[:name] | |
42 | + params[:path] ||= params[:name] | |
43 | + project_attrs = {} | |
44 | + params.each_pair do |k ,v| | |
45 | + if Project.attribute_names.include? k | |
46 | + project_attrs[k] = v | |
47 | + end | |
48 | + end | |
49 | + @project = Project.create_by_user(project_attrs, current_user) | |
40 | 50 | if @project.saved? |
41 | 51 | present @project, with: Entities::Project |
42 | 52 | else | ... | ... |
1 | 1 | module Gitlab |
2 | - # Custom parser for Gitlab-flavored Markdown | |
2 | + # Custom parser for GitLab-flavored Markdown | |
3 | 3 | # |
4 | - # It replaces references in the text with links to the appropriate items in Gitlab. | |
4 | + # It replaces references in the text with links to the appropriate items in | |
5 | + # GitLab. | |
5 | 6 | # |
6 | 7 | # Supported reference formats are: |
7 | 8 | # * @foo for team members |
... | ... | @@ -10,19 +11,20 @@ module Gitlab |
10 | 11 | # * $123 for snippets |
11 | 12 | # * 123456 for commits |
12 | 13 | # |
13 | - # Examples | |
14 | + # It also parses Emoji codes to insert images. See | |
15 | + # http://www.emoji-cheat-sheet.com/ for a list of the supported icons. | |
14 | 16 | # |
15 | - # >> m = Markdown.new(...) | |
17 | + # Examples | |
16 | 18 | # |
17 | - # >> m.parse("Hey @david, can you fix this?") | |
19 | + # >> gfm("Hey @david, can you fix this?") | |
18 | 20 | # => "Hey <a href="/gitlab/team_members/1">@david</a>, can you fix this?" |
19 | 21 | # |
20 | - # >> m.parse("Commit 35d5f7c closes #1234") | |
22 | + # >> gfm("Commit 35d5f7c closes #1234") | |
21 | 23 | # => "Commit <a href="/gitlab/commits/35d5f7c">35d5f7c</a> closes <a href="/gitlab/issues/1234">#1234</a>" |
22 | - class Markdown | |
23 | - include Rails.application.routes.url_helpers | |
24 | - include ActionView::Helpers | |
25 | - | |
24 | + # | |
25 | + # >> gfm(":trollface:") | |
26 | + # => "<img alt=\":trollface:\" class=\"emoji\" src=\"/images/trollface.png" title=\":trollface:\" /> | |
27 | + module Markdown | |
26 | 28 | REFERENCE_PATTERN = %r{ |
27 | 29 | ([^\w&;])? # Prefix (1) |
28 | 30 | ( # Reference (2) |
... | ... | @@ -33,15 +35,52 @@ module Gitlab |
33 | 35 | ([^\w&;])? # Suffix (6) |
34 | 36 | }x.freeze |
35 | 37 | |
38 | + EMOJI_PATTERN = %r{(:(\S+):)}.freeze | |
39 | + | |
36 | 40 | attr_reader :html_options |
37 | 41 | |
38 | - def initialize(project, html_options = {}) | |
39 | - @project = project | |
42 | + # Public: Parse the provided text with GitLab-Flavored Markdown | |
43 | + # | |
44 | + # text - the source text | |
45 | + # html_options - extra options for the reference links as given to link_to | |
46 | + # | |
47 | + # Note: reference links will only be generated if @project is set | |
48 | + def gfm(text, html_options = {}) | |
49 | + return text if text.nil? | |
50 | + return text if @project.nil? | |
51 | + | |
40 | 52 | @html_options = html_options |
53 | + | |
54 | + # Extract pre blocks so they are not altered | |
55 | + # from http://github.github.com/github-flavored-markdown/ | |
56 | + extractions = {} | |
57 | + text.gsub!(%r{<pre>.*?</pre>|<code>.*?</code>}m) do |match| | |
58 | + md5 = Digest::MD5.hexdigest(match) | |
59 | + extractions[md5] = match | |
60 | + "{gfm-extraction-#{md5}}" | |
61 | + end | |
62 | + | |
63 | + # TODO: add popups with additional information | |
64 | + | |
65 | + text = parse(text) | |
66 | + | |
67 | + # Insert pre block extractions | |
68 | + text.gsub!(/\{gfm-extraction-(\h{32})\}/) do | |
69 | + extractions[$1] | |
70 | + end | |
71 | + | |
72 | + sanitize text.html_safe, attributes: ActionView::Base.sanitized_allowed_attributes + %w(id class) | |
41 | 73 | end |
42 | 74 | |
75 | + private | |
76 | + | |
77 | + # Private: Parses text for references and emoji | |
78 | + # | |
79 | + # text - Text to parse | |
80 | + # | |
81 | + # Returns parsed text | |
43 | 82 | def parse(text) |
44 | - text.gsub(REFERENCE_PATTERN) do |match| | |
83 | + text = text.gsub(REFERENCE_PATTERN) do |match| | |
45 | 84 | prefix = $1 || '' |
46 | 85 | reference = $2 |
47 | 86 | identifier = $3 || $4 || $5 |
... | ... | @@ -53,9 +92,26 @@ module Gitlab |
53 | 92 | match |
54 | 93 | end |
55 | 94 | end |
95 | + | |
96 | + text = text.gsub(EMOJI_PATTERN) do |match| | |
97 | + if valid_emoji?($2) | |
98 | + image_tag("emoji/#{$2}.png", size: "20x20", class: 'emoji', title: $1, alt: $1) | |
99 | + else | |
100 | + match | |
101 | + end | |
102 | + end | |
103 | + | |
104 | + text | |
56 | 105 | end |
57 | 106 | |
58 | - private | |
107 | + # Private: Checks if an emoji icon exists in the image asset directory | |
108 | + # | |
109 | + # emoji - Identifier of the emoji as a string (e.g., "+1", "heart") | |
110 | + # | |
111 | + # Returns boolean | |
112 | + def valid_emoji?(emoji) | |
113 | + File.exists?(Rails.root.join('app', 'assets', 'images', 'emoji', "#{emoji}.png")) | |
114 | + end | |
59 | 115 | |
60 | 116 | # Private: Dispatches to a dedicated processing method based on reference |
61 | 117 | # | ... | ... |
... | ... | @@ -1,122 +0,0 @@ |
1 | -#!/bin/sh | |
2 | - | |
3 | -# ABOUT | |
4 | -# This script performs a complete installation of Gitlab (master branch). | |
5 | -# Is can be run with one command without needing _any_ user input after that. | |
6 | -# This script only works on Amazon Web Services (AWS). | |
7 | -# The operating system used is Ubuntu 12.04 64bit. | |
8 | - | |
9 | -# HOWTO | |
10 | -# Signup for AWS, free tier are available at http://aws.amazon.com/free/ | |
11 | -# Go to EC2 tab in the AWS console EC2 https://console.aws.amazon.com/ec2/home | |
12 | -# Click the 'Launch Instance' button | |
13 | -# Select: 'Quick launch wizard' and continue | |
14 | -# Choose a key pair => Create New => Name it => Download it | |
15 | -# Choose a Launch Configuration => Select 'More Amazon Marketplace Images' | |
16 | -# Press 'Continue' | |
17 | -# Enter 'ubuntu/images/ubuntu-precise-12.04-amd64-server-20120424' and press 'Search' | |
18 | -# Select the only result (ami-3c994355) and press 'Continue' | |
19 | -# Press 'Edit details' if you want to modify something, for example make the type 'c1.medium' to make the install faster. | |
20 | -# Press the 'Launch' button | |
21 | -# Press 'Close' | |
22 | -# Click 'Security Groups' under the left hand menu 'NETWORK & SECURITY' | |
23 | -# Select the newly create seciruty group, probably named 'quicklaunch-1' | |
24 | -# Click on the Inbound tab | |
25 | -# In the 'Create a new rule' dropdown select 'HTTP' | |
26 | -# Press 'Add Rule' | |
27 | -# In the 'Create a new rule' dropdown select 'HTTPS' | |
28 | -# Press 'Add Rule' | |
29 | -# Press 'Apply Rule Changes' | |
30 | -# Give the following command in your local terminal while suptituting the UPPERCASE items | |
31 | -# 'ssh -i LOCATION_OF_AWS_KEY_PAIR_PRIVATE_KEY PUBLIC_DNS_OF_THE_NEW_SERVER' | |
32 | -# Execute the curl command below and when its ready follow the printed 'Log in instuctions' | |
33 | -# curl https://raw.github.com/gitlabhq/gitlabhq/master/lib/support/aws/debian_ubuntu_aws.sh | sh | |
34 | - | |
35 | -# Prevent fingerprint prompt for localhost in step 1 to 3. | |
36 | -echo "Host localhost | |
37 | - StrictHostKeyChecking no | |
38 | - UserKnownHostsFile=/dev/null" | sudo tee -a /etc/ssh/ssh_config | |
39 | - | |
40 | -# Existing script for Step 1 to 3 | |
41 | -curl https://raw.github.com/gitlabhq/gitlabhq/master/doc/debian_ubuntu.sh | sh | |
42 | - | |
43 | -# Install MySQL | |
44 | -sudo apt-get install -y makepasswd # Needed to create a unique password non-interactively. | |
45 | -userPassword=$(makepasswd --char=10) # Generate a random MySQL password | |
46 | -# Note that the lines below creates a cleartext copy of the random password in /var/cache/debconf/passwords.dat | |
47 | -# This file is normally only readable by root and the password will be deleted by the package management system after install. | |
48 | -echo mysql-server mysql-server/root_password password $userPassword | sudo debconf-set-selections | |
49 | -echo mysql-server mysql-server/root_password_again password $userPassword | sudo debconf-set-selections | |
50 | -sudo apt-get install -y mysql-server | |
51 | - | |
52 | -# Gitlab install | |
53 | -sudo gem install charlock_holmes --version '0.6.8' | |
54 | -sudo pip install pygments | |
55 | -sudo gem install bundler | |
56 | -sudo su -l gitlab -c "git clone git://github.com/gitlabhq/gitlabhq.git gitlab" # Using master everywhere. | |
57 | -sudo su -l gitlab -c "cd gitlab && mkdir tmp" | |
58 | -sudo su -l gitlab -c "cd gitlab/config && cp gitlab.yml.example gitlab.yml" | |
59 | -sudo su -l gitlab -c "cd gitlab/config && cp database.yml.example database.yml" | |
60 | -sudo sed -i 's/"secure password"/"'$userPassword'"/' /home/gitlab/gitlab/config/database.yml # Insert the mysql root password. | |
61 | -sudo su -l gitlab -c "cd gitlab && bundle install --without development test --deployment" | |
62 | -sudo su -l gitlab -c "cd gitlab && bundle exec rake gitlab:app:setup RAILS_ENV=production" | |
63 | - | |
64 | -# Setup gitlab hooks | |
65 | -sudo cp /home/gitlab/gitlab/lib/hooks/post-receive /home/git/share/gitolite/hooks/common/post-receive | |
66 | -sudo chown git:git /home/git/share/gitolite/hooks/common/post-receive | |
67 | - | |
68 | -# Set the first occurrence of host in the Gitlab config to the publicly available domain name | |
69 | -sudo sed -i '0,/host/s/localhost/'`wget -qO- http://instance-data/latest/meta-data/public-hostname`'/' /home/gitlab/gitlab/config/gitlab.yml | |
70 | - | |
71 | -# Gitlab installation test (optional) | |
72 | -# sudo -u gitlab bundle exec rake gitlab:app:status RAILS_ENV=production | |
73 | -# sudo -u gitlab bundle exec rails s -e production | |
74 | -# sudo -u gitlab bundle exec rake environment resque:work QUEUE=* RAILS_ENV=production BACKGROUND=no | |
75 | - | |
76 | -# Install and configure Nginx | |
77 | -sudo apt-get install -y nginx | |
78 | -sudo cp /home/gitlab/gitlab/lib/support/nginx-gitlab /etc/nginx/sites-available/gitlab | |
79 | -sudo ln -s /etc/nginx/sites-available/gitlab /etc/nginx/sites-enabled/gitlab | |
80 | -sudo sed -i 's/YOUR_SERVER_IP/'`wget -qO- http://instance-data/latest/meta-data/local-ipv4`'/' /etc/nginx/sites-available/gitlab # Set private ip address (public won't work). | |
81 | -sudo sed -i 's/YOUR_SERVER_FQDN/'`wget -qO- http://instance-data/latest/meta-data/public-hostname`'/' /etc/nginx/sites-available/gitlab # Set public dns domain name. | |
82 | - | |
83 | -# Configure Unicorn | |
84 | -sudo -u gitlab cp /home/gitlab/gitlab/config/unicorn.rb.orig /home/gitlab/gitlab/config/unicorn.rb | |
85 | - | |
86 | -# Create a Gitlab service | |
87 | -sudo cp /home/gitlab/gitlab/lib/support/init-gitlab /etc/init.d/gitlab | |
88 | -sudo chmod +x /etc/init.d/gitlab && sudo update-rc.d gitlab defaults | |
89 | - | |
90 | -## Gitlab service commands (unicorn and resque) | |
91 | -## restart doesn't restart resque, only start/stop effect it. | |
92 | -sudo -u gitlab service gitlab start | |
93 | -# sudo -u gitlab service gitlab restart | |
94 | -# sudo -u gitlab service gitlab stop | |
95 | - | |
96 | -# nginx Service commands | |
97 | -# sudo service nginx start | |
98 | -sudo service nginx restart | |
99 | -# sudo service nginx stop | |
100 | - | |
101 | -# Manual startup commands for troubleshooting when the service commands do not work | |
102 | -# sudo -u gitlab bundle exec unicorn_rails -c config/unicorn.rb -E production -D | |
103 | -# sudo su -l gitlab -c "cd gitlab && ./resque.sh" | |
104 | - | |
105 | -# Monitoring commands | |
106 | -# sudo tail -f /var/log/nginx/access.log; | |
107 | -# sudo tail -f /var/log/nginx/error.log; | |
108 | - | |
109 | -# Go to gitlab directory by default on next login. | |
110 | -echo 'cd /home/gitlab/gitlab' >> /home/ubuntu/.bashrc | |
111 | - | |
112 | -echo '' | |
113 | -echo '###########################################' | |
114 | -echo '# Log in instuctions #' | |
115 | -echo '###########################################' | |
116 | -echo '' | |
117 | -echo "Surf to this Gitlab installation in your browser:" | |
118 | -echo "http://`wget -qO- http://instance-data/latest/meta-data/public-hostname`/" | |
119 | -echo '' | |
120 | -echo 'and login with the following Email and Password:' | |
121 | -echo 'admin@local.host' | |
122 | -echo '5iveL!fe' | |
123 | 0 | \ No newline at end of file |
... | ... | @@ -1,54 +0,0 @@ |
1 | -#! /bin/bash | |
2 | -### BEGIN INIT INFO | |
3 | -# Provides: gitlab | |
4 | -# Required-Start: $local_fs $remote_fs $network $syslog redis-server | |
5 | -# Required-Stop: $local_fs $remote_fs $network $syslog | |
6 | -# Default-Start: 2 3 4 5 | |
7 | -# Default-Stop: 0 1 6 | |
8 | -# Short-Description: GitLab git repository management | |
9 | -# Description: GitLab git repository management | |
10 | -### END INIT INFO | |
11 | - | |
12 | -DAEMON_OPTS="-c /home/gitlab/gitlab/config/unicorn.rb -E production -D" | |
13 | -NAME=unicorn | |
14 | -DESC="Gitlab service" | |
15 | -PID=/home/gitlab/gitlab/tmp/pids/unicorn.pid | |
16 | -RESQUE_PID=/home/gitlab/gitlab/tmp/pids/resque_worker.pid | |
17 | - | |
18 | -case "$1" in | |
19 | - start) | |
20 | - CD_TO_APP_DIR="cd /home/gitlab/gitlab" | |
21 | - START_DAEMON_PROCESS="bundle exec unicorn_rails $DAEMON_OPTS" | |
22 | - START_RESQUE_PROCESS="./resque.sh" | |
23 | - | |
24 | - echo -n "Starting $DESC: " | |
25 | - if [ `whoami` = root ]; then | |
26 | - sudo -u gitlab sh -l -c "$CD_TO_APP_DIR > /dev/null 2>&1 && $START_DAEMON_PROCESS && $START_RESQUE_PROCESS" | |
27 | - else | |
28 | - $CD_TO_APP_DIR > /dev/null 2>&1 && $START_DAEMON_PROCESS && $START_RESQUE_PROCESS | |
29 | - fi | |
30 | - echo "$NAME." | |
31 | - ;; | |
32 | - stop) | |
33 | - echo -n "Stopping $DESC: " | |
34 | - kill -QUIT `cat $PID` | |
35 | - kill -QUIT `cat $RESQUE_PID` | |
36 | - echo "$NAME." | |
37 | - ;; | |
38 | - restart) | |
39 | - echo -n "Restarting $DESC: " | |
40 | - kill -USR2 `cat $PID` | |
41 | - echo "$NAME." | |
42 | - ;; | |
43 | - reload) | |
44 | - echo -n "Reloading $DESC configuration: " | |
45 | - kill -HUP `cat $PID` | |
46 | - echo "$NAME." | |
47 | - ;; | |
48 | - *) | |
49 | - echo "Usage: $NAME {start|stop|restart|reload}" >&2 | |
50 | - exit 1 | |
51 | - ;; | |
52 | -esac | |
53 | - | |
54 | -exit 0 |
... | ... | @@ -1,33 +0,0 @@ |
1 | -upstream gitlab { | |
2 | - server unix:/home/gitlab/gitlab/tmp/sockets/gitlab.socket; | |
3 | -} | |
4 | - | |
5 | -server { | |
6 | - listen YOUR_SERVER_IP:80; # e.g., listen 192.168.1.1:80; | |
7 | - server_name YOUR_SERVER_FQDN; # e.g., server_name source.example.com; | |
8 | - root /home/gitlab/gitlab/public; | |
9 | - | |
10 | - # individual nginx logs for this gitlab vhost | |
11 | - access_log /var/log/nginx/gitlab_access.log; | |
12 | - error_log /var/log/nginx/gitlab_error.log; | |
13 | - | |
14 | - location / { | |
15 | - # serve static files from defined root folder;. | |
16 | - # @gitlab is a named location for the upstream fallback, see below | |
17 | - try_files $uri $uri/index.html $uri.html @gitlab; | |
18 | - } | |
19 | - | |
20 | - # if a file, which is not found in the root folder is requested, | |
21 | - # then the proxy pass the request to the upsteam (gitlab unicorn) | |
22 | - location @gitlab { | |
23 | - proxy_redirect off; | |
24 | - | |
25 | - # you need to change this to "https", if you set "ssl" directive to "on" | |
26 | - proxy_set_header X-FORWARDED_PROTO http; | |
27 | - proxy_set_header Host $http_host; | |
28 | - proxy_set_header X-Real-IP $remote_addr; | |
29 | - | |
30 | - proxy_pass http://gitlab; | |
31 | - } | |
32 | -} | |
33 | - |
1 | 1 | IMPORT_DIRECTORY = 'import_projects' |
2 | -REPOSITORY_DIRECTORY = '/home/git/repositories' | |
3 | 2 | |
4 | 3 | desc "Imports existing Git repos into new projects from the import_projects folder" |
5 | 4 | task :import_projects, [:email] => :environment do |t, args| |
5 | + REPOSITORY_DIRECTORY = Gitlab.config.git_base_path | |
6 | + | |
6 | 7 | user_email = args.email |
7 | 8 | repos_to_import = Dir.glob("#{IMPORT_DIRECTORY}/*") |
8 | 9 | ... | ... |
1 | 1 | namespace :gitlab do |
2 | 2 | namespace :gitolite do |
3 | - desc "GITLAB | Write GITLAB hook for gitolite" | |
3 | + desc "GITLAB | Write GitLab hook for gitolite" | |
4 | 4 | task :write_hooks => :environment do |
5 | 5 | gitolite_hooks_path = File.join(Gitlab.config.git_hooks_path, "common") |
6 | 6 | gitlab_hooks_path = Rails.root.join("lib", "hooks") | ... | ... |
... | ... | @@ -11,6 +11,9 @@ module Factory |
11 | 11 | def self.new(type, *args) |
12 | 12 | FactoryGirl.build(type, *args) |
13 | 13 | end |
14 | + def self.attributes(type, *args) | |
15 | + FactoryGirl.attributes_for(type, *args) | |
16 | + end | |
14 | 17 | end |
15 | 18 | |
16 | 19 | FactoryGirl.define do |
... | ... | @@ -28,7 +31,7 @@ FactoryGirl.define do |
28 | 31 | email { Faker::Internet.email } |
29 | 32 | name |
30 | 33 | password "123456" |
31 | - password_confirmation "123456" | |
34 | + password_confirmation { password } | |
32 | 35 | |
33 | 36 | trait :admin do |
34 | 37 | admin true | ... | ... |
1 | 1 | require 'spec_helper' |
2 | 2 | |
3 | -describe "Factories" do | |
4 | - describe 'User' do | |
5 | - it "builds a valid instance" do | |
6 | - build(:user).should be_valid | |
7 | - end | |
8 | - | |
9 | - it "builds a valid admin instance" do | |
10 | - build(:admin).should be_valid | |
11 | - end | |
12 | - end | |
13 | - | |
14 | - describe 'Project' do | |
15 | - it "builds a valid instance" do | |
16 | - build(:project).should be_valid | |
17 | - end | |
18 | - end | |
19 | - | |
20 | - describe 'Issue' do | |
21 | - it "builds a valid instance" do | |
22 | - build(:issue).should be_valid | |
23 | - end | |
24 | - | |
25 | - it "builds a valid closed instance" do | |
26 | - build(:closed_issue).should be_valid | |
27 | - end | |
28 | - end | |
29 | - | |
30 | - describe 'MergeRequest' do | |
31 | - it "builds a valid instance" do | |
32 | - build(:merge_request).should be_valid | |
33 | - end | |
34 | - end | |
35 | - | |
36 | - describe 'Note' do | |
37 | - it "builds a valid instance" do | |
38 | - build(:note).should be_valid | |
39 | - end | |
40 | - end | |
41 | - | |
42 | - describe 'Event' do | |
43 | - it "builds a valid instance" do | |
44 | - build(:event).should be_valid | |
45 | - end | |
46 | - end | |
47 | - | |
48 | - describe 'Key' do | |
49 | - it "builds a valid instance" do | |
50 | - build(:key).should be_valid | |
51 | - end | |
52 | - | |
53 | - it "builds a valid deploy key instance" do | |
54 | - build(:deploy_key).should be_valid | |
55 | - end | |
56 | - | |
57 | - it "builds a valid personal key instance" do | |
58 | - build(:personal_key).should be_valid | |
59 | - end | |
60 | - end | |
61 | - | |
62 | - describe 'Milestone' do | |
63 | - it "builds a valid instance" do | |
64 | - build(:milestone).should be_valid | |
65 | - end | |
66 | - end | |
67 | - | |
68 | - describe 'SystemHook' do | |
69 | - it "builds a valid instance" do | |
70 | - build(:system_hook).should be_valid | |
71 | - end | |
72 | - end | |
73 | - | |
74 | - describe 'ProjectHook' do | |
75 | - it "builds a valid instance" do | |
76 | - build(:project_hook).should be_valid | |
77 | - end | |
78 | - end | |
79 | - | |
80 | - describe 'Wiki' do | |
81 | - it "builds a valid instance" do | |
82 | - build(:wiki).should be_valid | |
83 | - end | |
84 | - end | |
85 | - | |
86 | - describe 'Snippet' do | |
87 | - it "builds a valid instance" do | |
88 | - build(:snippet).should be_valid | |
3 | +FactoryGirl.factories.map(&:name).each do |factory_name| | |
4 | + describe "#{factory_name} factory" do | |
5 | + it 'should be valid' do | |
6 | + build(factory_name).should be_valid | |
89 | 7 | end |
90 | 8 | end |
91 | 9 | end | ... | ... |
... | ... | @@ -208,6 +208,46 @@ describe GitlabMarkdownHelper do |
208 | 208 | gfm(actual).should match(expected) |
209 | 209 | end |
210 | 210 | end |
211 | + | |
212 | + describe "emoji" do | |
213 | + it "matches at the start of a string" do | |
214 | + gfm(":+1:").should match(/<img/) | |
215 | + end | |
216 | + | |
217 | + it "matches at the end of a string" do | |
218 | + gfm("This gets a :-1:").should match(/<img/) | |
219 | + end | |
220 | + | |
221 | + it "matches with adjacent text" do | |
222 | + gfm("+1 (:+1:)").should match(/<img/) | |
223 | + end | |
224 | + | |
225 | + it "has a title attribute" do | |
226 | + gfm(":-1:").should match(/title=":-1:"/) | |
227 | + end | |
228 | + | |
229 | + it "has an alt attribute" do | |
230 | + gfm(":-1:").should match(/alt=":-1:"/) | |
231 | + end | |
232 | + | |
233 | + it "has an emoji class" do | |
234 | + gfm(":+1:").should match('class="emoji"') | |
235 | + end | |
236 | + | |
237 | + it "sets height and width" do | |
238 | + actual = gfm(":+1:") | |
239 | + actual.should match(/width="20"/) | |
240 | + actual.should match(/height="20"/) | |
241 | + end | |
242 | + | |
243 | + it "keeps whitespace intact" do | |
244 | + gfm("This deserves a :+1: big time.").should match(/deserves a <img.+\/> big time/) | |
245 | + end | |
246 | + | |
247 | + it "ignores invalid emoji" do | |
248 | + gfm(":invalid-emoji:").should_not match(/<img/) | |
249 | + end | |
250 | + end | |
211 | 251 | end |
212 | 252 | |
213 | 253 | describe "#link_to_gfm" do | ... | ... |
... | ... | @@ -24,7 +24,7 @@ describe Notify do |
24 | 24 | end |
25 | 25 | |
26 | 26 | it 'has the correct subject' do |
27 | - should have_subject /^gitlab \| Account was created for you$/ | |
27 | + should have_subject /^gitlab \| Account was created for you$/i | |
28 | 28 | end |
29 | 29 | |
30 | 30 | it 'contains the new user\'s login name' do | ... | ... |
... | ... | @@ -9,6 +9,7 @@ describe Milestone do |
9 | 9 | describe "Validation" do |
10 | 10 | it { should validate_presence_of(:title) } |
11 | 11 | it { should validate_presence_of(:project_id) } |
12 | + it { should ensure_inclusion_of(:closed).in_array([true, false]) } | |
12 | 13 | end |
13 | 14 | |
14 | 15 | let(:milestone) { Factory :milestone } | ... | ... |
... | ... | @@ -35,6 +35,16 @@ describe Note do |
35 | 35 | note = Factory(:note, note: "-1 for this") |
36 | 36 | note.should_not be_upvote |
37 | 37 | end |
38 | + | |
39 | + it "recognizes a +1 emoji as a vote" do | |
40 | + note = build(:note, note: ":+1: for this") | |
41 | + note.should be_upvote | |
42 | + end | |
43 | + | |
44 | + it "recognizes a neutral emoji note" do | |
45 | + note = build(:note, note: "I would :+1: this, but I don't want to") | |
46 | + note.should_not be_upvote | |
47 | + end | |
38 | 48 | end |
39 | 49 | |
40 | 50 | let(:project) { create(:project) } | ... | ... |
... | ... | @@ -37,6 +37,10 @@ describe Project do |
37 | 37 | # TODO: Formats |
38 | 38 | |
39 | 39 | it { should validate_presence_of(:owner) } |
40 | + it { should ensure_inclusion_of(:issues_enabled).in_array([true, false]) } | |
41 | + it { should ensure_inclusion_of(:wall_enabled).in_array([true, false]) } | |
42 | + it { should ensure_inclusion_of(:merge_requests_enabled).in_array([true, false]) } | |
43 | + it { should ensure_inclusion_of(:wiki_enabled).in_array([true, false]) } | |
40 | 44 | |
41 | 45 | it "should not allow new projects beyond user limits" do |
42 | 46 | project.stub(:owner).and_return(double(can_create_project?: false, projects_limit: 1)) |
... | ... | @@ -239,7 +243,7 @@ describe Project do |
239 | 243 | end |
240 | 244 | end |
241 | 245 | |
242 | - describe :update_merge_requests do | |
246 | + describe :update_merge_requests do | |
243 | 247 | let(:project) { Factory :project } |
244 | 248 | |
245 | 249 | before do |
... | ... | @@ -259,7 +263,7 @@ describe Project do |
259 | 263 | @merge_request.closed.should be_true |
260 | 264 | end |
261 | 265 | |
262 | - it "should update merge request commits with new one if pushed to source branch" do | |
266 | + it "should update merge request commits with new one if pushed to source branch" do | |
263 | 267 | @merge_request.last_commit.should == nil |
264 | 268 | project.update_merge_requests("8716fc78f3c65bbf7bcf7b574febd583bc5d2812", "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a", "refs/heads/master", @key.user) |
265 | 269 | @merge_request.reload | ... | ... |
... | ... | @@ -31,36 +31,46 @@ describe User do |
31 | 31 | it { should respond_to(:private_token) } |
32 | 32 | end |
33 | 33 | |
34 | - it "should return valid identifier" do | |
35 | - user = User.new(email: "test@mail.com") | |
36 | - user.identifier.should == "test_mail_com" | |
37 | - end | |
34 | + describe '#identifier' do | |
35 | + it "should return valid identifier" do | |
36 | + user = build(:user, email: "test@mail.com") | |
37 | + user.identifier.should == "test_mail_com" | |
38 | + end | |
38 | 39 | |
39 | - it "should return identifier without + sign" do | |
40 | - user = User.new(email: "test+foo@mail.com") | |
41 | - user.identifier.should == "test_foo_mail_com" | |
42 | - end | |
40 | + it "should return identifier without + sign" do | |
41 | + user = build(:user, email: "test+foo@mail.com") | |
42 | + user.identifier.should == "test_foo_mail_com" | |
43 | + end | |
43 | 44 | |
44 | - it "should execute callback when force_random_password specified" do | |
45 | - user = User.new(email: "test@mail.com", force_random_password: true) | |
46 | - user.should_receive(:generate_password) | |
47 | - user.save | |
45 | + it "should conform to Gitolite's required identifier pattern" do | |
46 | + user = build(:user, email: "_test@example.com") | |
47 | + user.identifier.should == 'test_example_com' | |
48 | + end | |
48 | 49 | end |
49 | 50 | |
50 | - it "should not generate password by default" do | |
51 | - user = Factory(:user, password: 'abcdefg', password_confirmation: 'abcdefg') | |
52 | - user.password.should == 'abcdefg' | |
53 | - end | |
51 | + describe '#generate_password' do | |
52 | + it "should execute callback when force_random_password specified" do | |
53 | + user = build(:user, force_random_password: true) | |
54 | + user.should_receive(:generate_password) | |
55 | + user.save | |
56 | + end | |
57 | + | |
58 | + it "should not generate password by default" do | |
59 | + user = create(:user, password: 'abcdefg') | |
60 | + user.password.should == 'abcdefg' | |
61 | + end | |
54 | 62 | |
55 | - it "should generate password when forcing random password" do | |
56 | - Devise.stub(:friendly_token).and_return('123456789') | |
57 | - user = User.create(email: "test1@mail.com", force_random_password: true) | |
58 | - user.password.should == user.password_confirmation | |
59 | - user.password.should == '12345678' | |
63 | + it "should generate password when forcing random password" do | |
64 | + Devise.stub(:friendly_token).and_return('123456789') | |
65 | + user = create(:user, password: 'abcdefg', force_random_password: true) | |
66 | + user.password.should == '12345678' | |
67 | + end | |
60 | 68 | end |
61 | 69 | |
62 | - it "should have authentication token" do | |
63 | - user = Factory(:user) | |
64 | - user.authentication_token.should_not == "" | |
70 | + describe 'authentication token' do | |
71 | + it "should have authentication token" do | |
72 | + user = Factory(:user) | |
73 | + user.authentication_token.should_not be_blank | |
74 | + end | |
65 | 75 | end |
66 | 76 | end | ... | ... |
... | ... | @@ -10,7 +10,7 @@ describe UsersProject do |
10 | 10 | let!(:users_project) { create(:users_project) } |
11 | 11 | |
12 | 12 | it { should validate_presence_of(:user_id) } |
13 | - it { should validate_uniqueness_of(:user_id).scoped_to(:project_id) } | |
13 | + it { should validate_uniqueness_of(:user_id).scoped_to(:project_id).with_message(/already exists/) } | |
14 | 14 | |
15 | 15 | it { should validate_presence_of(:project_id) } |
16 | 16 | end | ... | ... |
... | ... | @@ -27,38 +27,40 @@ describe Gitlab::API do |
27 | 27 | |
28 | 28 | describe "POST /projects" do |
29 | 29 | it "should create new project without code and path" do |
30 | - lambda { | |
31 | - name = "foo" | |
32 | - post api("/projects", user), { | |
33 | - name: name | |
34 | - } | |
35 | - response.status.should == 201 | |
36 | - json_response["name"].should == name | |
37 | - json_response["code"].should == name | |
38 | - json_response["path"].should == name | |
39 | - }.should change{Project.count}.by(1) | |
40 | - end | |
41 | - it "should create new project" do | |
42 | - lambda { | |
43 | - name = "foo" | |
44 | - path = "bar" | |
45 | - code = "bazz" | |
46 | - post api("/projects", user), { | |
47 | - code: code, | |
48 | - path: path, | |
49 | - name: name | |
50 | - } | |
51 | - response.status.should == 201 | |
52 | - json_response["name"].should == name | |
53 | - json_response["path"].should == path | |
54 | - json_response["code"].should == code | |
55 | - }.should change{Project.count}.by(1) | |
56 | - end | |
57 | - it "should not create project without name" do | |
58 | - lambda { | |
59 | - post api("/projects", user) | |
60 | - response.status.should == 404 | |
61 | - }.should_not change{Project.count} | |
30 | + expect { post api("/projects", user), name: 'foo' }.to change {Project.count}.by(1) | |
31 | + end | |
32 | + | |
33 | + it "should not create new project without name" do | |
34 | + expect { post api("/projects", user) }.to_not change {Project.count} | |
35 | + end | |
36 | + | |
37 | + it "should respond with 201 on success" do | |
38 | + post api("/projects", user), name: 'foo' | |
39 | + response.status.should == 201 | |
40 | + end | |
41 | + | |
42 | + it "should repsond with 404 on failure" do | |
43 | + post api("/projects", user) | |
44 | + response.status.should == 404 | |
45 | + end | |
46 | + | |
47 | + it "should assign attributes to project" do | |
48 | + project = Factory.attributes(:project, { | |
49 | + path: 'path', | |
50 | + code: 'code', | |
51 | + description: Faker::Lorem.sentence, | |
52 | + default_branch: 'stable', | |
53 | + issues_enabled: false, | |
54 | + wall_enabled: false, | |
55 | + merge_requests_enabled: false, | |
56 | + wiki_enabled: false | |
57 | + }) | |
58 | + | |
59 | + post api("/projects", user), project | |
60 | + | |
61 | + project.each_pair do |k,v| | |
62 | + json_response[k.to_s].should == v | |
63 | + end | |
62 | 64 | end |
63 | 65 | end |
64 | 66 | ... | ... |
... | ... | @@ -0,0 +1,72 @@ |
1 | +require 'spec_helper' | |
2 | + | |
3 | +describe Project, "Repository" do | |
4 | + let(:project) { build(:project) } | |
5 | + | |
6 | + describe "#empty_repo?" do | |
7 | + it "should return true if the repo doesn't exist" do | |
8 | + project.stub(repo_exists?: false, has_commits?: true) | |
9 | + project.should be_empty_repo | |
10 | + end | |
11 | + | |
12 | + it "should return true if the repo has commits" do | |
13 | + project.stub(repo_exists?: true, has_commits?: false) | |
14 | + project.should be_empty_repo | |
15 | + end | |
16 | + | |
17 | + it "should return false if the repo exists and has commits" do | |
18 | + project.stub(repo_exists?: true, has_commits?: true) | |
19 | + project.should_not be_empty_repo | |
20 | + end | |
21 | + end | |
22 | + | |
23 | + describe "#discover_default_branch" do | |
24 | + let(:master) { double(name: 'master') } | |
25 | + let(:stable) { double(name: 'stable') } | |
26 | + | |
27 | + it "returns 'master' when master exists" do | |
28 | + project.should_receive(:heads).and_return([stable, master]) | |
29 | + project.discover_default_branch.should == 'master' | |
30 | + end | |
31 | + | |
32 | + it "returns non-master when master exists but default branch is set to something else" do | |
33 | + project.default_branch = 'stable' | |
34 | + project.should_receive(:heads).and_return([stable, master]) | |
35 | + project.discover_default_branch.should == 'stable' | |
36 | + end | |
37 | + | |
38 | + it "returns a non-master branch when only one exists" do | |
39 | + project.should_receive(:heads).and_return([stable]) | |
40 | + project.discover_default_branch.should == 'stable' | |
41 | + end | |
42 | + | |
43 | + it "returns nil when no branch exists" do | |
44 | + project.should_receive(:heads).and_return([]) | |
45 | + project.discover_default_branch.should be_nil | |
46 | + end | |
47 | + end | |
48 | + | |
49 | + describe "#root_ref" do | |
50 | + it "returns default_branch when set" do | |
51 | + project.default_branch = 'stable' | |
52 | + project.root_ref.should == 'stable' | |
53 | + end | |
54 | + | |
55 | + it "returns 'master' when default_branch is nil" do | |
56 | + project.default_branch = nil | |
57 | + project.root_ref.should == 'master' | |
58 | + end | |
59 | + end | |
60 | + | |
61 | + describe "#root_ref?" do | |
62 | + it "returns true when branch is root_ref" do | |
63 | + project.default_branch = 'stable' | |
64 | + project.root_ref?('stable').should be_true | |
65 | + end | |
66 | + | |
67 | + it "returns false when branch is not root_ref" do | |
68 | + project.default_branch = nil | |
69 | + project.root_ref?('stable').should be_false | |
70 | + end | |
71 | + end | |
72 | +end | ... | ... |