Add CI quality gate
This commit is contained in:
@@ -8,6 +8,14 @@ steps:
|
|||||||
- rustup component add rustfmt
|
- rustup component add rustfmt
|
||||||
- cargo fmt -- --check
|
- cargo fmt -- --check
|
||||||
|
|
||||||
|
- name: check
|
||||||
|
image: rust:latest
|
||||||
|
environment:
|
||||||
|
CARGO_HOME: /tmp/cargo
|
||||||
|
commands:
|
||||||
|
- apt-get update -qq && apt-get install -y -qq pkg-config libssl-dev libdbus-1-dev zlib1g-dev > /dev/null 2>&1
|
||||||
|
- cargo check --all-targets --all-features
|
||||||
|
|
||||||
- name: clippy
|
- name: clippy
|
||||||
image: rust:latest
|
image: rust:latest
|
||||||
environment:
|
environment:
|
||||||
@@ -15,7 +23,7 @@ steps:
|
|||||||
commands:
|
commands:
|
||||||
- apt-get update -qq && apt-get install -y -qq pkg-config libssl-dev libdbus-1-dev zlib1g-dev > /dev/null 2>&1
|
- apt-get update -qq && apt-get install -y -qq pkg-config libssl-dev libdbus-1-dev zlib1g-dev > /dev/null 2>&1
|
||||||
- rustup component add clippy
|
- rustup component add clippy
|
||||||
- cargo clippy -- -D warnings
|
- cargo clippy --all-targets --all-features -- -D warnings
|
||||||
|
|
||||||
- name: test
|
- name: test
|
||||||
image: rust:latest
|
image: rust:latest
|
||||||
@@ -23,4 +31,4 @@ steps:
|
|||||||
CARGO_HOME: /tmp/cargo
|
CARGO_HOME: /tmp/cargo
|
||||||
commands:
|
commands:
|
||||||
- apt-get update -qq && apt-get install -y -qq pkg-config libssl-dev libdbus-1-dev zlib1g-dev > /dev/null 2>&1
|
- apt-get update -qq && apt-get install -y -qq pkg-config libssl-dev libdbus-1-dev zlib1g-dev > /dev/null 2>&1
|
||||||
- cargo test
|
- cargo test --all-features
|
||||||
|
|||||||
1
AGENT.md
1
AGENT.md
@@ -13,5 +13,6 @@
|
|||||||
|
|
||||||
- Не запускай `cargo run`, `cargo build`, `cargo test`, `cargo check` без прямой команды пользователя.
|
- Не запускай `cargo run`, `cargo build`, `cargo test`, `cargo check` без прямой команды пользователя.
|
||||||
- Не коммить изменения, пока пользователь не попросит.
|
- Не коммить изменения, пока пользователь не попросит.
|
||||||
|
- Если пользователь попросил тесты/коммит/план до конца, используй quality gate из [DEVELOPMENT.md](DEVELOPMENT.md).
|
||||||
- После функциональной правки дай короткий ручной сценарий проверки.
|
- После функциональной правки дай короткий ручной сценарий проверки.
|
||||||
- Обновляй [CONTEXT.md](CONTEXT.md), только если изменились статус, риск, архитектурное решение или следующий шаг.
|
- Обновляй [CONTEXT.md](CONTEXT.md), только если изменились статус, риск, архитектурное решение или следующий шаг.
|
||||||
|
|||||||
@@ -21,6 +21,20 @@ cargo check
|
|||||||
|
|
||||||
В финальном ответе после изменения укажи, какие cargo-команды не запускались, и дай минимальную ручную проверку.
|
В финальном ответе после изменения укажи, какие cargo-команды не запускались, и дай минимальную ручную проверку.
|
||||||
|
|
||||||
|
## Quality Gate
|
||||||
|
|
||||||
|
Если пользователь прямо попросил проверить, закоммитить или выполнить план с тестами, используй тот же набор проверок, что и CI:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo fmt -- --check
|
||||||
|
cargo check --all-targets --all-features
|
||||||
|
cargo clippy --all-targets --all-features -- -D warnings
|
||||||
|
cargo test --all-features
|
||||||
|
git diff --check
|
||||||
|
```
|
||||||
|
|
||||||
|
Перед коммитом не оставляй `*.snap.new` файлы.
|
||||||
|
|
||||||
## Scope
|
## Scope
|
||||||
|
|
||||||
- Делай одну логическую правку за раз.
|
- Делай одну логическую правку за раз.
|
||||||
|
|||||||
@@ -43,9 +43,7 @@ fn benchmark_format_simple_text(c: &mut Criterion) {
|
|||||||
let entities = vec![];
|
let entities = vec![];
|
||||||
|
|
||||||
c.bench_function("format_simple_text", |b| {
|
c.bench_function("format_simple_text", |b| {
|
||||||
b.iter(|| {
|
b.iter(|| format_text_with_entities(black_box(&text), black_box(&entities), Color::White));
|
||||||
format_text_with_entities(black_box(&text), black_box(&entities), Color::White)
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,9 +51,7 @@ fn benchmark_format_markdown_text(c: &mut Criterion) {
|
|||||||
let (text, entities) = create_text_with_entities();
|
let (text, entities) = create_text_with_entities();
|
||||||
|
|
||||||
c.bench_function("format_markdown_text", |b| {
|
c.bench_function("format_markdown_text", |b| {
|
||||||
b.iter(|| {
|
b.iter(|| format_text_with_entities(black_box(&text), black_box(&entities), Color::White));
|
||||||
format_text_with_entities(black_box(&text), black_box(&entities), Color::White)
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,9 +75,7 @@ fn benchmark_format_long_text(c: &mut Criterion) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.bench_function("format_long_text_with_100_entities", |b| {
|
c.bench_function("format_long_text_with_100_entities", |b| {
|
||||||
b.iter(|| {
|
b.iter(|| format_text_with_entities(black_box(&text), black_box(&entities), Color::White));
|
||||||
format_text_with_entities(black_box(&text), black_box(&entities), Color::White)
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -216,11 +216,11 @@ Target files:
|
|||||||
|
|
||||||
Steps:
|
Steps:
|
||||||
|
|
||||||
- [ ] Add CI steps for `cargo check --all-targets --all-features`.
|
- [x] Add CI steps for `cargo check --all-targets --all-features`.
|
||||||
- [ ] Add CI steps for `cargo clippy --all-targets --all-features -- -D warnings`.
|
- [x] Add CI steps for `cargo clippy --all-targets --all-features -- -D warnings`.
|
||||||
- [ ] Add CI steps for `cargo test --all-features`.
|
- [x] Add CI steps for `cargo test --all-features`.
|
||||||
- [ ] Document the same commands in `DEVELOPMENT.md` or `AGENT.md`.
|
- [x] Document the same commands in `DEVELOPMENT.md` or `AGENT.md`.
|
||||||
- [ ] Keep CI commands aligned with the commands used by agents and humans locally.
|
- [x] Keep CI commands aligned with the commands used by agents and humans locally.
|
||||||
|
|
||||||
Acceptance criteria:
|
Acceptance criteria:
|
||||||
|
|
||||||
@@ -231,13 +231,13 @@ Acceptance criteria:
|
|||||||
|
|
||||||
Before considering the refactor layer complete:
|
Before considering the refactor layer complete:
|
||||||
|
|
||||||
- [ ] `cargo check --all-targets --all-features` passes.
|
- [x] `cargo check --all-targets --all-features` passes.
|
||||||
- [ ] `cargo clippy --all-targets --all-features -- -D warnings` passes.
|
- [x] `cargo clippy --all-targets --all-features -- -D warnings` passes.
|
||||||
- [ ] `cargo test --all-features` passes.
|
- [x] `cargo test --all-features` passes.
|
||||||
- [ ] `git diff --check` passes.
|
- [x] `git diff --check` passes.
|
||||||
- [ ] No unexpected `*.snap.new` files remain.
|
- [x] No unexpected `*.snap.new` files remain.
|
||||||
- [ ] `rg -n "current_chat_messages_mut|chats_mut|folders_mut|pending_user_ids_mut|user_cache_mut" src/tdlib` shows only intentionally contained internal access.
|
- [x] `rg -n "current_chat_messages_mut|chats_mut|folders_mut|pending_user_ids_mut|user_cache_mut" src/tdlib` shows only intentionally contained internal access.
|
||||||
- [ ] `rg -n "unwrap\\(|expect\\(|panic!\\(" src` has no risky production UI or TDLib data-path panics left.
|
- [x] `rg -n "unwrap\\(|expect\\(|panic!\\(" src` has no risky production UI or TDLib data-path panics left.
|
||||||
|
|
||||||
## Recommended Commit Order
|
## Recommended Commit Order
|
||||||
|
|
||||||
|
|||||||
@@ -33,17 +33,12 @@ pub fn acquire_lock(account_name: &str) -> Result<File, String> {
|
|||||||
|
|
||||||
// Ensure parent directory exists
|
// Ensure parent directory exists
|
||||||
if let Some(parent) = lock_path.parent() {
|
if let Some(parent) = lock_path.parent() {
|
||||||
fs::create_dir_all(parent).map_err(|e| {
|
fs::create_dir_all(parent)
|
||||||
format!(
|
.map_err(|e| format!("Не удалось создать директорию для lock-файла: {}", e))?;
|
||||||
"Не удалось создать директорию для lock-файла: {}",
|
|
||||||
e
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let file = File::create(&lock_path).map_err(|e| {
|
let file = File::create(&lock_path)
|
||||||
format!("Не удалось создать lock-файл {}: {}", lock_path.display(), e)
|
.map_err(|e| format!("Не удалось создать lock-файл {}: {}", lock_path.display(), e))?;
|
||||||
})?;
|
|
||||||
|
|
||||||
file.try_lock_exclusive().map_err(|_| {
|
file.try_lock_exclusive().map_err(|_| {
|
||||||
format!(
|
format!(
|
||||||
|
|||||||
@@ -74,4 +74,3 @@ pub async fn select_folder<T: TdClientTrait>(app: &mut App<T>, folder_idx: usize
|
|||||||
app.chat_list_state.select(Some(0));
|
app.chat_list_state.select(Some(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,10 +21,7 @@ pub mod modal;
|
|||||||
pub mod profile;
|
pub mod profile;
|
||||||
pub mod search;
|
pub mod search;
|
||||||
|
|
||||||
pub use chat_loader::{
|
pub use chat_loader::{process_chat_init_events, process_pending_chat_init};
|
||||||
process_chat_init_events,
|
|
||||||
process_pending_chat_init,
|
|
||||||
};
|
|
||||||
pub use clipboard::*;
|
pub use clipboard::*;
|
||||||
pub use global::*;
|
pub use global::*;
|
||||||
pub use profile::get_available_actions_count;
|
pub use profile::get_available_actions_count;
|
||||||
|
|||||||
@@ -56,12 +56,7 @@ pub fn render<T: TdClientTrait>(f: &mut Frame, area: Rect, app: &App<T>) {
|
|||||||
if idx > 0 {
|
if idx > 0 {
|
||||||
lines.push(Line::from(""));
|
lines.push(Line::from(""));
|
||||||
}
|
}
|
||||||
lines.extend(render_message_item(
|
lines.extend(render_message_item(msg, idx == selected_index, content_width, 3));
|
||||||
msg,
|
|
||||||
idx == selected_index,
|
|
||||||
content_width,
|
|
||||||
3,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if lines.is_empty() {
|
if lines.is_empty() {
|
||||||
|
|||||||
@@ -80,12 +80,7 @@ pub fn render<T: TdClientTrait>(f: &mut Frame, area: Rect, app: &App<T>) {
|
|||||||
if idx > 0 {
|
if idx > 0 {
|
||||||
lines.push(Line::from(""));
|
lines.push(Line::from(""));
|
||||||
}
|
}
|
||||||
lines.extend(render_message_item(
|
lines.extend(render_message_item(msg, idx == selected_index, content_width, 2));
|
||||||
msg,
|
|
||||||
idx == selected_index,
|
|
||||||
content_width,
|
|
||||||
2,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use chrono::{DateTime, Local, NaiveDate, Utc};
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use chrono::FixedOffset;
|
use chrono::FixedOffset;
|
||||||
|
use chrono::{DateTime, Local, NaiveDate, Utc};
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
pub trait LocalTimeSource {
|
pub trait LocalTimeSource {
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ fn snapshot_chat_with_unread_count() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_incoming_message_shows_unread_badge() {
|
fn test_incoming_message_shows_unread_badge() {
|
||||||
|
|
||||||
// Создаём чат БЕЗ непрочитанных сообщений
|
// Создаём чат БЕЗ непрочитанных сообщений
|
||||||
let chat = TestChatBuilder::new("Friend", 999)
|
let chat = TestChatBuilder::new("Friend", 999)
|
||||||
.unread_count(0)
|
.unread_count(0)
|
||||||
@@ -485,7 +484,6 @@ fn snapshot_chat_search_mode() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn snapshot_chat_with_online_status() {
|
fn snapshot_chat_with_online_status() {
|
||||||
|
|
||||||
let chat = TestChatBuilder::new("Alice", 123)
|
let chat = TestChatBuilder::new("Alice", 123)
|
||||||
.last_message("Hey there!")
|
.last_message("Hey there!")
|
||||||
.build();
|
.build();
|
||||||
|
|||||||
@@ -144,19 +144,13 @@ impl TestAppBuilder {
|
|||||||
|
|
||||||
/// Добавить сообщение для чата
|
/// Добавить сообщение для чата
|
||||||
pub fn with_message(mut self, chat_id: i64, message: MessageInfo) -> Self {
|
pub fn with_message(mut self, chat_id: i64, message: MessageInfo) -> Self {
|
||||||
self.messages
|
self.messages.entry(chat_id).or_default().push(message);
|
||||||
.entry(chat_id)
|
|
||||||
.or_default()
|
|
||||||
.push(message);
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Добавить несколько сообщений для чата
|
/// Добавить несколько сообщений для чата
|
||||||
pub fn with_messages(mut self, chat_id: i64, messages: Vec<MessageInfo>) -> Self {
|
pub fn with_messages(mut self, chat_id: i64, messages: Vec<MessageInfo>) -> Self {
|
||||||
self.messages
|
self.messages.entry(chat_id).or_default().extend(messages);
|
||||||
.entry(chat_id)
|
|
||||||
.or_default()
|
|
||||||
.extend(messages);
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user