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
11 changes: 10 additions & 1 deletion .github/actions/post-qc-comment/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@ name: Post QC comment
description: Build the model-quality report and create or update the single QC comment on the pull request.

inputs:
mode:
description: >-
"both" (default) builds the report and posts the comment; "build" only renders
data/testResults/model_qc_summary.md (so it can be committed first); "post" only
posts the already-rendered summary (use after the commit).
required: false
default: both
running-groups:
description: Groups still running (their rows show as running); "all", "memote", or empty.
required: false
Expand Down Expand Up @@ -32,6 +39,7 @@ runs:
using: composite
steps:
- name: Build report
if: inputs.mode == 'both' || inputs.mode == 'build'
shell: bash
env:
RUNNING_GROUPS: ${{ inputs.running-groups }}
Expand All @@ -41,7 +49,8 @@ runs:
run: python code/test/buildReport.py

- name: Create or update the comment
uses: actions/github-script@v7
if: inputs.mode == 'both' || inputs.mode == 'post'
uses: actions/github-script@v9
env:
ISSUE_NUMBER: ${{ inputs.issue-number }}
with:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/add-contributor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
steps:
- name: Parse the command
id: parse
uses: actions/github-script@v7
uses: actions/github-script@v9
with:
script: |
const body = context.payload.comment.body || '';
Expand Down Expand Up @@ -88,7 +88,7 @@ jobs:

- name: Reply with the pull request link
if: steps.parse.outputs.found == 'true' && steps.cpr.outputs.pull-request-number
uses: actions/github-script@v7
uses: actions/github-script@v9
with:
script: |
const n = '${{ steps.cpr.outputs.pull-request-number }}';
Expand Down
8 changes: 5 additions & 3 deletions .github/workflows/gene-essentiality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,12 @@ jobs:
echo "GENEESS_EOF"
} >> "$GITHUB_OUTPUT"

# This workflow is dispatched (by /run gene-essentiality), so it has no
# pull_request context; the PR number arrives as the `pr` input instead.
- name: Mention PR# in README.md
if: github.event_name == 'pull_request'
if: inputs.pr != ''
env:
PR_NUMBER: ${{ github.event.number }}
PR_NUMBER: ${{ inputs.pr }}
run: sed -i -e "s/[[:digit:]]\{3,4\}\*\* (gene /$PR_NUMBER\*\* (gene /" data/testResults/README.md

- name: Update local branch before committing changes
Expand Down Expand Up @@ -110,7 +112,7 @@ jobs:

