Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 92 additions & 65 deletions .github/workflows/devbox-ci.yml → .github/workflows/devkit-ci.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name: DevBox CI
name: DevKit CI

on:
pull_request:
paths:
- 'devbox/**'
- 'devkit/**'
workflow_dispatch:
inputs:
level:
Expand Down Expand Up @@ -32,56 +32,60 @@ jobs:
- name: Install just
uses: extractions/setup-just@v2

- name: Install envsubst
run: sudo apt-get install -y gettext-base

- name: Validate justfile
working-directory: devbox
working-directory: devkit
run: just --list

- name: Validate docker-compose
working-directory: devbox
working-directory: devkit
run: |
for p in single cluster cluster4 cluster5 tabletopic analytics; do
echo "=== Profile: $p ==="
docker compose -f docker-compose.yml --profile $p config --services
done

- name: Validate config generation
working-directory: devbox
working-directory: devkit
run: |
# Generate cluster-id without kafka-storage.sh
mkdir -p .devbox
echo "test-cluster-id" > .devbox/cluster-id
mkdir -p .devkit
echo "test-cluster-id" > .devkit/cluster-id

# Single node, no features
just generate-config 1 ""
grep -q "node.id=0" .devbox/config/node-0.properties
grep -q "controller.quorum.voters=0@node-0:9093" .devbox/config/node-0.properties
! grep -q "broker.rack" .devbox/config/node-0.properties
grep -q "node.id=0" .devkit/config/node-0.properties
grep -q "controller.quorum.voters=0@node-0:9093" .devkit/config/node-0.properties
! grep -q "broker.rack" .devkit/config/node-0.properties
echo "✓ Single node config OK"

# 3-node cluster with zerozone
just generate-config 3 "zerozone"
grep -q "broker.rack=az-0" .devbox/config/node-0.properties
grep -q "broker.rack=az-1" .devbox/config/node-1.properties
grep -q "broker.rack=az-2" .devbox/config/node-2.properties
grep -q "zonerouter" .devbox/config/node-0.properties
grep -q "controller.quorum.voters=0@node-0:9093,1@node-1:9093,2@node-2:9093" .devbox/config/node-0.properties
grep -q "broker.rack=az-0" .devkit/config/node-0.properties
grep -q "broker.rack=az-1" .devkit/config/node-1.properties
grep -q "broker.rack=az-2" .devkit/config/node-2.properties
grep -q "zonerouter" .devkit/config/node-0.properties
grep -q "controller.quorum.voters=0@node-0:9093,1@node-1:9093,2@node-2:9093" .devkit/config/node-0.properties
echo "✓ Cluster + zerozone config OK"

# Tabletopic feature
just generate-config 1 "tabletopic"
grep -q "automq.table.topic.catalog.type=rest" .devbox/config/node-0.properties
grep -q "automq.table.topic.catalog.type=rest" .devkit/config/node-0.properties
echo "✓ Tabletopic config OK"

# Combined features
just generate-config 1 "tabletopic zerozone"
grep -q "automq.table.topic" .devbox/config/node-0.properties
grep -q "zonerouter" .devbox/config/node-0.properties
grep -q "broker.rack" .devbox/config/node-0.properties
grep -q "automq.table.topic" .devkit/config/node-0.properties
grep -q "zonerouter" .devkit/config/node-0.properties
grep -q "broker.rack" .devkit/config/node-0.properties
echo "✓ Combined features config OK"

smoke:
name: Smoke
needs: lint
if: ${{ github.event_name == 'pull_request' || inputs.level == 'smoke' || inputs.level == 'full' }}
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
Expand All @@ -94,60 +98,72 @@ jobs:

- uses: extractions/setup-just@v2

- name: Cache Gradle
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: ${{ runner.os }}-gradle-

- name: Gradle build
run: ./gradlew :core:build :tools:build :shell:build -x test

- name: Start single node
working-directory: devbox
working-directory: devkit
run: just start

- name: Wait for healthy
run: |
for i in $(seq 1 30); do
S=$(docker inspect --format='{{.State.Health.Status}}' node-0 2>/dev/null)
[ "$S" = "healthy" ] && echo "✓ node-0 healthy" && exit 0
sleep 5
done
echo "Timeout waiting for node-0" && docker logs node-0 | tail -50 && exit 1
working-directory: devkit
run: just wait

