diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..ed0a581 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,23 @@ +--- +name: Bug report +about: Report a reproducible problem +labels: bug +--- + +## Summary + +## Steps to Reproduce +1. +2. +3. + +## Expected + +## Actual + +## Environment +- Go version: +- OS: +- Commit/Tag: + +## Additional Context diff --git a/.github/ISSUE_TEMPLATE/documentation.md b/.github/ISSUE_TEMPLATE/documentation.md new file mode 100644 index 0000000..4612317 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation.md @@ -0,0 +1,11 @@ +--- +name: Documentation +about: Request documentation changes or additions +labels: documentation +--- + +## Summary + +## Proposed Change + +## References diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..2e8e9fd --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,13 @@ +--- +name: Feature request +about: Propose an enhancement +labels: enhancement +--- + +## Problem + +## Proposal + +## Alternatives Considered + +## Additional Context diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..7560519 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "weekly" + - package-ecosystem: "gomod" + directory: "/examples/hello-mysql" + schedule: + interval: "weekly" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..f7bab0a --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,11 @@ +## Summary +- + +## Changes +- + +## Testing +- + +## Notes +- diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..fcb5bf5 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,27 @@ +name: codeql + +on: + push: + branches: + - main + pull_request: + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + strategy: + fail-fast: false + matrix: + language: ["go"] + steps: + - uses: actions/checkout@v4 + - uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + - uses: github/codeql-action/autobuild@v3 + - uses: github/codeql-action/analyze@v3 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 667cb2f..386ecd2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,6 +10,7 @@ go test ./... ## Guidelines +- Contribute via fork + pull request (recommended). Direct pushes to the main repo are restricted. - Follow Go formatting with `gofmt`. - Run `make fmt` before committing. - Run `make lint` for lint checks. diff --git a/README.md b/README.md index df6fcca..939f962 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,10 @@ modkit is a Go-idiomatic backend service framework built around an explicit modu This repository is in early MVP implementation. APIs and structure may change before v0.1.0. +## API Stability + +Until `v0.1.0`, public APIs may change without notice. After `v0.1.0`, changes will follow semantic versioning. + ## What Is modkit? modkit provides: @@ -33,6 +37,10 @@ Example app: - See `docs/tooling.md` +## Contributing + +Contributions are welcome via fork + pull request. Direct pushes to the main repo are restricted. + ## Architecture Overview - **module**: metadata for imports/providers/controllers/exports. diff --git a/examples/hello-mysql/internal/seed/seed_test.go b/examples/hello-mysql/internal/seed/seed_test.go index 1bec12f..b1be1c4 100644 --- a/examples/hello-mysql/internal/seed/seed_test.go +++ b/examples/hello-mysql/internal/seed/seed_test.go @@ -18,6 +18,10 @@ func TestSeed_InsertsDefaultUsersIfEmpty(t *testing.T) { _ = container.Terminate(ctx) }() + if err := waitForMySQL(ctx, dsn); err != nil { + t.Fatalf("mysql not ready: %v", err) + } + db, err := mysql.Open(dsn) if err != nil { t.Fatalf("open db: %v", err) @@ -88,3 +92,36 @@ func startMySQL(t *testing.T, ctx context.Context) (testcontainers.Container, st dsn := "root:password@tcp(" + host + ":" + port.Port() + ")/app?parseTime=true&multiStatements=true" return container, dsn } + +func waitForMySQL(ctx context.Context, dsn string) error { + deadline, ok := ctx.Deadline() + if !ok { + deadline = time.Now().Add(30 * time.Second) + } + + for { + db, err := mysql.Open(dsn) + if err == nil { + pingCtx, cancel := context.WithTimeout(ctx, 2*time.Second) + pingErr := db.PingContext(pingCtx) + cancel() + _ = db.Close() + if pingErr == nil { + return nil + } + } + + if time.Now().After(deadline) { + if err != nil { + return err + } + return context.DeadlineExceeded + } + + select { + case <-ctx.Done(): + return ctx.Err() + case <-time.After(500 * time.Millisecond): + } + } +}