From 089e3f46f730d9ee2131825636a6ae61a42acb16 Mon Sep 17 00:00:00 2001 From: Pavel Balashou Date: Wed, 25 Feb 2026 11:05:33 +0100 Subject: [PATCH] Address Rubocop complaints volume 1. --- .../import/jira_import_state_machine.rb | 26 +- app/models/import/jira_user.rb | 4 +- .../import/jira_fetch_groups_and_users_job.rb | 20 +- app/workers/import/jira_fetch_projects_job.rb | 16 +- .../jira_import_groups_and_users_job.rb | 12 +- .../import/jira_import_projects_job.rb | 14 +- .../jira_open_project_reference_creation.rb | 14 +- app/workers/import/jira_revert_import_job.rb | 32 +-- config/initializers/instrumentation.rb | 4 +- config/initializers/statesman.rb | 2 + ...0927215339_create_jira_migration_tables.rb | 18 +- script/jira/gen_jira_projects.rb | 17 +- .../import/jira/instances_controller_spec.rb | 5 +- spec/rails_helper.rb | 10 +- .../import/jira_wiki_markup_converter_spec.rb | 6 +- .../import/jira_workers_integration_spec.rb | 237 ------------------ 16 files changed, 103 insertions(+), 334 deletions(-) delete mode 100644 spec/workers/import/jira_workers_integration_spec.rb diff --git a/app/models/import/jira_import_state_machine.rb b/app/models/import/jira_import_state_machine.rb index 03c2b6c1463..c9e31175dbf 100644 --- a/app/models/import/jira_import_state_machine.rb +++ b/app/models/import/jira_import_state_machine.rb @@ -78,13 +78,13 @@ module Import transition from: GROUPS_AND_USERS_FETCHING, to: [GROUPS_AND_USERS_FETCHING_ERROR, GROUPS_AND_USERS_FETCHING_CANCELLING, GROUPS_AND_USERS_FETCHING_DONE] - transition from: GROUPS_AND_USERS_FETCHING_CANCELLING, to: [GROUPS_AND_USERS_FETCHING_CANCELLED] + transition from: GROUPS_AND_USERS_FETCHING_CANCELLING, to: [GROUPS_AND_USERS_FETCHING_CANCELLED] transition from: GROUPS_AND_USERS_FETCHING_ERROR, to: [GROUPS_AND_USERS_FETCHING] transition from: GROUPS_AND_USERS_FETCHING_DONE, to: [GROUPS_AND_USERS_IMPORTING] - transition from: GROUPS_AND_USERS_IMPORTING, to: [GROUPS_AND_USERS_IMPORTING_ERROR, - GROUPS_AND_USERS_IMPORTING_DONE] - transition from: GROUPS_AND_USERS_IMPORTING_ERROR, to: [GROUPS_AND_USERS_IMPORTING] - transition from: GROUPS_AND_USERS_IMPORTING_DONE, to: [IMPORT_SCOPE] + transition from: GROUPS_AND_USERS_IMPORTING, to: [GROUPS_AND_USERS_IMPORTING_ERROR, + GROUPS_AND_USERS_IMPORTING_DONE] + transition from: GROUPS_AND_USERS_IMPORTING_ERROR, to: [GROUPS_AND_USERS_IMPORTING] + transition from: GROUPS_AND_USERS_IMPORTING_DONE, to: [IMPORT_SCOPE] transition from: IMPORT_SCOPE, to: [CONFIGURING] transition from: CONFIGURING, to: [PROJECTS_META_FETCHING] transition from: PROJECTS_META_FETCHING, to: [PROJECTS_META_DONE, PROJECTS_META_ERROR] @@ -98,35 +98,35 @@ module Import transition from: REVERT_CANCELLED, to: [REVERTING] transition from: REVERT_ERROR, to: [REVERTING] - after_transition(to: :groups_and_users_fetching) do |jira_import, transition| + after_transition(to: :groups_and_users_fetching) do |jira_import, _transition| Import::JiraFetchGroupsAndUsersJob.perform_later(jira_import.id) end - after_transition(to: :groups_and_users_importing) do |jira_import, transition| + after_transition(to: :groups_and_users_importing) do |jira_import, _transition| Import::JiraImportGroupsAndUsersJob.perform_later(jira_import.id) end - after_transition(to: :groups_and_users_fetching_done) do |jira_import, transition| + after_transition(to: :groups_and_users_fetching_done) do |jira_import, _transition| jira_import.update_column(:cursor, nil) end - after_transition(to: :groups_and_users_importing_done) do |jira_import, transition| + after_transition(to: :groups_and_users_importing_done) do |jira_import, _transition| jira_import.update_column(:cursor, nil) end - after_transition(to: :reverted) do |jira_import, transition| + after_transition(to: :reverted) do |jira_import, _transition| jira_import.update_column(:cursor, nil) end - after_transition(to: :instance_meta_fetching) do |jira_import, transition| + after_transition(to: :instance_meta_fetching) do |jira_import, _transition| Import::JiraInstanceMetaDataJob.perform_later(jira_import.id) end - after_transition(to: :projects_meta_fetching) do |jira_import, transition| + after_transition(to: :projects_meta_fetching) do |jira_import, _transition| Import::JiraProjectsMetaDataJob.perform_later(jira_import.id) end - after_transition(to: :importing) do |jira_import, transition| + after_transition(to: :importing) do |jira_import, _transition| Import::JiraFetchAndImportProjectsJob.perform_later(jira_import.id) end diff --git a/app/models/import/jira_user.rb b/app/models/import/jira_user.rb index e6795e87de1..415cef51b65 100644 --- a/app/models/import/jira_user.rb +++ b/app/models/import/jira_user.rb @@ -40,8 +40,8 @@ module Import end def to_op_attributes - firstname = payload["displayName"].split(" ")[0..-2].join(" ") - lastname = payload["displayName"].split(" ")[-1] + firstname = payload["displayName"].split[0..-2].join(" ") + lastname = payload["displayName"].split[-1] { login: payload["name"], password: SecureRandom.uuid, diff --git a/app/workers/import/jira_fetch_groups_and_users_job.rb b/app/workers/import/jira_fetch_groups_and_users_job.rb index 4490205d9e7..26e67cc07ad 100644 --- a/app/workers/import/jira_fetch_groups_and_users_job.rb +++ b/app/workers/import/jira_fetch_groups_and_users_job.rb @@ -33,7 +33,7 @@ module Import include JobIteration::Iteration class GroupMembersEnumerator - def initialize(jira_client, group_name:, page_size: 30, cursor:) + def initialize(jira_client, group_name:, cursor:, page_size: 30) @jira_client = jira_client @group_name = group_name @page = @jira_client.group_members(group_name:, start_at: cursor, max_results: page_size) @@ -41,10 +41,10 @@ module Import # Jira DC has it is own page limit configuration. # Therefore it makes sense to respect it. server_page_size = @page["maxResults"] - @page_size = if server_page_size != page_size - server_page_size - else + @page_size = if server_page_size == page_size page_size + else + server_page_size end @cursor = cursor || 0 end @@ -65,10 +65,10 @@ module Import # Jira DC has it is own page limit configuration. # Therefore it makes sense to respect it. server_page_size = @page["maxResults"] - @page_size = if @page_size != server_page_size - server_page_size - else + @page_size = if @page_size == server_page_size @page_size + else + server_page_size end break if @page["isLast"] @@ -98,7 +98,7 @@ module Import def build_enumerator(jira_import_id, cursor:) jira_import = Import::JiraImport.find(jira_import_id) - group_names = jira_import.client.groups["groups"].map { |g| g["name"] } + group_names = jira_import.client.groups["groups"].pluck("name") enumerator_builder.nested( [ ->(cursor) { enumerator_builder.array(group_names, cursor:) }, @@ -121,7 +121,7 @@ module Import def each_iteration(users_batch, jira_import_id) jira_import = Import::JiraImport.find(jira_import_id) jira_client = jira_import.client - updated_at = Time.now + updated_at = Time.zone.now created_at = updated_at users_upsert_data = users_batch.map do |jira_user| jira_user_key = jira_user.fetch("key") @@ -137,7 +137,7 @@ module Import updated_at: } end - Import::JiraUser.upsert_all(users_upsert_data, unique_by: [:jira_id, :jira_user_key]) + Import::JiraUser.upsert_all(users_upsert_data, unique_by: %i[jira_id jira_user_key]) end end end diff --git a/app/workers/import/jira_fetch_projects_job.rb b/app/workers/import/jira_fetch_projects_job.rb index b0ab1c403c6..84dfc6aaa62 100644 --- a/app/workers/import/jira_fetch_projects_job.rb +++ b/app/workers/import/jira_fetch_projects_job.rb @@ -35,7 +35,7 @@ module Import project_ids = jira_import.project_ids jira = jira_import.jira jira_id = jira.id - updated_at = Time.now + updated_at = Time.zone.now created_at = updated_at jira_client = Import::JiraClient.new(url: jira.url, personal_access_token: jira.personal_access_token) @@ -51,7 +51,7 @@ module Import updated_at: } end - Import::JiraIssueType.upsert_all(issue_types_upsert_data, unique_by: [:jira_id, :jira_issue_type_id]) + Import::JiraIssueType.upsert_all(issue_types_upsert_data, unique_by: %i[jira_id jira_issue_type_id]) # PRIORITIES SYNC priorities = jira_client.priorities @@ -65,7 +65,7 @@ module Import updated_at: } end - Import::JiraPriority.upsert_all(priorities_upsert_data, unique_by: [:jira_id, :jira_priority_id]) + Import::JiraPriority.upsert_all(priorities_upsert_data, unique_by: %i[jira_id jira_priority_id]) # STATUSES SYNC statuses = jira_client.statuses @@ -79,7 +79,7 @@ module Import updated_at: } end - Import::JiraStatus.upsert_all(statuses_upsert_data, unique_by: [:jira_id, :jira_status_id]) + Import::JiraStatus.upsert_all(statuses_upsert_data, unique_by: %i[jira_id jira_status_id]) # PROJECTS SYNC projects_upsert_data = jira_client.projects.map do |p| @@ -92,10 +92,10 @@ module Import updated_at: } end - Import::JiraProject.upsert_all(projects_upsert_data, unique_by: [:jira_id, :jira_project_id]) + Import::JiraProject.upsert_all(projects_upsert_data, unique_by: %i[jira_id jira_project_id]) # ISSUES SYNC - Import::JiraProject.where(jira_id:, jira_project_id: project_ids).each do |jira_project| + Import::JiraProject.where(jira_id:, jira_project_id: project_ids).find_each do |jira_project| jql = "project=#{jira_project.payload['key']}" result = jira_client.issues(jql:, start_at: 0, @@ -114,7 +114,7 @@ module Import updated_at: } end - Import::JiraIssue.upsert_all(issues_upsert_data, unique_by: [:jira_id, :jira_issue_id]) + Import::JiraIssue.upsert_all(issues_upsert_data, unique_by: %i[jira_id jira_issue_id]) while total > start_at + max_results start_at += max_results result = jira_client.issues(jql:, @@ -134,7 +134,7 @@ module Import updated_at: } end - Import::JiraIssue.upsert_all(issues_upsert_data, unique_by: [:jira_id, :jira_issue_id]) + Import::JiraIssue.upsert_all(issues_upsert_data, unique_by: %i[jira_id jira_issue_id]) end end end diff --git a/app/workers/import/jira_import_groups_and_users_job.rb b/app/workers/import/jira_import_groups_and_users_job.rb index fab232f488d..5845ea0f3d3 100644 --- a/app/workers/import/jira_import_groups_and_users_job.rb +++ b/app/workers/import/jira_import_groups_and_users_job.rb @@ -68,7 +68,7 @@ module Import call = Users::CreateService .new(user: User.system) .call(jira_user.to_op_attributes) - call.on_success do |result| + call.on_success do |_result| create_reference!( op_leg: call.result, jira_leg: jira_user, @@ -76,7 +76,7 @@ module Import uses_existing: false ) end - call.on_failure do |result| + call.on_failure do |_result| if call.errors.find { |error| error.type == :taken }.present? user = jira_user.try_to_find_existing_op_users.first if user.present? @@ -94,9 +94,7 @@ module Import end end - jira_user_groups = jira_user.payload["groups"]["items"].map do |item| - item["name"] - end + jira_user_groups = jira_user.payload["groups"]["items"].pluck("name") jira_user_groups.each do |group_name| call = Groups::CreateService @@ -111,7 +109,7 @@ module Import uses_existing: false ) end - call.on_failure do |result| + call.on_failure do |_result| if call.errors.find { |error| error.type == :taken }.present? group = Group.where(name: group_name).first if group.present? @@ -132,7 +130,7 @@ module Import jira_import_id:, jira_entity_id: jira_user.id, jira_entity_class: jira_user.class.to_s - ).pluck(:op_entity_id).first + ).pick(:op_entity_id) group = Group.find_by!(name: group_name) Groups::AddUsersService .new(group, current_user: User.system) diff --git a/app/workers/import/jira_import_projects_job.rb b/app/workers/import/jira_import_projects_job.rb index 2f37e7695fc..d2acda022e8 100644 --- a/app/workers/import/jira_import_projects_job.rb +++ b/app/workers/import/jira_import_projects_job.rb @@ -46,11 +46,11 @@ module Import service_call = Roles::CreateService.new(user:).call( name: "JiraMember", - permissions: [:add_work_packages, - :view_work_packages, - :add_work_package_comments, - :add_work_package_attachments, - :work_package_assigned] + permissions: %i[add_work_packages + view_work_packages + add_work_package_comments + add_work_package_attachments + work_package_assigned] ) if service_call.success? create_reference!( @@ -64,7 +64,7 @@ module Import end project_role = Role.find_by!(name: "JiraMember") - Import::JiraProject.where(jira_id:, jira_project_id: project_ids).each do |jira_project| + Import::JiraProject.where(jira_id:, jira_project_id: project_ids).find_each do |jira_project| ### PROJECT service_call = Projects::CreateService .new(user:) @@ -90,7 +90,7 @@ module Import jira_import:, uses_existing: false ) - Import::JiraIssue.where(jira_id:, jira_project_id: jira_project.id).each do |jira_issue| + Import::JiraIssue.where(jira_id:, jira_project_id: jira_project.id).find_each do |jira_issue| ### TYPE issue_type = jira_issue.payload["fields"]["issuetype"] type = Type.where("LOWER(name) = LOWER(?)", issue_type["name"]).first diff --git a/app/workers/import/jira_open_project_reference_creation.rb b/app/workers/import/jira_open_project_reference_creation.rb index 886dec3e526..70376dced8e 100644 --- a/app/workers/import/jira_open_project_reference_creation.rb +++ b/app/workers/import/jira_open_project_reference_creation.rb @@ -35,13 +35,13 @@ module Import def create_reference!(op_leg:, jira_leg:, jira_import:, uses_existing:) Import::JiraOpenProjectReference.insert_all( [ - op_entity_id: op_leg.id, - op_entity_class: op_leg.class.to_s, - jira_entity_id: jira_leg&.id, - jira_entity_class: jira_leg&.class&.to_s, - jira_import_id: jira_import.id, - jira_id: jira_import.jira.id, - uses_existing: + { op_entity_id: op_leg.id, + op_entity_class: op_leg.class.to_s, + jira_entity_id: jira_leg&.id, + jira_entity_class: jira_leg&.class&.to_s, + jira_import_id: jira_import.id, + jira_id: jira_import.jira.id, + uses_existing: } ], unique_by: %i[op_entity_id op_entity_class] ) diff --git a/app/workers/import/jira_revert_import_job.rb b/app/workers/import/jira_revert_import_job.rb index 010b906412f..2a824582494 100644 --- a/app/workers/import/jira_revert_import_job.rb +++ b/app/workers/import/jira_revert_import_job.rb @@ -83,9 +83,9 @@ module Import .where(jira_import_id: @jira_import.id) .where(op_entity_class: "Project") .find_each do |ref| - op_leg = ref.op_leg - service_call = ::Projects::DeleteService.new(user: @user, model: op_leg).call - raise service_call.message if service_call.failure? + op_leg = ref.op_leg + service_call = ::Projects::DeleteService.new(user: @user, model: op_leg).call + raise service_call.message if service_call.failure? end end @@ -94,9 +94,9 @@ module Import .where(jira_import_id: @jira_import.id) .where(op_entity_class: ["Type", "IssuePriority", "Status"]) .find_each do |ref| - op_leg = ref.op_leg - uses_existing = ref.uses_existing - op_leg.destroy! unless uses_existing + op_leg = ref.op_leg + uses_existing = ref.uses_existing + op_leg.destroy! unless uses_existing end end @@ -105,10 +105,10 @@ module Import .where(jira_import_id: @jira_import.id) .where(op_entity_class: "User") .find_each do |ref| - op_leg = ref.op_leg - # EmptyContract is used to make deletion not dependent on Setting.users_deletable_by_admins - service_call = ::Users::DeleteService.new(user: @user, model: op_leg, contract_class: EmptyContract).call - raise service_call.message if service_call.failure? + op_leg = ref.op_leg + # EmptyContract is used to make deletion not dependent on Setting.users_deletable_by_admins + service_call = ::Users::DeleteService.new(user: @user, model: op_leg, contract_class: EmptyContract).call + raise service_call.message if service_call.failure? end end @@ -117,9 +117,9 @@ module Import .where(jira_import_id: @jira_import.id) .where(op_entity_class: "Group") .find_each do |ref| - op_leg = ref.op_leg - service_call = ::Groups::DeleteService.new(user: @user, model: op_leg).call - raise service_call.message if service_call.failure? + op_leg = ref.op_leg + service_call = ::Groups::DeleteService.new(user: @user, model: op_leg).call + raise service_call.message if service_call.failure? end end @@ -128,9 +128,9 @@ module Import .where(jira_import_id: @jira_import.id) .where(op_entity_class: "ProjectRole") .find_each do |ref| - op_leg = ref.op_leg - service_call = ::Roles::DeleteService.new(user: @user, model: op_leg).call - raise service_call.message if service_call.failure? + op_leg = ref.op_leg + service_call = ::Roles::DeleteService.new(user: @user, model: op_leg).call + raise service_call.message if service_call.failure? end end diff --git a/config/initializers/instrumentation.rb b/config/initializers/instrumentation.rb index 909bfa2f3f7..587579c5eb7 100644 --- a/config/initializers/instrumentation.rb +++ b/config/initializers/instrumentation.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Possible events related to job-iteration. # https://github.com/Shopify/job-iteration/blob/main/guides/best-practices.md#instrumentation # build_enumerator.iteration @@ -15,6 +17,6 @@ ActiveSupport::Notifications.monotonic_subscribe("each_iteration.iteration") do max_iteration_runtime = 3.minutes if elapsed >= max_iteration_runtime Rails.logger.warn "[Iteration] job_class=#{tags[:job_class]} " \ - "each_iteration runtime exceeded limit of #{max_iteration_runtime}s" + "each_iteration runtime exceeded limit of #{max_iteration_runtime}s" end end diff --git a/config/initializers/statesman.rb b/config/initializers/statesman.rb index a94bf3406c0..2fd1b7ae630 100644 --- a/config/initializers/statesman.rb +++ b/config/initializers/statesman.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # config/initializers/statesman.rb Statesman.configure do storage_adapter(Statesman::Adapters::ActiveRecord) diff --git a/db/migrate/20250927215339_create_jira_migration_tables.rb b/db/migrate/20250927215339_create_jira_migration_tables.rb index 40d5cdc4aa5..953a5a13c86 100644 --- a/db/migrate/20250927215339_create_jira_migration_tables.rb +++ b/db/migrate/20250927215339_create_jira_migration_tables.rb @@ -30,7 +30,7 @@ class CreateJiraMigrationTables < ActiveRecord::Migration[8.0] t.string :jira_project_id t.references :jira, foreign_key: { on_delete: :cascade, on_update: :cascade } t.references :jira_import, foreign_key: { on_delete: :cascade, on_update: :cascade } - t.index [:jira_id, :jira_project_id], unique: true + t.index %i[jira_id jira_project_id], unique: true t.timestamps end @@ -48,7 +48,7 @@ class CreateJiraMigrationTables < ActiveRecord::Migration[8.0] t.string :jira_issue_id t.references :jira, foreign_key: { on_delete: :cascade, on_update: :cascade } t.references :jira_import, foreign_key: { on_delete: :cascade, on_update: :cascade } - t.index [:jira_id, :jira_issue_id], unique: true + t.index %i[jira_id jira_issue_id], unique: true t.timestamps end @@ -58,7 +58,7 @@ class CreateJiraMigrationTables < ActiveRecord::Migration[8.0] t.string :jira_issue_type_id t.references :jira, foreign_key: { on_delete: :cascade, on_update: :cascade } t.references :jira_import, foreign_key: { on_delete: :cascade, on_update: :cascade } - t.index [:jira_id, :jira_issue_type_id], unique: true + t.index %i[jira_id jira_issue_type_id], unique: true t.timestamps end @@ -68,7 +68,7 @@ class CreateJiraMigrationTables < ActiveRecord::Migration[8.0] t.string :jira_priority_id t.references :jira, foreign_key: { on_delete: :cascade, on_update: :cascade } t.references :jira_import, foreign_key: { on_delete: :cascade, on_update: :cascade } - t.index [:jira_id, :jira_priority_id], unique: true + t.index %i[jira_id jira_priority_id], unique: true t.timestamps end @@ -78,7 +78,7 @@ class CreateJiraMigrationTables < ActiveRecord::Migration[8.0] t.string :jira_status_id t.references :jira, foreign_key: { on_delete: :cascade, on_update: :cascade } t.references :jira_import, foreign_key: { on_delete: :cascade, on_update: :cascade } - t.index [:jira_id, :jira_status_id], unique: true + t.index %i[jira_id jira_status_id], unique: true t.timestamps end @@ -88,7 +88,7 @@ class CreateJiraMigrationTables < ActiveRecord::Migration[8.0] t.string :jira_status_category_id t.references :jira, foreign_key: { on_delete: :cascade, on_update: :cascade } t.references :jira_import, foreign_key: { on_delete: :cascade, on_update: :cascade } - t.index [:jira_id, :jira_status_category_id], unique: true + t.index %i[jira_id jira_status_category_id], unique: true t.timestamps end @@ -98,7 +98,7 @@ class CreateJiraMigrationTables < ActiveRecord::Migration[8.0] t.string :jira_field_id t.references :jira, foreign_key: { on_delete: :cascade, on_update: :cascade } t.references :jira_import, foreign_key: { on_delete: :cascade, on_update: :cascade } - t.index [:jira_id, :jira_field_id], unique: true + t.index %i[jira_id jira_field_id], unique: true t.timestamps end @@ -108,7 +108,7 @@ class CreateJiraMigrationTables < ActiveRecord::Migration[8.0] t.string :jira_user_key t.references :jira, foreign_key: { on_delete: :cascade, on_update: :cascade } t.references :jira_import, foreign_key: { on_delete: :cascade, on_update: :cascade } - t.index [:jira_id, :jira_user_key], unique: true + t.index %i[jira_id jira_user_key], unique: true t.timestamps end @@ -121,7 +121,7 @@ class CreateJiraMigrationTables < ActiveRecord::Migration[8.0] t.boolean :uses_existing t.references :jira, foreign_key: { on_delete: :cascade, on_update: :cascade } t.references :jira_import, foreign_key: { on_delete: :cascade, on_update: :cascade } - t.index [:op_entity_id, :op_entity_class], unique: true + t.index %i[op_entity_id op_entity_class], unique: true t.timestamps end diff --git a/script/jira/gen_jira_projects.rb b/script/jira/gen_jira_projects.rb index e084cdf2551..6d66a19122e 100755 --- a/script/jira/gen_jira_projects.rb +++ b/script/jira/gen_jira_projects.rb @@ -132,7 +132,7 @@ class JiraProjectCreator "This is a duplicate of the %s issue.", "Closing as won't fix. The %s behavior is expected.", "Reopening this - the fix didn't fully address %s.", - "Updated the priority based on customer feedback.", + "Updated the priority based on customer feedback." ].freeze PROJECT_CATEGORIES = [ @@ -496,15 +496,14 @@ class JiraProjectCreator created_users = create_users(num_users) @users += created_users puts "Created #{created_users.length.to_s.green} users" - puts else # Fetch existing users to use for assignments puts "Fetching existing users...".cyan existing_users = @dry_run ? sample_users : fetch_users @users += existing_users puts "Found #{existing_users.length.to_s.green} existing users" - puts end + puts # Fetch available statuses statuses = @dry_run ? sample_statuses : fetch_statuses @@ -626,7 +625,8 @@ class JiraProjectCreator begin result = post("/rest/api/2/user", payload) # Store password for later use with basic auth (for comments) - { "name" => result["name"], "displayName" => result["displayName"], "emailAddress" => result["emailAddress"], "password" => password } + { "name" => result["name"], "displayName" => result["displayName"], "emailAddress" => result["emailAddress"], + "password" => password } rescue StandardError => e puts "⚠ Warning:".yellow + " Could not create user #{username}: #{e.message}" nil @@ -666,9 +666,12 @@ class JiraProjectCreator def sample_users [ - { "name" => "john.smith", "displayName" => "John Smith", "emailAddress" => "john.smith@example.com", "password" => "password123" }, - { "name" => "jane.doe", "displayName" => "Jane Doe", "emailAddress" => "jane.doe@example.com", "password" => "password123" }, - { "name" => "bob.wilson", "displayName" => "Bob Wilson", "emailAddress" => "bob.wilson@example.com", "password" => "password123" } + { "name" => "john.smith", "displayName" => "John Smith", "emailAddress" => "john.smith@example.com", + "password" => "password123" }, + { "name" => "jane.doe", "displayName" => "Jane Doe", "emailAddress" => "jane.doe@example.com", + "password" => "password123" }, + { "name" => "bob.wilson", "displayName" => "Bob Wilson", "emailAddress" => "bob.wilson@example.com", + "password" => "password123" } ] end diff --git a/spec/controllers/admin/import/jira/instances_controller_spec.rb b/spec/controllers/admin/import/jira/instances_controller_spec.rb index c3ccae95702..b67a3389a6a 100644 --- a/spec/controllers/admin/import/jira/instances_controller_spec.rb +++ b/spec/controllers/admin/import/jira/instances_controller_spec.rb @@ -492,8 +492,9 @@ RSpec.describe Admin::Import::Jira::InstancesController do it "uses the stored token when personal_access_token param is blank" do post :test, params: { id: jira_with_token.id, url: "https://jira.example.com", personal_access_token: "" }, - format: :turbo_stream - expect(Import::JiraClient).to have_received(:new).with(url: "https://jira.example.com", personal_access_token: "stored_token") + format: :turbo_stream + expect(Import::JiraClient).to have_received(:new).with(url: "https://jira.example.com", + personal_access_token: "stored_token") end end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index a21a49d4494..085f96e6ab4 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -70,16 +70,16 @@ require "paper_trail/frameworks/rspec" require_relative "support/parallel_helper" require_relative "support/download_list" require_relative "support/capybara" -Dir[Rails.root.join("spec/support/**/*.rb")].sort.each { |f| require_relative f } -Dir[Rails.root.join("spec/features/support/**/*.rb")].sort.each { |f| require f } -Dir[Rails.root.join("spec/lib/api/v3/support/**/*.rb")].sort.each { |f| require f } -Dir[Rails.root.join("spec/requests/api/v3/support/**/*.rb")].sort.each { |f| require f } +Rails.root.glob("spec/support/**/*.rb").each { |f| require_relative f } +Rails.root.glob("spec/features/support/**/*.rb").each { |f| require f } +Rails.root.glob("spec/lib/api/v3/support/**/*.rb").each { |f| require f } +Rails.root.glob("spec/requests/api/v3/support/**/*.rb").each { |f| require f } # Checks for pending migration and applies them before tests are run. # If you are not using ActiveRecord, you can remove this line. ActiveRecord::Migration.maintain_test_schema! unless ENV["CI"] -ActiveRecord::Base.logger = ActiveSupport::Logger.new(STDOUT, level: :debug) if ENV["SQL_DEBUG_OUTPUT"] +ActiveRecord::Base.logger = ActiveSupport::Logger.new($stdout, level: :debug) if ENV["SQL_DEBUG_OUTPUT"] RSpec.configure do |config| # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures diff --git a/spec/services/import/jira_wiki_markup_converter_spec.rb b/spec/services/import/jira_wiki_markup_converter_spec.rb index f619b245fb9..339d540dc49 100644 --- a/spec/services/import/jira_wiki_markup_converter_spec.rb +++ b/spec/services/import/jira_wiki_markup_converter_spec.rb @@ -466,9 +466,9 @@ RSpec.describe Import::JiraWikiMarkupConverter do end let(:output) do "panel text\n" \ - "panel text\n" \ - "panel text\n" \ - "panel text" + "panel text\n" \ + "panel text\n" \ + "panel text" end it "does produce all code blocks" do diff --git a/spec/workers/import/jira_workers_integration_spec.rb b/spec/workers/import/jira_workers_integration_spec.rb deleted file mode 100644 index add27898ea1..00000000000 --- a/spec/workers/import/jira_workers_integration_spec.rb +++ /dev/null @@ -1,237 +0,0 @@ -# frozen_string_literal: true - -#-- copyright -# OpenProject is an open source project management software. -# Copyright (C) the OpenProject GmbH -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License version 3. -# -# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -# Copyright (C) 2006-2013 Jean-Philippe Lang -# Copyright (C) 2010-2013 the ChiliProject Team -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# See COPYRIGHT and LICENSE files for more details. -#++ - -require "spec_helper" - -RSpec.describe("Jira workers integration", :webmock) do - it do - stub_request(:get, "http://jira-software.local/secure/attachment/10000/test.png") - .with( - headers: { - "Accept" => "application/json", - "Accept-Encoding" => "gzip, deflate", - "Authorization" => "Bearer ", - "User-Agent" => "OpenProject 17.2.0 HTTPX Client" - } - ) - .to_return(status: 200, body: Rails.root.join("spec/fixtures/files/image.png").read.to_s, headers: { "accept-ranges" => "bytes", - "cache-control" => "private, max-age=31536000", - "content-disposition" => "inline; filename*=UTF-8''test.png;", - "content-security-policy" => "sandbox", - "content-type" => "image/png", - "date" => "Mon, 26 Jan 2026 15:04:31 GMT", - "expires" => "Wed, 31 Dec 1969 23:59:59 GMT", - "referrer-policy" => "strict-origin-when-cross-origin", - "server-timing" => "threadId;desc=36", - "set-cookie" => "JSESSIONID=2874FED596DDBB7B0684E4E041E38068; Path=/; HttpOnly, atlassian.xsrf.token=BKKL-N2L6-7B3J-QCK5_edf8f5667143397d5c45e14bf1c9a6617bc84515_lin; Path=/", - "strict-transport-security" => "max-age=31536000", - "x-arequestid" => "904x339x1", - "x-asessionid" => "15y1bjv", - "x-content-type-options" => "nosniff", - "x-frame-options" => "SAMEORIGIN", - "x-seraph-loginreason" => "OK", - "x-xss-protection" => "1; mode=block", - "content-length" => "13147" }) - # OPEN PROJECT OBJECTS - author = create(:admin) - jira = create(:jira) - jira_import = create( - :jira_import, - status: "configured", - jira:, - projects: [{ "id" => "10002", "key" => "PROCESS1", "name" => "PROCESS_MANAGEMENT1" }, - { "id" => "10001", "key" => "KANBAN1", "name" => "KANBAN1" }], - author: - ) - create(:type_bug, :default) - create(:priority, name: "Medium") - create(:status, name: "Backlog") - - # JIRA OBJECTS - create( - :jira_user, - payload: { "key" => "JIRAUSER10000", "name" => "pavel.balashou", - "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "expand" => "groups,applicationRoles", "groups" => { "size" => 3, "items" => [{ "name" => "Group 1", "self" => "http://jira-software.local/rest/api/2/group?groupname=Group+1" }, { "name" => "jira-administrators", "self" => "http://jira-software.local/rest/api/2/group?groupname=jira-administrators" }, { "name" => "jira-software-users", "self" => "http://jira-software.local/rest/api/2/group?groupname=jira-software-users" }] }, "locale" => "en_US", "deleted" => false, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com", "lastLoginTime" => "2026-01-26T16:21:10+0000", "applicationRoles" => { "size" => 1, "items" => [] } }, - jira_user_key: "JIRAUSER10000", - jira:, - jira_import: - ) - create( - :jira_status, - payload: { "id" => "3", "name" => "In Progress", "self" => "http://jira-software.local/rest/api/2/status/3", - "iconUrl" => "http://jira-software.local/images/icons/statuses/inprogress.png", "description" => "This issue is being actively worked on at the moment by the assignee.", "statusCategory" => { "id" => 4, "key" => "indeterminate", "name" => "In Progress", "self" => "http://jira-software.local/rest/api/2/statuscategory/4", "colorName" => "inprogress" } }, - jira_status_id: "3", - jira:, - jira_import: - ) - create( - :jira_status, - payload: { "id" => "10002", "name" => "Backlog", "self" => "http://jira-software.local/rest/api/2/status/10002", - "iconUrl" => "http://jira-software.local/", "description" => "", "statusCategory" => { "id" => 2, "key" => "new", "name" => "To Do", "self" => "http://jira-software.local/rest/api/2/statuscategory/2", "colorName" => "default" } }, - jira_status_id: "10002", - jira:, - jira_import: - ) - create( - :jira_status, - payload: { "id" => "10001", "name" => "Done", "self" => "http://jira-software.local/rest/api/2/status/10001", - "iconUrl" => "http://jira-software.local/", "description" => "", "statusCategory" => { "id" => 3, "key" => "done", "name" => "Done", "self" => "http://jira-software.local/rest/api/2/statuscategory/3", "colorName" => "success" } }, - jira_status_id: "10001", - jira:, - jira_import: - ) - create( - :jira_priority, - payload: { "id" => "3", "name" => "Medium", "self" => "http://jira-software.local/rest/api/2/priority/3", - "iconUrl" => "http://jira-software.local/images/icons/priorities/medium.svg", "description" => "Has the potential to affect progress.", "statusColor" => "#ffab00" }, - jira_priority_id: "3", - jira:, - jira_import: - ) - create( - :jira_priority, - payload: { "id" => "10001", "name" => "MAXIMUM123", "self" => "http://jira-software.local/rest/api/2/priority/10001", - "iconUrl" => "http://jira-software.local/images/icons/priorities/critical.svg", "description" => "", "statusColor" => "#ffffff" }, - jira_priority_id: "10001", - jira:, - jira_import: - ) - create( - :jira_issue_type, - payload: { "id" => "10002", "name" => "Task", "self" => "http://jira-software.local/rest/api/2/issuetype/10002", - "iconUrl" => "http://jira-software.local/secure/viewavatar?size=xsmall&avatarId=10318&avatarType=issuetype", "subtask" => false, "avatarId" => 10318, "description" => "A task that needs to be done." }, - jira_issue_type_id: "10002", - jira:, - jira_import: - ) - create( - :jira_issue_type, - payload: { "id" => "10004", "name" => "Bug", "self" => "http://jira-software.local/rest/api/2/issuetype/10004", - "iconUrl" => "http://jira-software.local/secure/viewavatar?size=xsmall&avatarId=10303&avatarType=issuetype", "subtask" => false, "avatarId" => 10303, "description" => "A problem which impairs or prevents the functions of the product." }, - jira_issue_type_id: "10004", - jira:, - jira_import: - ) - - summary1 = "Test Story created by Pavel" - summary2 = "Define basic database structure for Jira entities" - description1 = "Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.\r\n\r\nLorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.\r\n\r\nLorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.\r\n\r\nLorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.\r\n\r\nLorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos." - description2 = "*About Scrum*\r\n\r\nScrum is an iterative approach to Agile software development. The methodology has been around since the 1980s but was popularised by Jeff Sutherland and Ken Schwaber.\r\n\r\nScrum breaks the development of a product down in to discrete iterations (termed Sprints) that each deliver functionality that could potentially be shipped to users.\r\n\r\nThe Scrum Alliance offers an excellent [introduction to Scrum|http://www.scrumalliance.org/resources/47] that provides an overview of key Scrum concepts, stakeholders, processes and artefacts.\r\n\r\n[~pavel.balashou]" - jira_projects = [ - create( - :jira_project, - jira_project_id: "10002", - payload: { "id" => "10002", "key" => "PROCESS1", "name" => "PROCESS_MANAGEMENT1", - "self" => "http://jira-software.local/rest/api/2/project/10002", "expand" => "description,lead,createdAt,createdBy,lastUpdatedAt,lastUpdatedBy,url,projectKeys", "archived" => false, "avatarUrls" => { "16x16" => "http://jira-software.local/secure/projectavatar?size=xsmall&avatarId=10324", "24x24" => "http://jira-software.local/secure/projectavatar?size=small&avatarId=10324", "32x32" => "http://jira-software.local/secure/projectavatar?size=medium&avatarId=10324", "48x48" => "http://jira-software.local/secure/projectavatar?avatarId=10324" }, "description" => "", "projectKeys" => ["PROCESS1"], "projectTypeKey" => "business" }, - jira:, - jira_import: - ), - create( - :jira_project, - jira_project_id: "10001", - payload: { "id" => "10001", "key" => "KANBAN1", "name" => "KANBAN1", - "self" => "http://jira-software.local/rest/api/2/project/10001", "expand" => "description,lead,createdAt,createdBy,lastUpdatedAt,lastUpdatedBy,url,projectKeys", "archived" => false, "avatarUrls" => { "16x16" => "http://jira-software.local/secure/projectavatar?size=xsmall&avatarId=10324", "24x24" => "http://jira-software.local/secure/projectavatar?size=small&avatarId=10324", "32x32" => "http://jira-software.local/secure/projectavatar?size=medium&avatarId=10324", "48x48" => "http://jira-software.local/secure/projectavatar?avatarId=10324" }, "description" => "", "projectKeys" => ["KANBAN1"], "projectTypeKey" => "software" }, - jira:, - jira_import: - ) - ] - create(:jira_issue, - payload: { "id" => "10023", "key" => "KANBAN1-1", "self" => "http://jira-software.local/rest/api/2/issue/10023", - "expand" => "operations,versionedRepresentations,editmeta,changelog,renderedFields", "fields" => { "votes" => { "self" => "http://jira-software.local/rest/api/2/issue/KANBAN1-1/votes", "votes" => 0, "hasVoted" => false }, "labels" => [], "status" => { "id" => "10002", "name" => "Backlog", "self" => "http://jira-software.local/rest/api/2/status/10002", "iconUrl" => "http://jira-software.local/", "description" => "", "statusCategory" => { "id" => 2, "key" => "new", "name" => "To Do", "self" => "http://jira-software.local/rest/api/2/statuscategory/2", "colorName" => "default" } }, "comment" => { "total" => 0, "startAt" => 0, "comments" => [], "maxResults" => 1000 }, "created" => "2025-09-27T19:54:09.000+0000", "creator" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "duedate" => nil, "project" => { "id" => "10001", "key" => "KANBAN1", "name" => "KANBAN1", "self" => "http://jira-software.local/rest/api/2/project/10001", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/projectavatar?size=xsmall&avatarId=10324", "24x24" => "http://jira-software.local/secure/projectavatar?size=small&avatarId=10324", "32x32" => "http://jira-software.local/secure/projectavatar?size=medium&avatarId=10324", "48x48" => "http://jira-software.local/secure/projectavatar?avatarId=10324" }, "projectTypeKey" => "software" }, "summary" => "Test Story created by Pavel", "updated" => "2025-11-11T11:35:54.000+0000", "watches" => { "self" => "http://jira-software.local/rest/api/2/issue/KANBAN1-1/watchers", "isWatching" => true, "watchCount" => 1 }, "worklog" => { "total" => 0, "startAt" => 0, "worklogs" => [], "maxResults" => 20 }, "assignee" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "priority" => { "id" => "10001", "name" => "MAXIMUM123", "self" => "http://jira-software.local/rest/api/2/priority/10001", "iconUrl" => "http://jira-software.local/images/icons/priorities/critical.svg" }, "progress" => { "total" => 0, "progress" => 0 }, "reporter" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "subtasks" => [], "versions" => [], "issuetype" => { "id" => "10004", "name" => "Bug", "self" => "http://jira-software.local/rest/api/2/issuetype/10004", "iconUrl" => "http://jira-software.local/secure/viewavatar?size=xsmall&avatarId=10303&avatarType=issuetype", "subtask" => false, "avatarId" => 10303, "description" => "A problem which impairs or prevents the functions of the product." }, "timespent" => nil, "workratio" => -1, "archivedby" => nil, "attachment" => [], "components" => [], "issuelinks" => [], "lastViewed" => "2025-11-11T11:36:14.767+0000", "resolution" => nil, "description" => description1, "environment" => nil, "fixVersions" => [], "archiveddate" => nil, "timeestimate" => nil, "timetracking" => {}, "resolutiondate" => nil, "aggregateprogress" => { "total" => 0, "progress" => 0 }, "customfield_10000" => "{summaryBean=com.atlassian.jira.plugin.devstatus.rest.SummaryBean@4cdbd778[summary={pullrequest=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@7ca60471[byInstanceType={},overall=PullRequestOverallBean{stateCount=0, state='OPEN', details=PullRequestOverallDetails{openCount=0, mergedCount=0, declinedCount=0}}], build=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@4bd69234[byInstanceType={},overall=com.atlassian.jira.plugin.devstatus.summary.beans.BuildOverallBean@79f92b3[failedBuildCount=0,successfulBuildCount=0,unknownBuildCount=0,count=0,lastUpdated=,lastUpdatedTimestamp=]], review=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@52cbca94[byInstanceType={},overall=com.atlassian.jira.plugin.devstatus.summary.beans.ReviewsOverallBean@2c628134[dueDate=,overDue=false,state=,stateCount=0,count=0,lastUpdated=,lastUpdatedTimestamp=]], deployment-environment=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@53daf1be[byInstanceType={},overall=com.atlassian.jira.plugin.devstatus.summary.beans.DeploymentOverallBean@28abeb7c[showProjects=false,successfulCount=0,topEnvironments=[],count=0,lastUpdated=,lastUpdatedTimestamp=]], repository=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@24380b97[byInstanceType={},overall=com.atlassian.jira.plugin.devstatus.summary.beans.CommitOverallBean@1c6b5505[count=0,lastUpdated=,lastUpdatedTimestamp=]], branch=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@18381037[byInstanceType={},overall=com.atlassian.jira.plugin.devstatus.summary.beans.BranchOverallBean@6f3ff847[count=0,lastUpdated=,lastUpdatedTimestamp=]]},configErrors=[],errors=[]], devSummaryJson={\"cachedValue\":{\"errors\":[],\"configErrors\":[],\"summary\":{\"pullrequest\":{\"overall\":{\"count\":0,\"lastUpdated\":null,\"stateCount\":0,\"state\":\"OPEN\",\"details\":{\"openCount\":0,\"mergedCount\":0,\"declinedCount\":0,\"total\":0},\"open\":true},\"byInstanceType\":{}},\"build\":{\"overall\":{\"count\":0,\"lastUpdated\":null,\"failedBuildCount\":0,\"successfulBuildCount\":0,\"unknownBuildCount\":0},\"byInstanceType\":{}},\"review\":{\"overall\":{\"count\":0,\"lastUpdated\":null,\"stateCount\":0,\"state\":null,\"dueDate\":null,\"overDue\":false,\"completed\":false},\"byInstanceType\":{}},\"deployment-environment\":{\"overall\":{\"count\":0,\"lastUpdated\":null,\"topEnvironments\":[],\"showProjects\":false,\"successfulCount\":0},\"byInstanceType\":{}},\"repository\":{\"overall\":{\"count\":0,\"lastUpdated\":null},\"byInstanceType\":{}},\"branch\":{\"overall\":{\"count\":0,\"lastUpdated\":null},\"byInstanceType\":{}}}},\"isStale\":false}}", "customfield_10100" => "0|i00053:", "customfield_10101" => nil, "customfield_10102" => nil, "customfield_10107" => nil, "customfield_10108" => nil, "customfield_10109" => nil, "customfield_10110" => nil, "customfield_10111" => nil, "aggregatetimespent" => nil, "timeoriginalestimate" => nil, "aggregatetimeestimate" => nil, "aggregatetimeoriginalestimate" => nil }, "changelog" => { "total" => 3, "startAt" => 0, "histories" => [{ "id" => "10300", "items" => [{ "to" => "10001", "from" => "3", "field" => "priority", "toString" => "MAXIMUM123", "fieldtype" => "jira", "fromString" => "Medium" }], "author" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "created" => "2025-11-11T11:02:34.764+0000" }, { "id" => "10301", "items" => [{ "to" => "10004", "from" => "10001", "field" => "issuetype", "toString" => "Bug", "fieldtype" => "jira", "fromString" => "Story" }], "author" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "created" => "2025-11-11T11:35:27.844+0000" }, { "id" => "10302", "items" => [{ "to" => "JIRAUSER10000", "from" => nil, "field" => "assignee", "toString" => "Pavel Balashou", "fieldtype" => "jira", "fromString" => nil }], "author" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "created" => "2025-11-11T11:35:54.887+0000" }], "maxResults" => 3 }, "renderedFields" => nil }, - jira_project_id: jira_projects[0].id, - jira_issue_id: "10023", - jira:, - jira_import:) - create(:jira_issue, - payload: { "id" => "10024", "key" => "PROCESS1-1", "self" => "http://jira-software.local/rest/api/2/issue/10024", - "expand" => "operations,versionedRepresentations,editmeta,changelog,renderedFields", "fields" => { "votes" => { "self" => "http://jira-software.local/rest/api/2/issue/PROCESS1-1/votes", "votes" => 0, "hasVoted" => false }, "labels" => [], "status" => { "id" => "3", "name" => "In Progress", "self" => "http://jira-software.local/rest/api/2/status/3", "iconUrl" => "http://jira-software.local/images/icons/statuses/inprogress.png", "description" => "This issue is being actively worked on at the moment by the assignee.", "statusCategory" => { "id" => 4, "key" => "indeterminate", "name" => "In Progress", "self" => "http://jira-software.local/rest/api/2/statuscategory/4", "colorName" => "inprogress" } }, "comment" => { "total" => 0, "startAt" => 0, "comments" => [], "maxResults" => 1000 }, "created" => "2025-09-27T21:19:06.000+0000", "creator" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "duedate" => nil, "project" => { "id" => "10002", "key" => "PROCESS1", "name" => "PROCESS_MANAGEMENT1", "self" => "http://jira-software.local/rest/api/2/project/10002", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/projectavatar?size=xsmall&avatarId=10324", "24x24" => "http://jira-software.local/secure/projectavatar?size=small&avatarId=10324", "32x32" => "http://jira-software.local/secure/projectavatar?size=medium&avatarId=10324", "48x48" => "http://jira-software.local/secure/projectavatar?avatarId=10324" }, "projectTypeKey" => "business" }, "summary" => "Define basic database structure for Jira entities", "updated" => "2025-09-27T21:19:21.000+0000", "watches" => { "self" => "http://jira-software.local/rest/api/2/issue/PROCESS1-1/watchers", "isWatching" => true, "watchCount" => 1 }, "worklog" => { "total" => 0, "startAt" => 0, "worklogs" => [], "maxResults" => 20 }, "assignee" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "priority" => { "id" => "3", "name" => "Medium", "self" => "http://jira-software.local/rest/api/2/priority/3", "iconUrl" => "http://jira-software.local/images/icons/priorities/medium.svg" }, "progress" => { "total" => 0, "progress" => 0 }, "reporter" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "subtasks" => [], "versions" => [], "issuetype" => { "id" => "10002", "name" => "Task", "self" => "http://jira-software.local/rest/api/2/issuetype/10002", "iconUrl" => "http://jira-software.local/secure/viewavatar?size=xsmall&avatarId=10318&avatarType=issuetype", "subtask" => false, "avatarId" => 10318, "description" => "A task that needs to be done." }, "timespent" => nil, "workratio" => -1, "archivedby" => nil, "attachment" => [], "components" => [], "issuelinks" => [], "lastViewed" => "2025-12-15T10:17:16.017+0000", "resolution" => nil, "description" => description2, "environment" => nil, "fixVersions" => [], "archiveddate" => nil, "timeestimate" => nil, "timetracking" => {}, "resolutiondate" => nil, "aggregateprogress" => { "total" => 0, "progress" => 0 }, "customfield_10000" => "{summaryBean=com.atlassian.jira.plugin.devstatus.rest.SummaryBean@3603b315[summary={pullrequest=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@11b1ed03[byInstanceType={},overall=PullRequestOverallBean{stateCount=0, state='OPEN', details=PullRequestOverallDetails{openCount=0, mergedCount=0, declinedCount=0}}], build=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@7add0bd[byInstanceType={},overall=com.atlassian.jira.plugin.devstatus.summary.beans.BuildOverallBean@19eaecbe[failedBuildCount=0,successfulBuildCount=0,unknownBuildCount=0,count=0,lastUpdated=,lastUpdatedTimestamp=]], review=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@2b46900f[byInstanceType={},overall=com.atlassian.jira.plugin.devstatus.summary.beans.ReviewsOverallBean@6db4f412[dueDate=,overDue=false,state=,stateCount=0,count=0,lastUpdated=,lastUpdatedTimestamp=]], deployment-environment=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@475f921[byInstanceType={},overall=com.atlassian.jira.plugin.devstatus.summary.beans.DeploymentOverallBean@4ab46a0d[showProjects=false,successfulCount=0,topEnvironments=[],count=0,lastUpdated=,lastUpdatedTimestamp=]], repository=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@556d4dbc[byInstanceType={},overall=com.atlassian.jira.plugin.devstatus.summary.beans.CommitOverallBean@1f333767[count=0,lastUpdated=,lastUpdatedTimestamp=]], branch=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@34247951[byInstanceType={},overall=com.atlassian.jira.plugin.devstatus.summary.beans.BranchOverallBean@5d2989da[count=0,lastUpdated=,lastUpdatedTimestamp=]]},configErrors=[],errors=[]], devSummaryJson={\"cachedValue\":{\"errors\":[],\"configErrors\":[],\"summary\":{\"pullrequest\":{\"overall\":{\"count\":0,\"lastUpdated\":null,\"stateCount\":0,\"state\":\"OPEN\",\"details\":{\"openCount\":0,\"mergedCount\":0,\"declinedCount\":0,\"total\":0},\"open\":true},\"byInstanceType\":{}},\"build\":{\"overall\":{\"count\":0,\"lastUpdated\":null,\"failedBuildCount\":0,\"successfulBuildCount\":0,\"unknownBuildCount\":0},\"byInstanceType\":{}},\"review\":{\"overall\":{\"count\":0,\"lastUpdated\":null,\"stateCount\":0,\"state\":null,\"dueDate\":null,\"overDue\":false,\"completed\":false},\"byInstanceType\":{}},\"deployment-environment\":{\"overall\":{\"count\":0,\"lastUpdated\":null,\"topEnvironments\":[],\"showProjects\":false,\"successfulCount\":0},\"byInstanceType\":{}},\"repository\":{\"overall\":{\"count\":0,\"lastUpdated\":null},\"byInstanceType\":{}},\"branch\":{\"overall\":{\"count\":0,\"lastUpdated\":null},\"byInstanceType\":{}}}},\"isStale\":false}}", "customfield_10100" => "0|i0005b:", "customfield_10101" => nil, "customfield_10102" => nil, "customfield_10107" => nil, "customfield_10108" => nil, "customfield_10109" => nil, "customfield_10110" => nil, "customfield_10111" => nil, "aggregatetimespent" => nil, "timeoriginalestimate" => nil, "aggregatetimeestimate" => nil, "aggregatetimeoriginalestimate" => nil }, "changelog" => { "total" => 1, "startAt" => 0, "histories" => [{ "id" => "10027", "items" => [{ "to" => "3", "from" => "1", "field" => "status", "toString" => "In Progress", "fieldtype" => "jira", "fromString" => "Open" }], "author" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "created" => "2025-09-27T21:19:21.128+0000" }], "maxResults" => 1 }, "renderedFields" => nil }, - jira_project_id: jira_projects[1].id, - jira_issue_id: "10024", - jira:, - jira_import:) - create(:jira_issue, - payload: { "id" => "10000", "key" => "PROCESS1-3", "self" => "http://jira-software.local/rest/api/2/issue/10000", - "expand" => "operations,versionedRepresentations,editmeta,changelog,renderedFields", "fields" => { "votes" => { "self" => "http://jira-software.local/rest/api/2/issue/PROCESS1-3/votes", "votes" => 0, "hasVoted" => false }, "labels" => [], "status" => { "id" => "10001", "name" => "Done", "self" => "http://jira-software.local/rest/api/2/status/10001", "iconUrl" => "http://jira-software.local/", "description" => "", "statusCategory" => { "id" => 3, "key" => "done", "name" => "Done", "self" => "http://jira-software.local/rest/api/2/statuscategory/3", "colorName" => "success" } }, "comment" => { "total" => 4, "startAt" => 0, "comments" => [{ "id" => "10100", "body" => "qweqweqwe", "self" => "http://jira-software.local/rest/api/2/issue/10000/comment/10100", "author" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "created" => "2025-10-29T15:12:27.174+0000", "updated" => "2025-10-29T15:12:27.174+0000", "updateAuthor" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" } }, { "id" => "10101", "body" => "weqweqweqweqw", "self" => "http://jira-software.local/rest/api/2/issue/10000/comment/10101", "author" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "created" => "2025-10-29T15:12:30.121+0000", "updated" => "2025-10-29T15:12:30.121+0000", "updateAuthor" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" } }, { "id" => "10102", "body" => "qweqweqwe", "self" => "http://jira-software.local/rest/api/2/issue/10000/comment/10102", "author" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "created" => "2025-10-29T15:12:33.593+0000", "updated" => "2025-10-29T15:12:33.593+0000", "updateAuthor" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" } }, { "id" => "10200", "body" => "Comment 4\r\nqweqweqwe", "self" => "http://jira-software.local/rest/api/2/issue/10000/comment/10200", "author" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "created" => "2026-01-22T11:55:43.300+0000", "updated" => "2026-01-22T11:55:43.300+0000", "updateAuthor" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" } }], "maxResults" => 1000 }, "created" => "2025-09-26T17:30:06.000+0000", "creator" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "duedate" => nil, "project" => { "id" => "10002", "key" => "PROCESS1", "name" => "PROCESS_MANAGEMENT1", "self" => "http://jira-software.local/rest/api/2/project/10002", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/projectavatar?size=xsmall&avatarId=10324", "24x24" => "http://jira-software.local/secure/projectavatar?size=small&avatarId=10324", "32x32" => "http://jira-software.local/secure/projectavatar?size=medium&avatarId=10324", "48x48" => "http://jira-software.local/secure/projectavatar?avatarId=10324" }, "projectTypeKey" => "business" }, "summary" => "As an Agile team, I'd like to learn about Scrum >> Click the \"SCRUM1-1\" link at the left of this row to see detail in the Description tab on the right @jira", "updated" => "2026-01-22T11:55:43.000+0000", "watches" => { "self" => "http://jira-software.local/rest/api/2/issue/PROCESS1-3/watchers", "isWatching" => true, "watchCount" => 1 }, "worklog" => { "total" => 0, "startAt" => 0, "worklogs" => [], "maxResults" => 20 }, "assignee" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "priority" => { "id" => "3", "name" => "Medium", "self" => "http://jira-software.local/rest/api/2/priority/3", "iconUrl" => "http://jira-software.local/images/icons/priorities/medium.svg" }, "progress" => { "total" => 0, "progress" => 0 }, "reporter" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "subtasks" => [], "versions" => [], "issuetype" => { "id" => "10002", "name" => "Task", "self" => "http://jira-software.local/rest/api/2/issuetype/10002", "iconUrl" => "http://jira-software.local/secure/viewavatar?size=xsmall&avatarId=10318&avatarType=issuetype", "subtask" => false, "avatarId" => 10318, "description" => "A task that needs to be done." }, "timespent" => nil, "workratio" => -1, "archivedby" => nil, "attachment" => [{ "id" => "10000", "self" => "http://jira-software.local/rest/api/2/attachment/10000", "size" => 13147, "author" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "content" => "http://jira-software.local/secure/attachment/10000/test.png", "created" => "2025-12-02T15:27:52.218+0000", "filename" => "test.png", "mimeType" => "image/png", "thumbnail" => "http://jira-software.local/secure/thumbnail/10000/_thumb_10000.png" }], "components" => [], "issuelinks" => [], "lastViewed" => "2026-01-22T11:54:40.794+0000", "resolution" => { "id" => "10000", "name" => "Done", "self" => "http://jira-software.local/rest/api/2/resolution/10000", "description" => "Work has been completed on this issue." }, "description" => "*About Scrum*\r\n\r\nScrum is an iterative approach to Agile software development. The methodology has been around since the 1980s but was popularised by Jeff Sutherland and Ken Schwaber.\r\n\r\nScrum breaks the development of a product down in to discrete iterations (termed Sprints) that each deliver functionality that could potentially be shipped to users.\r\n\r\nThe Scrum Alliance offers an excellent [introduction to Scrum|http://www.scrumalliance.org/resources/47] that provides an overview of key Scrum concepts, stakeholders, processes and artefacts.\r\n\r\n[~pavel.balashou] ", "environment" => nil, "fixVersions" => [], "archiveddate" => nil, "timeestimate" => nil, "timetracking" => {}, "resolutiondate" => "2025-11-11T12:02:42.000+0000", "aggregateprogress" => { "total" => 0, "progress" => 0 }, "customfield_10000" => "{summaryBean=com.atlassian.jira.plugin.devstatus.rest.SummaryBean@68f846[summary={pullrequest=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@f3b23e9[byInstanceType={},overall=PullRequestOverallBean{stateCount=0, state='OPEN', details=PullRequestOverallDetails{openCount=0, mergedCount=0, declinedCount=0}}], build=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@6a9f9e9a[byInstanceType={},overall=com.atlassian.jira.plugin.devstatus.summary.beans.BuildOverallBean@3ceddc4b[failedBuildCount=0,successfulBuildCount=0,unknownBuildCount=0,count=0,lastUpdated=,lastUpdatedTimestamp=]], review=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@63827814[byInstanceType={},overall=com.atlassian.jira.plugin.devstatus.summary.beans.ReviewsOverallBean@59076277[dueDate=,overDue=false,state=,stateCount=0,count=0,lastUpdated=,lastUpdatedTimestamp=]], deployment-environment=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@4ffa5c83[byInstanceType={},overall=com.atlassian.jira.plugin.devstatus.summary.beans.DeploymentOverallBean@1da7deb3[showProjects=false,successfulCount=0,topEnvironments=[],count=0,lastUpdated=,lastUpdatedTimestamp=]], repository=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@6d1547cb[byInstanceType={},overall=com.atlassian.jira.plugin.devstatus.summary.beans.CommitOverallBean@fe394c4[count=0,lastUpdated=,lastUpdatedTimestamp=]], branch=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@1260cfff[byInstanceType={},overall=com.atlassian.jira.plugin.devstatus.summary.beans.BranchOverallBean@3111c946[count=0,lastUpdated=,lastUpdatedTimestamp=]]},configErrors=[],errors=[]], devSummaryJson={\"cachedValue\":{\"errors\":[],\"configErrors\":[],\"summary\":{\"pullrequest\":{\"overall\":{\"count\":0,\"lastUpdated\":null,\"stateCount\":0,\"state\":\"OPEN\",\"details\":{\"openCount\":0,\"mergedCount\":0,\"declinedCount\":0,\"total\":0},\"open\":true},\"byInstanceType\":{}},\"build\":{\"overall\":{\"count\":0,\"lastUpdated\":null,\"failedBuildCount\":0,\"successfulBuildCount\":0,\"unknownBuildCount\":0},\"byInstanceType\":{}},\"review\":{\"overall\":{\"count\":0,\"lastUpdated\":null,\"stateCount\":0,\"state\":null,\"dueDate\":null,\"overDue\":false,\"completed\":false},\"byInstanceType\":{}},\"deployment-environment\":{\"overall\":{\"count\":0,\"lastUpdated\":null,\"topEnvironments\":[],\"showProjects\":false,\"successfulCount\":0},\"byInstanceType\":{}},\"repository\":{\"overall\":{\"count\":0,\"lastUpdated\":null},\"byInstanceType\":{}},\"branch\":{\"overall\":{\"count\":0,\"lastUpdated\":null},\"byInstanceType\":{}}}},\"isStale\":false}}", "customfield_10100" => "0|hzzzzz:", "customfield_10101" => nil, "customfield_10102" => nil, "customfield_10107" => nil, "customfield_10108" => nil, "customfield_10109" => nil, "customfield_10110" => nil, "customfield_10111" => nil, "aggregatetimespent" => nil, "timeoriginalestimate" => nil, "aggregatetimeestimate" => nil, "aggregatetimeoriginalestimate" => nil }, "changelog" => { "total" => 9, "startAt" => 0, "histories" => [{ "id" => "10200", "items" => [{ "to" => "10002", "from" => "10000", "field" => "project", "toString" => "PROCESS_MANAGEMENT1", "fieldtype" => "jira", "fromString" => "SCRUM1" }, { "to" => nil, "from" => nil, "field" => "Key", "toString" => "PROCESS1-3", "fieldtype" => "jira", "fromString" => "SCRUM1-1" }, { "to" => "10002", "from" => "10001", "field" => "issuetype", "toString" => "Task", "fieldtype" => "jira", "fromString" => "Story" }, { "to" => "10200", "from" => "10000", "field" => "Workflow", "toString" => "PROCESS1: Process Management Workflow", "fieldtype" => "jira", "fromString" => "Software Simplified Workflow for Project SCRUM1" }, { "to" => "1", "from" => "10000", "field" => "status", "toString" => "Open", "fieldtype" => "jira", "fromString" => "To Do" }, { "to" => nil, "from" => nil, "field" => "Story Points", "toString" => "", "fieldtype" => "custom", "fromString" => "2" }, { "to" => nil, "from" => "10001", "field" => "Fix Version", "toString" => nil, "fieldtype" => "jira", "fromString" => "Version 2.0" }], "author" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "created" => "2025-10-29T13:51:50.757+0000" }, { "id" => "10303", "items" => [{ "to" => "3", "from" => "1", "field" => "status", "toString" => "In Progress", "fieldtype" => "jira", "fromString" => "Open" }], "author" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "created" => "2025-11-11T12:01:55.697+0000" }, { "id" => "10304", "items" => [{ "to" => "10004", "from" => "3", "field" => "status", "toString" => "Under Review", "fieldtype" => "jira", "fromString" => "In Progress" }], "author" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "created" => "2025-11-11T12:02:28.548+0000" }, { "id" => "10305", "items" => [{ "to" => "10005", "from" => "10004", "field" => "status", "toString" => "Approved", "fieldtype" => "jira", "fromString" => "Under Review" }], "author" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "created" => "2025-11-11T12:02:33.114+0000" }, { "id" => "10306", "items" => [{ "to" => "10001", "from" => "10005", "field" => "status", "toString" => "Done", "fieldtype" => "jira", "fromString" => "Approved" }, { "to" => "10000", "from" => nil, "field" => "resolution", "toString" => "Done", "fieldtype" => "jira", "fromString" => nil }], "author" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "created" => "2025-11-11T12:02:42.812+0000" }, { "id" => "10400", "items" => [{ "to" => "JIRAUSER10000", "from" => nil, "field" => "assignee", "toString" => "Pavel Balashou", "fieldtype" => "jira", "fromString" => nil }], "author" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "created" => "2025-11-25T07:46:14.257+0000" }, { "id" => "10401", "items" => [{ "to" => nil, "from" => nil, "field" => "summary", "toString" => "As an Agile team, I'd like to learn about Scrum >> Click the \"SCRUM1-1\" link at the left of this row to see detail in the Description tab on the right @jira", "fieldtype" => "jira", "fromString" => "As an Agile team, I'd like to learn about Scrum >> Click the \"SCRUM1-1\" link at the left of this row to see detail in the Description tab on the right" }], "author" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "created" => "2025-11-25T07:58:06.899+0000" }, { "id" => "10402", "items" => [{ "to" => nil, "from" => nil, "field" => "description", "toString" => "*About Scrum*\r\n\r\nScrum is an iterative approach to Agile software development. The methodology has been around since the 1980s but was popularised by Jeff Sutherland and Ken Schwaber.\r\n\r\nScrum breaks the development of a product down in to discrete iterations (termed Sprints) that each deliver functionality that could potentially be shipped to users.\r\n\r\nThe Scrum Alliance offers an excellent [introduction to Scrum|http://www.scrumalliance.org/resources/47] that provides an overview of key Scrum concepts, stakeholders, processes and artefacts.\r\n\r\n[~pavel.balashou] ", "fieldtype" => "jira", "fromString" => "*About Scrum*\n\nScrum is an iterative approach to Agile software development. The methodology has been around since the 1980s but was popularised by Jeff Sutherland and Ken Schwaber. \n\nScrum breaks the development of a product down in to discrete iterations (termed Sprints) that each deliver functionality that could potentially be shipped to users.\n\nThe Scrum Alliance offers an excellent [introduction to Scrum|http://www.scrumalliance.org/resources/47] that provides an overview of key Scrum concepts, stakeholders, processes and artefacts." }], "author" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "created" => "2025-11-25T07:58:13.271+0000" }, { "id" => "10501", "items" => [{ "to" => "10000", "from" => nil, "field" => "Attachment", "toString" => "test.png", "fieldtype" => "jira", "fromString" => nil }], "author" => { "key" => "JIRAUSER10000", "name" => "pavel.balashou", "self" => "http://jira-software.local/rest/api/2/user?username=pavel.balashou", "active" => true, "timeZone" => "Etc/UTC", "avatarUrls" => { "16x16" => "http://jira-software.local/secure/useravatar?size=xsmall&avatarId=10334", "24x24" => "http://jira-software.local/secure/useravatar?size=small&avatarId=10334", "32x32" => "http://jira-software.local/secure/useravatar?size=medium&avatarId=10334", "48x48" => "http://jira-software.local/secure/useravatar?avatarId=10334" }, "displayName" => "Pavel Balashou", "emailAddress" => "ba1ashpash@gmail.com" }, "created" => "2025-12-02T15:27:52.298+0000" }], "maxResults" => 9 }, "renderedFields" => nil }, - jira_project_id: jira_projects[1].id, - jira_issue_id: "10000", - jira:, - jira_import:) - - # IMPORT USERS - expect(Import::JiraOpenProjectReference.count).to eq(0) - - expect(User.count).to eq(2) - expect(Group.count).to eq(0) - - expect(User.where(login: "pavel.balashou").count).to eq(0) - Import::JiraImportGroupsAndUsersJob.perform_now(jira_import.id) - - user = User.where(login: "pavel.balashou").first - expect(user).to be_present - expect(user.groups.count).to eq(3) - expect(Group.count).to eq(3) - expect(Import::JiraOpenProjectReference.count).to eq(4) - - expect(Project.count).to eq(0) - expect(WorkPackage.count).to eq(0) - expect(Type.count).to eq(1) - expect(Status.count).to eq(1) - expect(IssuePriority.count).to eq(1) - - # IMPORT PROJECTS - Import::JiraImportProjectsJob.perform_now(jira_import.id) - - expect(Project.count).to eq(2) - expect(ProjectRole.where(name: "JiraMember").first).to be_present - expect(WorkPackage.count).to eq(3) - expect(Type.count).to eq(2) - expect(Status.count).to eq(3) - expect(IssuePriority.count).to eq(2) - expect(WorkPackage.pluck(:description)).to include(description1, description2) - expect(WorkPackage.pluck(:subject)).to include(summary1, summary2) - expect(Import::JiraOpenProjectReference.count).to eq(17) - expect(WorkPackage.all.map(&:journals).count).to eq(3) - - # REVERT PROJECTS IMPORT - Import::JiraRevertImportJob.perform_now(jira_import.id) - - expect(ProjectRole.where(name: "JiraMember").first).to be_blank - expect(Project.count).to eq(0) - expect(WorkPackage.count).to eq(0) - expect(Type.count).to eq(1) - expect(Status.count).to eq(1) - expect(IssuePriority.count).to eq(1) - - expect(User.where(login: "pavel.balashou").count).to eq(0) - expect(Group.count).to eq(0) - - expect(Import::JiraOpenProjectReference.count).to eq(0) - end -end