From d02f9589c405bb8ad6cbc98236220d8852662f71 Mon Sep 17 00:00:00 2001 From: MAEDA Go Date: Tue, 13 Oct 2026 14:12:22 +0900 Subject: [PATCH] Fix CSV import misdetecting apostrophes in field values as the field wrapper --- app/models/import.rb | 8 +++++++- test/fixtures/files/import_issues_with_apostrophes.csv | 4 ++++ test/unit/issue_import_test.rb | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/files/import_issues_with_apostrophes.csv diff --git a/app/models/import.rb b/app/models/import.rb index 42274a39d..a16703464 100644 --- a/app/models/import.rb +++ b/app/models/import.rb @@ -73,7 +73,13 @@ class Import < ApplicationRecord separator = [',', ';'].max_by {|sep| content.count(sep)} newline = content.index("\r\n") ? "\r\n" : '' # blank means auto - wrapper = ['"', "'"].max_by {|quote_char| content.count(quote_char)} + wrapper = ['"', "'"].max_by do |quote_char| + sep = Regexp.escape(separator) + quote = Regexp.escape(quote_char) + # Apostrophes in unwrapped fields should not be treated as wrappers + wrapped_field = /(?:\A|#{sep}|\n)#{quote}(?:[^#{quote}]|#{quote}#{quote})*#{quote}(?=#{sep}|\r?\n|\z)/n + content.scan(wrapped_field).size + end guessed_encoding = Redmine::CodesetUtil.guess_encoding(content) encoding = diff --git a/test/fixtures/files/import_issues_with_apostrophes.csv b/test/fixtures/files/import_issues_with_apostrophes.csv new file mode 100644 index 000000000..edfa93479 --- /dev/null +++ b/test/fixtures/files/import_issues_with_apostrophes.csv @@ -0,0 +1,4 @@ +tracker,subject,description +Bug,Can't log in after resetting the password,The login form rejects the new password +Bug,Search doesn't find closed issues,Closed issues are missing from the search results +Feature request,Show the user's avatar in the issue list,Display the avatar next to the assignee name diff --git a/test/unit/issue_import_test.rb b/test/unit/issue_import_test.rb index de4207045..54697fa31 100644 --- a/test/unit/issue_import_test.rb +++ b/test/unit/issue_import_test.rb @@ -471,6 +471,7 @@ class IssueImportTest < ActiveSupport::TestCase to_test = { 'import_issues.csv' => '"', 'import_issues_single_quotation.csv' => "'", + 'import_issues_with_apostrophes.csv' => '"', # Use '"' as a wrapper for CSV file with no wrappers 'import_dates.csv' => '"', } -- 2.55.0