Skip to content

feat(cli): support glob patterns in .blaxelignore - #354

Open
michaelbrusegard wants to merge 1 commit into
blaxel-ai:mainfrom
michaelbrusegard:feat/blaxelignore-globs
Open

feat(cli): support glob patterns in .blaxelignore#354
michaelbrusegard wants to merge 1 commit into
blaxel-ai:mainfrom
michaelbrusegard:feat/blaxelignore-globs

Conversation

@michaelbrusegard

@michaelbrusegard michaelbrusegard commented Jul 21, 2026

Copy link
Copy Markdown

Fixes ENG-4085

Summary

  • match .blaxelignore entries with Docker's maintained pattern matcher
  • support *, ?, **, character classes, and ordered ! exclusions
  • preserve the existing behavior where unanchored literal paths match at any depth
  • compile patterns once per archive and return a clear error for invalid patterns
  • keep .env.build unconditionally excluded

This makes it practical to share one ignore policy between .dockerignore and .blaxelignore, including patterns such as **/*.test.ts and **/.env.*.

Testing

  • go test -count=1 ./...
  • go build ./...
  • golangci-lint run --new-from-rev=origin/main (0 new issues)

Lint baseline

make lint still reports 15 pre-existing findings in unrelated files on main; this change introduces none.


Note

Replaces the simple string-prefix/contains/suffix ignore-path matching with Docker's patternmatcher library, enabling glob patterns (*, **, ?, [...]) and ordered ! exclusions in .blaxelignore. Unanchored literal paths are automatically prefixed with **/ to preserve existing depth-agnostic matching behavior. .env.build is appended last to remain unconditionally excluded.

Written by Mendral for commit 53d41e8.

@mendral-app

mendral-app Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

🧪 Testing Guide

What this PR addresses

Replaces the literal string-matching logic in .blaxelignore with Docker's moby/patternmatcher library, enabling glob patterns (*, ?, **, character classes) and ordered ! exclusions. Previously, .blaxelignore only supported exact literal path segments. This PR also ensures .env.build is always excluded (appended last so it can't be negated).

Steps to reproduce the original issue

  1. Create a Blaxel project with a .blaxelignore containing glob patterns like **/*.test.ts or **/.env.*.
  2. Run a deploy (or trigger archive creation).
  3. Before this PR: those glob patterns are treated as literal path segments and won't match any files — test files and env files end up in the archive.

What to verify (expected behavior)

Unit tests:

go test -count=1 ./cli/...

All existing and new tests should pass, including:

  • TestDeploymentShouldIgnorePath — literal paths still match at any depth (backwards compat).
  • TestDeploymentShouldIgnoreGlobPatterns**/*.test.ts, **/.env.*, and ! negations work correctly.
  • TestDeploymentShouldIgnoreAnchoredLiteralPath./infra only matches at root, not nested.
  • TestNewIgnoredPathMatcherRejectsInvalidPattern — malformed patterns like [invalid return a clear error.

Behavioral checks:

  • Unanchored literal paths (e.g. node_modules) still match at any directory depth (no regression).
  • Anchored paths (./infra or /infra) only match at the project root.
  • !-prefixed patterns correctly re-include previously excluded files.
  • .env.build is always excluded regardless of ignore file contents.
  • Volume-template deployments still skip ignore logic entirely.

Build & lint:

go build ./...
golangci-lint run

Note

Posted by PR Testing Guide · Tag @mendral-app with feedback.

@mendral-app

mendral-app Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

🔀 Interaction Flow

Here's how the new glob-based ignore matching flows through the affected components:

sequenceDiagram
    participant CA as createArchive()
    participant IP as IgnoredPaths()
    participant NM as newIgnoredPathMatcher()
    participant NP as normalizeIgnorePattern()
    participant PM as moby/patternmatcher
    participant IM as ignoredPathMatcher.matches()

    CA->>IP: Load .blaxelignore patterns
    IP-->>IP: Read file, split lines, skip comments/blanks
    IP-->>IP: Append ".env.build" (unconditional)
    IP-->>CA: []string patterns

    CA->>NM: Compile patterns (root, patterns)
    loop For each pattern
        NM->>NP: normalizeIgnorePattern(pattern)
        NP-->>NP: Handle ! negation prefix
        NP-->>NP: Handle / or ./ anchor prefix
        NP-->>NP: Prepend **/ if unanchored literal
        NP-->>NM: normalized pattern
    end
    NM->>PM: patternmatcher.New(normalizedPatterns)
    PM-->>NM: compiled PatternMatcher
    NM-->>CA: &ignoredPathMatcher{root, matcher}

    loop filepath.Walk directory tree
        CA->>IM: matches(absolutePath)
        IM-->>IM: filepath.Rel → toArchivePath
        IM->>PM: MatchesOrParentMatches(relativePath)
        PM-->>IM: bool (ignored?)
        IM-->>CA: true → skip / false → add to archive
    end
Loading

Summary

The PR replaces the old shouldIgnorePath() string-prefix/suffix matching with a structured pipeline:

  1. LoadIgnoredPaths() reads .blaxelignore, always appending .env.build last to guarantee exclusion.
  2. CompilenewIgnoredPathMatcher() normalizes each pattern (handling negation !, anchoring /, and adding **/ for backward-compat literals), then delegates to moby/patternmatcher for one-time compilation.
  3. Match — During the archive walk, ignoredPathMatcher.matches() converts each absolute path to a relative archive path and checks it against the compiled matcher (including parent-directory matching).

This enables Docker-style glob patterns (**/*.test.ts, **/.env.*), ordered ! exclusions, and character classes — all compiled once per archive operation.

Note

Posted by PR Sequence Diagram · Tag @mendral-app with feedback.

@mendral-app mendral-app Bot 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.

LGTM

The implementation is clean and well-tested. The riskiest part—normalizeIgnorePattern—correctly handles negation, anchoring, and the **/ prefix for backward-compat literals. One pre-existing concern worth noting: the inline comment stripping at line 1991 (strings.Index(line, "#")) will now corrupt glob patterns containing # (e.g., character classes [#abc]), but since that code is unchanged, it's outside the scope of this review. The changed code itself is correct.

Tag @mendral-app with feedback or questions. View session

@mendral-app

mendral-app Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

📋 Created Linear issue ENG-4085 — status: In Progress

  • Assignee: unassigned (PR author not found in Linear workspace)
  • Labels: Feature, CLI
  • Estimate: M (4 files, ~152 lines changed)
  • PR linked: ✅ Issue will auto-close when this PR merges

Auto-created because no Linear reference was found in the PR title, description, or branch name.

Note

Posted by Linear Issue Enforcer · Tag @mendral-app with feedback.

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.

1 participant