Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
c61888b
fix(python): tag wheels from the bundled library and build linux-arm64
GabrielMarquezMatte Oct 14, 2026
465ff7a
Merge branch 'master' into develop
GabrielMarquezMatte Oct 14, 2026
86a636d
ci: report every required CodeQL check; build macOS x64 and musllinux…
GabrielMarquezMatte Oct 14, 2026
44311c9
docs: state the 7.x compatibility policy and validate packages agains…
GabrielMarquezMatte Oct 14, 2026
a5b476d
feat(python)!: open every kind of input through open_workbook
GabrielMarquezMatte Oct 14, 2026
7b2a46d
feat(python)!: write to a path or a binary stream through one write f…
GabrielMarquezMatte Oct 14, 2026
9b6f5f1
feat(python)!: stream and encrypt to a path or a binary stream throug…
GabrielMarquezMatte Oct 14, 2026
699b400
feat(python)!: slim the public API to one shape per read and one writ…
GabrielMarquezMatte Oct 14, 2026
3d805d1
docs: list the Python API reductions in the v7 migration guide
GabrielMarquezMatte Oct 14, 2026
0f20dfe
feat(cpp)!: slim the C++ binding's public API for 7.0
GabrielMarquezMatte Oct 14, 2026
467d7d7
docs: list the C++ API reductions in the v7 migration guide
GabrielMarquezMatte Oct 14, 2026
bf29e32
feat(rust)!: slim the public API for 7.0
GabrielMarquezMatte Oct 14, 2026
8d4b55f
docs: list the Rust API reductions in the v7 migration guide
GabrielMarquezMatte Oct 14, 2026
8dc9671
feat(python)!: share read method names with the other bindings; Cell.…
GabrielMarquezMatte Oct 14, 2026
daeea32
Bump the analyzers group with 2 updates
dependabot[bot] Oct 14, 2026
c30dbb8
Bump the test group with 2 updates
dependabot[bot] Oct 14, 2026
429a70b
Bump the benchmarks group with 1 update
dependabot[bot] Oct 14, 2026
e3f1744
feat(rust)!: share read method names with the other bindings and take…
GabrielMarquezMatte Oct 14, 2026
1e14e26
feat(cpp)!: share read function names with the other bindings and tak…
GabrielMarquezMatte Oct 14, 2026
59ac565
docs: list the shared read vocabulary in the v7 migration guide
GabrielMarquezMatte Oct 14, 2026
ac2ea52
Merge pull request #145 from GabrielMarquezMatte/dependabot/nuget/tes…
GabrielMarquezMatte Oct 14, 2026
0780fcc
Merge pull request #144 from GabrielMarquezMatte/dependabot/nuget/tes…
GabrielMarquezMatte Oct 14, 2026
a4ad749
Merge pull request #143 from GabrielMarquezMatte/dependabot/nuget/dev…
GabrielMarquezMatte Oct 14, 2026
728b6a7
feat: update data classes to frozen dataclasses and improve keyword-o…
Oct 15, 2026
daad018
perf(python): build Cell as a non-frozen slots dataclass
GabrielMarquezMatte Oct 15, 2026
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
7 changes: 7 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,13 @@ jobs:
if: env.RUN == 'true' && matrix.os == 'ubuntu-latest'
run: dotnet format whitespace ExcelReader.slnx --verify-no-changes

# Packing runs package validation, which fails on any binary break against the last release.
- name: Validate packages against the last release
if: env.RUN == 'true' && matrix.os == 'ubuntu-latest'
run: |
dotnet pack src/ExcelReader.Core/ExcelReader.Core.csproj --configuration Release --no-build --output ./package-validation
dotnet pack src/ExcelReader.Arrow/ExcelReader.Arrow.csproj --configuration Release --no-build --output ./package-validation

- name: Test (Release)
if: env.RUN == 'true'
run: >-
Expand Down
38 changes: 17 additions & 21 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ jobs:
if: github.event.pull_request.draft != true
runs-on: ubuntu-latest
outputs:
languages: ${{ steps.languages.outputs.value }}
csharp: ${{ github.event_name != 'pull_request' || steps.filter.outputs.csharp == 'true' }}
python: ${{ github.event_name != 'pull_request' || steps.filter.outputs.python == 'true' }}
steps:
- name: Checkout
uses: actions/checkout@v7
Expand All @@ -45,46 +46,40 @@ jobs:
- 'python/**'
- '.github/workflows/codeql.yml'

