Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
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
29 changes: 26 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ jobs:
matrix:
os:
- ubuntu-latest
- windows-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
Expand All @@ -48,9 +47,8 @@ jobs:
matrix:
os:
- ubuntu-latest
- windows-latest
env:
V8TR_CI_TARGET_OS: ${{ runner.os }}
V8TR_CI_TARGET_OS: ${{ matrix.os }}
steps:
- name: Checkout repository
uses: actions/checkout@v6
Expand All @@ -73,6 +71,11 @@ jobs:
ACTOR: ${{ github.actor }}
HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
REPOSITORY: ${{ github.repository }}
MATRIX_OS: ${{ matrix.os }}
V8TR_PLATFORM_BUNDLE_URL_LINUX: ${{ secrets.V8TR_PLATFORM_BUNDLE_URL_LINUX }}
V8TR_PLATFORM_BUNDLE_SHA256_LINUX: ${{ secrets.V8TR_PLATFORM_BUNDLE_SHA256_LINUX }}
V8TR_PLATFORM_BUNDLE_URL_WINDOWS: ${{ secrets.V8TR_PLATFORM_BUNDLE_URL_WINDOWS }}
V8TR_PLATFORM_BUNDLE_SHA256_WINDOWS: ${{ secrets.V8TR_PLATFORM_BUNDLE_SHA256_WINDOWS }}
run: |
trusted="true"

Expand All @@ -82,6 +85,26 @@ jobs:
trusted="false"
fi

case "$MATRIX_OS" in
ubuntu-latest)
bundle_url="$V8TR_PLATFORM_BUNDLE_URL_LINUX"
bundle_sha256="$V8TR_PLATFORM_BUNDLE_SHA256_LINUX"
;;
windows-latest)
bundle_url="$V8TR_PLATFORM_BUNDLE_URL_WINDOWS"
bundle_sha256="$V8TR_PLATFORM_BUNDLE_SHA256_WINDOWS"
;;
*)
echo "Unsupported matrix.os: $MATRIX_OS" >&2
exit 2
;;
esac

if [[ -z "$bundle_url" || -z "$bundle_sha256" ]]; then
trusted="false"
echo "V8TR_DESIGNER_ALLOW_MISSING_CONFIG=1" >> "$GITHUB_ENV"
fi

echo "trusted=$trusted" >> "$GITHUB_OUTPUT"

if [[ "$trusted" != "true" ]]; then
Expand Down
7 changes: 7 additions & 0 deletions SKILL/references/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,15 @@ EDT syntax:

```bash
v8-runner syntax edt
v8-runner syntax edt --project <SOURCE_SET>
v8-runner syntax edt --project <SOURCE_SET> --exception-file tools/syntax-check-exception-file.txt
```

Use `--project <SOURCE_SET>` to check one configured EDT source-set by `source-set[].name`
from `v8project.yaml`; it is not the EDT `.project` display name.
Use `--exception-file <PATH>` when a project keeps a legacy syntax exception list; each
non-empty line is matched against parsed EDT issues after normalization.

## Artifacts

Preserve failed test artifacts under:
Expand Down
8 changes: 5 additions & 3 deletions docs/CAPABILITIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ v8-runner test va --feature login --filter-tag @smoke
```bash
v8-runner syntax designer-config [FLAGS]
v8-runner syntax designer-modules [FLAGS]
v8-runner syntax edt [--project <PROJECT>...]
v8-runner syntax edt [--project <SOURCE_SET>...] [--exception-file <PATH>]
```

`designer-config`:
Expand All @@ -202,8 +202,10 @@ v8-runner syntax edt [--project <PROJECT>...]
`edt`:

- Только `builder=DESIGNER`, `format=EDT`.
- Повторяемый `--project`.
- Без `--project` использует дефолтный набор EDT-проектов из конфига.
- Повторяемый `--project`; значение выбирается из `source-set[].name` в `v8project.yaml`.
- Без `--project` использует все EDT source-set из конфига.
- `--exception-file` читает legacy-файл исключений: каждая непустая строка исключает
совпавшую EDT issue после нормализации регистра, пробелов и пунктуации.

