Skip to content

Commit 1844331

Browse files
committed
Add api for s3 processing
Add github release actions Add asynchronous file processing Use file name as process identifier Limit textract attempts Rename env variables Re-add script Adjust release workflow Add AWS authorization by access keys Merge api and script code Update README Handle runtime errors while processing files Fix `has_finished` field collect endpoint Add download logging Write PDF incrementally Add `AWS_REGION` environment variable to API Add `SKIP_PROCESSING` variable to api Add logging to api Remove aws session by tokens Check if file exists before processing
1 parent 70316d3 commit 1844331

31 files changed

+1453
-390
lines changed

.dockerignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/.github
2+
/.venv
3+
/tmp
4+
/.env
5+
/.env.*
6+
/docker-compose.yml
7+
/Dockerfile
8+
/README.md
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
name: "Create Docker Image"
2+
description: "Builds a docker image and tags it"
3+
inputs:
4+
IMAGE_NAME:
5+
description: "The image name"
6+
required: true
7+
VERSION:
8+
description: "The version of the image"
9+
required: true
10+
TAG:
11+
description: "The tag of the image, in addition to the version"
12+
required: true
13+
OTHER_TAGS:
14+
description: "Any additional tags, passed directly to docker/metadata-action"
15+
DOCKERFILE:
16+
description: "The path to the Dockerfile"
17+
required: true
18+
GITHUB_TOKEN:
19+
description: "The github token"
20+
required: true
21+
22+
runs:
23+
using: "composite"
24+
steps:
25+
- name: Checkout repository
26+
uses: actions/checkout@v4
27+
28+
- name: Set environment variables
29+
shell: bash
30+
run: |
31+
echo COMMITED_AT=$(git show -s --format=%cI ${{ github.sha }}) >> $GITHUB_ENV
32+
echo REVISION=$(git rev-parse --short HEAD) >> $GITHUB_ENV
33+
34+
- name: Collect docker image metadata
35+
id: meta-data
36+
uses: docker/metadata-action@v5
37+
with:
38+
images: ${{ inputs.IMAGE_NAME }}
39+
labels: |
40+
org.opencontainers.image.created=${{ env.COMMITED_AT }}
41+
org.opencontainers.image.version=v${{ inputs.VERSION }}
42+
org.opencontainers.image.maintainer=EBP Schweiz AG
43+
flavor: |
44+
latest=${{ inputs.TAG == 'latest' }}
45+
tags: |
46+
type=raw,value=${{ inputs.TAG }}
47+
type=raw,value=${{ inputs.VERSION }}
48+
${{ inputs.OTHER_TAGS }}
49+
50+
- name: Log in to the GitHub container registry
51+
uses: docker/login-action@v3
52+
with:
53+
registry: ghcr.io
54+
username: ${{ github.repository_owner }}
55+
password: ${{ inputs.GITHUB_TOKEN }}
56+
57+
- name: Build and push Docker image
58+
uses: docker/build-push-action@v5
59+
with:
60+
context: ./
61+
file: ${{ inputs.DOCKERFILE }}
62+
push: true
63+
tags: ${{ steps.meta-data.outputs.tags }}
64+
labels: ${{ steps.meta-data.outputs.labels }}
65+
no-cache: true
66+
build-args: |
67+
APP_VERSION=${{ inputs.VERSION }}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: "Tag Commit"
2+
description: "Creates or updates a commit tag"
3+
inputs:
4+
TAG_NAME:
5+
description: "The tag's name"
6+
required: true
7+
SHA:
8+
description: "The SHA of the commit to be tagged"
9+
required: true
10+
11+
runs:
12+
using: "composite"
13+
steps:
14+
- name: Create/update tag
15+
uses: actions/github-script@v7
16+
env:
17+
TAG: ${{ inputs.TAG_NAME }}
18+
SHA: ${{ inputs.SHA }}
19+
with:
20+
script: |
21+
github.rest.git.createRef({
22+
owner: context.repo.owner,
23+
repo: context.repo.repo,
24+
ref: `refs/tags/${process.env.TAG}`,
25+
sha: process.env.SHA
26+
}).catch(err => {
27+
if (err.status !== 422) throw err;
28+
github.rest.git.updateRef({
29+
owner: context.repo.owner,
30+
repo: context.repo.repo,
31+
ref: `tags/${process.env.TAG}`,
32+
sha: process.env.SHA
33+
});
34+
})

