Merge branch 'master' into matbaj/gitlab-ce-add-inherit-command

This commit is contained in:
Sean McGivern 2018-04-24 13:59:00 +01:00
commit 6a88ffb412
465 changed files with 2770 additions and 2486 deletions

View File

@ -75,7 +75,7 @@ stages:
.use-mysql: &use-mysql
services:
- mysql:latest
- mysql:5.7
- redis:alpine
.rails5-variables: &rails5-variables

View File

@ -143,7 +143,7 @@ Lint/MissingCopEnableDirective:
Lint/NestedPercentLiteral:
Exclude:
- 'lib/gitlab/git/repository.rb'
- 'spec/support/email_format_shared_examples.rb'
- 'spec/support/shared_examples/email_format_shared_examples.rb'
# Offense count: 1
Lint/ReturnInVoidContext:
@ -195,8 +195,8 @@ Naming/HeredocDelimiterCase:
- 'spec/lib/gitlab/diff/parser_spec.rb'
- 'spec/lib/json_web_token/rsa_token_spec.rb'
- 'spec/models/commit_spec.rb'
- 'spec/support/repo_helpers.rb'
- 'spec/support/seed_repo.rb'
- 'spec/support/helpers/repo_helpers.rb'
- 'spec/support/helpers/seed_repo.rb'
# Offense count: 112
# Configuration parameters: Blacklist.
@ -496,7 +496,7 @@ Style/EmptyLiteral:
- 'spec/lib/gitlab/request_context_spec.rb'
- 'spec/lib/gitlab/workhorse_spec.rb'
- 'spec/requests/api/jobs_spec.rb'
- 'spec/support/chat_slash_commands_shared_examples.rb'
- 'spec/support/shared_examples/chat_slash_commands_shared_examples.rb'
# Offense count: 102
# Cop supports --auto-correct.

View File

@ -2,6 +2,241 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
## 10.7.1 (2018-04-23)
### Fixed (11 changes)
- [API] Fix URLs in the `Link` header for `GET /projects/:id/repository/contributors` when no value is passed for `order_by` or `sort`. !18393
- Fix a case with secret variables being empty sometimes. !18400
- Fix `Trace::HttpIO` can not render multi-byte chars. !18417
- Fix specifying a non-default ref when requesting an archive using the legacy URL. !18468
- Respect visibility options and description when importing project from template. !18473
- Removes 'No Job log' message from build trace. !18523
- Align action icons in pipeline graph.
- Fix direct_upload when records with null file_store are used.
- Removed alert box in IDE when redirecting to new merge request.
- Fixed IDE not loading for sub groups.
- Fixed IDE not showing loading state when tree is loading.
### Performance (4 changes)
- Validate project path prior to hitting the database. !18322
- Add index to file_store on ci_job_artifacts. !18444
- Fix N+1 queries when loading participants for a commit note.
- Support Markdown rendering using multiple projects.
### Added (1 change)
- Add an API endpoint to download git repository snapshots. !18173
## 10.7.0 (2018-04-22)
### Security (6 changes, 2 of them are from the community)
- Fixed some SSRF vulnerabilities in services, hooks and integrations. !2337
- Update ruby-saml to 1.7.2 and omniauth-saml to 1.10.0. !17734 (Takuya Noguchi)
- Update rack-protection to 2.0.1. !17835 (Takuya Noguchi)
- Adds confidential notes channel for Slack/Mattermost.
- Fix XSS on diff view stored on filenames.
- Fix GitLab Auth0 integration signing in the wrong user.
### Fixed (65 changes, 20 of them are from the community)
- File uploads in remote storage now support project renaming. !4597
- Fixed bug in dropdown selector when selecting the same selection again. !14631 (bitsapien)
- Fixed group deletion linked to Mattermost. !16209 (Julien Millau)
- Create commit API and Web IDE obey LFS filters. !16718
- Set breadcrumb for admin/runners/show. !17431 (Takuya Noguchi)
- Enable restore rake task to handle nested storage directories. !17516 (Balasankar C)
- Fix hover style of dropdown items in the right sidebar. !17519
- Improve empty state for canceled job. !17646
- Fix generated URL when listing repoitories for import. !17692
- Use singular in the diff stats if only one line has been changed. !17697 (Jan Beckmann)
- Long instance urls do not overflow anymore during project creation. !17717
- Fix importing multiple assignees from GitLab export. !17718
- Correct copy text for the promote milestone and label modals. !17726
- Fix search results stripping last endline when parsing the results. !17777 (Jasper Maes)
- Add read-only banner to all pages. !17798
- Fix viewing diffs on old merge requests. !17805
- Fix forking to subgroup via API when namespace is given by name. !17815 (Jan Beckmann)
- Fix UI breakdown for Create merge request button. !17821 (Takuya Noguchi)
- Unify format for nested non-task lists. !17823 (Takuya Noguchi)
- UX re-design branch items with flexbox. !17832 (Takuya Noguchi)
- Use porcelain commit lookup method on CI::CreatePipelineService. !17911
- Update dashboard milestones breadcrumb link. !17933 (George Tsiolis)
- Deleting a MR you are assigned to should decrements counter. !17951 (m b)
- Update no repository placeholder. !17964 (George Tsiolis)
- Drop JSON response in Project Milestone along with avoiding error. !17977 (Takuya Noguchi)
- Fix personal access token clipboard button style. !17978 (Fabian Schneider)
- Avoid validation errors when running the Pages domain verification service. !17992
- Project creation will now raise an error if a service template is invalid. !18013
- Add better LDAP connection handling. !18039
- Fix autolinking URLs containing ampersands. !18045
- Fix exceptions raised when migrating pipeline stages in the background. !18076
- Always display Labels section in issuable sidebar, even when the project has no labels. !18081 (Branka Martinovic)
- Fixed gitlab:uploads:migrate task ignoring some uploads. !18082
- Fixed gitlab:uploads:migrate task failing for Groups' avatar. !18088
- Increase dropdown width in pipeline graph & center action icon. !18089
- Fix `JobsController#raw` endpoint can not read traces in database. !18101
- Fix `gitlab-rake gitlab:two_factor:disable_for_all_users`. !18154
- Adjust 404's for LegacyDiffNote discussion rendering. !18201
- Work around Prometheus Helm chart name changes to fix integration. !18206 (joshlambert)
- Prioritize weight over title when sorting charts. !18233
- Verify that deploy token has valid access when pulling container registry image. !18260
- Stop redirecting the page in pipeline main actions.
- Fixed IDE button opening the wrong URL in tree list.
- Ensure hooks run when a deploy key without a user pushes.
- Fix 404 in group boards when moving issue between lists.
- Display state indicator for issuable references in non-project scope (e.g. when referencing issuables from group scope).
- Add missing port to artifact links.
- Fix data race between ObjectStorage background_upload and Pages publishing.
- Fixes unresolved discussions rendering the error state instead of the diff.
- Don't show Jump to Discussion button on Issues.
- Fix bug rendering group icons when forking.
- Automatically cleanup stale worktrees and lock files upon a push.
- Use the GitLab version as part of the appearances cache key.
- Fix Firefox stealing formatting characters on issue notes.
- Include matching branches and tags in protected branches / tags count. (Jan Beckmann)
- Fix 500 error when a merge request from a fork has conflicts and has not yet been updated.
- Test if remote repository exists when importing wikis.
- Hide emoji popup after multiple spaces. (Jan Beckmann)
- Fix relative uri when "#" is in branch name. (Jan)
- Escape Markdown characters properly when using autocomplete.
- Ignore project internal references in group context.
- Fix finding wiki file when Gitaly is enabled.
- Fix listing commit branch/tags that contain special characters.
- Ensure internal users (ghost, support bot) get assigned a namespace.
- Fix links to subdirectories of a directory with a plus character in its path.
### Deprecated (1 change)
- Remove support for legacy tar.gz pages artifacts. !18090
### Changed (22 changes, 2 of them are from the community)
- Add yellow favicon when `CANARY=true` to differientate canary environment. !12477
- Use human readable value build_timeout in Project. !17386
- Improved visual styles and consistency for commit hash and possible actions across commit lists. !17406
- Don't create permanent redirect routes. !17521
- Add empty repo check before running AutoDevOps pipeline. !17605
- Update wording to specify create/manage project vs group labels in labels dropdown. !17640
- Add tooltips to icons in lists of issues and merge requests. !17700
- Change avatar error message to include allowed file formats. !17747 (Fabian Schneider)
- Polish design for verifying domains. !17767
- Move email footer info to a single line. !17916
- Add average and maximum summary statistics to the prometheus dashboard. !17921
- Add additional cluster usage metrics to usage ping. !17922
- Move 'Registry' after 'CI/CD' in project navigation sidebar. !18018 (Elias Werberich)
- Redesign application settings to match project settings. !18019
- Allow HTTP(s) when git request is made by GitLab CI. !18021
- Added hover background color to IDE file list rows.
- Make project avatar in IDE consistent with the rest of GitLab.
- Show issues of subgroups in group-level issue board.
- Repository checksum calculation is handled by Gitaly when feature is enabled.
- Allow viewing timings for AJAX requests in the performance bar.
- Fixes remove source branch checkbox being visible when user cannot remove the branch.
- Make /-/ delimiter optional for search endpoints.
### Performance (24 changes, 11 of them are from the community)
- Move AssigneeTitle vue component. !17397 (George Tsiolis)
- Move TimeTrackingCollapsedState vue component. !17399 (George Tsiolis)
- Move MemoryGraph and MemoryUsage vue components. !17533 (George Tsiolis)
- Move UnresolvedDiscussions vue component. !17538 (George Tsiolis)
- Move NothingToMerge vue component. !17544 (George Tsiolis)
- Move ShaMismatch vue component. !17546 (George Tsiolis)
- Stop caching highlighted diffs in Redis unnecessarily. !17746
- Add i18n and update specs for ShaMismatch vue component. !17870 (George Tsiolis)
- Update spec import path for vue mount component helper. !17880 (George Tsiolis)
- Move TimeTrackingComparisonPane vue component. !17931 (George Tsiolis)
- Improves the performance of projects list page. !17934
- Remove N+1 query for Noteable association. !17956
- Improve performance of loading issues with lots of references to merge requests. !17986
- Reuse root_ref_hash for performance on Branches. !17998 (Takuya Noguchi)
- Update asciidoctor-plantuml to 0.0.8. !18022 (Takuya Noguchi)
- Cache personal projects count. !18197
- Reduce complexity of issuable finder query. !18219
- Reduce number of queries when viewing a merge request.
- Free open file descriptors and libgit2 buffers in UpdatePagesService.
- Memoize Git::Repository#has_visible_content?.
- Require at least one filter when listing issues or merge requests on dashboard page.
- lazy load diffs on merge request discussions.
- Bulk deleting refs is handled by Gitaly by default.
- ListCommitsByOid is executed by Gitaly by default.
### Added (38 changes, 7 of them are from the community)
- Add HTTPS-only pages. !16273 (rfwatson)
- adds closed by informations in issue api. !17042 (haseebeqx)
- Projects and groups badges settings UI. !17114
- Add per-runner configured job timeout. !17221
- Add alternate archive route for simplified packaging. !17225
- Add support for pipeline variables expressions in only/except. !17316
- Add object storage support for LFS objects, CI artifacts, and uploads. !17358
- Added confirmation modal for changing username. !17405
- Implement foreground verification of CI artifacts. !17578
- Extend API for exporting a project with direct upload URL. !17686
- Move ci/lint under project's namespace. !17729
- Add Total CPU/Memory consumption metrics for Kubernetes. !17731
- Adds the option to the project export API to override the project description and display GitLab export description once imported. !17744
- Port direct upload of LFS artifacts from EE. !17752
- Adds support for OmniAuth JWT provider. !17774
- Display error message on job's tooltip if this one fails. !17782
- Add 'Assigned Issues' and 'Assigned Merge Requests' as dashboard view choices for users. !17860 (Elias Werberich)
- Extend API for importing a project export with overwrite support. !17883
- Create Deploy Tokens to allow permanent access to repository and registry. !17894
- Detect commit message trailers and link users properly to their accounts on Gitlab. !17919 (cousine)
- Adds cancel btn to new pages domain page. !18026 (Jacopo Beschi @jacopo-beschi)
- API: Add parameter merge_method to projects. !18031 (Jan Beckmann)
- Introduce simpler env vars for auto devops REPLICAS and CANARY_REPLICAS #41436. !18036
- Allow overriding params on project import through API. !18086
- Support LFS objects when importing/exporting GitLab project archives. !18115
- Store sha256 checksum of artifact metadata. !18149
- Limit the number of failed logins when using LDAP for authentication. !43525
- Allow assigning and filtering issuables by ancestor group labels.
- Include subgroup issues when searching for group issues using the API.
- Allow to store uploads by default on Object Storage.
- Add slash command for moving issues. (Adam Pahlevi)
- Render MR commit SHA instead "diffs" when viable.
- Send @mention notifications even if a user has explicitly unsubscribed from item.
- Add support for Sidekiq JSON logging.
- Add Gitaly call details to performance bar.
- Add support for patch link extension for commit links on GitLab Flavored Markdown.
- Allow feature gates to be removed through the API.
- Allow merge requests related to a commit to be found via API.
### Other (27 changes, 11 of them are from the community)
- Send notification emails when push to a merge request. !7610 (YarNayar)
- Rename modal.vue to deprecated_modal.vue. !17438
- Atomic generation of internal ids for issues. !17580
- Use object ID to prevent duplicate keys Vue warning on Issue Boards page during development. !17682
- Update foreman from 0.78.0 to 0.84.0. !17690 (Takuya Noguchi)
- Add realtime pipeline status for adding/viewing files. !17705
- Update documentation to reflect current minimum required versions of node and yarn. !17706
- Update knapsack to 1.16.0. !17735 (Takuya Noguchi)
- Update CI services documnetation. !17749
- Added i18n support for the prometheus memory widget. !17753
- Use specific names for filtered CI variable controller parameters. !17796
- Apply NestingDepth (level 5) (framework/dropdowns.scss). !17820 (Takuya Noguchi)
- Clean up selectors in framework/header.scss. !17822 (Takuya Noguchi)
- Bump `state_machines-activerecord` to 0.5.1. !17924 (blackst0ne)
- Increase the memory limits used in the unicorn killer. !17948
- Replace the spinach test with an rspec analog. !17950 (blackst0ne)
- Remove unused index from events table. !18014
- Make all workhorse gitaly calls opt-out, take 2. !18043
- Update brakeman 3.6.1 to 4.2.1. !18122 (Takuya Noguchi)
- Replace the `project/issues/labels.feature` spinach test with an rspec analog. !18126 (blackst0ne)
- Bump html-pipeline to 2.7.1. !18132 (@blackst0ne)
- Remove test_ci rake task. !18139 (Takuya Noguchi)
- Add documentation for Pipelines failure reasons. !18352
- Improve JIRA event descriptions.
- Add query counts to profiler output.
- Move Sidekiq exporter logs to log/sidekiq_exporter.log.
- Upgrade Gitaly to upgrade its charlock_holmes.
## 10.6.4 (2018-04-09)
### Fixed (8 changes, 1 of them is from the community)

