Skip to content
Open
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
14 changes: 12 additions & 2 deletions .github/workflows/lima.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ on:

permissions: {}

# needed for logformatter
env:
PR_NUMBER: ${{ github.event.pull_request.number || '' }}
PR_TITLE: ${{ github.event.pull_request.title || '' }}
GITHUB_RUN_ID: ${{ github.run_id }}

jobs:
lima:
if: ${{ inputs.if }}
Expand Down Expand Up @@ -64,6 +70,10 @@ jobs:
run: | # zizmor: ignore[template-injection]
./hack/ci/ci.sh ${{ inputs.test }} ${{ inputs.mode }} ${{ inputs.priv }} ${{ inputs.distro }}

- name: Output failure log as GITHUB_STEP_SUMMARY
if: failure()
run: hack/ci/github_log_summary.py hack/ci/logs/*.html > $GITHUB_STEP_SUMMARY || true

# TODO: figure out how to cache the binaries from the build job to the actual test tasks
# - name: Upload binaries as artifact
# if: ${{ inputs.test == 'build' }}
Expand All @@ -77,6 +87,6 @@ jobs:
if: always() # always collect the log
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a #v7.0.1
with:
name: "journal-${{ inputs.test }}-${{ inputs.mode }}-${{ inputs.priv }}-${{ inputs.distro }}.log"
path: "./hack/ci/journal.log"
name: "${{ inputs.test }}-${{ inputs.mode }}-${{ inputs.priv }}-${{ inputs.distro }}.logs"
path: "./hack/ci/logs/*"
if-no-files-found: ignore
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ coverprofile
/docs/*.[158].gz
/docs/build/
/docs/remote
/hack/ci/logs/
**.DS_Store
.gopathok
.idea*
Expand Down
15 changes: 11 additions & 4 deletions hack/ci/ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,30 @@ IMAGE_URL="https://objectstorage.us-ashburn-1.oraclecloud.com/n/id0lmbbwgcdv/b/p

trap "limactl delete --force $LIMA_VM_NAME" EXIT

echo "::group::Starting VM"
limactl --yes start --plain --name=$LIMA_VM_NAME --cpus $(nproc) --memory 8 --nested-virt \
--set ".images=[{\"location\":\"$IMAGE_URL\", \"arch\": \"x86_64\"}]" \
"$SCRIPT_DIR/template.lima.yml"

limactl copy "$REPO_DIR" $LIMA_VM_NAME:/var/tmp/podman
limactl shell $LIMA_VM_NAME mkdir -p /var/tmp/podman-container-tools

limactl copy "$REPO_DIR" $LIMA_VM_NAME:/var/tmp/podman-container-tools/podman

echo "::endgroup::"

set +e

limactl shell --workdir /var/tmp/podman $LIMA_VM_NAME ./hack/ci/runner.sh "${@}"
limactl shell --preserve-env --workdir /var/tmp/podman-container-tools/podman $LIMA_VM_NAME ./hack/ci/runner.sh "${@}"
rc=$?

limactl shell --workdir /var/tmp/podman $LIMA_VM_NAME sudo ./hack/ci/logcollector.sh journal &> "$SCRIPT_DIR/journal.log"
echo "::group::Collecting logs"
limactl copy $LIMA_VM_NAME:/var/tmp/podman-container-tools/podman/hack/ci/logs/ $SCRIPT_DIR/logs
echo "::endgroup::"

# TODO: figure out how to cache the binaries from the build job to the actual test tasks
# Copy the binaries out of the VM in gh actions so we can upload them as artifact
# if [[ -n "$GITHUB_ACTIONS" && "$TEST" == build ]]; then
# limactl copy $LIMA_VM_NAME:/var/tmp/podman/bin "$REPO_DIR/bin" || die "failed to copy binaries"
# limactl copy $LIMA_VM_NAME:/var/tmp/podman-container-tools/podman/bin "$REPO_DIR/bin" || die "failed to copy binaries"
# fi

exit $rc
128 changes: 128 additions & 0 deletions hack/ci/github_log_summary.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#!/usr/bin/env python

from html.parser import HTMLParser
import html
import sys

class GinkgoLogFilterParser(HTMLParser):
def __init__(self):
super().__init__()
# Stack to keep track of nested elements
self.stack = []
# Store the raw HTML strings of matching 'tt' elements
self.results = []

def _get_classes(self, attrs):
"""Helper to extract classes from an attribute list."""
for attr, value in attrs:
if attr == 'class' and value:
return value.split()
return []

def handle_starttag(self, tag, attrs):
classes = self._get_classes(attrs)
is_tt = 'tt' in classes
is_failed = 'log-failed' in classes

# If we see a 'log-failed' class, flag all 'tt' ancestors in the stack
if is_failed:
for node in self.stack:
if node['is_tt']:
node['keep'] = True

# Push the new element to the stack
self.stack.append({
'tag': tag,
'text_chunks': [],
'is_tt': is_tt,
'keep': False
})

def handle_startendtag(self, tag, attrs):
# Handle self-closing tags just to check for the failure class
classes = self._get_classes(attrs)
if 'log-failed' in classes:
for node in self.stack:
if node['is_tt']:
node['keep'] = True

def handle_data(self, data):
# Capture raw text data
if self.stack:
self.stack[-1]['text_chunks'].append(data)

def handle_endtag(self, tag):
# Find the matching start tag in the stack
for i in reversed(range(len(self.stack))):
if self.stack[i]['tag'] == tag:
# Pop the matching tag and any unclosed children
while len(self.stack) > i:
node = self.stack.pop()

# Join all the collected text for this node
node_text = "".join(node['text_chunks'])
# Trim down the spaces for the ginkgo long indentation.
node_text = node_text.removeprefix(' ' * 9)

# If this is a 'tt' element and it contains a 'log-failed' child, save the text
if node['is_tt'] and node['keep']:
self.results.append(node_text)

# Pass the text of this node up to its parent so we don't lose inner text
if self.stack:
self.stack[-1]['text_chunks'].append(node_text)
break

class BatsLogFilterParser(HTMLParser):
def __init__(self):
super().__init__()
# Current Tag which text should be stored
self.record = None
self.data = ""

def _get_classes(self, attrs):
"""Helper to extract classes from an attribute list."""
for attr, value in attrs:
if attr == 'class' and value:
return value.split()
return []

def handle_starttag(self, tag, attrs):
classes = self._get_classes(attrs)

if 'bats-failed' in classes or 'bats-log-failblock' in classes or 'bats-log' in classes:
self.record = tag

def handle_data(self, data):
if self.record:
self.data += data

def handle_endtag(self, tag):
if self.record == tag:
self.data += "\n"
self.record = None



def filter_html_file(file_path):
# Read the HTML content
with open(file_path, 'r', encoding='utf-8') as f:
html_content = f.read()

if 'int-' in file_path:
parser = GinkgoLogFilterParser()
parser.feed(html_content)
return parser.results

parser = BatsLogFilterParser()
parser.feed(html_content)
return [parser.data]


# Running the filter
matching_elements = filter_html_file(sys.argv[1])

for element in matching_elements:
print(f"```")
print(element)
print("```")
5 changes: 5 additions & 0 deletions hack/ci/lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ OS_RELEASE_ID="$(
)"
OS_REL_VER="$OS_RELEASE_ID-$OS_RELEASE_VER"

TEST_NAME=$(
IFS=-
echo "${*}"
)

function die() {
echo "$1" >&2
exit 1
Expand Down
Loading
Loading