Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 121 additions & 16 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,45 @@ on:

# This allows a subsequently queued workflow run to interrupt previous runs.
concurrency:
group: "${{ github.workflow }} @ ${{ github.ref }}"
group: '${{ github.workflow }} @ ${{ github.ref }}'
cancel-in-progress: true

jobs:
# Since the name of the matrix job depends on the version, we define another job with a more stable name.
test_results:
if: ${{ always() }}
orchestrate:
name: Orchestrate matrix from Docker Hub
runs-on: ubuntu-latest
name: Test Results
needs: [test]
outputs:
postgis_tags: ${{ steps.prepare.outputs.postgis_tags }}
steps:
- run: '[[ "${{ needs.test.result }}" == "success" ]]'
- name: Query Docker Hub tags and build matrix
id: prepare
run: |
# https://www.postgresql.org/support/versioning/
pg_targets='[14, 15, 16, 17, 18]'

tags=$(
curl -s "https://hub.docker.com/v2/repositories/postgis/postgis/tags?page_size=100" |
jq --compact-output '
.results
| map(.name) as $tags
| '"$pg_targets"'
| map(
. as $target
| $tags
| map(select(test("^\($target)-\\d+\\.\\d+$")))[0]
)
'
)

if [[ $(jq 'length' <<< "$tags") -ne $(jq 'length' <<< "$tags") ]]; then
echo "Error: Could not find tags for all PostgreSQL targets" >&2
exit 1
fi

echo "postgis_tags=$tags" >> $GITHUB_OUTPUT
Comment on lines +25 to +48
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the reasoning behind needing to do this instead of an array of versions? is it just because postgis does not have the same versions as postgres in docker?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly the postgis version vary depending on on the pg version. Here we ensure we are using the latest, yet not the master branch. This is the most likely used by users of this repo IMO. We could also consider adding postgis to the matrix, and just check if version tags exists. Something like:

jobs:
  orchestrate:
    matrix:
      postgres: [14, 15, ..]
      postgis: [3.5, 3.6]
    output:
      tags: ...
    run: Check if matrix elements contain tags

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok got it. Seems fine as if. If there's issues with versioning for some reason later we could move to the tags you suggested but doesn't seem like a problem

test:
runs-on: ubuntu-latest
needs: [orchestrate]
services:
postgis:
image: postgis/postgis:${{matrix.pg}}
Expand All @@ -38,15 +63,14 @@ jobs:
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
AR_VERSION: 8.0.0.1
strategy:
fail-fast: false
matrix:
# https://ruby-lang.org/en/downloads/branches
ruby: ["3.4", "3.3", "3.2"]
ruby: ['3.4', '3.3', '3.2']
# https://www.postgresql.org/support/versioning/
pg: [12-master, 13-master, 14-master, 15-master, 16-master]
# See (and update!) `pg_targets` above for selected pg versions.
pg: ${{ fromJson(needs.orchestrate.outputs.postgis_tags) }}
steps:
- name: Set Up Actions
uses: actions/checkout@v4
Expand All @@ -59,11 +83,9 @@ jobs:
bundler-cache: true
- name: Setup Database
run: |
psql -d postgresql://postgres:postgres@localhost:5432/postgres \
-c "create database postgis_adapter_test" \
-c "create database activerecord_unittest" \
-c "create database activerecord_unittest2"
for db in postgis_adapter_test activerecord_unittest activerecord_unittest2; do
for db in activerecord_unittest activerecord_unittest2; do
psql -d postgresql://postgres:postgres@localhost:5432/postgres \
-c "create database $db"
psql -d postgresql://postgres:postgres@localhost:5432/$db -c "create extension postgis"
done
- name: Run Tests
Expand All @@ -74,3 +96,86 @@ jobs:
PGPASSWORD: postgres
TESTOPTS: --profile=3
TEST_TIMEOUT: 30
RAILS_MINITEST_PLUGIN: '1'
JSON_REPORTER: 'report.json'
- name: Upload Report
if: ${{ failure() && steps.test.conclusion == 'failure' }}
uses: actions/upload-artifact@v4
with:
name: report-${{ matrix.pg }}-${{ matrix.ruby }}
path: report.json
# Since the name of the matrix job depends on the version,
# we define another job with a more stable name. This jobs
# also gives a nice summary of failing tests.
test_results:
if: always()
runs-on: ubuntu-latest
name: Test Results
needs: [test]
steps:
- name: Check Success
run: |
result="${{ needs.test.result }}"