- name: Topic operations
working-directory: devbox
working-directory: devkit
run: |
just topic-create ci-test
just topic-list 2>&1 | grep ci-test
just topic-describe ci-test 2>&1 | grep "PartitionCount: 1"
echo "✓ Topic operations OK"

- name: Produce and consume
working-directory: devkit
run: |
echo -e "ci-msg-1\nci-msg-2" | docker exec -i node-0 bash -c \
"KAFKA_HEAP_OPTS='-Xms256m -Xmx256m' KAFKA_JVM_PERFORMANCE_OPTS='' /opt/automq/bin/kafka-console-producer.sh --bootstrap-server localhost:9092 --topic ci-test"
docker exec node-0 bash -c \
"KAFKA_HEAP_OPTS='-Xms256m -Xmx256m' KAFKA_JVM_PERFORMANCE_OPTS='' /opt/automq/bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic ci-test --from-beginning --max-messages 2 --timeout-ms 15000" \
2>&1 | grep ci-msg-1
echo -e "ci-msg-1\nci-msg-2" | just produce ci-test
just consume ci-test --from-beginning --max-messages 2 --timeout-ms 15000 2>&1 | grep ci-msg-1
echo "✓ Produce/consume OK"

- name: Consumer group operations
working-directory: devkit
run: |
just group-list 2>&1 | grep -q "."
just group-describe ci-consumer 2>&1 || true # group may not exist yet, just verify command works
just broker-list 2>&1 | grep -q "node-0"
just broker-config 0 2>&1 | grep -q "advertised.listeners"
echo "✓ Consumer group and cluster operations OK"

- name: Bin passthrough
working-directory: devbox
working-directory: devkit
run: |
just bin kafka-broker-api-versions.sh --bootstrap-server localhost:9092 2>&1 | grep -q "ApiVersion"
echo "✓ Bin passthrough OK"

- name: JMX operations
working-directory: devbox
working-directory: devkit
run: |
just jmx -e domains 2>&1 | grep -q "kafka.server"
just jmx -e 'beans -d kafka.server' 2>&1 | grep -q "kafka.server"
just jmx -e 'get -b kafka.server:name=BrokerState,type=KafkaServer Value' 2>&1 | grep -q "Value = 3"
echo "✓ JMX operations OK"

- name: Stop
if: always()
working-directory: devbox
working-directory: devkit
run: just stop

full:
name: Full
needs: lint
if: ${{ github.event_name == 'pull_request' || inputs.level == 'full' }}
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
Expand All @@ -160,60 +176,71 @@ jobs:

- uses: extractions/setup-just@v2

- name: Cache Gradle
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: ${{ runner.os }}-gradle-

- name: Gradle build
run: ./gradlew :core:build :tools:build :shell:build -x test

- name: Test tabletopic
working-directory: devbox
working-directory: devkit
run: |
just start 1 tabletopic
for i in $(seq 1 30); do
S=$(docker inspect --format='{{.State.Health.Status}}' node-0 2>/dev/null)
[ "$S" = "healthy" ] && break; sleep 5
done
just wait
curl -sf http://localhost:8181/v1/config > /dev/null
echo "✓ Iceberg REST OK"
for i in $(seq 1 30); do
curl -sf http://localhost:8081/ > /dev/null && echo "✓ Schema Registry OK" && break
sleep 5
done
grep -q "automq.table.topic" .devbox/config/node-0.properties
grep -q "automq.table.topic" .devkit/config/node-0.properties
echo "✓ Tabletopic config merged"
just stop

- name: Test 4-node cluster (3 controller + 1 broker)
working-directory: devbox
working-directory: devkit
run: |
just start 4
# Verify role configs
grep -q "process.roles=broker,controller" .devbox/config/node-0.properties
grep -q "process.roles=broker,controller" .devbox/config/node-1.properties
grep -q "process.roles=broker,controller" .devbox/config/node-2.properties
grep -q "^process.roles=broker$" .devbox/config/node-3.properties
grep -q "controller.quorum.voters=0@node-0:9093,1@node-1:9093,2@node-2:9093" .devbox/config/node-0.properties
just wait
grep -q "process.roles=broker,controller" .devkit/config/node-0.properties
grep -q "process.roles=broker,controller" .devkit/config/node-1.properties
grep -q "process.roles=broker,controller" .devkit/config/node-2.properties
grep -q "^process.roles=broker$" .devkit/config/node-3.properties
grep -q "controller.quorum.voters=0@node-0:9093,1@node-1:9093,2@node-2:9093" .devkit/config/node-0.properties
echo "✓ Role configs correct"
# Wait for healthy
for node in 0 1 2 3; do
for i in $(seq 1 30); do
S=$(docker inspect --format='{{.State.Health.Status}}' node-${node} 2>/dev/null)
[ "$S" = "healthy" ] && echo "✓ node-${node} healthy" && break
sleep 5
done
done
# Test topic operations
just topic-create mixed-ci-test
just topic-describe mixed-ci-test 2>&1 | grep -E "Leader: [0123]"
echo "✓ Mixed cluster (3 controller + 1 broker) OK"
just perf-produce mixed-ci-test --num-records 100 --record-size 512 --throughput -1 2>&1 | grep -q "records sent"
echo "✓ Perf produce OK"
just arthas-exec 0 version 2>&1 | grep -q "arthas"
echo "✓ Arthas OK"
just chaos-delay 100 node-0
just chaos-status 2>&1 | grep -q "node-0"
just chaos-reset
just chaos-status 2>&1 | grep -q "minio"
echo "✓ Chaos OK"
just stop

- name: Test zerozone config
working-directory: devbox
working-directory: devkit
run: |
just start 5 zerozone
grep -q "broker.rack=az-0" .devbox/config/node-0.properties
grep -q "broker.rack=az-1" .devbox/config/node-1.properties
grep -q "broker.rack=az-2" .devbox/config/node-2.properties
grep -q "broker.rack=az-0" .devbox/config/node-3.properties
grep -q "broker.rack=az-1" .devbox/config/node-4.properties
grep -q "broker.rack=az-0" .devkit/config/node-0.properties
grep -q "broker.rack=az-1" .devkit/config/node-1.properties
grep -q "broker.rack=az-2" .devkit/config/node-2.properties
grep -q "broker.rack=az-0" .devkit/config/node-3.properties
grep -q "broker.rack=az-1" .devkit/config/node-4.properties
echo "✓ ZeroZone broker.rack round-robin OK"
just stop

- name: Cleanup
if: always()
working-directory: devkit
run: just clean
36 changes: 36 additions & 0 deletions CONTRIBUTING_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,42 @@ or [Slack](https://join.slack.com/t/automq/shared_invite/zt-29h17vye9-thf31ebIVL
Before getting started, please review AutoMQ's Code of Conduct. Everyone interacting in Slack or Wechat
follow [Code of Conduct](CODE_OF_CONDUCT.md).

## Suggested Onboarding Path for New Contributors

## Quick Start for First-Time Contributors (Recommended)

If you are new to AutoMQ, we recommend starting with the simplest path before diving into local builds.

**Option 1: Quick exploration (recommended for beginners)**
- Run AutoMQ using Docker as described in the README
- Verify you can:
- Start the broker
- Create a topic
- Produce and consume messages
- This helps you understand AutoMQ behavior without local environment setup

**Option 2: DevKit local development (recommended for code contributions)**
- Use the Docker Compose-based DevKit to start a local AutoMQ cluster with MinIO and JDWP debug ports
- Quick start:
- `cd devkit`
- `just start-build` (single node) or `just start-build 3` (3-node cluster)
- Useful shortcuts: `just topic-list`, `just produce <topic>`, `just logs`
- See full instructions in [devkit/README.md](devkit/README.md)

**Option 3: Manual local development setup**
- Follow the steps below to build and run AutoMQ locally with IDEA/manual configuration
- This path is useful when you need full control over local components and configs

> Tip: If you encounter setup issues, check [devkit/README.md](devkit/README.md), “Local Debug with IDEA”, and S3 configuration sections below.


If you are new to AutoMQ, it is recommended to first deploy and run AutoMQ using Docker as described in the README.
This helps you quickly understand AutoMQ’s core concepts and behavior without local environment complexity.

After gaining familiarity, contributors who want to work on code can follow the steps in this guide to build and run AutoMQ locally.
For most contributors, we recommend starting with DevKit (`devkit/README.md`) and using the manual setup only when deeper environment customization is needed.


## Code Contributions

Most of the issues open for contributions are tagged with 'good first issue.' To claim one, simply reply with 'pick up' in the issue and the AutoMQ maintainers will assign the issue to you. If you have any questions about the 'good first issue' please feel free to ask. We will do our best to clarify any doubts you may have.
Expand Down
Loading
Loading