Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Léo-Paul Géneau
gitlab-ce
Commits
c1fc5da1
Commit
c1fc5da1
authored
Feb 19, 2020
by
GitLab Bot
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add latest changes from gitlab-org/gitlab@master
parent
82a708b9
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
244 additions
and
449 deletions
+244
-449
app/assets/javascripts/create_merge_request_dropdown.js
app/assets/javascripts/create_merge_request_dropdown.js
+3
-5
app/assets/javascripts/vue_shared/components/markdown/toolbar.vue
...ts/javascripts/vue_shared/components/markdown/toolbar.vue
+3
-4
app/services/audit_event_service.rb
app/services/audit_event_service.rb
+24
-1
app/views/projects/issues/_new_branch.html.haml
app/views/projects/issues/_new_branch.html.haml
+1
-1
changelogs/unreleased/202274-migrate-fa-spinner-to-spinner.yml
...elogs/unreleased/202274-migrate-fa-spinner-to-spinner.yml
+5
-0
changelogs/unreleased/rk4bir-master-patch-85217.yml
changelogs/unreleased/rk4bir-master-patch-85217.yml
+5
-0
changelogs/unreleased/sh-avoid-current-settings-rake-task.yml
...gelogs/unreleased/sh-avoid-current-settings-rake-task.yml
+5
-0
config/initializers/1_settings.rb
config/initializers/1_settings.rb
+1
-1
config/initializers/sidekiq.rb
config/initializers/sidekiq.rb
+4
-0
config/settings.rb
config/settings.rb
+6
-0
lib/gitlab/ci/templates/Jobs/Test.gitlab-ci.yml
lib/gitlab/ci/templates/Jobs/Test.gitlab-ci.yml
+6
-4
lib/gitlab/jira/http_client.rb
lib/gitlab/jira/http_client.rb
+6
-1
spec/config/settings_spec.rb
spec/config/settings_spec.rb
+6
-0
spec/frontend/create_merge_request_dropdown_spec.js
spec/frontend/create_merge_request_dropdown_spec.js
+1
-1
spec/frontend/environments/environments_app_spec.js
spec/frontend/environments/environments_app_spec.js
+168
-0
spec/javascripts/environments/environments_app_spec.js
spec/javascripts/environments/environments_app_spec.js
+0
-279
spec/javascripts/environments/mock_data.js
spec/javascripts/environments/mock_data.js
+0
-66
spec/lib/gitlab/ci/templates/Jobs/test_gitlab_ci_yaml_spec.rb
.../lib/gitlab/ci/templates/Jobs/test_gitlab_ci_yaml_spec.rb
+0
-86
No files found.
app/assets/javascripts/create_merge_request_dropdown.js
View file @
c1fc5da1
...
...
@@ -42,7 +42,7 @@ export default class CreateMergeRequestDropdown {
this
.
refInput
=
this
.
wrapperEl
.
querySelector
(
'
.js-ref
'
);
this
.
refMessage
=
this
.
wrapperEl
.
querySelector
(
'
.js-ref-message
'
);
this
.
unavailableButton
=
this
.
wrapperEl
.
querySelector
(
'
.unavailable
'
);
this
.
unavailableButtonArrow
=
this
.
unavailableButton
.
querySelector
(
'
.
fa
'
);
this
.
unavailableButtonArrow
=
this
.
unavailableButton
.
querySelector
(
'
.
spinner
'
);
this
.
unavailableButtonText
=
this
.
unavailableButton
.
querySelector
(
'
.text
'
);
this
.
branchCreated
=
false
;
...
...
@@ -417,13 +417,11 @@ export default class CreateMergeRequestDropdown {
setUnavailableButtonState
(
isLoading
=
true
)
{
if
(
isLoading
)
{
this
.
unavailableButtonArrow
.
classList
.
add
(
'
fa-spin
'
);
this
.
unavailableButtonArrow
.
classList
.
add
(
'
fa-spinner
'
);
this
.
unavailableButtonArrow
.
classList
.
remove
(
'
hide
'
);
this
.
unavailableButtonArrow
.
classList
.
remove
(
'
fa-exclamation-triangle
'
);
this
.
unavailableButtonText
.
textContent
=
__
(
'
Checking branch availability...
'
);
}
else
{
this
.
unavailableButtonArrow
.
classList
.
remove
(
'
fa-spin
'
);
this
.
unavailableButtonArrow
.
classList
.
remove
(
'
fa-spinner
'
);
this
.
unavailableButtonArrow
.
classList
.
add
(
'
hide
'
);
this
.
unavailableButtonArrow
.
classList
.
add
(
'
fa-exclamation-triangle
'
);
this
.
unavailableButtonText
.
textContent
=
__
(
'
New branch unavailable
'
);
}
...
...
app/assets/javascripts/vue_shared/components/markdown/toolbar.vue
View file @
c1fc5da1
<
script
>
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
import
{
GlLink
}
from
'
@gitlab/ui
'
;
import
{
GlLink
,
GlLoadingIcon
}
from
'
@gitlab/ui
'
;
export
default
{
components
:
{
GlLink
,
GlLoadingIcon
,
},
props
:
{
markdownDocsPath
:
{
...
...
@@ -54,9 +55,7 @@ export default {
<i
class=
"fa fa-file-image-o toolbar-button-icon"
aria-hidden=
"true"
></i>
<span
class=
"attaching-file-message"
></span>
<span
class=
"uploading-progress"
>
0%
</span>
<span
class=
"uploading-spinner"
>
<i
class=
"fa fa-spinner fa-spin toolbar-button-icon"
aria-hidden=
"true"
></i>
</span>
<gl-loading-icon
inline
class=
"align-text-bottom"
/>
</span>
<span
class=
"uploading-error-container hide"
>
<span
class=
"uploading-error-icon"
>
...
...
app/services/audit_event_service.rb
View file @
c1fc5da1
# frozen_string_literal: true
class
AuditEventService
# Instantiates a new service
#
# @param author [User] the user who authors the change
# @param entity [Object] an instance of either Project/Group/User type. This
# param is also used to determine at which level the audit events are
# shown.
# - Project: events are visible at Project level
# - Group: events are visible at Group level
# - User: events are visible at Instance level
# @param details [Hash] details to be added to audit event
#
# @return [AuditEventService]
def
initialize
(
author
,
entity
,
details
=
{})
@author
,
@entity
,
@details
=
author
,
entity
,
details
@author
=
author
@entity
=
entity
@details
=
details
end
# Builds the @details attribute for authentication
#
# This uses the @author as the target object being changed
#
# @return [AuditEventService]
def
for_authentication
@details
=
{
with:
@details
[
:with
],
...
...
@@ -16,11 +35,15 @@ class AuditEventService
self
end
# Writes event to a file and creates an event record in DB
#
# @return [SecurityEvent] persited if saves and non-persisted if fails
def
security_event
log_security_event_to_file
log_security_event_to_database
end
# Writes event to a file
def
log_security_event_to_file
file_logger
.
info
(
base_payload
.
merge
(
formatted_details
))
end
...
...
app/views/projects/issues/_new_branch.html.haml
View file @
c1fc5da1
...
...
@@ -13,7 +13,7 @@
.create-mr-dropdown-wrap.d-inline-block.full-width-mobile.js-create-mr
{
data:
{
project_path:
@project
.
full_path
,
project_id:
@project
.
id
,
can_create_path:
can_create_path
,
create_mr_path:
create_mr_path
,
create_branch_path:
create_branch_path
,
refs_path:
refs_path
,
is_confidential:
can_create_confidential_merge_request?
.
to_s
}
}
.btn-group.btn-group-sm.unavailable
%button
.btn.btn-grouped
{
type:
'button'
,
disabled:
'disabled'
}
=
icon
(
'spinner'
,
class:
'fa-spin'
)
.spinner.align-text-bottom.mr-1.hide
%span
.text
Checking branch availability…
...
...
changelogs/unreleased/202274-migrate-fa-spinner-to-spinner.yml
0 → 100644
View file @
c1fc5da1
---
title
:
New loading spinner for attachemnt uploads via discussion boxes
merge_request
:
25057
author
:
Philip Jonas
type
:
changed
changelogs/unreleased/rk4bir-master-patch-85217.yml
0 → 100644
View file @
c1fc5da1
---
title
:
Migrated from .fa-spinner to .spinner in app/assets/javascripts/create_merge_request_dropdown.js
merge_request
:
24917
author
:
Raihan Kabir (gitlab/rk4bir)
type
:
changed
changelogs/unreleased/sh-avoid-current-settings-rake-task.yml
0 → 100644
View file @
c1fc5da1
---
title
:
Only load usage ping cron schedule for Sidekiq
merge_request
:
25325
author
:
type
:
other
config/initializers/1_settings.rb
View file @
c1fc5da1
...
...
@@ -446,7 +446,7 @@ Settings.cron_jobs['stuck_import_jobs_worker'] ||= Settingslogic.new({})
Settings
.
cron_jobs
[
'stuck_import_jobs_worker'
][
'cron'
]
||=
'15 * * * *'
Settings
.
cron_jobs
[
'stuck_import_jobs_worker'
][
'job_class'
]
=
'StuckImportJobsWorker'
Settings
.
cron_jobs
[
'gitlab_usage_ping_worker'
]
||=
Settingslogic
.
new
({})
Settings
.
cron_jobs
[
'gitlab_usage_ping_worker'
][
'cron'
]
||=
Settings
.
__send__
(
:cron_for_usage_ping
)
Settings
.
cron_jobs
[
'gitlab_usage_ping_worker'
][
'cron'
]
||=
nil
# This is dynamically loaded in the sidekiq initializer
Settings
.
cron_jobs
[
'gitlab_usage_ping_worker'
][
'job_class'
]
=
'GitlabUsagePingWorker'
Settings
.
cron_jobs
[
'stuck_merge_jobs_worker'
]
||=
Settingslogic
.
new
({})
Settings
.
cron_jobs
[
'stuck_merge_jobs_worker'
][
'cron'
]
||=
'0 */2 * * *'
...
...
config/initializers/sidekiq.rb
View file @
c1fc5da1
# frozen_string_literal: true
require
'sidekiq/web'
def
enable_reliable_fetch?
...
...
@@ -71,6 +73,8 @@ Sidekiq.configure_server do |config|
Sidekiq
::
ReliableFetch
.
setup_reliable_fetch!
(
config
)
end
Gitlab
.
config
.
load_dynamic_cron_schedules!
# Sidekiq-cron: load recurring jobs from gitlab.yml
# UGLY Hack to get nested hash from settingslogic
cron_jobs
=
JSON
.
parse
(
Gitlab
.
config
.
cron_jobs
.
to_json
)
...
...
config/settings.rb
View file @
c1fc5da1
# frozen_string_literal: true
require
'settingslogic'
require
'digest/md5'
...
...
@@ -143,6 +145,10 @@ class Settings < Settingslogic
Gitlab
::
Application
.
secrets
.
db_key_base
end
def
load_dynamic_cron_schedules!
cron_jobs
[
'gitlab_usage_ping_worker'
][
'cron'
]
||=
cron_for_usage_ping
end
private
def
base_url
(
config
)
...
...
lib/gitlab/ci/templates/Jobs/Test.gitlab-ci.yml
View file @
c1fc5da1
...
...
@@ -15,7 +15,9 @@ test:
-
export DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${DB_HOST}:5432/${POSTGRES_DB}"
-
cp -R . /tmp/app
-
/bin/herokuish buildpack test
rules
:
-
if
:
'
$TEST_DISABLED'
when
:
never
-
if
:
'
$CI_COMMIT_TAG
||
$CI_COMMIT_BRANCH'
only
:
-
branches
-
tags
except
:
variables
:
-
$TEST_DISABLED
lib/gitlab/jira/http_client.rb
View file @
c1fc5da1
...
...
@@ -12,7 +12,12 @@ module Gitlab
def
request
(
*
args
)
result
=
make_request
(
*
args
)
raise
JIRA
::
HTTPError
.
new
(
result
.
response
)
unless
result
.
response
.
is_a?
(
Net
::
HTTPSuccess
)
unless
result
.
response
.
is_a?
(
Net
::
HTTPSuccess
)
Gitlab
::
ErrorTracking
.
track_and_raise_exception
(
JIRA
::
HTTPError
.
new
(
result
.
response
),
response_body:
result
.
body
)
end
result
end
...
...
spec/config/settings_spec.rb
View file @
c1fc5da1
...
...
@@ -9,6 +9,12 @@ describe Settings do
end
end
describe
'.load_dynamic_cron_schedules!'
do
it
'generates a valid cron schedule'
do
expect
(
Fugit
::
Cron
.
parse
(
described_class
.
load_dynamic_cron_schedules!
)).
to
be_a
(
Fugit
::
Cron
)
end
end
describe
'.attr_encrypted_db_key_base_truncated'
do
it
'is a string with maximum 32 bytes size'
do
expect
(
described_class
.
attr_encrypted_db_key_base_truncated
.
bytesize
)
...
...
spec/frontend/create_merge_request_dropdown_spec.js
View file @
c1fc5da1
...
...
@@ -15,7 +15,7 @@ describe('CreateMergeRequestDropdown', () => {
<div id="dummy-wrapper-element">
<div class="available"></div>
<div class="unavailable">
<div class="
fa
"></div>
<div class="
spinner
"></div>
<div class="text"></div>
</div>
<div class="js-ref"></div>
...
...
spec/frontend/environments/environments_app_spec.js
0 → 100644
View file @
c1fc5da1
import
{
mount
,
shallowMount
}
from
'
@vue/test-utils
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
Container
from
'
~/environments/components/container.vue
'
;
import
EmptyState
from
'
~/environments/components/empty_state.vue
'
;
import
EnvironmentsApp
from
'
~/environments/components/environments_app.vue
'
;
import
{
environment
,
folder
}
from
'
./mock_data
'
;
describe
(
'
Environment
'
,
()
=>
{
let
mock
;
let
wrapper
;
const
mockData
=
{
endpoint
:
'
environments.json
'
,
canCreateEnvironment
:
true
,
canReadEnvironment
:
true
,
newEnvironmentPath
:
'
environments/new
'
,
helpPagePath
:
'
help
'
,
canaryDeploymentFeatureId
:
'
canary_deployment
'
,
showCanaryDeploymentCallout
:
true
,
userCalloutsPath
:
'
/callouts
'
,
lockPromotionSvgPath
:
'
/assets/illustrations/lock-promotion.svg
'
,
helpCanaryDeploymentsPath
:
'
help/canary-deployments
'
,
};
const
mockRequest
=
(
response
,
body
)
=>
{
mock
.
onGet
(
mockData
.
endpoint
).
reply
(
response
,
body
,
{
'
X-nExt-pAge
'
:
'
2
'
,
'
x-page
'
:
'
1
'
,
'
X-Per-Page
'
:
'
1
'
,
'
X-Prev-Page
'
:
''
,
'
X-TOTAL
'
:
'
37
'
,
'
X-Total-Pages
'
:
'
2
'
,
});
};
const
createWrapper
=
(
shallow
=
false
)
=>
{
const
fn
=
shallow
?
shallowMount
:
mount
;
wrapper
=
fn
(
EnvironmentsApp
,
{
propsData
:
mockData
});
return
axios
.
waitForAll
();
};
beforeEach
(()
=>
{
mock
=
new
MockAdapter
(
axios
);
});
afterEach
(()
=>
{
wrapper
.
destroy
();
mock
.
restore
();
});
describe
(
'
successful request
'
,
()
=>
{
describe
(
'
without environments
'
,
()
=>
{
beforeEach
(()
=>
{
mockRequest
(
200
,
{
environments
:
[]
});
return
createWrapper
(
true
);
});
it
(
'
should render the empty state
'
,
()
=>
{
expect
(
wrapper
.
find
(
EmptyState
).
exists
()).
toBe
(
true
);
});
describe
(
'
when it is possible to enable a review app
'
,
()
=>
{
beforeEach
(()
=>
{
mockRequest
(
200
,
{
environments
:
[],
review_app
:
{
can_setup_review_app
:
true
}
});
return
createWrapper
();
});
it
(
'
should render the enable review app button
'
,
()
=>
{
expect
(
wrapper
.
find
(
'
.js-enable-review-app-button
'
).
text
()).
toContain
(
'
Enable review app
'
,
);
});
});
});
describe
(
'
with paginated environments
'
,
()
=>
{
const
environmentList
=
[
environment
];
beforeEach
(()
=>
{
mockRequest
(
200
,
{
environments
:
environmentList
,
stopped_count
:
1
,
available_count
:
0
,
});
return
createWrapper
();
});
it
(
'
should render a conatiner table with environments
'
,
()
=>
{
const
containerTable
=
wrapper
.
find
(
Container
);
expect
(
containerTable
.
exists
()).
toBe
(
true
);
expect
(
containerTable
.
props
(
'
environments
'
).
length
).
toEqual
(
environmentList
.
length
);
expect
(
containerTable
.
find
(
'
.environment-name
'
).
text
()).
toEqual
(
environmentList
[
0
].
name
);
});
describe
(
'
pagination
'
,
()
=>
{
it
(
'
should render pagination
'
,
()
=>
{
expect
(
wrapper
.
findAll
(
'
.gl-pagination li
'
).
length
).
toEqual
(
9
);
});
it
(
'
should make an API request when page is clicked
'
,
()
=>
{
jest
.
spyOn
(
wrapper
.
vm
,
'
updateContent
'
).
mockImplementation
(()
=>
{});
wrapper
.
find
(
'
.gl-pagination li:nth-child(3) .page-link
'
).
trigger
(
'
click
'
);
expect
(
wrapper
.
vm
.
updateContent
).
toHaveBeenCalledWith
({
scope
:
'
available
'
,
page
:
'
2
'
});
});
it
(
'
should make an API request when using tabs
'
,
()
=>
{
jest
.
spyOn
(
wrapper
.
vm
,
'
updateContent
'
).
mockImplementation
(()
=>
{});
wrapper
.
find
(
'
.js-environments-tab-stopped
'
).
trigger
(
'
click
'
);
expect
(
wrapper
.
vm
.
updateContent
).
toHaveBeenCalledWith
({
scope
:
'
stopped
'
,
page
:
'
1
'
});
});
});
});
});
describe
(
'
unsuccessful request
'
,
()
=>
{
beforeEach
(()
=>
{
mockRequest
(
500
,
{});
return
createWrapper
(
true
);
});
it
(
'
should render empty state
'
,
()
=>
{
expect
(
wrapper
.
find
(
EmptyState
).
exists
()).
toBe
(
true
);
});
});
describe
(
'
expandable folders
'
,
()
=>
{
beforeEach
(()
=>
{
mockRequest
(
200
,
{
environments
:
[
folder
],
stopped_count
:
1
,
available_count
:
0
,
});
mock
.
onGet
(
environment
.
folder_path
).
reply
(
200
,
{
environments
:
[
environment
]
});
return
createWrapper
().
then
(()
=>
{
// open folder
wrapper
.
find
(
'
.folder-name
'
).
trigger
(
'
click
'
);
return
axios
.
waitForAll
();
});
});
it
(
'
should open a closed folder
'
,
()
=>
{
expect
(
wrapper
.
find
(
'
.folder-icon.ic-chevron-right
'
).
exists
()).
toBe
(
false
);
});
it
(
'
should close an opened folder
'
,
()
=>
{
expect
(
wrapper
.
find
(
'
.folder-icon.ic-chevron-down
'
).
exists
()).
toBe
(
true
);
// close folder
wrapper
.
find
(
'
.folder-name
'
).
trigger
(
'
click
'
);
wrapper
.
vm
.
$nextTick
(()
=>
{
expect
(
wrapper
.
find
(
'
.folder-icon.ic-chevron-down
'
).
exists
()).
toBe
(
false
);
});
});
it
(
'
should show children environments
'
,
()
=>
{
expect
(
wrapper
.
findAll
(
'
.js-child-row
'
).
length
).
toEqual
(
1
);
});
it
(
'
should show a button to show all environments
'
,
()
=>
{
expect
(
wrapper
.
find
(
'
.text-center > a.btn
'
).
text
()).
toContain
(
'
Show all
'
);
});
});
});
spec/javascripts/environments/environments_app_spec.js
deleted
100644 → 0
View file @
82a708b9
import
Vue
from
'
vue
'
;
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
mountComponent
from
'
spec/helpers/vue_mount_component_helper
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
environmentsComponent
from
'
~/environments/components/environments_app.vue
'
;
import
{
environment
,
folder
}
from
'
./mock_data
'
;
describe
(
'
Environment
'
,
()
=>
{
const
mockData
=
{
endpoint
:
'
environments.json
'
,
canCreateEnvironment
:
true
,
canReadEnvironment
:
true
,
newEnvironmentPath
:
'
environments/new
'
,
helpPagePath
:
'
help
'
,
canaryDeploymentFeatureId
:
'
canary_deployment
'
,
showCanaryDeploymentCallout
:
true
,
userCalloutsPath
:
'
/callouts
'
,
lockPromotionSvgPath
:
'
/assets/illustrations/lock-promotion.svg
'
,
helpCanaryDeploymentsPath
:
'
help/canary-deployments
'
,
};
let
EnvironmentsComponent
;
let
component
;
let
mock
;
beforeEach
(()
=>
{
mock
=
new
MockAdapter
(
axios
);
EnvironmentsComponent
=
Vue
.
extend
(
environmentsComponent
);
});
afterEach
(()
=>
{
component
.
$destroy
();
mock
.
restore
();
});
describe
(
'
successful request
'
,
()
=>
{
describe
(
'
without environments
'
,
()
=>
{
beforeEach
(
done
=>
{
mock
.
onGet
(
mockData
.
endpoint
).
reply
(
200
,
{
environments
:
[]
});
component
=
mountComponent
(
EnvironmentsComponent
,
mockData
);
setTimeout
(()
=>
{
done
();
},
0
);
});
it
(
'
should render the empty state
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.js-new-environment-button
'
).
textContent
).
toContain
(
'
New environment
'
,
);
expect
(
component
.
$el
.
querySelector
(
'
.js-blank-state-title
'
).
textContent
).
toContain
(
"
You don't have any environments right now
"
,
);
});
describe
(
'
when it is possible to enable a review app
'
,
()
=>
{
beforeEach
(
done
=>
{
mock
.
onGet
(
mockData
.
endpoint
)
.
reply
(
200
,
{
environments
:
[],
review_app
:
{
can_setup_review_app
:
true
}
});
component
=
mountComponent
(
EnvironmentsComponent
,
mockData
);
setTimeout
(()
=>
{
done
();
},
0
);
});
it
(
'
should render the enable review app button
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.js-enable-review-app-button
'
).
textContent
).
toContain
(
'
Enable review app
'
,
);
});
});
});
describe
(
'
with paginated environments
'
,
()
=>
{
beforeEach
(
done
=>
{
mock
.
onGet
(
mockData
.
endpoint
).
reply
(
200
,
{
environments
:
[
environment
],
stopped_count
:
1
,
available_count
:
0
,
},
{
'
X-nExt-pAge
'
:
'
2
'
,
'
x-page
'
:
'
1
'
,
'
X-Per-Page
'
:
'
1
'
,
'
X-Prev-Page
'
:
''
,
'
X-TOTAL
'
:
'
37
'
,
'
X-Total-Pages
'
:
'
2
'
,
},
);
component
=
mountComponent
(
EnvironmentsComponent
,
mockData
);
setTimeout
(()
=>
{
done
();
},
0
);
});
it
(
'
should render a table with environments
'
,
()
=>
{
expect
(
component
.
$el
.
querySelectorAll
(
'
table
'
)).
not
.
toBeNull
();
expect
(
component
.
$el
.
querySelector
(
'
.environment-name
'
).
textContent
.
trim
()).
toEqual
(
environment
.
name
,
);
});
describe
(
'
pagination
'
,
()
=>
{
it
(
'
should render pagination
'
,
()
=>
{
expect
(
component
.
$el
.
querySelectorAll
(
'
.gl-pagination li
'
).
length
).
toEqual
(
9
);
});
it
(
'
should make an API request when page is clicked
'
,
done
=>
{
spyOn
(
component
,
'
updateContent
'
);
setTimeout
(()
=>
{
component
.
$el
.
querySelector
(
'
.gl-pagination li:nth-child(3) .page-link
'
).
click
();
expect
(
component
.
updateContent
).
toHaveBeenCalledWith
({
scope
:
'
available
'
,
page
:
'
2
'
});
done
();
},
0
);
});
it
(
'
should make an API request when using tabs
'
,
done
=>
{
setTimeout
(()
=>
{
spyOn
(
component
,
'
updateContent
'
);
component
.
$el
.
querySelector
(
'
.js-environments-tab-stopped
'
).
click
();
expect
(
component
.
updateContent
).
toHaveBeenCalledWith
({
scope
:
'
stopped
'
,
page
:
'
1
'
});
done
();
},
0
);
});
});
});
});
describe
(
'
unsuccessfull request
'
,
()
=>
{
beforeEach
(
done
=>
{
mock
.
onGet
(
mockData
.
endpoint
).
reply
(
500
,
{});
component
=
mountComponent
(
EnvironmentsComponent
,
mockData
);
setTimeout
(()
=>
{
done
();
},
0
);
});
it
(
'
should render empty state
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.js-blank-state-title
'
).
textContent
).
toContain
(
"
You don't have any environments right now
"
,
);
});
});
describe
(
'
expandable folders
'
,
()
=>
{
beforeEach
(()
=>
{
mock
.
onGet
(
mockData
.
endpoint
).
reply
(
200
,
{
environments
:
[
folder
],
stopped_count
:
0
,
available_count
:
1
,
},
{
'
X-nExt-pAge
'
:
'
2
'
,
'
x-page
'
:
'
1
'
,
'
X-Per-Page
'
:
'
1
'
,
'
X-Prev-Page
'
:
''
,
'
X-TOTAL
'
:
'
37
'
,
'
X-Total-Pages
'
:
'
2
'
,
},
);
mock
.
onGet
(
environment
.
folder_path
).
reply
(
200
,
{
environments
:
[
environment
]
});
component
=
mountComponent
(
EnvironmentsComponent
,
mockData
);
});
it
(
'
should open a closed folder
'
,
done
=>
{
setTimeout
(()
=>
{
component
.
$el
.
querySelector
(
'
.folder-name
'
).
click
();
Vue
.
nextTick
(()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.folder-icon.ic-chevron-right
'
)).
toBe
(
null
);
done
();
});
},
0
);
});
it
(
'
should close an opened folder
'
,
done
=>
{
setTimeout
(()
=>
{
// open folder
component
.
$el
.
querySelector
(
'
.folder-name
'
).
click
();
Vue
.
nextTick
(()
=>
{
// close folder
component
.
$el
.
querySelector
(
'
.folder-name
'
).
click
();
Vue
.
nextTick
(()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.folder-icon.ic-chevron-down
'
)).
toBe
(
null
);
done
();
});
});
},
0
);
});
it
(
'
should show children environments and a button to show all environments
'
,
done
=>
{
setTimeout
(()
=>
{
// open folder
component
.
$el
.
querySelector
(
'
.folder-name
'
).
click
();
Vue
.
nextTick
(()
=>
{
// wait for next async request
setTimeout
(()
=>
{
expect
(
component
.
$el
.
querySelectorAll
(
'
.js-child-row
'
).
length
).
toEqual
(
1
);
expect
(
component
.
$el
.
querySelector
(
'
.text-center > a.btn
'
).
textContent
).
toContain
(
'
Show all
'
,
);
done
();
});
});
},
0
);
});
});
describe
(
'
methods
'
,
()
=>
{
beforeEach
(()
=>
{
mock
.
onGet
(
mockData
.
endpoint
).
reply
(
200
,
{
environments
:
[],
stopped_count
:
0
,
available_count
:
1
,
},
{},
);
component
=
mountComponent
(
EnvironmentsComponent
,
mockData
);
spyOn
(
window
.
history
,
'
pushState
'
).
and
.
stub
();
});
describe
(
'
updateContent
'
,
()
=>
{
it
(
'
should set given parameters
'
,
done
=>
{
component
.
updateContent
({
scope
:
'
stopped
'
,
page
:
'
3
'
})
.
then
(()
=>
{
expect
(
component
.
page
).
toEqual
(
'
3
'
);
expect
(
component
.
scope
).
toEqual
(
'
stopped
'
);
expect
(
component
.
requestData
.
scope
).
toEqual
(
'
stopped
'
);
expect
(
component
.
requestData
.
page
).
toEqual
(
'
3
'
);
done
();
})
.
catch
(
done
.
fail
);
});
});
describe
(
'
onChangeTab
'
,
()
=>
{
it
(
'
should set page to 1
'
,
()
=>
{
spyOn
(
component
,
'
updateContent
'
);
component
.
onChangeTab
(
'
stopped
'
);
expect
(
component
.
updateContent
).
toHaveBeenCalledWith
({
scope
:
'
stopped
'
,
page
:
'
1
'
});
});
});
describe
(
'
onChangePage
'
,
()
=>
{
it
(
'
should update page and keep scope
'
,
()
=>
{
spyOn
(
component
,
'
updateContent
'
);
component
.
onChangePage
(
4
);
expect
(
component
.
updateContent
).
toHaveBeenCalledWith
({
scope
:
component
.
scope
,
page
:
'
4
'
});
});
});
});
});
spec/javascripts/environments/mock_data.js
deleted
100644 → 0
View file @
82a708b9
export
const
environmentsList
=
[
{
name
:
'
DEV
'
,
size
:
1
,
id
:
7
,
state
:
'
available
'
,
external_url
:
null
,
environment_type
:
null
,
last_deployment
:
null
,
has_stop_action
:
false
,
environment_path
:
'
/root/review-app/environments/7
'
,
stop_path
:
'
/root/review-app/environments/7/stop
'
,
created_at
:
'
2017-01-31T10:53:46.894Z
'
,
updated_at
:
'
2017-01-31T10:53:46.894Z
'
,
},
{
folderName
:
'
build
'
,
size
:
5
,
id
:
12
,
name
:
'
build/update-README
'
,
state
:
'
available
'
,
external_url
:
null
,
environment_type
:
'
build
'
,
last_deployment
:
null
,
has_stop_action
:
false
,
environment_path
:
'
/root/review-app/environments/12
'
,
stop_path
:
'
/root/review-app/environments/12/stop
'
,
created_at
:
'
2017-02-01T19:42:18.400Z
'
,
updated_at
:
'
2017-02-01T19:42:18.400Z
'
,
},
];
export
const
environment
=
{
name
:
'
DEV
'
,
size
:
1
,
latest
:
{
id
:
7
,
name
:
'
DEV
'
,
state
:
'
available
'
,
external_url
:
null
,
environment_type
:
null
,
last_deployment
:
null
,
has_stop_action
:
false
,
environment_path
:
'
/root/review-app/environments/7
'
,
stop_path
:
'
/root/review-app/environments/7/stop
'
,
created_at
:
'
2017-01-31T10:53:46.894Z
'
,
updated_at
:
'
2017-01-31T10:53:46.894Z
'
,
folder_path
:
'
/root/review-app/environments/7
'
,
},
};
export
const
folder
=
{
folderName
:
'
build
'
,
size
:
5
,
id
:
12
,
name
:
'
build/update-README
'
,
state
:
'
available
'
,
external_url
:
null
,
environment_type
:
'
build
'
,
last_deployment
:
null
,
has_stop_action
:
false
,
environment_path
:
'
/root/review-app/environments/12
'
,
stop_path
:
'
/root/review-app/environments/12/stop
'
,
created_at
:
'
2017-02-01T19:42:18.400Z
'
,
updated_at
:
'
2017-02-01T19:42:18.400Z
'
,
};
spec/lib/gitlab/ci/templates/Jobs/test_gitlab_ci_yaml_spec.rb
deleted
100644 → 0
View file @
82a708b9
# frozen_string_literal: true
require
'spec_helper'
describe
'Jobs/Test.gitlab-ci.yml'
do
subject
(
:template
)
{
Gitlab
::
Template
::
GitlabCiYmlTemplate
.
find
(
'Jobs/Test'
)
}
describe
'the created pipeline'
do
let_it_be
(
:user
)
{
create
(
:admin
)
}
let_it_be
(
:project
)
{
create
(
:project
,
:repository
)
}
let
(
:default_branch
)
{
'master'
}
let
(
:pipeline_ref
)
{
default_branch
}
let
(
:service
)
{
Ci
::
CreatePipelineService
.
new
(
project
,
user
,
ref:
pipeline_ref
)
}
let
(
:pipeline
)
{
service
.
execute!
(
:push
)
}
let
(
:build_names
)
{
pipeline
.
builds
.
pluck
(
:name
)
}
before
do
stub_ci_pipeline_yaml_file
(
template
.
content
)
allow_any_instance_of
(
Ci
::
BuildScheduleWorker
).
to
receive
(
:perform
).
and_return
(
true
)
allow
(
project
).
to
receive
(
:default_branch
).
and_return
(
default_branch
)
end
context
'on master'
do
it
'creates the test job'
do
expect
(
build_names
).
to
contain_exactly
(
'test'
)
end
end
context
'on another branch'
do
let
(
:pipeline_ref
)
{
'feature'
}
it
'creates the test job'
do
expect
(
build_names
).
to
contain_exactly
(
'test'
)
end
end
context
'on tag'
do
let
(
:pipeline_ref
)
{
'v1.0.0'
}
it
'creates the test job'
do
expect
(
pipeline
).
to
be_tag
expect
(
build_names
).
to
contain_exactly
(
'test'
)
end
end
context
'on merge request'
do
let
(
:service
)
{
MergeRequests
::
CreatePipelineService
.
new
(
project
,
user
)
}
let
(
:merge_request
)
{
create
(
:merge_request
,
:simple
,
source_project:
project
)
}
let
(
:pipeline
)
{
service
.
execute
(
merge_request
)
}
it
'has no jobs'
do
expect
(
pipeline
).
to
be_merge_request_event
expect
(
build_names
).
to
be_empty
end
end
context
'TEST_DISABLED is set'
do
before
do
create
(
:ci_variable
,
key:
'TEST_DISABLED'
,
value:
'true'
,
project:
project
)
end
context
'on master'
do
it
'has no jobs'
do
expect
{
pipeline
}.
to
raise_error
(
Ci
::
CreatePipelineService
::
CreateError
)
end
end
context
'on another branch'
do
let
(
:pipeline_ref
)
{
'feature'
}
it
'has no jobs'
do
expect
{
pipeline
}.
to
raise_error
(
Ci
::
CreatePipelineService
::
CreateError
)
end
end
context
'on tag'
do
let
(
:pipeline_ref
)
{
'v1.0.0'
}
it
'has no jobs'
do
expect
{
pipeline
}.
to
raise_error
(
Ci
::
CreatePipelineService
::
CreateError
)
end
end
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment