Commit 4537623d12fb7372262267be5d6ec3b41f3f476c

Authored by Dmitriy Zaporozhets
2 parents c7e490eb 1a83fea7

Merge branch 'master' into karlhungus-mr-on-fork

Conflicts:
	app/contexts/filter_context.rb
	app/contexts/search_context.rb
	app/models/merge_request.rb
	app/models/note.rb
	app/views/shared/_merge_requests.html.haml
	spec/controllers/commit_controller_spec.rb
	spec/services/notification_service_spec.rb
Showing 165 changed files with 1334 additions and 909 deletions   Show diff stats
.gitignore
... ... @@ -30,3 +30,5 @@ vendor/bundle/*
30 30 rails_best_practices_output.html
31 31 doc/code/*
32 32 .secret
  33 +*.log
  34 +public/uploads.*
... ...
CONTRIBUTING.md
... ... @@ -2,6 +2,12 @@
2 2  
3 3 This guide details how to use issues and pull requests to improve GitLab.
4 4  
  5 +- [Closing policy for issues and pull requests](#closing-policy-for-issues-and-pull-requests)
  6 +- [Issue tracker](#issue-tracker)
  7 +- [Pull requests](#pull-requests)
  8 +
  9 +If you want to know how the GitLab team handles contributions have a look at [the GitLab contributing process](PROCESS.md).
  10 +
5 11 ## Closing policy for issues and pull requests
6 12  
7 13 GitLab is a popular open source project and the capacity to deal with issues and pull requests is limited. Out of respect for our volunteers, issues and pull requests not in line with the guidelines listed in this document may be closed without notice.
... ...
Gemfile
... ... @@ -23,7 +23,7 @@ gem 'omniauth-github'
23 23  
24 24 # Extracting information from a git repository
25 25 # Provide access to Gitlab::Git library
26   -gem 'gitlab_git', '~> 1.4.1'
  26 +gem "gitlab_git", "~> 2.0.0.pre"
27 27  
28 28 # Ruby/Rack Git Smart-HTTP Server Handler
29 29 gem 'gitlab-grack', '~> 1.0.1', require: 'grack'
... ...
Gemfile.lock
... ... @@ -176,7 +176,7 @@ GEM
176 176 gitlab-pygments.rb (0.3.2)
177 177 posix-spawn (~> 0.3.6)
178 178 yajl-ruby (~> 1.1.0)
179   - gitlab_git (1.4.1)
  179 + gitlab_git (2.0.0.pre)
180 180 activesupport (~> 3.2.13)
181 181 github-linguist (~> 2.3.4)
182 182 gitlab-grit (~> 2.6.0)
... ... @@ -275,7 +275,7 @@ GEM
275 275 minitest (4.7.4)
276 276 modernizr (2.6.2)
277 277 sprockets (~> 2.0)
278   - multi_json (1.7.7)
  278 + multi_json (1.7.8)
279 279 multi_xml (0.5.4)
280 280 multipart-post (1.2.0)
281 281 mysql2 (0.3.11)
... ... @@ -568,7 +568,7 @@ DEPENDENCIES
568 568 gitlab-gollum-lib (~> 1.0.1)
569 569 gitlab-grack (~> 1.0.1)
570 570 gitlab-pygments.rb (~> 0.3.2)
571   - gitlab_git (~> 1.4.1)
  571 + gitlab_git (~> 2.0.0.pre)
572 572 gitlab_meta (= 6.0)
573 573 gitlab_omniauth-ldap (= 1.0.3)
574 574 gon
... ...
PROCESS.md 0 → 100644
... ... @@ -0,0 +1,103 @@
  1 +# GitLab Contributing Process
  2 +
  3 +## Purpose of describing the contributing process
  4 +
  5 +Below we describe the contributing process for two reasons. Contributors know what to expect from maintainers (initial, response within xx days, friendly treatment, etc). And maintainers know what to expect from contributors (use latest version, confirm the issue is addressed, friendly treatment, etc).
  6 +
  7 +## How we handle issues
  8 +
  9 +The priority should be mentioning people that can help and assigning workflow labels. Workflow labels are purposely not very detailed since that would be hard to keep updated as you would need to reevaluate them after every comment. We optionally use functional labels on demand when want to group related issues to get an overview (for example all issues related to RVM, to tackle them in one go) and to add details to the issue.
  10 +
  11 +If an issue is complex and needs the attention of a specific person, assignment is a good option but assigning issues might discourage other people from contributing to that issue. We need all the contributions we can get so this should never be discouraged. Also, an assigned person might not have time for a few weeks, so others should feel free to takeover.
  12 +
  13 +Priority (from high to low):
  14 +
  15 +1. Mentioning people (very important)
  16 +2. Workflow labels
  17 +3. Functional labels (less important)
  18 +4. Assigning issues (optional)
  19 +
  20 +## Workflow labels
  21 +
  22 +- _Awaiting feedback_: Feedback pending from the reporter
  23 +- _Awaiting confirmation of fix_: The issue should already be solved in **master** (generally you can avoid this workflow item and just close the issue right away)
  24 +- _Attached PR_: There is a PR attached and the discussion should happen there
  25 + - We need to let issues stay in sync with the PR's. We can do this with a "Closing #XXXX" or "Fixes #XXXX" comment in the PR. We can't close the issue when there is a pull request because sometimes a PR is not good and we just close the PR, then the issue must stay.
  26 +- _Awaiting developer action/feedback_: Issue needs to be fixed or clarified by a developer
  27 +
  28 +## Functional labels
  29 +
  30 +These labels describe what development specialities are involved such as: PostgreSQL, UX, LDAP.
  31 +
  32 +## Label colors
  33 +- Light orange `#fef2c0`: workflow labels for issue team members (awaiting feedback, awaiting confirmation of fix)
  34 +- Bright orange `#eb6420`: workflow labels for core team members (attached PR, awaiting developer action/feedback)
  35 +- Light blue `#82C5FF`: functional labels
  36 +- Green labels `#009800`: issues that can generally be ignored. For example, issues given the following labels normally can be closed immediately:
  37 + - Feature request (see copy & paste response: [Feature requests](#feature-requests))
  38 + - Support (see copy & paste response: [Support requests and configuration questions](#support-requests-and-configuration-questions)
  39 +
  40 +## Common actions
  41 +
  42 +### Issue team
  43 +- Looks for issues without workflow labels and triages issue
  44 +- Monitors pull requests
  45 +- Closes invalid issues and pull requests with a comment (duplicates, [feature requests](#feature-requests), [fixed in newer version](#issue-fixed-in-newer-version), [issue report for old version](#issue-report-for-old-version), not a problem in GitLab, etc.)
  46 +- Assigns appropriate [labels](#how-we-handle-issues)
  47 +- Asks for feedback from issue reporter/pull request initiator ([invalid issue reports](#improperly-formatted-issue), [format code](#code-format), etc.)
  48 +- Asks for feedback from the relevant developer(s) based on the [list of members and their specialities](http://gitlab.org/team/)
  49 +- Monitors all issues/pull requests for feedback (but especially ones commented on since automatically watching them):
  50 +- Assigns issues to developers if they indicate they are fixing it
  51 +- Assigns pull requests to developers if they indicate they will take care of merge
  52 +- Closes issues with no feedback from the reporter for two weeks
  53 +- Closes stale pull requests
  54 +
  55 +### Development team
  56 +
  57 +- Responds to issues and pull requests the issue team mentions them in
  58 +- Monitors for new issues in _Awaiting developer action/feedback_ with no developer activity (once a week)
  59 +- Monitors for new pull requests (at least once a week)
  60 +- Manages their work queue by looking at issues and pull requests assigned to them
  61 +- Close fixed issues (via commit messages or manually)
  62 +- Codes [new features](http://feedback.gitlab.com/forums/176466-general/filters/top)!
  63 +- Response guidelines
  64 +- Be kind to people trying to contribute. Be aware that people can be a non-native or a native English speaker, they might not understand thing or they might be very sensitive to how your word things. Use emoji to express your feelings (hearth, star, smile, etc.). Some good tips about giving feedback to pull requests is in the [Thoughtbot code review guide](https://github.com/thoughtbot/guides/tree/master/code-review).
  65 +
  66 +## Copy & paste responses
  67 +
  68 +### Improperly formatted issue
  69 +
  70 +Thanks for the issue report. Please reformat your issue to conform to the issue tracker guidelines found in our \[contributing guidelines\]\(https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md#issue-tracker-guidelines).
  71 +
  72 +### Feature requests
  73 +
  74 +Thanks for your interest in GitLab. We don't use the GitHub issue tracker for feature requests. Please use http://feedback.gitlab.com/ for this purpose or create a pull request implementing this feature. Have a look at the \[contribution guidelines\]\(https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md) for more information.
  75 +
  76 +### Issue report for old version
  77 +
  78 +Thanks for the issue report but we only support issues for the latest stable version of GitLab. I'm closing this issue but if you still experience this problem in the latest stable version, please open a new issue (but also reference the old issue(s)). Make sure to also include the necessary debugging information conforming to the issue tracker guidelines found in our \[contributing guidelines\]\(https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md#issue-tracker-guidelines).
  79 +
  80 +### Support requests and configuration questions
  81 +
  82 +Thanks for your interest in GitLab. We don't use the GitHub issue tracker for support requests and configuration questions. Please use the \[support forum\]\(https://groups.google.com/forum/#!forum/gitlabhq), \[Stack Overflow\]\(http://stackoverflow.com/questions/tagged/gitlab), the unofficial #gitlab IRC channel on Freenode or the http://www.gitlab.com paid services for this purpose. Have a look at the \[contribution guidelines\]\(https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md) for more information.
  83 +
  84 +### Code format
  85 +
  86 +Please use ``` to format console output, logs, and code as it's very hard to read otherwise.
  87 +
  88 +### Issue fixed in newer version
  89 +
  90 +Thanks for the issue report. This issue has already been fixed in newer versions of GitLab. Due to the size of this project and our limited resources we are only able to support the latest stable release as outlined in our \[contributing guidelines\]\(https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md#issue-tracker). In order to get this bug fix and enjoy many new features please \[upgrade\]\(http://blog.gitlab.org/). If you still experience issues at that time please open a new issue following our issue tracker guidelines found in the \[contributing guidelines\]\(https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md#issue-tracker-guidelines).
  91 +
  92 +### Improperly formatted pull request
  93 +
  94 +Thanks for your interest in improving the GitLab codebase! Please update your pull request according to the \[contributing guidelines\]\(https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md#pull-request-guidelines).
  95 +
  96 +### Inactivity close of an issue
  97 +
  98 +It's been at least 2 weeks (and a new release) since we heard from you. I'm closing this issue but if you still experience this problem, please open a new issue (but also reference the old issue(s)). Make sure to also include the necessary debugging information conforming to the issue tracker guidelines found in our \[contributing guidelines\]\(https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md#issue-tracker-guidelines).
  99 +
  100 +### Inactivity close of a pull request
  101 +
  102 +This pull request has been closed because a request for more information has not been reacted to for more than 2 weeks. If you respond and conform to the pull request guidelines in our \[contributing guidelines\]\(https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md#pull-requests) we will reopen this pull request.
  103 +
... ...
README.md
... ... @@ -147,6 +147,8 @@ or start each component separately
147 147  
148 148 * [Mailing list](https://groups.google.com/forum/#!forum/gitlabhq) and [Stack Overflow](http://stackoverflow.com/questions/tagged/gitlab) are the best places to ask questions. For example you can use it if you have questions about: permission denied errors, invisible repos, can't clone/pull/push or with web hooks that don't fire. Please search for similar issues before posting your own, there's a good chance somebody else had the same issue you have now and has resolved it. There are a lot of helpful GitLab users there who may be able to help you quickly. If your particular issue turns out to be a bug, it will find its way from there to a fix.
149 149  
  150 +* [Unofficial #gitlab IRC on Freenode](http://www.freenode.net/) is another way to get in touch with other GitLab users who may be able to help you.
  151 +
150 152 * [Feedback and suggestions forum](http://feedback.gitlab.com) is the place to propose and discuss new features for GitLab.
151 153  
152 154 * [Contributing guide](https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md) describes how to submit pull requests and issues. Pull requests and issues not in line with the guidelines in this document will be closed.
... ...
app/assets/javascripts/behaviors/toggler_behavior.coffee
... ... @@ -11,3 +11,7 @@ $ ->
11 11 container = $(".js-toggle-visibility-container")
12 12 container.toggleClass("hide")
13 13 e.preventDefault()
  14 +
  15 + $("body").on "click", ".js-toggle-button", (e) ->
  16 + $(@).closest(".js-toggle-container").find(".js-toggle-content").toggle()
  17 + e.preventDefault()
... ...
app/assets/javascripts/branch-graph.js.coffee
... ... @@ -62,22 +62,22 @@ class BranchGraph
62 62 cuday = 0
63 63 cumonth = ""
64 64  
65   - r.rect(0, 0, 26, @barHeight).attr fill: "#222"
66   - r.rect(26, 0, 20, @barHeight).attr fill: "#444"
  65 + r.rect(0, 0, 40, @barHeight).attr fill: "#222"
  66 + r.rect(40, 0, 30, @barHeight).attr fill: "#444"
67 67  
68 68 for day, mm in @days
69 69 if cuday isnt day[0]
70 70 # Dates
71   - r.text(36, @offsetY + @unitTime * mm, day[0])
  71 + r.text(55, @offsetY + @unitTime * mm, day[0])
72 72 .attr(
73 73 font: "12px Monaco, monospace"
74   - fill: "#DDD"
  74 + fill: "#BBB"
75 75 )
76 76 cuday = day[0]
77 77  
78 78 if cumonth isnt day[1]
79 79 # Months
80   - r.text(13, @offsetY + @unitTime * mm, day[1])
  80 + r.text(20, @offsetY + @unitTime * mm, day[1])
81 81 .attr(
82 82 font: "12px Monaco, monospace"
83 83 fill: "#EEE"
... ...
app/assets/javascripts/dispatcher.js.coffee
... ... @@ -39,7 +39,9 @@ class Dispatcher
39 39  
40 40 switch path.first()
41 41 when 'admin' then new Admin()
42   - when 'wikis' then new Wikis()
  42 + when 'projects'
  43 + new Wikis() if path[1] == 'wikis'
  44 +
43 45  
44 46 initSearch: ->
45 47 autocomplete_json = $('.search-autocomplete-json').data('autocomplete-opts')
... ...
app/assets/javascripts/extensions/jquery.js.coffee
... ... @@ -7,3 +7,7 @@ $.fn.enableButton = ->
7 7 $(@).removeAttr('disabled').
8 8 removeClass('disabled')
9 9  
  10 +$.fn.disableButton = ->
  11 + $(@).attr('disabled', 'disabled').
  12 + addClass('disabled')
  13 +
... ...
app/assets/javascripts/gfm_auto_complete.js.coffee
... ... @@ -44,7 +44,7 @@ GitLab.GfmAutoComplete =
44 44 tpl: @Issues.template
45 45 callbacks:
46 46 before_save: (issues) ->
47   - $.map issues, (i) -> id: i.id, title: i.title, search: "#{i.id} #{i.title}"
  47 + $.map issues, (i) -> id: i.id, title: sanitize(i.title), search: "#{i.id} #{i.title}"
48 48  
49 49 input.one "focus", =>
50 50 $.getJSON(@dataSource).done (data) ->
... ...
app/assets/javascripts/main.js.coffee
... ... @@ -119,7 +119,7 @@ $ ->
119 119  
120 120  
121 121 # Commit show suppressed diff
122   - $(".supp_diff_link").bind "click", ->
  122 + $(".content").on "click", ".supp_diff_link", ->
123 123 $(@).next('table').show()
124 124 $(@).remove()
125 125  
... ...
app/assets/javascripts/merge_requests.js.coffee
... ... @@ -22,12 +22,7 @@ class MergeRequest
22 22 this.$('.show-all-commits').on 'click', =>
23 23 this.showAllCommits()
24 24  
25   - modal = $('#modal_merge_info').modal modal: true, show:false
26   -
27   - $('.how_to_merge_link').bind "click", ->
28   - modal.show()
29   - $('.modal-header .close').bind "click", ->
30   - modal.hide()
  25 + modal = $('#modal_merge_info').modal(show: false)
31 26  
32 27 # Local jQuery finder
33 28 $: (selector) ->
... ...
app/assets/javascripts/notes.js
... ... @@ -227,10 +227,11 @@ var NoteList = {
227 227 // Show the attachment delete link
228 228 note.find(".js-note-attachment-delete").show();
229 229  
  230 + GitLab.GfmAutoComplete.setup();
  231 +
230 232 var form = note.find(".note-edit-form");
231 233 form.show();
232 234  
233   -
234 235 var textarea = form.find("textarea");
235 236 var p = $("<p></p>").text(textarea.val());
236 237 var hidden_div = $('<div class="note-original-content"></div>').append(p);
... ...
app/assets/javascripts/wikis.js.coffee
1 1 class Wikis
2 2 constructor: ->
3   - modal = $('#modal-new-wiki').modal({modal: true, show:false})
4   -
5   - $('.add-new-wiki').bind "click", ->
6   - modal.show()
7   -
8 3 $('.build-new-wiki').bind "click", ->
9 4 field = $('#new_wiki_path')
10 5 slug = field.val()
... ... @@ -13,7 +8,5 @@ class Wikis
13 8 if(slug.length > 0)
14 9 location.href = path + "/" + slug
15 10  
16   - $('.modal-header .close').bind "click", ->
17   - modal.hide()
18 11  
19 12 @Wikis = Wikis
... ...
app/assets/stylesheets/common.scss
... ... @@ -81,33 +81,6 @@ span.update-author {
81 81 font-weight: normal;
82 82 }
83 83  
84   -form {
85   - @extend .form-horizontal;
86   -
87   - .actions {
88   - @extend .form-actions;
89   - }
90   -
91   - .clearfix {
92   - @extend .control-group;
93   - }
94   -
95   - .input {
96   - @extend .controls;
97   - }
98   -
99   - label {
100   - @extend .control-label;
101   - }
102   - .xlarge {
103   - @extend .input-xlarge;
104   - }
105   - .xxlarge {
106   - @extend .input-xxlarge;
107   - }
108   -}
109   -
110   -
111 84 .field_with_errors {
112 85 display: inline;
113 86 }
... ... @@ -121,15 +94,6 @@ ul.breadcrumb {
121 94 }
122 95  
123 96 a {
124   - color: #474D57;
125   - font-weight: bold;
126   - font-size: 14px;
127   - }
128   -}
129   -
130   -input[type=text] {
131   - &.large_text {
132   - padding: 6px;
133 97 font-size: 16px;
134 98 }
135 99 }
... ...
app/assets/stylesheets/gitlab_bootstrap.scss
... ... @@ -2,11 +2,49 @@
2 2 $baseFontSize: 13px !default;
3 3 $baseLineHeight: 18px !default;
4 4  
5   -// BOOTSTRAP
6   -@import "bootstrap";
  5 +/**
  6 + * BOOTSTRAP
  7 + */
  8 +@import "bootstrap/variables";
  9 +@import "bootstrap/mixins";
  10 +@import "bootstrap/reset";
  11 +@import "bootstrap/scaffolding";
  12 +@import "bootstrap/grid";
  13 +@import "bootstrap/layouts";
  14 +@import "bootstrap/type";
  15 +@import "bootstrap/code";
  16 +@import "bootstrap/forms";
  17 +@import "bootstrap/tables";
  18 +@import "bootstrap/sprites";
  19 +@import "bootstrap/dropdowns";
  20 +@import "bootstrap/wells";
  21 +@import "bootstrap/component-animations";
  22 +@import "bootstrap/close";
  23 +@import "bootstrap/button-groups";
  24 +@import "bootstrap/alerts";
  25 +@import "bootstrap/navs";
  26 +@import "bootstrap/navbar";
  27 +@import "bootstrap/breadcrumbs";
  28 +@import "bootstrap/pagination";
  29 +@import "bootstrap/pager";
  30 +@import "bootstrap/modals";
  31 +@import "bootstrap/tooltip";
  32 +@import "bootstrap/popovers";
  33 +@import "bootstrap/thumbnails";
  34 +@import "bootstrap/media";
  35 +@import "bootstrap/labels-badges";
  36 +@import "bootstrap/progress-bars";
  37 +@import "bootstrap/accordion";
  38 +@import "bootstrap/carousel";
  39 +@import "bootstrap/hero-unit";
  40 +@import "bootstrap/utilities";
7 41 @import "bootstrap/responsive-utilities";
8 42 @import "bootstrap/responsive-1200px-min";
9 43  
  44 +/**
  45 + * Font icons
  46 + *
  47 + */
