Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
19 changes: 16 additions & 3 deletions .github/workflows/test_integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@
# Workflow configuration for S-CORE CI - Bazel Build & Test baselibs
# This workflow runs Bazel build and test when triggered by specific pull request events.

name: Bazel Build some repositories
name: build latest mains
on:
workflow_dispatch:
push:
pull_request:
schedule:
- cron: '30 2 * * *' # Every night at 02:30 UTC on main branch
jobs:
integration_test:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -51,9 +52,21 @@ jobs:
disk-cache: ${{ github.workflow }}
# Share repository cache between workflows.
repository-cache: true
- name: Update known good commits
run: |
echo "::group::get latest commits from module branches"
python3 tools/update_module_latest.py --output known_good.updated.json
cat known_good.updated.json
echo "::endgroup::"
echo "::group::update score_modules.MODULE.bazel"
python3 tools/update_module_from_known_good.py --known known_good.updated.json
cat score_modules.MODULE.bazel
echo "::endgroup::"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Bazel build targets
run: |
./integration_test.sh
./integration_test.sh --known-good known_good.updated.json
- name: Show disk space after build
if: always()
run: |
Expand Down
2 changes: 2 additions & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,15 @@ use_repo(pip, "pip_score_venv_test")

# communication module dependencies
# archive_override are not forwarded by bazel_dep, so we need to redefine it here
bazel_dep(name = "rules_boost", repo_name = "com_github_nelhage_rules_boost")
archive_override(
module_name = "rules_boost",
strip_prefix = "rules_boost-master",
urls = ["https://github.com/nelhage/rules_boost/archive/refs/heads/master.tar.gz"],
)

# git_override are not forwarded by bazel_dep, so we need to redefine it here
bazel_dep(name = "trlc")
git_override(
module_name = "trlc",
remote = "https://github.com/bmw-software-engineering/trlc.git",
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ bazel build --config bl-x86_64-linux @score_baselibs//score/... --verbose_failur

### Communication
```bash
bazel build --config bl-x86_64-linux @score_communication//score/mw/com:com --verbose_failures
bazel build --config bl-x86_64-linux @communication//score/mw/com:com --verbose_failures
```

### Persistency
Expand Down
112 changes: 100 additions & 12 deletions integration_test.sh
Original file line number Diff line number Diff line change
@@ -1,24 +1,79 @@
#!/usr/bin/env bash
set -euox pipefail
set -euo pipefail

# Integration build script.
# Captures warning counts for regression tracking.
#
# Usage: ./integration_test.sh [--known-good <path>]
# --known-good: Optional path to known_good.json file

CONFIG=${CONFIG:-bl-x86_64-linux}
LOG_DIR=${LOG_DIR:-_logs/logs}
SUMMARY_FILE=${SUMMARY_FILE:-_logs/build_summary.md}
mkdir -p "${LOG_DIR}" || true
KNOWN_GOOD_FILE=""

# maybe move this to known_good.json or a config file later
declare -A BUILD_TARGET_GROUPS=(
[baselibs]="@score_baselibs//score/..."
[score_baselibs]="@score_baselibs//score/..."
[score_communication]="@score_communication//score/mw/com:com"
[persistency]="@score_persistency//src/cpp/src/... @score_persistency//src/rust/..."
[score_persistency]="@score_persistency//src/cpp/src/... @score_persistency//src/rust/..."
#[score_logging]="@score_logging//src/..."
[score_orchestrator]="@score_orchestrator//src/..."
[score_test_scenarios]="@score_test_scenarios//..."
[score_feo]="@score_feo//..."
)

# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
--known-good)
KNOWN_GOOD_FILE="$2"
shift 2
;;
*)
echo "Unknown option: $1"
echo "Usage: $0 [--known-good <path>]"
exit 1
;;
esac
done

mkdir -p "${LOG_DIR}" || true

# Function to extract commit hash from known_good.json
get_commit_hash() {
local module_name=$1
local known_good_file=$2

if [[ -z "${known_good_file}" ]] || [[ ! -f "${known_good_file}" ]]; then
echo "N/A"
return
fi

# Get the script directory
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# Use the Python script to extract module info
python3 "${script_dir}/tools/get_module_info.py" "${known_good_file}" "${module_name}" "hash" 2>/dev/null || echo "N/A"
}

