Skip to content

Commit fd612c7

Browse files
committed
feat: Add RPM packaging and GitHub Actions release workflow
Implement comprehensive RPM packaging with static linking for RHEL/AlmaLinux/Rocky Linux 9. ## RPM Packaging - Add spec file for building static-linked RPM packages (support/rpm/mygramdb.spec) - Create Docker-based RPM build environment (support/rpm/Dockerfile.rpmbuild) - Implement automated build script (support/rpm/test-rpm-build.sh) - Add systemd service file (support/systemd/mygramdb.service) - Use Git tag-based versioning for RPM packages ## GitHub Actions - Add release workflow triggered by version tags (v*) - Automated RPM build, test, and GitHub release creation - Install verification in AlmaLinux 9 container ## Static Linking - Configure CMake with -DBUILD_SHARED_LIBS=OFF for minimal dependencies - Only requires libicu and MySQL client libraries (auto-installed) - Binary size: ~1.8MB for mygramdb, ~68KB for mygram-cli ## File Organization - Move Docker files to support/docker/ - Move development scripts to support/dev/ - Add support/rpm/ for RPM packaging infrastructure - Add support/systemd/ for systemd service files ## Daemon & Security Features - Add daemon mode support (--daemon flag) - Implement root user prevention for security - Add file logging support (--log-file flag) - Comprehensive daemon and logging tests ## Testing Infrastructure - Reorganize tests into integration/ and unit test directories - Add integration test scripts for daemon mode and security - Add comprehensive logging configuration tests - Improve test organization and isolation ## Documentation - Update installation docs with RPM installation instructions - Add daemon mode and logging configuration examples - Update Docker deployment documentation Breaking Changes: - Docker-related files moved from docker/ to support/docker/ - scripts/run-clang-tidy.sh moved to support/dev/ Closes: Issues related to RPM packaging and release automation
1 parent eaaadef commit fd612c7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+2009
-171
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ jobs:
4040
- 'third_party/**'
4141
- 'Makefile'
4242
- 'Dockerfile'
43-
- 'docker/**'
43+
- 'support/docker/**'
4444
- 'examples/**'
4545
- '.dockerignore'
4646

.github/workflows/release.yml

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
build-rpm:
13+
name: Build RPM Package
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- name: Checkout code
18+
uses: actions/checkout@v4
19+
with:
20+
fetch-depth: 0 # Fetch all history for git describe
21+
22+
- name: Set up Docker Buildx
23+
uses: docker/setup-buildx-action@v3
24+
25+
- name: Extract version from tag
26+
id: version
27+
run: |
28+
VERSION="${GITHUB_REF#refs/tags/v}"
29+
echo "version=$VERSION" >> $GITHUB_OUTPUT
30+
echo "Building version: $VERSION"
31+
32+
- name: Build RPM package
33+
run: |
34+
cd support/rpm
35+
./test-rpm-build.sh
36+
37+
- name: List generated RPMs
38+
run: |
39+
echo "Generated RPM packages:"
40+
ls -lh dist/rpm/*.rpm
41+
42+
- name: Test RPM installation (AlmaLinux 9)
43+
run: |
44+
docker run --rm -v "$(pwd)/dist:/dist" almalinux:9 bash -c "
45+
echo '=== Installing Oracle MySQL 8.0 repository ==='
46+
dnf install -y https://dev.mysql.com/get/mysql84-community-release-el9-1.noarch.rpm > /dev/null 2>&1
47+
dnf module disable -y mysql > /dev/null 2>&1
48+
49+
echo '=== Installing MygramDB RPM ==='
50+
dnf install -y /dist/rpm/mygramdb-${{ steps.version.outputs.version }}-*.el9.*.rpm
51+
52+
echo '=== Verifying installation ==='
53+
echo 'Checking for missing library dependencies...'
54+
ldd /usr/bin/mygramdb | grep 'not found' && exit 1 || echo 'mygramdb: OK'
55+
ldd /usr/bin/mygram-cli | grep 'not found' && exit 1 || echo 'mygram-cli: OK'
56+
57+
echo '=== Installation test passed! ==='
58+
"
59+
60+
- name: Upload RPM artifacts
61+
uses: actions/upload-artifact@v4
62+
with:
63+
name: rpm-packages
64+
path: |
65+
dist/rpm/*.rpm
66+
retention-days: 30
67+
68+
- name: Create GitHub Release
69+
uses: softprops/action-gh-release@v1
70+
with:
71+
name: Release ${{ steps.version.outputs.version }}
72+
draft: false
73+
prerelease: false
74+
generate_release_notes: true
75+
files: |
76+
dist/rpm/mygramdb-${{ steps.version.outputs.version }}-*.el9.*.rpm
77+
dist/rpm/mygramdb-debuginfo-${{ steps.version.outputs.version }}-*.el9.*.rpm
78+
dist/rpm/mygramdb-debugsource-${{ steps.version.outputs.version }}-*.el9.*.rpm
79+
body: |
80+
## MygramDB ${{ steps.version.outputs.version }}
81+
82+
### Installation (RHEL/AlmaLinux/Rocky Linux 9)
83+
84+
```bash
85+
# Install Oracle MySQL 8.0 repository
86+
sudo dnf install -y https://dev.mysql.com/get/mysql84-community-release-el9-1.noarch.rpm
87+
sudo dnf module disable -y mysql
88+
89+
# Download and install MygramDB RPM
90+
wget https://github.com/${{ github.repository }}/releases/download/v${{ steps.version.outputs.version }}/mygramdb-${{ steps.version.outputs.version }}-1.el9.aarch64.rpm
91+
sudo dnf install -y ./mygramdb-${{ steps.version.outputs.version }}-1.el9.aarch64.rpm
92+
93+
# Configure and start service
94+
sudo cp /etc/mygramdb/config.yaml.example /etc/mygramdb/config.yaml
95+
sudo vi /etc/mygramdb/config.yaml # Edit configuration
96+
sudo systemctl enable --now mygramdb
97+
```
98+
99+
### Package Details
100+
- **Platform**: RHEL 9 / AlmaLinux 9 / Rocky Linux 9
101+
- **Architecture**: aarch64 (ARM64)
102+
- **Build Type**: Static linking (minimal dependencies)
103+
- **Dependencies**: libicu, MySQL client libraries (auto-installed)
104+
105+
### Files Included
106+
- Binary: `/usr/bin/mygramdb`
107+
- CLI client: `/usr/bin/mygram-cli`
108+
- Systemd service: `/usr/lib/systemd/system/mygramdb.service`
109+
- Config example: `/etc/mygramdb/config.yaml.example`
110+
- Data directory: `/var/lib/mygramdb`

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
build/
33
build-*/
44
cmake-build-*/
5+
dist/
56
*.o
67
*.a
78
*.so
@@ -58,7 +59,7 @@ snapshots/
5859

