Skip to content

.2059806565729300:95ad92ec965053fa925b1bca48fad429_69e3499ab13256d09ece8088.69e4d39ab13256d09ece855f.69e4d3997afba9383018b93d:Trae CN.T(2026/4/19 21:07:38)#1277

Closed
Wpc-121 wants to merge 5 commits intoActivityWatch:masterfrom
Wpc-121:bug_rep_07
Closed

.2059806565729300:95ad92ec965053fa925b1bca48fad429_69e3499ab13256d09ece8088.69e4d39ab13256d09ece855f.69e4d3997afba9383018b93d:Trae CN.T(2026/4/19 21:07:38)#1277
Wpc-121 wants to merge 5 commits intoActivityWatch:masterfrom
Wpc-121:bug_rep_07

Conversation

@Wpc-121
Copy link
Copy Markdown
Contributor

@Wpc-121 Wpc-121 commented Apr 19, 2026

添加Windows安装包验证脚本

添加用于验证Windows安装包和zip压缩包内容一致性的脚本

Wpc-121 added 5 commits April 19, 2026 00:11
重构集成测试脚本,增加健康检查轮询机制替代固定等待时间
添加详细的测试帮助文档和环境变量配置说明
改进日志记录和错误检测功能
添加全局和单测超时控制,改进错误分类和诊断信息
添加 pytest-timeout 依赖,支持进程树清理
优化日志输出和错误处理流程
添加 GitHub Actions 集成测试工作流,支持通过输入参数跳过构建步骤直接下载二进制文件
设置全局测试超时和分步超时控制
支持多平台(ubuntu/macos)测试环境
在构建流程中添加 doctor 检查步骤,确保环境依赖正确
新增严格模式验证脚本,检查打包内容和版本一致性
优化构建日志输出,增加详细步骤和错误处理
添加用于验证Windows安装包和zip压缩包内容一致性的脚本
import json
import signal
import atexit
import sys


GLOBAL_SERVER_PROCESS: Optional['ServerProcess'] = None
GLOBAL_TEST_TIMEOUT: int = 120
for child in children:
try:
child.kill()
except psutil.NoSuchProcess:

try:
parent.kill()
except psutil.NoSuchProcess:
for p in still_alive:
try:
p.kill()
except psutil.NoSuchProcess:
p.kill()
except psutil.NoSuchProcess:
pass
except psutil.NoSuchProcess:
else:
try:
os.killpg(os.getpgid(pid), signal.SIGKILL)
except ProcessLookupError:
except OSError:
try:
os.kill(pid, signal.SIGKILL)
except ProcessLookupError:

start_time = time.time()
poll_count = 0
last_exit_check = 0
if path and os.path.exists(path):
try:
os.remove(path)
except Exception:
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 19, 2026

Greptile Summary

This PR adds Windows artifact verification (verify-windows-artifacts.sh), a general package verification script (verify-package.sh), a new make doctor dependency check, PACKAGE_STRICT CI mode, and a rewritten integration test module (integration_tests.py) with health-polling, error classification, and timeout protection.

  • P1 — local outside function in verify-windows-artifacts.sh: local diff_count=$? at script scope causes bash to exit with code 1 (via set -e) precisely when differences are found, making the error-reporting path unreachable.
  • P1 — return $total_differences wraps at 255: compare_manifests returns $total_differences as a bash exit code; values ≥ 256 wrap to 0, silently treating large discrepancy counts as "no differences".
  • P1 — make doctor ERRORS variable lost across recipe lines: Each Makefile recipe line runs in its own shell, so ERRORS=1 set in one block is invisible to the final check — doctor always exits 0 regardless of missing tools.

Confidence Score: 3/5

Three P1 defects mean the primary new verification paths are broken and should be fixed before merging.

The PR's stated purpose is to add reliable Windows artifact verification. All three P1 bugs directly undermine that goal: the windows-artifact script aborts on errors (the exact case it should handle), the difference count overflows silently, and the doctor check is a no-op. The rest of the code (integration tests, verify-package.sh, CI wiring) is solid.

scripts/package/verify-windows-artifacts.sh (two P1 bugs) and Makefile (doctor ERRORS variable scope issue) need fixes before this is reliable in CI.

Important Files Changed

