Skip to content

Commit 5f1b8cf

Browse files
authored
Add release workflow (#699)
* Create Contents.m * Add workflow file for preparing new release * Update worflow to run on a matrix of platforms * Update CloneNwbTest.m Add ad hoc pc compatibility fix * Update requirements.txt Some requirements are not present by default on windows runners * Update prepare_release.yml Fix problems running tests on mac and windows runners * Update prepare_release.yml Update job name * Update prepare_release.yml Use deploy key as this will job will push back to protected branch * Add page in docs detailing how to create a release * Update releases.rst Fix rst formatting * Update prepare_release.yml
1 parent d38a5f7 commit 5f1b8cf

File tree

7 files changed

+302
-1
lines changed

7 files changed

+302
-1
lines changed

+tests/+unit/+file/CloneNwbTest.m

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ function testCloneNwbFile(testCase)
4040

4141
function restoreNwbFileClass(classDefStr)
4242
fid = fopen( fullfile(misc.getMatnwbDir(), 'NwbFile.m'), 'wt' );
43+
if ispc % Ad hoc fix when saving to file using fwrite on pc
44+
classDefStr = strrep(classDefStr, newline, '');
45+
end
4346
fwrite(fid, classDefStr);
4447
fclose(fid);
4548
end

+tests/requirements.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
hdf5plugin
21
scipy
2+
matplotlib
3+
hdf5plugin
4+
dataframe_image
35
git+https://github.com/NeurodataWithoutBorders/nwbinspector.git@dev
46
git+https://github.com/NeurodataWithoutBorders/pynwb.git@dev

.github/workflows/prepare_release.yml

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
# Run MATLAB tests across multiple MATLAB versions and create a draft release
2+
3+
name: Prepare release
4+
on:
5+
workflow_dispatch:
6+
inputs:
7+
version:
8+
description: 'Version number in major.minor.patch format, i.e 2.8.0'
9+
required: true
10+
type: string
11+
12+
jobs:
13+
validate_version:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- name: Check version format
17+
run: |
18+
version="${{ github.event.inputs.version }}"
19+
if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
20+
echo "Error: Input for 'version' ('$version') is not in the expected major.minor.patch format."
21+
exit 1
22+
fi
23+
echo "Version '$version' is valid."
24+
25+
run_tests:
26+
name: Run MATLAB tests (${{ matrix.matlab-version }} on ${{ matrix.os }})
27+
runs-on: ${{ matrix.os }}
28+
needs: [validate_version]
29+
strategy:
30+
fail-fast: false
31+
matrix:
32+
os: [windows-latest, ubuntu-latest, macos-13]
33+
matlab-version: [R2021a, R2021b, R2022a, R2022b, R2023a, R2023b, R2024a, R2024b]
34+
include:
35+
- matlab-version: R2021a
36+
python-version: '3.9'
37+
skip-pynwb-compatibilty-test-for-tutorial: '1'
38+
- matlab-version: R2021b
39+
python-version: '3.9'
40+
skip-pynwb-compatibilty-test-for-tutorial: '1'
41+
- matlab-version: R2022a
42+
python-version: '3.9'
43+
skip-pynwb-compatibilty-test-for-tutorial: '0'
44+
- matlab-version: R2022b
45+
python-version: '3.9'
46+
skip-pynwb-compatibilty-test-for-tutorial: '0'
47+
- matlab-version: R2023a
48+
python-version: '3.10'
49+
skip-pynwb-compatibilty-test-for-tutorial: '0'
50+
- matlab-version: R2023b
51+
python-version: '3.10'
52+
skip-pynwb-compatibilty-test-for-tutorial: '0'
53+
- matlab-version: R2024a
54+
python-version: '3.11'
55+
skip-pynwb-compatibilty-test-for-tutorial: '0'
56+
- matlab-version: R2024b
57+
python-version: '3.11'
58+
skip-pynwb-compatibilty-test-for-tutorial: '0'
59+
steps:
60+
- name: Check out repository
61+
uses: actions/checkout@v4
62+
63+
- name: Install python
64+
uses: actions/setup-python@v5
65+
with:
66+
python-version: ${{ matrix.python-version }}
67+
68+
- name: Install python dependencies
69+
run: |
70+
python -m pip install -U pip
71+
pip install -r +tests/requirements.txt
72+
python -m pip list
73+
74+
- name: Configure python env (macOS, ubuntu)
75+
if: runner.os != 'Windows'
76+
run: |
77+
echo "HDF5_PLUGIN_PATH=$(python -c "import hdf5plugin; print(hdf5plugin.PLUGINS_PATH)")" >> "$GITHUB_ENV"
78+
79+
- name: Configure python env (Windows)
80+
if: runner.os == 'Windows'
81+
shell: pwsh
82+
run: |
83+
$pluginPath = python -c "import hdf5plugin; print(hdf5plugin.PLUGINS_PATH)"
84+
Add-Content -Path $env:GITHUB_ENV -Value "HDF5_PLUGIN_PATH=$pluginPath"
85+
86+
- name: Install MATLAB
87+
uses: matlab-actions/setup-matlab@v2
88+
with:
89+
release: ${{ matrix.matlab-version }}
90+
91+
- name: Run tests
92+
uses: matlab-actions/run-command@v2
93+
env:
94+
HDF5_PLUGIN_PATH: ${{ env.HDF5_PLUGIN_PATH }}
95+
with:
96+
command: |
97+
setenv("SKIP_PYNWB_COMPATIBILITY_TEST_FOR_TUTORIALS", ...
98+
num2str(${{ matrix.skip-pynwb-compatibilty-test-for-tutorial }}))
99+
pyenv("ExecutionMode", "OutOfProcess");
100+
results = assertSuccess(nwbtest('ReportOutputFolder', '.'));
101+
assert(~isempty(results), 'No tests ran');
102+
103+
- name: Upload JUnit results
104+
if: always()
105+
uses: actions/upload-artifact@v4
106+
with:
107+
name: test-results-${{ matrix.os }}-${{ matrix.matlab-version }}
108+
path: testResults.xml
109+
110+
publish_junit:
111+
name: Publish JUnit test results
112+
runs-on: ubuntu-latest
113+
if: always()
114+
needs: [run_tests]
115+
steps:
116+
- name: Check out repository
117+
uses: actions/checkout@v4
118+
119+
- name: Retrieve result files
120+
uses: actions/download-artifact@v4
121+
with:
122+
pattern: test-results-*
123+
merge-multiple: false
124+
125+
- name: Publish test results
126+
uses: mikepenz/action-junit-report@v4
127+
with:
128+
report_paths: '*/testResults.xml'
129+
130+
update_version:
131+
name: Create new draft relase for given version
132+
runs-on: ubuntu-latest
133+
needs: [run_tests]
134+
steps:
135+
- name: Checkout repository using deploy key
136+
uses: actions/checkout@v4
137+
with:
138+
ref: refs/heads/main
139+
ssh-key: ${{ secrets.DEPLOY_KEY }}
140+
141+
- name: Update Contents.m file
142+
run: |
143+
# Read the template file
144+
template=$(cat .github/workflows/templates/contents_header_template.txt)
145+
146+
# Get current date in DD-MMM-YYYY format
147+
date_string=$(date +"%d-%b-%Y")
148+
149+
# Get current year
150+
year_number=$(date +"%Y")
151+
152+
# Replace placeholders in template
153+
header="${template/\{\{version_number\}\}/${{ github.event.inputs.version }}}"
154+
header="${header/\{\{date_string\}\}/$date_string}"
155+
header="${header/\{\{year_number\}\}/$year_number}"
156+
157+
# Extract the content after the header from the current Contents.m file
158+
content=$(awk '/^% -{10,}/{flag=1;next} flag{print}' Contents.m)
159+
160+
# Combine new header with existing content
161+
echo "$header" > Contents.m
162+
echo "$content" >> Contents.m
163+
164+
- name: Commit updated Contents.m file
165+
continue-on-error: true
166+
run: |
167+
git config user.name "${{ github.workflow }} by ${{ github.actor }}"
168+
git config user.email "<>"
169+
git add Contents.m
170+
git commit -m "Update version number in Contents.m"
171+
git fetch
172+
git push
173+
174+
- name: Set up Python
175+
uses: actions/setup-python@v4
176+
with:
177+
python-version: '3.12' # Pinned to 3.12 because of pybadges dependencies
178+
179+
- name: Generate tested with badge
180+
run: |
181+
pip install --upgrade setuptools
182+
pip install pybadges
183+
mkdir -p .github/badges/v${{ inputs.version }}
184+
python -c "
185+
from pybadges import badge
186+
with open('.github/badges/v${{ inputs.version }}/tested_with.svg', 'w') as f:
187+
f.write(badge(
188+
left_text='tested with',
189+
right_text='R2021a | R2021b | R2022a | R2022b | R2023a | R2023b | R2024 | R2024b',
190+
right_color='green'
191+
))
192+
"
193+
194+
- name: Tag repository with version tag
195+
if: always()
196+
run: |
197+
git fetch
198+
199+
git config user.name "${{ github.workflow }} by ${{ github.actor }}"
200+
git config user.email "<>"
201+
202+
# Create the tag with a message
203+
git tag -a "${{ inputs.version }}" -m "Release ${{ inputs.version }}"
204+
205+
# Push the new tag to the remote repository
206+
git push origin "${{ inputs.version }}"
207+
208+
# Commit the SVG for the MATLAB releases test badge to gh-badges branch
209+
- name: Checkout gh-badges branch
210+
uses: actions/checkout@v4
211+
with:
212+
ref: gh-badges
213+
path: gh-badges
214+
215+
- name: Push to gh-badges
216+
run: |
217+
mkdir -p gh-badges/.github/badges/v${{ inputs.version }}
218+
cp .github/badges/v${{ inputs.version }}/tested_with.svg gh-badges/.github/badges/v${{ inputs.version }}/tested_with.svg
219+
cd gh-badges
220+
221+
git config user.name "${{ github.workflow }} by ${{ github.actor }}"
222+
git config user.email "<>"
223+
224+
# Only proceed with commit and push if changes are detected
225+
if [[ $(git add .github/badges/* --dry-run | wc -l) -gt 0 ]]; then
226+
git add .github/badges/*
227+
git commit -m "Update 'tested_with' badge for release v${{ inputs.version }}"
228+
git push -f
229+
else
230+
echo "Nothing to commit"
231+
fi
232+
233+
# Create the release
234+
- name: Create GitHub release
235+
uses: ncipollo/release-action@v1
236+
with:
237+
draft: true
238+
tag: ${{ inputs.version }}
239+
generateReleaseNotes: true
240+
body: |
241+
![Tested On Platforms](https://raw.githubusercontent.com/NeurodataWithoutBorders/matnwb/refs/heads/gh-badges/.github/badges/tested_on.svg)
242+
![MATLAB Versions Tested](https://raw.githubusercontent.com/NeurodataWithoutBorders/matnwb/refs/heads/gh-badges/.github/badges/v${{ inputs.version }}/tested_with.svg)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
% MatNWB : NWB For MATLAB
2+
% Version {{version_number}} (R2019b+) {{date_string}}
3+
%
4+
% Copyright (c) {{year_number}}, Neurodata Without Borders
5+
% ---------------------------------------------

Contents.m

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
% MatNWB : NWB For MATLAB
2+
% Version 2.7.0 (R2019b+) 19-Nov-2024
3+
%
4+
% Copyright (c) 2024, Neurodata Without Borders
5+
% ---------------------------------------------
6+
%
7+
% Functions:
8+
%
9+
% NwbFile - Root object representing an NWB file.
10+
% generateCore - Generate Matlab classes from NWB core schema files
11+
% generateExtension - Generate Matlab classes from NWB extension schema file
12+
% inspectNwbFile - Run nwbinspector on the specified NWB file
13+
% nwbClearGenerated - Clear generated class files.
14+
% nwbExport - Writes an NWB file.
15+
% nwbInstallExtension - Installs a specified NWB extension.
16+
% nwbRead - Read an NWB file.
17+
% nwbtest - Run MatNWB test suite.
18+
%
19+
% Namespaces:
20+
% types - Namespace containing classes for neurodata types.
21+
% util - Namespace containing utility functions.
22+
%
23+
% Folders:
24+
%
25+
% tutorials - Livescript tutorials demonstrating how to work with MatNWB
26+
% namespaces - Cached namespace specifications
27+
% nwb-schema - Source NWB specification schemas for different NWB versions

docs/source/index.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,5 @@ Contents
3939

4040
pages/developer/contributing
4141
pages/developer/documentation
42+
pages/developer/releases
43+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
.. _how-to-create-release:
2+
3+
How to Create a New Release
4+
===========================
5+
6+
1. **Navigate to the** `"Actions" <https://github.com/NeurodataWithoutBorders/matnwb/actions/workflows/prepare_release.yml>`_ **tab** in the MatNwb repository on GitHub.
7+
8+
2. **Click "Run workflow"**, then:
9+
- Enter the desired version number in ``major.minor.patch`` format (e.g., ``2.8.0``).
10+
- Click the **Run workflow** button to start the process.
11+
12+
3. **Monitor the workflow** as it runs across multiple MATLAB and OS configurations. The workflow is successful if:
13+
- The version string is valid.
14+
- All tests pass successfully.
15+
16+
4. **Confirm the draft release** once the workflow completes:
17+
- A new tag (matching your version number) is pushed to the repository.
18+
- A draft release is automatically generated with updated badges and the revised ``Contents.m`` file.
19+
20+
5. **(Optional) Finalize the release** by editing the draft release in GitHub’s "Releases" section, adding any additional details, and clicking **"Publish release"**.

0 commit comments

Comments
 (0)