Merge pull request 'feat: expose application version and update CI release workflow' (#1) from v1.0.0 into main

Reviewed-on: http://git.jdbnet.co.uk/jamie/goexplore/pulls/1
This commit was merged in pull request #1.
This commit is contained in:
2026-06-09 13:55:23 +01:00
9 changed files with 145 additions and 90 deletions
-48
View File
@@ -1,48 +0,0 @@
name: Build and Upload Binaries
on:
push:
branches:
- main
jobs:
build-and-upload:
runs-on: build-htz-01
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Build Windows and Linux AMD64 binaries
run: |
mkdir -p dist
# Build Linux amd64 and Windows amd64 binaries
docker run --rm -v ${{ github.workspace }}:/workspace -w /workspace cr.jdbnet.co.uk/jdbnet/wails-builder:latest bash -c "
# Install frontend dependencies
cd frontend && npm install && cd ..
# Linux amd64
wails build -platform linux/amd64 -tags webkit2_41 -clean
cp build/bin/goexplore dist/goexplore-linux-amd64
# Windows amd64
wails build -platform windows/amd64 -clean -nsis
cp build/bin/GoExplore-amd64-installer.exe dist/goexplore-windows-installer.exe
"
- name: Upload to Cloudflare R2
env:
AWS_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: auto
R2_ENDPOINT: ${{ secrets.R2_ENDPOINT_URL }}
run: |
aws s3 cp dist/goexplore-linux-amd64 s3://apps/goexplore/goexplore-linux-amd64 --endpoint-url "$R2_ENDPOINT"
aws s3 cp dist/goexplore-windows-installer.exe s3://apps/goexplore/goexplore-windows-installer.exe --endpoint-url "$R2_ENDPOINT"
- name: Clean up
run: sudo rm -rf dist build/bin/*
+81
View File
@@ -0,0 +1,81 @@
name: Release
on:
pull_request:
branches:
- main
types: [closed]
jobs:
release:
if: github.event.pull_request.merged == true && startsWith(github.head_ref, 'v')
runs-on: build-htz-01
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Extract Version
id: get_version
run: |
# Remove 'v' prefix for some contexts if needed, but we'll use it raw
RAW_VERSION=${{ github.head_ref }}
CLEAN_VERSION=${RAW_VERSION#v}
echo "VERSION=${RAW_VERSION}" >> $GITHUB_OUTPUT
echo "CLEAN_VERSION=${CLEAN_VERSION}" >> $GITHUB_OUTPUT
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Build Binaries
run: |
mkdir -p dist
# Build Linux amd64 and Windows amd64 binaries using custom docker image
docker run --rm -v ${{ github.workspace }}:/workspace -w /workspace cr.jdbnet.co.uk/jdbnet/wails-builder:latest bash -c "
# Inject version into wails.json for NSIS & executable properties
sed -i 's/\"productVersion\": \".*\"/\"productVersion\": \"${{ steps.get_version.outputs.CLEAN_VERSION }}\"/' wails.json
# Install frontend dependencies
cd frontend && npm install && cd ..
# Linux amd64
wails build -platform linux/amd64 -tags webkit2_41 -clean -ldflags \"-X main.Version=${{ steps.get_version.outputs.VERSION }}\"
cp build/bin/goexplore dist/goexplore-linux-amd64
# Windows amd64
wails build -platform windows/amd64 -clean -nsis -ldflags \"-X main.Version=${{ steps.get_version.outputs.VERSION }}\"
cp build/bin/GoExplore-amd64-installer.exe dist/goexplore-windows-installer.exe
"
# - name: Generate Changelog
# id: changelog
# uses: https://github.com/metcalfc/changelog-generator@v4.6.2
# with:
# myToken: ${{ secrets.GITHUB_TOKEN }}
- name: Create Gitea Release
uses: https://gitea.com/actions/gitea-release-action@v1
with:
tag_name: ${{ steps.get_version.outputs.VERSION }}
name: GoExplore ${{ steps.get_version.outputs.VERSION }}
body: ${{ steps.changelog.outputs.changelog }}
draft: false
prerelease: false
files: |
dist/goexplore-linux-amd64
dist/goexplore-windows-installer.exe
- name: Upload to Cloudflare R2
env:
AWS_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: auto
R2_ENDPOINT: ${{ secrets.R2_ENDPOINT_URL }}
run: |
aws s3 cp dist/goexplore-linux-amd64 s3://apps/goexplore/goexplore-linux-amd64 --endpoint-url "$R2_ENDPOINT"
aws s3 cp dist/goexplore-windows-installer.exe s3://apps/goexplore/goexplore-windows-installer.exe --endpoint-url "$R2_ENDPOINT"
- name: Clean up
run: sudo rm -rf dist build/bin/*
+4
View File
@@ -44,6 +44,10 @@ func (a *App) startup(ctx context.Context) {
a.ctx = ctx a.ctx = ctx
} }
func (a *App) GetVersion() string {
return Version
}
func (a *App) GetConnections() []config.ConnectionConfig { func (a *App) GetConnections() []config.ConnectionConfig {
if a.cfg == nil { if a.cfg == nil {
return nil return nil
+1
View File
@@ -11,6 +11,7 @@
<div class="sidebar-header"> <div class="sidebar-header">
<img src="./src/assets/appicon.png" alt="Icon" style="width: 24px; height: 24px; margin-right: 0.5rem;"/> <img src="./src/assets/appicon.png" alt="Icon" style="width: 24px; height: 24px; margin-right: 0.5rem;"/>
<span>GoExplore</span> <span>GoExplore</span>
<span id="app-version" style="font-size: 0.7rem; color: var(--text-secondary); margin-left: 0.5rem; border: 1px solid var(--border); padding: 0.1rem 0.3rem; border-radius: 4px;"></span>
</div> </div>
<div class="conn-list" id="conn-list"> <div class="conn-list" id="conn-list">
<!-- Connections will be populated here --> <!-- Connections will be populated here -->
+23 -15
View File
@@ -1,4 +1,4 @@
import { ListDir, GetConnections, SaveConnection, DeleteConnection, Delete, Rename, PromptUploadFiles, PromptUploadDirectory, PromptDownload, TransferItems, GetTransfers, ClearTransfers } from '../wailsjs/go/main/App.js'; import { GetVersion, ListDir, GetConnections, SaveConnection, DeleteConnection, Delete, Rename, PromptUploadFiles, PromptUploadDirectory, PromptDownload, TransferItems, GetTransfers, ClearTransfers } from '../wailsjs/go/main/App.js';
let currentConn = 'local'; let currentConn = 'local';
let currentPath = ''; let currentPath = '';
@@ -24,6 +24,14 @@ async function init() {
} }
} }
try {
const version = await GetVersion();
const vSpan = document.getElementById('app-version');
if (vSpan && version) {
vSpan.innerText = version;
}
} catch (e) { }
await loadConnections(); await loadConnections();
await loadDirectory(currentConn, currentPath); await loadDirectory(currentConn, currentPath);
@@ -46,7 +54,7 @@ async function init() {
await SaveConnection(conn, secret); await SaveConnection(conn, secret);
closeConnModal(); closeConnModal();
loadConnections(); loadConnections();
} catch(err) { } catch (err) {
alert("Failed to save connection: " + err); alert("Failed to save connection: " + err);
} }
}); });
@@ -70,7 +78,7 @@ async function loadConnections() {
list.appendChild(el); list.appendChild(el);
}); });
} }
} catch(e) { } catch (e) {
console.error(e); console.error(e);
} }
} }
@@ -128,17 +136,17 @@ window.updateProtocolFields = () => {
}; };
window.deleteConnection = async () => { window.deleteConnection = async () => {
if(!confirm("Are you sure you want to delete this connection?")) return; if (!confirm("Are you sure you want to delete this connection?")) return;
const id = document.getElementById('conn-id').value; const id = document.getElementById('conn-id').value;
try { try {
await DeleteConnection(id); await DeleteConnection(id);
closeConnModal(); closeConnModal();
if(currentConn === id) { if (currentConn === id) {
switchConn('local'); switchConn('local');
} else { } else {
loadConnections(); loadConnections();
} }
} catch(err) { } catch (err) {
alert("Failed to delete connection: " + err); alert("Failed to delete connection: " + err);
} }
}; };
@@ -168,7 +176,7 @@ async function loadDirectory(connId, path) {
if (a.is_dir !== b.is_dir) return a.is_dir ? -1 : 1; if (a.is_dir !== b.is_dir) return a.is_dir ? -1 : 1;
let cmp = 0; let cmp = 0;
switch(sortField) { switch (sortField) {
case 'name': case 'name':
cmp = a.name.localeCompare(b.name); cmp = a.name.localeCompare(b.name);
break; break;
@@ -223,9 +231,9 @@ async function loadDirectory(connId, path) {
selectedItems = []; selectedItems = [];
allRows.forEach(r => r.classList.remove('selected')); allRows.forEach(r => r.classList.remove('selected'));
for(let i=startIdx; i<=endIdx; i++) { for (let i = startIdx; i <= endIdx; i++) {
const row = allRows[i]; const row = allRows[i];
if(row.dataset.path) { if (row.dataset.path) {
row.classList.add('selected'); row.classList.add('selected');
selectedItems.push({ selectedItems.push({
path: row.dataset.path, path: row.dataset.path,
@@ -251,7 +259,7 @@ async function loadDirectory(connId, path) {
} }
tbody.appendChild(tr); tbody.appendChild(tr);
}); });
} catch(e) { } catch (e) {
tbody.innerHTML = `<tr><td colspan="4" style="color: var(--error)">Error: ${e}</td></tr>`; tbody.innerHTML = `<tr><td colspan="4" style="color: var(--error)">Error: ${e}</td></tr>`;
} }
} }
@@ -279,7 +287,7 @@ function formatDate(dateString) {
if (!dateString) return '-'; if (!dateString) return '-';
const d = new Date(dateString); const d = new Date(dateString);
if (isNaN(d.getTime())) return dateString; if (isNaN(d.getTime())) return dateString;
return `${String(d.getDate()).padStart(2, '0')}/${String(d.getMonth()+1).padStart(2, '0')}/${d.getFullYear()} ${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`; return `${String(d.getDate()).padStart(2, '0')}/${String(d.getMonth() + 1).padStart(2, '0')}/${d.getFullYear()} ${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`;
} }
window.setSort = (field) => { window.setSort = (field) => {
@@ -300,7 +308,7 @@ window.clearTransfers = async () => {
try { try {
await ClearTransfers(); await ClearTransfers();
pollTransfers(); pollTransfers();
} catch(e) { } catch (e) {
console.error(e); console.error(e);
} }
}; };
@@ -338,7 +346,7 @@ async function pollTransfers() {
</div>`; </div>`;
}); });
list.innerHTML = html; list.innerHTML = html;
} catch(e) { } catch (e) {
console.error(e); console.error(e);
} }
} }
@@ -527,7 +535,7 @@ window.loadTransferDestDirectory = async (connId, path) => {
} }
tbody.appendChild(tr); tbody.appendChild(tr);
}); });
} catch(e) { } catch (e) {
tbody.innerHTML = `<tr><td style="color: var(--error)">Error: ${e}</td></tr>`; tbody.innerHTML = `<tr><td style="color: var(--error)">Error: ${e}</td></tr>`;
} }
}; };
@@ -540,7 +548,7 @@ window.executeTransfer = async () => {
showTransfers(); showTransfers();
selectedItems = []; selectedItems = [];
Array.from(document.querySelectorAll('#file-list tr')).forEach(r => r.classList.remove('selected')); Array.from(document.querySelectorAll('#file-list tr')).forEach(r => r.classList.remove('selected'));
} catch(e) { } catch (e) {
alert("Transfer failed: " + e); alert("Transfer failed: " + e);
} }
}; };
+2
View File
@@ -15,6 +15,8 @@ export function GetConnections():Promise<Array<config.ConnectionConfig>>;
export function GetTransfers():Promise<Array<transfer.Transfer>>; export function GetTransfers():Promise<Array<transfer.Transfer>>;
export function GetVersion():Promise<string>;
export function ListDir(arg1:string,arg2:string):Promise<Array<explorer.FileEntry>>; export function ListDir(arg1:string,arg2:string):Promise<Array<explorer.FileEntry>>;
export function MkDir(arg1:string,arg2:string):Promise<void>; export function MkDir(arg1:string,arg2:string):Promise<void>;
+4
View File
@@ -22,6 +22,10 @@ export function GetTransfers() {
return window['go']['main']['App']['GetTransfers'](); return window['go']['main']['App']['GetTransfers']();
} }
export function GetVersion() {
return window['go']['main']['App']['GetVersion']();
}
export function ListDir(arg1, arg2) { export function ListDir(arg1, arg2) {
return window['go']['main']['App']['ListDir'](arg1, arg2); return window['go']['main']['App']['ListDir'](arg1, arg2);
} }
+2
View File
@@ -20,6 +20,8 @@ var assets embed.FS
//go:embed build/appicon.png //go:embed build/appicon.png
var icon []byte var icon []byte
var Version string = "dev"
func installLinux() { func installLinux() {
if runtime.GOOS != "linux" { if runtime.GOOS != "linux" {
return return
+2 -1
View File
@@ -11,6 +11,7 @@
}, },
"info": { "info": {
"companyName": "JDB-NET Limited", "companyName": "JDB-NET Limited",
"productName": "GoExplore" "productName": "GoExplore",
"productVersion": "0.0.0"
} }
} }