Skip to content

Add megatests helper#69

Merged
maxulysse merged 12 commits into
nf-core:mainfrom
maxulysse:mega-tests
May 22, 2026
Merged

Add megatests helper#69
maxulysse merged 12 commits into
nf-core:mainfrom
maxulysse:mega-tests

Conversation

@maxulysse

Copy link
Copy Markdown
Member

No description provided.

@maxulysse

Copy link
Copy Markdown
Member Author

@nf-core-bot fox linting pretty please 🙏

Comment thread nf-test.config Outdated
Co-authored-by: Maxime U Garcia <max.u.garcia@gmail.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a new file-listing helper intended for “megatests” style outputs, aiming to make filesystem snapshots work consistently across local directories and cloud URIs by leveraging Nextflow’s filesystem layer when available.

Changes:

  • Added getAllFiles() to list files under a root path with include/ignore filtering and optional directory entries, with Nextflow-aware path resolution for cloud URIs.
  • Added/updated nf-test coverage and fixtures for local file listing and an S3-based snapshot scenario, plus related nf-test/Nextflow configuration.
  • Documented the new helper and added an nf-test plugin dependency for VCF hashing in snapshots.

Reviewed changes

Copilot reviewed 12 out of 13 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
tests/nextflow.config Adds AWS client config (anonymous access) for tests.
tests/getAllFilesFromS3/main.nf.test.snap New snapshot for S3 listing + downloaded-file checksums.
tests/getAllFilesFromS3/main.nf.test Adds nf-test that lists an S3 prefix and validates snapshots.
tests/getAllFilesFromS3/main.nf Adds stub workflow for the S3 test case.
tests/getAllFiles/main.nf.test.snap New snapshot for getAllFiles() local-path behavior.
tests/getAllFiles/main.nf.test Adds nf-test exercising getAllFiles() options (ignore/include/includeDir/ignoreFile).
tests/getAllFiles/main.nf Adds workflow that generates stable/unstable outputs for listing tests.
tests/getAllFiles/.nftignore Adds ignore globs used by the new local listing test.
tests/filterNextflowOutput/main.nf.test.snap Updates snapshots for Nextflow output changes and tool versions.
tests/filterNextflowOutput/main.nf Minor formatting change in params block.
src/main/java/nf_core/nf/test/utils/Methods.java Implements getAllFiles() + Nextflow path resolution; adds S3 CLI helpers and download helper.
nf-test.config Loads nft-vcf plugin for VCF checksum functionality in tests.
docs/usage.md Documents getAllFiles() usage and options.
Comments suppressed due to low confidence (1)

src/main/java/nf_core/nf/test/utils/Methods.java:1304

  • downloadFromS3(...) waits for the aws s3 cp process without consuming stdout/stderr (and with redirectErrorStream(false)). The AWS CLI typically writes progress to stderr, which can fill the buffer and deadlock/hang the process. Prefer Utils.runProcess(...) (captures stdout/stderr) or redirect/drain streams, and include stderr in the failure exception to make CI failures diagnosable.
    List<String> cmd = new ArrayList<>(Arrays.asList("aws", "s3", "cp"));
    if (noSignRequest) {
      cmd.add("--no-sign-request");
    }
    cmd.add(s3Uri);
    cmd.add(destFile.toString());

    ProcessBuilder pb = new ProcessBuilder(cmd);
    pb.redirectErrorStream(false);
    Process process = pb.start();
    int exitCode = process.waitFor();
    if (exitCode != 0) {
      throw new IOException(
          "AWS CLI returned exit code " + exitCode + " when downloading: " + s3Uri);
    }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1024 to +1034
List<String> ignoreGlobs =
(List<String>) options.getOrDefault("ignore", new ArrayList<String>());
List<String> includeGlobs =
(List<String>) options.getOrDefault("include", Arrays.asList("**", "*"));
Boolean includeDir = (Boolean) options.getOrDefault("includeDir", false);
String ignoreFilePath = (String) options.get("ignoreFile");