## Файлы и артефакты

Expand Down
4 changes: 4 additions & 0 deletions scripts/test/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ live-mcp-http.py
bash scripts/test/ci-rust.sh
```

GitHub Actions currently runs this blocking contract on `ubuntu-latest`.
Re-enabling Windows as blocking requires hardening the existing Unix-assumptive
unit/helper tests first.

### Happy-path CI helper

```bash
Expand Down
25 changes: 13 additions & 12 deletions spec/acceptance/real-environment-validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

## Цель

Начиная с `2026-04-22`, source of truth для real-env happy-path является GitHub Actions workflow [`ci.yml`](../.github/workflows/ci.yml) с matrix на `ubuntu-latest` и `windows-latest`, а локальные скрипты в `scripts/test/*` остаются helper/entrypoint-слоем для этого workflow.
Начиная с `2026-04-22`, source of truth для real-env happy-path является GitHub Actions workflow [`ci.yml`](../.github/workflows/ci.yml), а локальные скрипты в `scripts/test/*` остаются helper/entrypoint-слоем для этого workflow.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Исправьте относительный путь к ci.yml в ссылке.

На Line 5 указан ../.github/workflows/ci.yml, но из spec/acceptance/ корректный путь — ../../.github/workflows/ci.yml; текущая ссылка битая.

🔧 Предлагаемое исправление
-Начиная с `2026-04-22`, source of truth для real-env happy-path является GitHub Actions workflow [`ci.yml`](../.github/workflows/ci.yml), а локальные скрипты в `scripts/test/*` остаются helper/entrypoint-слоем для этого workflow.
+Начиная с `2026-04-22`, source of truth для real-env happy-path является GitHub Actions workflow [`ci.yml`](../../.github/workflows/ci.yml), а локальные скрипты в `scripts/test/*` остаются helper/entrypoint-слоем для этого workflow.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Начиная с `2026-04-22`, source of truth для real-env happy-path является GitHub Actions workflow [`ci.yml`](../.github/workflows/ci.yml), а локальные скрипты в `scripts/test/*` остаются helper/entrypoint-слоем для этого workflow.
Начиная с `2026-04-22`, source of truth для real-env happy-path является GitHub Actions workflow [`ci.yml`](../../.github/workflows/ci.yml), а локальные скрипты в `scripts/test/*` остаются helper/entrypoint-слоем для этого workflow.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@spec/acceptance/real-environment-validation.md` at line 5, The relative link
to the CI workflow is incorrect; update the link string
"../.github/workflows/ci.yml" in the
spec/acceptance/real-environment-validation.md content to the correct relative
path "../../.github/workflows/ci.yml" so the Markdown reference points to the
actual .github/workflows/ci.yml file.


Обязательный smoke-контур для обеих ОС один и тот же:
Обязательный smoke-контур:

1. `build`
2. `syntax/check`
Expand Down Expand Up @@ -47,9 +47,9 @@ bash scripts/test/ci-rust.sh
- `V8_RUNNER_CI_SCOPE=runtime-locks` запускает только lock-focused regression subset
- `V8_RUNNER_CI_SCOPE=happy-path` запускает обязательную цепочку `build -> syntax/check -> test -> package -> deploy-ready artifacts`

### 2. Mandatory Linux/Windows happy-path
### 2. Mandatory happy-path

Назначение: одинаково обязательный smoke для `Linux` и `Windows` на trusted контексте.
Назначение: обязательный smoke на trusted контексте. Blocking GitHub Actions runner сейчас `ubuntu-latest`; Windows full-test/live path остается TODO до hardening существующих Unix-assumptive тестов и helper-фикстур.

Canonical entrypoint:

Expand All @@ -64,7 +64,7 @@ V8_RUNNER_CI_SCOPE=happy-path bash scripts/test/ci-rust.sh
3. `cargo test --locked`
4. `bash scripts/test/live-cli-fixture.sh`

`scripts/test/live-cli-fixture.sh` в mandatory профиле обязан выполнить одинаковые стадии для обеих ОС:
`scripts/test/live-cli-fixture.sh` в mandatory профиле обязан выполнить стадии:

1. `init/setup infobase`
2. `build --full-rebuild`
Expand Down Expand Up @@ -158,19 +158,19 @@ python3 scripts/test/live-mcp-http.py
bash scripts/test/live-cli-ibcmd.sh
```

