Skip to content

Quick view: image viewer has context menu #793

Quick view: image viewer has context menu

Quick view: image viewer has context menu #793

Workflow file for this run

name: CI
on:
push:
branches-ignore: [gh-pages] # metrics commits to gh-pages must not re-trigger CI
tags: ['**'] # but keep tag pushes so the create-release job still runs
pull_request:
workflow_dispatch:
# github-action-benchmark pushes the metrics history to the gh-pages branch.
permissions:
contents: write
deployments: write
pull-requests: read # dorny/paths-filter reads the changed-files list on PRs
env:
# Path to the solution file relative to the root of the project.
SOLUTION_FILE_PATH: .
# Configuration type to build.
# You can convert this to a build matrix if you need coverage of multiple configuration types.
# https://docs.github.com/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
BUILD_CONFIGURATION: Release
jobs:
changes:
name: Detect test-relevant changes
runs-on: ubuntu-latest
outputs:
# A manual (workflow_dispatch) run always counts as test-relevant; otherwise defer to the path filter.
tests_relevant: ${{ steps.filter.outputs.tests_relevant == 'true' || github.event_name == 'workflow_dispatch' }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Detect test-relevant changes
uses: dorny/paths-filter@v4
id: filter
with:
filters: |
tests_relevant:
- 'file-commander-core/src/**'
- 'file-commander-core/core-tests/**'
- 'qt-app/src/**' # compiled by the gui-tests target (typed prompt, dialog, launch routing)
- 'qt-app/gui-tests/**'
- 'thin_io/**'
- '.github/workflows/CI.yml'
- 'global.pri'
- 'file-commander-core/config.pri'
build:
name: Build app & installer on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-22.04, macos-14, windows-latest]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Sys info
if: "startsWith(matrix.os, 'mac')"
run: |
sysctl -a | grep cpu | grep hw
sysctl -a | grep brand_string
sysctl -n hw.machine
- name: Sys info
if: "startsWith(matrix.os, 'ubuntu')"
run: |
lscpu
- name: LOC count - app
if: "startsWith(matrix.os, 'windows')"
shell: pwsh
run: |
winget install --id AlDanial.Cloc --exact --silent --accept-package-agreements --accept-source-agreements
"$env:LOCALAPPDATA\Microsoft\WinGet\Links" >> $env:GITHUB_PATH
$loc = (cloc --include-lang="C,C++,C/C++ Header" --strip-str-comments --exclude-dir=tests,bin,build,.git,3rdparty,trigramfrequencytables,gui-tests,core-tests --json --quiet ./qt-app/ ./plugins/ ./file-commander-core/ | ConvertFrom-Json).SUM.code
"App C/C++ code: $loc LOC"
"LOC_APP=$loc" >> $env:GITHUB_ENV
- name: LOC count - libs
if: "startsWith(matrix.os, 'windows')"
shell: pwsh
run: |
$loc = (cloc --include-lang="C,C++,C/C++ Header" --strip-str-comments --exclude-dir=tests,bin,build,.git,3rdparty,trigramfrequencytables,qt-app,plugins,file-commander-core --json --quiet . | ConvertFrom-Json).SUM.code
"Libs C/C++ code: $loc LOC"
"LOC_LIBS=$loc" >> $env:GITHUB_ENV
- name: Install Qt
if: "startsWith(matrix.os, 'windows')"
uses: jurplel/install-qt-action@v4
with:
version: '6.10.*'
target: desktop
arch: 'win64_msvc2022_64'
archives: 'qtbase icu qtsvg'
modules: 'qt5compat qtimageformats'
cache: 'true'
- name: Install Qt
if: "startsWith(matrix.os, 'ubuntu')"
uses: jurplel/install-qt-action@v4
with:
version: '6.10.*'
target: desktop
arch: 'linux_gcc_64'
archives: 'qtbase icu qtsvg'
modules: 'qt5compat qtimageformats'
cache: 'true'
- name: Install Qt
if: "startsWith(matrix.os, 'macos')"
uses: jurplel/install-qt-action@v4
with:
version: '6.10.*'
target: desktop
arch: 'clang_64'
archives: 'qtbase icu qtsvg'
modules: 'qt5compat qtimageformats'
cache: 'true'
- name: Setup MSVC Developer Command Prompt
if: startsWith(matrix.os, 'windows')
uses: ilammy/msvc-dev-cmd@v1
- name: Windows - building main installer
if: startsWith(matrix.os, 'windows')
shell: cmd
run: |
%QT_ROOT_DIR%\bin\qmake.exe -v
set QTDIR64=%QT_ROOT_DIR%
cd installer\windows\
create_installer.bat
cd ..\..
xcopy /R /Y .\installer\windows\binaries\64\msvcr\* .\bin\release\
xcopy /R /Y .\installer\windows\binaries\64\Qt\* .\bin\release\
- name: Mac
if: startsWith(matrix.os, 'macos')
working-directory: ${{env.GITHUB_WORKSPACE}}
run: |
clang --version
./installer/mac/create_dmg.sh $QT_ROOT_DIR
- name: Linux
if: startsWith(matrix.os, 'ubuntu')
working-directory: ${{env.GITHUB_WORKSPACE}}
run: |
export QT_DEBUG_PLUGINS=1
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test # jammy ships nothing newer than gcc-12
sudo apt update -y; sudo apt install -qq gcc-14 g++-14 libglu1-mesa-dev libx11-xcb-dev '^libxcb*' '^libxkb*' libfuse2
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-14 50
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 50
g++ --version
export PATH=$QT_ROOT_DIR/bin/:$PATH
wget -c -nv "https://github.com/probonopd/linuxdeployqt/releases/download/7/linuxdeployqt-7-x86_64.AppImage"
chmod a+x linuxdeployqt-7-x86_64.AppImage
unset QTDIR; unset QT_PLUGIN_PATH ; unset LD_LIBRARY_PATH
$QT_ROOT_DIR/bin/qmake -r CONFIG+=release
make -j$(nproc)
# Linux: building AppImage
cp ./qt-app/resources/icon.png ./bin/release/
cp ./installer/linux/file_commander.desktop ./bin/release/
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${QT_ROOT_DIR}/lib/
sudo ldconfig
./linuxdeployqt-7-x86_64.AppImage ./bin/release/FileCommander -appimage -unsupported-allow-new-glibc -bundle-non-qt-libs -qmake=$QT_ROOT_DIR/bin/qmake -extra-plugins=platforms/,iconengines/,imageformats/,tls/,networkinformation/,platformthemes/,wayland-decoration-client/,wayland-graphics-integration-client/,wayland-shell-integration -executable=./bin/release/libplugin_filecomparison.so.1.0.0 -executable=./bin/release/libplugin_imageviewer.so.1.0.0 -executable=./bin/release/libplugin_textviewer.so.1.0.0
ls -Ac
mv ./File_Commander*.AppImage ./FileCommander.AppImage
- name: Binary sizes - Windows
if: startsWith(matrix.os, 'windows')
shell: pwsh
run: |
# Sizes of our own binaries (app + every plugin); the Qt/MSVC runtime DLLs xcopied into bin/ are excluded by name.
$exe = Get-Item "bin\release\FileCommander.exe"
foreach ($b in @($exe) + (Get-ChildItem "bin\release\plugin_*.dll")) {
"{0,10:N2} KB {1}" -f ($b.Length / 1KB), $b.Name
}
# Per-PE-section on-disk sizes from the "size of raw data" field of each SECTION HEADER.
# dumpbin is on PATH via the earlier MSVC dev-cmd step.
$name = $null
$sections = @()
foreach ($line in (dumpbin /headers $exe.FullName)) {
if ($line -match '^\s+(\S+) name$') { $name = $Matches[1] }
elseif ($line -match '^\s+([0-9A-Fa-f]+) size of raw data$' -and $name) {
$sections += [pscustomobject]@{ Name = $name; KB = [math]::Round([Convert]::ToInt64($Matches[1], 16) / 1KB, 2) }
$name = $null
}
}
$sections = $sections | Sort-Object KB -Descending
$sections | Format-Table Name, KB -AutoSize
"EXE_KB=$([math]::Round($exe.Length / 1KB, 2))" >> $env:GITHUB_ENV
"IMAGEVIEWER_KB=$([math]::Round((Get-Item 'bin\release\plugin_imageviewer.dll').Length / 1KB, 2))" >> $env:GITHUB_ENV
"TEXTVIEWER_KB=$([math]::Round((Get-Item 'bin\release\plugin_textviewer.dll').Length / 1KB, 2))" >> $env:GITHUB_ENV
# Per-section charts cover the main executable only.
"SECTIONS_JSON=$($sections | ConvertTo-Json -Compress -AsArray)" >> $env:GITHUB_ENV
# Record LOC, exe size + per-section sizes to the gh-pages history and regenerate the chart.
# Only on pushes to master so PRs/forks don't write history (and forks lack a write token).
- name: Assemble metrics data
if: github.event_name == 'push' && github.ref == 'refs/heads/master' && startsWith(matrix.os, 'windows')
shell: pwsh
run: |
$data = @(
@{ name = 'Lines of code (app)'; unit = 'LOC'; value = [int]$env:LOC_APP }
@{ name = 'Lines of code (libs)'; unit = 'LOC'; value = [int]$env:LOC_LIBS }
@{ name = 'FileCommander.exe size'; unit = 'KB'; value = [double]$env:EXE_KB }
@{ name = 'plugin_imageviewer.dll size'; unit = 'KB'; value = [double]$env:IMAGEVIEWER_KB }
@{ name = 'plugin_textviewer.dll size'; unit = 'KB'; value = [double]$env:TEXTVIEWER_KB }
)
# FileCommander.exe's PE sections, measured by the earlier size step. Each becomes its own chart; .msvcjmc is skipped.
foreach ($s in ($env:SECTIONS_JSON | ConvertFrom-Json) | Where-Object Name -ne '.msvcjmc') {
$data += @{ name = "Section $($s.Name)"; unit = 'KB'; value = $s.KB }
}
$data | ConvertTo-Json -AsArray | Out-File -FilePath metrics.json -Encoding utf8
Get-Content metrics.json
- name: Update metrics history & chart (gh-pages)
if: github.event_name == 'push' && github.ref == 'refs/heads/master' && startsWith(matrix.os, 'windows')
uses: benchmark-action/github-action-benchmark@v1
with:
name: File Commander metrics
tool: customSmallerIsBetter
output-file-path: metrics.json
benchmark-data-dir-path: dev/metrics # where data.js + index.html live on gh-pages (default: dev/bench)
github-token: ${{ secrets.GITHUB_TOKEN }}
auto-push: true
# Don't treat a change as a regression
comment-on-alert: false
fail-on-alert: false
# Sizes of our own binaries (app + every plugin), excluding the Qt/system libs the deploy tools copy into bin/.
- name: Binary sizes - Mac
if: startsWith(matrix.os, 'macos')
run: |
cd bin/release
for f in FileCommander.app/Contents/MacOS/FileCommander libplugin_*.dylib; do
[ -f "$f" ] && [ ! -L "$f" ] || continue
awk -v b="$(wc -c < "$f")" -v n="$f" 'BEGIN { printf "%10.2f KB %s\n", b/1024, n }'
done
- name: Binary sizes - Linux
if: startsWith(matrix.os, 'ubuntu')
run: |
cd bin/release
for f in FileCommander libplugin_*.so.*; do
[ -f "$f" ] && [ ! -L "$f" ] || continue
awk -v b="$(wc -c < "$f")" -v n="$f" 'BEGIN { printf "%10.2f KB %s\n", b/1024, n }'
done
- name: Test launch
if: startsWith(matrix.os, 'macos')
run: ./bin/release/FileCommander.app/Contents/MacOS/FileCommander --test-launch
- name: Test launch
if: startsWith(matrix.os, 'ubuntu')
run: |
xvfb-run --auto-servernum ./bin/release/FileCommander --test-launch
- name: Test launch
if: startsWith(matrix.os, 'windows')
run: |
.\bin\release\FileCommander.exe --test-launch
- name: Archive DMG
if: success() && startsWith(matrix.os, 'macos')
uses: actions/upload-artifact@v4
with:
name: FileCommander.dmg
path: FileCommander.dmg
- name: Archive AppImage
if: success() && startsWith(matrix.os, 'ubuntu')
uses: actions/upload-artifact@v4
with:
name: FileCommander.AppImage
path: FileCommander.AppImage
- name: Archive Installer
if: success() && startsWith(matrix.os, 'windows')
uses: actions/upload-artifact@v4
with:
name: FileCommander.exe
path: installer/windows/FileCommander.exe
test:
name: Build & run tests on ${{ matrix.os }}
needs: changes
if: needs.changes.outputs.tests_relevant == 'true' || startsWith(github.ref, 'refs/tags/')
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-22.04, macos-14, windows-latest]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Qt
if: "startsWith(matrix.os, 'windows')"
uses: jurplel/install-qt-action@v4
with:
version: '6.10.*'
target: desktop
arch: 'win64_msvc2022_64'
archives: 'qtbase icu qtsvg'
modules: 'qt5compat qtimageformats'
cache: 'true'
- name: Install Qt
if: "startsWith(matrix.os, 'ubuntu')"
uses: jurplel/install-qt-action@v4
with:
version: '6.10.*'
target: desktop
arch: 'linux_gcc_64'
archives: 'qtbase icu qtsvg'
modules: 'qt5compat qtimageformats'
cache: 'true'
- name: Install Qt
if: "startsWith(matrix.os, 'macos')"
uses: jurplel/install-qt-action@v4
with:
version: '6.10.*'
target: desktop
arch: 'clang_64'
archives: 'qtbase icu qtsvg'
modules: 'qt5compat qtimageformats'
cache: 'true'
- name: Setup MSVC Developer Command Prompt
if: startsWith(matrix.os, 'windows')
uses: ilammy/msvc-dev-cmd@v1
- name: Linux - install build & deploy dependencies
if: startsWith(matrix.os, 'ubuntu')
run: |
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test # jammy ships nothing newer than gcc-12
sudo apt update -y; sudo apt install -qq gcc-14 g++-14 libglu1-mesa-dev libx11-xcb-dev '^libxcb*' '^libxkb*' libfuse2
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-14 50
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 50
g++ --version
wget -c -nv "https://github.com/probonopd/linuxdeployqt/releases/download/7/linuxdeployqt-7-x86_64.AppImage"
chmod a+x linuxdeployqt-7-x86_64.AppImage
- name: Building tests - Windows
if: startsWith(matrix.os, 'windows')
working-directory: ${{env.GITHUB_WORKSPACE}}
shell: cmd
run: |
cd file-commander-core\core-tests\
dir
"%QT_ROOT_DIR%\bin\qmake.exe" -tp vc -r
msbuild /t:Build /p:Configuration=Release;PlatformToolset=v143 core-tests.sln
- name: Setup RAM Disk
if: startsWith(matrix.os, 'windows')
uses: chad-golden/setup-ramdisk@v1.0.1
with:
size-in-mb: 512 # Optional: Default is 2048
drive-letter: 'R' # Optional: Default is R
copy-workspace: false # Optional: Default is false
- name: Second RAM disk and temp folders
if: startsWith(matrix.os, 'windows')
shell: pwsh
run: |
# Fail the step if imdisk does (pwsh otherwise propagates only the last command's exit code)
$PSNativeCommandUseErrorActionPreference = $true
$ErrorActionPreference = 'Stop'
# The action above leaves ImDisk in System32, so a second RAM disk is one command. S: has to be a
# volume genuinely distinct from R: - that is the whole point of the cross-volume tests.
imdisk -a -s 128M -m S: -p "/FS:NTFS /Q /Y"
# R: is created by the third-party action; format it here so its filesystem is ours to state rather than
# to inherit. Wipes the disk, which is only safe while the action's copy-workspace input is false.
# format.com, not Format-Volume: ImDisk volumes are absent from the Storage provider the cmdlets query.
format.com R: /FS:NTFS /Q /Y /V:RAMDISK
# imdisk delegates -p to format.com and does not report its failure, so assert the end state on both disks:
# anything but NTFS silently drops the reparse-point coverage that needs it. DriveInfo asks the filesystem
# directly, for the same reason format.com is used above.
foreach ($letter in 'R', 'S') {
$filesystem = [System.IO.DriveInfo]::new("${letter}:").DriveFormat
if ($filesystem -ne 'NTFS') { throw "${letter}: is $filesystem, expected NTFS" }
}
New-Item -Path R:\Temp -ItemType Directory -Force
New-Item -Path S:\Temp -ItemType Directory -Force
echo "TEMP=R:\\Temp" >> $env:GITHUB_ENV
echo "TMP=R:\\Temp" >> $env:GITHUB_ENV
echo "TMPDIR=R:\\Temp" >> $env:GITHUB_ENV
echo "FILE_COMMANDER_TEST_SECOND_VOLUME=S:\\Temp" >> $env:GITHUB_ENV
# The runner is elevated, so symlink creation is available; setting this turns a failure to create one
# into a test failure instead of a skip.
echo "FILE_COMMANDER_TEST_SYMLINKS=1" >> $env:GITHUB_ENV
- name: Running tests - Windows
if: startsWith(matrix.os, 'windows')
shell: pwsh
run: |
# Fail the step on the first test executable that exits with a nonzero code (default pwsh behavior only propagates the last command's exit code)
$PSNativeCommandUseErrorActionPreference = $true
$ErrorActionPreference = 'Stop'
.\bin\release\fso_test.exe
.\bin\release\fso_test_high_level.exe
.\bin\release\panel_test.exe
.\bin\release\filesearchengine_test.exe
$N=20
For ($i=1; $i -le $N; $i++) {
Write-Output "Iteration $i/$N"
$randomSeed = Get-Date -UFormat %s
& .\bin\release\fileoperations_test.exe --std-seed $randomSeed;
}
$randomSeed = Get-Date -UFormat %s
& .\bin\release\filecomparator_test.exe --std-seed $randomSeed;
& .\bin\release\fileoperations_gui_test.exe
- name: Building tests - Mac
if: startsWith(matrix.os, 'macos')
run: |
cd file-commander-core/core-tests
$QT_ROOT_DIR/bin/qmake -r CONFIG+=release
make -j$(sysctl -n hw.ncpu)
cd ../../
for f in $(find bin/release/ -name *.app); do $QT_ROOT_DIR/bin/macdeployqt $f; done
- name: Case-sensitive second volume for filesystem tests - Mac
if: startsWith(matrix.os, 'macos')
run: |
set -e
# TMPDIR is on the system volume, so this RAM disk is genuinely different. HFSX also gives the
# rename tests a case-sensitive volume without provisioning and attaching another disk.
disk=$(hdiutil attach -nomount ram://262144 | awk '{print $1}') # 512-byte sectors: 128 MB
diskutil erasevolume HFSX fc-second "$disk"
echo "FILE_COMMANDER_TEST_SECOND_VOLUME=/Volumes/fc-second" >> $GITHUB_ENV
echo "FILE_COMMANDER_TEST_CASE_SENSITIVE_VOLUME=/Volumes/fc-second" >> $GITHUB_ENV
- name: Running tests - Mac
if: startsWith(matrix.os, 'macos')
run: |
set -e; ./bin/release/fso_test.app/Contents/MacOS/fso_test
set -e; ./bin/release/fso_test_high_level.app/Contents/MacOS/fso_test_high_level
set -e; ./bin/release/panel_test.app/Contents/MacOS/panel_test
set -e; ./bin/release/filesearchengine_test.app/Contents/MacOS/filesearchengine_test
set -e; for i in `seq 1 20`; do echo "Iteration $i"; ./bin/release/fileoperations_test.app/Contents/MacOS/fileoperations_test --std-seed $(date +%s); sleep 1; done
set -e; ./bin/release/filecomparator_test.app/Contents/MacOS/filecomparator_test --std-seed $(date +%s)
set -e; ./bin/release/fileoperations_gui_test.app/Contents/MacOS/fileoperations_gui_test
- name: Building tests - Linux
if: startsWith(matrix.os, 'ubuntu')
run: |
cd file-commander-core/core-tests
$QT_ROOT_DIR/bin/qmake -r CONFIG+=release
make -j$(nproc)
cd ../../
./linuxdeployqt-7-x86_64.AppImage ./bin/release/fso_test -unsupported-allow-new-glibc -bundle-non-qt-libs -extra-plugins=platforms/
./linuxdeployqt-7-x86_64.AppImage ./bin/release/fso_test_high_level -unsupported-allow-new-glibc -bundle-non-qt-libs -extra-plugins=platforms/
./linuxdeployqt-7-x86_64.AppImage ./bin/release/panel_test -unsupported-allow-new-glibc -bundle-non-qt-libs -extra-plugins=platforms/
./linuxdeployqt-7-x86_64.AppImage ./bin/release/filesearchengine_test -unsupported-allow-new-glibc -bundle-non-qt-libs -extra-plugins=platforms/
./linuxdeployqt-7-x86_64.AppImage ./bin/release/fileoperations_test -unsupported-allow-new-glibc -bundle-non-qt-libs -extra-plugins=platforms/
./linuxdeployqt-7-x86_64.AppImage ./bin/release/filecomparator_test -unsupported-allow-new-glibc -bundle-non-qt-libs -extra-plugins=platforms/
./linuxdeployqt-7-x86_64.AppImage ./bin/release/fileoperations_gui_test -unsupported-allow-new-glibc -bundle-non-qt-libs -extra-plugins=platforms/
- name: Second volume for cross-volume tests - Linux
if: startsWith(matrix.os, 'ubuntu')
run: |
set -e
# /tmp shares the root filesystem here, so a separate tmpfs mount is what makes a rename into the
# destination genuinely report EXDEV.
sudo mkdir -p /mnt/fc-second
sudo mount -t tmpfs -o size=128M tmpfs /mnt/fc-second
sudo chown "$(id -u):$(id -g)" /mnt/fc-second
echo "FILE_COMMANDER_TEST_SECOND_VOLUME=/mnt/fc-second" >> $GITHUB_ENV
- name: Running tests - Linux
if: startsWith(matrix.os, 'ubuntu')
run: |
set -e; ./bin/release/fso_test
set -e; ./bin/release/fso_test_high_level
set -e; ./bin/release/panel_test
set -e; ./bin/release/filesearchengine_test
set -e; for i in `seq 1 20`; do echo "Iteration $i"; ./bin/release/fileoperations_test --std-seed $(date +%s); sleep 1; done
set -e; ./bin/release/filecomparator_test --std-seed $(date +%s)
set -e; QT_QPA_PLATFORM=offscreen ./bin/release/fileoperations_gui_test
create-release:
needs: [build, test]
if: success() && startsWith(github.ref, 'refs/tags/')
permissions:
contents: write
deployments: write
pull-requests: read
runs-on: windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # required to access full history and tags
fetch-tags: true
- name: Download EXE
uses: actions/download-artifact@v4
with:
name: FileCommander.exe
path: .
- name: Download DMG
uses: actions/download-artifact@v4
with:
name: FileCommander.dmg
path: .
- name: Download AppImage
uses: actions/download-artifact@v4
with:
name: FileCommander.AppImage
path: .
- name: Generate changelog (commits between previous tag and this tag)
id: changelog
shell: pwsh
env:
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_REPOSITORY: ${{ github.repository }}
CURRENT_REF: ${{ github.ref }}
run: |
$ErrorActionPreference = "Stop"
# Extract current tag name (strip refs/tags/)
$currentTag = $env:CURRENT_REF -replace '^refs/tags/', ''
# Ensure tags are present
git fetch --tags --prune
# Find previous tag (newest first, excluding current tag)
$tags = git tag --sort=-creatordate
$prevTag = $tags | Where-Object { $_ -ne $currentTag } | Select-Object -First 1
if ([string]::IsNullOrEmpty($prevTag)) {
$title = "Changes up to $currentTag"
$commits = git log `
$currentTag `
--pretty=format:"- %s ([%h]($($env:GITHUB_SERVER_URL)/$($env:GITHUB_REPOSITORY)/commit/%H))"
}
else {
# Resolve the commit the previous tag points to and exclude it explicitly
$prevCommit = git rev-list -n 1 $prevTag
$commits = git log `
$currentTag `
--not $prevCommit `
--pretty=format:"- %s ([%h]($($env:GITHUB_SERVER_URL)/$($env:GITHUB_REPOSITORY)/commit/%H))"
}
if ([string]::IsNullOrWhiteSpace($commits)) {
$commits = "(no commits)"
}
# Write multiline output for softprops/action-gh-release
"body<<EOF" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
$commits | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
"EOF" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
- name: Create Release
uses: softprops/action-gh-release@v2
if: success() && startsWith(github.ref, 'refs/tags/')
with:
files: |
FileCommander.exe
FileCommander.dmg
FileCommander.AppImage
token: ${{ secrets.GITHUB_TOKEN }}
tag_name: ${{ github.ref }}
name: ${{ github.ref_name }}
body: ${{ steps.changelog.outputs.body }}