From 58670aff706480e28f194ca7c2ddee8f1beeef92 Mon Sep 17 00:00:00 2001 From: Samad Yar Khan Date: Mon, 27 May 2024 22:26:02 +0530 Subject: [PATCH 1/8] Add sample version.text file --- version.txt | 3 + web-server/pages/api/internal/version.ts | 129 +++++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 version.txt create mode 100644 web-server/pages/api/internal/version.ts diff --git a/version.txt b/version.txt new file mode 100644 index 000000000..adaee293f --- /dev/null +++ b/version.txt @@ -0,0 +1,3 @@ +tags: middlewareeng/middleware:latest, middlewareeng/middleware:v1.0.0 +sha: d6e3d1a09f5b4f9c3e8d3e5e7a7c9e0b4a2d9c3a +date: 2024-04-13T12:57:39.272597Z \ No newline at end of file diff --git a/web-server/pages/api/internal/version.ts b/web-server/pages/api/internal/version.ts new file mode 100644 index 000000000..df79e7ca5 --- /dev/null +++ b/web-server/pages/api/internal/version.ts @@ -0,0 +1,129 @@ +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 dockerHubBaseUrl = '`https://hub.docker.com/layers/middlewareeng/middleware' + + +const endpoint = new Endpoint(nullSchema); + +endpoint.handle.GET(nullSchema, async (req, res) => { + return res.send(await checkNewImageRelease()); +}); + +interface VersionInfo { + tags: string; + sha: string; + date: string; +} + +interface CheckResult { + 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(): VersionInfo { + 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 { + tags: versionInfo['tags'], + sha: versionInfo['sha'], + date: versionInfo['date'] + }; +} + +async function fetchDockerHubTags(): Promise< + { name: string; last_updated: string; digest: string }[] +> { + const fetchTagsUrl = `${dockerHubBaseUrl}/tags/` + const response = await axios.get(fetchTagsUrl); + + return response.data.results.map((tag) => ({ + name: tag.name, + digest: tag.images[0].digest, + last_updated: tag.last_updated + })); +} + +async function checkNewImageRelease(): Promise { + const versionInfo = readVersionFile(); + const localDate = new Date(versionInfo.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 = `${dockerHubBaseUrl}/${latestTag.name}/images/${latestTag.digest}`; + + return { + latest_github_commit: versionInfo.sha, + latest_docker_image: latestDockerImageLink, + is_update_available: isUpdateAvailable + }; +} + +export default endpoint.serve(); From 60ea1c86461f6db4ab0cea474fe87c3934456818 Mon Sep 17 00:00:00 2001 From: Samad Yar Khan Date: Mon, 27 May 2024 22:27:11 +0530 Subject: [PATCH 2/8] Update build file to add logic for version data updation --- .github/workflows/build.yml | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 053f82c6c..786d23592 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -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) }}" @@ -89,6 +88,33 @@ jobs: digest="${{ steps.build.outputs.digest }}" touch "/tmp/digests/${digest#sha256:}" + - name: Update version.txt + run: | + echo "Updating version.txt" + TAGS="${{ steps.meta.outputs.tags }}" + SHA="${{ github.sha }}" + DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ") + if [ ! -f version.txt ]; then + echo "tags: $TAGS" > version.txt + echo "sha: $SHA" >> version.txt + echo "date: $DATE" >> version.txt + else + sed -i 's/^tags:.*/tags: $TAGS/' version.txt + sed -i 's/^sha:.*/sha: $SHA/' version.txt + if ! grep -q '^date:' version.txt; then + echo "date: $DATE" >> version.txt + else + sed -i 's/^date:.*/date: $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: From ab1616480ea4b5a882c416a11f9c258f343fc20b Mon Sep 17 00:00:00 2001 From: Samad Yar Khan Date: Mon, 27 May 2024 22:28:07 +0530 Subject: [PATCH 3/8] Add version api in nextjs backend --- web-server/pages/api/internal/version.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/web-server/pages/api/internal/version.ts b/web-server/pages/api/internal/version.ts index df79e7ca5..2900d593a 100644 --- a/web-server/pages/api/internal/version.ts +++ b/web-server/pages/api/internal/version.ts @@ -14,8 +14,7 @@ const versionFilePath = path.join( 'version.txt' ); -const dockerHubBaseUrl = '`https://hub.docker.com/layers/middlewareeng/middleware' - +const dockerRepoName = 'middlewareeng/middleware'; const endpoint = new Endpoint(nullSchema); @@ -93,8 +92,8 @@ function readVersionFile(): VersionInfo { async function fetchDockerHubTags(): Promise< { name: string; last_updated: string; digest: string }[] > { - const fetchTagsUrl = `${dockerHubBaseUrl}/tags/` - const response = await axios.get(fetchTagsUrl); + const dockerHubUrl = `https://hub.docker.com/v2/repositories/${dockerRepoName}/tags/`; + const response = await axios.get(dockerHubUrl); return response.data.results.map((tag) => ({ name: tag.name, @@ -116,8 +115,7 @@ async function checkNewImageRelease(): Promise { const latestRemoteDate = new Date(latestTag.last_updated); const isUpdateAvailable = latestRemoteDate > localDate; - - const latestDockerImageLink = `${dockerHubBaseUrl}/${latestTag.name}/images/${latestTag.digest}`; + const latestDockerImageLink = `https://hub.docker.com/layers/${dockerRepoName}/${latestTag.name}/images/${latestTag.digest}`; return { latest_github_commit: versionInfo.sha, From 78209e5e6d94167e1aba90e4b03bfc09a147f4a3 Mon Sep 17 00:00:00 2001 From: Samad Yar Khan Date: Mon, 27 May 2024 23:32:33 +0530 Subject: [PATCH 4/8] Update interface name to CheckNewVersionResponse --- web-server/pages/api/internal/version.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web-server/pages/api/internal/version.ts b/web-server/pages/api/internal/version.ts index 2900d593a..202799e0c 100644 --- a/web-server/pages/api/internal/version.ts +++ b/web-server/pages/api/internal/version.ts @@ -28,7 +28,7 @@ interface VersionInfo { date: string; } -interface CheckResult { +interface CheckNewVersionResponse { latest_github_commit: string; latest_docker_image: string; is_update_available: boolean; @@ -102,7 +102,7 @@ async function fetchDockerHubTags(): Promise< })); } -async function checkNewImageRelease(): Promise { +async function checkNewImageRelease(): Promise { const versionInfo = readVersionFile(); const localDate = new Date(versionInfo.date); const remoteTags = await fetchDockerHubTags(); From 13cae1da0da0ed065a12829099cccf9e286a9772 Mon Sep 17 00:00:00 2001 From: Samad Yar Khan Date: Mon, 27 May 2024 23:35:51 +0530 Subject: [PATCH 5/8] Update interface name VersionInfo to ProjectVersionInfo --- web-server/pages/api/internal/version.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web-server/pages/api/internal/version.ts b/web-server/pages/api/internal/version.ts index 202799e0c..d76ed8eec 100644 --- a/web-server/pages/api/internal/version.ts +++ b/web-server/pages/api/internal/version.ts @@ -22,7 +22,7 @@ endpoint.handle.GET(nullSchema, async (req, res) => { return res.send(await checkNewImageRelease()); }); -interface VersionInfo { +interface ProjectVersionInfo { tags: string; sha: string; date: string; @@ -74,7 +74,7 @@ interface DockerImage { last_pushed: string; } -function readVersionFile(): VersionInfo { +function readVersionFile(): ProjectVersionInfo { const data = fs.readFileSync(versionFilePath, 'utf8'); const lines = data.split('\n').filter(Boolean); const versionInfo: { [key: string]: string } = {}; From 822c0d20b49d800ccf38d6cfc0d1dbafbeefdf2f Mon Sep 17 00:00:00 2001 From: Samad Yar Khan Date: Tue, 28 May 2024 00:18:31 +0530 Subject: [PATCH 6/8] Update sample version.txt file --- version.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/version.txt b/version.txt index adaee293f..daa272d7a 100644 --- a/version.txt +++ b/version.txt @@ -1,3 +1,3 @@ -tags: middlewareeng/middleware:latest, middlewareeng/middleware:v1.0.0 -sha: d6e3d1a09f5b4f9c3e8d3e5e7a7c9e0b4a2d9c3a -date: 2024-04-13T12:57:39.272597Z \ No newline at end of file +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 \ No newline at end of file From 4453db1b8322047ba15abd4089914ee73675be34 Mon Sep 17 00:00:00 2001 From: Samad Yar Khan Date: Tue, 28 May 2024 00:18:57 +0530 Subject: [PATCH 7/8] Update build workflow --- .github/workflows/build.yml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 786d23592..0f5a5ad65 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -91,20 +91,20 @@ jobs: - name: Update version.txt run: | echo "Updating version.txt" - TAGS="${{ steps.meta.outputs.tags }}" - SHA="${{ github.sha }}" - DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ") + 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 "tags: $TAGS" > version.txt - echo "sha: $SHA" >> version.txt - echo "date: $DATE" >> version.txt + 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/^tags:.*/tags: $TAGS/' version.txt - sed -i 's/^sha:.*/sha: $SHA/' version.txt - if ! grep -q '^date:' version.txt; then - echo "date: $DATE" >> version.txt + 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/^date:.*/date: $DATE/' version.txt + sed -i "s/^DOCKER_IMAGE_BUILD_DATE:.*/DOCKER_IMAGE_BUILD_DATE: $DOCKER_IMAGE_BUILD_DATE/" version.txt fi fi cat version.txt From 03d343fb20dda39b81d7b45c34907861027e23cd Mon Sep 17 00:00:00 2001 From: Samad Yar Khan Date: Tue, 28 May 2024 00:19:08 +0530 Subject: [PATCH 8/8] Update versions api --- web-server/pages/api/internal/version.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/web-server/pages/api/internal/version.ts b/web-server/pages/api/internal/version.ts index d76ed8eec..ec2343bb7 100644 --- a/web-server/pages/api/internal/version.ts +++ b/web-server/pages/api/internal/version.ts @@ -23,9 +23,9 @@ endpoint.handle.GET(nullSchema, async (req, res) => { }); interface ProjectVersionInfo { - tags: string; - sha: string; - date: string; + docker_image_tags: string; + merge_commit_sha: string; + docker_image_build_date: string; } interface CheckNewVersionResponse { @@ -83,9 +83,9 @@ function readVersionFile(): ProjectVersionInfo { versionInfo[key] = value; }); return { - tags: versionInfo['tags'], - sha: versionInfo['sha'], - date: versionInfo['date'] + docker_image_tags: versionInfo['DOCKER_IMAGE_TAGS'], + merge_commit_sha: versionInfo['MERGE_COMMIT_SHA'], + docker_image_build_date: versionInfo['DOCKER_IMAGE_BUILD_DATE'] }; } @@ -104,7 +104,7 @@ async function fetchDockerHubTags(): Promise< async function checkNewImageRelease(): Promise { const versionInfo = readVersionFile(); - const localDate = new Date(versionInfo.date); + const localDate = new Date(versionInfo.docker_image_build_date); const remoteTags = await fetchDockerHubTags(); remoteTags.sort( @@ -118,7 +118,7 @@ async function checkNewImageRelease(): Promise { const latestDockerImageLink = `https://hub.docker.com/layers/${dockerRepoName}/${latestTag.name}/images/${latestTag.digest}`; return { - latest_github_commit: versionInfo.sha, + latest_github_commit: versionInfo.merge_commit_sha, latest_docker_image: latestDockerImageLink, is_update_available: isUpdateAvailable };