aws / aws-sam-cli

CLI tool to build, test, debug, and deploy Serverless applications using AWS SAM
https://aws.amazon.com/serverless/sam/
Apache License 2.0
6.51k stars 1.17k forks source link

Are Gradle Modules Supported? #3227

Open oharaandrew314 opened 3 years ago

oharaandrew314 commented 3 years ago

I want to package and deploy a specific gradle module in my repo. The folder structure is roughly like:

core
|  build.gradle
server
|  build.gradle
lambdas
|  build.gradle
build.gradle
lambdas.yml
settings.gradle
gradlew
gradlew.bat
gradle
|  wrapper

My lambdas.yml is roughly like:

...

Resources:
  LambdaHandler:
    Type: AWS::Serverless::Function
    Properties:
      Runtime: java11
      CodeUri: .
      Handler: com.company.service.LambdaClass
      ...

...

But when I build with the SAM CLI: sam build --template-file lambdas.yml I get a deployment package containting only the top-level gradle dependencies, and none of my own code.

I have tried various different options, such as moving the SAM template to the lambdas module, changing the CodeUri in the SAM template, and adding --base-dir lambdas to the build command, but they all result in various error messages about how it can't find the gradle wrapper.

Is there any way to easily support a multi-module gradle project? I can't just add the gradle wrapper to the lambdas dir, because then it's no longer multi-module.

awood45 commented 3 years ago

Can you explain a little more about what you're trying to do? Is the intention to vendor some dependencies shared across different CodeUris for different handlers? Is this all for one handler?

awood45 commented 3 years ago

I ask because the standard structure we've designed around would have build.gradle, gradle, gradlew, and gradlew.bat together in a folder like lambdas in your example with a src folder within.

See sam init with java11 and gradle options selected. I want to understand what you're trying to do where that model doesn't fit to figure out the best way forward.

oharaandrew314 commented 3 years ago

So the architecture you're describing sounds like it would have a self-contained gradle project and wrapper in each folder. I was hoping to have a single multi-module gradle project, where there's a gradle wrapper at the repo's root, and multiple gradle modules within. The modules would be like:

I wanted to do this in a multi-module fashion to share the core code into my lambda without inheriting the heavy dependencies of server. I wanted SAM to deploy the artifact generated by the lambdas module, but it would only deploy the root module, which was empty; I couldn't just make lambdas its own self-contained gradle project with its own wrapper, because it wouldn't be able to share code with core.

Having said all this, I was able to bypass the issue by making my lambdas module into its own self-contained gradle project in its own repo; I duplicated the code I wanted to share from core. I'm not saying the architecture I was hoping for is a very common or important one to support, but hopefully I've explained it well enough for you to see why someone might want to do it that way. I understand if you don't think it's important enough to support, but if there's a simple workaround I could have used to make it work, then great.

awood45 commented 3 years ago

Totally understood, I'm just not a Gradle expert personally so wanted to understand what you were going for in more detail.

It does sound like a variation of vendoring a dependency. For example, if you were able to depend on the code within core as a dependency package for server and lambdas cleanly, does that get you to the same goal of reducing code duplication?

oharaandrew314 commented 3 years ago

Yeah, that would get me what I was hoping for.

On Wed., Sep. 1, 2021, 6:19 p.m. Alex Wood, @.***> wrote:

Totally understood, I'm just not a Gradle expert personally so wanted to understand what you were going for in more detail.

It does sound like a variation of vendoring a dependency. For example, if you were able to depend on the code within core as a dependency package for server and lambdas cleanly, does that get you to the same goal of reducing code duplication?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/aws/aws-sam-cli/issues/3227#issuecomment-910830467, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAG2JSGUECI4IC32XDABUOTT72RGVANCNFSM5DHIORIQ . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

salvianreynaldi commented 2 years ago

We've been using gradle multi project build for a while, too. It seems redundant to have multiple gradle builds (each with its own gradlew, gradlew.bat, gradle) in 1 git repository.

One workaround is probably to use Makefile to execute some gradle tasks and output them to .aws-sam/build, @oharaandrew314. It's still not ideal if we store 100+ lambda functions in the repo, but probably we shouldn't anyway.

salvianreynaldi commented 2 years ago

So I've used this workaround for a while template.yaml

  FunctionA:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: java-gradle
    Metadata:
      BuildMethod: makefile
  FunctionB:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: java-gradle
    Metadata:
      BuildMethod: makefile

java-gradle/MakeFile

build-FunctionA:
    ./gradlew :func-a:build
build-FunctionB:
    ./gradlew :func-b:build

Sadly, sam build cache doesn't work if 2+ functions share a CodeUri (https://github.com/aws/aws-sam-cli/issues/3099#issuecomment-1024581685). Hopefully SAM adds proper support for gradle multi project builds, with working build cache 👍

thanhj commented 2 years ago

I also have the same thinking. Supporting multiple gradle-modules would be great. Another annoying I got when using the current lambda gradle template is that I have to open 2 Intellij windows, one for editing files in root folder and another window is for the Java module, this should be solved with multiple gradle-modules as well (same for maven template). Even better, if we can introduce a new multiple gradle multiple-modules template together with a shared lib layer, something like: https://medium.com/@rostyslav.myronenko/aws-sam-for-a-serverless-java-application-505e1d58a737#b9f5

I am really looking forward for this enhancement. Or any direction/guide for doing it, I am willing to contribute.

thanhj commented 2 years ago

@salvianreynaldi do you have a sample project somewhere? I think it is the best temporary solution while waiting for the enhancement.