# Function to extract repo URL from known_good.json
get_module_repo() {
local module_name=$1
local known_good_file=$2

if [[ -z "${known_good_file}" ]] || [[ ! -f "${known_good_file}" ]]; then
echo "N/A"
return
fi

# Get the script directory
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# Use the Python script to extract module repo
python3 "${script_dir}/tools/get_module_info.py" "${known_good_file}" "${module_name}" "repo" 2>/dev/null || echo "N/A"
}

warn_count() {
# Grep typical compiler and Bazel warnings; adjust patterns as needed.
local file=$1
Expand All @@ -35,29 +90,41 @@ timestamp() { date '+%Y-%m-%d %H:%M:%S'; }

echo "=== Integration Build Started $(timestamp) ===" | tee "${SUMMARY_FILE}"
echo "Config: ${CONFIG}" | tee -a "${SUMMARY_FILE}"
if [[ -n "${KNOWN_GOOD_FILE}" ]]; then
echo "Known Good File: ${KNOWN_GOOD_FILE}" | tee -a "${SUMMARY_FILE}"
fi
echo "" >> "${SUMMARY_FILE}"
echo "## Build Groups Summary" >> "${SUMMARY_FILE}"
echo "" >> "${SUMMARY_FILE}"
# Markdown table header
{
echo "| Group | Status | Duration (s) | Warnings | Deprecated refs |";
echo "|-------|--------|--------------|----------|-----------------|";
echo "| Group | Status | Duration (s) | Warnings | Deprecated refs | Commit/Version |";
echo "|-------|--------|--------------|----------|-----------------|----------------|";
} >> "${SUMMARY_FILE}"

overall_warn_total=0
overall_depr_total=0

# Track if any build group failed
any_failed=0

for group in "${!BUILD_TARGET_GROUPS[@]}"; do
targets="${BUILD_TARGET_GROUPS[$group]}"
log_file="${LOG_DIR}/${group}.log"

# Log build group banner only to stdout/stderr (not into summary table file)
echo "--- Building group: ${group} ---"
start_ts=$(date +%s)
echo "bazel build --config "${CONFIG}" ${targets} --verbose_failures"
# GitHub Actions log grouping start
echo "::group::Bazel build (${group})"
start_ts=$(date +%s)
set +e
bazel build --config "${CONFIG}" ${targets} --verbose_failures 2>&1 | tee "$log_file"
build_status=${PIPESTATUS[0]}
# Track if any build group failed
if [[ ${build_status} -ne 0 ]]; then
any_failed=1
fi
set -e
echo "::endgroup::" # End Bazel build group
end_ts=$(date +%s)
Expand All @@ -72,16 +139,37 @@ for group in "${!BUILD_TARGET_GROUPS[@]}"; do
else
status_symbol="❌(${build_status})"
fi
echo "| ${group} | ${status_symbol} | ${duration} | ${w_count} | ${d_count} |" | tee -a "${SUMMARY_FILE}"

# Get commit hash/version for this group (group name is the module name)
commit_hash=$(get_commit_hash "${group}" "${KNOWN_GOOD_FILE}")
repo=$(get_module_repo "${group}" "${KNOWN_GOOD_FILE}")

# Truncate commit hash for display (first 8 chars)
if [[ "${commit_hash}" != "N/A" ]] && [[ ${#commit_hash} -gt 8 ]]; then
commit_hash_display="${commit_hash:0:8}"
else
commit_hash_display="${commit_hash}"
fi

# Only add link if KNOWN_GOOD_FILE is set
if [[ -n "${KNOWN_GOOD_FILE}" ]]; then
commit_version_cell="[${commit_hash_display}](${repo}/tree/${commit_hash})"
else
commit_version_cell="${commit_hash_display}"
fi

echo "| ${group} | ${status_symbol} | ${duration} | ${w_count} | ${d_count} | ${commit_version_cell} |" | tee -a "${SUMMARY_FILE}"
done

# Append aggregate totals row to summary table
echo "| TOTAL | | | ${overall_warn_total} | ${overall_depr_total} |" >> "${SUMMARY_FILE}"

# Display the full build summary explicitly at the end
echo "| TOTAL | | | ${overall_warn_total} | ${overall_depr_total} | |" >> "${SUMMARY_FILE}"
echo '::group::Build Summary'
echo '=== Build Summary (echo) ==='
cat "${SUMMARY_FILE}" || echo "(Could not read summary file ${SUMMARY_FILE})"
echo '::endgroup::'

exit 0
# Report to GitHub Actions if any build group failed
if [[ ${any_failed} -eq 1 ]]; then
echo "::error::One or more build groups failed. See summary above."
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

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

Script does not exit with non-zero status when builds fail. After line 173, add exit 1 to ensure the script returns a failure exit code when any_failed is set.

Suggested change
echo "::error::One or more build groups failed. See summary above."
echo "::error::One or more build groups failed. See summary above."
exit 1

Copilot uses AI. Check for mistakes.
exit 1
fi
55 changes: 55 additions & 0 deletions known_good.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"timestamp": "2025-08-13T12:55:10Z",
"modules": {
"score_baselibs": {
"version": "0.1.3",
"repo": "https://github.com/eclipse-score/baselibs.git",
"branch": "s_core_release_v0_5_0"
},
"score_communication": {
"version": "0.1.1",
"repo": "https://github.com/eclipse-score/communication.git",
"branch": "s_core_release_v0_5_0"
},
"score_persistency": {
"version": "0.2.1",
"repo": "https://github.com/eclipse-score/persistency.git"
},
"score_orchestrator": {
"version": "0.0.3",
"repo": "https://github.com/eclipse-score/orchestrator.git"
},
"score_tooling": {
"version": "1.0.2",
"repo": "https://github.com/eclipse-score/tooling.git"
},
"score_platform": {
"hash": "a9cf44be1342f3c62111de2249eb3132f5ab88da",
"repo": "https://github.com/eclipse-score/score.git"
},
"score_bazel_platforms": {
"version": "0.0.2",
"repo": "https://github.com/eclipse-score/bazel_platforms.git"
},
"score_test_scenarios": {
"version": "0.3.0",
"repo": "https://github.com/eclipse-score/testing_tools.git"
},
"score_docs_as_code": {
"version": "2.0.1",
"repo": "https://github.com/eclipse-score/docs-as-code.git"
},
"score_process": {
"version": "1.3.1",
"repo": "https://github.com/eclipse-score/process_description.git"
},
"score_feo": {
"version": "1.0.2",
"repo": "https://github.com/eclipse-score/feo.git",
"branch": "candidate_v0.5"
}
},
"manifest_sha256": "4c9b7f...",
"suite": "full",
"duration_s": 742
}
74 changes: 74 additions & 0 deletions tools/get_module_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/usr/bin/env python3
"""Extract module information from known_good.json."""

import json
import sys
from typing import Dict, Any


def load_module_data(known_good_file: str, module_name: str) -> Dict[str, Any]:
"""
Load module data from known_good.json.

Args:
known_good_file: Path to the known_good.json file
module_name: Name of the module to look up

Returns:
Dictionary with module data, or empty dict if not found
"""
try:
with open(known_good_file, 'r') as f:
data = json.load(f)
modules = data.get('modules', {})
return modules.get(module_name, {})
except Exception:
return {}


def get_module_field(module_data: Dict[str, Any], field: str = 'hash') -> str:
"""
Extract a specific field from module data.

Args:
module_data: Dictionary with module information
field: Field to extract ('hash', 'version', 'repo', or 'all')

Returns:
Requested field value, or 'N/A' if not found
For 'hash': truncated to 8 chars if longer
For 'all': returns hash/version (prefers hash, falls back to version)
"""
if not module_data:
return 'N/A'

if field == 'repo':
repo = module_data.get('repo', 'N/A')
# Remove .git suffix if present
if repo.endswith('.git'):
repo = repo[:-4]
return repo
elif field == 'version':
return module_data.get('version', 'N/A')
elif field == 'hash':
hash_val = module_data.get('hash', 'N/A')
return hash_val
else: # field == 'all' or default
hash_val = module_data.get('hash', module_data.get('version', 'N/A'))
return hash_val


if __name__ == '__main__':
if len(sys.argv) < 3 or len(sys.argv) > 4:
print('Usage: get_module_info.py <known_good.json> <module_name> [field]')
print(' field: hash (default), version, repo, or all')
print('N/A')
sys.exit(1)

known_good_file = sys.argv[1]
module_name = sys.argv[2]
field = sys.argv[3] if len(sys.argv) == 4 else 'all'

module_data = load_module_data(known_good_file, module_name)
result = get_module_field(module_data, field)
print(result)
1 change: 1 addition & 0 deletions tools/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
PyGithub>=2.1.1
Copy link
Member

Choose a reason for hiding this comment

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

is this actually used? I also cannot find someone using this file?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

update_module_latest.sh has the option to use the PyGithub instead of gh cli

Loading
Loading