diff --git a/.github/build/build_info.json b/.github/build/build_info.json
index 07f13d17..8befffd8 100644
--- a/.github/build/build_info.json
+++ b/.github/build/build_info.json
@@ -16,5 +16,10 @@
"darwin": {
"amd64": {"arch": "o64", "name": "macos-64"},
"arm64": {"arch": "oa64", "name": "macos-arm64-v8a"}
+ },
+ "windows": {
+ "386": {"arch": "i686", "name": "windows-32"},
+ "amd64": {"arch": "x86_64", "name": "windows-64"},
+ "arm64": {"arch": "aarch64", "name": "windows-arm64-v8a"}
}
}
diff --git a/app/src/views/system/Upgrade.vue b/app/src/views/system/Upgrade.vue
index 9d7207a9..8f0c2d67 100644
--- a/app/src/views/system/Upgrade.vue
+++ b/app/src/views/system/Upgrade.vue
@@ -193,6 +193,9 @@ async function performUpgrade() {
{{ $gettext('Pre-release') }}
+
+ {{ $gettext('Dev') }}
+
diff --git a/internal/version/dev_build.go b/internal/version/dev_build.go
new file mode 100644
index 00000000..be1e5ff5
--- /dev/null
+++ b/internal/version/dev_build.go
@@ -0,0 +1,77 @@
+package version
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "time"
+
+ "github.com/pkg/errors"
+)
+
+const (
+ GithubDevCommitAPI = "https://api.github.com/repos/0xJacky/nginx-ui/commits/dev?per_page=1"
+ CloudflareWorkerAPI = "https://nginx-ui-proxy.langgood.com"
+)
+
+type TCommit struct {
+ SHA string `json:"sha"`
+ Commit struct {
+ Message string `json:"message"`
+ Committer struct {
+ Date time.Time `json:"date"`
+ } `json:"committer"`
+ } `json:"commit"`
+}
+
+func getDevBuild() (data TRelease, err error) {
+ resp, err := http.Get(GithubDevCommitAPI)
+ if err != nil {
+ return
+ }
+
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return
+ }
+ defer resp.Body.Close()
+ commit := TCommit{}
+ err = json.Unmarshal(body, &commit)
+ if err != nil {
+ return
+ }
+ if len(commit.SHA) < 7 {
+ err = errors.New("invalid commit SHA")
+ return
+ }
+ shortSHA := commit.SHA[:7]
+
+ resp, err = http.Get(fmt.Sprintf("%s/dev-builds/%s", CloudflareWorkerAPI, shortSHA))
+ if err != nil {
+ return
+ }
+
+ body, err = io.ReadAll(resp.Body)
+ if err != nil {
+ return
+ }
+ defer resp.Body.Close()
+
+ assets := []TReleaseAsset{}
+ err = json.Unmarshal(body, &assets)
+ if err != nil {
+ return
+ }
+
+ data = TRelease{
+ TagName: "sha-" + shortSHA,
+ Name: shortSHA,
+ Body: commit.Commit.Message,
+ Type: ReleaseTypeDev,
+ PublishedAt: commit.Commit.Committer.Date,
+ Assets: assets,
+ }
+
+ return
+}
diff --git a/internal/version/release.go b/internal/version/release.go
index 463f80a7..f9ea8136 100644
--- a/internal/version/release.go
+++ b/internal/version/release.go
@@ -14,6 +14,14 @@ const (
GithubReleasesListAPI = "https://api.github.com/repos/0xJacky/nginx-ui/releases"
)
+type ReleaseType string
+
+const (
+ ReleaseTypeStable ReleaseType = "stable"
+ ReleaseTypePrerelease ReleaseType = "prerelease"
+ ReleaseTypeDev ReleaseType = "dev"
+)
+
type TReleaseAsset struct {
Name string `json:"name"`
BrowserDownloadUrl string `json:"browser_download_url"`
@@ -26,6 +34,7 @@ type TRelease struct {
PublishedAt time.Time `json:"published_at"`
Body string `json:"body"`
Prerelease bool `json:"prerelease"`
+ Type ReleaseType `json:"type"`
Assets []TReleaseAsset `json:"assets"`
}
@@ -58,6 +67,7 @@ func getLatestRelease() (data TRelease, err error) {
err = errors.Wrap(err, "service.getLatestRelease json.Unmarshal err")
return
}
+ data.Type = ReleaseTypeStable
return
}
@@ -92,6 +102,7 @@ func getLatestPrerelease() (data TRelease, err error) {
if release.Prerelease && release.PublishedAt.After(latestDate) {
data = release
latestDate = release.PublishedAt
+ data.Type = ReleaseTypePrerelease
}
}
@@ -104,12 +115,12 @@ func GetRelease(channel string) (data TRelease, err error) {
return TRelease{}, err
}
- switch channel {
+ switch ReleaseType(channel) {
default:
fallthrough
- case "stable":
+ case ReleaseTypeStable:
return stableRelease, nil
- case "prerelease":
+ case ReleaseTypePrerelease:
preRelease, err := getLatestPrerelease()
if err != nil {
return TRelease{}, err
@@ -120,5 +131,11 @@ func GetRelease(channel string) (data TRelease, err error) {
return preRelease, nil
}
return stableRelease, nil
+ case ReleaseTypeDev:
+ devRelease, err := getDevBuild()
+ if err != nil {
+ return TRelease{}, err
+ }
+ return devRelease, nil
}
}