Merge fix/shared-ecosystem-ci: shared Arch CI image + clippy fixes
All checks were successful
dev release / build (push) Successful in 36s
All checks were successful
dev release / build (push) Successful in 36s
This commit is contained in:
commit
598f85d930
12 changed files with 97 additions and 53 deletions
24
.forgejo/workflows/check.yml
Normal file
24
.forgejo/workflows/check.yml
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
name: check
|
||||||
|
|
||||||
|
# Fast-fail lint/test on short-lived work branches, before it ever reaches
|
||||||
|
# main and triggers a dev-track release build.
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ['feature/**', 'fix/**']
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check:
|
||||||
|
runs-on: [self-hosted, hestia]
|
||||||
|
steps:
|
||||||
|
- name: checkout
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
rm -rf src && mkdir src
|
||||||
|
git clone --branch "${GITHUB_REF_NAME}" --depth 1 \
|
||||||
|
"https://git.breadway.dev/${GITHUB_REPOSITORY}.git" src
|
||||||
|
|
||||||
|
- name: clippy
|
||||||
|
run: cd src && bash ci/build.sh cargo clippy --workspace --all-targets --locked -- -D warnings
|
||||||
|
|
||||||
|
- name: test
|
||||||
|
run: cd src && bash ci/build.sh cargo test --workspace --locked
|
||||||
|
|
@ -19,7 +19,7 @@ jobs:
|
||||||
"https://git.breadway.dev/${GITHUB_REPOSITORY}.git" src
|
"https://git.breadway.dev/${GITHUB_REPOSITORY}.git" src
|
||||||
|
|
||||||
- name: build
|
- name: build
|
||||||
run: cd src && cargo build --release --locked
|
run: cd src && bash ci/build.sh cargo build --release --locked
|
||||||
|
|
||||||
- name: compute dev version
|
- name: compute dev version
|
||||||
run: |
|
run: |
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ jobs:
|
||||||
"https://git.breadway.dev/${GITHUB_REPOSITORY}.git" src
|
"https://git.breadway.dev/${GITHUB_REPOSITORY}.git" src
|
||||||
|
|
||||||
- name: build
|
- name: build
|
||||||
run: cd src && cargo build --release --locked
|
run: cd src && bash ci/build.sh cargo build --release --locked
|
||||||
|
|
||||||
- name: prepare artifacts
|
- name: prepare artifacts
|
||||||
run: |
|
run: |
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ jobs:
|
||||||
"https://git.breadway.dev/${GITHUB_REPOSITORY}.git" src
|
"https://git.breadway.dev/${GITHUB_REPOSITORY}.git" src
|
||||||
|
|
||||||
- name: build
|
- name: build
|
||||||
run: cd src && cargo build --release --locked
|
run: cd src && bash ci/build.sh cargo build --release --locked
|
||||||
|
|
||||||
- name: prepare artifacts
|
- name: prepare artifacts
|
||||||
run: |
|
run: |
|
||||||
|
|
|
||||||
1
ci/bread-ecosystem.rev
Normal file
1
ci/bread-ecosystem.rev
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
620c5a1317a6b57276eabca961facdb78bf510db
|
||||||
20
ci/build.sh
Executable file
20
ci/build.sh
Executable file
|
|
@ -0,0 +1,20 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Delegates to bread-ecosystem's shared CI build image/script, pinned to
|
||||||
|
# the commit in ci/bread-ecosystem.rev — not `main`. bread-ecosystem's CI
|
||||||
|
# files now affect every product's release pipeline, so bumping the pin
|
||||||
|
# is a deliberate act instead of silent drift.
|
||||||
|
#
|
||||||
|
# Usage: ci/build.sh cargo build --release --locked
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
REV="$(cat "${ROOT}/ci/bread-ecosystem.rev")"
|
||||||
|
|
||||||
|
CACHE_DIR="/tmp/bread-ecosystem-ci-${REV}"
|
||||||
|
if [ ! -d "$CACHE_DIR" ]; then
|
||||||
|
rm -rf /tmp/bread-ecosystem-ci-*
|
||||||
|
git clone https://git.breadway.dev/Breadway/bread-ecosystem.git "$CACHE_DIR"
|
||||||
|
git -C "$CACHE_DIR" checkout --quiet "$REV"
|
||||||
|
fi
|
||||||
|
|
||||||
|
bash "${CACHE_DIR}/ci/build.sh" breadmon "$ROOT" "$@"
|
||||||
|
|
@ -103,7 +103,7 @@ pub fn snap_position(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Move the selected monitor by (dx, dy) pixels, then snap.
|
/// Move the selected monitor by (dx, dy) pixels, then snap.
|
||||||
pub fn move_selected(state: &LayoutState, monitors: &mut Vec<Monitor>, dx: i32, dy: i32) {
|
pub fn move_selected(state: &LayoutState, monitors: &mut [Monitor], dx: i32, dy: i32) {
|
||||||
let idx = state.selected;
|
let idx = state.selected;
|
||||||
if idx >= monitors.len() {
|
if idx >= monitors.len() {
|
||||||
return;
|
return;
|
||||||
|
|
@ -116,7 +116,7 @@ pub fn move_selected(state: &LayoutState, monitors: &mut Vec<Monitor>, dx: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Place monitors in a left-to-right row with no gaps.
|
/// Place monitors in a left-to-right row with no gaps.
|
||||||
pub fn auto_arrange(monitors: &mut Vec<Monitor>) {
|
pub fn auto_arrange(monitors: &mut [Monitor]) {
|
||||||
let mut cursor = 0i32;
|
let mut cursor = 0i32;
|
||||||
for m in monitors.iter_mut() {
|
for m in monitors.iter_mut() {
|
||||||
m.x = cursor;
|
m.x = cursor;
|
||||||
|
|
|
||||||
|
|
@ -62,13 +62,12 @@ pub fn find_mirror_modes(source: &Monitor, target: &Monitor) -> Option<MirrorRes
|
||||||
// Approximate: check all source ARs within 5%
|
// Approximate: check all source ARs within 5%
|
||||||
for &s_ar in src_by_ar.keys() {
|
for &s_ar in src_by_ar.keys() {
|
||||||
let s_ratio = ratio_f64(s_ar);
|
let s_ratio = ratio_f64(s_ar);
|
||||||
if (s_ratio - tgt_ratio).abs() / s_ratio < 0.05 {
|
if (s_ratio - tgt_ratio).abs() / s_ratio < 0.05
|
||||||
if !candidates.iter().any(|c| c.src_ar == s_ar && c.tgt_ar == tgt_ar) {
|
&& !candidates.iter().any(|c| c.src_ar == s_ar && c.tgt_ar == tgt_ar) {
|
||||||
candidates.push(Candidate { src_ar: s_ar, tgt_ar, is_exact: false });
|
candidates.push(Candidate { src_ar: s_ar, tgt_ar, is_exact: false });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if candidates.is_empty() {
|
if candidates.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ pub fn from_monitors(name: &str, monitors: &[Monitor]) -> Profile {
|
||||||
|
|
||||||
/// Apply a profile's settings onto a list of live monitors (matched by name).
|
/// Apply a profile's settings onto a list of live monitors (matched by name).
|
||||||
/// Monitors not in the profile are left unchanged.
|
/// Monitors not in the profile are left unchanged.
|
||||||
pub fn apply_to_monitors(profile: &Profile, monitors: &mut Vec<Monitor>) {
|
pub fn apply_to_monitors(profile: &Profile, monitors: &mut [Monitor]) {
|
||||||
for pm in &profile.monitors {
|
for pm in &profile.monitors {
|
||||||
if let Some(m) = monitors.iter_mut().find(|m| m.name == pm.name) {
|
if let Some(m) = monitors.iter_mut().find(|m| m.name == pm.name) {
|
||||||
if let Some(mode) = Mode::parse(&format!("{}Hz", pm.mode)) {
|
if let Some(mode) = Mode::parse(&format!("{}Hz", pm.mode)) {
|
||||||
|
|
|
||||||
|
|
@ -242,15 +242,15 @@ fn handle_field_key(event: KeyEvent, state: &mut AppState) {
|
||||||
state.dirty = true;
|
state.dirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
KeyCode::Char('l') | KeyCode::Right => {
|
KeyCode::Char('l') | KeyCode::Right
|
||||||
if state.config.res_idx + 1 < state.config.resolutions.len() {
|
if state.config.res_idx + 1 < state.config.resolutions.len() =>
|
||||||
|
{
|
||||||
state.config.res_idx += 1;
|
state.config.res_idx += 1;
|
||||||
let m = &state.monitors[idx];
|
let m = &state.monitors[idx];
|
||||||
state.config.update_refreshes(m);
|
state.config.update_refreshes(m);
|
||||||
sync_mode_to_monitor(state, idx);
|
sync_mode_to_monitor(state, idx);
|
||||||
state.dirty = true;
|
state.dirty = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
ConfigField::Refresh => match event.code {
|
ConfigField::Refresh => match event.code {
|
||||||
|
|
@ -261,13 +261,13 @@ fn handle_field_key(event: KeyEvent, state: &mut AppState) {
|
||||||
state.dirty = true;
|
state.dirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
KeyCode::Char('l') | KeyCode::Right => {
|
KeyCode::Char('l') | KeyCode::Right
|
||||||
if state.config.refresh_idx + 1 < state.config.refreshes.len() {
|
if state.config.refresh_idx + 1 < state.config.refreshes.len() =>
|
||||||
|
{
|
||||||
state.config.refresh_idx += 1;
|
state.config.refresh_idx += 1;
|
||||||
sync_mode_to_monitor(state, idx);
|
sync_mode_to_monitor(state, idx);
|
||||||
state.dirty = true;
|
state.dirty = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
ConfigField::Scale => match event.code {
|
ConfigField::Scale => match event.code {
|
||||||
|
|
@ -335,13 +335,13 @@ fn handle_field_key(event: KeyEvent, state: &mut AppState) {
|
||||||
state.dirty = true;
|
state.dirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
KeyCode::Char('l') | KeyCode::Right => {
|
KeyCode::Char('l') | KeyCode::Right
|
||||||
if state.config.mirror_idx + 1 < state.config.mirror_options.len() {
|
if state.config.mirror_idx + 1 < state.config.mirror_options.len() =>
|
||||||
|
{
|
||||||
state.config.mirror_idx += 1;
|
state.config.mirror_idx += 1;
|
||||||
sync_mirror_to_monitor(state, idx);
|
sync_mirror_to_monitor(state, idx);
|
||||||
state.dirty = true;
|
state.dirty = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -259,9 +259,9 @@ pub fn canvas_area(terminal_size: (u16, u16)) -> Rect {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn in_canvas(col: u16, row: u16, canvas: Rect) -> bool {
|
fn in_canvas(col: u16, row: u16, canvas: Rect) -> bool {
|
||||||
col >= canvas.x + 1
|
col > canvas.x
|
||||||
&& col < canvas.x + canvas.width.saturating_sub(1)
|
&& col < canvas.x + canvas.width.saturating_sub(1)
|
||||||
&& row >= canvas.y + 1
|
&& row > canvas.y
|
||||||
&& row < canvas.y + canvas.height.saturating_sub(1)
|
&& row < canvas.y + canvas.height.saturating_sub(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -210,10 +210,11 @@ pub fn handle_mouse(event: MouseEvent, state: &mut AppState) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
r if r >= 7 => {
|
r if r >= 7
|
||||||
// Result panel: Apply is on the line with buttons.
|
// Result panel: Apply is on the line with buttons.
|
||||||
// Rough column check: col < 20 = Apply, col >= 20 = Cancel
|
// Rough column check: col < 20 = Apply, col >= 20 = Cancel
|
||||||
if state.mirror.result.is_some() {
|
&& state.mirror.result.is_some() =>
|
||||||
|
{
|
||||||
let col = event.column;
|
let col = event.column;
|
||||||
if col < 20 {
|
if col < 20 {
|
||||||
// Activate Apply
|
// Activate Apply
|
||||||
|
|
@ -238,7 +239,6 @@ pub fn handle_mouse(event: MouseEvent, state: &mut AppState) {
|
||||||
state.mirror.focused = 0;
|
state.mirror.focused = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue