Skip to content

Commit df739bf

Browse files
authored
Merge pull request #6 from vrk-kpa/ckan-2.11
Ckan 2.11
2 parents 051df6b + d857295 commit df739bf

27 files changed

Lines changed: 511 additions & 183 deletions

.github/workflows/test.yml

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ jobs:
77
- uses: actions/checkout@v3
88
- uses: actions/setup-python@v2
99
with:
10-
python-version: '3.9'
10+
python-version: '3.10'
1111
- name: Install requirements
1212
run: pip install flake8 pycodestyle
1313
- name: Check syntax
@@ -19,16 +19,21 @@ jobs:
1919
needs: lint
2020
strategy:
2121
matrix:
22-
ckan-version: [2.9, 2.9-py2, 2.8, 2.7]
22+
include:
23+
- ckan-version: "2.11"
24+
ckan-image: "ckan/ckan-dev:2.11-py3.10"
25+
- ckan-version: "2.10"
26+
ckan-image: "ckan/ckan-dev:2.10-py3.10"
2327
fail-fast: false
2428

2529
name: CKAN ${{ matrix.ckan-version }}
2630
runs-on: ubuntu-latest
2731
container:
28-
image: openknowledge/ckan-dev:${{ matrix.ckan-version }}
32+
image: ${{ matrix.ckan-image }}
33+
options: --user root
2934
services:
3035
solr:
31-
image: ckan/ckan-solr:${{ matrix.ckan-version }}
36+
image: ckan/ckan-solr:${{ matrix.ckan-version }}-solr9
3237
postgres:
3338
image: ckan/ckan-postgres-dev:${{ matrix.ckan-version }}
3439
env:
@@ -46,24 +51,55 @@ jobs:
4651
CKAN_REDIS_URL: redis://redis:6379/1
4752

4853
steps:
54+
4955
- uses: actions/checkout@v3
56+
- name: Setup qsv
57+
run: |
58+
apt install unzip
59+
wget https://github.com/jqnatividad/qsv/releases/download/3.3.0/qsv-3.3.0-x86_64-unknown-linux-musl.zip
60+
unzip qsv-3.3.0-x86_64-unknown-linux-musl.zip -d $RUNNER_TEMP/qsvbin
61+
echo "$RUNNER_TEMP/qsvbin" >> $GITHUB_PATH
62+
63+
- run: qsv --version
64+
5065
- name: Install requirements
5166
run: |
52-
apk add file
5367
pip install -r requirements.txt
5468
pip install -r dev-requirements.txt
5569
pip install -e .
5670
# Replace default path to CKAN core config file with the one on the container
5771
sed -i -e 's/use = config:.*/use = config:\/srv\/app\/src\/ckan\/test-core.ini/' test.ini
58-
- name: Setup extension (CKAN >= 2.9)
59-
if: ${{ matrix.ckan-version != '2.7' && matrix.ckan-version != '2.8' }}
72+
73+
# Replace qsv bin to one in path, will produce error in logs
74+
sed -i -e 's/ckanext.qa.qsv_bin.*/ckanext.qa.qsv_bin = qsv/' test.ini
75+
76+
- name: Setup extension
6077
run: |
6178
ckan -c test.ini db init
62-
ckan -c test.ini qa init
63-
- name: Setup extension (CKAN < 2.9)
64-
if: ${{ matrix.ckan-version == '2.7' || matrix.ckan-version == '2.8' }}
65-
run: |
66-
paster --plugin=ckan db init -c test.ini
67-
paster --plugin=ckanext-qa qa init -c test.ini
79+
ckan -c test.ini db upgrade -p qa
80+
6881
- name: Run tests
69-
run: pytest --ckan-ini=test.ini --cov=ckanext.qa --disable-warnings ckanext/qa/tests
82+
run: pytest --ckan-ini=test.ini --cov=ckanext.qa --disable-warnings ckanext/qa/tests --junitxml=junit.xml -o junit_family=legacy
83+
84+
- name: install codecov requirements
85+
run: |
86+
apt-get update
87+
apt-get install -y curl gpg
88+
89+
- name: Upload coverage reports to Codecov
90+
uses: codecov/codecov-action@v5
91+
if: ${{ !cancelled() }}
92+
continue-on-error: true #don't fail if we can't upload (ie a fork that does not have integration plugged in)
93+
with:
94+
token: ${{ secrets.CODECOV_TOKEN }}
95+
verbose: false # optional (default = false)
96+
flags: ckan-${{ matrix.ckan-version }}
97+
98+
- name: Upload test results to Codecov
99+
uses: codecov/test-results-action@v1
100+
if: ${{ !cancelled() }}
101+
continue-on-error: true #don't fail if we can't upload (ie a fork that does not have integration plugged in)
102+
with:
103+
token: ${{ secrets.CODECOV_TOKEN }}
104+
verbose: false # optional (default = false)
105+
flags: ckan-${{ matrix.ckan-version }}

