Skip to main content
MCReleaser provides powerful file handling capabilities using glob patterns. Understanding how to select files correctly ensures your releases contain exactly what you need.

The FILES Property

The FILES environment variable (or -Dfiles property for CLI) accepts glob patterns to select which files to upload. From CLIPropertyKey.java:8:
PropertyKey FILES = new PropertyKey("files");
From CLIExecutor.java:38-40:
String fileGlobs = CLIPropertyKey.FILES.getValue();
Validate.check(fileGlobs != null, "File globs not found");
return PathUtil.getFileBundle(Paths.get("."), StringUtil.splitSpace(fileGlobs));
File globs are required. MCReleaser will fail if no files pattern is provided.

Glob Pattern Basics

Glob patterns are file path matching patterns similar to shell wildcards:
PatternMatchesExample
*Any characters except /*.jar matches mod.jar but not subdir/mod.jar
**Any characters including /**/*.jar matches all .jar files recursively
?Single charactermod-?.jar matches mod-1.jar
[abc]One character from setmod-[123].jar matches mod-1.jar, mod-2.jar
{a,b}Alternatives*.{jar,zip} matches both .jar and .zip files

Primary vs Secondary Files

MCReleaser distinguishes between primary and secondary files:
  • Primary file: The main artifact (e.g., your mod JAR)
  • Secondary files: Additional files (e.g., sources, javadocs, dependencies)
From FileBundle.java:7-14:
public record FileBundle(File primaryFile, List<File> secondaryFiles) {
    public List<File> allFiles() {
        List<File> files = new ArrayList<>();
        files.add(primaryFile);
        files.addAll(secondaryFiles);
        return files;
    }
}

How Files Are Selected

From PathUtil.java:54-69:
for (String glob : fileGlobs) {
    PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:" + glob);
    if (primaryMatcher == null) {
        primaryMatcher = matcher;  // First glob is primary
    } else {
        secondaryMatchers.add(matcher);  // Subsequent globs are secondary
    }
}
1

First Glob Pattern

The first glob pattern selects the primary file. If multiple files match, the most recent one is chosen.
2

Additional Glob Patterns

Any additional glob patterns select secondary files (all matches are included).
3

Space-Separated

Multiple patterns are separated by spaces in the FILES property.

Common File Selection Patterns

Single JAR File

Select a single JAR file from the build directory:
java \
  -Dfiles="build/libs/*.jar" \
  # ... other properties
  -jar mcreleaser.jar

Exclude Specific Files

Select JAR files but exclude sources and javadocs:
java \
  -Dfiles="build/libs/*-[0-9]*.jar" \
  # ... other properties
  -jar mcreleaser.jar
The pattern *-[0-9]*.jar matches files like mod-1.0.0.jar but excludes mod-1.0.0-sources.jar and mod-1.0.0-javadoc.jar.

Primary JAR with Sources

Upload the main JAR as primary and sources as secondary:
java \
  -Dfiles="build/libs/*-[0-9]*.jar build/libs/*-sources.jar" \
  # ... other properties
  -jar mcreleaser.jar
This will:
  1. Use *-[0-9]*.jar to find the primary file (e.g., mod-1.0.0.jar)
  2. Use *-sources.jar to find secondary files (e.g., mod-1.0.0-sources.jar)

Multiple File Types

Include JARs and ZIP files:
java \
  -Dfiles="build/libs/*.jar build/distributions/*.zip" \
  # ... other properties
  -jar mcreleaser.jar
Find files in nested directories:
java \
  -Dfiles="**/build/libs/*.jar" \
  # ... other properties
  -jar mcreleaser.jar
The ** pattern searches recursively through all subdirectories.

Practical Examples

Gradle Multi-Module Project

For a multi-module Gradle project with Fabric and Forge subprojects:
java \
  -Dfiles="fabric/build/libs/*-[0-9]*.jar forge/build/libs/*-[0-9]*.jar" \
  # ... other properties
  -jar mcreleaser.jar
This selects:
  • Primary: First matching JAR from fabric/build/libs/
  • Secondary: All matching JARs from forge/build/libs/

Maven Project

For a Maven project with target directory:
java \
  -Dfiles="target/*-[0-9]*.jar" \
  # ... other properties
  -jar mcreleaser.jar

Shadow JAR Only

If you build both regular and shadow (fat) JARs:
java \
  -Dfiles="build/libs/*-all.jar" \
  # ... other properties
  -jar mcreleaser.jar
Or:
java \
  -Dfiles="build/libs/*-shadow.jar" \
  # ... other properties
  -jar mcreleaser.jar

