Code Monkey home page Code Monkey logo

forma's People

Contributors

grine4ka avatar ikarenkov avatar michaem avatar ntnsmirnov avatar samokryl avatar stepango avatar tonykolomeytsev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

forma's Issues

I don't understand the reason for the error: ProjectValidationError

I've been trying to make a module for three hours already.

Caused by: com.stepango.forma.error.ProjectValidationError: Project example: name does not match type requirements
Projects of type "LibraryTarget" should contain name suffix "library" 
	at com.stepango.forma.validation.ValidatorKt.throwProjectValidationError(Validator.kt:44)
	at com.stepango.forma.validation.ValidatorKt.validateName(Validator.kt:36)
	at com.stepango.forma.validation.ValidatorKt$validator$1.validate(Validator.kt:26)
	at com.stepango.forma.validation.ValidatorKt.validate(Validator.kt:21)
	at AndroidUtilKt.androidUtil(androidUtil.kt:42)
	at AndroidUtilKt.androidUtil$default(androidUtil.kt:72)
	at Build_gradle.<init>(Unknown Source)
	... 136 more

file build.gradle.kts in my example-module:

plugins {
    id("com.android.library")
    id("kotlin-android")
}

repositories {
    jcenter()
    google()
}

androidLibrary(
    packageName = "com.example",
    dependencies = deps(
        androidxDeps.core,
        androidxDeps.appcompat,
        androidxDeps.material,
        androidxDeps.constraintlayout
    )
)

what am I doing wrong? Thanks. :)

Add kotlin directory to main and test sources as default

In kotlin module we can use sources with path src/main/kotlin, but in android-library module only src/main/java available out of the box. We can add kotlin directory to sourceSet for each android-library. We just need add it to androidLibraryFeatureDefinition fun.

Create hybrid configuration example

Introduce stub targets

feature-api
feature-impl
feature-stub

introduce new API for adding project dependencies
During IDE sync impl will be substituted with stub for improved IDE performance, using (compileOnly+runtimeOnly/implementation) configuration based on local flags

Version Code and Version Name in binary

Currently versionCode and versionName are placed in FormaConfiguration, but it's not global configuration responsibility to use single version configuration for whole project. We should have ability to set version code/name in binary. Maybe we have to use version code in application target, because Gradle limitations

The SDK path does not belong to a directory.

When I open the project on Android Studio, it will show popup with:

The path
'\Users\stepango\Library\Android\sdk'
does not belong to a directory.

Android Studio will use this Android SDK instead:
'C:\Android\sdk'
and will modify the project's local.properties file.

After closing popup IDE replaces these settings with:
Untitled234

Clean sample on the clean

Legacy part of our sample doesn't have almost clean architecture.
That's why, we had some stuck trouble with relations between presentation layer and data layer.
For example check out these files CharacterPageDataSource.kt and CharactersListViewModel.kt and you'll see.

GlobalScope.launch(CoroutineExceptionHandler { _, _ ->
            retry = {
                loadInitial(params, callback)
            }
            networkState.postValue(NetworkState.Error())
        })

DataSource shouldn't know anything about scopes.

Necessary to make sample architecture more cleaner with weak deps between presentation layer and data by implementing use case on domain layer.
It will be necessary for future, for example, to make tests functionality from Forma.

Generate target structure based on minimal available configuration

For example, we can generate a target structure based on the initial configuration in the build file

api(
    packageName = "com.stepango.blockme.character.list.api",
    owner = Teams.core
)

src/main/java/com/stepango/blockme/character/list/api folder could be generated

Custom validation rules API

Validation rules:
Self-validation(name)
Dependencies validation(test, annotationPrecessor, projects)
Content validation

Failed run with configureondemand=true

Seems has some kind problem with org.gradle.configureondemand=true mode, when you're trying to run on emulator.

Here some log:

FAILURE: Build failed with an exception.

* What went wrong:
Could not determine the dependencies of task ':binary:compileDebugJavaWithJavac'.
> Could not resolve all dependencies for configuration ':binary:debugCompileClasspath'.
   > A problem occurred configuring project ':feature:home:api'.
      > org.gradle.api.internal.initialization.DefaultClassLoaderScope@275cba33 must be locked before it can be used to compute a classpath!


