name: Jan Build Electron App Nightly or Manual on: schedule: - cron: '0 20 * * *' # At 8 PM UTC, which is 3 AM UTC+7 workflow_dispatch: jobs: delete-cloudflare-r2-folder: runs-on: ubuntu-latest environment: production steps: - name: install-aws-cli-action uses: unfor19/install-aws-cli-action@v1 - name: Delete cloudflare-r2 folder using awscli s3api continue-on-error: true run: | # Get the list of objects in the 'latest' folder OBJECTS=$(aws s3api list-objects --bucket ${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }} --prefix "latest/" --query 'Contents[].{Key: Key}' --endpoint-url https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com | jq -c .) # Create a JSON file for the delete operation echo "{\"Objects\": $OBJECTS, \"Quiet\": false}" > delete.json # Delete the objects echo q | aws s3api delete-objects --bucket ${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }} --delete file://delete.json --endpoint-url https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com # Remove the JSON file rm delete.json env: AWS_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_SECRET_ACCESS_KEY }} AWS_DEFAULT_REGION: auto AWS_EC2_METADATA_DISABLED: "true" build-macos: runs-on: macos-latest needs: delete-cloudflare-r2-folder environment: production permissions: contents: write steps: - name: Getting the repo uses: actions/checkout@v3 - name: Installing node uses: actions/setup-node@v1 with: node-version: 20 - name: Install jq uses: dcarbone/install-jq-action@v2.0.1 - name: Update app version based on latest release tag with build number id: version_update run: | # Function to get the latest release tag get_latest_tag() { local retries=0 local max_retries=3 local tag while [ $retries -lt $max_retries ]; do tag=$(curl -s https://api.github.com/repos/janhq/jan/releases/latest | jq -r .tag_name) if [ -n "$tag" ] && [ "$tag" != "null" ]; then echo $tag return else let retries++ echo "Retrying... ($retries/$max_retries)" sleep 2 fi done echo "Failed to fetch latest tag after $max_retries attempts." exit 1 } # Get the latest release tag from GitHub API LATEST_TAG=$(get_latest_tag) # Remove the 'v' and append the build number to the version NEW_VERSION="${LATEST_TAG#v}-${GITHUB_RUN_NUMBER}" echo "New version: $NEW_VERSION" # Update the version in electron/package.json jq --arg version "$NEW_VERSION" '.version = $version' electron/package.json > /tmp/package.json mv /tmp/package.json electron/package.json echo "::set-output name=new_version::$NEW_VERSION" jq '.build.publish = [{"provider": "generic", "url": "${{ secrets.CLOUDFLARE_R2_PUBLIC_URL }}", "channel": "latest"}]' electron/package.json > /tmp/package.json mv /tmp/package.json electron/package.json - name: Get Cer for code signing run: base64 -d <<< "$CODE_SIGN_P12_BASE64" > /tmp/codesign.p12 shell: bash env: CODE_SIGN_P12_BASE64: ${{ secrets.CODE_SIGN_P12_BASE64 }} - uses: apple-actions/import-codesign-certs@v2 continue-on-error: true with: p12-file-base64: ${{ secrets.CODE_SIGN_P12_BASE64 }} p12-password: ${{ secrets.CODE_SIGN_P12_PASSWORD }} - name: Build and publish app run: | make build env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} CSC_LINK: "/tmp/codesign.p12" CSC_KEY_PASSWORD: ${{ secrets.CODE_SIGN_P12_PASSWORD }} CSC_IDENTITY_AUTO_DISCOVERY: "true" APPLE_ID: ${{ secrets.APPLE_ID }} APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} APP_PATH: "." DEVELOPER_ID: ${{ secrets.DEVELOPER_ID }} - name: Upload Artifact uses: actions/upload-artifact@v2 with: name: jan-mac-x64-${{ steps.version_update.outputs.new_version }} path: ./electron/dist/jan-mac-x64-${{ steps.version_update.outputs.new_version }}.dmg - name: Upload Artifact uses: actions/upload-artifact@v2 with: name: jan-mac-arm64-${{ steps.version_update.outputs.new_version }} path: ./electron/dist/jan-mac-arm64-${{ steps.version_update.outputs.new_version }}.dmg - name: put-object using awscli s3api continue-on-error: true run: | ls -al ./electron/dist aws s3api put-object --endpoint-url https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com --bucket ${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }} --key "latest/jan-mac-x64-${{ steps.version_update.outputs.new_version }}.dmg" --body "./electron/dist/jan-mac-x64-${{ steps.version_update.outputs.new_version }}.dmg" --content-type "application/octet-stream" aws s3api put-object --endpoint-url https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com --bucket ${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }} --key "latest/jan-mac-arm64-${{ steps.version_update.outputs.new_version }}.dmg" --body "./electron/dist/jan-mac-arm64-${{ steps.version_update.outputs.new_version }}.dmg" --content-type "application/octet-stream" aws s3api put-object --endpoint-url https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com --bucket ${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }} --key "latest/jan-mac-x64-${{ steps.version_update.outputs.new_version }}.zip" --body "./electron/dist/jan-mac-x64-${{ steps.version_update.outputs.new_version }}.zip" --content-type "application/zip" aws s3api put-object --endpoint-url https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com --bucket ${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }} --key "latest/jan-mac-arm64-${{ steps.version_update.outputs.new_version }}.zip" --body "./electron/dist/jan-mac-arm64-${{ steps.version_update.outputs.new_version }}.zip" --content-type "application/zip" aws s3api put-object --endpoint-url https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com --bucket ${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }} --key "${{ steps.version_update.outputs.new_version }}/jan-mac-x64-${{ steps.version_update.outputs.new_version }}.dmg" --body "./electron/dist/jan-mac-x64-${{ steps.version_update.outputs.new_version }}.dmg" --content-type "application/octet-stream" aws s3api put-object --endpoint-url https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com --bucket ${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }} --key "${{ steps.version_update.outputs.new_version }}/jan-mac-arm64-${{ steps.version_update.outputs.new_version }}.dmg" --body "./electron/dist/jan-mac-arm64-${{ steps.version_update.outputs.new_version }}.dmg" --content-type "application/octet-stream" aws s3api put-object --endpoint-url https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com --bucket ${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }} --key "${{ steps.version_update.outputs.new_version }}/latest-mac.yml" --body "./electron/dist/latest-mac.yml" --content-type "text/yaml" aws s3api put-object --endpoint-url https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com --bucket ${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }} --key "latest/latest-mac.yml" --body "./electron/dist/latest-mac.yml" --content-type "text/yaml" env: AWS_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_SECRET_ACCESS_KEY }} AWS_DEFAULT_REGION: auto AWS_EC2_METADATA_DISABLED: "true" build-windows-x64: runs-on: windows-latest needs: delete-cloudflare-r2-folder permissions: contents: write steps: - name: Getting the repo uses: actions/checkout@v3 - name: Installing node uses: actions/setup-node@v1 with: node-version: 20 - name: Install jq uses: dcarbone/install-jq-action@v2.0.1 - name: Update app version base on tag id: version_update shell: bash run: | # Function to get the latest release tag get_latest_tag() { local retries=0 local max_retries=3 local tag while [ $retries -lt $max_retries ]; do tag=$(curl -s https://api.github.com/repos/janhq/jan/releases/latest | jq -r .tag_name) if [ -n "$tag" ] && [ "$tag" != "null" ]; then echo $tag return else let retries++ echo "Retrying... ($retries/$max_retries)" sleep 2 fi done echo "Failed to fetch latest tag after $max_retries attempts." exit 1 } # Get the latest release tag from GitHub API LATEST_TAG=$(get_latest_tag) # Remove the 'v' and append the build number to the version NEW_VERSION="${LATEST_TAG#v}-${GITHUB_RUN_NUMBER}" echo "New version: $NEW_VERSION" # Update the version in electron/package.json jq --arg version "$NEW_VERSION" '.version = $version' electron/package.json > /tmp/package.json mv /tmp/package.json electron/package.json echo "::set-output name=new_version::$NEW_VERSION" jq '.build.publish = [{"provider": "generic", "url": "${{ secrets.CLOUDFLARE_R2_PUBLIC_URL }}", "channel": "latest"}]' electron/package.json > /tmp/package.json mv /tmp/package.json electron/package.json jq '.build.win.sign = "./sign.js"' electron/package.json > /tmp/package.json mv /tmp/package.json electron/package.json - name: Install AzureSignTool run: | dotnet tool install --global AzureSignTool - name: Build app run: | make build env: AZURE_KEY_VAULT_URI: ${{ secrets.AZURE_KEY_VAULT_URI }} AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} AZURE_CERT_NAME: ${{ secrets.AZURE_CERT_NAME }} - name: Upload Artifact uses: actions/upload-artifact@v2 with: name: jan-win-x64-${{ steps.version_update.outputs.new_version }} path: ./electron/dist/*.exe - name: put-object using awscli s3api shell: bash run: | ls -al ./electron/dist aws s3api put-object --endpoint-url https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com --bucket ${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }} --key "latest/jan-win-x64-${{ steps.version_update.outputs.new_version }}.exe" --body "./electron/dist/jan-win-x64-${{ steps.version_update.outputs.new_version }}.exe" aws s3api put-object --endpoint-url https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com --bucket ${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }} --key "latest/jan-win-x64-${{ steps.version_update.outputs.new_version }}.exe.blockmap" --body "./electron/dist/jan-win-x64-${{ steps.version_update.outputs.new_version }}.exe.blockmap" aws s3api put-object --endpoint-url https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com --bucket ${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }} --key "${{ steps.version_update.outputs.new_version }}/jan-win-x64-${{ steps.version_update.outputs.new_version }}.exe" --body "./electron/dist/jan-win-x64-${{ steps.version_update.outputs.new_version }}.exe" aws s3api put-object --endpoint-url https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com --bucket ${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }} --key "latest/latest.yml" --body "./electron/dist/latest.yml" aws s3api put-object --endpoint-url https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com --bucket ${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }} --key "${{ steps.version_update.outputs.new_version }}/latest.yml" --body "./electron/dist/latest.yml" env: AWS_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_SECRET_ACCESS_KEY }} AWS_DEFAULT_REGION: auto AWS_EC2_METADATA_DISABLED: "true" build-linux-x64: runs-on: ubuntu-latest needs: delete-cloudflare-r2-folder environment: production env: SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_TOKEN }} permissions: contents: write steps: - name: Getting the repo uses: actions/checkout@v3 - name: Installing node uses: actions/setup-node@v1 with: node-version: 20 - name: Install jq uses: dcarbone/install-jq-action@v2.0.1 - name: Update app version base on tag id: version_update run: | # Function to get the latest release tag get_latest_tag() { local retries=0 local max_retries=3 local tag while [ $retries -lt $max_retries ]; do tag=$(curl -s https://api.github.com/repos/janhq/jan/releases/latest | jq -r .tag_name) if [ -n "$tag" ] && [ "$tag" != "null" ]; then echo $tag return else let retries++ echo "Retrying... ($retries/$max_retries)" sleep 2 fi done echo "Failed to fetch latest tag after $max_retries attempts." exit 1 } # Get the latest release tag from GitHub API LATEST_TAG=$(get_latest_tag) # Remove the 'v' and append the build number to the version NEW_VERSION="${LATEST_TAG#v}-${GITHUB_RUN_NUMBER}" echo "New version: $NEW_VERSION" # Update the version in electron/package.json jq --arg version "$NEW_VERSION" '.version = $version' electron/package.json > /tmp/package.json mv /tmp/package.json electron/package.json echo "::set-output name=new_version::$NEW_VERSION" jq '.build.publish = [{"provider": "generic", "url": "${{ secrets.CLOUDFLARE_R2_PUBLIC_URL }}", "channel": "latest"}]' electron/package.json > /tmp/package.json mv /tmp/package.json electron/package.json - name: Build and publish app run: | make build env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload Artifact uses: actions/upload-artifact@v2 with: name: jan-linux-amd64-${{ steps.version_update.outputs.new_version }} path: ./electron/dist/*.deb - name: put-object using awscli s3api run: | ls -al ./electron/dist aws s3api put-object --endpoint-url https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com --bucket ${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }} --key "latest/jan-linux-amd64-${{ steps.version_update.outputs.new_version }}.deb" --body "./electron/dist/jan-linux-amd64-${{ steps.version_update.outputs.new_version }}.deb" --content-type "application/octet-stream" aws s3api put-object --endpoint-url https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com --bucket ${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }} --key "${{ steps.version_update.outputs.new_version }}/jan-linux-amd64-${{ steps.version_update.outputs.new_version }}.deb" --body "./electron/dist/jan-linux-amd64-${{ steps.version_update.outputs.new_version }}.deb" --content-type "application/octet-stream" aws s3api put-object --endpoint-url https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com --bucket ${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }} --key "latest/latest-linux.yml" --body "./electron/dist/latest-linux.yml" --content-type "text/yaml" aws s3api put-object --endpoint-url https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com --bucket ${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }} --key "${{ steps.version_update.outputs.new_version }}/latest-linux.yml" --body "./electron/dist/latest-linux.yml" --content-type "text/yaml" env: AWS_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_SECRET_ACCESS_KEY }} AWS_DEFAULT_REGION: auto AWS_EC2_METADATA_DISABLED: "true" noti-discord-nightly-and-update-url-readme: needs: [build-macos, build-windows-x64, build-linux-x64, delete-cloudflare-r2-folder] environment: production if: github.event_name == 'schedule' runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v3 with: fetch-depth: "0" token: ${{ secrets.PAT_SERVICE_ACCOUNT }} - name: Notify Discord uses: Ilshidur/action-discord@master with: args: "Nightly build artifact: https://github.com/janhq/jan/actions/runs/{{ GITHUB_RUN_ID }}" env: DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} - name: Update README.md with artifact URL run: | sed -i "s|||" README.md git config --global user.email "service@jan.ai" git config --global user.name "Service Account" git add README.md git commit -m "${GITHUB_REPOSITORY}: Update README.md with nightly build artifact URL" git -c http.extraheader="AUTHORIZATION: bearer ${{ secrets.PAT_SERVICE_ACCOUNT }}" push origin HEAD:main env: GITHUB_RUN_ID: ${{ github.run_id }} noti-discord-manual-and-update-url-readme: needs: [build-macos, build-windows-x64, build-linux-x64, delete-cloudflare-r2-folder] environment: production if: github.event_name == 'workflow_dispatch' runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v3 with: fetch-depth: "0" token: ${{ secrets.PAT_SERVICE_ACCOUNT }} - name: Notify Discord uses: Ilshidur/action-discord@master with: args: "Manual build artifact: https://github.com/janhq/jan/actions/runs/{{ GITHUB_RUN_ID }}" env: DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} # Update README.md with artifact URL if manual build from main branch - name: Update README.md with artifact URL if: github.ref == 'refs/heads/main' run: | sed -i "s|||" README.md git config --global user.email "service@jan.ai" git config --global user.name "Service Account" git add README.md git commit -m "${GITHUB_REPOSITORY}: Update README.md with nightly build artifact URL" git -c http.extraheader="AUTHORIZATION: bearer ${{ secrets.PAT_SERVICE_ACCOUNT }}" push origin HEAD:main env: GITHUB_RUN_ID: ${{ github.run_id }}