diff --git a/+labkit/+app/+internal/+launcher/dispatch.m b/+labkit/+app/+internal/+launcher/dispatch.m index b95134bd..7a474944 100644 --- a/+labkit/+app/+internal/+launcher/dispatch.m +++ b/+labkit/+app/+internal/+launcher/dispatch.m @@ -143,12 +143,13 @@ maintenanceGrid.Padding = [5 5 5 5]; maintenanceGrid.RowSpacing = 5; maintenanceGrid.ColumnSpacing = 6; -docsToolButton = uibutton(maintenanceGrid, "Text", "Local Documentation"); +docsToolButton = uibutton(maintenanceGrid, ... + "Text", "Generate Local Documentation"); codeButton = uibutton(maintenanceGrid, "Text", "Run Code Analyzer"); profileButton = uibutton(maintenanceGrid, "Text", "Profile Selected App"); cleanButton = uibutton(maintenanceGrid, "Text", "Clean Artifacts"); docsToolButton.Tooltip = ... - "Open local documentation, or offer to generate it when missing."; + "Rebuild the ignored local site from current documentation sources."; codeButton.Tooltip = ... "Run MATLAB Code Analyzer and write the repository report."; profileButton.Tooltip = ... @@ -211,7 +212,7 @@ releaseButton.ButtonPushedFcn = @(~, ~) manageVersion("stable"); versionsButton.ButtonPushedFcn = @(~, ~) manageVersion("browse"); cleanButton.ButtonPushedFcn = @(~, ~) runMaintenance("clean"); -docsToolButton.ButtonPushedFcn = @(~, ~) openDocumentation("local"); +docsToolButton.ButtonPushedFcn = @(~, ~) runMaintenance("docs"); codeButton.ButtonPushedFcn = @(~, ~) runMaintenance("codecheck"); profileButton.ButtonPushedFcn = @(~, ~) runMaintenance("profile"); packageButton.ButtonPushedFcn = @(~, ~) packageChecked("source"); @@ -332,24 +333,13 @@ function openDocumentation(source) app.command + "..."); try page = documentationPage(root, app.command, source); - catch cause - if source == "local" && string(cause.identifier) == ... - "labkit:app:internal:launcher:LocalDocumentationMissing" - [page, source] = resolveMissingLocalDocumentation(app); - if strlength(page) == 0 - setStatus("Local documentation action cancelled."); - endAction(); - return; - end - else - setStatus("Documentation unavailable: " + failureText(cause)); - endAction(); - return; - end - end - try if launcherGuiTestMode() ~= "hidden" - web(page, "-browser"); + browserStatus = web(char(page), "-browser"); + if browserStatus ~= 0 + error( ... + "labkit:app:internal:launcher:BrowserUnavailable", ... + "The system browser could not open the documentation."); + end end setStatus("Opened " + source + " documentation for " + ... app.command + "."); @@ -359,23 +349,6 @@ function openDocumentation(source) endAction(); end - function [page, source] = resolveMissingLocalDocumentation(app) - source = "local"; - choice = localDocumentationChoice(fig, app.command); - switch choice - case "Generate Local" - callTool(root, fullfile("tools", "docs"), ... - "renderLabKitDocs", fullfile(root, "docs"), ... - fullfile(root, "site")); - page = documentationPage(root, app.command, "local"); - case "Open Online" - source = "online"; - page = documentationPage(root, app.command, "online"); - otherwise - page = ""; - end - end - function manageVersion(mode) if state.busy return; @@ -412,6 +385,11 @@ function runMaintenance(kind) "ProgressFcn", @reportProgress); setStatus("Clean Artifacts complete: " + ... string(result.removedCount) + " target(s) removed."); + case "docs" + callTool(root, fullfile("tools", "docs"), ... + "renderLabKitDocs", fullfile(root, "docs"), ... + fullfile(root, "site")); + setStatus("Local documentation generated from current sources."); case "codecheck" callTool(root, fullfile("tools", "codecheck"), ... "runCodecheckReport", root, ... @@ -538,7 +516,7 @@ function updateInfo() info = struct( ... "name", "labkit_launcher", ... "displayName", "LabKit App Launcher", ... - "version", "1.8.0", ... + "version", "1.8.1", ... "updated", "2026-07-30"); end @@ -967,23 +945,6 @@ function addPathIfMissing(folder, varargin) end end -function choice = localDocumentationChoice(fig, command) -if launcherGuiTestMode() == "hidden" - choice = "Open Online"; - if isappdata(groot, "labkitLauncherDocumentationChoice") - choice = string(getappdata( ... - groot, "labkitLauncherDocumentationChoice")); - end - return; -end -choice = string(uiconfirm(fig, ... - "Local documentation is not available for " + command + ... - ". Generate it now, or open the online documentation?", ... - "Local Documentation", ... - "Options", {"Open Online", "Generate Local", "Cancel"}, ... - "DefaultOption", 1, "CancelOption", 3)); -end - function tf = isStructuralStartupFailure(cause) id = string(cause.identifier); tf = startsWith(id, "MATLAB:UndefinedFunction") || ... diff --git a/+labkit/AGENTS.md b/+labkit/AGENTS.md index 280ad699..b218e4d1 100644 --- a/+labkit/AGENTS.md +++ b/+labkit/AGENTS.md @@ -102,8 +102,7 @@ Use `labkittest.explain` to find the exact owner and contract. `Typical Call:`. - Private helpers document caller, shapes, side effects, and assumptions. - An app-facing facade change updates its `version.m`, owning manual, and one - component history record before the `develop` or `hotfix/*` PR is - merge-ready. + component history record before the `develop` PR is merge-ready. ## Validation diff --git a/.github/scripts/check_integration_policy.py b/.github/scripts/check_integration_policy.py index 43dfdb2f..b0389cdd 100644 --- a/.github/scripts/check_integration_policy.py +++ b/.github/scripts/check_integration_policy.py @@ -111,10 +111,9 @@ def validate_branch( if event_name != "pull_request" or base_ref != "main": return [] errors = [] - if head_ref != "develop" and not head_ref.startswith("hotfix/"): + if head_ref != "develop": errors.append( - "Pull requests to main must come from develop or hotfix/*, " - f'not "{head_ref}".' + f'Pull requests to main must come from develop, not "{head_ref}".' ) if head_repository != repository: errors.append( diff --git a/.github/scripts/test_check_integration_policy.py b/.github/scripts/test_check_integration_policy.py index b4bf74d5..1adac525 100644 --- a/.github/scripts/test_check_integration_policy.py +++ b/.github/scripts/test_check_integration_policy.py @@ -14,15 +14,12 @@ class IntegrationPolicyTest(unittest.TestCase): - def test_main_pull_request_requires_integration_or_hotfix_branch(self): + def test_main_pull_request_requires_repository_develop_branch(self): self.assertEqual( MODULE.validate_branch( "pull_request", "main", "feature", "owner/repo", "owner/repo" ), - [ - "Pull requests to main must come from develop or hotfix/*, " - 'not "feature".' - ], + ['Pull requests to main must come from develop, not "feature".'], ) self.assertEqual( MODULE.validate_branch( @@ -42,7 +39,7 @@ def test_main_pull_request_requires_integration_or_hotfix_branch(self): MODULE.validate_branch( "pull_request", "main", "hotfix/export", "owner/repo", "owner/repo" ), - [], + ['Pull requests to main must come from develop, not "hotfix/export".'], ) def test_direct_semantic_steps_accept_only_one_public_transition(self): diff --git a/AGENTS.md b/AGENTS.md index 6b66c91a..04f92c34 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -137,8 +137,8 @@ tests, history, and details out of the public repository. - Run the smallest source-aligned test during branch iteration. Before a branch is ready for PR review, do not run broad changed-file or full-suite gates; use focused fast tests for the current small step. Run `changedFast` once - when preparing `develop` or a `hotfix/*` branch for PR review. There is no - conservative local changed task; required PR CI owns complete validation. + when preparing `develop` for PR review. There is no conservative local + changed task; required PR CI owns complete validation. The protected main-push run repeats only policy and the aggregate gate for the exact squash commit because its tree is the already-validated PR result. - After failure, fix and rerun the narrowest failed file, method, or suite; do not repeatedly @@ -163,9 +163,10 @@ tests, history, and details out of the public repository. ## Git workflow 1. Inspect status and alignment before editing. Preserve unrelated user work. - Ordinary work starts on the permanent `develop` branch after fetching and - confirming that it contains `origin/main`. Never edit or commit directly on - `main`, including for documentation, CI, release preparation, and bug fixes. + All work starts on the canonical `develop` branch after fetching and + confirming that it was created from the current `origin/main`. Never edit + or commit directly on `main`, including for documentation, CI, release + preparation, emergency repairs, and bug fixes. 2. When a multi-commit migration needs a roadmap, write it in `.agents/migration_guide.md` as a standalone `develop` checkpoint before implementation. Do not add a future-state migration page under `docs/`. @@ -176,25 +177,21 @@ tests, history, and details out of the public repository. delivery stream. Push completed checkpoints promptly. Once a `develop -> main` PR opens, freeze `develop` until the PR is merged or closed; do not mix later work into its moving head. -4. A production emergency may use a short-lived `hotfix/` branch - created from aligned `origin/main`. Keep it bounded to the repair, validate - it like `develop`, and merge it only through a `hotfix/* -> main` PR. - Ordinary features, maintenance, documentation, and CI work are not hotfixes. -5. Keep branch work stable with small logical purpose-based commits and focused +4. Keep branch work stable with small logical purpose-based commits and focused validation. Prepare user docs, component versions, and structured history as the single net change that the PR will squash into; do not accumulate release semantics from intermediate branch commits. -6. Main accepts PRs only from the repository-owned `develop` or `hotfix/*` - branch. Run `changedFast` once before final review, inspect required PR CI, - and read only failing logs. Squash-merge with an explicit compliant subject. -7. After the merge, inspect the exact lightweight main-push policy gate once +5. Main accepts PRs only from the repository-owned `develop` branch. Run + `changedFast` once before final review, inspect required PR CI, and read only + failing logs. Squash-merge with an explicit compliant subject. +6. After the merge, inspect the exact lightweight main-push policy gate once and complete any authorized release from that exact commit. Do not repeat - the MATLAB matrix already required on the up-to-date PR. Then fetch, merge - `origin/main` into `develop`, verify that `origin/main` is an ancestor and - that the two branch trees have no diff, and push the sync merge before new - work starts. After a hotfix sync, delete only the merged `hotfix/*` branch; - never delete `develop`. -8. Never force-push without explicit approval. Stop and report permission, + the MATLAB matrix already required on the up-to-date PR. Before deleting + `develop`, verify its PR is merged, it has no unmerged commits, and no open + PR depends on it. Delete local and remote `develop`, recreate both at the + exact new `origin/main` commit, restore branch protection, and verify + `develop == origin/main` before new work starts. Never create a sync commit. +7. Never force-push without explicit approval. Stop and report permission, protection, review, CI, sync, or cleanup blockers rather than bypassing them. Branch protection must require `CI Gate`, PR review flow, linear main history, and conversation resolution for administrators as well as ordinary @@ -227,7 +224,7 @@ explicit compliant squash subject; do not rely on GitHub defaults. and release records. Do not encode versions in package, folder, file, function, class, type, protocol, test, or current-architecture names; use one stable semantic name and let the version contract express compatibility. -- Before a `develop` or `hotfix/*` PR is merge-ready, source changes to a +- Before a `develop` PR is merge-ready, source changes to a versioned app/facade or launcher update its source version, owning manual, and one structured component history record. Compare the PR base and head: each existing component advances by exactly one direct patch, minor, or diff --git a/apps/AGENTS.md b/apps/AGENTS.md index 2289443d..826767ee 100644 --- a/apps/AGENTS.md +++ b/apps/AGENTS.md @@ -122,7 +122,7 @@ find the exact owner and contract; App authors never invent test paths. - Source or user-visible behavior changes update `AppVersion` and `Updated` in the App's `definition.m`, owned documentation, and component history before - the `develop` or `hotfix/*` PR is merge-ready. + the `develop` PR is merge-ready. - Test GUI wiring semantically: controls, choices, events, workflow outcomes, viewport behavior, and traces. A synthetic project is validated headlessly and launched through the native adapter; test calculations and exports diff --git a/docs/apps/labkit-core/launcher/README.md b/docs/apps/labkit-core/launcher/README.md index 6a388ccf..860c8750 100644 --- a/docs/apps/labkit-core/launcher/README.md +++ b/docs/apps/labkit-core/launcher/README.md @@ -26,7 +26,7 @@ tool availability, or the active maintenance operation. | Versions and Install | **Latest** | Installs the current `main` branch archive. | | Versions and Install | **Release** | Installs the latest stable GitHub release. | | Versions and Install | **Versions** | Opens the release, tag, and commit selector for deliberate upgrade or rollback. | -| Development and Maintenance | **Local Documentation** | Opens the selected app's local manual. If `site/` is missing, offers **Open Online** (the default), **Generate Local**, or **Cancel**. | +| Development and Maintenance | **Generate Local Documentation** | Rebuilds the complete ignored `site/` folder from the current Markdown and public MATLAB help. It does not open a page or choose between online and local help. | | Development and Maintenance | **Run Code Analyzer** | Scans the checkout and writes JSON and HTML Code Analyzer reports. | | Development and Maintenance | **Profile Selected App** | Starts the selected app under the MATLAB profiler and saves its report when the app closes. | | Development and Maintenance | **Clean Artifacts** | Removes ignored generated reports under `artifacts/`; it does not delete app projects or exported laboratory results. | @@ -82,8 +82,9 @@ Documentation lookup uses the discovered public App folder and the unique path-conventional manual at `docs/apps///README.md`. It does not require a separately maintained App catalog. The visible launcher opens online documentation by default. Local generation is an explicit source-checkout -convenience and writes the ignored `site/` folder; the deployed site is -generated independently from `main` by GitHub Actions. +convenience: **Generate Local Documentation** always rebuilds the ignored +`site/` folder and reports completion without opening a browser. The deployed +site is generated independently from `main` by GitHub Actions. ## App Discovery diff --git a/docs/development/maintain-and-release/documentation.md b/docs/development/maintain-and-release/documentation.md index 153748e1..748b168c 100644 --- a/docs/development/maintain-and-release/documentation.md +++ b/docs/development/maintain-and-release/documentation.md @@ -299,8 +299,9 @@ folder is ignored by Git and may be deleted or regenerated at any time. The Documentation Pages workflow performs the same build from the exact `main` source and deploys the resulting artifact to GitHub Pages. It never commits generated files back to `main` or `develop`. The visible Launcher opens -that online site by default. Its **Local Documentation** action offers to -generate `site/` when a selected local page is absent. +that online site by default. Its **Generate Local Documentation** maintenance +action always rebuilds the complete ignored `site/` folder from current +sources; it does not open a page or choose a reading destination. For direct MATLAB syntax, result fields, missing-output reconstruction, and consistency-check behavior, see diff --git a/docs/development/maintain-and-release/release.md b/docs/development/maintain-and-release/release.md index ea95cd65..52b051de 100644 --- a/docs/development/maintain-and-release/release.md +++ b/docs/development/maintain-and-release/release.md @@ -17,19 +17,18 @@ compatibility, choose a major version. If the implementation changes a user workflow without intentionally breaking compatibility, describe it in the release notes so launcher users can choose or roll back versions deliberately. -On the permanent `develop` branch, or on a bounded `hotfix/*` branch created -from `origin/main`, choose each component's final version directly from the PR -base, not from intermediate branch commits. A branch may edit version metadata -while work is evolving, but its merge-ready state must be exactly one -semantic-version step from the mainline baseline: the next patch, the next -minor with patch zero, or the next major with minor and patch zero. The related -component history record describes that direct `main baseline -> PR final` -transition. CI verifies existing App, facade, and launcher transitions before -MATLAB setup. This prevents temporary branch versions from accumulating into -artificial public version jumps. Maintain user documentation with the same -squash-oriented view: it describes the final branch behavior and one net -compatibility transition, not the sequence of intermediate commits used to -develop it. +On the canonical `develop` branch created from `origin/main`, choose each +component's final version directly from the PR base, not from intermediate +branch commits. A branch may edit version metadata while work is evolving, but +its merge-ready state must be exactly one semantic-version step from the +mainline baseline: the next patch, the next minor with patch zero, or the next +major with minor and patch zero. The related component history record +describes that direct `main baseline -> PR final` transition. CI verifies +existing App, facade, and launcher transitions before MATLAB setup. This +prevents temporary branch versions from accumulating into artificial public +version jumps. Maintain user documentation with the same squash-oriented view: +it describes the final branch behavior and one net compatibility transition, +not the sequence of intermediate commits used to develop it. ## Tags @@ -55,11 +54,12 @@ confirmation, an existing tag or release, or the absence of a successful same-commit main CI run prevents tag creation. Ordinary push, pull-request, and documentation workflows never create release tags. -After the PR merge and its exact main-push CI complete, fetch the remote and -merge `origin/main` back into `develop`. Before starting new work, verify that -`origin/main` is an ancestor of `develop` and that their trees have no diff, -then push the sync merge. A merged `hotfix/*` branch is deleted only after this -sync; the permanent `develop` branch is never deleted or force-pushed. +After the PR merge and its exact main-push CI complete, verify that `develop` +has no unmerged commits and no open PR depends on it. Delete local and remote +`develop`, recreate both at the exact new `origin/main` commit, restore its +branch protection, and verify that the two refs resolve to the same SHA before +starting new work. Do not merge main back into develop and do not create a +branch-sync commit. ```bash gh workflow run release.yml --ref main \ diff --git a/docs/development/maintain-and-release/testing.md b/docs/development/maintain-and-release/testing.md index 6d480482..047ae9f1 100644 --- a/docs/development/maintain-and-release/testing.md +++ b/docs/development/maintain-and-release/testing.md @@ -126,8 +126,8 @@ manual boundary. A focused-local result is rapid author feedback, not merge safety evidence; CI runs the full platform profiles. Run focused behavior during iteration. Run `changedFast` once when `develop` -or a `hotfix/*` branch is ready for final PR review. CI owns broad platform -validation; do not repeatedly run broad tasks after each small edit. +is ready for final PR review. CI owns broad platform validation; do not +repeatedly run broad tasks after each small edit. ## Artifacts and Failures @@ -191,9 +191,9 @@ on every required shard. Configure repository branch protection to require policy. It uploads the catalog artifacts even after failure. Coverage is an explicit report, not a duplicate CI gate. -`main` is release-only and accepts pull requests from the repository-owned -permanent `develop` branch or a bounded `hotfix/*` branch. The lightweight -policy job rejects every other PR source before MATLAB setup. It also compares +`main` is release-only and accepts pull requests only from the +repository-owned `develop` branch. The lightweight policy job rejects every +other PR source before MATLAB setup. It also compares the PR base and head for App, facade, and launcher source ownership, direct semantic version steps, and matching component-history transitions. Branch protection separately rejects direct pushes, including administrator pushes. diff --git a/docs/history/records/2026/07/LK-20260730-local-documentation-generation-boundary.md b/docs/history/records/2026/07/LK-20260730-local-documentation-generation-boundary.md new file mode 100644 index 00000000..2c580c1f --- /dev/null +++ b/docs/history/records/2026/07/LK-20260730-local-documentation-generation-boundary.md @@ -0,0 +1,72 @@ +# Local documentation generation boundary + +```labkit-change +id: LK-20260730-local-documentation-generation-boundary +date: 2026-07-30 +sequence: 164 +type: fix +compatibility: compatible +component: `labkit_launcher` | `1.8.0 -> 1.8.1` +scope: Nonblocking and single-purpose local documentation maintenance +``` + +## Context + +The first online-first documentation delivery made the Launcher maintenance +button open an existing local page or synchronously ask whether to generate, +open online, or cancel when that page was absent. The confirmation call used a +return value, which blocks MATLAB execution. On affected desktop versions the +callback could remain at **Opening local documentation** without restoring the +Launcher controls. + +## Decision and rationale + +Keep documentation reading and documentation generation as separate actions. +**Documentation and History** owns online reading. **Generate Local +Documentation** owns one deterministic maintenance operation: rebuild the +complete ignored `site/` folder from current authored sources. It does not open +a browser or display a source-choice dialog. + +This smaller boundary removes the blocking confirmation path, avoids overlap +between two Launcher buttons, and guarantees that selecting local generation +always refreshes stale output rather than merely opening it. + +## Changes + +- Renamed the maintenance action to **Generate Local Documentation**. +- Made every activation call the repository documentation renderer for the + complete `docs/` to `site/` build. +- Removed local-page opening and online/local/cancel prompting from that + maintenance callback. +- Kept the programmatic explicit `"local"` documentation lookup for callers + that need an already-generated filesystem path. + +## User and data impact + +The maintenance button now consistently generates current local help and then +restores the Launcher controls. Online help remains the default reading path. +No App project, input, result, export, or scientific behavior changes. + +## Compatibility and migration + +The change is compatible with existing Launcher startup and online +documentation behavior. Users who want local reading generate the site first, +then open the returned programmatic local path or browse the `site/` folder. + +## Validation + +Launcher specifications verify that the online reading button does not +generate local output and that the local maintenance button calls only the +documentation renderer with the current `docs/` and ignored `site/` roots, +reports completion, and restores controls. + +## Evidence + +The Launcher dispatch implementation, its bounded system specifications, the +Launcher manual, public help, and this record are the reviewable evidence. + +## Known limitations and follow-up + +Automated hidden-GUI checks do not measure documentation rendering time or +prove native browser behavior. The generation action intentionally remains +synchronous so its completion status cannot precede the finished local site. diff --git a/docs/history/records/2026/07/LK-20260730-single-develop-integration-path.md b/docs/history/records/2026/07/LK-20260730-single-develop-integration-path.md new file mode 100644 index 00000000..0c926c12 --- /dev/null +++ b/docs/history/records/2026/07/LK-20260730-single-develop-integration-path.md @@ -0,0 +1,69 @@ +# Single develop integration path + +```labkit-change +id: LK-20260730-single-develop-integration-path +date: 2026-07-30 +sequence: 165 +type: ci +compatibility: compatible +component: `repository` +scope: One integration branch with clean post-merge recreation +``` + +## Context + +Allowing both long-lived develop work and short-lived hotfix branches created +two delivery routes with different naming and validation expectations. +Squash-merging develop and then merging main back into it also retained the +original branch commits, the squash commit, and an additional synchronization +commit, making the integration history progressively harder to read. + +## Decision and rationale + +Use one repository-owned route for every change, including emergency repairs: +`develop -> main`. Main rejects pull requests from every other branch. + +After a develop pull request is merged and its exact main-push gate completes, +delete develop and recreate it at the new main commit. This makes the two refs +identical at the start of every delivery cycle and removes the need for +synchronization commits. Deletion is permitted only after confirming that the +merged pull request contains all develop changes and no open pull request +depends on the branch; branch protection is restored immediately after +recreation. + +## Changes + +- Removed hotfix branches from the documented and executable integration + policy. +- Made the policy check accept only the repository-owned develop branch for a + pull request targeting main. +- Replaced post-merge main-to-develop synchronization with guarded deletion + and exact recreation from main. + +## User and data impact + +This changes repository maintenance only. Product behavior, project data, +scientific results, and exported files are unchanged. + +## Compatibility and migration + +Existing open work must be placed on develop before delivery. There is no +alternate emergency branch path and no reduced validation class for small +repairs. + +## Validation + +Integration-policy tests verify that develop is accepted and feature, fork, +and formerly accepted hotfix heads are rejected. Repository architecture and +documentation consistency checks verify the durable policy and history. + +## Evidence + +The integration policy script and tests, root and scoped agent constitutions, +release/testing manuals, and this record are the reviewable evidence. + +## Known limitations and follow-up + +Deleting a protected develop branch requires a temporary, narrowly scoped +protection change. If GitHub cannot perform that operation safely, stop and +report the blocker rather than substituting a force-push or sync commit. diff --git a/labkit_launcher.m b/labkit_launcher.m index fb04d307..0bcd93cb 100644 --- a/labkit_launcher.m +++ b/labkit_launcher.m @@ -11,6 +11,8 @@ % APPCOMMAND, "local") returns its generated local HTML page and raises % labkit:app:internal:launcher:LocalDocumentationMissing when `site/` has % not been generated. The programmatic form never opens a browser or prompt. +% In the visible Launcher, Generate Local Documentation always rebuilds the +% complete ignored `site/` folder and does not open a documentation page. if nargout > 1 error("labkit_launcher:TooManyOutputs", "labkit_launcher returns at most one output."); diff --git a/tests/specs/system/launcher/LauncherDispatchSpec.m b/tests/specs/system/launcher/LauncherDispatchSpec.m index 89034253..18a546df 100644 --- a/tests/specs/system/launcher/LauncherDispatchSpec.m +++ b/tests/specs/system/launcher/LauncherDispatchSpec.m @@ -122,6 +122,33 @@ function documentationButtonUsesOnlineSourceWithoutGeneratingSite(testCase) delete(fig); delete(cleanup) end + function localDocumentationButtonOnlyRegeneratesCurrentSite(testCase) + root = testCase.applyFixture( ... + matlab.unittest.fixtures.TemporaryFolderFixture).Folder; + command = "labkit_Marker_app"; + writeEntry(root, fullfile("apps", "image_tools", "marker"), ... + command); + writeText(fullfile(root, "docs", "apps", "image_tools", ... + "marker", "README.md"), "# Marker"); + writeToolStub(root, "docs", "renderLabKitDocs"); + cleanup = launcherGuiFixture("renderLabKitDocs"); + + fig = labkit.app.internal.launcher.dispatch(root); + button = findall(fig, "Type", "uibutton", ... + "Text", "Generate Local Documentation"); + button.ButtonPushedFcn(button, []); + + call = getappdata(groot, "fixtureToolCall"); + testCase.verifyEqual(string(call.name), "renderLabKitDocs"); + testCase.verifyEqual(string(call.args), string({ ... + fullfile(root, "docs"), fullfile(root, "site")})); + testCase.verifyTrue(any(contains(launcherText(fig), ... + "Local documentation generated from current sources."))); + testCase.verifyEqual(string(button.Enable), "on"); + testCase.verifyEqual(string(fig.Pointer), "arrow"); + delete(fig); delete(cleanup) + end + function launcherPreservesVisualSelectionAndDoubleClickContracts(testCase) root = testCase.applyFixture( ... matlab.unittest.fixtures.TemporaryFolderFixture).Folder; @@ -181,7 +208,7 @@ function launcherPreservesVisualSelectionAndDoubleClickContracts(testCase) testCase.verifyTrue(all(ismember([ ... "Open Selected App", "Refresh App List", ... "Documentation and History", "Latest", "Release", "Versions", ... - "Local Documentation", "Run Code Analyzer", ... + "Generate Local Documentation", "Run Code Analyzer", ... "Profile Selected App", "Clean Artifacts", ... "Package Checked", "Checked P-code"], buttons))); testCase.verifyFalse(any(buttons == "Open Debug")); @@ -341,7 +368,7 @@ function toolButtonsAdaptExactPublicContracts(testCase) addpath(dottedMaintenance, "-begin"); fig = labkit.app.internal.launcher.dispatch(root); buttons = [ ... - "Clean Artifacts", "Local Documentation", ... + "Clean Artifacts", "Generate Local Documentation", ... "Run Code Analyzer", "Profile Selected App"]; expected = [ ... "cleanLabKitArtifacts", "renderLabKitDocs", ... @@ -352,11 +379,6 @@ function toolButtonsAdaptExactPublicContracts(testCase) if isappdata(groot, "fixtureToolCall") rmappdata(groot, "fixtureToolCall"); end - if index == 2 - setappdata(groot, ... - "labkitLauncherDocumentationChoice", ... - "Generate Local"); - end button = findall(fig, "Type", "uibutton", "Text", buttons(index)); button.ButtonPushedFcn(button, []); call = getappdata(groot, "fixtureToolCall"); @@ -514,7 +536,6 @@ function writeLaunchProbeEntry(filepath, command) "fixtureLaunchedCommand" "fixtureLaunchSnapshot" "fixtureVersionCalls" - "labkitLauncherDocumentationChoice" "fixtureToolCall" "fixtureToolCalls" ];