Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
28 changes: 27 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ jobs:
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=false,name-canonical=true,push=true


- name: Print build output
run: echo "${{ toJson(steps.build.outputs) }}"

Expand All @@ -89,6 +88,33 @@ jobs:
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"

- name: Update version.txt
run: |
echo "Updating version.txt"
DOCKER_IMAGE_TAGS="${{ steps.meta.outputs.tags }}"
MERGE_COMMIT_SHA="${{ github.sha }}"
DOCKER_IMAGE_BUILD_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
if [ ! -f version.txt ]; then
echo "DOCKER_IMAGE_TAGS: $DOCKER_IMAGE_TAGS" > version.txt
echo "MERGE_COMMIT_SHA: $MERGE_COMMIT_SHA" >> version.txt
echo "DOCKER_IMAGE_BUILD_DATE: $DOCKER_IMAGE_BUILD_DATE" >> version.txt
else
sed -i "s/^DOCKER_IMAGE_TAGS:.*/DOCKER_IMAGE_TAGS: $DOCKER_IMAGE_TAGS/" version.txt
sed -i "s/^MERGE_COMMIT_SHA:.*/MERGE_COMMIT_SHA: $MERGE_COMMIT_SHA/" version.txt
if ! grep -q '^DOCKER_IMAGE_BUILD_DATE:' version.txt; then
echo "DOCKER_IMAGE_BUILD_DATE: $DOCKER_IMAGE_BUILD_DATE" >> version.txt
else
sed -i "s/^DOCKER_IMAGE_BUILD_DATE:.*/DOCKER_IMAGE_BUILD_DATE: $DOCKER_IMAGE_BUILD_DATE/" version.txt
fi
fi
cat version.txt

- name: Commit version.txt
uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: "Update version.txt for new Docker image"
file_pattern: version.txt

- name: Upload digest
uses: actions/upload-artifact@v4
with:
Expand Down
3 changes: 3 additions & 0 deletions version.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
DOCKER_IMAGE_TAGS: middlewareeng/middleware:latest, middlewareeng/middleware:v1.0.0
MERGE_COMMIT_SHA: d6e3d1a09f5b4f9c3e8d3e5e7a7c9e0b4a2d9c3a
DOCKER_IMAGE_BUILD_DATE: 2024-04-13T12:57:39.272597Z
127 changes: 127 additions & 0 deletions web-server/pages/api/internal/version.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { Endpoint, nullSchema } from '@/api-helpers/global';
import * as fs from 'fs';
import * as path from 'path';
import axios from 'axios';

const versionFilePath = path.join(
__dirname,
'..',
'..',
'..',
'..',
'..',
'..',
'version.txt'
);

const dockerRepoName = 'middlewareeng/middleware';

const endpoint = new Endpoint(nullSchema);

endpoint.handle.GET(nullSchema, async (req, res) => {
return res.send(await checkNewImageRelease());
});

interface ProjectVersionInfo {
docker_image_tags: string;
merge_commit_sha: string;
docker_image_build_date: string;
}

interface CheckNewVersionResponse {
latest_github_commit: string;
latest_docker_image: string;
is_update_available: boolean;
}

interface DockerHubAPIResponse {
count: number;
next: string | null;
previous: string | null;
results: TagResult[];
}

interface TagResult {
creator: number;
id: number;
images: DockerImage[];
last_updated: string;
last_updater: number;
last_updater_username: string;
name: string;
repository: number;
full_size: number;
v2: boolean;
tag_status: string;
tag_last_pulled: string;
tag_last_pushed: string;
media_type: string;
content_type: string;
digest: string;
}

interface DockerImage {
architecture: string;
features: string;
variant: string | null;
digest: string;
os: string;
os_features: string;
os_version: string | null;
size: number;
status: string;
last_pulled: string | null;
last_pushed: string;
}

function readVersionFile(): ProjectVersionInfo {
const data = fs.readFileSync(versionFilePath, 'utf8');
const lines = data.split('\n').filter(Boolean);
const versionInfo: { [key: string]: string } = {};
lines.forEach((line) => {
const [key, value] = line.split(': ');
versionInfo[key] = value;
});
return {
docker_image_tags: versionInfo['DOCKER_IMAGE_TAGS'],
merge_commit_sha: versionInfo['MERGE_COMMIT_SHA'],
docker_image_build_date: versionInfo['DOCKER_IMAGE_BUILD_DATE']
};
}

async function fetchDockerHubTags(): Promise<
{ name: string; last_updated: string; digest: string }[]
> {
const dockerHubUrl = `https://hub.docker.com/v2/repositories/${dockerRepoName}/tags/`;
const response = await axios.get<DockerHubAPIResponse>(dockerHubUrl);

return response.data.results.map((tag) => ({
name: tag.name,
digest: tag.images[0].digest,
last_updated: tag.last_updated
}));
}

async function checkNewImageRelease(): Promise<CheckNewVersionResponse> {
const versionInfo = readVersionFile();
const localDate = new Date(versionInfo.docker_image_build_date);
const remoteTags = await fetchDockerHubTags();

remoteTags.sort(
(a, b) =>
new Date(b.last_updated).getTime() - new Date(a.last_updated).getTime()
);
const latestTag = remoteTags[0];
const latestRemoteDate = new Date(latestTag.last_updated);
const isUpdateAvailable = latestRemoteDate > localDate;

const latestDockerImageLink = `https://hub.docker.com/layers/${dockerRepoName}/${latestTag.name}/images/${latestTag.digest}`;

return {
latest_github_commit: versionInfo.merge_commit_sha,
latest_docker_image: latestDockerImageLink,
is_update_available: isUpdateAvailable
};
}

export default endpoint.serve();