From b821c98ddde4d78396731310d6be3460c290655e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=A5=E6=B5=A9?= Date: Mon, 30 Sep 2024 14:13:23 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/_files/.npmrc | 1 + .github/_files/package.json | 6 + .github/_files/pnpm-lock.yaml | 125 ++++++++++ .../workflows/deploy-dist-to-surge-tetst.yaml | 26 ++ .github/workflows/docker-build-push-test.yaml | 133 +++++++++++ .../npm-build-fix-to-nexus-test.yaml | 26 ++ .../setup-node-environment-test.yaml | 133 +++++++++++ .../upload-to-alist-example-test.yaml | 52 ++++ .gitignore | 1 + .releaserc.json | 7 + Dockerfile.test | 12 + README.md | 1 + deploy-dist-to-surge/action.yml | 22 ++ docker-build-push/action.yml | 99 ++++++++ npm-build-fix-to-nexus/action.yml | 71 ++++++ renovate.json | 17 ++ setup-node-environment/action.yml | 224 ++++++++++++++++++ upload-to-alist/action.yml | 87 +++++++ 18 files changed, 1043 insertions(+) create mode 100644 .github/_files/.npmrc create mode 100644 .github/_files/package.json create mode 100644 .github/_files/pnpm-lock.yaml create mode 100644 .github/workflows/deploy-dist-to-surge-tetst.yaml create mode 100644 .github/workflows/docker-build-push-test.yaml create mode 100644 .github/workflows/npm-build-fix-to-nexus-test.yaml create mode 100644 .github/workflows/setup-node-environment-test.yaml create mode 100644 .github/workflows/upload-to-alist-example-test.yaml create mode 100644 .gitignore create mode 100644 .releaserc.json create mode 100644 Dockerfile.test create mode 100644 README.md create mode 100644 deploy-dist-to-surge/action.yml create mode 100644 docker-build-push/action.yml create mode 100644 npm-build-fix-to-nexus/action.yml create mode 100644 renovate.json create mode 100644 setup-node-environment/action.yml create mode 100644 upload-to-alist/action.yml diff --git a/.github/_files/.npmrc b/.github/_files/.npmrc new file mode 100644 index 0000000..83c86a7 --- /dev/null +++ b/.github/_files/.npmrc @@ -0,0 +1 @@ +use-node-version=22.14.0 # https://pnpm.io/zh/npmrc#use-node-version \ No newline at end of file diff --git a/.github/_files/package.json b/.github/_files/package.json new file mode 100644 index 0000000..4619ad8 --- /dev/null +++ b/.github/_files/package.json @@ -0,0 +1,6 @@ +{ + "packageManager": "pnpm@10.6.5", + "dependencies": { + "bun": "^1.2.5" + } +} \ No newline at end of file diff --git a/.github/_files/pnpm-lock.yaml b/.github/_files/pnpm-lock.yaml new file mode 100644 index 0000000..ebdc08d --- /dev/null +++ b/.github/_files/pnpm-lock.yaml @@ -0,0 +1,125 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + bun: + specifier: ^1.2.5 + version: 1.2.5 + +packages: + + '@oven/bun-darwin-aarch64@1.2.5': + resolution: {integrity: sha512-ggZfdpgUJ/OiWrfcfTgHeSTHcec5HAjkGrZHL9FJ/R60sydRKPYHgAgexdIoJAGfsCVAL+x7y8NSTRIAX8J4Ng==} + cpu: [arm64] + os: [darwin] + + '@oven/bun-darwin-x64-baseline@1.2.5': + resolution: {integrity: sha512-3W1RO3/D6Z1S79J47F/DLzmK+dgkYq5hS1ShOCSBAYTTA2b1ZuymaN8avGzSb9ed5W0QfxtyeAksfEY2xUBOqA==} + cpu: [x64] + os: [darwin] + + '@oven/bun-darwin-x64@1.2.5': + resolution: {integrity: sha512-4zqyQLJB33s99KcTxH6yQqH5EYBmF1qofQTtLsToIFbIZN1NqSp/aegYiGmxO5Kj/BuWsy8Wf8MS6vX2O0o2Lw==} + cpu: [x64] + os: [darwin] + + '@oven/bun-linux-aarch64-musl@1.2.5': + resolution: {integrity: sha512-URlISBOE2HQi8qdru691OYywJRwChxMfXFbk26tCgdZ01LgGAKsIjAYylefuSsPuA697imDN3Pel3D7rveusmw==} + cpu: [aarch64] + os: [linux] + + '@oven/bun-linux-aarch64@1.2.5': + resolution: {integrity: sha512-NQFtAVyQyJhLYrhFVxKdh6cqrDNc60pBnBGLQSO8PU+oyFyiJ3e3gGXjLzMbxd6cJxNIK5FZ0JIq96WljKAhlg==} + cpu: [arm64] + os: [linux] + + '@oven/bun-linux-x64-baseline@1.2.5': + resolution: {integrity: sha512-fCm/qp7e3VYlaoRs6NIEsKubPqyxjzLv8/qZkxeLLOlPd7CS8L26UY4KPOSjA+wrhPT+Nxsyvl/EEJq2R/iauA==} + cpu: [x64] + os: [linux] + + '@oven/bun-linux-x64-musl-baseline@1.2.5': + resolution: {integrity: sha512-H7tuJz7mZvOTPo4yLbIXIxkiDGWSGd2DbwGl4zNol/FURqGsKQVqpomv86yl9KCXsUUOm5FX2i5Ed+ro8N//Cg==} + cpu: [x64] + os: [linux] + + '@oven/bun-linux-x64-musl@1.2.5': + resolution: {integrity: sha512-DuU2kQnY48g9tNWjFrZqyG+U2emCBwlhOPxbuY/TMVVNSTMAcQbE/bb3s2pZdhZH5ssjc5SH/ZyWU1TePcYB2A==} + cpu: [x64] + os: [linux] + + '@oven/bun-linux-x64@1.2.5': + resolution: {integrity: sha512-pa3kQ4cXNV0jk5aM8+Hdmxr+b4QoPVgeAIA454SN5l3hMGfNsHjczKpsz0ksInZ8506iMMTCPEBXpyQJcSme+Q==} + cpu: [x64] + os: [linux] + + '@oven/bun-windows-x64-baseline@1.2.5': + resolution: {integrity: sha512-j5FxI8FeKfWI6rEXA+1O3ASBMTp5CFcZ7MR+/aCpiBKrDse32wLaZMVGnvqQqs4y0YHUvR8b7eXHHTboezjL1w==} + cpu: [x64] + os: [win32] + + '@oven/bun-windows-x64@1.2.5': + resolution: {integrity: sha512-oNDdPmzsCyvCATiYgkKWgxOeEx2F7m/i2MGUba+YJAeVXJsJg9iPJrLVBtETvKoSAgkXViwoUEw2U25jRYsp4g==} + cpu: [x64] + os: [win32] + + bun@1.2.5: + resolution: {integrity: sha512-fbQLt+DPiGUrPKdmsHRRT7cQAlfjdxPVFvLZrsUPmKiTdv+pU50ypdx9yRJluknSbyaZchFVV7Lx2KXikXKX2Q==} + cpu: [arm64, x64, aarch64] + os: [darwin, linux, win32] + hasBin: true + +snapshots: + + '@oven/bun-darwin-aarch64@1.2.5': + optional: true + + '@oven/bun-darwin-x64-baseline@1.2.5': + optional: true + + '@oven/bun-darwin-x64@1.2.5': + optional: true + + '@oven/bun-linux-aarch64-musl@1.2.5': + optional: true + + '@oven/bun-linux-aarch64@1.2.5': + optional: true + + '@oven/bun-linux-x64-baseline@1.2.5': + optional: true + + '@oven/bun-linux-x64-musl-baseline@1.2.5': + optional: true + + '@oven/bun-linux-x64-musl@1.2.5': + optional: true + + '@oven/bun-linux-x64@1.2.5': + optional: true + + '@oven/bun-windows-x64-baseline@1.2.5': + optional: true + + '@oven/bun-windows-x64@1.2.5': + optional: true + + bun@1.2.5: + optionalDependencies: + '@oven/bun-darwin-aarch64': 1.2.5 + '@oven/bun-darwin-x64': 1.2.5 + '@oven/bun-darwin-x64-baseline': 1.2.5 + '@oven/bun-linux-aarch64': 1.2.5 + '@oven/bun-linux-aarch64-musl': 1.2.5 + '@oven/bun-linux-x64': 1.2.5 + '@oven/bun-linux-x64-baseline': 1.2.5 + '@oven/bun-linux-x64-musl': 1.2.5 + '@oven/bun-linux-x64-musl-baseline': 1.2.5 + '@oven/bun-windows-x64': 1.2.5 + '@oven/bun-windows-x64-baseline': 1.2.5 diff --git a/.github/workflows/deploy-dist-to-surge-tetst.yaml b/.github/workflows/deploy-dist-to-surge-tetst.yaml new file mode 100644 index 0000000..cfd1e50 --- /dev/null +++ b/.github/workflows/deploy-dist-to-surge-tetst.yaml @@ -0,0 +1,26 @@ +on: + pull_request: + paths: + - "deploy-dist-to-surge/**" + - ".github/workflows/deploy-dist-to-surge-test.yaml" + push: + paths: + - "deploy-dist-to-surge/**" + - ".github/workflows/deploy-dist-to-surge-test.yaml" +env: + TZ: Asia/Shanghai + +jobs: + job: + runs-on: ubuntu-latest + steps: + - name: 准备部署文件 + run: | + mkdir dist + html="

