Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature-1342: add actions #1360

Merged
merged 3 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
25 changes: 25 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Application
APP_PORT=3000

# Cognito
COGNITO_AWS_REGION=eu-west-1
COGNITO_CLIENT_ID=10h1tga4i933buv25lelalmtrn
COGNITO_POOL_ID=eu-west-1_dbfEb2FuH

# S3
S3_AWS_REGION=eu-west-1
AWS_ACCESS_KEY_ID=minio
AWS_SECRET_ACCESS_KEY=minio123
S3_BUCKET=ngmpub-userdata-local
PROJECTS_S3_BUCKET=ngmpub-project-files-local
S3_ENDPOINT=http://minio:9000

# Database
PGUSER=www-data
PGPASSWORD=www-data
PGHOST=db
PGPORT=5432
PGDATABASE=swissgeol-local

# sqlx
DATABASE_URL=postgres://${PGUSER}:${PGPASSWORD}@${PGHOST}:${PGPORT}/${PGDATABASE}
71 changes: 71 additions & 0 deletions .github/actions/create-image/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: "Create Docker Image"
description: "Builds a docker image and tags it"
inputs:
IMAGE_NAME:
description: "The image name"
required: true
VERSION:
description: "The version of the image"
required: true
TAG:
description: "The tag of the image, in addition to the version"
required: true
OTHER_TAGS:
description: "Any additional tags, passed directly to docker/metadata-action"
DOCKERFILE:
description: "The path to the Dockerfile"
required: true
GITHUB_TOKEN:
description: "The github token"
required: true
CONTEXT:
description: "The build context"
default: "./"
required: false

runs:
using: "composite"
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set environment variables
shell: bash
run: |
echo COMMITED_AT=$(git show -s --format=%cI ${{ github.sha }}) >> $GITHUB_ENV
echo REVISION=$(git rev-parse --short HEAD) >> $GITHUB_ENV

- name: Collect docker image metadata
id: meta-data
uses: docker/metadata-action@v5
with:
images: ${{ inputs.IMAGE_NAME }}
labels: |
org.opencontainers.image.created=${{ env.COMMITED_AT }}
org.opencontainers.image.version=v${{ inputs.VERSION }}
org.opencontainers.image.maintainer=EBP Schweiz AG
flavor: |
latest=${{ inputs.TAG == 'latest' }}
tags: |
type=raw,value=${{ inputs.TAG }}
type=raw,value=${{ inputs.VERSION }}
${{ inputs.OTHER_TAGS }}

- name: Log in to the GitHub container registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ inputs.GITHUB_TOKEN }}

- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: ${{ inputs.CONTEXT }}
file: ${{ inputs.DOCKERFILE }}
push: true
tags: ${{ steps.meta-data.outputs.tags }}
labels: ${{ steps.meta-data.outputs.labels }}
no-cache: true
build-args: |
APP_VERSION=${{ inputs.VERSION }}
34 changes: 34 additions & 0 deletions .github/actions/tag-commit/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: "Tag Commit"
description: "Creates or updates a commit tag"
inputs:
TAG_NAME:
description: "The tag's name"
required: true
SHA:
description: "The SHA of the commit to be tagged"
required: true

runs:
using: "composite"
steps:
- name: Create/update tag
uses: actions/github-script@v7
env:
TAG: ${{ inputs.TAG_NAME }}
SHA: ${{ inputs.SHA }}
with:
script: |
github.rest.git.createRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: `refs/tags/${process.env.TAG}`,
sha: process.env.SHA
}).catch(err => {
if (err.status !== 422) throw err;
github.rest.git.updateRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: `tags/${process.env.TAG}`,
sha: process.env.SHA
});
})
107 changes: 107 additions & 0 deletions .github/scripts/find-version.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
const findNextVersion = (tags, branch) => {
const version = findMostRecentVersion(tags);
if (branch.startsWith("feature/")) {
// It's a minor feature.

// If the previous version was a full release or a patch dev release,
// we are a completely new minor dev release.
// Otherwise, the previous version was itself a minor dev release,
// and we can reuse its number.
if (version.preRelease == null || version.patch !== 0) {
version.minor += 1;
version.patch = 0;
}
} else {
// It's a patch.

// If the previous version was a full release,
// we are a completely new patch dev release.
// Otherwise, we can simply reuse the previous version's number.
if (version.preRelease == null) {
version.patch += 1;
}
}

version.preRelease ??= 0;
version.preRelease += 1;
return version;
};