### GitHub Actions matrix
### GitHub Actions

Для `ubuntu-latest` и `windows-latest` blocking использует один и тот же entrypoint:
Blocking path использует entrypoint:

```bash
V8_RUNNER_CI_SCOPE=happy-path bash scripts/test/ci-rust.sh
```

Текущая реализация workflow wiring:

- `.github/workflows/ci.yml` публикует два matrix job: `contract` и `happy-path`
- `contract` всегда запускает `bash scripts/test/ci-rust.sh` с `V8_RUNNER_CI_SCOPE=contract`
- `happy-path` всегда запускает `V8_RUNNER_CI_SCOPE=happy-path bash scripts/test/ci-rust.sh`
- `.github/workflows/ci.yml` публикует два job: `contract` и `happy-path`
- `contract` запускает `bash scripts/test/ci-rust.sh` с `V8_RUNNER_CI_SCOPE=contract`
- `happy-path` запускает `V8_RUNNER_CI_SCOPE=happy-path bash scripts/test/ci-rust.sh`; без platform bundle secrets workflow передает `V8TR_DESIGNER_ALLOW_MISSING_CONFIG=1`, поэтому Rust build/check/test остаются blocking, а live fixture завершается soft-skip
- trusted path использует `scripts/test/ci-platform-install.sh`, `scripts/test/ci-designer-config.sh` и `scripts/test/ci-ibsrv.sh`
- upload deploy-ready артефактов делает только trusted happy-path после успешной non-empty validation в `live-cli-fixture.sh`

Expand All @@ -194,8 +194,8 @@ Windows runner contract for this helper layer is explicit:

| Контур | Linux | Windows | Blocking | Build | Syntax/check | Test | Package | Deploy-ready artifacts |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| `ci-rust contract` | yes | yes | yes | Rust | Rust | Rust | no | no |
| `ci-rust happy-path` | yes | yes | yes on trusted | Rust + real 1C | real | Rust by default; real 1C opt-in | real | real |
| `ci-rust contract` | yes | planned | yes | Rust | Rust | Rust | no | no |
| `ci-rust happy-path` | yes | planned | yes on trusted | Rust + real 1C | real | Rust by default; real 1C opt-in | real | real |
| `live-mcp-http` | optional | optional | no | real via MCP | real via MCP | real via MCP | n/a | n/a |
| `live-cli-ibcmd` | optional | optional | no | real (`IBCMD`) | n/a | n/a | diagnostic dump/export only | n/a |
| `live-cli-designer` | optional | optional | no | real (`DESIGNER`) | real | real opt-in | real | real |
Expand All @@ -207,3 +207,4 @@ Windows runner contract for this helper layer is explicit:
- `live-cli-fixture` по умолчанию не запускает 1С test-stage; `va`, `yaxunit-all` и `module` остаются opt-in режимами для стендов, где установлен и проверен соответствующий headless runner.
- `live-mcp-http` и `live-cli-ibcmd` остаются отдельными non-blocking контурами.
- Mandatory designer smoke requires `V8TR_DESIGNER_REAL_CONFIG`; `V8TR_DESIGNER_ALLOW_MISSING_CONFIG=1` is reserved for fork/non-blocking soft-skip contexts.
- Windows GitHub Actions full-test/live path is intentionally not blocking yet; current TODO is to remove Unix-only path and fake-executable assumptions from tests before re-enabling Windows as blocking.
6 changes: 5 additions & 1 deletion src/cli/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,9 +333,13 @@ pub enum SyntaxTarget {
DesignerModules(DesignerModulesSyntaxArgs),
/// Check via EDT validate
Edt {
/// EDT project names
/// EDT source-set names from v8project.yaml
#[arg(long = "project")]
projects: Vec<String>,

/// File with syntax issue exception lines
#[arg(long = "exception-file")]
exception_file: Option<std::path::PathBuf>,
},
}