README.rst

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ Requirements
3232
Before installing ckanext-qa, make sure that you have installed the following:
3333

3434
* CKAN 2.1+ (tests are only running for CKAN 2.7+)
35+
* QSV (https://github.com/dathere/qsv) identifying files
3536
* ckanext-archiver 2.0+ (https://github.com/ckan/ckanext-archiver)
3637
* ckanext-report (https://github.com/datagovuk/ckanext-report) for reporting
3738

@@ -59,13 +60,15 @@ To install ckanext-qa, ensure you have previously installed ckanext-archiver (v2
5960

6061
4. Now create the database tables::
6162

62-
paster --plugin=ckanext-qa qa init --config=production.ini
63+
ckan -c ckan.ini qa init
6364

6465
5. Add ``qa`` to the ``ckan.plugins`` setting BEFORE ``archiver`` in your CKAN
6566
config file (by default the config file is located at
66-
``/etc/ckan/default/production.ini``).
67+
``/etc/ckan/default/ckan.ini``).
68+
69+
6. Add ``qsv`` binary path to ``ckanext.qa.qsv_bin`` config variable.
6770

68-
6. Restart CKAN. For example if you've deployed CKAN with Apache on Ubuntu::
71+
7. Restart CKAN. For example if you've deployed CKAN with Apache on Ubuntu::
6972

7073
sudo service apache2 reload
7174

ckanext/qa/cli.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ def update(ids, queue):
6161

6262
@qa.command()
6363
@click.argument('filepaths', nargs=-1)
64+
@click.option('-f', '--filepaths', help='Filepaths to sniff')
6465
def sniff(filepaths):
6566
if len(filepaths) < 1:
6667
print('Not enough arguments', filepaths)

ckanext/qa/config_declaration.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
version: 1
2+
groups:
3+
- annotation: QA settings
4+
options:
5+
- key: ckanext.qa.qsv_bin
6+
description: Path to QSV binary
7+
default: /usr/local/bin/qsv

ckanext/qa/lib.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22
import json
33
import re
44
import logging
5-
from ckan.plugins.toolkit import config
5+
from ckan.plugins import toolkit as tk
66

77
from ckan import plugins as p
88
from ckanext.qa.tasks import update_package, update
99

1010
log = logging.getLogger(__name__)
1111

12+
config = tk.config
13+
enqueue_job = tk.enqueue_job
14+
1215
_RESOURCE_FORMAT_SCORES = None
1316

1417

@@ -19,10 +22,11 @@ def compat_enqueue(name, fn, queue, args=None):
1922
'''
2023
try:
2124
# Try to use RQ
22-
from ckan.plugins.toolkit import enqueue_job
25+
log.debug('Trying to use RQ')
2326
enqueue_job(fn, args=args, queue=queue)
2427
except ImportError:
2528
# Fallback to Celery
29+
log.debug('RQ not installed, falling back to Celery')
2630
import uuid
2731
from ckan.lib.celery_app import celery
2832
celery.send_task(name, args=args + [queue], task_id=str(uuid.uuid4()))
@@ -87,7 +91,7 @@ def munge_format_to_be_canonical(format_name):
8791
def create_qa_update_package_task(package, queue):
8892

8993
compat_enqueue('qa.update_package', update_package, queue, args=[package.id])
90-
log.debug('QA of package put into celery queue %s: %s',
94+
log.debug('QA of package put into queue %s: %s',
9195
queue, package.name)
9296

9397

@@ -99,5 +103,5 @@ def create_qa_update_task(resource, queue):
99103

100104
compat_enqueue('qa.update', update, queue, args=[resource.id])
101105

102-
log.debug('QA of resource put into celery queue %s: %s/%s url=%r',
106+
log.debug('QA of resource put into queue %s: %s/%s url=%r',
103107
queue, package.name, resource.id, resource.url)

ckanext/qa/migration/qa/README

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Generic single-database configuration.
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# A generic, single database configuration.
2+
3+
[alembic]
4+
# path to migration scripts
5+
script_location = %(here)s
6+
7+
# template used to generate migration files
8+
# file_template = %%(rev)s_%%(slug)s
9+
10+
# timezone to use when rendering the date
11+
# within the migration file as well as the filename.
12+
# string value is passed to dateutil.tz.gettz()
13+
# leave blank for localtime
14+
# timezone =
15+
16+
# max length of characters to apply to the
17+
# "slug" field
18+
#truncate_slug_length = 40
19+
20+
# set to 'true' to run the environment during
21+
# the 'revision' command, regardless of autogenerate
22+
# revision_environment = false
23+
24+
# set to 'true' to allow .pyc and .pyo files without
25+
# a source .py file to be detected as revisions in the
26+
# versions/ directory
27+
# sourceless = false
28+
29+
# version location specification; this defaults
30+
# to /srv/app/ckanext/ckanext-qa/ckanext/qa/migration/qa/versions. When using multiple version
31+
# directories, initial revisions must be specified with --version-path
32+
# version_locations = %(here)s/bar %(here)s/bat /srv/app/ckanext/ckanext-qa/ckanext/qa/migration/qa/versions
33+
34+
# the output encoding used when revision files
35+
# are written from script.py.mako
36+
# output_encoding = utf-8
37+
38+
sqlalchemy.url = driver://user:pass@localhost/dbname
39+
40+
41+
# Logging configuration
42+
[loggers]
43+
keys = root,sqlalchemy,alembic
44+
45+
[handlers]
46+
keys = console
47+
48+
[formatters]
49+
keys = generic
50+
51+
[logger_root]
52+
level = WARN
53+
handlers = console
54+
qualname =
55+
56+
[logger_sqlalchemy]
57+
level = WARN
58+
handlers =
59+
qualname = sqlalchemy.engine
60+
61+
[logger_alembic]
62+
level = INFO
63+
handlers =
64+
qualname = alembic
65+
66+
[handler_console]
67+
class = StreamHandler
68+
args = (sys.stderr,)
69+
level = NOTSET
70+
formatter = generic
71+
72+
[formatter_generic]
73+
format = %(levelname)-5.5s [%(name)s] %(message)s
74+
datefmt = %H:%M:%S

ckanext/qa/migration/qa/env.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# -*- coding: utf-8 -*-
2+
3+
from __future__ import with_statement
4+
from alembic import context
5+
from sqlalchemy import engine_from_config, pool
6+
from logging.config import fileConfig
7+
from ckan.model.meta import metadata
8+
9+
import os
10+
11+
# this is the Alembic Config object, which provides
12+
# access to the values within the .ini file in use.
13+
config = context.config
14+
15+
# Interpret the config file for Python logging.
16+
# This line sets up loggers basically.
17+
fileConfig(config.config_file_name)
18+
19+
# add your model's MetaData object here
20+
# for 'autogenerate' support
21+
# from myapp import mymodel
22+
# target_metadata = mymodel.Base.metadata
23+
target_metadata = metadata
24+
25+
# other values from the config, defined by the needs of env.py,
26+
# can be acquired:
27+
# my_important_option = config.get_main_option("my_important_option")
28+
# ... etc.
29+
30+
name = os.path.basename(os.path.dirname(__file__))
31+
32+
33+
def include_object(object, object_name, type_, reflected, compare_to):
34+
if type_ == "table":
35+
return object_name.startswith(name)
36+
return True
37+
38+
39+
def run_migrations_offline():
40+
"""Run migrations in 'offline' mode.
41+
42+
This configures the context with just a URL
43+
and not an Engine, though an Engine is acceptable
44+
here as well. By skipping the Engine creation
45+
we don't even need a DBAPI to be available.
46+
47+
Calls to context.execute() here emit the given string to the
48+
script output.
49+
50+
"""
51+
52+
url = config.get_main_option(u"sqlalchemy.url")
53+
context.configure(
54+
url=url, target_metadata=target_metadata, literal_binds=True,
55+
version_table=u'{}_alembic_version'.format(name),
56+
include_object=include_object,
57+
)
58+
59+
with context.begin_transaction():
60+
context.run_migrations()
61+
62+
63+
def run_migrations_online():
64+
"""Run migrations in 'online' mode.
65+
66+
In this scenario we need to create an Engine
67+
and associate a connection with the context.
68+
69+
"""
70+
connectable = engine_from_config(
71+
config.get_section(config.config_ini_section),
72+
prefix=u'sqlalchemy.',
73+
poolclass=pool.NullPool)
74+
75+
with connectable.connect() as connection:
76+
context.configure(
77+
connection=connection,
78+
target_metadata=target_metadata,
79+
version_table=u'{}_alembic_version'.format(name),
80+
include_object=include_object,
81+
)
82+
83+
with context.begin_transaction():
84+
context.run_migrations()
85+
86+
87+
if context.is_offline_mode():
88+
run_migrations_offline()
89+
else:
90+
run_migrations_online()
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
"""${message}
2+
3+
Revision ID: ${up_revision}
4+
Revises: ${down_revision | comma,n}
5+
Create Date: ${create_date}
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
${imports if imports else ""}
11+
12+
# revision identifiers, used by Alembic.
13+
revision = ${repr(up_revision)}
14+
down_revision = ${repr(down_revision)}
15+
branch_labels = ${repr(branch_labels)}
16+
depends_on = ${repr(depends_on)}
17+
18+
19+
def upgrade():
20+
${upgrades if upgrades else "pass"}
21+
22+
23+
def downgrade():
24+
${downgrades if downgrades else "pass"}

0 commit comments

Comments
 (0)