Filename Overview
scripts/package/verify-windows-artifacts.sh New script comparing source directory vs zip manifest; has two P1 bugs: local at script scope aborts on differences (with set -e), and return $total_differences wraps at 255 hiding large discrepancy counts.
Makefile Significant additions: doctor target, venv-check, package-pre-check, enhanced test-integration, and PACKAGE_STRICT support; but the doctor target's ERRORS variable is lost across separate recipe shell invocations, making it always exit 0.
scripts/package/verify-package.sh New script verifying package executables, directories, and version consistency; logic looks correct with proper strict/non-strict mode handling.
scripts/package/package-all.sh Refactored packaging script with improved logging; minor concern about hardcoded installer output path assumption for Windows.
scripts/tests/integration_tests.py New integration test module with health polling, error classification, global timeout, and clean process teardown; well-structured and robust.
.github/workflows/test.yml Adds workflow_dispatch inputs and a new integration job for Ubuntu/macOS; Windows is missing from the matrix despite this PR's focus on Windows artifacts.
.github/workflows/build.yml Adds make doctor pre-build check and switches to PACKAGE_STRICT=true make package in CI; doctor effectiveness is undermined by the Makefile ERRORS variable bug.
.github/workflows/build-tauri.yml Same doctor + PACKAGE_STRICT pattern as build.yml, with TAURI_BUILD=true; same caveats apply.
pyproject.toml Adds pytest-timeout and psutil as dev dependencies to support the new integration test module.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[make package] --> B[package-pre-check\nvenv + submodule check]
    B --> C[Build submodules\nfor each PACKAGEABLE]
    C --> D[Copy to dist/activitywatch/]
    D --> E[package-all.sh\nBuild zip + installer]
    E --> F{PACKAGE_STRICT?}
    F -- true --> G[verify-package.sh --strict\nExit non-zero on errors]
    F -- false --> H[verify-package.sh\nReport only, exit 0]
    G --> I{Windows?}
    H --> I
    I -- yes --> J[verify-windows-artifacts.sh\nCompare source dir vs zip]
    J --> K{Differences?}
    K -- none --> L[Exit 0 ✓]
    K -- found --> M["local diff_count=\$?\n⚠ ABORTS with set -e"]
    M --> N[Exit 1 ❌ unexpected]

    style M fill:#f88,stroke:#c00
    style N fill:#f88,stroke:#c00
Loading

Reviews (1): Last reviewed commit: "feat(scripts): 添加Windows安装包验证脚本" | Re-trigger Greptile

exit 0
else
# Differences found
local diff_count=$?
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 local used outside a function — script aborts when differences are found

local is only valid inside a bash function. At the top level of a script, bash emits bash: local: can only be used in a function and returns exit code 1. Because the script runs with set -euo pipefail (line 26), that exit code causes an immediate abort the moment the else branch is taken — i.e., exactly when differences are found. The very error path that should report differences and exit 2 (strict mode) instead silently dies with exit code 1.

Suggested change
local diff_count=$?
diff_count=$?

rm -f "$missing_files" "$extra_files" "$different_sizes"

# Return count of differences
return $total_differences
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 return value capped at 255 — large difference counts silently become 0

Bash return only accepts values 0–255 (unsigned 8-bit). When total_differences is 256 or more, the return value wraps: 256 → 0, which makes the caller's if compare_manifests … branch succeed ("no differences"), completely hiding the real failures. Consider printing the count and returning a fixed sentinel instead:

Suggested change
return $total_differences
echo "$total_differences"
return $(( total_differences > 0 ? 1 : 0 ))

And in the caller update the capture accordingly:

if diff_count=$(compare_manifests "$SOURCE_MANIFEST" "$ZIP_MANIFEST" "Source Directory" "Zip Archive"); then

Comment thread Makefile
Comment on lines +103 to +228
doctor: venv-check
@echo "==========================================================================="
@echo "ActivityWatch Build Environment Doctor"
@echo "==========================================================================="
@echo ""
@echo "--- Python Environment ---"
@echo ""
@echo -n " Python: "
@if command -v python3 >/dev/null 2>&1; then \
PY_VER=$$(python3 --version 2>&1); \
echo "✓ $$PY_VER"; \
else \
echo "✗ python3 not found in PATH"; \
ERRORS=1; \
fi

@echo -n " pip: "
@if python3 -m pip --version >/dev/null 2>&1; then \
PIP_VER=$$(python3 -m pip --version 2>&1 | cut -d' ' -f2); \
echo "✓ $$PIP_VER"; \
else \
echo "✗ pip not available"; \
ERRORS=1; \
fi

@echo -n " poetry: "
@if command -v poetry >/dev/null 2>&1; then \
POETRY_VER=$$(poetry --version 2>&1 | sed 's/.*version \([0-9.]*\).*/\1/'); \
echo "✓ $$POETRY_VER"; \
else \
echo "✗ poetry not found in PATH"; \
echo " Install with: pip3 install poetry==1.4.2"; \
ERRORS=1; \
fi