.github/scripts/find-version.js

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
const findNextVersion = (tags, branch) => {
2+
const version = findMostRecentVersion(tags);
3+
if (version == null) {
4+
return {
5+
major: 1,
6+
minor: 0,
7+
patch: 0,
8+
preRelease: 1,
9+
};
10+
}
11+
if (branch.startsWith("feature/")) {
12+
// It's a minor feature.
13+
14+
// If the previous version was a full release or a patch dev release,
15+
// we are a completely new minor dev release.
16+
// Otherwise, the previous version was itself a minor dev release,
17+
// and we can reuse its number.
18+
if (version.preRelease == null || version.patch !== 0) {
19+
version.minor += 1;
20+
version.patch = 0;
21+
}
22+
} else {
23+
// It's a patch.
24+
25+
// If the previous version was a full release,
26+
// we are a completely new patch dev release.
27+
// Otherwise, we can simply reuse the previous version's number.
28+
if (version.preRelease == null) {
29+
version.patch += 1;
30+
}
31+
}
32+
33+
version.preRelease ??= 0;
34+
version.preRelease += 1;
35+
return version;
36+
};
37+
38+
const findMostRecentVersion = (tags) => {
39+
const versions = findAllVersions(tags);
40+
if (versions.length === 0) {
41+
return null;
42+
}
43+
return versions[0];
44+
};
45+
46+
const findOutdatedVersions = (tags, recentTag) => {
47+
const recentVersion = parseVersion(recentTag);
48+
if (recentVersion == null) {
49+
throw new Error(`recent tag '${recentTag}' is not a version number`);
50+
}
51+
const versions = findAllVersions(tags);
52+
return versions.filter(
53+
(version) =>
54+
// Select all pre-releases that appear before the most recent one.
55+
version.preRelease != null && compareVersions(recentVersion, version) > 0
56+
);
57+
};
58+
59+
const findAllVersions = (tags) => {
60+
return tags
61+
.map(parseVersion)
62+
.filter((it) => it != null)
63+
.sort((a, b) => compareVersions(a, b) * -1);
64+
};
65+
66+
const SEMANTIC_VERSION_PATTERN = /^\d+\.\d+\.\d+(?:-dev\d+)?$/;
67+
const parseVersion = (tag) => {
68+
if (!SEMANTIC_VERSION_PATTERN.test(tag)) {
69+
return null;
70+
}
71+
const [major, minor, patch, preRelease] = tag.split(/[.\-]/);
72+
return {
73+
major: parseInt(major),
74+
minor: parseInt(minor),
75+
patch: parseInt(patch),
76+
preRelease: preRelease && parseInt(preRelease.substring(3)),
77+
};
78+
};
79+
80+
const compareVersions = (a, b) => {
81+
if (a.major !== b.major) {
82+
return a.major - b.major;
83+
}
84+
if (a.minor !== b.minor) {
85+
return a.minor - b.minor;
86+
}
87+
if (a.patch !== b.patch) {
88+
return a.patch - b.patch;
89+
}
90+
if (a.preRelease !== b.preRelease) {
91+
if (a.preRelease == null) {
92+
return 1;
93+
}
94+
if (b.preRelease == null) {
95+
return -1;
96+
}
97+
return a.preRelease - b.preRelease;
98+
}
99+
return 0;
100+
};
101+
102+
const makeVersionTag = ({ major, minor, patch, preRelease }) => {
103+
const tag = `${major}.${minor}.${patch}`;
104+
if (preRelease == null) {
105+
return tag;
106+
}
107+
return `${tag}-dev${preRelease}`;
108+
};
109+
110+
module.exports = {
111+
findNextVersion,
112+
findMostRecentVersion,
113+
findOutdatedVersions,
114+
makeVersionTag,
115+
};

.github/scripts/remove-packages.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
const { Octokit } = require("@octokit/rest");
2+
3+
const removePackageVersions = async (imageUrl, imageVersions) => {
4+
const octokit = new Octokit({
5+
auth: process.env.GITHUB_TOKEN,
6+
});
7+
8+
const [_imageHost, imageOwner, imageName] = imageUrl.split("/");
9+
const imageIds = await loadOutdatedVersionIds(octokit, imageOwner, imageName, imageVersions);
10+
for (const imageId of imageIds) {
11+
await octokit.rest.packages.deletePackageVersionForOrg({
12+
package_type: "container",
13+
package_name: imageName,
14+
org: imageOwner,
15+
package_version_id: imageId,
16+
});
17+
}
18+
};
19+
20+
const loadOutdatedVersionIds = async (octokit, imageOwner, imageName, versions) => {
21+
let page = 0;
22+
versions = new Set(versions);
23+
24+
const ids = new Set();
25+
while (true) {
26+
const response = await octokit.rest.packages.getAllPackageVersionsForPackageOwnedByOrg({
27+
package_type: "container",
28+
package_name: imageName,
29+
org: imageOwner,
30+
page,
31+
});
32+
if (response.data.length === 0) {
33+
break;
34+
}
35+
for (const entry of response.data) {
36+
// Match any of the requested version's ids,
37+
// as well as any ids that do not have a tag anymore, i.e. are fully unused.
38+
const { tags } = entry.metadata.container;
39+
const matchedTags = tags.filter((tag) => versions.delete(tag));
40+
if (tags.length === 0 || matchedTags.length !== 0) {
41+
ids.add(entry.id);
42+
}
43+
}
44+
page += 1;
45+
}
46+
return ids;
47+
};
48+
49+
module.exports = {
50+
removePackageVersions,
51+
};

