Commit 681b0db6 authored by Achilleas Pipinellis's avatar Achilleas Pipinellis

Merge branch 'master' into 'ce-to-ee-2018-08-15'

# Conflicts:
#   doc/api/settings.md
parents e407e1c5 2d25b865
<!--See the general documentation guidelines https://docs.gitlab.com/ee/development/documentation -->
<!-- Mention "documentation" or "docs" in the issue title -->
<!-- Use this description template for new docs or updates to existing docs. -->
<!-- Check the documentation structure guidelines for guidance: https://docs.gitlab.com/ee/development/documentation/structure.html-->
- [ ] Documents Feature A <!-- feature name -->
- [ ] Follow-up from: #XXX, !YYY <!-- Mention related issues, MRs, and epics when available -->
## New doc or update?
<!-- Mark either of these boxes: -->
- [ ] New documentation
- [ ] Update existing documentation
## Checklists
### Product Manager
<!-- Reference: https://docs.gitlab.com/ee/development/documentation/workflow.html#1-product-manager-s-role-in-the-documentation-process -->
- [ ] Add the correct labels
- [ ] Add the correct milestone
- [ ] Indicate the correct document/directory for this feature <!-- (ping the tech writers for help if you're not sure) -->
- [ ] Fill the doc blurb below
#### Documentation blurb
<!-- Documentation template: https://docs.gitlab.com/ee/development/documentation/structure.html#documentation-template-for-new-docs -->
- Doc **title**
<!-- write the doc title here -->
- Feature **overview/description**
<!-- Write the feature overview here -->
- Feature **use cases**
<!-- Write the use cases here -->
### Developer
<!-- Reference: https://docs.gitlab.com/ee/development/documentation/workflow.html#2-developer-s-role-in-the-documentation-process -->
- [ ] Copy the doc blurb above and paste it into the doc
- [ ] Write the tutorial - explain how to use the feature
- [ ] Submit the MR using the appropriate MR description template
/label ~Documentation
<!--See the general Documentation guidelines https://docs.gitlab.com/ee/development/documentation/ -->
<!-- Use this description template for changing documentation location. For new docs or updates to existing docs, use the "Documentation" template -->
## What does this MR do?
<!-- Briefly describe what this MR is about -->
## Related issues
<!-- Mention the issue(s) this MR closes or is related to -->
Closes
## Moving docs to a new location?
Read the guidelines:
https://docs.gitlab.com/ce/development/documentation/index.html#changing-document-location
- [ ] Make sure the old link is not removed and has its contents replaced with
a link to the new location.
- [ ] Make sure internal links pointing to the document in question are not broken.
- [ ] Search and replace any links referring to old docs in GitLab Rails app,
specifically under the `app/views/` and `ee/app/views` (for GitLab EE) directories.
- [ ] Make sure to add [`redirect_from`](https://docs.gitlab.com/ce/development/writing_documentation.html#redirections-for-pages-with-disqus-comments)
to the new document if there are any Disqus comments on the old document thread.
- [ ] Update the link in `features.yml` (if applicable)
- [ ] If working on CE and the `ee-compat-check` jobs fails, submit an MR to EE
with the changes as well (https://docs.gitlab.com/ce/development/writing_documentation.html#cherry-picking-from-ce-to-ee).
- [ ] Ping one of the technical writers for review.
/label ~Documentation
<!--See the general Documentation guidelines https://docs.gitlab.com/ee/development/documentation/index.html --> <!--See the general documentation guidelines https://docs.gitlab.com/ee/development/documentation -->
<!-- Mention "documentation" or "docs" in the MR title -->
<!-- Use this description template for new docs or updates to existing docs. For changing documentation location use the "Change documentation location" template -->
## What does this MR do? ## What does this MR do?
...@@ -10,20 +14,19 @@ ...@@ -10,20 +14,19 @@
Closes Closes
## Moving docs to a new location? ## Author's checklist
Read the guidelines: - [ ] [Apply the correct labels and milestone](https://docs.gitlab.com/ee/development/documentation/workflow.html#2-developer-s-role-in-the-documentation-process)
https://docs.gitlab.com/ee/development/documentation/#changing-document-location - [ ] Crosslink the document from the higher-level index
- [ ] Crosslink the document from other subject-related docs
- [ ] Make sure the old link is not removed and has its contents replaced with - [ ] Correctly apply the product [badges](https://docs.gitlab.com/ee/development/documentation/styleguide.html#product-badges) and [tiers](https://docs.gitlab.com/ee/development/documentation/styleguide.html#gitlab-versions-and-tiers)
a link to the new location. - [ ] [Port the MR to EE (or backport from CE)](https://docs.gitlab.com/ee/development/documentation/index.html#cherry-picking-from-ce-to-ee): _always recommended, required when the `ee-compat-check` job fails_
- [ ] Make sure internal links pointing to the document in question are not broken.
- [ ] Search and replace any links referring to the old docs in the GitLab Rails app, ## Review checklist
specifically under the `app/views/` and `ee/app/views` (for GitLab EE) directories.
- [ ] Make sure to add [`redirect_from`](https://docs.gitlab.com/ee/development/documentation/index.html#redirections-for-pages-with-disqus-comments) - [ ] Your team's review (required)
to the new document if there are any Disqus comments on the old document thread. - [ ] PM's review (recommended, but not a blocker)
- [ ] If working on CE and the `ee-compat-check` jobs fails, [submit an MR to EE - [ ] Technical writer's review (required)
with the changes](https://docs.gitlab.com/ee/development/documentation/index.html#cherry-picking-from-ce-to-ee) as well. - [ ] Merge the EE-MR first, CE-MR afterwards
- [ ] Ping one of the technical writers for review.
/label ~Documentation /label ~Documentation
...@@ -124,6 +124,11 @@ target. However, if one does and falls into either of the above categories, it's ...@@ -124,6 +124,11 @@ target. However, if one does and falls into either of the above categories, it's
the reviewer's responsibility to manage the above communication and assignment the reviewer's responsibility to manage the above communication and assignment
on behalf of the community member. on behalf of the community member.
Every new feature or change should be shipped with its corresponding documentation
in accordance with the
[documentation process](https://docs.gitlab.com/ee/development/documentation/workflow.html)
and [structure](https://docs.gitlab.com/ee/development/documentation/structure.html).
#### What happens if these deadlines are missed? #### What happens if these deadlines are missed?
If a small or large feature is _not_ with a maintainer or reviewer by the If a small or large feature is _not_ with a maintainer or reviewer by the
...@@ -149,14 +154,9 @@ and to prevent any last minute surprises. ...@@ -149,14 +154,9 @@ and to prevent any last minute surprises.
### On the 7th ### On the 7th
Merge requests should still be complete, following the Merge requests should still be complete, following the [definition of done][done].
[definition of done][done]. The single exception is documentation, and this can
only be left until after the freeze if:
* There is a follow-up issue to add documentation. #### Feature merge requests
* It is assigned to the person writing documentation for this feature, and they
are aware of it.
* It is in the correct milestone, with the ~Deliverable label.
If a merge request is not ready, but the developers and Product Manager If a merge request is not ready, but the developers and Product Manager
responsible for the feature think it is essential that it is in the release, responsible for the feature think it is essential that it is in the release,
...@@ -172,6 +172,23 @@ information, see ...@@ -172,6 +172,23 @@ information, see
[Automatic CE->EE merge][automatic_ce_ee_merge] and [Automatic CE->EE merge][automatic_ce_ee_merge] and
[Guidelines for implementing Enterprise Edition features][ee_features]. [Guidelines for implementing Enterprise Edition features][ee_features].
#### Documentation merge requests
Documentation is part of the product and must be shipped with the feature.
The single exception for the feature freeze is documentation, and it can
be left to be **merged up to the 14th** if:
* There is a follow-up issue to add documentation.
* It is assigned to the developer writing documentation for this feature, and they
are aware of it.
* It is in the correct milestone, with the labels ~Documentation, ~Deliverable,
~missed-deliverable, and "pick into X.Y" applied.
* It must be reviewed and approved by a technical writer.
For more information read the process for
[documentation shipped late](https://docs.gitlab.com/ee/development/documentation/workflow.html#documentation-shipped-late).
### After the 7th ### After the 7th
Once the stable branch is frozen, the only MRs that can be cherry-picked into Once the stable branch is frozen, the only MRs that can be cherry-picked into
...@@ -180,7 +197,7 @@ the stable branch are: ...@@ -180,7 +197,7 @@ the stable branch are:
* Fixes for [regressions](#regressions) where the affected version `xx.x` in `regression:xx.x` is the current release. See [Managing bugs](#managing-bugs) section. * Fixes for [regressions](#regressions) where the affected version `xx.x` in `regression:xx.x` is the current release. See [Managing bugs](#managing-bugs) section.
* Fixes for security issues * Fixes for security issues
* Fixes or improvements to automated QA scenarios * Fixes or improvements to automated QA scenarios
* Documentation updates for changes in the same release * [Documentation updates](https://docs.gitlab.com/ee/development/documentation/workflow.html#documentation-shipped-late) for changes in the same release
* New or updated translations (as long as they do not touch application code) * New or updated translations (as long as they do not touch application code)
During the feature freeze all merge requests that are meant to go into the During the feature freeze all merge requests that are meant to go into the
......
import initSettingsPanels from '~/settings_panels'; import initSettingsPanels from '~/settings_panels';
import projectSelect from '~/project_select';
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
// Initialize expandable settings panels // Initialize expandable settings panels
initSettingsPanels(); initSettingsPanels();
projectSelect();
}); });
...@@ -14,6 +14,7 @@ export default function projectSelect() { ...@@ -14,6 +14,7 @@ export default function projectSelect() {
this.orderBy = $(select).data('orderBy') || 'id'; this.orderBy = $(select).data('orderBy') || 'id';
this.withIssuesEnabled = $(select).data('withIssuesEnabled'); this.withIssuesEnabled = $(select).data('withIssuesEnabled');
this.withMergeRequestsEnabled = $(select).data('withMergeRequestsEnabled'); this.withMergeRequestsEnabled = $(select).data('withMergeRequestsEnabled');
this.allowClear = $(select).data('allowClear') || false;
placeholder = "Search for project"; placeholder = "Search for project";
if (this.includeGroups) { if (this.includeGroups) {
...@@ -71,6 +72,13 @@ export default function projectSelect() { ...@@ -71,6 +72,13 @@ export default function projectSelect() {
text: function (project) { text: function (project) {
return project.name_with_namespace || project.name; return project.name_with_namespace || project.name;
}, },
initSelection: function(el, callback) {
return Api.project(el.val()).then(({ data }) => callback(data));
},
allowClear: this.allowClear,
dropdownCssClass: "ajax-project-dropdown" dropdownCssClass: "ajax-project-dropdown"
}); });
if (simpleFilter) return select; if (simpleFilter) return select;
......
# LicenseTemplateFinder
#
# Used to find license templates, which may come from a variety of external
# sources
#
# Arguments:
# popular: boolean. When set to true, only "popular" licenses are shown. When
# false, all licenses except popular ones are shown. When nil (the
# default), *all* licenses will be shown.
class LicenseTemplateFinder
prepend ::EE::LicenseTemplateFinder
attr_reader :params
def initialize(params = {})
@params = params
end
def execute
Licensee::License.all(featured: popular_only?).map do |license|
LicenseTemplate.new(
id: license.key,
name: license.name,
nickname: license.nickname,
category: (license.featured? ? :Popular : :Other),
content: license.content,
url: license.url,
meta: license.meta
)
end
end
private
def popular_only?
params.fetch(:popular, nil)
end
end
...@@ -182,12 +182,14 @@ module BlobHelper ...@@ -182,12 +182,14 @@ module BlobHelper
def licenses_for_select def licenses_for_select
return @licenses_for_select if defined?(@licenses_for_select) return @licenses_for_select if defined?(@licenses_for_select)
licenses = Licensee::License.all grouped_licenses = LicenseTemplateFinder.new.execute.group_by(&:category)
categories = grouped_licenses.keys
@licenses_for_select = { @licenses_for_select = categories.each_with_object({}) do |category, hash|
Popular: licenses.select(&:featured).map { |license| { name: license.name, id: license.key } }, hash[category] = grouped_licenses[category].map do |license|
Other: licenses.reject(&:featured).map { |license| { name: license.name, id: license.key } } { name: license.name, id: license.id }
} end
end
end end
def ref_project def ref_project
......
class LicenseTemplate
PROJECT_TEMPLATE_REGEX =
%r{[\<\{\[]
(project|description|
one\sline\s.+\swhat\sit\sdoes\.) # matching the start and end is enough here
[\>\}\]]}xi.freeze
YEAR_TEMPLATE_REGEX = /[<{\[](year|yyyy)[>}\]]/i.freeze
FULLNAME_TEMPLATE_REGEX =
%r{[\<\{\[]
(fullname|name\sof\s(author|copyright\sowner))
[\>\}\]]}xi.freeze
attr_reader :id, :name, :category, :nickname, :url, :meta
alias_method :key, :id
def initialize(id:, name:, category:, content:, nickname: nil, url: nil, meta: {})
@id = id
@name = name
@category = category
@content = content
@nickname = nickname
@url = url
@meta = meta
end
def popular?
category == :Popular
end
alias_method :featured?, :popular?
# Returns the text of the license
def content
if @content.respond_to?(:call)
@content = @content.call
else
@content
end
end
# Populate placeholders in the LicenseTemplate content
def resolve!(project_name: nil, fullname: nil, year: Time.now.year.to_s)
# Ensure the string isn't shared with any other instance of LicenseTemplate
new_content = content.dup
new_content.gsub!(YEAR_TEMPLATE_REGEX, year) if year.present?
new_content.gsub!(PROJECT_TEMPLATE_REGEX, project_name) if project_name.present?
new_content.gsub!(FULLNAME_TEMPLATE_REGEX, fullname) if fullname.present?
@content = new_content
self
end
end
...@@ -4,6 +4,8 @@ module Groups ...@@ -4,6 +4,8 @@ module Groups
class DestroyService < Groups::BaseService class DestroyService < Groups::BaseService
prepend ::EE::Groups::DestroyService prepend ::EE::Groups::DestroyService
DestroyError = Class.new(StandardError)
def async_execute def async_execute
job_id = GroupDestroyWorker.perform_async(group.id, current_user.id) job_id = GroupDestroyWorker.perform_async(group.id, current_user.id)
Rails.logger.info("User #{current_user.id} scheduled a deletion of group ID #{group.id} with job ID #{job_id}") Rails.logger.info("User #{current_user.id} scheduled a deletion of group ID #{group.id} with job ID #{job_id}")
...@@ -14,9 +16,8 @@ module Groups ...@@ -14,9 +16,8 @@ module Groups
group.projects.each do |project| group.projects.each do |project|
# Execute the destruction of the models immediately to ensure atomic cleanup. # Execute the destruction of the models immediately to ensure atomic cleanup.
# Skip repository removal because we remove directory with namespace success = ::Projects::DestroyService.new(project, current_user).execute
# that contain all these repositories raise DestroyError, "Project #{project.id} can't be deleted" unless success
::Projects::DestroyService.new(project, current_user, skip_repo: project.legacy_storage?).execute
end end
group.children.each do |group| group.children.each do |group|
......
...@@ -385,6 +385,8 @@ ...@@ -385,6 +385,8 @@
.settings-content .settings-content
= render partial: 'slack' = render partial: 'slack'
= render_if_exists 'admin/application_settings/templates', expanded: expanded
%section.settings.as-third-party-offers.no-animate#js-third-party-offers-settings{ class: ('expanded' if expanded) } %section.settings.as-third-party-offers.no-animate#js-third-party-offers-settings{ class: ('expanded' if expanded) }
.settings-header .settings-header
%h4 %h4
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
User cohorts are shown for the last #{@cohorts[:months_included]} User cohorts are shown for the last #{@cohorts[:months_included]}
months. Only users with activity are counted in the cohort total; inactive months. Only users with activity are counted in the cohort total; inactive
users are counted separately. users are counted separately.
= link_to icon('question-circle'), help_page_path('user/admin_area/user_cohorts', anchor: 'cohorts'), title: 'About this feature', target: '_blank' = link_to icon('question-circle'), help_page_path('user/instance_statistics/user_cohorts', anchor: 'cohorts'), title: 'About this feature', target: '_blank'
.table-holder .table-holder
%table.table %table.table
......
...@@ -4,4 +4,4 @@ ...@@ -4,4 +4,4 @@
%h4 Data is still calculating... %h4 Data is still calculating...
%p %p
In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index. In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index.
= link_to 'Learn more', help_page_path('user/admin_area/monitoring/convdev'), target: '_blank' = link_to 'Learn more', help_page_path('user/instance_statistics/convdev'), target: '_blank'
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
index index
%br %br
score score
= link_to icon('question-circle', 'aria-hidden' => 'true'), help_page_path('user/admin_area/monitoring/convdev') = link_to icon('question-circle', 'aria-hidden' => 'true'), help_page_path('user/instance_statistics/convdev')
.convdev-cards.board-card-container .convdev-cards.board-card-container
- @metric.cards.each do |card| - @metric.cards.each do |card|
......
---
title: 'Fix: Project deletion may not log audit events during group deletion'
merge_request: 21162
author:
type: fixed
...@@ -170,6 +170,7 @@ module Gitlab ...@@ -170,6 +170,7 @@ module Gitlab
%w[images javascripts stylesheets].each do |path| %w[images javascripts stylesheets].each do |path|
config.assets.paths << "#{config.root}/ee/app/assets/#{path}" config.assets.paths << "#{config.root}/ee/app/assets/#{path}"
end end
config.assets.precompile << "shared/snowplow/sp.js"
# Compile non-JS/CSS assets in the ee/app/assets folder by default # Compile non-JS/CSS assets in the ee/app/assets folder by default
# Mimic sprockets-rails default: https://github.com/rails/sprockets-rails/blob/v3.2.1/lib/sprockets/railtie.rb#L84-L87 # Mimic sprockets-rails default: https://github.com/rails/sprockets-rails/blob/v3.2.1/lib/sprockets/railtie.rb#L84-L87
......
...@@ -206,6 +206,7 @@ ActiveRecord::Schema.define(version: 20180808162000) do ...@@ -206,6 +206,7 @@ ActiveRecord::Schema.define(version: 20180808162000) do
t.string "encrypted_external_auth_client_key_pass_iv" t.string "encrypted_external_auth_client_key_pass_iv"
t.string "email_additional_text" t.string "email_additional_text"
t.boolean "enforce_terms", default: false t.boolean "enforce_terms", default: false
t.integer "file_template_project_id"
t.boolean "pseudonymizer_enabled", default: false, null: false t.boolean "pseudonymizer_enabled", default: false, null: false
t.boolean "hide_third_party_offers", default: false, null: false t.boolean "hide_third_party_offers", default: false, null: false
t.boolean "snowplow_enabled", default: false, null: false t.boolean "snowplow_enabled", default: false, null: false
...@@ -2963,6 +2964,7 @@ ActiveRecord::Schema.define(version: 20180808162000) do ...@@ -2963,6 +2964,7 @@ ActiveRecord::Schema.define(version: 20180808162000) do
add_index "web_hooks", ["type"], name: "index_web_hooks_on_type", using: :btree add_index "web_hooks", ["type"], name: "index_web_hooks_on_type", using: :btree
add_foreign_key "application_settings", "namespaces", column: "custom_project_templates_group_id", on_delete: :nullify add_foreign_key "application_settings", "namespaces", column: "custom_project_templates_group_id", on_delete: :nullify
add_foreign_key "application_settings", "projects", column: "file_template_project_id", name: "fk_ec757bd087", on_delete: :nullify
add_foreign_key "approvals", "merge_requests", name: "fk_310d714958", on_delete: :cascade add_foreign_key "approvals", "merge_requests", name: "fk_310d714958", on_delete: :cascade
add_foreign_key "approver_groups", "namespaces", column: "group_id", on_delete: :cascade add_foreign_key "approver_groups", "namespaces", column: "group_id", on_delete: :cascade
add_foreign_key "badges", "namespaces", column: "group_id", on_delete: :cascade add_foreign_key "badges", "namespaces", column: "group_id", on_delete: :cascade
......
...@@ -110,7 +110,6 @@ created in snippets, wikis, and repos. ...@@ -110,7 +110,6 @@ created in snippets, wikis, and repos.
basic Postfix mail server with IMAP authentication on Ubuntu for incoming basic Postfix mail server with IMAP authentication on Ubuntu for incoming
emails. emails.
- **(Premium)** [Additional custom email text](../user/admin_area/settings/email.md): Set a custom message that appears at the bottom of the every email. - **(Premium)** [Additional custom email text](../user/admin_area/settings/email.md): Set a custom message that appears at the bottom of the every email.
- [User Cohorts](../user/admin_area/user_cohorts.md): Display the monthly cohorts of new users and their activities over time.
[reply by email]: reply_by_email.md [reply by email]: reply_by_email.md
[issues by email]: ../user/project/issues/create_new_issue.md#new-issue-via-email [issues by email]: ../user/project/issues/create_new_issue.md#new-issue-via-email
...@@ -156,7 +155,6 @@ created in snippets, wikis, and repos. ...@@ -156,7 +155,6 @@ created in snippets, wikis, and repos.
- [Monitoring uptime](../user/admin_area/monitoring/health_check.md): Check the server status using the health check endpoint. - [Monitoring uptime](../user/admin_area/monitoring/health_check.md): Check the server status using the health check endpoint.
- [IP whitelist](monitoring/ip_whitelist.md): Monitor endpoints that provide health check information when probed. - [IP whitelist](monitoring/ip_whitelist.md): Monitor endpoints that provide health check information when probed.
- [Monitoring GitHub imports](monitoring/github_imports.md): GitLab's GitHub Importer displays Prometheus metrics to monitor the health and progress of the importer. - [Monitoring GitHub imports](monitoring/github_imports.md): GitLab's GitHub Importer displays Prometheus metrics to monitor the health and progress of the importer.
- [Conversational Development (ConvDev) Index](../user/admin_area/monitoring/convdev.md): Provides an overview of your entire instance's feature usage.
### Performance Monitoring ### Performance Monitoring
......
...@@ -58,6 +58,7 @@ Example response: ...@@ -58,6 +58,7 @@ Example response:
"performance_bar_allowed_group_id": 42, "performance_bar_allowed_group_id": 42,
"instance_statistics_visibility_private": false, "instance_statistics_visibility_private": false,
"user_show_add_ssh_key_message": true "user_show_add_ssh_key_message": true
"file_template_project_id": 1
} }
``` ```
...@@ -108,6 +109,7 @@ PUT /application/settings ...@@ -108,6 +109,7 @@ PUT /application/settings
| `email_author_in_body` | boolean | no | Some email servers do not support overriding the email sender name. Enable this option to include the name of the author of the issue, merge request or comment in the email body instead. | | `email_author_in_body` | boolean | no | Some email servers do not support overriding the email sender name. Enable this option to include the name of the author of the issue, merge request or comment in the email body instead. |
| `email_additional_text` | string | no | **(Premium)** Additional text added to the bottom of every email for legal/auditing/compliance reasons reasons | | `email_additional_text` | string | no | **(Premium)** Additional text added to the bottom of every email for legal/auditing/compliance reasons reasons |
| `enabled_git_access_protocol` | string | no | Enabled protocols for Git access. Allowed values are: `ssh`, `http`, and `nil` to allow both protocols. | | `enabled_git_access_protocol` | string | no | Enabled protocols for Git access. Allowed values are: `ssh`, `http`, and `nil` to allow both protocols. |
| `file_template_project_id | integer | no | **(Premium)** The ID of a project to load custom file templates from |
| `geo_status_timeout` | integer | no | The amount of seconds after which a request to get a secondary node status will time out. | | `geo_status_timeout` | integer | no | The amount of seconds after which a request to get a secondary node status will time out. |
| `gravatar_enabled` | boolean | no | Enable Gravatar | | `gravatar_enabled` | boolean | no | Enable Gravatar |
| `help_page_hide_commercial_content` | boolean | no | Hide marketing-related entries from help | | `help_page_hide_commercial_content` | boolean | no | Hide marketing-related entries from help |
...@@ -241,5 +243,6 @@ Example response: ...@@ -241,5 +243,6 @@ Example response:
"performance_bar_allowed_group_id": 42, "performance_bar_allowed_group_id": 42,
"instance_statistics_visibility_private": false, "instance_statistics_visibility_private": false,
"user_show_add_ssh_key_message": true "user_show_add_ssh_key_message": true
"file_template_project_id": 1
} }
``` ```
...@@ -25,52 +25,23 @@ them to review it for you. ...@@ -25,52 +25,23 @@ them to review it for you.
We use the [monthly release blog post](https://about.gitlab.com/handbook/marketing/blog/release-posts/#monthly-releases) as a changelog checklist to ensure everything We use the [monthly release blog post](https://about.gitlab.com/handbook/marketing/blog/release-posts/#monthly-releases) as a changelog checklist to ensure everything
is documented. is documented.
Whenever you submit a merge request for the documentation, use the documentation MR description template. Whenever you submit a merge request for the documentation, use the
"Documentation" MR description template. If you're changing documentation
location, use the MR description template called "Change documentation
location" instead.
Please check the [documentation workflow](https://about.gitlab.com/handbook/product/technical-writing/workflow/) before getting started. ## Documentation workflow
## Documentation structure Please read through the [documentation workflow](workflow.md) before getting started.
- Overview and use cases: what it is, why it is necessary, why one would use it
- Requirements: what do we need to get started
- Tutorial: how to set it up, how to use it
Always link a new document from its topic-related index, otherwise, it will
not be included it in the documentation site search.
_Note: to be extended._
### Feature overview and use cases
Every major feature (regardless if present in GitLab Community or Enterprise editions)
should present, at the beginning of the document, two main sections: **overview** and
**use cases**. Every GitLab EE-only feature should also contain these sections.
**Overview**: as the name suggests, the goal here is to provide an overview of the feature. ## Documentation structure
Describe what is it, what it does, why it is important/cool/nice-to-have,
what problem it solves, and what you can do with this feature that you couldn't
do before.
**Use cases**: provide at least two, ideally three, use cases for every major feature.
You should answer this question: what can you do with this feature/change? Use cases
are examples of how this feature or change can be used in real life.
Examples:
- CE and EE: [Issues](../user/project/issues/index.md#use-cases)
- CE and EE: [Merge Requests](../user/project/merge_requests/index.md#overview)
- EE-only: [Geo](https://docs.gitlab.com/ee/gitlab-geo/README.html#overview)
- EE-only: [Jenkins integration](https://docs.gitlab.com/ee/integration/jenkins.md#overview)
Note that if you don't have anything to add between the doc title (`<h1>`) and
the header `## Overview`, you can omit the header, but keep the content of the
overview there.
> **Overview** and **use cases** are required to **every** Enterprise Edition feature, Follow through the [documentation structure guide](structure.md) for learning
and for every **major** feature present in Community Edition. how to structure GitLab docs.
## Markdown and styles ## Markdown and styles
Currently GitLab docs use Redcarpet as [markdown](../user/markdown.md) engine, but there's an [open discussion](https://gitlab.com/gitlab-com/gitlab-docs/issues/50) for implementing Kramdown in the near future. Currently GitLab docs use Redcarpet as [markdown](../../user/markdown.md) engine, but there's an [open discussion](https://gitlab.com/gitlab-com/gitlab-docs/issues/50) for implementing Kramdown in the near future.
All the docs follow the [documentation style guidelines](styleguide.md). All the docs follow the [documentation style guidelines](styleguide.md).
...@@ -84,9 +55,18 @@ In order to have a [solid site structure](https://searchengineland.com/seo-benef ...@@ -84,9 +55,18 @@ In order to have a [solid site structure](https://searchengineland.com/seo-benef
all docs should be linked. Every new document should be cross-linked to its related documentation, and linked from its topic-related index, when existent. all docs should be linked. Every new document should be cross-linked to its related documentation, and linked from its topic-related index, when existent.
The directories `/workflow/`, `/gitlab-basics/`, `/university/`, and `/articles/` have The directories `/workflow/`, `/gitlab-basics/`, `/university/`, and `/articles/` have
been deprecated and the majority their docs have been moved to their correct location been **deprecated** and the majority their docs have been moved to their correct location
in small iterations. Please don't create new docs in these folders. in small iterations. Please don't create new docs in these folders.
### Documentation files
- When you create a new directory, always start with an `index.md` file.
Do not use another file name and **do not** create `README.md` files
- **Do not** use special chars and spaces, or capital letters in file names,
directory names, branch names, and anything that generates a path.
- Max screenshot size: 100KB
- We do not support videos (yet)
### Location and naming documents ### Location and naming documents
The documentation hierarchy can be vastly improved by providing a better layout The documentation hierarchy can be vastly improved by providing a better layout
...@@ -116,7 +96,7 @@ The table below shows what kind of documentation goes where. ...@@ -116,7 +96,7 @@ The table below shows what kind of documentation goes where.
--- ---
**General rules:** **General rules & best practices:**
1. The correct naming and location of a new document, is a combination 1. The correct naming and location of a new document, is a combination
of the relative URL of the document in question and the GitLab Map design of the relative URL of the document in question and the GitLab Map design
...@@ -203,7 +183,7 @@ Things to note: ...@@ -203,7 +183,7 @@ Things to note:
documentation, sometimes it might be useful to search a path deeper. documentation, sometimes it might be useful to search a path deeper.
- The `*.md` extension is not used when a document is linked to GitLab's - The `*.md` extension is not used when a document is linked to GitLab's
built-in help page, that's why we omit it in `git grep`. built-in help page, that's why we omit it in `git grep`.
- Use the checklist on the documentation MR description template. - Use the checklist on the "Change documentation location" MR description template.
#### Alternative redirection method #### Alternative redirection method
...@@ -514,7 +494,7 @@ Suppose there's a process to go from point A to point B in 5 steps: `(A) 1 > 2 > ...@@ -514,7 +494,7 @@ Suppose there's a process to go from point A to point B in 5 steps: `(A) 1 > 2 >
A **guide** can be understood as a description of certain processes to achieve a particular objective. A guide brings you from A to B describing the characteristics of that process, but not necessarily going over each step. It can mention, for example, steps 2 and 3, but does not necessarily explain how to accomplish them. A **guide** can be understood as a description of certain processes to achieve a particular objective. A guide brings you from A to B describing the characteristics of that process, but not necessarily going over each step. It can mention, for example, steps 2 and 3, but does not necessarily explain how to accomplish them.
- Live example: "[Static sites and GitLab Pages domains (Part 1)](../user/project/pages/getting_started_part_one.md) to [Creating and Tweaking GitLab CI/CD for GitLab Pages (Part 4)](../../user/project/pages/getting_started_part_four.md)" - Live example: "[Static sites and GitLab Pages domains (Part 1)](../../user/project/pages/getting_started_part_one.md) to [Creating and Tweaking GitLab CI/CD for GitLab Pages (Part 4)](../../user/project/pages/getting_started_part_four.md)"
A **tutorial** requires a clear **step-by-step** guidance to achieve a singular objective. It brings you from A to B, describing precisely all the necessary steps involved in that process, showing each of the 5 steps to go from A to B. A **tutorial** requires a clear **step-by-step** guidance to achieve a singular objective. It brings you from A to B, describing precisely all the necessary steps involved in that process, showing each of the 5 steps to go from A to B.
It does not only describes steps 2 and 3, but also shows you how to accomplish them. It does not only describes steps 2 and 3, but also shows you how to accomplish them.
......
---
description: Learn the how to correctly structure GitLab documentation.
---
# Documentation structure
For consistency throughout the documentation, it's important to maintain the same
structure among the docs.
Before getting started, read through the following docs:
- [Contributing to GitLab documentation](index.md#contributing-to-docs)
- [Merge requests for GitLab documentation](index.md#merge-requests-for-gitlab-documentation)
- [Branch naming for docs-only changes](index.md#branch-naming)
- [Documentation directory structure](index.md#documentation-directory-structure)
- [Documentation style guidelines](styleguide.md)
- [Documentation workflow](workflow.md)
## Documentation blurb
Every document should include the following content in the following sequence:
- **Feature name**: defines an intuitive name for the feature that clearly
states what it is and is consistent with any relevant UI text.
- **Feature overview** and description: describe what it is, what it does, and in what context it should be used.
- **Use cases**: describes real use case scenarios for that feature.
- **Requirements**: describes what software and/or configuration is required to be able to
use the feature and, if applicable, prerequisite knowledge for being able to follow/implement the tutorial.
For example, familiarity with GitLab CI/CD, an account on a third-party service, dependencies installed, etc.
Link each one to its most relevant resource; i.e., where the reader can go to begin to fullfil that requirement.
(Another doc page, a third party application's site, etc.)
- **Instructions**: clearly describes the steps to use the feature, leaving no gaps.
- **Troubleshooting** guide (recommended but not required): if you know beforehand what issues
one might have when setting it up, or when something is changed, or on upgrading, it's
important to describe those too. Think of things that may go wrong and include them in the
docs. This is important to minimize requests for support, and to avoid doc comments with
questions that you know someone might ask. Answering them beforehand only makes your
document better and more approachable.
For additional details, see the subsections below, as well as the [Documentation template for new docs](#Documentation-template-for-new-docs).
### Feature overview and use cases
Every major feature (regardless if present in GitLab Community or Enterprise editions)
should present, at the beginning of the document, two main sections: **overview** and
**use cases**. Every GitLab EE-only feature should also contain these sections.
**Overview**: as the name suggests, the goal here is to provide an overview of the feature.
Describe what is it, what it does, why it is important/cool/nice-to-have,
what problem it solves, and what you can do with this feature that you couldn't
do before.
**Use cases**: provide at least two, ideally three, use cases for every major feature.
You should answer this question: what can you do with this feature/change? Use cases
are examples of how this feature or change can be used in real life.
Examples:
- CE and EE: [Issues](../user/project/issues/index.md#use-cases)
- CE and EE: [Merge Requests](../user/project/merge_requests/index.md#overview)
- EE-only: [Geo](https://docs.gitlab.com/ee/gitlab-geo/README.html#overview)
- EE-only: [Jenkins integration](https://docs.gitlab.com/ee/integration/jenkins.md#overview)
Note that if you don't have anything to add between the doc title (`<h1>`) and
the header `## Overview`, you can omit the header, but keep the content of the
overview there.
> **Overview** and **use cases** are required to **every** Enterprise Edition feature,
and for every **major** feature present in Community Edition.
### Discoverability
Your new document will be discoverable by the user only if:
- Crosslinked from the higher-level index (e.g., Issue Boards docs
should be linked from Issues; Prometheus docs should be linked from
Monitoring; CI/CD tutorials should be linked from CI/CD examples).
- When referencing other GitLab products and features, link to their
respective docs; when referencing third-party products or technologies,
link out to their external sites, documentation, and resources.
- The headings are clear. E.g., "App testing" is a bad heading, "Testing
an application with GitLab CI/CD" is much better. Think of something
someone will search for and use these keywords in the headings.
## Documentation template for new docs
To start a new document, respect the file tree and file name guidelines,
as well as the style guidelines. Use the following template:
```md
---
description: "short document description." # Up to ~200 chars long. They will be displayed in Google Search Snippets.
---
# Feature Name **[TIER]** (1)
> [Introduced](link_to_issue_or_mr) in GitLab Tier X.Y (2).
A short description for the feature (can be the same used in the frontmatter's
`description`).
## Overview
To write the feature overview, you should consider answering the following questions:
- What is it?
- Who is it for?
- What is the context in which it is used and are there any prerequisites/requirements?
- What can the user do with it? (Be sure to consider multiple audiences, like GitLab admin and developer-user.)
- What are the benefits to using it over any alternatives?
## Use cases
Describe one to three use cases for that feature. Give real-life examples.
## Requirements
State any requirements, if any, for using the feature and/or following along with the tutorial.
The only assumption that is redundant and doesn't need to be mentioned is having an account
on GitLab.
## Instructions
("Instructions" is not necessarily the name of the heading)
- Write a step-by-step guide, with no gaps between the steps.
- Start with an h2 (`##`), break complex steps into small steps using
subheadings h3 > h4 > h5 > h6. _Never skip the hierarchy level, such
as h2 > h4_, as it will break the TOC and may affect the breadcrumbs.
- Use short and descriptive headings (up to ~50 chars). You can use one
single heading `## How it works` for the instructions when the feature
is simple and the document is short.
- Be clear, concise, and stick to the goal of the doc: explain how to
use that feature.
- Use inclusive language and avoid jargons, as well as uncommon and
fancy words. The docs should be clear and very easy to understand.
- Write in the 3rd person (use "we", "you", "us", "one", instead of "I" or "me").
- Always provide internal and external reference links.
- Always link the doc from its higher-level index.
<!-- ## Troubleshooting
Add a troubleshooting guide when possible/applicable. -->
```
Notes:
- (1): Apply the [tier badges](styleguide.md#product-badges) accordingly
- (2): Apply the correct format for the [GitLab version introducing the feature](styleguide.md#gitlab-versions-and-tiers)
...@@ -10,6 +10,22 @@ GitLab documentation. Check the ...@@ -10,6 +10,22 @@ GitLab documentation. Check the
Check the GitLab handbook for the [writing styles guidelines](https://about.gitlab.com/handbook/communication/#writing-style-guidelines). Check the GitLab handbook for the [writing styles guidelines](https://about.gitlab.com/handbook/communication/#writing-style-guidelines).
## Files
- [Directory structure](index.md#location-and-naming-documents): place the docs
in the correct location
- [Documentation files](index.md#documentation-files): name the files accordingly
- [Markdown](../../user/markdown.md): use the GitLab Flavored Markdown in the
documentation
NOTE: **Note:**
**Do not** use capital letters, spaces, or special chars in file names,
branch names, directory names, headings, or in anything that generates a path.
NOTE: **Note:**
**Do not** create new `README.md` files, name them `index.md` instead. There's
a test that will fail if it spots a new `README.md` file.
## Text ## Text
- Split up long lines (wrap text), this makes it much easier to review and edit. Only - Split up long lines (wrap text), this makes it much easier to review and edit. Only
...@@ -61,7 +77,8 @@ For punctuation rules, please refer to the [GitLab UX guide](https://design.gitl ...@@ -61,7 +77,8 @@ For punctuation rules, please refer to the [GitLab UX guide](https://design.gitl
- Add **only one H1** in each document, by adding `#` at the beginning of - Add **only one H1** in each document, by adding `#` at the beginning of
it (when using markdown). The `h1` will be the document `<title>`. it (when using markdown). The `h1` will be the document `<title>`.
- For subheadings, use `##`, `###` and so on - Start with an h2 (`##`), and respect the order h2 > h3 > h4 > h5 > h6.
Never skip the hierarchy level, such as h2 > h4
- Avoid putting numbers in headings. Numbers shift, hence documentation anchor - Avoid putting numbers in headings. Numbers shift, hence documentation anchor
links shift too, which eventually leads to dead links. If you think it is links shift too, which eventually leads to dead links. If you think it is
compelling to add numbers in headings, make sure to at least discuss it with compelling to add numbers in headings, make sure to at least discuss it with
...@@ -115,10 +132,7 @@ needs to expand the tab to find the settings you're referring to ...@@ -115,10 +132,7 @@ needs to expand the tab to find the settings you're referring to
the `.md` document that you're working on is located. Always prepend their the `.md` document that you're working on is located. Always prepend their
names with the name of the document that they will be included in. For names with the name of the document that they will be included in. For
example, if there is a document called `twitter.md`, then a valid image name example, if there is a document called `twitter.md`, then a valid image name
could be `twitter_login_screen.png`. [**Exception**: images for could be `twitter_login_screen.png`.
[articles](index.md#technical-articles) should be
put in a directory called `img` underneath `/articles/article_title/img/`, therefore,
there's no need to prepend the document name to their filenames.]
- Images should have a specific, non-generic name that will differentiate them. - Images should have a specific, non-generic name that will differentiate them.
- Keep all file names in lower case. - Keep all file names in lower case.
- Consider using PNG images instead of JPEG. - Consider using PNG images instead of JPEG.
...@@ -126,6 +140,8 @@ needs to expand the tab to find the settings you're referring to ...@@ -126,6 +140,8 @@ needs to expand the tab to find the settings you're referring to
- Compress gifs with <https://ezgif.com/optimize> or similar tool. - Compress gifs with <https://ezgif.com/optimize> or similar tool.
- Images should be used (only when necessary) to _illustrate_ the description - Images should be used (only when necessary) to _illustrate_ the description
of a process, not to _replace_ it. of a process, not to _replace_ it.
- Max image size: 100KB (gifs included).
- The GitLab docs do not support videos yet.
Inside the document: Inside the document:
......
---
description: Learn the process of shipping documentation for GitLab.
---
# Documentation process at GitLab
At GitLab, developers contribute new or updated documentation along with their code, but product managers and technical writers also have essential roles in the process.
- Product Managers (PMs): in the issue for all new and updated features,
PMs include specific documentation requirements that the developer who is
writing or updating the docs must meet, along with feature descriptions
and use cases. They call out any specific areas where collaborating with
a technical writer is recommended, and usually act as the first reviewer
of the docs.
- Developers: author documentation and merge it on time (up to a week after
the feature freeze).
- Technical Writers: review each issue to ensure PM's requirements are complete,
help developers with any questions throughout the process, and act as the final
reviewer of all new and updated docs content before it's merged.
## Requirements
Documentation must be delivered whenever:
- A new feature is shipped
- There are changes to the UI
- A process, workflow, or previously documented feature is changed
Documentation is not required when a feature is changed on the backend
only and does not directly affect the way that any regular user or
administrator would interact with GitLab.
NOTE: **Note:**
When refactoring documentation in needed, it should be submitted it in its own MR.
**Do not** join new features' MRs with refactoring existing docs, as they might have
different priorities.
NOTE: **Note:**
[Smaller MRs are better](https://gitlab.com/gitlab-com/blog-posts/issues/185#note_4401010)! Do not mix subjects, and ship the smallest MR possible.
### Documentation review process
The docs shipped by the developer should be reviewed by the PM (for accuracy) and a Technical Writer (for clarity and structure).
#### Documentation updates that require Technical Writer review
Every documentation change that meets the criteria below must be reviewed by a Technical Writer
to ensure clarity and discoverability, and avoid redundancy, bad file locations, typos, broken links, etc.
Within the GitLab issue or MR, ping the relevant technical writer for the subject area. If you're not sure who that is,
ping any of them or all of them (`@gl\-docsteam`).
A Technical Writer must review documentation updates that involve:
- Docs introducing new features
- Changing documentation location
- Refactoring existing documentation
- Creating new documentation files
If you need any help to choose the correct place for a doc, discuss a documentation
idea or outline, or request any other help, ping a Technical Writer on your issue, MR,
or on Slack in `#docs`.
#### Skip the PM's review
When there's a non-significant change to the docs, you can skip the review
of the PM. Add the same labels as you would for a regular doc change and
assign the correct milestone. In these cases, assign a Technical Writer
for approval/merge, or mention `@gl\-docsteam` in case you don't know
which Tech Writer to assign for.
#### Skip the entire review
When the MR only contains corrections to the content (typos, grammar,
broken links, etc), it can be merged without the PM's and Tech Writer's review.
## Documentation structure
Read through the [documentation structure](structure.md) docs for an overview.
## Documentation workflow
To follow a consistent workflow every month, documentation changes
involve the Product Managers, the developer who shipped the feature,
and the Technical Writing team. Each role is described below.
### 1. Product Manager's role in the documentation process
The Product Manager (PM) should add to the feature issue:
- Feature name, overview/description, and use cases, for the [documentation blurb](structure.md#documentation-blurb)
- The documentation requirements for the developer working on the docs
- What new page, new subsection of an existing page, or other update to an existing page/subsection is needed.
- Just one page/section/update or multiple (perhaps there's an end user and admin change needing docs, or we need to update a previously recommended workflow, or we want to link the new feature from various places; consider and mention all ways documentation should be affected
- Suggested title of any page or subsection, if applicable
- Label the issue with `Documentation`, `Deliverable`, `docs:P1`, and assign
the correct milestone
### 2. Developer's role in the documentation process
As a developer, or as a community contributor, you should ship the documentation
with the feature, as in GitLab the documentation is part of the product.
The docs can either be shipped along with the MR introducing the code, or,
alternatively, created from a follow-up issue and MR.
The docs should be shipped **by the feature freeze date**. Justified
exceptions are accepted, as long as the [following process](#documentation-shipped-late)
and the missed-deliverable due date (the 14th of each month) are both respected.
#### Documentation shipped in the feature MR
The developer should add to the feature MR the documentation containing:
- The [documentation blurb](structure.md#documentation-blurb): copy the
feature name, overview/description, and use cases from the feature issue
- Instructions: write how to use the feature, step by step, with no gaps.
- [Crosslink for discoverability](structure.md#discoverability): link with
internal docs and external resources (if applicable)
- Index: link the new doc or the new heading from the higher-level index
for [discoverability](#discoverability)
- [Screenshots](styleguide.md#images): when necessary, add screenshots for:
- Illustrating a step of the process
- Indicating the location of a navigation menu
- Label the MR with `Documentation`, `Deliverable`, `docs-P1`, and assign
the correct milestone
- Assign the PM for review
- When done, mention the `@gl\-docsteam` in the MR asking for review
- **Due date**: feature freeze date and time
#### Documentation shipped in a follow-up MR
If the docs aren't being shipped within the feature MR:
- Create a new issue mentioning "docs" or "documentation" in the title (use the Documentation issue description template)
- Label the issue with: `Documentation`, `Deliverable`, `docs-P1`, `<product-label>`
(product label == CI/CD, Pages, Prometheus, etc)
- Add the correct milestone
- Create a new MR for shipping the docs changes and follow the same
process [described above](#documentation-shipped-in-the-feature-mr)
- Use the MR description template called "Documentation"
- Add the same labels and milestone as you did for the issue
- Assign the PM for review
- When done, mention the `@gl\-docsteam` in the MR asking for review
- **Due date**: feature freeze date and time
#### Documentation shipped late
Shipping late means that you are affecting the whole feature workflow
as well as other teams' priorities (PMs, tech writers, release managers,
release post reviewers), so every effort should be made to avoid this.
If you did not ship the docs within the feature freeze, proceed as
[described above](#documentation-shipped-in-a-follow-up-mr) and,
besides the regular labels, include the labels `Pick into X.Y` and
`missed-deliverable` in the issue and the MR, and assign them the correct
milestone.
The **due date** for **merging** `missed-deliverable` MRs is on the
**14th** of each month.
### 3. Technical Writer's role in the documentation process
- **Planning**
- Once an issue contains a Documentation label and the current milestone, a
technical writer reviews the Product Manager's documentation requirements
- Once the documentation requirements are approved, the technical writer can
work with the developer to discuss any documentation questions and plans/outlines, as needed.
- **Review** - A technical writer must review the documentation for:
- Clarity
- Relevance (make sure the content is appropriate given the impact of the feature)
- Location (make sure the doc is in the correct dir and has the correct name)
- Syntax, typos, and broken links
- Improvements to the content
- Accordance to the [docs style guide](styleguide.md)
<!-- TBA: issue and MR description templates as part of the process -->
<!--
## New features vs feature updates
- TBA:
- Describe the difference between new features and feature updates
- Creating a new doc vs updating an existing doc
-->
...@@ -36,10 +36,10 @@ ...@@ -36,10 +36,10 @@
1. Click **Create project**. 1. Click **Create project**.
## Custom project templates ## Custom project templates **[PREMIUM ONLY]**
> **Notes:** > [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/6860) in
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/6860) in [GitLab Edition Premium][ee] 11.2 [GitLab Premium](https://about.gitlab.com/pricing) 11.2.
When you create a new project, creating it based on custom project templates is a convenient option to bootstrap an existing project boilerplate. When you create a new project, creating it based on custom project templates is a convenient option to bootstrap an existing project boilerplate.
If a custom group is defined on the instance, projects within this group are available as project templates within the "Create from template" section. These templates are shown in the "Custom" tab. In addition, you can click on "Preview" to explore what this project templates includes. If a custom group is defined on the instance, projects within this group are available as project templates within the "Create from template" section. These templates are shown in the "Custom" tab. In addition, you can click on "Preview" to explore what this project templates includes.
......
# Conversational Development Index ---
redirect_to: '../../instance_statistics/convdev.md'
---
> [Introduced][ce-30469] in GitLab 9.3. This document was moved to [another location](../../instance_statistics/convdev.md).
Conversational Development Index (ConvDev) gives you an overview of your entire
instance's feature usage, from idea to production. It looks at your usage in the
past 30 days, averaged over the number of active users in that time period. It also
provides a lead score per feature, which is calculated based on GitLab's analysis
of top performing instances, based on [usage ping data][ping] that GitLab has
collected. Your score is compared to the lead score, expressed as a percentage.
The overall index score is an average over all your feature scores.
![ConvDev index](img/convdev_index.png)
The page also provides helpful links to articles and GitLab docs, to help you
improve your scores.
Your GitLab instance's usage ping must be activated in order to use this feature.
Usage ping data is aggregated on GitLab's servers for analysis. Your usage
information is **not sent** to any other GitLab instances.
If you have just started using GitLab, it may take a few weeks for data to be
collected before this feature is available.
This feature is accessible only to a system admin, at
**Admin area > Overview > ConvDev Index**.
[ce-30469]: https://gitlab.com/gitlab-org/gitlab-ce/issues/30469
[ping]: ../settings/usage_statistics.md#usage-ping
# Instance-level Template Repository
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5986) in
> [GitLab Premium](https://about.gitlab.com/pricing) 11.3.
## Overview
In hosted systems, enterprises often have a need to share their own templates
across teams. This feature allows an administrator to pick a project to be the
instance-wide collection of templates. These templates are then exposed to all
users while the project remains secure. Currently supported templates: Licenses.
## Configuration
An administrator can choose any project to be the template repository. This is
done through the `Settings` page in the `Admin Area` or through the API. On the
`Settings` page, there is a `Templates` section with a selection box for
choosing a project:
![](img/file_template_admin_area.png)
Once a project has been selected you can add custom templates to the repository,
and they will appear in the appropriate places in the frontend and API.
Templates must be added to a specific subdirectory in the repository,
corresponding to the kind of template. They must also have the correct extension
for the template type.
Currently, only custom license templates are supported. This must go in the
`LICENSE/` subdirectory, and must have `.txt` file extensions. So, the hierarchy
should look like this:
```text
|-- README.md
|-- LICENSE
|-- custom_license.txt
|-- another_license.txt
```
Once this is established, the list of `Custom` licenses will be included when
creating a new file and the file type is `License`. These will appear at the
bottom of the list:
![](img/file_template_user_dropdown.png)
If this feature has been disabled or no licenses are present, then there will be
no `Custom` section in the selection dropdown.
...@@ -6,7 +6,7 @@ to perform various actions. ...@@ -6,7 +6,7 @@ to perform various actions.
All statistics are opt-out, you can enable/disable them from the admin panel All statistics are opt-out, you can enable/disable them from the admin panel
under **Admin area > Settings > Usage statistics**. under **Admin area > Settings > Usage statistics**.
## Version check ## Version check **[CORE ONLY]**
If enabled, version check will inform you if a new version is available and the If enabled, version check will inform you if a new version is available and the
importance of it through a status. This is shown on the help page (i.e. `/help`) importance of it through a status. This is shown on the help page (i.e. `/help`)
...@@ -29,7 +29,7 @@ secure. ...@@ -29,7 +29,7 @@ secure.
If you disable version check, this information will not be collected. Enable or If you disable version check, this information will not be collected. Enable or
disable the version check at **Admin area > Settings > Usage statistics**. disable the version check at **Admin area > Settings > Usage statistics**.
## Usage ping ## Usage ping **[CORE ONLY]**
> [Introduced][ee-557] in GitLab Enterprise Edition 8.10. More statistics > [Introduced][ee-557] in GitLab Enterprise Edition 8.10. More statistics
[were added][ee-735] in GitLab Enterprise Edition [were added][ee-735] in GitLab Enterprise Edition
...@@ -68,6 +68,15 @@ production: &base ...@@ -68,6 +68,15 @@ production: &base
usage_ping_enabled: false usage_ping_enabled: false
``` ```
## Instance statistics visibility **[CORE ONLY]**
Once usage ping is enabled, GitLab will gather data from other instances and
will be able to show [usage statistics](../../instance_statistics/index.md)
of your instance to your users.
This can be restricted to admins by selecting "Only admins" in the Instance
Statistics visibility section under **Admin area > Settings > Usage statistics**.
[ee-557]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/557 [ee-557]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/557
[ee-735]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/735 [ee-735]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/735
[ce-23361]: https://gitlab.com/gitlab-org/gitlab-ce/issues/23361 [ce-23361]: https://gitlab.com/gitlab-org/gitlab-ce/issues/23361
......
# Cohorts ---
redirect_to: '../instance_statistics/user_cohorts.md'
---
> **Notes:** This document was moved to [another location](../instance_statistics/user_cohorts.md).
> [Introduced][ce-23361] in GitLab 9.1.
As a benefit of having the [usage ping active](settings/usage_statistics.md),
GitLab lets you analyze the users' activities of your GitLab installation.
Under `/admin/cohorts`, when the usage ping is active, GitLab will show the
monthly cohorts of new users and their activities over time.
## Overview
How do we read the user cohorts table? Let's take an example with the following
user cohorts.
![User cohort example](img/cohorts.png)
For the cohort of June 2016, 163 users have been added on this server and have
been active since this month. One month later, in July 2016, out of
these 163 users, 155 users (or 95% of the June cohort) are still active. Two
months later, 139 users (or 85%) are still active. 9 months later, we can see
that only 6% of this cohort are still active.
The Inactive users column shows the number of users who have been added during
the month, but who have never actually had any activity in the instance.
How do we measure the activity of users? GitLab considers a user active if:
* the user signs in
* the user has Git activity (whether push or pull).
## Setup
1. [Activate the usage ping](settings/usage_statistics.md)
2. Go to `/admin/cohorts` to see the user cohorts of the server
[ce-23361]: https://gitlab.com/gitlab-org/gitlab-ce/issues/23361
...@@ -173,3 +173,7 @@ Automate GitLab via [API](../api/README.md). ...@@ -173,3 +173,7 @@ Automate GitLab via [API](../api/README.md).
## Git and GitLab ## Git and GitLab
Learn what is [Git](../topics/git/index.md) and its best practices. Learn what is [Git](../topics/git/index.md) and its best practices.
## Instance statistics
See [various statistics](instance_statistics/index.md) of your GitLab instance.
# Conversational Development Index
> [Introduced][ce-30469] in GitLab 9.3.
Conversational Development Index (ConvDev) gives you an overview of your entire
instance's feature usage, from idea to production. It looks at your usage in the
past 30 days, averaged over the number of active users in that time period. It also
provides a lead score per feature, which is calculated based on GitLab's analysis
of top performing instances, based on [usage ping data][ping] that GitLab has
collected. Your score is compared to the lead score, expressed as a percentage.
The overall index score is an average over all your feature scores.
![ConvDev index](img/convdev_index.png)
The page also provides helpful links to articles and GitLab docs, to help you
improve your scores.
Your GitLab instance's usage ping must be activated in order to use this feature.
Usage ping data is aggregated on GitLab's servers for analysis. Your usage
information is **not sent** to any other GitLab instances.
If you have just started using GitLab, it may take a few weeks for data to be
collected before this feature is available.
[ce-30469]: https://gitlab.com/gitlab-org/gitlab-ce/issues/30469
[ping]: ../admin_area/settings/usage_statistics.md#usage-ping
# Instance statistics
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/41416)
in GitLab 11.2.
Instance statistics gives users or admins access to instance-wide analytics.
They are accessible to all users by default (GitLab admins can restrict its
visibility in the [admin area](../admin_area/settings/usage_statistics.md)),
and can be accessed via the top bar.
![Instance Statistics button](img/instance_statistics_button.png)
For the statistics to show up, [usage ping must be enabled](../admin_area/settings/usage_statistics.md#usage-ping)
by an admin in the admin settings area.
There are two kinds of statistics:
- [Conversational Development (ConvDev) Index](convdev.md): Provides an overview of your entire instance's feature usage.
- [User Cohorts](user_cohorts.md): Display the monthly cohorts of new users and their activities over time.
# Cohorts
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/23361)
in GitLab 9.1.
As a benefit of having the [usage ping active](../admin_area/settings/usage_statistics.md),
GitLab lets you analyze the users' activities over time of your GitLab installation.
## Overview
How do we read the user cohorts table? Let's take an example with the following
user cohorts.
![User cohort example](img/cohorts.png)
For the cohort of Jan 2018, 15 users have been added on this server and have
been active since this month. One month later, in Feb 2018, all 15 users are
still active. 6 months later (Month 6, July), we can see 10 users from this cohort
are active, or 66% of the original cohort of 15 that joined in January.
The Inactive users column shows the number of users who have been added during
the month, but who have never actually had any activity in the instance.
How do we measure the activity of users? GitLab considers a user active if:
* the user signs in
* the user has Git activity (whether push or pull).
...@@ -11,8 +11,8 @@ ...@@ -11,8 +11,8 @@
1. [From SVN](svn.md) 1. [From SVN](svn.md)
1. [From TFS](tfs.md) 1. [From TFS](tfs.md)
1. [From repo by URL](repo_by_url.md) 1. [From repo by URL](repo_by_url.md)
1. [By uploading a manifest file (AOSP)](manifest.md)
1. [From Gemnasium](gemnasium.md) 1. [From Gemnasium](gemnasium.md)
1. [By uploading a manifest file](manifest.md)
In addition to the specific migration documentation above, you can import any In addition to the specific migration documentation above, you can import any
Git repository via HTTP from the New Project page. Be aware that if the Git repository via HTTP from the New Project page. Be aware that if the
......
# Import multiple repositories by uploading a manifest file # Import multiple repositories by uploading a manifest file
GitLab allows you to import all the required git repositories GitLab allows you to import all the required Git repositories
based a manifest file like the one used by the [Android repository](https://android.googlesource.com/platform/manifest/+/2d6f081a3b05d8ef7a2b1b52b0d536b2b74feab4/default.xml). based on a manifest file like the one used by the
This feature can be very handy when you need to import a project with many repositories like Android Open Source Project (AOSP). [Android repository](https://android.googlesource.com/platform/manifest/+/2d6f081a3b05d8ef7a2b1b52b0d536b2b74feab4/default.xml).
This feature can be very handy when you need to import a project with many
repositories like the Android Open Source Project (AOSP).
## Requirements
>**Note:** GitLab must be using PostgreSQL for its database, since
This feature requires [subgroups](../../group/subgroups/index.md) to be supported by your database. [subgroups](../../group/subgroups/index.md) are needed for the manifest import
to work.
You can do it by following next steps: Read more about the [database requirements](../../../install/requirements.md#database).
1. From your GitLab dashboard click **New project** ## Manifest format
1. Switch to the **Import project** tab
1. Click on the **Manifest file** button
1. Provide GitLab with a manifest xml file
1. Select a group you want to import to (you need to create a group first if you don't have one)
1. Click **List available repositories**
1. You will be redirected to the import status page with projects list based on manifest file
1. Check the list and click 'Import all repositories' to start import.
![Manifest upload](img/manifest_upload.png) A manifest must be an XML file. There must be one `remote` tag with a `review`
attribute that contains a URL to a Git server, and each `project` tag must have
a `name` and `path` attribute. GitLab will then build the URL to the repository
by combining the URL from the `remote` tag with a project name.
A path attribute will be used to represent the project path in GitLab.
![Manifest status](img/manifest_status.png) Below is a valid example of a manifest file:
### Manifest format
A manifest must be an XML file. There must be one `remote` tag with `review` attribute
that contains a URL to a git server. Each `project` tag must have `name` and `path` attribute.
GitLab will build URL to the repository by combining URL from `remote` tag with a project name.
A path attribute will be used to represent project path in GitLab system.
Below is a valid example of manifest file.
```xml ```xml
<manifest> <manifest>
...@@ -41,9 +33,24 @@ Below is a valid example of manifest file. ...@@ -41,9 +33,24 @@ Below is a valid example of manifest file.
</manifest> </manifest>
``` ```
As result next projects will be created: As a result, the following projects will be created:
| GitLab | Import URL | | GitLab | Import URL |
|---|---| |---|---|
| https://gitlab/YOUR_GROUP/build/make | https://android-review.googlesource.com/platform/build | | https://gitlab.com/YOUR_GROUP/build/make | https://android-review.googlesource.com/platform/build |
| https://gitlab/YOUR_GROUP/build/blueprint | https://android-review.googlesource.com/platform/build/blueprint | | https://gitlab.com/YOUR_GROUP/build/blueprint | https://android-review.googlesource.com/platform/build/blueprint |
## Importing the repositories
You can start the import with:
1. From your GitLab dashboard click **New project**
1. Switch to the **Import project** tab
1. Click on the **Manifest file** button
1. Provide GitLab with a manifest xml file
1. Select a group you want to import to (you need to create a group first if you don't have one)
1. Click **List available repositories**. At this point, you will be redirected
to the import status page with projects list based on the manifest file.
1. Check the list and click **Import all repositories** to start the import.
![Manifest status](img/manifest_status.png)
...@@ -24,6 +24,10 @@ module EE ...@@ -24,6 +24,10 @@ module EE
attrs << :email_additional_text attrs << :email_additional_text
end end
if License.feature_available?(:custom_file_templates)
attrs << :file_template_project_id
end
if License.feature_available?(:pseudonymizer) if License.feature_available?(:pseudonymizer)
attrs << :pseudonymizer_enabled attrs << :pseudonymizer_enabled
end end
......
module EE
module LicenseTemplateFinder
include ::Gitlab::Utils::StrongMemoize
extend ::Gitlab::Utils::Override
override :execute
def execute
return super unless custom_templates?
extra = custom_licenses.map do |template|
LicenseTemplate.new(
id: template.name,
name: template.name,
nickname: template.name,
category: :Custom,
content: -> { template.content }
)
end
super + extra
end
private
def custom_templates?
!popular_only? &&
::License.feature_available?(:custom_file_templates) &&
template_project.present?
end
def custom_licenses
::Gitlab::Template::LicenseTemplate.all(template_project)
end
def template_project
strong_memoize(:template_project) { ::Gitlab::CurrentSettings.file_template_project }
end
end
end
...@@ -97,7 +97,10 @@ module EE ...@@ -97,7 +97,10 @@ module EE
end end
def self.possible_licensed_attributes def self.possible_licensed_attributes
repository_mirror_attributes + external_authorization_service_attributes + [:email_additional_text] repository_mirror_attributes + external_authorization_service_attributes + %i[
email_additional_text
file_template_project_id
]
end end
end end
end end
...@@ -11,6 +11,8 @@ module EE ...@@ -11,6 +11,8 @@ module EE
EMAIL_ADDITIONAL_TEXT_CHARACTER_LIMIT = 10_000 EMAIL_ADDITIONAL_TEXT_CHARACTER_LIMIT = 10_000
belongs_to :file_template_project, class_name: "Project"
ignore_column :minimum_mirror_sync_time ignore_column :minimum_mirror_sync_time
validates :shared_runners_minutes, validates :shared_runners_minutes,
......
...@@ -40,6 +40,7 @@ class License < ActiveRecord::Base ...@@ -40,6 +40,7 @@ class License < ActiveRecord::Base
board_assignee_lists board_assignee_lists
board_milestone_lists board_milestone_lists
cross_project_pipelines cross_project_pipelines
custom_file_templates
email_additional_text email_additional_text
db_load_balancing db_load_balancing
deploy_board deploy_board
...@@ -150,6 +151,7 @@ class License < ActiveRecord::Base ...@@ -150,6 +151,7 @@ class License < ActiveRecord::Base
GLOBAL_FEATURES = %i[ GLOBAL_FEATURES = %i[
admin_audit_log admin_audit_log
auditor_user auditor_user
custom_file_templates
db_load_balancing db_load_balancing
elastic_search elastic_search
extended_audit_events extended_audit_events
......
- if License.feature_available?(:custom_file_templates)
%section.settings.as-visibility-access.no-animate#js-visibility-settings{ class: ('expanded' if expanded) }
.settings-header
%h4
= _('Templates')
%button.btn.js-settings-toggle{ type: 'button' }
= expanded ? _('Collapse') : _('Expand')
%p
= _('Set instance-wide template repository')
.settings-content
= form_for @application_setting, url: admin_application_settings_path, html: { class: 'fieldset-form' } do |f|
= form_errors(@application_setting)
%fieldset
.form-group
= f.label :file_template_project_id, class: 'label-light' do
.form-text.text-muted
Select a
= link_to 'template repository', help_page_path("user/admin_area/settings/instance_template_repository", anchor: "version-check")
= project_select_tag('application_setting[file_template_project_id]', class: 'project-item-select hidden-filter-value', toggle_class: 'js-project-search js-project-filter js-filter-submit', dropdown_class: 'dropdown-menu-selectable dropdown-menu-project js-filter-submit',
placeholder: admin_project_dropdown_label('Search projects'), idAttribute: 'id', data: { order_by: 'last_activity_at', idattribute: 'id', all_projects: 'true', simple_filter: true, allow_clear: true}, value: @application_setting.file_template_project_id)
= f.submit 'Save changes', class: "btn btn-success"
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
;(function(p,l,o,w,i,n,g){if(!p[i]){p.GlobalSnowplowNamespace=p.GlobalSnowplowNamespace||[]; ;(function(p,l,o,w,i,n,g){if(!p[i]){p.GlobalSnowplowNamespace=p.GlobalSnowplowNamespace||[];
p.GlobalSnowplowNamespace.push(i);p[i]=function(){(p[i].q=p[i].q||[]).push(arguments) p.GlobalSnowplowNamespace.push(i);p[i]=function(){(p[i].q=p[i].q||[]).push(arguments)
};p[i].q=p[i].q||[];n=l.createElement(o);g=l.getElementsByTagName(o)[0];n.async=1; };p[i].q=p[i].q||[];n=l.createElement(o);g=l.getElementsByTagName(o)[0];n.async=1;
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","#{asset_url('/assets/shared/snowplow/sp.js')}","snowplow")); n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","#{asset_url('shared/snowplow/sp.js')}","snowplow"));
window.snowplow('newTracker', 'cf', '#{Gitlab::CurrentSettings.snowplow_collector_uri}', { window.snowplow('newTracker', 'cf', '#{Gitlab::CurrentSettings.snowplow_collector_uri}', {
appId: '#{Gitlab::CurrentSettings.snowplow_site_id}', appId: '#{Gitlab::CurrentSettings.snowplow_site_id}',
......
---
title: Added an instance-level license template project
merge_request: 6631
author: Dan Barker
type: added
title: Corrected URL for snowplow client side JS
merge_request: 6899
author:
type: fixed
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddProjectToApplicationSettings < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_column :application_settings, :file_template_project_id, :integer
add_concurrent_foreign_key :application_settings, :projects, column: :file_template_project_id, on_delete: :nullify
end
def down
remove_foreign_key :application_settings, column: :file_template_project_id
remove_column :application_settings, :file_template_project_id, :integer
end
end
...@@ -120,6 +120,7 @@ module EE ...@@ -120,6 +120,7 @@ module EE
::License.feature_available?(:external_authorization_service) ::License.feature_available?(:external_authorization_service)
end) end)
expose :email_additional_text, if: ->(_instance, _opts) { ::License.feature_available?(:email_additional_text) } expose :email_additional_text, if: ->(_instance, _opts) { ::License.feature_available?(:email_additional_text) }
expose :file_template_project_id, if: ->(_instance, _opts) { ::License.feature_available?(:custom_file_templates) }
end end
end end
......
module Gitlab
module Template
class LicenseTemplate < BaseTemplate
class << self
def extension
'.txt'
end
def base_dir
'LICENSE/'
end
def finder(project)
Gitlab::Template::Finders::RepoTemplateFinder.new(project, self.base_dir, self.extension, self.categories)
end
end
end
end
end
require 'spec_helper'
describe LicenseTemplateFinder do
describe '#execute' do
subject(:result) { described_class.new(params).execute }
let(:params) { {} }
let(:project) { create(:project) }
let(:custom) { result.select { |template| template.category == :Custom } }
before do
stub_ee_application_setting(file_template_project: project)
allow(Gitlab::Template::LicenseTemplate)
.to receive(:all)
.with(project)
.and_return([OpenStruct.new(name: "custom template")])
end
context 'custom file templates feature enabled' do
before do
stub_licensed_features(custom_file_templates: true)
end
it 'includes custom file templates' do
expect(custom.map(&:name)).to contain_exactly("custom template")
end
it 'skips custom file templates when only "popular" templates are requested' do
params[:popular] = true
expect(custom).to be_empty
end
end
context 'custom file templates feature disabled' do
it 'does not include custom file templates' do
stub_licensed_features(custom_file_templates: false)
expect(custom).to be_empty
end
end
end
end
require 'spec_helper'
describe BlobHelper do
include TreeHelper
describe '#licenses_for_select' do
subject(:result) { helper.licenses_for_select }
let(:categories) { result.keys }
let(:custom) { result[:Custom] }
let(:popular) { result[:Popular] }
let(:other) { result[:Other] }
let(:project) { create(:project) }
it 'returns Custom licenses when enabled' do
stub_licensed_features(custom_file_templates: true)
stub_ee_application_setting(file_template_project: project)
expect(Gitlab::Template::LicenseTemplate)
.to receive(:all)
.with(project)
.and_return([OpenStruct.new(name: "name")])
expect(categories).to contain_exactly(:Popular, :Other, :Custom)
expect(custom).to contain_exactly({ name: "name", id: "name" })
expect(popular).to be_present
expect(other).to be_present
end
it 'returns no Custom licenses when disabled' do
stub_licensed_features(custom_file_templates: false)
expect(categories).to contain_exactly(:Popular, :Other)
expect(custom).to be_nil
expect(popular).to be_present
expect(other).to be_present
end
end
end
...@@ -5,6 +5,7 @@ describe API::Settings, 'EE Settings' do ...@@ -5,6 +5,7 @@ describe API::Settings, 'EE Settings' do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:admin) { create(:admin) } let(:admin) { create(:admin) }
let(:project) { create(:project) }
before do before do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
...@@ -12,12 +13,15 @@ describe API::Settings, 'EE Settings' do ...@@ -12,12 +13,15 @@ describe API::Settings, 'EE Settings' do
describe "PUT /application/settings" do describe "PUT /application/settings" do
it 'sets EE specific settings' do it 'sets EE specific settings' do
stub_licensed_features(custom_file_templates: true)
put api("/application/settings", admin), put api("/application/settings", admin),
help_text: 'Help text', help_text: 'Help text',
snowplow_collector_uri: 'https://snowplow.example.com', snowplow_collector_uri: 'https://snowplow.example.com',
snowplow_cookie_domain: '.example.com', snowplow_cookie_domain: '.example.com',
snowplow_enabled: true, snowplow_enabled: true,
snowplow_site_id: 'site_id' snowplow_site_id: 'site_id',
file_template_project_id: project.id
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(200)
expect(json_response['help_text']).to eq('Help text') expect(json_response['help_text']).to eq('Help text')
...@@ -25,6 +29,7 @@ describe API::Settings, 'EE Settings' do ...@@ -25,6 +29,7 @@ describe API::Settings, 'EE Settings' do
expect(json_response['snowplow_cookie_domain']).to eq('.example.com') expect(json_response['snowplow_cookie_domain']).to eq('.example.com')
expect(json_response['snowplow_enabled']).to be_truthy expect(json_response['snowplow_enabled']).to be_truthy
expect(json_response['snowplow_site_id']).to eq('site_id') expect(json_response['snowplow_site_id']).to eq('site_id')
expect(json_response['file_template_project_id']).to eq(project.id)
end end
end end
...@@ -72,6 +77,7 @@ describe API::Settings, 'EE Settings' do ...@@ -72,6 +77,7 @@ describe API::Settings, 'EE Settings' do
it 'allows updating the settings' do it 'allows updating the settings' do
put api("/application/settings", admin), settings put api("/application/settings", admin), settings
expect(response).to have_gitlab_http_status(200)
settings.each do |attribute, value| settings.each do |attribute, value|
expect(ApplicationSetting.current.public_send(attribute)).to eq(value) expect(ApplicationSetting.current.public_send(attribute)).to eq(value)
...@@ -111,6 +117,13 @@ describe API::Settings, 'EE Settings' do ...@@ -111,6 +117,13 @@ describe API::Settings, 'EE Settings' do
it_behaves_like 'settings for licensed features' it_behaves_like 'settings for licensed features'
end end
context 'custom file template project' do
let(:settings) { { file_template_project_id: project.id } }
let(:feature) { :custom_file_templates }
it_behaves_like 'settings for licensed features'
end
context "missing snowplow_collector_uri value when snowplow_enabled is true" do context "missing snowplow_collector_uri value when snowplow_enabled is true" do
it "returns a blank parameter error message" do it "returns a blank parameter error message" do
put api("/application/settings", admin), snowplow_enabled: true put api("/application/settings", admin), snowplow_enabled: true
......
...@@ -1187,7 +1187,7 @@ module API ...@@ -1187,7 +1187,7 @@ module API
class License < Grape::Entity class License < Grape::Entity
expose :key, :name, :nickname expose :key, :name, :nickname
expose :featured, as: :popular expose :popular?, as: :popular
expose :url, as: :html_url expose :url, as: :html_url
expose(:source_url) { |license| license.meta['source'] } expose(:source_url) { |license| license.meta['source'] }
expose(:description) { |license| license.meta['description'] } expose(:description) { |license| license.meta['description'] }
......
...@@ -151,6 +151,7 @@ module API ...@@ -151,6 +151,7 @@ module API
optional :email_additional_text, type: String, desc: 'Additional text added to the bottom of every email for legal/auditing/compliance reasons' optional :email_additional_text, type: String, desc: 'Additional text added to the bottom of every email for legal/auditing/compliance reasons'
optional :help_text, type: String, desc: 'GitLab server administrator information' optional :help_text, type: String, desc: 'GitLab server administrator information'
optional :repository_size_limit, type: Integer, desc: 'Size limit per repository (MB)' optional :repository_size_limit, type: Integer, desc: 'Size limit per repository (MB)'
optional :file_template_project_id, type: Integer, desc: 'ID of project where instance-level file templates are stored.'
optional :repository_storages, type: Array[String], desc: 'A list of names of enabled storage paths, taken from `gitlab.yml`. New projects will be created in one of these stores, chosen at random.' optional :repository_storages, type: Array[String], desc: 'A list of names of enabled storage paths, taken from `gitlab.yml`. New projects will be created in one of these stores, chosen at random.'
optional :snowplow_enabled, type: Boolean, desc: 'Enable Snowplow' optional :snowplow_enabled, type: Boolean, desc: 'Enable Snowplow'
given snowplow_enabled: ->(val) { val } do given snowplow_enabled: ->(val) { val } do
...@@ -203,6 +204,10 @@ module API ...@@ -203,6 +204,10 @@ module API
unless ::License.feature_available?(:email_additional_text) unless ::License.feature_available?(:email_additional_text)
attrs = attrs.except(:email_additional_text) attrs = attrs.except(:email_additional_text)
end end
unless ::License.feature_available?(:custom_file_templates)
attrs = attrs.except(:file_template_project_id)
end
## EE-only END: Remove unlicensed attributes ## EE-only END: Remove unlicensed attributes
if ApplicationSettings::UpdateService.new(current_settings, current_user, attrs).execute if ApplicationSettings::UpdateService.new(current_settings, current_user, attrs).execute
......
...@@ -16,31 +16,8 @@ module API ...@@ -16,31 +16,8 @@ module API
gitlab_version: 8.15 gitlab_version: 8.15
} }
}.freeze }.freeze
PROJECT_TEMPLATE_REGEX =
%r{[\<\{\[]
(project|description|
one\sline\s.+\swhat\sit\sdoes\.) # matching the start and end is enough here
[\>\}\]]}xi.freeze
YEAR_TEMPLATE_REGEX = /[<{\[](year|yyyy)[>}\]]/i.freeze
FULLNAME_TEMPLATE_REGEX =
%r{[\<\{\[]
(fullname|name\sof\s(author|copyright\sowner))
[\>\}\]]}xi.freeze
helpers do helpers do
def parsed_license_template
# We create a fresh Licensee::License object since we'll modify its
# content in place below.
template = Licensee::License.new(params[:name])
template.content.gsub!(YEAR_TEMPLATE_REGEX, Time.now.year.to_s)
template.content.gsub!(PROJECT_TEMPLATE_REGEX, params[:project]) if params[:project].present?
fullname = params[:fullname].presence || current_user.try(:name)
template.content.gsub!(FULLNAME_TEMPLATE_REGEX, fullname) if fullname
template
end
def render_response(template_type, template) def render_response(template_type, template)
not_found!(template_type.to_s.singularize) unless template not_found!(template_type.to_s.singularize) unless template
present template, with: Entities::Template present template, with: Entities::Template
...@@ -56,11 +33,12 @@ module API ...@@ -56,11 +33,12 @@ module API
use :pagination use :pagination
end end
get "templates/licenses" do get "templates/licenses" do
options = { popular = declared(params)[:popular]
featured: declared(params)[:popular].present? ? true : nil popular = to_boolean(popular) if popular.present?
}
licences = ::Kaminari.paginate_array(Licensee::License.all(options)) templates = LicenseTemplateFinder.new(popular: popular).execute
present paginate(licences), with: Entities::License
present paginate(::Kaminari.paginate_array(templates)), with: ::API::Entities::License
end end
desc 'Get the text for a specific license' do desc 'Get the text for a specific license' do
...@@ -71,9 +49,15 @@ module API ...@@ -71,9 +49,15 @@ module API
requires :name, type: String, desc: 'The name of the template' requires :name, type: String, desc: 'The name of the template'
end end
get "templates/licenses/:name", requirements: { name: /[\w\.-]+/ } do get "templates/licenses/:name", requirements: { name: /[\w\.-]+/ } do
not_found!('License') unless Licensee::License.find(declared(params)[:name]) templates = LicenseTemplateFinder.new.execute
template = templates.find { |template| template.key == params[:name] }
not_found!('License') unless template.present?
template = parsed_license_template template.resolve!(
project_name: params[:project].presence,
fullname: params[:fullname].presence || current_user&.name
)
present template, with: ::API::Entities::License present template, with: ::API::Entities::License
end end
......
...@@ -21,7 +21,7 @@ module Gitlab ...@@ -21,7 +21,7 @@ module Gitlab
def category_directory(category) def category_directory(category)
return @base_dir unless category.present? return @base_dir unless category.present?
@base_dir + @categories[category] File.join(@base_dir, @categories[category])
end end
class << self class << self
......
...@@ -27,7 +27,7 @@ module Gitlab ...@@ -27,7 +27,7 @@ module Gitlab
directory = select_directory(file_name) directory = select_directory(file_name)
raise FileNotFoundError if directory.nil? raise FileNotFoundError if directory.nil?
category_directory(directory) + file_name File.join(category_directory(directory), file_name)
end end
def list_files_for(dir) def list_files_for(dir)
...@@ -37,8 +37,8 @@ module Gitlab ...@@ -37,8 +37,8 @@ module Gitlab
entries = @repository.tree(:head, dir).entries entries = @repository.tree(:head, dir).entries
names = entries.map(&:name) paths = entries.map(&:path)
names.select { |f| f =~ self.class.filter_regex(@extension) } paths.select { |f| f =~ self.class.filter_regex(@extension) }
end end
private private
...@@ -47,10 +47,10 @@ module Gitlab ...@@ -47,10 +47,10 @@ module Gitlab
return [] unless @commit return [] unless @commit
# Insert root as directory # Insert root as directory
directories = ["", @categories.keys] directories = ["", *@categories.keys]
directories.find do |category| directories.find do |category|
path = category_directory(category) + file_name path = File.join(category_directory(category), file_name)
@repository.blob_at(@commit.id, path) @repository.blob_at(@commit.id, path)
end end
end end
......
...@@ -6361,6 +6361,9 @@ msgstr "" ...@@ -6361,6 +6361,9 @@ msgstr ""
msgid "Set default and restrict visibility levels. Configure import sources and git access protocol." msgid "Set default and restrict visibility levels. Configure import sources and git access protocol."
msgstr "" msgstr ""
msgid "Set instance-wide template repository"
msgstr ""
msgid "Set max session time for web terminal." msgid "Set max session time for web terminal."
msgstr "" msgstr ""
...@@ -6854,6 +6857,9 @@ msgstr "" ...@@ -6854,6 +6857,9 @@ msgstr ""
msgid "Template" msgid "Template"
msgstr "" msgstr ""
msgid "Templates"
msgstr ""
msgid "Terms of Service Agreement and Privacy Policy" msgid "Terms of Service Agreement and Privacy Policy"
msgstr "" msgstr ""
......
require 'spec_helper'
describe LicenseTemplateFinder do
describe '#execute' do
subject(:result) { described_class.new(params).execute }
let(:categories) { categorised_licenses.keys }
let(:categorised_licenses) { result.group_by(&:category) }
context 'popular: true' do
let(:params) { { popular: true } }
it 'only returns popular licenses' do
expect(categories).to contain_exactly(:Popular)
expect(categorised_licenses[:Popular]).to be_present
end
end
context 'popular: false' do
let(:params) { { popular: false } }
it 'only returns unpopular licenses' do
expect(categories).to contain_exactly(:Other)
expect(categorised_licenses[:Other]).to be_present
end
end
context 'popular: nil' do
let(:params) { { popular: nil } }
it 'returns all licenses known by the Licensee gem' do
from_licensee = Licensee::License.all.map { |l| l.key }
expect(result.map(&:id)).to match_array(from_licensee)
end
it 'correctly copies all attributes' do
licensee = Licensee::License.all.first
found = result.find { |r| r.key == licensee.key }
aggregate_failures do
%i[key name content nickname url meta featured?].each do |k|
expect(found.public_send(k)).to eq(licensee.public_send(k))
end
end
end
end
end
end
require 'spec_helper'
describe Gitlab::Template::Finders::RepoTemplateFinder do
set(:project) { create(:project, :repository) }
let(:categories) { { 'HTML' => 'html' } }
subject(:finder) { described_class.new(project, 'files/', '.html', categories) }
describe '#read' do
it 'returns the content of the given path' do
result = finder.read('files/html/500.html')
expect(result).to be_present
end
it 'raises an error if the path does not exist' do
expect { finder.read('does/not/exist') }.to raise_error(described_class::FileNotFoundError)
end
end
describe '#find' do
it 'returns the full path of the found template' do
result = finder.find('500')
expect(result).to eq('files/html/500.html')
end
end
describe '#list_files_for' do
it 'returns the full path of the found files' do
result = finder.list_files_for('files/html')
expect(result).to contain_exactly('files/html/500.html')
end
end
end
require 'spec_helper'
describe LicenseTemplate do
describe '#content' do
it 'calls a proc exactly once if provided' do
lazy = build_template(-> { 'bar' })
content = lazy.content
expect(content).to eq('bar')
expect(content.object_id).to eq(lazy.content.object_id)
content.replace('foo')
expect(lazy.content).to eq('foo')
end
it 'returns a string if provided' do
lazy = build_template('bar')
expect(lazy.content).to eq('bar')
end
end
describe '#resolve!' do
let(:content) do
<<~TEXT
Pretend License
[project]
Copyright (c) [year] [fullname]
TEXT
end
let(:expected) do
<<~TEXT
Pretend License
Foo Project
Copyright (c) 1985 Nick Thomas
TEXT
end
let(:template) { build_template(content) }
it 'updates placeholders in a copy of the template content' do
expect(template.content.object_id).to eq(content.object_id)
template.resolve!(project_name: "Foo Project", fullname: "Nick Thomas", year: "1985")
expect(template.content).to eq(expected)
expect(template.content.object_id).not_to eq(content.object_id)
end
end
def build_template(content)
described_class.new(id: 'foo', name: 'foo', category: :Other, content: content)
end
end
...@@ -56,6 +56,8 @@ describe API::Templates do ...@@ -56,6 +56,8 @@ describe API::Templates do
end end
it 'returns a license template' do it 'returns a license template' do
expect(response).to have_gitlab_http_status(200)
expect(json_response['key']).to eq('mit') expect(json_response['key']).to eq('mit')
expect(json_response['name']).to eq('MIT License') expect(json_response['name']).to eq('MIT License')
expect(json_response['nickname']).to be_nil expect(json_response['nickname']).to be_nil
...@@ -181,6 +183,7 @@ describe API::Templates do ...@@ -181,6 +183,7 @@ describe API::Templates do
it 'replaces the copyright owner placeholder with the name of the current user' do it 'replaces the copyright owner placeholder with the name of the current user' do
get api('/templates/licenses/mit', user) get api('/templates/licenses/mit', user)
expect(response).to have_gitlab_http_status(200)
expect(json_response['content']).to include("Copyright (c) #{Time.now.year} #{user.name}") expect(json_response['content']).to include("Copyright (c) #{Time.now.year} #{user.name}")
end end
end end
......
...@@ -97,6 +97,17 @@ describe Groups::DestroyService do ...@@ -97,6 +97,17 @@ describe Groups::DestroyService do
it_behaves_like 'group destruction', false it_behaves_like 'group destruction', false
end end
context 'repository removal status is taken into account' do
it 'raises exception' do
expect_next_instance_of(::Projects::DestroyService) do |destroy_service|
expect(destroy_service).to receive(:execute).and_return(false)
end
expect { destroy_group(group, user, false) }
.to raise_error(Groups::DestroyService::DestroyError, "Project #{project.id} can't be deleted" )
end
end
describe 'repository removal' do describe 'repository removal' do
before do before do
destroy_group(group, user, false) destroy_group(group, user, false)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment