Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions .claude/skills/update-progress/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
name: update-progress
description: >
Update GitHub issue percentage titles for the critter integration plan (#4179).
Use after checking off any task in a phase issue, or after merging a phase PR.
Recomputes phase % and parent % from live checkbox state and updates all titles.
allowed-tools: Bash(gh:*), Bash(awk:*), Bash(grep:*), Bash(sed:*)
---

# Update Critter Integration Progress

## When to use

After completing any task in issues #4184–#4190 — check the box in the issue first,
then run this skill to recompute and update all percentages.

The GitHub workflow (`.github/workflows/update-critter-progress.yml`) handles this
automatically on PR merges and issue edits. Use this skill for manual updates or
to verify the current state.

## Formulas (source of truth: docs/critter-integration-plan.md)

```
phase_percentage = (completed_tasks_in_phase / total_tasks_in_phase) * 100
parent_percentage = (total_completed_tasks_across_all_phases / 53) * 100
```

Both are rounded to the nearest integer.

## Phase reference

| Issue | Phase | Tasks |
|-------|-------|-------|
| #4184 | Phase 1: Extract Mapper interface and add config option | 9 |
| #4185 | Phase 2: VarHandle accessor generator | 6 |
| #4186 | Phase 3: Move critter-core into morphia-core | 8 |
| #4187 | Phase 4: CritterMapper implementation | 9 |
| #4188 | Phase 5: Wire CritterMapper into MorphiaDatastore | 5 |
| #4189 | Phase 6: Test infrastructure and CI matrix | 7 |
| #4190 | Phase 7: Cleanup and documentation | 9 |
| **Total** | | **53** |

## Steps

Run the shared script:

```bash
bash .github/scripts/update-critter-progress.sh
```

The script:
1. Fetches each phase issue body and counts `- [x]` entries
2. Updates each phase issue title to `[XX%] Phase N: ...`
3. Closes phase issues that reach 100% and checks their box in #4179
4. Updates `#4179` title to `[XX%] Integrate critter-core into morphia-core`

## Manual commands (if running ad hoc)

```bash
# Count checked tasks in a phase issue
gh issue view 4184 --repo MorphiaOrg/morphia --json body -q '.body' \
| grep -c '^\- \[x\]'

# Update a phase issue title
gh issue edit 4184 --repo MorphiaOrg/morphia --title "[33%] Phase 1: Extract Mapper interface and add config option"

# Update parent
gh issue edit 4179 --repo MorphiaOrg/morphia --title "[6%] Integrate critter-core into morphia-core"
```
85 changes: 85 additions & 0 deletions .github/scripts/update-critter-progress.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/usr/bin/env bash
# Updates GitHub issue percentage titles for the critter integration plan.
# Source of truth for formulas: docs/critter-integration-plan.md
#
# Usage: GH_TOKEN=<token> ./update-critter-progress.sh
#
# Derives subissues dynamically from the checkboxes in the parent issue body.
# Phase percentages: (completed_tasks_in_phase / total_tasks_in_phase) * 100
# Parent percentage: (total_completed_across_all_phases / total_across_all_phases) * 100

set -euo pipefail

REPO="MorphiaOrg/morphia"
PARENT_ISSUE=4179

total_done=0
total_tasks=0
declare -a completed_phases=()

echo "Computing critter integration progress..."

# Fetch parent body and extract subissue numbers from its checkboxes
parent_body=$(gh issue view "$PARENT_ISSUE" --repo "$REPO" --json body -q '.body')
subissues=$(printf '%s' "$parent_body" | grep '^\- \[' | grep -o '#[0-9]*' | tr -d '#')

for issue in $subissues; do
body=$(gh issue view "$issue" --repo "$REPO" --json body -q '.body')
done_count=$(printf '%s' "$body" | grep -ci '^\- \[x\]' || true)
tasks=$(printf '%s' "$body" | grep -ci '^\- \[' || true)

total_done=$((total_done + done_count))
total_tasks=$((total_tasks + tasks))

pct=$(awk "BEGIN { printf \"%.0f\", ($done_count * 100) / ($tasks > 0 ? $tasks : 1) }")
current_title=$(gh issue view "$issue" --repo "$REPO" --json title -q '.title')
bare_title=$(printf '%s' "$current_title" | sed 's/^\[[0-9]*%\] //')
new_title="[$pct%] $bare_title"

if [ "$current_title" != "$new_title" ]; then
gh issue edit "$issue" --repo "$REPO" --title "$new_title"
echo " #$issue: $current_title → $new_title"
else
echo " #$issue: unchanged ($current_title)"
fi

if [ "$done_count" -eq "$tasks" ] && [ "$tasks" -gt 0 ]; then
completed_phases+=("$issue")
state=$(gh issue view "$issue" --repo "$REPO" --json state -q '.state')
if [ "$state" = "OPEN" ]; then
gh issue close "$issue" --repo "$REPO"
echo " #$issue: closed (all $tasks tasks complete)"
fi
fi
done

# Update parent title
parent_pct=$(awk "BEGIN { printf \"%.0f\", ($total_done * 100) / ($total_tasks > 0 ? $total_tasks : 1) }")
current_parent_title=$(gh issue view "$PARENT_ISSUE" --repo "$REPO" --json title -q '.title')
bare_parent_title=$(printf '%s' "$current_parent_title" | sed 's/^\[[0-9]*%\] //')
new_parent_title="[$parent_pct%] $bare_parent_title"

if [ "$current_parent_title" != "$new_parent_title" ]; then
gh issue edit "$PARENT_ISSUE" --repo "$REPO" --title "$new_parent_title"
echo " #$PARENT_ISSUE: $current_parent_title → $new_parent_title"
else
echo " #$PARENT_ISSUE: unchanged ($current_parent_title)"
fi

# Check completed-phase boxes in parent body
if [ ${#completed_phases[@]} -gt 0 ]; then
updated_body="$parent_body"
changed=false
for issue in "${completed_phases[@]}"; do
if printf '%s' "$updated_body" | grep -q "^- \[ \] #$issue"; then
updated_body=$(printf '%s' "$updated_body" | sed "s/^- \[ \] #$issue/- [x] #$issue/")
changed=true
echo " #$PARENT_ISSUE: checked box for #$issue"
fi
done
if [ "$changed" = "true" ]; then
gh issue edit "$PARENT_ISSUE" --repo "$REPO" --body "$updated_body"
fi
fi

echo "Done: $total_done/$total_tasks tasks complete ($parent_pct%)"
33 changes: 33 additions & 0 deletions .github/workflows/update-critter-progress.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Update Critter Integration Progress

# Runs whenever a PR is merged or a tracked issue is edited (e.g. checkbox ticked).
# Recomputes phase and parent percentages using the formulas in docs/critter-integration-plan.md.

on:
pull_request:
types: [closed]
issues:
types: [edited]

jobs:
update-progress:
runs-on: ubuntu-latest
permissions:
issues: write
# Run on merged PRs, or edits to the parent/phase issues only
if: |
(github.event_name == 'pull_request' && github.event.pull_request.merged == true) ||
(github.event_name == 'issues' && contains(
fromJson('[4179, 4184, 4185, 4186, 4187, 4188, 4189, 4190]'),
github.event.issue.number
))
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 1

- name: Update issue percentages
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: bash .github/scripts/update-critter-progress.sh
10 changes: 9 additions & 1 deletion core/src/main/java/dev/morphia/MorphiaDatastore.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import dev.morphia.mapping.EntityModelImporter;
import dev.morphia.mapping.Mapper;
import dev.morphia.mapping.MappingException;
import dev.morphia.mapping.ReflectiveMapper;
import dev.morphia.mapping.ShardKeyType;
import dev.morphia.mapping.codec.EnumCodecProvider;
import dev.morphia.mapping.codec.MorphiaCodecProvider;
Expand Down Expand Up @@ -124,7 +125,7 @@ public class MorphiaDatastore implements Datastore {
@MorphiaInternal
public MorphiaDatastore(MongoClient client, MorphiaConfig config) {
this.mongoClient = client;
this.mapper = new Mapper(config);
this.mapper = createMapper(config);
this.queryFactory = mapper.getConfig().queryFactory();
importModels();

Expand Down Expand Up @@ -234,6 +235,13 @@ public void applyDocumentValidations() {
}
}

private static Mapper createMapper(MorphiaConfig config) {
return switch (config.mapper()) {
case CRITTER -> throw new MappingException(Sofia.mapperNotYetAvailable("CRITTER"));
case LEGACY -> new ReflectiveMapper(config);
};
}

/**
* @return the Mapper used by this Datastore
*/
Expand Down
Loading
Loading