.github/workflows/publish-edge.yml

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
name: Publish Edge
2+
3+
on:
4+
push:
5+
branches:
6+
- "develop"
7+
- "feature/asset-35-*"
8+
9+
workflow_dispatch:
10+
inputs:
11+
version:
12+
type: string
13+
description: |
14+
Version number (e.g. 1.2.3-dev1).
15+
Leave empty to determine the next version automatically.
16+
required: false
17+
default: ""
18+
is-edge:
19+
type: boolean
20+
description: "Tag the commit and published image with `edge`."
21+
default: true
22+
23+
permissions: write-all
24+
25+
env:
26+
IS_EDGE: ${{ github.event_name == 'push' || github.event.inputs.is-edge == 'true' }}
27+
28+
jobs:
29+
determine_version:
30+
name: "determine version"
31+
runs-on: ubuntu-latest
32+
outputs:
33+
version: ${{ steps.find_version.outputs.result || github.event.inputs.version }}
34+
steps:
35+
- name: Checkout repository
36+
uses: actions/checkout@v4
37+
if: ${{ github.event.inputs.version == '' }}
38+
- name: Get tags of edge commit
39+
id: get_edge_tags
40+
if: ${{ github.event.inputs.version == '' }}
41+
run: |
42+
git fetch --tags
43+
EDGE_COMMIT=$(git rev-list -n 1 edge 2>/dev/null || git rev-parse HEAD)
44+
EDGE_TAGS=$(printf "%s," $(git tag --contains $EDGE_COMMIT))
45+
EDGE_TAGS=${EDGE_TAGS%,}
46+
echo "edge_tags=$EDGE_TAGS" >> "$GITHUB_OUTPUT"
47+
- name: Find next version
48+
id: find_version
49+
if: ${{ github.event.inputs.version == '' }}
50+
uses: actions/github-script@v7
51+
env:
52+
EDGE_TAGS: ${{ steps.get_edge_tags.outputs.edge_tags }}
53+
with:
54+
result-encoding: string
55+
script: |
56+
const { findNextVersion } = require('./.github/scripts/find-version.js');
57+
const tags = process.env.EDGE_TAGS.split(',');
58+
const targetBranch = context.payload.ref.replace('refs/heads/', '');
59+
60+
const pullRequests = await github.rest.pulls.list({
61+
owner: context.repo.owner,
62+
repo: context.repo.repo,
63+
state: 'closed',
64+
base: targetBranch,
65+
sort: 'updated',
66+
direction: 'desc'
67+
});
68+
69+
const mergedPullRequest = pullRequests.data.find(pr => pr.merge_commit_sha === context.payload.after);
70+
const sourceBranch = mergedPullRequest == null
71+
? targetBranch
72+
: mergedPullRequest.head.ref.replace('refs/heads/', '')
73+
74+
const version = findNextVersion(tags, sourceBranch);
75+
return `${version.major}.${version.minor}.${version.patch}-dev${version.preRelease}`;
76+
77+
build_and_push_api:
78+
name: "build and push api"
79+
needs:
80+
- determine_version
81+
runs-on: ubuntu-latest
82+
steps:
83+
- name: Checkout repository
84+
uses: actions/checkout@v4
85+
- name: Create image
86+
uses: ./.github/actions/create-image
87+
with:
88+
IMAGE_NAME: ${{ vars.BASE_IMAGE_NAME }}-api
89+
TAG: ${{ env.IS_EDGE == 'true' && 'edge' || '' }}
90+
VERSION: ${{ needs.determine_version.outputs.version }}
91+
DOCKERFILE: Dockerfile
92+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
93+
94+
tag_commit:
95+
name: "tag commit"
96+
needs:
97+
- determine_version
98+
- build_and_push_api
99+
runs-on: ubuntu-latest
100+
steps:
101+
- name: Checkout repository
102+
uses: actions/checkout@v4
103+
- name: tag edge
104+
if: ${{ env.IS_EDGE == 'true' }}
105+
uses: ./.github/actions/tag-commit
106+
with:
107+
TAG_NAME: edge
108+
SHA: ${{ github.sha }}
109+
- name: tag version
110+
uses: ./.github/actions/tag-commit
111+
with:
112+
TAG_NAME: ${{ needs.determine_version.outputs.version }}
113+
SHA: ${{ github.sha }}

0 commit comments

Comments
 (0)