Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
cd353c7
test data update
ievdokdm Feb 23, 2026
f4c319b
chore(conductor): Add new track 'For PreSubmitView move all state cha…
ievdokdm Feb 23, 2026
457dafa
feat(dashboard): Create PresubmitState with basic properties
ievdokdm Feb 23, 2026
2deb247
feat(dashboard): Add update method to PresubmitState
ievdokdm Feb 23, 2026
e87e8d0
feat(dashboard): Implement fetchAvailableShas and fetchGuardStatus in…
ievdokdm Feb 23, 2026
05756b4
test(dashboard): Add comprehensive unit tests for PresubmitState
ievdokdm Feb 23, 2026
9ab5683
conductor(plan): Mark phase 'Phase 1: Foundation' as complete
ievdokdm Feb 23, 2026
50c75b7
feat(dashboard): Provide PresubmitState to the widget tree
ievdokdm Feb 23, 2026
4ddb067
changes after loop detected
ievdokdm Feb 24, 2026
9f3e27d
refactor: Move presubmit view state management and data fetching to a…
ievdokdm Feb 24, 2026
bd309f3
feat: Add URL synchronization for PreSubmitView based on selected SHA…
ievdokdm Feb 25, 2026
1e372d5
feat: Add automatic data refreshing and recent commit fetching to the…
ievdokdm Feb 25, 2026
6fa7578
refactor: Update color opacity application to `withValues(alpha:)` an…
ievdokdm Feb 25, 2026
5be557b
feat: Add a shared utility for generating LUCI build log URLs and int…
ievdokdm Feb 25, 2026
13b563e
style: format `Uri.https` calls and `dartInternalLogBase` for improve…
ievdokdm Feb 25, 2026
8ad336e
Simplify dev presubmit check response by removing random test counts …
ievdokdm Feb 25, 2026
47bde1d
archived conductor track
ievdokdm Feb 25, 2026
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
5 changes: 5 additions & 0 deletions conductor/archive/refactor_presubmit_state_20260223/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Track refactor_presubmit_state_20260223 Context

- [Specification](./spec.md)
- [Implementation Plan](./plan.md)
- [Metadata](./metadata.json)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"track_id": "refactor_presubmit_state_20260223",
"type": "refactor",
"status": "new",
"created_at": "2026-02-23T10:00:00Z",
"updated_at": "2026-02-23T10:00:00Z",
"description": "For PreSubmitView move all state change logic to PresubmitState similarly to how BuildDashboardPage use BuildState"
}
26 changes: 26 additions & 0 deletions conductor/archive/refactor_presubmit_state_20260223/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Implementation Plan - Refactor PreSubmitView State Management

## Phase 1: Foundation - Create PresubmitState [checkpoint: 584afaa]
This phase focuses on creating the new `PresubmitState` class and migrating the core data fetching logic.

- [x] Task: Create `dashboard/lib/state/presubmit.dart` with `PresubmitState` class, including `repo`, `pr`, and `sha` properties.
- [x] Task: Implement initialization and update methods for `repo`, `pr`, and `sha` in `PresubmitState`.
- [x] Task: Implement `fetchAvailableShas` and `fetchGuardStatus` in `PresubmitState`.
- [x] Task: Write unit tests for `PresubmitState` in `dashboard/test/state/presubmit_test.dart`.
- [x] Task: Conductor - User Manual Verification 'Phase 1: Foundation' (Protocol in workflow.md)

## Phase 2: Refactor PreSubmitView
This phase integrates `PresubmitState` into the main `PreSubmitView` widget and removes its local state.

- [x] Task: Update `dashboard/lib/main.dart` or the relevant state provider to instantiate and provide `PresubmitState`.
- [~] Task: Refactor `_PreSubmitViewState` to use `PresubmitState` for context management (repo, pr, sha) and data fetching.
- [ ] Task: Update `dashboard/test/views/presubmit_view_test.dart` to ensure compatibility with the new state management.
- [ ] Task: Conductor - User Manual Verification 'Phase 2: Refactor PreSubmitView' (Protocol in workflow.md)