* Exception is:
org.gradle.api.internal.tasks.TaskDependencyResolveException: Could not determine the dependencies of task ':binary:compileDebugJavaWithJavac'.
	at org.gradle.api.internal.tasks.CachingTaskDependencyResolveContext.getDependencies(CachingTaskDependencyResolveContext.java:71)
	at org.gradle.execution.plan.TaskDependencyResolver.resolveDependenciesFor(TaskDependencyResolver.java:46)
	at org.gradle.execution.plan.LocalTaskNode.getDependencies(LocalTaskNode.java:154)
	at org.gradle.execution.plan.LocalTaskNode.resolveDependencies(LocalTaskNode.java:122)
	at org.gradle.execution.plan.DefaultExecutionPlan.doAddNodes(DefaultExecutionPlan.java:171)
	at org.gradle.execution.plan.DefaultExecutionPlan.addEntryTasks(DefaultExecutionPlan.java:135)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph.addEntryTasks(DefaultTaskExecutionGraph.java:160)
	at org.gradle.execution.TaskNameResolvingBuildConfigurationAction.configure(TaskNameResolvingBuildConfigurationAction.java:49)
	at org.gradle.execution.DefaultBuildConfigurationActionExecuter.configure(DefaultBuildConfigurationActionExecuter.java:55)
	at org.gradle.execution.DefaultBuildConfigurationActionExecuter.access$000(DefaultBuildConfigurationActionExecuter.java:26)
	at org.gradle.execution.DefaultBuildConfigurationActionExecuter$1.proceed(DefaultBuildConfigurationActionExecuter.java:63)
	at org.gradle.execution.DefaultTasksBuildExecutionAction.configure(DefaultTasksBuildExecutionAction.java:45)
	at org.gradle.execution.DefaultBuildConfigurationActionExecuter.configure(DefaultBuildConfigurationActionExecuter.java:55)
	at org.gradle.execution.DefaultBuildConfigurationActionExecuter.access$000(DefaultBuildConfigurationActionExecuter.java:26)
	at org.gradle.execution.DefaultBuildConfigurationActionExecuter$1.proceed(DefaultBuildConfigurationActionExecuter.java:63)
	at org.gradle.execution.ExcludedTaskFilteringBuildConfigurationAction.configure(ExcludedTaskFilteringBuildConfigurationAction.java:48)
	at org.gradle.execution.DefaultBuildConfigurationActionExecuter.configure(DefaultBuildConfigurationActionExecuter.java:55)
	at org.gradle.execution.DefaultBuildConfigurationActionExecuter.lambda$select$0(DefaultBuildConfigurationActionExecuter.java:42)
	at org.gradle.internal.Factories$1.create(Factories.java:31)
	at org.gradle.api.internal.project.DefaultProjectStateRegistry.withMutableStateOfAllProjects(DefaultProjectStateRegistry.java:142)
	at org.gradle.api.internal.project.DefaultProjectStateRegistry.withMutableStateOfAllProjects(DefaultProjectStateRegistry.java:129)
	at org.gradle.execution.DefaultBuildConfigurationActionExecuter.select(DefaultBuildConfigurationActionExecuter.java:40)
	at org.gradle.initialization.DefaultTaskExecutionPreparer.prepareForTaskExecution(DefaultTaskExecutionPreparer.java:38)
	at org.gradle.initialization.BuildOperationFiringTaskExecutionPreparer$CalculateTaskGraph.populateTaskGraph(BuildOperationFiringTaskExecutionPreparer.java:117)
	at org.gradle.initialization.BuildOperationFiringTaskExecutionPreparer$CalculateTaskGraph.run(BuildOperationFiringTaskExecutionPreparer.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:56)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$run$1(DefaultBuildOperationExecutor.java:71)
	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.runWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:45)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:71)
	at org.gradle.initialization.BuildOperationFiringTaskExecutionPreparer.prepareForTaskExecution(BuildOperationFiringTaskExecutionPreparer.java:56)
	at org.gradle.initialization.DefaultGradleLauncher.prepareTaskExecution(DefaultGradleLauncher.java:233)
	at org.gradle.initialization.DefaultGradleLauncher.doClassicBuildStages(DefaultGradleLauncher.java:167)
	at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:148)
	at org.gradle.initialization.DefaultGradleLauncher.executeTasks(DefaultGradleLauncher.java:124)
	at org.gradle.internal.invocation.GradleBuildController$1.create(GradleBuildController.java:72)
	at org.gradle.internal.invocation.GradleBuildController$1.create(GradleBuildController.java:67)
	at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:203)
	at org.gradle.internal.invocation.GradleBuildController.doBuild(GradleBuildController.java:67)
	at org.gradle.internal.invocation.GradleBuildController.run(GradleBuildController.java:56)
	at org.gradle.tooling.internal.provider.runner.BuildModelActionRunner.run(BuildModelActionRunner.java:56)
	at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
	at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
	at org.gradle.launcher.exec.BuildOutcomeReportingBuildActionRunner.run(BuildOutcomeReportingBuildActionRunner.java:63)
	at org.gradle.tooling.internal.provider.ValidatingBuildActionRunner.run(ValidatingBuildActionRunner.java:32)
	at org.gradle.tooling.internal.provider.FileSystemWatchingBuildActionRunner.run(FileSystemWatchingBuildActionRunner.java:77)
	at org.gradle.launcher.exec.BuildCompletionNotifyingBuildActionRunner.run(BuildCompletionNotifyingBuildActionRunner.java:41)
	at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner$3.call(RunAsBuildOperationBuildActionRunner.java:49)
	at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner$3.call(RunAsBuildOperationBuildActionRunner.java:44)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:200)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:195)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:62)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$call$2(DefaultBuildOperationExecutor.java:76)
	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.callWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:54)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:76)
	at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner.run(RunAsBuildOperationBuildActionRunner.java:44)
	at org.gradle.launcher.exec.InProcessBuildActionExecuter.lambda$execute$0(InProcessBuildActionExecuter.java:54)
	at org.gradle.composite.internal.DefaultRootBuildState.run(DefaultRootBuildState.java:86)
	at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:53)
	at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:29)
	at org.gradle.launcher.exec.BuildTreeScopeLifecycleBuildActionExecuter.lambda$execute$0(BuildTreeScopeLifecycleBuildActionExecuter.java:33)
	at org.gradle.internal.buildtree.BuildTreeState.run(BuildTreeState.java:49)
	at org.gradle.launcher.exec.BuildTreeScopeLifecycleBuildActionExecuter.execute(BuildTreeScopeLifecycleBuildActionExecuter.java:32)
	at org.gradle.launcher.exec.BuildTreeScopeLifecycleBuildActionExecuter.execute(BuildTreeScopeLifecycleBuildActionExecuter.java:27)
	at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:104)
	at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:55)
	at org.gradle.tooling.internal.provider.SubscribableBuildActionExecuter.execute(SubscribableBuildActionExecuter.java:64)
	at org.gradle.tooling.internal.provider.SubscribableBuildActionExecuter.execute(SubscribableBuildActionExecuter.java:37)
	at org.gradle.tooling.internal.provider.SessionScopeLifecycleBuildActionExecuter.lambda$execute$0(SessionScopeLifecycleBuildActionExecuter.java:54)
	at org.gradle.internal.session.BuildSessionState.run(BuildSessionState.java:67)
	at org.gradle.tooling.internal.provider.SessionScopeLifecycleBuildActionExecuter.execute(SessionScopeLifecycleBuildActionExecuter.java:50)
	at org.gradle.tooling.internal.provider.SessionScopeLifecycleBuildActionExecuter.execute(SessionScopeLifecycleBuildActionExecuter.java:36)
	at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:36)
	at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:25)
	at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:59)
	at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:31)
	at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:55)
	at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:41)
	at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:47)
	at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:31)
	at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:65)
	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:39)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:29)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:35)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:78)
	at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:75)
	at org.gradle.util.Swapper.swap(Swapper.java:38)
	at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:75)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:55)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:63)
	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:84)
	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:52)
	at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:297)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
