sidenotes 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 24381f7028cc342a69f1b713f2604ae0a0bdc829d675f8f866241550e13b4440
4
- data.tar.gz: 384a71a3b65bf767fd3634a84e03125329cb72fb5638dd29a9160a3f157e9bca
3
+ metadata.gz: 49cfca99965003c2f6fbff02ac2d9a930671bec5bb36f0cafecbb03e8c2e47f1
4
+ data.tar.gz: 505db15a10c3df2c3af8d3d3425d1cb3ea4580faf22a24fe0ba10a48dd0c432d
5
5
  SHA512:
6
- metadata.gz: 23c955f99d8e8c4f46c221cc96332907ba20dd6492271eb176ce2ca07a40842a460720b17f8294acdc929980e59b014706acf4ac8363c405708df4864d07c368
7
- data.tar.gz: 8a37de79dc70a7e941845485b2435bbabf9580fc07caaa6db9c86a4f55204fd3d84cbc01c23be1196c87715a83c52b6daae899e6c41061bd953ac6a8e6063ecb
6
+ metadata.gz: 042f58ab4161438219e6980cd8637bb07395e91bd4240e1c7bc729362c3a27d99b0d67cd2ff91c17103a58deb2fd6fa830de42749bdc1bceadc44fd7c7fb6334
7
+ data.tar.gz: 6e621545a5d90913fa388317bec1fc84bd75c7f0e2407be88f701eeff6d4d957a5f1b949379475b4ae4668edecf6af72dfd42db3adebb19b1b58fdde5f7ff808
data/CHANGELOG.md CHANGED
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.2.1] - 2026-05-01
9
+
10
+ ### Added
11
+
12
+ - `sidenotes:verify` now detects pending migrations and reports them as drift (exits 1). This catches the case where a migration file exists but hasn't been applied, where the sidecars and DB happen to match but the test suite would later fail with `ActiveRecord::PendingMigrationError`.
13
+ - Verifier API: `Sidenotes::Verifier#pending_migrations`, `#pending_migrations?`
14
+
15
+ ### Changed
16
+
17
+ - `Verifier#drift?` and `#issue_count` now include pending migrations.
18
+ - Migration context lookup supports both pre-7.2 (`connection.migration_context`) and 7.2+ (`connection_pool.migration_context`) APIs.
19
+
8
20
  ## [0.2.0] - 2026-04-29
9
21
 
10
22
  ### Added
data/README.md CHANGED
@@ -79,7 +79,7 @@ rake sidenotes:clean
79
79
  rake sidenotes:verify
80
80
  ```
81
81
 
82
- Compares each `.annotations/` sidecar file against the live database schema and reports drift (missing/extra columns, indexes, associations, foreign keys, or models without sidecars). Exits with status `1` if any drift is detected, making it suitable for CI:
82
+ Compares each `.annotations/` sidecar file against the live database schema and reports drift (missing/extra columns, indexes, associations, foreign keys, or models without sidecars). It also surfaces **pending migrations** — if a migration file exists but hasn't been applied, sidenotes flags it before doing the schema comparison, since the test suite would fail later anyway. Exits with status `1` if any drift or pending migrations are detected, making it suitable for CI:
83
83
 
84
84
  ```yaml
85
85
  # .github/workflows/ci.yml
@@ -68,18 +68,37 @@ module Sidenotes
68
68
  puts "Checking #{verifier.checked_count} model annotations against database..."
69
69
  puts
70
70
 
71
+ print_pending_migrations(verifier) if verifier.pending_migrations?
72
+ print_drifts(verifier)
73
+ print_missing_sidecars(verifier)
74
+ print_summary(verifier)
75
+ end
76
+
77
+ def self.print_pending_migrations(verifier)
78
+ puts ' PENDING MIGRATIONS detected (run `rails db:migrate` first):'
79
+ verifier.pending_migrations.each do |m|
80
+ puts " - #{m['version']} #{m['name']}"
81
+ end
82
+ puts
83
+ end
84
+
85
+ def self.print_drifts(verifier)
71
86
  verifier.drifts.each do |drift|