## Phase 3: Refactor LogViewerPane and Finalize
This phase completes the migration by moving the check details logic and performing final verification.

- [ ] Task: Implement `fetchCheckDetails` and associated state (`selectedCheck`, `checks`) in `PresubmitState`.
- [ ] Task: Refactor `_LogViewerPaneState` in `dashboard/lib/views/presubmit_view.dart` to use `PresubmitState`.
- [ ] Task: Final verification of `PreSubmitView` functionality and test coverage.
- [ ] Task: Conductor - User Manual Verification 'Phase 3: Refactor LogViewerPane and Finalize' (Protocol in workflow.md)
38 changes: 38 additions & 0 deletions conductor/archive/refactor_presubmit_state_20260223/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Specification - Refactor PreSubmitView State Management

## Overview
This track involves refactoring the `PreSubmitView` to move its state and logic into a dedicated `PresubmitState` class, following the pattern used by `BuildDashboardPage` and `BuildState`. This will improve code organization, testability, and consistency across the Cocoon dashboard.

## Goals
- Extract all data fetching and processing logic from `PreSubmitView` into `PresubmitState`.
- Centralize state management for PR summaries, guard statuses, and check details.
- Align the architecture of `PreSubmitView` with the project's established patterns.

## Functional Requirements
- **PresubmitState Class:**
- Inherit from `ChangeNotifier`.
- Hold context properties: `repo`, `pr`, and `sha`.
- Handle fetching available SHAs for a PR (`fetchAvailableShas`).
- Handle fetching guard status for a specific SHA (`fetchGuardStatus`).
- Handle fetching check details/logs (`fetchCheckDetails`).
- Expose state properties: `repo`, `pr`, `sha`, `guardResponse`, `isLoading`, `availableSummaries`, `selectedCheck`, `checks`.
- **PreSubmitView Integration:**
- Use `Provider.of<PresubmitState>` to access state and trigger actions.
- Remove local state variables and direct `CocoonService` calls from `_PreSubmitViewState`.
- **LogViewerPane Integration:**
- Use `PresubmitState` for fetching and displaying check details.
- Remove local state variables from `_LogViewerPaneState`.

## Non-Functional Requirements
- **Consistency:** Follow the adaptive alignment with `BuildState`.
- **Testability:** The new `PresubmitState` should be easily testable in isolation.

## Acceptance Criteria
- `PreSubmitView` functions identically to its current implementation from a user perspective.
- `PreSubmitView` and its sub-widgets do not hold local state for data fetched from the backend.
- Existing tests for `PreSubmitView` pass after the refactor.
- New unit tests for `PresubmitState` cover the migrated logic.

## Out of Scope
- Changing the UI layout or design of `PreSubmitView`.
- Implementing new features or fixing unrelated bugs in `PreSubmitView`.
5 changes: 5 additions & 0 deletions conductor/tracks.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,8 @@
- [x] **Track: Add sha to and show it on presubmit view of dashborad on a header along with PR and author**
*Link: [./archive/presubmit_header_sha_20260217/](./archive/presubmit_header_sha_20260217/)*

---

- [x] **Track: For PreSubmitView move all state change logic to PresubmitState similarly to how BuildDashboardPage use BuildState**
*Link: [./archive/refactor_presubmit_state_20260223/](./archive/refactor_presubmit_state_20260223/)*

