Skip to content

Commit 4fab2d9

Browse files
authored
feat: add ci infra (#10)
1 parent 2700751 commit 4fab2d9

12 files changed

Lines changed: 713 additions & 84 deletions

File tree

.github/workflows/ci.yaml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: Build
2+
3+
on:
4+
pull_request:
5+
workflow_dispatch:
6+
push:
7+
branches: [ main ]
8+
9+
jobs:
10+
build:
11+
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- uses: actions/checkout@v4
16+
17+
18+
- name: Set up JDK
19+
uses: actions/setup-java@v4
20+
with:
21+
distribution: "graalvm"
22+
java-version: "23"
23+
cache: "gradle"
24+
25+
- name: Set up Gradle
26+
uses: gradle/actions/setup-gradle@v3
27+
28+
- name: Test with Gradle
29+
run: |
30+
./gradlew clean
31+
./gradlew spotlessApply
32+
./gradlew build test --stacktrace
33+
34+
- name: Jacoco
35+
run: ./gradlew jacocoTestReport
36+
37+
- name: Upload coverage to Codecov
38+
uses: codecov/codecov-action@v5
39+
with:
40+
token: ${{ secrets.CODECOV_TOKEN }}
41+
slug: eschizoid/mcp-github-code-analyzer
42+
files: ./build/reports/jacoco/test/jacocoTestReport.xml

.github/workflows/release.yaml

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
name: Release
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
releaseType:
7+
description: "Release Type"
8+
required: true
9+
default: "patch"
10+
type: choice
11+
options:
12+
- patch
13+
- minor
14+
- major
15+
16+
jobs:
17+
release:
18+
runs-on: ubuntu-latest
19+
permissions:
20+
contents: write
21+
timeout-minutes: 120
22+
23+
steps:
24+
- uses: actions/checkout@v4
25+
with:
26+
fetch-depth: 0
27+
28+
- name: Set up JDK
29+
uses: actions/setup-java@v4
30+
with:
31+
distribution: "graalvm"
32+
java-version: "23"
33+
cache: "gradle"
34+
35+
- name: Set Git Identity
36+
run: |
37+
git config --global user.email "mariano.gonzalez.mx@gmail.com"
38+
git config --global user.name "Mariano Gonzalez"
39+
40+
- name: Setup GPG
41+
uses: crazy-max/ghaction-import-gpg@v6
42+
with:
43+
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
44+
passphrase: ${{ secrets.GPG_PASSPHRASE }}
45+
46+
- name: Update Version and Create Tag
47+
id: version
48+
run: |
49+
# Create release with specified increment type
50+
./gradlew release -Prelease.incrementer=${{ inputs.releaseType }} -Prelease.disableChecks -x test
51+
52+
# Get the version number
53+
RAW_VERSION=$(./gradlew currentVersion -q -Prelease.quiet)
54+
55+
# Use the actual tag name that was created (with 'v' prefix)
56+
TAG_VERSION="v$RAW_VERSION"
57+
58+
echo "version=$RAW_VERSION" >> $GITHUB_OUTPUT
59+
echo "tagName=$TAG_VERSION" >> $GITHUB_OUTPUT
60+
61+
- name: Build project
62+
run: |
63+
./gradlew clean build publish
64+
env:
65+
JRELEASER_GITHUB_TOKEN: ${{ secrets.JRELEASER_GITHUB_TOKEN }}
66+
JRELEASER_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
67+
JRELEASER_GPG_PUBLIC_KEY: ${{ secrets.GPG_PUBLIC_KEY }}
68+
JRELEASER_GPG_SECRET_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
69+
JRELEASER_MAVENCENTRAL_SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
70+
JRELEASER_MAVENCENTRAL_SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
71+
72+
- name: Create GitHub Release
73+
uses: softprops/action-gh-release@v2
74+
with:
75+
tag_name: ${{ steps.version.outputs.tagName }}
76+
name: Release ${{ steps.version.outputs.version }}
77+
generate_release_notes: true
78+
files: |
79+
build/staging-deploy/io/github/eschizoid/mcp-github-code-analyzer/${{ steps.version.outputs.version }}/**/*
80+
81+
- name: Publish to Maven Central
82+
env:
83+
JRELEASER_GITHUB_TOKEN: ${{ secrets.JRELEASER_GITHUB_TOKEN }}
84+
JRELEASER_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
85+
JRELEASER_GPG_PUBLIC_KEY: ${{ secrets.GPG_PUBLIC_KEY }}
86+
JRELEASER_GPG_SECRET_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
87+
JRELEASER_MAVENCENTRAL_SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
88+
JRELEASER_MAVENCENTRAL_SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
89+
run: |
90+
./gradlew jreleaserFullRelease --stacktrace

README.md

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,30 @@ A Kotlin server application that analyzes GitHub repositories using AI models th
1717

1818
- JDK 23 or higher
1919
- Kotlin 1.9.x
20+
- Gradle 8.0 or higher
21+
- [Ollama](https://github.com/ollama/ollama) 3.2 or higher (for model API)
22+
- [MCP Inspector](https://github.com/modelcontextprotocol/inspector) (for model context protocol)
2023

2124
### Installation
2225

2326
1. Clone this repository
2427
2. Build the project using Gradle:
2528

26-
```bash
27-
./gradlew build
28-
```
29+
```bash
30+
./gradlew build
31+
```
32+
33+
3. Start Ollama server:
34+
35+
```bash
36+
ollama run llama3.2
37+
```
38+
39+
4. Start the MCP Inspector:
40+
41+
```bash
42+
npx @modelcontextprotocol/inspector
43+
```
2944

3045
### Configuration
3146

build.gradle.kts

Lines changed: 115 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,29 @@
1+
import org.jreleaser.model.Active.ALWAYS
2+
import org.jreleaser.model.Active.NEVER
3+
14
plugins {
5+
java
6+
application
7+
`maven-publish`
8+
signing
9+
jacoco
210
kotlin("jvm") version "2.1.0"
311
kotlin("plugin.serialization") version "2.1.0"
412
id("com.diffplug.spotless") version "7.0.3"
5-
application
13+
id("pl.allegro.tech.build.axion-release") version "1.18.7"
14+
id("org.jreleaser") version "1.17.0"
615
}
716

8-
group = "mcp.code.analysis"
17+
scmVersion {
18+
unshallowRepoOnCI.set(true)
19+
tag { prefix.set("v") }
20+
}
921

10-
version = "1.0-SNAPSHOT"
22+
group = "io.github.eschizoid"
23+
24+
version = rootProject.scmVersion.version
25+
26+
description = "MCP Server for GitHub Code Repositories Analysis"
1127

1228
dependencies {
1329
// Kotlin standard library
@@ -29,18 +45,21 @@ dependencies {
2945

3046
// Logging
3147
implementation("ch.qos.logback:logback-classic:1.5.18")
48+
implementation("org.slf4j:jul-to-slf4j:2.0.17")
3249

3350
// Coroutines
34-
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
51+
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
3552

3653
// Serialization
37-
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
54+
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.1")
3855

3956
// JGit for repository interaction
4057
implementation("org.eclipse.jgit:org.eclipse.jgit:7.2.1.202505142326-r")
4158

4259
// Testing
4360
testImplementation(kotlin("test"))
61+
testImplementation("io.mockk:mockk:1.14.2")
62+
testImplementation("io.ktor:ktor-client-mock-jvm:$ktorVersion")
4463
}
4564

4665
application { mainClass.set("MainKt") }
@@ -57,7 +76,11 @@ tasks.jar {
5776

5877
tasks.test { useJUnitPlatform() }
5978

60-
kotlin { jvmToolchain(23) }
79+
java {
80+
withSourcesJar()
81+
withJavadocJar()
82+
toolchain { languageVersion = JavaLanguageVersion.of(23) }
83+
}
6184

6285
spotless {
6386
kotlin {
@@ -79,3 +102,89 @@ spotless {
79102
target("*.gradle.kts")
80103
}
81104
}
105+
106+
signing {
107+
afterEvaluate { sign(publishing.publications["maven"]) }
108+
109+
val signingKey = System.getenv("JRELEASER_GPG_SECRET_KEY") ?: project.properties["signing.secretKey"]?.toString()
110+
val signingPassword = System.getenv("JRELEASER_GPG_PASSPHRASE") ?: project.properties["signing.password"]?.toString()
111+
112+
if (signingKey != null && signingPassword != null) {
113+
useInMemoryPgpKeys(signingKey, signingPassword)
114+
}
115+
}
116+
117+
publishing {
118+
publications {
119+
create<MavenPublication>("maven") {
120+
groupId = "io.github.eschizoid"
121+
artifactId = "mcp-github-code-analyzer"
122+
from(components["java"])
123+
124+
pom {
125+
name.set("mcp-github-code-analyzer")
126+
description.set("MCP Server for GitHub Code Repositories Analysis")
127+
url.set("https://github.com/eschizoid/mcp-github-code-analyzer")
128+
inceptionYear.set("2025")
129+
130+
licenses {
131+
license {
132+
name.set("Apache License 2.0")
133+
url.set("https://www.apache.org/licenses/LICENSE-2.0")
134+
}
135+
}
136+
137+
developers {
138+
developer {
139+
id.set("eschizoid")
140+
name.set("Mariano Gonzalez")
141+
email.set("mariano.gonzalez.mx@gmail.com")
142+
}
143+
}
144+
145+
scm {
146+
connection.set("scm:git:git://github.com/eschizoid/mcp-github-code-analyzer.git")
147+
developerConnection.set("scm:git:ssh://github.com/eschizoid/mcp-github-code-analyzer.git")
148+
url.set("https://github.com/eschizoid/mcp-github-code-analyzer")
149+
}
150+
}
151+
}
152+
}
153+
154+
repositories { maven { url = uri(layout.buildDirectory.dir("staging-deploy")) } }
155+
}
156+
157+
jreleaser {
158+
project {
159+
name.set("mcp-github-code-analyzer")
160+
description.set("MCP Server for GitHub Code Repositories Analysis")
161+
authors.set(listOf("Mariano Gonzalez"))
162+
license.set("Apache-2.0")
163+
links { homepage.set("https://github.com/eschizoid/mcp-github-code-analyzer") }
164+
inceptionYear.set("2025")
165+
tags.set(listOf("MCP", "LLM", "Ollama", "kotlin", "github", "code analysis"))
166+
}
167+
168+
signing { active.set(NEVER) }
169+
170+
deploy {
171+
maven {
172+
mavenCentral {
173+
create("sonatype") {
174+
active.set(ALWAYS)
175+
url.set("https://central.sonatype.com/api/v1/publisher")
176+
stagingRepository("build/staging-deploy")
177+
enabled.set(true)
178+
sign.set(false)
179+
}
180+
}
181+
}
182+
}
183+
184+
release {
185+
github {
186+
enabled.set(true)
187+
overwrite.set(false)
188+
}
189+
}
190+
}

0 commit comments

Comments
 (0)