From 21eab03684865f56bb38fb983303ed5ac8a36948 Mon Sep 17 00:00:00 2001 From: kuaifan Date: Thu, 14 Nov 2024 14:49:14 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E5=AE=A2=E6=88=B7?= =?UTF-8?q?=E7=AB=AF=E5=8D=87=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/publish-android.yml | 63 ------ .github/workflows/publish-desktop-mac.yml | 35 ---- .github/workflows/publish-desktop-win.yml | 31 --- .github/workflows/publish.yml | 244 ++++++++++++++++++++++ app/Http/Controllers/IndexController.php | 49 +++-- app/Module/Base.php | 29 ++- cmd | 1 + electron/build.js | 14 +- package.json | 2 +- 9 files changed, 305 insertions(+), 163 deletions(-) delete mode 100644 .github/workflows/publish-android.yml delete mode 100644 .github/workflows/publish-desktop-mac.yml delete mode 100644 .github/workflows/publish-desktop-win.yml create mode 100644 .github/workflows/publish.yml diff --git a/.github/workflows/publish-android.yml b/.github/workflows/publish-android.yml deleted file mode 100644 index 4b401ae82..000000000 --- a/.github/workflows/publish-android.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: Publish Android - -on: - push: - tags: - - 'v*' - -jobs: - Build: - name: Build Android - runs-on: ubuntu-latest - environment: build - - if: startsWith(github.event.ref, 'refs/tags/v') - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Use Node.js 20.x - uses: actions/setup-node@v1 - with: - node-version: 20.x - - - name: Build Js - uses: nick-fields/retry@v2 - with: - timeout_minutes: 10 - max_attempts: 5 - command: | - git submodule init - git submodule update --remote "resources/mobile" - ./cmd appbuild publish - - - name: Set up JDK 11 - uses: actions/setup-java@v3 - with: - distribution: 'zulu' - java-version: '11' - - - name: Build Android - uses: nick-fields/retry@v2 - with: - timeout_minutes: 60 - max_attempts: 10 - command: | - cd resources/mobile/platforms/android/eeuiApp - chmod +x ./gradlew - ./gradlew assembleRelease --quiet - - - name: Upload File - env: - DP_KEY: ${{ secrets.DP_KEY }} - run: | - node ./electron/build.js android-upload - - - name: Release - uses: softprops/action-gh-release@v2 - env: - GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} - GITHUB_REPOSITORY: ${{ github.repository }} - with: - files: | - resources/mobile/platforms/android/eeuiApp/app/build/outputs/apk/release/*.apk diff --git a/.github/workflows/publish-desktop-mac.yml b/.github/workflows/publish-desktop-mac.yml deleted file mode 100644 index 7692ce537..000000000 --- a/.github/workflows/publish-desktop-mac.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Publish Mac - -on: - push: - tags: - - 'v*' - -jobs: - Build: - name: Build Mac - runs-on: macos-12 - environment: build - - if: startsWith(github.event.ref, 'refs/tags/v') - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Use Node.js 20.x - uses: actions/setup-node@v1 - with: - node-version: 20.x - - - name: Build - env: - APPLEID: ${{ secrets.APPLEID }} - APPLEIDPASS: ${{ secrets.APPLEIDPASS }} - CSC_LINK: ${{ secrets.CSC_LINK }} - CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} - DP_KEY: ${{ secrets.DP_KEY }} - GH_TOKEN: ${{ secrets.GH_TOKEN }} - GH_REPOSITORY: ${{ github.repository }} - run: | - ./cmd electron mac - diff --git a/.github/workflows/publish-desktop-win.yml b/.github/workflows/publish-desktop-win.yml deleted file mode 100644 index 3b9deb151..000000000 --- a/.github/workflows/publish-desktop-win.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: Publish Win - -on: - push: - tags: - - 'v*' - -jobs: - Build: - name: Build Windows - runs-on: windows-latest - environment: build - - if: startsWith(github.event.ref, 'refs/tags/v') - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Use Node.js 20.x - uses: actions/setup-node@v1 - with: - node-version: 20.x - - - name: Build - env: - DP_KEY: ${{ secrets.DP_KEY }} - GH_TOKEN: ${{ secrets.GH_TOKEN }} - GH_REPOSITORY: ${{ github.repository }} - shell: bash - run: | - ./cmd electron win diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 000000000..d5e52b330 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,244 @@ +name: "Publish" + +on: + push: + branches: + - "pro" + +jobs: + check-version: + permissions: + contents: read + runs-on: ubuntu-latest + outputs: + should_release: ${{ steps.check-tag.outputs.should_release }} + version: ${{ steps.get-version.outputs.version }} + + steps: + - uses: actions/checkout@v4 + + - name: Get version from package.json + id: get-version + run: | + VERSION=$(node -p "require('./package.json').version") + echo "version=$VERSION" >> $GITHUB_OUTPUT + + - name: Check if tag exists + id: check-tag + run: | + VERSION=${{ steps.get-version.outputs.version }} + if git ls-remote --tags origin | grep -q "refs/tags/v${VERSION}$"; then + echo "This version v${VERSION} has been released" + echo "should_release=false" >> $GITHUB_OUTPUT + else + echo "Version v${VERSION} has not been released, continue building" + echo "should_release=true" >> $GITHUB_OUTPUT + fi + + create-release: + needs: check-version + if: needs.check-version.outputs.should_release == 'true' + permissions: + contents: write + runs-on: ubuntu-latest + outputs: + release_id: ${{ steps.create-release.outputs.result }} + + steps: + - uses: actions/checkout@v4 + + - name: create release + id: create-release + uses: actions/github-script@v7 + with: + script: | + // 获取最新的 tag + const { data: tags } = await github.rest.repos.listTags({ + owner: context.repo.owner, + repo: context.repo.repo, + per_page: 1 + }); + + // 获取提交日志 + let changelog = ''; + if (tags.length > 0) { + const { data: commits } = await github.rest.repos.compareCommits({ + owner: context.repo.owner, + repo: context.repo.repo, + base: tags[0].name, + head: 'HEAD' + }); + + // 按类型分组提交 + const groups = { + 'feat:': { title: '## Features', commits: [] }, + 'fix:': { title: '## Bug Fixes', commits: [] }, + 'perf:': { title: '## Performance Improvements', commits: [] } + }; + + // 分类收集提交 + commits.commits.forEach(commit => { + const message = commit.commit.message.split('\n')[0].trim(); + for (const [prefix, group] of Object.entries(groups)) { + if (message.startsWith(prefix)) { + // 移除前缀后添加到对应分组 + const cleanMessage = message.slice(prefix.length).trim(); + group.commits.push(`- ${cleanMessage}`); + break; + } + } + }); + + // 生成更新日志 + const sections = []; + for (const group of Object.values(groups)) { + if (group.commits.length > 0) { + sections.push(`${group.title}\n\n${group.commits.join('\n')}`); + } + } + + if (sections.length > 0) { + changelog = '# Changelog\n\n' + sections.join('\n\n'); + } + } + + // 创建 release + const { data } = await github.rest.repos.createRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + tag_name: `v${{ needs.check-version.outputs.version }}`, + name: `${{ needs.check-version.outputs.version }}`, + body: changelog || 'No significant changes in this release.', + draft: true, + prerelease: false + }) + return data.id + + build-client: + needs: [ check-version, create-release ] + if: needs.check-version.outputs.should_release == 'true' + permissions: + contents: write + strategy: + fail-fast: false + matrix: + include: + - platform: "macos-latest" + build_type: "mac" + args: "--target aarch64-apple-darwin" + - platform: "macos-latest" + build_type: "mac" + args: "--target x86_64-apple-darwin" + - platform: "ubuntu-latest" + build_type: "android" + args: "" + - platform: "windows-latest" + build_type: "windows" + args: "" + + runs-on: ${{ matrix.platform }} + environment: build + + steps: + - uses: actions/checkout@v4 + + - name: Use Node.js 20.x + uses: actions/setup-node@v1 + with: + node-version: 20.x + + # Android 构建步骤 + - name: Build Js for Android + if: matrix.build_type == 'android' + uses: nick-fields/retry@v2 + with: + timeout_minutes: 10 + max_attempts: 5 + command: | + git submodule init + git submodule update --remote "resources/mobile" + ./cmd appbuild publish + + - name: Setup JDK 11 for Android + if: matrix.build_type == 'android' + uses: actions/setup-java@v3 + with: + distribution: "zulu" + java-version: "11" + + - name: Build Android App + if: matrix.build_type == 'android' + uses: nick-fields/retry@v2 + with: + timeout_minutes: 60 + max_attempts: 10 + command: | + cd resources/mobile/platforms/android/eeuiApp + chmod +x ./gradlew + ./gradlew assembleRelease --quiet + + - name: Upload Android File + if: matrix.build_type == 'android' + env: + DP_KEY: ${{ secrets.DP_KEY }} + run: | + node ./electron/build.js android-upload + + # Mac 构建步骤 + - name: Build Mac App + if: matrix.build_type == 'mac' + env: + APPLEID: ${{ secrets.APPLEID }} + APPLEIDPASS: ${{ secrets.APPLEIDPASS }} + CSC_LINK: ${{ secrets.CSC_LINK }} + CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} + DP_KEY: ${{ secrets.DP_KEY }} + GH_TOKEN: ${{ secrets.GH_TOKEN }} + GH_REPOSITORY: ${{ github.repository }} + run: | + ./cmd electron mac + + # Windows 构建步骤 + - name: Build Windows App + if: matrix.build_type == 'windows' + env: + DP_KEY: ${{ secrets.DP_KEY }} + GH_TOKEN: ${{ secrets.GH_TOKEN }} + GH_REPOSITORY: ${{ github.repository }} + shell: bash + run: | + ./cmd electron win + + # 上传Android构建产物 + - name: Upload Android Release Assets + env: + GH_TOKEN: ${{ secrets.GH_TOKEN }} + if: matrix.build_type == 'android' + uses: softprops/action-gh-release@v2 + with: + tag_name: v${{ needs.check-version.outputs.version }} + files: | + resources/mobile/platforms/android/eeuiApp/app/build/outputs/apk/release/*.apk + + # publish-release: + # needs: [check-version, create-release, builds] + # if: needs.check-version.outputs.should_release == 'true' + # permissions: + # contents: write + # runs-on: ubuntu-latest + + # steps: + # - name: publish release + # id: publish-release + # uses: actions/github-script@v7 + # env: + # release_id: ${{ needs.create-release.outputs.release_id }} + # with: + # script: | + # github.rest.repos.updateRelease({ + # owner: context.repo.owner, + # repo: context.repo.repo, + # release_id: process.env.release_id, + # draft: false, + # prerelease: false + # }) diff --git a/app/Http/Controllers/IndexController.php b/app/Http/Controllers/IndexController.php index 1c72b50f9..a45fbd21c 100755 --- a/app/Http/Controllers/IndexController.php +++ b/app/Http/Controllers/IndexController.php @@ -126,7 +126,7 @@ class IndexController extends InvokeController // 其他 'bot', 'robot', 'auto', 'anonymous', 'guest', 'default', 'new', 'old' ]; - $filterWords = array_map(function($word) { + $filterWords = array_map(function ($word) { return preg_quote($word, '/'); }, $filterWords); $name = preg_replace('/' . implode('|', $filterWords) . '/iu', '', $name) ?: $name; @@ -157,7 +157,7 @@ class IndexController extends InvokeController '\x{1F900}-\x{1F9FF}', '\x{1F600}-\x{1F64F}' ]; - $filterSymbols = array_map(function($symbol) { + $filterSymbols = array_map(function ($symbol) { return preg_quote($symbol, '/'); }, $filterSymbols); $name = preg_replace('/[' . implode('', $filterSymbols) . ']/u', '', $name) ?: $name; @@ -171,7 +171,7 @@ class IndexController extends InvokeController if (empty($color)) { $color = '#ffffff'; $cacheKey = "avatarBackgroundColor::" . md5($name); - $background = Cache::rememberForever($cacheKey, function() { + $background = Cache::rememberForever($cacheKey, function () { return RandomColor::one(['luminosity' => 'dark']); }); } @@ -192,7 +192,7 @@ class IndexController extends InvokeController 'shape' => 'square', 'width' => $size, 'height' => $size, - 'chars' => 2, + 'chars' => 2, 'fontSize' => $size / 2.9, 'uppercase' => true, 'fonts' => [resource_path('assets/statics/fonts/Source_Han_Sans_SC_Regular.otf')], @@ -264,7 +264,6 @@ class IndexController extends InvokeController public function desktop__publish($name = '') { $publishVersion = Request::header('publish-version'); - $fileNum = Request::get('file_num', 1); $latestFile = public_path("uploads/desktop/latest"); $latestVersion = file_exists($latestFile) ? trim(file_get_contents($latestFile)) : "0.0.1"; if (strtolower($name) === 'latest') { @@ -272,27 +271,29 @@ class IndexController extends InvokeController } // 上传 if (preg_match("/^\d+\.\d+\.\d+$/", $publishVersion)) { - $uploadSuccessFileNum = (int)Cache::get($publishVersion, 0); + // 判断密钥 $publishKey = Request::header('publish-key'); if ($publishKey !== env('APP_KEY')) { return Base::retError("key error"); } + // 判断版本 if (version_compare($publishVersion, $latestVersion) > -1) { // 限制上传版本必须 ≥ 当前版本 - $publishPath = "uploads/desktop/{$publishVersion}/"; - $res = Base::upload([ - "file" => Request::file('file'), - "type" => 'publish', - "path" => $publishPath, - "fileName" => true, - "quality" => 100 - ]); - if (Base::isSuccess($res)) { + $action = Request::get('action'); + $draftPath = "uploads/desktop-draft/{$publishVersion}/"; + if ($action === 'release') { + // 将草稿版本发布为正式版本 + $draftPath = public_path($draftPath); + $releasePath = public_path("uploads/desktop/{$publishVersion}/"); + if (!file_exists($draftPath)) { + return Base::retError("draft version not exists"); + } + if (file_exists($releasePath)) { + Base::deleteDirAndFile($releasePath); + } + Base::copyDirectory($draftPath, $releasePath); file_put_contents($latestFile, $publishVersion); - $uploadSuccessFileNum = $uploadSuccessFileNum + 1; - Cache::set($publishVersion, $uploadSuccessFileNum, 7200); - } - if ($uploadSuccessFileNum >= $fileNum) { // 删除旧版本 + Base::deleteDirAndFile(public_path("uploads/desktop-draft")); $dirs = Base::recursiveDirs(public_path("uploads/desktop"), false); sort($dirs); $num = 0; @@ -309,8 +310,16 @@ class IndexController extends InvokeController Base::deleteDirAndFile($dir); } } + return Base::retSuccess('success'); } - return $res; + // 上传草稿版本 + return Base::upload([ + "file" => Request::file('file'), + "type" => 'publish', + "path" => $draftPath, + "fileName" => true, + "quality" => 100 + ]); } } // 列表 diff --git a/app/Module/Base.php b/app/Module/Base.php index 0538e1192..d640eab65 100755 --- a/app/Module/Base.php +++ b/app/Module/Base.php @@ -13,7 +13,6 @@ use League\CommonMark\Exception\CommonMarkException; use Overtrue\Pinyin\Pinyin; use Redirect; use Request; -use Response; use Storage; use Symfony\Component\HttpFoundation\File\Exception\FileException; use Symfony\Component\HttpFoundation\File\File; @@ -372,6 +371,34 @@ class Base } } + /** + * 复制文件夹 + * @param $source + * @param $destination + * @return bool + */ + public static function copyDirectory($source, $destination) + { + if (!is_dir($source)) { + return false; + } + if (!is_dir($destination)) { + Base::makeDir($destination); + } + $dir = opendir($source); + while (false !== ($file = readdir($dir))) { + if (($file != '.') && ($file != '..')) { + if (is_dir($source . '/' . $file)) { + self::copyDirectory($source . '/' . $file, $destination . '/' . $file); + } else { + copy($source . '/' . $file, $destination . '/' . $file); + } + } + } + closedir($dir); + return true; + } + /** * * 截取字符串 diff --git a/cmd b/cmd index ec0dd2da6..8aaa20981 100755 --- a/cmd +++ b/cmd @@ -174,6 +174,7 @@ run_electron() { mkdir -p ./electron/public cp ./electron/index.html ./electron/public/index.html npx vite build -- fromcmd electronBuild + echo "" fi node ./electron/build.js $argv } diff --git a/electron/build.js b/electron/build.js index f7f5fd13e..31b8502f0 100644 --- a/electron/build.js +++ b/electron/build.js @@ -292,7 +292,7 @@ function androidUpload(url) { uploadOras[filename] = ora(`Upload [0%] ${filename}`).start() const formData = new FormData() formData.append("file", fs.createReadStream(localFile)); - formData.append("file_num", 1); + formData.append("action", "draft"); await axiosAutoTry({ axios: { method: 'post', @@ -358,16 +358,6 @@ function genericPublish({url, key, version, output}) { if (err) { console.warn(err) } else { - let uploadFileNum = 0; - for (const filename of files) { - const localFile = path.join(filePath, filename) - if (fs.existsSync(localFile)) { - const fileStat = fs.statSync(localFile) - if (fileStat.isFile()) { - uploadFileNum += 1; - } - } - } const uploadOras = {} for (const filename of files) { const localFile = path.join(filePath, filename) @@ -377,7 +367,7 @@ function genericPublish({url, key, version, output}) { uploadOras[filename] = ora(`Upload [0%] ${filename}`).start() const formData = new FormData() formData.append("file", fs.createReadStream(localFile)); - formData.append("file_num", uploadFileNum); + formData.append("action", "draft"); await axiosAutoTry({ axios: { method: 'post', diff --git a/package.json b/package.json index c0b80e11b..a697c3fc2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "DooTask", - "version": "0.39.97", + "version": "0.39.98", "codeVerson": 154, "description": "DooTask is task management system.", "scripts": {