From 3a852314311f26024c654f2d085ba229a0c2c466 Mon Sep 17 00:00:00 2001
From: Mashi <67765922+atouu@users.noreply.github.com>
Date: Wed, 24 Jun 2026 13:40:25 +0800
Subject: [PATCH 1/6] Add nightly build channel in build workflow
---
.github/workflows/build.yml | 79 ++++++++++++++++++++++++++-----------
appcast.py | 4 +-
2 files changed, 58 insertions(+), 25 deletions(-)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 5c71c6a69..6ff3c6b90 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -6,21 +6,29 @@ on:
default: "0.0.0"
required: true
type: string
+ channel:
+ description: 'Channel'
+ type: choice
+ required: true
+ default: 'beta'
+ options:
+ - 'stable'
+ - 'beta'
+ - 'nightly'
release:
type: boolean
default: false
description: "Release"
- beta:
- type: boolean
- default: true
- description: "Beta"
draft:
type: boolean
default: true
description: "Draft"
+run-name: Build ${{ inputs.version }}
+
env:
- release-name: ${{ inputs.version }}${{ inputs.beta && ' Beta' || '' }}
+ release-name: ${{ inputs.version }}${{ inputs.channel == 'beta' && ' Beta' || '' }}
+ release-tag: ${{ inputs.channel == 'nightly' && 'nightly' || inputs.version }}
jobs:
build:
@@ -51,7 +59,7 @@ jobs:
node-version: 20
- name: Install NSIS via Chocolatey
run: choco install nsis --version=3.11 --no-progress
- if: ${{ matrix.arch.os == 'win' }}
+ if: ${{ matrix.arch.os == 'win' && inputs.channel != 'nightly' }}
- uses: justalemon/VersionPatcher@v0.7.1
with:
version: ${{ inputs.version }}
@@ -66,15 +74,15 @@ jobs:
run: dotnet restore OpenUtau -r ${{ matrix.arch.rid }}
- name: Build (Windows and Linux)
- run: dotnet publish OpenUtau -c Release -r ${{ matrix.arch.rid }} --self-contained true -o bin/${{ matrix.arch.name }}/
+ run: dotnet publish OpenUtau -c Release -r ${{ matrix.arch.rid }} --self-contained true -o bin/${{ matrix.arch.name }}/ -p:Nightly=${{ inputs.channel == 'nightly' }}
if: ${{ matrix.arch.os != 'osx' }}
- name: Build (MacOS)
- run: dotnet msbuild OpenUtau -t:BundleApp -p:Configuration=Release -p:RuntimeIdentifier=${{ matrix.arch.rid }} -p:UseAppHost=true -p:SelfContained=true -p:OutputPath=../bin/${{ matrix.arch.name }}/
+ run: dotnet msbuild OpenUtau -t:BundleApp -p:Configuration=Release -p:RuntimeIdentifier=${{ matrix.arch.rid }} -p:UseAppHost=true -p:SelfContained=true -p:OutputPath=../bin/${{ matrix.arch.name }}/ -p:Nightly=${{ inputs.channel == 'nightly' }}
if: ${{ matrix.arch.os == 'osx' }}
- name: Write release channel info
- run: "@{Beta=$${{ inputs.beta }}} | ConvertTo-Json > bin/${{ matrix.arch.name }}/prefs-default.json"
+ run: "@{Beta=$${{ inputs.channel == 'beta' }}} | ConvertTo-Json > bin/${{ matrix.arch.name }}/prefs-default.json"
shell: pwsh
# Create Zip
@@ -114,7 +122,7 @@ jobs:
with:
script-file: OpenUtau.nsi
arguments: "-DPRODUCT_VERSION=${{ inputs.version }} -DARCH=${{ matrix.arch.arch }}"
- if: ${{ matrix.arch.os == 'win' }}
+ if: ${{ matrix.arch.os == 'win' && inputs.channel != 'nightly' }}
# Create Dmg
- name: Create Dmg
@@ -161,7 +169,7 @@ jobs:
with:
name: OpenUtau-${{ matrix.arch.name }}.exe
path: OpenUtau-${{ matrix.arch.name }}.exe
- if: ${{ !inputs.release && matrix.arch.os == 'win' }}
+ if: ${{ !inputs.release && matrix.arch.os == 'win' && inputs.channel != 'nightly' }}
- uses: actions/upload-artifact@v4
with:
@@ -177,33 +185,33 @@ jobs:
# Appcast
- name: Appcast Windows
- shell: cmd
+ shell: bash
run: |
- python appcast.py -v=${{ inputs.version }} -o=windows -r=${{ matrix.arch.name }} -f=OpenUtau-${{ matrix.arch.name }}.zip
- python appcast.py -v=${{ inputs.version }} -o=windows -r=${{ matrix.arch.name }}-installer -f=OpenUtau-${{ matrix.arch.name }}.exe
+ python appcast.py -v=${{ inputs.version }} -o=windows -r=${{ matrix.arch.name }} -t ${{ env.release-tag }} -f=OpenUtau-${{ matrix.arch.name }}.zip
+ if ${{ inputs.channel != 'nightly' }}; then
+ python appcast.py -v=${{ inputs.version }} -o=windows -r=${{ matrix.arch.name }}-installer -f=OpenUtau-${{ matrix.arch.name }}.exe
+ fi
if: ${{ inputs.release && matrix.arch.os == 'win' }}
- name: Appcast MacOS
run: |
- python appcast.py -v=${{ inputs.version }} -o=macos -r=${{ matrix.arch.name }} -f=OpenUtau-${{ matrix.arch.name }}.dmg
+ python appcast.py -v=${{ inputs.version }} -o=macos -r=${{ matrix.arch.name }} -t ${{ env.release-tag }} -f=OpenUtau-${{ matrix.arch.name }}.dmg
if: ${{ inputs.release && matrix.arch.os == 'osx' }}
- name: Appcast Linux
run: |
- python appcast.py -v=${{ inputs.version }} -o=linux -r=${{ matrix.arch.name }} -f=OpenUtau-${{ matrix.arch.name }}.tar.gz
+ python appcast.py -v=${{ inputs.version }} -o=linux -r=${{ matrix.arch.name }} -t ${{ env.release-tag }} -f=OpenUtau-${{ matrix.arch.name }}.tar.gz
if: ${{ inputs.release && matrix.arch.os == 'linux' }}
# Release
- - name: Release
- uses: softprops/action-gh-release@v2
+ - name: Regular Release
+ uses: ncipollo/release-action@v1
with:
- tag_name: ${{ inputs.version }}
+ tag: ${{ inputs.version }}
name: ${{ env.release-name }}
- prerelease: ${{ inputs.beta }}
+ prerelease: ${{ inputs.channel != 'stable' }}
draft: ${{ inputs.draft }}
- files: |
- appcast.${{ matrix.arch.name }}*.xml
- OpenUtau-${{ matrix.arch.name }}.*
+ artifacts: "appcast.${{ matrix.arch.name }}*.xml,OpenUtau-${{ matrix.arch.name }}.*"
body: |
See [Getting Started](https://github.com/stakira/OpenUtau/wiki/Getting-Started) for how to use.
@@ -211,4 +219,27 @@ jobs:
## macOS says "This app is damaged"
Open a terminal and run `xattr -rc /Applications/OpenUtau.app`. Try opening OpenUtau again.
- if: ${{ inputs.release }}
+ if: ${{ inputs.release && inputs.channel != 'nightly' }}
+
+ - name: Nightly Release
+ uses: ncipollo/release-action@v1
+ with:
+ tag: nightly
+ name: Nightly
+ prerelease: true
+ draft: ${{ inputs.draft }}
+ artifacts: "appcast.${{ matrix.arch.name }}*.xml,OpenUtau-${{ matrix.arch.name }}.*"
+ body: |
+ > [!WARNING]
+ > Nightly builds are for testing purposes only and must not use for production.
+ > If you encounter bugs, check the [FAQ](https://github.com/stakira/OpenUtau/wiki/FAQ) first, then open an issue if needed.
+
+ | Build Version | Commit |
+ | --------------------- | ----------------- |
+ | ${{ inputs.version }} | ${{ github.sha }} |
+
+ ## macOS says "This app is damaged"
+ Open a terminal and run `xattr -rc /Applications/OpenUtau.app`. Try opening OpenUtau again.
+ allowUpdates: true
+ replaceArtifacts: true
+ if: ${{ inputs.release && inputs.channel == 'nightly' }}
diff --git a/appcast.py b/appcast.py
index 22f1d6fbd..1a19f8491 100644
--- a/appcast.py
+++ b/appcast.py
@@ -7,12 +7,14 @@ def main():
parser.add_argument('-o', '--os', help='OS name', required=True)
parser.add_argument('-r', '--rid', help='RID', required=True)
parser.add_argument('-f', '--file', help='File name', required=True)
+ parser.add_argument('-t', '--tag', help='Tag (Version if unspecified)')
args = parser.parse_args()
appcast_ver = args.version
appcast_os = args.os
appcast_rid = args.rid
appcast_file = args.file
+ appcast_tag = args.tag or args.version
xml = '''
@@ -31,7 +33,7 @@ def main():
''' % (appcast_ver, datetime.now().strftime("%a, %d %b %Y %H:%M:%S %z"),
- appcast_ver, appcast_file, appcast_ver, appcast_ver, appcast_os)
+ appcast_tag, appcast_file, appcast_ver, appcast_ver, appcast_os)
with open("appcast.%s.xml" % (appcast_rid), 'w') as f:
f.write(xml)
From 33276df0cc8fc87332a981abbad478c261f27ce8 Mon Sep 17 00:00:00 2001
From: Mashi <67765922+atouu@users.noreply.github.com>
Date: Wed, 24 Jun 2026 22:36:58 +0800
Subject: [PATCH 2/6] Add nightly workflow for scheduled builds
---
.github/workflows/build.yml | 3 +--
.github/workflows/nightly.yml | 43 +++++++++++++++++++++++++++++++++++
2 files changed, 44 insertions(+), 2 deletions(-)
create mode 100644 .github/workflows/nightly.yml
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 6ff3c6b90..12c7be5a3 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -227,6 +227,7 @@ jobs:
tag: nightly
name: Nightly
prerelease: true
+ allowUpdates: true
draft: ${{ inputs.draft }}
artifacts: "appcast.${{ matrix.arch.name }}*.xml,OpenUtau-${{ matrix.arch.name }}.*"
body: |
@@ -240,6 +241,4 @@ jobs:
## macOS says "This app is damaged"
Open a terminal and run `xattr -rc /Applications/OpenUtau.app`. Try opening OpenUtau again.
- allowUpdates: true
- replaceArtifacts: true
if: ${{ inputs.release && inputs.channel == 'nightly' }}
diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml
new file mode 100644
index 000000000..26e5f7afb
--- /dev/null
+++ b/.github/workflows/nightly.yml
@@ -0,0 +1,43 @@
+name: Nightly
+
+on:
+ schedule:
+ - cron: '0 1 * * *'
+ workflow_dispatch:
+ push:
+
+jobs:
+ trigger:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ - name: Check for changes
+ id: check_changes
+ run: |
+ # Only trigger nightly from these folders
+ REGEX="^(OpenUtau(.Plugin.Builtin|.Core|)|runtimes)"
+ echo "changes=$(git log --since="yesterday" --name-only --oneline --pretty=format:"" | grep -m1 -E "$REGEX")" >> $GITHUB_OUTPUT
+ - name: Get Version
+ id: get_version
+ if: ${{ steps.check_changes.outputs.changes != '' }}
+ env:
+ GH_TOKEN: ${{ github.token }}
+ REPO: openutau/OpenUtau # Please modify if you want to release your fork
+ run: |
+ latest=$(gh release list --repo $REPO --json tagName --json tagName --jq 'first(.[] | select(.tagName | test("^[0-9]+\\.[0-9]+\\.[0-9]+$"))).tagName')
+ nextver=$(npx -y semver -i patch ${latest})
+ echo fullver=${nextver}-nightly.`date +%Y%m%d` >> $GITHUB_OUTPUT
+ - name: Trigger Build
+ if: ${{ steps.check_changes.outputs.changes != '' }}
+ uses: benc-uk/workflow-dispatch@v1
+ with:
+ workflow: build.yml
+ inputs: '{ "channel": "nightly", "version": "${{ steps.get_version.outputs.fullver }}", "release": true, "draft": false }'
+ - name: Delete workflow runs
+ uses: Mattraks/delete-workflow-runs@v2
+ with:
+ retain_days: 5
+ keep_minimum_runs: 5
+ delete_workflow_pattern: nightly
From e9d2ab06f019b7ac850b463bc5eca3fd9ee16fec Mon Sep 17 00:00:00 2001
From: atouu <67765922+atouu@users.noreply.github.com>
Date: Wed, 24 Jun 2026 23:59:13 +0800
Subject: [PATCH 3/6] Add checks for nightly and use informational version
---
OpenUtau/OpenUtau.csproj | 6 ++++
OpenUtau/Program.cs | 4 ++-
OpenUtau/ViewModels/MainWindowViewModel.cs | 5 ++-
OpenUtau/ViewModels/PreferencesViewModel.cs | 6 ++++
OpenUtau/ViewModels/UpdaterViewModel.cs | 35 +++++++++++++++------
OpenUtau/Views/PreferencesDialog.axaml | 5 +--
6 files changed, 47 insertions(+), 14 deletions(-)
diff --git a/OpenUtau/OpenUtau.csproj b/OpenUtau/OpenUtau.csproj
index 85bf69c8b..b829664bb 100644
--- a/OpenUtau/OpenUtau.csproj
+++ b/OpenUtau/OpenUtau.csproj
@@ -15,6 +15,9 @@
true
embedded
+
+ false
+
OpenUtau
@@ -126,4 +129,7 @@
Resources.Designer.cs
+
+ $(DefineConstants);NIGHTLY
+
\ No newline at end of file
diff --git a/OpenUtau/Program.cs b/OpenUtau/Program.cs
index dab8b1029..98c6a0954 100644
--- a/OpenUtau/Program.cs
+++ b/OpenUtau/Program.cs
@@ -34,7 +34,9 @@ public static void Main(string[] args) {
Log.Information($"{RuntimeInformation.OSDescription} " +
$"{RuntimeInformation.OSArchitecture} " +
$"{RuntimeInformation.ProcessArchitecture}");
- Log.Information($"OpenUtau v{Assembly.GetEntryAssembly()?.GetName().Version} " +
+ Log.Information($"OpenUtau v{Assembly.GetEntryAssembly()
+ ?.GetCustomAttribute()
+ ?.InformationalVersion} " +
$"{RuntimeInformation.RuntimeIdentifier}");
Log.Information($"Data path = {PathManager.Inst.DataPath}");
Log.Information($"Cache path = {PathManager.Inst.CachePath}");
diff --git a/OpenUtau/ViewModels/MainWindowViewModel.cs b/OpenUtau/ViewModels/MainWindowViewModel.cs
index d3090673f..c930eaf12 100644
--- a/OpenUtau/ViewModels/MainWindowViewModel.cs
+++ b/OpenUtau/ViewModels/MainWindowViewModel.cs
@@ -4,6 +4,7 @@
using System.Linq;
using System.Reactive;
using System.Threading.Tasks;
+using System.Reflection;
using Avalonia.Threading;
using DynamicData.Binding;
using OpenUtau.App.Views;
@@ -72,7 +73,9 @@ public class MainWindowViewModel : ViewModelBase, ICmdSubscriber {
[Reactive] public string ClearCacheHeader { get; set; }
public bool ProjectSaved => !string.IsNullOrEmpty(DocManager.Inst.Project.FilePath) && DocManager.Inst.Project.Saved;
- public string AppVersion => $"OpenUtau v{System.Reflection.Assembly.GetEntryAssembly()?.GetName().Version}";
+ public string AppVersion => $"OpenUtau v{Assembly.GetEntryAssembly()
+ ?.GetCustomAttribute()
+ ?.InformationalVersion}";
[Reactive] public double Progress { get; set; }
[Reactive] public string ProgressText { get; set; }
[Reactive] public bool ShowPianoRoll { get; set; }
diff --git a/OpenUtau/ViewModels/PreferencesViewModel.cs b/OpenUtau/ViewModels/PreferencesViewModel.cs
index 0683b822e..094505c39 100644
--- a/OpenUtau/ViewModels/PreferencesViewModel.cs
+++ b/OpenUtau/ViewModels/PreferencesViewModel.cs
@@ -128,6 +128,12 @@ public int SafeMaxThreadCount {
[Reactive] public bool RememberVsqx { get; set; }
public string WinePath => Preferences.Default.WinePath;
+ #if NIGHTLY
+ public bool IsNightly => true;
+ #else
+ public bool IsNightly => false;
+ #endif
+
public PreferencesViewModel() {
var audioOutput = PlaybackManager.Inst.AudioOutput;
if (audioOutput != null) {
diff --git a/OpenUtau/ViewModels/UpdaterViewModel.cs b/OpenUtau/ViewModels/UpdaterViewModel.cs
index ff24dedd2..3225dc0ac 100644
--- a/OpenUtau/ViewModels/UpdaterViewModel.cs
+++ b/OpenUtau/ViewModels/UpdaterViewModel.cs
@@ -4,6 +4,7 @@
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
+using System.Reflection;
using Avalonia.Media;
using NetSparkleUpdater;
using NetSparkleUpdater.AppCastHandlers;
@@ -29,10 +30,13 @@ class GithubRelease {
public bool draft;
public bool prerelease;
public string name = string.Empty;
+ public string tag_name = string.Empty;
public GithubReleaseAsset[] assets = new GithubReleaseAsset[0];
#pragma warning restore 0649
}
- public string AppVersion => $"v{System.Reflection.Assembly.GetEntryAssembly()?.GetName().Version}";
+ public string AppVersion => $"v{Assembly.GetEntryAssembly()
+ ?.GetCustomAttribute()
+ ?.InformationalVersion}";
public bool IsDarkMode => ThemeManager.IsDarkMode;
[Reactive] public string UpdaterStatus { get; set; }
[Reactive] public bool UpdateAvailable { get; set; }
@@ -84,17 +88,28 @@ public UpdaterViewModel() {
client.DefaultRequestHeaders.Add("Accept", "application/json");
client.DefaultRequestHeaders.Add("User-Agent", "Other");
client.Timeout = TimeSpan.FromSeconds(30);
- using var resposne = await client.GetAsync("https://api.github.com/repos/stakira/OpenUtau/releases");
+
+ #if !NIGHTLY
+ using var resposne = await client.GetAsync("https://api.github.com/repos/openutau/OpenUtau/releases");
+ #else
+ using var resposne = await client.GetAsync("https://api.github.com/repos/openutau/OpenUtau/releases/tags/nightly");
+ #endif
+
resposne.EnsureSuccessStatusCode();
string respBody = await resposne.Content.ReadAsStringAsync();
- List? releases = JsonConvert.DeserializeObject>(respBody);
- if (releases == null) {
- return null;
- }
- return releases
- .Where(r => !r.draft && r.prerelease == Preferences.Default.Beta)
- .OrderByDescending(r => r.id)
- .FirstOrDefault();
+
+ #if !NIGHTLY
+ List? releases = JsonConvert.DeserializeObject>(respBody);
+ if (releases == null) {
+ return null;
+ }
+ return releases
+ .Where(r => !r.draft && r.tag_name != "nightly" && r.prerelease == Preferences.Default.Beta)
+ .OrderByDescending(r => r.id)
+ .FirstOrDefault();
+ #else
+ return JsonConvert.DeserializeObject(respBody);
+ #endif
}
static GithubReleaseAsset? SelectAppcast(GithubRelease release) {
diff --git a/OpenUtau/Views/PreferencesDialog.axaml b/OpenUtau/Views/PreferencesDialog.axaml
index 290323724..ee614774c 100644
--- a/OpenUtau/Views/PreferencesDialog.axaml
+++ b/OpenUtau/Views/PreferencesDialog.axaml
@@ -82,11 +82,12 @@
-
+
-
+
+
From e5cbed31c6d8fdc1144225c8773e46d87d5eb688 Mon Sep 17 00:00:00 2001
From: atouu <67765922+atouu@users.noreply.github.com>
Date: Thu, 25 Jun 2026 00:11:06 +0800
Subject: [PATCH 4/6] Move nightly note to Strings.axaml
---
OpenUtau/Strings/Strings.axaml | 1 +
OpenUtau/Views/PreferencesDialog.axaml | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/OpenUtau/Strings/Strings.axaml b/OpenUtau/Strings/Strings.axaml
index bfc779b45..3ac5b0983 100644
--- a/OpenUtau/Strings/Strings.axaml
+++ b/OpenUtau/Strings/Strings.axaml
@@ -592,6 +592,7 @@ Warning: this option removes custom presets.
Editing
General
Note: please restart OpenUtau after changing this item.
+ Note: Switching between channels is not supported in nightly builds.
Oto Editor
Default Oto Editor
setParam Path
diff --git a/OpenUtau/Views/PreferencesDialog.axaml b/OpenUtau/Views/PreferencesDialog.axaml
index ee614774c..1b3b08e08 100644
--- a/OpenUtau/Views/PreferencesDialog.axaml
+++ b/OpenUtau/Views/PreferencesDialog.axaml
@@ -87,7 +87,7 @@
-
+
From 63d7a8b4e4232f8d51f8315d9277efd715f6c81f Mon Sep 17 00:00:00 2001
From: Mashi <67765922+atouu@users.noreply.github.com>
Date: Thu, 25 Jun 2026 00:16:21 +0800
Subject: [PATCH 5/6] Remove push trigger from nightly workflow
---
.github/workflows/nightly.yml | 1 -
1 file changed, 1 deletion(-)
diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml
index 26e5f7afb..fd11d503b 100644
--- a/.github/workflows/nightly.yml
+++ b/.github/workflows/nightly.yml
@@ -4,7 +4,6 @@ on:
schedule:
- cron: '0 1 * * *'
workflow_dispatch:
- push:
jobs:
trigger:
From 22c87b50c2684e399b90cd79306de89ff5404deb Mon Sep 17 00:00:00 2001
From: Mashi <67765922+atouu@users.noreply.github.com>
Date: Thu, 25 Jun 2026 00:36:50 +0800
Subject: [PATCH 6/6] Enable allowUpdates option in build workflow
---
.github/workflows/build.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 12c7be5a3..c6847f8b4 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -210,6 +210,7 @@ jobs:
tag: ${{ inputs.version }}
name: ${{ env.release-name }}
prerelease: ${{ inputs.channel != 'stable' }}
+ allowUpdates: true
draft: ${{ inputs.draft }}
artifacts: "appcast.${{ matrix.arch.name }}*.xml,OpenUtau-${{ matrix.arch.name }}.*"
body: |