View File

@ -26,7 +26,9 @@ _This notice should stay as the first item in the CONTRIBUTING.md file._
- [Type labels (~"feature proposal", ~bug, ~customer, etc.)](#type-labels-feature-proposal-bug-customer-etc)
- [Subject labels (~wiki, ~"container registry", ~ldap, ~api, etc.)](#subject-labels-wiki-container-registry-ldap-api-etc)
- [Team labels (~"CI/CD", ~Discussion, ~Edge, ~Platform, etc.)](#team-labels-cicd-discussion-edge-platform-etc)
- [Priority labels (~Deliverable, ~Stretch, ~"Next Patch Release")](#priority-labels-deliverable-stretch-next-patch-release)
- [Milestone labels (~Deliverable, ~Stretch, ~"Next Patch Release")](#milestone-labels-deliverable-stretch-next-patch-release)
- [Priority labels (~Deliverable, ~Stretch, ~"Next Patch Release")](#bug-priority-labels-p1-p2-p3-etc)
- [Severity labels (~Deliverable, ~Stretch, ~"Next Patch Release")](#bug-severity-labels-s1-s2-s3-etc)
- [Label for community contributors (~"Accepting Merge Requests")](#label-for-community-contributors-accepting-merge-requests)
- [Implement design & UI elements](#implement-design-ui-elements)
- [Issue tracker](#issue-tracker)
@ -127,6 +129,8 @@ Most issues will have labels for at least one of the following:
- Subject: ~wiki, ~"container registry", ~ldap, ~api, ~frontend, etc.
- Team: ~"CI/CD", ~Discussion, ~Edge, ~Platform, etc.
- Milestone: ~Deliverable, ~Stretch, ~"Next Patch Release"
- Priority: ~P1, ~P2, ~P3, ~P4
- Severity: ~S1, ~S2, ~S3, ~S4
All labels, their meaning and priority are defined on the
[labels page][labels-page].
@ -210,7 +214,7 @@ This label documents the planned timeline & urgency which is used to measure aga
| Label | Meaning | Estimate time to fix | Guidance |
|-------|-----------------|------------------------------------------------------------------|----------|
| ~P1 | Urgent Priority | The current release | |
| ~P1 | Urgent Priority | The current release + potentially immediate hotfix to GitLab.com | |
| ~P2 | High Priority | The next release | |
| ~P3 | Medium Priority | Within the next 3 releases (approx one quarter) | |
| ~P4 | Low Priority | Anything outside the next 3 releases (approx beyond one quarter) | The issue is prominent but does not impact user workflow and a workaround is documented |

View File

@ -1 +1 @@
0.95.0
0.96.1

View File

@ -178,7 +178,7 @@ GEM
docile (1.1.5)
domain_name (0.5.20170404)
unf (>= 0.0.5, < 1.0.0)
doorkeeper (4.3.1)
doorkeeper (4.3.2)
railties (>= 4.2)
doorkeeper-openid_connect (1.3.0)
doorkeeper (~> 4.3)

View File

@ -1 +1 @@
10.7.0-pre
10.8.0-pre

View File

@ -113,6 +113,8 @@ class List {
issue.id = data.id;
issue.iid = data.iid;
issue.project = data.project;
issue.path = data.real_path;
issue.referencePath = data.reference_path;
if (this.issuesSize > 1) {
const moveBeforeId = this.issues[1].id;

View File

@ -84,20 +84,21 @@ export default class CreateMergeRequestDropdown {
if (data.can_create_branch) {
this.available();
this.enable();
this.updateBranchName(data.suggested_branch_name);
if (!this.droplabInitialized) {
this.droplabInitialized = true;
this.initDroplab();
this.bindEvents();
}
} else if (data.has_related_branch) {
} else {
this.hide();
}
})
.catch(() => {
this.unavailable();
this.disable();
Flash('Failed to check if a new branch can be created.');
Flash(__('Failed to check related branches.'));
});
}
@ -409,13 +410,16 @@ export default class CreateMergeRequestDropdown {
this.unavailableButton.classList.remove('hide');
}
updateBranchName(suggestedBranchName) {
this.branchInput.value = suggestedBranchName;
this.updateCreatePaths('branch', suggestedBranchName);
}
updateInputState(target, ref, result) {
// target - 'branch' or 'ref' - which the input field we are searching a ref for.
// ref - string - what a user typed.
// result - string - what has been found on backend.
const pathReplacement = `$1${ref}`;
// If a found branch equals exact the same text a user typed,
// that means a new branch cannot be created as it already exists.
if (ref === result) {
@ -426,18 +430,12 @@ export default class CreateMergeRequestDropdown {
this.refIsValid = true;
this.refInput.dataset.value = ref;
this.showAvailableMessage('ref');
this.createBranchPath = this.createBranchPath.replace(this.regexps.ref.createBranchPath,
pathReplacement);
this.createMrPath = this.createMrPath.replace(this.regexps.ref.createMrPath,
pathReplacement);
this.updateCreatePaths(target, ref);
}
} else if (target === 'branch') {
this.branchIsValid = true;
this.showAvailableMessage('branch');
this.createBranchPath = this.createBranchPath.replace(this.regexps.branch.createBranchPath,
pathReplacement);
this.createMrPath = this.createMrPath.replace(this.regexps.branch.createMrPath,
pathReplacement);
this.updateCreatePaths(target, ref);
} else {
this.refIsValid = false;
this.refInput.dataset.value = ref;
@ -457,4 +455,15 @@ export default class CreateMergeRequestDropdown {
this.disableCreateAction();
}
}
// target - 'branch' or 'ref'
// ref - string - the new value to use as branch or ref
updateCreatePaths(target, ref) {
const pathReplacement = `$1${ref}`;
this.createBranchPath = this.createBranchPath.replace(this.regexps[target].createBranchPath,
pathReplacement);
this.createMrPath = this.createMrPath.replace(this.regexps[target].createMrPath,
pathReplacement);
}
}

View File

@ -1427,7 +1427,7 @@ export default class Notes {
const { discussion_html } = data;
const lines = $(discussion_html).find('.line_holder');
lines.addClass('fade-in');
$container.find('tbody').prepend(lines);
$container.find('.diff-content > table > tbody').prepend(lines);
const fileHolder = $container.find('.file-holder');
$container.find('.line-holder-placeholder').remove();
syntaxHighlight(fileHolder);

View File

@ -19,7 +19,7 @@ function getSystemDate(systemUtcOffsetSeconds) {
const date = new Date();
const localUtcOffsetMinutes = 0 - date.getTimezoneOffset();
const systemUtcOffsetMinutes = systemUtcOffsetSeconds / 60;
date.setMinutes((date.getMinutes() - localUtcOffsetMinutes) + systemUtcOffsetMinutes);
date.setMinutes(date.getMinutes() - localUtcOffsetMinutes + systemUtcOffsetMinutes);
return date;
}
@ -35,18 +35,36 @@ function formatTooltipText({ date, count }) {
return `${contribText}<br />${dateDayName} ${dateText}`;
}
const initColorKey = () => d3.scaleLinear().range(['#acd5f2', '#254e77']).domain([0, 3]);
const initColorKey = () =>
d3
.scaleLinear()
.range(['#acd5f2', '#254e77'])
.domain([0, 3]);
export default class ActivityCalendar {
constructor(container, timestamps, calendarActivitiesPath, utcOffset = 0) {
constructor(container, timestamps, calendarActivitiesPath, utcOffset = 0, firstDayOfWeek = 0) {
this.calendarActivitiesPath = calendarActivitiesPath;
this.clickDay = this.clickDay.bind(this);
this.currentSelectedDate = '';
this.daySpace = 1;
this.daySize = 15;
this.daySizeWithSpace = this.daySize + (this.daySpace * 2);
this.monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
this.daySizeWithSpace = this.daySize + this.daySpace * 2;
this.monthNames = [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec',
];
this.months = [];
this.firstDayOfWeek = firstDayOfWeek;
// Loop through the timestamps to create a group of objects
// The group of objects will be grouped based on the day of the week they are
@ -70,7 +88,7 @@ export default class ActivityCalendar {
// Create a new group array if this is the first day of the week
// or if is first object
if ((day === 0 && i !== 0) || i === 0) {
if ((day === this.firstDayOfWeek && i !== 0) || i === 0) {
this.timestampsTmp.push([]);
group += 1;
}
@ -109,21 +127,30 @@ export default class ActivityCalendar {
}
renderSvg(container, group) {
const width = ((group + 1) * this.daySizeWithSpace) + this.getExtraWidthPadding(group);
return d3.select(container)
const width = (group + 1) * this.daySizeWithSpace + this.getExtraWidthPadding(group);
return d3
.select(container)
.append('svg')
.attr('width', width)
.attr('height', 167)
.attr('class', 'contrib-calendar');
.attr('width', width)
.attr('height', 167)
.attr('class', 'contrib-calendar');
}
dayYPos(day) {
return this.daySizeWithSpace * ((day + 7 - this.firstDayOfWeek) % 7);
}
renderDays() {
this.svg.selectAll('g').data(this.timestampsTmp).enter().append('g')
this.svg
.selectAll('g')
.data(this.timestampsTmp)
.enter()
.append('g')
.attr('transform', (group, i) => {
_.each(group, (stamp, a) => {
if (a === 0 && stamp.day === 0) {
const month = stamp.date.getMonth();
const x = (this.daySizeWithSpace * i) + 1 + this.daySizeWithSpace;
const x = this.daySizeWithSpace * i + 1 + this.daySizeWithSpace;
const lastMonth = _.last(this.months);
if (
lastMonth == null ||
@ -133,86 +160,113 @@ export default class ActivityCalendar {
}
}
});
return `translate(${(this.daySizeWithSpace * i) + 1 + this.daySizeWithSpace}, 18)`;
return `translate(${this.daySizeWithSpace * i + 1 + this.daySizeWithSpace}, 18)`;
})
.selectAll('rect')
.data(stamp => stamp)
.enter()
.append('rect')
.attr('x', '0')
.attr('y', stamp => this.daySizeWithSpace * stamp.day)
.attr('width', this.daySize)
.attr('height', this.daySize)
.attr('fill', stamp => (
stamp.count !== 0 ? this.color(Math.min(stamp.count, 40)) : '#ededed'
))
.attr('title', stamp => formatTooltipText(stamp))
.attr('class', 'user-contrib-cell js-tooltip')
.attr('data-container', 'body')
.on('click', this.clickDay);
.data(stamp => stamp)
.enter()
.append('rect')
.attr('x', '0')
.attr('y', stamp => this.dayYPos(stamp.day))
.attr('width', this.daySize)
.attr('height', this.daySize)
.attr(
'fill',
stamp => (stamp.count !== 0 ? this.color(Math.min(stamp.count, 40)) : '#ededed'),
)
.attr('title', stamp => formatTooltipText(stamp))
.attr('class', 'user-contrib-cell js-tooltip')
.attr('data-container', 'body')
.on('click', this.clickDay);
}
renderDayTitles() {
const days = [
{
text: 'M',
y: 29 + (this.daySizeWithSpace * 1),
}, {
y: 29 + this.dayYPos(1),
},
{
text: 'W',
y: 29 + (this.daySizeWithSpace * 3),
}, {
y: 29 + this.dayYPos(2),
},
{
text: 'F',
y: 29 + (this.daySizeWithSpace * 5),
y: 29 + this.dayYPos(3),
},
];
this.svg.append('g')
this.svg
.append('g')
.selectAll('text')
.data(days)
.enter()
.append('text')
.attr('text-anchor', 'middle')
.attr('x', 8)
.attr('y', day => day.y)
.text(day => day.text)
.attr('class', 'user-contrib-text');
.data(days)
.enter()
.append('text')
.attr('text-anchor', 'middle')
.attr('x', 8)
.attr('y', day => day.y)
.text(day => day.text)
.attr('class', 'user-contrib-text');
}
renderMonths() {
this.svg.append('g')
this.svg
.append('g')
.attr('direction', 'ltr')
.selectAll('text')
.data(this.months)
.enter()
.append('text')
.attr('x', date => date.x)
.attr('y', 10)
.attr('class', 'user-contrib-text')
.text(date => this.monthNames[date.month]);
.data(this.months)
.enter()
.append('text')
.attr('x', date => date.x)
.attr('y', 10)
.attr('class', 'user-contrib-text')
.text(date => this.monthNames[date.month]);
}
renderKey() {
const keyValues = ['no contributions', '1-9 contributions', '10-19 contributions', '20-29 contributions', '30+ contributions'];
const keyColors = ['#ededed', this.colorKey(0), this.colorKey(1), this.colorKey(2), this.colorKey(3)];
const keyValues = [
'no contributions',
'1-9 contributions',
'10-19 contributions',
'20-29 contributions',
'30+ contributions',
];
const keyColors = [
'#ededed',
this.colorKey(0),
this.colorKey(1),
this.colorKey(2),
this.colorKey(3),
];
this.svg.append('g')
.attr('transform', `translate(18, ${(this.daySizeWithSpace * 8) + 16})`)
this.svg
.append('g')
.attr('transform', `translate(18, ${this.daySizeWithSpace * 8 + 16})`)
.selectAll('rect')
.data(keyColors)
.enter()
.append('rect')
.attr('width', this.daySize)
.attr('height', this.daySize)
.attr('x', (color, i) => this.daySizeWithSpace * i)
.attr('y', 0)
.attr('fill', color => color)
.attr('class', 'js-tooltip')
.attr('title', (color, i) => keyValues[i])
.attr('data-container', 'body');
.data(keyColors)
.enter()
.append('rect')
.attr('width', this.daySize)
.attr('height', this.daySize)
.attr('x', (color, i) => this.daySizeWithSpace * i)
.attr('y', 0)
.attr('fill', color => color)
.attr('class', 'js-tooltip')
.attr('title', (color, i) => keyValues[i])
.attr('data-container', 'body');
}
initColor() {
const colorRange = ['#ededed', this.colorKey(0), this.colorKey(1), this.colorKey(2), this.colorKey(3)];
return d3.scaleThreshold().domain([0, 10, 20, 30]).range(colorRange);
const colorRange = [
'#ededed',
this.colorKey(0),
this.colorKey(1),
this.colorKey(2),
this.colorKey(3),
];
return d3
.scaleThreshold()
.domain([0, 10, 20, 30])
.range(colorRange);
}
clickDay(stamp) {
@ -227,14 +281,15 @@ export default class ActivityCalendar {
$('.user-calendar-activities').html(LOADING_HTML);
axios.get(this.calendarActivitiesPath, {
params: {
date,
},
responseType: 'text',
})
.then(({ data }) => $('.user-calendar-activities').html(data))
.catch(() => flash(__('An error occurred while retrieving calendar activity')));
axios
.get(this.calendarActivitiesPath, {
params: {
date,
},
responseType: 'text',
})
.then(({ data }) => $('.user-calendar-activities').html(data))
.catch(() => flash(__('An error occurred while retrieving calendar activity')));
} else {
this.currentSelectedDate = '';
$('.user-calendar-activities').html('');

View File

@ -32,26 +32,38 @@ export default {
required: true,
},
buttonDisabled: {
requestFinishedFor: {
type: String,
required: false,
default: null,
default: '',
},
},
data() {
return {
isDisabled: false,
linkRequested: '',
};
},
computed: {
cssClass() {
const actionIconDash = dasherize(this.actionIcon);
return `${actionIconDash} js-icon-${actionIconDash}`;
},
isDisabled() {
return this.buttonDisabled === this.link;
},
watch: {
requestFinishedFor() {
if (this.requestFinishedFor === this.linkRequested) {
this.isDisabled = false;
}
},
},
methods: {
onClickAction() {
$(this.$el).tooltip('hide');
eventHub.$emit('graphAction', this.link);
this.linkRequested = this.link;
this.isDisabled = true;
},
},
};
@ -62,7 +74,8 @@ export default {
@click="onClickAction"
v-tooltip
:title="tooltipText"
class="btn btn-blank btn-transparent ci-action-icon-container ci-action-icon-wrapper"
class="js-ci-action btn btn-blank
btn-transparent ci-action-icon-container ci-action-icon-wrapper"
:class="cssClass"
data-container="body"
:disabled="isDisabled"

View File

@ -1,53 +0,0 @@
<script>
import icon from '../../../vue_shared/components/icon.vue';
import tooltip from '../../../vue_shared/directives/tooltip';
/**
* Renders either a cancel, retry or play icon pointing to the given path.
* TODO: Remove UJS from here and use an async request instead.
*/
export default {
components: {
icon,
},
directives: {
tooltip,
},
props: {
tooltipText: {
type: String,
required: true,
},
link: {
type: String,
required: true,
},
actionMethod: {
type: String,
required: true,
},
actionIcon: {
type: String,
required: true,
},
},
};
</script>
<template>
<a
v-tooltip
:data-method="actionMethod"
:title="tooltipText"
:href="link"
rel="nofollow"
class="ci-action-icon-wrapper js-ci-status-icon"
data-container="body"
aria-label="Job's action"
>
<icon :name="actionIcon" />
</a>
</template>

View File

@ -1,77 +1,83 @@
<script>
import $ from 'jquery';
import jobNameComponent from './job_name_component.vue';
import jobComponent from './job_component.vue';
import tooltip from '../../../vue_shared/directives/tooltip';
import $ from 'jquery';
import JobNameComponent from './job_name_component.vue';
import JobComponent from './job_component.vue';
import tooltip from '../../../vue_shared/directives/tooltip';
/**
* Renders the dropdown for the pipeline graph.
*
* The following object should be provided as `job`:
*
* {
* "id": 4256,
* "name": "test",
* "status": {
* "icon": "icon_status_success",
* "text": "passed",
* "label": "passed",
* "group": "success",
* "details_path": "/root/ci-mock/builds/4256",
* "action": {
* "icon": "retry",
* "title": "Retry",
* "path": "/root/ci-mock/builds/4256/retry",
* "method": "post"
* }
* }
* }
*/
export default {
directives: {
tooltip,
/**
* Renders the dropdown for the pipeline graph.
*
* The following object should be provided as `job`:
*
* {
* "id": 4256,
* "name": "test",
* "status": {
* "icon": "icon_status_success",
* "text": "passed",
* "label": "passed",
* "group": "success",
* "details_path": "/root/ci-mock/builds/4256",
* "action": {
* "icon": "retry",
* "title": "Retry",
* "path": "/root/ci-mock/builds/4256/retry",
* "method": "post"
* }
* }
* }
*/
export default {
directives: {
tooltip,
},
components: {
JobComponent,
JobNameComponent,
},
props: {
job: {
type: Object,
required: true,
},
components: {
jobComponent,
jobNameComponent,
requestFinishedFor: {
type: String,
required: false,
default: '',
},
},
props: {
job: {
type: Object,
required: true,
},
computed: {
tooltipText() {
return `${this.job.name} - ${this.job.status.label}`;
},
},
computed: {
tooltipText() {
return `${this.job.name} - ${this.job.status.label}`;
},
},
mounted() {
this.stopDropdownClickPropagation();
},
mounted() {
this.stopDropdownClickPropagation();
},
methods: {
/**
* When the user right clicks or cmd/ctrl + click in the job name
* the dropdown should not be closed and the link should open in another tab,
* so we stop propagation of the click event inside the dropdown.
methods: {
/**
* When the user right clicks or cmd/ctrl + click in the job name or the action icon
* the dropdown should not be closed so we stop propagation
* of the click event inside the dropdown.
*
* Since this component is rendered multiple times per page we need to guarantee we only
* target the click event of this component.
*/
stopDropdownClickPropagation() {
$(this.$el
.querySelectorAll('.js-grouped-pipeline-dropdown a.mini-pipeline-graph-dropdown-item'))
.on('click', (e) => {
e.stopPropagation();
});
},
stopDropdownClickPropagation() {
$(
'.js-grouped-pipeline-dropdown button, .js-grouped-pipeline-dropdown a.mini-pipeline-graph-dropdown-item',
this.$el,
).on('click', e => {
e.stopPropagation();
});
},
};
},
};
</script>
<template>
<div class="ci-job-dropdown-container">
@ -101,8 +107,8 @@
:key="i">
<job-component
:job="item"
:is-dropdown="true"
css-class-job-name="mini-pipeline-graph-dropdown-item"
:request-finished-for="requestFinishedFor"
/>
</li>
</ul>

View File

@ -7,7 +7,6 @@ export default {
StageColumnComponent,
LoadingIcon,
},
props: {
isLoading: {
type: Boolean,
@ -17,10 +16,10 @@ export default {
type: Object,
required: true,
},
actionDisabled: {
requestFinishedFor: {
type: String,
required: false,
default: null,
default: '',
},
},
@ -75,7 +74,7 @@ export default {
:key="stage.name"
:stage-connector-class="stageConnectorClass(index, stage)"
:is-first-column="isFirstColumn(index)"
:action-disabled="actionDisabled"
:request-finished-for="requestFinishedFor"
/>
</ul>
</div>

View File

@ -1,6 +1,5 @@
<script>
import ActionComponent from './action_component.vue';
import DropdownActionComponent from './dropdown_action_component.vue';
import JobNameComponent from './job_name_component.vue';
import tooltip from '../../../vue_shared/directives/tooltip';
@ -32,10 +31,8 @@ import tooltip from '../../../vue_shared/directives/tooltip';
export default {
components: {
ActionComponent,
DropdownActionComponent,
JobNameComponent,
},
directives: {
tooltip,
},
@ -44,26 +41,17 @@ export default {
type: Object,
required: true,
},
cssClassJobName: {
type: String,
required: false,
default: '',
},
isDropdown: {
type: Boolean,
required: false,
default: false,
},
actionDisabled: {
requestFinishedFor: {
type: String,
required: false,
default: null,
default: '',
},
},
computed: {
status() {
return this.job && this.job.status ? this.job.status : {};
@ -134,19 +122,11 @@ export default {
</div>
<action-component
v-if="hasAction && !isDropdown"
v-if="hasAction"
:tooltip-text="status.action.title"
:link="status.action.path"
:action-icon="status.action.icon"
:button-disabled="actionDisabled"
/>
<dropdown-action-component
v-if="hasAction && isDropdown"
:tooltip-text="status.action.title"
:link="status.action.path"
:action-icon="status.action.icon"
:action-method="status.action.method"
:request-finished-for="requestFinishedFor"
/>
</div>
</template>

View File

@ -29,10 +29,11 @@ export default {
required: false,
default: '',
},
actionDisabled: {
requestFinishedFor: {
type: String,
required: false,
default: null,
default: '',
},
},
@ -74,12 +75,12 @@ export default {
v-if="job.size === 1"
:job="job"
css-class-job-name="build-content"
:action-disabled="actionDisabled"
/>
<dropdown-job-component
v-if="job.size > 1"
:job="job"
:request-finished-for="requestFinishedFor"
/>
</li>

View File

@ -25,7 +25,7 @@ export default () => {
data() {
return {
mediator,
actionDisabled: null,
requestFinishedFor: null,
};
},
created() {
@ -36,15 +36,17 @@ export default () => {
},
methods: {
postAction(action) {
this.actionDisabled = action;
// Click was made, reset this variable
this.requestFinishedFor = null;
this.mediator.service.postAction(action)
this.mediator.service
.postAction(action)
.then(() => {
this.mediator.refreshPipeline();
this.actionDisabled = null;
this.requestFinishedFor = action;
})
.catch(() => {
this.actionDisabled = null;
this.requestFinishedFor = action;
Flash(__('An error occurred while making the request.'));
});
},
@ -54,7 +56,7 @@ export default () => {
props: {
isLoading: this.mediator.state.isLoading,
pipeline: this.mediator.store.state.pipeline,
actionDisabled: this.actionDisabled,
requestFinishedFor: this.requestFinishedFor,
},
});
},
@ -79,7 +81,8 @@ export default () => {
},
methods: {
postAction(action) {
this.mediator.service.postAction(action.path)
this.mediator.service
.postAction(action.path)
.then(() => this.mediator.refreshPipeline())
.catch(() => Flash(__('An error occurred while making the request.')));
},

View File

@ -1,52 +1,52 @@
<script>
import ciIcon from './ci_icon.vue';
import tooltip from '../directives/tooltip';
/**
* Renders CI Badge link with CI icon and status text based on
* API response shared between all places where it is used.
*
* Receives status object containing:
* status: {
* details_path: "/gitlab-org/gitlab-ce/pipelines/8150156" // url
* group:"running" // used for CSS class
* icon: "icon_status_running" // used to render the icon
* label:"running" // used for potential tooltip
* text:"running" // text rendered
* }
*
* Used in:
* - Pipelines table - first column
* - Jobs table - first column
* - Pipeline show view - header
* - Job show view - header
* - MR widget
*/
import CiIcon from './ci_icon.vue';
import tooltip from '../directives/tooltip';
/**
* Renders CI Badge link with CI icon and status text based on
* API response shared between all places where it is used.
*
* Receives status object containing:
* status: {
* details_path: "/gitlab-org/gitlab-ce/pipelines/8150156" // url
* group:"running" // used for CSS class
* icon: "icon_status_running" // used to render the icon
* label:"running" // used for potential tooltip
* text:"running" // text rendered
* }
*
* Used in:
* - Pipelines table - first column
* - Jobs table - first column
* - Pipeline show view - header
* - Job show view - header
* - MR widget
*/
export default {
components: {
ciIcon,
export default {
components: {
CiIcon,
},
directives: {
tooltip,
},
props: {
status: {
type: Object,
required: true,
},
directives: {
tooltip,
showText: {
type: Boolean,
required: false,
default: true,
},
props: {
status: {
type: Object,
required: true,
},
showText: {
type: Boolean,
required: false,
default: true,
},
},
computed: {
cssClass() {
const className = this.status.group;
return className ? `ci-status ci-${className}` : 'ci-status';
},
computed: {
cssClass() {
const className = this.status.group;
return className ? `ci-status ci-${className}` : 'ci-status';
},
},
};
},
};
</script>
<template>
<a

View File

@ -1,45 +1,44 @@
<script>
import icon from '../../vue_shared/components/icon.vue';
import Icon from '../../vue_shared/components/icon.vue';
/**
* Renders CI icon based on API response shared between all places where it is used.
*
* Receives status object containing:
* status: {
* details_path: "/gitlab-org/gitlab-ce/pipelines/8150156" // url
* group:"running" // used for CSS class
* icon: "icon_status_running" // used to render the icon
* label:"running" // used for potential tooltip
* text:"running" // text rendered
* }
*
* Used in:
* - Pipelines table Badge
* - Pipelines table mini graph
* - Pipeline graph
* - Pipeline show view badge
* - Jobs table
* - Jobs show view header
* - Jobs show view sidebar
*/
export default {
components: {
icon,
/**
* Renders CI icon based on API response shared between all places where it is used.
*
* Receives status object containing:
* status: {
* details_path: "/gitlab-org/gitlab-ce/pipelines/8150156" // url
* group:"running" // used for CSS class
* icon: "icon_status_running" // used to render the icon
* label:"running" // used for potential tooltip
* text:"running" // text rendered
* }
*
* Used in:
* - Pipelines table Badge
* - Pipelines table mini graph
* - Pipeline graph
* - Pipeline show view badge
* - Jobs table
* - Jobs show view header
* - Jobs show view sidebar
*/
export default {
components: {
Icon,
},
props: {
status: {
type: Object,
required: true,
},
props: {
status: {
type: Object,
required: true,
},
},
computed: {
cssClass() {
const status = this.status.group;
return `ci-status-icon ci-status-icon-${status} js-ci-status-icon-${status}`;
},
computed: {
cssClass() {
const status = this.status.group;
return `ci-status-icon ci-status-icon-${status} js-ci-status-icon-${status}`;
},
},
};
},
};
</script>
<template>
<span :class="cssClass">

View File

@ -1,40 +1,50 @@
<script>
/**
* Falls back to the code used in `copy_to_clipboard.js`
*/
import tooltip from '../directives/tooltip';
/**
* Falls back to the code used in `copy_to_clipboard.js`
*
* Renders a button with a clipboard icon that copies the content of `data-clipboard-text`
* when clicked.
*
* @example
* <clipboard-button
* title="Copy to clipbard"
* text="Content to be copied"
* css-class="btn-transparent"
* />
*/
import tooltip from '../directives/tooltip';
export default {
name: 'ClipboardButton',
directives: {
tooltip,
export default {
name: 'ClipboardButton',
directives: {
tooltip,
},
props: {
text: {
type: String,
required: true,
},
props: {
text: {
type: String,
required: true,
},
title: {
type: String,
required: true,
},
tooltipPlacement: {
type: String,
required: false,
default: 'top',
},
tooltipContainer: {
type: [String, Boolean],
required: false,
default: false,
},
cssClass: {
type: String,
required: false,
default: 'btn-default',
},
title: {
type: String,
required: true,
},
};
tooltipPlacement: {
type: String,
required: false,
default: 'top',
},
tooltipContainer: {
type: [String, Boolean],
required: false,
default: false,
},
cssClass: {
type: String,
required: false,
default: 'btn-default',
},
},
};
</script>
<template>

View File

@ -1,119 +1,111 @@
<script>
import commitIconSvg from 'icons/_icon_commit.svg';
import userAvatarLink from './user_avatar/user_avatar_link.vue';
import tooltip from '../directives/tooltip';
import icon from '../../vue_shared/components/icon.vue';
import UserAvatarLink from './user_avatar/user_avatar_link.vue';
import tooltip from '../directives/tooltip';
import Icon from '../../vue_shared/components/icon.vue';
export default {
directives: {
tooltip,
export default {
directives: {
tooltip,
},
components: {
UserAvatarLink,
Icon,
},
props: {
/**
* Indicates the existance of a tag.
* Used to render the correct icon, if true will render `fa-tag` icon,
* if false will render a svg sprite fork icon
*/
tag: {
type: Boolean,
required: false,
default: false,
},
components: {
userAvatarLink,
icon,
/**
* If provided is used to render the branch name and url.
* Should contain the following properties:
* name
* ref_url
*/
commitRef: {
type: Object,
required: false,
default: () => ({}),
},
/**
* Used to link to the commit sha.
*/
commitUrl: {
type: String,
required: false,
default: '',
},
props: {
/**
* Indicates the existance of a tag.
* Used to render the correct icon, if true will render `fa-tag` icon,
* if false will render a svg sprite fork icon
*/
tag: {
type: Boolean,
required: false,
default: false,
},
/**
* If provided is used to render the branch name and url.
* Should contain the following properties:
* name
* ref_url
*/
commitRef: {
type: Object,
required: false,
default: () => ({}),
},
/**
* Used to link to the commit sha.
*/
commitUrl: {
type: String,
required: false,
default: '',
},
/**
* Used to show the commit short sha that links to the commit url.
*/
shortSha: {
type: String,
required: false,
default: '',
},
/**
* If provided shows the commit tile.
*/
title: {
type: String,
required: false,
default: '',
},
/**
* If provided renders information about the author of the commit.
* When provided should include:
* `avatar_url` to render the avatar icon
* `web_url` to link to user profile
* `username` to render alt and title tags
*/
author: {
type: Object,
required: false,
default: () => ({}),
},
showBranch: {
type: Boolean,
required: false,
default: true,
},
/**
* Used to show the commit short sha that links to the commit url.
*/
shortSha: {
type: String,
required: false,
default: '',
},
computed: {
/**
* Used to verify if all the properties needed to render the commit
* ref section were provided.
*
* @returns {Boolean}
*/
hasCommitRef() {
return this.commitRef && this.commitRef.name && this.commitRef.ref_url;
},
/**
* Used to verify if all the properties needed to render the commit
* author section were provided.
*
* @returns {Boolean}
*/
hasAuthor() {
return this.author &&
this.author.avatar_url &&
this.author.path &&
this.author.username;
},
/**
* If information about the author is provided will return a string
* to be rendered as the alt attribute of the img tag.
*
* @returns {String}
*/
userImageAltDescription() {
return this.author &&
this.author.username ? `${this.author.username}'s avatar` : null;
},
/**
* If provided shows the commit tile.
*/
title: {
type: String,
required: false,
default: '',
},
created() {
this.commitIconSvg = commitIconSvg;
/**
* If provided renders information about the author of the commit.
* When provided should include:
* `avatar_url` to render the avatar icon
* `web_url` to link to user profile
* `username` to render alt and title tags
*/
author: {
type: Object,
required: false,
default: () => ({}),
},
};
showBranch: {
type: Boolean,
required: false,
default: true,
},
},
computed: {
/**
* Used to verify if all the properties needed to render the commit
* ref section were provided.
*
* @returns {Boolean}
*/
hasCommitRef() {
return this.commitRef && this.commitRef.name && this.commitRef.ref_url;
},
/**
* Used to verify if all the properties needed to render the commit
* author section were provided.
*
* @returns {Boolean}
*/
hasAuthor() {
return this.author && this.author.avatar_url && this.author.path && this.author.username;
},
/**
* If information about the author is provided will return a string
* to be rendered as the alt attribute of the img tag.
*
* @returns {String}
*/
userImageAltDescription() {
return this.author && this.author.username ? `${this.author.username}'s avatar` : null;
},
},
};
</script>
<template>
<div class="branch-commit">
@ -141,11 +133,10 @@
{{ commitRef.name }}
</a>
</template>
<div
v-html="commitIconSvg"
<icon
name="commit"
class="commit-icon js-commit-icon"
>
</div>
/>
<a
class="commit-sha"

View File

@ -1,33 +1,33 @@
<script>
import { __ } from '~/locale';
/**
* Port of detail_behavior expand button.
*
* @example
* <expand-button>
* <template slot="expanded">
* Text goes here.
* </template>
* </expand-button>
*/
export default {
name: 'ExpandButton',
data() {
return {
isCollapsed: true,
};
import { __ } from '~/locale';
/**
* Port of detail_behavior expand button.
*
* @example
* <expand-button>
* <template slot="expanded">
* Text goes here.
* </template>
* </expand-button>
*/
export default {
name: 'ExpandButton',
data() {
return {
isCollapsed: true,
};
},
computed: {
ariaLabel() {
return __('Click to expand text');
},
computed: {
ariaLabel() {
return __('Click to expand text');
},
},
methods: {
onClick() {
this.isCollapsed = !this.isCollapsed;
},
methods: {
onClick() {
this.isCollapsed = !this.isCollapsed;
},
},
};
},
};
</script>
<template>
<span>

View File

@ -1,78 +1,78 @@
<script>
import ciIconBadge from './ci_badge_link.vue';
import loadingIcon from './loading_icon.vue';
import timeagoTooltip from './time_ago_tooltip.vue';
import tooltip from '../directives/tooltip';
import userAvatarImage from './user_avatar/user_avatar_image.vue';
import CiIconBadge from './ci_badge_link.vue';
import LoadingIcon from './loading_icon.vue';
import TimeagoTooltip from './time_ago_tooltip.vue';
import tooltip from '../directives/tooltip';
import UserAvatarImage from './user_avatar/user_avatar_image.vue';
/**
* Renders header component for job and pipeline page based on UI mockups
*
* Used in:
* - job show page
* - pipeline show page
*/
export default {
components: {
ciIconBadge,
loadingIcon,
timeagoTooltip,
userAvatarImage,
/**
* Renders header component for job and pipeline page based on UI mockups
*
* Used in:
* - job show page
* - pipeline show page
*/
export default {
components: {
CiIconBadge,
LoadingIcon,
TimeagoTooltip,
UserAvatarImage,
},
directives: {
tooltip,
},
props: {
status: {
type: Object,
required: true,
},
directives: {
tooltip,
itemName: {
type: String,
required: true,
},
props: {
status: {
type: Object,
required: true,
},
itemName: {
type: String,
required: true,
},
itemId: {
type: Number,
required: true,
},
time: {
type: String,
required: true,
},
user: {
type: Object,
required: false,
default: () => ({}),
},
actions: {
type: Array,
required: false,
default: () => [],
},
hasSidebarButton: {
type: Boolean,
required: false,
default: false,
},
shouldRenderTriggeredLabel: {
type: Boolean,
required: false,
default: true,
},
itemId: {
type: Number,
required: true,
},
time: {
type: String,
required: true,
},
user: {
type: Object,
required: false,
default: () => ({}),
},
actions: {
type: Array,
required: false,
default: () => [],
},
hasSidebarButton: {
type: Boolean,
required: false,
default: false,
},
shouldRenderTriggeredLabel: {
type: Boolean,
required: false,
default: true,
},
},
computed: {
userAvatarAltText() {
return `${this.user.name}'s avatar`;
},
computed: {
userAvatarAltText() {
return `${this.user.name}'s avatar`;
},
},
methods: {
onClickAction(action) {
this.$emit('actionClicked', action);
},
methods: {
onClickAction(action) {
this.$emit('actionClicked', action);
},
};
},
};
</script>
<template>

View File

@ -1,76 +1,75 @@
<script>
/* This is a re-usable vue component for rendering a svg sprite
icon
/* This is a re-usable vue component for rendering a svg sprite
icon
Sample configuration:
Sample configuration:
<icon
name="retry"
:size="32"
css-classes="top"
/>
<icon
name="retry"
:size="32"
css-classes="top"
/>
*/
// only allow classes in images.scss e.g. s12
const validSizes = [8, 12, 16, 18, 24, 32, 48, 72];
*/
// only allow classes in images.scss e.g. s12
const validSizes = [8, 12, 16, 18, 24, 32, 48, 72];
export default {
props: {
name: {
type: String,
required: true,
},
export default {
props: {
name: {
type: String,
required: true,
},
size: {
type: Number,
required: false,
default: 16,
validator(value) {
return validSizes.includes(value);
},
},
cssClasses: {
type: String,
required: false,
default: '',
},
width: {
type: Number,
required: false,
default: null,
},
height: {
type: Number,
required: false,
default: null,
},
y: {
type: Number,
required: false,
default: null,
},
x: {
type: Number,
required: false,
default: null,
size: {
type: Number,
required: false,
default: 16,
validator(value) {
return validSizes.includes(value);
},
},
computed: {
spriteHref() {
return `${gon.sprite_icons}#${this.name}`;
},
iconSizeClass() {
return this.size ? `s${this.size}` : '';
},
cssClasses: {
type: String,
required: false,
default: '',
},
};
width: {
type: Number,
required: false,
default: null,
},
height: {
type: Number,
required: false,
default: null,
},
y: {
type: Number,
required: false,
default: null,
},
x: {
type: Number,
required: false,
default: null,
},
},
computed: {
spriteHref() {
return `${gon.sprite_icons}#${this.name}`;
},
iconSizeClass() {
return this.size ? `s${this.size}` : '';
},
},
};
</script>
<template>
@ -79,7 +78,8 @@
:width="width"
:height="height"
:x="x"
:y="y">
:y="y"
>
<use v-bind="{ 'xlink:href':spriteHref }" />
</svg>
</template>

View File

@ -1,4 +1,5 @@
<script>
import $ from 'jquery';
import { __ } from '~/locale';
import LabelsSelect from '~/labels_select';
import LoadingIcon from '../../loading_icon.vue';
@ -98,11 +99,18 @@ export default {
this.labelsDropdown = new LabelsSelect(this.$refs.dropdownButton, {
handleClick: this.handleClick,
});
$(this.$refs.dropdown).on('hidden.gl.dropdown', this.handleDropdownHidden);
},
methods: {
handleClick(label) {
this.$emit('onLabelClick', label);
},
handleCollapsedValueClick() {
this.$emit('toggleCollapse');
},
handleDropdownHidden() {
this.$emit('onDropdownClose');
},
},
};
</script>
@ -112,6 +120,7 @@ export default {
<dropdown-value-collapsed
v-if="showCreate"
:labels="context.labels"
@onValueClick="handleCollapsedValueClick"
/>
<dropdown-title
:can-edit="canEdit"
@ -133,7 +142,10 @@ export default {
:name="hiddenInputName"
:label="label"
/>
<div class="dropdown">
<div
class="dropdown"
ref="dropdown"
>
<dropdown-button
:ability-name="abilityName"
:field-name="hiddenInputName"

View File

@ -26,6 +26,11 @@ export default {
return labelsString;
},
},
methods: {
handleClick() {
this.$emit('onValueClick');
},
},
};
</script>
@ -36,6 +41,7 @@ export default {
data-placement="left"
data-container="body"
:title="labelsList"
@click="handleClick"
>
<i
aria-hidden="true"

View File

@ -468,6 +468,14 @@
margin-bottom: 10px;
white-space: normal;
.ci-job-dropdown-container {
// override dropdown.scss
.dropdown-menu li button {
padding: 0;
text-align: center;
}
}
// ensure .build-content has hover style when action-icon is hovered
.ci-job-dropdown-container:hover .build-content {
@extend .build-content:hover;

View File

@ -134,11 +134,11 @@ class Projects::IssuesController < Projects::ApplicationController
def can_create_branch
can_create = current_user &&
can?(current_user, :push_code, @project) &&
@issue.can_be_worked_on?(current_user)
@issue.can_be_worked_on?
respond_to do |format|
format.json do
render json: { can_create_branch: can_create, has_related_branch: @issue.has_related_branch? }
render json: { can_create_branch: can_create, suggested_branch_name: @issue.suggested_branch_name }
end
end
end
@ -177,7 +177,7 @@ class Projects::IssuesController < Projects::ApplicationController
end
def authorize_create_merge_request!
render_404 unless can?(current_user, :push_code, @project) && @issue.can_be_worked_on?(current_user)
render_404 unless can?(current_user, :push_code, @project) && @issue.can_be_worked_on?
end
def render_issue_json

View File

@ -78,8 +78,6 @@ class Projects::JobsController < Projects::ApplicationController
result.merge!(trace.to_h)
end
result[:html] = result[:html].presence || 'No job log'
render json: result
end
end

View File

@ -32,6 +32,7 @@ class UsersFinder
users = by_active(users)
users = by_external_identity(users)
users = by_external(users)
users = by_2fa(users)
users = by_created_at(users)
users = by_custom_attributes(users)
@ -76,4 +77,15 @@ class UsersFinder
users.external
end
def by_2fa(users)
case params[:two_factor]
when 'enabled'
users.with_two_factor
when 'disabled'
users.without_two_factor
else
users
end
end
end

View File

@ -81,6 +81,14 @@ module GitlabRoutingHelper
end
end
def edit_milestone_path(entity, *args)
if entity.parent.is_a?(Group)
edit_group_milestone_path(entity.parent, entity, *args)
else
edit_project_milestone_path(entity.parent, entity, *args)
end
end
def toggle_subscription_path(entity, *args)
if entity.is_a?(Issue)
toggle_subscription_project_issue_path(entity.project, entity)

View File

@ -27,6 +27,7 @@ module Ci
has_one :metadata, class_name: 'Ci::BuildMetadata'
delegate :timeout, to: :metadata, prefix: true, allow_nil: true
delegate :gitlab_deploy_token, to: :project
##
# The "environment" field for builds is a String, and is the unexpanded name!
@ -604,6 +605,7 @@ module Ci
.append(key: 'CI_REGISTRY_USER', value: CI_REGISTRY_USER)
.append(key: 'CI_REGISTRY_PASSWORD', value: token, public: false)
.append(key: 'CI_REPOSITORY_URL', value: repo_url, public: false)
.concat(deploy_token_variables)
end
end
@ -654,6 +656,15 @@ module Ci
end
end
def deploy_token_variables
Gitlab::Ci::Variables::Collection.new.tap do |variables|
break variables unless gitlab_deploy_token
variables.append(key: 'CI_DEPLOY_USER', value: gitlab_deploy_token.name)
variables.append(key: 'CI_DEPLOY_PASSWORD', value: gitlab_deploy_token.token, public: false)
end
end
def environment_url
options&.dig(:environment, :url) || persisted_environment&.external_url
end

View File

@ -27,8 +27,9 @@ module AtomicInternalId
module ClassMethods
def has_internal_id(column, scope:, init:) # rubocop:disable Naming/PredicateName
before_validation(on: :create) do
if read_attribute(column).blank?
scope_attrs = { scope => association(scope).reader }
scope_value = association(scope).reader
if read_attribute(column).blank? && scope_value
scope_attrs = { scope_value.class.table_name.singularize.to_sym => scope_value }
usage = self.class.table_name.to_sym
new_iid = InternalId.generate_next(self, scope_attrs, usage, init)

View File

@ -31,12 +31,13 @@ module Avatarable
asset_host = ActionController::Base.asset_host
use_asset_host = asset_host.present?
use_authentication = respond_to?(:public?) && !public?
# Avatars for private and internal groups and projects require authentication to be viewed,
# which means they can only be served by Rails, on the regular GitLab host.
# If an asset host is configured, we need to return the fully qualified URL
# instead of only the avatar path, so that Rails doesn't prefix it with the asset host.
if use_asset_host && respond_to?(:public?) && !public?
if use_asset_host && use_authentication
use_asset_host = false
only_path = false
end
@ -49,6 +50,6 @@ module Avatarable
url_base << gitlab_config.relative_url_root
end
url_base + avatar.url
url_base + avatar.local_url
end
end

View File

@ -1,22 +0,0 @@
module NonatomicInternalId
extend ActiveSupport::Concern
included do
validate :set_iid, on: :create
validates :iid, presence: true, numericality: true
end
def set_iid
if iid.blank?
parent = project || group
records = parent.public_send(self.class.name.tableize) # rubocop:disable GitlabSecurity/PublicSend
max_iid = records.maximum(:iid)
self.iid = max_iid.to_i + 1
end
end
def to_param
iid.to_s
end
end

View File

@ -102,7 +102,7 @@ module Routable
# the route. Caching this per request ensures that even if we have multiple instances,
# we will not have to duplicate work, avoiding N+1 queries in some cases.
def full_path
return uncached_full_path unless RequestStore.active?
return uncached_full_path unless RequestStore.active? && persisted?
RequestStore[full_path_key] ||= uncached_full_path
end
@ -124,6 +124,11 @@ module Routable
end
end
# Group would override this to check from association
def owned_by?(user)
owner == user
end
private
def set_path_errors

View File

@ -1,13 +1,21 @@
# Uniquify
#
# Return a version of the given 'base' string that is unique
# by appending a counter to it. Uniqueness is determined by
# repeated calls to the passed block.
#
# You can pass an initial value for the counter, if not given
# counting starts from 1.
#
# If `base` is a function/proc, we expect that calling it with a
# candidate counter returns a string to test/return.
class Uniquify
# Return a version of the given 'base' string that is unique
# by appending a counter to it. Uniqueness is determined by
# repeated calls to the passed block.
#
# If `base` is a function/proc, we expect that calling it with a
# candidate counter returns a string to test/return.
def initialize(counter = nil)
@counter = counter
end
def string(base)
@base = base
@counter = nil
increment_counter! while yield(base_string)
base_string

View File

@ -4,6 +4,7 @@ class DeployToken < ActiveRecord::Base
add_authentication_token_field :token
AVAILABLE_SCOPES = %i(read_repository read_registry).freeze
GITLAB_DEPLOY_TOKEN_NAME = 'gitlab-deploy-token'.freeze
default_value_for(:expires_at) { Forever.date }
@ -17,6 +18,10 @@ class DeployToken < ActiveRecord::Base
scope :active, -> { where("revoked = false AND expires_at >= NOW()") }
def self.gitlab_deploy_token
active.find_by(name: GITLAB_DEPLOY_TOKEN_NAME)
end
def revoke!
update!(revoked: true)
end

View File

@ -1,11 +1,13 @@
class Deployment < ActiveRecord::Base
include NonatomicInternalId
include AtomicInternalId
belongs_to :project, required: true
belongs_to :environment, required: true
belongs_to :user
belongs_to :deployable, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations
has_internal_id :iid, scope: :project, init: ->(s) { s&.project&.deployments&.maximum(:iid) }
validates :sha, presence: true
validates :ref, presence: true

View File

@ -125,6 +125,10 @@ class Group < Namespace
self[:lfs_enabled]
end
def owned_by?(user)
owners.include?(user)
end
def add_users(users, access_level, current_user: nil, expires_at: nil)
GroupMember.add_users(
self,

View File

@ -12,8 +12,9 @@
# * (Optionally) add columns to `internal_ids` if needed for scope.
class InternalId < ActiveRecord::Base
belongs_to :project
belongs_to :namespace
enum usage: { issues: 0 }
enum usage: { issues: 0, merge_requests: 1, deployments: 2, milestones: 3, epics: 4 }
validates :usage, presence: true

View File

@ -194,6 +194,15 @@ class Issue < ActiveRecord::Base
branches_with_iid - branches_with_merge_request
end
def suggested_branch_name
return to_branch_name unless project.repository.branch_exists?(to_branch_name)
start_counting_from = 2
Uniquify.new(start_counting_from).string(-> (counter) { "#{to_branch_name}-#{counter}" }) do |suggested_branch_name|
project.repository.branch_exists?(suggested_branch_name)
end
end
# Returns boolean if a related branch exists for the current issue
# ignores merge requests branchs
def has_related_branch?
@ -248,11 +257,8 @@ class Issue < ActiveRecord::Base
end
end
def can_be_worked_on?(current_user)
!self.closed? &&
!self.project.forked? &&
self.related_branches(current_user).empty? &&
self.closed_by_merge_requests(current_user).empty?
def can_be_worked_on?
!self.closed? && !self.project.forked?
end
# Returns `true` if the current issue can be viewed by either a logged in User

View File

@ -1,5 +1,5 @@
class MergeRequest < ActiveRecord::Base
include NonatomicInternalId
include AtomicInternalId
include Issuable
include Noteable
include Referable
@ -18,6 +18,8 @@ class MergeRequest < ActiveRecord::Base
belongs_to :source_project, class_name: "Project"
belongs_to :merge_user, class_name: "User"
has_internal_id :iid, scope: :target_project, init: ->(s) { s&.target_project&.merge_requests&.maximum(:iid) }
has_many :merge_request_diffs
has_one :merge_request_diff,

View File

@ -8,7 +8,7 @@ class Milestone < ActiveRecord::Base
Started = MilestoneStruct.new('Started', '#started', -3)
include CacheMarkdownField
include NonatomicInternalId
include AtomicInternalId
include Sortable
include Referable
include StripAttribute
@ -21,6 +21,9 @@ class Milestone < ActiveRecord::Base
belongs_to :project
belongs_to :group
has_internal_id :iid, scope: :project, init: ->(s) { s&.project&.milestones&.maximum(:iid) }
has_internal_id :iid, scope: :group, init: ->(s) { s&.group&.milestones&.maximum(:iid) }
has_many :issues
has_many :labels, -> { distinct.reorder('labels.title') }, through: :issues
has_many :merge_requests

View File

@ -1879,6 +1879,10 @@ class Project < ActiveRecord::Base
[]
end
def gitlab_deploy_token
@gitlab_deploy_token ||= deploy_tokens.gitlab_deploy_token
end
private
def storage

View File

@ -1,5 +1,51 @@
require "flowdock-git-hook"
# Flow dock depends on Grit to compute the number of commits between two given
# commits. To make this depend on Gitaly, a monkey patch is applied
module Flowdock
class Git
# pass down a Repository all the way down
def repo
@options[:repo]
end
def config
{}
end
def messages
Git::Builder.new(repo: repo,
ref: @ref,
before: @from,
after: @to,
commit_url: @commit_url,
branch_url: @branch_url,
diff_url: @diff_url,
repo_url: @repo_url,
repo_name: @repo_name,
permanent_refs: @permanent_refs,
tags: tags
).to_hashes
end
class Builder
def commits
@repo.commits_between(@before, @after).map do |commit|
{
url: @opts[:commit_url] ? @opts[:commit_url] % [commit.sha] : nil,
id: commit.sha,
message: commit.message,
author: {
name: commit.author_name,
email: commit.author_email
}
}
end
end
end
end
end
class FlowdockService < Service
prop_accessor :token
validates :token, presence: true, if: :activated?
@ -34,7 +80,7 @@ class FlowdockService < Service
data[:before],
data[:after],
token: token,
repo: project.repository.path_to_repo,
repo: project.repository,
repo_url: "#{Gitlab.config.gitlab.url}/#{project.full_path}",
commit_url: "#{Gitlab.config.gitlab.url}/#{project.full_path}/commit/%s",
diff_url: "#{Gitlab.config.gitlab.url}/#{project.full_path}/compare/%s...%s"

View File

@ -22,7 +22,7 @@ class GroupPolicy < BasePolicy
condition(:can_change_parent_share_with_group_lock) { can?(:change_share_with_group_lock, @subject.parent) }
condition(:has_projects) do
GroupProjectsFinder.new(group: @subject, current_user: @user).execute.any?
GroupProjectsFinder.new(group: @subject, current_user: @user, options: { include_subgroups: true }).execute.any?
end
with_options scope: :subject, score: 0
@ -43,7 +43,11 @@ class GroupPolicy < BasePolicy
end
rule { admin } .enable :read_group
rule { has_projects } .enable :read_group
rule { has_projects }.policy do
enable :read_group
enable :read_label
end
rule { has_access }.enable :read_namespace

View File

@ -260,7 +260,7 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
if current_user && can?(current_user, :admin_pipeline, project) && repository.gitlab_ci_yml.blank? && !show_auto_devops_callout
OpenStruct.new(enabled: auto_devops_enabled?,
label: auto_devops_enabled? ? _('Auto DevOps enabled') : _('Enable Auto DevOps'),
link: project_settings_ci_cd_path(project, anchor: 'js-general-pipeline-settings'))
link: project_settings_ci_cd_path(project, anchor: 'autodevops-settings'))
elsif auto_devops_enabled?
OpenStruct.new(enabled: true,
label: _('Auto DevOps enabled'),

View File

@ -65,6 +65,10 @@ class GitlabUploader < CarrierWave::Uploader::Base
!!model
end
def local_url
File.join('/', self.class.base_dir, dynamic_segment, filename)
end
private
# Designed to be overridden by child uploaders that have a dynamic path

View File

@ -21,7 +21,7 @@
.help-block
Manage repository storage paths. Learn more in the
= succeed "." do
= link_to "repository storages documentation", help_page_path("administration/repository_storages")
= link_to "repository storages documentation", help_page_path("administration/repository_storage_paths")
.sub-section
%h4 Circuit breaker
.form-group

View File

@ -22,7 +22,7 @@
%hr
%p
- link_to_auto_devops_settings = link_to(s_('AutoDevOps|enable Auto DevOps (Beta)'), project_settings_ci_cd_path(@project, anchor: 'js-general-pipeline-settings'))
- link_to_auto_devops_settings = link_to(s_('AutoDevOps|enable Auto DevOps (Beta)'), project_settings_ci_cd_path(@project, anchor: 'autodevops-settings'))
- link_to_add_kubernetes_cluster = link_to(s_('AutoDevOps|add a Kubernetes cluster'), new_project_cluster_path(@project))
= s_('AutoDevOps|You can automatically build and test your application if you %{link_to_auto_devops_settings} for this project. You can automatically deploy it as well, if you %{link_to_add_kubernetes_cluster}.').html_safe % { link_to_auto_devops_settings: link_to_auto_devops_settings, link_to_add_kubernetes_cluster: link_to_add_kubernetes_cluster }

View File

@ -15,7 +15,7 @@
- unless @repository.gitlab_ci_yml
= link_to 'Get started with Pipelines', help_page_path('ci/quick_start/README'), class: 'btn btn-info'
= link_to ci_lint_path, class: 'btn btn-default' do
= link_to project_ci_lint_path(@project), class: 'btn btn-default' do
%span CI lint
.content-list.builds-content-list

View File

@ -26,7 +26,7 @@
%ul
- pipeline.yaml_errors.split(",").each do |error|
%li= error
You can also test your .gitlab-ci.yml in the #{link_to "Lint", ci_lint_path}
You can also test your .gitlab-ci.yml in the #{link_to "Lint", project_ci_lint_path(@project)}
- if pipeline.project.builds_enabled? && !pipeline.ci_yaml_file
.bs-callout.bs-callout-warning

View File

@ -0,0 +1,40 @@
.row.prepend-top-default
.col-lg-12
= form_for @project, url: project_settings_ci_cd_path(@project) do |f|
= form_errors(@project)
%fieldset.builds-feature
.form-group
- message = auto_devops_warning_message(@project)
- ci_file_formatted = '<code>.gitlab-ci.yml</code>'.html_safe
- if message
%p.settings-message.text-center
= message.html_safe
= f.fields_for :auto_devops_attributes, @auto_devops do |form|
.radio
= form.label :enabled_true do
= form.radio_button :enabled, 'true'
%strong= s_('CICD|Enable Auto DevOps')
%br
= s_('CICD|The Auto DevOps pipeline configuration will be used when there is no %{ci_file} in the project.').html_safe % { ci_file: ci_file_formatted }
.radio
= form.label :enabled_false do
= form.radio_button :enabled, 'false'
%strong= s_('CICD|Disable Auto DevOps')
%br
= s_('CICD|An explicit %{ci_file} needs to be specified before you can begin using Continuous Integration and Delivery.').html_safe % { ci_file: ci_file_formatted }
.radio
= form.label :enabled_ do
= form.radio_button :enabled, ''
%strong= s_('CICD|Instance default (%{state})') % { state: "#{Gitlab::CurrentSettings.auto_devops_enabled? ? _('enabled') : _('disabled')}" }
%br
= s_('CICD|Follow the instance default to either have Auto DevOps enabled or disabled when there is no project specific %{ci_file}.').html_safe % { ci_file: ci_file_formatted }
= form.label :domain, class:"prepend-top-10" do
= _('Domain')
= form.text_field :domain, class: 'form-control', placeholder: 'domain.com'
.help-block
= s_('CICD|You need to specify a domain if you want to use Auto Review Apps and Auto Deploy stages.')
= f.submit 'Save changes', class: "btn btn-success prepend-top-15"

View File

@ -3,44 +3,6 @@
= form_for @project, url: project_settings_ci_cd_path(@project) do |f|
= form_errors(@project)
%fieldset.builds-feature
.form-group
%h5 Auto DevOps (Beta)
%p
Auto DevOps will automatically build, test, and deploy your application based on a predefined Continuous Integration and Delivery configuration.
= link_to 'Learn more about Auto DevOps', help_page_path('topics/autodevops/index.md')
- message = auto_devops_warning_message(@project)
- if message
%p.settings-message.text-center
= message.html_safe
= f.fields_for :auto_devops_attributes, @auto_devops do |form|
.radio
= form.label :enabled_true do
= form.radio_button :enabled, 'true'
%strong Enable Auto DevOps
%br
%span.descr
The Auto DevOps pipeline configuration will be used when there is no <code>.gitlab-ci.yml</code> in the project.
.radio
= form.label :enabled_false do
= form.radio_button :enabled, 'false'
%strong Disable Auto DevOps
%br
%span.descr
An explicit <code>.gitlab-ci.yml</code> needs to be specified before you can begin using Continuous Integration and Delivery.
.radio
= form.label :enabled_ do
= form.radio_button :enabled, ''
%strong Instance default (#{Gitlab::CurrentSettings.auto_devops_enabled? ? 'enabled' : 'disabled'})
%br
%span.descr
Follow the instance default to either have Auto DevOps enabled or disabled when there is no project specific <code>.gitlab-ci.yml</code>.
%p
You need to specify a domain if you want to use Auto Review Apps and Auto Deploy stages.
= form.text_field :domain, class: 'form-control', placeholder: 'domain.com'
%hr
.form-group.append-bottom-default.js-secret-runner-token
= f.label :runners_token, "Runner token", class: 'label-light'
.form-control.js-secret-value-placeholder

View File

@ -12,10 +12,22 @@
%button.btn.js-settings-toggle{ type: 'button' }
= expanded ? 'Collapse' : 'Expand'
%p
Update your CI/CD configuration, like job timeout or Auto DevOps.
Access your runner token, customize your pipeline configuration, and view your pipeline status and coverage report.
.settings-content
= render 'form'
%section.settings#autodevops-settings.no-animate{ class: ('expanded' if expanded) }
.settings-header
%h4
= s_('CICD|Auto DevOps (Beta)')
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
= expanded ? _('Collapse') : _('Expand')
%p
= s_('CICD|Auto DevOps will automatically build, test, and deploy your application based on a predefined Continuous Integration and Delivery configuration.')
= link_to s_('CICD|Learn more about Auto DevOps'), help_page_path('topics/autodevops/index.md')
.settings-content
= render 'autodevops_form'
%section.settings.no-animate{ class: ('expanded' if expanded) }
.settings-header
%h4

View File

@ -9,7 +9,7 @@
- link = link_to(s_('AutoDevOps|Auto DevOps documentation'), help_page_path('topics/autodevops/index.md'), target: '_blank', rel: 'noopener noreferrer')
= s_('AutoDevOps|Learn more in the %{link_to_documentation}').html_safe % { link_to_documentation: link }
.banner-buttons
= link_to s_('AutoDevOps|Enable in settings'), project_settings_ci_cd_path(@project, anchor: 'js-general-pipeline-settings'), class: 'btn js-close-callout'
= link_to s_('AutoDevOps|Enable in settings'), project_settings_ci_cd_path(@project, anchor: 'autodevops-settings'), class: 'btn js-close-callout'
%button.btn-transparent.banner-close.close.js-close-callout{ type: 'button',
'aria-label' => 'Dismiss Auto DevOps box' }

View File

@ -1,5 +0,0 @@
---
title: Enable restore rake task to handle nested storage directories
merge_request: 17516
author: Balasankar C
type: fixed

View File

@ -1,5 +0,0 @@
---
title: Add support for patch link extension for commit links on GitLab Flavored Markdown
merge_request:
author:
type: added

View File

@ -1,5 +0,0 @@
---
title: Include matching branches and tags in protected branches / tags count
merge_request:
author: Jan Beckmann
type: fixed

View File

@ -1,5 +0,0 @@
---
title: Send notification emails when push to a merge request
merge_request: 7610
author: YarNayar
type: feature

View File

@ -1,5 +0,0 @@
---
title: Adds cancel btn to new pages domain page
merge_request: 18026
author: Jacopo Beschi @jacopo-beschi
type: added

View File

@ -1,5 +0,0 @@
---
title: Atomic generation of internal ids for issues.
merge_request: 17580
author:
type: other

View File

@ -1,5 +0,0 @@
---
title: Create Deploy Tokens to allow permanent access to repository and registry
merge_request: 17894
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Prevent pipeline actions in dropdown to redirct to a new page
merge_request:
author:
type: fixed

View File

@ -1,5 +0,0 @@
---
title: Drop JSON response in Project Milestone along with avoiding error
merge_request: 17977
author: Takuya Noguchi
type: fixed

View File

@ -1,5 +0,0 @@
---
title: Fix generated URL when listing repoitories for import
merge_request: 17692
author:
type: fixed

View File

@ -1,5 +0,0 @@
---
title: lazy load diffs on merge request discussions
merge_request:
author:
type: performance

View File

@ -1,5 +0,0 @@
---
title: Fixed bug in dropdown selector when selecting the same selection again
merge_request: 14631
author: bitsapien
type: fixed

View File

@ -1,5 +0,0 @@
---
title: Apply NestingDepth (level 5) (framework/dropdowns.scss)
merge_request: 17820
author: Takuya Noguchi
type: other

View File

@ -1,5 +0,0 @@
---
title: 'API: Add parameter merge_method to projects'
merge_request: 18031
author: Jan Beckmann
type: added

View File

@ -1,5 +0,0 @@
---
title: Add object storage support for LFS objects, CI artifacts, and uploads.
merge_request: 17358
author:
type: added

View File

@ -1,5 +0,0 @@
---
title: Increase dropdown width in pipeline graph & center action icon
merge_request: 18089
author:
type: fixed

View File

@ -1,5 +0,0 @@
---
title: 'Introduce simpler env vars for auto devops REPLICAS and CANARY_REPLICAS #41436'
merge_request: 18036
author:
type: added

View File

@ -1,5 +0,0 @@
---
title: Added confirmation modal for changing username
merge_request: 17405
author:
type: added

View File

@ -1,5 +0,0 @@
---
title: Adds the option to the project export API to override the project description and display GitLab export description once imported
merge_request: 17744
author:
type: added

View File

@ -1,5 +0,0 @@
---
title: adds closed by informations in issue api
merge_request: 17042
author: haseebeqx
type: added

View File

@ -1,5 +0,0 @@
---
title: Fix XSS on diff view stored on filenames
merge_request:
author:
type: security

View File

@ -1,5 +0,0 @@
---
title: Long instance urls do not overflow anymore during project creation
merge_request: 17717
author:
type: fixed

View File

@ -1,6 +0,0 @@
---
title: Improved visual styles and consistency for commit hash and possible actions
across commit lists
merge_request: 17406
author:
type: changed

View File

@ -1,5 +0,0 @@
---
title: Improve empty state for canceled job
merge_request: 17646
author:
type: fixed

View File

@ -1,5 +0,0 @@
---
title: Fix hover style of dropdown items in the right sidebar
merge_request: 17519
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Show new branch/mr button even when branch exists
merge_request: 17712
author: Jacopo Beschi @jacopo-beschi
type: added

View File

@ -1,5 +0,0 @@
---
title: Fix Firefox stealing formatting characters on issue notes
merge_request:
author:
type: fixed

View File

@ -0,0 +1,6 @@
---
title: Fix discussions API setting created_at for notable in a group or notable in
a project in a group with owners
merge_request: 18464
author:
type: fixed

View File

@ -1,5 +0,0 @@
---
title: Improve performance of loading issues with lots of references to merge requests
merge_request: 17986
author:
type: performance

View File

@ -1,5 +0,0 @@
---
title: Polish design for verifying domains
merge_request: 17767
author:
type: changed

View File

@ -1,6 +0,0 @@
---
title: Require at least one filter when listing issues or merge requests on dashboard
page
merge_request:
author:
type: performance

View File

@ -1,5 +0,0 @@
---
title: Use specific names for filtered CI variable controller parameters
merge_request: 17796
author:
type: other

View File

@ -0,0 +1,5 @@
---
title: Create settings section for autodevops
merge_request: 18321
author:
type: changed

View File

@ -1,5 +0,0 @@
---
title: Add empty repo check before running AutoDevOps pipeline
merge_request: 17605
author:
type: changed

View File

@ -1,5 +0,0 @@
---
title: Adds support for OmniAuth JWT provider
merge_request: 17774
author:
type: added

View File

@ -1,5 +0,0 @@
---
title: Limit the number of failed logins when using LDAP for authentication
merge_request: 43525
author:
type: added

View File

@ -1,5 +0,0 @@
---
title: Improves the performance of projects list page
merge_request: 17934
author:
type: performance

View File

@ -1,5 +0,0 @@
---
title: Move ci/lint under project's namespace
merge_request: 17729
author:
type: added

View File

@ -1,5 +0,0 @@
---
title: Update wording to specify create/manage project vs group labels in labels dropdown
merge_request: 17640
author:
type: changed

View File

@ -1,5 +0,0 @@
---
title: Set breadcrumb for admin/runners/show
merge_request: 17431
author: Takuya Noguchi
type: fixed

View File

@ -1,6 +0,0 @@
---
title: Update documentation to reflect current minimum required versions of node and
yarn
merge_request: 17706
author:
type: other

View File

@ -1,5 +0,0 @@
---
title: Store sha256 checksum of artifact metadata
merge_request: 18149
author:
type: added

Some files were not shown because too many files have changed in this diff Show More