Skip to content

Commit dd2c313

Browse files
authored
Merge pull request #17 from JSONbored/codex/standardize-package-tags
feat(release): standardize package tags and add release automation
2 parents f1ce628 + f2ae7ae commit dd2c313

7 files changed

Lines changed: 344 additions & 30 deletions

File tree

.github/workflows/build.yml

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -297,22 +297,38 @@ jobs:
297297
username: ${{ github.actor }}
298298
password: ${{ secrets.GITHUB_TOKEN }}
299299

300-
- name: Extract metadata
301-
id: meta
302-
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
303-
with:
304-
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
305-
tags: |
306-
type=raw,value=latest,enable={{is_default_branch}}
307-
type=sha,format=long
300+
- name: Compute image tags
301+
id: prep
302+
run: |
303+
image="$(printf '%s' "${REGISTRY}/${IMAGE_NAME}" | tr '[:upper:]' '[:lower:]')"
304+
sha_tag="${image}:sha-${GITHUB_SHA}"
305+
raw_version="$(sed -n 's/^ARG UPSTREAM_VERSION=//p' Dockerfile | head -n1)"
306+
upstream_version="${raw_version%%@*}"
307+
aio_track="aio-v1"
308+
309+
{
310+
echo "upstream_version=${upstream_version}"
311+
echo "tags<<EOF"
312+
echo "${image}:latest"
313+
if [[ -n "${upstream_version}" ]]; then
314+
echo "${image}:${upstream_version}"
315+
echo "${image}:${upstream_version}-${aio_track}"
316+
fi
317+
echo "${sha_tag}"
318+
echo "EOF"
319+
} >> "${GITHUB_OUTPUT}"
308320
309321
- name: Build and push Docker image
310322
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
311323
with:
312324
context: .
313325
push: true
314-
tags: ${{ steps.meta.outputs.tags }}
315-
labels: ${{ steps.meta.outputs.labels }}
326+
tags: ${{ steps.prep.outputs.tags }}
327+
labels: |
328+
org.opencontainers.image.source=https://github.com/JSONbored/mem0-aio
329+
org.opencontainers.image.title=mem0-aio
330+
org.opencontainers.image.version=${{ steps.prep.outputs.upstream_version || '' }}
331+
io.jsonbored.upstream.name=Mem0
316332
platforms: ${{ env.PUBLISH_PLATFORMS }}
317333
cache-from: type=gha
318334
cache-to: type=gha,mode=max

