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
153 changes: 153 additions & 0 deletions .github/workflows/build-and-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
name: Build and release

on:
push:
branches:
- main
tags:
- "v*"
pull_request:
branches:
- main
workflow_dispatch:

permissions:
contents: read

jobs:
build:
name: Build Windows installer
runs-on: windows-latest
outputs:
version: ${{ steps.version.outputs.number }}

steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up .NET 10
uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x

- name: Determine version
id: version
shell: pwsh
run: |
[xml] $project = Get-Content OneNoteExporter.csproj
$projectVersion = $project.Project.PropertyGroup.Version | Select-Object -First 1

if (-not $projectVersion) {
throw "No <Version> was found in OneNoteExporter.csproj."
}

if ($env:GITHUB_REF_TYPE -eq 'tag') {
if ($env:GITHUB_REF_NAME -notmatch '^v(?<version>\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)$') {
throw "Release tags must use semantic versioning, for example v1.2.0."
}

$version = $Matches.version
if ($version -ne $projectVersion) {
throw "Tag version $version does not match project version $projectVersion."
}
}
else {
$version = $projectVersion
}

"number=$version" >> $env:GITHUB_OUTPUT
Write-Host "Building version $version"

- name: Restore dependencies
run: dotnet restore OneNoteExporter.csproj --runtime win-x64

- name: Publish self-contained application
shell: pwsh
env:
APP_VERSION: ${{ steps.version.outputs.number }}
run: |
dotnet publish OneNoteExporter.csproj `
--configuration Release `
--runtime win-x64 `
--self-contained true `
--no-restore `
--output build `
-p:PublishSingleFile=false `
"-p:Version=$env:APP_VERSION"

- name: Compile installer
shell: pwsh
env:
APP_VERSION: ${{ steps.version.outputs.number }}
run: |
$isccCandidates = @(
'C:\Program Files (x86)\Inno Setup 6\ISCC.exe',
'C:\Program Files\Inno Setup 6\ISCC.exe'
)
$iscc = $isccCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1

if (-not $iscc) {
choco install innosetup --yes --no-progress
$iscc = $isccCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1
}

if (-not $iscc) {
throw 'Inno Setup compiler was not found after installation.'
}

& $iscc "/DMyAppVersion=$env:APP_VERSION" innosetup.iss
if ($LASTEXITCODE -ne 0) {
throw "Inno Setup failed with exit code $LASTEXITCODE."
}

- name: Create SHA-256 checksum
shell: pwsh
env:
APP_VERSION: ${{ steps.version.outputs.number }}
run: |
$installer = Get-Item "artifacts\OneNoteBackupExporter_Setup_$env:APP_VERSION.exe"
$hash = (Get-FileHash $installer.FullName -Algorithm SHA256).Hash.ToLowerInvariant()
"$hash $($installer.Name)" | Set-Content "$($installer.FullName).sha256" -Encoding ascii

- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: OneNoteBackupExporter-${{ steps.version.outputs.number }}
path: |
artifacts/OneNoteBackupExporter_Setup_${{ steps.version.outputs.number }}.exe
artifacts/OneNoteBackupExporter_Setup_${{ steps.version.outputs.number }}.exe.sha256
if-no-files-found: error
retention-days: 14

release:
name: Publish GitHub release
if: startsWith(github.ref, 'refs/tags/v')
needs: build
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- name: Download installer artifact
uses: actions/download-artifact@v4
with:
name: OneNoteBackupExporter-${{ needs.build.outputs.version }}
path: artifacts

- name: Create release and upload installer
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
TAG: ${{ github.ref_name }}
run: |
set -euo pipefail
assets=(artifacts/*)

if gh release view "$TAG" >/dev/null 2>&1; then
gh release upload "$TAG" "${assets[@]}" --clobber
else
gh release create "$TAG" "${assets[@]}" \
--verify-tag \
--title "OneNote Backup Exporter $TAG" \
--generate-notes
fi
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
bin/
obj/
build/
artifacts/

# Setup-EXE (wird als GitHub Release Asset hochgeladen)
*.exe
Expand Down
8 changes: 4 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ OneNote Desktop

```
OneNoteExporterC#/
├── OneNoteExporter.csproj Target: net10.0-windows, UseWPF, PlatformTarget=x86
├── OneNoteExporter.csproj Target: net10.0-windows, UseWPF, PlatformTarget=x64
├── OneNoteExporter.sln
├── App.xaml Global styles (colors, buttons, inputs)
├── App.xaml.cs Global exception handler
Expand All @@ -48,14 +48,14 @@ dotnet build
# Run (debug)
dotnet run