Caused by: org.gradle.api.artifacts.ResolveException: Could not resolve all dependencies for configuration ':binary:debugCompileClasspath'.
	at org.gradle.api.internal.artifacts.ivyservice.ErrorHandlingConfigurationResolver.wrapException(ErrorHandlingConfigurationResolver.java:104)
	at org.gradle.api.internal.artifacts.ivyservice.ErrorHandlingConfigurationResolver.resolveBuildDependencies(ErrorHandlingConfigurationResolver.java:65)
	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.lambda$resolveGraphForBuildDependenciesIfRequired$6(DefaultConfiguration.java:809)
	at org.gradle.api.internal.project.DefaultProjectStateRegistry$CalculatedModelValueImpl.update(DefaultProjectStateRegistry.java:376)
	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.resolveGraphForBuildDependenciesIfRequired(DefaultConfiguration.java:805)
	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.access$1800(DefaultConfiguration.java:148)
	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$SelectedArtifactsProvider.getTaskDependencyValue(DefaultConfiguration.java:1296)
	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$SelectedArtifactsProvider.getTaskDependencyValue(DefaultConfiguration.java:1292)
	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$ConfigurationFileCollection.visitDependencies(DefaultConfiguration.java:1335)
	at org.gradle.api.internal.tasks.CachingTaskDependencyResolveContext$TaskGraphImpl.getNodeValues(CachingTaskDependencyResolveContext.java:114)
	at org.gradle.internal.graph.CachingDirectedGraphWalker$GraphWithEmptyEdges.getNodeValues(CachingDirectedGraphWalker.java:213)
	at org.gradle.internal.graph.CachingDirectedGraphWalker.doSearch(CachingDirectedGraphWalker.java:121)
	at org.gradle.internal.graph.CachingDirectedGraphWalker.findValues(CachingDirectedGraphWalker.java:73)
	at org.gradle.api.internal.tasks.CachingTaskDependencyResolveContext.getDependencies(CachingTaskDependencyResolveContext.java:69)
	... 115 more
