diff options
139 files changed, 1142 insertions, 735 deletions
diff --git a/CHANGELOG b/CHANGELOG index 9e10ea4afb7..92500596656 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +v 7.9.0 (unreleased) + - Fix broken access control for note attachments (Hannes Rosenögger) + v 7.8.0 (unreleased) - Replace highlight.js with rouge-fork rugments (Stefan Tatschner) - Make project search case insensitive (Hannes Rosenögger) @@ -10,7 +13,7 @@ v 7.8.0 (unreleased) - View note image attachments in new tab when clicked instead of downloading them - Improve sorting logic in UI and API. Explicitly define what sorting method is used by default - Allow more variations for commit messages closing issues (Julien Bianchi and Hannes Rosenögger) - - Fix overflow at sidebar when have several itens + - Fix overflow at sidebar when have several items - Add notes for label changes in issue and merge requests - Show tags in commit view (Hannes Rosenögger) - Only count a user's vote once on a merge request or issue (Michael Clarke) @@ -54,6 +57,13 @@ v 7.8.0 (unreleased) - Link head panel titles to relevant root page. - Allow users that signed up via OAuth to set their password in order to use Git over HTTP(S). - Upgrade Rails gem to version 4.1.9. + - Show users button to share their newly created public or internal projects on twitter + - Add quick help links to the GitLab pricing and feature comparison pages. + - Fix duplicate authorized applications in user profile and incorrect application client count in admin area. + - Make sure Markdown previews always use the same styling as the eventual destination. + - Remove deprecated Group#owner_id from API + - Show projects user contributed to on user page. Show stars near project on user page. + - Improve database performance for GitLab v 7.7.2 - Update GitLab Shell to version 2.4.2 that fixes a bug when developers can push to protected branch diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION index 35cee72dcbf..aedc15bb0c6 100644 --- a/GITLAB_SHELL_VERSION +++ b/GITLAB_SHELL_VERSION @@ -1 +1 @@ -2.4.3 +2.5.3 diff --git a/Gemfile.lock b/Gemfile.lock index 1cd7caa782d..2e3dc252a09 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -47,6 +47,9 @@ GEM astrolabe (1.3.0) parser (>= 2.2.0.pre.3, < 3.0) attr_required (1.0.0) + autoprefixer-rails (5.1.6) + execjs + json awesome_print (1.2.0) axiom-types (0.0.5) descendants_tracker (~> 0.0.1) @@ -57,8 +60,9 @@ GEM erubis (>= 2.6.6) binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) - bootstrap-sass (3.0.3.0) - sass (~> 3.2) + bootstrap-sass (3.3.3) + autoprefixer-rails (>= 5.0.0.1) + sass (>= 3.2.19) browser (0.7.2) builder (3.2.2) cal-heatmap-rails (0.0.1) diff --git a/PROCESS.md b/PROCESS.md index 5cc25de05a4..1b6b3e7d32d 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -71,7 +71,7 @@ Thanks for the issue report. Please reformat your issue to conform to the issue ### Feature requests -Thank you for your interest in improving GitLab. We don't use the issue tracker for feature requests. Things that are wrong but are not a regression compared to older versions of GitLab are considered feature requests and not issues. Please use the [feature request forum](http://feedback.gitlab.com/) for this purpose or create a merge request implementing this feature. Have a look at the \[contribution guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md) for more information. +Thank you for your interest in improving GitLab. We don't use the issue tracker for feature requests. Things that are wrong but are not a regression compared to older versions of GitLab are considered feature requests and not issues. Please use the \[feature request forum\]\(http://feedback.gitlab.com/) for this purpose or create a merge request implementing this feature. Have a look at the \[contribution guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md) for more information. ### Issue report for old version diff --git a/README.md b/README.md index 8bfb301d1c7..b4f28a41be3 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ Please see the [requirements documentation](doc/install/requirements.md) for sys ## Installation -The recommended way to install GitLab is using the provided [Omnibus packages](https://about.gitlab.com/downloads/). Compared to a manual installation, this is faster and less error prone. Just select your operating system, download the respective package (Debian or RPM) and install it using the system's package manager. +The recommended way to install GitLab is using the provided [Omnibus packages](https://about.gitlab.com/downloads/). Compared to an installation from source, this is faster and less error prone. Just select your operating system, download the respective package (Debian or RPM) and install it using the system's package manager. There are various other options to install GitLab, please refer to the [installation page on the GitLab website](https://about.gitlab.com/installation/) for more information. @@ -76,7 +76,7 @@ Since 2011 a minor or major version of GitLab is released on the 22nd of every m ## Upgrading -For updating the Omnibus installation please see the [update documentation](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/update.md). For manual installations there is an [upgrader script](doc/update/upgrader.md) and there are [upgrade guides](doc/update) detailing all necessary commands to migrate to the next version. +For updating the Omnibus installation please see the [update documentation](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/update.md). For installations from source there is an [upgrader script](doc/update/upgrader.md) and there are [upgrade guides](doc/update) detailing all necessary commands to migrate to the next version. ## Install a development environment @@ -1 +1 @@ -7.8.0.pre +7.9.0.pre diff --git a/app/assets/javascripts/issue.js.coffee b/app/assets/javascripts/issue.js.coffee index 45c248e6fb6..9b7c1be8355 100644 --- a/app/assets/javascripts/issue.js.coffee +++ b/app/assets/javascripts/issue.js.coffee @@ -15,3 +15,9 @@ class @Issue "issue" updateTaskState ) + + $('.issuable-affix').affix offset: + top: -> + @top = $('.issue-details').outerHeight(true) + 25 + bottom: -> + @bottom = $('.footer').outerHeight(true) diff --git a/app/assets/javascripts/issues.js.coffee b/app/assets/javascripts/issues.js.coffee index 2499ad5ad80..6513f4bcefc 100644 --- a/app/assets/javascripts/issues.js.coffee +++ b/app/assets/javascripts/issues.js.coffee @@ -15,7 +15,7 @@ $(this).html totalIssues + 1 else $(this).html totalIssues - 1 - $("body").on "click", ".issues-filters .dropdown-menu a", -> + $("body").on "click", ".issues-other-filters .dropdown-menu a", -> $('.issues-list').block( message: null, overlayCSS: @@ -77,9 +77,9 @@ ids.push $(value).attr("data-id") $("#update_issues_ids").val ids - $(".issues-filters").hide() + $(".issues-other-filters").hide() $(".issues_bulk_update").show() else $("#update_issues_ids").val [] $(".issues_bulk_update").hide() - $(".issues-filters").show() + $(".issues-other-filters").show() diff --git a/app/assets/javascripts/merge_request.js.coffee b/app/assets/javascripts/merge_request.js.coffee index 5bcbd56852d..757592842eb 100644 --- a/app/assets/javascripts/merge_request.js.coffee +++ b/app/assets/javascripts/merge_request.js.coffee @@ -20,6 +20,12 @@ class @MergeRequest if $("a.btn-close").length $("li.task-list-item input:checkbox").prop("disabled", false) + $('.issuable-affix').affix offset: + top: -> + @top = $('.merge-request-details').outerHeight(true) + 70 + bottom: -> + @bottom = $('.footer').outerHeight(true) + # Local jQuery finder $: (selector) -> this.$el.find(selector) diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee index 47c5ecdedf1..1c090bd06dc 100644 --- a/app/assets/javascripts/notes.js.coffee +++ b/app/assets/javascripts/notes.js.coffee @@ -77,7 +77,7 @@ class @Notes $(document).off "click", ".js-discussion-reply-button" $(document).off "click", ".js-add-diff-note-button" $(document).off "visibilitychange" - $(document).off "keypress", @notes_forms + $(document).off "keydown", @notes_forms $(document).off "keyup", ".js-note-text" $(document).off "click", ".js-note-target-reopen" $(document).off "click", ".js-note-target-close" @@ -272,7 +272,7 @@ class @Notes note_li = $(".note-row-" + note.id) note_li.replaceWith(note.html) note_li.find('.note-edit-form').hide() - note_li.find('.note-text').show() + note_li.find('.note-body > .note-text').show() ### Called in response to clicking the edit note link @@ -284,7 +284,7 @@ class @Notes showEditForm: (e) -> e.preventDefault() note = $(this).closest(".note") - note.find(".note-text").hide() + note.find(".note-body > .note-text").hide() note.find(".note-header").hide() base_form = note.find(".note-edit-form") form = base_form.clone().insertAfter(base_form) @@ -311,7 +311,7 @@ class @Notes cancelEdit: (e) -> e.preventDefault() note = $(this).closest(".note") - note.find(".note-text").show() + note.find(".note-body > .note-text").show() note.find(".note-header").show() note.find(".current-note-edit-form").remove() @@ -345,7 +345,7 @@ class @Notes removeAttachment: -> note = $(this).closest(".note") note.find(".note-attachment").remove() - note.find(".note-text").show() + note.find(".note-body > .note-text").show() note.find(".js-note-attachment-delete").hide() note.find(".note-edit-form").hide() diff --git a/app/assets/stylesheets/generic/typography.scss b/app/assets/stylesheets/generic/typography.scss index 58243bc5ba2..c547ebb3aaf 100644 --- a/app/assets/stylesheets/generic/typography.scss +++ b/app/assets/stylesheets/generic/typography.scss @@ -17,6 +17,10 @@ h3.page-title { font-size: 22px; } +h4.page-title { + margin-top: 0px; +} + h6 { color: #888; text-transform: uppercase; @@ -131,4 +135,4 @@ textarea.js-gfm-input { .strikethrough { text-decoration: line-through; -}
\ No newline at end of file +} diff --git a/app/assets/stylesheets/highlight/dark.scss b/app/assets/stylesheets/highlight/dark.scss index 4095d35b05f..fcd4d47bace 100644 --- a/app/assets/stylesheets/highlight/dark.scss +++ b/app/assets/stylesheets/highlight/dark.scss @@ -12,6 +12,7 @@ border-left: 1px solid #666; } + // highlight line via anchor pre.hll { background-color: #fff !important; } diff --git a/app/assets/stylesheets/highlight/monokai.scss b/app/assets/stylesheets/highlight/monokai.scss index 730018e3e28..bcd2e716657 100644 --- a/app/assets/stylesheets/highlight/monokai.scss +++ b/app/assets/stylesheets/highlight/monokai.scss @@ -12,6 +12,11 @@ border-left: 1px solid #555; } + // highlight line via anchor + pre.hll { + background-color: #49483e !important; + } + .hll { background-color: #49483e } .c { color: #75715e } /* Comment */ .err { color: #960050; background-color: #1e0010 } /* Error */ diff --git a/app/assets/stylesheets/highlight/solarized_dark.scss b/app/assets/stylesheets/highlight/solarized_dark.scss index be6904100ec..4a6b759bd2c 100644 --- a/app/assets/stylesheets/highlight/solarized_dark.scss +++ b/app/assets/stylesheets/highlight/solarized_dark.scss @@ -12,6 +12,11 @@ border-left: 1px solid #113b46; } + // highlight line via anchor + pre.hll { + background-color: #073642 !important; + } + /* Solarized Dark For use with Jekyll and Pygments diff --git a/app/assets/stylesheets/highlight/solarized_light.scss b/app/assets/stylesheets/highlight/solarized_light.scss index 55be6e30383..7254f4d7ac1 100644 --- a/app/assets/stylesheets/highlight/solarized_light.scss +++ b/app/assets/stylesheets/highlight/solarized_light.scss @@ -12,6 +12,11 @@ border-left: 1px solid #c5d0d4; } + // highlight line via anchor + pre.hll { + background-color: #eee8d5 !important; + } + /* Solarized Light For use with Jekyll and Pygments diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss index 050a5d241a6..4d6f5dfd91e 100644 --- a/app/assets/stylesheets/highlight/white.scss +++ b/app/assets/stylesheets/highlight/white.scss @@ -12,6 +12,11 @@ border-left: 1px solid #bbb; } + // highlight line via anchor + pre.hll { + background-color: #f8eec7 !important; + } + .hll { background-color: #f8f8f8 } .c { color: #999988; font-style: italic; } .err { color: #a61717; background-color: #e3d2d2; } diff --git a/app/assets/stylesheets/sections/dashboard.scss b/app/assets/stylesheets/sections/dashboard.scss index 77d403cc687..feb9a4ad295 100644 --- a/app/assets/stylesheets/sections/dashboard.scss +++ b/app/assets/stylesheets/sections/dashboard.scss @@ -120,6 +120,15 @@ } } +.dash-new-group { + background: $bg_success; + border: 1px solid $border_success; + + a { + color: #FFF; + } +} + .dash-list .str-truncated { max-width: 72%; } diff --git a/app/assets/stylesheets/sections/events.scss b/app/assets/stylesheets/sections/events.scss index 9582c995980..b7614513216 100644 --- a/app/assets/stylesheets/sections/events.scss +++ b/app/assets/stylesheets/sections/events.scss @@ -64,6 +64,10 @@ .md { font-size: 13px; + + iframe.twitter-share-button { + vertical-align: bottom; + } } pre { diff --git a/app/assets/stylesheets/sections/issuable.scss b/app/assets/stylesheets/sections/issuable.scss new file mode 100644 index 00000000000..75bd39853bd --- /dev/null +++ b/app/assets/stylesheets/sections/issuable.scss @@ -0,0 +1,25 @@ +@media (max-width: $screen-sm-max) { + .issuable-affix { + margin-top: 20px; + } +} + +@media (max-width: $screen-md-max) { + .issuable-affix { + position: static; + } +} + +@media (min-width: $screen-md-max) { + .issuable-affix { + &.affix-top { + position: static; + } + + &.affix { + position: fixed; + top: 70px; + width: 220px; + } + } +} diff --git a/app/assets/stylesheets/sections/issues.scss b/app/assets/stylesheets/sections/issues.scss index 7a9d3334d96..ccfc9b704a6 100644 --- a/app/assets/stylesheets/sections/issues.scss +++ b/app/assets/stylesheets/sections/issues.scss @@ -94,8 +94,15 @@ } } -.issue-show-labels .color-label { - padding: 6px 10px; +.issue-show-labels { + a { + margin-right: 5px; + margin-bottom: 5px; + display: inline-block; + .color-label { + padding: 6px 10px; + } + } } form.edit-issue { diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/sections/merge_requests.scss index 0e27c389387..a3eabb5e330 100644 --- a/app/assets/stylesheets/sections/merge_requests.scss +++ b/app/assets/stylesheets/sections/merge_requests.scss @@ -24,6 +24,7 @@ .accept-control { display: inline-block; + margin: 0; margin-left: 20px; padding: 10px 0; line-height: 20px; @@ -31,6 +32,7 @@ .remove_source_checkbox { margin: 0; + font-weight: bold; } } } @@ -185,6 +187,13 @@ } } -.merge-request-show-labels .label { - padding: 6px 10px; +.merge-request-show-labels { + a { + margin-right: 5px; + margin-bottom: 5px; + display: inline-block; + .color-label { + padding: 6px 10px; + } + } } diff --git a/app/assets/stylesheets/sections/nav_sidebar.scss b/app/assets/stylesheets/sections/nav_sidebar.scss index 9c7d1a03a03..3ef2a578b7f 100644 --- a/app/assets/stylesheets/sections/nav_sidebar.scss +++ b/app/assets/stylesheets/sections/nav_sidebar.scss @@ -40,12 +40,16 @@ .nav-sidebar li { &.active a { - color: #111; - background: #EEE; + color: #333; + background: #FFF; font-weight: bold; + border: 1px solid #EEE; + border-right: 1px solid transparent; + border-left: 3px solid $style_color; &.no-highlight { background: none; + border: none; } i { @@ -65,7 +69,7 @@ color: #555; display: block; text-decoration: none; - padding: 6px 15px; + padding: 8px 15px; font-size: 13px; line-height: 20px; text-shadow: 0 1px 2px #FFF; @@ -133,7 +137,7 @@ li a { padding-left: 18px; font-size: 14px; - padding: 10px 15px; + padding: 8px 15px; text-align: center; & > span { diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index 7458542fc73..2b0c500e97a 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -26,6 +26,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController :signup_enabled, :signin_enabled, :gravatar_enabled, + :twitter_sharing_enabled, :sign_in_text, :home_page_url ) diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 9e59264e418..eca7b39bcdf 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -12,11 +12,7 @@ class DashboardController < ApplicationController @groups = current_user.authorized_groups.order_name_asc @has_authorized_projects = @projects.count > 0 @projects_count = @projects.count - @projects = @projects.limit(@projects_limit) - - @events = Event.in_projects(current_user.authorized_projects.pluck(:id)) - @events = @event_filter.apply_filter(@events) - @events = @events.limit(20).offset(params[:offset] || 0) + @projects = @projects.includes(:namespace).limit(@projects_limit) @last_push = current_user.recent_push @@ -24,8 +20,16 @@ class DashboardController < ApplicationController respond_to do |format| format.html - format.json { pager_json("events/_events", @events.count) } - format.atom { render layout: false } + + format.json do + load_events + pager_json("events/_events", @events.count) + end + + format.atom do + load_events + render layout: false + end end end @@ -74,4 +78,10 @@ class DashboardController < ApplicationController def load_projects @projects = current_user.authorized_projects.sorted_by_activity.non_archived end + + def load_events + @events = Event.in_projects(current_user.authorized_projects.pluck(:id)) + @events = @event_filter.apply_filter(@events).with_associations + @events = @events.limit(20).offset(params[:offset] || 0) + end end diff --git a/app/controllers/explore/projects_controller.rb b/app/controllers/explore/projects_controller.rb index d75fd8e72fa..0e5891ae807 100644 --- a/app/controllers/explore/projects_controller.rb +++ b/app/controllers/explore/projects_controller.rb @@ -18,7 +18,7 @@ class Explore::ProjectsController < ApplicationController def starred @starred_projects = ProjectsFinder.new.execute(current_user) - @starred_projects = @starred_projects.order('star_count DESC') + @starred_projects = @starred_projects.reorder('star_count DESC') @starred_projects = @starred_projects.page(params[:page]).per(10) end end diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index aad3709090e..d011523c94f 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -10,11 +10,11 @@ class GroupsController < ApplicationController # Load group projects before_filter :load_projects, except: [:new, :create, :projects, :edit, :update] + before_filter :event_filter, only: :show + before_filter :set_title, only: [:new, :create] layout :determine_layout - before_filter :set_title, only: [:new, :create] - def new @group = Group.new end @@ -32,15 +32,21 @@ class GroupsController < ApplicationController end def show - @events = Event.in_projects(project_ids) - @events = event_filter.apply_filter(@events) - @events = @events.limit(20).offset(params[:offset] || 0) @last_push = current_user.recent_push if current_user + @projects = @projects.includes(:namespace) respond_to do |format| format.html - format.json { pager_json("events/_events", @events.count) } - format.atom { render layout: false } + + format.json do + load_events + pager_json("events/_events", @events.count) + end + + format.atom do + load_events + render layout: false + end end end @@ -149,4 +155,10 @@ class GroupsController < ApplicationController def group_params params.require(:group).permit(:name, :description, :path, :avatar) end + + def load_events + @events = Event.in_projects(project_ids) + @events = event_filter.apply_filter(@events).with_associations + @events = @events.limit(20).offset(params[:offset] || 0) + end end diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb index f7584c03411..a7863aba756 100644 --- a/app/controllers/profiles_controller.rb +++ b/app/controllers/profiles_controller.rb @@ -16,6 +16,7 @@ class ProfilesController < ApplicationController def applications @applications = current_user.oauth_applications @authorized_tokens = current_user.oauth_authorized_tokens + @authorized_apps = @authorized_tokens.map(&:application).uniq end def update diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb index dafbb4d51ea..08c7ce3f37d 100644 --- a/app/controllers/projects/tags_controller.rb +++ b/app/controllers/projects/tags_controller.rb @@ -27,7 +27,7 @@ class Projects::TagsController < Projects::ApplicationController tag = @repository.find_tag(params[:id]) if tag && @repository.rm_tag(tag.name) - Event.create_ref_event(@project, current_user, tag, 'rm', 'refs/tags') + EventCreateService.new.push_ref(@project, current_user, tag, 'rm', 'refs/tags') end respond_to do |format| diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index cf039d5f132..38341b1c8c6 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -5,9 +5,10 @@ class ProjectsController < ApplicationController # Authorize before_filter :authorize_admin_project!, only: [:edit, :update, :destroy, :transfer, :archive, :unarchive] + before_filter :set_title, only: [:new, :create] + before_filter :event_filter, only: :show layout 'navless', only: [:new, :create, :fork] - before_filter :set_title, only: [:new, :create] def new @project = Project.new @@ -65,9 +66,6 @@ class ProjectsController < ApplicationController end limit = (params[:limit] || 20).to_i - @events = @project.events.recent - @events = event_filter.apply_filter(@events) - @events = @events.limit(limit).offset(params[:offset] || 0) @show_star = !(current_user && current_user.starred?(@project)) @@ -85,7 +83,12 @@ class ProjectsController < ApplicationController end end - format.json { pager_json('events/_events', @events.count) } + format.json do + @events = @project.events.recent + @events = event_filter.apply_filter(@events).with_associations + @events = @events.limit(limit).offset(params[:offset] || 0) + pager_json('events/_events', @events.count) + end end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 84a04c5ebe6..4c2fe4c3c8d 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -4,19 +4,20 @@ class UsersController < ApplicationController layout :determine_layout def show - # Projects user can view - visible_projects = ProjectsFinder.new.execute(current_user) - authorized_projects_ids = visible_projects.pluck(:id) + @contributed_projects = Project. + where(id: authorized_projects_ids & @user.contributed_projects_ids). + in_group_namespace.includes(:namespace) @projects = @user.personal_projects. - where(id: authorized_projects_ids) + where(id: authorized_projects_ids).includes(:namespace) # Collect only groups common for both users @groups = @user.groups & GroupsFinder.new.execute(current_user) # Get user activity feed for projects common for both users @events = @user.recent_events. - where(project_id: authorized_projects_ids).limit(30) + where(project_id: authorized_projects_ids). + with_associations.limit(30) @title = @user.name @title_url = user_path(@user) @@ -28,8 +29,8 @@ class UsersController < ApplicationController end def calendar - visible_projects = ProjectsFinder.new.execute(current_user) - calendar = Gitlab::CommitsCalendar.new(visible_projects, @user) + projects = Project.where(id: authorized_projects_ids & @user.contributed_projects_ids) + calendar = Gitlab::CommitsCalendar.new(projects, @user) @timestamps = calendar.timestamps @starting_year = calendar.starting_year @starting_month = calendar.starting_month @@ -54,4 +55,10 @@ class UsersController < ApplicationController return authenticate_user! end end + + def authorized_projects_ids + # Projects user can view + @authorized_projects_ids ||= + ProjectsFinder.new.execute(current_user).pluck(:id) + end end diff --git a/app/finders/trending_projects_finder.rb b/app/finders/trending_projects_finder.rb index 32d7968924a..a79bd47d986 100644 --- a/app/finders/trending_projects_finder.rb +++ b/app/finders/trending_projects_finder.rb @@ -8,7 +8,7 @@ class TrendingProjectsFinder # for period of time - ex. month projects.joins(:notes).where('notes.created_at > ?', start_date). select("projects.*, count(notes.id) as ncount"). - group("projects.id").order("ncount DESC") + group("projects.id").reorder("ncount DESC") end private diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index c3c77d9880f..365de3595cd 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -51,7 +51,13 @@ module ApplicationHelper end def project_icon(project_id, options = {}) - project = Project.find_with_namespace(project_id) + project = + if project_id.is_a?(Project) + project = project_id + else + Project.find_with_namespace(project_id) + end + if project.avatar.present? image_tag project.avatar.url, options elsif project.avatar_in_git diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 04299316102..1ee086da997 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -3,6 +3,10 @@ module ApplicationSettingsHelper current_application_settings.gravatar_enabled? end + def twitter_sharing_enabled? + current_application_settings.twitter_sharing_enabled? + end + def signup_enabled? current_application_settings.signup_enabled? end diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb index f5f27223d5b..798d62b3a09 100644 --- a/app/helpers/blob_helper.rb +++ b/app/helpers/blob_helper.rb @@ -17,7 +17,7 @@ module BlobHelper end def no_highlight_files - %w(credits changelog copying copyright license authors) + %w(credits changelog news copying copyright license authors) end def edit_blob_link(project, ref, path, options = {}) diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index 6e7aa521302..063916a8df8 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -10,11 +10,15 @@ module EventsHelper end def event_action_name(event) - target = if event.target_type - event.target_type.titleize.downcase - else - 'project' - end + target = if event.target_type + if event.note? + event.note_target_type + else + event.target_type.titleize.downcase + end + else + 'project' + end [event.action_name, target].join(" ") end @@ -42,21 +46,30 @@ module EventsHelper end def event_feed_title(event) - if event.issue? - "#{event.author_name} #{event.action_name} issue ##{event.target_iid}: #{event.issue_title} at #{event.project_name}" - elsif event.merge_request? - "#{event.author_name} #{event.action_name} MR ##{event.target_iid}: #{event.merge_request_title} at #{event.project_name}" - elsif event.push? - "#{event.author_name} #{event.push_action_name} #{event.ref_type} #{event.ref_name} at #{event.project_name}" - elsif event.membership_changed? - "#{event.author_name} #{event.action_name} #{event.project_name}" - elsif event.note? && event.note_commit? - "#{event.author_name} commented on #{event.note_target_type} #{event.note_short_commit_id} at #{event.project_name}" - elsif event.note? - "#{event.author_name} commented on #{event.note_target_type} ##{truncate event.note_target_iid} at #{event.project_name}" - else - "" + words = [] + words << event.author_name + words << event_action_name(event) + + if event.push? + words << event.ref_type + words << event.ref_name + words << "at" + elsif event.commented? + if event.note_commit? + words << event.note_short_commit_id + else + words << "##{truncate event.note_target_iid}" + end + words << "at" + elsif event.target + words << "##{event.target_iid}:" + words << event.target.title if event.target.respond_to?(:title) + words << "at" end + + words << event.project_name + + words.join(" ") end def event_feed_url(event) @@ -106,8 +119,6 @@ module EventsHelper render "events/event_push", event: event elsif event.merge_request? render "events/event_merge_request", merge_request: event.merge_request - elsif event.push? - render "events/event_push", event: event elsif event.note? render "events/event_note", note: event.note end diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb index 800cacdc2c2..ab30f498c01 100644 --- a/app/helpers/gitlab_markdown_helper.rb +++ b/app/helpers/gitlab_markdown_helper.rb @@ -110,7 +110,7 @@ module GitlabMarkdownHelper end def link_to_ignore?(link) - if link =~ /\#\w+/ + if link =~ /\A\#\w+/ # ignore anchors like <a href="#my-header"> true else @@ -122,10 +122,11 @@ module GitlabMarkdownHelper ["http://","https://", "ftp://", "mailto:"] end - def rebuild_path(path) - path.gsub!(/(#.*)/, "") + def rebuild_path(file_path) + file_path = file_path.dup + file_path.gsub!(/(#.*)/, "") id = $1 || "" - file_path = relative_file_path(path) + file_path = relative_file_path(file_path) file_path = sanitize_slashes(file_path) [ diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 6d4e220b16c..f1d918e5457 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -8,6 +8,7 @@ # signup_enabled :boolean # signin_enabled :boolean # gravatar_enabled :boolean +# twitter_sharing_enabled :boolean # sign_in_text :text # created_at :datetime # updated_at :datetime @@ -30,6 +31,7 @@ class ApplicationSetting < ActiveRecord::Base default_branch_protection: Settings.gitlab['default_branch_protection'], signup_enabled: Settings.gitlab['signup_enabled'], signin_enabled: Settings.gitlab['signin_enabled'], + twitter_sharing_enabled: Settings.gitlab['twitter_sharing_enabled'], gravatar_enabled: Settings.gravatar['enabled'], sign_in_text: Settings.extra['sign_in_text'], ) diff --git a/app/models/event.rb b/app/models/event.rb index 9a42d380f87..5579ab1dbb0 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -47,31 +47,9 @@ class Event < ActiveRecord::Base scope :recent, -> { order("created_at DESC") } scope :code_push, -> { where(action: PUSHED) } scope :in_projects, ->(project_ids) { where(project_id: project_ids).recent } + scope :with_associations, -> { includes(project: :namespace) } class << self - def create_ref_event(project, user, ref, action = 'add', prefix = 'refs/heads') - commit = project.repository.commit(ref.target) - - if action.to_s == 'add' - before = '00000000' - after = commit.id - else - before = commit.id - after = '00000000' - end - - Event.create( - project: project, - action: Event::PUSHED, - data: { - ref: "#{prefix}/#{ref.name}", - before: before, - after: after - }, - author_id: user.id - ) - end - def reset_event_cache_for(target) Event.where(target_id: target.id, target_type: target.class.to_s). order('id DESC').limit(100). @@ -84,6 +62,8 @@ class Event < ActiveRecord::Base true elsif membership_changed? true + elsif created_project? + true else (issue? || merge_request? || note? || milestone?) && target end @@ -98,25 +78,51 @@ class Event < ActiveRecord::Base end def target_title - if target && target.respond_to?(:title) - target.title - end + target.title if target && target.respond_to?(:title) + end + + def created? + action == CREATED end def push? - action == self.class::PUSHED && valid_push? + action == PUSHED && valid_push? end def merged? - action == self.class::MERGED + action == MERGED end def closed? - action == self.class::CLOSED + action == CLOSED end def reopened? - action == self.class::REOPENED + action == REOPENED + end + + def joined? + action == JOINED + end + + def left? + action == LEFT + end + + def commented? + action == COMMENTED + end + + def membership_changed? + joined? || left? + end + + def created_project? + created? && !target + end + + def created_target? + created? && target end def milestone? @@ -135,32 +141,32 @@ class Event < ActiveRecord::Base target_type == "MergeRequest" end - def joined? - action == JOINED - end - - def left? - action == LEFT - end - - def membership_changed? - joined? || left? + def milestone + target if milestone? end def issue - target if target_type == "Issue" + target if issue? end def merge_request - target if target_type == "MergeRequest" + target if merge_request? end def note - target if target_type == "Note" + target if note? end def action_name - if closed? + if push? + if new_ref? + "pushed new" + elsif rm_ref? + "deleted" + else + "pushed to" + end + elsif closed? "closed" elsif merged? "accepted" @@ -168,6 +174,10 @@ class Event < ActiveRecord::Base 'joined' elsif left? 'left' + elsif commented? + "commented on" + elsif created_project? + "created" else "opened" end @@ -236,16 +246,6 @@ class Event < ActiveRecord::Base tag? ? "tag" : "branch" end - def push_action_name - if new_ref? - "pushed new" - elsif rm_ref? - "deleted" - else - "pushed to" - end - end - def push_with_commits? md_ref? && commits.any? && commit_from && commit_to end diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb index 30c09f768d7..e4791d0f0aa 100644 --- a/app/models/members/project_member.rb +++ b/app/models/members/project_member.rb @@ -114,13 +114,11 @@ class ProjectMember < Member end def post_create_hook - Event.create( - project_id: self.project.id, - action: Event::JOINED, - author_id: self.user.id - ) - - notification_service.new_team_member(self) unless owner? + unless owner? + event_service.join_project(self.project, self.user) + notification_service.new_team_member(self) + end + system_hook_service.execute_hooks_for(self, :create) end @@ -129,15 +127,14 @@ class ProjectMember < Member end def post_destroy_hook - Event.create( - project_id: self.project.id, - action: Event::LEFT, - author_id: self.user.id - ) - + event_service.leave_project(self.project, self.user) system_hook_service.execute_hooks_for(self, :destroy) end + def event_service + EventCreateService.new + end + def notification_service NotificationService.new end diff --git a/app/models/user.rb b/app/models/user.rb index 5f98bfb7870..21ccc76978e 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -55,14 +55,13 @@ class User < ActiveRecord::Base include Gitlab::ConfigHelper include TokenAuthenticatable extend Gitlab::ConfigHelper - extend Gitlab::CurrentSettings + include Gitlab::CurrentSettings default_value_for :admin, false default_value_for :can_create_group, gitlab_config.default_can_create_group default_value_for :can_create_team, false default_value_for :hide_no_ssh_key, false default_value_for :hide_no_password, false - default_value_for :projects_limit, current_application_settings.default_projects_limit default_value_for :theme_id, gitlab_config.default_theme devise :database_authenticatable, :lockable, :async, @@ -141,6 +140,7 @@ class User < ActiveRecord::Base before_save :ensure_authentication_token after_save :ensure_namespace_correct + after_initialize :set_projects_limit after_create :post_create_hook after_destroy :post_destroy_hook @@ -255,7 +255,7 @@ class User < ActiveRecord::Base counter = 0 base = username while User.by_login(username).present? || Namespace.by_path(username).present? - counter += 1 + counter += 1 username = "#{base}#{counter}" end @@ -459,10 +459,17 @@ class User < ActiveRecord::Base def set_notification_email if self.notification_email.blank? || !self.all_emails.include?(self.notification_email) - self.notification_email = self.email + self.notification_email = self.email end end + def set_projects_limit + connection_default_value_defined = new_record? && !projects_limit_changed? + return unless self.projects_limit.nil? || connection_default_value_defined + + self.projects_limit = current_application_settings.default_projects_limit + end + def requires_ldap_check? if !Gitlab.config.ldap.enabled false @@ -559,7 +566,7 @@ class User < ActiveRecord::Base def post_create_hook log_info("User \"#{self.name}\" (#{self.email}) was created") - notification_service.new_user(self, @reset_token) + notification_service.new_user(self, @reset_token) if self.created_by_id system_hook_service.execute_hooks_for(self, :create) end @@ -607,4 +614,13 @@ class User < ActiveRecord::Base def oauth_authorized_tokens Doorkeeper::AccessToken.where(resource_owner_id: self.id, revoked_at: nil) end + + def contributed_projects_ids + Event.where(author_id: self). + where("created_at > ?", Time.now - 1.year). + code_push. + reorder(project_id: :desc). + select('DISTINCT(project_id)'). + map(&:project_id) + end end diff --git a/app/services/create_branch_service.rb b/app/services/create_branch_service.rb index 901f67bafb3..5e971c7891c 100644 --- a/app/services/create_branch_service.rb +++ b/app/services/create_branch_service.rb @@ -17,7 +17,7 @@ class CreateBranchService < BaseService new_branch = repository.find_branch(branch_name) if new_branch - Event.create_ref_event(project, current_user, new_branch, 'add') + EventCreateService.new.push_ref(project, current_user, new_branch, 'add') return success(new_branch) else return error('Invalid reference name') diff --git a/app/services/create_tag_service.rb b/app/services/create_tag_service.rb index 041c2287c36..a735d3f7f20 100644 --- a/app/services/create_tag_service.rb +++ b/app/services/create_tag_service.rb @@ -26,7 +26,7 @@ class CreateTagService < BaseService project.gitlab_ci_service.async_execute(push_data) end - Event.create_ref_event(project, current_user, new_tag, 'add', 'refs/tags') + EventCreateService.new.push_ref(project, current_user, new_tag, 'add', 'refs/tags') success(new_tag) else error('Invalid reference name') diff --git a/app/services/delete_branch_service.rb b/app/services/delete_branch_service.rb index cae6327fe72..c26aee2b0aa 100644 --- a/app/services/delete_branch_service.rb +++ b/app/services/delete_branch_service.rb @@ -25,7 +25,7 @@ class DeleteBranchService < BaseService end if repository.rm_branch(branch_name) - Event.create_ref_event(project, current_user, branch, 'rm') + EventCreateService.new.push_ref(project, current_user, branch, 'rm') success('Branch was removed') else return error('Failed to remove branch') diff --git a/app/services/event_create_service.rb b/app/services/event_create_service.rb index 8d8a5873e62..ba9547b9242 100644 --- a/app/services/event_create_service.rb +++ b/app/services/event_create_service.rb @@ -7,58 +7,98 @@ # class EventCreateService def open_issue(issue, current_user) - create_event(issue, current_user, Event::CREATED) + create_record_event(issue, current_user, Event::CREATED) end def close_issue(issue, current_user) - create_event(issue, current_user, Event::CLOSED) + create_record_event(issue, current_user, Event::CLOSED) end def reopen_issue(issue, current_user) - create_event(issue, current_user, Event::REOPENED) + create_record_event(issue, current_user, Event::REOPENED) end def open_mr(merge_request, current_user) - create_event(merge_request, current_user, Event::CREATED) + create_record_event(merge_request, current_user, Event::CREATED) end def close_mr(merge_request, current_user) - create_event(merge_request, current_user, Event::CLOSED) + create_record_event(merge_request, current_user, Event::CLOSED) end def reopen_mr(merge_request, current_user) - create_event(merge_request, current_user, Event::REOPENED) + create_record_event(merge_request, current_user, Event::REOPENED) end def merge_mr(merge_request, current_user) - create_event(merge_request, current_user, Event::MERGED) + create_record_event(merge_request, current_user, Event::MERGED) end def open_milestone(milestone, current_user) - create_event(milestone, current_user, Event::CREATED) + create_record_event(milestone, current_user, Event::CREATED) end def close_milestone(milestone, current_user) - create_event(milestone, current_user, Event::CLOSED) + create_record_event(milestone, current_user, Event::CLOSED) end def reopen_milestone(milestone, current_user) - create_event(milestone, current_user, Event::REOPENED) + create_record_event(milestone, current_user, Event::REOPENED) end def leave_note(note, current_user) - create_event(note, current_user, Event::COMMENTED) + create_record_event(note, current_user, Event::COMMENTED) + end + + def join_project(project, current_user) + create_event(project, current_user, Event::JOINED) + end + + def leave_project(project, current_user) + create_event(project, current_user, Event::LEFT) + end + + def create_project(project, current_user) + create_event(project, current_user, Event::CREATED) + end + + def push_ref(project, current_user, ref, action = 'add', prefix = 'refs/heads') + commit = project.repository.commit(ref.target) + + if action.to_s == 'add' + before = '00000000' + after = commit.id + else + before = commit.id + after = '00000000' + end + + data = { + ref: "#{prefix}/#{ref.name}", + before: before, + after: after + } + + push(project, current_user, data) + end + + def push(project, current_user, push_data) + create_event(project, current_user, Event::PUSHED, data: push_data) end private - def create_event(record, current_user, status) - Event.create( - project: record.project, - target_id: record.id, - target_type: record.class.name, + def create_record_event(record, current_user, status) + create_event(record.project, current_user, status, target_id: record.id, target_type: record.class.name) + end + + def create_event(project, current_user, status, attributes = {}) + attributes.reverse_merge!( + project: project, action: status, author_id: current_user.id ) + + Event.create(attributes) end end diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb index c775f79ec29..f21e6ac207d 100644 --- a/app/services/git_push_service.rb +++ b/app/services/git_push_service.rb @@ -52,7 +52,7 @@ class GitPushService end @push_data = post_receive_data(oldrev, newrev, ref) - create_push_event(@push_data) + EventCreateService.new.push(project, user, @push_data) project.execute_hooks(@push_data.dup, :push_hooks) project.execute_services(@push_data.dup) end @@ -60,15 +60,6 @@ class GitPushService protected - def create_push_event(push_data) - Event.create!( - project: project, - action: Event::PUSHED, - data: push_data, - author_id: push_data[:user_id] - ) - end - # Extract any GFM references from the pushed commit messages. If the configured issue-closing regex is matched, # close the referenced Issue. Create cross-reference Notes corresponding to any other referenced Mentionables. def process_commit_messages(ref) diff --git a/app/services/git_tag_push_service.rb b/app/services/git_tag_push_service.rb index c24809ad607..46d8987f12d 100644 --- a/app/services/git_tag_push_service.rb +++ b/app/services/git_tag_push_service.rb @@ -5,7 +5,7 @@ class GitTagPushService @project, @user = project, user @push_data = create_push_data(oldrev, newrev, ref) - create_push_event + EventCreateService.new.push(project, user, @push_data) project.repository.expire_cache project.execute_hooks(@push_data.dup, :tag_push_hooks) @@ -22,13 +22,4 @@ class GitTagPushService Gitlab::PushDataBuilder. build(project, user, oldrev, newrev, ref, []) end - - def create_push_event - Event.create!( - project: project, - action: Event::PUSHED, - data: push_data, - author_id: push_data[:user_id] - ) - end end diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb index 139de70114b..4fe790b98f1 100644 --- a/app/services/projects/create_service.rb +++ b/app/services/projects/create_service.rb @@ -52,13 +52,7 @@ module Projects end end - if @project.persisted? - if @project.wiki_enabled? - @project.create_wiki - end - - after_create_actions - end + after_create_actions if @project.persisted? @project rescue => ex @@ -79,6 +73,10 @@ module Projects def after_create_actions log_info("#{@project.owner.name} created a new project \"#{@project.name_with_namespace}\"") + + @project.create_wiki if @project.wiki_enabled? + + event_service.create_project(@project, current_user) system_hook_service.execute_hooks_for(@project, :create) unless @project.group diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index ae0c70a79c7..f528d69f431 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -19,6 +19,11 @@ = f.label :gravatar_enabled, class: 'control-label' .col-sm-10 = f.check_box :gravatar_enabled, class: 'checkbox' + .form-group + = f.label :twitter_sharing_enabled, "Twitter enabled", class: 'control-label' + .col-sm-10 + = f.check_box :twitter_sharing_enabled, class: 'checkbox' + %span.help-block Show users button to share their newly created public or internal projects on twitter %fieldset %legend Misc .form-group diff --git a/app/views/admin/applications/index.html.haml b/app/views/admin/applications/index.html.haml index f2fed51eaf8..d550278710e 100644 --- a/app/views/admin/applications/index.html.haml +++ b/app/views/admin/applications/index.html.haml @@ -17,6 +17,6 @@ %tr{:id => "application_#{application.id}"} %td= link_to application.name, admin_application_path(application) %td= application.redirect_uri - %td= application.access_tokens.count + %td= application.access_tokens.map(&:resource_owner_id).uniq.count %td= link_to 'Edit', edit_admin_application_path(application), class: 'btn btn-link' %td= render 'delete_form', application: application diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml index dffb4f0d82d..0f9cdfc9e8e 100644 --- a/app/views/admin/projects/index.html.haml +++ b/app/views/admin/projects/index.html.haml @@ -13,15 +13,13 @@ .form-group %strong Activity .checkbox - = label_tag :with_push, 'Not empty' - = check_box_tag :with_push, 1, params[:with_push] - - %span.light Projects with push events + = label_tag :with_push do + = check_box_tag :with_push, 1, params[:with_push] + %span Projects with push events .checkbox - = label_tag :abandoned, 'Abandoned' - = check_box_tag :abandoned, 1, params[:abandoned] - - %span.light No activity over 6 month + = label_tag :abandoned do + = check_box_tag :abandoned, 1, params[:abandoned] + %span No activity over 6 month %fieldset %strong Visibility level: diff --git a/app/views/dashboard/_activities.html.haml b/app/views/dashboard/_activities.html.haml index fdf96dd6f56..c1fc1602d0a 100644 --- a/app/views/dashboard/_activities.html.haml +++ b/app/views/dashboard/_activities.html.haml @@ -1,9 +1,4 @@ = render "events/event_last_push", event: @last_push = render 'shared/event_filter' - -- if @events.any? - .content_list -- else - .nothing-here-block Projects activity will be displayed here - +.content_list = spinner diff --git a/app/views/dashboard/_groups.html.haml b/app/views/dashboard/_groups.html.haml index ddf44270802..e3df43d8892 100644 --- a/app/views/dashboard/_groups.html.haml +++ b/app/views/dashboard/_groups.html.haml @@ -3,7 +3,7 @@ .input-group = search_field_tag :filter_group, nil, placeholder: 'Filter by name', class: 'dash-filter form-control' - if current_user.can_create_group? - .input-group-addon + .input-group-addon.dash-new-group = link_to new_group_path, class: "" do %strong New group %ul.well-list.dash-list diff --git a/app/views/dashboard/_project.html.haml b/app/views/dashboard/_project.html.haml index d638a161f40..3dd69df523d 100644 --- a/app/views/dashboard/_project.html.haml +++ b/app/views/dashboard/_project.html.haml @@ -1,6 +1,6 @@ = link_to namespace_project_path(project.namespace, project), class: dom_class(project) do .dash-project-avatar - = project_icon("#{project.namespace.to_param}/#{project.to_param}", alt: '', class: 'avatar project-avatar s40') + = project_icon(project, alt: '', class: 'avatar project-avatar s40') .dash-project-access-icon = visibility_level_icon(project.visibility_level) %span.str-truncated diff --git a/app/views/devise/sessions/_new_base.html.haml b/app/views/devise/sessions/_new_base.html.haml index ab9085f0ba7..54a39726771 100644 --- a/app/views/devise/sessions/_new_base.html.haml +++ b/app/views/devise/sessions/_new_base.html.haml @@ -2,11 +2,11 @@ = f.text_field :login, class: "form-control top", placeholder: "Username or Email", autofocus: "autofocus" = f.password_field :password, class: "form-control bottom", placeholder: "Password" - if devise_mapping.rememberable? - .remember-me - %label.checkbox.remember_me{for: "user_remember_me"} + .remember-me.checkbox + %label{for: "user_remember_me"} = f.check_box :remember_me %span Remember me - .pull-right - = link_to "Forgot your password?", new_password_path(resource_name) + .pull-right + = link_to "Forgot your password?", new_password_path(resource_name) %div = f.submit "Sign in", class: "btn btn-save" diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml index c7976ba564f..02b1dec753c 100644 --- a/app/views/events/_event.html.haml +++ b/app/views/events/_event.html.haml @@ -3,12 +3,14 @@ .event-item-timestamp #{time_ago_with_tooltip(event.created_at)} - = cache event do + = cache [event, current_user] do = image_tag avatar_icon(event.author_email, 24), class: "avatar s24", alt:'' - if event.push? = render "events/event/push", event: event - - elsif event.note? + - elsif event.commented? = render "events/event/note", event: event + - elsif event.created_project? + = render "events/event/created_project", event: event - else = render "events/event/common", event: event
\ No newline at end of file diff --git a/app/views/events/event/_common.html.haml b/app/views/events/event/_common.html.haml index b3f32dab79c..a39e62e9dac 100644 --- a/app/views/events/event/_common.html.haml +++ b/app/views/events/event/_common.html.haml @@ -1,15 +1,17 @@ .event-title %span.author_name= link_to_author event - %span.event_label{class: event.action_name}= event_action_name(event) + %span.event_label{class: event.action_name} + = event_action_name(event) + - if event.target %strong= link_to "##{event.target_iid}", [event.project.namespace.becomes(Namespace), event.project, event.target] - - else - %strong= gfm event.target_title - at + at + - if event.project = link_to_project event.project - else = event.project_name + - if event.target.respond_to?(:title) .event-body .event-note diff --git a/app/views/events/event/_created_project.html.haml b/app/views/events/event/_created_project.html.haml new file mode 100644 index 00000000000..3c7153d235f --- /dev/null +++ b/app/views/events/event/_created_project.html.haml @@ -0,0 +1,27 @@ +.event-title + %span.author_name= link_to_author event + %span.event_label{class: event.action_name} + = event_action_name(event) + + - if event.project + = link_to_project event.project + - else + = event.project_name + +- if current_user == event.author && !event.project.private? && twitter_sharing_enabled? + .event-body + .event-note + .md + %p + Congratulations! Why not share your accomplishment with the world? + + %a.twitter-share-button{ | + href: "https://twitter.com/share", | + "data-url" => event.project.web_url, | + "data-text" => "I just created a new project in GitLab! GitLab is version control on your server.", | + "data-size" => "medium", | + "data-related" => "gitlab", | + "data-hashtags" => "gitlab", | + "data-count" => "none"} + Tweet + %script{src: "//platform.twitter.com/widgets.js"}
\ No newline at end of file diff --git a/app/views/events/event/_note.html.haml b/app/views/events/event/_note.html.haml index 6ec8e54fba5..0acb8538778 100644 --- a/app/views/events/event/_note.html.haml +++ b/app/views/events/event/_note.html.haml @@ -1,6 +1,10 @@ .event-title %span.author_name= link_to_author event - %span.event_label commented on #{event_note_title_html(event)} at + %span.event_label + = event.action_name + = event_note_title_html(event) + at + - if event.project = link_to_project event.project - else diff --git a/app/views/events/event/_push.html.haml b/app/views/events/event/_push.html.haml index 092d246a94c..489138887ae 100644 --- a/app/views/events/event/_push.html.haml +++ b/app/views/events/event/_push.html.haml @@ -1,6 +1,6 @@ .event-title %span.author_name= link_to_author event - %span.event_label.pushed #{event.push_action_name} #{event.ref_type} + %span.event_label.pushed #{event.action_name} #{event.ref_type} - if event.rm_ref? %strong= event.ref_name - else diff --git a/app/views/explore/projects/_project.html.haml b/app/views/explore/projects/_project.html.haml index cdd6ede36a1..d65fb529373 100644 --- a/app/views/explore/projects/_project.html.haml +++ b/app/views/explore/projects/_project.html.haml @@ -3,11 +3,9 @@ .project-access-icon = visibility_level_icon(project.visibility_level) = link_to project.name_with_namespace, [project.namespace.becomes(Namespace), project] - - - if current_page?(starred_explore_projects_path) - %strong.pull-right - %i.fa.fa-star - = pluralize project.star_count, 'star' + %span.pull-right + %i.fa.fa-star + = project.star_count .project-info - if project.description.present? diff --git a/app/views/groups/_projects.html.haml b/app/views/groups/_projects.html.haml index 5fe93f4e083..2f28470f8be 100644 --- a/app/views/groups/_projects.html.haml +++ b/app/views/groups/_projects.html.haml @@ -13,7 +13,7 @@ %li.project-row = link_to namespace_project_path(project.namespace, project), class: dom_class(project) do .dash-project-avatar - = project_icon("#{project.namespace.to_param}/#{project.to_param}", alt: '', class: 'avatar s40') + = project_icon(project, alt: '', class: 'avatar s40') .dash-project-access-icon = visibility_level_icon(project.visibility_level) %span.str-truncated diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index f2e591c1939..d5af859ee62 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -13,10 +13,7 @@ - if current_user = render "events/event_last_push", event: @last_push = render 'shared/event_filter' - - if @events.any? - .content_list - - else - .nothing-here-block Project activity will be displayed here + .content_list = spinner %aside.side.col-md-4 = render "projects", projects: @projects diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml index 7b8193abfdf..af39dfeac5b 100644 --- a/app/views/help/index.html.haml +++ b/app/views/help/index.html.haml @@ -42,3 +42,9 @@ %li Use = link_to 'shortcuts', '#', onclick: 'Shortcuts.showHelp(event)' + %li + Get a support + = link_to 'subscription', 'https://about.gitlab.com/pricing/' + %li + = link_to 'Compare', 'https://about.gitlab.com/features/#compare' + GitLab editions diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml index 62a51047c3c..67e2721bb4a 100644 --- a/app/views/layouts/nav/_project.html.haml +++ b/app/views/layouts/nav/_project.html.haml @@ -49,8 +49,14 @@ %span Graphs + = nav_link(controller: :milestones) do + = link_to project_milestones_path(@project), title: 'Milestones' do + %i.fa.fa-clock-o + %span + Milestones + - if project_nav_tab? :issues - = nav_link(controller: %w(issues milestones labels)) do + = nav_link(controller: :issues) do = link_to url_for_project_issues, title: 'Issues', class: 'shortcuts-issues' do %i.fa.fa-exclamation-circle %span @@ -66,6 +72,12 @@ Merge Requests %span.count.merge_counter= @project.merge_requests.opened.count + = nav_link(controller: :labels) do + = link_to project_labels_path(@project), title: 'Labels' do + %i.fa.fa-tags + %span + Labels + - if project_nav_tab? :wiki = nav_link(controller: :wikis) do = link_to namespace_project_wiki_path(@project.namespace, @project, :home), title: 'Wiki', class: 'shortcuts-wiki' do diff --git a/app/views/profiles/applications.html.haml b/app/views/profiles/applications.html.haml index cb24e4a3dde..4b5817e10bf 100644 --- a/app/views/profiles/applications.html.haml +++ b/app/views/profiles/applications.html.haml @@ -36,12 +36,12 @@ %th Scope %th %tbody - - @authorized_tokens.each do |token| - - application = token.application - %tr{:id => "application_#{application.id}"} - %td= application.name + - @authorized_apps.each do |app| + - token = app.authorized_tokens.order('created_at desc').first + %tr{:id => "application_#{app.id}"} + %td= app.name %td= token.created_at %td= token.scopes - %td= render 'doorkeeper/authorized_applications/delete_form', application: application + %td= render 'doorkeeper/authorized_applications/delete_form', application: app - else %p.light You dont have any authorized applications diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml index 60d461da664..c0e13e67be3 100644 --- a/app/views/projects/_home_panel.html.haml +++ b/app/views/projects/_home_panel.html.haml @@ -1,7 +1,7 @@ - empty_repo = @project.empty_repo? .project-home-panel{:class => ("empty-project" if empty_repo)} .project-identicon-holder - = project_icon("#{@project.namespace.to_param}/#{@project.to_param}", alt: '', class: 'avatar project-avatar') + = project_icon(@project, alt: '', class: 'avatar project-avatar') .project-home-row .project-home-desc - if @project.description.present? diff --git a/app/views/projects/_issuable_form.html.haml b/app/views/projects/_issuable_form.html.haml index 52a31610e6c..a7d5a52584c 100644 --- a/app/views/projects/_issuable_form.html.haml +++ b/app/views/projects/_issuable_form.html.haml @@ -15,7 +15,7 @@ = f.label :description, 'Description', class: 'control-label' .col-sm-10 - = render layout: 'projects/md_preview' do + = render layout: 'projects/md_preview', locals: { preview_class: "wiki" } do = render 'projects/zen', f: f, attr: :description, classes: 'description form-control' .col-sm-12.hint diff --git a/app/views/projects/_issues_nav.html.haml b/app/views/projects/_issues_nav.html.haml deleted file mode 100644 index 3f14616af2c..00000000000 --- a/app/views/projects/_issues_nav.html.haml +++ /dev/null @@ -1,51 +0,0 @@ -%ul.nav.nav-tabs - - if project_nav_tab? :issues - = nav_link(controller: :issues) do - = link_to namespace_project_issues_path(@project.namespace, @project), class: "tab" do - %i.fa.fa-exclamation-circle - Issues - - if project_nav_tab? :merge_requests - = nav_link(controller: :merge_requests) do - = link_to namespace_project_merge_requests_path(@project.namespace, @project), class: "tab" do - %i.fa.fa-tasks - Merge Requests - = nav_link(controller: :milestones) do - = link_to namespace_project_milestones_path(@project.namespace, @project), class: "tab" do - %i.fa.fa-clock-o - Milestones - = nav_link(controller: :labels) do - = link_to namespace_project_labels_path(@project.namespace, @project), class: "tab" do - %i.fa.fa-tags - Labels - - - - if current_controller?(:issues) - - if current_user - %li.hidden-xs - = link_to namespace_project_issues_path(@project.namespace, @project, :atom, { private_token: current_user.private_token }) do - %i.fa.fa-rss - - %li.pull-right - .pull-right - .pull-left - = form_tag namespace_project_issues_path(@project.namespace, @project), method: :get, id: "issue_search_form", class: 'pull-left issue-search-form' do - .append-right-10.hidden-xs.hidden-sm - = search_field_tag :issue_search, params[:issue_search], { placeholder: 'Filter by title or description', class: 'form-control issue_search search-text-input input-mn-300' } - = hidden_field_tag :state, params['state'] - = hidden_field_tag :scope, params['scope'] - = hidden_field_tag :assignee_id, params['assignee_id'] - = hidden_field_tag :milestone_id, params['milestone_id'] - = hidden_field_tag :label_id, params['label_id'] - - - if can? current_user, :write_issue, @project - = link_to new_namespace_project_issue_path(@project.namespace, @project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "btn btn-new pull-left", title: "New Issue", id: "new_issue_link" do - %i.fa.fa-plus - New Issue - - - if current_controller?(:merge_requests) - %li.pull-right - .pull-right - - if can? current_user, :write_merge_request, @project - = link_to new_namespace_project_merge_request_path(@project.namespace, @project), class: "btn btn-new pull-left", title: "New Merge Request" do - %i.fa.fa-plus - New Merge Request diff --git a/app/views/projects/_md_preview.html.haml b/app/views/projects/_md_preview.html.haml index a2c8ee1d116..f356a25dbfa 100644 --- a/app/views/projects/_md_preview.html.haml +++ b/app/views/projects/_md_preview.html.haml @@ -10,4 +10,4 @@ .md-write-holder = yield .md-preview-holder.hide - .js-md-preview + .js-md-preview{class: (preview_class if defined?(preview_class))} diff --git a/app/views/projects/_visibility_level.html.haml b/app/views/projects/_visibility_level.html.haml index 5f34e66b3ed..42c8e685224 100644 --- a/app/views/projects/_visibility_level.html.haml +++ b/app/views/projects/_visibility_level.html.haml @@ -7,8 +7,8 @@ - Gitlab::VisibilityLevel.values.each do |level| .radio - restricted = restricted_visibility_levels.include?(level) - = f.radio_button :visibility_level, level, checked: (visibility_level == level), disabled: restricted = label :project_visibility_level, level do + = f.radio_button :visibility_level, level, checked: (visibility_level == level), disabled: restricted = visibility_level_icon(level) .option-title = visibility_level_label(level) diff --git a/app/views/projects/diffs/_warning.html.haml b/app/views/projects/diffs/_warning.html.haml index de091038e30..5725c84600f 100644 --- a/app/views/projects/diffs/_warning.html.haml +++ b/app/views/projects/diffs/_warning.html.haml @@ -15,5 +15,5 @@ %p To preserve performance only %strong #{allowed_diff_size} of #{diffs.size} - files displayed. + files are displayed. diff --git a/app/views/projects/issues/_discussion.html.haml b/app/views/projects/issues/_discussion.html.haml index c7c8af2f2c0..1579e7c5ccf 100644 --- a/app/views/projects/issues/_discussion.html.haml +++ b/app/views/projects/issues/_discussion.html.haml @@ -14,24 +14,24 @@ .voting_notes#notes= render "projects/notes/notes_with_form" .col-md-3 - %div - .clearfix - %span.slead.has_tooltip{:"data-original-title" => 'Cross-project reference'} - = cross_project_reference(@project, @issue) - %hr - .context - %cite.cgray - = render partial: 'issue_context', locals: { issue: @issue } - %hr - .clearfix - .votes-holder - %h6 Votes - #votes= render 'votes/votes_block', votable: @issue - - - if @issue.labels.any? + .issuable-affix + .clearfix + %span.slead.has_tooltip{:"data-original-title" => 'Cross-project reference'} + = cross_project_reference(@project, @issue) %hr - %h6 Labels - .issue-show-labels - - @issue.labels.each do |label| - = link_to namespace_project_issues_path(@project.namespace, @project, label_name: label.name) do - %p= render_colored_label(label) + .context + %cite.cgray + = render partial: 'issue_context', locals: { issue: @issue } + %hr + .clearfix + .votes-holder + %h6 Votes + #votes= render 'votes/votes_block', votable: @issue + + - if @issue.labels.any? + %hr + %h6 Labels + .issue-show-labels + - @issue.labels.each do |label| + = link_to namespace_project_issues_path(@project.namespace, @project, label_name: label.name) do + = render_colored_label(label) diff --git a/app/views/projects/issues/_issues.html.haml b/app/views/projects/issues/_issues.html.haml index 73ce78133d5..5d243adb5fe 100644 --- a/app/views/projects/issues/_issues.html.haml +++ b/app/views/projects/issues/_issues.html.haml @@ -1,18 +1,3 @@ -.append-bottom-10 - .check-all-holder - = check_box_tag "check_all_issues", nil, false, class: "check_all_issues left", disabled: !can?(current_user, :modify_issue, @project) - = render 'shared/issuable_filter' - - .clearfix - .issues_bulk_update.hide - = form_tag bulk_update_namespace_project_issues_path(@project.namespace, @project), method: :post do - = select_tag('update[status]', options_for_select([['Open', 'open'], ['Closed', 'closed']]), prompt: "Status") - = project_users_select_tag('update[assignee_id]', placeholder: 'Assignee') - = select_tag('update[milestone_id]', bulk_update_milestone_options, prompt: "Milestone") - = hidden_field_tag 'update[issues_ids]', [] - = hidden_field_tag :status, params[:status] - = button_tag "Update issues", class: "btn update_selected_issues btn-save" - .panel.panel-default %ul.well-list.issues-list = render @issues diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml index 0d00d6bfded..0d0e3e3c82f 100644 --- a/app/views/projects/issues/index.html.haml +++ b/app/views/projects/issues/index.html.haml @@ -1,4 +1,36 @@ -= render "projects/issues_nav" +.append-bottom-10 + .pull-right + .pull-left + - if current_user + .hidden-xs.pull-left + = link_to project_issues_path(@project, :atom, { private_token: current_user.private_token }), class: 'btn append-right-10' do + %i.fa.fa-rss + + = form_tag project_issues_path(@project), method: :get, id: "issue_search_form", class: 'pull-left issue-search-form' do + .append-right-10.hidden-xs.hidden-sm + = search_field_tag :issue_search, params[:issue_search], { placeholder: 'Filter by title or description', class: 'form-control issue_search search-text-input input-mn-300' } + = hidden_field_tag :state, params['state'] + = hidden_field_tag :scope, params['scope'] + = hidden_field_tag :assignee_id, params['assignee_id'] + = hidden_field_tag :milestone_id, params['milestone_id'] + = hidden_field_tag :label_id, params['label_id'] + + - if can? current_user, :write_issue, @project + = link_to new_project_issue_path(@project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "btn btn-new pull-left", title: "New Issue", id: "new_issue_link" do + %i.fa.fa-plus + New Issue + + = render 'shared/issuable_filter' + + .clearfix + .issues_bulk_update.hide + = form_tag bulk_update_project_issues_path(@project), method: :post do + = select_tag('update[status]', options_for_select([['Open', 'open'], ['Closed', 'closed']]), prompt: "Status") + = project_users_select_tag('update[assignee_id]', placeholder: 'Assignee') + = select_tag('update[milestone_id]', bulk_update_milestone_options, prompt: "Milestone") + = hidden_field_tag 'update[issues_ids]', [] + = hidden_field_tag :status, params[:status] + = button_tag "Update issues", class: "btn update_selected_issues btn-save" .issues-holder = render "issues" diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml index ca38a4e765d..224ad4041ea 100644 --- a/app/views/projects/issues/show.html.haml +++ b/app/views/projects/issues/show.html.haml @@ -1,37 +1,40 @@ -%h4.page-title - .issue-box{ class: issue_box_class(@issue) } - - if @issue.closed? - Closed - - else - Open - Issue ##{@issue.iid} - %small.creator - · created by #{link_to_member(@project, @issue.author)} #{issue_timestamp(@issue)} +.issue + .issue-details + %h4.page-title + .issue-box{ class: issue_box_class(@issue) } + - if @issue.closed? + Closed + - else + Open + Issue ##{@issue.iid} + %small.creator + · created by #{link_to_member(@project, @issue.author)} #{issue_timestamp(@issue)} - .pull-right - - if can?(current_user, :write_issue, @project) - = link_to new_namespace_project_issue_path(@project.namespace, @project), class: "btn btn-grouped new-issue-link", title: "New Issue", id: "new_issue_link" do - %i.fa.fa-plus - New Issue - - if can?(current_user, :modify_issue, @issue) - - if @issue.closed? - = link_to 'Reopen', namespace_project_issue_path(@project.namespace, @project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn btn-grouped btn-reopen" - - else - = link_to 'Close', namespace_project_issue_path(@project.namespace, @project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn btn-grouped btn-close", title: "Close Issue" + .pull-right + - if can?(current_user, :write_issue, @project) + = link_to new_namespace_project_issue_path(@project.namespace, @project), class: "btn btn-grouped new-issue-link", title: "New Issue", id: "new_issue_link" do + %i.fa.fa-plus + New Issue + - if can?(current_user, :modify_issue, @issue) + - if @issue.closed? + = link_to 'Reopen', namespace_project_issue_path(@project.namespace, @project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn btn-grouped btn-reopen" + - else + = link_to 'Close', namespace_project_issue_path(@project.namespace, @project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn btn-grouped btn-close", title: "Close Issue" - = link_to edit_namespace_project_issue_path(@project.namespace, @project, @issue), class: "btn btn-grouped issuable-edit" do - %i.fa.fa-pencil-square-o - Edit + = link_to edit_namespace_project_issue_path(@project.namespace, @project, @issue), class: "btn btn-grouped issuable-edit" do + %i.fa.fa-pencil-square-o + Edit -%hr -%h3.issue-title - = gfm escape_once(@issue.title) -%div - - if @issue.description.present? - .description - .wiki - = preserve do - = markdown(@issue.description, parse_tasks: true) + %hr + %h3.issue-title + = gfm escape_once(@issue.title) + %div + - if @issue.description.present? + .description + .wiki + = preserve do + = markdown(@issue.description, parse_tasks: true) -%hr -= render "projects/issues/discussion" + %hr + .issue-discussion + = render "projects/issues/discussion" diff --git a/app/views/projects/labels/index.html.haml b/app/views/projects/labels/index.html.haml index c53d75b1bb6..0700e72d39c 100644 --- a/app/views/projects/labels/index.html.haml +++ b/app/views/projects/labels/index.html.haml @@ -1,5 +1,3 @@ -= render "projects/issues_nav" - - if can? current_user, :admin_label, @project = link_to new_namespace_project_label_path(@project.namespace, @project), class: "pull-right btn btn-new" do New label diff --git a/app/views/projects/merge_requests/_discussion.html.haml b/app/views/projects/merge_requests/_discussion.html.haml index e3d3e69a9d3..b05f0c24320 100644 --- a/app/views/projects/merge_requests/_discussion.html.haml +++ b/app/views/projects/merge_requests/_discussion.html.haml @@ -10,22 +10,23 @@ = render "projects/merge_requests/show/participants" = render "projects/notes/notes_with_form" .col-md-3 - .clearfix - %span.slead.has_tooltip{:"data-original-title" => 'Cross-project reference'} - = cross_project_reference(@project, @merge_request) - %hr - .context - %cite.cgray - = render partial: 'projects/merge_requests/show/context', locals: { merge_request: @merge_request } - %hr - .votes-holder - %h6 Votes - #votes= render 'votes/votes_block', votable: @merge_request - - - if @merge_request.labels.any? + .issuable-affix + .clearfix + %span.slead.has_tooltip{:"data-original-title" => 'Cross-project reference'} + = cross_project_reference(@project, @merge_request) + %hr + .context + %cite.cgray + = render partial: 'projects/merge_requests/show/context', locals: { merge_request: @merge_request } %hr - %h6 Labels - .merge-request-show-labels - - @merge_request.labels.each do |label| - = link_to namespace_project_merge_requests_path(@project.namespace, @project, label_name: label.name) do - %p= render_colored_label(label) + .votes-holder + %h6 Votes + #votes= render 'votes/votes_block', votable: @merge_request + + - if @merge_request.labels.any? + %hr + %h6 Labels + .merge-request-show-labels + - @merge_request.labels.each do |label| + = link_to namespace_project_merge_requests_path(@project.namespace, @project, label_name: label.name) do + = render_colored_label(label) diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml index 3567401817b..fb1e5737680 100644 --- a/app/views/projects/merge_requests/_merge_request.html.haml +++ b/app/views/projects/merge_requests/_merge_request.html.haml @@ -18,7 +18,7 @@ - if merge_request.assignee assigned to #{link_to_member(merge_request.source_project, merge_request.assignee)} - else - Work In Progress + Unassigned - if merge_request.votes_count > 0 = render 'votes/votes_inline', votable: merge_request - if merge_request.notes.any? diff --git a/app/views/projects/merge_requests/_new_submit.html.haml b/app/views/projects/merge_requests/_new_submit.html.haml index 2a3fce0df30..75d65e6649c 100644 --- a/app/views/projects/merge_requests/_new_submit.html.haml +++ b/app/views/projects/merge_requests/_new_submit.html.haml @@ -19,7 +19,7 @@ .form-group.issuable-description = f.label :description, 'Description', class: 'control-label' .col-sm-10 - = render layout: 'projects/md_preview' do + = render layout: 'projects/md_preview', locals: { preview_class: "wiki" } do = render 'projects/zen', f: f, attr: :description, classes: 'description form-control' .col-sm-12-hint diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index 45c3a419d97..a53aed2f38a 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -1,37 +1,38 @@ .merge-request{'data-url' => namespace_project_merge_request_path(@project.namespace, @project, @merge_request)} - = render "projects/merge_requests/show/mr_title" - %hr - = render "projects/merge_requests/show/mr_box" - %hr - .append-bottom-20 - .slead - %span From - - if @merge_request.for_fork? - %strong.label-branch< - - if @merge_request.source_project - = link_to @merge_request.source_project_namespace, namespace_project_path(@merge_request.source_project.namespace, @merge_request.source_project) - - else - \ #{@merge_request.source_project_namespace} - \:#{@merge_request.source_branch} - %span into - %strong.label-branch #{@merge_request.target_project_namespace}:#{@merge_request.target_branch} - - else - %strong.label-branch #{@merge_request.source_branch} - %span into - %strong.label-branch #{@merge_request.target_branch} - - if @merge_request.open? - %span.pull-right - .btn-group - %a.btn.dropdown-toggle{ data: {toggle: :dropdown} } - %i.fa.fa-download - Download as - %span.caret - %ul.dropdown-menu - %li= link_to "Email Patches", namespace_project_merge_request_path(@project.namespace, @project, @merge_request, format: :patch) - %li= link_to "Plain Diff", namespace_project_merge_request_path(@project.namespace, @project, @merge_request, format: :diff) + .merge-request-details + = render "projects/merge_requests/show/mr_title" + %hr + = render "projects/merge_requests/show/mr_box" + %hr + .append-bottom-20 + .slead + %span From + - if @merge_request.for_fork? + %strong.label-branch< + - if @merge_request.source_project + = link_to @merge_request.source_project_namespace, namespace_project_path(@merge_request.source_project.namespace, @merge_request.source_project) + - else + \ #{@merge_request.source_project_namespace} + \:#{@merge_request.source_branch} + %span into + %strong.label-branch #{@merge_request.target_project_namespace}:#{@merge_request.target_branch} + - else + %strong.label-branch #{@merge_request.source_branch} + %span into + %strong.label-branch #{@merge_request.target_branch} + - if @merge_request.open? + %span.pull-right + .btn-group + %a.btn.dropdown-toggle{ data: {toggle: :dropdown} } + %i.fa.fa-download + Download as + %span.caret + %ul.dropdown-menu + %li= link_to "Email Patches", namespace_project_merge_request_path(@project.namespace, @project, @merge_request, format: :patch) + %li= link_to "Plain Diff", namespace_project_merge_request_path(@project.namespace, @project, @merge_request, format: :diff) - = render "projects/merge_requests/show/how_to_merge" - = render "projects/merge_requests/show/state_widget" + = render "projects/merge_requests/show/how_to_merge" + = render "projects/merge_requests/show/state_widget" - if @commits.present? %ul.nav.nav-tabs.merge-request-tabs diff --git a/app/views/projects/merge_requests/index.html.haml b/app/views/projects/merge_requests/index.html.haml index 2654ea70990..35e85156951 100644 --- a/app/views/projects/merge_requests/index.html.haml +++ b/app/views/projects/merge_requests/index.html.haml @@ -1,7 +1,10 @@ -= render "projects/issues_nav" - .merge-requests-holder .append-bottom-10 + .pull-right + - if can? current_user, :write_merge_request, @project + = link_to new_project_merge_request_path(@project), class: "btn btn-new pull-left", title: "New Merge Request" do + %i.fa.fa-plus + New Merge Request = render 'shared/issuable_filter' .panel.panel-default %ul.well-list.mr-list diff --git a/app/views/projects/merge_requests/show/_mr_accept.html.haml b/app/views/projects/merge_requests/show/_mr_accept.html.haml index 12ab184973c..fb2c3220b8a 100644 --- a/app/views/projects/merge_requests/show/_mr_accept.html.haml +++ b/app/views/projects/merge_requests/show/_mr_accept.html.haml @@ -17,7 +17,7 @@ .accept-action = f.submit "Accept Merge Request", class: "btn btn-create accept_merge_request" - if can_remove_branch?(@merge_request.source_project, @merge_request.source_branch) && !@merge_request.for_fork? - .accept-control + .accept-control.checkbox = label_tag :should_remove_source_branch, class: "remove_source_checkbox" do = check_box_tag :should_remove_source_branch Remove source-branch diff --git a/app/views/projects/milestones/_form.html.haml b/app/views/projects/milestones/_form.html.haml index 46132eed0b9..e9c2a73bd3f 100644 --- a/app/views/projects/milestones/_form.html.haml +++ b/app/views/projects/milestones/_form.html.haml @@ -21,7 +21,7 @@ .form-group.milestone-description = f.label :description, "Description", class: "control-label" .col-sm-10 - = render layout: 'projects/md_preview' do + = render layout: 'projects/md_preview', locals: { preview_class: "wiki" } do = render 'projects/zen', f: f, attr: :description, classes: 'description form-control' .hint .pull-left Milestones are parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"), target: '_blank'}. diff --git a/app/views/projects/milestones/index.html.haml b/app/views/projects/milestones/index.html.haml index 084c6d010da..d3eab8d6d75 100644 --- a/app/views/projects/milestones/index.html.haml +++ b/app/views/projects/milestones/index.html.haml @@ -1,12 +1,8 @@ -= render "projects/issues_nav" -.milestones_content - %h3.page-title - Milestones - - if can? current_user, :admin_milestone, @project - = link_to new_namespace_project_milestone_path(@project.namespace, @project), class: "pull-right btn btn-new", title: "New Milestone" do - %i.fa.fa-plus - New Milestone - +.pull-right + - if can? current_user, :admin_milestone, @project + = link_to new_namespace_project_milestone_path(@project.namespace, @project), class: "pull-right btn btn-new", title: "New Milestone" do + %i.fa.fa-plus + New Milestone = render 'shared/milestones_filter' .milestones diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml index 3107766e993..fea96f37011 100644 --- a/app/views/projects/milestones/show.html.haml +++ b/app/views/projects/milestones/show.html.haml @@ -1,4 +1,3 @@ -= render "projects/issues_nav" %h4.page-title .issue-box{ class: issue_box_class(@milestone) } - if @milestone.closed? diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index 61f6a66c386..6f5851d61a1 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -52,7 +52,7 @@ %i.fa.fa-github Import projects from GitHub = render 'github_import_modal' - + .project-import.form-group .col-sm-2 .col-sm-10 @@ -60,7 +60,7 @@ = link_to status_import_gitlab_path do %i.fa.fa-heart Import projects from GitLab.com - - else + - elsif request.host != 'gitlab.com' = link_to '#', class: 'how_to_import_link light' do %i.fa.fa-heart Import projects from GitLab.com @@ -99,4 +99,4 @@ e.preventDefault() import_modal = $(this).parent().find(".modal").show() $('.modal-header .close').bind 'click', -> - $(".modal").hide()
\ No newline at end of file + $(".modal").hide() diff --git a/app/views/projects/notes/_edit_form.html.haml b/app/views/projects/notes/_edit_form.html.haml index 9fda7aafd51..602acd6d010 100644 --- a/app/views/projects/notes/_edit_form.html.haml +++ b/app/views/projects/notes/_edit_form.html.haml @@ -1,6 +1,6 @@ .note-edit-form = form_for note, url: namespace_project_note_path(@project.namespace, @project, note), method: :put, remote: true, authenticity_token: true do |f| - = render layout: 'projects/md_preview' do + = render layout: 'projects/md_preview', locals: { preview_class: "note-text" } do = render 'projects/zen', f: f, attr: :note, classes: 'note_text js-note-text' diff --git a/app/views/projects/notes/_form.html.haml b/app/views/projects/notes/_form.html.haml index 28c11aa5548..e1f2754f0d4 100644 --- a/app/views/projects/notes/_form.html.haml +++ b/app/views/projects/notes/_form.html.haml @@ -5,7 +5,7 @@ = f.hidden_field :noteable_id = f.hidden_field :noteable_type - = render layout: 'projects/md_preview' do + = render layout: 'projects/md_preview', locals: { preview_class: "note-text" } do = render 'projects/zen', f: f, attr: :note, classes: 'note_text js-note-text' diff --git a/app/views/projects/wikis/_form.html.haml b/app/views/projects/wikis/_form.html.haml index 1e1400058e1..0d52f9ecbb6 100644 --- a/app/views/projects/wikis/_form.html.haml +++ b/app/views/projects/wikis/_form.html.haml @@ -22,7 +22,7 @@ .form-group.wiki-content = f.label :content, class: 'control-label' .col-sm-10 - = render layout: 'projects/md_preview' do + = render layout: 'projects/md_preview', locals: { preview_class: "wiki" } do = render 'projects/zen', f: f, attr: :content, classes: 'description form-control' .col-sm-12.hint .pull-left Wiki content is parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"), target: '_blank'} diff --git a/app/views/shared/_file_highlight.html.haml b/app/views/shared/_file_highlight.html.haml index 52b48ff7451..fba69dd0f3f 100644 --- a/app/views/shared/_file_highlight.html.haml +++ b/app/views/shared/_file_highlight.html.haml @@ -7,4 +7,5 @@ = link_to "#L#{i}", id: "L#{i}", rel: "#L#{i}" do %i.fa.fa-link = i - = highlight(blob.name, blob.data) + :preserve + #{highlight(blob.name, blob.data)} diff --git a/app/views/shared/_issuable_filter.html.haml b/app/views/shared/_issuable_filter.html.haml index 0e094d8844b..61647b09527 100644 --- a/app/views/shared/_issuable_filter.html.haml +++ b/app/views/shared/_issuable_filter.html.haml @@ -1,6 +1,6 @@ .issues-filters - .pull-left.append-right-20 - %ul.nav.nav-pills.nav-compact + .issues-state-filters + %ul.nav.nav-tabs %li{class: ("active" if params[:state] == 'opened')} = link_to page_filter_path(state: 'opened') do %i.fa.fa-exclamation-circle @@ -14,99 +14,106 @@ %i.fa.fa-compass All - .dropdown.inline.assignee-filter - %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} - %i.fa.fa-user - %span.light assignee: - - if @assignee.present? - %strong= @assignee.name - - elsif params[:assignee_id] == "0" - Unassigned - - else - Any - %b.caret - %ul.dropdown-menu - %li - = link_to page_filter_path(assignee_id: nil) do - Any - = link_to page_filter_path(assignee_id: 0) do - Unassigned - - @assignees.sort_by(&:name).each do |user| - %li - = link_to page_filter_path(assignee_id: user.id) do - = image_tag avatar_icon(user.email), class: "avatar s16", alt: '' - = user.name - - .dropdown.inline.prepend-left-10.author-filter - %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} - %i.fa.fa-user - %span.light author: - - if @author.present? - %strong= @author.name - - elsif params[:author_id] == "0" - Unassigned - - else - Any - %b.caret - %ul.dropdown-menu - %li - = link_to page_filter_path(author_id: nil) do - Any - = link_to page_filter_path(author_id: 0) do - Unassigned - - @authors.sort_by(&:name).each do |user| - %li - = link_to page_filter_path(author_id: user.id) do - = image_tag avatar_icon(user.email), class: "avatar s16", alt: '' - = user.name - - .dropdown.inline.prepend-left-10.milestone-filter - %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} - %i.fa.fa-clock-o - %span.light milestone: - - if @milestone.present? - %strong= @milestone.title - - elsif params[:milestone_id] == "0" - None (backlog) - - else - Any - %b.caret - %ul.dropdown-menu - %li - = link_to page_filter_path(milestone_id: nil) do - Any - = link_to page_filter_path(milestone_id: 0) do - None (backlog) - - @milestones.each do |milestone| - %li - = link_to page_filter_path(milestone_id: milestone.id) do - %strong= milestone.title - %small.light= milestone.expires_at + %div + - if controller.controller_name == 'issues' + .check-all-holder + = check_box_tag "check_all_issues", nil, false, + class: "check_all_issues left", + disabled: !can?(current_user, :modify_issue, @project) + .issues-other-filters + .dropdown.inline.assignee-filter + %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} + %i.fa.fa-user + %span.light assignee: + - if @assignee.present? + %strong= @assignee.name + - elsif params[:assignee_id] == "0" + Unassigned + - else + Any + %b.caret + %ul.dropdown-menu + %li + = link_to page_filter_path(assignee_id: nil) do + Any + = link_to page_filter_path(assignee_id: 0) do + Unassigned + - @assignees.sort_by(&:name).each do |user| + %li + = link_to page_filter_path(assignee_id: user.id) do + = image_tag avatar_icon(user.email), class: "avatar s16", alt: '' + = user.name - - if @project - .dropdown.inline.prepend-left-10.labels-filter - %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} - %i.fa.fa-tags - %span.light label: - - if params[:label_name].present? - %strong= params[:label_name] - - else - Any - %b.caret - %ul.dropdown-menu - %li - = link_to page_filter_path(label_name: nil) do + .dropdown.inline.prepend-left-10.author-filter + %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} + %i.fa.fa-user + %span.light author: + - if @author.present? + %strong= @author.name + - elsif params[:author_id] == "0" + Unassigned + - else Any - - if @project.labels.any? - - @project.labels.each do |label| + %b.caret + %ul.dropdown-menu + %li + = link_to page_filter_path(author_id: nil) do + Any + = link_to page_filter_path(author_id: 0) do + Unassigned + - @authors.sort_by(&:name).each do |user| %li - = link_to page_filter_path(label_name: label.name) do - = render_colored_label(label) - - else + = link_to page_filter_path(author_id: user.id) do + = image_tag avatar_icon(user.email), class: "avatar s16", alt: '' + = user.name + + .dropdown.inline.prepend-left-10.milestone-filter + %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} + %i.fa.fa-clock-o + %span.light milestone: + - if @milestone.present? + %strong= @milestone.title + - elsif params[:milestone_id] == "0" + None (backlog) + - else + Any + %b.caret + %ul.dropdown-menu %li - = link_to generate_namespace_project_labels_path(@project.namespace, @project, redirect: request.original_url), method: :post do - %i.fa.fa-plus-circle - Create default labels + = link_to page_filter_path(milestone_id: nil) do + Any + = link_to page_filter_path(milestone_id: 0) do + None (backlog) + - @milestones.each do |milestone| + %li + = link_to page_filter_path(milestone_id: milestone.id) do + %strong= milestone.title + %small.light= milestone.expires_at + + - if @project + .dropdown.inline.prepend-left-10.labels-filter + %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} + %i.fa.fa-tags + %span.light label: + - if params[:label_name].present? + %strong= params[:label_name] + - else + Any + %b.caret + %ul.dropdown-menu + %li + = link_to page_filter_path(label_name: nil) do + Any + - if @project.labels.any? + - @project.labels.each do |label| + %li + = link_to page_filter_path(label_name: label.name) do + = render_colored_label(label) + - else + %li + = link_to generate_namespace_project_labels_path(@project.namespace, @project, redirect: request.original_url), method: :post do + %i.fa.fa-plus-circle + Create default labels - .pull-right - = render 'shared/sort_dropdown' + .pull-right + = render 'shared/sort_dropdown' diff --git a/app/views/shared/_milestones_filter.html.haml b/app/views/shared/_milestones_filter.html.haml index 208f1b77372..f685ae7726c 100644 --- a/app/views/shared/_milestones_filter.html.haml +++ b/app/views/shared/_milestones_filter.html.haml @@ -1,5 +1,5 @@ .milestones-filters.append-bottom-10 - %ul.nav.nav-pills.nav-compact + %ul.nav.nav-tabs %li{class: ("active" if params[:state].blank? || params[:state] == 'opened')} = link_to milestones_filter_path(state: 'opened') do %i.fa.fa-exclamation-circle diff --git a/app/views/users/_projects.html.haml b/app/views/users/_projects.html.haml index 1d38f8e8ab8..c925a48f550 100644 --- a/app/views/users/_projects.html.haml +++ b/app/views/users/_projects.html.haml @@ -1,6 +1,21 @@ -.panel.panel-default - .panel-heading Personal projects - %ul.well-list - - projects.each do |project| - %li - = link_to_project project +- if @contributed_projects.present? + .panel.panel-default + .panel-heading Projects contributed to + %ul.well-list + - @contributed_projects.sort_by(&:star_count).reverse.each do |project| + %li + = link_to_project project + %span.pull-right.light + %i.fa.fa-star + = project.star_count + +- if @projects.present? + .panel.panel-default + .panel-heading Personal projects + %ul.well-list + - @projects.sort_by(&:star_count).reverse.each do |project| + %li + = link_to_project project + %span.pull-right.light + %i.fa.fa-star + = project.star_count diff --git a/app/views/users/calendar.html.haml b/app/views/users/calendar.html.haml index 13bdc5ed1e7..1d1c974da24 100644 --- a/app/views/users/calendar.html.haml +++ b/app/views/users/calendar.html.haml @@ -1,4 +1,4 @@ -%h4 Calendar +%h4 Commits calendar #cal-heatmap.calendar :javascript new calendar( diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index b05918b019e..5e82d5780cf 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -35,9 +35,7 @@ = render @events .col-md-4 = render 'profile', user: @user - - if @projects.present? - = render 'projects', projects: @projects - + = render 'projects' :coffeescript $ -> diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index d7c1a8428ac..6a8bbb80b9c 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -112,6 +112,7 @@ end Settings.gitlab['time_zone'] ||= nil Settings.gitlab['signup_enabled'] ||= true if Settings.gitlab['signup_enabled'].nil? Settings.gitlab['signin_enabled'] ||= true if Settings.gitlab['signin_enabled'].nil? +Settings.gitlab['twitter_sharing_enabled'] ||= true if Settings.gitlab['twitter_sharing_enabled'].nil? Settings.gitlab['restricted_visibility_levels'] = Settings.send(:verify_constant_array, Gitlab::VisibilityLevel, Settings.gitlab['restricted_visibility_levels'], []) Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil? Settings.gitlab['issue_closing_pattern'] = '((?:[Cc]los(?:e[sd]?|ing)|[Ff]ix(?:e[sd]|ing)?|[Rr]esolv(?:e[sd]?|ing)) +(?:(?:issues? +)?#\d+(?:(?:, *| +and +)?))+)' if Settings.gitlab['issue_closing_pattern'].nil? diff --git a/db/fixtures/development/01_admin.rb b/db/fixtures/development/01_admin.rb index 1b2dec31323..bba2fc4b186 100644 --- a/db/fixtures/development/01_admin.rb +++ b/db/fixtures/development/01_admin.rb @@ -3,6 +3,7 @@ Gitlab::Seeder.quiet do s.id = 1 s.name = 'Administrator' s.email = 'admin@example.com' + s.notification_email = 'admin@example.com' s.username = 'root' s.password = '5iveL!fe' s.admin = true diff --git a/db/migrate/20150213104043_add_twitter_sharing_enabled_to_application_settings.rb b/db/migrate/20150213104043_add_twitter_sharing_enabled_to_application_settings.rb new file mode 100644 index 00000000000..a0439172391 --- /dev/null +++ b/db/migrate/20150213104043_add_twitter_sharing_enabled_to_application_settings.rb @@ -0,0 +1,5 @@ +class AddTwitterSharingEnabledToApplicationSettings < ActiveRecord::Migration + def change + add_column :application_settings, :twitter_sharing_enabled, :boolean, default: true + end +end diff --git a/doc/README.md b/doc/README.md index 79d4f5273ee..4e00dceac2b 100644 --- a/doc/README.md +++ b/doc/README.md @@ -10,10 +10,11 @@ - [SSH](ssh/README.md) Setup your ssh keys and deploy keys for secure access to your projects. - [Web hooks](web_hooks/web_hooks.md) Let GitLab notify you when new code has been pushed to your project. - [Workflow](workflow/README.md) Using GitLab functionality and importing projects from GitHub and SVN. +- [GitLab as OAuth2 authentication service provider](integration/oauth_provider.md). It allows you to login to other applications from GitLab. ## Administrator documentation -- [Install](install/README.md) Requirements, directory structures and manual installation. +- [Install](install/README.md) Requirements, directory structures and installation from source. - [Integration](integration/README.md) How to integrate with systems such as JIRA, Redmine, LDAP and Twitter. - [Raketasks](raketasks/README.md) Backups, maintenance, automatic web hook setup and the importing of projects. - [Custom git hooks](hooks/custom_hooks.md) Custom git hooks (on the filesystem) for when web hooks aren't enough. diff --git a/doc/api/README.md b/doc/api/README.md index 8cbba8598d5..dec530d0b81 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -22,6 +22,7 @@ ## Clients Find API Clients for GitLab [on our website](https://about.gitlab.com/applications/#api-clients). +You can use [GitLab as an OAuth2 client](oauth2.md) to make API calls. ## Introduction @@ -67,7 +68,7 @@ curl https://localhost:3000/api/v3/user?access_token=OAUTH-TOKEN curl -H "Authorization: Bearer OAUTH-TOKEN" https://localhost:3000/api/v3/user ``` -Read more about [OAuth2 in GitLab](oauth2.md). +Read more about [GitLab as an OAuth2 client](oauth2.md). ## Status codes diff --git a/doc/api/branches.md b/doc/api/branches.md index 319f0b47386..6a9c10c8520 100644 --- a/doc/api/branches.md +++ b/doc/api/branches.md @@ -15,27 +15,20 @@ Parameters: ```json [ { - "name": "master", "commit": { + "author_email": "john@example.com", + "author_name": "John Smith", + "authored_date": "2012-06-27T05:51:39-07:00", + "committed_date": "2012-06-28T03:44:20-07:00", + "committer_email": "john@example.com", + "committer_name": "John Smith", "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c", - "parents": [ - { - "id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8" - } - ], - "tree": "46e82de44b1061621357f24c05515327f2795a95", "message": "add projects API", - "author": { - "name": "John Smith", - "email": "john@example.com" - }, - "committer": { - "name": "John Smith", - "email": "john@example.com" - }, - "authored_date": "2012-06-27T05:51:39-07:00", - "committed_date": "2012-06-28T03:44:20-07:00" + "parent_ids": [ + "4ad91d3c1144c406e50c7b33bae684bd6837faf8" + ] }, + "name": "master", "protected": true } ] @@ -56,27 +49,20 @@ Parameters: ```json { - "name": "master", "commit": { + "author_email": "john@example.com", + "author_name": "John Smith", + "authored_date": "2012-06-27T05:51:39-07:00", + "committed_date": "2012-06-28T03:44:20-07:00", + "committer_email": "john@example.com", + "committer_name": "John Smith", "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c", - "parents": [ - { - "id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8" - } - ], - "tree": "46e82de44b1061621357f24c05515327f2795a95", "message": "add projects API", - "author": { - "name": "John Smith", - "email": "john@example.com" - }, - "committer": { - "name": "John Smith", - "email": "john@example.com" - }, - "authored_date": "2012-06-27T05:51:39-07:00", - "committed_date": "2012-06-28T03:44:20-07:00" + "parent_ids": [ + "4ad91d3c1144c406e50c7b33bae684bd6837faf8" + ] }, + "name": "master", "protected": true } ``` @@ -97,27 +83,20 @@ Parameters: ```json { - "name": "master", "commit": { + "author_email": "john@example.com", + "author_name": "John Smith", + "authored_date": "2012-06-27T05:51:39-07:00", + "committed_date": "2012-06-28T03:44:20-07:00", + "committer_email": "john@example.com", + "committer_name": "John Smith", "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c", - "parents": [ - { - "id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8" - } - ], - "tree": "46e82de44b1061621357f24c05515327f2795a95", "message": "add projects API", - "author": { - "name": "John Smith", - "email": "john@example.com" - }, - "committer": { - "name": "John Smith", - "email": "john@example.com" - }, - "authored_date": "2012-06-27T05:51:39-07:00", - "committed_date": "2012-06-28T03:44:20-07:00" + "parent_ids": [ + "4ad91d3c1144c406e50c7b33bae684bd6837faf8" + ] }, + "name": "master", "protected": true } ``` @@ -138,27 +117,20 @@ Parameters: ```json { - "name": "master", "commit": { + "author_email": "john@example.com", + "author_name": "John Smith", + "authored_date": "2012-06-27T05:51:39-07:00", + "committed_date": "2012-06-28T03:44:20-07:00", + "committer_email": "john@example.com", + "committer_name": "John Smith", "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c", - "parents": [ - { - "id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8" - } - ], - "tree": "46e82de44b1061621357f24c05515327f2795a95", "message": "add projects API", - "author": { - "name": "John Smith", - "email": "john@example.com" - }, - "committer": { - "name": "John Smith", - "email": "john@example.com" - }, - "authored_date": "2012-06-27T05:51:39-07:00", - "committed_date": "2012-06-28T03:44:20-07:00" + "parent_ids": [ + "4ad91d3c1144c406e50c7b33bae684bd6837faf8" + ] }, + "name": "master", "protected": false } ``` @@ -177,21 +149,20 @@ Parameters: ```json { - "name": "my-new-branch", "commit": { - "id": "8848c0e90327a0b70f1865b843fb2fbfb9345e57", - "message": "Merge pull request #54 from brightbox/use_fog_brightbox_module\n\nUpdate to use fog-brightbox module", - "parent_ids": [ - "fff449e0bf453576f16c91d6544f00a2664009d8", - "f93a93626fec20fd659f4ed3ab2e64019b6169ae" - ], - "authored_date": "2014-02-20T19:54:55+02:00", - "author_name": "john smith", "author_email": "john@example.com", - "committed_date": "2014-02-20T19:54:55+02:00", - "committer_name": "john smith", - "committer_email": "john@example.com" + "author_name": "John Smith", + "authored_date": "2012-06-27T05:51:39-07:00", + "committed_date": "2012-06-28T03:44:20-07:00", + "committer_email": "john@example.com", + "committer_name": "John Smith", + "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c", + "message": "add projects API", + "parent_ids": [ + "4ad91d3c1144c406e50c7b33bae684bd6837faf8" + ] }, + "name": "master", "protected": false } ``` diff --git a/doc/api/groups.md b/doc/api/groups.md index 3c1858e697d..b5a4b05ccaf 100644 --- a/doc/api/groups.md +++ b/doc/api/groups.md @@ -14,7 +14,6 @@ GET /groups "id": 1, "name": "Foobar Group", "path": "foo-bar", - "owner_id": 18, "description": "An interesting group" } ] @@ -87,7 +86,6 @@ GET /groups?search=foobar "id": 1, "name": "Foobar Group", "path": "foo-bar", - "owner_id": 18, "description": "An interesting group" } ] diff --git a/doc/api/oauth2.md b/doc/api/oauth2.md index 7bb391054ce..d416a826f79 100644 --- a/doc/api/oauth2.md +++ b/doc/api/oauth2.md @@ -1,14 +1,17 @@ -# OAuth2 authentication +# GitLab as an OAuth2 client -OAuth2 is a protocol that enables us to get access to private details of user's account without getting its password. +This document is about using other OAuth authentication service providers to sign into GitLab. +If you want GitLab to be an OAuth authentication service provider to sign into other services please see the [Oauth2 provider documentation](../integration/oauth_provider.md). -Before using the OAuth2 you should create an application in user's account. Each application getting unique App ID and App Secret parameters. You should not share them. +OAuth2 is a protocol that enables us to authenticate a user without requiring them to give their password. + +Before using the OAuth2 you should create an application in user's account. Each application gets a unique App ID and App Secret parameters. You should not share these. This functionality is based on [doorkeeper gem](https://github.com/doorkeeper-gem/doorkeeper) ## Web Application Flow -This flow is using for authentication from third-party web sites and probably is most used. +This flow is using for authentication from third-party web sites and is probably used the most. It basically consists of an exchange of an authorization token for an access token. For more detailed info, check out the [RFC spec here](http://tools.ietf.org/html/rfc6749#section-4.1) This flow consists from 3 steps. diff --git a/doc/development/omnibus.md b/doc/development/omnibus.md new file mode 100644 index 00000000000..0ba354d28a2 --- /dev/null +++ b/doc/development/omnibus.md @@ -0,0 +1,32 @@ +# What you should know about omnibus packages + +Most users install GitLab using our omnibus packages. As a developer it can be +good to know how the omnibus packages differ from what you have on your laptop +when you are coding. + +## Files are owned by root by default + +All the files in the Rails tree (`app/`, `config/` etc.) are owned by 'root' in +omnibus installations. This makes the installation simpler and it provides +extra security. The omnibus reconfigure script contains commands that give +write access to the 'git' user only where needed. + +For example, the 'git' user is allowed to write in the `log/` directory, in +`public/uploads`, and they are allowed to rewrite the `db/schema.rb` file. + +In other cases, the reconfigure script tricks GitLab into not trying to write a +file. For instance, GitLab will generate a `.secret` file if it cannot find one +and write it to the Rails root. In the omnibus packages, reconfigure writes the +`.secret` file first, so that GitLab never tries to write it. + +## Code, data and logs are in separate directories + +The omnibus design separates code (read-only, under `/opt/gitlab`) from data +(read/write, under `/var/opt/gitlab`) and logs (read/write, under +`/var/log/gitlab`). To make this happen the reconfigure script sets custom +paths where it can in GitLab config files, and where there are no path +settings, it uses symlinks. + +For example, `config/gitlab.yml` is treated as data so that file is a symlink. +The same goes for `public/uploads`. The `log/` directory is replaced by omnibus +with a symlink to `/var/log/gitlab/gitlab-rails`. diff --git a/doc/hooks/custom_hooks.md b/doc/hooks/custom_hooks.md index 00867ead80d..f7d4f3de68b 100644 --- a/doc/hooks/custom_hooks.md +++ b/doc/hooks/custom_hooks.md @@ -24,7 +24,7 @@ set up a custom hook. 1. Pick a project that needs a custom git hook. 1. On the GitLab server, navigate to the project's repository directory. -For a manual install the path is usually +For an installation from source the path is usually `/home/git/repositories/<group>/<project>.git`. For Omnibus installs the path is usually `/var/opt/gitlab/git-data/repositories/<group>/<project>.git`. 1. Create a new directory in this location called `custom_hooks`. diff --git a/doc/install/installation.md b/doc/install/installation.md index bd81073c7eb..f5dcec2f61e 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -2,7 +2,7 @@ ## Consider the Omnibus package installation -Since a manual installation is a lot of work and error prone we strongly recommend the fast and reliable [Omnibus package installation](https://about.gitlab.com/downloads/) (deb/rpm). +Since an installation from source is a lot of work and error prone we strongly recommend the fast and reliable [Omnibus package installation](https://about.gitlab.com/downloads/) (deb/rpm). ## Select Version to Install @@ -183,9 +183,9 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da ### Clone the Source # Clone GitLab repository - sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 7-6-stable gitlab + sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 7-8-stable gitlab -**Note:** You can change `7-6-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server! +**Note:** You can change `7-8-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server! ### Configure It @@ -280,7 +280,7 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da GitLab Shell is an SSH access and repository management software developed specially for GitLab. # Run the installation task for gitlab-shell (replace `REDIS_URL` if needed): - sudo -u git -H bundle exec rake gitlab:shell:install[v2.4.2] REDIS_URL=unix:/var/run/redis/redis.sock RAILS_ENV=production + sudo -u git -H bundle exec rake gitlab:shell:install[v2.4.3] REDIS_URL=unix:/var/run/redis/redis.sock RAILS_ENV=production # By default, the gitlab-shell config is generated from your main GitLab config. # You can review (and modify) the gitlab-shell config as follows: diff --git a/doc/install/requirements.md b/doc/install/requirements.md index 2cf9e82fd21..5bdb9caa2bf 100644 --- a/doc/install/requirements.md +++ b/doc/install/requirements.md @@ -22,7 +22,7 @@ For the installations options please see [the installation page on the GitLab we - FreeBSD On the above unsupported distributions is still possible to install GitLab yourself. -Please see the [manual installation guide](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md) and the [unofficial installation guides](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Unofficial-Installation-Guides) on the public wiki for more information. +Please see the [installation from source guide](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md) and the [unofficial installation guides](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Unofficial-Installation-Guides) on the public wiki for more information. ### Non-Unix operating systems such as Windows diff --git a/doc/integration/README.md b/doc/integration/README.md index 1fc8ab997ec..e5f33d8deed 100644 --- a/doc/integration/README.md +++ b/doc/integration/README.md @@ -8,9 +8,8 @@ See the documentation below for details on how to configure these services. - [LDAP](ldap.md) Set up sign in via LDAP - [OmniAuth](omniauth.md) Sign in via Twitter, GitHub, GitLab, and Google via OAuth. - [Slack](slack.md) Integrate with the Slack chat service -- [OAuth2 provider](oauth_provider.md) OAuth2 application creation -Jenkins support is [available in GitLab EE](http://doc.gitlab.com/ee/integration/jenkins.html). +GitLab Enterprise Edition contains [advanced JIRA support](http://doc.gitlab.com/ee/integration/jira.html) and [advanced Jenkins support](http://doc.gitlab.com/ee/integration/jenkins.html). ## Project services diff --git a/doc/integration/external-issue-tracker.md b/doc/integration/external-issue-tracker.md index 53d6898b6e8..96755707dee 100644 --- a/doc/integration/external-issue-tracker.md +++ b/doc/integration/external-issue-tracker.md @@ -8,6 +8,8 @@ GitLab has a great issue tracker but you can also use an external issue tracker ![Jira screenshot](jira-integration-points.png) +GitLab Enterprise Edition contains [advanced JIRA support](http://doc.gitlab.com/ee/integration/jira.html). + ## Configuration ### Project Service @@ -23,7 +25,6 @@ Fill in the required details on the page: * `issues_url` The URL to the issue in Redmine project that is linked to this GitLab project. Note that the `issues_url` requires `:id` in the url. This id is used by GitLab as a placeholder to replace the issue number. * `new_issue_url` This is the URL to create a new issue in Redmine for the project linked to this GitLab project. - ### Service Template It is necessary to configure the external issue tracker per project, because project specific details are needed for the integration with GitLab. diff --git a/doc/integration/github.md b/doc/integration/github.md index c9c27859c5e..137d7e9d632 100644 --- a/doc/integration/github.md +++ b/doc/integration/github.md @@ -35,7 +35,7 @@ To enable the GitHub OmniAuth provider you must register your application with G sudo -u git -H editor config/gitlab.yml ``` -1. See [Initial OmniAuth Configuration](README.md#initial-omniauth-configuration) for inital settings. +1. See [Initial OmniAuth Configuration](omniauth.md#initial-omniauth-configuration) for inital settings. 1. Add the provider configuration: diff --git a/doc/integration/gitlab.md b/doc/integration/gitlab.md index b95ef5c0af3..87400bed5b5 100644 --- a/doc/integration/gitlab.md +++ b/doc/integration/gitlab.md @@ -1,10 +1,13 @@ -# GitLab OAuth2 OmniAuth Provider +# Integrate your server with GitLab.com -To enable the GitLab OmniAuth provider you must register your application with GitLab. GitLab will generate a client ID and secret key for you to use. +Import projects from GitLab.com and login to your GitLab instance with your GitLab.com account. -1. Sign in to GitLab. +To enable the GitLab.com OmniAuth provider you must register your application with GitLab.com. +GitLab.com will generate a application ID and secret key for you to use. -1. Navigate to your settings. +1. Sign in to GitLab.com + +1. Navigate to your profile settings. 1. Select "Applications" in the left menu. @@ -15,17 +18,17 @@ To enable the GitLab OmniAuth provider you must register your application with G - Redirect URI: ``` - http://gitlab.example.com/import/gitlab/callback - http://gitlab.example.com/users/auth/gitlab/callback + http://your-gitlab.example.com/import/gitlab/callback + http://your-gitlab.example.com/users/auth/gitlab/callback ``` The first link is required for the importer and second for the authorization. 1. Select "Submit". -1. You should now see a Application ID and Secret. Keep this page open as you continue configuration. - -1. You should now see a Client ID and Client Secret near the top right of the page (see screenshot). Keep this page open as you continue configuration. ![GitHub app](github_app.png) +1. You should now see a Client ID and Client Secret near the top right of the page (see screenshot). + Keep this page open as you continue configuration. + ![GitLab app](gitlab_app.png) 1. On your GitLab server, open the configuration file. @@ -43,7 +46,7 @@ To enable the GitLab OmniAuth provider you must register your application with G sudo -u git -H editor config/gitlab.yml ``` -1. See [Initial OmniAuth Configuration](README.md#initial-omniauth-configuration) for inital settings. +1. See [Initial OmniAuth Configuration](omniauth.md#initial-omniauth-configuration) for inital settings. 1. Add the provider configuration: @@ -76,4 +79,6 @@ To enable the GitLab OmniAuth provider you must register your application with G 1. Restart GitLab for the changes to take effect. -On the sign in page there should now be a GitLab icon below the regular sign in form. Click the icon to begin the authentication process. GitLab will ask the user to sign in and authorize the GitLab application. If everything goes well the user will be returned to your GitLab instance and will be signed in. +On the sign in page there should now be a GitLab.com icon below the regular sign in form. +Click the icon to begin the authentication process. GitLab.com will ask the user to sign in and authorize the GitLab application. +If everything goes well the user will be returned to your GitLab instance and will be signed in. diff --git a/doc/integration/gitlab_app.png b/doc/integration/gitlab_app.png Binary files differnew file mode 100644 index 00000000000..3f9391a821b --- /dev/null +++ b/doc/integration/gitlab_app.png diff --git a/doc/integration/google.md b/doc/integration/google.md index 76beac16c49..168077c2770 100644 --- a/doc/integration/google.md +++ b/doc/integration/google.md @@ -68,9 +68,9 @@ To enable the Google OAuth2 OmniAuth provider you must register your application args: { access_type: 'offline', approval_prompt: '' } } ``` -1. Change 'YOUR APP ID' to the client ID from the GitHub application page from step 7. +1. Change 'YOUR APP ID' to the client ID from the Google Developer page from step 10. -1. Change 'YOUR APP SECRET' to the client secret from the GitHub application page from step 7. +1. Change 'YOUR APP SECRET' to the client secret from the Google Developer page from step 10. 1. Save the configuration file. diff --git a/doc/integration/oauth_provider.md b/doc/integration/oauth_provider.md index 5fdb74a43df..192c321f712 100644 --- a/doc/integration/oauth_provider.md +++ b/doc/integration/oauth_provider.md @@ -1,4 +1,8 @@ -## GitLab as OAuth2 provider +## GitLab as OAuth2 authentication service provider + +This document is about using GitLab as an OAuth authentication service provider to sign into other services. +If you want to use other OAuth authentication service providers to sign into GitLab please see the [OAuth2 client documentation](../api/oauth2.md) + OAuth2 provides client applications a 'secure delegated access' to server resources on behalf of a resource owner. Or you can allow users to sign in to your application with their GitLab.com account. In fact OAuth allows to issue access token to third-party clients by an authorization server, with the approval of the resource owner, or end-user. diff --git a/doc/integration/omniauth.md b/doc/integration/omniauth.md index 7433de33909..c92fa3ee4b7 100644 --- a/doc/integration/omniauth.md +++ b/doc/integration/omniauth.md @@ -70,7 +70,7 @@ Now we can choose one or more of the Supported Providers below to continue confi ## Supported Providers - [GitHub](github.md) -- [GitLab](gitlab.md) +- [GitLab.com](gitlab.md) - [Google](google.md) - [Shibboleth](shibboleth.md) - [Twitter](twitter.md) diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md index bbcf395c745..99cdfff0ac6 100644 --- a/doc/raketasks/backup_restore.md +++ b/doc/raketasks/backup_restore.md @@ -137,7 +137,7 @@ with the name of your bucket: Please be informed that a backup does not store your configuration files. If you use an Omnibus package please see the [instructions in the readme to backup your configuration](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md#backup-and-restore-omnibus-gitlab-configuration). If you have a cookbook installation there should be a copy of your configuration in Chef. -If you have a manual installation please consider backing up your `gitlab.yml` file, any SSL keys and certificates, and your [SSH host keys](https://superuser.com/questions/532040/copy-ssh-keys-from-one-server-to-another-server/532079#532079). +If you have an installation from source, please consider backing up your `gitlab.yml` file, any SSL keys and certificates, and your [SSH host keys](https://superuser.com/questions/532040/copy-ssh-keys-from-one-server-to-another-server/532079#532079). ## Restore a previously created backup diff --git a/doc/raketasks/import.md b/doc/raketasks/import.md index 9a10c8d6850..8a38937062e 100644 --- a/doc/raketasks/import.md +++ b/doc/raketasks/import.md @@ -13,7 +13,7 @@ - For omnibus-gitlab, it is located at: `/var/opt/gitlab/git-data/repositories` by default, unless you changed it in the `/etc/gitlab/gitlab.rb` file. -- For manual installations, it is usually located at: `/home/git/repositories` or you can see where +- For installations from source, it is usually located at: `/home/git/repositories` or you can see where your repositories are located by looking at `config/gitlab.yml` under the `gitlab_shell => repos_path` entry. New folder needs to have git user ownership and read/write/execute access for git user and its group: @@ -47,7 +47,7 @@ with `/home/git`. $ sudo gitlab-rake gitlab:import:repos ``` -#### Manual Installation +#### Installation from source Before running this command you need to change the directory to where your GitLab installation is located: diff --git a/doc/update/5.4-to-6.0.md b/doc/update/5.4-to-6.0.md index d18c3fe8586..d9c6d9bfb91 100644 --- a/doc/update/5.4-to-6.0.md +++ b/doc/update/5.4-to-6.0.md @@ -5,6 +5,9 @@ GitLab 6.0 is affected by critical security vulnerabilities CVE-2013-4490 and CVE-2013-4489. +**You need to follow this guide first, before updating past 6.0, as it contains critical migration steps that are only present +in the `6-0-stable` branch** + ## Deprecations ### Global projects diff --git a/doc/update/6.x-or-7.x-to-7.7.md b/doc/update/6.x-or-7.x-to-7.8.md index 8280cf2f38f..90d889d5113 100644 --- a/doc/update/6.x-or-7.x-to-7.7.md +++ b/doc/update/6.x-or-7.x-to-7.8.md @@ -1,7 +1,7 @@ -# From 6.x or 7.x to 7.7 -*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/6.x-or-7.x-to-7.4.md) for the most up to date instructions.* +# From 6.x or 7.x to 7.8 +*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/6.x-or-7.x-to-7.8.md) for the most up to date instructions.* -This allows you to upgrade any version of GitLab from 6.0 and up (including 7.0 and up) to 7.7. +This allows you to upgrade any version of GitLab from 6.0 and up (including 7.0 and up) to 7.8. ## Global issue numbers @@ -71,7 +71,7 @@ sudo -u git -H git checkout -- db/schema.rb # local changes will be restored aut For GitLab Community Edition: ```bash -sudo -u git -H git checkout 7-7-stable +sudo -u git -H git checkout 7-8-stable ``` OR @@ -79,7 +79,7 @@ OR For GitLab Enterprise Edition: ```bash -sudo -u git -H git checkout 7-7-stable-ee +sudo -u git -H git checkout 7-8-stable-ee ``` ## 4. Install additional packages @@ -123,7 +123,7 @@ sudo apt-get install libkrb5-dev ```bash cd /home/git/gitlab-shell sudo -u git -H git fetch -sudo -u git -H git checkout v2.4.1 +sudo -u git -H git checkout v2.4.3 ``` ## 7. Install libs, migrations, etc. @@ -158,14 +158,14 @@ sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab TIP: to see what changed in `gitlab.yml.example` in this release use next command: ``` -git diff 6-0-stable:config/gitlab.yml.example 7-7-stable:config/gitlab.yml.example +git diff 6-0-stable:config/gitlab.yml.example 7-8-stable:config/gitlab.yml.example ``` -* Make `/home/git/gitlab/config/gitlab.yml` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-7-stable/config/gitlab.yml.example but with your settings. -* Make `/home/git/gitlab/config/unicorn.rb` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-7-stable/config/unicorn.rb.example but with your settings. -* Make `/home/git/gitlab-shell/config.yml` the same as https://gitlab.com/gitlab-org/gitlab-shell/blob/v2.4.0/config.yml.example but with your settings. -* HTTP setups: Make `/etc/nginx/sites-available/gitlab` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-7-stable/lib/support/nginx/gitlab but with your settings. -* HTTPS setups: Make `/etc/nginx/sites-available/gitlab-ssl` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-7-stable/lib/support/nginx/gitlab-ssl but with your settings. +* Make `/home/git/gitlab/config/gitlab.yml` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-8-stable/config/gitlab.yml.example but with your settings. +* Make `/home/git/gitlab/config/unicorn.rb` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-8-stable/config/unicorn.rb.example but with your settings. +* Make `/home/git/gitlab-shell/config.yml` the same as https://gitlab.com/gitlab-org/gitlab-shell/blob/v2.4.3/config.yml.example but with your settings. +* HTTP setups: Make `/etc/nginx/sites-available/gitlab` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-8-stable/lib/support/nginx/gitlab but with your settings. +* HTTPS setups: Make `/etc/nginx/sites-available/gitlab-ssl` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-8-stablef/lib/support/nginx/gitlab-ssl but with your settings. * Copy rack attack middleware config ```bash @@ -235,7 +235,7 @@ SET foreign_key_checks = 1; # Find MySQL users mysql> SELECT user FROM mysql.user WHERE user LIKE '%git%'; -# If git user exists and gitlab user does not exist +# If git user exists and gitlab user does not exist # you are done with the database cleanup tasks mysql> \q @@ -273,11 +273,11 @@ mysql> \q sudo -u git -H editor /home/git/gitlab/config/database.yml ``` -## Things went south? Revert to previous version (6.0) +## Things went south? Revert to previous version (7.0) ### 1. Revert the code to the previous version -Follow the [upgrade guide from 5.4 to 6.0](5.4-to-6.0.md), except for the database migration (the backup is already migrated to the previous version). +Follow the [upgrade guide from 6.9 to 7.0](6.9-to-7.0.md), except for the database migration (the backup is already migrated to the previous version). ### 2. Restore from the backup: diff --git a/doc/update/7.7-to-7.8.md b/doc/update/7.7-to-7.8.md new file mode 100644 index 00000000000..01b4fc4c992 --- /dev/null +++ b/doc/update/7.7-to-7.8.md @@ -0,0 +1,119 @@ +# From 7.7 to 7.8 + +### 0. Stop server + + sudo service gitlab stop + +### 1. Backup + +```bash +cd /home/git/gitlab +sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production +``` + +### 2. Get latest code + +```bash +sudo -u git -H git fetch --all +sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically +``` + +For GitLab Community Edition: + +```bash +sudo -u git -H git checkout 7-8-stable +``` + +OR + +For GitLab Enterprise Edition: + +```bash +sudo -u git -H git checkout 7-8-stable-ee +``` + +### 3. Update gitlab-shell + +```bash +cd /home/git/gitlab-shell +sudo -u git -H git fetch +sudo -u git -H git checkout v2.4.3 +``` + +### 4. Install libs, migrations, etc. + +```bash +sudo apt-get install libkrb5-dev + +cd /home/git/gitlab + +# MySQL installations (note: the line below states '--without ... postgres') +sudo -u git -H bundle install --without development test postgres --deployment + +# PostgreSQL installations (note: the line below states '--without ... mysql') +sudo -u git -H bundle install --without development test mysql --deployment + +# Run database migrations +sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production + +# Clean up assets and cache +sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS_ENV=production + +# Update init.d script +sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab +``` + +### 5. Update config files + +#### New configuration options for `gitlab.yml` + +There are new configuration options available for [`gitlab.yml`](config/gitlab.yml.example). View them with the command below and apply them to your current `gitlab.yml`. + +``` +git diff origin/7-6-stable:config/gitlab.yml.example origin/7-8-stable:config/gitlab.yml.example +``` + +#### Change Nginx settings + +* HTTP setups: Make `/etc/nginx/sites-available/gitlab` the same as [`lib/support/nginx/gitlab`](/lib/support/nginx/gitlab) but with your settings +* HTTPS setups: Make `/etc/nginx/sites-available/gitlab-ssl` the same as [`lib/support/nginx/gitlab-ssl`](/lib/support/nginx/gitlab-ssl) but with your setting + +#### Setup time zone (optional) + +Consider setting the time zone in `gitlab.yml` otherwise GitLab will default to UTC. If you set a time zone previously in [`application.rb`](config/application.rb) (unlikely), unset it. + +### 6. Start application + + sudo service gitlab start + sudo service nginx restart + +### 7. Check application status + +Check if GitLab and its environment are configured correctly: + + sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production + +To make sure you didn't miss anything run a more thorough check with: + + sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production + +If all items are green, then congratulations upgrade is complete! + +### 8. GitHub settings (if applicable) + +If you are using GitHub as an OAuth provider for authentication, you should change the callback URL so that it +only contains a root URL (ex. `https://gitlab.example.com/`) + +## Things went south? Revert to previous version (7.6) + +### 1. Revert the code to the previous version +Follow the [upgrade guide from 7.5 to 7.6](7.5-to-7.6.md), except for the database migration +(The backup is already migrated to the previous version) + +### 2. Restore from the backup: + +```bash +cd /home/git/gitlab +sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production +``` +If you have more than one backup *.tar file(s) please add `BACKUP=timestamp_of_backup` to the command above. diff --git a/doc/update/README.md b/doc/update/README.md index 5380ddbd030..0472537eeb5 100644 --- a/doc/update/README.md +++ b/doc/update/README.md @@ -4,11 +4,11 @@ Depending on the installation method and your GitLab version, there are multiple - [Omnibus update guide](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/update.md) contains the steps needed to update a GitLab [package](https://about.gitlab.com/downloads/). -## Manual Installation +## Installation from source -- [The individual upgrade guides](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/update) are for those who have installed GitLab manually. +- [The individual upgrade guides](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/update) are for those who have installed GitLab from source. - [The CE to EE update guides](https://gitlab.com/subscribers/gitlab-ee/tree/master/doc/update) are for subscribers of the Enterprise Edition only. The steps are very similar to a version upgrade: stop the server, get the code, update config files for the new functionality, install libs and do migrations, update the init script, start the application and check the application status. -- [Upgrader](upgrader.md) is an automatic ruby script that performs the update for manual installations. +- [Upgrader](upgrader.md) is an automatic ruby script that performs the update for installations from source. - [Patch versions](patch_versions.md) guide includes the steps needed for a patch version, eg. 6.2.0 to 6.2.1. ## Miscellaneous diff --git a/features/dashboard/dashboard.feature b/features/dashboard/dashboard.feature index bebaa78e46c..1959d327082 100644 --- a/features/dashboard/dashboard.feature +++ b/features/dashboard/dashboard.feature @@ -27,11 +27,11 @@ Feature: Dashboard Scenario: I should see User joined Project event Given user with name "John Doe" joined project "Shop" When I visit dashboard page - Then I should see "John Doe joined project at Shop" event + Then I should see "John Doe joined project Shop" event @javascript Scenario: I should see User left Project event Given user with name "John Doe" joined project "Shop" And user with name "John Doe" left project "Shop" When I visit dashboard page - Then I should see "John Doe left project at Shop" event + Then I should see "John Doe left project Shop" event diff --git a/features/project/active_tab.feature b/features/project/active_tab.feature index ed548177837..05faad4e645 100644 --- a/features/project/active_tab.feature +++ b/features/project/active_tab.feature @@ -106,24 +106,19 @@ Feature: Project Active Tab And no other sub tabs should be active And the active main tab should be Commits - # Sub Tabs: Issues - Scenario: On Project Issues/Browse Given I visit my project's issues page - Then the active sub tab should be Issues - And no other sub tabs should be active - And the active main tab should be Issues + Then the active main tab should be Issues + And no other main tabs should be active Scenario: On Project Issues/Milestones Given I visit my project's issues page And I click the "Milestones" tab - Then the active sub tab should be Milestones - And no other sub tabs should be active - And the active main tab should be Issues + Then the active main tab should be Milestones + And no other main tabs should be active Scenario: On Project Issues/Labels Given I visit my project's issues page And I click the "Labels" tab - Then the active sub tab should be Labels - And no other sub tabs should be active - And the active main tab should be Issues + Then the active main tab should be Labels + And no other main tabs should be active diff --git a/features/steps/dashboard/dashboard.rb b/features/steps/dashboard/dashboard.rb index f9b1f18562a..8508b2a8096 100644 --- a/features/steps/dashboard/dashboard.rb +++ b/features/steps/dashboard/dashboard.rb @@ -37,8 +37,8 @@ class Spinach::Features::Dashboard < Spinach::FeatureSteps ) end - step 'I should see "John Doe joined project at Shop" event' do - page.should have_content "John Doe joined project at #{project.name_with_namespace}" + step 'I should see "John Doe joined project Shop" event' do + page.should have_content "John Doe joined project #{project.name_with_namespace}" end step 'user with name "John Doe" left project "Shop"' do @@ -50,8 +50,8 @@ class Spinach::Features::Dashboard < Spinach::FeatureSteps ) end - step 'I should see "John Doe left project at Shop" event' do - page.should have_content "John Doe left project at #{project.name_with_namespace}" + step 'I should see "John Doe left project Shop" event' do + page.should have_content "John Doe left project #{project.name_with_namespace}" end step 'I have group with projects' do diff --git a/features/steps/project/active_tab.rb b/features/steps/project/active_tab.rb index bb42d15eae5..dd3215adb1a 100644 --- a/features/steps/project/active_tab.rb +++ b/features/steps/project/active_tab.rb @@ -93,11 +93,11 @@ class Spinach::Features::ProjectActiveTab < Spinach::FeatureSteps ensure_active_sub_tab('Issues') end - step 'the active sub tab should be Milestones' do - ensure_active_sub_tab('Milestones') + step 'the active main tab should be Milestones' do + ensure_active_main_tab('Milestones') end - step 'the active sub tab should be Labels' do - ensure_active_sub_tab('Labels') + step 'the active main tab should be Labels' do + ensure_active_main_tab('Labels') end end diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb index e477444023d..d358f1d875f 100644 --- a/features/steps/project/merge_requests.rb +++ b/features/steps/project/merge_requests.rb @@ -253,7 +253,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps end step 'I should still see a comment like "Line is correct" in the first file' do - within '.files [id^=diff]:nth-child(1) .note-text' do + within '.files [id^=diff]:nth-child(1) .note-body > .note-text' do page.should have_visible_content "Line is correct" end end @@ -271,7 +271,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps end step 'I should see comments on the side-by-side diff page' do - within '.files [id^=diff]:nth-child(1) .parallel .note-text' do + within '.files [id^=diff]:nth-child(1) .parallel .note-body > .note-text' do page.should have_visible_content "Line is correct" end end diff --git a/features/steps/shared/note.rb b/features/steps/shared/note.rb index 625bcc0b266..45773056953 100644 --- a/features/steps/shared/note.rb +++ b/features/steps/shared/note.rb @@ -116,7 +116,7 @@ module SharedNote end step 'The comment with the header should not have an ID' do - within(".note-text") do + within(".note-body > .note-text") do page.should have_content("Comment with a header") page.should_not have_css("#comment-with-a-header") end diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 8d0664386b4..7572104fc16 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -65,7 +65,7 @@ module API end class Group < Grape::Entity - expose :id, :name, :path, :owner_id, :description + expose :id, :name, :path, :description end class GroupDetail < Group diff --git a/lib/api/groups.rb b/lib/api/groups.rb index 384a28e41f5..a92abd4b690 100644 --- a/lib/api/groups.rb +++ b/lib/api/groups.rb @@ -33,9 +33,9 @@ module API attrs = attributes_for_keys [:name, :path, :description] @group = Group.new(attrs) - @group.owner = current_user if @group.save + @group.add_owner(current_user) present @group, with: Entities::Group else render_api_error!("Failed to save group #{@group.errors.messages}", 400) diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index a50ee4659a3..228a719fbdf 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -83,7 +83,7 @@ module API end def authenticate_by_gitlab_shell_token! - unauthorized! unless secret_token == params['secret_token'] + unauthorized! unless secret_token == params['secret_token'].try(:chomp) end def authenticated_as_admin! @@ -236,7 +236,7 @@ module API end def secret_token - File.read(Rails.root.join('.gitlab_shell_secret')) + File.read(Rails.root.join('.gitlab_shell_secret')).chomp end def handle_member_errors(errors) diff --git a/lib/api/internal.rb b/lib/api/internal.rb index b5542c1874b..ba3fe619b92 100644 --- a/lib/api/internal.rb +++ b/lib/api/internal.rb @@ -74,7 +74,7 @@ module API if message = BroadcastMessage.current present message, with: Entities::BroadcastMessage else - not_found! + {} end end end diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb index 93e7edf508c..1a25eebe7d1 100644 --- a/lib/gitlab/current_settings.rb +++ b/lib/gitlab/current_settings.rb @@ -1,11 +1,15 @@ module Gitlab module CurrentSettings def current_application_settings - if ActiveRecord::Base.connected? && ActiveRecord::Base.connection.table_exists?('application_settings') - ApplicationSetting.current || - ApplicationSetting.create_from_defaults - else - fake_application_settings + key = :current_application_settings + + RequestStore.store[key] ||= begin + if ActiveRecord::Base.connected? && ActiveRecord::Base.connection.table_exists?('application_settings') + RequestStore.store[:current_application_settings] = + (ApplicationSetting.current || ApplicationSetting.create_from_defaults) + else + fake_application_settings + end end end diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb index 6444cec7eb5..9b31190a882 100644 --- a/lib/gitlab/git_access.rb +++ b/lib/gitlab/git_access.rb @@ -6,6 +6,8 @@ module Gitlab attr_reader :params, :project, :git_cmd, :user def self.can_push_to_branch?(user, project, ref) + return false unless user + if project.protected_branch?(ref) && !(project.developers_can_push_to_protected_branch?(ref) && project.team.developer?(user)) user.can?(:push_code_to_protected_branches, project) diff --git a/safe/public.pem b/safe/public.pem new file mode 100644 index 00000000000..c5ffe20a5c7 --- /dev/null +++ b/safe/public.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnp2mUaLBoHFX127ysonX +OihiGpI4098eFfH1iAxpKHIof0vs0jFF05IUScNXJZ1U3w8G1U/unY/wGGa3NzAb +ZfDd22eOF6X2Gfiey6U4w9dFf0/UT5x1bphlpX357yh4O9oWWuNaWD062DTbOOsJ +U6UW2U/sZAu/QScys0Nw+gJ58t93hb4jFq+nO5IAQc6g4S8ek5YvIXOshFEpF2in +ZLbSYowx92+9GzfjvdQ7fk0Q2ssg0zfScVa6FY8n019osz0SC3wcSd/qicdfecpu +7oycpd9YDqk4lufE1qVMOsgE8OO4KXMrByz2f+T0p/bH9zdBa5HYylf1T7i60hIL +kQIDAQAB +-----END PUBLIC KEY----- diff --git a/spec/features/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb index 5c8b1f5be36..c47368b1fda 100644 --- a/spec/features/notes_on_merge_requests_spec.rb +++ b/spec/features/notes_on_merge_requests_spec.rb @@ -81,7 +81,7 @@ describe 'Comments' do within("#note_#{note.id}") do expect(find('.current-note-edit-form', visible: true)).to be_visible expect(find('.note-edit-form', visible: true)).to be_visible - expect(find(:css, '.note-text', visible: false)).not_to be_visible + expect(find(:css, '.note-body > .note-text', visible: false)).not_to be_visible end end diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb index 2caeb0dd856..68269ad25a8 100644 --- a/spec/helpers/gitlab_markdown_helper_spec.rb +++ b/spec/helpers/gitlab_markdown_helper_spec.rb @@ -584,7 +584,7 @@ describe GitlabMarkdownHelper do it "should leave code blocks untouched" do allow(helper).to receive(:user_color_scheme_class).and_return(:white) - target_html = "<pre class=\"code highlight white plaintext\"><code>some code from $40\nhere too\n</code></pre>\n" + target_html = "<pre class=\"code highlight white plaintext\"><code>some code from $#{snippet.id}\nhere too\n</code></pre>\n" expect(helper.markdown("\n some code from $#{snippet.id}\n here too\n")). to eq(target_html) @@ -638,6 +638,18 @@ describe GitlabMarkdownHelper do expect(markdown(actual)).to match(expected) end + it "should handle relative urls for a file in master with an anchor" do + actual = "[GitLab API doc](doc/api/README.md#section)\n" + expected = "<p><a href=\"/#{project.path_with_namespace}/blob/#{@ref}/doc/api/README.md#section\">GitLab API doc</a></p>\n" + expect(markdown(actual)).to match(expected) + end + + it "should not handle relative urls for the current file with an anchor" do + actual = "[GitLab API doc](#section)\n" + expected = "<p><a href=\"#section\">GitLab API doc</a></p>\n" + expect(markdown(actual)).to match(expected) + end + it "should handle relative urls for a directory in master" do actual = "[GitLab API doc](doc/api)\n" expected = "<p><a href=\"/#{project.path_with_namespace}/tree/#{@ref}/doc/api\">GitLab API doc</a></p>\n" diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb index 10b467d85fd..4c7d15d6594 100644 --- a/spec/requests/api/internal_spec.rb +++ b/spec/requests/api/internal_spec.rb @@ -32,7 +32,8 @@ describe API::API, api: true do it do get api("/internal/broadcast_message"), secret_token: secret_token - expect(response.status).to eq(404) + expect(response.status).to eq(200) + expect(json_response).to be_empty end end end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 170ede57310..0b3a47e3273 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -347,7 +347,7 @@ describe API::API, api: true do end describe 'GET /projects/:id/events' do - before { project_member } + before { project_member2 } it 'should return a project events' do get api("/projects/#{project.id}/events", user) @@ -356,7 +356,7 @@ describe API::API, api: true do expect(json_event['action_name']).to eq('joined') expect(json_event['project_id'].to_i).to eq(project.id) - expect(json_event['author_username']).to eq(user.username) + expect(json_event['author_username']).to eq(user3.username) end it 'should return a 404 error if not found' do diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index 1c150cbfe25..f869488d8d8 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -22,16 +22,7 @@ module TestEnv # Disable mailer for spinach tests disable_mailer if opts[:mailer] == false - # Clean /tmp/tests - tmp_test_path = Rails.root.join('tmp', 'tests') - - if File.directory?(tmp_test_path) - Dir.entries(tmp_test_path).each do |entry| - unless ['.', '..', 'gitlab-shell', factory_repo_name].include?(entry) - FileUtils.rm_r(File.join(tmp_test_path, entry)) - end - end - end + clean_test_path FileUtils.mkdir_p(repos_path) @@ -50,15 +41,30 @@ module TestEnv allow_any_instance_of(NotificationService).to receive(:mailer).and_call_original end + # Clean /tmp/tests + # + # Keeps gitlab-shell and gitlab-test + def clean_test_path + tmp_test_path = Rails.root.join('tmp', 'tests', '**') + + Dir[tmp_test_path].each do |entry| + unless File.basename(entry) =~ /\Agitlab-(shell|test)\z/ + FileUtils.rm_rf(entry) + end + end + end + def setup_gitlab_shell - `rake gitlab:shell:install` + unless File.directory?(Rails.root.join(*%w(tmp tests gitlab-shell))) + `rake gitlab:shell:install` + end end def setup_factory_repo clone_url = "https://gitlab.com/gitlab-org/#{factory_repo_name}.git" unless File.directory?(factory_repo_path) - system(*%W(git clone #{clone_url} #{factory_repo_path})) + system(*%W(git clone -q #{clone_url} #{factory_repo_path})) end Dir.chdir(factory_repo_path) do @@ -79,7 +85,7 @@ module TestEnv end # We must copy bare repositories because we will push to them. - system(*%W(git clone --bare #{factory_repo_path} #{factory_repo_path_bare})) + system(*%W(git clone -q --bare #{factory_repo_path} #{factory_repo_path_bare})) end def copy_repo(project) @@ -101,7 +107,7 @@ module TestEnv end def factory_repo_path_bare - factory_repo_path.to_s + '_bare' + "#{factory_repo_path}_bare" end def factory_repo_name |