if [[ $result == "success" || $result == "skipped" ]]; then
echo "All tests passed :taco:" >>$GITHUB_STEP_SUMMARY
exit 0
else
exit 1
fi
- name: Download Reports
if: failure()
uses: actions/download-artifact@v4
with:
path: reports
- name: Aggregate Reports
if: failure()
run: |
cat <<EOF >>$GITHUB_STEP_SUMMARY
# Failing Tests

<table>
<thead>
<tr>
<th>#</th>
<th>Test</th>
<th>Failure</th>
</tr>
</thead>
<tbody>
EOF

jq --slurp --raw-output '
map(.failed_tests) | flatten | map({
klass,
NAME,
failure: .failures[0],
source_url: (
.source_location | if (.[0] | contains("/gems/")) then
(.[0] | capture("rails-(?<sha>.*?)/(?<path>.*)")) *
{line: .[1], server: "https://github.com", repo: "rails/rails"}
else
(.[0] | capture("activerecord-postgis-adapter/(?<path>test/.*)") *
{line: .[1], sha: $ENV.GITHUB_SHA, repo: $ENV.GITHUB_REPOSITORY, server: $ENV.GITHUB_SERVER_URL}
end | "\(.server)/\(.repo)/blob/\(.sha)/\(.path)#L\(.line)"
)
}) | group_by(.) | map(.[0] * { count: length }) | sort[0:100][]
| "<tr>"
+ "<td><strong>\(.count)</strong></td>"
+ "<td><a href=\"\(.source_url)\">\(.klass)#\(.NAME)</a></td>"
+ "<td><pre>\(.failure)</pre></td>"
+ "</tr>"
' reports/*/report.json >>$GITHUB_STEP_SUMMARY

cat <<EOF >>$GITHUB_STEP_SUMMARY
</tbody>
</table>
EOF

# Do not print json if too large.
[[ "$(du -s reports | cut -f1)" -gt 124 ]] && exit 0

echo >>$GITHUB_STEP_SUMMARY
echo '```json' >>$GITHUB_STEP_SUMMARY
jq --slurp --compact-output '.' reports/*/report.json >>$GITHUB_STEP_SUMMARY
echo '```' >>$GITHUB_STEP_SUMMARY
19 changes: 11 additions & 8 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ Fork the repo:

`git clone [email protected]:rgeo/activerecord-postgis-adapter.git`

Set up your test database:
Set up your test databases:

```sh
createuser -s postgres
psql -U postgres -c "create database postgis_adapter_test"
psql -U postgres -d postgis_adapter_test -c "create extension postgis"
for db in activerecord_unittest activerecord_unittest2; do
psql -U postgres -c "create database $db"
psql -U postgres -d $db -c "create extension postgis"
done
```

You may also set up environment variables to define the database connection.
Expand All @@ -21,10 +23,11 @@ export PGUSER=postgis_test
export PGPASSWORD=password123
export PGPORT=95432
export PGHOST=127.0.0.2
export PGDATABASE=postgis_adapter_test

psql -c "create database postgis_adapter_test"
psql -c "create extension postgis"
for db in activerecord_unittest activerecord_unittest2; do
psql -U postgres -c "create database $db"
psql -U postgres -d $db -c "create extension postgis"
done
```

Install dependencies:
Expand All @@ -40,8 +43,8 @@ Make sure the tests pass:
Run tests with a specific ActiveRecord version:

```sh
AR_VERSION=7.0.1 bundle install
AR_VERSION=7.0.1 bundle exec rake test
AR_VERSION=<any commit hash, tag, branch name> bundle install
AR_VERSION=<any commit hash, tag, branch name> bundle exec rake test
```

To run a specific test, use the `POSTGIS_TEST_FILES` environment variable:
Expand Down
4 changes: 1 addition & 3 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ gem "pg", "~> 1.0", platform: :ruby
gem "byebug" if ENV["BYEBUG"]

def activerecord_version
return ENV["AR_VERSION"] if ENV["AR_VERSION"]

require "uri"
require "yaml"
require "net/http"
Expand All @@ -29,7 +27,7 @@ def activerecord_version
ver["number"]
end
# Need to install for tests
gem "rails", github: "rails/rails", tag: "v#{activerecord_version}"
gem "rails", github: "rails/rails", ref: ENV.fetch("AR_VERSION", "v#{activerecord_version}")

group :development do
# Gems used by the ActiveRecord test suite
Expand Down
6 changes: 3 additions & 3 deletions activerecord-postgis-adapter.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Gem::Specification.new do |spec|
spec.summary = "ActiveRecord adapter for PostGIS, based on RGeo."
spec.description =
"ActiveRecord connection adapter for PostGIS. It is based on the stock " \
"PostgreSQL adapter, and adds built-in support for the spatial extensions "\
"PostgreSQL adapter, and adds built-in support for the spatial extensions " \
"provided by PostGIS. It uses the RGeo library to represent spatial data in Ruby."

spec.version = ActiveRecord::ConnectionAdapters::PostGIS::VERSION
Expand All @@ -20,8 +20,8 @@ Gem::Specification.new do |spec|
# ruby-lang.org/en/downloads/branches
spec.required_ruby_version = ">= 3.2.0"

spec.add_dependency "activerecord", "~> 8.0.0"
spec.add_dependency "rgeo-activerecord", "~> 8.0.0"
spec.add_dependency "activerecord", "~> 8.1.0"
spec.add_dependency "rgeo-activerecord", "~> 8.1.0"

spec.add_development_dependency "rake", "~> 13.0"
spec.add_development_dependency "minitest", "~> 5.4"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
module ActiveRecord # :nodoc:
module ConnectionAdapters # :nodoc:
module PostGIS # :nodoc:
class SpatialColumn < ConnectionAdapters::PostgreSQLColumn # :nodoc:
class Column < PostgreSQL::Column # :nodoc:
# sql_type examples:
# "Geometry(Point,4326)"
# "Geography(Point,4326)"
def initialize(name, default, sql_type_metadata = nil, null = true,
def initialize(name, cast_type, default, sql_type_metadata = nil, null = true,
default_function = nil, collation: nil, comment: nil,
serial: nil, generated: nil, spatial: nil, identity: nil)
@sql_type_metadata = sql_type_metadata
super(name, cast_type, default, sql_type_metadata, null, default_function,
collation: collation, comment: comment, serial: serial, generated: generated, identity: identity)
@geographic = !!(sql_type_metadata.sql_type =~ /geography\(/i)
if spatial
# This case comes from an entry in the geometry_columns table
Expand All @@ -30,8 +31,6 @@ def initialize(name, default, sql_type_metadata = nil, null = true,
# @geometric_type = geo_type_from_sql_type(sql_type)
build_from_sql_type(sql_type_metadata.sql_type)
end
super(name, default, sql_type_metadata, null, default_function,
collation: collation, comment: comment, serial: serial, generated: generated, identity: identity)
if spatial? && @srid
@limit = { srid: @srid, type: to_type_name(geometric_type) }
@limit[:has_z] = true if @has_z
Expand All @@ -58,6 +57,49 @@ def spatial?
%i[geometry geography].include?(@sql_type_metadata.type)
end

def init_with(coder)
@geographic = coder["geographic"]
@geometric_type = coder["geometric_type"]
@has_m = coder["has_m"]
@has_z = coder["has_z"]
@srid = coder["srid"]
@limit = coder["limit"]
super
end

def encode_with(coder)
coder["geographic"] = @geographic
coder["geometric_type"] = @geometric_type
coder["has_m"] = @has_m
coder["has_z"] = @has_z
coder["srid"] = @srid
coder["limit"] = @limit
super
end

def ==(other)
other.is_a?(Column) &&
super &&
other.geographic == geographic &&
other.geometric_type == geometric_type &&
other.has_m == has_m &&
other.has_z == has_z &&
other.srid == srid &&
other.limit == limit
end
alias :eql? :==

def hash
Column.hash ^
super.hash ^
geographic.hash ^
geometric_type.hash ^
has_m.hash ^
has_z.hash ^
srid.hash ^
limit.hash
end

private

def set_geometric_type_from_name(name)
Expand Down
Loading