Caused by: org.gradle.api.ProjectConfigurationException: A problem occurred configuring project ':feature:home:api'.
	at org.gradle.configuration.project.LifecycleProjectEvaluator.wrapException(LifecycleProjectEvaluator.java:75)
	at org.gradle.configuration.project.LifecycleProjectEvaluator.addConfigurationFailure(LifecycleProjectEvaluator.java:68)
	at org.gradle.configuration.project.LifecycleProjectEvaluator.access$400(LifecycleProjectEvaluator.java:51)
	at org.gradle.configuration.project.LifecycleProjectEvaluator$EvaluateProject.lambda$run$0(LifecycleProjectEvaluator.java:102)
	at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.lambda$applyToMutableState$0(DefaultProjectStateRegistry.java:264)
	at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.fromMutableState(DefaultProjectStateRegistry.java:281)
	at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.applyToMutableState(DefaultProjectStateRegistry.java:263)
	at org.gradle.configuration.project.LifecycleProjectEvaluator$EvaluateProject.run(LifecycleProjectEvaluator.java:91)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:56)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$run$1(DefaultBuildOperationExecutor.java:71)
	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.runWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:45)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:71)
	at org.gradle.configuration.project.LifecycleProjectEvaluator.evaluate(LifecycleProjectEvaluator.java:63)
	at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:715)
	at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:145)
	at org.gradle.api.internal.project.ConfigurationOnDemandProjectAccessListener.evaluateProjectAndDiscoverTasks(ConfigurationOnDemandProjectAccessListener.java:34)
	at org.gradle.api.internal.project.ConfigurationOnDemandProjectAccessListener.beforeResolvingProjectDependency(ConfigurationOnDemandProjectAccessListener.java:30)
	at org.gradle.internal.service.scopes.BuildScopeServices$1.beforeResolvingProjectDependency(BuildScopeServices.java:226)
	at org.gradle.api.internal.artifacts.dependencies.DefaultProjectDependency.beforeResolved(DefaultProjectDependency.java:124)
	at org.gradle.api.internal.artifacts.ivyservice.moduleconverter.dependencies.ProjectIvyDependencyDescriptorFactory.createDependencyDescriptor(ProjectIvyDependencyDescriptorFactory.java:43)
	at org.gradle.api.internal.artifacts.ivyservice.moduleconverter.dependencies.DefaultDependencyDescriptorFactory.createDependencyDescriptor(DefaultDependencyDescriptorFactory.java:47)
	at org.gradle.api.internal.artifacts.ivyservice.moduleconverter.dependencies.DefaultLocalConfigurationMetadataBuilder.addDependencies(DefaultLocalConfigurationMetadataBuilder.java:58)
	at org.gradle.api.internal.artifacts.ivyservice.moduleconverter.dependencies.DefaultLocalConfigurationMetadataBuilder.addDependenciesAndExcludes(DefaultLocalConfigurationMetadataBuilder.java:48)
	at org.gradle.internal.component.local.model.DefaultLocalComponentMetadata$DefaultLocalConfigurationMetadata.realizeDependencies(DefaultLocalComponentMetadata.java:535)
	at org.gradle.internal.component.local.model.DefaultLocalComponentMetadata$DefaultLocalConfigurationMetadata.addDefinedExcludes(DefaultLocalComponentMetadata.java:482)
	at org.gradle.internal.component.local.model.DefaultLocalComponentMetadata$DefaultLocalConfigurationMetadata.getExcludes(DefaultLocalComponentMetadata.java:473)
	at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.NodeState.computeNodeExclusions(NodeState.java:690)
	at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.NodeState.computeModuleResolutionFilter(NodeState.java:680)
	at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.NodeState.visitOutgoingDependencies(NodeState.java:253)
	at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.DependencyGraphBuilder.traverseGraph(DependencyGraphBuilder.java:183)
	at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.DependencyGraphBuilder.resolve(DependencyGraphBuilder.java:145)
	at org.gradle.api.internal.artifacts.ivyservice.resolveengine.DefaultArtifactDependencyResolver.resolve(DefaultArtifactDependencyResolver.java:145)
	at org.gradle.api.internal.artifacts.ivyservice.DefaultConfigurationResolver.resolveBuildDependencies(DefaultConfigurationResolver.java:136)
	at org.gradle.api.internal.artifacts.ivyservice.ShortCircuitEmptyConfigurationResolver.resolveBuildDependencies(ShortCircuitEmptyConfigurationResolver.java:76)
	at org.gradle.api.internal.artifacts.ivyservice.ErrorHandlingConfigurationResolver.resolveBuildDependencies(ErrorHandlingConfigurationResolver.java:63)
	... 127 more
