Electron Builder - Nightly / Manual #96
This file contains 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: 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/[email protected] | |
- 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/[email protected] | |
- 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/[email protected] | |
- 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|<a href='https://github.com/janhq/jan/actions/runs/.*'>|<a href='https://github.com/janhq/jan/actions/runs/${GITHUB_RUN_ID}'>|" README.md | |
git config --global user.email "[email protected]" | |
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|<a href='https://github.com/janhq/jan/actions/runs/.*'>|<a href='https://github.com/janhq/jan/actions/runs/${GITHUB_RUN_ID}'>|" README.md | |
git config --global user.email "[email protected]" | |
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 }} |