Fix josh-proxy rejecting stored filter path with slash
Josh-proxy's parser treats "/" in :+ paths as a filter separator, so :+.josh-filters/backend fails. Use flat naming at repo root: .josh-filter-<target>.josh referenced as :+.josh-filter-<target>. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -431,7 +431,7 @@ cmd_preflight() {
|
|||||||
echo "4. Exclude filter files"
|
echo "4. Exclude filter files"
|
||||||
|
|
||||||
while IFS= read -r target_name; do
|
while IFS= read -r target_name; do
|
||||||
local filter_file=".josh-filters/${target_name}.josh"
|
local filter_file=".josh-filter-${target_name}.josh"
|
||||||
if [ -f "$filter_file" ]; then
|
if [ -f "$filter_file" ]; then
|
||||||
if git ls-files --error-unmatch "$filter_file" >/dev/null 2>&1; then
|
if git ls-files --error-unmatch "$filter_file" >/dev/null 2>&1; then
|
||||||
pass "${filter_file} exists and is tracked"
|
pass "${filter_file} exists and is tracked"
|
||||||
|
|||||||
@@ -541,7 +541,7 @@ targets:
|
|||||||
|
|
||||||
### How it works
|
### How it works
|
||||||
|
|
||||||
When `exclude` is present, josh-sync generates a `.josh-filters/<target>.josh` file containing a [josh stored filter](https://josh-project.github.io/josh/reference/filters.html) with `:exclude` clauses:
|
When `exclude` is present, josh-sync generates a `.josh-filter-<target>.josh` file at the monorepo root containing a [josh stored filter](https://josh-project.github.io/josh/reference/filters.html) with `:exclude` clauses:
|
||||||
|
|
||||||
```
|
```
|
||||||
:/services/billing:exclude[
|
:/services/billing:exclude[
|
||||||
@@ -551,6 +551,8 @@ When `exclude` is present, josh-sync generates a `.josh-filters/<target>.josh` f
|
|||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The file is referenced in the josh-proxy URL as `:+.josh-filter-<target>` (flat naming — josh-proxy's parser treats `/` in `:+` paths as a filter separator, so subdirectory paths don't work).
|
||||||
|
|
||||||
Josh-proxy reads this file from the monorepo and applies the filter at the transport layer. This means:
|
Josh-proxy reads this file from the monorepo and applies the filter at the transport layer. This means:
|
||||||
- **Forward sync**: the filtered clone already excludes the files
|
- **Forward sync**: the filtered clone already excludes the files
|
||||||
- **Reverse sync**: pushes through josh also respect the exclusion
|
- **Reverse sync**: pushes through josh also respect the exclusion
|
||||||
@@ -572,11 +574,11 @@ Josh uses `::` patterns inside `:exclude[...]`:
|
|||||||
### Setup
|
### Setup
|
||||||
|
|
||||||
1. Add `exclude` to the target in `.josh-sync.yml`
|
1. Add `exclude` to the target in `.josh-sync.yml`
|
||||||
2. Run `josh-sync preflight` — this generates `.josh-filters/<target>.josh`
|
2. Run `josh-sync preflight` — this generates `.josh-filter-<target>.josh`
|
||||||
3. Commit the generated file: `git add .josh-filters/ && git commit`
|
3. Commit the generated file: `git add .josh-filter-*.josh && git commit`
|
||||||
4. Forward sync will now exclude the specified files
|
4. Forward sync will now exclude the specified files
|
||||||
|
|
||||||
If you change the `exclude` list, re-run `preflight` and commit the updated `.josh-filters/` file.
|
If you change the `exclude` list, re-run `preflight` and commit the updated `.josh-filter-*.josh` file.
|
||||||
|
|
||||||
## Adding a New Target
|
## Adding a New Target
|
||||||
|
|
||||||
|
|||||||
@@ -8,9 +8,11 @@
|
|||||||
# Requires: lib/core.sh sourced first, yq and jq on PATH
|
# Requires: lib/core.sh sourced first, yq and jq on PATH
|
||||||
|
|
||||||
# ─── Josh Filter File Generation ──────────────────────────────────
|
# ─── Josh Filter File Generation ──────────────────────────────────
|
||||||
# Generates .josh-filters/<target>.josh for targets with exclude patterns.
|
# Generates .josh-filter-<target>.josh for targets with exclude patterns.
|
||||||
# These files must be committed to the monorepo — josh-proxy reads them
|
# These files must be committed to the monorepo — josh-proxy reads them
|
||||||
# from the repo at clone time via the :+ stored filter syntax.
|
# from the repo at clone time via the :+ stored filter syntax.
|
||||||
|
# Files are at the repo root (flat naming) because josh-proxy's parser
|
||||||
|
# treats "/" in :+ paths as a filter separator.
|
||||||
|
|
||||||
_generate_josh_filters() {
|
_generate_josh_filters() {
|
||||||
local has_excludes
|
local has_excludes
|
||||||
@@ -20,8 +22,6 @@ _generate_josh_filters() {
|
|||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p .josh-filters
|
|
||||||
|
|
||||||
local target_name subfolder exclude_patterns filter_content
|
local target_name subfolder exclude_patterns filter_content
|
||||||
while IFS= read -r target_name; do
|
while IFS= read -r target_name; do
|
||||||
subfolder=$(echo "$JOSH_SYNC_TARGETS" | jq -r --arg n "$target_name" \
|
subfolder=$(echo "$JOSH_SYNC_TARGETS" | jq -r --arg n "$target_name" \
|
||||||
@@ -33,7 +33,7 @@ _generate_josh_filters() {
|
|||||||
${exclude_patterns}
|
${exclude_patterns}
|
||||||
]"
|
]"
|
||||||
|
|
||||||
local filter_file=".josh-filters/${target_name}.josh"
|
local filter_file=".josh-filter-${target_name}.josh"
|
||||||
local existing=""
|
local existing=""
|
||||||
if [ -f "$filter_file" ]; then
|
if [ -f "$filter_file" ]; then
|
||||||
existing=$(cat "$filter_file")
|
existing=$(cat "$filter_file")
|
||||||
@@ -75,9 +75,9 @@ parse_config() {
|
|||||||
export JOSH_SYNC_TARGETS
|
export JOSH_SYNC_TARGETS
|
||||||
JOSH_SYNC_TARGETS=$(echo "$config_json" | jq '[.targets[] | . +
|
JOSH_SYNC_TARGETS=$(echo "$config_json" | jq '[.targets[] | . +
|
||||||
# Auto-derive josh_filter from subfolder if not set
|
# Auto-derive josh_filter from subfolder if not set
|
||||||
# When exclude patterns are present, use a stored josh filter (:+.josh-filters/<name>)
|
# When exclude patterns are present, use a stored josh filter (:+.josh-filter-<name>)
|
||||||
(if (.exclude // [] | length) > 0 then
|
(if (.exclude // [] | length) > 0 then
|
||||||
{josh_filter: (":+.josh-filters/" + .name)}
|
{josh_filter: (":+.josh-filter-" + .name)}
|
||||||
elif (.josh_filter // "") == "" then
|
elif (.josh_filter // "") == "" then
|
||||||
{josh_filter: (":/" + .subfolder)}
|
{josh_filter: (":/" + .subfolder)}
|
||||||
else {} end) +
|
else {} end) +
|
||||||
@@ -98,7 +98,7 @@ parse_config() {
|
|||||||
)
|
)
|
||||||
]')
|
]')
|
||||||
|
|
||||||
# Generate .josh-filters/*.josh for targets with exclude patterns
|
# Generate .josh-filter-*.josh for targets with exclude patterns
|
||||||
_generate_josh_filters
|
_generate_josh_filters
|
||||||
|
|
||||||
# Load .env credentials (if present, not required — CI sets these via secrets)
|
# Load .env credentials (if present, not required — CI sets these via secrets)
|
||||||
|
|||||||
@@ -75,7 +75,7 @@
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"items": { "type": "string" },
|
"items": { "type": "string" },
|
||||||
"default": [],
|
"default": [],
|
||||||
"description": "File/directory patterns to exclude from sync via josh :exclude filter. Josh pattern syntax: 'dir/' for directories, '*.ext' for globs, '**/dir/' for nested matches. Generates a .josh-filters/<target>.josh file that must be committed."
|
"description": "File/directory patterns to exclude from sync via josh :exclude filter. Josh pattern syntax: 'dir/' for directories, '*.ext' for globs, '**/dir/' for nested matches. Generates a .josh-filter-<target>.josh file that must be committed."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user