10 48 @import "font-awesome";
11 49  
12 50 /**
... ... @@ -26,3 +64,4 @@ $baseLineHeight: 18px !default;
26 64 @import "gitlab_bootstrap/files.scss";
27 65 @import "gitlab_bootstrap/tables.scss";
28 66 @import "gitlab_bootstrap/lists.scss";
  67 +@import "gitlab_bootstrap/forms.scss";
... ...
app/assets/stylesheets/gitlab_bootstrap/blocks.scss
... ... @@ -10,15 +10,34 @@
10 10 *
11 11 */
12 12 .ui-box {
13   - background: #F9F9F9;
  13 + background: #FFF;
14 14 margin-bottom: 20px;
15 15 border: 1px solid #CCC;
16 16 word-wrap: break-word;
17   - @include solid-shade;
  17 +
  18 + &.small-box {
  19 + margin-bottom: 10px;
  20 +
  21 + .title {
  22 + font-size: 13px;
  23 + line-height: 30px;
  24 +
  25 + a {
  26 + color: #666;
  27 + &:hover {
  28 + text-decoration: underline;
  29 + }
  30 + }
  31 + }
  32 + }
18 33  
19 34 &.ui-box-show {
20 35 margin:20px 0;
21 36 background: #FFF;
  37 +
  38 + .control-group {
  39 + margin-bottom: 0;
  40 + }
22 41 }
23 42  
24 43 &.ui-box-danger {
... ... @@ -71,10 +90,6 @@
71 90 border-top: 1px solid #eee;
72 91 }
73 92  
74   - &.white {
75   - background: #fff;
76   - }
77   -
78 93 ul {
79 94 margin: 0;
80 95 }
... ... @@ -102,6 +117,8 @@
102 117  
103 118 .btn {
104 119 vertical-align: middle;
  120 + padding: 4px 12px;
  121 + @include box-shadow(0 0px 1px 1px #f2f2f2);
105 122 }
106 123  
107 124 .nav-pills {
... ...
app/assets/stylesheets/gitlab_bootstrap/buttons.scss
1 1 .btn {
  2 + display: inline-block;
  3 + padding: 6px 12px;
  4 + margin-bottom: 0;
  5 + font-size: 13px;
  6 + line-height: $baseLineHeight;
  7 + text-align: center;
  8 + vertical-align: middle;
  9 + cursor: pointer;
  10 + border: 1px solid #BBB;
  11 + color: $style_color;
  12 + @include border-radius($baseBorderRadius);
  13 + @include box-shadow(inset 0 1px 0 rgba(255,255,255,.2));
2 14 @include linear-gradient(#f1f1f1, #e1e1e1);
3 15 text-shadow: 0 1px 1px #FFF;
4   - border-color: #BBB;
  16 + text-decoration: none;
5 17  
  18 + &.hover,
6 19 &:hover {
  20 + color: $style_color;
7 21 background: #f1f1f1;
8   - @include linear-gradient(#fAfAfA, #f1f1f1);
9 22 border-color: #AAA;
10   - color: #333;
  23 + text-decoration: none;
  24 + @include linear-gradient(#fAfAfA, #f1f1f1);
11 25 }
12 26  
13   - &.btn-primary {
14   - background: #2a79A3;
15   - @include linear-gradient(#47A7b7, #2585b5);
16   - border-color: #2A79A3;
17   - color: #fff;
18   - text-shadow: 0 1px 1px #268;
19   - &:hover {
20   - background: $primary_color;
21   - color: #fff;
22   - }
  27 + &.focus,
  28 + &:focus {
  29 + text-decoration: none;
  30 + @include box-shadow(inset 0 2px 4px rgba(0,0,0,.15));
  31 + }
23 32  
24   - &.disabled {
25   - color: #fff;
26   - background: $primary_color;
27   - }
  33 + &.active,
  34 + &:active {
  35 + background-image: none;
  36 + outline: 0;
  37 + text-decoration: none;
  38 + @include box-shadow(inset 0 2px 4px rgba(0,0,0,.15));
28 39 }
29 40  
30   - &.btn-info {
31   - background: #5aB9C3;
32   - border-color: $primary_color;
33   - color: #fff;
34   - text-shadow: 0 1px 1px #268;
35   - &:hover {
36   - background: $primary_color;
37   - color: #fff;
38   - }
  41 + &.disabled,
  42 + &[disabled] {
  43 + cursor: default;
  44 + background-image: none;
  45 + @include opacity(65);
  46 + @include box-shadow(none);
  47 + }
39 48  
40   - &.disabled {
41   - color: #fff;
42   - background: $primary_color;
  49 + &.btn-primary {
  50 + color: #FFF;
  51 + border-color: #189;
  52 + text-shadow: 0 1px 1px #189;
  53 + @include linear-gradient(#4AC, #289);
  54 +
  55 + &.hover,
  56 + &:hover,
  57 + &.disabled,
  58 + &[disabled] {
  59 + color: #FFF;
  60 + background: #389;
43 61 }
44 62 }
45 63  
46 64 &.btn-success {
47   - &:hover {
48   - background: #51a351;
  65 + color: #FFF;
  66 + border-color: #1A1;
  67 + text-shadow: 0 1px 1px #FFF;
  68 + text-shadow: 0 1px 1px #181;
  69 + @include linear-gradient(#62C452, #51a351);
  70 +
  71 +
  72 + &.hover,
  73 + &:hover,
  74 + &.disabled,
  75 + &[disabled] {
  76 + color: #FFF;
  77 + background: #2A2;
49 78 }
  79 + }
  80 +
  81 + &.btn-danger {
  82 + color: #FFF;
  83 + text-shadow: 0 1px 1px #811;
  84 + border-color: #BD362F;
  85 + @include linear-gradient(#EE5F5B, #BD362F);
50 86  
51   - &.disabled {
52   - color: #fff;
53   - background: #2b2;
  87 +
  88 + &.hover,
  89 + &:hover,
  90 + &.disabled,
  91 + &[disabled] {
  92 + color: #FFF;
  93 + background: #A22;
54 94 }
55 95 }
56 96  
  97 + &.btn-new {
  98 + @extend .btn-success;
  99 + }
  100 +
57 101 &.btn-create {
58 102 @extend .wide;
59 103 @extend .btn-success;
... ... @@ -67,12 +111,6 @@
67 111 &.btn-close,
68 112 &.btn-remove {
69 113 @extend .btn-danger;
70   - border-color: #BD362F;
71   -
72   - &:hover {
73   - color: #fff;
74   - background: #EE4E49;
75   - }
76 114 }
77 115  
78 116 &.btn-cancel {
... ... @@ -84,13 +122,9 @@
84 122 padding-right: 20px;
85 123 }
86 124  
87   - &.small {
88   - @extend .btn-small;
89   - }
90   -
91   - &.active {
92   - border-color: #aaa;
93   - background-color: #ccc;
  125 + &.btn-small {
  126 + padding: 2px 10px;
  127 + font-size: 12px;
94 128 }
95 129  
96 130 &.btn-tiny {
... ... @@ -104,9 +138,4 @@
104 138 margin-right: 7px;
105 139 float: left;
106 140 }
107   -
108   - &.padded {
109   - margin-right: 3px;
110   - padding: 4px 10px 4px;
111   - }
112 141 }
... ...
app/assets/stylesheets/gitlab_bootstrap/common.scss
... ... @@ -48,7 +48,13 @@
48 48 line-height: 36px;
49 49 }
50 50  
51   -p.slead { color: #456; font-size: 16px; margin-bottom: 12px; font-weight: 200; line-height: 24px; }
  51 +.slead {
  52 + color: #666;
  53 + font-size: 14px;
  54 + margin-bottom: 12px;
  55 + font-weight: normal;
  56 + line-height: 24px;
  57 +}
52 58  
53 59 /** FORMS **/
54 60 input[type='search'].search-text-input {
... ... @@ -66,7 +72,7 @@ input[type=&#39;text&#39;].danger {
66 72 text-shadow: 0 1px 1px #fff
67 73 }
68 74  
69   -fieldset legend { font-size: 17px; }
  75 +fieldset legend { font-size: 15px; }
70 76  
71 77 .tab-content {
72 78 overflow: visible;
... ... @@ -90,3 +96,11 @@ pre.well-pre {
90 96 border-radius: 0;
91 97 color: #555;
92 98 }
  99 +
  100 +.input-append .btn.active, .input-prepend .btn.active {
  101 + background: #CCC;
  102 + border-color: #BBB;
  103 + text-shadow: 0 1px 1px #fff;
  104 + font-weight: bold;
  105 + @include box-shadow(inset 0 2px 4px rgba(0,0,0,.15));
  106 +}
... ...
app/assets/stylesheets/gitlab_bootstrap/files.scss
... ... @@ -3,18 +3,18 @@
3 3 *
4 4 */
5 5 .file-holder {
6   - border: 1px solid #BBB;
  6 + border: 1px solid #CCC;
7 7 margin-bottom: 1em;
8   - @include solid-shade;
9 8  
10 9 .file-title {
11 10 border-bottom: 1px solid #bbb;
12 11 @include bg-dark-gray-gradient;
  12 + text-shadow: 0 1px 1px #fff;
13 13 margin: 0;
14 14 font-weight: normal;
15 15 font-weight: bold;
16 16 text-align: left;
17   - color: #666;
  17 + color: $style_color;
18 18 padding: 9px 10px;
19 19 height: 18px;
20 20  
... ...
app/assets/stylesheets/gitlab_bootstrap/forms.scss 0 → 100644
... ... @@ -0,0 +1,29 @@
  1 +form {
  2 + @extend .form-horizontal;
  3 +
  4 + label {
  5 + @extend .control-label;
  6 + }
  7 +}
  8 +
  9 +input {
  10 + &.input-xpadding {
  11 + padding: 6px 10px;
  12 + }
  13 +}
  14 +
  15 +.control-group {
  16 + .control-label {
  17 + padding-top: 6px;
  18 + }
  19 + .controls {
  20 + input, textarea {
  21 + padding: 6px 10px;
  22 + }
  23 +
  24 + input[type="radio"], input[type="checkbox"] {
  25 + margin-top: 6px;
  26 + }
  27 + }
  28 +}
  29 +
... ...
app/assets/stylesheets/gitlab_bootstrap/lists.scss
... ... @@ -6,7 +6,6 @@
6 6 margin: 0;
7 7 list-style: none;
8 8 li {
9   - background-color: #FFF;
10 9 padding: 10px;
11 10 min-height: 20px;
12 11 border-bottom: 1px solid #eee;
... ... @@ -84,4 +83,13 @@ ul.bordered-list {
84 83 a { color: #777; }
85 84 }
86 85 }
  86 +
  87 + &.top-list {
  88 + li:first-child {
  89 + padding-top: 0;
  90 + h4, h5 {
  91 + margin-top: 0;
  92 + }
  93 + }
  94 + }
87 95 }
... ...
app/assets/stylesheets/gitlab_bootstrap/mixins.scss
... ... @@ -90,7 +90,6 @@
90 90 @mixin page-title {
91 91 color: $style_color;
92 92 font-size: 20px;
93   - font-weight: normal;
94 93 line-height: 1.5;
95 94 margin-top: 0px;
96 95 margin-bottom: 15px;
... ...
app/assets/stylesheets/gitlab_bootstrap/nav.scss
... ... @@ -10,6 +10,7 @@
10 10 > li > a {
11 11 @include border-radius(0);
12 12 }
  13 +
13 14 &.nav-stacked {
14 15 > li > a {
15 16 border-left: 4px solid #EEE;
... ... @@ -30,6 +31,12 @@
30 31 }
31 32 }
32 33 }
  34 +
  35 + &.nav-pills-small {
  36 + > li > a {
  37 + padding: 8px 12px;
  38 + }
  39 + }
33 40 }
34 41  
35 42 .nav-pills > .active > a > i[class^="icon-"] { background: inherit; }
... ...
app/assets/stylesheets/gitlab_bootstrap/tables.scss
1 1 table {
2 2 @extend .table;
3 3 @extend .table-striped;
4   - @include solid-shade;
5   - border: 1px solid #bbb;
  4 + border: 1px solid #CCC;
6 5 width: 100%;
7 6  
8 7 &.low {
... ... @@ -20,7 +19,7 @@ table {
20 19 th {
21 20 font-weight: bold;
22 21 vertical-align: middle;
23   - border-bottom: 1px solid #bbb;
  22 + border-bottom: 1px solid #CCC;
24 23 text-shadow: 0 1px 1px #fff;
25 24 @include bg-dark-gray-gradient;
26 25  
... ... @@ -46,11 +45,11 @@ table {
46 45 }
47 46  
48 47 &:first-child {
49   - border-left: 1px solid #bbb;
  48 + border-left: 1px solid #CCC;
50 49 }
51 50  
52 51 &:last-child {
53   - border-right: 1px solid #bbb;
  52 + border-right: 1px solid #CCC;
54 53 }
55 54 }
56 55  
... ...
app/assets/stylesheets/gitlab_bootstrap/typography.scss
... ... @@ -2,6 +2,10 @@
2 2 * Headers
3 3 *
4 4 */
  5 +h1, h2, h3, h4, h5, h6 {
  6 + font-weight: 500;
  7 + line-height: 1.1;
  8 +}
5 9  
6 10 h1.page-title {
7 11 @include page-title;
... ... @@ -48,13 +52,6 @@ a {
48 52 text-decoration: underline;
49 53 }
50 54  
51   - &.btn {
52   - color: $style_color;
53   - &:hover {
54   - color: $style_color;
55   - }
56   - }
57   -
58 55 &.dark {
59 56 color: $style_color;
60 57 }
... ...
app/assets/stylesheets/sections/commits.scss
... ... @@ -421,8 +421,8 @@
421 421  
422 422 .commits-compare-switch{
423 423 background: url("switch_icon.png") no-repeat center center;
424   - width: 16px;
425   - height: 18px;
  424 + width: 22px;
  425 + height: 22px;
426 426 text-indent: -9999px;
427 427 float: left;
428 428 margin-right: 9px;
... ... @@ -471,3 +471,7 @@ li.commit {
471 471 }
472 472 }
473 473 }
  474 +
  475 +.commit-breadcrumb {
  476 + padding: 0;
  477 +}
... ...
app/assets/stylesheets/sections/issues.scss
... ... @@ -44,7 +44,7 @@ input.check_all_issues {
44 44 margin: 0;
45 45 margin-right: 10px;
46 46 position: relative;
47   - top: 8px;
  47 + top: 10px;
48 48 height: 22px;
49 49 }
50 50  
... ... @@ -52,6 +52,10 @@ input.check_all_issues {
52 52 .title {
53 53 height: 40px;
54 54 }
  55 +
  56 + form {
  57 + margin: 0;
  58 + }
55 59 }
56 60  
57 61 .btn.close_issue {
... ... @@ -88,14 +92,11 @@ input.check_all_issues {
88 92 }
89 93  
90 94 .update_selected_issues {
91   - position: relative;
92   - top:5px;
93 95 margin-left: 4px;
94   - float: left;
95 96 }
96 97  
97 98 .update_issues_text {
98   - padding: 3px;
  99 + padding: 5px;
99 100 line-height: 28px;
100 101 float: left;
101 102 color: #479;
... ...
app/assets/stylesheets/sections/nav.scss
... ... @@ -7,7 +7,7 @@
7 7  
8 8 ul {
9 9 margin: auto;
10   - height: 42px;
  10 + height: 40px;
11 11 overflow: hidden;
12 12 .count {
13 13 font-weight: normal;
... ... @@ -74,7 +74,7 @@
74 74 text-align: center;
75 75 font-weight: normal;
76 76 height: 38px;
77   - line-height: 36px;
  77 + line-height: 34px;
78 78 color: #777;
79 79 text-shadow: 0 1px 1px white;
80 80 padding: 0 10px;
... ...
app/assets/stylesheets/sections/projects.scss
1 1 .new_project,
2 2 .edit_project {
3   - .project_name_holder {
4   - input,
5   - label {
6   - font-size: 16px;
7   - line-height: 20px;
8   - padding: 8px;
9   - }
10   - .btn {
11   - padding: 6px 10px;
12   - margin-left: 10px;
13   - margin-bottom: 8px;
14   - }
15   - }
16   - .adv_settings {
17   - h6 { margin-left: 40px; }
18   - }
19   -
20 3 fieldset.features {
21 4 .control-label {
22 5 font-weight: bold;
... ... @@ -30,6 +13,10 @@
30 13 padding: 4px 7px;
31 14 border: 1px solid #CCC;
32 15 margin-bottom: 20px;
  16 +
  17 + .btn {
  18 + padding: 4px 12px;
  19 + }
33 20 }
34 21  
35 22 .project_clone_holder {
... ... @@ -114,7 +101,7 @@ ul.nav.nav-projects-tabs {
114 101 .public-clone {
115 102 background: #333;
116 103 color: #f5f5f5;
117   - padding: 5px 10px;
  104 + padding: 6px 10px;
118 105 margin: 1px;
119 106 font-weight: normal;
120 107 }
... ...
app/assets/stylesheets/sections/tree.scss
... ... @@ -104,6 +104,8 @@
104 104 }
105 105  
106 106 .tree-btn-group {
  107 + top: 2px;
  108 +
107 109 .btn {
108 110 margin-right: 0px;
109 111 padding: 2px 10px;
... ...
app/assets/stylesheets/themes/ui_mars.scss
... ... @@ -31,8 +31,4 @@
31 31 border-left: 1px solid #666;
32 32 }
33 33 }
34   -
35   - .main-nav {
36   - box-shadow: 0 -1px 0 white inset;
37   - }
38 34 }
... ...
app/contexts/filter_context.rb
... ... @@ -11,8 +11,8 @@ class FilterContext
11 11 end
12 12  
13 13 def apply_filter items
14   - if params[:project_id]
15   - items = items.by_project(params[:project_id])
  14 + if params[:project_id].present?
  15 + items = items.where(project_id: params[:project_id])
16 16 end
17 17  
18 18 if params[:search].present?
... ...
app/contexts/merge_requests_load_context.rb
... ... @@ -2,7 +2,7 @@
2 2 # based on filtering passed via params for @project
3 3 class MergeRequestsLoadContext < BaseContext
4 4 def execute
5   - type = params[:f]
  5 + type = params[:status]
6 6  
7 7 merge_requests = project.merge_requests
8 8  
... ...
app/contexts/search_context.rb
... ... @@ -11,7 +11,7 @@ class SearchContext
11 11 return result unless query.present?
12 12  
13 13 projects = Project.where(id: project_ids)
14   - result[:projects] = projects.search(query).limit(10)
  14 + result[:projects] = projects.search(query).limit(20)
15 15  
16 16 # Search inside singe project
17 17 project = projects.first if projects.length == 1
... ... @@ -19,8 +19,8 @@ class SearchContext
19 19 if params[:search_code].present?
20 20 result[:blobs] = project.repository.search_files(query, params[:repository_ref]) unless project.empty_repo?
21 21 else
22   - result[:merge_requests] = MergeRequest.in_projects(project_ids).search(query).limit(10)
23   - result[:issues] = Issue.where(project_id: project_ids).search(query).limit(10)
  22 + result[:merge_requests] = MergeRequest.in_projects(project_ids).search(query).limit(20)
  23 + result[:issues] = Issue.where(project_id: project_ids).search(query).limit(20)
24 24 result[:wiki_pages] = []
25 25 end
26 26 result
... ...
app/controllers/profiles/groups_controller.rb
... ... @@ -2,7 +2,7 @@ class Profiles::GroupsController &lt; ApplicationController
2 2 layout "profile"
3 3  
4 4 def index
5   - @groups = current_user.authorized_groups.page(params[:page]).per(20)
  5 + @user_groups = current_user.users_groups.page(params[:page]).per(20)
6 6 end
7 7  
8 8 def leave
... ...
app/controllers/projects/branches_controller.rb
... ... @@ -11,6 +11,10 @@ class Projects::BranchesController &lt; Projects::ApplicationController
11 11 @branches = Kaminari.paginate_array(@repository.branches).page(params[:page]).per(30)
12 12 end
13 13  
  14 + def recent
  15 + @branches = @repository.recent_branches
  16 + end
  17 +
14 18 def create
15 19 @repository.add_branch(params[:branch_name], params[:ref])
16 20  
... ...
app/controllers/projects/edit_tree_controller.rb
... ... @@ -10,7 +10,7 @@ class Projects::EditTreeController &lt; Projects::ApplicationController
10 10 before_filter :edit_requirements, only: [:show, :update]
11 11  
12 12 def show
13   - @last_commit = @project.repository.last_commit_for(@ref, @path).sha
  13 + @last_commit = Gitlab::Git::Commit.last_for_path(@project.repository, @ref, @path).sha
14 14 end
15 15  
16 16 def update
... ...
app/controllers/projects/repositories_controller.rb
... ... @@ -4,10 +4,6 @@ class Projects::RepositoriesController &lt; Projects::ApplicationController
4 4 before_filter :authorize_code_access!
5 5 before_filter :require_non_empty_project
6 6  
7   - def show
8   - @activities = @repository.commits_with_refs(20)
9   - end
10   -
11 7 def stats
12 8 @stats = Gitlab::Git::Stats.new(@repository.raw, @repository.root_ref)
13 9 @graph = @stats.graph
... ...
app/controllers/users_groups_controller.rb
... ... @@ -13,7 +13,8 @@ class UsersGroupsController &lt; ApplicationController
13 13 end
14 14  
15 15 def update
16   - # TODO: implement
  16 + @member = @group.users_groups.find(params[:id])
  17 + @member.update_attributes(params[:users_group])
17 18 end
18 19  
19 20 def destroy
... ...
app/helpers/commits_helper.rb
... ... @@ -15,61 +15,9 @@ module CommitsHelper
15 15 commit_person_link(commit, options.merge(source: :committer))
16 16 end
17 17  
18   - def identification_type(line)
19   - if line[0] == "+"
20   - "new"
21   - elsif line[0] == "-"
22   - "old"
23   - else
24   - nil
25   - end
26   - end
27   -
28   - def build_line_anchor(diff, line_new, line_old)
29   - "#{hexdigest(diff.new_path)}_#{line_old}_#{line_new}"
30   - end
31   -
32 18 def each_diff_line(diff, index)
33   - diff_arr = diff.diff.lines.to_a
34   -
35   - line_old = 1
36   - line_new = 1
37   - type = nil
38   -
39   - lines_arr = ::Gitlab::InlineDiff.processing diff_arr
40   - lines_arr.each do |line|
41   - next if line.match(/^\-\-\- \/dev\/null/)
42   - next if line.match(/^\+\+\+ \/dev\/null/)
43   - next if line.match(/^\-\-\- a/)
44   - next if line.match(/^\+\+\+ b/)
45   -
46   - full_line = html_escape(line.gsub(/\n/, ''))
47   - full_line = ::Gitlab::InlineDiff.replace_markers full_line
48   -
49   - if line.match(/^@@ -/)
50   - type = "match"
51   -
52   - line_old = line.match(/\-[0-9]*/)[0].to_i.abs rescue 0
53   - line_new = line.match(/\+[0-9]*/)[0].to_i.abs rescue 0
54   -
55   - next if line_old == 1 && line_new == 1 #top of file
56   - yield(full_line, type, nil, nil, nil)
57   - next
58   - else
59   - type = identification_type(line)
60   - line_code = build_line_anchor(diff, line_new, line_old)
61   - yield(full_line, type, line_code, line_new, line_old)
62   - end
63   -
64   -
65   - if line[0] == "+"
66   - line_new += 1
67   - elsif line[0] == "-"
68   - line_old += 1
69   - else
70   - line_new += 1
71   - line_old += 1
72   - end
  19 + Gitlab::DiffParser.new(diff).each do |full_line, type, line_code, line_new, line_old|
  20 + yield(full_line, type, line_code, line_new, line_old)
73 21 end
74 22 end
75 23  
... ...
app/helpers/dashboard_helper.rb
1 1 module DashboardHelper
2   - def dashboard_filter_path(entity, options={})
  2 + def filter_path(entity, options={})
3 3 exist_opts = {
4 4 status: params[:status],
5 5 project_id: params[:project_id],
... ... @@ -7,12 +7,9 @@ module DashboardHelper
7 7  
8 8 options = exist_opts.merge(options)
9 9  
10   - case entity
11   - when 'issue' then
12   - issues_dashboard_path(options)
13   - when 'merge_request'
14   - merge_requests_dashboard_path(options)
15   - end
  10 + path = request.path
  11 + path << "?#{options.to_param}"
  12 + path
16 13 end
17 14  
18 15 def entities_per_project project, entity
... ...
app/helpers/groups_helper.rb
1 1 module GroupsHelper
2   - def group_filter_path(entity, options={})
3   - exist_opts = {
4   - status: params[:status],
5   - project_id: params[:project_id],
6   - }
7   -
8   - options = exist_opts.merge(options)
9   -
10   - case entity
11   - when 'issue' then
12   - issues_group_path(@group, options)
13   - when 'merge_request'
14   - merge_requests_group_path(@group, options)
15   - end
16   - end
17   -
18 2 def remove_user_from_group_message(group, user)
19 3 "You are going to remove #{user.name} from #{group.name} Group. Are you sure?"
20 4 end
... ...
app/helpers/notifications_helper.rb
1 1 module NotificationsHelper
  2 + def notification_icon(notification)
  3 + if notification.disabled?
  4 + content_tag :i, nil, class: 'icon-circle cred'
  5 + elsif notification.participating?
  6 + content_tag :i, nil, class: 'icon-circle cblue'
  7 + elsif notification.watch?
  8 + content_tag :i, nil, class: 'icon-circle cgreen'
  9 + else
  10 + content_tag :i, nil, class: 'icon-circle-blank cblue'
  11 + end
  12 + end
2 13 end
... ...
app/helpers/tree_helper.rb
... ... @@ -39,12 +39,12 @@ module TreeHelper
39 39 #
40 40 # Returns boolean
41 41 def markup?(filename)
42   - filename.end_with?(*%w(.textile .rdoc .org .creole
43   - .mediawiki .rst .asciidoc .pod))
  42 + filename.downcase.end_with?(*%w(.textile .rdoc .org .creole
  43 + .mediawiki .rst .asciidoc .pod))
44 44 end
45 45  
46 46 def gitlab_markdown?(filename)
47   - filename.end_with?(*%w(.mdown .md .markdown))
  47 + filename.downcase.end_with?(*%w(.mdown .md .markdown))
48 48 end
49 49  
50 50 def plain_text_readme? filename
... ... @@ -57,6 +57,8 @@ module TreeHelper
57 57 end
58 58  
59 59 def allowed_tree_edit?
  60 + return false unless @repository.branch_names.include?(@ref)
  61 +
60 62 if @project.protected_branch? @ref
61 63 can?(current_user, :push_code_to_protected_branches, @project)
62 64 else
... ...
app/models/deprecated/user_team.rb
  1 +# Will be removed in 6.1 with tables
  2 +#
1 3 # == Schema Information
2 4 #
3 5 # Table name: user_teams
... ...
app/models/deprecated/user_team_project_relationship.rb
  1 +# Will be removed in 6.1 with tables
  2 +#
1 3 # == Schema Information
2 4 #
3 5 # Table name: user_team_project_relationships
... ...
app/models/deprecated/user_team_user_relationship.rb
  1 +# Will be removed in 6.1 with tables
  2 +#
1 3 # == Schema Information
2 4 #
3 5 # Table name: user_team_user_relationships
... ...
app/models/merge_request.rb
... ... @@ -149,11 +149,12 @@ class MergeRequest &lt; ActiveRecord::Base
149 149 end
150 150  
151 151 def unmerged_diffs
152   - if for_fork?
153   - diffs = Gitlab::Satellite::MergeAction.new(author, self).diffs_between_satellite
154   - else
155   - diffs = target_project.repository.diffs_between(source_branch, target_branch)
156   - end
  152 + diffs = if for_fork?
  153 + Gitlab::Satellite::MergeAction.new(author, self).diffs_between_satellite
  154 + else
  155 + Gitlab::Git::Diff.between(project.repository, source_branch, target_branch)
  156 + end
  157 +
157 158 diffs ||= []
158 159 diffs
159 160 end
... ...
app/models/note.rb
... ... @@ -50,6 +50,9 @@ class Note &lt; ActiveRecord::Base
50 50 scope :inc_author_project, ->{ includes(:project, :author) }
51 51 scope :inc_author, ->{ includes(:author) }
52 52  
  53 + serialize :st_diff
  54 + before_create :set_diff, if: ->(n) { n.line_code.present? }
  55 +
53 56 def self.create_status_change_note(noteable, project, author, status)
54 57 create({
55 58 noteable: noteable,
... ... @@ -67,28 +70,61 @@ class Note &lt; ActiveRecord::Base
67 70 nil
68 71 end
69 72  
70   - def diff
71   - if noteable.diffs.present?
72   - noteable.diffs.select do |d|
73   - if d.new_path
74   - Digest::SHA1.hexdigest(d.new_path) == diff_file_index
75   - end
76   - end.first
  73 + def find_diff
  74 + return nil unless noteable && noteable.diffs.present?
  75 +
  76 + @diff ||= noteable.diffs.find do |d|
  77 + Digest::SHA1.hexdigest(d.new_path) == diff_file_index if d.new_path
77 78 end
78 79 end
79 80  
  81 + def set_diff
  82 + # First lets find notes with same diff
  83 + # before iterating over all mr diffs
  84 + diff = Note.where(noteable_id: self.noteable_id, noteable_type: self.noteable_type, line_code: self.line_code).last.try(:diff)
  85 + diff ||= find_diff
  86 +
  87 + self.st_diff = diff.to_hash if diff
  88 + end
  89 +
  90 + def diff
  91 + @diff ||= Gitlab::Git::Diff.new(st_diff) if st_diff.respond_to?(:map)
  92 + end
  93 +
  94 + def active?
  95 + # TODO: determine if discussion is outdated
  96 + # according to recent MR diff or not
  97 + true
  98 + end
  99 +
80 100 def diff_file_index
81 101 line_code.split('_')[0]
82 102 end
83 103  
84 104 def diff_file_name
85   - diff.new_path
  105 + diff.new_path if diff
  106 + end
  107 +
  108 + def diff_old_line
  109 + line_code.split('_')[1].to_i
86 110 end
87 111  
88 112 def diff_new_line
89 113 line_code.split('_')[2].to_i
90 114 end
91 115  
  116 + def diff_line
  117 + return @diff_line if @diff_line
  118 +
  119 + if diff
  120 + Gitlab::DiffParser.new(diff).each do |full_line, type, line_code, line_new, line_old|
  121 + @diff_line = full_line if line_code == self.line_code
  122 + end
  123 + end
  124 +
  125 + @diff_line
  126 + end
  127 +
92 128 def discussion_id
93 129 @discussion_id ||= [:discussion, noteable_type.try(:underscore), noteable_id || commit_id, line_code].join("-").to_sym
94 130 end
... ...
app/models/repository.rb
... ... @@ -18,19 +18,25 @@ class Repository
18 18 end
19 19  
20 20 def commit(id = nil)
21   - commit = raw_repository.commit(id)
  21 + commit = Gitlab::Git::Commit.find(raw_repository, id)
22 22 commit = Commit.new(commit) if commit
23 23 commit
24 24 end
25 25  
26 26 def commits(ref, path = nil, limit = nil, offset = nil)
27   - commits = raw_repository.commits(ref, path, limit, offset)
  27 + commits = Gitlab::Git::Commit.where(
  28 + repo: raw_repository,
  29 + ref: ref,
  30 + path: path,
  31 + limit: limit,
  32 + offset: offset,
  33 + )
28 34 commits = Commit.decorate(commits) if commits.present?
29 35 commits
30 36 end
31 37  
32   - def commits_between(target, source)
33   - commits = raw_repository.commits_between(target, source)
  38 + def commits_between(from, to)
  39 + commits = Gitlab::Git::Commit.between(raw_repository, from, to)
34 40 commits = Commit.decorate(commits) if commits.present?
35 41 commits
36 42 end
... ... @@ -43,6 +49,12 @@ class Repository
43 49 tags.find { |tag| tag.name == name }
44 50 end
45 51  
  52 + def recent_branches(limit = 20)
  53 + branches.sort do |a, b|
  54 + a.commit.committed_date <=> b.commit.committed_date
  55 + end[0..limit]
  56 + end
  57 +
46 58 def add_branch(branch_name, ref)
47 59 Rails.cache.delete(cache_key(:branch_names))
48 60  
... ...
app/services/notification_service.rb
... ... @@ -102,19 +102,22 @@ class NotificationService
102 102 # ignore wall messages
103 103 return true unless note.noteable_type.present?
104 104  
  105 + # ignore gitlab service messages
  106 + return true if note.note =~ /\A_Status changed to closed_/
  107 +
105 108 opts = { noteable_type: note.noteable_type, project_id: note.project_id }
106 109  
107 110 if note.commit_id.present?
108 111 opts.merge!(commit_id: note.commit_id)
109   - recipients = [note.commit_author]
110 112 else
111 113 opts.merge!(noteable_id: note.noteable_id)
112   - target = note.noteable
113   - if target.respond_to?(:participants)
114   - recipients = target.participants
115   - else
116   - recipients = []
117   - end
  114 + end
  115 +
  116 + target = note.noteable
  117 + if target.respond_to?(:participants)
  118 + recipients = target.participants
  119 + else
  120 + recipients = note.mentioned_users
118 121 end
119 122  
120 123 # Get users who left comment in thread
... ...
app/views/admin/groups/edit.html.haml
... ... @@ -4,22 +4,22 @@
4 4 - if @group.errors.any?
5 5 .alert.alert-error
6 6 %span= @group.errors.full_messages.first
7   - .clearfix.group_name_holder
  7 + .control-group.group_name_holder
8 8 = f.label :name do
9 9 Group name is
10   - .input
11   - = f.text_field :name, placeholder: "Example Group", class: "xxlarge"
  10 + .controls
  11 + = f.text_field :name, placeholder: "Example Group", class: "input-xxlarge"
12 12  
13   - .clearfix.group-description-holder
  13 + .control-group.group-description-holder
14 14 = f.label :description, "Details"
15   - .input
16   - = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4
  15 + .controls
  16 + = f.text_area :description, maxlength: 250, class: "input-xxlarge js-gfm-input", rows: 4
17 17  
18   - .clearfix.group_name_holder
  18 + .control-group.group_name_holder
19 19 = f.label :path do
20 20 %span.cred Group path is
21   - .input
22   - = f.text_field :path, placeholder: "example-group", class: "xxlarge danger"
  21 + .controls
  22 + = f.text_field :path, placeholder: "example-group", class: "input-xxlarge danger"
23 23 %ul.cred
24 24 %li Changing group path can have unintended side effects.
25 25 %li Renaming group path will rename directory for all related projects
... ...
app/views/admin/groups/index.html.haml
... ... @@ -4,7 +4,7 @@
4 4 allows you to keep projects organized.
5 5 Use groups for uniting related projects.
6 6  
7   - = link_to 'New Group', new_admin_group_path, class: "btn btn-small pull-right"
  7 + = link_to 'New Group', new_admin_group_path, class: "btn btn-new pull-right"
8 8 %br
9 9 = form_tag admin_groups_path, method: :get, class: 'form-inline' do
10 10 = text_field_tag :name, params[:name], class: "span6"
... ...
app/views/admin/groups/new.html.haml
... ... @@ -4,15 +4,15 @@
4 4 - if @group.errors.any?
5 5 .alert.alert-error
6 6 %span= @group.errors.full_messages.first
7   - .clearfix
  7 + .control-group
8 8 = f.label :name do
9 9 Group name is
10   - .input
11   - = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left"
12   - .clearfix.group-description-holder
  10 + .controls
  11 + = f.text_field :name, placeholder: "Ex. OpenSource", class: "input-xxlarge left"
  12 + .control-group.group-description-holder
13 13 = f.label :description, "Details"
14   - .input
15   - = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4
  14 + .controls
  15 + = f.text_area :description, maxlength: 250, class: "input-xxlarge js-gfm-input", rows: 4
16 16  
17 17 .form-actions
18 18 = f.submit 'Create group', class: "btn btn-create"
... ...
app/views/admin/hooks/index.html.haml
... ... @@ -10,10 +10,10 @@
10 10 .alert.alert-error
11 11 - @hook.errors.full_messages.each do |msg|
12 12 %p= msg
13   - .clearfix
  13 + .control-group
14 14 = f.label :url, "URL:"
15   - .input
16   - = f.text_field :url, class: "text_field xxlarge"
  15 + .controls
  16 + = f.text_field :url, class: "text_field input-xxlarge input-xpadding"
17 17 &nbsp;
18 18 = f.submit "Add System Hook", class: "btn btn-create"
19 19 %hr
... ...
app/views/admin/projects/index.html.haml
... ... @@ -38,7 +38,7 @@
38 38 .title
39 39 Projects (#{@projects.total_count})
40 40 .pull-right
41   - = link_to 'New Project', new_project_path, class: "btn btn-small btn-primary wide"
  41 + = link_to 'New Project', new_project_path, class: "btn btn-new"
42 42 %ul.well-list
43 43 - @projects.each do |project|
44 44 %li
... ...
app/views/admin/users/_form.html.haml
... ... @@ -8,28 +8,28 @@
8 8  
9 9 %fieldset
10 10 %legend Account
11   - .clearfix
  11 + .control-group
12 12 = f.label :name
13   - .input
  13 + .controls
14 14 = f.text_field :name, required: true, autocomplete: "off"
15 15 %span.help-inline * required
16   - .clearfix
  16 + .control-group
17 17 = f.label :username
18   - .input
  18 + .controls
19 19 = f.text_field :username, required: true, autocomplete: "off"
20 20 %span.help-inline * required
21   - .clearfix
  21 + .control-group
22 22 = f.label :email
23   - .input
  23 + .controls
24 24 = f.text_field :email, required: true, autocomplete: "off"
25 25 %span.help-inline * required
26 26  
27 27 - if @user.new_record?
28 28 %fieldset
29 29 %legend Password
30   - .clearfix
  30 + .control-group
31 31 = f.label :password
32   - .input
  32 + .controls
33 33 %strong
34 34 A temporary password will be generated and sent to user.
35 35 %br
... ... @@ -37,33 +37,33 @@
37 37 - else
38 38 %fieldset
39 39 %legend Password
40   - .clearfix
  40 + .control-group
41 41 = f.label :password
42   - .input= f.password_field :password, disabled: f.object.force_random_password
43   - .clearfix
  42 + .controls= f.password_field :password, disabled: f.object.force_random_password
  43 + .control-group
44 44 = f.label :password_confirmation
45   - .input= f.password_field :password_confirmation, disabled: f.object.force_random_password
  45 + .controls= f.password_field :password_confirmation, disabled: f.object.force_random_password
46 46  
47 47 %fieldset
48 48 %legend Access
49 49 .row
50 50 .span8
51   - .clearfix
  51 + .control-group
52 52 = f.label :projects_limit
53   - .input= f.number_field :projects_limit
  53 + .controls= f.number_field :projects_limit
54 54  
55   - .clearfix
  55 + .control-group
56 56 = f.label :can_create_group
57   - .input= f.check_box :can_create_group
  57 + .controls= f.check_box :can_create_group
58 58  
59   - .clearfix
  59 + .control-group
60 60 = f.label :can_create_team
61   - .input= f.check_box :can_create_team
  61 + .controls= f.check_box :can_create_team
62 62  
63   - .clearfix
  63 + .control-group
64 64 = f.label :admin do
65 65 %strong.cred Administrator
66   - .input= f.check_box :admin
  66 + .controls= f.check_box :admin
67 67 .span4
68 68 - unless @user.new_record?
69 69 .alert.alert-error
... ... @@ -75,17 +75,17 @@
75 75 = link_to 'Block User', block_admin_user_path(@user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn btn-small btn-remove"
76 76 %fieldset
77 77 %legend Profile
78   - .clearfix
  78 + .control-group
79 79 = f.label :skype
80   - .input= f.text_field :skype
81   - .clearfix
  80 + .controls= f.text_field :skype
  81 + .control-group
82 82 = f.label :linkedin
83   - .input= f.text_field :linkedin
84   - .clearfix
  83 + .controls= f.text_field :linkedin
  84 + .control-group
85 85 = f.label :twitter
86   - .input= f.text_field :twitter
  86 + .controls= f.text_field :twitter
87 87  
88   - .actions
  88 + .form-actions
89 89 - if @user.new_record?
90 90 = f.submit 'Create user', class: "btn btn-create"
91 91 = link_to 'Cancel', admin_users_path, class: "btn btn-cancel"
... ...
app/views/admin/users/index.html.haml
... ... @@ -30,7 +30,7 @@
30 30 .title
31 31 Users (#{@users.total_count})
32 32 .pull-right
33   - = link_to 'New User', new_admin_user_path, class: "btn btn-small wide btn-primary"
  33 + = link_to 'New User', new_admin_user_path, class: "btn btn-new"
34 34 %ul.well-list
35 35 - @users.each do |user|
36 36 %li
... ... @@ -55,4 +55,4 @@
55 55 - else
56 56 = link_to 'Block', block_admin_user_path(user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn btn-small btn-remove"
57 57 = link_to 'Destroy', [:admin, user], confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?", method: :delete, class: "btn btn-small btn-remove"
58   - = paginate @users, theme: "gitlab"
  58 + = paginate @users, theme: "gitlab"
... ...
app/views/dashboard/_filter.html.haml
... ... @@ -1,27 +0,0 @@
1   -= form_tag dashboard_filter_path(entity), method: 'get' do
2   - %fieldset
3   - %ul.nav.nav-pills.nav-stacked
4   - %li{class: ("active" if !params[:status])}
5   - = link_to dashboard_filter_path(entity, status: nil) do
6   - Open
7   - %li{class: ("active" if params[:status] == 'closed')}
8   - = link_to dashboard_filter_path(entity, status: 'closed') do
9   - Closed
10   - %li{class: ("active" if params[:status] == 'all')}
11   - = link_to dashboard_filter_path(entity, status: 'all') do
12   - All
13   -
14   - %fieldset
15   - %legend Projects:
16   - %ul.nav.nav-pills.nav-stacked
17   - - @projects.each do |project|
18   - - unless entities_per_project(project, entity).zero?
19   - %li{class: ("active" if params[:project_id] == project.id.to_s)}
20   - = link_to dashboard_filter_path(entity, project_id: project.id) do
21   - = project.name_with_namespace
22   - %small.pull-right= entities_per_project(project, entity)
23   -
24   - %fieldset
25   - %hr
26   - = link_to "Reset", dashboard_filter_path(entity), class: 'btn pull-right'
27   -
app/views/dashboard/issues.html.haml
1 1 %h3.page-title
2   - Issues
3   - %span.light
4   - &ndash;
5   - Assigned to you
  2 + Issues assigned to me
6 3 %span.pull-right #{@issues.total_count} issues
7 4  
  5 +%p.light
  6 + For all issues you should visit project issues page. Or you can use search panel to find specific issue
  7 +%hr
  8 +
8 9 .row
9 10 .span3
10   - = render 'filter', entity: 'issue'
  11 + = render 'shared/filter', entity: 'issue'
11 12 .span9
12   - - if @issues.any?
13   - - @issues.group_by(&:project).each do |group|
14   - %div.ui-box
15   - - project = group[0]
16   - .title
17   - = link_to_project project
18   - &nbsp;
19   - %i.icon-angle-right
20   - &nbsp;
21   - = link_to 'issues', project_issues_path(project)
22   -
23   - %ul.well-list.issues-list
24   - - group[1].each do |issue|
25   - = render 'projects/issues/issue', issue: issue
26   - %hr
27   - = paginate @issues, theme: "gitlab"
28   - - else
29   - %p.nothing_here_message Nothing to show here
  13 + = render 'shared/issues'
... ...
app/views/dashboard/merge_requests.html.haml
1 1 %h3.page-title
2 2 Merge Requests
3   - %span.light
4   - &ndash;
5   - Authored by or assigned to you
6 3 %span.pull-right #{@merge_requests.total_count} merge requests
7 4  
  5 +
  6 +%p.light
  7 + Only merge requests authored or assigned to you are listed here.
  8 +%hr
8 9 .row
9 10 .span3
10   - = render 'filter', entity: 'merge_request'
  11 + = render 'shared/filter', entity: 'merge_request'
11 12 .span9
12 13 = render 'shared/merge_requests'
... ...
app/views/dashboard/projects.html.haml
  1 +%h3.page-title My Projects
  2 +%p.light
  3 + All projects you have access to are listed here. Public projects are not included here unless you have membership in it
  4 +%hr
1 5 .row
2 6 .span3
3 7 %ul.nav.nav-pills.nav-stacked
... ... @@ -32,7 +36,7 @@
32 36 = label.name
33 37  
34 38 .span9
35   - %ul.bordered-list.my-projects
  39 + %ul.bordered-list.my-projects.top-list
36 40 - @projects.each do |project|
37 41 %li
38 42 %h4.project-title
... ...
app/views/groups/_new_group_member.html.haml
1 1 = form_for @users_group, url: group_users_groups_path(@group) do |f|
2 2 %fieldset
3   - %legend= "New Group member(s) for #{@group.name}"
  3 + %legend
  4 + New member(s) for
  5 + %strong #{@group.name}
  6 + group
4 7  
5   - %h6 1. Choose users you want in the group
6   - .clearfix
  8 + %p 1. Choose users you want in the group
  9 + .control-group
7 10 = f.label :user_ids, "People"
8   - .input= users_select_tag(:user_ids, multiple: true, class: 'input-large')
  11 + .controls= users_select_tag(:user_ids, multiple: true, class: 'input-large')
9 12  
10   - %h6 2. Set access level for them
11   - .clearfix
  13 + %p 2. Set access level for them
  14 + .control-group
12 15 = f.label :group_access, "Group Access"
13   - .input= select_tag :group_access, options_for_select(UsersGroup.group_access_roles, @users_group.group_access), class: "project-access-select chosen"
  16 + .controls= select_tag :group_access, options_for_select(UsersGroup.group_access_roles, @users_group.group_access), class: "project-access-select chosen"
14 17  
15 18 .form-actions
16 19 = f.submit 'Add users into group', class: "btn btn-create"
... ...
app/views/groups/edit.html.haml
... ... @@ -20,22 +20,22 @@
20 20 .ui-box
21 21 .title
22 22 %strong= @group.name
23   - Group Settings:
  23 + group settings:
24 24 %div.form-holder
25 25 = form_for @group do |f|
26 26 - if @group.errors.any?
27 27 .alert.alert-error
28 28 %span= @group.errors.full_messages.first
29   - .clearfix
  29 + .control-group
30 30 = f.label :name do
31 31 Group name is
32   - .input
33   - = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left"
  32 + .controls
  33 + = f.text_field :name, placeholder: "Ex. OpenSource", class: "input-xxlarge left"
34 34  
35   - .clearfix.group-description-holder
  35 + .control-group.group-description-holder
36 36 = f.label :description, "Details"
37   - .input
38   - = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4
  37 + .controls
  38 + = f.text_area :description, maxlength: 250, class: "input-xxlarge js-gfm-input", rows: 4
39 39  
40 40 .form-actions
41 41 = f.submit 'Save group', class: "btn btn-save"
... ... @@ -44,7 +44,7 @@
44 44 .ui-box
45 45 .title
46 46 %strong= @group.name
47   - Projects:
  47 + projects:
48 48 - if can? current_user, :manage_group, @group
49 49 %span.pull-right
50 50 = link_to new_project_path(namespace_id: @group.id), class: "btn btn-tiny" do
... ... @@ -85,4 +85,4 @@
85 85 %p
86 86 %strong Removed group can not be restored!
87 87  
88   - = link_to 'Remove Group', @group, confirm: 'Removed group can not be restored! Are you sure?', method: :delete, class: "btn btn-remove btn-small"
  88 + = link_to 'Remove Group', @group, confirm: 'Removed group can not be restored! Are you sure?', method: :delete, class: "btn btn-remove"
... ...
app/views/groups/issues.html.haml
... ... @@ -6,18 +6,6 @@
6 6 %hr
7 7 .row
8 8 .span3
9   - = render 'filter', entity: 'issue'
  9 + = render 'shared/filter', entity: 'issue'
10 10 .span9
11   - - if @issues.any?
12   - - @issues.group_by(&:project).each do |group|
13   - %div.ui-box
14   - - project = group[0]
15   - .title
16   - = link_to_project project
17   - %ul.well-list.issues-list
18   - - group[1].each do |issue|
19   - = render 'projects/issues/issue', issue: issue
20   - %hr
21   - = paginate @issues, theme: "gitlab"
22   - - else
23   - %p.nothing_here_message Nothing to show here
  11 + = render 'shared/issues'
... ...
app/views/groups/members.html.haml
  1 +%h3.page-title
  2 + Group members
  3 +%p.light
  4 + Members of group have access to all group projects.
  5 +%hr
1 6 - can_manage_group = current_user.can? :manage_group, @group
2   -.row
3   - .span6
4   - - if can_manage_group
5   - = render "new_group_member"
6   - - else
7   - .light-well
8   - %h4.nothing_here_message
9   - Only group owners can manage group members
10   - .span6
11   - .ui-box
12   - .title
13   - %strong #{@group.name}
14   - Group Members
15   - %small
16   - (#{@members.count})
17   - %ul.well-list
18   - - @members.each do |member|
19   - = render 'users_groups/users_group', member: member, show_controls: can_manage_group
20   - %p.light
21   - Group members get access to all projects in this group
  7 +.ui-box
  8 + .title
  9 + %strong #{@group.name}
  10 + group members
  11 + %small
  12 + (#{@members.count})
  13 + %ul.well-list
  14 + - @members.each do |member|
  15 + = render 'users_groups/users_group', member: member, show_controls: can_manage_group
  16 +- if can_manage_group
  17 + = render "new_group_member"
... ...
app/views/groups/merge_requests.html.haml
... ... @@ -6,6 +6,6 @@
6 6 %hr
7 7 .row
8 8 .span3
9   - = render 'filter', entity: 'merge_request'
  9 + = render 'shared/filter', entity: 'merge_request'
10 10 .span9
11 11 = render 'shared/merge_requests'
... ...
app/views/groups/new.html.haml
... ... @@ -2,19 +2,19 @@
2 2 - if @group.errors.any?
3 3 .alert.alert-error
4 4 %span= @group.errors.full_messages.first
5   - .clearfix
  5 + .control-group
6 6 = f.label :name do
7 7 Group name is
8   - .input
9   - = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left"
  8 + .controls
  9 + = f.text_field :name, placeholder: "Ex. OpenSource", class: "input-xxlarge left"
10 10  
11   - .clearfix.group-description-holder
  11 + .control-group.group-description-holder
12 12 = f.label :description, "Details"
13   - .input
14   - = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4
  13 + .controls
  14 + = f.text_area :description, maxlength: 250, class: "input-xxlarge js-gfm-input", rows: 4
15 15  
16   - .clearfix
17   - .input
  16 + .control-group
  17 + .controls
18 18 %ul
19 19 %li Group is kind of directory for several projects
20 20 %li All created groups are private
... ...
app/views/help/index.html.haml
... ... @@ -8,8 +8,6 @@
8 8 %br
9 9 Fast, secure and stable solution based on Ruby on Rails.
10 10  
11   -%br
12   -
13 11 .row
14 12 .span4
15 13 .ui-box
... ...
app/views/notify/new_user_email.html.haml
... ... @@ -4,7 +4,7 @@
4 4 - if Gitlab.config.gitlab.signup_enabled
5 5 Your account has been created successfully.
6 6 - else
7   - The Administrator created an account for you. Now you are a member of company GitLab application.
  7 + The Administrator created an account for you. Now you are a member of the company GitLab application.
8 8 %p
9 9 login..........................................
10 10 %code= @user['email']
... ...
app/views/notify/new_user_email.text.erb
1 1 Hi <%= @user.name %>!
2 2  
3   -The Administrator created an account for you. Now you are a member of company GitLab application.
  3 +The Administrator created an account for you. Now you are a member of the company GitLab application.
4 4  
5 5 login.................. <%= @user.email %>
6 6 <% if @user.created_by_id %>
... ...
app/views/profiles/account.html.haml
  1 +%h3.page-title
  2 + Account settings
  3 +%p.light
  4 + You can change password, username, private token here.
  5 + - if current_user.ldap_user?
  6 + Some options are unavailable for LDAP accounts
  7 +%hr
1 8 - unless current_user.ldap_user?
2 9 - if Gitlab.config.omniauth.enabled
3 10 %fieldset
... ... @@ -20,15 +27,15 @@
20 27 - @user.errors.full_messages.each do |msg|
21 28 %li= msg
22 29  
23   - .clearfix
  30 + .control-group
24 31 = f.label :password
25   - .input= f.password_field :password, required: true
26   - .clearfix
  32 + .controls= f.password_field :password, required: true
  33 + .control-group
27 34 = f.label :password_confirmation
28   - .input
  35 + .controls
29 36 = f.password_field :password_confirmation, required: true
30   - .clearfix
31   - .input
  37 + .control-group
  38 + .controls
32 39 = f.submit 'Save password', class: "btn btn-save"
33 40  
34 41  
... ... @@ -47,7 +54,7 @@
47 54 It can be used for atom feed or API
48 55 %p.cgray
49 56 - if current_user.private_token
50   - = text_field_tag "token", current_user.private_token, class: "xxlarge large_text"
  57 + = text_field_tag "token", current_user.private_token, class: "input-xxlarge large_text input-xpadding"
51 58 = f.submit 'Reset', confirm: "Are you sure?", class: "btn btn-primary btn-build-token"
52 59 - else
53 60 %span You don`t have one yet. Click generate to fix it.
... ... @@ -63,7 +70,7 @@
63 70 = form_for @user, url: update_username_profile_path, method: :put, remote: true do |f|
64 71 .padded
65 72 = f.label :username
66   - .input
  73 + .controls
67 74 = f.text_field :username, required: true
68 75 &nbsp;
69 76 %span.loading-gif.hide= image_tag "ajax_loader.gif"
... ... @@ -76,7 +83,7 @@
76 83 %ul.cred
77 84 %li It will change web url for personal projects.
78 85 %li It will change the git path to repositories for personal projects.
79   - .input
  86 + .controls
80 87 = f.submit 'Save username', class: "btn btn-save"
81 88  
82 89 - if gitlab_config.signup_enabled
... ...
app/views/profiles/design.html.haml
  1 +%h3.page-title
  2 + My appearance settings
  3 +%p.light
  4 + Appearance settings saved to your profile and available across all devices
  5 +%hr
  6 +
1 7 = form_for @user, url: profile_path, remote: true, method: :put do |f|
2 8 %fieldset.application-theme
3 9 %legend
... ...
app/views/profiles/groups/index.html.haml
  1 +%h3.page-title
  2 + Group membership
  3 + - if current_user.can_create_group?
  4 + %span.pull-right
  5 + = link_to new_group_path, class: "btn btn-new" do
  6 + %i.icon-plus
  7 + New Group
  8 +%p.light
  9 + Members of group have access to all group projects.
  10 +%hr
1 11 .ui-box
2 12 .title
3 13 %strong Groups
4   - (#{@groups.count})
5   - - if current_user.can_create_group?
6   - %span.pull-right
7   - = link_to new_group_path, class: "btn btn-small btn-primary" do
8   - %i.icon-plus
9   - New Group
  14 + (#{@user_groups.count})
10 15 %ul.well-list
11   - - @groups.each do |group|
  16 + - @user_groups.each do |user_group|
  17 + - group = user_group.group
12 18 %li
13 19 .pull-right
14 20 - if can?(current_user, :manage_group, group)
... ... @@ -23,4 +29,7 @@
23 29 = link_to group, class: 'group-name' do
24 30 = group.name
25 31  
26   -= paginate @groups
  32 + as #{user_group.human_access}
  33 +
  34 +
  35 += paginate @user_groups
... ...
app/views/profiles/history.html.haml
  1 +%h3.page-title
  2 + Account history
  3 +%p.light
  4 + You can see all events authored by your account here
  5 +%hr
1 6 .profile_history
2 7 = render @events
3 8 %hr
... ...
app/views/profiles/keys/_form.html.haml
... ... @@ -6,18 +6,18 @@
6 6 - @key.errors.full_messages.each do |msg|
7 7 %li= msg
8 8  
9   - .clearfix
  9 + .control-group
10 10 = f.label :title
11   - .input= f.text_field :title
12   - .clearfix
  11 + .controls= f.text_field :title, class: "input-xlarge"
  12 + .control-group
13 13 = f.label :key
14   - .input
  14 + .controls
15 15 %p.light
16 16 Paste your public key here. Read more about how generate it #{link_to "here", help_ssh_path}
17   - = f.text_area :key, class: [:xxlarge, :thin_area]
  17 + = f.text_area :key, class: "input-xxlarge thin_area"
18 18  
19 19  
20   - .actions
  20 + .form-actions
21 21 = f.submit 'Add key', class: "btn btn-create"
22 22 = link_to "Cancel", profile_keys_path, class: "btn btn-cancel"
23 23  
... ...
app/views/profiles/keys/index.html.haml
  1 +%h3.page-title
  2 + My SSH keys
  3 + .pull-right
  4 + = link_to "Add SSH Key", new_profile_key_path, class: "btn btn-new"
1 5 %p.light
2 6 SSH key allows you to establish a secure connection between your computer and GitLab
3   -%p.light
  7 + %br
4 8 Before you can add ssh key you need to
5 9 = link_to "generate it", help_ssh_path
6   -
  10 +%hr
7 11  
8 12  
9 13 .ui-box
10 14 .title
11 15 SSH Keys (#{@keys.count})
12   - .pull-right
13   - = link_to "Add SSH Key", new_profile_key_path, class: "btn btn-small btn-primary"
14 16 %ul.well-list#keys-table
15 17 = render @keys
16 18 - if @keys.blank?
... ...
app/views/profiles/notifications/_settings.html.haml
... ... @@ -2,6 +2,8 @@
2 2 .row
3 3 .span4
4 4 %span
  5 + = notification_icon(notification)
  6 +
5 7 - if membership.kind_of? UsersGroup
6 8 = link_to membership.group.name, membership.group
7 9 - else
... ...
app/views/profiles/notifications/show.html.haml
1   -%h3.page-title Setup your notification level
2   -
3   -%p.light
4   - %strong Disabled
5   - &ndash; You will not get any notifications via email
  1 +%h3.page-title
  2 + Notifications settings
6 3 %p.light
7   - %strong Participating
8   - &ndash; You will receive only notifications from related resources(ex. from assigned issue or your commit)
9   -%p.light
10   - %strong Watch
11   - &ndash; You will receive all notifications from projects in which you participate
  4 + Application use email specified in your profile for notifications
12 5 %hr
  6 +.alert.alert-info
  7 + %p
  8 + %i.icon-circle.cred
  9 + %strong Disabled
  10 + &ndash; You will not get any notifications via email
  11 + %p
  12 + %i.icon-circle.cblue
  13 + %strong Participating
  14 + &ndash; You will receive only notifications from related resources(ex. from assigned issue or your commit)
  15 + %p
  16 + %i.icon-circle.cgreen
  17 + %strong Watch
  18 + &ndash; You will receive all notifications from projects in which you participate
13 19  
14 20 .row
15 21 .span4
16   - %h5 Global setting
  22 + %h4
  23 + = notification_icon(@notification)
  24 + Global setting
17 25 .span7
18 26 = form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications' do
19 27 = hidden_field_tag :notification_type, 'global'
... ... @@ -30,20 +38,21 @@
30 38 = radio_button_tag :notification_level, Notification::N_WATCH, @notification.watch?, class: 'trigger-submit'
31 39 %span Watch
32 40  
33   -%hr
  41 +%br
34 42 = link_to '#', class: 'js-toggle-visibility-link' do
35   - %h6.btn.btn-tiny
  43 + %span.btn.btn-tiny
36 44 %i.icon-chevron-down
37 45 %span Advanced notifications settings
38 46 .js-toggle-visibility-container.hide
39   - %h5 Groups:
40   - %ul.well-list
  47 + %hr
  48 + %h4 Groups:
  49 + %ul.bordered-list
41 50 - @users_groups.each do |users_group|
42 51 - notification = Notification.new(users_group)
43 52 = render 'settings', type: 'group', membership: users_group, notification: notification
44 53  
45   - %h5 Projects:
46   - %ul.well-list
  54 + %h4 Projects:
  55 + %ul.bordered-list
47 56 - @users_projects.each do |users_project|
48 57 - notification = Notification.new(users_project)
49 58 = render 'settings', type: 'project', membership: users_project, notification: notification
... ...
app/views/profiles/passwords/new.html.haml
... ... @@ -10,13 +10,13 @@
10 10 - @user.errors.full_messages.each do |msg|
11 11 %li= msg
12 12  
13   - .clearfix
  13 + .control-group
14 14 = f.label :password
15   - .input= f.password_field :password, required: true
16   - .clearfix
  15 + .controls= f.password_field :password, required: true
  16 + .control-group
17 17 = f.label :password_confirmation
18   - .input
  18 + .controls
19 19 = f.password_field :password_confirmation, required: true
20   - .clearfix
21   - .input
  20 + .control-group
  21 + .controls
22 22 = f.submit 'Set new password', class: "btn btn-create"
... ...
app/views/profiles/show.html.haml
... ... @@ -87,4 +87,4 @@
87 87 = link_to "Add Public Key", new_profile_key_path, class: "btn btn-small"
88 88  
89 89 .form-actions
90   - = f.submit 'Save', class: "btn btn-save"
  90 + = f.submit 'Save changes', class: "btn btn-save"
... ...
app/views/projects/blame/_head.html.haml
... ... @@ -1,2 +0,0 @@
1   -%div.tree-ref-holder
2   - = render 'shared/ref_switcher', destination: 'tree', path: params[:path]
app/views/projects/blame/show.html.haml
1   -= render "head"
  1 +%h3.page-title Blame view
2 2  
3 3 #tree-holder.tree-holder
4   - %ul.breadcrumb
5   - %li
6   - %i.icon-angle-right
7   - = link_to project_tree_path(@project, @ref) do
8   - = @project.name
9   - - tree_breadcrumbs(@tree, 6) do |link|
10   - \/
11   - %li= link
12   - .clear
13   -
14 4 .file-holder
15 5 .file-title
16 6 %i.icon-file
17 7 %span.file_name
18   - = @blob.name
  8 + = @path
19 9 %small= number_to_human_size @blob.size
20 10 %span.options= render "projects/blob/actions"
21 11 .file-content.blame
... ...
app/views/projects/blob/_actions.html.haml
1 1 .btn-group.tree-btn-group
2 2 -# only show edit link for text files
3 3 - if @blob.text?
4   - = link_to "edit", project_edit_tree_path(@project, @id), class: "btn btn-tiny", disabled: !allowed_tree_edit?
5   - = link_to "raw", project_raw_path(@project, @id), class: "btn btn-tiny", target: "_blank"
  4 + = link_to "edit", project_edit_tree_path(@project, @id), class: "btn btn-small", disabled: !allowed_tree_edit?
  5 + = link_to "raw", project_raw_path(@project, @id), class: "btn btn-small", target: "_blank"
6 6 -# only show normal/blame view links for text files
7 7 - if @blob.text?
8 8 - if current_page? project_blame_path(@project, @id)
9   - = link_to "normal view", project_blob_path(@project, @id), class: "btn btn-tiny"
  9 + = link_to "normal view", project_blob_path(@project, @id), class: "btn btn-small"
10 10 - else
11   - = link_to "blame", project_blame_path(@project, @id), class: "btn btn-tiny" unless @blob.empty?
12   - = link_to "history", project_commits_path(@project, @id), class: "btn btn-tiny"
  11 + = link_to "blame", project_blame_path(@project, @id), class: "btn btn-small" unless @blob.empty?
  12 + = link_to "history", project_commits_path(@project, @id), class: "btn btn-small"
... ...
app/views/projects/branches/_filter.html.haml 0 → 100644
... ... @@ -0,0 +1,17 @@
  1 +%ul.nav.nav-pills.nav-stacked
  2 + = nav_link(path: 'branches#recent') do
  3 + = link_to 'Recent', recent_project_branches_path(@project)
  4 + = nav_link(path: 'protected_branches#index') do
  5 + = link_to project_protected_branches_path(@project) do
  6 + Protected
  7 + %i.icon-lock
  8 + = nav_link(path: 'branches#index') do
  9 + = link_to 'All branches', project_branches_path(@project)
  10 +
  11 +
  12 +%hr
  13 +- if can? current_user, :push_code, @project
  14 + = link_to new_project_branch_path(@project), class: 'btn btn-create' do
  15 + %i.icon-add-sign
  16 + New branch
  17 +
... ...
app/views/projects/branches/index.html.haml
1 1 = render "projects/commits/head"
2 2 .row
3 3 .span3
4   - = render "projects/repositories/filter"
  4 + = render "filter"
5 5 .span9
6 6 - unless @branches.empty?
7 7 %ul.bordered-list
... ...
app/views/projects/branches/recent.html.haml 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 += render "projects/commits/head"
  2 +.row
  3 + .span3
  4 + = render "filter"
  5 + .span9
  6 + %ul.bordered-list
  7 + - @branches.each do |branch|
  8 + = render "projects/branches/branch", branch: branch
... ...
app/views/projects/commits/_head.html.haml
... ... @@ -7,7 +7,7 @@
7 7 = link_to 'Compare', project_compare_index_path(@project)
8 8  
9 9 = nav_link(html_options: {class: branches_tab_class}) do
10   - = link_to project_repository_path(@project) do
  10 + = link_to recent_project_branches_path(@project) do
11 11 Branches
12 12 %span.badge= @repository.branches.length
13 13  
... ...
app/views/projects/commits/_text_file.html.haml
... ... @@ -3,7 +3,7 @@
3 3 %a.supp_diff_link Diff suppressed. Click to show
4 4  
5 5 %table.text-file{class: "#{'hide' if too_big}"}
6   - - each_diff_line(diff, index) do |line, type, line_code, line_new, line_old|
  6 + - each_diff_line(diff, index) do |line, type, line_code, line_new, line_old, raw_line|
7 7 %tr.line_holder{ id: line_code, class: "#{type}" }
8 8 - if type == "match"
9 9 %td.old_line= "..."
... ... @@ -20,4 +20,4 @@
20 20 - if @reply_allowed
21 21 - comments = @line_notes.select { |n| n.line_code == line_code }.sort_by(&:created_at)
22 22 - unless comments.empty?
23   - = render "projects/notes/diff_notes_with_reply", notes: comments
  23 + = render "projects/notes/diff_notes_with_reply", notes: comments, line: line
... ...
app/views/projects/commits/show.html.haml
1 1 = render "head"
2 2  
3 3 - if @path.present?
4   - %ul.breadcrumb
  4 + %ul.breadcrumb.commit-breadcrumb
5 5 %li.light
6 6 History for
7 7 = commits_breadcrumbs
... ...
app/views/projects/compare/_form.html.haml
... ... @@ -14,9 +14,9 @@
14 14 .pull-left
15 15 - if params[:to] && params[:from]
16 16 = link_to 'switch', {from: params[:to], to: params[:from]}, {class: 'commits-compare-switch has_tooltip', title: 'Switch base of comparison'}
17   - = text_field_tag :from, params[:from], placeholder: "master", class: "xlarge"
  17 + = text_field_tag :from, params[:from], placeholder: "master", class: "input-xlarge input-xpadding"
18 18 = "..."
19   - = text_field_tag :to, params[:to], placeholder: "aa8b4ef", class: "xlarge"
  19 + = text_field_tag :to, params[:to], placeholder: "aa8b4ef", class: "input-xlarge input-xpadding"
20 20 .pull-left
21 21 &nbsp;
22 22 = submit_tag "Compare", class: "btn btn-create commits-compare-btn"
... ...
app/views/projects/create.js.haml
... ... @@ -4,5 +4,6 @@
4 4 - else
5 5 :plain
6 6 $(".project-edit-errors").html("#{escape_javascript(render('errors'))}");
  7 + $('.project-submit').enable();
7 8 $('.save-project-loader').hide();
8 9 $('.project-edit-container').show();
... ...
app/views/projects/deploy_keys/_form.html.haml
... ... @@ -6,18 +6,18 @@
6 6 - @key.errors.full_messages.each do |msg|
7 7 %li= msg
8 8  
9   - .clearfix
  9 + .control-group
10 10 = f.label :title
11   - .input= f.text_field :title
12   - .clearfix
  11 + .controls= f.text_field :title, class: 'input-xlarge'
  12 + .control-group
13 13 = f.label :key
14   - .input
15   - = f.text_area :key, class: [:xxlarge, :thin_area]
16   - %p.hint
  14 + .controls
  15 + %p.light
17 16 Paste a machine public key here. Read more about how generate it
18 17 = link_to "here", help_ssh_path
  18 + = f.text_area :key, class: "input-xxlarge thin_area"
19 19  
20   - .actions
  20 + .form-actions
21 21 = f.submit 'Create', class: "btn-create btn"
22 22 = link_to "Cancel", project_deploy_keys_path(@project), class: "btn btn-cancel"
23 23  
... ...
app/views/projects/deploy_keys/index.html.haml
1   -%p.slead
2   - Deploy keys allow read-only access to repository. They can be used for CI, staging or production servers
  1 +%h3.page-title
  2 + Deploy keys allow read-only access to repository
3 3  
4   -%p
5   - You can create a deploy key or add existing one
6   - = link_to new_project_deploy_key_path(@project), class: "btn btn-primary pull-right", title: "New Deploy Key" do
  4 + = link_to new_project_deploy_key_path(@project), class: "btn btn-new pull-right", title: "New Deploy Key" do
7 5 %i.icon-plus
8 6 New Deploy Key
9 7  
  8 +%p.light
  9 + They can be used for CI, staging or production servers.
  10 + You can create a deploy key or add existing one
  11 +
10 12 %hr.clearfix
11 13  
12 14 .row
13 15 .span5.enabled-keys
14   - %h5.cgreen
15   - Enabled deploy keys
16   - %small for this project
  16 + %h5
  17 + %strong.cgreen Enabled deploy keys
  18 + for this project
17 19 %ul.bordered-list
18 20 = render @enabled_keys
19 21 - if @enabled_keys.blank?
... ... @@ -21,10 +23,10 @@
21 23 %p.nothing_here_message Create #{link_to 'new deploy key', new_project_deploy_key_path(@project)} or add existing one
22 24 .span5.available-keys
23 25 %h5
24   - Available deploy keys
25   - %small from projects you are able to manage
  26 + %strong Deploy keys
  27 + from projects available for you
26 28 %ul.bordered-list
27 29 = render @available_keys
28 30 - if @available_keys.blank?
29 31 .light-well
30   - %p.nothing_here_message All deploy keys created in projects you own will be displayed here
  32 + %p.nothing_here_message All deploy keys created in projects you participate will be displayed here
... ...
app/views/projects/edit.html.haml
... ... @@ -4,28 +4,28 @@
4 4 .ui-box.white
5 5 .title
6 6 %strong= @project.name
7   - Project Settings:
  7 + project settings:
8 8 .form-holder
9 9 = form_for(@project, remote: true) do |f|
10 10 %fieldset
11   - .clearfix.project_name_holder
  11 + .control-group.project_name_holder
12 12 = f.label :name do
13 13 Project name is
14   - .input
  14 + .controls
15 15 = f.text_field :name, placeholder: "Example Project", class: "span5"
16 16  
17 17  
18   - .clearfix
  18 + .control-group
19 19 = f.label :description do
20 20 Project description
21 21 %span.light (optional)
22   - .input
  22 + .controls
23 23 = f.text_area :description, placeholder: "awesome project", class: "span5", rows: 3, maxlength: 250
24 24  
25   - - unless @project.empty_repo?
26   - .clearfix
  25 + - if @project.repository.exists? && @project.repository.branch_names.any?
  26 + .control-group
27 27 = f.label :default_branch, "Default Branch"
28   - .input= f.select(:default_branch, @repository.branch_names, {}, {class: 'chosen'})
  28 + .controls= f.select(:default_branch, @repository.branch_names, {}, {class: 'chosen'})
29 29  
30 30  
31 31 - if can?(current_user, :change_public_mode, @project)
... ... @@ -66,11 +66,11 @@
66 66 - if Project.issues_tracker.values.count > 1
67 67 .control-group
68 68 = f.label :issues_tracker, "Issues tracker", class: 'control-label'
69   - .input= f.select(:issues_tracker, Project.issues_tracker.values, {}, { disabled: !@project.issues_enabled })
  69 + .controls= f.select(:issues_tracker, Project.issues_tracker.values, {}, { disabled: !@project.issues_enabled })
70 70  
71   - .clearfix
  71 + .control-group
72 72 = f.label :issues_tracker_id, "Project name or id in issues tracker", class: 'control-label'
73   - .input= f.text_field :issues_tracker_id, disabled: !@project.can_have_issues_tracker_id?
  73 + .controls= f.text_field :issues_tracker_id, disabled: !@project.can_have_issues_tracker_id?
74 74  
75 75 .control-group
76 76 = f.label :merge_requests_enabled, "Merge Requests", class: 'control-label'
... ... @@ -98,7 +98,7 @@
98 98  
99 99  
100 100 .form-actions
101   - = f.submit 'Save', class: "btn btn-save"
  101 + = f.submit 'Save changes', class: "btn btn-save"
102 102  
103 103 - if can?(current_user, :change_namespace, @project)
104 104 .ui-box.ui-box-danger
... ... @@ -110,7 +110,7 @@
110 110 = f.label :namespace_id do
111 111 %span Namespace
112 112 .controls
113   - .clearfix
  113 + .control-group
114 114 = f.select :namespace_id, namespaces_options(@project.namespace_id), {prompt: 'Choose a project namespace'}, {class: 'chosen'}
115 115 %ul
116 116 %li Be careful. Changing project namespace can have unintended side effects
... ... @@ -130,7 +130,7 @@
130 130 = f.label :path do
131 131 %span Path
132 132 .controls
133   - .clearfix
  133 + .control-group
134 134 = f.text_field :path
135 135 %ul
136 136 %li Be careful. Rename of project repo can have unintended side effects
... ...
app/views/projects/edit_tree/show.html.haml
  1 +%h3.page-title Edit mode
1 2 .file-editor
2 3 = form_tag(project_edit_tree_path(@project, @id), method: :put, class: "form-horizontal") do
3 4 .file-holder
... ...
app/views/projects/hooks/index.html.haml
... ... @@ -11,10 +11,10 @@
11 11 .alert.alert-error
12 12 - @hook.errors.full_messages.each do |msg|
13 13 %p= msg
14   - .clearfix
  14 + .control-group
15 15 = f.label :url, "URL:"
16   - .input
17   - = f.text_field :url, class: "text_field xxlarge"
  16 + .controls
  17 + = f.text_field :url, class: "text_field input-xxlarge input-xpadding", placeholder: 'http://example.com/trigger-ci.json'
18 18 &nbsp;
19 19 = f.submit "Add Web Hook", class: "btn btn-create"
20 20 %hr
... ...
app/views/projects/issues/_filter.html.haml
... ... @@ -18,6 +18,9 @@
18 18 All
19 19  
20 20 %fieldset
21   - %hr
22   - = link_to "Reset", project_issues_path(@project), class: 'btn pull-right'
  21 + - if %w(status milestone_id assignee_id label_name).select { |k| params[k].present? }.any?
  22 + = link_to project_issues_path(@project), class: 'cgray pull-right' do
  23 + %i.icon-remove
  24 + Clear filter
  25 +
23 26  
... ...
app/views/projects/issues/_form.html.haml
... ... @@ -8,18 +8,18 @@
8 8 %br
9 9 .ui-box.ui-box-show
10 10 .ui-box-head
11   - .clearfix
  11 + .control-group
12 12 = f.label :title do
13 13 %strong= "Subject *"
14   - .input
15   - = f.text_field :title, maxlength: 255, class: "xxlarge js-gfm-input", autofocus: true, required: true
  14 + .controls
  15 + = f.text_field :title, maxlength: 255, class: "input-xxlarge js-gfm-input", autofocus: true, required: true
16 16 .ui-box-body
17   - .clearfix
  17 + .control-group
18 18 .issue_assignee.pull-left
19 19 = f.label :assignee_id do
20 20 %i.icon-user
21 21 Assign to
22   - .input
  22 + .controls
23 23 .pull-left
24 24 = f.select(:assignee_id, @project.team.members.sort_by(&:name).map {|p| [ p.name, p.id ] }, { include_blank: "Select a user" }, {class: 'chosen'})
25 25 .pull-right
... ... @@ -29,25 +29,25 @@
29 29 = f.label :milestone_id do
30 30 %i.icon-time
31 31 Milestone
32   - .input= f.select(:milestone_id, @project.milestones.active.all.collect {|p| [ p.title, p.id ] }, { include_blank: "Select milestone" }, {class: 'chosen'})
  32 + .controls= f.select(:milestone_id, @project.milestones.active.all.collect {|p| [ p.title, p.id ] }, { include_blank: "Select milestone" }, {class: 'chosen'})
33 33  
34 34 .ui-box-bottom
35   - .clearfix
  35 + .control-group
36 36 = f.label :label_list do
37 37 %i.icon-tag
38 38 Labels
39   - .input
40   - = f.text_field :label_list, maxlength: 2000, class: "xxlarge"
  39 + .controls
  40 + = f.text_field :label_list, maxlength: 2000, class: "input-xxlarge"
41 41 %p.hint Separate labels with commas.
42 42  
43   - .clearfix
  43 + .control-group
44 44 = f.label :description, "Details"
45   - .input
46   - = f.text_area :description, class: "xxlarge js-gfm-input", rows: 14
  45 + .controls
  46 + = f.text_area :description, class: "input-xxlarge js-gfm-input", rows: 14
47 47 %p.hint Issues are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
48 48  
49 49  
50   - .actions
  50 + .form-actions
51 51 - if @issue.new_record?
52 52 = f.submit 'Submit new issue', class: "btn btn-create"
53 53 -else
... ...
app/views/projects/issues/index.html.haml
... ... @@ -6,7 +6,7 @@
6 6 .pull-right
7 7 .span6
8 8 - if can? current_user, :write_issue, @project
9   - = link_to new_project_issue_path(@project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "btn btn-primary pull-right", title: "New Issue", id: "new_issue_link" do
  9 + = link_to new_project_issue_path(@project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "btn btn-new pull-right", title: "New Issue", id: "new_issue_link" do
10 10 %i.icon-plus
11 11 New Issue
12 12 = form_tag project_issues_path(@project), method: :get, remote: true, id: "issue_search_form", class: 'pull-right' do
... ... @@ -14,7 +14,7 @@
14 14 = hidden_field_tag :assignee_id, params[:assignee_id], id: 'search_assignee_id'
15 15 = hidden_field_tag :milestone_id, params[:milestone_id], id: 'search_milestone_id'
16 16 = hidden_field_tag :label_name, params[:label_name], id: 'search_label_name'
17   - = search_field_tag :issue_search, nil, { placeholder: 'Search', class: 'issue_search input-xlarge append-right-10 search-text-input' }
  17 + = search_field_tag :issue_search, nil, { placeholder: 'Filter by title or description', class: 'input-xpadding issue_search input-xlarge append-right-10 search-text-input' }
18 18  
19 19 .row
20 20 .span3
... ...
app/views/projects/merge_requests/_filter.html.haml
1 1 = form_tag project_issues_path(@project), method: 'get' do
2 2 %fieldset
3 3 %ul.nav.nav-pills.nav-stacked
4   - %li{class: ("active" if (params[:f] == 'open' || !params[:f]))}
5   - = link_to project_merge_requests_path(@project, f: 'open', milestone_id: params[:milestone_id]) do
  4 + %li{class: ("active" if (params[:status] == 'open' || !params[:status]))}
  5 + = link_to project_merge_requests_path(@project, status: 'open', milestone_id: params[:milestone_id]) do
6 6 Open
7   - %li{class: ("active" if params[:f] == "closed")}
8   - = link_to project_merge_requests_path(@project, f: "closed", milestone_id: params[:milestone_id]) do
  7 + %li{class: ("active" if params[:status] == "closed")}
  8 + = link_to project_merge_requests_path(@project, status: "closed", milestone_id: params[:milestone_id]) do
9 9 Closed
10   - %li{class: ("active" if params[:f] == 'assigned-to-me')}
11   - = link_to project_merge_requests_path(@project, f: 'assigned-to-me', milestone_id: params[:milestone_id]) do
  10 + %li{class: ("active" if params[:status] == 'assigned-to-me')}
  11 + = link_to project_merge_requests_path(@project, status: 'assigned-to-me', milestone_id: params[:milestone_id]) do
12 12 Assigned To Me
13   - %li{class: ("active" if params[:f] == 'all')}
14   - = link_to project_merge_requests_path(@project, f: 'all', milestone_id: params[:milestone_id]) do
  13 + %li{class: ("active" if params[:status] == 'all')}
  14 + = link_to project_merge_requests_path(@project, status: 'all', milestone_id: params[:milestone_id]) do
15 15 All
16 16  
17 17 %fieldset
18   - %hr
19   - = link_to "Reset", project_merge_requests_path(@project), class: 'btn pull-right'
20   -
  18 + - if %w(status milestone_id assignee_id label_name).select { |k| params[k].present? }.any?
  19 + = link_to project_merge_requests_path(@project), class: 'cgray pull-right' do
  20 + %i.icon-remove
  21 + Clear filter
... ...
app/views/projects/merge_requests/_form.html.haml
... ... @@ -33,21 +33,21 @@
33 33 %i.icon-paper-clip
34 34 Details
35 35 .merge-request-form-info
36   - .clearfix
  36 + .control-group
37 37 = f.label :title do
38 38 %strong= "Title *"
39   - .input= f.text_field :title, class: "input-xxlarge pad js-gfm-input", maxlength: 255, rows: 5, required: true
40   - .clearfix
  39 + .controls= f.text_field :title, class: "input-xxlarge pad js-gfm-input", maxlength: 255, rows: 5, required: true
  40 + .control-group
41 41 .left
42 42 = f.label :assignee_id do
43 43 %i.icon-user
44 44 Assign to
45   - .input= f.select(:assignee_id, @project.team.members.sort_by(&:name).map {|p| [ p.name, p.id ] }, { include_blank: "Select user" }, {class: 'chosen span3'})
  45 + .controls= f.select(:assignee_id, @project.team.members.sort_by(&:name).map {|p| [ p.name, p.id ] }, { include_blank: "Select user" }, {class: 'chosen span3'})
46 46 .left
47 47 = f.label :milestone_id do
48 48 %i.icon-time
49 49 Milestone
50   - .input= f.select(:milestone_id, @project.milestones.active.all.map {|p| [ p.title, p.id ] }, { include_blank: "Select milestone" }, {class: 'chosen'})
  50 + .controls= f.select(:milestone_id, @project.milestones.active.all.map {|p| [ p.title, p.id ] }, { include_blank: "Select milestone" }, {class: 'chosen'})
51 51  
52 52 .form-actions
53 53 - if @merge_request.new_record?
... ...
app/views/projects/merge_requests/edit.html.haml
1 1 %h3.page-title
2   - = "Edit merge request #{@merge_request.id}"
  2 + = "Edit merge request ##{@merge_request.id}"
3 3 %hr
4 4 = render 'form'
... ...
app/views/projects/merge_requests/index.html.haml
1 1 - if can? current_user, :write_merge_request, @project
2   - = link_to new_project_merge_request_path(@project), class: "pull-right btn btn-primary", title: "New Merge Request" do
  2 + = link_to new_project_merge_request_path(@project), class: "pull-right btn btn-new", title: "New Merge Request" do
3 3 %i.icon-plus
4 4 New Merge Request
5 5 %h3.page-title
... ...
app/views/projects/merge_requests/show/_how_to_merge.html.haml
1 1 %div#modal_merge_info.modal.hide
2 2 .modal-header
3   - %a.close{href: "#"} ×
4   - %h3 How To Merge
  3 + %a.close{href: "#", "data-dismiss" => "modal"} ×
  4 + %h3 How to merge
5 5 .modal-body
6 6 - if @merge_request.for_fork?
7 7 - source_remote = @merge_request.source_project.namespace.nil? ? "source" :@merge_request.source_project.namespace.path
... ...
app/views/projects/merge_requests/show/_mr_accept.html.haml
... ... @@ -11,7 +11,8 @@
11 11 %p
12 12 You can accept this request automatically.
13 13 If you still want to do it manually -
14   - %strong= link_to "click here", "#", class: "how_to_merge_link vlink", title: "How To Merge"
  14 + %strong
  15 + = link_to "click here", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal"
15 16 for instructions
16 17 .accept_group
17 18 = f.submit "Accept Merge Request", class: "btn btn-create accept_merge_request"
... ... @@ -31,7 +32,7 @@
31 32 .automerge_widget.cannot_be_merged{style: "display:none"}
32 33 .alert.alert-disabled
33 34 %span
34   - = link_to "Show how to merge", "#", class: "how_to_merge_link btn btn-small padded", title: "How To Merge"
  35 + = link_to "Show how to merge", "#modal_merge_info", class: "how_to_merge_link btn btn-small padded", title: "How To Merge", "data-toggle" => "modal"
35 36 &nbsp;
36 37 %strong This request can't be merged with GitLab. You should do it manually
37 38  
... ...
app/views/projects/milestones/_form.html.haml
... ... @@ -26,13 +26,13 @@
26 26 .span6
27 27 .control-group
28 28 = f.label :due_date, "Due Date", class: "control-label"
29   - .input= f.hidden_field :due_date
  29 + .controls= f.hidden_field :due_date
30 30 .controls
31 31 .datepicker
32 32  
33 33 .form-actions
34 34 - if @milestone.new_record?
35   - = f.submit 'Create milestone', class: "btn-save btn"
  35 + = f.submit 'Create milestone', class: "btn-create btn"
36 36 = link_to "Cancel", project_milestones_path(@project), class: "btn btn-cancel"
37 37 -else
38 38 = f.submit 'Save changes', class: "btn-save btn"
... ...
app/views/projects/milestones/_milestone.html.haml
... ... @@ -4,8 +4,7 @@
4 4 = link_to edit_project_milestone_path(milestone.project, milestone), class: "btn btn-small edit-milestone-link grouped" do
5 5 %i.icon-edit
6 6 Edit
7   - - if milestone.can_be_closed?
8   - = link_to 'Close', project_milestone_path(@project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-small btn-remove"
  7 + = link_to 'Close Milestone', project_milestone_path(@project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-small btn-remove"
9 8 %h4
10 9 = link_to_gfm truncate(milestone.title, length: 100), project_milestone_path(milestone.project, milestone)
11 10 - if milestone.expired? and not milestone.closed?
... ...
app/views/projects/milestones/index.html.haml
... ... @@ -3,7 +3,7 @@
3 3 %h3.page-title
4 4 Milestones
5 5 - if can? current_user, :admin_milestone, @project
6   - = link_to new_project_milestone_path(@project), class: "pull-right btn btn-primary", title: "New Milestone" do
  6 + = link_to new_project_milestone_path(@project), class: "pull-right btn btn-new", title: "New Milestone" do
7 7 %i.icon-plus
8 8 New Milestone
9 9  
... ...
app/views/projects/milestones/show.html.haml
1 1 = render "projects/issues/head"
2   -.row
3   - .span6
4   - %h3.page-title
5   - Milestone ##{@milestone.id}
6   - %small
7   - = @milestone.expires_at
8   - .back-link
9   - = link_to project_milestones_path(@project) do
10   - &larr; To milestones list
11   - .span6
12   - .pull-right
13   - - unless @milestone.closed?
14   - = link_to new_project_issue_path(@project, issue: { milestone_id: @milestone.id }), class: "btn btn-small grouped", title: "New Issue" do
15   - %i.icon-plus
16   - New Issue
17   - = link_to 'Browse Issues', project_issues_path(@milestone.project, milestone_id: @milestone.id), class: "btn edit-milestone-link small grouped"
18   - - if can?(current_user, :admin_milestone, @project)
19   - = link_to edit_project_milestone_path(@project, @milestone), class: "btn btn-small grouped" do
20   - %i.icon-edit
21   - Edit
  2 +%h3.page-title
  3 + Milestone ##{@milestone.id}
  4 + %small
  5 + = @milestone.expires_at
  6 + .pull-right
  7 + - if can?(current_user, :admin_milestone, @project)
  8 + = link_to edit_project_milestone_path(@project, @milestone), class: "btn grouped" do
  9 + %i.icon-edit
  10 + Edit
  11 + = link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-remove"
22 12  
  13 +- if @milestone.issues.any? && @milestone.can_be_closed?
  14 + .alert.alert-success
  15 + %span All issues for this milestone are closed. You may close milestone now.
23 16  
  17 +.back-link
  18 + = link_to project_milestones_path(@project) do
  19 + &larr; To milestones list
24 20  
25   -- if @milestone.can_be_closed?
26   - %hr
27   - %p
28   - %span All issues for this milestone are closed. You may close milestone now.
29   - = link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-small btn-remove"
30 21  
31 22 .ui-box.ui-box-show
32 23 .ui-box-head
... ... @@ -69,6 +60,11 @@
69 60 Participants
70 61 %span.badge= @users.count
71 62  
  63 + .pull-right
  64 + = link_to new_project_issue_path(@project, issue: { milestone_id: @milestone.id }), class: "btn btn-small grouped", title: "New Issue" do
  65 + %i.icon-plus
  66 + New Issue
  67 + = link_to 'Browse Issues', project_issues_path(@milestone.project, milestone_id: @milestone.id), class: "btn btn-small edit-milestone-link grouped"
72 68  
73 69 .tab-content
74 70 .tab-pane.active#tab-issues
... ...
app/views/projects/network/_head.html.haml
... ... @@ -15,7 +15,7 @@
15 15 .control-group
16 16 = label_tag :search , "Looking for commit:", class: 'control-label light'
17 17 .controls
18   - = text_field_tag :q, @options[:q], placeholder: "Input SHA", class: "search-input xlarge"
  18 + = text_field_tag :q, @options[:q], placeholder: "Input SHA", class: "search-input input-xlarge"
19 19 = button_tag type: 'submit', class: 'btn vtop' do
20 20 %i.icon-search
21 21 - @options.each do |key, value|
... ...
app/views/projects/new.html.haml
1   -.project-edit-container
  1 +%p.slead
  2 + New projects are private by default. You choose who can see the project and commit to repository.
  3 +%hr
  4 +.project-edit-container.prepend-top-10
2 5 .project-edit-errors
3 6 = render 'projects/errors'
4 7 .project-edit-content
5 8 = form_for @project, remote: true do |f|
6   - .clearfix.project_name_holder
  9 + .control-group.project_name_holder
7 10 = f.label :name do
8   - Project name is
9   - .input
10   - = f.text_field :name, placeholder: "Example Project", class: "xxlarge", tabindex: 1, autofocus: true
11   - = f.submit 'Create project', class: "btn btn-create project-submit", tabindex: 4
  11 + %strong Project name is
  12 + .controls
  13 + = f.text_field :name, placeholder: "Example Project", class: "input-xlarge", tabindex: 1, autofocus: true
12 14  
13 15 - if current_user.can_select_namespace?
14   - .clearfix
  16 + .control-group
15 17 = f.label :namespace_id do
16 18 %span Namespace
17   - .input
  19 + .controls
18 20 = f.select :namespace_id, namespaces_options(params[:namespace_id] || :current_user), {}, {class: 'chosen', tabindex: 2}
19 21  
20   - .clearfix
21   - .input
  22 + .control-group
  23 + .controls
22 24 = link_to "#", class: 'appear-link' do
23 25 %i.icon-upload-alt
24 26 %span Import existing repository?
25   - .clearfix.appear-data.import-url-data
  27 + .control-group.appear-data.import-url-data
26 28 = f.label :import_url do
27 29 %span Import existing repo
28   - .input
29   - = f.text_field :import_url, class: 'xlarge', placeholder: 'https://github.com/randx/six.git'
  30 + .controls
  31 + = f.text_field :import_url, class: 'input-xlarge', placeholder: 'https://github.com/randx/six.git'
30 32 .light
31 33 URL must be cloneable
32   - .clearfix
  34 + .control-group
33 35 = f.label :description do
34 36 Description
35 37 %span.light (optional)
36   - .input
37   - = f.text_area :description, placeholder: "awesome project", class: "span5", rows: 3, maxlength: 250, tabindex: 3
  38 + .controls
  39 + = f.text_area :description, placeholder: "awesome project", class: "input-xlarge", rows: 3, maxlength: 250, tabindex: 3
38 40  
39   - %p.padded
40   - New projects are private by default. You choose who can see the project and commit to repository.
41   - %hr
  41 + .form-actions
  42 + = f.submit 'Create project', class: "btn btn-create project-submit", tabindex: 4
42 43  
43   - - if current_user.can_create_group?
44   - .clearfix
45   - .input.light
46   - Need a group for several dependent projects?
47   - = link_to new_group_path, class: "btn btn-tiny" do
48   - Create a group
  44 + - if current_user.can_create_group?
  45 + .pull-right
  46 + .controls.light
  47 + Need a group for several dependent projects?
  48 + = link_to new_group_path, class: "btn btn-tiny" do
  49 + Create a group
49 50  
50 51 .save-project-loader.hide
51 52 %center
... ...
app/views/projects/notes/_diff_notes_with_reply.html.haml
1 1 - note = notes.first # example note
2   -%tr.notes_holder
3   - %td.notes_line{ colspan: 2 }
4   - %span.btn.disabled
5   - %i.icon-comment
6   - = notes.count
7   - %td.notes_content
8   - %ul.notes{ rel: note.discussion_id }
9   - = render notes
  2 +-# Check if line want not changed since comment was left
  3 +- if !defined?(line) || line == note.diff_line
  4 + %tr.notes_holder
  5 + %td.notes_line{ colspan: 2 }
  6 + %span.btn.disabled
  7 + %i.icon-comment
  8 + = notes.count
  9 + %td.notes_content
  10 + %ul.notes{ rel: note.discussion_id }
  11 + = render notes
10 12  
11   - = render "projects/notes/discussion_reply_button", note: note
  13 + = render "projects/notes/discussion_reply_button", note: note
... ...
app/views/projects/notes/_discussion.html.haml
... ... @@ -36,7 +36,7 @@
36 36 ago
37 37 .discussion-body
38 38 - if note.for_diff_line?
39   - - if note.diff
  39 + - if note.active?
40 40 .content
41 41 .file= render "projects/notes/discussion_diff", discussion_notes: discussion_notes, note: note
42 42 - else
... ...
app/views/projects/notes/_note.html.haml
... ... @@ -8,8 +8,11 @@
8 8 - if(note.author_id == current_user.id) || can?(current_user, :admin_note, @project)
9 9 = link_to "#", title: "Edit comment", class: "js-note-edit" do
10 10 %i.icon-edit
  11 + Edit
  12 + &nbsp;
11 13 = link_to project_note_path(@project, note), title: "Remove comment", method: :delete, confirm: 'Are you sure you want to remove this comment?', remote: true, class: "danger js-note-delete" do
12 14 %i.icon-trash.cred
  15 + Remove
13 16 = image_tag gravatar_icon(note.author_email), class: "avatar s32"
14 17 = link_to_member(@project, note.author, avatar: false)
15 18 %span.note-last-update
... ...
app/views/projects/protected_branches/index.html.haml
1 1 = render "projects/commits/head"
2 2 .row
3 3 .span3
4   - = render "projects/repositories/filter"
  4 + = render "projects/branches/filter"
5 5 .span9
6 6 .alert.alert-info
7 7 %p Protected branches designed to prevent push for all except #{link_to "masters", help_permissions_path, class: "vlink"}.
... ...
app/views/projects/repositories/_filter.html.haml
... ... @@ -1,17 +0,0 @@
1   -%ul.nav.nav-pills.nav-stacked
2   - = nav_link(path: 'repositories#show') do
3   - = link_to 'Recent', project_repository_path(@project)
4   - = nav_link(path: 'protected_branches#index') do
5   - = link_to project_protected_branches_path(@project) do
6   - Protected
7   - %i.icon-lock
8   - = nav_link(path: 'branches#index') do
9   - = link_to 'All branches', project_branches_path(@project)
10   -
11   -
12   -%hr
13   -- if can? current_user, :push_code, @project
14   - = link_to new_project_branch_path(@project), class: 'btn btn-create' do
15   - %i.icon-add-sign
16   - New branch
17   -
app/views/projects/repositories/show.html.haml
... ... @@ -1,9 +0,0 @@
1   -= render "projects/commits/head"
2   -.row
3   - .span3
4   - = render "filter"
5   - .span9
6   - %ul.bordered-list
7   - - @activities.each do |update|
8   - = render "projects/branches/branch", branch: update.head
9   -
app/views/projects/snippets/_form.html.haml
... ... @@ -9,16 +9,16 @@
9 9 - @snippet.errors.full_messages.each do |msg|
10 10 %li= msg
11 11  
12   - .clearfix
  12 + .control-group
13 13 = f.label :title
14   - .input= f.text_field :title, placeholder: "Example Snippet", class: 'input-xlarge', required: true
15   - .clearfix
  14 + .controls= f.text_field :title, placeholder: "Example Snippet", class: 'input-xlarge', required: true
  15 + .control-group
16 16 = f.label "Lifetime"
17   - .input= f.select :expires_at, lifetime_select_options, {}, {class: 'chosen span2'}
18   - .clearfix
  17 + .controls= f.select :expires_at, lifetime_select_options, {}, {class: 'chosen span2'}
  18 + .control-group
19 19 .file-editor
20 20 = f.label :file_name, "File"
21   - .input
  21 + .controls
22 22 .file-holder.snippet
23 23 .file-title
24 24 = f.text_field :file_name, placeholder: "example.rb", class: 'snippet-file-name', required: true
... ...
app/views/projects/team_members/_form.html.haml
... ... @@ -9,16 +9,16 @@
9 9 %li= msg
10 10  
11 11 %h6 1. Choose people you want in the team
12   - .clearfix
  12 + .control-group
13 13 = f.label :user_ids, "People"
14   - .input
  14 + .controls
15 15 = users_select_tag(:user_ids, multiple: true)
16 16  
17 17 %h6 2. Set access level for them
18   - .clearfix
  18 + .control-group
19 19 = f.label :project_access, "Project Access"
20   - .input= select_tag :project_access, options_for_select(Project.access_options, @user_project_relation.project_access), class: "project-access-select chosen"
  20 + .controls= select_tag :project_access, options_for_select(Project.access_options, @user_project_relation.project_access), class: "project-access-select chosen"
21 21  
22   - .actions
  22 + .form-actions
23 23 = f.submit 'Add users', class: "btn btn-create"
24 24 = link_to "Cancel", project_team_index_path(@project), class: "btn btn-cancel"
... ...
app/views/projects/team_members/_group_members.html.haml
1 1 .ui-box
2 2 .title
3   - %strong #{@group.name} Group
4   - members (#{@group.users_groups.count})
  3 + %strong #{@group.name}
  4 + group members (#{@group.users_groups.count})
5 5 .pull-right
6 6 = link_to members_group_path(@group), class: 'btn btn-small' do
7 7 %i.icon-edit
... ...
app/views/projects/team_members/_team.html.haml
... ... @@ -2,8 +2,8 @@
2 2 - can_admin_project = (can? current_user, :admin_project, @project)
3 3 .ui-box
4 4 .title
5   - %strong #{@project.name} Project
6   - members (#{members.count})
  5 + %strong #{@project.name}
  6 + project members (#{members.count})
7 7 %ul.well-list
8 8 - members.each do |team_member|
9 9 = render 'team_member', member: team_member, current_user_can_admin_project: can_admin_project
... ...
app/views/projects/team_members/import.html.haml
1 1 %h3.page-title
2   - = "Import team from another project"
  2 + = "Import members from another project"
  3 +%p.light
  4 + Only project members will be improted. Group members will be skipped.
3 5 %hr
4   -%p.slead
5   - Read more about project team import #{link_to "here", '#', class: 'vlink'}.
6 6 = form_tag apply_import_project_team_members_path(@project), method: 'post' do
7   - %p.slead Choose project you want to use as team source:
8 7 .padded
9 8 = label_tag :source_project_id, "Project"
10   - .input= select_tag(:source_project_id, options_from_collection_for_select(current_user.authorized_projects, :id, :name_with_namespace), prompt: "Select project", class: "chosen xxlarge", required: true)
  9 + .controls= select_tag(:source_project_id, options_from_collection_for_select(current_user.authorized_projects, :id, :name_with_namespace), prompt: "Select project", class: "chosen xxlarge", required: true)
11 10  
12   - .actions
13   - = submit_tag 'Import', class: "btn btn-save"
  11 + .form-actions
  12 + = submit_tag 'Import project members', class: "btn btn-create"
14 13 = link_to "Cancel", project_team_index_path(@project), class: "btn btn-cancel"
15 14  
... ...
app/views/projects/team_members/index.html.haml
... ... @@ -3,14 +3,14 @@
3 3  
4 4 - if can? current_user, :admin_team_member, @project
5 5 %span.pull-right
6   - = link_to import_project_team_members_path(@project), class: "btn btn-small grouped", title: "Import team from another project" do
7   - Import team from another project
8   - = link_to new_project_team_member_path(@project), class: "btn btn-primary small grouped", title: "New Team Member" do
  6 + = link_to new_project_team_member_path(@project), class: "btn btn-new grouped", title: "New Team Member" do
9 7 New Team Member
  8 + = link_to import_project_team_members_path(@project), class: "btn grouped", title: "Import team from another project" do
  9 + Import members
10 10  
11 11 %p.light
12 12 Read more about project permissions
13 13 %strong= link_to "here", help_permissions_path, class: "vlink"
  14 += render "team", members: @users_projects
14 15 - if @group
15 16 = render "group_members"
16   -= render "team", members: @users_projects
... ...
app/views/projects/wikis/_form.html.haml
... ... @@ -15,7 +15,7 @@
15 15 = f.select :format, options_for_select(GollumWiki::MARKUPS, {selected: @wiki.format}), {}, class: "pull-right input-medium"
16 16 = f.label :format, class: "pull-right", style: "padding-right: 20px;"
17 17 .ui-box-body
18   - .input
  18 + .controls
19 19 %span.cgray
20 20 Wiki content is parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
21 21 To link to a (new) page you can just type
... ... @@ -23,14 +23,17 @@
23 23 \.
24 24  
25 25 .ui-box-bottom
26   - = f.label :content
27   - .input= f.text_area :content, class: 'span8 js-gfm-input'
  26 + .control-group
  27 + = f.label :content
  28 + .controls= f.text_area :content, class: 'span8 js-gfm-input'
28 29 .ui-box-bottom
29   - = f.label :commit_message
30   - .input= f.text_field :message, class: 'span8'
31   - .actions
32   - = f.submit 'Save', class: "btn-save btn"
  30 + .control-group
  31 + = f.label :commit_message
  32 + .controls= f.text_field :message, class: 'span8'
  33 + .form-actions
33 34 - if @wiki && @wiki.persisted?
  35 + = f.submit 'Save changes', class: "btn-save btn"
34 36 = link_to "Cancel", project_wiki_path(@project, @wiki), class: "btn btn-cancel"
35 37 - else
  38 + = f.submit 'Create page', class: "btn-create btn"
36 39 = link_to "Cancel", project_wiki_path(@project, :home), class: "btn btn-cancel"
... ...
app/views/projects/wikis/_nav.html.haml
... ... @@ -12,7 +12,7 @@
12 12  
13 13 - if can?(current_user, :write_wiki, @project)
14 14 .pull-right
15   - = link_to '#', class: "add-new-wiki btn btn-small btn-primary" do
  15 + = link_to '#modal-new-wiki', class: "add-new-wiki btn btn-new", "data-toggle" => "modal" do
16 16 %i.icon-plus
17 17 New Page
18 18  
... ...
app/views/projects/wikis/_new.html.haml
1 1 %div#modal-new-wiki.modal.hide
2 2 .modal-header
3   - %a.close{href: "#"} ×
  3 + %a.close{href: "#", "data-dismiss" => "modal"} ×
4 4 %h3.page-title New Wiki Page
5 5 .modal-body
6 6 = label_tag :new_wiki_path do
... ...
app/views/projects/wikis/git_access.html.haml
1 1 = render 'nav'
2 2 %h3.page-title
3   - Git Access
  3 + Git access for
4 4 %strong= @gollum_wiki.path_with_namespace
5 5 = render 'main_links'
6 6  
7   -%br
8 7 .content
9 8 .project_clone_panel
10 9 .row
... ...
app/views/public/projects/index.html.haml
... ... @@ -7,7 +7,7 @@
7 7 .pull-right
8 8 = form_tag public_projects_path, method: :get, class: 'form-inline' do |f|
9 9 .search-holder
10   - .input
  10 + .controls
11 11 = search_field_tag :search, params[:search], placeholder: "gitlab-ci", class: "span3 search-text-input", id: "projects_search"
12 12 = submit_tag 'Search', class: "btn btn-primary wide"
13 13  
... ...
app/views/search/show.html.haml
... ... @@ -2,7 +2,7 @@
2 2 .search-holder
3 3 = label_tag :search do
4 4 %span Looking for
5   - .input
  5 + .controls
6 6 = search_field_tag :search, params[:search], placeholder: "issue 143", class: "input-xxlarge search-text-input", id: "dashboard_search"
7 7 = hidden_field_tag :project_id, params[:project_id]
8 8 = hidden_field_tag :group_id, params[:group_id]
... ...
app/views/shared/_filter.html.haml 0 → 100644
... ... @@ -0,0 +1,29 @@
  1 += form_tag filter_path(entity), method: 'get' do
  2 + %fieldset
  3 + %ul.nav.nav-pills.nav-stacked
  4 + %li{class: ("active" if params[:status].blank?)}
  5 + = link_to filter_path(entity, status: nil) do
  6 + Open
  7 + %li{class: ("active" if params[:status] == 'closed')}
  8 + = link_to filter_path(entity, status: 'closed') do
  9 + Closed
  10 + %li{class: ("active" if params[:status] == 'all')}
  11 + = link_to filter_path(entity, status: 'all') do
  12 + All
  13 +
  14 + %fieldset
  15 + %legend Projects:
  16 + %ul.nav.nav-pills.nav-pills-small.nav-stacked
  17 + - @projects.each do |project|
  18 + - unless entities_per_project(project, entity).zero?
  19 + %li{class: ("active" if params[:project_id] == project.id.to_s)}
  20 + = link_to filter_path(entity, project_id: project.id) do
  21 + = project.name_with_namespace
  22 + %small.pull-right= entities_per_project(project, entity)
  23 +
  24 + %fieldset
  25 + - if params[:status].present? || params[:project_id].present?
  26 + = link_to filter_path(entity, status: nil, project_id: nil), class: 'pull-right cgray' do
  27 + %i.icon-remove
  28 + Clear filter
  29 +
... ...
app/views/shared/_issues.html.haml 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +- if @issues.any?
  2 + - @issues.group_by(&:project).each do |group|
  3 + .ui-box.small-box
  4 + - project = group[0]
  5 + .title
  6 + = link_to_project project
  7 + = link_to 'show all', project_issues_path(project), class: 'pull-right'
  8 +
  9 + %ul.well-list.issues-list
  10 + - group[1].each do |issue|
  11 + = render 'projects/issues/issue', issue: issue
  12 + = paginate @issues, theme: "gitlab"
  13 +- else
  14 + %p.nothing_here_message Nothing to show here
  15 +
... ...
app/views/shared/_merge_requests.html.haml
1 1 - if @merge_requests.any?
2 2 - @merge_requests.group_by(&:target_project).each do |group|
3   - .ui-box
  3 + .ui-box.small-box
4 4 - project = group[0]
5 5 .title
6 6 = link_to_project project
7 7 %ul.well-list.mr-list
8 8 - group[1].each do |merge_request|
9 9 = render 'projects/merge_requests/merge_request', merge_request: merge_request
10   - %hr
11 10 = paginate @merge_requests, theme: "gitlab"
12 11  
13 12 - else
... ...
app/views/snippets/_form.html.haml
... ... @@ -9,16 +9,16 @@
9 9 - @snippet.errors.full_messages.each do |msg|
10 10 %li= msg
11 11  
12   - .clearfix
  12 + .control-group
13 13 = f.label :title
14   - .input= f.text_field :title, placeholder: "Example Snippet", class: 'input-xlarge', required: true
15   - .clearfix
  14 + .controls= f.text_field :title, placeholder: "Example Snippet", class: 'input-xlarge', required: true
  15 + .control-group
16 16 = f.label "Private?"
17   - .input= f.check_box :private, {class: ''}
18   - .clearfix
  17 + .controls= f.check_box :private, {class: ''}
  18 + .control-group
19 19 .file-editor
20 20 = f.label :file_name, "File"
21   - .input
  21 + .controls
22 22 .file-holder.snippet
23 23 .file-title
24 24 = f.text_field :file_name, placeholder: "example.rb", class: 'snippet-file-name', required: true
... ...
app/views/snippets/current_user_index.html.haml
1 1 %h3.page-title
2 2 My Snippets
3   - %small share code pastes with others out of git repository
4 3 .pull-right
5   - = link_to new_snippet_path, class: "btn btn-small add_new grouped btn-primary", title: "New Snippet" do
  4 + = link_to new_snippet_path, class: "btn btn-new grouped", title: "New Snippet" do
6 5 Add new snippet
7   - = link_to snippets_path, class: "btn btn-small grouped" do
  6 + = link_to snippets_path, class: "btn grouped" do
8 7 Discover snippets
9 8  
  9 +%p.light
  10 + Share code pastes with others out of git repository
10 11 %hr
11 12  
12 13 .row
... ...
app/views/snippets/index.html.haml
1 1 %h3.page-title
2 2 Public snippets
3   - %small share code pastes with others out of git repository
4 3  
5 4 .pull-right
6   - = link_to new_snippet_path, class: "btn btn-small add_new grouped btn-primary", title: "New Snippet" do
  5 + = link_to new_snippet_path, class: "btn btn-new grouped", title: "New Snippet" do
7 6 Add new snippet
8   - = link_to user_snippets_path(current_user), class: "btn btn-small grouped" do
  7 + = link_to user_snippets_path(current_user), class: "btn grouped" do
9 8 My snippets
10 9  
  10 +%p.light
  11 + Public snippets created by you and other users are listed here
  12 +
11 13 %hr
12 14 = render 'snippets'
13 15  
... ...
app/views/snippets/show.html.haml
... ... @@ -7,7 +7,7 @@
7 7 private
8 8  
9 9 .pull-right
10   - = link_to new_snippet_path, class: "btn btn-small add_new grouped btn-primary", title: "New Snippet" do
  10 + = link_to new_snippet_path, class: "btn btn-new btn-small", title: "New Snippet" do
11 11 Add new snippet
12 12  
13 13  
... ...
app/views/users_groups/_users_group.html.haml
1 1 - user = member.user
2 2 - return unless user
3   -%li{class: dom_class(member)}
  3 +%li{class: "#{dom_class(member)} js-toggle-container", id: dom_id(member)}
4 4 = image_tag gravatar_icon(user.email, 16), class: "avatar s16"
5 5 %strong= user.name
6 6 %span.cgray= user.username
... ... @@ -8,12 +8,16 @@
8 8 %span.label.label-success It's you
9 9  
10 10 %span.pull-right
11   - - if @group.owners.include?(user)
12   - %span.label.label-info Group Owner
13   - - else
14   - = member.human_access
  11 + %strong= member.human_access
15 12  
16 13 - if show_controls && user != @group.owner && user != current_user
  14 + = link_to '#', class: "btn-tiny btn js-toggle-button", title: 'Edit access level' do
  15 + %i.icon-edit
17 16 = link_to group_users_group_path(@group, member), confirm: remove_user_from_group_message(@group, user), method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
18 17 %i.icon-minus.icon-white
19 18  
  19 + .edit-member.hide.js-toggle-content
  20 + = form_for [@group, member], remote: true do |f|
  21 + .alert.prepend-top-20
  22 + = f.select :group_access, options_for_select(UsersGroup.group_access_roles, member.group_access)
  23 + = f.submit 'Save', class: 'btn btn-save'
... ...
app/views/users_groups/update.js.haml 0 → 100644
... ... @@ -0,0 +1,2 @@
  1 +:plain
  2 + $("##{dom_id(@member)}").replaceWith('#{escape_javascript(render(@member, member: @member, show_controls: true))}');
... ...
config/routes.rb
... ... @@ -225,8 +225,13 @@ Gitlab::Application.routes.draw do
225 225 end
226 226 end
227 227  
  228 + resources :branches, only: [:index, :new, :create, :destroy] do
  229 + collection do
  230 + get :recent
  231 + end
  232 + end
  233 +
228 234 resources :tags, only: [:index, :new, :create, :destroy]
229   - resources :branches, only: [:index, :new, :create, :destroy]
230 235 resources :protected_branches, only: [:index, :create, :destroy]
231 236  
232 237 resources :refs, only: [] do
... ...
db/migrate/20130804151314_add_st_diff_to_note.rb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +class AddStDiffToNote < ActiveRecord::Migration
  2 + def change
  3 + add_column :notes, :st_diff, :text, :null => true
  4 + end
  5 +end
... ...
db/schema.rb
... ... @@ -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 => 20130624162710) do
  14 +ActiveRecord::Schema.define(:version => 20130804151314) do
15 15  
16 16 create_table "deploy_keys_projects", :force => true do |t|
17 17 t.integer "deploy_key_id", :null => false
... ... @@ -148,6 +148,7 @@ ActiveRecord::Schema.define(:version =&gt; 20130624162710) do
148 148 t.string "line_code"
149 149 t.string "commit_id"
150 150 t.integer "noteable_id"
  151 + t.text "st_diff"
151 152 end
152 153  
153 154 add_index "notes", ["author_id"], :name => "index_notes_on_author_id"
... ...
doc/api/README.md
... ... @@ -87,3 +87,4 @@ When listing resources you can pass the following parameters:
87 87  
88 88 + [php-gitlab-api](https://github.com/m4tthumphrey/php-gitlab-api) - PHP
89 89 + [Ruby Wrapper](https://github.com/NARKOZ/gitlab) - Ruby
  90 ++ [python-gitlab](https://github.com/Itxaka/python-gitlab) - Python
... ...
doc/install/installation.md
... ... @@ -71,6 +71,9 @@ Make sure you have the right version of Python installed.
71 71 # If you get a "command not found" error create a link to the python binary
72 72 sudo ln -s /usr/bin/python /usr/bin/python2
73 73  
  74 + # For reStructuredText markup language support install required package:
  75 + sudo apt-get install python-docutils
  76 +
74 77 **Note:** In order to receive mail notifications, make sure to install a
75 78 mail server. By default, Debian is shipped with exim4 whereas Ubuntu
76 79 does not ship with one. The recommended mail server is postfix and you can install it with:
... ... @@ -119,7 +122,7 @@ GitLab Shell is a ssh access and repository management software developed specia
119 122 cd gitlab-shell
120 123  
121 124 # switch to right version
122   - sudo -u git -H git checkout v1.4.0
  125 + sudo -u git -H git checkout v1.7.0
123 126  
124 127 sudo -u git -H cp config.yml.example config.yml
125 128  
... ... @@ -196,6 +199,7 @@ You can change `5-3-stable` to `master` if you want the *bleeding edge* version,
196 199 # Edit user.email according to what is set in gitlab.yml
197 200 sudo -u git -H git config --global user.name "GitLab"
198 201 sudo -u git -H git config --global user.email "gitlab@localhost"
  202 + sudo -u git -H git config --global core.autocrlf input
199 203  
200 204 **Important Note:**
201 205 Make sure to edit both `gitlab.yml` and `unicorn.rb` to match your setup.
... ...
doc/update/5.4-to-6.0.md
... ... @@ -9,9 +9,13 @@ So you need to move all your global projects under group/users manually before u
9 9  
10 10 #### Teams
11 11  
12   -We drop teams support as separate entity for 6.0 in favor of group membership.
13   -So now you will be able to manage group members in order to provide access to corresponding projects.
14   -
  12 +We deprecate teams as separate entity in 6.0 in favor of group membership.
  13 +The old combination of groups and teams was confusing for a lot of people.
  14 +And when the members of a team where changed this wasn't reflected in the project permissions.
  15 +In GitLab 6.0 you will be able to add members to a group with a permission level for each member.
  16 +These group members will have access to the projects in that group.
  17 +Any changes to group members will immediately be reflected in the project permissions.
  18 +You can even have multiple owners for a group, greatly simplifying administration.
15 19  
16 20 ### 0. Backup
17 21  
... ... @@ -35,7 +39,14 @@ sudo -u git -H git fetch
35 39 sudo -u git -H git checkout 6-0-dev
36 40 ```
37 41  
38   -### 3. Install libs, migrations, etc.
  42 +### 3. Install additional packages
  43 +
  44 +```bash
  45 +# For reStructuredText markup language support install required package:
  46 +sudo apt-get install python-docutils
  47 +```
  48 +
  49 +### 4. Install libs, migrations, etc.
39 50  
40 51 ```bash
41 52 cd /home/git/gitlab
... ... @@ -50,15 +61,16 @@ sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
50 61 sudo -u git -H bundle exec rake migrate_groups RAILS_ENV=production
51 62 sudo -u git -H bundle exec rake migrate_global_projects RAILS_ENV=production
52 63 sudo -u git -H bundle exec rake migrate_keys RAILS_ENV=production
  64 +sudo -u git -H bundle exec rake migrate_inline_notes RAILS_ENV=production
53 65  
54 66 ```
55 67  
56   -### 4. Update config files
  68 +### 5. Update config files
57 69  
58 70 * Make `/home/git/gitlab/config/gitlab.yml` same as https://github.com/gitlabhq/gitlabhq/blob/5-3-stable/config/gitlab.yml.example but with your settings.
59 71 * Make `/home/git/gitlab/config/puma.rb` same as https://github.com/gitlabhq/gitlabhq/blob/5-3-stable/config/puma.rb.example but with your settings.
60 72  
61   -### 5. Update Init script
  73 +### 6. Update Init script
62 74  
63 75 ```bash
64 76 sudo rm /etc/init.d/gitlab
... ... @@ -66,12 +78,12 @@ sudo curl --output /etc/init.d/gitlab https://raw.github.com/gitlabhq/gitlabhq/5
66 78 sudo chmod +x /etc/init.d/gitlab
67 79 ```
68 80  
69   -### 6. Start application
  81 +### 7. Start application
70 82  
71 83 sudo service gitlab start
72 84 sudo service nginx restart
73 85  
74   -### 7. Check application status
  86 +### 8. Check application status
75 87  
76 88 Check if GitLab and its environment are configured correctly:
77 89  
... ... @@ -81,4 +93,4 @@ To make sure you didn&#39;t miss anything run a more thorough check with:
81 93  
82 94 sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
83 95  
84   -If all items are green, then congratulations upgrade complete!
85 96 \ No newline at end of file
  97 +If all items are green, then congratulations upgrade complete!
... ...
features/steps/profile/profile.rb
... ... @@ -12,7 +12,7 @@ class Profile &lt; Spinach::FeatureSteps
12 12 fill_in "user_skype", with: "testskype"
13 13 fill_in "user_linkedin", with: "testlinkedin"
14 14 fill_in "user_twitter", with: "testtwitter"
15   - click_button "Save"
  15 + click_button "Save changes"
16 16 @user.reload
17 17 end
18 18  
... ...
features/steps/profile/profile_notifications.rb
... ... @@ -7,7 +7,7 @@ class ProfileNotifications &lt; Spinach::FeatureSteps
7 7 end
8 8  
9 9 step 'I should see global notifications settings' do
10   - page.should have_content "Setup your notification level"
  10 + page.should have_content "Notifications settings"
11 11 page.should have_content "Global setting"
12 12 end
13 13 end
... ...
features/steps/project/project.rb
... ... @@ -9,7 +9,7 @@ class ProjectFeature &lt; Spinach::FeatureSteps
9 9 end
10 10  
11 11 And 'I save project' do
12   - click_button 'Save'
  12 + click_button 'Save changes'
13 13 end
14 14  
15 15 Then 'I should see project with new settings' do
... ...
features/steps/project/project_wiki.rb
... ... @@ -5,7 +5,7 @@ class ProjectWiki &lt; Spinach::FeatureSteps
5 5 include SharedPaths
6 6  
7 7 Given 'I click on the Cancel button' do
8   - within(:css, ".actions") do
  8 + within(:css, ".form-actions") do
9 9 click_on "Cancel"
10 10 end
11 11 end
... ... @@ -17,7 +17,7 @@ class ProjectWiki &lt; Spinach::FeatureSteps
17 17  
18 18 Given 'I create the Wiki Home page' do
19 19 fill_in "Content", with: '[link test](test)'
20   - click_on "Save"
  20 + click_on "Create page"
21 21 end
22 22  
23 23 Then 'I should see the newly created wiki page' do
... ... @@ -43,7 +43,7 @@ class ProjectWiki &lt; Spinach::FeatureSteps
43 43  
44 44 And 'I change the content' do
45 45 fill_in "Content", with: 'Updated Wiki Content'
46   - click_on "Save"
  46 + click_on "Save changes"
47 47 end
48 48  
49 49 Then 'I should see the updated content' do
... ...
lib/api/internal.rb
1 1 module API
2 2 # Internal access API
3 3 class Internal < Grape::API
  4 +
  5 + DOWNLOAD_COMMANDS = %w{ git-upload-pack git-upload-archive }
  6 + PUSH_COMMANDS = %w{ git-receive-pack }
  7 +
4 8 namespace 'internal' do
5 9 #
6 10 # Check if ssh key has access to project code
... ... @@ -26,16 +30,16 @@ module API
26 30  
27 31  
28 32 if key.is_a? DeployKey
29   - key.projects.include?(project) && git_cmd == 'git-upload-pack'
  33 + key.projects.include?(project) && DOWNLOAD_COMMANDS.include?(git_cmd)
30 34 else
31 35 user = key.user
32 36  
33 37 return false if user.blocked?
34 38  
35 39 action = case git_cmd
36   - when 'git-upload-pack', 'git-upload-archive'
  40 + when *DOWNLOAD_COMMANDS
37 41 then :download_code
38   - when 'git-receive-pack'
  42 + when *PUSH_COMMANDS
39 43 then
40 44 if project.protected_branch?(params[:ref])
41 45 :push_code_to_protected_branches
... ...
lib/backup/manager.rb 0 → 100644
... ... @@ -0,0 +1,106 @@
  1 +module Backup
  2 + class Manager
  3 + def pack
  4 + # saving additional informations
  5 + s = {}
  6 + s[:db_version] = "#{ActiveRecord::Migrator.current_version}"
  7 + s[:backup_created_at] = Time.now
  8 + s[:gitlab_version] = %x{git rev-parse HEAD}.gsub(/\n/,"")
  9 + s[:tar_version] = %x{tar --version | head -1}.gsub(/\n/,"")
  10 +
  11 + Dir.chdir(Gitlab.config.backup.path)
  12 +
  13 + File.open("#{Gitlab.config.backup.path}/backup_information.yml", "w+") do |file|
  14 + file << s.to_yaml.gsub(/^---\n/,'')
  15 + end
  16 +
  17 + # create archive
  18 + print "Creating backup archive: #{s[:backup_created_at].to_i}_gitlab_backup.tar ... "
  19 + if Kernel.system("tar -cf #{s[:backup_created_at].to_i}_gitlab_backup.tar repositories/ db/ uploads/ backup_information.yml")
  20 + puts "done".green
  21 + else
  22 + puts "failed".red
  23 + end
  24 + end
  25 +
  26 + def cleanup
  27 + print "Deleting tmp directories ... "
  28 + if Kernel.system("rm -rf repositories/ db/ uploads/ backup_information.yml")
  29 + puts "done".green
  30 + else
  31 + puts "failed".red
  32 + end
  33 + end
  34 +
  35 + def remove_old
  36 + # delete backups
  37 + print "Deleting old backups ... "
  38 + keep_time = Gitlab.config.backup.keep_time.to_i
  39 + path = Gitlab.config.backup.path
  40 +
  41 + if keep_time > 0
  42 + removed = 0
  43 + file_list = Dir.glob(Rails.root.join(path, "*_gitlab_backup.tar"))
  44 + file_list.map! { |f| $1.to_i if f =~ /(\d+)_gitlab_backup.tar/ }
  45 + file_list.sort.each do |timestamp|
  46 + if Time.at(timestamp) < (Time.now - keep_time)
  47 + if system("rm #{timestamp}_gitlab_backup.tar")
  48 + removed += 1
  49 + end
  50 + end
  51 + end
  52 + puts "done. (#{removed} removed)".green
  53 + else
  54 + puts "skipping".yellow
  55 + end
  56 + end
  57 +
  58 + def unpack
  59 + Dir.chdir(Gitlab.config.backup.path)
  60 +
  61 + # check for existing backups in the backup dir
  62 + file_list = Dir.glob("*_gitlab_backup.tar").each.map { |f| f.split(/_/).first.to_i }
  63 + puts "no backups found" if file_list.count == 0
  64 + if file_list.count > 1 && ENV["BACKUP"].nil?
  65 + puts "Found more than one backup, please specify which one you want to restore:"
  66 + puts "rake gitlab:backup:restore BACKUP=timestamp_of_backup"
  67 + exit 1
  68 + end
  69 +
  70 + tar_file = ENV["BACKUP"].nil? ? File.join("#{file_list.first}_gitlab_backup.tar") : File.join(ENV["BACKUP"] + "_gitlab_backup.tar")
  71 +
  72 + unless File.exists?(tar_file)
  73 + puts "The specified backup doesn't exist!"
  74 + exit 1
  75 + end
  76 +
  77 + print "Unpacking backup ... "
  78 + unless Kernel.system("tar -xf #{tar_file}")
  79 + puts "failed".red
  80 + exit 1
  81 + else
  82 + puts "done".green
  83 + end
  84 +
  85 + settings = YAML.load_file("backup_information.yml")
  86 + ENV["VERSION"] = "#{settings[:db_version]}" if settings[:db_version].to_i > 0
  87 +
  88 + # backups directory is not always sub of Rails root and able to execute the git rev-parse below
  89 + begin
  90 + Dir.chdir(Rails.root)
  91 +
  92 + # restoring mismatching backups can lead to unexpected problems
  93 + if settings[:gitlab_version] != %x{git rev-parse HEAD}.gsub(/\n/, "")
  94 + puts "GitLab version mismatch:".red
  95 + puts " Your current HEAD differs from the HEAD in the backup!".red
  96 + puts " Please switch to the following revision and try again:".red
  97 + puts " revision: #{settings[:gitlab_version]}".red
  98 + exit 1
  99 + end
  100 + ensure
  101 + # chdir back to original intended dir
  102 + Dir.chdir(Gitlab.config.backup.path)
  103 + end
  104 + end
  105 + end
  106 +end
... ...
lib/extracts_path.rb
... ... @@ -95,13 +95,9 @@ module ExtractsPath
95 95 # resolved (e.g., when a user inserts an invalid path or ref).
96 96 def assign_ref_vars
97 97 @id = get_id
98   -
99 98 @ref, @path = extract_ref(@id)
100   -
101 99 @repo = @project.repository
102   -
103 100 @commit = @repo.commit(@ref)
104   -
105 101 @tree = Tree.new(@repo, @commit.id, @ref, @path)
106 102 @hex_path = Digest::SHA1.hexdigest(@path)
107 103 @logs_path = logs_file_project_ref_path(@project, @ref, @path)
... ...
lib/gitlab/blacklist.rb
... ... @@ -3,7 +3,7 @@ module Gitlab
3 3 extend self
4 4  
5 5 def path
6   - %w(admin dashboard groups help profile projects search public assets u s teams merge_requests issues users snippets services)
  6 + %w(admin dashboard groups help profile projects search public assets u s teams merge_requests issues users snippets services repository)
7 7 end
8 8 end
9 9 end
... ...
lib/gitlab/diff_parser.rb 0 → 100644
... ... @@ -0,0 +1,77 @@
  1 +module Gitlab
  2 + class DiffParser
  3 + include Enumerable
  4 +
  5 + attr_reader :lines, :new_path
  6 +
  7 + def initialize(diff)
  8 + @lines = diff.diff.lines.to_a
  9 + @new_path = diff.new_path
  10 + end
  11 +
  12 + def each
  13 + line_old = 1
  14 + line_new = 1
  15 + type = nil
  16 +
  17 + lines_arr = ::Gitlab::InlineDiff.processing lines
  18 + lines_arr.each do |line|
  19 + raw_line = line.dup
  20 +
  21 + next if line.match(/^\-\-\- \/dev\/null/)
  22 + next if line.match(/^\+\+\+ \/dev\/null/)
  23 + next if line.match(/^\-\-\- a/)
  24 + next if line.match(/^\+\+\+ b/)
  25 +
  26 + full_line = html_escape(line.gsub(/\n/, ''))
  27 + full_line = ::Gitlab::InlineDiff.replace_markers full_line
  28 +
  29 + if line.match(/^@@ -/)
  30 + type = "match"
  31 +
  32 + line_old = line.match(/\-[0-9]*/)[0].to_i.abs rescue 0
  33 + line_new = line.match(/\+[0-9]*/)[0].to_i.abs rescue 0
  34 +
  35 + next if line_old == 1 && line_new == 1 #top of file
  36 + yield(full_line, type, nil, nil, nil)
  37 + next
  38 + else
  39 + type = identification_type(line)
  40 + line_code = generate_line_code(new_path, line_new, line_old)
  41 + yield(full_line, type, line_code, line_new, line_old, raw_line)
  42 + end
  43 +
  44 +
  45 + if line[0] == "+"
  46 + line_new += 1
  47 + elsif line[0] == "-"
  48 + line_old += 1
  49 + else
  50 + line_new += 1
  51 + line_old += 1
  52 + end
  53 + end
  54 + end
  55 +
  56 + private
  57 +
  58 + def identification_type(line)
  59 + if line[0] == "+"
  60 + "new"
  61 + elsif line[0] == "-"
  62 + "old"
  63 + else
  64 + nil
  65 + end
  66 + end
  67 +
  68 + def generate_line_code(path, line_new, line_old)
  69 + "#{Digest::SHA1.hexdigest(path)}_#{line_old}_#{line_new}"
  70 + end
  71 +
  72 + def html_escape str
  73 + replacements = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;', "'" => '&#39;' }
  74 + str.gsub(/[&"'><]/, replacements)
  75 + end
  76 + end
  77 +end
... ...
lib/gitlab/markdown.rb
... ... @@ -167,7 +167,7 @@ module Gitlab
167 167  
168 168 def reference_user(identifier)
169 169 if member = @project.team_members.find { |user| user.username == identifier }
170   - link_to("@#{identifier}", user_path(identifier), html_options.merge(class: "gfm gfm-team_member #{html_options[:class]}")) if member
  170 + link_to("@#{identifier}", user_url(identifier), html_options.merge(class: "gfm gfm-team_member #{html_options[:class]}")) if member
171 171 end
172 172 end
173 173  
... ...
lib/gitlab/satellite/edit_file_action.rb
... ... @@ -49,7 +49,7 @@ module Gitlab
49 49 protected
50 50  
51 51 def can_edit?(last_commit)
52   - current_last_commit = @project.repository.last_commit_for(ref, file_path).sha
  52 + current_last_commit = Gitlab::Git::Commit.last_for_path(@project.repository, ref, file_path).sha
53 53 last_commit == current_last_commit
54 54 end
55 55 end
... ...
lib/tasks/gitlab/backup.rake
... ... @@ -11,49 +11,10 @@ namespace :gitlab do
11 11 Rake::Task["gitlab:backup:repo:create"].invoke
12 12 Rake::Task["gitlab:backup:uploads:create"].invoke
13 13  
14   -
15   - # saving additional informations
16   - s = {}
17   - s[:db_version] = "#{ActiveRecord::Migrator.current_version}"
18   - s[:backup_created_at] = Time.now
19   - s[:gitlab_version] = %x{git rev-parse HEAD}.gsub(/\n/,"")
20   - s[:tar_version] = %x{tar --version | head -1}.gsub(/\n/,"")
21   -
22   - Dir.chdir(Gitlab.config.backup.path)
23   -
24   - File.open("#{Gitlab.config.backup.path}/backup_information.yml", "w+") do |file|
25   - file << s.to_yaml.gsub(/^---\n/,'')
26   - end
27   -
28   - # create archive
29   - print "Creating backup archive: #{s[:backup_created_at].to_i}_gitlab_backup.tar ... "
30   - if Kernel.system("tar -cf #{s[:backup_created_at].to_i}_gitlab_backup.tar repositories/ db/ uploads/ backup_information.yml")
31   - puts "done".green
32   - else
33   - puts "failed".red
34   - end
35   -
36   - # cleanup: remove tmp files
37   - print "Deleting tmp directories ... "
38   - if Kernel.system("rm -rf repositories/ db/ uploads/ backup_information.yml")
39   - puts "done".green
40   - else
41   - puts "failed".red
42   - end
43   -
44   - # delete backups
45   - print "Deleting old backups ... "
46   - if Gitlab.config.backup.keep_time > 0
47   - file_list = Dir.glob("*_gitlab_backup.tar").map { |f| f.split(/_/).first.to_i }
48   - file_list.sort.each do |timestamp|
49   - if Time.at(timestamp) < (Time.now - Gitlab.config.backup.keep_time)
50   - %x{rm #{timestamp}_gitlab_backup.tar}
51   - end
52   - end
53   - puts "done".green
54   - else
55   - puts "skipping".yellow
56   - end
  14 + backup = Backup::Manager.new
  15 + backup.pack
  16 + backup.cleanup
  17 + backup.remove_old
57 18 end
58 19  
59 20 # Restore backup of GitLab system
... ... @@ -61,64 +22,15 @@ namespace :gitlab do
61 22 task restore: :environment do
62 23 warn_user_is_not_gitlab
63 24  
64   - Dir.chdir(Gitlab.config.backup.path)
65   -
66   - # check for existing backups in the backup dir
67   - file_list = Dir.glob("*_gitlab_backup.tar").each.map { |f| f.split(/_/).first.to_i }
68   - puts "no backups found" if file_list.count == 0
69   - if file_list.count > 1 && ENV["BACKUP"].nil?
70   - puts "Found more than one backup, please specify which one you want to restore:"
71   - puts "rake gitlab:backup:restore BACKUP=timestamp_of_backup"
72   - exit 1
73   - end
74   -
75   - tar_file = ENV["BACKUP"].nil? ? File.join("#{file_list.first}_gitlab_backup.tar") : File.join(ENV["BACKUP"] + "_gitlab_backup.tar")
76   -
77   - unless File.exists?(tar_file)
78   - puts "The specified backup doesn't exist!"
79   - exit 1
80   - end
81   -
82   - print "Unpacking backup ... "
83   - unless Kernel.system("tar -xf #{tar_file}")
84   - puts "failed".red
85   - exit 1
86   - else
87   - puts "done".green
88   - end
89   -
90   - settings = YAML.load_file("backup_information.yml")
91   - ENV["VERSION"] = "#{settings[:db_version]}" if settings[:db_version].to_i > 0
92   -
93   - # backups directory is not always sub of Rails root and able to execute the git rev-parse below
94   - begin
95   - Dir.chdir(Rails.root)
96   -
97   - # restoring mismatching backups can lead to unexpected problems
98   - if settings[:gitlab_version] != %x{git rev-parse HEAD}.gsub(/\n/, "")
99   - puts "GitLab version mismatch:".red
100   - puts " Your current HEAD differs from the HEAD in the backup!".red
101   - puts " Please switch to the following revision and try again:".red
102   - puts " revision: #{settings[:gitlab_version]}".red
103   - exit 1
104   - end
105   - ensure
106   - # chdir back to original intended dir
107   - Dir.chdir(Gitlab.config.backup.path)
108   - end
  25 + backup = Backup::Manager.new
  26 + backup.unpack
109 27  
110 28 Rake::Task["gitlab:backup:db:restore"].invoke
111 29 Rake::Task["gitlab:backup:repo:restore"].invoke
112 30 Rake::Task["gitlab:backup:uploads:restore"].invoke
113 31 Rake::Task["gitlab:shell:setup"].invoke
114 32  
115   - # cleanup: remove tmp files
116   - print "Deleting tmp directories ... "
117   - if Kernel.system("rm -rf repositories/ db/ uploads/ backup_information.yml")
118   - puts "done".green
119   - else
120   - puts "failed".red
121   - end
  33 + backup.cleanup
122 34 end
123 35  
124 36 namespace :repo do
... ...
lib/tasks/migrate/migrate_inline_notes.rake 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +desc "GITLAB | Migrate inline notes"
  2 +task migrate_inline_notes: :environment do
  3 + Note.where('line_code IS NOT NULL').find_each(batch_size: 100) do |note|
  4 + begin
  5 + note.set_diff
  6 + if note.save
  7 + print '.'
  8 + else
  9 + print 'F'
  10 + end
  11 + rescue
  12 + print 'F'
  13 + end
  14 + end
  15 +end
  16 +
... ...
lib/tasks/migrate/migrate_keys.rake
1 1 desc "GITLAB | Migrate SSH Keys"
2 2 task migrate_keys: :environment do
3 3 puts "This will add fingerprint to ssh keys in db"
  4 + puts "If you have duplicate keys https://github.com/gitlabhq/gitlabhq/issues/4453 all but the first will be deleted".yellow
4 5 ask_to_continue
5 6  
6 7 Key.find_each(batch_size: 20) do |key|
7 8 if key.valid? && key.save
8 9 print '.'
  10 + elsif key.fingerprint.present?
  11 + puts "\nDeleting #{key.inspect}".yellow
  12 + key.destroy
9 13 else
10 14 print 'F'
11 15 end
12 16 end
  17 + print "\n"
13 18 end
14 19  
15 20  
... ...
spec/controllers/commit_controller_spec.rb
... ... @@ -2,8 +2,8 @@ require &#39;spec_helper&#39;
2 2  
3 3 describe Projects::CommitController do
4 4 let(:project) { create(:project_with_code) }
5   - let(:user) { create(:user) }
6   - let(:commit) { project.repository.last_commit_for("master") }
  5 + let(:user) { create(:user) }
  6 + let(:commit) { project.repository.commit("master") }
7 7  
8 8 before do
9 9 sign_in(user)
... ...
spec/features/security/project_access_spec.rb
... ... @@ -175,8 +175,8 @@ describe &quot;Application access&quot; do
175 175 it { should be_denied_for :visitor }
176 176 end
177 177  
178   - describe "GET /project_code/repository" do
179   - subject { project_repository_path(project) }
  178 + describe "GET /project_code/branches/recent" do
  179 + subject { recent_project_branches_path(project) }
180 180  
181 181 it { should be_allowed_for master }
182 182 it { should be_allowed_for reporter }
... ... @@ -186,7 +186,7 @@ describe &quot;Application access&quot; do
186 186 it { should be_denied_for :visitor }
187 187 end
188 188  
189   - describe "GET /project_code/repository/branches" do
  189 + describe "GET /project_code/branches" do
190 190 subject { project_branches_path(project) }
191 191  
192 192 before do
... ... @@ -202,7 +202,7 @@ describe &quot;Application access&quot; do
202 202 it { should be_denied_for :visitor }
203 203 end
204 204  
205   - describe "GET /project_code/repository/tags" do
  205 + describe "GET /project_code/tags" do
206 206 subject { project_tags_path(project) }
207 207  
208 208 before do
... ... @@ -417,8 +417,8 @@ describe &quot;Application access&quot; do
417 417 it { should be_denied_for :visitor }
418 418 end
419 419  
420   - describe "GET /project_code/repository" do
421   - subject { project_repository_path(project) }
  420 + describe "GET /project_code/branches/recent" do
  421 + subject { recent_project_branches_path(project) }
422 422  
423 423 it { should be_allowed_for master }
424 424 it { should be_allowed_for reporter }
... ... @@ -428,7 +428,7 @@ describe &quot;Application access&quot; do
428 428 it { should be_denied_for :visitor }
429 429 end
430 430  
431   - describe "GET /project_code/repository/branches" do
  431 + describe "GET /project_code/branches" do
432 432 subject { project_branches_path(project) }
433 433  
434 434 before do
... ... @@ -444,7 +444,7 @@ describe &quot;Application access&quot; do
444 444 it { should be_denied_for :visitor }
445 445 end
446 446  
447   - describe "GET /project_code/repository/tags" do
  447 + describe "GET /project_code/tags" do
448 448 subject { project_tags_path(project) }
449 449  
450 450 before do
... ...
spec/requests/api/internal_spec.rb
... ... @@ -100,6 +100,32 @@ describe API::API do
100 100 end
101 101 end
102 102 end
  103 +
  104 + context "deploy key" do
  105 + let(:key) { create(:deploy_key) }
  106 +
  107 + context "added to project" do
  108 + before do
  109 + key.projects << project
  110 + end
  111 +
  112 + it do
  113 + archive(key, project)
  114 +
  115 + response.status.should == 200
  116 + response.body.should == 'true'
  117 + end
  118 + end
  119 +
  120 + context "not added to project" do
  121 + it do
  122 + archive(key, project)
  123 +
  124 + response.status.should == 200
  125 + response.body.should == 'false'
  126 + end
  127 + end
  128 + end
103 129 end
104 130  
105 131 def pull(key, project)
... ... @@ -121,4 +147,14 @@ describe API::API do
121 147 action: 'git-receive-pack'
122 148 )
123 149 end
  150 +
  151 + def archive(key, project)
  152 + get(
  153 + api("/internal/allowed"),
  154 + ref: 'master',
  155 + key_id: key.id,
  156 + project: project.path_with_namespace,
  157 + action: 'git-upload-archive'
  158 + )
  159 + end
124 160 end
... ...
spec/services/notification_service_spec.rb
... ... @@ -47,7 +47,7 @@ describe NotificationService do
47 47 end
48 48  
49 49 context 'commit note' do
50   - let(:note) { create :note_on_commit }
  50 + let(:note) { create(:note_on_commit) }
51 51  
52 52 before do
53 53 build_team(note.project)
... ... @@ -55,32 +55,35 @@ describe NotificationService do
55 55  
56 56 describe :new_note do
57 57 it do
58   - should_email(@u_watcher.id)
59   - should_not_email(note.author_id)
60   - should_not_email(@u_participating.id)
61   - should_not_email(@u_disabled.id)
  58 + should_email(@u_watcher.id, note)
  59 + should_not_email(@u_mentioned.id, note)
  60 + should_not_email(note.author_id, note)
  61 + should_not_email(@u_participating.id, note)
  62 + should_not_email(@u_disabled.id, note)
62 63 notification.new_note(note)
63 64 end
64 65  
65 66 it do
66   - create(:note_on_commit,
  67 + new_note = create(:note_on_commit,
67 68 author: @u_participating,
68 69 project_id: note.project_id,
69   - commit_id: note.commit_id)
70   -
71   - should_email(@u_watcher.id)
72   - should_email(@u_participating.id)
73   - should_not_email(note.author_id)
74   - should_not_email(@u_disabled.id)
75   - notification.new_note(note)
  70 + commit_id: note.commit_id,
  71 + note: '@mention referenced')
  72 +
  73 + should_email(@u_watcher.id, new_note)
  74 + should_email(@u_mentioned.id, new_note)
  75 + should_not_email(new_note.author_id, new_note)
  76 + should_not_email(@u_participating.id, new_note)
  77 + should_not_email(@u_disabled.id, new_note)
  78 + notification.new_note(new_note)
76 79 end
77 80  
78   - def should_email(user_id)
79   - Notify.should_receive(:note_commit_email).with(user_id, note.id)
  81 + def should_email(user_id, n)
  82 + Notify.should_receive(:note_commit_email).with(user_id, n.id)
80 83 end
81 84  
82   - def should_not_email(user_id)
83   - Notify.should_not_receive(:note_commit_email).with(user_id, note.id)
  85 + def should_not_email(user_id, n)
  86 + Notify.should_not_receive(:note_commit_email).with(user_id, n.id)
84 87 end
85 88 end
86 89 end
... ...