72
87
  puts " #{File.basename(drift.sidecar_path)} - DRIFT:"
73
88
  drift.issues.each { |issue| puts " #{issue}" }
74
89
  puts
75
90
  end
91
+ end
76
92
 
93
+ def self.print_missing_sidecars(verifier)
77
94
  verifier.missing_sidecars.each do |name|
78
95
  puts " #{name} - MISSING (model exists, no sidecar file)"
79
96
  end
97
+ end
80
98
 
99
+ def self.print_summary(verifier)
81
100
  if verifier.drift?
82
- puts "#{verifier.issue_count} issue(s) found. Run `rake sidenotes:generate` to update."
101
+ puts "#{verifier.issue_count} issue(s) found. Run `rake db:migrate && rake sidenotes:generate` to update."
83
102
  else
84
103
  puts 'All annotations are up to date.'
85
104
  end
@@ -7,20 +7,37 @@ module Sidenotes
7
7
  class Verifier
8
8
  Drift = Struct.new(:model_name, :sidecar_path, :issues, keyword_init: true)
9
9
 
10
- attr_reader :drifts, :missing_sidecars, :checked_count
10
+ attr_reader :drifts, :missing_sidecars, :checked_count, :pending_migrations
11
11
 
12
12
  def initialize
13
13
  @drifts = []
14
14
  @missing_sidecars = []
15
15
  @checked_count = 0
16
+ @pending_migrations = []
16
17
  end
17
18
 
18
19
  def verify_all
20
+ check_pending_migrations
19
21
  generator = Generator.new
20
22
  generator.discover_models.each { |model| verify_model(model) }
21
23
  self
22
24
  end
23
25
 
26
+ def check_pending_migrations
27
+ context = migration_context
28
+ return unless context.respond_to?(:pending_migrations)
29
+
30
+ @pending_migrations = context.pending_migrations.map do |m|
31
+ { 'version' => m.version, 'name' => m.name }
32
+ end
33
+ rescue StandardError => e
34
+ warn "Sidenotes: could not check pending migrations: #{e.message}"
35
+ end
36
+
37
+ def pending_migrations?
38
+ pending_migrations.any?
39
+ end
40
+
24
41
  def verify_model(model)
25
42
  inspector = ModelInspector.new(model)
26
43
  return unless inspector.inspectable?
@@ -43,15 +60,29 @@ module Sidenotes
43
60
  end
44
61
 
45
62
  def drift?
46
- drifts.any? || missing_sidecars.any?
63
+ drifts.any? || missing_sidecars.any? || pending_migrations?
47
64
  end
48
65
 
49
66
  def issue_count
50
- drifts.sum { |d| d.issues.size } + missing_sidecars.size
67
+ drifts.sum { |d| d.issues.size } + missing_sidecars.size + pending_migrations.size
51
68
  end
52
69
 
53
70
  private
54
71
 
72
+ def migration_context
73
+ return nil unless defined?(ActiveRecord::Base)
74
+
75
+ pool = ActiveRecord::Base.connection_pool
76
+ return pool.migration_context if pool.respond_to?(:migration_context)
77
+
78
+ conn = ActiveRecord::Base.connection
79
+ return conn.migration_context if conn.respond_to?(:migration_context)
80
+
81
+ nil
82
+ rescue StandardError
83
+ nil
84
+ end
85
+
55
86
  def sidecar_path_for(model)
56
87
  config = Sidenotes.configuration
57
88
  File.join(config.output_directory, "#{model.name.underscore}.#{config.file_extension}")
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sidenotes
4
- VERSION = '0.2.0'
4
+ VERSION = '0.2.1'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidenotes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wes Mason
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-04-29 00:00:00.000000000 Z
11
+ date: 2026-05-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord