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
27 changes: 27 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: CI

on:
push:
pull_request:
branches: [main]
schedule:
- cron: '0 0 * * 0'

jobs:
test:
name: Test (Octave ${{ matrix.octave }})
runs-on: ubuntu-latest
container: gnuoctave/octave:${{ matrix.octave }}
strategy:
matrix:
octave: ["8.4.0", "9.4.0", "10.3.0", "11.3.0"]
fail-fast: false

steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # actions/checkout@v6.0.3
with:
submodules: recursive

- name: Build and test
run: make check-ci
13 changes: 13 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,19 @@ Your contribution must be an independent work or derived from code that may be r

[Fork](https://github.com/gnu-octave/pkg-control/fork) the pkg-control repository to your own account and clone the resulting repository. Refer to the [README](README.md) file for information about how to build the package archive which can be installed in GNU Octave.

### Running tests locally

The easiest way to run the test suite locally is with Docker. Make sure the
submodules are initialized first, then run:

```bash
git submodule update --init
make check-local
```

This pulls the latest `gnuoctave/octave` image and runs the full test suite
inside it, matching the CI environment. Docker must be installed and running.

### Pull request

When your changes are finished, commit and push the change to your forked repository on Github (make sure your fork is up to date) and create a pull request.
Expand Down
11 changes: 10 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ DOCS_PDF := $(DOCS_DIR)/$(PACKAGE).pdf
DOCS_QCH := $(DOCS_DIR)/$(PACKAGE).qch
DOCS_LOGO := $(DOCS_DIR)/$(PACKAGE).svg

.PHONY: help dist docs-html docs release install all check run clean
.PHONY: help dist docs-html docs release install all check check-ci check-local run clean

help:
@echo " "
Expand Down Expand Up @@ -208,6 +208,15 @@ check: install
$(OCTAVE) --path "inst/" --path "src/" \
--eval 'pkg test control'

check-ci:
test -f $(SRC)/Makefile.conf || (cd $(SRC) && ./bootstrap && ./configure)
$(MAKE) -C $(SRC) all
$(OCTAVE) --no-gui --version
$(OCTAVE) --no-gui --path "inst/" --path "src/" devel/run_tests.m

check-local:
docker compose --file devel/compose.yaml --project-directory . run --rm octave

clean:
$(RM) -r $(TARGET_DIR)
$(MAKE) -C $(SRC) clean
Expand Down
7 changes: 7 additions & 0 deletions devel/compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
services:
octave:
image: gnuoctave/octave:latest
working_dir: /workspace
volumes:
- .:/workspace
command: make check-ci
57 changes: 57 additions & 0 deletions devel/run_tests.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
## Run embedded %!test blocks from source without installing the package.
##
## The canonical way (according to the docs I've found) to to actually test is
## to call 'pkg test control' but that is coupled to docs today because it
## requires you to install first, but to install you have to build a release
## tarball with dist which depends on docs. This is a "hack" to get around that
## and just run the tests directly. This should probably change in the future
## b/c searching and grepping through a bunch of src files to test is very
## awkward.
##
## Called by 'make check-ci'. Exit code is nonzero if any tests fail.

## Register autoloads from PKG_ADD directives (normally done by pkg install)

src_path = fullfile (fileparts (mfilename ("fullpath")), "..", "src");

## Find all .cc files in src/ b/c those are compiled to .oct files. We literally
## just want this out of the cpp files so that we know what .oct file we should
## target
## // PKG_ADD: autoload ("__sl_sb03md__", "__control_slicot_functions__.oct");
cc_files = glob (fullfile (src_path, "*.cc"));

## Read every file and grep of PKG_ADD, call autoload() on it with the absolute
## path to the .oct file. Autoload registers a deffered load which tells octave
## "when someone calls funcname, load filepath to find it, the .oct file isn't
## actually loaded until that first call"
for i = 1:numel (cc_files)
txt = fileread (cc_files{i});
## Use a regex to capture the 2 arguments (function name and .oct filename)
toks = regexp (txt, 'PKG_ADD: autoload \("(\w+)", "(\w+\.oct)"\)', "tokens");
for j = 1:numel (toks)
autoload (toks{j}{1}, fullfile (src_path, toks{j}{2}));
endfor
endfor

## Find all the class dirs to test ("inst", "inst/@tf", etc...)
dirs = [{"inst"}, cellstr(glob ("inst/@*"))'];

n_pass = 0;
n_total = 0;

## For every dir we collected, go through every mfile and call test
for i = 1:numel (dirs)
mfiles = dir (fullfile (dirs{i}, "*.m"));
for j = 1:numel (mfiles)
f = fullfile (mfiles(j).folder, mfiles(j).name);
## collect output args from test call
## https://docs.octave.org/v11.1.0/Test-Functions.html
[p, total, xfail, xbug, skip, rtskip] = test (f, "quiet", stdout);
n_pass += p;
n_total += total - xfail - xbug - skip - rtskip;
endfor
endfor

n_fail = n_total - n_pass;
fprintf ("\nTotal: %d passed, %d failed\n", n_pass, n_fail);
exit (n_fail > 0);