Skip to content

Commit 8fdb287

Browse files
committed
feat: implement CI/CD workflow for container image builds and releases
- Add GitHub Actions workflow for building and publishing container images - Configure Semantic Release for automated versioning - Implement conventional commit validation - Add Docker layer caching for improved build performance - Add documentation for CI/CD process Fixes #18
1 parent a66aa65 commit 8fdb287

File tree

6 files changed

+331
-0
lines changed

6 files changed

+331
-0
lines changed

‎.github/workflows/commit-lint.yml‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: Lint Commit Messages
2+
3+
on:
4+
pull_request:
5+
branches: [ main ]
6+
7+
jobs:
8+
commitlint:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- name: Checkout
12+
uses: actions/checkout@v4
13+
with:
14+
fetch-depth: 0
15+
16+
- name: Setup Node.js
17+
uses: actions/setup-node@v4
18+
with:
19+
node-version: '20'
20+
cache: 'npm'
21+
22+
- name: Install dependencies
23+
run: |
24+
npm install -g @commitlint/cli @commitlint/config-conventional
25+
26+
- name: Create commitlint config
27+
run: |
28+
echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js
29+
30+
- name: Validate commit messages
31+
run: npx commitlint --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }} --verbose
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
name: Build and Publish Container
2+
3+
on:
4+
pull_request:
5+
branches: [ main ]
6+
types: [opened, synchronize, reopened]
7+
push:
8+
branches: [ main ]
9+
paths-ignore:
10+
- '**.md'
11+
- 'docs/**'
12+
- '.github/*.md'
13+
14+
jobs:
15+
semantic-release:
16+
runs-on: ubuntu-latest
17+
outputs:
18+
new_release_published: ${{ steps.semantic.outputs.new_release_published }}
19+
new_release_version: ${{ steps.semantic.outputs.new_release_version }}
20+
steps:
21+
- name: Checkout
22+
uses: actions/checkout@v4
23+
with:
24+
fetch-depth: 0
25+
persist-credentials: false
26+
27+
- name: Setup Node.js
28+
uses: actions/setup-node@v4
29+
with:
30+
node-version: '20'
31+
cache: 'npm'
32+
33+
- name: Install dependencies
34+
run: npm install -g semantic-release @semantic-release/git @semantic-release/changelog @semantic-release/github
35+
36+
- name: Semantic Release
37+
id: semantic
38+
env:
39+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
40+
run: |
41+
OUTPUT=$(npx semantic-release --dry-run)
42+
if echo "$OUTPUT" | grep -q "The next release version is"; then
43+
VERSION=$(echo "$OUTPUT" | grep "The next release version is" | sed 's/.*The next release version is \([0-9]\+\.[0-9]\+\.[0-9]\+\).*/\1/')
44+
echo "new_release_published=true" >> $GITHUB_OUTPUT
45+
echo "new_release_version=$VERSION" >> $GITHUB_OUTPUT
46+
# Run the actual release
47+
npx semantic-release
48+
else
49+
echo "new_release_published=false" >> $GITHUB_OUTPUT
50+
echo "No new version to be released"
51+
fi
52+
53+
build-and-push:
54+
needs: semantic-release
55+
if: needs.semantic-release.outputs.new_release_published == 'true'
56+
runs-on: ubuntu-latest
57+
permissions:
58+
contents: read
59+
packages: write
60+
61+
steps:
62+
- name: Checkout
63+
uses: actions/checkout@v4
64+
65+
- name: Set up Docker Buildx
66+
uses: docker/setup-buildx-action@v3
67+
68+
- name: Cache Docker layers
69+
uses: actions/cache@v3
70+
with:
71+
path: /tmp/.buildx-cache
72+
key: ${{ runner.os }}-buildx-${{ github.sha }}
73+
restore-keys: |
74+
${{ runner.os }}-buildx-
75+
76+
- name: Login to GitHub Container Registry
77+
uses: docker/login-action@v3
78+
with:
79+
registry: ghcr.io
80+
username: ${{ github.actor }}
81+
password: ${{ secrets.GITHUB_TOKEN }}
82+
83+
- name: Extract metadata for Docker
84+
id: meta
85+
uses: docker/metadata-action@v5
86+
with:
87+
images: ghcr.io/${{ github.repository }}
88+
tags: |
89+
type=semver,pattern={{version}},value=${{ needs.semantic-release.outputs.new_release_version }}
90+
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }}
91+
92+
- name: Build and push Docker image
93+
uses: docker/build-push-action@v5
94+
with:
95+
context: .
96+
push: true
97+
tags: ${{ steps.meta.outputs.tags }}
98+
labels: ${{ steps.meta.outputs.labels }}
99+
cache-from: type=local,src=/tmp/.buildx-cache
100+
cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max
101+
102+
- name: Move cache
103+
run: |
104+
rm -rf /tmp/.buildx-cache
105+
mv /tmp/.buildx-cache-new /tmp/.buildx-cache

‎.releaserc.json‎

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
{
2+
"branches": [
3+
"main"
4+
],
5+
"plugins": [
6+
[
7+
"@semantic-release/commit-analyzer",
8+
{
9+
"preset": "conventionalcommits",
10+
"releaseRules": [
11+
{"type": "feat", "release": "minor"},
12+
{"type": "fix", "release": "patch"},
13+
{"type": "docs", "release": "patch"},
14+
{"type": "style", "release": "patch"},
15+
{"type": "refactor", "release": "patch"},
16+
{"type": "perf", "release": "patch"},
17+
{"type": "test", "scope": "*", "release": "patch"},
18+
{"type": "build", "scope": "*", "release": "patch"},
19+
{"type": "ci", "scope": "*", "release": "patch"}
20+
]
21+
}
22+
],
23+
[
24+
"@semantic-release/release-notes-generator",
25+
{
26+
"preset": "conventionalcommits",
27+
"presetConfig": {
28+
"types": [
29+
{"type": "feat", "section": "Features"},
30+
{"type": "fix", "section": "Bug Fixes"},
31+
{"type": "docs", "section": "Documentation"},
32+
{"type": "style", "section": "Styling"},
33+
{"type": "refactor", "section": "Code Refactoring"},
34+
{"type": "perf", "section": "Performance Improvements"},
35+
{"type": "test", "section": "Tests"},
36+
{"type": "build", "section": "Build System"},
37+
{"type": "ci", "section": "Continuous Integration"}
38+
]
39+
}
40+
}
41+
],
42+
[
43+
"@semantic-release/changelog",
44+
{
45+
"changelogFile": "CHANGELOG.md"
46+
}
47+
],
48+
[
49+
"@semantic-release/github",
50+
{
51+
"assets": [
52+
{"path": "CHANGELOG.md", "label": "Changelog"}
53+
]
54+
}
55+
],
56+
[
57+
"@semantic-release/git",
58+
{
59+
"assets": ["CHANGELOG.md", "package.json"],
60+
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
61+
}
62+
]
63+
]
64+
}

‎README.md‎

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Valkey MCP Task Management Server
22

