【新增】图标 #2
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: TaskBridge Release | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: "Release version, for example v0.1.0" | |
| required: true | |
| type: string | |
| publish_latest: | |
| description: "Also publish the Docker latest tag" | |
| required: true | |
| default: true | |
| type: boolean | |
| permissions: | |
| contents: write | |
| packages: write | |
| concurrency: | |
| group: release-${{ github.event_name == 'workflow_dispatch' && inputs.version || github.ref_name }} | |
| cancel-in-progress: false | |
| env: | |
| RELEASE_VERSION: ${{ github.event_name == 'workflow_dispatch' && inputs.version || github.ref_name }} | |
| DOCKERHUB_IMAGE: ${{ vars.DOCKERHUB_IMAGE || '27xk/taskbridge' }} | |
| jobs: | |
| prepare: | |
| name: Prepare GitHub Release | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Validate release version | |
| shell: bash | |
| run: | | |
| if [[ ! "${RELEASE_VERSION}" =~ ^v[0-9]+(\.[0-9]+){0,2}([-.][0-9A-Za-z.]+)?$ ]]; then | |
| echo "::error::Release version must start with v, for example v0.1.0." | |
| exit 1 | |
| fi | |
| - name: Ensure release tag exists | |
| if: ${{ github.event_name == 'workflow_dispatch' }} | |
| shell: bash | |
| run: | | |
| git fetch --tags --force | |
| if git rev-parse -q --verify "refs/tags/${RELEASE_VERSION}" >/dev/null; then | |
| echo "Tag ${RELEASE_VERSION} already exists." | |
| else | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| git tag "${RELEASE_VERSION}" "${GITHUB_SHA}" | |
| git push origin "refs/tags/${RELEASE_VERSION}" | |
| fi | |
| - name: Create release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ env.RELEASE_VERSION }} | |
| name: TaskBridge ${{ env.RELEASE_VERSION }} | |
| target_commitish: ${{ github.sha }} | |
| generate_release_notes: true | |
| body: | | |
| Release assets are uploaded by the Android and Windows build jobs. | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| android: | |
| name: Build Android APK | |
| runs-on: ubuntu-latest | |
| needs: prepare | |
| defaults: | |
| run: | |
| working-directory: android | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Set up JDK | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: temurin | |
| java-version: "17" | |
| - name: Set up Gradle | |
| uses: gradle/actions/setup-gradle@v4 | |
| with: | |
| gradle-home-cache-cleanup: true | |
| - name: Decode Android signing key | |
| shell: bash | |
| run: | | |
| if [ -n "$ANDROID_KEYSTORE_BASE64" ]; then | |
| echo "$ANDROID_KEYSTORE_BASE64" | base64 --decode > release.keystore | |
| fi | |
| env: | |
| ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} | |
| - name: Make Gradle wrapper executable | |
| run: chmod +x gradlew | |
| - name: Run unit tests | |
| run: ./gradlew testReleaseUnitTest -PTASKBRIDGE_USE_CHINA_MIRRORS=false --stacktrace | |
| - name: Build release APK | |
| run: ./gradlew :app:assembleRelease -PTASKBRIDGE_USE_CHINA_MIRRORS=false --stacktrace | |
| env: | |
| ANDROID_KEYSTORE_PATH: ${{ github.workspace }}/android/release.keystore | |
| ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} | |
| ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} | |
| ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }} | |
| - name: Prepare Android artifact | |
| shell: bash | |
| run: | | |
| mkdir -p ../artifacts | |
| find app/build/outputs/apk -maxdepth 3 -type f -print | |
| cp app/build/outputs/apk/release/app-release.apk "../artifacts/TaskBridge-${RELEASE_VERSION}-android.apk" | |
| - name: Publish Android release asset | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ env.RELEASE_VERSION }} | |
| files: artifacts/*.apk | |
| fail_on_unmatched_files: true | |
| overwrite_files: true | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| desktop: | |
| name: Build Windows installer | |
| runs-on: windows-latest | |
| needs: prepare | |
| defaults: | |
| run: | |
| working-directory: desktop | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "22" | |
| cache: npm | |
| cache-dependency-path: desktop/package-lock.json | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Build Windows installer | |
| run: npm run dist | |
| env: | |
| CSC_IDENTITY_AUTO_DISCOVERY: "false" | |
| ELECTRON_CACHE: ${{ github.workspace }}\\.cache\\electron | |
| ELECTRON_BUILDER_CACHE: ${{ github.workspace }}\\.cache\\electron-builder | |
| - name: Prepare desktop artifacts | |
| shell: pwsh | |
| run: | | |
| New-Item -ItemType Directory -Force -Path ..\artifacts | Out-Null | |
| Get-ChildItem -Path release -Recurse -File | Select-Object FullName, Length | |
| Get-ChildItem -Path release -File | Where-Object { $_.Extension -in '.exe', '.blockmap' } | ForEach-Object { | |
| Copy-Item -LiteralPath $_.FullName -Destination ..\artifacts\$($_.Name) | |
| } | |
| - name: Publish Windows release assets | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ env.RELEASE_VERSION }} | |
| files: artifacts/* | |
| fail_on_unmatched_files: true | |
| overwrite_files: true | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| docker: | |
| name: Build and publish backend image | |
| runs-on: ubuntu-latest | |
| needs: prepare | |
| outputs: | |
| ghcr_image: ${{ steps.image.outputs.ghcr }} | |
| dockerhub_image: ${{ steps.image.outputs.dockerhub }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Log in to Docker Hub | |
| uses: docker/login-action@v3 | |
| with: | |
| username: ${{ secrets.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: Resolve image name | |
| id: image | |
| shell: bash | |
| run: | | |
| ghcr_image="ghcr.io/${GITHUB_REPOSITORY_OWNER}/taskbridge" | |
| dockerhub_image="${DOCKERHUB_IMAGE}" | |
| echo "ghcr=${ghcr_image,,}" >> "$GITHUB_OUTPUT" | |
| echo "dockerhub=${dockerhub_image,,}" >> "$GITHUB_OUTPUT" | |
| - name: Docker metadata | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: | | |
| ${{ steps.image.outputs.ghcr }} | |
| ${{ steps.image.outputs.dockerhub }} | |
| tags: | | |
| type=raw,value=${{ env.RELEASE_VERSION }} | |
| type=raw,value=latest,enable=${{ github.event_name == 'push' || inputs.publish_latest == true }} | |
| - name: Build and push backend image | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: ./backend | |
| file: ./backend/Dockerfile | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| release: | |
| name: Update GitHub Release | |
| runs-on: ubuntu-latest | |
| needs: | |
| - android | |
| - desktop | |
| - docker | |
| steps: | |
| - name: Update release notes | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ env.RELEASE_VERSION }} | |
| name: TaskBridge ${{ env.RELEASE_VERSION }} | |
| target_commitish: ${{ github.sha }} | |
| generate_release_notes: true | |
| body: | | |
| Backend Docker images: | |
| - `${{ needs.docker.outputs.ghcr_image }}:${{ env.RELEASE_VERSION }}` | |
| - `${{ needs.docker.outputs.dockerhub_image }}:${{ env.RELEASE_VERSION }}` | |
| When `latest` is enabled, these tags are also published: | |
| - `${{ needs.docker.outputs.ghcr_image }}:latest` | |
| - `${{ needs.docker.outputs.dockerhub_image }}:latest` | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |