diff --git a/docs/page.md b/docs/page.md index 00627fd..2d3c8af 100644 --- a/docs/page.md +++ b/docs/page.md @@ -84,9 +84,10 @@ issues are marked `ships anyway` in the list. A chosen issue that links only to it has nothing to ship there, such as `SHOP-150 not merged`. Services no chosen issue touches are dimmed, and projects the issues link to that are not in the report are listed under the services. -Unticking an issue clears the picks only it needed. A pick made by hand stays until the chosen issues change, and the -line says which chosen issues it does not ship. The address keeps the issues before the picks, as -`issues=SHOP-140,SHOP-141&team/api=2.5.0`. +Unticking an issue clears the picks only it needed. It works the other way too: clearing a pick, or picking an older +tag that does not ship a chosen issue, unticks that issue, and the picks only it needed in other services go with it. +An address whose picks miss a chosen issue loads with the issue unticked. The address keeps the issues before the +picks, as `issues=SHOP-140,SHOP-141&team/api=2.5.0`. ## Release diff --git a/release_scope/_static/index.html b/release_scope/_static/index.html index 1beb4a3..de297d6 100644 --- a/release_scope/_static/index.html +++ b/release_scope/_static/index.html @@ -210,9 +210,6 @@
- - - @@ -548,7 +545,6 @@ planAlso: "also ships", planNoTag: "{keys}: no tag yet.", planElsewhere: "{items}, nothing to pick", - planMissed: "{tag} does not ship {keys}", }, ru: { language: "Язык", @@ -649,7 +645,6 @@ planAlso: "также войдут", planNoTag: "{keys}: тега ещё нет.", planElsewhere: "{items}, выбирать нечего", - planMissed: "{tag} не содержит {keys}", }, }; @@ -956,13 +951,6 @@ const candidate = this.pickOf(service); return candidate ? candidate.jira_keys.map((item) => item.key).filter((key) => !this.chosen.includes(key)) : []; }, - missedBy(service) { - const tag = this.picks[service.project]; - if (!tag || !this.planOf(service)) return []; - const picked = service.rows.findIndex((row) => row.tags.some((item) => item.name === tag)); - return this.chosen.filter((key) => - this.reach[key].some((item) => item.project === service.project && item.state === "tag" && picked > item.index)); - }, shipsAnyway(key) { return !this.chosen.includes(key) && this.picked.some(({ candidate }) => candidate.jira_keys.some((item) => item.key === key)); }, @@ -1011,9 +999,21 @@ pick(service, tag, element) { this.picks[service.project] = tag; + this.untickMissed(service); element.closest("details").open = false; this.writeHash(); }, + untickMissed(service) { + const tag = this.picks[service.project]; + const picked = tag ? service.rows.findIndex((row) => row.tags.some((item) => item.name === tag)) : -1; + const missed = this.chosen.filter((key) => + this.reach[key].some((item) => item.project === service.project && item.state === "tag" && (picked === -1 || picked > item.index))); + if (!missed.length) return; + this.chosen = this.chosen.filter((key) => !missed.includes(key)); + this.applyIssues(); + this.picks[service.project] = tag; + delete this.autoPicks[service.project]; + }, closeServices() { for (const item of document.querySelectorAll("details.service[open]")) item.open = false; }, @@ -1040,6 +1040,7 @@ this.picks[service.project] = known ? tag : ""; if (known) wanted.delete(service.project); } + for (const service of this.pickable) this.untickMissed(service); } this.ignored = [ ...issues.filter((key) => !(key in this.reach)), diff --git a/tests/test_browser.py b/tests/test_browser.py index fb75d6e..cefb0b3 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -131,3 +131,41 @@ def test_demo_screenshot_shows_an_issue_with_its_picks( assert output.read_bytes().startswith(b"\x89PNG") expect(page.locator("details.service .chip:visible > span")).to_have_text(["2.5.0", "1.9.0"]) assert errors == [] + + +def test_clearing_an_issue_pick_unticks_the_issue_and_survives_a_reload( + page: Page, site: str, errors: list[str] +) -> None: + page.goto(site) + _issue(page, "SHOP-12").check() + + page.locator("details.service .chip").get_by_role("button").click() + + expect(_issue(page, "SHOP-12")).not_to_be_checked() + expect(page.locator("details.service .chip")).to_be_hidden() + expect(page).not_to_have_url(re.compile("#")) + page.reload() + expect(page.locator("details.service .chip")).to_be_hidden() + assert errors == [] + + +def test_picking_an_older_tag_unticks_the_issues_it_misses(page: Page, site: str, errors: list[str]) -> None: + page.goto(site) + _issue(page, "SHOP-12").check() + + page.locator("details.service summary").click() + page.locator(".tag", has_text="1.1.0").get_by_role("button").click() + + expect(_issue(page, "SHOP-12")).not_to_be_checked() + expect(page.locator("details.service .chip > span")).to_have_text("1.1.0") + expect(page).to_have_url(re.compile(r"#team/svc=1\.1\.0$")) + assert errors == [] + + +def test_an_address_with_an_older_pick_unticks_the_issues_it_misses(page: Page, site: str, errors: list[str]) -> None: + page.goto(f"{site}#issues=SHOP-12&team/svc=1.1.0") + + expect(_issue(page, "SHOP-12")).not_to_be_checked() + expect(page.locator("details.service .chip > span")).to_have_text("1.1.0") + expect(page).to_have_url(re.compile(r"#team/svc=1\.1\.0$")) + assert errors == []