5960
# SQL files (may contain sensitive data)
6061
*.sql
61-
!docker/mysql/init/*.sql
62+
!support/docker/mysql/init/*.sql
6263

6364
# Backup directory
6465
backup/

CMakeLists.txt

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,33 @@ cmake_minimum_required(VERSION 3.15)
22
# Set CMake policy to suppress deprecation warnings from dependencies
33
cmake_policy(SET CMP0048 NEW)
44
cmake_policy(SET CMP0077 NEW)
5-
project(MygramDB VERSION 1.0.0 LANGUAGES CXX C)
5+
6+
# Get version from environment variable or git tag
7+
if(DEFINED ENV{MYGRAMDB_VERSION})
8+
set(PROJECT_VERSION_FROM_ENV "$ENV{MYGRAMDB_VERSION}")
9+
message(STATUS "Version from environment: ${PROJECT_VERSION_FROM_ENV}")
10+
project(MygramDB VERSION ${PROJECT_VERSION_FROM_ENV} LANGUAGES CXX C)
11+
else()
12+
# Get version from git tag
13+
execute_process(
14+
COMMAND git describe --tags --abbrev=0
15+
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
16+
OUTPUT_VARIABLE GIT_TAG
17+
OUTPUT_STRIP_TRAILING_WHITESPACE
18+
ERROR_QUIET
19+
)
20+
21+
# Parse version from tag (remove 'v' prefix if present)
22+
if(GIT_TAG)
23+
string(REGEX REPLACE "^v" "" PROJECT_VERSION_FROM_GIT "${GIT_TAG}")
24+
message(STATUS "Version from git tag: ${PROJECT_VERSION_FROM_GIT}")
25+
else()
26+
set(PROJECT_VERSION_FROM_GIT "0.0.0")
27+
message(WARNING "No git tag found, using default version: ${PROJECT_VERSION_FROM_GIT}")
28+
endif()
29+
30+
project(MygramDB VERSION ${PROJECT_VERSION_FROM_GIT} LANGUAGES CXX C)
31+
endif()
632

733
# C++ Standard
834
set(CMAKE_CXX_STANDARD 17)
@@ -102,7 +128,9 @@ if(PkgConfig_FOUND)
102128
if(MYSQL_FOUND)
103129
message(STATUS "Found MySQL client via pkg-config")
104130
message(STATUS " Include dirs: ${MYSQL_INCLUDE_DIRS}")
105-
message(STATUS " Libraries: ${MYSQL_LIBRARIES}")
131+
message(STATUS " Libraries: ${MYSQL_LINK_LIBRARIES}")
132+
# Use LINK_LIBRARIES which includes full link flags
133+
set(MYSQL_LIBRARIES ${MYSQL_LINK_LIBRARIES})
106134
endif()
107135
endif()
108136

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ RUN mkdir -p /var/lib/mygramdb /etc/mygramdb && \
6464
COPY --from=builder /build/examples/config-minimal.yaml /etc/mygramdb/config.yaml.example
6565

6666
# Copy entrypoint script
67-
COPY docker/entrypoint.sh /usr/local/bin/entrypoint.sh
67+
COPY support/docker/entrypoint.sh /usr/local/bin/entrypoint.sh
6868
RUN chmod +x /usr/local/bin/entrypoint.sh
6969

7070
# Switch to non-root user

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ format-check:
147147

148148
# Check code with clang-tidy
149149
lint: build
150-
@bash scripts/run-clang-tidy.sh
150+
@bash support/dev/run-clang-tidy.sh
151151

152152
# Build and run mygramdb
153153
run: build

docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ services:
2424
- "${MYSQL_PORT:-3306}:3306"
2525
volumes:
2626
- mysql_data:/var/lib/mysql
27-
- ./docker/mysql/init:/docker-entrypoint-initdb.d:ro
27+
- ./support/docker/mysql/init:/docker-entrypoint-initdb.d:ro
2828
healthcheck:
2929
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD:-root_secure_password}"]
3030
interval: 10s

docs/en/configuration.md

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,15 +80,15 @@ memory:
8080
dump:
8181
dir: "/var/lib/mygramdb/dumps"
8282
default_filename: "mygramdb.dmp"
83-
interval_sec: 600
83+
interval_sec: 0 # 0 = disabled (set to 7200 for 120-minute intervals)
8484
retain: 3
8585

8686
api:
8787
tcp:
8888
bind: "127.0.0.1"
8989
port: 11016
9090
http:
91-
enable: true
91+
enable: false # Disabled by default
9292
bind: "127.0.0.1"
9393
port: 8080
9494
enable_cors: false
@@ -102,6 +102,7 @@ network:
102102
logging:
103103
level: "info"
104104
json: true
105+
file: ""
105106
```
106107
107108
### JSON Format (config.json)
@@ -175,7 +176,7 @@ The same configuration in JSON format:
175176
"dump": {
176177
"dir": "/var/lib/mygramdb/dumps",
177178
"default_filename": "mygramdb.dmp",
178-
"interval_sec": 600,
179+
"interval_sec": 0,
179180
"retain": 3
180181
},
181182
"api": {
@@ -184,7 +185,7 @@ The same configuration in JSON format:
184185
"port": 11016
185186
},
186187
"http": {
187-
"enable": true,
188+
"enable": false,
188189
"bind": "127.0.0.1",
189190
"port": 8080,
190191
"enable_cors": false,
@@ -460,7 +461,7 @@ Dump (snapshot) persistence settings with automatic backup:
460461
- Directory is created automatically on startup if it doesn't exist
461462
- Write permissions are verified at startup
462463
- **default_filename**: Default filename for manual `DUMP SAVE` commands (default: `mygramdb.dmp`)
463-
- **interval_sec**: Auto-save interval in seconds (default: `600`, `0` = disabled)
464+
- **interval_sec**: Auto-save interval in seconds (default: `0` = disabled, recommended: `7200` for 120-minute intervals)
464465
- Automatic dumps are saved with timestamp-based filenames: `auto_YYYYMMDD_HHMMSS.dmp`
465466
- Similar to Redis RDB persistence
466467
- **retain**: Number of auto-saved dumps to retain (default: `3`)
@@ -485,7 +486,7 @@ api:
485486
```yaml
486487
api:
487488
http:
488-
enable: true # Default: true
489+
enable: true # Default: false
489490
bind: "127.0.0.1" # Default: 127.0.0.1 (localhost only)
490491
port: 8080 # Default: 8080
491492
enable_cors: false # Default: disabled. Enable only when exposing to browsers.
@@ -538,11 +539,28 @@ Logging configuration:
538539
- **level**: Log level (default: `info`)
539540
- Options: `debug`, `info`, `warn`, `error`
540541
- **json**: JSON format output (default: `true`)
542+
- **file**: Log file path (default: `""` = stdout)
543+
- Empty string: log to stdout (recommended for systemd/Docker)
544+
- File path: log to file (e.g., `/var/log/mygramdb/mygramdb.log`)
545+
- **Required when using `-d`/`--daemon` option** (stdout is redirected to `/dev/null` in daemon mode)
541546

542547
```yaml
543548
logging:
544549
level: "info"
545550
json: true
551+
file: "" # Empty = stdout, or set file path
552+
```
553+
554+
**systemd/Docker (recommended)**:
555+
```yaml
556+
logging:
557+
file: "" # Log to stdout, captured by systemd journal
558+
```
559+
560+
**Daemon mode (`-d` option)**:
561+
```yaml
562+
logging:
563+
file: "/var/log/mygramdb/mygramdb.log" # Must specify file for daemon mode
546564
```
547565

548566
## Cache Section

docs/en/docker-deployment.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,15 +193,15 @@ Adjust these in `docker-compose.prod.yml` based on your workload.
193193

194194
## Database Initialization
195195

196-
The MySQL container automatically executes scripts in `docker/mysql/init/`:
196+
The MySQL container automatically executes scripts in `support/docker/mysql/init/`:
197197

198198
- `01-create-tables.sql` - Creates sample tables
199199

200200
To add your own initialization scripts:
201201

202202
```bash
203203
# Create your SQL script
204-
cat > docker/mysql/init/02-my-tables.sql <<EOF
204+
cat > support/docker/mysql/init/02-my-tables.sql <<EOF
205205
CREATE TABLE my_table (
206206
id BIGINT PRIMARY KEY,
207207
content TEXT

0 commit comments

Comments
 (0)