- name: Select languages
id: languages
run: |
if [ '${{ github.event_name }}' != 'pull_request' ]; then
echo 'value=["csharp","python"]' >> "$GITHUB_OUTPUT"
exit 0
fi
languages=()
if [ '${{ steps.filter.outputs.csharp }}' = 'true' ]; then
languages+=('"csharp"')
fi
if [ '${{ steps.filter.outputs.python }}' = 'true' ]; then
languages+=('"python"')
fi
echo "value=[$(IFS=,; echo "${languages[*]}")]" >> "$GITHUB_OUTPUT"

# Both languages always get a job: "Analyze (csharp)" and "Analyze (python)" are required checks, and
# a check whose job never starts stays pending. An unchanged language's job skips its steps instead.
analyze:
name: Analyze (${{ matrix.language }})
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.languages != '[]'

strategy:
fail-fast: false
matrix:
language: ${{ fromJSON(needs.changes.outputs.languages) }}
language: [csharp, python]

env:
RUN: ${{ needs.changes.outputs[matrix.language] }}

steps:
- name: Skip (language unchanged)
if: env.RUN != 'true'
run: echo "No ${{ matrix.language }} changes; skipping the analysis."

- name: Checkout
if: env.RUN == 'true'
uses: actions/checkout@v7

- name: Setup .NET
if: matrix.language == 'csharp'
if: env.RUN == 'true' && matrix.language == 'csharp'
uses: actions/setup-dotnet@v6
with:
global-json-file: global.json
cache: true
cache-dependency-path: '**/*.csproj'