const findMostRecentVersion = (tags) => {
const versions = findAllVersions(tags);
if (versions.length === 0) {
throw new Error("unable to find a valid version on current edge tag");
}
return versions[0];
};

const findOutdatedVersions = (tags, recentTag) => {
const recentVersion = parseVersion(recentTag);
if (recentVersion == null) {
throw new Error(`recent tag '${recentTag}' is not a version number`);
}
const versions = findAllVersions(tags);
return versions.filter(
(version) =>
// Select all pre-releases that appear before the most recent one.
version.preRelease != null && compareVersions(recentVersion, version) > 0
);
};

const findAllVersions = (tags) => {
return tags
.map(parseVersion)
.filter((it) => it != null)
.sort((a, b) => compareVersions(a, b) * -1);
};

const SEMANTIC_VERSION_PATTERN = /^\d+\.\d+\.\d+(?:-dev\d+)?$/;
const parseVersion = (tag) => {
if (!SEMANTIC_VERSION_PATTERN.test(tag)) {
return null;
}
const [major, minor, patch, preRelease] = tag.split(/[.\-]/);
return {
major: parseInt(major),
minor: parseInt(minor),
patch: parseInt(patch),
preRelease: preRelease && parseInt(preRelease.substring(3)),
};
};

const compareVersions = (a, b) => {
if (a.major !== b.major) {
return a.major - b.major;
}
if (a.minor !== b.minor) {
return a.minor - b.minor;
}
if (a.patch !== b.patch) {
return a.patch - b.patch;
}
if (a.preRelease !== b.preRelease) {
if (a.preRelease == null) {
return 1;
}
if (b.preRelease == null) {
return -1;
}
return a.preRelease - b.preRelease;
}
return 0;
};

const makeVersionTag = ({ major, minor, patch, preRelease }) => {
const tag = `${major}.${minor}.${patch}`;
if (preRelease == null) {
return tag;
}
return `${tag}-dev${preRelease}`;
};

module.exports = {
findNextVersion,
findMostRecentVersion,
findOutdatedVersions,
makeVersionTag,
};
51 changes: 51 additions & 0 deletions .github/scripts/remove-packages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const removePackageVersions = async (imageUrl, imageVersions) => {
const { Octokit } = await import("@octokit/rest");

const octokit = new Octokit({
auth: process.env.GITHUB_TOKEN,
});

const [_imageHost, imageOwner, imageName] = imageUrl.split("/");
const imageIds = await loadOutdatedVersionIds(octokit, imageOwner, imageName, imageVersions);
for (const imageId of imageIds) {
await octokit.rest.packages.deletePackageVersionForOrg({
package_type: "container",
package_name: imageName,
org: imageOwner,
package_version_id: imageId,
});
}
};

const loadOutdatedVersionIds = async (octokit, imageOwner, imageName, versions) => {
let page = 0;
versions = new Set(versions);

const ids = new Set();
while (true) {
const response = await octokit.rest.packages.getAllPackageVersionsForPackageOwnedByOrg({
package_type: "container",
package_name: imageName,
org: imageOwner,
page,
});
if (response.data.length === 0) {
break;
}
for (const entry of response.data) {
// Match any of the requested version's ids,
// as well as any ids that do not have a tag anymore, i.e. are fully unused.
const { tags } = entry.metadata.container;
const matchedTags = tags.filter((tag) => versions.delete(tag));
if (tags.length === 0 || matchedTags.length !== 0) {
ids.add(entry.id);
}
}
page += 1;
}
return ids;
};

module.exports = {
removePackageVersions,
};
22 changes: 22 additions & 0 deletions .github/scripts/wait_for_service.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/bash

MAX_RETRY_COUNT=10
SERVICE_NAME="$1"

if [ ! -n "$SERVICE_NAME" ]; then
echo "Usage: wait_for_container.sh <service_name>"
exit 1
fi

for i in $(seq 1 $MAX_RETRY_COUNT); do
if [ "$(docker inspect -f '{{.State.Health.Status}}' "swissgeol-viewer-app-$SERVICE_NAME-1")" == "healthy" ]; then
echo "Service $SERVICE_NAME is healthy!"
exit 0
else
echo "Waiting for $SERVICE_NAME to be healthy... (attempt $i of $MAX_RETRY_COUNT)"
sleep 10
fi
done

echo "Service $SERVICE_NAME did not become healthy in time."
exit 1
Loading
Loading