.github/workflows/release.yml

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
name: Release / mem0-aio
2+
3+
on:
4+
workflow_dispatch:
5+
pull_request_target:
6+
types: [closed]
7+
8+
jobs:
9+
prepare-release:
10+
if: ${{ github.ref == 'refs/heads/main' }}
11+
runs-on: ubuntu-latest
12+
permissions:
13+
contents: write
14+
pull-requests: write
15+
steps:
16+
- name: Checkout
17+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
18+
with:
19+
fetch-depth: 0
20+
- name: Install git-cliff
21+
env:
22+
GIT_CLIFF_VERSION: 2.12.0
23+
run: |
24+
archive="git-cliff-${GIT_CLIFF_VERSION}-x86_64-unknown-linux-gnu.tar.gz"
25+
curl -fsSL -o "/tmp/${archive}" "https://github.com/orhun/git-cliff/releases/download/v${GIT_CLIFF_VERSION}/${archive}"
26+
tar -xzf "/tmp/${archive}" -C /tmp
27+
install "/tmp/git-cliff-${GIT_CLIFF_VERSION}/git-cliff" /usr/local/bin/git-cliff
28+
- name: Compute release version
29+
id: version
30+
run: echo "release_version=$(python3 scripts/release.py next-version)" >> "${GITHUB_OUTPUT}"
31+
- name: Generate changelog
32+
env:
33+
GITHUB_REPO: ${{ github.repository }}
34+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
35+
RELEASE_VERSION: ${{ steps.version.outputs.release_version }}
36+
run: git-cliff --config cliff.toml --tag "${RELEASE_VERSION}" --output CHANGELOG.md
37+
- name: Create release PR
38+
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
39+
with:
40+
commit-message: "chore(release): ${{ steps.version.outputs.release_version }}"
41+
title: "chore(release): ${{ steps.version.outputs.release_version }}"
42+
body: |
43+
This PR prepares `${{ steps.version.outputs.release_version }}`.
44+
branch: "release/${{ steps.version.outputs.release_version }}"
45+
delete-branch: true
46+
47+
publish-release-on-merge:
48+
if: "${{ github.event_name == 'pull_request_target' && github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'main' && startsWith(github.event.pull_request.title, 'chore(release): ') }}"
49+
runs-on: ubuntu-latest
50+
permissions:
51+
contents: write
52+
steps:
53+
- name: Checkout merge commit
54+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
55+
with:
56+
ref: ${{ github.event.pull_request.merge_commit_sha }}
57+
fetch-depth: 0
58+
- name: Determine release version
59+
id: version
60+
env:
61+
PR_TITLE: ${{ github.event.pull_request.title }}
62+
run: |
63+
release_version="${PR_TITLE#chore(release): }"
64+
echo "release_version=${release_version}" >> "${GITHUB_OUTPUT}"
65+
test "$(python3 scripts/release.py latest-changelog-version)" = "${release_version}"
66+
- name: Extract release notes
67+
id: notes
68+
env:
69+
RELEASE_VERSION: ${{ steps.version.outputs.release_version }}
70+
run: |
71+
{
72+
echo "release_notes<<EOF"
73+
python3 scripts/release.py extract-release-notes "${RELEASE_VERSION}"
74+
echo "EOF"
75+
} >> "${GITHUB_OUTPUT}"
76+
- name: Create Git tag if missing
77+
env:
78+
RELEASE_VERSION: ${{ steps.version.outputs.release_version }}
79+
MERGE_SHA: ${{ github.event.pull_request.merge_commit_sha }}
80+
run: |
81+
if git rev-parse "${RELEASE_VERSION}" >/dev/null 2>&1; then exit 0; fi
82+
git config user.name "github-actions[bot]"
83+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
84+
git tag "${RELEASE_VERSION}" "${MERGE_SHA}"
85+
git push origin "${RELEASE_VERSION}"
86+
- name: Publish GitHub release
87+
env:
88+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
89+
RELEASE_VERSION: ${{ steps.version.outputs.release_version }}
90+
RELEASE_NOTES: ${{ steps.notes.outputs.release_notes }}
91+
MERGE_SHA: ${{ github.event.pull_request.merge_commit_sha }}
92+
run: |
93+
if gh release view "${RELEASE_VERSION}" >/dev/null 2>&1; then exit 0; fi
94+
notes_file="$(mktemp)"
95+
printf '%s\n' "${RELEASE_NOTES}" > "${notes_file}"
96+
gh release create "${RELEASE_VERSION}" --title "${RELEASE_VERSION}" --notes-file "${notes_file}" --target "${MERGE_SHA}"

AGENTS.md

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,40 @@
1-
# mem0-aio Agent Notes
1+
# AGENTS.md
22

3-
`mem0-aio` packages OpenMemory / Mem0 as a single Unraid container with an embedded Qdrant vector store.
3+
This repository is part of a broader portfolio of Unraid-first AIO projects.
44

5-
## Runtime Shape
5+
## Repository intent
66

7-
- OpenMemory web UI
8-
- OpenMemory API / MCP service
9-
- Internal Qdrant for vector storage
10-
- Same-origin UI-to-API default flow for simple Unraid installs
7+
- This repo packages an opinionated, beginner-friendly Unraid AIO deployment.
8+
- Default behavior should optimize for a reliable first boot on Unraid.
9+
- Advanced users should retain escape hatches where supported.
1110

12-
## Important Behavior
11+
## Engineering expectations
1312

14-
- The vendored `openmemory` submodule is part of the upstream tracking story here.
15-
- `upstream.toml` uses `submodule_path = "openmemory"`.
16-
- Beginner installs should work with internal Qdrant by default.
17-
- A placeholder `OPENAI_API_KEY` fallback exists only to keep startup stable; real memory generation still needs a valid provider.
13+
- Prefer consistency with `unraid-aio-template` over one-off repo behavior.
14+
- Keep CI and release behavior aligned with the rest of the AIO fleet.
15+
- Respect protected branches and use PR-based automation for external sync flows.
16+
- Favor operational clarity over cleverness.
1817

19-
## CI And Publish Policy
18+
## Release model
2019

21-
- Validation and smoke tests should run on PRs and branch pushes.
22-
- Publish should happen only from the default branch.
23-
- GHCR image naming must stay lowercase.
20+
- Container packages publish automatically from `main`.
21+
- Formal changelog updates and GitHub Releases are release-driven.
22+
- Releases use `upstream version + aio revision`, for example `v1.0.9-aio.1`.
23+
- Keep changelog-friendly Conventional Commit titles and PR titles.
2424

