Skip to content

Commit 3054c56

Browse files
authored
Merge branch 'master' into laurent
2 parents 46788e2 + 228ca78 commit 3054c56

22 files changed

Lines changed: 1296 additions & 448 deletions
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
name: "🧹 Cleanup Lint Branches"
2+
3+
# This workflow automatically cleans up lint/* branches that have been merged or closed.
4+
# It helps maintain a clean repository by removing branches created by the linter workflow
5+
# after their associated pull requests are no longer active.
6+
7+
on:
8+
# Run daily at 00:00 UTC
9+
schedule:
10+
- cron: '0 0 * * *'
11+
12+
# Allow manual triggering with optional dry-run mode
13+
workflow_dispatch:
14+
inputs:
15+
dry_run:
16+
description: 'Dry run mode (preview deletions without actually deleting)'
17+
required: false
18+
type: boolean
19+
default: true
20+
21+
permissions:
22+
contents: write
23+
pull-requests: read
24+
25+
jobs:
26+
cleanup:
27+
name: Clean up merged/closed lint branches
28+
runs-on: ubuntu-latest
29+
30+
steps:
31+
- name: Checkout repository
32+
uses: actions/checkout@v4
33+
with:
34+
fetch-depth: 0 # Fetch all branches and history
35+
token: ${{ secrets.GITHUB_TOKEN }}
36+
37+
- name: Setup GitHub CLI
38+
run: |
39+
# Verify gh CLI is available (pre-installed on ubuntu-latest)
40+
gh --version
41+
env:
42+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
43+
44+
- name: Cleanup lint branches
45+
env:
46+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
47+
# Default to true (dry-run mode) unless explicitly set to false
48+
# This ensures safe operation for both scheduled and manual triggers
49+
DRY_RUN: ${{ github.event.inputs.dry_run == 'false' && 'false' || 'true' }}
50+
BRANCH_AGE_DAYS: 7
51+
run: |
52+
set -e
53+
set -o pipefail
54+
55+
echo "🧹 Starting lint branch cleanup..."
56+
echo "Dry run mode: $DRY_RUN"
57+
echo "Branch age threshold for orphaned branches: $BRANCH_AGE_DAYS days"
58+
echo ""
59+
60+
# Get current date in seconds since epoch
61+
current_date=$(date +%s)
62+
age_threshold_seconds=$((BRANCH_AGE_DAYS * 86400))
63+
64+
# Track statistics
65+
total_branches=0
66+
deleted_branches=0
67+
skipped_branches=0
68+
error_branches=0
69+
70+
# Get all remote branches matching the pattern lint/style-fixes-*
71+
echo "📋 Fetching lint branches..."
72+
lint_branches=$(git for-each-ref --format='%(refname:short)' 'refs/remotes/origin/lint/style-fixes-*' | sed 's|^origin/||' || echo "")
73+
74+
if [ -z "$lint_branches" ]; then
75+
echo "✅ No lint branches found matching 'lint/style-fixes-*'"
76+
exit 0
77+
fi
78+
79+
echo "Found $(echo "$lint_branches" | wc -l) lint branches"
80+
echo ""
81+
82+
# Process each branch (using while read to handle special characters safely)
83+
while IFS= read -r branch; do
84+
[ -z "$branch" ] && continue
85+
total_branches=$((total_branches + 1))
86+
echo "🔍 Processing: $branch"
87+
88+
# Validate branch name matches expected pattern
89+
if [[ ! "$branch" =~ ^lint/style-fixes-[0-9]+$ ]]; then
90+
echo " ⚠️ Warning: Branch name doesn't match expected pattern, skipping"
91+
skipped_branches=$((skipped_branches + 1))
92+
echo ""
93+
continue
94+
fi
95+
96+
# Check if there's a PR for this branch
97+
pr_number=$(gh pr list --state all --head "$branch" --json number --jq '.[0].number // empty' 2>/dev/null || echo "")
98+
99+
should_delete=false
100+
delete_reason=""
101+
102+
if [ -n "$pr_number" ]; then
103+
# PR exists, check its state
104+
echo " Found PR #$pr_number"
105+
106+
pr_state=$(gh pr view "$pr_number" --json state --jq '.state' 2>/dev/null || echo "")
107+
pr_merged=$(gh pr view "$pr_number" --json merged --jq '.merged' 2>/dev/null || echo "false")
108+
109+
if [ "$pr_merged" = "true" ]; then
110+
should_delete=true
111+
delete_reason="PR #$pr_number was merged"
112+
elif [ "$pr_state" = "CLOSED" ]; then
113+
should_delete=true
114+
delete_reason="PR #$pr_number was closed"
115+
else
116+
echo " ⏭️ Skipping: PR #$pr_number is still open"
117+
skipped_branches=$((skipped_branches + 1))
118+
fi
119+
else
120+
# No PR found - check if branch is old enough to delete
121+
echo " No associated PR found (orphaned branch)"
122+
123+
# Get the last commit date on this branch
124+
last_commit_date=$(git log -1 --format=%ct "origin/$branch" 2>/dev/null || echo "0")
125+
126+
if [ "$last_commit_date" != "0" ]; then
127+
branch_age_seconds=$((current_date - last_commit_date))
128+
branch_age_days=$((branch_age_seconds / 86400))
129+
130+
echo " Branch age: $branch_age_days days"
131+
132+
if [ $branch_age_seconds -gt $age_threshold_seconds ]; then
133+
should_delete=true
134+
delete_reason="Orphaned branch older than $BRANCH_AGE_DAYS days (age: $branch_age_days days)"
135+
else
136+
echo " ⏭️ Skipping: Orphaned branch is only $branch_age_days days old (threshold: $BRANCH_AGE_DAYS days)"
137+
skipped_branches=$((skipped_branches + 1))
138+
fi
139+
else
140+
echo " ⚠️ Warning: Could not determine branch age"
141+
skipped_branches=$((skipped_branches + 1))
142+
fi
143+
fi
144+
145+
# Delete the branch if appropriate
146+
if [ "$should_delete" = "true" ]; then
147+
if [ "$DRY_RUN" = "true" ]; then
148+
echo " 🔍 [DRY RUN] Would delete: $delete_reason"
149+
deleted_branches=$((deleted_branches + 1))
150+
else
151+
echo " 🗑️ Deleting: $delete_reason"
152+
# Use git push for safer deletion with validated branch name
153+
delete_error=$(git push origin --delete "$branch" 2>&1)
154+
exit_code=$?
155+
if [ $exit_code -eq 0 ]; then
156+
echo " ✅ Successfully deleted"
157+
deleted_branches=$((deleted_branches + 1))
158+
else
159+
echo " ❌ Failed to delete branch: $delete_error"
160+
error_branches=$((error_branches + 1))
161+
fi
162+
fi
163+
fi
164+
165+
echo ""
166+
done <<< "$lint_branches"
167+
168+
# Print summary
169+
echo "📊 Cleanup Summary"
170+
echo "=================="
171+
echo "Total lint branches processed: $total_branches"
172+
if [ "$DRY_RUN" = "true" ]; then
173+
echo "Branches that would be deleted: $deleted_branches"
174+
else
175+
echo "Branches deleted: $deleted_branches"
176+
fi
177+
echo "Branches skipped: $skipped_branches"
178+
if [ $error_branches -gt 0 ]; then
179+
echo "Branches with errors: $error_branches"
180+
fi
181+
echo ""
182+
183+
if [ "$DRY_RUN" = "true" ]; then
184+
echo "✅ Dry run completed - no branches were actually deleted"
185+
else
186+
echo "✅ Cleanup completed"
187+
fi

