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
23 changes: 21 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ If you need to create small or medium projects (<300 modules), you can use the w
## CLI
### Install
```
curl -L https://github.com/cdsap/ProjectGenerator/releases/download/v0.4.0/projectGenerator --output projectGenerator
curl -L https://github.com/cdsap/ProjectGenerator/releases/download/v0.4.1/projectGenerator --output projectGenerator
chmod 0757 projectGenerator
```

Expand Down Expand Up @@ -51,6 +51,8 @@ Then, you can use the versions.yaml in the `generate-project` command:
- `--versions-file`: Path to a custom YAML file with dependency versions
- `--project-name`: Name of the project
- `--agp9`: Use AGP 9.x (default: false). Only for Android projects.
- `--room-database`: Enable Room database generation (default: false). Only for Android projects.
- `--android-kotlin-multiplatform-library`: For Android projects, generate Android library modules with `com.android.kotlin.multiplatform.library` instead of `com.android.library` (default: false).

#### Example: Generate a project with custom options
```bash
Expand Down Expand Up @@ -78,7 +80,7 @@ ProjectGenerator(
```
### Dependency
```
implementation("io.github.cdsap:projectgenerator:0.4.0")
implementation("io.github.cdsap:projectgenerator:0.4.1")
```

# Options
Expand Down Expand Up @@ -132,6 +134,23 @@ Kotlin-JVM project
./projectGenerator generate-project --shape triangle --layers 5 --modules 100 --type jvm
```

## Android-only options
### `--room-database`
Enable Room database generation in Android projects.

##### Example
```kotlin
./projectGenerator generate-project --type android --modules 100 --room-database
```

### `--android-kotlin-multiplatform-library`
Use the Android Kotlin Multiplatform library plugin for generated Android library modules.

##### Example
```kotlin
./projectGenerator generate-project --type android --modules 100 --android-kotlin-multiplatform-library
```

## `Classes Module`
Classes generated per module, options:
* classes: Classes to generate per module. Default 5.
Expand Down
2 changes: 1 addition & 1 deletion backend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ RUN npm install
COPY . .

# Download CLI
RUN curl -L https://github.com/cdsap/ProjectGenerator/releases/download/v0.4.0/projectGenerator \
RUN curl -L https://github.com/cdsap/ProjectGenerator/releases/download/v0.4.1/projectGenerator \
--output /usr/local/bin/projectGenerator && \
chmod 0755 /usr/local/bin/projectGenerator

Expand Down
27 changes: 20 additions & 7 deletions backend/server.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -43,23 +43,34 @@ app.post('/api/generate', upload.single('versions-file'), async (req, res) => {
const tmpDir = fs.mkdtempSync('/tmp/gen-');
const outputName = `project-${uuidv4()}`;
const outputZip = path.join(tmpDir, `${outputName}.zip`);
const toBool = (value) => value === true || value === 'true' || value === '1' || value === 1;

// reCAPTCHA validation
const isCaptchaValid = await verifyCaptcha(body.captchaToken);
if (!isCaptchaValid) return res.status(403).send('Invalid CAPTCHA');

// Limit modules to maximum of 1500
// Limit modules to maximum of 300
const modules = Math.min(parseInt(body.modules) || 0, 300);
console.log(`Modules requested: ${body.modules}, limited to: ${modules}`);

// Accept both legacy and current field names from frontend clients
const type = body.type || 'android';
const diInput = (body.di || body['di-type'] || 'hilt').toString().toLowerCase();
const supportedDi = new Set(['hilt', 'metro', 'none']);
const di = supportedDi.has(diInput) ? diInput : 'hilt';
const roomDatabase = toBool(body['room-database']) || toBool(body.roomDatabase);
const androidKmpLibrary =
toBool(body['android-kotlin-multiplatform-library']) ||
toBool(body.androidKotlinMultiplatformLibrary);

// ✅ Build CLI args safely
const args = [
`--shape`, body.shape || 'rectangle',
`--modules`, modules,
`--layers`, body.layers || 5,
`--language`, body.language || 'kts',
`--di`, body['di-type'] || 'hilt',
`--type`, body.type || 'android',
`--di`, di,
`--type`, type,
`--classes-module`, Math.min(parseInt(body['classes-module']) || 15, 15),
`--classes-module-type`, body['classes-module-type'] || 'fixed',
`--type-of-string-resources`, body['type-of-string-resources'] || 'normal',
Expand All @@ -68,11 +79,13 @@ app.post('/api/generate', upload.single('versions-file'), async (req, res) => {

// Add project name if provided
if (body['project-name']) { args.push('--project-name', body['project-name']);}
if (body['generate-unit-test'] === 'true' || body['generate-unit-test'] === true) args.push('--generate-unit-test');
if (body['agp9'] === 'true' || body['agp9'] === true) args.push('--agp9');
if (body.develocity === 'true' || body.develocity === true) args.push('--develocity');
if (toBool(body['generate-unit-test']) || toBool(body.generateUnitTest)) args.push('--generate-unit-test');
if (toBool(body['agp9'])) args.push('--agp9');
if (toBool(body.develocity)) args.push('--develocity');
if (body['develocity-url']) args.push('--develocity-url', body['develocity-url']);
if (body.type === 'android' && body.processor) args.push('--processor', body.processor);
if (type === 'android' && body.processor) args.push('--processor', body.processor);
if (type === 'android' && roomDatabase) args.push('--room-database');
if (type === 'android' && androidKmpLibrary) args.push('--android-kotlin-multiplatform-library');
if (req.file) args.push('--versions-file', req.file.path);

const command = `/usr/local/bin/projectGenerator generate-project ${args.join(' ')}`;
Expand Down
4 changes: 2 additions & 2 deletions project-generator/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ plugins {
}

group = "io.github.cdsap"
version = "0.4.0"
version = "0.4.1"

dependencies {
implementation(libs.kotlinx.coroutines.core)
Expand Down Expand Up @@ -37,7 +37,7 @@ tasks.register<Test>("unitTest") {
mavenPublishing {
publishToMavenCentral()
signAllPublications()
coordinates("io.github.cdsap", "projectgenerator", "0.4.0")
coordinates("io.github.cdsap", "projectgenerator", "0.4.1")

pom {
scm {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package io.github.cdsap.projectgenerator

import io.github.cdsap.projectgenerator.model.Android
import io.github.cdsap.projectgenerator.model.ClassesPerModule
import io.github.cdsap.projectgenerator.model.ClassesPerModuleType
import io.github.cdsap.projectgenerator.model.DependencyInjection
import io.github.cdsap.projectgenerator.model.Gradle
import io.github.cdsap.projectgenerator.model.Language
import io.github.cdsap.projectgenerator.model.Project
import io.github.cdsap.projectgenerator.model.Shape
import io.github.cdsap.projectgenerator.model.TypeOfStringResources
import io.github.cdsap.projectgenerator.model.TypeProjectRequested
import io.github.cdsap.projectgenerator.model.Versions
import io.github.cdsap.projectgenerator.writer.GradleWrapper
import org.gradle.testkit.runner.GradleRunner
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.EnumSource
import org.junit.jupiter.api.io.TempDir
import java.io.File
import java.nio.file.Path

class RoomDiVariantsAssembleE2EValidationTest {
@TempDir
lateinit var tempDir: Path

@ParameterizedTest
@EnumSource(DependencyInjection::class)
fun `room builds debug and release with assemble for all di modes`(di: DependencyInjection) {
val projectName = "room_assemble_${di.name.lowercase()}"
ProjectGenerator(
modules = 8,
shape = Shape.FLAT,
language = Language.KTS,
typeOfProjectRequested = TypeProjectRequested.ANDROID,
classesPerModule = ClassesPerModule(ClassesPerModuleType.FIXED, 12),
versions = Versions(
project = Project(jdk = "17"),
di = di,
android = Android(roomDatabase = true)
),
typeOfStringResources = TypeOfStringResources.NORMAL,
layers = 2,
generateUnitTest = false,
gradle = GradleWrapper(Gradle.GRADLE_9_3_0),
path = tempDir.toFile().path,
projectName = projectName
).write()

val projectDir = File("$tempDir/$projectName/project_kts")
val assemble = GradleRunner.create()
.withProjectDir(projectDir)
.withArguments("clean", "assemble")
.build()

assertTrue(assemble.output.contains("BUILD SUCCESSFUL"))
assertTrue(assemble.output.contains("assembleDebug"))
assertTrue(assemble.output.contains("assembleRelease"))
}
}