25-
## What To Preserve
25+
## Unraid expectations
2626

27-
- Keep the browser experience single-origin by default.
28-
- Keep Qdrant internal unless a user explicitly overrides storage strategy.
29-
- Smoke tests should validate restart and persistence, not just the first boot.
27+
- Unraid-facing XML/icon assets should stay aligned with `awesome-unraid`.
28+
- User-facing metadata should remain accurate:
29+
- `Project`
30+
- `Support`
31+
- `TemplateURL`
32+
- `Icon`
33+
- `Overview`
34+
- `Category`
35+
36+
## Documentation expectations
37+
38+
- Be explicit about operational tradeoffs.
39+
- Do not imply the AIO model removes inherent complexity from the upstream software.
40+
- Keep beginner defaults simple, but document power-user override paths where they exist.

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ Local validation completed on March 29, 2026:
5454
- restart and persistence smoke coverage added
5555
- workflow hardening added with pinned action SHAs, dependency review, and upstream release tracking
5656

57+
## Releases
58+
59+
`mem0-aio` uses upstream-version-plus-AIO-revision releases such as `v1.0.9-aio.1`.
60+
61+
Every `main` build publishes `latest`, the exact pinned upstream version, an explicit packaging line tag, and `sha-<commit>`.
62+
63+
See [docs/releases.md](/Users/shadowbook/Documents/mem0-aio/docs/releases.md) for the release workflow details.
64+
5765
## Support
5866

5967
- Issues: [JSONbored/mem0-aio issues](https://github.com/JSONbored/mem0-aio/issues)

cliff.toml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
[changelog]
2+
header = """
3+
# Changelog
4+
5+
All notable changes to this project will be documented in this file.
6+
"""
7+
body = """
8+
{% if version %}## {{ version }} - {{ timestamp | date(format="%Y-%m-%d") }}{% else %}## Unreleased{% endif %}
9+
{% for group, commits in commits | group_by(attribute="group") -%}
10+
### {{ group }}
11+
{% for commit in commits -%}
12+
- {{ commit.message | split(pat="\n") | first | trim | upper_first }}
13+
{% endfor %}
14+
{% if not loop.last %}\n{% endif -%}
15+
{% endfor -%}
16+
"""
17+
trim = true
18+
footer = "<!-- generated by git-cliff -->"
19+
20+
[git]
21+
conventional_commits = true
22+
filter_unconventional = false
23+
require_conventional = false
24+
split_commits = false
25+
protect_breaking_commits = true
26+
tag_pattern = '^v?[0-9].*-aio\\.[0-9]+$'
27+
sort_commits = "oldest"
28+
commit_preprocessors = [
29+
{ pattern = " \\(#\\d+\\)$", replace = "" },
30+
]
31+
commit_parsers = [
32+
{ message = "^Merge pull request", skip = true },
33+
{ message = "^chore\\(release\\):", skip = true },
34+
{ message = "^feat", group = "Features" },
35+
{ message = "^fix", group = "Fixes" },
36+
{ message = "^perf", group = "Performance" },
37+
{ message = "^refactor", group = "Refactors" },
38+
{ message = "^docs?", group = "Documentation" },
39+
{ message = "^ci", group = "CI" },
40+
{ message = "^test", group = "Tests" },
41+
{ message = "^build", group = "Build" },
42+
{ message = "^chore\\(deps", group = "Dependency Updates" },
43+
{ message = "^chore", group = "Maintenance" },
44+
{ message = "^revert", group = "Reverts" },
45+
{ message = "^[A-Z].*", group = "Other Changes" },
46+
]

docs/releases.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Releases
2+
3+
`mem0-aio` uses upstream-version-plus-AIO-revision releases such as `v1.0.9-aio.1`.
4+
5+
## Published image tags
6+
7+
Every `main` build publishes:
8+
9+
- `latest`
10+
- the exact pinned upstream version
11+
- an explicit packaging line tag like `v1.0.9-aio-v1`
12+
- `sha-<commit>`
13+
14+
## Release flow
15+
16+
1. Trigger **Release / mem0-aio** from `main`.
17+
2. The workflow computes the next `upstream-aio.N` version and opens a release PR.
18+
3. Merge that PR into `main`.
19+
4. After merge, the workflow creates the Git tag and GitHub Release automatically.

0 commit comments

Comments
 (0)