3+
[![Build and Publish Container](https://github.com/jbrinkman/valkey-ai-tasks/actions/workflows/container-build.yml/badge.svg)](https://github.com/jbrinkman/valkey-ai-tasks/actions/workflows/container-build.yml)
4+
[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg)](https://conventionalcommits.org)
5+
36
A task management system that implements the Model Context Protocol (MCP) for seamless integration with agentic AI tools. This system allows AI agents to create, manage, and track tasks within plans using Valkey as the persistence layer.
47

58
## Features
@@ -186,6 +189,77 @@ The MCP server can be configured using the following environment variables:
186189
- `SERVER_READ_TIMEOUT`: Maximum duration for reading the entire request in seconds (default: 60)
187190
- `SERVER_WRITE_TIMEOUT`: Maximum duration for writing the response in seconds (default: 60)
188191

192+
## CI/CD Workflow
193+
194+
This project uses GitHub Actions for continuous integration and delivery, automatically building and publishing container images to GitHub Container Registry (ghcr.io).
195+
196+
### Conventional Commits
197+
198+
All commits to this repository must follow the [Conventional Commits](https://www.conventionalcommits.org/) specification. This enables automated versioning, changelog generation, and release management.
199+
200+
The commit message format is:
201+
202+
```
203+
<type>[optional scope]: <description>
204+
205+
[optional body]
206+
207+
[optional footer(s)]
208+
```
209+
210+
Where `type` is one of:
211+
- `feat`: A new feature
212+
- `fix`: A bug fix
213+
- `docs`: Documentation changes
214+
- `style`: Changes that don't affect code meaning (formatting, etc.)
215+
- `refactor`: Code changes that neither fix bugs nor add features
216+
- `perf`: Performance improvements
217+
- `test`: Adding or correcting tests
218+
- `build`: Changes to build system or dependencies
219+
- `ci`: Changes to CI configuration
220+
- `chore`: Other changes that don't modify source or test files
221+
222+
Breaking changes must be indicated by `!` after the type/scope or by including `BREAKING CHANGE:` in the footer.
223+
224+
### Automated Versioning
225+
226+
The project uses [Semantic Release](https://github.com/semantic-release/semantic-release) to automatically determine the next version number based on conventional commits:
227+
228+
- `fix:` commits increment the patch version (1.0.0 → 1.0.1)
229+
- `feat:` commits increment the minor version (1.0.0 → 1.1.0)
230+
- Breaking changes increment the major version (1.0.0 → 2.0.0)
231+
232+
### Container Image Workflow
233+
234+
The GitHub Actions workflow automatically:
235+
236+
1. Validates that commits follow the conventional format
237+
2. Determines the next semantic version based on commit messages
238+
3. Builds the Docker image using the project's Dockerfile
239+
4. Tags the image with the semantic version and 'latest' tag
240+
5. Pushes the image to GitHub Container Registry (ghcr.io)
241+
6. Creates a Git tag for the version
242+
7. Generates a changelog
243+
8. Creates a GitHub Release with release notes
244+
245+
#### Required GitHub Secrets
246+
247+
To enable the CI/CD workflow to function properly, the following GitHub secrets need to be configured in your repository:
248+
249+
- `GITHUB_TOKEN`: This is automatically provided by GitHub Actions and is used for authentication with GitHub Container Registry. Make sure it has the necessary permissions for `packages:read` and `packages:write`.
250+
251+
No additional secrets are required as the workflow uses the built-in `GITHUB_TOKEN` for all authentication needs.
252+
253+
### Using the Container Images
254+
255+
The container images are published to GitHub Container Registry and can be pulled using:
256+
257+
```bash
258+
docker pull ghcr.io/jbrinkman/valkey-ai-tasks:latest
259+
# or a specific version
260+
docker pull ghcr.io/jbrinkman/valkey-ai-tasks:1.2.3
261+
```
262+
189263
## MCP API Reference
190264

191265
The MCP server supports two transport protocols: Server-Sent Events (SSE) and Streamable HTTP. Each protocol exposes similar endpoints but with different interaction patterns.

‎commitlint.config.js‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
module.exports = {
2+
extends: ['@commitlint/config-conventional'],
3+
rules: {
4+
'body-leading-blank': [1, 'always'],
5+
'body-max-line-length': [2, 'always', 100],
6+
'footer-leading-blank': [1, 'always'],
7+
'footer-max-line-length': [2, 'always', 100],
8+
'header-max-length': [2, 'always', 100],
9+
'subject-case': [
10+
2,
11+
'never',
12+
['sentence-case', 'start-case', 'pascal-case', 'upper-case'],
13+
],
14+
'subject-empty': [2, 'never'],
15+
'subject-full-stop': [2, 'never', '.'],
16+
'type-case': [2, 'always', 'lower-case'],
17+
'type-empty': [2, 'never'],
18+
'type-enum': [
19+
2,
20+
'always',
21+
[
22+
'build',
23+
'chore',
24+
'ci',
25+
'docs',
26+
'feat',
27+
'fix',
28+
'perf',
29+
'refactor',
30+
'revert',
31+
'style',
32+
'test'
33+
],
34+
],
35+
},
36+
};

‎package.json‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "valkey-ai-tasks",
3+
"version": "0.0.0-development",
4+
"private": true,
5+
"description": "Task management system that implements the Model Context Protocol (MCP) for seamless integration with agentic AI tools",
6+
"repository": {
7+
"type": "git",
8+
"url": "https://github.com/jbrinkman/valkey-ai-tasks.git"
9+
},
10+
"devDependencies": {
11+
"@commitlint/cli": "^18.4.3",
12+
"@commitlint/config-conventional": "^18.4.3",
13+
"@semantic-release/changelog": "^6.0.3",
14+
"@semantic-release/git": "^10.0.1",
15+
"conventional-changelog-conventionalcommits": "^7.0.2",
16+
"semantic-release": "^22.0.12"
17+
},
18+
"scripts": {
19+
"semantic-release": "semantic-release"
20+
}
21+
}

0 commit comments

Comments
 (0)