Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-07-19 00:09:42 +00:00
parent 540020f815
commit 91d37b9714
28 changed files with 494 additions and 69 deletions

View File

@ -49,3 +49,5 @@ export const SEARCH_RESULTS_DESCRIPTION = 'search-results-description';
export const SCOPE_TOKEN_MAX_LENGTH = 36; export const SCOPE_TOKEN_MAX_LENGTH = 36;
export const INPUT_FIELD_PADDING = 52; export const INPUT_FIELD_PADDING = 52;
export const HEADER_INIT_EVENTS = ['input', 'focus'];

View File

@ -1,4 +1,5 @@
import * as Sentry from '@sentry/browser'; import * as Sentry from '@sentry/browser';
import { HEADER_INIT_EVENTS } from './constants';
async function eventHandler(callback = () => {}) { async function eventHandler(callback = () => {}) {
if (this.newHeaderSearchFeatureFlag) { if (this.newHeaderSearchFeatureFlag) {
@ -28,21 +29,25 @@ async function eventHandler(callback = () => {}) {
} }
function cleanEventListeners() { function cleanEventListeners() {
document.querySelector('#search').removeEventListener('focus', eventHandler); HEADER_INIT_EVENTS.forEach((eventType) => {
document.querySelector('#search').removeEventListener(eventType, eventHandler);
});
} }
function initHeaderSearch() { function initHeaderSearch() {
const searchInputBox = document.querySelector('#search'); const searchInputBox = document.querySelector('#search');
searchInputBox?.addEventListener( HEADER_INIT_EVENTS.forEach((eventType) => {
'focus', searchInputBox?.addEventListener(
eventHandler.bind( eventType,
{ searchInputBox, newHeaderSearchFeatureFlag: gon?.features?.newHeaderSearch }, eventHandler.bind(
cleanEventListeners, { searchInputBox, newHeaderSearchFeatureFlag: gon?.features?.newHeaderSearch },
), cleanEventListeners,
{ once: true }, ),
); { once: true },
);
});
} }
export default initHeaderSearch; export default initHeaderSearch;
export { eventHandler }; export { eventHandler, cleanEventListeners };

View File

@ -6,9 +6,14 @@ module Types
graphql_name 'CiRunnerUpgradeStatusType' graphql_name 'CiRunnerUpgradeStatusType'
::Ci::RunnerVersion::STATUS_DESCRIPTIONS.each do |status, description| ::Ci::RunnerVersion::STATUS_DESCRIPTIONS.each do |status, description|
status = :invalid if status == :invalid_version status_name_src =
if status == :invalid_version
:invalid
else
status
end
value status.to_s.upcase, description: description, value: status value status_name_src.to_s.upcase, description: description, value: status
end end
end end
end end

View File

@ -7,7 +7,7 @@ module Ci
enum_with_nil status: { enum_with_nil status: {
not_processed: nil, not_processed: nil,
invalid_version: -1, # Named invalid_version to avoid clash with auto-generated `invalid?` ActiveRecord method invalid_version: -1,
unknown: 0, unknown: 0,
not_available: 1, not_available: 1,
available: 2, available: 2,

View File

@ -1049,8 +1049,8 @@ class Repository
blob_data_at(sha, '.lfsconfig') blob_data_at(sha, '.lfsconfig')
end end
def changelog_config(ref = 'HEAD') def changelog_config(ref, path)
blob_data_at(ref, Gitlab::Changelog::Config::FILE_PATH) blob_data_at(ref, path)
end end
def fetch_ref(source_repository, source_ref:, target_ref:) def fetch_ref(source_repository, source_ref:, target_ref:)

View File

@ -41,6 +41,9 @@ module Repositories
# The `trailer` argument is the Git trailer to use for determining what # The `trailer` argument is the Git trailer to use for determining what
# commits to include in the changelog. # commits to include in the changelog.
# #
# The `config_file` arguments specifies the path to the configuration file as
# stored in the project's Git repository.
#
# The `file` arguments specifies the name/path of the file to commit the # The `file` arguments specifies the name/path of the file to commit the
# changes to. If the file doesn't exist, it's created automatically. # changes to. If the file doesn't exist, it's created automatically.
# #
@ -57,6 +60,7 @@ module Repositories
to: branch, to: branch,
date: DateTime.now, date: DateTime.now,
trailer: DEFAULT_TRAILER, trailer: DEFAULT_TRAILER,
config_file: Gitlab::Changelog::Config::DEFAULT_FILE_PATH,
file: DEFAULT_FILE, file: DEFAULT_FILE,
message: "Add changelog for version #{version}" message: "Add changelog for version #{version}"
) )
@ -68,13 +72,14 @@ module Repositories
@date = date @date = date
@branch = branch @branch = branch
@trailer = trailer @trailer = trailer
@config_file = config_file
@file = file @file = file
@message = message @message = message
end end
# rubocop: enable Metrics/ParameterLists # rubocop: enable Metrics/ParameterLists
def execute(commit_to_changelog: true) def execute(commit_to_changelog: true)
config = Gitlab::Changelog::Config.from_git(@project, @user) config = Gitlab::Changelog::Config.from_git(@project, @user, @config_file)
from = start_of_commit_range(config) from = start_of_commit_range(config)
# For every entry we want to only include the merge request that # For every entry we want to only include the merge request that

View File

@ -7,7 +7,7 @@ module WaitableWorker
# Schedules multiple jobs and waits for them to be completed. # Schedules multiple jobs and waits for them to be completed.
def bulk_perform_and_wait(args_list) def bulk_perform_and_wait(args_list)
# Short-circuit: it's more efficient to do small numbers of jobs inline # Short-circuit: it's more efficient to do small numbers of jobs inline
if args_list.size == 1 || (args_list.size <= 3 && !inline_refresh_only_for_single_element?) if args_list.size == 1
return bulk_perform_inline(args_list) return bulk_perform_inline(args_list)
end end
@ -29,10 +29,6 @@ module WaitableWorker
bulk_perform_async(failed) if failed.present? bulk_perform_async(failed) if failed.present?
end end
def inline_refresh_only_for_single_element?
Feature.enabled?(:inline_project_authorizations_refresh_only_for_single_element)
end
end end
def perform(*args) def perform(*args)

View File

@ -1,8 +0,0 @@
---
name: inline_project_authorizations_refresh_only_for_single_element
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91572
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/366815
milestone: '15.2'
type: development
group: group::workspace
default_enabled: false

View File

@ -319,6 +319,7 @@ Supported attributes:
| `date` | datetime | no | The date and time of the release, defaults to the current time. | | `date` | datetime | no | The date and time of the release, defaults to the current time. |
| `branch` | string | no | The branch to commit the changelog changes to, defaults to the project's default branch. | | `branch` | string | no | The branch to commit the changelog changes to, defaults to the project's default branch. |
| `trailer` | string | no | The Git trailer to use for including commits, defaults to `Changelog`. | | `trailer` | string | no | The Git trailer to use for including commits, defaults to `Changelog`. |
| `config_file` | string | no | The path of changelog configuration file in the project's Git repository, defaults to `.gitlab/changelog_config.yml`. |
| `file` | string | no | The file to commit the changes to, defaults to `CHANGELOG.md`. | | `file` | string | no | The file to commit the changes to, defaults to `CHANGELOG.md`. |
| `message` | string | no | The commit message to produce when committing the changes, defaults to `Add changelog for version X` where X is the value of the `version` argument. | | `message` | string | no | The commit message to produce when committing the changes, defaults to `Add changelog for version X` where X is the value of the `version` argument. |
@ -453,7 +454,7 @@ If a revert commit includes the trailer used for generating changelogs
### Customize the changelog output ### Customize the changelog output
The output is customized using a YAML configuration file stored in your The output is customized using a YAML configuration file stored in your
project's Git repository. This file must reside in project's Git repository. This default configuration file path is
`.gitlab/changelog_config.yml`. `.gitlab/changelog_config.yml`.
You can set the following variables in this file: You can set the following variables in this file:
@ -736,6 +737,7 @@ Supported attributes:
| `to` | string | no | The end of the range of commits (as a SHA) to use for the changelog. This commit _is_ included in the list. Defaults to the branch specified in the `branch` attribute. | | `to` | string | no | The end of the range of commits (as a SHA) to use for the changelog. This commit _is_ included in the list. Defaults to the branch specified in the `branch` attribute. |
| `date` | datetime | no | The date and time of the release, ISO 8601 formatted. Example: `2016-03-11T03:45:40Z`. Defaults to the current time. | | `date` | datetime | no | The date and time of the release, ISO 8601 formatted. Example: `2016-03-11T03:45:40Z`. Defaults to the current time. |
| `trailer` | string | no | The Git trailer to use for including commits, defaults to `Changelog`. | | `trailer` | string | no | The Git trailer to use for including commits, defaults to `Changelog`. |
| `config_file` | string | no | The path of changelog configuration file in the project's Git repository, defaults to `.gitlab/changelog_config.yml`. |
```shell ```shell
curl --header "PRIVATE-TOKEN: token" "https://gitlab.com/api/v4/projects/42/repository/changelog?version=1.0.0" curl --header "PRIVATE-TOKEN: token" "https://gitlab.com/api/v4/projects/42/repository/changelog?version=1.0.0"

View File

@ -238,6 +238,10 @@ module API
end end
params do params do
use :release_params use :release_params
optional :config_file,
type: String,
desc: "The file path to the configuration file as stored in the project's Git repository. Defaults to '.gitlab/changelog_config.yml'"
end end
get ':id/repository/changelog' do get ':id/repository/changelog' do
service = ::Repositories::ChangelogService.new( service = ::Repositories::ChangelogService.new(
@ -262,6 +266,10 @@ module API
type: String, type: String,
desc: 'The branch to commit the changelog changes to' desc: 'The branch to commit the changelog changes to'
optional :config_file,
type: String,
desc: "The file path to the configuration file as stored in the project's Git repository. Defaults to '.gitlab/changelog_config.yml'"
optional :file, optional :file,
type: String, type: String,
desc: 'The file to commit the changelog changes to', desc: 'The file to commit the changelog changes to',

View File

@ -7,9 +7,9 @@ module Gitlab
# When rendering changelog entries, authors are not included. # When rendering changelog entries, authors are not included.
AUTHORS_NONE = 'none' AUTHORS_NONE = 'none'
# The path to the configuration file as stored in the project's Git # The default path to the configuration file as stored in the project's Git
# repository. # repository.
FILE_PATH = '.gitlab/changelog_config.yml' DEFAULT_FILE_PATH = '.gitlab/changelog_config.yml'
# The default date format to use for formatting release dates. # The default date format to use for formatting release dates.
DEFAULT_DATE_FORMAT = '%Y-%m-%d' DEFAULT_DATE_FORMAT = '%Y-%m-%d'
@ -36,8 +36,9 @@ module Gitlab
attr_accessor :date_format, :categories, :template, :tag_regex, :always_credit_user_ids attr_accessor :date_format, :categories, :template, :tag_regex, :always_credit_user_ids
def self.from_git(project, user = nil) def self.from_git(project, user = nil, path = nil)
if (yaml = project.repository.changelog_config.presence) yaml = project.repository.changelog_config('HEAD', path.presence || DEFAULT_FILE_PATH)
if yaml.present?
from_hash(project, YAML.safe_load(yaml), user) from_hash(project, YAML.safe_load(yaml), user)
else else
new(project) new(project)

View File

@ -0,0 +1,86 @@
# frozen_string_literal: true
module Gitlab
module GithubImport
module Importer
module Events
class CrossReferenced
attr_reader :project, :user_id
def initialize(project, user_id)
@project = project
@user_id = user_id
end
# issue_event - An instance of `Gitlab::GithubImport::Representation::IssueEvent`.
def execute(issue_event)
mentioned_in_record_class = mentioned_in_type(issue_event)
mentioned_in_number = issue_event.source.dig(:issue, :number)
mentioned_in_record = init_mentioned_in(
mentioned_in_record_class, mentioned_in_number
)
return if mentioned_in_record.nil?
note_body = cross_reference_note_content(mentioned_in_record.gfm_reference(project))
track_activity(mentioned_in_record_class)
create_note(issue_event, note_body)
end
private
def track_activity(mentioned_in_class)
return if mentioned_in_class != Issue
Gitlab::UsageDataCounters::HLLRedisCounter.track_event(
Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_CROSS_REFERENCED,
values: user_id
)
end
def create_note(issue_event, note_body)
Note.create!(
system: true,
noteable_type: Issue.name,
noteable_id: issue_event.issue_db_id,
project: project,
author_id: user_id,
note: note_body,
system_note_metadata: SystemNoteMetadata.new(action: 'cross_reference'),
created_at: issue_event.created_at
)
end
def mentioned_in_type(issue_event)
is_pull_request = issue_event.source.dig(:issue, :pull_request).present?
is_pull_request ? MergeRequest : Issue
end
# record_class - Issue/MergeRequest
def init_mentioned_in(record_class, iid)
db_id = fetch_mentioned_in_db_id(record_class, iid)
return if db_id.nil?
record = record_class.new(id: db_id, iid: iid)
record.project = project
record.readonly!
record
end
# record_class - Issue/MergeRequest
def fetch_mentioned_in_db_id(record_class, number)
sawyer_mentioned_in_adapter = Struct.new(:iid, :issuable_type, keyword_init: true)
mentioned_in_adapter = sawyer_mentioned_in_adapter.new(
iid: number, issuable_type: record_class.name
)
Gitlab::GithubImport::IssuableFinder.new(project, mentioned_in_adapter).database_id
end
def cross_reference_note_content(gfm_reference)
"#{::SystemNotes::IssuablesService.cross_reference_note_prefix}#{gfm_reference}"
end
end
end
end
end
end

View File

@ -30,6 +30,9 @@ module Gitlab
when 'renamed' when 'renamed'
Gitlab::GithubImport::Importer::Events::Renamed.new(project, author_id) Gitlab::GithubImport::Importer::Events::Renamed.new(project, author_id)
.execute(issue_event) .execute(issue_event)
when 'cross-referenced'
Gitlab::GithubImport::Importer::Events::CrossReferenced.new(project, author_id)
.execute(issue_event)
else else
Gitlab::GithubImport::Logger.debug( Gitlab::GithubImport::Logger.debug(
message: 'UNSUPPORTED_EVENT_TYPE', message: 'UNSUPPORTED_EVENT_TYPE',

View File

@ -21,14 +21,12 @@ module Gitlab
author_id, author_found = user_finder.author_id_for(note) author_id, author_found = user_finder.author_id_for(note)
note_body = MarkdownText.format(note.note, note.author, author_found)
attributes = { attributes = {
noteable_type: note.noteable_type, noteable_type: note.noteable_type,
noteable_id: noteable_id, noteable_id: noteable_id,
project_id: project.id, project_id: project.id,
author_id: author_id, author_id: author_id,
note: note_body, note: note_body(author_found),
discussion_id: note.discussion_id, discussion_id: note.discussion_id,
system: false, system: false,
created_at: note.created_at, created_at: note.created_at,
@ -48,6 +46,13 @@ module Gitlab
def find_noteable_id def find_noteable_id
GithubImport::IssuableFinder.new(project, note).database_id GithubImport::IssuableFinder.new(project, note).database_id
end end
private
def note_body(author_found)
text = MarkdownText.convert_ref_links(note.note, project)
MarkdownText.format(text, note.author, author_found)
end
end end
end end
end end

View File

@ -19,6 +19,7 @@ module Gitlab
end end
def each_associated(parent_record, associated) def each_associated(parent_record, associated)
compose_associated_id!(parent_record, associated)
return if already_imported?(associated) return if already_imported?(associated)
Gitlab::GithubImport::ObjectCounter.increment(project, object_type, :fetched) Gitlab::GithubImport::ObjectCounter.increment(project, object_type, :fetched)
@ -68,6 +69,13 @@ module Gitlab
def collection_options def collection_options
{ state: 'all', sort: 'created', direction: 'asc' } { state: 'all', sort: 'created', direction: 'asc' }
end end
# Cross-referenced events on Github doesn't have id.
def compose_associated_id!(issue, event)
return if event.event != 'cross-referenced'
event.id = "cross-reference##{issue.id}-in-#{event.source.issue.id}"
end
end end
end end
end end

View File

@ -5,8 +5,34 @@ module Gitlab
class MarkdownText class MarkdownText
include Gitlab::EncodingHelper include Gitlab::EncodingHelper
def self.format(*args) ISSUE_REF_MATCHER = '%{github_url}/%{import_source}/issues'
new(*args).to_s PULL_REF_MATCHER = '%{github_url}/%{import_source}/pull'
class << self
def format(*args)
new(*args).to_s
end
# Links like `https://domain.github.com/<namespace>/<project>/pull/<iid>` needs to be converted
def convert_ref_links(text, project)
matcher_options = { github_url: github_url, import_source: project.import_source }
issue_ref_matcher = ISSUE_REF_MATCHER % matcher_options
pull_ref_matcher = PULL_REF_MATCHER % matcher_options
url_helpers = Rails.application.routes.url_helpers
text.gsub(issue_ref_matcher, url_helpers.project_issues_url(project))
.gsub(pull_ref_matcher, url_helpers.project_merge_requests_url(project))
end
private
# Returns github domain without slash in the end
def github_url
oauth_config = Gitlab::Auth::OAuth::Provider.config_for('github') || {}
url = oauth_config['url'].presence || 'https://github.com'
url = url.chop if url.end_with?('/')
url
end
end end
# text - The Markdown text as a String. # text - The Markdown text as a String.

View File

@ -9,7 +9,8 @@ module Gitlab
attr_reader :attributes attr_reader :attributes
expose_attribute :id, :actor, :event, :commit_id, :label_title, :old_title, :new_title, :created_at expose_attribute :id, :actor, :event, :commit_id, :label_title, :old_title, :new_title,
:source, :created_at
expose_attribute :issue_db_id # set in SingleEndpointIssueEventsImporter#each_associated expose_attribute :issue_db_id # set in SingleEndpointIssueEventsImporter#each_associated
# Builds a event from a GitHub API response. # Builds a event from a GitHub API response.
@ -24,6 +25,7 @@ module Gitlab
label_title: event.label && event.label[:name], label_title: event.label && event.label[:name],
old_title: event.rename && event.rename[:from], old_title: event.rename && event.rename[:from],
new_title: event.rename && event.rename[:to], new_title: event.rename && event.rename[:to],
source: event.source,
issue_db_id: event.issue_db_id, issue_db_id: event.issue_db_id,
created_at: event.created_at created_at: event.created_at
) )

View File

@ -1,6 +1,6 @@
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures'; import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
import initHeaderSearch, { eventHandler } from '~/header_search/init'; import initHeaderSearch, { eventHandler, cleanEventListeners } from '~/header_search/init';
describe('Header Search EventListener', () => { describe('Header Search EventListener', () => {
beforeEach(() => { beforeEach(() => {
@ -21,24 +21,25 @@ describe('Header Search EventListener', () => {
it('attached event listener', () => { it('attached event listener', () => {
const searchInputBox = document?.querySelector('#search'); const searchInputBox = document?.querySelector('#search');
const addEventListener = jest.spyOn(searchInputBox, 'addEventListener'); const addEventListenerSpy = jest.spyOn(searchInputBox, 'addEventListener');
initHeaderSearch(); initHeaderSearch();
expect(addEventListener).toBeCalled(); expect(addEventListenerSpy).toBeCalledTimes(2);
}); });
it('removes event listener ', async () => { it('removes event listener ', async () => {
const removeEventListener = jest.fn(); const searchInputBox = document?.querySelector('#search');
const removeEventListenerSpy = jest.spyOn(searchInputBox, 'removeEventListener');
jest.mock('~/header_search', () => ({ initHeaderSearchApp: jest.fn() })); jest.mock('~/header_search', () => ({ initHeaderSearchApp: jest.fn() }));
await eventHandler.apply( await eventHandler.apply(
{ {
newHeaderSearchFeatureFlag: true, newHeaderSearchFeatureFlag: true,
searchInputBox: document.querySelector('#search'), searchInputBox: document.querySelector('#search'),
}, },
[removeEventListener], [cleanEventListeners],
); );
expect(removeEventListener).toBeCalled(); expect(removeEventListenerSpy).toBeCalledTimes(2);
}); });
it('attaches new vue dropdown when feature flag is enabled', async () => { it('attaches new vue dropdown when feature flag is enabled', async () => {

View File

@ -3,14 +3,22 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Types::Ci::RunnerUpgradeStatusTypeEnum do RSpec.describe Types::Ci::RunnerUpgradeStatusTypeEnum do
let(:model_only_enum_values) { %w[not_processed] }
let(:expected_graphql_source_values) do
Ci::RunnerVersion.statuses.keys - model_only_enum_values
end
specify { expect(described_class.graphql_name).to eq('CiRunnerUpgradeStatusType') } specify { expect(described_class.graphql_name).to eq('CiRunnerUpgradeStatusType') }
it 'exposes all upgrade status values except not_processed' do it 'exposes all upgrade status values except not_processed' do
expect(described_class.values.keys).to match_array( expect(described_class.values.keys).to match_array(
Ci::RunnerVersion.statuses.keys expected_graphql_source_values
.reject { |k| k == 'not_processed' } .map(&:upcase)
.map { |k| k.upcase }
.map { |v| v == 'INVALID_VERSION' ? 'INVALID' : v } .map { |v| v == 'INVALID_VERSION' ? 'INVALID' : v }
) )
end end
it 'exposes all upgrade status values except enum-only values' do
expect(described_class.values.values.map(&:value).map(&:to_s)).to match_array(expected_graphql_source_values)
end
end end

View File

@ -20,6 +20,18 @@ RSpec.describe Gitlab::Changelog::Config do
described_class.from_git(project) described_class.from_git(project)
end end
it "retrieves the specified configuration from git" do
allow(project.repository)
.to receive(:changelog_config).with('HEAD', 'specified_changelog_config.yml')
.and_return("---\ndate_format: '%Y'")
expect(described_class)
.to receive(:from_hash)
.with(project, { 'date_format' => '%Y' }, nil)
described_class.from_git(project, nil, 'specified_changelog_config.yml')
end
it 'returns the default configuration when no YAML file exists in Git' do it 'returns the default configuration when no YAML file exists in Git' do
allow(project.repository) allow(project.repository)
.to receive(:changelog_config) .to receive(:changelog_config)

View File

@ -0,0 +1,96 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::GithubImport::Importer::Events::CrossReferenced, :clean_gitlab_redis_cache do
subject(:importer) { described_class.new(project, user.id) }
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
let(:sawyer_stub) { Struct.new(:iid, :issuable_type, keyword_init: true) }
let(:issue) { create(:issue, project: project) }
let(:referenced_in) { build_stubbed(:issue, project: project) }
let(:commit_id) { nil }
let(:issue_event) do
Gitlab::GithubImport::Representation::IssueEvent.from_json_hash(
'id' => 6501124486,
'node_id' => 'CE_lADOHK9fA85If7x0zwAAAAGDf0mG',
'url' => 'https://api.github.com/repos/elhowm/test-import/issues/events/6501124486',
'actor' => { 'id' => 4, 'login' => 'alice' },
'event' => 'cross-referenced',
'source' => {
'type' => 'issue',
'issue' => {
'number' => referenced_in.iid,
'pull_request' => pull_request_resource
}
},
'created_at' => '2022-04-26 18:30:53 UTC',
'issue_db_id' => issue.id
)
end
let(:pull_request_resource) { nil }
let(:expected_note_attrs) do
{
system: true,
noteable_type: Issue.name,
noteable_id: issue_event.issue_db_id,
project_id: project.id,
author_id: user.id,
note: expected_note_body,
created_at: issue_event.created_at
}.stringify_keys
end
context 'when referenced in other issue' do
let(:expected_note_body) { "mentioned in issue ##{issue.iid}" }
before do
other_issue_resource = sawyer_stub.new(iid: referenced_in.iid, issuable_type: 'Issue')
Gitlab::GithubImport::IssuableFinder.new(project, other_issue_resource)
.cache_database_id(referenced_in.iid)
end
it 'creates expected note' do
importer.execute(issue_event)
expect(issue.notes.count).to eq 1
expect(issue.notes[0]).to have_attributes expected_note_attrs
expect(issue.notes[0].system_note_metadata.action).to eq 'cross_reference'
end
end
context 'when referenced in pull request' do
let(:referenced_in) { build_stubbed(:merge_request, project: project) }
let(:pull_request_resource) { { 'id' => referenced_in.iid } }
let(:expected_note_body) { "mentioned in merge request !#{referenced_in.iid}" }
before do
other_issue_resource =
sawyer_stub.new(iid: referenced_in.iid, issuable_type: 'MergeRequest')
Gitlab::GithubImport::IssuableFinder.new(project, other_issue_resource)
.cache_database_id(referenced_in.iid)
end
it 'creates expected note' do
importer.execute(issue_event)
expect(issue.notes.count).to eq 1
expect(issue.notes[0]).to have_attributes expected_note_attrs
expect(issue.notes[0].system_note_metadata.action).to eq 'cross_reference'
end
end
context 'when referenced in out of project issue/pull_request' do
it 'creates expected note' do
importer.execute(issue_event)
expect(issue.notes.count).to eq 0
end
end
end

View File

@ -87,6 +87,13 @@ RSpec.describe Gitlab::GithubImport::Importer::IssueEventImporter, :clean_gitlab
Gitlab::GithubImport::Importer::Events::Renamed Gitlab::GithubImport::Importer::Events::Renamed
end end
context "when it's cross-referenced issue event" do
let(:event_name) { 'cross-referenced' }
it_behaves_like 'triggers specific event importer',
Gitlab::GithubImport::Importer::Events::CrossReferenced
end
context "when it's unknown issue event" do context "when it's unknown issue event" do
let(:event_name) { 'fake' } let(:event_name) { 'fake' }

View File

@ -12,6 +12,54 @@ RSpec.describe Gitlab::GithubImport::MarkdownText do
end end
end end
describe '.convert_ref_links' do
let_it_be(:project) { create(:project) }
let(:paragraph) { FFaker::Lorem.paragraph }
let(:sentence) { FFaker::Lorem.sentence }
let(:issue_id) { rand(100) }
let(:pull_id) { rand(100) }
let(:text_in) do
<<-TEXT
#{paragraph}
https://github.com/#{project.import_source}/issues/#{issue_id}
#{sentence}
https://github.com/#{project.import_source}/pull/#{pull_id}
TEXT
end
let(:text_out) do
<<-TEXT
#{paragraph}
http://localhost/#{project.full_path}/-/issues/#{issue_id}
#{sentence}
http://localhost/#{project.full_path}/-/merge_requests/#{pull_id}
TEXT
end
it { expect(described_class.convert_ref_links(text_in, project)).to eq text_out }
context 'when Github EE with custom domain name' do
let(:github_domain) { 'https://custom.github.com/' }
let(:text_in) do
<<-TEXT
#{paragraph}
#{github_domain}#{project.import_source}/issues/#{issue_id}
#{sentence}
#{github_domain}#{project.import_source}/pull/#{pull_id}
TEXT
end
before do
allow(Gitlab::Auth::OAuth::Provider)
.to receive(:config_for).with('github').and_return({ 'url' => github_domain })
end
it { expect(described_class.convert_ref_links(text_in, project)).to eq text_out }
end
end
describe '#to_s' do describe '#to_s' do
it 'returns the text when the author was found' do it 'returns the text when the author was found' do
author = double(:author, login: 'Alice') author = double(:author, login: 'Alice')

View File

@ -21,6 +21,10 @@ RSpec.describe Gitlab::GithubImport::Representation::IssueEvent do
expect(issue_event.commit_id).to eq('570e7b2abdd848b95f2f578043fc23bd6f6fd24d') expect(issue_event.commit_id).to eq('570e7b2abdd848b95f2f578043fc23bd6f6fd24d')
end end
it 'includes the issue event source' do
expect(issue_event.source).to eq({ type: 'issue', id: 123456 })
end
it 'includes the issue_db_id' do it 'includes the issue_db_id' do
expect(issue_event.issue_db_id).to eq(100500) expect(issue_event.issue_db_id).to eq(100500)
end end
@ -89,7 +93,7 @@ RSpec.describe Gitlab::GithubImport::Representation::IssueEvent do
let(:response) do let(:response) do
event_resource = Struct.new( event_resource = Struct.new(
:id, :node_id, :url, :actor, :event, :commit_id, :commit_url, :label, :id, :node_id, :url, :actor, :event, :commit_id, :commit_url, :label,
:rename, :issue_db_id, :created_at, :performed_via_github_app, :rename, :issue_db_id, :created_at, :performed_via_github_app, :source,
keyword_init: true keyword_init: true
) )
user_resource = Struct.new(:id, :login, keyword_init: true) user_resource = Struct.new(:id, :login, keyword_init: true)
@ -103,6 +107,7 @@ RSpec.describe Gitlab::GithubImport::Representation::IssueEvent do
commit_url: 'https://api.github.com/repos/octocat/Hello-World/commits'\ commit_url: 'https://api.github.com/repos/octocat/Hello-World/commits'\
'/570e7b2abdd848b95f2f578043fc23bd6f6fd24d', '/570e7b2abdd848b95f2f578043fc23bd6f6fd24d',
rename: with_rename ? { from: 'old title', to: 'new title' } : nil, rename: with_rename ? { from: 'old title', to: 'new title' } : nil,
source: { type: 'issue', id: 123456 },
issue_db_id: 100500, issue_db_id: 100500,
label: with_label ? { name: 'label title' } : nil, label: with_label ? { name: 'label title' } : nil,
created_at: '2022-04-26 18:30:53 UTC', created_at: '2022-04-26 18:30:53 UTC',
@ -134,6 +139,7 @@ RSpec.describe Gitlab::GithubImport::Representation::IssueEvent do
'label_title' => (with_label ? 'label title' : nil), 'label_title' => (with_label ? 'label title' : nil),
'old_title' => with_rename ? 'old title' : nil, 'old_title' => with_rename ? 'old title' : nil,
'new_title' => with_rename ? 'new title' : nil, 'new_title' => with_rename ? 'new title' : nil,
'source' => { 'type' => 'issue', 'id' => 123456 },
"issue_db_id" => 100500, "issue_db_id" => 100500,
'created_at' => '2022-04-26 18:30:53 UTC', 'created_at' => '2022-04-26 18:30:53 UTC',
'performed_via_github_app' => nil 'performed_via_github_app' => nil

View File

@ -2735,6 +2735,33 @@ RSpec.describe Repository do
end end
end end
describe '#changelog_config' do
let(:user) { create(:user) }
let(:changelog_config_path) { Gitlab::Changelog::Config::DEFAULT_FILE_PATH }
before do
repository.create_file(
user,
changelog_config_path,
'CONTENT',
message: '...',
branch_name: 'master'
)
end
context 'when there is a changelog_config_path at the commit' do
it 'returns the content' do
expect(repository.changelog_config(repository.commit.sha, changelog_config_path)).to eq('CONTENT')
end
end
context 'when there is no changelog_config_path at the commit' do
it 'returns nil' do
expect(repository.changelog_config(repository.commit.parent.sha, changelog_config_path)).to be_nil
end
end
end
describe '#route_map_for' do describe '#route_map_for' do
before do before do
repository.create_file(User.last, '.gitlab/route-map.yml', 'CONTENT', message: 'Add .gitlab/route-map.yml', branch_name: 'master') repository.create_file(User.last, '.gitlab/route-map.yml', 'CONTENT', message: 'Add .gitlab/route-map.yml', branch_name: 'master')

View File

@ -784,6 +784,40 @@ RSpec.describe API::Repositories do
expect(json_response['notes']).to be_present expect(json_response['notes']).to be_present
end end
it 'supports specified config file path' do
spy = instance_spy(Repositories::ChangelogService)
expect(Repositories::ChangelogService)
.to receive(:new)
.with(
project,
user,
version: '1.0.0',
from: 'foo',
to: 'bar',
date: DateTime.new(2020, 1, 1),
trailer: 'Foo',
config_file: 'specified_changelog_config.yml'
)
.and_return(spy)
expect(spy).to receive(:execute).with(commit_to_changelog: false)
get(
api("/projects/#{project.id}/repository/changelog", user),
params: {
version: '1.0.0',
from: 'foo',
to: 'bar',
date: '2020-01-01',
trailer: 'Foo',
config_file: 'specified_changelog_config.yml'
}
)
expect(response).to have_gitlab_http_status(:ok)
end
context 'when previous tag version does not exist' do context 'when previous tag version does not exist' do
it_behaves_like '422 response' do it_behaves_like '422 response' do
let(:request) { get api("/projects/#{project.id}/repository/changelog", user), params: { version: 'v0.0.0' } } let(:request) { get api("/projects/#{project.id}/repository/changelog", user), params: { version: 'v0.0.0' } }
@ -905,5 +939,45 @@ RSpec.describe API::Repositories do
expect(response).to have_gitlab_http_status(:unprocessable_entity) expect(response).to have_gitlab_http_status(:unprocessable_entity)
expect(json_response['message']).to eq('Failed to generate the changelog: oops') expect(json_response['message']).to eq('Failed to generate the changelog: oops')
end end
it "support specified config file path" do
spy = instance_spy(Repositories::ChangelogService)
expect(Repositories::ChangelogService)
.to receive(:new)
.with(
project,
user,
version: '1.0.0',
from: 'foo',
to: 'bar',
date: DateTime.new(2020, 1, 1),
branch: 'kittens',
trailer: 'Foo',
config_file: 'specified_changelog_config.yml',
file: 'FOO.md',
message: 'Commit message'
)
.and_return(spy)
allow(spy).to receive(:execute).with(commit_to_changelog: true)
post(
api("/projects/#{project.id}/repository/changelog", user),
params: {
version: '1.0.0',
from: 'foo',
to: 'bar',
date: '2020-01-01',
branch: 'kittens',
trailer: 'Foo',
config_file: 'specified_changelog_config.yml',
file: 'FOO.md',
message: 'Commit message'
}
)
expect(response).to have_gitlab_http_status(:ok)
end
end end
end end

View File

@ -194,6 +194,25 @@ RSpec.describe Repositories::ChangelogService do
end end
end end
end end
context 'with specified changelog config file path' do
it 'return specified changelog content' do
config = Gitlab::Changelog::Config.from_hash(project, { 'template' => 'specified_changelog_content' }, creator)
allow(Gitlab::Changelog::Config)
.to receive(:from_git)
.with(project, creator, 'specified_changelog_config.yml')
.and_return(config)
described_class
.new(project, creator, version: '1.0.0', from: sha1, config_file: 'specified_changelog_config.yml')
.execute(commit_to_changelog: commit_to_changelog)
changelog = project.repository.blob_at('master', 'CHANGELOG.md')&.data
expect(changelog).to include('specified_changelog_content')
end
end
end end
describe '#start_of_commit_range' do describe '#start_of_commit_range' do

View File

@ -54,25 +54,6 @@ RSpec.describe WaitableWorker do
worker.bulk_perform_and_wait(arguments) worker.bulk_perform_and_wait(arguments)
end end
context 'when the feature flag `inline_project_authorizations_refresh_only_for_single_element` is turned off' do
before do
stub_feature_flags(inline_project_authorizations_refresh_only_for_single_element: false)
end
it 'inlines the jobs' do
args_list = [[1], [2], [3]]
expect(worker).to receive(:bulk_perform_inline).with(args_list).and_call_original
expect(Gitlab::AppJsonLogger).to(
receive(:info).with(a_hash_including('message' => 'running inline',
'class' => 'Gitlab::Foo::Bar::DummyWorker',
'job_status' => 'running',
'queue' => 'foo_bar_dummy'))
.exactly(3).times)
worker.bulk_perform_and_wait(args_list)
end
end
end end
context '>= 4 jobs' do context '>= 4 jobs' do