# Publish self-contained x86
dotnet publish -c Release -r win-x86 --self-contained true
# Publish self-contained x64
dotnet publish -c Release -r win-x64 --self-contained true
```

## Critical Technical Details

### COM Compatibility
- **`PlatformTarget=x86` is mandatory** – most OneNote Desktop installations are 32-bit. Changing to x64 or AnyCPU will cause "Class not registered" COM errors.
- **`PlatformTarget=x64` is mandatory** – this build targets current 64-bit OneNote Desktop installations. Changing the platform can cause "Class not registered" COM errors.
- **NuGet package:** `Interop.Microsoft.Office.Interop.OneNote` v1.1.0.2 (NOT `Microsoft.Office.Interop.OneNote`)
- **Do NOT add `<UseWindowsForms>true</UseWindowsForms>`** – causes namespace conflict with the COM `Application` class

Expand Down
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,24 @@ Talks directly to OneNote Desktop via the COM AP.

## Download

Go to [Releases](../../releases/latest) and download `OneNoteBackupExporter_Setup_1.0.0.exe`. Run the installer, done.
Go to [Releases](../../releases/latest) and download the latest
`OneNoteBackupExporter_Setup_<version>.exe`. Run the installer, done. A matching
`.sha256` file is included so the download can be verified.

## Automated builds and releases

GitHub Actions builds a self-contained Windows x64 application and compiles the Inno Setup
installer for every pull request and every push to `main`. The installer and its SHA-256
checksum are available as workflow artifacts for 14 days.

To publish a release:

1. Update `<Version>` in `OneNoteExporter.csproj` and commit the change.
2. Create and push a matching tag, for example `v1.2.0`.
3. GitHub Actions builds the installer, creates the GitHub release with generated notes, and
uploads the installer plus checksum automatically.

The tag and project versions must match; otherwise the release build fails without publishing.

## Requirements

Expand Down
21 changes: 15 additions & 6 deletions build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,15 @@ $ErrorActionPreference = 'Stop'

$ProjectRoot = $PSScriptRoot
$BuildDir = Join-Path $ProjectRoot 'build'
$ArtifactDir = Join-Path $ProjectRoot 'artifacts'
$PublishDir = Join-Path $ProjectRoot 'bin\Release\net10.0-windows\win-x64\publish'
$ProjectFile = Join-Path $ProjectRoot 'OneNoteExporter.csproj'
[xml]$ProjectXml = Get-Content $ProjectFile
$Version = $ProjectXml.Project.PropertyGroup.Version | Select-Object -First 1

if (-not $Version) {
throw 'Keine <Version> in OneNoteExporter.csproj gefunden.'
}

# ── 1. build-Ordner leeren / anlegen ─────────────────────────────────────────
Write-Host ">> Bereite build-Ordner vor..." -ForegroundColor Cyan
Expand All @@ -20,11 +28,12 @@ New-Item -ItemType Directory -Path $BuildDir | Out-Null

# ── 2. dotnet publish (Release, self-contained, x64) ─────────────────────────
Write-Host ">> Starte dotnet publish..." -ForegroundColor Cyan
dotnet publish "$ProjectRoot\OneNoteExporter.csproj" `
dotnet publish $ProjectFile `
-c Release `
-r win-x64 `
--self-contained true `
-p:PublishSingleFile=false
-p:PublishSingleFile=false `
"-p:Version=$Version"

if ($LASTEXITCODE -ne 0) {
Write-Host "FEHLER: dotnet publish fehlgeschlagen (Exit-Code $LASTEXITCODE)." -ForegroundColor Red
Expand All @@ -49,22 +58,22 @@ $IsssPaths = @(
$Iscc = $IsssPaths | Where-Object { Test-Path $_ } | Select-Object -First 1

if (-not $Iscc) {
Write-Host "WARNUNG: ISCC.exe nicht gefunden – Installer wird übersprungen." -ForegroundColor Yellow
Write-Host "WARNUNG: ISCC.exe nicht gefunden - Installer wird übersprungen." -ForegroundColor Yellow
Write-Host " -> Inno Setup installieren: https://jrsoftware.org/isdl.php" -ForegroundColor Yellow
}
elseif (-not (Test-Path $IssFile)) {
Write-Host "WARNUNG: innosetup.iss nicht gefunden – Installer wird übersprungen." -ForegroundColor Yellow
Write-Host "WARNUNG: innosetup.iss nicht gefunden - Installer wird übersprungen." -ForegroundColor Yellow
}
else {
Write-Host ">> Starte Inno Setup: $Iscc" -ForegroundColor Cyan
& $Iscc $IssFile
& $Iscc "/DMyAppVersion=$Version" $IssFile
if ($LASTEXITCODE -ne 0) {
Write-Host "FEHLER: Inno Setup fehlgeschlagen (Exit-Code $LASTEXITCODE)." -ForegroundColor Red
exit $LASTEXITCODE
}

# Setup-EXE ausgeben
$SetupExe = Get-ChildItem -Path $ProjectRoot -Filter 'OneNoteBackupExporter_Setup_*.exe' |
$SetupExe = Get-ChildItem -Path $ArtifactDir -Filter 'OneNoteBackupExporter_Setup_*.exe' |
Sort-Object LastWriteTime -Descending |
Select-Object -First 1
if ($SetupExe) {
Expand Down
13 changes: 8 additions & 5 deletions innosetup.iss
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
#define MyAppName "OneNoteBackupExporter"
#define MyAppVersion "1.1.0"
#ifndef MyAppVersion
#define MyAppVersion "1.1.0"
#endif
#define MyAppPublisher "JLI Software"
#define MyAppURL "https://github.com/vikingjunior12/OneNoteBackupExporter"
#define MyAppURL "https://github.com/jli-software/OneNoteBackupExporter"
#define MyAppExeName "OneNoteExporter.exe"
#define MyBuildDir "C:\Users\JLi1\Nextcloud\C#_pwsh\OneNoteExporterC#\build"
#define MyBuildDir SourcePath + "build"
#define MyOutputDir SourcePath + "artifacts"

[Setup]
AppId={{BBAE42F6-2F7E-474E-9A2D-C771DB475E3F}
Expand All @@ -18,7 +21,7 @@ UninstallDisplayIcon={app}\{#MyAppExeName}
ArchitecturesAllowed=x64compatible
ArchitecturesInstallIn64BitMode=x64compatible
DisableProgramGroupPage=yes
OutputDir=C:\Users\JLi1\Nextcloud\C#_pwsh\OneNoteExporterC#\
OutputDir={#MyOutputDir}
OutputBaseFilename=OneNoteBackupExporter_Setup_{#MyAppVersion}
SolidCompression=yes
WizardStyle=modern
Expand All @@ -30,7 +33,7 @@ Name: "english"; MessagesFile: "compiler:Default.isl"
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked

[Files]
; Gesamter Build-Ordner (self-contained, x86)
; Self-contained x64 publish output
Source: "{#MyBuildDir}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs

[Icons]
Expand Down
73 changes: 27 additions & 46 deletions release.sh
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,59 +1,40 @@
# release.sh – GitHub Release erstellen und Setup-EXE hochladen
# Voraussetzungen: git, gh (GitHub CLI), authentifiziert via `gh auth login`
#!/usr/bin/env bash
# release.sh – passenden Release-Tag erstellen und zu GitHub pushen
# GitHub Actions baut und veröffentlicht Installer und Prüfsumme automatisch.

set -euo pipefail

VERSION="1.1.0"
if [[ $# -ne 1 ]]; then
echo "Verwendung: $0 <version> (zum Beispiel: $0 1.2.0)"
exit 1
fi

VERSION="${1#v}"
TAG="v${VERSION}"
SETUP_EXE="OneNoteBackupExporter_Setup_${VERSION}.exe"
REPO="vikingjunior12/OneNoteBackupExporter"

# ── Prüfungen ────────────────────────────────────────────────────────────────
if ! command -v gh &>/dev/null; then
echo "FEHLER: 'gh' (GitHub CLI) ist nicht installiert."
echo " -> pacman -S github-cli"
if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+([+-][0-9A-Za-z.-]+)?$ ]]; then
echo "FEHLER: Ungültige Version: $VERSION"
exit 1
fi

PROJECT_VERSION=$(sed -n 's:.*<Version>\([^<]*\)</Version>.*:\1:p' OneNoteExporter.csproj | head -n 1)
if [[ "$VERSION" != "$PROJECT_VERSION" ]]; then
echo "FEHLER: Version $VERSION stimmt nicht mit der Projektversion $PROJECT_VERSION überein."
exit 1
fi

if [[ ! -f "$SETUP_EXE" ]]; then
echo "FEHLER: Setup-Datei nicht gefunden: $SETUP_EXE"
echo " -> Erst build.ps1 + Inno Setup ausführen"
if [[ -n "$(git status --porcelain)" ]]; then
echo "FEHLER: Das Arbeitsverzeichnis enthält nicht committete Änderungen."
exit 1
fi

# ── Tag erstellen (falls noch nicht vorhanden) ────────────────────────────────
if git rev-parse "$TAG" &>/dev/null; then
echo ">> Tag $TAG existiert bereits, wird übersprungen."
else
echo ">> Erstelle Tag $TAG ..."
git tag -a "$TAG" -m "Release $TAG"
git push origin "$TAG"
git fetch origin --tags
if git rev-parse --verify --quiet "refs/tags/$TAG" >/dev/null; then
echo "FEHLER: Tag $TAG existiert bereits."
exit 1
fi

# ── GitHub Release erstellen + EXE hochladen ─────────────────────────────────
echo ">> Erstelle GitHub Release $TAG ..."
gh release create "$TAG" "$SETUP_EXE" \
--repo "$REPO" \
--title "OneNoteBackupExporter $TAG" \
--notes "## OneNoteBackupExporter $TAG

### New Features

- **Section export**: Notebooks can now be expanded to show individual sections — select and export only the sections you need
- Sections from nested section groups are fully supported (shown as \`📂 Group / 📄 Section\`)
- Encrypted and recycle-bin sections are automatically skipped
- Mixed export: combine whole-notebook exports and section-level exports in a single run
- Sections are saved into a notebook-named subfolder to keep the output organised (e.g. \`MyNotebook/Section1.onepkg\`)
- Export button text dynamically reflects the selection (e.g. \`Export 1 notebook(s) + 3 section(s)\`)

### Installation
1. Download \`$SETUP_EXE\`
2. Run the installer
3. OneNote Desktop must be installed and opened at least once

### System Requirements
- Windows 10/11 x64
- Microsoft OneNote Desktop (Microsoft 365 or 2019/2021)"

echo ""
echo "Release erfolgreich: https://github.com/${REPO}/releases/tag/${TAG}"
git tag -a "$TAG" -m "Release $TAG"
git push origin "$TAG"

echo "Tag $TAG wurde gepusht. GitHub Actions erstellt jetzt das Release."
Loading