Skip to content

Commit 887e17d

Browse files
authored
Merge pull request #401 from middlewarehq/GROW-1558
Add mechanism to save app version and check for new released
2 parents 36c0fb2 + 03d343f commit 887e17d

File tree

3 files changed

+157
-1
lines changed

3 files changed

+157
-1
lines changed

.github/workflows/build.yml

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ jobs:
7979
labels: ${{ steps.meta.outputs.labels }}
8080
outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=false,name-canonical=true,push=true
8181

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

@@ -89,6 +88,33 @@ jobs:
8988
digest="${{ steps.build.outputs.digest }}"
9089
touch "/tmp/digests/${digest#sha256:}"
9190
91+
- name: Update version.txt
92+
run: |
93+
echo "Updating version.txt"
94+
DOCKER_IMAGE_TAGS="${{ steps.meta.outputs.tags }}"
95+
MERGE_COMMIT_SHA="${{ github.sha }}"
96+
DOCKER_IMAGE_BUILD_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
97+
if [ ! -f version.txt ]; then
98+
echo "DOCKER_IMAGE_TAGS: $DOCKER_IMAGE_TAGS" > version.txt
99+
echo "MERGE_COMMIT_SHA: $MERGE_COMMIT_SHA" >> version.txt
100+
echo "DOCKER_IMAGE_BUILD_DATE: $DOCKER_IMAGE_BUILD_DATE" >> version.txt
101+
else
102+
sed -i "s/^DOCKER_IMAGE_TAGS:.*/DOCKER_IMAGE_TAGS: $DOCKER_IMAGE_TAGS/" version.txt
103+
sed -i "s/^MERGE_COMMIT_SHA:.*/MERGE_COMMIT_SHA: $MERGE_COMMIT_SHA/" version.txt
104+
if ! grep -q '^DOCKER_IMAGE_BUILD_DATE:' version.txt; then
105+
echo "DOCKER_IMAGE_BUILD_DATE: $DOCKER_IMAGE_BUILD_DATE" >> version.txt
106+
else
107+
sed -i "s/^DOCKER_IMAGE_BUILD_DATE:.*/DOCKER_IMAGE_BUILD_DATE: $DOCKER_IMAGE_BUILD_DATE/" version.txt
108+
fi
109+
fi
110+
cat version.txt
111+
112+
- name: Commit version.txt
113+
uses: stefanzweifel/git-auto-commit-action@v4
114+
with:
115+
commit_message: "Update version.txt for new Docker image"
116+
file_pattern: version.txt
117+
92118
- name: Upload digest
93119
uses: actions/upload-artifact@v4
94120
with:

version.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
DOCKER_IMAGE_TAGS: middlewareeng/middleware:latest, middlewareeng/middleware:v1.0.0
2+
MERGE_COMMIT_SHA: d6e3d1a09f5b4f9c3e8d3e5e7a7c9e0b4a2d9c3a
3+
DOCKER_IMAGE_BUILD_DATE: 2024-04-13T12:57:39.272597Z
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import { Endpoint, nullSchema } from '@/api-helpers/global';
2+
import * as fs from 'fs';
3+
import * as path from 'path';
4+
import axios from 'axios';
5+
6+
const versionFilePath = path.join(
7+
__dirname,
8+
'..',
9+
'..',
10+
'..',
11+
'..',
12+
'..',
13+
'..',
14+
'version.txt'
15+
);
16+
17+
const dockerRepoName = 'middlewareeng/middleware';
18+
19+
const endpoint = new Endpoint(nullSchema);
20+
21+
endpoint.handle.GET(nullSchema, async (req, res) => {
22+
return res.send(await checkNewImageRelease());
23+
});
24+
25+
interface ProjectVersionInfo {
26+
docker_image_tags: string;
27+
merge_commit_sha: string;
28+
docker_image_build_date: string;
29+
}
30+
31+
interface CheckNewVersionResponse {
32+
latest_github_commit: string;
33+
latest_docker_image: string;
34+
is_update_available: boolean;
35+
}
36+
37+
interface DockerHubAPIResponse {
38+
count: number;
39+
next: string | null;
40+
previous: string | null;
41+
results: TagResult[];
42+
}
43+
44+
interface TagResult {
45+
creator: number;
46+
id: number;
47+
images: DockerImage[];
48+
last_updated: string;
49+
last_updater: number;
50+
last_updater_username: string;
51+
name: string;
52+
repository: number;
53+
full_size: number;
54+
v2: boolean;
55+
tag_status: string;
56+
tag_last_pulled: string;
57+
tag_last_pushed: string;
58+
media_type: string;
59+
content_type: string;
60+
digest: string;
61+
}
62+
63+
interface DockerImage {
64+
architecture: string;
65+
features: string;
66+
variant: string | null;
67+
digest: string;
68+
os: string;
69+
os_features: string;
70+
os_version: string | null;
71+
size: number;
72+
status: string;
73+
last_pulled: string | null;
74+
last_pushed: string;
75+
}
76+
77+
function readVersionFile(): ProjectVersionInfo {
78+
const data = fs.readFileSync(versionFilePath, 'utf8');
79+
const lines = data.split('\n').filter(Boolean);
80+
const versionInfo: { [key: string]: string } = {};
81+
lines.forEach((line) => {
82+
const [key, value] = line.split(': ');
83+
versionInfo[key] = value;
84+
});
85+
return {
86+
docker_image_tags: versionInfo['DOCKER_IMAGE_TAGS'],
87+
merge_commit_sha: versionInfo['MERGE_COMMIT_SHA'],
88+
docker_image_build_date: versionInfo['DOCKER_IMAGE_BUILD_DATE']
89+
};
90+
}
91+
92+
async function fetchDockerHubTags(): Promise<
93+
{ name: string; last_updated: string; digest: string }[]
94+
> {
95+
const dockerHubUrl = `https://hub.docker.com/v2/repositories/${dockerRepoName}/tags/`;
96+
const response = await axios.get<DockerHubAPIResponse>(dockerHubUrl);
97+
98+
return response.data.results.map((tag) => ({
99+
name: tag.name,
100+
digest: tag.images[0].digest,
101+
last_updated: tag.last_updated
102+
}));
103+
}
104+
105+
async function checkNewImageRelease(): Promise<CheckNewVersionResponse> {
106+
const versionInfo = readVersionFile();
107+
const localDate = new Date(versionInfo.docker_image_build_date);
108+
const remoteTags = await fetchDockerHubTags();
109+
110+
remoteTags.sort(
111+
(a, b) =>
112+
new Date(b.last_updated).getTime() - new Date(a.last_updated).getTime()
113+
);
114+
const latestTag = remoteTags[0];
115+
const latestRemoteDate = new Date(latestTag.last_updated);
116+
const isUpdateAvailable = latestRemoteDate > localDate;
117+
118+
const latestDockerImageLink = `https://hub.docker.com/layers/${dockerRepoName}/${latestTag.name}/images/${latestTag.digest}`;
119+
120+
return {
121+
latest_github_commit: versionInfo.merge_commit_sha,
122+
latest_docker_image: latestDockerImageLink,
123+
is_update_available: isUpdateAvailable
124+
};
125+
}
126+
127+
export default endpoint.serve();

0 commit comments

Comments
 (0)