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
120 changes: 120 additions & 0 deletions .github/scripts/nftest_coverage_comment.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#!/usr/bin/env bash

# See the NOTICE file distributed with this work for additional information
# regarding copyright ownership.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -euo pipefail

FILE=$1
if [[ ! -s "$FILE" ]]; then
echo "Coverage file $FILE is empty. Exiting."
exit 1
fi
COVERAGE_THRESHOLD=${COVERAGE_THRESHOLD:-90}
MARKER="<!-- nf-test-coverage-report -->"

: "${GITHUB_TOKEN:?Missing GITHUB_TOKEN}"
: "${GITHUB_REPOSITORY:?Missing GITHUB_REPOSITORY}"
: "${GITHUB_EVENT_PATH:?Missing GITHUB_EVENT_PATH}"

# Get PR number
PR_NUMBER=$(jq -r '.pull_request.number' "$GITHUB_EVENT_PATH")

if [[ -z "$PR_NUMBER" || "$PR_NUMBER" == "null" ]]; then
echo "Not running on a pull request. Exiting."
exit 0
fi

# ---- Parse nf-test coverage totals ----
COVERAGE_LINE=$(grep -E '(COVERAGE:|Status:)' "$FILE" | tail -1 || true)
if [[ -z "$COVERAGE_LINE" ]]; then
echo "ERROR: Could not find coverage line in $FILE"
cat "$FILE"
exit 1
fi

if echo "$COVERAGE_LINE" | grep -q 'COVERAGE:'; then
TOTAL_COVERAGE=$(echo "$COVERAGE_LINE" | grep -oE '[0-9]+(\.[0-9]+)?%' | tr -d '%' || true)
HIT_FILES=$(echo "$COVERAGE_LINE" | grep -oE '[0-9]+ of' | grep -oE '[0-9]+' || true)
TOTAL_FILES=$(echo "$COVERAGE_LINE" | grep -oE 'of [0-9]+' | grep -oE '[0-9]+' || true)
else
# New format: "Status: 26 of 64 modules and workflows are covered ... (40.62%)"
TOTAL_COVERAGE=$(echo "$COVERAGE_LINE" | grep -oE '\([0-9]+(\.[0-9]+)?%\)' | tr -d '()%' || true)
HIT_FILES=$(echo "$COVERAGE_LINE" | grep -oE '[0-9]+ of' | grep -oE '[0-9]+' || true)
TOTAL_FILES=$(echo "$COVERAGE_LINE" | grep -oE 'of [0-9]+' | grep -oE '[0-9]+' || true)
fi

if [[ -z "$TOTAL_COVERAGE" || \
-z "$HIT_FILES" || \
-z "$TOTAL_FILES" || "$TOTAL_FILES" -eq 0 ]];
then
echo "Could not parse coverage percentage from: $COVERAGE_LINE"
exit 1
fi

COVERAGE_OK=$(awk -v cov="$TOTAL_COVERAGE" -v th="$COVERAGE_THRESHOLD" \
'BEGIN { print (cov >= th) ? "yes" : "no" }')

if [[ "$COVERAGE_OK" == "yes" ]]; then
STATUS_ICON="✅"
STATUS_TEXT="Coverage meets threshold"
else
STATUS_ICON="❌"
STATUS_TEXT="Coverage below ${COVERAGE_THRESHOLD}% threshold"
fi


# ---- Comment body ----
COMMENT_BODY=$(cat <<EOF
$MARKER
### 🧪 nf-test Coverage Report

**Total coverage:** **${TOTAL_COVERAGE}%**
**Lines:** $HIT_FILES / $TOTAL_FILES
**Status:** $STATUS_ICON $STATUS_TEXT
EOF
)

# ---- GitHub API ----
API_URL="https://api.github.com"
COMMENTS_URL="$API_URL/repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/comments"
AUTH_HEADER="Authorization: Bearer $GITHUB_TOKEN"

EXISTING_COMMENT_ID=$(curl -s \
-H "$AUTH_HEADER" \
-H "Accept: application/vnd.github+json" \
"$COMMENTS_URL" \
| jq -r ".[] | select(.body | contains(\"$MARKER\")) | .id")

if [[ -n "$EXISTING_COMMENT_ID" ]]; then
echo "Updating existing nf-test coverage comment"
curl -s -X PATCH \
-H "$AUTH_HEADER" \
-H "Accept: application/vnd.github+json" \
"$API_URL/repos/$GITHUB_REPOSITORY/issues/comments/$EXISTING_COMMENT_ID" \
-d "$(jq -nc --arg body "$COMMENT_BODY" '{body: $body}')"
else
echo "Creating nf-test coverage comment"
curl -s -X POST \
-H "$AUTH_HEADER" \
-H "Accept: application/vnd.github+json" \
"$COMMENTS_URL" \
-d "$(jq -nc --arg body "$COMMENT_BODY" '{body: $body}')"
fi

# ---- Fail CI if coverage too low ----
if [[ "$COVERAGE_OK" != "yes" ]]; then
echo "Coverage ${TOTAL_COVERAGE}% is below threshold ${COVERAGE_THRESHOLD}%"
exit 1
fi
127 changes: 127 additions & 0 deletions .github/scripts/py_coverage_comment.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
#!/usr/bin/env bash

# See the NOTICE file distributed with this work for additional information
# regarding copyright ownership.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -euo pipefail

LCOV_FILE=$1
if [[ ! -s "$LCOV_FILE" ]]; then
echo "Coverage file $LCOV_FILE is empty. Exiting."
exit 1
fi
COVERAGE_THRESHOLD=${COVERAGE_THRESHOLD:-90}
MARKER="<!-- python-lcov-coverage-report -->"