Expand Down
6 changes: 5 additions & 1 deletion src/cli/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1185,8 +1185,12 @@ fn map_syntax_request(args: &SyntaxArgs) -> Result<SyntaxRequest, UseCaseError>
SyntaxTarget::DesignerModules(modules) => {
SyntaxTargetRequest::DesignerModules(map_designer_modules_request(modules)?)
}
SyntaxTarget::Edt { projects } => SyntaxTargetRequest::Edt {
SyntaxTarget::Edt {
projects,
exception_file,
} => SyntaxTargetRequest::Edt {
projects: projects.clone(),
exception_file: exception_file.clone(),
},
},
})
Expand Down
4 changes: 2 additions & 2 deletions src/mcp/edt_syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pub async fn execute(
) -> Result<UseCaseResult<SyntaxCheckResult>, EdtSyntaxTransportError> {
let started = Instant::now();
let projects = match &request.target {
SyntaxTargetRequest::Edt { projects } => projects,
SyntaxTargetRequest::Edt { projects, .. } => projects,
_ => {
let error = AppError::Validation(
"shared EDT syntax executor requires an EDT syntax target".to_owned(),
Expand Down Expand Up @@ -328,7 +328,7 @@ fn resolve_edt_source_sets<'a>(

if !unknown.is_empty() {
return Err(AppError::Validation(format!(
"unknown EDT project(s): {}",
"unknown EDT source-set(s): {}",
unknown.join(", ")
)));
}
Expand Down
6 changes: 5 additions & 1 deletion src/mcp/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,7 @@ pub(crate) fn normalize_check_syntax_edt_request(
SyntaxRequest {
target: SyntaxTargetRequest::Edt {
projects: normalize_edt_projects(request.project_name.as_deref()),
exception_file: None,
},
}
}
Expand Down Expand Up @@ -1470,7 +1471,10 @@ mod tests {
let requests = service.port.syntax_requests.borrow();
assert_eq!(
requests[0].1.target,
SyntaxTargetRequest::Edt { projects: vec![] }
SyntaxTargetRequest::Edt {
projects: vec![],
exception_file: None
}
);
}

Expand Down
33 changes: 30 additions & 3 deletions src/platform/interactive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1049,7 +1049,7 @@ mod tests {
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use std::time::{Duration, Instant};
use tempfile::tempdir;

#[cfg(unix)]
Expand Down Expand Up @@ -1295,6 +1295,10 @@ mod tests {

#[cfg(unix)]
fn is_process_alive(pid: u32) -> bool {
if process_is_zombie(pid) {
return false;
}

Command::new("kill")
.args(["-0", &pid.to_string()])
.stderr(std::process::Stdio::null())
Expand All @@ -1303,6 +1307,30 @@ mod tests {
.unwrap_or(false)
}

#[cfg(unix)]
fn process_is_zombie(pid: u32) -> bool {
let stat_path = format!("/proc/{pid}/stat");
let Ok(stat) = fs::read_to_string(stat_path) else {
return false;
};
let Some(after_name) = stat.rsplit_once(") ") else {
return false;
};
after_name.1.starts_with("Z ")
}

#[cfg(unix)]
fn wait_until_process_exits(pid: u32, timeout: Duration) -> bool {
let deadline = Instant::now() + timeout;
while Instant::now() < deadline {
if !is_process_alive(pid) {
return true;
}
thread::sleep(Duration::from_millis(25));
}
!is_process_alive(pid)
}

#[cfg(unix)]
#[test]
fn startup_waits_for_prompt() {
Expand Down Expand Up @@ -1616,9 +1644,8 @@ mod tests {
assert!(is_process_alive(child_pid));

executor.kill().expect("kill executor");
thread::sleep(Duration::from_millis(50));

assert!(!is_process_alive(child_pid));
assert!(wait_until_process_exits(child_pid, Duration::from_secs(2)));
}

#[cfg(unix)]
Expand Down
Loading