-
Notifications
You must be signed in to change notification settings - Fork 179
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat/support gradle root deps #116
Changes from all commits
97c7315
5b73fa4
15f5af5
1030bd6
60818b4
db5b36b
bffa8df
748f307
0583626
7ef81e0
99a9552
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -56,16 +56,25 @@ func (builder *GradleBuilder) Analyze(m module.Module, allowUnresolved bool) ([] | |
gradleLogger.Debugf("Running Gradle analysis: %#v %#v in %s", m, allowUnresolved, m.Dir) | ||
|
||
moduleConfigurationKey := strings.Split(m.Name, ":") | ||
|
||
taskName := "dependencies" // defaults to root gradle dependencies task | ||
|
||
if moduleConfigurationKey[0] != "" { | ||
// a subtask was configured | ||
taskName = moduleConfigurationKey[0] + ":dependencies" | ||
} | ||
|
||
taskConfiguration := "compile" | ||
taskName := moduleConfigurationKey[0] | ||
if len(moduleConfigurationKey) == 2 { | ||
if len(moduleConfigurationKey) == 2 && moduleConfigurationKey[1] != "" { | ||
taskConfiguration = moduleConfigurationKey[1] | ||
} | ||
|
||
// TODO: We need to let the user configure the right configurations | ||
// NOTE: we are intentionally using exec.Command over runLogged here, due to path issues with defining cmd.Dir | ||
// TODO: set TERM=dumb | ||
dependenciesOutput, err := exec.Command(builder.GradleCmd, taskName+":dependencies", "-q", "--configuration="+taskConfiguration, "--offline", "-a").Output() | ||
dependenciesCmd := exec.Command(builder.GradleCmd, taskName, "-q", "--configuration="+taskConfiguration, "--offline", "-a") | ||
dependenciesCmd.Env = os.Environ() | ||
dependenciesCmd.Env = append(dependenciesCmd.Env, "TERM=dumb") | ||
|
||
dependenciesOutput, err := dependenciesCmd.Output() | ||
if len(dependenciesOutput) == 0 || err != nil { | ||
return nil, fmt.Errorf("could not run Gradle task %s:dependencies", taskName) | ||
} | ||
|
@@ -139,10 +148,21 @@ func (builder *GradleBuilder) DiscoverModules(dir string) ([]module.Config, erro | |
} | ||
} | ||
|
||
return moduleConfigurations, nil | ||
if len(moduleConfigurations) > 0 { | ||
return moduleConfigurations, nil | ||
} | ||
|
||
// If task list succeeds but returns no subproject dependencies tasks, fall back to the root `dependencies` task | ||
return []module.Config{ | ||
{ | ||
Name: ":compile", | ||
Path: "build.gradle", | ||
Type: "gradle", | ||
}, | ||
}, nil | ||
} | ||
|
||
// Fall back to "app" as default task, even though technically it would be "" (root) | ||
// If task list fails, fall back to "app" as default task, even though technically it would be "" (root) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this behaviour correct? Should we expect There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm 50/50 on having this fallback vs erroring if
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the question is whether I don't have much experience with the Gradle ecosystem, so I trust your intention on this. |
||
return []module.Config{ | ||
{ | ||
Name: "app:compile", | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,24 +11,101 @@ Gradle support in FOSSA CLI depends on the following tools existing in your envi | |
|
||
### Automatic Configuration | ||
|
||
When running `fossa init`, FOSSA will look for a root Gradle build (`build.gradle`) and interrogate it for build-able tasks. From there, it will write module configurations into your `.fossa.yml` for every task that supports a `:dependency` sub-task. | ||
`fossa init` will attempt a "best-effort" strategy to look through all available Gradle tasks/configurations and elect the most likely ones used for a production build. | ||
|
||
1. Look for a root Gradle build (`build.gradle`) | ||
2. Run and parse the output of `gradle tasks --all -q -a --offline` to find all available sub-tasks that support a `:dependencies` command | ||
3. If task list succeeds but no sub-tasks are available, fallback to the root `dependencies` task in `build.gradle` | ||
4. Filter out any suspicious-looking tasks (i.e. labeled `test` or `testCompile`) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should really mention that there's a flag to disable this. |
||
5. Write tasks to configuration (`fossa.yml`) | ||
|
||
If a gradle wrapper was provided in the same directory (`./gradlew`), `fossa` will prefer to use that over the local `gradle` binary. | ||
|
||
### Manual Configuration | ||
|
||
Add a `gradle` module with the path to the `pom.xml` in your project. | ||
`fossa init` will automatically generate this configuration for you, but if you'd like to manually configure, add a `gradle` module to your `fossa.yml`: | ||
|
||
```yaml | ||
analyze: | ||
modules: | ||
- name: {task}:{configuration} | ||
path: {path-to-build.gradle} | ||
type: gradle | ||
``` | ||
|
||
For Gradle modules, `fossa` requires a few peices of information to run dependency analysis: | ||
|
||
- `task` - the name of the task/subtask used to generate your build (most often this is `app` or empty string `''` for root) | ||
- `configuration` - the configuration your task runs during a production build (if undefined, defaults to `compile`) | ||
- `path` - path to your `*.gradle` build file relative to your repo root directory (usually this is just `build.gradle`) | ||
|
||
If you don't specify a task, `fossa` will run the default `dependencies` located in your root `*.gradle` file: | ||
|
||
```yaml | ||
analyze: | ||
modules: | ||
- name: :compile # runs the root `dependencies` task with `compile` configuration | ||
path: build.gradle | ||
type: gradle | ||
``` | ||
|
||
You can customize your configuration by modifying the `name` entry using the template `{task}:{configuration}`. | ||
|
||
```yaml | ||
analyze: | ||
modules: | ||
- name: app:runtime # runs `app:dependencies` task with `runtime` configuration | ||
path: build.gradle | ||
type: gradle | ||
``` | ||
|
||
NOTE: If you don't specify a configuration at all, `fossa` will default to `compile`. For example: | ||
|
||
```yaml | ||
analyze: | ||
modules: | ||
- name: your-mvn-project | ||
path: pom.xml | ||
type: mvn | ||
- name: app # runs `app:dependencies` task with `compile` configuration | ||
path: build.gradle | ||
type: gradle | ||
- name: '' # empty - runs root `dependencies` task with `compile` configuration | ||
path: build.gradle | ||
type: gradle | ||
``` | ||
|
||
## Design | ||
NOTE: While `app` and `compile` are two very common tasks/configurations, your Gradle build may be different. For instance, many Gradle builds may use the configuration `release` or `default` instead of `compile`. See the `Troubleshooting` section below for steps in figuring out the right configuration for you. | ||
|
||
## Troubleshooting | ||
Since `fossa` operates directly on Gradle, it requires your build environment to be satisfied and Gradle tasks to reliably succeed before `fossa` can run. | ||
|
||
Most issues are often fixed by simply verifying that your Gradle build succeeds. | ||
|
||
### Errors during `fossa init` | ||
FOSSA's autoconfiguration depends on `gradle tasks --all`. If `fossa init` is failing to discover the right tasks/configuration, make sure: | ||
|
||
1. `gradle tasks --all` succeeds in your environment | ||
2. Your `path` entry in `fossa.yml` is points to the right `*.gradle` file | ||
|
||
### Issues with dependency data | ||
|
||
If you're having trouble getting correct dependency data, try verifying the following: | ||
|
||
1. Your configuration and task name is valid (i.e. `app:compile` vs `customTask:customConfiguration`) in `fossa.yml` | ||
2. You get the desired output from your configured dependencies task `gradle {subtask}:dependencies --configuration={configuration}` (i.e. `gradle app:dependencies --configuration=compile`) | ||
|
||
If running the gradle command in your terminal does not succeed that means your gradle build is not properly configured. | ||
|
||
If it does succeed but produces unexpected or empty output, it means you have likely selected the wrong task or configuration for `fossa` to analyze. Running without the `--configuration` will give you the full output and help you find the right configuration to select. | ||
|
||
### Reporting issues | ||
|
||
If you're still having problems, open up an issue on this repo with the full logs/output of `fossa -o --debug` and your `fossa.yml` file. | ||
|
||
Optionally, provide your `build.gradle` for more context. | ||
|
||
## Roadmap | ||
|
||
### Analysis | ||
If you'd like to help us improve our Gradle integration, please feel free to file and assign yourself to an issue on this repo. | ||
|
||
Analysis will support any tasks you can run `:dependendencies` on with the "compile" configuration. This is equivalent to `gradle app:dependencies --configuration=compile`. | ||
1. Support multiple independent "root" Gradle builds that may be segregated in a codebase | ||
2. Implement a cheap build validation method to tell the user whether a Gradle build is satisfied without invoking a Gradle runtime | ||
3. Support multiple configurations for a single module definition i.e. `app:compile:runtime` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the issue described in this comment?