${{ github.event_name }}: ${{ github.sha }}

" + echo $html > dist/index.html + - uses: yanhao98/composite-actions/deploy-dist-to-surge@main + id: surge_deploy + - name: Check Surge URL + run: | + echo "steps.surge_deploy.outputs.url: ${{ steps.surge_deploy.outputs.url }}" diff --git a/.github/workflows/docker-build-push-test.yaml b/.github/workflows/docker-build-push-test.yaml new file mode 100644 index 0000000..bdf566f --- /dev/null +++ b/.github/workflows/docker-build-push-test.yaml @@ -0,0 +1,133 @@ +# name: _打包推送镜像 +on: + workflow_dispatch: + pull_request: + paths: + - 'docker-build-push/**' + - '.github/workflows/docker-build-push-test.yaml' + push: + paths: + - 'docker-build-push/**' + - '.github/workflows/docker-build-push-test.yaml' +env: + TZ: Asia/Shanghai + +jobs: + build-and-push-ghcr: + runs-on: ubuntu-latest + env: + # https://github.com/docker/metadata-action/tree/v5/?tab=readme-ov-file#semver + # Event: push, Ref: refs/head/main, Tags: main + # Event: push tag, Ref: refs/tags/v1.2.3, Tags: 1.2.3, 1.2, 1, latest + # Event: push tag, Ref: refs/tags/v2.0.8-rc1, Tags: 2.0.8-rc1 + metadata-action-tags: | + type=ref,event=branch + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + + steps: + - name: 🔑 登录 GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: 🐳 构建并推送 Docker 镜像 + uses: yanhao98/composite-actions/docker-build-push@main + with: + file: ./Dockerfile.test + platforms: linux/amd64,linux/arm64 + push: true + load: false + meta_images: ghcr.io/${{ github.repository }} + meta_tags: ${{ env.metadata-action-tags }} + cache-from: type=gha,scope=${{ github.workflow }} + cache-to: type=gha,scope=${{ github.workflow }} + + build-and-push-multi-registry: + runs-on: ubuntu-latest + steps: + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ vars.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - uses: yanhao98/composite-actions/docker-build-push@main + id: docker-build-push + with: + file: ./Dockerfile.test + platforms: linux/amd64,linux/arm64 + push: true + load: false + meta_images: | + docker.io/${{ vars.DOCKERHUB_USERNAME }}/docker-example + ghcr.io/${{ github.repository }} + meta_tags: | # https://github.com/docker/metadata-action + type=raw,value=latest,enable=true + + cache-gha: + runs-on: ubuntu-latest + steps: + - uses: yanhao98/composite-actions/docker-build-push@main + id: docker-build-push + with: + file: ./Dockerfile.test + platforms: linux/amd64 + push: false + load: true + build-args: | + SHA=${{ github.sha }} + # ##### + # scope: https://github.com/docker/build-push-action/issues/252#issuecomment-881050512 + # cache-to: mode=max + # ##### + cache-from: type=gha,scope=${{ github.workflow }} + cache-to: type=gha,scope=${{ github.workflow }} + - name: Check Docker image + run: | + set -x; + docker images; + docker run --rm ${{ steps.docker-build-push.outputs.imageid }} cat /root/sha.txt; + + cache-local: + runs-on: ubuntu-latest + steps: + - name: 🗄️ 缓存Docker层 + uses: actions/cache@v4 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-IMAGE_NAME-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx-IMAGE_NAME- + - uses: yanhao98/composite-actions/docker-build-push@main + id: docker-build-push + with: + file: ./Dockerfile.test + platforms: linux/amd64 + push: false + load: true + build-args: | + SHA=${{ github.sha }} + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache-new + # Temp fix: 如果要在一个 job 中多次使用 buildx 缓存才需要这个步骤。 + # https://github.com/docker/build-push-action/issues/252 + # https://github.com/moby/buildkit/issues/1896 + - name: 🔄 更新缓存 + run: | + rm -rf /tmp/.buildx-cache + mv /tmp/.buildx-cache-new /tmp/.buildx-cache + - name: Check Docker image + run: | + set -x; + docker images; + docker run --rm ${{ steps.docker-build-push.outputs.imageid }} cat /root/sha.txt; diff --git a/.github/workflows/npm-build-fix-to-nexus-test.yaml b/.github/workflows/npm-build-fix-to-nexus-test.yaml new file mode 100644 index 0000000..b36ae53 --- /dev/null +++ b/.github/workflows/npm-build-fix-to-nexus-test.yaml @@ -0,0 +1,26 @@ +on: + pull_request: + paths: + - "npm-build-fix-to-nexus/**" + - ".github/workflows/npm-build-fix-to-nexus-test.yaml" + push: + paths: + - "npm-build-fix-to-nexus/**" + - ".github/workflows/npm-build-fix-to-nexus-test.yaml" +env: + TZ: Asia/Shanghai + +jobs: + upload_npm_fix_to_nexus: + runs-on: ubuntu-latest + steps: + - name: Prepare + run: | + mkdir npm-build-fix-to-nexus + - uses: yanhao98/composite-actions/npm-build-fix-to-nexus@main + with: + package_json_url: 'https://www.unpkg.com/fuck-your-code/package.json' + pack_workspace: './npm-build-fix-to-nexus' + build_command: 'whoami' + nexus_post_url: 'https://nexus.oo1.dev/service/rest/v1/components?repository=npm-hosted' + nexus_auth: ${{ secrets.NEXUS_AUTH }} \ No newline at end of file diff --git a/.github/workflows/setup-node-environment-test.yaml b/.github/workflows/setup-node-environment-test.yaml new file mode 100644 index 0000000..06ecdc1 --- /dev/null +++ b/.github/workflows/setup-node-environment-test.yaml @@ -0,0 +1,133 @@ +on: + pull_request: + paths: + - "setup-node-environment/**" + - ".github/workflows/setup-node-environment-test.yaml" + push: + paths: + - "setup-node-environment/**" + - ".github/workflows/setup-node-environment-test.yaml" +env: + TZ: Asia/Shanghai + package_json_content: | + { + "packageManager": "pnpm@10.6.5", + "dependencies": { + "bun": "^1.2.5" + } + } + +concurrency: + group: ${{ github.event_name }}-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash + +jobs: + generate_lock: + runs-on: ubuntu-latest + outputs: + lock_file_content: ${{ steps.generate_lock.outputs.lock_file_content }} + steps: + - uses: pnpm/action-setup@v4 + with: + version: latest + standalone: true + - id: generate_lock + env: + CI: 'false' + run: | + set -x; + cat < package.json + ${{ env.package_json_content }} + EOF + pnpm config list + cat package.json + pnpm install --lockfile-only + echo "lock_file_content<> $GITHUB_OUTPUT + cat pnpm-lock.yaml >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + tests: + needs: generate_lock + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + checkout: + - true + - false + container: + - 'yanhao98/runner-images:pnpm' + - '' # gitea/runner-images:ubuntu-latest + npmrc_content: + - '' + - | + use-node-version=22.14.0 # https://pnpm.io/zh/npmrc#use-node-version + lock_file: + - 'true' + - 'false' + cwd: + - '' + - 'test' + container: ${{ matrix.container }} + steps: + - uses: actions/checkout@main + if: matrix.checkout == 'true' + - name: 打印 matrix + run: | + echo "🤖---- 打印 matrix ----🤖" + echo "container: ${{ matrix.container }}" + echo "checkout: ${{ matrix.checkout }}" + echo "npmrc_content: ${{ matrix.npmrc_content }}" + echo "lock_file: ${{ matrix.lock_file }}" + echo "cwd: ${{ matrix.cwd }}" + echo "GITHUB_WORKSPACE: ${{ github.workspace }}" + + - name: Create test directory + if: matrix.cwd != '' + run: | + mkdir -p ${{ matrix.cwd }} + pwd + + - name: Create .npmrc + working-directory: ${{ matrix.cwd }} + if: matrix.npmrc_content != '' + run: | + set -x; + ls -l -R . + cat < .npmrc + ${{ matrix.npmrc_content }} + EOF + pwd + + - name: Create package.json + working-directory: ${{ matrix.cwd }} + run: | + mkdir -p ${{ github.workspace }}/.git + cat < package.json + ${{ env.package_json_content }} + EOF + set -x; + ls -l -R . + cat package.json + pwd + + - name: Create pnpm-lock.yaml + working-directory: ${{ matrix.cwd }} + if: matrix.lock_file == 'true' + run: | + mkdir -p ${{ github.workspace }}/.git + cat < pnpm-lock.yaml + ${{ needs.generate_lock.outputs.lock_file_content }} + EOF + set -x; + ls -l -R . + cat pnpm-lock.yaml + + - uses: yanhao98/composite-actions/setup-node-environment@main + with: + package_json_cwd: ${{ matrix.cwd }} + # pnpm_standalone: true \ No newline at end of file diff --git a/.github/workflows/upload-to-alist-example-test.yaml b/.github/workflows/upload-to-alist-example-test.yaml new file mode 100644 index 0000000..181a412 --- /dev/null +++ b/.github/workflows/upload-to-alist-example-test.yaml @@ -0,0 +1,52 @@ +name: Upload to Alist Example + +on: + pull_request: + paths: + - "upload-to-alist/**" + - ".github/workflows/upload-to-alist-example-test.yaml" + push: + paths: + - "upload-to-alist/**" + - ".github/workflows/upload-to-alist-example-test.yaml" + +env: + TZ: Asia/Shanghai + +jobs: + upload: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: 📝 生成构建产物的文件名 + id: filename + run: | + PROJECT_NAME=$(echo ${{ github.repository }} | cut -d'/' -f2) + DATE=$(date '+%Y%m%d_%H%M') + SHORT_HASH=$(git rev-parse --short HEAD) + + FILENAME="${PROJECT_NAME}_${DATE}_${SHORT_HASH}.txt" + echo "📝 生成的文件名: $FILENAME" + echo "FILENAME=${FILENAME}" >> $GITHUB_OUTPUT + + - name: Create test file + run: | + cat > ${{ steps.filename.outputs.FILENAME }} << EOF + # 测试文件 + + - 项目: ${{ github.repository }} + - 分支: ${{ github.ref_name }} + - 提交: $(git rev-parse HEAD) + - 时间: $(date '+%Y-%m-%d %H:%M:%S %Z') + - 触发事件: ${{ github.event_name }} + EOF + + - uses: yanhao98/composite-actions/upload-to-alist@main + with: + alist_url: ${{ vars.ALIST_URL }} + alist_username: ${{ secrets.ALIST_USERNAME }} + alist_password: ${{ secrets.ALIST_PASSWORD }} + alist_target: ${{ vars.alist_target_base }}/github-actions/upload-to-alist/${{ steps.filename.outputs.FILENAME }} + file: ${{ steps.filename.outputs.FILENAME }} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/.releaserc.json b/.releaserc.json new file mode 100644 index 0000000..b875d81 --- /dev/null +++ b/.releaserc.json @@ -0,0 +1,7 @@ +{ + "plugins": [ + "@semantic-release/commit-analyzer", + "@semantic-release/release-notes-generator", + "@semantic-release/changelog" + ] +} \ No newline at end of file diff --git a/Dockerfile.test b/Dockerfile.test new file mode 100644 index 0000000..dddf08f --- /dev/null +++ b/Dockerfile.test @@ -0,0 +1,12 @@ +# syntax=docker/dockerfile:1.14-labs +FROM alpine:latest + +ARG SHA=unspecified +ENV SHA=$SHA + +COPY <> $GITHUB_OUTPUT diff --git a/docker-build-push/action.yml b/docker-build-push/action.yml new file mode 100644 index 0000000..0dec0e5 --- /dev/null +++ b/docker-build-push/action.yml @@ -0,0 +1,99 @@ +# - https://docs.docker.com/build/ci/github-actions/push-multi-registries/ + +# - https://github.com/docker/build-push-action + +name: "打包推送 Docker 镜像" +description: "打包 Docker 镜像并推送到 Docker Hub" +inputs: + file: + description: "Dockerfile 文件路径" + default: "./Dockerfile" + required: false + context: + description: "Docker 构建上下文路径" + default: "." + required: false + platforms: + description: "Docker 构建平台" + default: "linux/amd64,linux/arm64" + required: false + push: + description: "是否推送 Docker 镜像" + default: "false" + required: false + load: + description: "是否加载 Docker 镜像" + default: "false" + required: false + meta_images: + description: "docker/metadata-action 的 images 参数" + required: false + meta_tags: + description: "docker/metadata-action 的 tags 参数" + required: false + cache-from: + description: "docker/build-push-action 的 cache-from 参数" + required: false + cache-to: + description: "docker/build-push-action 的 cache-to 参数" + required: false + build-args: + description: "Docker 构建参数,格式如: KEY1=VALUE1,KEY2=VALUE2" + required: false +outputs: + imageid: + description: "Docker 镜像 ID" + value: ${{ steps.build.outputs.imageid }} +runs: + using: "composite" + steps: + - name: echo Start + shell: bash + run: echo -e "\n[$(date +'%Y-%m-%d %H:%M:%S')] 🤖🤖🤖 Start 🤖🤖🤖" + + - id: check-git-folder + shell: bash + run: | + # 🤖 判断是否存在 .git 文件夹 🤖 + [ -d .git ] && { echo "🤖 Found .git folder"; echo "git-folder-exists=true" >> $GITHUB_OUTPUT; } || { echo "🤖 No .git folder found"; echo "git-folder-exists=false" >> $GITHUB_OUTPUT; } + - uses: actions/checkout@main + if: steps.check-git-folder.outputs.git-folder-exists == 'false' + with: + filter: blob:none + show-progress: false + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + context: git + # flavor + images: ${{ inputs.meta_images }} + tags: ${{ inputs.meta_tags }} + # sep-tags: ',' + # sep-labels: ',' + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build and push + id: build + uses: docker/build-push-action@v6 + with: + file: ${{ inputs.file }} + context: ${{ inputs.context }} + platforms: ${{ inputs.platforms }} + push: ${{ inputs.push }} + load: ${{ inputs.load }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: ${{ inputs.cache-from }} + cache-to: ${{ inputs.cache-to }} + build-args: ${{ inputs.build-args }} + + - name: echo End + shell: bash + run: echo -e "\n[$(date +'%Y-%m-%d %H:%M:%S')] 🤖🤖🤖 End 🤖🤖🤖" \ No newline at end of file diff --git a/npm-build-fix-to-nexus/action.yml b/npm-build-fix-to-nexus/action.yml new file mode 100644 index 0000000..c17b7a7 --- /dev/null +++ b/npm-build-fix-to-nexus/action.yml @@ -0,0 +1,71 @@ +name: '发布修复包到 Nexus' +description: '发布 npm 修复包到 Nexus' +inputs: + package_json_url: + description: 'package.json 文件的 URL' + required: true + pack_workspace: + description: '打包工作目录' + required: true + build_command: + description: '构建命令' + required: true + nexus_post_url: + description: 'Nexus URL' + required: true + nexus_auth: + description: 'Nexus 认证信息' + required: true +runs: + using: 'composite' + steps: + - name: 下载 package.json 文件 + shell: bash + run: wget ${{ inputs.package_json_url }} -O /tmp/package.json + - name: 更新版本号 + shell: bash + run: | + # 获取当前版本 + VERSION=$(node -p "require('/tmp/package.json').version") + + # 分解版本号 + IFS='.' read -r major minor patch <<< "$VERSION" + + # 增加patch版本 + new_patch=$((patch + 1)) + + # 生成新版本号基础部分 + NEW_VERSION="$major.$minor.$new_patch" + + # 添加-fix后缀 + NEW_VERSION="$NEW_VERSION-fix" + + # 添加时间戳 + TIMESTAMP=$(date -u +"%Y%m%d%H%M") + NEW_VERSION="$NEW_VERSION.$TIMESTAMP" + + echo "Current version: $VERSION" + echo "New version: $NEW_VERSION" + + # 更新package.json中的版本号 + sed -i "s/\"version\": \".*\"/\"version\": \"$NEW_VERSION\"/" /tmp/package.json + - uses: yanhao98/composite-actions/setup-node-environment@main + - name: 构建项目 + shell: bash + run: ${{ inputs.build_command }} + - name: 打包 tgz + id: pack_tgz + working-directory: ${{ inputs.pack_workspace }} + shell: bash + run: | + rm -rf *.tgz + cp /tmp/package.json . + tgz=$(npm pack) + echo "tgz=$tgz" >> $GITHUB_OUTPUT + - name: 上传到 Nexus + working-directory: ${{ inputs.pack_workspace }} + shell: bash + run: | + curl -i -X POST "${{ inputs.nexus_post_url }}" \ + -H "Authorization: Basic ${{ inputs.nexus_auth }}" \ + -F "npm.asset=@${{ steps.pack_tgz.outputs.tgz }}" diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..d3e2a5c --- /dev/null +++ b/renovate.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "https://git.1-h.cc/examples/renovate-example/raw/branch/main/default.json5", + ":automergeAll" + ], + "dependencyDashboard": false, + "packageRules": [ + { "minimumReleaseAge": "1 days", "matchPackageNames": [ "*" ] } + ], + "ignoreDeps": [], + "ignorePaths": [ + "package.json", + ".npmrc", + "Dockerfile.test" + ] +} \ No newline at end of file diff --git a/setup-node-environment/action.yml b/setup-node-environment/action.yml new file mode 100644 index 0000000..b6f519b --- /dev/null +++ b/setup-node-environment/action.yml @@ -0,0 +1,224 @@ +# 🔗 链接: +# 源文件: https://github.com/obytes/react-native-template-obytes/blob/master/.github/actions/setup-node-pnpm-install/action.yml +# 复合操作文档: https://docs.github.com/en/actions/creating-actions/creating-a-composite-action + +# ✍️ 描述: +# 这是一个复合操作,意味着它可以在其他操作中使用。 +# 它几乎用于所有工作流中,以设置环境并安装依赖项。 +# 在此处更新包管理器或 Node 版本将反映在所有工作流中。 + +# 👀 使用示例: +# - name : 📦 设置 Node + PNPM + 安装依赖 +# uses: ./.github/actions/setup-node-pnpm-install + +name: '设置 Node 环境' +description: '设置 pnpm + Node.js + 安装依赖项' +inputs: + pnpm_standalone: # 是否将 pnpm 用作独立包 https://github.com/pnpm/action-setup?tab=readme-ov-file#standalone + description: '是否将 pnpm 用作独立包' + required: false + default: 'false' + package_json_cwd: # https://github.com/pnpm/action-setup/blob/d648c2dd069001a242c621c8306af467f150e99d/action.yml#L18C3-L18C20 + description: 'package.json 的所在目录' + required: false + default: '.' +runs: + using: 'composite' + steps: + - id: check-git-folder + shell: bash + run: | + # 🤖----判断是否存在 .git 文件夹----🤖 # + [ -d ${{ github.workspace }}/.git ] && { echo "🤖 找到 .git 文件夹"; echo "git-folder-exists=true" >> $GITHUB_OUTPUT; } || { echo "🤖 未找到 .git 文件夹"; echo "git-folder-exists=false" >> $GITHUB_OUTPUT; } + + - uses: actions/checkout@v4.2.2 + if: steps.check-git-folder.outputs.git-folder-exists == 'false' + with: + # fetch-depth: 0 # 0 代表完整检出,semantic-release 需要 + filter: blob:none # 我们不需要所有 blob,只需要完整的树 + show-progress: false + + - id: prepare + shell: bash + working-directory: ${{ inputs.package_json_cwd }} + run: | + # 🤖---- 准备环境变量 ----🤖 # + + # --- 1. 包管理器 --- + echo "::group::📦 获取包管理器信息" + pkg_manager=$(node -p "try { require('./package.json').packageManager } catch(e) { '' }") + echo "从 package.json 获取的包管理器: $pkg_manager" + echo "::endgroup::" + + # --- 2. 确定 PNPM 版本 --- + echo "::group::🔧 确定 PNPM 版本" + pnpm_version="" + # 如果 packageManager 为空、undefined 或 null,则使用最新的 pnpm + if [ -z "$pkg_manager" ] || [ "$pkg_manager" == "undefined" ] || [ "$pkg_manager" == "null" ]; then + pnpm_version="latest" + echo "未指定或无效的 packageManager,使用 pnpm 版本: latest" + else + # 如果指定了 pnpm 版本(例如 "pnpm@8.6.0"),则提取版本号 + if [[ "$pkg_manager" == pnpm* ]]; then + pnpm_version=$(echo "$pkg_manager" | cut -d '@' -f 2) + echo "使用 package.json 中的 pnpm 版本: $pnpm_version" + else + echo "指定了非 pnpm 包管理器: $pkg_manager。将由 pnpm/action-setup 处理版本。" + # 让 pnpm/action-setup 根据 corepack 或其默认设置决定版本 + pnpm_version="" # 如果不是 pnpm 或未正确指定,则显式设置为空 + fi + fi + echo "::endgroup::" + + # --- 3. 检查 PNPM 安装情况 --- + echo "::group::🔍 检查 PNPM 安装情况" + is_pnpm_installed="false" + pnpm_executable_path="" + installed_pnpm_version="无法获取" # 版本检查失败时的默认值 + + # 使用 command -v 检查 pnpm 是否在 PATH 中并且可执行 + if command -v pnpm >/dev/null 2>&1; then + pnpm_executable_path=$(command -v pnpm) + echo "找到 PNPM 可执行文件于: $pnpm_executable_path" + # 尝试获取版本号,但不因失败而退出 + if pnpm_version_output=$(pnpm --version 2>/dev/null); then + installed_pnpm_version="$pnpm_version_output" + is_pnpm_installed="true" # 确认 pnpm 可执行且能获取版本 + echo "已安装的 PNPM 版本: $installed_pnpm_version" + else + # pnpm 命令存在但获取版本失败,可能安装不完整或有问题 + is_pnpm_installed="true" # 标记为已安装,因为命令存在 + echo "警告:PNPM 命令存在,但无法获取版本号。可能安装不完整或存在问题。" + echo "将继续执行,后续步骤可能会重新安装或修复。" + fi + else + echo "PNPM 未在 PATH 中找到或不可执行。" + is_pnpm_installed="false" + fi + echo "::endgroup::" + + # --- 4. 检查 PNPM Lock 文件 --- + echo "::group::📄 检查 PNPM Lock 文件" + has_pnpm_lock="false" + if [ -f pnpm-lock.yaml ]; then + has_pnpm_lock="true" + echo "找到 pnpm-lock.yaml。" + else + echo "未找到 pnpm-lock.yaml。" + fi + echo "::endgroup::" + + # --- 5. 确定 Node.js 版本并清理 .npmrc --- + echo "::group::⚙️ 确定 Node.js 版本并清理 .npmrc" + node_version="lts/*" # 默认 Node 版本 + if [ ! -f .npmrc ]; then + echo "未找到 .npmrc,创建一个空文件。" + touch .npmrc + else + echo "找到 .npmrc 文件。" + fi + + # 从 .npmrc 读取 use-node-version + node_version_in_npmrc=$(sed -n 's/.*use-node-version=\([0-9.]*\).*/\1/p' .npmrc) + if [ -n "$node_version_in_npmrc" ]; then + node_major_version_in_npmrc=$(echo "$node_version_in_npmrc" | cut -d. -f1) + if [ -n "$node_major_version_in_npmrc" ]; then + node_version="$node_major_version_in_npmrc" + echo ".npmrc 中指定的 Node 版本: $node_version_in_npmrc -> 使用主版本: $node_version" + else + echo "无法从 .npmrc ($node_version_in_npmrc) 提取主 Node 版本。使用默认值: $node_version" + fi + else + echo ".npmrc 中未找到 'use-node-version'。使用默认值: $node_version" + fi + + # 清理 .npmrc:删除 use-node-version 和 node-mirror 行 + echo "正在清理 .npmrc..." + # 使用 -i.bak 以兼容不同 sed 版本,并在创建备份后删除 + sed -i.bak -e '/use-node-version/d' -e '/node-mirror/d' .npmrc + [ -f .npmrc.bak ] && rm .npmrc.bak + echo ".npmrc 已清理。" + echo "::endgroup::" + + # --- 6. 设置输出 --- + echo "::group::🚀 设置 GitHub Actions 输出" + echo "packageManager=${pkg_manager}" >> $GITHUB_OUTPUT + echo "pnpmVersion=${pnpm_version}" >> $GITHUB_OUTPUT + echo "pnpmInstalled=${is_pnpm_installed}" >> $GITHUB_OUTPUT + echo "pnpmLockExists=${has_pnpm_lock}" >> $GITHUB_OUTPUT + echo "nodeVersion=${node_version}" >> $GITHUB_OUTPUT + echo "输出已设置:" + printf " %-16s %s\n" "packageManager:" "${pkg_manager}" + printf " %-16s %s\n" "pnpmVersion:" "${pnpm_version}" + printf " %-16s %s\n" "pnpmInstalled:" "${is_pnpm_installed}" + printf " %-16s %s\n" "pnpmLockExists:" "${has_pnpm_lock}" + printf " %-16s %s\n" "nodeVersion:" "${node_version}" + echo "::endgroup::" + + - uses: pnpm/action-setup@v4 # https://github.com/pnpm/action-setup?tab=readme-ov-file#inputs + if: steps.prepare.outputs.pnpmInstalled == 'false' + with: + version: ${{ steps.prepare.outputs.pnpmVersion }} + standalone: ${{ inputs.pnpm_standalone }} + + - uses: actions/setup-node@v4 # https://github.com/actions/setup-node?tab=readme-ov-file#usage + with: + node-version: ${{ steps.prepare.outputs.nodeVersion }} + cache: '' + + - id: pnpm-store-dir + shell: bash + run: | + echo "🤖---- 获取 PNPM 存储目录 ----🤖" + echo "PNPM 存储目录: $(pnpm store path)" + echo "pnpmStoreDir=$(pnpm store path)" >> $GITHUB_OUTPUT + + - id: cache-pnpm-restore + uses: actions/cache/restore@v4 # https://github.com/actions/cache/blob/main/restore/action.yml + with: + path: ${{ steps.pnpm-store-dir.outputs.pnpmStoreDir }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - run: echo "package-import-method=hardlink" >> .npmrc + shell: bash + + - if: steps.cache-pnpm-restore.outputs.cache-hit == 'true' + working-directory: ${{ inputs.package_json_cwd }} + shell: bash + run: | + echo "🤖---- 缓存命中,安装依赖 ----🤖" + pnpm install --prefer-offline + # --frozen-lockfile + # ERR_PNPM_NO_LOCKFILE  Cannot install with "frozen-lockfile" because pnpm-lock.yaml is absent + + - if: steps.cache-pnpm-restore.outputs.cache-hit != 'true' + working-directory: ${{ inputs.package_json_cwd }} + shell: bash + run: | + echo "🤖---- 缓存未命中,安装依赖 ----🤖" + set -x; + pnpm fetch # https://pnpm.io/zh/cli/fetch + pnpm install --prefer-offline + # --frozen-lockfile + # ERR_PNPM_NO_LOCKFILE  Cannot install with "frozen-lockfile" because pnpm-lock.yaml is absent + pnpm store prune + + - id: cache-pnpm-save + if: always() && steps.cache-pnpm-restore.outputs.cache-hit == 'false' + uses: actions/cache/save@v4 + with: + path: ${{ steps.pnpm-store-dir.outputs.pnpmStoreDir }} + key: ${{ steps.cache-pnpm-restore.outputs.cache-primary-key }} + +# # https://github.com/pnpm/pnpm/issues/7192#issuecomment-2353298966 +# package-import-method=hardlink + +# rm -r node_modules +# pnpm fetch +# pnpm install --offline +# pnpm store prune +# # +# rm -r node_modules +# pnpm install --offline \ No newline at end of file diff --git a/upload-to-alist/action.yml b/upload-to-alist/action.yml new file mode 100644 index 0000000..0b00695 --- /dev/null +++ b/upload-to-alist/action.yml @@ -0,0 +1,87 @@ +name: '上传文件到 Alist' +description: '将文件上传到 Alist 服务器' +inputs: + alist_url: + description: 'Alist 服务器地址(不包含末尾的 /)' + required: true + default: 'https://alist.oo1.dev' + alist_username: + description: 'Alist 用户名' + required: true + alist_password: + description: 'Alist 密码' + required: true + alist_target: + description: 'Alist 目标路径(完整路径,如:/folder/subfolder/file.zip)' + required: true + file: + description: '要上传的文件路径(完整路径,如:./path/to/file.zip)' + required: true + +runs: + using: 'composite' + steps: + - name: 检查文件 + shell: bash + run: | + if [ ! -f "${{ inputs.file }}" ]; then + echo "错误: 文件 '${{ inputs.file }}' 不存在" + exit 1 + fi + + # 获取文件大小 + file_size=$(stat -f%z "${{ inputs.file }}" 2>/dev/null || stat -c%s "${{ inputs.file }}") + echo "文件大小: $file_size 字节" + + if [ "$file_size" -eq 0 ]; then + echo "错误: 文件为空" + exit 1 + fi + + - name: 获取 Alist Token + shell: bash + id: get_token + run: | + response=$(curl -s --location '${{ inputs.alist_url }}/api/auth/login' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode "Username=${{ inputs.alist_username }}" \ + --data-urlencode "Password=${{ inputs.alist_password }}") + + if ! echo "$response" | jq -e . >/dev/null 2>&1; then + echo "错误: 服务器返回的不是有效的 JSON 响应" + echo "响应内容: $response" + exit 1 + fi + + token=$(echo "$response" | jq -r ".data.token") + + if [ "$token" = "null" ] || [ -z "$token" ]; then + echo "错误: 获取 token 失败" + echo "响应内容: $response" + exit 1 + fi + + echo "成功获取 token" + echo "token=$token" >> $GITHUB_OUTPUT + + - name: 上传文件到 Alist + shell: bash + run: | + response=$(curl -s --location --request PUT '${{ inputs.alist_url }}/api/fs/form' \ + --header "Authorization: ${{ steps.get_token.outputs.token }}" \ + --header "file-path: ${{ inputs.alist_target }}" \ + --form "file=@${{ inputs.file }}") + + if ! echo "$response" | jq -e . >/dev/null 2>&1; then + echo "错误: 服务器返回的不是有效的 JSON 响应" + echo "响应内容: $response" + exit 1 + fi + + if echo "$response" | jq -e '.code == 200' >/dev/null 2>&1; then + echo "✅ 文件上传成功" + else + echo "❌ 文件上传失败" + echo "错误响应: $response" + exit 1 + fi \ No newline at end of file