List<String> allIgnoreGlobs = new ArrayList<>(ignoreGlobs);
if (ignoreFilePath != null && !ignoreFilePath.isEmpty()) {
allIgnoreGlobs.addAll(readGlobsFromFile(ignoreFilePath));
}
Comment on lines +1099 to +1105
*/
private static Path resolveNextflowPath(String pathString) {
try {
Class<?> cls = Class.forName("nextflow.file.FileHelper");
Method method = cls.getMethod("asPath", String.class);
return (Path) method.invoke(null, pathString);
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException e) {
Comment on lines +1105 to +1111
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException e) {
return Paths.get(pathString);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
throw new RuntimeException(
"Failed to resolve path '" + pathString + "': " + cause.getMessage(), cause);
}
Comment on lines +1199 to +1206
cmd.add(normalizedPath);
ProcessBuilder pb = new ProcessBuilder(cmd);
pb.redirectErrorStream(false);
Process process = pb.start();

BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
List<String> files = new ArrayList<>();
String line;
Comment on lines +1282 to +1287
// Derive a stable local destination: <tmpdir>/nft-utils-s3/<key>
String keyPart = s3Uri.substring("s3://".length()); // "bucket/path/to/file"
int firstSlash = keyPart.indexOf('/');
String relativeKey = firstSlash >= 0 ? keyPart.substring(firstSlash + 1) : keyPart;

Path destFile = Paths.get(System.getProperty("java.io.tmpdir"), "nft-utils-s3", relativeKey);
Comment on lines +977 to +986
/**
* Lists all files at the given path, returning sorted relative paths.
*
* <p>Transparently supports local paths <em>and</em> any cloud URI recognised by
* Nextflow (e.g. {@code s3://}, {@code gs://}, {@code az://}) by delegating path
* resolution to {@code nextflow.file.FileHelper.asPath()} when that class is
* available on the runtime classpath (as it is when running inside nf-test).
* Falls back to {@link java.nio.file.Paths#get} for plain local paths when
* Nextflow is not present.
*
Comment thread docs/usage.md Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This file is getting pretty big, might be worth it to split it up in a future PR

Comment thread src/main/java/nf_core/nf/test/utils/Methods.java Outdated
Comment thread src/main/java/nf_core/nf/test/utils/Methods.java Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 9 out of 11 changed files in this pull request and generated 7 comments.

Comments suppressed due to low confidence (1)

docs/usage.md:231

  • This example passes noSignRequest to downloadFromS3, but that option is currently ignored by the implementation. Removing it keeps the example aligned with actual behavior.
        path(downloadFromS3("s3://my-bucket/results/${relPath}", noSignRequest: true).toString())

Comment on lines +1197 to +1201
// Derive a stable local destination mirroring the key path: <tmpdir>/nft-utils-cloud/<key>
int schemeEnd = cloudUri.indexOf("://");
String withoutScheme = schemeEnd >= 0 ? cloudUri.substring(schemeEnd + 3) : cloudUri;
int firstSlash = withoutScheme.indexOf('/');
String relativeKey = firstSlash >= 0 ? withoutScheme.substring(firstSlash + 1) : withoutScheme;
Comment on lines +1206 to +1210
List<String> cmd = Arrays.asList("nextflow", "fs", "cp", cloudUri, destFile.toString());
ProcessBuilder pb = new ProcessBuilder(cmd);
pb.redirectErrorStream(false);
Process process = pb.start();
int exitCode = process.waitFor();
Comment on lines +1121 to +1123
ProcessBuilder pb = new ProcessBuilder(cmd);
pb.redirectErrorStream(false);
Process process = pb.start();
Comment on lines +1149 to +1152
}

int exitCode = process.waitFor();
if (exitCode != 0) {
Comment thread docs/usage.md

Downloads a single file from S3 to a temporary local directory and returns the local path. The destination mirrors the S3 key structure under a plugin-specific temp directory, so repeated calls for the same URI are idempotent.

This function requires the AWS CLI to be available on the path.
Comment thread docs/usage.md
Comment on lines +217 to +222
Supported named parameters:

| Option | Type | Default | Description |
| --------------- | --------- | ------- | --------------------------------------------------------------------- |
| `noSignRequest` | `Boolean` | `false` | Pass `--no-sign-request` to the AWS CLI for publicly readable buckets |

Comment thread docs/usage.md

```groovy
// Download a file from a public bucket
def local_file = downloadFromS3("s3://my-public-bucket/data/sample.vcf.gz", noSignRequest: true)
@maxulysse maxulysse requested a review from nvnieuwk May 22, 2026 10:52

@nvnieuwk nvnieuwk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks good! Will definitely need to be properly tested once released but I don't see any obvious issues

@maxulysse maxulysse merged commit 107f7f3 into nf-core:main May 22, 2026
10 checks passed
@maxulysse maxulysse deleted the mega-tests branch May 22, 2026 11:58
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.

3 participants