Skip to content

Commit

Permalink
Merge pull request #6 from ds-wizard/release/1.2.0
Browse files Browse the repository at this point in the history
Release 1.2.0
  • Loading branch information
MarekSuchanek committed Jan 19, 2024
2 parents a02465e + 97d98a3 commit ca253af
Show file tree
Hide file tree
Showing 12 changed files with 180 additions and 133 deletions.
125 changes: 62 additions & 63 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,77 +10,76 @@ jobs:
runs-on: ubuntu-latest

env:
PUBLIC_IMAGE: datastewardshipwizard/nanopub-submission-service
PRIVATE_IMAGE: ${{ secrets.PRIVATE_REGISTRY_URL }}/nanopub-submission-service
TAG_DEVELOP: develop
TAG_LATEST: latest
PUBLIC_IMAGE_PREFIX: 'datastewardshipwizard'
DOCKER_IMAGE_NAME: 'nanopub-submission-service'
DOCKER_META_CONTEXT: '.'
DOCKER_META_FILE: 'Dockerfile'
DOCKER_META_PLATFORMS: 'linux/amd64,linux/arm64'

steps:
- uses: actions/checkout@v2
- name: '[setup] Check out repository'
uses: actions/checkout@v4
with:
fetch-depth: 0

# (1) -> Build Docker image
- name: Update build info
run: |
./scripts/build-info.sh
- name: '[setup] Set up QEMU'
uses: docker/setup-qemu-action@v3

- name: Docker build
run: |
docker build -t $PRIVATE_IMAGE:$GITHUB_SHA .
- name: '[setup] Set up Docker Buildx'
id: buildx
uses: docker/setup-buildx-action@v3

# (2) -> Docker image tagging
- name: Docker login
if: github.event_name == 'push'
- name: '[setup ]Update build info'
run: |
docker login -u "$DOCKER_HUB_USERNAME" -p "$DOCKER_HUB_PASSWORD"
docker login -u "$PRIVATE_REGISTRY_USERNAME" -p "$PRIVATE_REGISTRY_PASSWORD" "$PRIVATE_REGISTRY_URL"
env:
DOCKER_HUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }}
DOCKER_HUB_PASSWORD: ${{ secrets.DOCKER_HUB_PASSWORD }}
PRIVATE_REGISTRY_URL: ${{ secrets.PRIVATE_REGISTRY_URL }}
PRIVATE_REGISTRY_USERNAME: ${{ secrets.PRIVATE_REGISTRY_USERNAME }}
PRIVATE_REGISTRY_PASSWORD: ${{ secrets.PRIVATE_REGISTRY_PASSWORD }}
./scripts/build-info.sh
- name: Docker push - commit SHA (private)
if: github.event_name == 'push' && !startsWith(github.ref, 'refs/tags/')
run: |
docker push $PRIVATE_IMAGE:$GITHUB_SHA
- name: '[docker] Docker meta'
id: meta-test
uses: docker/metadata-action@v5
with:
images: |
${{ env.PUBLIC_IMAGE_PREFIX }}/${{ env.DOCKER_IMAGE_NAME }}
tags: |
type=sha
- name: Docker tag and push - branch (private)
if: github.event_name == 'push' && startsWith(github.ref, 'refs/heads/') && !contains(github.ref, 'release')
run: |
GITHUB_BRANCH=`echo $GITHUB_REF | cut -d/ -f3- | sed 's#/#-#g'`
docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $PRIVATE_IMAGE:$GITHUB_BRANCH
docker push $PRIVATE_IMAGE:$GITHUB_BRANCH
- name: '[docker] Docker build'
uses: docker/build-push-action@v4
with:
context: ${{ env.DOCKER_META_CONTEXT }}
file: ${{ env.DOCKER_META_FILE }}
platforms: ${{ env.DOCKER_META_PLATFORMS }}
push: false
tags: ${{ steps.meta-test.outputs.tags }}
labels: ${{ steps.meta-test.outputs.labels }}