Caused by: java.lang.IllegalArgumentException: org.gradle.api.internal.initialization.DefaultClassLoaderScope@275cba33 must be locked before it can be used to compute a classpath!
	at org.gradle.kotlin.dsl.provider.KotlinScriptClassPathProvider.exportClassPathFromHierarchyOf(KotlinScriptClassPathProvider.kt:151)
	at org.gradle.kotlin.dsl.provider.KotlinScriptClassPathProvider.computeCompilationClassPath(KotlinScriptClassPathProvider.kt:147)
	at org.gradle.kotlin.dsl.provider.KotlinScriptClassPathProvider.access$computeCompilationClassPath(KotlinScriptClassPathProvider.kt:95)
	at org.gradle.kotlin.dsl.provider.KotlinScriptClassPathProvider$compilationClassPathOf$1.invoke(KotlinScriptClassPathProvider.kt:143)
	at org.gradle.kotlin.dsl.provider.KotlinScriptClassPathProvider$compilationClassPathOf$1.invoke(KotlinScriptClassPathProvider.kt:95)
	at org.gradle.kotlin.dsl.provider.KotlinScriptClassPathProviderKt$sam$java_util_function_Function$0.apply(KotlinScriptClassPathProvider.kt)
	at org.gradle.kotlin.dsl.provider.KotlinScriptClassPathProvider.compilationClassPathOf(KotlinScriptClassPathProvider.kt:143)
	at org.gradle.kotlin.dsl.provider.StandardKotlinScriptEvaluator$InterpreterHost.compilationClassPathOf(KotlinScriptEvaluator.kt:265)
	at org.gradle.kotlin.dsl.execution.Interpreter.emitSpecializedProgramFor(Interpreter.kt:260)
	at org.gradle.kotlin.dsl.execution.Interpreter.eval(Interpreter.kt:183)
	at org.gradle.kotlin.dsl.provider.StandardKotlinScriptEvaluator.evaluate(KotlinScriptEvaluator.kt:124)
	at org.gradle.kotlin.dsl.provider.KotlinScriptPluginFactory$create$1.invoke(KotlinScriptPluginFactory.kt:51)
	at org.gradle.kotlin.dsl.provider.KotlinScriptPluginFactory$create$1.invoke(KotlinScriptPluginFactory.kt:36)
	at org.gradle.kotlin.dsl.provider.KotlinScriptPlugin.apply(KotlinScriptPlugin.kt:34)
	at org.gradle.configuration.BuildOperationScriptPlugin$1.run(BuildOperationScriptPlugin.java:65)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:56)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$run$1(DefaultBuildOperationExecutor.java:71)
	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.runWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:45)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:71)
	at org.gradle.configuration.BuildOperationScriptPlugin.lambda$apply$0(BuildOperationScriptPlugin.java:62)
	at org.gradle.configuration.internal.DefaultUserCodeApplicationContext.apply(DefaultUserCodeApplicationContext.java:43)
	at org.gradle.configuration.BuildOperationScriptPlugin.apply(BuildOperationScriptPlugin.java:62)
	at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.lambda$applyToMutableState$0(DefaultProjectStateRegistry.java:264)
	at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.fromMutableState(DefaultProjectStateRegistry.java:281)
	at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.applyToMutableState(DefaultProjectStateRegistry.java:263)
	at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:42)
	at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:26)
	at org.gradle.configuration.project.ConfigureActionsProjectEvaluator.evaluate(ConfigureActionsProjectEvaluator.java:35)
	at org.gradle.configuration.project.LifecycleProjectEvaluator$EvaluateProject.lambda$run$0(LifecycleProjectEvaluator.java:100)
	... 164 more