- name: Initialize CodeQL
if: env.RUN == 'true'
uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
Expand All @@ -93,13 +88,14 @@ jobs:
# Only the shipped projects: tests, benchmarks and the fuzz harness double the build for code
# no one runs against untrusted input.
- name: Build (Release)
if: matrix.language == 'csharp'
if: env.RUN == 'true' && matrix.language == 'csharp'
run: |
for project in src/*/*.csproj; do
dotnet build "$project" --configuration Release -p:RunAnalyzers=false
done

- name: Perform CodeQL Analysis
if: env.RUN == 'true'
uses: github/codeql-action/analyze@v4
with:
category: "/language:${{ matrix.language }}"
27 changes: 25 additions & 2 deletions .github/workflows/native-bindings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, macos-latest, macos-15-intel]

steps:
- name: Checkout
Expand Down Expand Up @@ -172,7 +172,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, macos-latest, macos-15-intel]

steps:
- name: Checkout
Expand Down Expand Up @@ -202,6 +202,12 @@ jobs:
- name: Run the Python tests
run: pytest python/tests -v

- name: Build the wheel and check it installs here
run: |
pip install build
python -m build --wheel python/ --outdir dist/
python python/scripts/check_wheel_tag.py dist

- name: Build the C smoke test
run: |
cmake -S tests/ExcelReader.NativeSmoke -B build/nativesmoke -DCMAKE_BUILD_TYPE=Release
Expand All @@ -215,6 +221,23 @@ jobs:
python python/benchmarks/bench_read.py --n 1
python python/benchmarks/bench_write.py --n 1

test-musl:
name: musl library + Python (${{ matrix.runner }})
needs: changes
if: needs.changes.outputs.native == 'true' || needs.changes.outputs.python == 'true'
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
runner: [ubuntu-latest, ubuntu-24.04-arm]

steps:
- name: Checkout
uses: actions/checkout@v7

- name: Build, test and wheel in Alpine
run: sh python/scripts/build_musl_wheel.sh

test-cpp:
name: C++ package + smoke test (${{ matrix.os }})
needs: [changes, build-native]
Expand Down
54 changes: 48 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, macos-latest, macos-15-intel]

steps:
- name: Checkout
Expand All @@ -92,7 +92,7 @@ jobs:
macOS) src=ExcelReader.Native.dylib; os=osx; ext=dylib ;;
*) src=ExcelReader.Native.so; os=linux; ext=so ;;
esac
arch=$([ "$(uname -m 2>/dev/null || echo x64)" = "arm64" ] && echo arm64 || echo x64)
case "$(uname -m)" in arm64|aarch64) arch=arm64 ;; *) arch=x64 ;; esac
mkdir -p release-assets
cp "python/src/excelreader/_lib/${src}" "release-assets/excelreader-native-${os}-${arch}.${ext}"

Expand All @@ -116,7 +116,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, macos-latest, macos-15-intel]

steps:
- name: Checkout
Expand All @@ -133,7 +133,7 @@ jobs:
id: rid
shell: bash
run: |
arch=$([ "$(uname -m 2>/dev/null || echo x64)" = "arm64" ] && echo arm64 || echo x64)
case "$(uname -m)" in arm64|aarch64) arch=arm64 ;; *) arch=x64 ;; esac
case "${{ runner.os }}" in
Windows) os=win ;;
macOS) os=osx ;;
Expand Down Expand Up @@ -175,7 +175,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, macos-latest, macos-15-intel]

steps:
- name: Checkout
Expand Down Expand Up @@ -209,16 +209,58 @@ jobs:
pip install build
python -m build --wheel python/ --outdir dist/

- name: Check the wheel installs here
run: python python/scripts/check_wheel_tag.py dist

- name: Upload wheel artifact
uses: actions/upload-artifact@v7
with:
name: wheel-${{ matrix.os }}
path: dist/*.whl
if-no-files-found: error

musl:
name: Build musl library and wheel (${{ matrix.arch }})
needs: build
runs-on: ${{ matrix.runner }}
strategy:
matrix:
include:
- { arch: x64, runner: ubuntu-latest }
- { arch: arm64, runner: ubuntu-24.04-arm }

steps:
- name: Checkout
uses: actions/checkout@v7

- name: Set package version
run: sed -i "s/^version = \".*\"/version = \"${{ needs.build.outputs.version }}\"/" python/pyproject.toml

- name: Build, test and wheel in Alpine
run: sh python/scripts/build_musl_wheel.sh

- name: Rename asset for this platform
run: |
mkdir -p release-assets
cp python/src/excelreader/_lib/ExcelReader.Native.so "release-assets/excelreader-native-linux-musl-${{ matrix.arch }}.so"

- name: Upload release asset
uses: actions/upload-artifact@v7
with:
name: release-native-musl-${{ matrix.arch }}
path: release-assets/*
if-no-files-found: error

- name: Upload wheel artifact
uses: actions/upload-artifact@v7
with:
name: wheel-musl-${{ matrix.arch }}
path: dist/*.whl
if-no-files-found: error

publish:
name: Publish to NuGet & GitHub Release
needs: [build, native, cli, python]
needs: [build, native, cli, python, musl]
runs-on: ubuntu-latest
permissions:
contents: write
Expand Down
15 changes: 15 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,21 @@ rewrites — see [ARCHITECTURE.md](ARCHITECTURE.md) for the shape of the codebas
`src/ExcelReader.Core/PublicAPI/PublicAPI.Unshipped.txt`. A bot promotes `Unshipped` →
`Shipped` automatically after each release — don't edit `Shipped.txt` by hand.

- **Minor versions don't break callers.** [docs/guide/versioning.md](docs/guide/versioning.md) is the
policy; in practice:
- A new member on a library-implemented interface (`IExcelWorkbook`, `IExcelSheet`,
`IExcelRowEnumerator`, `IWorkbookWriter`, `ISheetWriter`, `ITableSheetWriter`, `IRowWriter`)
gets a default implementation. A user-implemented one (`IExcelCellConverter`, `IExcelCellWriter`,
`IExcelRowMap`, `IExcelRecordMap`, `IRowRecord`, `IRowAccumulator`) gets no new member a user
would have to implement.
- A feature only some formats support goes on the concrete types first, or on its own interface
the way `ITableSheetWriter` sits beside `ISheetWriter`.
- New inputs go on the options object or a new overload, never as a new optional parameter on an
existing method.
- `dotnet pack` runs package validation against `PackageValidationBaselineVersion` in the
`ExcelReader.Core` and `ExcelReader.Arrow` projects, and CI runs it on every pull request.
After each release, move the baseline to the version just published.

- **Tests are required for behavior changes.** Run the suite before opening a PR:

```bash
Expand Down
4 changes: 2 additions & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@
it used to arrive transitively through Roslyn.Diagnostics.Analyzers, which brought a whole
Roslyn-internal ruleset along for those three rules. -->
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="10.0.401">
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="10.0.402">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Meziantou.Analyzer" Version="3.0.294">
<PackageReference Include="Meziantou.Analyzer" Version="3.0.303">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
Expand Down
Loading
Loading