Show import:status as done/total per plan
Assisted-by: GLM-5.3 via pi
diff --git a/tasks/import.rake b/tasks/import.rake
index fc48ad5..fb96549 100644
--- a/tasks/import.rake
+++ b/tasks/import.rake
@@ -87,22 +87,15 @@ namespace :import do
next
end
- # One aligned row per plan, the statuses as columns in their order
- # through an import, so where a plan has got to is read off the
- # row rather than parsed out of a sentence. The plan names are the
- # directories', copy-pasteable into PLAN=.
- headers = ["plan", "host", "contacts", "planned", "landed", "imported", "removed"]
- rows = plans.map { |plan|
- counts = plan.contacts.group_by(&:status).transform_values(&:length)
- [plan.dir.basename.to_s, plan.host || "—", plan.contacts.size.to_s,
- counts.fetch(nil, 0).to_s, counts.fetch("landed", 0).to_s,
- counts.fetch("imported", 0).to_s, counts.fetch("removed", 0).to_s]
- }
- widths = headers.each_index.map { |i| [headers[i].length, *rows.map { it[i].length }].max }
- table = rows.unshift(headers).map { |row|
- row.each_with_index.map { |cell, i| cell.public_send(i < 2 ? :ljust : :rjust, widths[i]) }.join(" ")
- }
- puts table
+ # One line per plan, as far along as it is: the fraction counts
+ # everything past “planned”, because from “landed” on the card is
+ # on the host — which is the state a glance wants. The rest of the
+ # state is what the next lines say acts on it. The plan names are
+ # the directories', copy-pasteable into PLAN=.
+ plans.each do |plan|
+ done = plan.contacts.size - plan.with_status(nil).size
+ puts "#{plan.dir.basename} #{done}/#{plan.contacts.size} contacts"
+ end
puts ""
landing = plans.find(&ImportTasks::TO_LAND)
diff --git a/test/tasks/test_import.rb b/test/tasks/test_import.rb
index 4c714ac..71223ff 100644
--- a/test/tasks/test_import.rb
+++ b/test/tasks/test_import.rb
@@ -21,16 +21,14 @@ class ImportStatusTaskTest < Minitest::Test
# A plan mid-flight — one contact through to the Mac-cleanup step,
# one past it — and one freshly built with everything still to do.
underway = Plan.write(imports / "macos-20260901T000000Z", source: "macos", created_at: Time.utc(2026, 9, 1), entries: [entry("kmnuqmzxylru"), entry("vmnlryyvktux")])
- underway.host = "https://contacts.example"
underway.record("kmnuqmzxylru", "imported")
underway.record("vmnlryyvktux", "removed")
Plan.write(imports / "macos-20260916T180412Z", source: "macos", created_at: Time.utc(2026, 9, 16, 18, 4, 12), entries: [entry("aaaaaaaaaaaa")])
out, = run_task(root)
- assert_match(%r{plan\s+host\s+contacts\s+planned\s+landed\s+imported\s+removed}, out)
- assert_match(/macos-20260901T000000Z\s+https:\/\/contacts\.example\s+2\s+0\s+0\s+1\s+1/, out)
- assert_match(/macos-20260916T180412Z\s+—\s+1\s+1\s+0\s+0\s+0/, out)
+ assert_includes out, "macos-20260901T000000Z 2/2 contacts\n"
+ assert_includes out, "macos-20260916T180412Z 0/1 contacts\n"
assert_includes out, "next: import:execute would land macos-20260916T180412Z\n"
assert_includes out, "next: import:macos:remove would clear macos-20260901T000000Z\n"
end