Build performance impact

Hi people,

I'm closely watching your progress and I like things. The only thing that stops me for trying it an overview report on the performance or build cache impact.

Do you plan something like this?

Optimize configuration time

Configuration takes a lot of time with forma.
Probably it happens because of a lot of transformations like Kotlin map or filter in deps.
Kotlin map creates ArrayList with 10 capacity under the hood. flatmap creates new ArrayList.

New navigation system

Our sample uses Jetpack Navigation. It brought some strong dependencies through whole project, such as

HomeFragment.kt
...
val navController = viewBinding.bottomNavigation.setupWithNavController(
            navGraphIds = navGraphIds,
            fragmentManager = childFragmentManager,
            containerId = R.id.nav_host_container,
            intent = requireActivity().intent
        )

or codegen into

CharactersListFragment.kt
...
is CharactersListViewEvent.OpenCharacterDetail ->
                findNavController().navigate(
                    CharactersListFragmentDirections
                        .actionCharactersListFragmentToCharacterDetailFragment(viewEvent.id))

It's not good decision without scalable points for projects "under Forma". And we think that will be good have some abstraction navigation layer, which will protect project structure, architecture from navigation tools dependencies, especially codegen from Navigation component.

That's why need to create own navigation system, which will be use by app presentation layer. May be after, we will think about additional navigation targets for Forma.
See here, some mind ideas how it may be look
navigation

Manifest generation brakes autocomplete in Android Studio

With manifest generation feature enabled autocomplete and auto import for packege.R and package.viewbinding.databinding doest work. Android Studio detect it as error, but it still compiled correctly. Also it start work if you create manifest file in main source set with same package like in build.gradle.kts file and keep manifest generation turned on.

Currently we have similar problem in view binding target: we need to manually import our viewbinding, but unless to Manifest generation, autocomplete works correctly for binding fields (it doest work for R in manifest generation)
photo_2021-03-30_11-25-34

Implement android_library module type

android_library - java variant, kt_android_library - kotlin variant
Limitations:

only NamedDependencies, res and utils dependencies allowed
the name should end with -library

Add support for vector drawable support library

We have to add ability to enable support vector drawables library. We can do it by default for minds <= 24 or we can pass it in FormaConfiguration. Also we can combine both solutions and add it to FormaConfiguration and enable by default if misSdk <= 24

No application changes occur when updating code / layout

Я делал небольшой пример приложения с несколькими модулями.
https://github.com/tequilaonelove/forma-sample.git
Столкнулся с какой-то странной проблемой.

При обновлении кода или макета, изменений в приложении не происходит. Например если внести какие-либо изменения в layout/activity_main.xml, например если убрать кнопку или поменять ей текст, то при последующем запуске на реальном устройстве Run app (Shift+F10) , - не происходит никаких изменений.

Чтобы произошли эти самые изменения, необходимо предварительно очистить весь кеш Clean Project и заново "сбилдить" проект.