5 changes: 5 additions & 0 deletions dashboard/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import 'firebase_options.dart';
import 'service/cocoon.dart';
import 'service/firebase_auth.dart';
import 'state/build.dart';
import 'state/presubmit.dart';
import 'views/build_dashboard_page.dart';
import 'views/presubmit_view.dart';
import 'views/tree_status_page.dart';
Expand Down Expand Up @@ -73,6 +74,10 @@ void main([List<String> args = const <String>[]]) async {
authService: authService,
cocoonService: cocoonService,
),
presubmitState: PresubmitState(
authService: authService,
cocoonService: cocoonService,
),
child: Now(child: const MyApp()),
),
);
Expand Down
176 changes: 131 additions & 45 deletions dashboard/lib/service/dev_cocoon.dart
Original file line number Diff line number Diff line change
Expand Up @@ -182,46 +182,120 @@ class DevelopmentCocoonService implements CocoonService {
required String repo,
required String sha,
}) async {
// Extract a number from the SHA if it's a mock SHA to provide varied data.
// Format: ..._#_mock_sha
final parts = sha.split('_');
final num = (sha.endsWith('_mock_sha') && parts.length > 2)
? parts[parts.length - 3]
: '1';
final prNum = int.tryParse(num) ?? 123;

return CocoonResponse.data(
PresubmitGuardResponse(
prNum: prNum,
checkRunId: 456,
author: _authors[prNum % _authors.length],
guardStatus: switch (num) {
'1' => GuardStatus.succeeded,
'2' => GuardStatus.failed,
_ => GuardStatus.inProgress,
},
stages: [
PresubmitGuardStage(
name: 'Engine',
createdAt: now.millisecondsSinceEpoch,
builds: {
'Mac mac_host_engine $num': TaskStatus.failed,
'Mac mac_ios_engine $num': TaskStatus.waitingForBackfill,
'Linux linux_android_aot_engine $num': TaskStatus.succeeded,
},
),
PresubmitGuardStage(
name: 'Framework',
createdAt: now.millisecondsSinceEpoch,
builds: {
'Linux framework_tests $num': TaskStatus.inProgress,
'Mac framework_tests $num': TaskStatus.cancelled,
'Linux android framework_tests $num': TaskStatus.skipped,
'Windows framework_tests $num': TaskStatus.infraFailure,
},
),
],
),
if (sha == 'cafe5_1_mock_sha') {
return CocoonResponse.data(
PresubmitGuardResponse(
prNum: 123,
checkRunId: 456,
author: _authors[0],
guardStatus: GuardStatus.inProgress,
stages: [
PresubmitGuardStage(
name: 'Engine',
createdAt: now.millisecondsSinceEpoch,
builds: {
'Mac mac_host_engine': TaskStatus.infraFailure,
'Mac mac_ios_engine': TaskStatus.cancelled,
'Linux linux_android_aot_engine': TaskStatus.infraFailure,
},
),
],
),
);
} else if (sha == 'face5_2_mock_sha') {
return CocoonResponse.data(
PresubmitGuardResponse(
prNum: 123,
checkRunId: 789,
author: _authors[1],
guardStatus: GuardStatus.failed,
stages: [
PresubmitGuardStage(
name: 'Engine',
createdAt: now.millisecondsSinceEpoch,
builds: {
'Mac mac_host_engine': TaskStatus.succeeded,
'Mac mac_ios_engine': TaskStatus.cancelled,
'Linux linux_android_aot_engine': TaskStatus.succeeded,
},
),
PresubmitGuardStage(
name: 'Framework',
createdAt: now.millisecondsSinceEpoch,
builds: {
'Linux framework_tests': TaskStatus.succeeded,
'Mac framework_tests': TaskStatus.failed,
'Linux android framework_tests': TaskStatus.skipped,
'Windows framework_tests': TaskStatus.failed,
},
),
],
),
);
} else if (sha == 'decaf_3_mock_sha') {
return CocoonResponse.data(
PresubmitGuardResponse(
prNum: 123,
checkRunId: 1011,
author: _authors[2],
guardStatus: GuardStatus.failed,
stages: [
PresubmitGuardStage(
name: 'Engine',
createdAt: now.millisecondsSinceEpoch,
builds: {
'Mac mac_host_engine': TaskStatus.succeeded,
'Mac mac_ios_engine': TaskStatus.cancelled,
'Linux linux_android_aot_engine': TaskStatus.succeeded,
},
),
PresubmitGuardStage(
name: 'Framework',
createdAt: now.millisecondsSinceEpoch,
builds: {
'Linux framework_tests': TaskStatus.succeeded,
'Mac framework_tests': TaskStatus.waitingForBackfill,
'Linux android framework_tests': TaskStatus.skipped,
'Windows framework_tests': TaskStatus.inProgress,
},
),
],
),
);
} else if (sha == 'deafcab_mock_sha') {
return CocoonResponse.data(
PresubmitGuardResponse(
prNum: 123,
checkRunId: 369,
author: _authors[3],
guardStatus: GuardStatus.succeeded,
stages: [
PresubmitGuardStage(
name: 'Engine',
createdAt: now.millisecondsSinceEpoch,
builds: {
'Mac mac_host_engine': TaskStatus.succeeded,
'Mac mac_ios_engine': TaskStatus.cancelled,
'Linux linux_android_aot_engine': TaskStatus.succeeded,
},
),
PresubmitGuardStage(
name: 'Framework',
createdAt: now.millisecondsSinceEpoch,
builds: {
'Linux framework_tests': TaskStatus.succeeded,
'Mac framework_tests': TaskStatus.succeeded,
'Linux android framework_tests': TaskStatus.skipped,
'Windows framework_tests': TaskStatus.succeeded,
},
),
],
),
);
}
return CocoonResponse.error(
'No presubmit guard data for sha $sha',
statusCode: 404,
);
}

Expand All @@ -237,14 +311,21 @@ class DevelopmentCocoonService implements CocoonService {
buildName: buildName,
creationTime: now.millisecondsSinceEpoch - 10000,
status: 'Succeeded',
buildNumber: 12345,
summary:
'[INFO] Starting task $buildName...\n[SUCCESS] Dependencies installed.\n[INFO] Running build script...\n[SUCCESS] All tests passed (452/452)',
'''
[INFO] Starting task $buildName...
[SUCCESS] Dependencies installed.
[INFO] Running build script...
[SUCCESS] All tests passed (452/452)
''',
),
PresubmitCheckResponse(
attemptNumber: 2,
buildName: buildName,
creationTime: now.millisecondsSinceEpoch,
status: 'Failed',
buildNumber: 67890,
summary:
'[INFO] Starting task $buildName...\n[ERROR] Test failed: Unit Tests',
),
Expand All @@ -259,19 +340,24 @@ class DevelopmentCocoonService implements CocoonService {
}) async {
return CocoonResponse.data([
PresubmitGuardSummary(
commitSha: 'decaf_1_mock_sha',
commitSha: 'decaf_3_mock_sha',
creationTime: now.millisecondsSinceEpoch,
guardStatus: GuardStatus.succeeded,
guardStatus: GuardStatus.inProgress,
),
PresubmitGuardSummary(
commitSha: 'face5_2_mock_sha',
creationTime: now.millisecondsSinceEpoch - 100000,
guardStatus: GuardStatus.failed,
),
PresubmitGuardSummary(
commitSha: 'cafe5_3_mock_sha',
commitSha: 'cafe5_1_mock_sha',
creationTime: now.millisecondsSinceEpoch - 200000,
guardStatus: GuardStatus.inProgress,
guardStatus: GuardStatus.failed,
),
PresubmitGuardSummary(
commitSha: 'deafcab_mock_sha',
creationTime: now.millisecondsSinceEpoch - 300000,
guardStatus: GuardStatus.succeeded,
),
]);
}
Expand Down
16 changes: 0 additions & 16 deletions dashboard/lib/state/build.dart
Original file line number Diff line number Diff line change
Expand Up @@ -420,22 +420,6 @@ class BuildState extends ChangeNotifier {
return true;
}

/// Gets the presubmit guard summaries for a given [repo] and [pr].
Future<List<PresubmitGuardSummary>?> fetchPresubmitGuardSummaries({
required String repo,
required String pr,
}) async {
final response = await cocoonService.fetchPresubmitGuardSummaries(
repo: repo,
pr: pr,
);
if (response.error != null) {
_errors.send('Failed to fetch guard summaries: ${response.error}');
return null;
}
return response.data;
}

/// Updates the suppression status of a test.
///
/// Returns true if the update was successful.
Expand Down
Loading
Loading