internetarchive / internetarchive/openlibrary

Name the conflicted PR on the Testing Environment red-dot hover

Open
#13,474 3 comments 0 reactions 1 assignee Claimed by @ANONYMOUSZED-beep View on GitHub
Affects: UI Good First Issue Lead: @RayBB Module: JavaScript Needs: Help Needs: Review Assignee Theme: Testing Type: Feature Request
Dominant language
Python
Stars
6.7k
Forks
2k
Avg merge
2d 19h
Merged PRs (30d)
138

Description

This is a good first issue — it's a small, self-contained change. You don't need to wait to be assigned: just comment that you'd like to work on it, then go ahead and open a pull request referencing this issue.

## Problem

On the `/status` page, the Testing Environment panel shows a red dot on rows whose PR failed to merge on the last deploy. Hovering the dot says **"Deploy failed (merge conflict)"** — but it doesn't say *which* PR caused the conflict. The maintainer has to dig into the legacy "Last Build Result" table or SSH into the testing box to read the deploy transcript.

## Solution

Change the red dot's tooltip to **"Merge conflict with #N"**, naming the PR. The number is already on the row, and the conflict flag already exists per-row — this is a one-file fix plus a string swap.

## How conflict detection works (for context)

1. **Deploy script** (`scripts/make-integration-branch.sh`): merges each active PR into the integration branch one at a time. On failure:
```
Merge conflict for PR #13466 (pinned 89d136474a…) — skipping
```
Saved as `_dev-merged_status.txt` on the testing box.

2. **Parser** (`openlibrary/plugins/openlibrary/status.py`): `_merge_conflicted_prs()` extracts the PR number from each entry's `pull_line` (primary: `origin pull/(\d+)/head`) or `status` line (fallback: `Merge conflict for PR #(\d+)`). Returns a `frozenset[int]`.

3. **Row flag**: `build_testing_status()` sets `merge_conflict = True` on each `TestingPRStatus` whose PR is in the set.

4. **Frontend** (`TestingRow.vue`): `dotLabel` computed reads this flag to set the tooltip.

## What to change

### `openlibrary/components/TestingEnvironment/TestingRow.vue`

Update `dotLabel`:

```js
// Before
const dotLabel = computed(() => {
if (mergeConflict.value) return props.strings.mergeConflict;
return liveNow.value ? props.strings.liveNow : props.strings.notLive;
});

// After
const dotLabel = computed(() => {
if (mergeConflict.value) return text('mergeConflictDot', `#${props.pr.pr}`);
return liveNow.value ? props.strings.liveNow : props.strings.notLive;
});
```

### `openlibrary/components/TestingEnvironment/utils.js`

Add the new string to `DEFAULT_STRINGS` and delete the old one:

```js
mergeConflictDot: 'Merge conflict with %s', // ADD
// mergeConflict: 'Deploy failed (merge conflict)', // DELETE (unused)
```

### `openlibrary/macros/TestingEnvironment.html.jinja`

Add the translated string and delete the old one:

```jinja
"mergeConflictDot": _("Merge conflict with %(pr)s", pr="%s"), {# ADD #}
{# "mergeConflict": _("Deploy failed (merge conflict)"), #} {# DELETE #}
```

### `openlibrary/i18n/messages.pot`

After changing the jinja macro, regenerate:

```bash
pre-commit run generate-pot
```

## Local development setup

Both fixture files (`_testing-prs.json`, `_dev-merged_status.txt`) are gitignored.

### Option A — run the deploy script against real PRs (recommended)

```bash
# 1. Create a testing state with real open PRs
cat > _testing-prs.json << 'ENDJSON'
{
"last_deploy_at": "2026-08-24T18:00:00+00:00",
"deploy_started_at": "2026-08-24T18:00:00+00:00",
"deployed": {
"13468": "Move featured subjects fetching from templates to Python handlers",
"13446": "Fix HTML entities in search page title",
"13445": "Enable ruff rules DTZ for proper use of Python datetimes",
"13438": "Normalize frozen GitHub Actions version skew",
"13431": "feat: add audiences field to /type/work schema",
"13429": "Surface Search Inside: modal band, wider rescue net"
},
"prs": [
{ "pr": 13468, "commit": "0fb3e4c220f43545ed39e7317336defc9d6aff1a", "active": true,
"title": "Move featured subjects fetching from templates to Python handlers",
"added_at": "2026-08-20T10:00:00+00:00", "added_by": "openlibrary",
"author": "CipherZ3r0", "assignee": "RayBB" },
{ "pr": 13446, "commit": "46f9ac83789f99415aba53c4fe4502eda4db8ec2", "active": true,
"title": "Fix HTML entities in search page title",
"added_at": "2026-08-20T10:00:00+00:00", "added_by": "openlibrary",
"author": "RayBB", "assignee": "jimchamp" },
{ "pr": 13445, "commit": "f41de1d09ce5505d5828267209b0126d4382eefd", "active": true,
"title": "Enable ruff rules DTZ for proper use of Python datetimes",
"added_at": "2026-08-20T10:00:00+00:00", "added_by": "openlibrary",
"author": "cclauss", "assignee": "" },
{ "pr": 13438, "commit": "04150b9853d0102ccc26c9c5abbca6b5d1014d04", "active": true,
"title": "Normalize frozen GitHub Actions version skew (follow-up to #13437)",
"added_at": "2026-08-21T10:00:00+00:00", "added_by": "openlibrary",
"author": "RayBB", "assignee": "" },
{ "pr": 13431, "commit": "f354f0a67105c1f1d6873ce630ddfd540730899d", "active": true,
"title": "feat: add audiences field to /type/work schema",
"added_at": "2026-08-21T10:00:00+00:00", "added_by": "openlibrary",
"author": "shoaib-inamdar", "assignee": "" },
{ "pr": 13429, "commit": "a38ada9aac9a8bc8601e882f79849e3c3e146dc1", "active": true,
"title": "Surface Search Inside: modal band, wider rescue net",
"added_at": "2026-08-21T10:00:00+00:00", "added_by": "openlibrary",
"author": "lokesh", "assignee": "" }
]
}
ENDJSON

# 2. Clone the repo and run the deploy script in a throwaway directory
rm -rf /tmp/ol-script-test
git clone --no-checkout . /tmp/ol-script-test
cd /tmp/ol-script-test
git checkout master
git remote set-url origin https://github.com/internetarchive/openlibrary.git
git config user.email "test@test.com"
git config user.name "Test"
cp /path/to/openlibrary/_testing-prs.json .

# 3. Run — conflicting PRs will appear in the output
./scripts/make-integration-branch.sh dev-test 2>&1 | tee _dev-merged_status.txt

# 4. Copy back and clean up
cp _dev-merged_status.txt /path/to/openlibrary/
rm -rf /tmp/ol-script-test
```

As of August 2026, this produces conflicts for **#13429**, **#13445**, and **#13466** — three red dots to hover.

### Option B — write a minimal transcript by hand

Create `_dev-merged_status.txt` directly:

```
On master
Already up to date.
---
origin pull/13466/head # pinned at 89d136474a
Auto-merging openlibrary/plugins/openlibrary/home.py
CONFLICT (content): Merge conflict in openlibrary/plugins/openlibrary/home.py
Automatic merge failed; fix conflicts and then commit the result.
Merge conflict for PR #13466 (pinned 89d136474a01ffa105cf198c057c25d2af2950ae) — skipping
---
origin pull/13468/head # pinned at 0fb3e4c220
Merge made by the 'ort' strategy.
---
Complete; testing created (SHA: 4c9f21a)
```

Make sure `_testing-prs.json` includes `"pr": 13466` with `"active": true`.

### Starting the dev server

```bash
docker compose up

# Log in as a maintainer
curl -s -c /tmp/ck.txt -X POST http://localhost:8080/account/login.json \
-H "Content-Type: application/json" \
-d '{"username":"openlibrary","password":"openlibrary"}'

# Open http://localhost:8080/status
# Log in as openlibrary / openlibrary
# Hard-refresh (Cmd+Shift+R) to load the updated JS bundle
```

## Testing

```bash
# Python tests (should pass)
uv run --with-requirements requirements_test.txt \
pytest openlibrary/tests/fastapi/test_testing_status.py -q

# JS tests (should pass)
npx jest tests/unit/js/testing-status.test.js

# Lint — all hooks green
pre-commit run --files \
openlibrary/components/TestingEnvironment/TestingRow.vue \
openlibrary/components/TestingEnvironment/utils.js \
openlibrary/macros/TestingEnvironment.html.jinja
```

## Acceptance criteria

- [ ] Hovering a red conflict dot shows "Merge conflict with #N"
- [ ] The old `mergeConflict` string ("Deploy failed (merge conflict)") is removed from `DEFAULT_STRINGS` and the jinja macro
- [ ] `messages.pot` is regenerated
- [ ] All existing Python and JS tests pass
- [ ] No regressions — other rows' dots/tooltips are unchanged

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.