Skip to content
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

Merged
merged 11 commits into from
Mar 21, 2018
Merged

Feat/support gradle root deps #116

merged 11 commits into from
Mar 21, 2018

Conversation

xizhao
Copy link
Contributor

@xizhao xizhao commented Mar 20, 2018

This PR adds support for Gradle projects that manage their dependencies via a root dependencies task rather than within a subtask.

Refs: #74 #114 #10

Changes

  • When fossa init does not find dependency subtasks, have it elect the root dependencies task for the name field in fossa.yml configuration (represented as an empty taskname + config :compile)
  • Support falling back to root dependency tasks when task name is unspecified in config
  • Strip ANSI from dependency output for more reliable parsing
  • Add extensive documentation + troubleshooting for our gradle integration
  • Add some configuration handling improvements

How to configure

For users that want to support root dep tasks, this should be a non-breaking change to existing config as well as provide OOTB support for new fossa init.

Options:

  1. Overwrite existing config with fossa init -O and confirm the right task/configuration in fossa.yml

OR

  1. Change your .fossa.yml file to have an empty task name; optionally specify your taskConfiguration:
analyze:
  modules:
    - name: :compile # this is valid, and will run `gradle dependencies --configuration=compile`
      path: build.gradle
      type: gradle
    - name: ''  # this is also valid, and will run `gradle dependencies --configuration=compile`
      path: build.gradle
      type: gradle

@xizhao xizhao requested a review from elldritch March 20, 2018 19:28

### Analysis
If you'd like to help us improve our Gradle integration, we have
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?


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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should probably also be tracked as issues, tagged with help wanted.

@@ -11,24 +11,103 @@ 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.
An average Gradle build, there are often hundreds of configuration paths that can influence what dependencies are included. In order to determine what tasks and configurations you care about, `fossa` will attempt a "best-effort" strategy during `fossa init` to discover the most likely configuration for a production-build scenario.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Grammar.

When running `fossa init`, FOSSA executes the following steps:

1. Look for a root Gradle build (`build.gradle`)
2. Run and parse the output of `gradle tasks --all -q -a --offline` to seek all available sub-tasks that support a `:dependencies` command
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/seek/find

@@ -11,24 +11,103 @@ 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.
An average Gradle build, there are often hundreds of configuration paths that can influence what dependencies are included. In order to determine what tasks and configurations you care about, `fossa` will attempt a "best-effort" strategy during `fossa init` to discover the most likely configuration for a production-build scenario.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is all kind of just marketing noise. I'd remove it.


- `task` - the name of the task/subtask used to generate your build (most often this is `app` or empty `` for root)
- `configuration` - the configuration your task runs during a production build (if undefined, defaults to `compile`)
- `path` - path to your `*.gradle` build file (usually this is just `build.gradle`)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Relative or absolute? Either? If relative, relative to what?

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
Copy link
Contributor

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?

if len(moduleConfigurationKey) == 2 {
if taskName != "" {
// this is not the root gradle project
taskName = taskName + ":"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Avoid mutation, it makes your intent much less clear.
  2. I'd locate this closer to where the variable is used, so it's clear that this is formatting for usage as an argument to gradle.

// this is not the root gradle project
taskName = taskName + ":"
}
if len(moduleConfigurationKey) == 2 && moduleConfigurationKey[1] != "" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this up to be next to the definition of taskConfiguration, so it's clear that your intent is to use a default value.

}

// 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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this behaviour correct? Should we expect app:compile to work even when gradle tasks fails, or should this be a fatal error?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm 50/50 on having this fallback vs erroring if gradle tasks fails, but:

  1. I believe app:compile is a sane default if a build.gradle is found
  2. Checking for a build.gradle is a valid way of identifying a module, and much simpler/more reliable then parsing output of gradle tasks

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the question is whether app:compile is likely to work. If it works, then this is great. If it doesn't work, then we've kicked a configuration error down the line into a much more obscure runtime error.

I don't have much experience with the Gradle ecosystem, so I trust your intention on this.

taskName = taskName + ":"

taskName := "dependencies" // defaults to root gradle dependencies task

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove newline (makes default-value intention clearer).

}

// 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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the question is whether app:compile is likely to work. If it works, then this is great. If it doesn't work, then we've kicked a configuration error down the line into a much more obscure runtime error.

I don't have much experience with the Gradle ecosystem, so I trust your intention on this.

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`)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should really mention that there's a flag to disable this.

@xizhao xizhao merged commit 85c1788 into master Mar 21, 2018
@elldritch elldritch deleted the feat/support-gradle-root-deps branch April 10, 2018 02:01
meghfossa pushed a commit that referenced this pull request Nov 12, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants