📦 Chore(custom): update publish workflow

This commit is contained in:
Kuingsmile
2026-01-16 11:03:05 +08:00
parent 529ae22fa8
commit 78ccf30737
12 changed files with 363 additions and 260 deletions

View File

@@ -41,10 +41,11 @@ body:
label: 系统信息 | System Information
options:
- Windows
- Win(arm64)
- Mac
- Mac(arm64)
- Linux
- All
- Linux(arm64)
validations:
required: true
- type: textarea

View File

@@ -41,10 +41,11 @@ body:
label: 系统信息 | System Information
options:
- Windows
- Win(arm64)
- Mac
- Mac(arm64)
- Linux
- All
- Linux(arm64)
validations:
required: true
- type: textarea
@@ -58,4 +59,4 @@ body:
attributes:
value: |
最后,喜欢 PicList 的话不妨给它点个 star~
Finally, if you like PicList, give it a star~
Finally, if you like PicList, give it a star~

View File

@@ -3,6 +3,11 @@ name: Build with architecture
on:
workflow_dispatch:
inputs:
tag_name:
description: 'Tag name to build'
required: false
default: 'preview'
type: string
publish_enabled:
description: 'Publish artifacts after build?'
required: true
@@ -34,7 +39,7 @@ on:
- ubuntu-24.04-arm-arm64-rpm
- All
permissions:
contents: read
contents: write
env:
ELECTRON_OUTPUT_PATH: ./dist_electron
@@ -154,10 +159,7 @@ jobs:
yarn global add xvfb-maybe
if [[ "${{ matrix.format }}" == "zip" || "${{ matrix.format }}" == "7z" ]]; then
echo "Target format is ${{ matrix.format }}, downloading all resources..."
yarn run prepare
else
echo "Target format is other, downloading themes only..."
yarn run prepare:themes
yarn run prepare:7za
fi
echo "Checking resources directory:"
ls -alh ./resources/theme || echo "Theme directory not found"
@@ -168,22 +170,6 @@ jobs:
echo "❌ 7za.exe does not exist"
fi
- name: Generate release notes
if: github.event.inputs.build_os == matrix.filter || github.event.inputs.build_os == 'All'
shell: bash
run: |
chmod +x ./scripts/generate-release-notes.sh
./scripts/generate-release-notes.sh
- name: Configure electron-builder.json
if: github.event.inputs.build_os == matrix.filter || github.event.inputs.build_os == 'All'
shell: bash
run: |
# Remove publish config if not publishing
if [ "${{ github.event.inputs.publish_enabled }}" == "false" ]; then
jq 'del(.publish)' electron-builder.json > tmp.json && mv tmp.json electron-builder.json
fi
- name: Build & release app
if: github.event.inputs.build_os == matrix.filter || github.event.inputs.build_os == 'All'
shell: bash
@@ -192,17 +178,12 @@ jobs:
export CSC_IDENTITY_AUTO_DISCOVERY=false
unset CSC_LINK WIN_CSC_LINK CSC_KEY_PASSWORD
fi
PUBLISH_ARG="never"
if [ "${{ github.event.inputs.publish_enabled }}" == "true" ]; then
PUBLISH_ARG="always"
fi
echo "Publishing argument: $PUBLISH_ARG"
if [[ "${{ matrix.os }}" == windows* ]]; then
yarn run build:win ${{ matrix.format}} --${{ matrix.arch }} --publish $PUBLISH_ARG
yarn run build:win ${{ matrix.format}} --${{ matrix.arch }} --publish never
elif [[ "${{ matrix.os }}" == macos* ]]; then
yarn run build:mac ${{ matrix.format}} --${{ matrix.arch }} --publish $PUBLISH_ARG
yarn run build:mac default --${{ matrix.arch }} --publish never
elif [[ "${{ matrix.os }}" == ubuntu* ]]; then
yarn run build:linux ${{ matrix.format}} --${{ matrix.arch }} --publish $PUBLISH_ARG
yarn run build:linux ${{ matrix.format}} --${{ matrix.arch }} --publish never
else
echo "Unsupported OS: ${{ matrix.os }}"
exit 1
@@ -210,11 +191,6 @@ jobs:
env:
USE_SYSTEM_FPM: ${{ matrix.os == 'ubuntu-24.04-arm' && 'true' || 'false' }}
GH_TOKEN: ${{ secrets.GH_TOKEN }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
R2_SECRET_ID: ${{ secrets.R2_SECRET_ID }}
R2_SECRET_KEY: ${{ secrets.R2_SECRET_KEY }}
R2_ACCOUNT_ID: ${{ secrets.R2_ACCOUNT_ID }}
ELECTRON_SKIP_NOTARIZATION: ${{ secrets.ELECTRON_SKIP_NOTARIZATION }}
XCODE_APP_LOADER_EMAIL: ${{ secrets.XCODE_APP_LOADER_EMAIL }}
XCODE_APP_LOADER_PASSWORD: ${{ secrets.XCODE_APP_LOADER_PASSWORD }}
@@ -239,6 +215,7 @@ jobs:
dist_electron/*.deb
dist_electron/*.rpm
dist_electron/*.snap
dist_electron/*.blockmap
retention-days: 30
if-no-files-found: 'ignore'
@@ -250,3 +227,99 @@ jobs:
path: dist_electron/**/*.yml
retention-days: 30
if-no-files-found: 'ignore'
combine-and-upload:
name: Combine and Upload Release
needs: build
runs-on: ubuntu-latest
steps:
- name: Check out git repository
uses: actions/checkout@v6
- name: Install Node.js
uses: actions/setup-node@v6
with:
node-version: "22.x"
- name: Install dependencies
shell: bash
run: |
yarn config set ignore-engines true
rm -rf node_modules && yarn install
- name: Generate Release Notes
run: |
chmod +x ./scripts/generate-release-notes.sh
./scripts/generate-release-notes.sh
- name: Download All Artifacts
uses: actions/download-artifact@v4
with:
pattern: '*-artifacts'
path: ./artifacts
- name: Download YML Artifacts
uses: actions/download-artifact@v4
with:
pattern: '*-yml'
path: ./yml-artifacts
merge-multiple: false
- name: List downloaded artifacts
run: |
echo "Downloaded artifacts structure:"
find ./yml-artifacts -type f -name "*.yml"
tree ./yml-artifacts
tree ./artifacts
- name: Combine and deduplicate yml files
run: |
node scripts/combine-yml.cjs ./yml-artifacts ./dist_electron/combined
echo "Combined YML files:"
ls -la ./dist_electron/combined/
echo "Latest combined YML content:"
cat ./dist_electron/combined/latest.yml
echo "Latest macOS combined YML content:"
cat ./dist_electron/combined/latest-mac.yml
echo "Latest linux combined YML content:"
cat ./dist_electron/combined/latest-linux.yml
echo "Latest linux ARM64 combined YML content:"
cat ./dist_electron/combined/latest-linux-arm64.yml
- name: Publish GitHub Dev Release
uses: softprops/action-gh-release@v2
continue-on-error: true
with:
token: ${{ secrets.GH_TOKEN }}
tag_name: ${{ github.event.inputs.tag_name }}
draft: true
prerelease: ${{ github.event.inputs.publish_enabled == 'false' || github.event.inputs.tag_name == 'preview' }}
body_path: ./release-notes.md
name: ${{ github.event.inputs.tag_name }}
files: |
!artifacts/**/*-unpacked/**
artifacts/**/*.exe
artifacts/**/*.dmg
artifacts/**/*.zip
artifacts/**/*.7z
artifacts/**/*.AppImage
artifacts/**/*.deb
artifacts/**/*.snap
artifacts/**/*.rpm
./dist_electron/combined/*.yml
artifacts/**/*.tar.gz
- name: Upload to S3
run: |
if [ "${{ github.event.inputs.publish_enabled }}" == "false" ]; then
echo "Publishing is disabled. Skipping upload to S3."
node scripts/upload-to-s3.js ./artifacts ./dist_electron/combined
exit 0
fi
node scripts/upload-to-s3.js ./artifacts ./dist_electron/combined false
env:
R2_SECRET_ID: ${{ secrets.R2_SECRET_ID }}
R2_SECRET_KEY: ${{ secrets.R2_SECRET_KEY }}
R2_ACCOUNT_ID: ${{ secrets.R2_ACCOUNT_ID }}

View File

@@ -14,22 +14,6 @@
"resources/**"
],
"files": ["out/**/*", "resources/**", "package.json", "!**/node_modules/typescript{,/**}"],
"publish": [
{
"provider": "s3",
"bucket": "piclist-dl",
"region": "auto",
"acl": "private",
"endpoint": "https://7ab4ed5cb1f4052a13d3b573876ecf33.r2.cloudflarestorage.com",
"path": "/latest"
},
{
"provider": "github",
"owner": "Kuingsmile",
"repo": "PicList",
"releaseType": "draft"
}
],
"dmg": {
"sign": false,
"contents": [

View File

@@ -35,12 +35,9 @@
"postinstall": "electron-builder install-app-deps",
"postuninstall": "electron-builder install-app-deps",
"prebuild": "electron-vite build",
"prepare": "node ./scripts/prepare.js --all",
"prepare:7zaip": "node ./scripts/prepare.js --type=7zip",
"prepare:themes": "node ./scripts/prepare.js --type=themes",
"prepare": "node ./scripts/prepare.js --type=themes",
"prepare:7za": "node ./scripts/prepare.js --type=7zip",
"preview": "electron-vite preview",
"release": "electron-vite build && electron-builder",
"sha256": "node ./scripts/gen-sha256.js",
"test": "vitest",
"winget": "node ./scripts/auto-winget.js"
},

View File

@@ -99,20 +99,20 @@ function main() {
fs.mkdirSync(outputDir, { recursive: true })
}
const windowsX64Ymls = findYmlInFolder(distPath, 'windows-x64-yml', 'latest.yml')
const windowsArm64Ymls = findYmlInFolder(distPath, 'windows-arm64-yml', 'latest.yml')
const macX64Ymls = findYmlInFolder(distPath, 'macos-x64-yml', 'latest-mac.yml')
const macArm64Ymls = findYmlInFolder(distPath, 'macos-arm64-yml', 'latest-mac.yml')
const linuxX64Ymls = findYmlInFolder(distPath, 'linux-x64-yml', 'latest-linux.yml')
const linuxArm64Ymls = findYmlInFolder(distPath, 'linux-arm64-yml', 'latest-linux-arm64.yml')
console.log('\nFound yml files:')
console.log(`Windows x64: ${windowsX64Ymls.map(f => path.basename(path.dirname(f))).join(', ')}`)
console.log(`Windows ARM64: ${windowsArm64Ymls.map(f => path.basename(path.dirname(f))).join(', ')}`)
console.log(`macOS x64: ${macX64Ymls.map(f => path.basename(path.dirname(f))).join(', ')}`)
console.log(`macOS ARM64: ${macArm64Ymls.map(f => path.basename(path.dirname(f))).join(', ')}`)
console.log(`Linux x64: ${linuxX64Ymls.map(f => path.basename(path.dirname(f))).join(', ')}`)
console.log(`Linux ARM64: ${linuxArm64Ymls.map(f => path.basename(path.dirname(f))).join(', ')}`)
const windowsX64Ymls = findYmlInFolder(distPath, 'windows-latest-x64-nsis-yml', 'latest.yml')
const windowsArm64Ymls = findYmlInFolder(distPath, 'windows-11-arm-arm64-nsis-yml', 'latest.yml')
const macX64Ymls = findYmlInFolder(distPath, 'macos-15-intel-x64-dmg-yml', 'latest-mac.yml')
const macArm64Ymls = findYmlInFolder(distPath, 'macos-latest-arm64-dmg-yml', 'latest-mac.yml')
const linuxX64AppImageYmls = findYmlInFolder(distPath, 'ubuntu-latest-x64-AppImage-yml', 'latest-linux.yml')
const linuxArm64AppImageYmls = findYmlInFolder(
distPath,
'ubuntu-24.04-arm-arm64-AppImage-yml',
'latest-linux-arm64.yml',
)
const linuxX64DebYmls = findYmlInFolder(distPath, 'ubuntu-latest-x64-deb-yml', 'latest-linux.yml')
const linuxArm64DebYmls = findYmlInFolder(distPath, 'ubuntu-24.04-arm-arm64-deb-yml', 'latest-linux-arm64.yml')
const linuxX64RpmYmls = findYmlInFolder(distPath, 'ubuntu-latest-x64-rpm-yml', 'latest-linux.yml')
const linuxArm64RpmYmls = findYmlInFolder(distPath, 'ubuntu-24.04-arm-arm64-rpm-yml', 'latest-linux-arm64.yml')
const windowsYmls = [...windowsX64Ymls, ...windowsArm64Ymls]
if (windowsYmls.length > 0) {
@@ -129,17 +129,20 @@ function main() {
} else {
console.log('\nNo macOS yml files found to combine')
}
const linuxX64Ymls = [...linuxX64AppImageYmls, ...linuxX64DebYmls, ...linuxX64RpmYmls]
if (linuxX64Ymls.length > 0) {
console.log('\nProcessing Linux x64 yml file (deduplicate only)...')
processSingleYmlFile(linuxX64Ymls[0], path.join(outputDir, 'latest-linux.yml'))
console.log(`\nCombining ${linuxX64Ymls.length} Linux x64 yml files...`)
combineYmlFiles(linuxX64Ymls, path.join(outputDir, 'latest-linux.yml'))
} else {
console.log('\nNo Linux x64 yml files found')
console.log('\nNo Linux x64 yml files found to combine')
}
const linuxArm64Ymls = [...linuxArm64AppImageYmls, ...linuxArm64DebYmls, ...linuxArm64RpmYmls]
if (linuxArm64Ymls.length > 0) {
console.log('\nProcessing Linux ARM64 yml file (deduplicate only)...')
processSingleYmlFile(linuxArm64Ymls[0], path.join(outputDir, 'latest-linux-arm64.yml'))
console.log(`\nCombining ${linuxArm64Ymls.length} Linux arm64 yml files...`)
combineYmlFiles(linuxArm64Ymls, path.join(outputDir, 'latest-linux-arm64.yml'))
} else {
console.log('\nNo Linux ARM64 yml files found')
console.log('\nNo Linux arm64 yml files found to combine')
}
console.log('\nYML combination and deduplication complete!')

View File

@@ -1,4 +1,8 @@
// different platform has different format
import pkg from '../package.json' with { type: 'json' }
import path from 'path'
const version = pkg.version
// macos
const darwin = [
@@ -7,12 +11,28 @@ const darwin = [
ext: '.dmg',
arch: '-arm64',
'version-file': 'latest-mac.yml',
path: 'macos-latest-arm64-dmg-artifacts',
},
{
appNameWithPrefix: 'PicList-',
ext: '.dmg',
arch: '-x64',
'version-file': 'latest-mac.yml',
path: 'macos-15-intel-x64-dmg-artifacts',
},
{
appNameWithPrefix: 'PicList-',
ext: '.zip',
arch: '-arm64',
'version-file': 'latest-mac.yml',
path: 'macos-latest-arm64-dmg-artifacts',
},
{
appNameWithPrefix: 'PicList-',
ext: '.zip',
arch: '-x64',
'version-file': 'latest-mac.yml',
path: 'macos-15-intel-x64-dmg-artifacts',
},
]
@@ -22,61 +42,106 @@ const linux = [
ext: '.AppImage',
arch: '-x86_64',
'version-file': 'latest-linux.yml',
path: 'ubuntu-latest-x64-AppImage-artifacts',
},
{
appNameWithPrefix: 'PicList-',
ext: '.AppImage',
arch: '-arm64',
'version-file': 'latest-linux.yml',
},
{
appNameWithPrefix: 'PicList-',
ext: '.snap',
arch: '-amd64',
'version-file': 'latest-linux.yml',
'version-file': 'latest-linux-arm64.yml',
path: 'ubuntu-24.04-arm-arm64-AppImage-artifacts',
},
{
appNameWithPrefix: 'PicList-',
ext: '.deb',
arch: '-amd64',
'version-file': 'latest-linux.yml',
path: 'ubuntu-latest-x64-deb-artifacts',
},
{
appNameWithPrefix: 'PicList-',
ext: '.deb',
arch: '-arm64',
'version-file': 'latest-linux-arm64.yml',
path: 'ubuntu-24.04-arm-arm64-deb-artifacts',
},
{
appNameWithPrefix: 'PicList-',
ext: '.rpm',
arch: '-x86_64',
'version-file': 'latest-linux.yml',
path: 'ubuntu-latest-x64-rpm-artifacts',
},
{
appNameWithPrefix: 'PicList-',
ext: '.rpm',
arch: '-aarch64',
'version-file': 'latest-linux-arm64.yml',
path: 'ubuntu-24.04-arm-arm64-rpm-artifacts',
},
{
appNameWithPrefix: 'PicList-',
ext: '.snap',
arch: '-amd64',
path: 'ubuntu-latest-x64-snap-artifacts',
},
]
// windows
const win32 = [
{
appNameWithPrefix: 'PicList-Setup-',
ext: '.exe',
arch: '-ia32',
'version-file': 'latest.yml',
},
{
appNameWithPrefix: 'PicList-Setup-',
ext: '.exe',
arch: '-x64',
'version-file': 'latest.yml',
},
{
appNameWithPrefix: 'PicList-Setup-',
ext: '.exe',
arch: '', // 32 & 64
'version-file': 'latest.yml',
path: 'windows-latest-x64-nsis-artifacts',
},
{
appNameWithPrefix: 'PicList-Setup-',
ext: '.exe',
arch: '-arm64',
'version-file': 'latest.yml',
path: 'windows-11-arm-arm64-nsis-artifacts',
},
{
appNameWithPrefix: 'PicList-Setup-',
ext: '.zip',
arch: '-x64-portable',
path: 'windows-latest-x64-zip-artifacts',
},
{
appNameWithPrefix: 'PicList-Setup-',
ext: '.zip',
arch: '-arm64-portable',
path: 'windows-11-arm-arm64-zip-artifacts',
},
{
appNameWithPrefix: 'PicList-Setup-',
ext: '.7z',
arch: '-x64-portable',
path: 'windows-latest-x64-7z-artifacts',
},
{
appNameWithPrefix: 'PicList-Setup-',
ext: '.7z',
arch: '-arm64-portable',
path: 'windows-11-arm-arm64-7z-artifacts',
},
]
export const generateFileName = (platformConfig, version) => {
return `${platformConfig.appNameWithPrefix}${version}${platformConfig.arch}${platformConfig.ext}`
}
export const fileList = [...darwin, ...linux, ...win32].map(platformConfig => {
const fileName = generateFileName(platformConfig, version)
return {
name: fileName,
path: path.join(platformConfig.path, fileName),
blockMapPath: path.join(platformConfig.path, `${fileName}.blockmap`),
}
})
export default {
darwin,
linux,

View File

@@ -1,137 +0,0 @@
import crypto from 'node:crypto'
import path from 'node:path'
import axios from 'axios'
import fs from 'fs-extra'
import pkg from '../package.json' with { type: 'json' }
const version = process.argv[2] || pkg.version
// Configuration
const BASE_URL = `https://github.com/Kuingsmile/PicList/releases/download/v${version}`
const DOWNLOAD_DIR = path.join('R:\\Downloads')
// File information
const files = [
{
name: 'PicList-x64.dmg',
url: `${BASE_URL}/PicList-${version}-x64.dmg`,
},
{
name: 'PicList-arm64.dmg',
url: `${BASE_URL}/PicList-${version}-arm64.dmg`,
},
]
/**
* Create progress bar string
*/
function getProgressBar(current, total, length = 20) {
const progress = Math.round((current / total) * length)
const percentage = Math.round((current / total) * 100)
const bar = '█'.repeat(progress) + '░'.repeat(length - progress)
return `[${bar}] ${percentage}% (${formatBytes(current)}/${formatBytes(total)})`
}
/**
* Format bytes to human-readable format
*/
function formatBytes(bytes, decimals = 2) {
if (bytes === 0) return '0 Bytes'
const k = 1024
const sizes = ['Bytes', 'KB', 'MB', 'GB']
const i = Math.floor(Math.log(bytes) / Math.log(k))
return parseFloat((bytes / Math.pow(k, i)).toFixed(decimals)) + ' ' + sizes[i]
}
/**
* Download file and calculate SHA256 hash
*/
async function downloadAndHash(fileInfo) {
const { url, name } = fileInfo
const filePath = path.join(DOWNLOAD_DIR, name)
console.log(`\nStarting download: ${name} from ${url}`)
try {
const response = await axios({
method: 'get',
url,
responseType: 'stream',
})
const writer = fs.createWriteStream(filePath)
response.data.pipe(writer)
const hash = crypto.createHash('sha256')
const progressTotal = parseInt(response.headers['content-length'], 10)
let progressCurrent = 0
response.data.on('data', chunk => {
hash.update(chunk)
progressCurrent += chunk.length
process.stdout.write(`\r${name}: ${getProgressBar(progressCurrent, progressTotal)}`)
})
await new Promise((resolve, reject) => {
writer.on('finish', resolve)
writer.on('error', reject)
response.data.on('error', reject)
})
const hashValue = hash.digest('hex')
console.log(`\n${name} SHA256: ${hashValue}`)
// Write hash to a file for reference
await fs.writeFile(`${filePath}.sha256`, hashValue)
console.log(`Hash saved to ${filePath}.sha256`)
if (process.argv.includes('--keep-files')) {
console.log(`Keeping file: ${filePath}`)
} else {
await fs.remove(filePath)
console.log(`Deleted: ${filePath}`)
}
return { name, hash: hashValue }
} catch (err) {
console.error(`\n❌ Error processing ${name}: ${err.message}`)
throw err
}
}
/**
* Main function
*/
async function main() {
console.log(`Generating SHA256 hashes for PicList v${version}`)
console.log(`Download directory: ${DOWNLOAD_DIR}`)
try {
// Ensure download directory exists
await fs.ensureDir(DOWNLOAD_DIR)
// Start all downloads concurrently
const results = await Promise.allSettled(files.map(downloadAndHash))
// Output summary
console.log('\n===== SUMMARY =====')
results.forEach((result, index) => {
const fileName = files[index].name
if (result.status === 'fulfilled') {
console.log(`${fileName}: ${result.value.hash}`)
} else {
console.log(`${fileName}: Failed - ${result.reason.message}`)
}
})
// Check if all downloads were successful
if (results.some(r => r.status === 'rejected')) {
process.exit(1)
}
} catch (err) {
console.error(`\nCritical error: ${err.message}`)
process.exit(1)
}
}
main()

View File

@@ -36,6 +36,7 @@ cat > "$OUTPUT_FILE" << EOF
### macOS
- DMG:
[**ARM64 (M1-M6)**](https://github.com/Kuingsmile/PicList/releases/download/v${VERSION}/PicList-${VERSION}-arm64.dmg) | [**Intel**](https://github.com/Kuingsmile/PicList/releases/download/v${VERSION}/PicList-${VERSION}-x64.dmg)
### Linux
@@ -44,6 +45,8 @@ cat > "$OUTPUT_FILE" << EOF
[**x64**](https://github.com/Kuingsmile/PicList/releases/download/v${VERSION}/PicList-${VERSION}-x86_64.AppImage) | [**ARM64**](https://github.com/Kuingsmile/PicList/releases/download/v${VERSION}/PicList-${VERSION}-arm64.AppImage)
- deb:
[**x64**](https://github.com/Kuingsmile/PicList/releases/download/v${VERSION}/Piclist-${VERSION}-amd64.deb) | [**ARM64**](https://github.com/Kuingsmile/PicList/releases/download/v${VERSION}/Piclist-${VERSION}-arm64.deb)
- rpm:
[**x64**](https://github.com/Kuingsmile/PicList/releases/download/v${VERSION}/Piclist-${VERSION}-x86_64.rpm) | [**ARM64**](https://github.com/Kuingsmile/PicList/releases/download/v${VERSION}/Piclist-${VERSION}-aarch64.rpm)
- snap:
[**x64**](https://github.com/Kuingsmile/PicList/releases/download/v${VERSION}/Piclist-${VERSION}-amd64.snap)

View File

@@ -1,6 +1,7 @@
import pkg from '../package.json' with { type: 'json' }
const version = pkg.version
// TODO: use the same name format
const generateURL = (platform, ext, prefix = 'PicList-') => {
return `https://release.piclist.cn/latest/${prefix}${version}${platform}${ext}`
}
@@ -9,18 +10,37 @@ const template = `
### 加速下载地址
#### MacOS
[PicList-${version}-arm64.dmg](${generateURL('-arm64', '.dmg', 'PicList-')})
[PicList-${version}-x64.dmg](${generateURL('-x64', '.dmg', 'PicList-')})
[PicList-${version}-universal.dmg](${generateURL('-universal', '.dmg', 'PicList-')})
- DMG:
[PicList-${version}-x64.dmg](${generateURL('-x64', '.dmg', 'PicList-')}) | [PicList-${version}-arm64.dmg](${generateURL('-arm64', '.dmg', 'PicList-')})
#### Windows
[PicList-Setup-${version}-ia32.exe](${generateURL('-ia32', '.exe', 'PicList-Setup-')})
[PicList-Setup-${version}-x64.exe](${generateURL('-x64', '.exe', 'PicList-Setup-')})
[PicList-Setup-${version}-arm64.exe](${generateURL('-arm64', '.exe', 'PicList-Setup-')})
[PicList-Setup-${version}.exe](${generateURL('', '.exe', 'PicList-Setup-')})
- Installer:
[PicList-Setup-${version}-x64.exe](${generateURL('-x64', '.exe', 'PicList-Setup-')}) | [PicList-Setup-${version}-arm64.exe](${generateURL('-arm64', '.exe', 'PicList-Setup-')})
- Portable:
[PicList-Setup-${version}-x64-portable.zip](${generateURL('-x64-portable', '.zip', 'PicList-Setup-')}) | [PicList-Setup-${version}-arm64-portable.zip](${generateURL('-arm64-portable', '.zip', 'PicList-Setup-')}) | [PicList-Setup-${version}-x64-portable.7z](${generateURL('-x64-portable', '.7z', 'PicList-Setup-')}) | [PicList-Setup-${version}-arm64-portable.7z](${generateURL('-arm64-portable', '.7z', 'PicList-Setup-')})
#### Linux
[PicList-${version}.AppImage](${generateURL('', '.AppImage', 'PicList-')})
[piclist_${version}_amd64.snap](${generateURL('_amd64', '.snap', 'piclist_')})`
- AppImage:
[PicList-${version}-x86_64.AppImage](${generateURL('-x86_64', '.AppImage', 'PicList-')}) | [PicList-${version}-arm64.AppImage](${generateURL('-arm64', '.AppImage', 'PicList-')})
- Deb:
[PicList-${version}-amd64.deb](${generateURL('-amd64', '.deb', 'PicList-')}) | [PicList-${version}-arm64.deb](${generateURL('-arm64', '.deb', 'PicList-')})
- Rpm:
[PicList-${version}-x86_64.rpm](${generateURL('-x86_64', '.rpm', 'PicList-')}) | [PicList-${version}-aarch64.rpm](${generateURL('-aarch64', '.rpm', 'PicList-')})
- Snap:
[PicList-${version}-amd64.snap](${generateURL('-amd64', '.snap', 'PicList-')})
`
console.log(template)

99
scripts/upload-to-s3.js Normal file
View File

@@ -0,0 +1,99 @@
import dotenv from 'dotenv'
import { fileList } from './config.js'
import fs from 'fs-extra'
import mime from 'mime'
import path from 'node:path'
import { S3Client } from '@aws-sdk/client-s3'
import { Upload } from '@aws-sdk/lib-storage'
dotenv.config()
const bucket = 'piclist-dl'
const folder = `latest/`
const R2_SECRET_ID = process.env.R2_SECRET_ID
const R2_SECRET_KEY = process.env.R2_SECRET_KEY
const R2_ACCOUNT_ID = process.env.R2_ACCOUNT_ID
console.log('fileList to upload:', JSON.stringify(fileList, null, 2))
const ymlFileList = ['latest-mac.yml', 'latest.yml', 'latest-linux.yml', 'latest-linux-arm64.yml']
const args = process.argv.slice(2)
const exePath = args[0] || './artifacts'
const ymlPath = args[1] || './dist_electron/combined'
const idDev = args[2] || true
const S3Options = {
credentials: {
accessKeyId: R2_SECRET_ID,
secretAccessKey: R2_SECRET_KEY,
},
endpoint: `https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com`,
sslEnabled: true,
region: 'auto',
}
const uploadFile = async filePath => {
try {
console.log('[INFO]: uploading file:', filePath)
const client = new S3Client(S3Options)
if (fs.existsSync(filePath)) {
const uploadDistToS3 = new Upload({
client,
params: {
Bucket: bucket,
Key: `${folder}${path.basename(filePath)}`,
Body: fs.createReadStream(filePath),
ContentType: path.basename(filePath).endsWith('.yml')
? mime.getType(path.basename(filePath))
: 'application/octet-stream',
},
})
uploadDistToS3.on('httpUploadProgress', progress => {
console.log(`[INFO]: ${path.basename(filePath)} - ${progress.loaded}/${progress.total}`)
})
if (idDev) {
console.log('[DEV]: upload params:', {
Bucket: bucket,
Key: `${folder}${path.basename(filePath)}`,
Body: '<<stream>>',
ContentType: path.basename(filePath).endsWith('.yml')
? mime.getType(path.basename(filePath))
: 'application/octet-stream',
})
} else {
await uploadDistToS3.done()
}
} else {
console.warn('[Warn] File not found:', filePath)
}
} catch (e) {
console.error('[ERROR]: upload failed:', e)
}
}
const upload = async () => {
console.log('[INFO]: Starting upload to S3...')
console.log('[INFO]: upload exePath:', exePath)
for (const file of fileList) {
const installerPath = path.join(exePath, file.path)
await uploadFile(installerPath)
}
console.log('[INFO]: upload blockmap files...')
for (const file of fileList) {
const installerPath = path.join(exePath, file.blockMapPath)
await uploadFile(installerPath)
}
for (const ymlFile of ymlFileList) {
const ymlFilePath = path.join(ymlPath, ymlFile)
await uploadFile(ymlFilePath)
}
}
const main = async () => {
await upload()
}
main()

View File

@@ -116,13 +116,9 @@ export async function setupAutoUpdater() {
updater.autoUpdater.forceDevUpdateConfig = true
updater.autoUpdater.autoDownload = false
updater.autoUpdater.on('update-available', updateAvailableHandler)
updater.autoUpdater.on('download-progress', progressHandler)
updater.autoUpdater.on('update-downloaded', downloadedHandler)
updater.autoUpdater.on('error', err => {
logger.error(err)
})
@@ -130,18 +126,16 @@ export async function setupAutoUpdater() {
}
export async function checkUpdateAndNotify(): Promise<void> {
if (isPortable()) {
const url = 'https://release.piclist.cn/latest/latest.yml'
const res = await axios.get(url, {
headers: { 'Content-Type': 'application/octet-stream' },
responseType: 'text',
})
const latest = yaml.parseDocument(res.data).toJSON() as unknown as updater.UpdateInfo
const currentVersion = pkg.version
if (latest.version !== currentVersion) {
newVersion = latest.version
updateAvailableHandler(latest)
}
const url = 'https://release.piclist.cn/latest/latest.yml'
const res = await axios.get(url, {
headers: { 'Content-Type': 'application/octet-stream' },
responseType: 'text',
})
const latest = yaml.parseDocument(res.data).toJSON() as unknown as updater.UpdateInfo
const currentVersion = pkg.version
if (latest.version !== currentVersion) {
newVersion = latest.version
updateAvailableHandler(latest)
}
}