Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .devcontainer/S-CORE/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -87,5 +87,5 @@ RUN groupadd --gid $USER_GID $USERNAME \
USER $USERNAME

# Install trudag using pipx
RUN pipx install git+https://gitlab.com/CodethinkLabs/trustable/trustable@9957f12171cb898d83df5ae708fdba0a38fece2e && \
RUN pipx install git+https://gitlab.com/CodethinkLabs/trustable/trustable@v2025.10.22 && \
pipx ensurepath
2 changes: 1 addition & 1 deletion .devcontainer/S-CORE/post_create_script.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ source .venv/bin/activate

# Install trustable
pip install --require-hashes -r .devcontainer/S-CORE/requirements.txt
pip install git+https://gitlab.com/CodethinkLabs/trustable/trustable@9957f12171cb898d83df5ae708fdba0a38fece2e
pip install git+https://gitlab.com/CodethinkLabs/trustable/trustable@v2025.10.22
95 changes: 62 additions & 33 deletions .dotstop.dot

Large diffs are not rendered by default.

168 changes: 102 additions & 66 deletions .dotstop_extensions/README.md

Large diffs are not rendered by default.

21 changes: 13 additions & 8 deletions .dotstop_extensions/data_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,16 @@ def get_my_data() -> list[dict]:
command = f"SELECT * FROM scores WHERE date=={info[0]}"
cursor.execute(command)
scores = cursor.fetchall()
date = datetime.fromtimestamp(info[0])
date_as_string = date.strftime("%a %b %d %H:%M:%S %Y")
# Return unix timestamp directly for trudag v2025.09.16+ compatibility
# (older versions expected formatted string, newer versions expect int)
date_timestamp = info[0]
if len(info) == 6:
branch_name = ""
else:
branch_name = info[6] if info[6]!=None else ""
commit = {"Repository root": info[1],
"Commit SHA": info[2],
"Commit date/time": date_as_string,
"Commit date/time": date_timestamp,
"Commit tag": info[3],
"CI job id": info[4],
"Schema version": info[5],
Expand Down Expand Up @@ -71,11 +72,15 @@ def push_my_data(data: list[dict]):
# extract data from data
info = data[0].get("info")
scores = data[0].get("scores")
# Currently, the commit date is stored as string.
# Since the local timezone is used and for comparison,
# it would be better to have it as a unix-timestamp.
datum_string = info.get("Commit date/time")
datum = int(datetime.strptime(datum_string, "%a %b %d %H:%M:%S %Y").timestamp())
# Starting with trudag v2025.09.16, the commit date is already a unix timestamp (int).
# For backward compatibility, handle both string and int formats.
datum_value = info.get("Commit date/time")
if isinstance(datum_value, str):
# Old format: string date, convert to timestamp
datum = int(datetime.strptime(datum_value, "%a %b %d %H:%M:%S %Y").timestamp())
else:
# New format: already a unix timestamp
datum = datum_value
# check if current commit coincides with existing commit
cursor.execute("SELECT MAX(date) AS recent_commit FROM commit_info")
if datum == cursor.fetchone()[0]:
Expand Down
57 changes: 57 additions & 0 deletions .dotstop_extensions/references.py
Original file line number Diff line number Diff line change
Expand Up @@ -951,3 +951,60 @@ def __str__(self):
title += "items "
title += ", ".join(self._items)
return title


class IncludeListReference(BaseReference):
"""
Reference that lists all #include lines in a given file (e.g. single_include/nlohmann/json.hpp).
Usage: IncludeListReference("single_include/nlohmann/json.hpp", "optional description")
"""
def __init__(self, path: str, description: str = "") -> None:
self._path = Path(path)
self._description = description

@classmethod
def type(cls) -> str:
return "include_list"

@property
def content(self) -> bytes:
if not self._path.is_file():
raise ReferenceError(f"Cannot get non-existent or non-regular file {self._path}")

text = self._path.read_text(encoding="utf-8")
includes = []

for line in text.splitlines():
# Only process lines that start with #include (ignoring whitespace)
if line.lstrip().startswith("#include"):
# Remove single-line comments
line = line.split("//")[0].rstrip()

# Remove multi-line comments
comment_start = line.find("/*")
if comment_start != -1:
comment_end = line.find("*/", comment_start)
if comment_end != -1:
line = line[:comment_start] + line[comment_end + 2:]

# Add the cleaned include line
includes.append(line.rstrip())

if not includes:
return b"No includes found"
return ("\n".join(includes)).encode("utf-8")

def as_markdown(self, filepath: None | str = None) -> str:
content = self.content.decode("utf-8")
if content == "No includes found":
return make_md_bullet_point(f"No includes found in {self._path}", 1)
md = format_cpp_code_as_markdown(content)
if self._description:
md = make_md_bullet_point(f"Description: {self._description}", 1) + "\n\n" + add_indentation(md, 1)
else:
md = add_indentation(md, 1)
return md

def __str__(self) -> str:
return f"List of included libraries for: {self._path}"

63 changes: 62 additions & 1 deletion .dotstop_extensions/test_references.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import tempfile
from pathlib import Path
from unittest.mock import patch
from references import CPPTestReference, JSONTestsuiteReference, FunctionReference, ItemReference, ListOfTestCases
from references import CPPTestReference, JSONTestsuiteReference, FunctionReference, ItemReference, IncludeListReference, ListOfTestCases
from validators import file_exists


Expand Down Expand Up @@ -856,3 +856,64 @@ def test_str_method():
"""Test __str__ method."""
list_ref = ListOfTestCases(["test_file"])
assert str(list_ref) == "List of all unit-tests"
def test_include_list_init():
ref = IncludeListReference("some/path.hpp", "my desc")
assert ref._path == Path("some/path.hpp")
assert ref._description == "my desc"

def test_type_classmethod_include_list():
assert IncludeListReference.type() == "include_list"

def test_content_includes_found():
content = '#include <iostream>\n #include "local.h"\nint x = 0;\n'
temp = create_temp_file(content, suffix='.hpp')
try:
ref = IncludeListReference(str(temp), "desc")
data = ref.content
assert isinstance(data, bytes)
decoded = data.decode('utf-8')
assert '#include <iostream>' in decoded
assert '#include "local.h"' in decoded
finally:
temp.unlink()

def test_content_no_includes():
temp = create_temp_file('int x = 1;\n// nothing to include\n', suffix='.hpp')
try:
ref = IncludeListReference(str(temp))
assert ref.content == b"No includes found"
finally:
temp.unlink()

def test_content_file_not_found():
ref = IncludeListReference("nonexistent_file_hopefully.hpp")
with pytest.raises(ReferenceError):
_ = ref.content

def test_as_markdown_with_description():
content = '#include <vector>\n#include "a.h"\n'
temp = create_temp_file(content, suffix='.hpp')
try:
ref = IncludeListReference(str(temp), "list of includes")
md = ref.as_markdown()
assert isinstance(md, str)
# starts with an indented bullet for description
assert md.startswith('\t- Description: list of includes')
assert '```cpp' in md
assert '#include <vector>' in md
finally:
temp.unlink()

def test_as_markdown_no_includes():
temp = create_temp_file('void f();\n', suffix='.hpp')
try:
ref = IncludeListReference(str(temp))
md = ref.as_markdown()
# should return a single indented bullet line about no includes
assert md.strip().startswith('- No includes found in')
finally:
temp.unlink()

def test_str_include_list():
ref = IncludeListReference("path/to/file.hpp")
assert str(ref) == f"List of included libraries for: {Path('path/to/file.hpp')}"
96 changes: 96 additions & 0 deletions .github/workflows/SME_review_checker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
name: SME Review Checker

on:
workflow_call:
inputs:
artifact_id:
description: 'Unique identifier for artifacts'
required: true
type: string

permissions:
contents: read
pull-requests: read

jobs:
check-SME-review:
runs-on: ubuntu-latest

steps:
- name: Harden Runner
uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1
with:
egress-policy: audit

- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0

- name: Get changed files
id: changed-files
run: |
# Get the base branch
BASE_BRANCH="${{ github.event.pull_request.base.ref || 'main' }}"

# Get all changed files in the PR
CHANGED_FILES=$(git diff --name-only origin/$BASE_BRANCH...HEAD)

# Save changed files to output
echo "files<<EOF" >> $GITHUB_OUTPUT
echo "$CHANGED_FILES" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT

- name: Check if supported statements are scored
run: |
# Read the changed files
CHANGED_FILES="${{ steps.changed-files.outputs.files }}"

# Process each changed file
while IFS= read -r file; do
# Skip empty lines
if [[ -z "$file" ]]; then
continue
fi

echo "Checking file: $file"

# Check if file is in TSF/trustable folder and ends with .md
if [[ "$file" == TSF/trustable/* && "$file" == *.md ]]; then
# Extract filename without path and extension
filename=$(basename "$file" .md)

# Skip README files
if [[ "$filename" == "README" ]]; then
continue
fi

echo "Checking TSF trustable file: $file (filename: $filename)"

# Check if filename pattern exists in .dotstop.dot
if grep -q "\"$filename\" -> " .dotstop.dot; then
echo " Found reference in .dotstop.dot for: $filename"

# Check if the file contains "score:" substring
if [[ -f "$file" ]] && grep -q "score:" "$file"; then
echo "ERROR: $file - Error: supported statements shall not be scored"
exit 1
fi
else
echo "No reference found in .dotstop.dot for: $filename"
fi
fi
done <<< "$CHANGED_FILES"

echo "All changed TSF items passed validation"

- name: Generate artifact
run: |
mkdir -p SME_review_checker
echo "SME review checker processed for ${{ inputs.artifact_id }}" > SME_review_checker/SME_review_checker.txt

- name: Upload SME review checker artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: ${{ inputs.artifact_id }}
path: SME_review_checker/
16 changes: 13 additions & 3 deletions .github/workflows/parent-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ jobs:
with:
artifact_id: "labeler-${{ github.sha }}"

SME_review_checker:
permissions:
contents: read
pull-requests: read
name: Run SME_review_checker Workflow
if: ${{ github.event_name == 'pull_request' }} # only run SME_review_checker for PRs
uses: ./.github/workflows/SME_review_checker.yml
with:
artifact_id: "SME_review_checker-${{ github.sha }}"

check_amalgamation:
name: Run Amalgamation Workflow
if: ${{ github.event_name == 'pull_request' }} # only run check_amalgamation for PRs
Expand Down Expand Up @@ -63,11 +73,11 @@ jobs:
collect_artifacts_pr:
name: "Collect Results & Deploy (PR)"
if: github.event_name == 'pull_request'
needs: [labeler, check_amalgamation, test_trudag_extensions, dependency_review, codeql, ubuntu]
needs: [labeler, SME_review_checker, check_amalgamation, test_trudag_extensions, dependency_review, codeql, ubuntu]
runs-on: ubuntu-latest
strategy:
matrix:
target: [labeler, check_amalgamation, test_trudag_extensions, dependency_review, codeql, ubuntu]
target: [labeler, SME_review_checker, check_amalgamation, test_trudag_extensions, dependency_review, codeql, ubuntu]

steps:
- name: Checkout code
Expand Down Expand Up @@ -96,7 +106,7 @@ jobs:
collect_artifacts_non_pr:
name: "Collect Results & Deploy (Non-PR)"
if: github.event_name != 'pull_request'
needs: [labeler, test_trudag_extensions, codeql, ubuntu] # no check_amalgamation or dependency_review if non PR
needs: [labeler, test_trudag_extensions, codeql, ubuntu] # no check_amalgamation, dependency_review or SME_review_checker if non PR
runs-on: ubuntu-latest
strategy:
matrix:
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/publish_documentation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,14 @@ jobs:
with:
python-version: '3.11.2'

# trudag version 2025.8.5
# trudag version v2025.10.22
- name: Install trudag and dependencies
run: |
sudo apt-get update
sudo apt-get install -y graphviz
pip install git+https://gitlab.com/CodethinkLabs/trustable/trustable@9957f12171cb898d83df5ae708fdba0a38fece2e
pip install --upgrade pip
pip install PyYAML requests
pip install git+https://gitlab.com/CodethinkLabs/trustable/trustable@v2025.10.22

- name: Install tools
run: |
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/test_publication.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,14 @@ jobs:
with:
python-version: '3.11.2'

# trudag version 2025.8.5
# trudag version v2025.10.22
- name: Install trudag and dependencies
run: |
sudo apt-get update
sudo apt-get install -y graphviz
pip install git+https://gitlab.com/CodethinkLabs/trustable/trustable@9957f12171cb898d83df5ae708fdba0a38fece2e
pip install --upgrade pip
pip install PyYAML requests
pip install git+https://gitlab.com/CodethinkLabs/trustable/trustable@v2025.10.22

- name: Generate trudag report
run: |
Expand Down
Loading
Loading