.github/workflows/tester.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,14 @@ jobs:
2828
steps:
2929
- uses: actions/checkout@v4
3030

31-
# 1. Setup uv instantly (replaces the heavy setup-miniconda)
3231
- name: Set up uv
3332
uses: astral-sh/setup-uv@v3
3433
with:
3534
version: "latest"
3635

37-
# 2. Pin the exact Python version from your matrix variable
3836
- name: Set up Python ${{ matrix.matrix.python-version }}
3937
run: uv python install ${{ matrix.python-version }}
4038

41-
# 3. Create a clean virtual environment and install everything at once
4239
- name: Install dependencies and library
4340
run: |
4441
uv pip install --system \
@@ -53,7 +50,6 @@ jobs:
5350
geoh5py \
5451
-e .[tests]
5552
56-
# 4. Run pytest directly inside the environment
5753
- name: pytest
5854
run: |
5955
pytest

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"LoopStructural": "1.6.23"
2+
"LoopStructural": "1.6.27"
33
}

LoopStructural/CHANGELOG.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,39 @@
11
# Changelog
22

3+
## [1.6.27](https://github.com/Loop3D/LoopStructural/compare/v1.6.26...v1.6.27) (2026-04-14)
4+
5+
6+
### Bug Fixes
7+
8+
* add caching of reused values ([54fba19](https://github.com/Loop3D/LoopStructural/commit/54fba19df600210e6c14fb895d20b7f00451f663))
9+
* numpy speed improvements ([5e29fa1](https://github.com/Loop3D/LoopStructural/commit/5e29fa15b13a0864baa83ef9c95feef99d4cae01))
10+
* remove redundant call to mask nan values in discrete interpolator ([ce082f6](https://github.com/Loop3D/LoopStructural/commit/ce082f6e49bda22f8e02346e4c9cea9a81ba2bc0))
11+
12+
## [1.6.26](https://github.com/Loop3D/LoopStructural/compare/v1.6.25...v1.6.26) (2026-02-11)
13+
14+
15+
### Bug Fixes
16+
17+
* add threshold variable and remove duplicate code ([4d60155](https://github.com/Loop3D/LoopStructural/commit/4d60155ebe079bfee4f23b1cb6a607778728de0f))
18+
* calculate fault normal from plane of points as well as trace ([71c6f17](https://github.com/Loop3D/LoopStructural/commit/71c6f17169326daf847dcabfcf4a995a99d8de9c))
19+
* ensure all data are copies of original datastructure ([f409ad8](https://github.com/Loop3D/LoopStructural/commit/f409ad88b130cc770bd98ec9f459909edf037da8))
20+
* incorrect boolean ([5d9e04b](https://github.com/Loop3D/LoopStructural/commit/5d9e04b3532cd6a05dd3d1bf18ddafd4410626a0))
21+
22+
## [1.6.25](https://github.com/Loop3D/LoopStructural/compare/v1.6.24...v1.6.25) (2026-01-31)
23+
24+
25+
### Bug Fixes
26+
27+
* prevent int overflow if bb min/max is defined as int ([65d2819](https://github.com/Loop3D/LoopStructural/commit/65d2819fcf6fe0b0e0440f487d3cf75e629341b7))
28+
* speed up model eval by collecting all conformable units ([9b4a719](https://github.com/Loop3D/LoopStructural/commit/9b4a7192fb75e5f2e002e8079891d0a7dd5487bc))
29+
30+
## [1.6.24](https://github.com/Loop3D/LoopStructural/compare/v1.6.23...v1.6.24) (2026-01-15)
31+
32+
33+
### Bug Fixes
34+
35+
* change default regularisation to 1.0 as 0.1 was causing overfitting ([fd3fd20](https://github.com/Loop3D/LoopStructural/commit/fd3fd201e743d421708d0999b367a77cb290696c))
36+
337
## [1.6.23](https://github.com/Loop3D/LoopStructural/compare/v1.6.22...v1.6.23) (2025-11-05)
438

539

LoopStructural/datatypes/_bounding_box.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,16 +60,16 @@ def __init__(
6060
# we want the local coordinates to start at 0
6161
# otherwise uses provided origin. This is useful for having multiple bounding boxes rela
6262
if global_origin is not None and origin is None:
63-
origin = np.zeros(np.array(global_origin).shape)
63+
origin = np.zeros(np.array(global_origin).shape, dtype=float)
6464
if global_maximum is not None and global_origin is not None:
65-
maximum = np.array(global_maximum) - np.array(global_origin)
66-
65+
maximum = np.array(global_maximum,dtype=float) - np.array(global_origin,dtype=float)
66+
6767
if maximum is None and nsteps is not None and step_vector is not None:
6868
maximum = np.array(origin) + np.array(nsteps) * np.array(step_vector)
6969
if origin is not None and global_origin is None:
7070
global_origin = np.zeros(3)
71-
self._origin = np.array(origin)
72-
self._maximum = np.array(maximum)
71+
self._origin = np.array(origin, dtype=float)
72+
self._maximum = np.array(maximum, dtype=float)
7373
self.dimensions = dimensions
7474
if self.origin.shape:
7575
if self.origin.shape[0] != self.dimensions:
@@ -80,7 +80,10 @@ def __init__(
8080
else:
8181
self.dimensions = dimensions
8282
self._global_origin = global_origin
83-
self.nsteps = np.array([50, 50, 25])
83+
if self.origin is not None and self.maximum is not None:
84+
self.nelements = 10_000
85+
else:
86+
self.nsteps = np.array([50, 50, 25])
8487
if nsteps is not None:
8588
self.nsteps = np.array(nsteps)
8689
self.name_map = {
@@ -219,6 +222,7 @@ def nelements(self):
219222
int
220223
Total number of elements (product of nsteps)
221224
"""
225+
222226
return self.nsteps.prod()
223227

224228
@property
@@ -230,7 +234,9 @@ def volume(self):
230234
float
231235
Volume of the bounding box
232236
"""
233-
return np.prod(self.maximum - self.origin)
237+
length = self.maximum - self.origin
238+
length = length.astype(float)
239+
return np.prod(length)
234240

235241
@property
236242
def bb(self):

0 commit comments

Comments
 (0)