pg_multitenant_schemas 0.2.0 → 0.2.3
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 +4 -4
- data/.actrc +17 -0
- data/.env.local.example +21 -0
- data/CHANGELOG.md +39 -1
- data/LOCAL_TESTING_SUMMARY.md +141 -0
- data/README.md +4 -4
- data/TESTING_LOCALLY.md +208 -0
- data/docs/README.md +4 -0
- data/docs/github_actions_permissions_fix.md +136 -0
- data/docs/github_actions_setup.md +181 -0
- data/docs/local_workflow_testing.md +314 -0
- data/docs/testing_rails_tasks.md +128 -0
- data/lib/pg_multitenant_schemas/migration_schema_operations.rb +99 -5
- data/lib/pg_multitenant_schemas/migrator.rb +66 -9
- data/lib/pg_multitenant_schemas/rails/railtie.rb +4 -1
- data/lib/pg_multitenant_schemas/schema_switcher.rb +34 -0
- data/lib/pg_multitenant_schemas/tasks/tenant_tasks.rake +0 -3
- data/lib/pg_multitenant_schemas/version.rb +1 -1
- data/pg_multitenant_schemas.gemspec +5 -5
- data/pre-push-check.sh +95 -0
- data/test-github-setup.sh +85 -0
- data/validate-github-commands.sh +47 -0
- metadata +20 -10
- data/lib/pg_multitenant_schemas/tasks/pg_multitenant_schemas.rake +0 -65
|
@@ -34,21 +34,115 @@ module PgMultitenantSchemas
|
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
def run_migrations
|
|
37
|
-
|
|
37
|
+
# Use the migration context to run migrations
|
|
38
|
+
migration_context_obj = migration_context
|
|
39
|
+
return unless migration_context_obj
|
|
40
|
+
|
|
41
|
+
migration_context_obj.migrate
|
|
38
42
|
end
|
|
39
43
|
|
|
40
44
|
def pending_migrations
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
migration_context_obj = migration_context
|
|
46
|
+
return [] unless migration_context_obj
|
|
47
|
+
|
|
48
|
+
all_migrations = migration_context_obj.migrations
|
|
49
|
+
applied_version_list = applied_versions
|
|
50
|
+
|
|
51
|
+
all_migrations.reject do |migration|
|
|
52
|
+
applied_version_list.include?(migration.version)
|
|
43
53
|
end
|
|
44
54
|
end
|
|
45
55
|
|
|
46
56
|
def applied_migrations
|
|
47
|
-
|
|
57
|
+
applied_versions
|
|
48
58
|
end
|
|
49
59
|
|
|
50
60
|
def migration_paths
|
|
51
|
-
|
|
61
|
+
migration_context_obj = migration_context
|
|
62
|
+
if migration_context_obj.respond_to?(:migrations_paths)
|
|
63
|
+
migration_context_obj.migrations_paths
|
|
64
|
+
elsif defined?(::Rails) && ::Rails.application
|
|
65
|
+
# Fallback to default Rails migration paths
|
|
66
|
+
::Rails.application.paths["db/migrate"].expanded
|
|
67
|
+
else
|
|
68
|
+
["db/migrate"]
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def migration_context
|
|
73
|
+
# Return nil if ActiveRecord is not available (for tests)
|
|
74
|
+
return nil unless defined?(ActiveRecord::Base)
|
|
75
|
+
|
|
76
|
+
# Rails 8 compatibility: Try multiple approaches
|
|
77
|
+
find_migration_context
|
|
78
|
+
rescue StandardError => e
|
|
79
|
+
# Use explicit Rails logger to avoid namespace conflicts
|
|
80
|
+
::Rails.logger&.warn("Failed to get migration context: #{e.message}") if defined?(::Rails)
|
|
81
|
+
nil
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def find_migration_context
|
|
85
|
+
if ActiveRecord::Base.respond_to?(:migration_context)
|
|
86
|
+
# Rails 8+: Try base migration context first
|
|
87
|
+
ActiveRecord::Base.migration_context
|
|
88
|
+
elsif ActiveRecord::Base.connection.respond_to?(:migration_context)
|
|
89
|
+
# Rails 7: Use connection migration context
|
|
90
|
+
ActiveRecord::Base.connection.migration_context
|
|
91
|
+
elsif defined?(ActiveRecord::MigrationContext)
|
|
92
|
+
# Fallback: Create a new migration context with default paths
|
|
93
|
+
create_fallback_migration_context
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def create_fallback_migration_context
|
|
98
|
+
paths = if defined?(::Rails) && ::Rails.application
|
|
99
|
+
::Rails.application.paths["db/migrate"].expanded
|
|
100
|
+
else
|
|
101
|
+
["db/migrate"]
|
|
102
|
+
end
|
|
103
|
+
ActiveRecord::MigrationContext.new(paths)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Get applied migration versions with Rails 8 compatibility
|
|
107
|
+
def applied_versions
|
|
108
|
+
# Return empty array if ActiveRecord is not available (for tests)
|
|
109
|
+
return [] unless defined?(ActiveRecord::Base)
|
|
110
|
+
|
|
111
|
+
applied_versions_from_context || applied_versions_from_database
|
|
112
|
+
rescue StandardError => e
|
|
113
|
+
# If anything fails, return empty array
|
|
114
|
+
::Rails.logger&.warn("Failed to get applied versions: #{e.message}") if defined?(::Rails)
|
|
115
|
+
[]
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def applied_versions_from_context
|
|
119
|
+
# Try using migration context first (for tests and Rails 7)
|
|
120
|
+
migration_context_obj = migration_context
|
|
121
|
+
return migration_context_obj.get_all_versions if migration_context_obj.respond_to?(:get_all_versions)
|
|
122
|
+
|
|
123
|
+
nil
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def applied_versions_from_database
|
|
127
|
+
# Fallback to direct database query (Rails 8)
|
|
128
|
+
connection = ActiveRecord::Base.connection
|
|
129
|
+
table_name = "schema_migrations"
|
|
130
|
+
|
|
131
|
+
ensure_schema_migrations_table_exists(connection, table_name)
|
|
132
|
+
|
|
133
|
+
# Query the table directly for maximum compatibility
|
|
134
|
+
connection.select_values("SELECT version FROM #{table_name} ORDER BY version")
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def ensure_schema_migrations_table_exists(connection, table_name)
|
|
138
|
+
# Ensure the schema_migrations table exists
|
|
139
|
+
return if connection.table_exists?(table_name)
|
|
140
|
+
|
|
141
|
+
# Create the table if it doesn't exist
|
|
142
|
+
connection.create_table(table_name, id: false) do |t|
|
|
143
|
+
t.string :version, null: false
|
|
144
|
+
end
|
|
145
|
+
connection.add_index(table_name, :version, unique: true, name: "unique_schema_migrations")
|
|
52
146
|
end
|
|
53
147
|
end
|
|
54
148
|
end
|
|
@@ -73,15 +73,72 @@ module PgMultitenantSchemas
|
|
|
73
73
|
puts "⏪ Rolling back #{steps} steps for #{schema_name}" if verbose
|
|
74
74
|
original_schema = current_schema
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
76
|
+
perform_rollback(schema_name, steps, verbose)
|
|
77
|
+
ensure
|
|
78
|
+
switch_to_schema(original_schema) if original_schema
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
private
|
|
82
|
+
|
|
83
|
+
def perform_rollback(schema_name, steps, verbose)
|
|
84
|
+
switch_to_schema(schema_name)
|
|
85
|
+
migration_context_obj = migration_context
|
|
86
|
+
|
|
87
|
+
unless migration_context_obj
|
|
88
|
+
puts " ❌ Cannot rollback: migration context not available" if verbose
|
|
89
|
+
return
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
migration_context_obj.rollback(migration_paths, steps)
|
|
93
|
+
puts " ✅ Rollback completed" if verbose
|
|
94
|
+
rescue StandardError => e
|
|
95
|
+
puts " ❌ Rollback failed: #{e.message}" if verbose
|
|
96
|
+
raise
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def migration_context
|
|
100
|
+
# Return nil if ActiveRecord is not available (for tests)
|
|
101
|
+
return nil unless defined?(ActiveRecord::Base)
|
|
102
|
+
|
|
103
|
+
# Rails 8 compatibility: Try multiple approaches
|
|
104
|
+
find_migration_context
|
|
105
|
+
rescue StandardError => e
|
|
106
|
+
# Use explicit Rails logger to avoid namespace conflicts
|
|
107
|
+
::Rails.logger&.warn("Failed to get migration context: #{e.message}") if defined?(::Rails)
|
|
108
|
+
nil
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def find_migration_context
|
|
112
|
+
if ActiveRecord::Base.respond_to?(:migration_context)
|
|
113
|
+
# Rails 8+: Try base migration context first
|
|
114
|
+
ActiveRecord::Base.migration_context
|
|
115
|
+
elsif ActiveRecord::Base.connection.respond_to?(:migration_context)
|
|
116
|
+
# Rails 7: Use connection migration context
|
|
117
|
+
ActiveRecord::Base.connection.migration_context
|
|
118
|
+
elsif defined?(ActiveRecord::MigrationContext)
|
|
119
|
+
# Fallback: Create a new migration context with default paths
|
|
120
|
+
create_fallback_migration_context
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def create_fallback_migration_context
|
|
125
|
+
paths = if defined?(::Rails) && ::Rails.application
|
|
126
|
+
::Rails.application.paths["db/migrate"].expanded
|
|
127
|
+
else
|
|
128
|
+
["db/migrate"]
|
|
129
|
+
end
|
|
130
|
+
ActiveRecord::MigrationContext.new(paths)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def migration_paths
|
|
134
|
+
migration_context_obj = migration_context
|
|
135
|
+
if migration_context_obj.respond_to?(:migrations_paths)
|
|
136
|
+
migration_context_obj.migrations_paths
|
|
137
|
+
elsif defined?(::Rails) && ::Rails.application
|
|
138
|
+
# Fallback to default Rails migration paths
|
|
139
|
+
::Rails.application.paths["db/migrate"].expanded
|
|
140
|
+
else
|
|
141
|
+
["db/migrate"]
|
|
85
142
|
end
|
|
86
143
|
end
|
|
87
144
|
end
|
|
@@ -14,7 +14,10 @@ module PgMultitenantSchemas
|
|
|
14
14
|
|
|
15
15
|
# Add rake tasks
|
|
16
16
|
rake_tasks do
|
|
17
|
-
|
|
17
|
+
# Load all task files
|
|
18
|
+
Dir[File.expand_path("../tasks/*.rake", __dir__)].each do |task_file|
|
|
19
|
+
load task_file
|
|
20
|
+
end
|
|
18
21
|
end
|
|
19
22
|
|
|
20
23
|
# Add generators
|
|
@@ -80,8 +80,42 @@ module PgMultitenantSchemas
|
|
|
80
80
|
get_result_value(result, 0, 0)
|
|
81
81
|
end
|
|
82
82
|
|
|
83
|
+
# List all schemas in the database
|
|
84
|
+
def list_schemas
|
|
85
|
+
conn = connection
|
|
86
|
+
result = execute_sql(conn, <<~SQL)
|
|
87
|
+
SELECT schema_name FROM information_schema.schemata#{" "}
|
|
88
|
+
ORDER BY schema_name
|
|
89
|
+
SQL
|
|
90
|
+
|
|
91
|
+
extract_schemas_from_result(result)
|
|
92
|
+
end
|
|
93
|
+
|
|
83
94
|
private
|
|
84
95
|
|
|
96
|
+
def extract_schemas_from_result(result)
|
|
97
|
+
schemas = []
|
|
98
|
+
|
|
99
|
+
if result.respond_to?(:rows)
|
|
100
|
+
# Rails ActiveRecord::Result
|
|
101
|
+
result.rows.each { |row| schemas << row[0] }
|
|
102
|
+
elsif result.respond_to?(:each)
|
|
103
|
+
# Raw PG::Result
|
|
104
|
+
result.each { |row| schemas << row["schema_name"] }
|
|
105
|
+
else
|
|
106
|
+
# Fallback for other result types
|
|
107
|
+
extract_schemas_fallback(result, schemas)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
schemas
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def extract_schemas_fallback(result, schemas)
|
|
114
|
+
(0...result.ntuples).each do |i|
|
|
115
|
+
schemas << get_result_value(result, i, 0)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
85
119
|
# Execute SQL - handles both Rails connections and raw PG connections
|
|
86
120
|
def execute_sql(conn, sql)
|
|
87
121
|
if conn.respond_to?(:execute)
|
|
@@ -8,9 +8,9 @@ Gem::Specification.new do |spec|
|
|
|
8
8
|
spec.authors = ["Ruben Paz"]
|
|
9
9
|
spec.email = ["rubenpazchuspe@outlook.com"]
|
|
10
10
|
|
|
11
|
-
spec.summary = "Modern PostgreSQL schema-based multitenancy for Rails
|
|
11
|
+
spec.summary = "Modern PostgreSQL schema-based multitenancy for Rails 7+ applications"
|
|
12
12
|
spec.description = "A modern Ruby gem that provides PostgreSQL schema-based multitenancy with automatic tenant " \
|
|
13
|
-
"resolution and schema switching.
|
|
13
|
+
"resolution and schema switching. Compatible with Rails 7+ and Ruby 3.0+, focusing on security, " \
|
|
14
14
|
"performance, and developer experience. Perfect for modern SaaS applications requiring " \
|
|
15
15
|
"secure tenant isolation."
|
|
16
16
|
spec.homepage = "https://github.com/rubenpazch/pg_multitenant_schemas"
|
|
@@ -34,8 +34,8 @@ Gem::Specification.new do |spec|
|
|
|
34
34
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
35
35
|
spec.require_paths = ["lib"]
|
|
36
36
|
|
|
37
|
-
# Runtime dependencies -
|
|
38
|
-
spec.add_dependency "activerecord", ">=
|
|
39
|
-
spec.add_dependency "activesupport", ">=
|
|
37
|
+
# Runtime dependencies - Rails 7+ support with Rails 8 optimizations
|
|
38
|
+
spec.add_dependency "activerecord", ">= 7.0", "< 9.0"
|
|
39
|
+
spec.add_dependency "activesupport", ">= 7.0", "< 9.0"
|
|
40
40
|
spec.add_dependency "pg", "~> 1.5"
|
|
41
41
|
end
|
data/pre-push-check.sh
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Pre-push check script for pg_multitenant_schemas gem
|
|
3
|
+
# Run this before pushing to GitHub to catch issues early
|
|
4
|
+
|
|
5
|
+
set -e # Exit on any error
|
|
6
|
+
|
|
7
|
+
echo "🔍 Running pre-push checks for pg_multitenant_schemas..."
|
|
8
|
+
echo ""
|
|
9
|
+
|
|
10
|
+
# Color codes for output
|
|
11
|
+
RED='\033[0;31m'
|
|
12
|
+
GREEN='\033[0;32m'
|
|
13
|
+
YELLOW='\033[1;33m'
|
|
14
|
+
NC='\033[0m' # No Color
|
|
15
|
+
|
|
16
|
+
# Function to print colored output
|
|
17
|
+
print_status() {
|
|
18
|
+
echo -e "${2}${1}${NC}"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
# Function to run a check
|
|
22
|
+
run_check() {
|
|
23
|
+
local name="$1"
|
|
24
|
+
local command="$2"
|
|
25
|
+
local optional="$3"
|
|
26
|
+
|
|
27
|
+
echo "📋 $name..."
|
|
28
|
+
if eval "$command"; then
|
|
29
|
+
print_status "✅ $name passed" "$GREEN"
|
|
30
|
+
else
|
|
31
|
+
if [ "$optional" = "true" ]; then
|
|
32
|
+
print_status "⚠️ $name failed (optional)" "$YELLOW"
|
|
33
|
+
else
|
|
34
|
+
print_status "❌ $name failed" "$RED"
|
|
35
|
+
exit 1
|
|
36
|
+
fi
|
|
37
|
+
fi
|
|
38
|
+
echo ""
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# 1. Check if we're in the right directory
|
|
42
|
+
if [ ! -f "pg_multitenant_schemas.gemspec" ]; then
|
|
43
|
+
print_status "❌ Not in pg_multitenant_schemas directory" "$RED"
|
|
44
|
+
exit 1
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
# 2. Install dependencies
|
|
48
|
+
run_check "Bundle install" "bundle install --quiet"
|
|
49
|
+
|
|
50
|
+
# 3. RuboCop
|
|
51
|
+
run_check "RuboCop (code style)" "bundle exec rubocop"
|
|
52
|
+
|
|
53
|
+
# 4. RSpec unit tests
|
|
54
|
+
run_check "RSpec unit tests" "bundle exec rspec --exclude-pattern '**/integration/**/*_spec.rb'"
|
|
55
|
+
|
|
56
|
+
# 5. Security audit
|
|
57
|
+
run_check "Security audit" "bundle audit" "true"
|
|
58
|
+
|
|
59
|
+
# 6. Gem build test
|
|
60
|
+
run_check "Gem build test" "gem build pg_multitenant_schemas.gemspec > /dev/null 2>&1 && rm -f pg_multitenant_schemas-*.gem"
|
|
61
|
+
|
|
62
|
+
# 7. Check for PostgreSQL and run integration tests
|
|
63
|
+
if command -v psql &> /dev/null && pg_isready &> /dev/null; then
|
|
64
|
+
# Check if test database exists, create if not
|
|
65
|
+
if ! psql -lqt | cut -d \| -f 1 | grep -qw pg_multitenant_test; then
|
|
66
|
+
echo "📋 Creating test database..."
|
|
67
|
+
createdb pg_multitenant_test || true
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
run_check "Integration tests" "PGDATABASE=pg_multitenant_test bundle exec rspec --tag integration" "true"
|
|
71
|
+
else
|
|
72
|
+
print_status "⚠️ PostgreSQL not available, skipping integration tests" "$YELLOW"
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
# 8. Check for uncommitted changes
|
|
76
|
+
if [ -n "$(git status --porcelain)" ]; then
|
|
77
|
+
print_status "⚠️ You have uncommitted changes" "$YELLOW"
|
|
78
|
+
git status --short
|
|
79
|
+
echo ""
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
# 9. Check current branch
|
|
83
|
+
current_branch=$(git branch --show-current)
|
|
84
|
+
if [ "$current_branch" = "main" ]; then
|
|
85
|
+
print_status "⚠️ You're on the main branch" "$YELLOW"
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
echo "🎉 All checks completed successfully!"
|
|
89
|
+
echo ""
|
|
90
|
+
echo "🚀 Your code is ready to push to GitHub!"
|
|
91
|
+
echo ""
|
|
92
|
+
echo "💡 Pro tip: You can test GitHub Actions locally using 'act':"
|
|
93
|
+
echo " brew install act"
|
|
94
|
+
echo " act push # Test CI workflow"
|
|
95
|
+
echo ""
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Test GitHub Actions permissions and setup locally
|
|
3
|
+
|
|
4
|
+
echo "🔍 Testing GitHub Actions setup and permissions..."
|
|
5
|
+
echo ""
|
|
6
|
+
|
|
7
|
+
# Check if we're in a Git repository
|
|
8
|
+
if ! git rev-parse --git-dir > /dev/null 2>&1; then
|
|
9
|
+
echo "❌ Not in a Git repository"
|
|
10
|
+
exit 1
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
# Check if we're on the right branch
|
|
14
|
+
current_branch=$(git branch --show-current)
|
|
15
|
+
echo "📋 Current branch: $current_branch"
|
|
16
|
+
|
|
17
|
+
# Check if we have the workflow files
|
|
18
|
+
if [ -f ".github/workflows/main.yml" ]; then
|
|
19
|
+
echo "✅ CI workflow file exists"
|
|
20
|
+
else
|
|
21
|
+
echo "❌ CI workflow file missing"
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
if [ -f ".github/workflows/release.yml" ]; then
|
|
25
|
+
echo "✅ Release workflow file exists"
|
|
26
|
+
else
|
|
27
|
+
echo "❌ Release workflow file missing"
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
# Check version file
|
|
31
|
+
if [ -f "lib/pg_multitenant_schemas/version.rb" ]; then
|
|
32
|
+
version=$(grep -E "VERSION = ['\"]" lib/pg_multitenant_schemas/version.rb | cut -d'"' -f2 | cut -d"'" -f2)
|
|
33
|
+
echo "✅ Version file exists: $version"
|
|
34
|
+
else
|
|
35
|
+
echo "❌ Version file missing"
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
# Check if gemspec exists
|
|
39
|
+
if [ -f "pg_multitenant_schemas.gemspec" ]; then
|
|
40
|
+
echo "✅ Gemspec file exists"
|
|
41
|
+
else
|
|
42
|
+
echo "❌ Gemspec file missing"
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
# Check remote origin
|
|
46
|
+
remote_url=$(git remote get-url origin 2>/dev/null || echo "No remote")
|
|
47
|
+
echo "📋 Remote origin: $remote_url"
|
|
48
|
+
|
|
49
|
+
# Test Git config (what GitHub Actions would use)
|
|
50
|
+
echo ""
|
|
51
|
+
echo "🧪 Testing Git configuration..."
|
|
52
|
+
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
53
|
+
git config --local user.name "github-actions[bot]"
|
|
54
|
+
echo "✅ Git config set for GitHub Actions bot"
|
|
55
|
+
|
|
56
|
+
# Test gem build
|
|
57
|
+
echo ""
|
|
58
|
+
echo "🧪 Testing gem build..."
|
|
59
|
+
if gem build pg_multitenant_schemas.gemspec > /dev/null 2>&1; then
|
|
60
|
+
echo "✅ Gem builds successfully"
|
|
61
|
+
rm -f pg_multitenant_schemas-*.gem
|
|
62
|
+
else
|
|
63
|
+
echo "❌ Gem build failed"
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
# Check for uncommitted changes
|
|
67
|
+
if [ -n "$(git status --porcelain)" ]; then
|
|
68
|
+
echo ""
|
|
69
|
+
echo "⚠️ You have uncommitted changes:"
|
|
70
|
+
git status --short
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
echo ""
|
|
74
|
+
echo "🎯 Next Steps:"
|
|
75
|
+
echo "1. Ensure repository has proper permissions set in GitHub:"
|
|
76
|
+
echo " - Go to Settings > Actions > General"
|
|
77
|
+
echo " - Set 'Workflow permissions' to 'Read and write permissions'"
|
|
78
|
+
echo " - Enable 'Allow GitHub Actions to create and approve pull requests'"
|
|
79
|
+
echo ""
|
|
80
|
+
echo "2. To trigger a release:"
|
|
81
|
+
echo " - Update version in lib/pg_multitenant_schemas/version.rb"
|
|
82
|
+
echo " - Commit and push to main branch"
|
|
83
|
+
echo " - GitHub Actions will automatically create a release"
|
|
84
|
+
echo ""
|
|
85
|
+
echo "📚 For more details, see: docs/github_actions_setup.md"
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Validate GitHub workflow commands locally
|
|
3
|
+
# This script tests the exact commands used in GitHub Actions
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
echo "🧪 Testing GitHub Actions commands locally..."
|
|
8
|
+
echo ""
|
|
9
|
+
|
|
10
|
+
# Test RuboCop (exact command from workflow)
|
|
11
|
+
echo "📋 Testing: bundle exec rubocop"
|
|
12
|
+
if bundle exec rubocop > /dev/null 2>&1; then
|
|
13
|
+
echo "✅ RuboCop passed"
|
|
14
|
+
else
|
|
15
|
+
echo "❌ RuboCop failed"
|
|
16
|
+
exit 1
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
# Test unit tests (exact command from workflow)
|
|
20
|
+
echo "📋 Testing: bundle exec rspec --exclude-pattern '**/integration/**/*_spec.rb'"
|
|
21
|
+
if bundle exec rspec --exclude-pattern '**/integration/**/*_spec.rb' > /dev/null 2>&1; then
|
|
22
|
+
echo "✅ Unit tests passed"
|
|
23
|
+
else
|
|
24
|
+
echo "❌ Unit tests failed"
|
|
25
|
+
exit 1
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# Test integration tests (exact command from workflow)
|
|
29
|
+
echo "📋 Testing: bundle exec rspec --tag integration"
|
|
30
|
+
if bundle exec rspec --tag integration > /dev/null 2>&1; then
|
|
31
|
+
echo "✅ Integration tests passed"
|
|
32
|
+
else
|
|
33
|
+
echo "⚠️ Integration tests failed (may need PostgreSQL setup)"
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# Test security audit (exact command from workflow)
|
|
37
|
+
echo "📋 Testing: bundle audit"
|
|
38
|
+
if bundle audit > /dev/null 2>&1; then
|
|
39
|
+
echo "✅ Security audit passed"
|
|
40
|
+
else
|
|
41
|
+
echo "⚠️ Security audit failed (may have vulnerabilities)"
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
echo ""
|
|
45
|
+
echo "🎉 GitHub Actions command validation complete!"
|
|
46
|
+
echo ""
|
|
47
|
+
echo "💡 These are the exact commands that run in GitHub Actions CI"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pg_multitenant_schemas
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ruben Paz
|
|
@@ -15,7 +15,7 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: '
|
|
18
|
+
version: '7.0'
|
|
19
19
|
- - "<"
|
|
20
20
|
- !ruby/object:Gem::Version
|
|
21
21
|
version: '9.0'
|
|
@@ -25,7 +25,7 @@ dependencies:
|
|
|
25
25
|
requirements:
|
|
26
26
|
- - ">="
|
|
27
27
|
- !ruby/object:Gem::Version
|
|
28
|
-
version: '
|
|
28
|
+
version: '7.0'
|
|
29
29
|
- - "<"
|
|
30
30
|
- !ruby/object:Gem::Version
|
|
31
31
|
version: '9.0'
|
|
@@ -35,7 +35,7 @@ dependencies:
|
|
|
35
35
|
requirements:
|
|
36
36
|
- - ">="
|
|
37
37
|
- !ruby/object:Gem::Version
|
|
38
|
-
version: '
|
|
38
|
+
version: '7.0'
|
|
39
39
|
- - "<"
|
|
40
40
|
- !ruby/object:Gem::Version
|
|
41
41
|
version: '9.0'
|
|
@@ -45,7 +45,7 @@ dependencies:
|
|
|
45
45
|
requirements:
|
|
46
46
|
- - ">="
|
|
47
47
|
- !ruby/object:Gem::Version
|
|
48
|
-
version: '
|
|
48
|
+
version: '7.0'
|
|
49
49
|
- - "<"
|
|
50
50
|
- !ruby/object:Gem::Version
|
|
51
51
|
version: '9.0'
|
|
@@ -64,15 +64,17 @@ dependencies:
|
|
|
64
64
|
- !ruby/object:Gem::Version
|
|
65
65
|
version: '1.5'
|
|
66
66
|
description: A modern Ruby gem that provides PostgreSQL schema-based multitenancy
|
|
67
|
-
with automatic tenant resolution and schema switching.
|
|
68
|
-
3.
|
|
69
|
-
SaaS applications requiring secure tenant isolation.
|
|
67
|
+
with automatic tenant resolution and schema switching. Compatible with Rails 7+
|
|
68
|
+
and Ruby 3.0+, focusing on security, performance, and developer experience. Perfect
|
|
69
|
+
for modern SaaS applications requiring secure tenant isolation.
|
|
70
70
|
email:
|
|
71
71
|
- rubenpazchuspe@outlook.com
|
|
72
72
|
executables: []
|
|
73
73
|
extensions: []
|
|
74
74
|
extra_rdoc_files: []
|
|
75
75
|
files:
|
|
76
|
+
- ".actrc"
|
|
77
|
+
- ".env.local.example"
|
|
76
78
|
- ".rspec"
|
|
77
79
|
- ".rubocop.yml"
|
|
78
80
|
- ".rubocop_simple.yml"
|
|
@@ -80,18 +82,24 @@ files:
|
|
|
80
82
|
- CHANGELOG.md
|
|
81
83
|
- CODE_OF_CONDUCT.md
|
|
82
84
|
- LICENSE.txt
|
|
85
|
+
- LOCAL_TESTING_SUMMARY.md
|
|
83
86
|
- README.md
|
|
84
87
|
- Rakefile
|
|
88
|
+
- TESTING_LOCALLY.md
|
|
85
89
|
- docs/README.md
|
|
86
90
|
- docs/configuration.md
|
|
87
91
|
- docs/context.md
|
|
88
92
|
- docs/errors.md
|
|
93
|
+
- docs/github_actions_permissions_fix.md
|
|
94
|
+
- docs/github_actions_setup.md
|
|
89
95
|
- docs/integration_testing.md
|
|
96
|
+
- docs/local_workflow_testing.md
|
|
90
97
|
- docs/migrator.md
|
|
91
98
|
- docs/rails_integration.md
|
|
92
99
|
- docs/schema_switcher.md
|
|
93
100
|
- docs/tenant_resolver.md
|
|
94
101
|
- docs/testing.md
|
|
102
|
+
- docs/testing_rails_tasks.md
|
|
95
103
|
- examples/context_management.rb
|
|
96
104
|
- examples/migration_workflow.rb
|
|
97
105
|
- examples/rails_integration/controller_examples.rb
|
|
@@ -111,15 +119,17 @@ files:
|
|
|
111
119
|
- lib/pg_multitenant_schemas/schema_switcher.rb
|
|
112
120
|
- lib/pg_multitenant_schemas/tasks/advanced_tasks.rake
|
|
113
121
|
- lib/pg_multitenant_schemas/tasks/basic_tasks.rake
|
|
114
|
-
- lib/pg_multitenant_schemas/tasks/pg_multitenant_schemas.rake
|
|
115
122
|
- lib/pg_multitenant_schemas/tasks/tenant_tasks.rake
|
|
116
123
|
- lib/pg_multitenant_schemas/tenant_resolver.rb
|
|
117
124
|
- lib/pg_multitenant_schemas/tenant_task_helpers.rb
|
|
118
125
|
- lib/pg_multitenant_schemas/version.rb
|
|
119
126
|
- pg_multitenant_schemas.gemspec
|
|
127
|
+
- pre-push-check.sh
|
|
120
128
|
- rails_integration/app/controllers/application_controller.rb
|
|
121
129
|
- rails_integration/app/models/tenant.rb
|
|
122
130
|
- sig/pg_multitenant_schemas.rbs
|
|
131
|
+
- test-github-setup.sh
|
|
132
|
+
- validate-github-commands.sh
|
|
123
133
|
homepage: https://github.com/rubenpazch/pg_multitenant_schemas
|
|
124
134
|
licenses:
|
|
125
135
|
- MIT
|
|
@@ -144,5 +154,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
144
154
|
requirements: []
|
|
145
155
|
rubygems_version: 3.6.7
|
|
146
156
|
specification_version: 4
|
|
147
|
-
summary: Modern PostgreSQL schema-based multitenancy for Rails
|
|
157
|
+
summary: Modern PostgreSQL schema-based multitenancy for Rails 7+ applications
|
|
148
158
|
test_files: []
|