@echo -n " setuptools: "
@SETUPTOOLS_VER=$(call setuptools_version); \
if [ -n "$$SETUPTOOLS_VER" ] && [ "$$SETUPTOOLS_VER" != "0.0.0" ]; then \
echo "✓ $$SETUPTOOLS_VER"; \
NEEDS_UPDATE=$(call version_gt,49.1.1,$$SETUPTOOLS_VER); \
if [ "$$NEEDS_UPDATE" = "1" ]; then \
echo " ⚠ Version <= 49.1.1, may cause issues (see: pypa/setuptools#1963)"; \
echo " Will be automatically updated during make build"; \
fi; \
else \
echo "✗ Could not determine setuptools version"; \
ERRORS=1; \
fi

@echo ""
@echo "--- Node.js Environment (for web UI) ---"
@echo ""
@echo -n " node: "
@if command -v node >/dev/null 2>&1; then \
NODE_VER=$$(node --version 2>&1); \
echo "✓ $$NODE_VER"; \
else \
echo "⚠ node not found in PATH (only needed for web UI build)"; \
echo " SKIP_WEBUI=true can be used to skip web UI build"; \
fi

@echo -n " npm: "
@if command -v npm >/dev/null 2>&1; then \
NPM_VER=$$(npm --version 2>&1); \
echo "✓ $$NPM_VER"; \
else \
echo "⚠ npm not found (only needed for web UI build)"; \
fi

@echo ""
@echo "--- Rust Environment (for aw-server-rust) ---"
@echo ""
@echo -n " rustc: "
@if command -v rustc >/dev/null 2>&1; then \
RUST_VER=$$(rustc --version 2>&1); \
echo "✓ $$RUST_VER"; \
else \
echo "⚠ rustc not found in PATH (only needed for aw-server-rust)"; \
echo " SKIP_SERVER_RUST=true can be used to skip Rust build"; \
fi

@echo -n " cargo: "
@if command -v cargo >/dev/null 2>&1; then \
CARGO_VER=$$(cargo --version 2>&1 | cut -d' ' -f2); \
echo "✓ $$CARGO_VER"; \
else \
echo "⚠ cargo not found (only needed for aw-server-rust)"; \
fi

@echo ""
@echo "--- Git Submodules ---"
@echo ""
@for module in aw-core aw-client aw-server; do \
echo -n " $$module: "; \
if [ -d "$$module/.git" ]; then \
echo "✓ initialized"; \
else \
echo "✗ not initialized"; \
echo " Run: git submodule update --init --recursive"; \
ERRORS=1; \
fi; \
done

@echo ""
@echo "==========================================================================="
@echo "Summary"
@echo "==========================================================================="
@echo ""
@echo "Virtual environment: ✓ Active"
@echo " Path: $$VIRTUAL_ENV"
@echo ""
@if [ -n "$$ERRORS" ]; then \
echo "❌ Some issues found. Please fix them before building."; \
exit 1; \
else \
echo "✅ All required dependencies look good!"; \
echo ""; \
echo " You can now run:"; \
echo " make build"; \
echo ""; \
echo " Or with options:"; \
echo " make build SKIP_WEBUI=true"; \
echo " make build SKIP_SERVER_RUST=true"; \
echo " make build RELEASE=true"; \
echo ""; \
fi
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 ERRORS variable never survives across recipe lines — doctor always exits 0

Each line in a Makefile recipe is executed in a separate shell. The ERRORS=1 assignments set in individual @if blocks are lost by the time the final @if [ -n "$$ERRORS" ] check runs, which always sees an empty variable and always exits 0. This means make doctor reports "✅ All required dependencies look good!" even when python3, poetry, or cargo are missing, making the "fail-fast" CI check ineffective.

Fix by collapsing the entire doctor body into a single recipe line joined with ; \ continuations, or by delegating to a shell script that maintains a single shell environment.

Comment on lines +198 to +204
runs-on: ${{ matrix.os }}
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
python_version: ['3.12']
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Windows missing from integration test matrix

The new integration job only targets ubuntu-latest and macos-latest, but the PR's primary motivation is verifying Windows artifacts (verify-windows-artifacts.sh, PACKAGE_STRICT CI changes). Windows integration coverage is absent from this job.

Consider adding windows-latest to the matrix so Windows-specific paths (7z compression, installer creation, aw-tauri.exe checks) are exercised in CI.

Comment on lines +196 to +200
log_ok "Inno Setup compilation complete"

log_action "Renaming installer: activitywatch-setup.exe → $installer_filename"
mv dist/activitywatch-setup.exe "dist/$installer_filename"
log_ok "Installer renamed"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Hardcoded installer output path may not match ISS compiler output

The rename assumes the Inno Setup compiler always writes to dist/activitywatch-setup.exe. If the .iss file specifies a different OutputBaseFilename or OutputDir, the mv will fail with a "No such file or directory" error. It would be safer to check for the file's existence before renaming, or to read the actual output location from the ISS script.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants