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
1
Merge Requests
1
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
nexedi
gitlab-ce
Commits
6c8ae41d
Commit
6c8ae41d
authored
Apr 09, 2021
by
Mireya Andres
Committed by
Sarah Groff Hennigh-Palermo
Apr 09, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add branch switcher UI to the pipeline editor [RUN ALL RSPEC] [RUN AS-IF-FOSS]
parent
5dcc79e3
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
337 additions
and
0 deletions
+337
-0
app/assets/javascripts/pipeline_editor/components/file_nav/branch_switcher.vue
...s/pipeline_editor/components/file_nav/branch_switcher.vue
+65
-0
app/assets/javascripts/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue
...e_editor/components/file_nav/pipeline_editor_file_nav.vue
+21
-0
app/assets/javascripts/pipeline_editor/graphql/queries/available_branches.graphql
...ipeline_editor/graphql/queries/available_branches.graphql
+9
-0
app/assets/javascripts/pipeline_editor/graphql/resolvers.js
app/assets/javascripts/pipeline_editor/graphql/resolvers.js
+17
-0
app/assets/javascripts/pipeline_editor/pipeline_editor_home.vue
...sets/javascripts/pipeline_editor/pipeline_editor_home.vue
+3
-0
app/controllers/projects/ci/pipeline_editor_controller.rb
app/controllers/projects/ci/pipeline_editor_controller.rb
+1
-0
config/feature_flags/development/pipeline_editor_branch_switcher.yml
...ure_flags/development/pipeline_editor_branch_switcher.yml
+8
-0
locale/gitlab.pot
locale/gitlab.pot
+3
-0
spec/frontend/pipeline_editor/components/file-nav/branch_switcher_spec.js
...peline_editor/components/file-nav/branch_switcher_spec.js
+123
-0
spec/frontend/pipeline_editor/components/file-nav/pipeline_editor_file_nav_spec.js
...itor/components/file-nav/pipeline_editor_file_nav_spec.js
+49
-0
spec/frontend/pipeline_editor/graphql/resolvers_spec.js
spec/frontend/pipeline_editor/graphql/resolvers_spec.js
+18
-0
spec/frontend/pipeline_editor/mock_data.js
spec/frontend/pipeline_editor/mock_data.js
+14
-0
spec/frontend/pipeline_editor/pipeline_editor_home_spec.js
spec/frontend/pipeline_editor/pipeline_editor_home_spec.js
+6
-0
No files found.
app/assets/javascripts/pipeline_editor/components/file_nav/branch_switcher.vue
0 → 100644
View file @
6c8ae41d
<
script
>
import
{
GlDropdown
,
GlDropdownItem
,
GlDropdownSectionHeader
,
GlIcon
}
from
'
@gitlab/ui
'
;
import
{
s__
}
from
'
~/locale
'
;
import
{
DEFAULT_FAILURE
}
from
'
~/pipeline_editor/constants
'
;
import
getAvailableBranches
from
'
~/pipeline_editor/graphql/queries/available_branches.graphql
'
;
import
getCurrentBranch
from
'
~/pipeline_editor/graphql/queries/client/current_branch.graphql
'
;
export
default
{
i18n
:
{
title
:
s__
(
'
Branches
'
),
fetchError
:
s__
(
'
Unable to fetch branch list for this project.
'
),
},
components
:
{
GlDropdown
,
GlDropdownItem
,
GlDropdownSectionHeader
,
GlIcon
,
},
inject
:
[
'
projectFullPath
'
],
apollo
:
{
branches
:
{
query
:
getAvailableBranches
,
variables
()
{
return
{
projectFullPath
:
this
.
projectFullPath
,
};
},
update
(
data
)
{
return
data
.
project
?.
repository
?.
branches
||
[];
},
error
()
{
this
.
$emit
(
'
showError
'
,
{
type
:
DEFAULT_FAILURE
,
reasons
:
[
this
.
$options
.
i18n
.
fetchError
],
});
},
},
currentBranch
:
{
query
:
getCurrentBranch
,
},
},
computed
:
{
hasBranchList
()
{
return
this
.
branches
?.
length
>
0
;
},
},
};
</
script
>
<
template
>
<gl-dropdown
v-if=
"hasBranchList"
class=
"gl-ml-2"
:text=
"currentBranch"
icon=
"branch"
>
<gl-dropdown-section-header>
{{
this
.
$options
.
i18n
.
title
}}
</gl-dropdown-section-header>
<gl-dropdown-item
v-for=
"branch in branches"
:key=
"branch.name"
:is-checked=
"currentBranch === branch.name"
:is-check-item=
"true"
>
<gl-icon
name=
"check"
class=
"gl-visibility-hidden"
/>
{{
branch
.
name
}}
</gl-dropdown-item>
</gl-dropdown>
</
template
>
app/assets/javascripts/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue
0 → 100644
View file @
6c8ae41d
<
script
>
import
glFeatureFlagsMixin
from
'
~/vue_shared/mixins/gl_feature_flags_mixin
'
;
import
BranchSwitcher
from
'
./branch_switcher.vue
'
;
export
default
{
components
:
{
BranchSwitcher
,
},
mixins
:
[
glFeatureFlagsMixin
()],
computed
:
{
showBranchSwitcher
()
{
return
this
.
glFeatures
.
pipelineEditorBranchSwitcher
;
},
},
};
</
script
>
<
template
>
<div
class=
"gl-mb-5"
>
<branch-switcher
v-if=
"showBranchSwitcher"
v-on=
"$listeners"
/>
</div>
</
template
>
app/assets/javascripts/pipeline_editor/graphql/queries/available_branches.graphql
0 → 100644
View file @
6c8ae41d
query
getAvailableBranches
(
$projectFullPath
:
ID
!)
{
project
(
fullPath
:
$projectFullPath
)
@client
{
repository
{
branches
{
name
}
}
}
}
app/assets/javascripts/pipeline_editor/graphql/resolvers.js
View file @
6c8ae41d
...
...
@@ -11,6 +11,23 @@ export const resolvers = {
}),
};
},
/* eslint-disable @gitlab/require-i18n-strings */
project
()
{
return
{
__typename
:
'
Project
'
,
repository
:
{
__typename
:
'
Repository
'
,
branches
:
[
{
__typename
:
'
Branch
'
,
name
:
'
master
'
},
{
__typename
:
'
Branch
'
,
name
:
'
main
'
},
{
__typename
:
'
Branch
'
,
name
:
'
develop
'
},
{
__typename
:
'
Branch
'
,
name
:
'
production
'
},
{
__typename
:
'
Branch
'
,
name
:
'
test
'
},
],
},
};
},
/* eslint-enable @gitlab/require-i18n-strings */
},
Mutation
:
{
lintCI
:
(
_
,
{
endpoint
,
content
,
dry_run
})
=>
{
...
...
app/assets/javascripts/pipeline_editor/pipeline_editor_home.vue
View file @
6c8ae41d
<
script
>
import
CommitSection
from
'
./components/commit/commit_section.vue
'
;
import
PipelineEditorFileNav
from
'
./components/file_nav/pipeline_editor_file_nav.vue
'
;
import
PipelineEditorHeader
from
'
./components/header/pipeline_editor_header.vue
'
;
import
PipelineEditorTabs
from
'
./components/pipeline_editor_tabs.vue
'
;
import
{
TABS_WITH_COMMIT_FORM
,
CREATE_TAB
}
from
'
./constants
'
;
...
...
@@ -7,6 +8,7 @@ import { TABS_WITH_COMMIT_FORM, CREATE_TAB } from './constants';
export
default
{
components
:
{
CommitSection
,
PipelineEditorFileNav
,
PipelineEditorHeader
,
PipelineEditorTabs
,
},
...
...
@@ -44,6 +46,7 @@ export default {
<
template
>
<div>
<pipeline-editor-file-nav
v-on=
"$listeners"
/>
<pipeline-editor-header
:ci-config-data=
"ciConfigData"
:is-new-ci-config-file=
"isNewCiConfigFile"
...
...
app/controllers/projects/ci/pipeline_editor_controller.rb
View file @
6c8ae41d
...
...
@@ -7,6 +7,7 @@ class Projects::Ci::PipelineEditorController < Projects::ApplicationController
push_frontend_feature_flag
(
:ci_config_merged_tab
,
@project
,
default_enabled: :yaml
)
push_frontend_feature_flag
(
:pipeline_status_for_pipeline_editor
,
@project
,
default_enabled: :yaml
)
push_frontend_feature_flag
(
:pipeline_editor_empty_state_action
,
@project
,
default_enabled: :yaml
)
push_frontend_feature_flag
(
:pipeline_editor_branch_switcher
,
@project
,
default_enabled: :yaml
)
end
feature_category
:pipeline_authoring
...
...
config/feature_flags/development/pipeline_editor_branch_switcher.yml
0 → 100644
View file @
6c8ae41d
---
name
:
pipeline_editor_branch_switcher
introduced_by_url
:
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57562
rollout_issue_url
:
https://gitlab.com/gitlab-org/gitlab/-/issues/326189
milestone
:
'
13.11'
type
:
development
group
:
group::pipeline authoring
default_enabled
:
false
locale/gitlab.pot
View file @
6c8ae41d
...
...
@@ -32829,6 +32829,9 @@ msgstr ""
msgid "Unable to create link to vulnerability"
msgstr ""
msgid "Unable to fetch branch list for this project."
msgstr ""
msgid "Unable to fetch unscanned projects"
msgstr ""
...
...
spec/frontend/pipeline_editor/components/file-nav/branch_switcher_spec.js
0 → 100644
View file @
6c8ae41d
import
{
GlDropdown
,
GlDropdownItem
,
GlIcon
}
from
'
@gitlab/ui
'
;
import
{
shallowMount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
createMockApollo
from
'
helpers/mock_apollo_helper
'
;
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
BranchSwitcher
from
'
~/pipeline_editor/components/file_nav/branch_switcher.vue
'
;
import
{
DEFAULT_FAILURE
}
from
'
~/pipeline_editor/constants
'
;
import
{
mockDefaultBranch
,
mockProjectBranches
,
mockProjectFullPath
}
from
'
../../mock_data
'
;
const
localVue
=
createLocalVue
();
localVue
.
use
(
VueApollo
);
describe
(
'
Pipeline editor branch switcher
'
,
()
=>
{
let
wrapper
;
let
mockApollo
;
let
mockAvailableBranchQuery
;
const
createComponentWithApollo
=
()
=>
{
const
resolvers
=
{
Query
:
{
project
:
mockAvailableBranchQuery
,
},
};
mockApollo
=
createMockApollo
([],
resolvers
);
wrapper
=
shallowMount
(
BranchSwitcher
,
{
localVue
,
apolloProvider
:
mockApollo
,
provide
:
{
projectFullPath
:
mockProjectFullPath
,
},
data
()
{
return
{
currentBranch
:
mockDefaultBranch
,
};
},
});
};
const
findDropdown
=
()
=>
wrapper
.
findComponent
(
GlDropdown
);
const
findDropdownItems
=
()
=>
wrapper
.
findAll
(
GlDropdownItem
);
beforeEach
(()
=>
{
mockAvailableBranchQuery
=
jest
.
fn
();
});
afterEach
(()
=>
{
wrapper
.
destroy
();
});
describe
(
'
while querying
'
,
()
=>
{
beforeEach
(()
=>
{
createComponentWithApollo
();
});
it
(
'
does not render dropdown
'
,
()
=>
{
expect
(
findDropdown
().
exists
()).
toBe
(
false
);
});
});
describe
(
'
after querying
'
,
()
=>
{
beforeEach
(
async
()
=>
{
mockAvailableBranchQuery
.
mockResolvedValue
(
mockProjectBranches
);
createComponentWithApollo
();
await
waitForPromises
();
});
it
(
'
query is called with correct variables
'
,
async
()
=>
{
expect
(
mockAvailableBranchQuery
).
toHaveBeenCalledTimes
(
1
);
expect
(
mockAvailableBranchQuery
).
toHaveBeenCalledWith
(
expect
.
anything
(),
{
fullPath
:
mockProjectFullPath
,
},
expect
.
anything
(),
expect
.
anything
(),
);
});
it
(
'
renders list of branches
'
,
()
=>
{
expect
(
findDropdown
().
exists
()).
toBe
(
true
);
expect
(
findDropdownItems
()).
toHaveLength
(
mockProjectBranches
.
repository
.
branches
.
length
);
});
it
(
'
renders current branch at the top of the list with a check mark
'
,
()
=>
{
const
firstDropdownItem
=
findDropdownItems
().
at
(
0
);
const
icon
=
firstDropdownItem
.
findComponent
(
GlIcon
);
expect
(
firstDropdownItem
.
text
()).
toBe
(
mockDefaultBranch
);
expect
(
icon
.
exists
()).
toBe
(
true
);
expect
(
icon
.
props
(
'
name
'
)).
toBe
(
'
check
'
);
});
it
(
'
does not render check mark for other branches
'
,
()
=>
{
const
secondDropdownItem
=
findDropdownItems
().
at
(
1
);
const
icon
=
secondDropdownItem
.
findComponent
(
GlIcon
);
expect
(
icon
.
classes
()).
toContain
(
'
gl-visibility-hidden
'
);
});
});
describe
(
'
on fetch error
'
,
()
=>
{
beforeEach
(
async
()
=>
{
mockAvailableBranchQuery
.
mockResolvedValue
(
new
Error
());
createComponentWithApollo
();
await
waitForPromises
();
});
it
(
'
does not render dropdown
'
,
()
=>
{
expect
(
findDropdown
().
exists
()).
toBe
(
false
);
});
it
(
'
shows an error message
'
,
()
=>
{
expect
(
wrapper
.
emitted
(
'
showError
'
)).
toBeDefined
();
expect
(
wrapper
.
emitted
(
'
showError
'
)[
0
]).
toEqual
([
{
reasons
:
[
wrapper
.
vm
.
$options
.
i18n
.
fetchError
],
type
:
DEFAULT_FAILURE
,
},
]);
});
});
});
spec/frontend/pipeline_editor/components/file-nav/pipeline_editor_file_nav_spec.js
0 → 100644
View file @
6c8ae41d
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
BranchSwitcher
from
'
~/pipeline_editor/components/file_nav/branch_switcher.vue
'
;
import
PipelineEditorFileNav
from
'
~/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue
'
;
describe
(
'
Pipeline editor file nav
'
,
()
=>
{
let
wrapper
;
const
mockProvide
=
{
glFeatures
:
{
pipelineEditorBranchSwitcher
:
true
,
},
};
const
createComponent
=
({
provide
=
{}
}
=
{})
=>
{
wrapper
=
shallowMount
(
PipelineEditorFileNav
,
{
provide
:
{
...
mockProvide
,
...
provide
,
},
});
};
const
findBranchSwitcher
=
()
=>
wrapper
.
findComponent
(
BranchSwitcher
);
afterEach
(()
=>
{
wrapper
.
destroy
();
});
describe
(
'
template
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
();
});
it
(
'
renders the branch switcher
'
,
()
=>
{
expect
(
findBranchSwitcher
().
exists
()).
toBe
(
true
);
});
});
describe
(
'
with branch switcher feature flag OFF
'
,
()
=>
{
it
(
'
does not render the branch switcher
'
,
()
=>
{
createComponent
({
provide
:
{
glFeatures
:
{
pipelineEditorBranchSwitcher
:
false
},
},
});
expect
(
findBranchSwitcher
().
exists
()).
toBe
(
false
);
});
});
});
spec/frontend/pipeline_editor/graphql/resolvers_spec.js
View file @
6c8ae41d
...
...
@@ -9,6 +9,7 @@ import {
mockDefaultBranch
,
mockLintResponse
,
mockProjectFullPath
,
mockProjectBranches
,
}
from
'
../mock_data
'
;
jest
.
mock
(
'
~/api
'
,
()
=>
{
...
...
@@ -46,6 +47,23 @@ describe('~/pipeline_editor/graphql/resolvers', () => {
await
expect
(
result
.
rawData
).
resolves
.
toBe
(
mockCiYml
);
});
});
describe
(
'
project
'
,
()
=>
{
it
(
'
resolves project data with type names
'
,
async
()
=>
{
const
result
=
await
resolvers
.
Query
.
project
();
// eslint-disable-next-line no-underscore-dangle
expect
(
result
.
__typename
).
toBe
(
'
Project
'
);
});
it
(
'
resolves project with available list of branches
'
,
async
()
=>
{
const
result
=
await
resolvers
.
Query
.
project
();
expect
(
result
.
repository
.
branches
).
toHaveLength
(
mockProjectBranches
.
repository
.
branches
.
length
,
);
});
});
});
describe
(
'
Mutation
'
,
()
=>
{
...
...
spec/frontend/pipeline_editor/mock_data.js
View file @
6c8ae41d
...
...
@@ -138,6 +138,20 @@ export const mergeUnwrappedCiConfig = (mergedConfig) => {
};
};
export
const
mockProjectBranches
=
{
__typename
:
'
Project
'
,
repository
:
{
__typename
:
'
Repository
'
,
branches
:
[
{
__typename
:
'
Branch
'
,
name
:
'
master
'
},
{
__typename
:
'
Branch
'
,
name
:
'
main
'
},
{
__typename
:
'
Branch
'
,
name
:
'
develop
'
},
{
__typename
:
'
Branch
'
,
name
:
'
production
'
},
{
__typename
:
'
Branch
'
,
name
:
'
test
'
},
],
},
};
export
const
mockProjectPipeline
=
{
pipeline
:
{
commitPath
:
'
/-/commit/aabbccdd
'
,
...
...
spec/frontend/pipeline_editor/pipeline_editor_home_spec.js
View file @
6c8ae41d
...
...
@@ -2,6 +2,7 @@ import { shallowMount } from '@vue/test-utils';
import
{
nextTick
}
from
'
vue
'
;
import
CommitSection
from
'
~/pipeline_editor/components/commit/commit_section.vue
'
;
import
PipelineEditorFileNav
from
'
~/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue
'
;
import
PipelineEditorHeader
from
'
~/pipeline_editor/components/header/pipeline_editor_header.vue
'
;
import
PipelineEditorTabs
from
'
~/pipeline_editor/components/pipeline_editor_tabs.vue
'
;
import
{
MERGED_TAB
,
VISUALIZE_TAB
}
from
'
~/pipeline_editor/constants
'
;
...
...
@@ -27,6 +28,7 @@ describe('Pipeline editor home wrapper', () => {
const
findPipelineEditorHeader
=
()
=>
wrapper
.
findComponent
(
PipelineEditorHeader
);
const
findPipelineEditorTabs
=
()
=>
wrapper
.
findComponent
(
PipelineEditorTabs
);
const
findCommitSection
=
()
=>
wrapper
.
findComponent
(
CommitSection
);
const
findFileNav
=
()
=>
wrapper
.
findComponent
(
PipelineEditorFileNav
);
afterEach
(()
=>
{
wrapper
.
destroy
();
...
...
@@ -38,6 +40,10 @@ describe('Pipeline editor home wrapper', () => {
createComponent
();
});
it
(
'
shows the file nav
'
,
()
=>
{
expect
(
findFileNav
().
exists
()).
toBe
(
true
);
});
it
(
'
shows the pipeline editor header
'
,
()
=>
{
expect
(
findPipelineEditorHeader
().
exists
()).
toBe
(
true
);
});
...
...
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