Complete Build Artifacts

Upload main JAR, sources, and javadocs:
java \
  -Dfiles="build/libs/*-[0-9]*.jar build/libs/*-sources.jar build/libs/*-javadoc.jar" \
  # ... other properties
  -jar mcreleaser.jar

File Selection Algorithm

Here’s how MCReleaser selects files (from PathUtil.java:18-52):
1

Walk Directory Tree

Starting from the current directory (.), MCReleaser walks through all files
2

Match Against Primary Pattern

For each file, check if it matches the primary glob pattern
3

Select Most Recent Primary

If multiple files match the primary pattern, the most recent (by modified time) is chosen
4

Match Against Secondary Patterns

All files matching secondary patterns are added to the secondary file list
5

Validate Primary File Exists

MCReleaser fails if no primary file is found
From PathUtil.java:29-35:
if (primaryFileMatcher.matches(relativePath)) {
    if (primaryFileRef.get() == null || !secondaryFileMatcher.isEmpty()) {
        primaryFileRef.set(file);
    } else {
        secondaryFiles.add(file);
    }
}
Files are sorted in reverse order before matching, ensuring the most recent file is selected as primary.

Docker and Environment Variables

When using Docker, file patterns work the same way:
docker run \
  -v $(pwd)/build:/workspace/build \
  -e FILES="build/libs/*.jar" \
  -e NAME="My Mod" \
  # ... other environment variables
  ghcr.io/hsgamer/mcreleaser:master
Mount your build directory into the container so MCReleaser can access the files.

CI/CD File Patterns

GitHub Actions

- name: Publish Release
  run: |
    java \
      -Dfiles="build/libs/*-[0-9]*.jar build/libs/*-sources.jar" \
      -Dname="${{ github.event.repository.name }}" \
      # ... other properties
      -jar mcreleaser.jar

GitLab CI

release:
  script:
    - |
      java \
        -Dfiles="build/libs/*-${CI_COMMIT_TAG}.jar" \
        -Dversion="${CI_COMMIT_TAG}" \
        # ... other properties
        -jar mcreleaser.jar

Troubleshooting

No Files Found

Problem: MCReleaser fails with “Primary file not found” Solutions:
  1. Verify the file actually exists: ls -la build/libs/
  2. Test your glob pattern: find . -name "your-pattern"
  3. Check the working directory: MCReleaser searches from . (current directory)
  4. Use absolute paths or ensure you’re in the correct directory

Wrong File Selected as Primary

Problem: Secondary file is selected as primary Solution: Ensure your first glob pattern is the most specific one for your primary file
# Bad: Sources might be selected as primary
-Dfiles="build/libs/*.jar"

# Good: Explicit primary selection
-Dfiles="build/libs/*-[0-9]*.jar build/libs/*-sources.jar"

Too Many Files Matched

Problem: Unwanted files are included Solution: Make your glob patterns more specific
# Too broad
-Dfiles="*.jar"

# More specific
-Dfiles="build/libs/mymod-*.jar"

# Very specific
-Dfiles="build/libs/mymod-[0-9].[0-9].[0-9].jar"

Advanced Patterns

Version-Specific Pattern

Match files with semantic version numbers:
java \
  -Dfiles="build/libs/*-[0-9].[0-9].[0-9].jar" \
  # ... other properties
  -jar mcreleaser.jar
Matches: mod-1.0.0.jar, mod-2.1.3.jar
Excludes: mod-sources.jar, mod-dev.jar

Platform-Specific Files

Match loader-specific builds:
java \
  -Dfiles="build/libs/*-fabric-*.jar build/libs/*-forge-*.jar" \
  # ... other properties
  -jar mcreleaser.jar

Character Class Exclusion

Exclude files with specific characters:
java \
  -Dfiles="build/libs/*-[!dev]*.jar" \
  # ... other properties
  -jar mcreleaser.jar
Excludes: mod-dev.jar
Includes: mod-1.0.0.jar, mod-release.jar

Best Practices

  1. Be Specific: Use precise patterns to avoid accidentally uploading wrong files
  2. Test Locally: Run find . -name "your-pattern" to verify your glob works
  3. Version in Filename: Include version numbers in filenames for clarity
  4. Consistent Naming: Use consistent file naming conventions across builds
  5. Exclude Build Artifacts: Don’t upload intermediate build files or non-release JARs

Next Steps

Publishing to Single Platform

Learn platform-specific publishing strategies

CI/CD Integration

Automate file uploads in your CI/CD pipeline

Build docs developers (and LLMs) love