: "${GITHUB_TOKEN:?Missing GITHUB_TOKEN}"
: "${GITHUB_REPOSITORY:?Missing GITHUB_REPOSITORY}"
: "${GITHUB_EVENT_PATH:?Missing GITHUB_EVENT_PATH}"

# Get PR number
PR_NUMBER=$(jq -r '.pull_request.number' "$GITHUB_EVENT_PATH")

if [[ -z "$PR_NUMBER" || "$PR_NUMBER" == "null" ]]; then
echo "Not running on a pull request. Exiting."
exit 0
fi

# ---- Parse LCOV totals ----
TOTAL_LINES=$(grep -h '^LF:' "$LCOV_FILE" | awk -F: '{sum += $2} END {print sum}')
HIT_LINES=$(grep -h '^LH:' "$LCOV_FILE" | awk -F: '{sum += $2} END {print sum}')

if [[ -z "$TOTAL_LINES" || "$TOTAL_LINES" -eq 0 ]]; then
echo "Failed to parse LCOV file"
exit 1
fi

TOTAL_COVERAGE=$(awk -v hit="$HIT_LINES" -v total="$TOTAL_LINES" \
'BEGIN { printf "%.2f", (hit / total) * 100 }')

COVERAGE_OK=$(awk -v cov="$TOTAL_COVERAGE" -v th="$COVERAGE_THRESHOLD" \
'BEGIN { print (cov >= th) ? "yes" : "no" }')

if [[ "$COVERAGE_OK" == "yes" ]]; then
STATUS_ICON="✅"
STATUS_TEXT="Coverage meets threshold"
else
STATUS_ICON="❌"
STATUS_TEXT="Coverage below ${COVERAGE_THRESHOLD}% threshold"
fi

# ---- Per-file coverage table ----
TABLE=$(awk '
BEGIN {
print "| File | Coverage |"
print "|------|----------|"
}
$1 ~ /^SF:/ { file = substr($1,4); lf=0; lh=0 }
$1 ~ /^LF:/ { lf = substr($1,4) }
$1 ~ /^LH:/ { lh = substr($1,4) }
$1 ~ /^end_of_record/ {
if (lf > 0) {
printf "| %s | %.2f%% |\n", file, (lh / lf) * 100
}
}
' "$LCOV_FILE")

# ---- Comment body ----
COMMENT_BODY=$(cat <<EOF
$MARKER
### 🐍 Python Coverage Report (coverage.py / lcov)

**Total coverage:** **${TOTAL_COVERAGE}%**
**Lines:** $HIT_LINES / $TOTAL_LINES
**Status:** $STATUS_ICON $STATUS_TEXT

<details>
<summary>Per-file coverage</summary>

$TABLE

</details>
EOF
)

# ---- GitHub API ----
API_URL="https://api.github.com"
COMMENTS_URL="$API_URL/repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/comments"
AUTH_HEADER="Authorization: Bearer $GITHUB_TOKEN"

EXISTING_COMMENT_ID=$(curl -s \
-H "$AUTH_HEADER" \
-H "Accept: application/vnd.github+json" \
"$COMMENTS_URL" \
| jq -r ".[] | select(.body | contains(\"$MARKER\")) | .id")

if [[ -n "$EXISTING_COMMENT_ID" ]]; then
echo "Updating existing Python coverage comment"
curl -s -X PATCH \
-H "$AUTH_HEADER" \
-H "Accept: application/vnd.github+json" \
"$API_URL/repos/$GITHUB_REPOSITORY/issues/comments/$EXISTING_COMMENT_ID" \
-d "$(jq -nc --arg body "$COMMENT_BODY" '{body: $body}')"
else
echo "Creating Python coverage comment"
curl -s -X POST \
-H "$AUTH_HEADER" \
-H "Accept: application/vnd.github+json" \
"$COMMENTS_URL" \
-d "$(jq -nc --arg body "$COMMENT_BODY" '{body: $body}')"
fi

# ---- Fail CI if coverage too low ----
if [[ "$COVERAGE_OK" != "yes" ]]; then
echo "Coverage ${TOTAL_COVERAGE}% is below threshold ${COVERAGE_THRESHOLD}%"
exit 1
fi
45 changes: 45 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# See the NOTICE file distributed with this work for additional information
# regarding copyright ownership.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

name: build
on: workflow_dispatch

env:
PYTHON_SRC_DIR: src/python/ensembl
RUST_SRC_DIR: src/rust/ensembl
BIN_DIR: nextflow/vcf_prepper/bin

jobs:
python:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install/Update Dependencies
run: python3 -m pip install --upgrade build
- name: Build
run: python3 -m build ${{ env.PYTHON_SRC_DIR }}

rust:
runs-on: ubuntu-latest
strategy:
matrix:
BUILD_TARGET: [
bed_to_wig,
merge_bed
vcf_to_bed
]
steps:
- uses: actions/checkout@v4
- name: Build ${{ matrix.BUILD_TARGET }}
run: cargo build --manifest_file ${{ env.RUST_SRC_DIR }}/${{ matrix.BUILD_TARGET }}/Cargo.toml --artifact-dir ${{ BIN_DIR }}
47 changes: 47 additions & 0 deletions .github/workflows/linting.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# See the NOTICE file distributed with this work for additional information
# regarding copyright ownership.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

name: linting
on: workflow_dispatch

# Make sure CI fails on all warnings, including Clippy lints
env:
RUSTFLAGS: "-Dwarnings"

jobs:
ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install ruff
- name: Run Ruff Check
run: ruff check --output-format=github .
- name: Run Ruff Format
run: ruff format

clippy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Clippy
run: cargo clippy --all-targets --all-features
- name: Run Rustfmt
run: cargo +nightly fmt
12 changes: 0 additions & 12 deletions .github/workflows/main.yml

This file was deleted.

Loading
Loading