- name: Docker tag and push - develop (public)
if: github.event_name == 'push' && github.ref == 'refs/heads/develop'
run: |
docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $PUBLIC_IMAGE:$TAG_DEVELOP
docker push $PUBLIC_IMAGE:$TAG_DEVELOP
- name: '[docker-hub] Docker login'
if: github.event_name != 'pull_request' && github.actor != 'dependabot[bot]'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}

- name: Docker tag and push - latest (public)
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
run: |
docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $PUBLIC_IMAGE:$TAG_LATEST
docker push $PUBLIC_IMAGE:$TAG_LATEST
- name: '[docker-hub] Docker meta'
id: meta-public
if: github.event_name != 'pull_request' && github.actor != 'dependabot[bot]'
uses: docker/metadata-action@v5
with:
images: |
${{ env.PUBLIC_IMAGE_PREFIX }}/${{ env.DOCKER_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }}
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.') }}
- name: Docker tag and push - version tag (public)
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
run: |
GITHUB_TAG=`echo $GITHUB_REF | cut -d/ -f3`
# Release vX.Y.Z
if [[ $GITHUB_TAG =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
IMAGE_TAG_MAJOR="$PUBLIC_IMAGE:"`echo $GITHUB_TAG | sed -E "s/v(.*)\..*\..*/\1/g"`
IMAGE_TAG_MINOR="$PUBLIC_IMAGE:"`echo $GITHUB_TAG | sed -E "s/v(.*)\..*/\1/g"`
IMAGE_TAG_PATCH="$PUBLIC_IMAGE:"`echo $GITHUB_TAG | sed -E "s/v//g"`
echo "Publishing release: $IMAGE_TAG_PATCH";
docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $IMAGE_TAG_MAJOR && docker push $IMAGE_TAG_MAJOR;
docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $IMAGE_TAG_MINOR && docker push $IMAGE_TAG_MINOR;
docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $IMAGE_TAG_PATCH && docker push $IMAGE_TAG_PATCH;
fi
# Release candidate vX.Y.Z-rc.R
if [[ $GITHUB_TAG =~ ^v[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$ ]]; then
IMAGE_TAG_RC="$PUBLIC_IMAGE:"`echo $GITHUB_TAG | sed -E "s/v//g"`
echo "Publishing release candidate: $IMAGE_TAG_RC";
docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $IMAGE_TAG_RC && docker push $IMAGE_TAG_RC;
fi
- name: '[docker-hub] Docker build+push'
uses: docker/build-push-action@v4
if: github.event_name != 'pull_request' && steps.meta-public.outputs.tags != ''
with:
context: ${{ env.DOCKER_META_CONTEXT }}
file: ${{ env.DOCKER_META_FILE }}
platforms: ${{ env.DOCKER_META_PLATFORMS }}
push: true
tags: ${{ steps.meta-public.outputs.tags }}
labels: ${{ steps.meta-public.outputs.labels }}
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM python:3.9-slim-buster
FROM python:3.11-slim-bookworm

RUN apt-get update && \
apt install -y --no-install-recommends bash default-jre && \
apt install -y --no-install-recommends bash default-jre build-essential gcc && \
rm -rf /var/lib/apt/lists/*

WORKDIR /app
Expand Down
Binary file removed bin/nanopub-1.36-jar-with-dependencies.jar
Binary file not shown.
Binary file added bin/nanopub-1.55-jar-with-dependencies.jar
Binary file not shown.
1 change: 0 additions & 1 deletion bin/np
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,3 @@ fi

>&2 echo "ERROR: Failed to find or download nanopub jar file."
exit 1

26 changes: 19 additions & 7 deletions nanopub_submitter/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

from typing import Tuple

from nanopub_submitter.config import cfg_parser
from nanopub_submitter.consts import NICE_NAME, VERSION, BUILD_INFO,\
from nanopub_submitter.config import cfg_parser, RequestConfig
from nanopub_submitter.consts import NICE_NAME, VERSION, BUILD_INFO, \
ENV_CONFIG, DEFAULT_CONFIG, DEFAULT_ENCODING
from nanopub_submitter.logger import LOG, init_default_logging, init_config_logging
from nanopub_submitter.mailer import Mailer
Expand Down Expand Up @@ -43,6 +43,12 @@ def _extract_content_type(header: str) -> Tuple[str, str]:
return input_format, DEFAULT_ENCODING


def _extract_servers(header: str) -> list[str]:
if header == '':
return []
return list(map(lambda x: x.strip(), header.split(',')))


@app.get(path='/')
async def get_info():
return fastapi.responses.JSONResponse(
Expand All @@ -62,7 +68,11 @@ async def submit_nanopub(request: fastapi.Request):
# (2) Extract data
submission_id = str(uuid.uuid4())
data = await request.body()
input_format, encoding = _extract_content_type(request.headers.get('Content-Type'))
input_format, encoding = _extract_content_type(request.headers.get('Content-Type', ''))
req_cfg = RequestConfig(
servers=_extract_servers(request.headers.get('X-NP-Servers', '')),
uri_replace=request.headers.get('X-URI-Replace', None)
)
if input_format != 'application/trig':
return fastapi.responses.Response(
status_code=fastapi.status.HTTP_400_BAD_REQUEST,
Expand All @@ -73,6 +83,7 @@ async def submit_nanopub(request: fastapi.Request):
try:
result = process(
cfg=cfg,
req_cfg=req_cfg,
submission_id=submission_id,
data=data.decode(encoding),
)
Expand All @@ -85,16 +96,17 @@ async def submit_nanopub(request: fastapi.Request):
LOG.error(f'[{submission_id}] Unexpected processing error: {str(e)}')
return fastapi.responses.PlainTextResponse(
status_code=fastapi.status.HTTP_500_INTERNAL_SERVER_ERROR,
content='Failed to process the nanopublication',
content=f'Failed to process the nanopublication: {str(e)}',
)
# (4) Mail
Mailer.get().notice(nanopub_uri=result.location)
# (5) Return
headers = dict()
if result.location is not None:
headers['Location'] = result.location
return fastapi.responses.Response(
status_code=fastapi.status.HTTP_201_CREATED,
headers={
'Location': result.location,
},
headers=headers,
content=str(result),
)

Expand Down
7 changes: 7 additions & 0 deletions nanopub_submitter/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,3 +260,10 @@ def config(self) -> SubmitterConfig:


cfg_parser = SubmitterConfigParser()


class RequestConfig:

def __init__(self, servers: list[str], uri_replace: Optional[str]):
self.servers = servers
self.uri_replace = uri_replace
2 changes: 1 addition & 1 deletion nanopub_submitter/consts.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
PACKAGE_NAME = 'nanopub_submitter'
NICE_NAME = 'DSW Nanopublication Submission Service'
PACKAGE_VERSION = '1.1.0'
PACKAGE_VERSION = '1.2.0'
ENV_CONFIG = 'SUBMISSION_CONFIG'
LOGGER_NAME = 'DSW_SUBMITTER'

Expand Down
69 changes: 48 additions & 21 deletions nanopub_submitter/nanopub.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from typing import Optional, Tuple

from nanopub_submitter.config import SubmitterConfig
from nanopub_submitter.config import SubmitterConfig, RequestConfig
from nanopub_submitter.consts import DEFAULT_ENCODING, PACKAGE_NAME, PACKAGE_VERSION
from nanopub_submitter.logger import LOG
from nanopub_submitter.triple_store import store_to_triple_store
Expand Down Expand Up @@ -40,9 +40,11 @@ def __str__(self):

class NanopubProcessingContext:

def __init__(self, submission_id: str, cfg: SubmitterConfig):
def __init__(self, submission_id: str, cfg: SubmitterConfig,
req_cfg: RequestConfig):
self.id = submission_id
self.cfg = cfg
self.req_cfg = req_cfg
self.uri = None

def cleanup(self):
Expand All @@ -54,6 +56,20 @@ def cleanup(self):
except Exception:
pass

@property
def target_servers(self) -> list[str]:
if len(self.req_cfg.servers) > 0:
return self.req_cfg.servers
return self.cfg.nanopub.target_servers

@property
def uri_replace(self) -> Optional[str]:
if self.req_cfg.uri_replace is None:
return self.cfg.nanopub.uri_replace
if '|' in self.req_cfg.uri_replace:
return self.req_cfg.uri_replace
return None

@property
def input_file(self) -> str:
return f'{self.id}.trig'
Expand Down Expand Up @@ -100,23 +116,29 @@ def _split_nanopubs(nanopub_bundle: str) -> list[str]:
def _publish_nanopub(nanopub_bundle: str, ctx: NanopubProcessingContext) -> list[str]:
success = []
nanopubs = _split_nanopubs(nanopub_bundle)
for server in ctx.cfg.nanopub.target_servers:
for server in ctx.target_servers:
ctx.debug(f'Submitting to: {server}')
ok = True
for nanopub in nanopubs:
r = requests.post(
url=server,
data=nanopub,
headers={
'Content-Type': f'application/trig; charset={DEFAULT_ENCODING}',
'User-Agent': f'{PACKAGE_NAME}/{PACKAGE_VERSION}',
}
)
if not r.ok:
try:
r = requests.post(
url=server,
data=nanopub.encode(encoding=DEFAULT_ENCODING),
headers={
'Content-Type': f'application/trig; charset={DEFAULT_ENCODING}',
'User-Agent': f'{PACKAGE_NAME}/{PACKAGE_VERSION}',
},
timeout=10,
)
if not r.ok:
ok = False
ctx.warn(f'Failed to publish nanopub via {server}')
ctx.debug(f'status={r.status_code}')
ctx.debug(r.text)
break
except Exception as e:
ok = False
ctx.warn(f'Failed to publish nanopub via {server}')
ctx.debug(f'status={r.status_code}')
ctx.debug(r.text)
ctx.warn(f'Failed to publish nanopub via {server}: {str(e)}')
break
if ok:
ctx.info(f'Nanopub published via {server}')
Expand Down Expand Up @@ -173,10 +195,10 @@ def _run_np_sign(ctx: NanopubProcessingContext) -> str:
ctx=ctx,
)
if exit_code != EXIT_SUCCESS:
LOG.warn(f'Failed to make TrustyURI ({exit_code}):\n{stdout}\n\n{stderr}')
LOG.warn(f'Failed to sign the nanopub ({exit_code}):\n{stdout}\n\n{stderr}')
raise NanopubProcessingError(
status_code=500,
message='Failed to make TrustyURI for nanopub.'
message='Failed to sign the nanopub.'
)
return ctx.signed_file

Expand All @@ -192,8 +214,13 @@ def _extract_np_uri(nanopub: str) -> Optional[str]:
return last_this_prefix


def process(cfg: SubmitterConfig, submission_id: str, data: str) -> NanopubSubmissionResult:
ctx = NanopubProcessingContext(submission_id=submission_id, cfg=cfg)
def process(cfg: SubmitterConfig, req_cfg: RequestConfig,
submission_id: str, data: str) -> NanopubSubmissionResult:
ctx = NanopubProcessingContext(
submission_id=submission_id,
cfg=cfg,
req_cfg=req_cfg,
)
ctx.debug('Preprocessing nanopublication as RDF')
try:
graph = rdflib.ConjunctiveGraph()
Expand Down Expand Up @@ -234,8 +261,8 @@ def process(cfg: SubmitterConfig, submission_id: str, data: str) -> NanopubSubmi
ctx.cleanup()
raise NanopubProcessingError(400, 'Failed to get nanopub URI')

if cfg.nanopub.uri_replace is not None:
old, new = cfg.nanopub.uri_replace.split('|', maxsplit=1)
if ctx.uri_replace is not None:
old, new = ctx.uri_replace.split('|', maxsplit=1)
new_uri = nanopub_uri.replace(old, new)
LOG.debug(f'Replacing {nanopub_uri} with {new_uri}')
nanopub_uri = new_uri
Expand Down
Loading

0 comments on commit ca253af

Please sign in to comment.