-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1360 from swisstopo/feature/viewer-1342-ci-cd
Feature-1342: add actions
- Loading branch information
Showing
20 changed files
with
1,205 additions
and
244 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
}); | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.