- name: Post comment
if: inputs.pr != ''
uses: actions/github-script@v7
uses: actions/github-script@v9
env:
TEST_RESULTS: ${{ steps.essentiality.outputs.results }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
Expand Down
7 changes: 3 additions & 4 deletions .github/workflows/memote-full.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@ env:
RESULT_FILES: >-
qc_duplicate_keys.csv qc_empty_reactions.csv qc_annotation_consistency.csv
qc_unused_entities.csv qc_duplicate_reactions.csv qc_metabolite_completeness.csv
qc_reaction_sanity.csv qc_annotation_issues.csv qc_growth.txt memote_score.md
macaw_results.csv balance_results.csv qc_structure_consistency.csv
qc_roundtrip_cobra.txt qc_roundtrip_raven.txt qc_yamllint.txt
qc_tasks_essential.txt qc_tasks_verification.txt
qc_reaction_sanity.csv qc_annotation_issues.csv qc_deprecation_completeness.csv
qc_status.tsv memote_score.md macaw_results.csv balance_results.csv
qc_structure_consistency.csv

jobs:
memote-full:
Expand Down
85 changes: 53 additions & 32 deletions .github/workflows/model-qc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,22 @@ on: [pull_request]

env:
# Committed result files, fetched from the target branch so buildReport can show a
# delta. No stamp files: freshness is passed to buildReport as RUNNING_GROUPS.
# delta. No stamp files: freshness is passed to buildReport as RUNNING_GROUPS. The
# one-line checks (round-trip, yamllint, metabolic tasks) and the growth value all
# live together in qc_status.tsv (see qcStatus.py) rather than one file each.
RESULT_FILES: >-
qc_duplicate_keys.csv qc_empty_reactions.csv qc_annotation_consistency.csv
qc_unused_entities.csv qc_duplicate_reactions.csv qc_metabolite_completeness.csv
qc_reaction_sanity.csv qc_annotation_issues.csv qc_growth.txt memote_score.md
macaw_results.csv balance_results.csv qc_structure_consistency.csv
qc_roundtrip_cobra.txt qc_roundtrip_raven.txt qc_yamllint.txt
qc_tasks_essential.txt qc_tasks_verification.txt

# One job runs every check and edits a single pull-request comment as results come
# in: it posts a "running" comment immediately, fills in the fast checks, then fills
# in the MEMOTE score when it finishes. Results are committed once, at the end, and
# only if they changed - so a change that does not affect the model adds no commit.
qc_reaction_sanity.csv qc_annotation_issues.csv qc_deprecation_completeness.csv
qc_status.tsv memote_score.md macaw_results.csv balance_results.csv
qc_structure_consistency.csv

# One job runs every check and edits a single pull-request comment. It posts a
# "running" comment immediately (all rows as hourglasses, no numbers), runs every
# check including the MEMOTE fast subset, commits the results once at the end (with
# [skip ci], and only if something changed), and only then edits the comment to show
# the results - so the comment never reports numbers, or links to CSVs, that are not
# yet on the branch.
jobs:
qc:
runs-on: ubuntu-latest
Expand All @@ -36,7 +39,9 @@ jobs:
uses: actions/checkout@v7

- name: Configure
run: echo "BASE_DIR=$RUNNER_TEMP/base" >> "$GITHUB_ENV"
run: |
echo "BASE_DIR=$RUNNER_TEMP/base" >> "$GITHUB_ENV"
echo "BASE_MODEL_DIR=$RUNNER_TEMP/base-model" >> "$GITHUB_ENV"

- name: Set up Python 3
uses: actions/setup-python@v6
Expand All @@ -53,6 +58,12 @@ jobs:
for f in $RESULT_FILES; do
git show "origin/$BASE_REF:data/testResults/$f" > "$BASE_DIR/$f" 2>/dev/null || rm -f "$BASE_DIR/$f"
done
# Base-branch model tables: qcModelChecks.py diffs them against this model
# to flag identifiers removed here but not moved to a deprecated list.
mkdir -p "$BASE_MODEL_DIR"
for f in reactions.tsv metabolites.tsv; do
git show "origin/$BASE_REF:model/$f" > "$BASE_MODEL_DIR/$f" 2>/dev/null || rm -f "$BASE_MODEL_DIR/$f"
done

# Immediate feedback: everything shows as running.
- name: Post running comment
Expand Down Expand Up @@ -95,11 +106,15 @@ jobs:

- name: YAML round-trip (cobrapy)
continue-on-error: true
run: python code/test/testYamlConversion.py --tool cobra && echo pass > data/testResults/qc_roundtrip_cobra.txt || echo fail > data/testResults/qc_roundtrip_cobra.txt
run: |
if python code/test/testYamlConversion.py --tool cobra; then r=pass; else r=fail; fi
python code/test/qcStatus.py roundtrip_cobra "$r"

- name: YAML round-trip (RAVEN)
continue-on-error: true
run: python code/test/testYamlConversion.py --tool raven-toolbox && echo pass > data/testResults/qc_roundtrip_raven.txt || echo fail > data/testResults/qc_roundtrip_raven.txt
run: |
if python code/test/testYamlConversion.py --tool raven-toolbox; then r=pass; else r=fail; fi
python code/test/qcStatus.py roundtrip_raven "$r"

- name: YAML lint
id: yamllint
Expand All @@ -111,23 +126,15 @@ jobs:

- name: Record YAML lint result
if: always()
run: echo "${{ steps.yamllint.outcome == 'success' && 'pass' || 'fail' }}" > data/testResults/qc_yamllint.txt
run: python code/test/qcStatus.py yamllint "${{ steps.yamllint.outcome == 'success' && 'pass' || 'fail' }}"

- name: Metabolic tasks (essential and verification)
continue-on-error: true
run: python code/test/testMetabolicTasks.py all

# Fast checks are in; MEMOTE is still running.
- name: Update comment with fast checks
uses: ./.github/actions/post-qc-comment
with:
running-groups: memote
base-ref: ${{ env.BASE_REF }}
base-dir: ${{ env.BASE_DIR }}
results-url-base: ${{ env.RESULTS_URL_BASE }}
run-url: ${{ env.RUN_URL }}
github-token: ${{ secrets.GITHUB_TOKEN }}

# The MEMOTE fast subset finishes quickly, so there is no interim update: all
# checks (fast + MEMOTE) run, then everything is committed once and the comment
# is posted from the committed files below. Until then the running comment stands.
- name: Install MEMOTE dependencies
run: pip install memote gurobipy

Expand Down Expand Up @@ -155,10 +162,13 @@ jobs:
timeout 2400 python code/test/memoteSnapshot.py \
|| echo "::warning::MEMOTE did not finish within 2400s; score unavailable this run."

# Everything is in.
- name: Update comment with all results
# Everything is in: render the final summary so it is part of the commit below,
# then post from the committed file - the comment is updated only after the
# results are committed (so its numbers and CSV links resolve).
- name: Render final report
uses: ./.github/actions/post-qc-comment
with:
mode: build
running-groups: ""
base-ref: ${{ env.BASE_REF }}
base-dir: ${{ env.BASE_DIR }}
Expand Down Expand Up @@ -195,6 +205,17 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

# Now that the results (including model_qc_summary.md) are committed, post the
# comment from the committed summary.
- name: Post final comment
if: always()
uses: ./.github/actions/post-qc-comment
with:
mode: post
run-url: ${{ env.RUN_URL }}
base-ref: ${{ env.BASE_REF }}
github-token: ${{ secrets.GITHUB_TOKEN }}

- name: Upload full MEMOTE result
uses: actions/upload-artifact@v7
with:
Expand All @@ -209,12 +230,12 @@ jobs:
run: |
fail=0
[ "${{ steps.qc.outcome }}" = "failure" ] && fail=1
for f in qc_roundtrip_cobra qc_roundtrip_raven qc_yamllint; do
[ "$(cat data/testResults/$f.txt 2>/dev/null)" = "fail" ] && { echo "::error::$f failed"; fail=1; }
for k in roundtrip_cobra roundtrip_raven yamllint; do
[ "$(python code/test/qcStatus.py --get $k)" = "fail" ] && { echo "::error::$k failed"; fail=1; }
done
for f in qc_tasks_essential qc_tasks_verification; do
v=$(cat "data/testResults/$f.txt" 2>/dev/null)
[ -n "$v" ] && [ "${v%%/*}" != "0" ] && { echo "::error::$f: ${v%%/*} task(s) failed"; fail=1; }
for k in tasks_essential tasks_verification; do
v=$(python code/test/qcStatus.py --get $k)
[ -n "$v" ] && [ "${v%%/*}" != "0" ] && { echo "::error::$k: ${v%%/*} task(s) failed"; fail=1; }
done
if [ "$fail" = 1 ]; then
echo "::error::A build gate failed; see the PR comment and the linked results."
Expand Down
Loading
Loading