Это занимает достаточно большое время, для такого маленького изменения. Я оставил ссылку на репозиторий, где существует эта проблема, чтобы можно было её воспроизвести.

Перезагрузка Android Studio и Invalidate Caches не помогает.. Где-то я ошибся или что-то упустил..?

Domain logic bug in the models

Current client has some overhead solution for created domain models.
There're CharacterDetail, CharacterItem, CharacterFavorite and all kind of this types has same structure

class [no matter] {
    val id: Long,
    val name: String,
    val description: String,
    val imageUrl: String
}

It happens, when developers doesn't use OOP concepts for created new types or not takes ready domain logic from backend.
For our sample, we need do more clearly models structure, cause it may be sensitive for semantic Forma targets, especially for dependencies.

Necessary, to hold only unique domain models and removed others.
For example, will remain:

  1. All structures for marvel service
  2. Character - as single a entity for our main domain logic
  3. CharacterDetail - as a extension for ICharacter api, cause we need to show relation between models into several :api targets
  4. CharacterItem- need to removed. Instead use Character as original type for list logic
  5. CharacterFavorite - redundant type, need to remove. For saving to database, just use same DTO class, but only on data layer.

Result: Need to get more clearly logic and dependencies between feature targets.

Implement Manifest template support for targets with packageName attribute

Right now packageName we define in build config and package in the manifest is just duplicated.
So what we need is create a universal manifest file, smth like:

<?xml version="1.0" encoding="utf-8"?>
<manifest package="${packageName}"/>

And make sure the generation of this file is automated for every new target, or even better - use a symlink(or some other approach) to a single file for all targets which need manifest. So having AndroidManisest in every target will become obsolete

We can figure out manifest extensions for Activities later. (Like merge universal template with additional provided manifest file)

Client config providing

Now api urls are located directly in NetworkModule, in: core: network: library

 Retrofit.Builder()
            .baseUrl("https://gateway.marvel.com/")
            .addConverterFactory(GsonConverterFactory.create())
            .build()

Necessary to make configs for sample application for putting url, api versions and other transport information there. After pass these configs to component modules, like : core: network: library

Move feature models from :databinding target to :api target

characters:list:databinding has some domain models. It was made as a first concept, during moving all relations sources with databinding library.
And now, we're ready to move out this domain sources from characters:list:databinding target into characters:list:api .

Just do that ;)

(See ready solution into :characters:favorite:api)

Extract `tools.forma.deps` plugin

  • Extract deps to separate module
  • Create publish configuration
  • Create set of Public API's(#67)
  • Setup CI publish trigger for tag deps-v*
  • Write docs

implement res module type

Limitations:

  • code not allowed
  • dependencies not allowed
  • the name should end with -res
  • all resource types can't be in one module, resource type allowed per module:
    string,
    layout, // includes menu
    drawable, //includes anim
    style, //includes color, dimen, font
    num, //includes bool, integer
    other //includes xml

not final

Create hybrid targets example

Using symlinks - design simplified targets structure, api/impl/stub in the same folder
Design flat directories structure to ease navigation and interactions with multiple modules

Implement targets deps API's

Currently Forma supports dependencies in form of String's and projects.
However, project function name does not correspond to internal Forma terminology as well as using Gradle API's directly which should be minimized.

Solution here is to design and implement target(...) function to replace project.

Options:

  1. Keep Gradle projects notation :parent:sub:project
  2. Replace with Bazel-like notation \parent\sub\project
  3. Support both, possibly with flags to favor one over another

Add transitiveDeps extension

For uniform typing add transitiveDeps like with deps

val String.transitiveDep: NamedDependency get() = transitiveDeps(this)

image

This will help maintain consistency in the declaration of libraries.

Support ViewBinding

Now we have support of dataBinding (contains viewBinding). We can't use Kotlin synthetic in deferent modules and it is deprecated since Kotlin 1.4.20. Need to add support of viewBinding

Implementation 'api' module type

api() - java variant type, kt_api() - kotlin variant.
This type only for modules with API (abstract classes and interfaces)

Limitations

  • Unit, Android tests not available
  • Project dependencies not allowed
  • Name should end with '-api'

Support build types

Necessary to support build types configurations for debug/release apk's.

Main steps:

  • POC DSL Forma build types
  • Build Types supporting
  • Proguards routines
  • Signing configs
  • Build Fields

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.