Build App Packages and Collect App Information #145
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: Build App Packages and Collect App Information | |
on: | |
workflow_dispatch: | |
schedule: | |
- cron: "0 0 * * *" # Run at midnight UTC every day | |
jobs: | |
build: | |
runs-on: macos-latest | |
steps: | |
- name: Checkout repository | |
uses: actions/checkout@v4 | |
with: | |
token: ${{ secrets.PAT }} | |
- name: Set up Python | |
uses: actions/setup-python@v2 | |
with: | |
python-version: "3.x" | |
- name: Install dependencies | |
run: | | |
python -m pip install --upgrade pip | |
pip install requests | |
- name: Make scrapers executable | |
run: chmod +x .github/scripts/scrapers/*.sh | |
- name: Collect app information | |
run: python .github/scripts/collect_app_info.py | |
- name: Find apps needing packaging | |
id: find-apps | |
run: | | |
echo "Finding apps that need special packaging..." | |
apps_to_build=() | |
for file in Apps/*.json; do | |
if [ -f "$file" ]; then | |
type=$(jq -r '.type // empty' "$file") | |
if [ "$type" = "app" ] || [ "$type" = "pkg_in_dmg" ]; then | |
app_name=$(basename "$file" .json) | |
url=$(jq -r '.url' "$file") | |
apps_to_build+=("$app_name:$url") | |
fi | |
fi | |
done | |
echo "APPS_TO_BUILD=${apps_to_build[*]}" >> $GITHUB_ENV | |
echo "Found apps: ${apps_to_build[*]}" | |
- name: Create supported_apps.json | |
run: | | |
python - <<EOF | |
import json | |
import os | |
import re | |
apps_folder = "Apps" | |
supported_apps = {} | |
for filename in os.listdir(apps_folder): | |
if filename.endswith(".json"): | |
app_name = os.path.splitext(filename)[0] | |
supported_apps[app_name] = f"https://raw.githubusercontent.com/ugurkocde/IntuneBrew/main/Apps/{filename}" | |
# Sort the dictionary alphabetically by keys | |
supported_apps = dict(sorted(supported_apps.items())) | |
with open("supported_apps.json", "w") as f: | |
json.dump(supported_apps, f, indent=4) | |
# Update README with total number of apps | |
total_apps = len(supported_apps) | |
with open("README.md", "r") as f: | |
readme_content = f.read() | |
# Create a badge-style apps count | |
apps_count_pattern = r'<p>\s*<a href="#-supported-applications">\s*<img src="https://img\.shields\.io/badge/Apps_Available-\d+-2ea44f\?style=flat"[^>]*>\s*</a>\s*</p>' | |
new_apps_badge = f' <p>\n <a href="#-supported-applications">\n <img src="https://img.shields.io/badge/Apps_Available-{total_apps}-2ea44f?style=flat" alt="TotalApps"/>\n </a>\n </p>' | |
# Replace the existing badge with the new one, or add if not found | |
if re.search(apps_count_pattern, readme_content): | |
readme_content = re.sub(apps_count_pattern, new_apps_badge, readme_content) | |
else: | |
# If no badge exists, add after the first paragraph in the centered div | |
readme_content = re.sub(r'( </p>)\n</div>', f'\\1\n{new_apps_badge}\n</div>', readme_content) | |
with open("README.md", "w") as f: | |
f.write(readme_content) | |
print(f"Updated README.md with {total_apps} apps badge") | |
EOF | |
- name: Process apps | |
if: env.APPS_TO_BUILD != '' | |
env: | |
AZURE_STORAGE_CONNECTION_STRING: ${{ secrets.AZURE_STORAGE_CONNECTION_STRING }} | |
run: | | |
WORKSPACE_DIR=$(pwd) | |
for app_info in $APPS_TO_BUILD; do | |
IFS=':' read -r app_name url <<< "$app_info" | |
echo "🔄 Processing $app_name..." | |
# Check if JSON file exists | |
if [ ! -f "$WORKSPACE_DIR/Apps/${app_name}.json" ]; then | |
echo "📝 JSON file for $app_name doesn't exist. Creating new JSON file..." | |
cat > "$WORKSPACE_DIR/Apps/${app_name}.json" << 'EOF' | |
{ | |
"display_name": "APP_NAME", | |
"version": "0.0.0", | |
"url": "URL", | |
"type": "app", | |
"installer_type": "pkg", | |
"download_page": "", | |
"previous_version": "" | |
} | |
EOF | |
sed -i '' "s/APP_NAME/$app_name/g" "$WORKSPACE_DIR/Apps/${app_name}.json" | |
sed -i '' "s|URL|$url|g" "$WORKSPACE_DIR/Apps/${app_name}.json" | |
echo "✅ Created new JSON file for $app_name" | |
else | |
echo "📄 Using existing JSON file for $app_name" | |
fi | |
# Get version and type from JSON file | |
version=$(jq -r '.version' "$WORKSPACE_DIR/Apps/${app_name}.json") | |
app_type=$(jq -r '.type' "$WORKSPACE_DIR/Apps/${app_name}.json") | |
echo "📦 Version: $version" | |
echo "🏷️ Type: $app_type" | |
# Skip if not a supported type | |
if [ "$app_type" != "app" ] && [ "$app_type" != "pkg_in_dmg" ] && [ "$app_type" != "pkg_in_pkg" ]; then | |
echo "⏭️ Skipping URL update for $app_name as it's not of type 'app', 'pkg_in_dmg', or 'pkg_in_pkg'" | |
continue | |
fi | |
# List existing versions of this app in Azure storage | |
existing_versions=$(az storage blob list --container-name pkg --prefix "${app_name}_" --query "[].name" -o tsv) | |
# Check if the exact version already exists | |
if echo "$existing_versions" | grep -q "^${app_name}_${version}.pkg$"; then | |
echo "Package ${app_name}_${version}.pkg already exists in Azure storage. Skipping..." | |
# Update the JSON file with Azure URL | |
azure_url="https://intunebrew.blob.core.windows.net/pkg/${app_name}_${version}.pkg" | |
# Get current version to store as previous_version | |
current_version=$(jq -r '.version' "$WORKSPACE_DIR/Apps/${app_name}.json") | |
jq --arg url "$azure_url" --arg version "$version" --arg prev_version "$current_version" '.url = $url | .version = $version | .previous_version = $prev_version' "$WORKSPACE_DIR/Apps/${app_name}.json" > temp.json && mv temp.json "$WORKSPACE_DIR/Apps/${app_name}.json" | |
continue | |
fi | |
if [ "$app_type" = "pkg_in_pkg" ]; then | |
echo "🔍 Processing PKG in PKG for $app_name..." | |
echo "📥 Downloading PKG from: $url" | |
# Set download path | |
download_path="$HOME/Desktop/${app_name}" | |
# Download PKG | |
curl -L -o "${download_path}.pkg" "$url" | |
if [ $? -eq 0 ]; then | |
echo "✅ PKG download successful" | |
ls -lh "${download_path}.pkg" | |
# Create temporary directory for extraction | |
echo "📂 Creating temporary directory for extraction" | |
temp_dir="${download_path}_extracted" | |
mkdir -p "$temp_dir" | |
# Extract PKG | |
echo "🔓 Extracting outer PKG..." | |
pkgutil --expand "${download_path}.pkg" "$temp_dir" | |
if [ $? -eq 0 ]; then | |
echo "✅ PKG extraction successful" | |
echo "📁 Extracted contents:" | |
ls -R "$temp_dir" | |
# Find inner PKG file | |
echo "🔍 Searching for inner PKG file..." | |
inner_pkg=$(find "$temp_dir" -name "*.pkg" -print -quit) | |
if [ -n "$inner_pkg" ]; then | |
echo "✅ Found inner PKG file: $inner_pkg" | |
echo "📦 Package size: $(ls -lh "$inner_pkg" | awk '{print $5}')" | |
# Copy inner PKG file with version in filename | |
echo "📋 Copying inner PKG file to ${app_name}_${version}.pkg" | |
cp "$inner_pkg" "${app_name}_${version}.pkg" | |
# Calculate SHA256 hash | |
echo "🔐 Calculating SHA256 hash..." | |
file_hash=$(shasum -a 256 "${app_name}_${version}.pkg" | awk '{print $1}') | |
echo "📝 SHA256: $file_hash" | |
# Upload to Azure | |
echo "☁️ Uploading to Azure Blob Storage..." | |
az storage blob upload \ | |
--container-name pkg \ | |
--file "${app_name}_${version}.pkg" \ | |
--name "${app_name}_${version}.pkg" \ | |
--overwrite true | |
if [ $? -eq 0 ]; then | |
echo "✅ Upload successful" | |
# Update JSON with Azure URL and SHA256 | |
echo "📝 Updating JSON file with new Azure URL and SHA256..." | |
azure_url="https://intunebrew.blob.core.windows.net/pkg/${app_name}_${version}.pkg" | |
jq --arg url "$azure_url" --arg filename "${app_name}_${version}.pkg" --arg sha "$file_hash" '.url = $url | .fileName = $filename | .sha = $sha' "$WORKSPACE_DIR/Apps/${app_name}.json" > temp.json && mv temp.json "$WORKSPACE_DIR/Apps/${app_name}.json" | |
if [ $? -eq 0 ]; then | |
echo "✅ JSON file updated successfully" | |
echo "🔗 New URL: $azure_url" | |
else | |
echo "❌ Failed to update JSON file" | |
fi | |
else | |
echo "❌ Failed to upload to Azure" | |
fi | |
else | |
echo "❌ No inner PKG file found in extracted contents" | |
echo "📁 Extracted contents:" | |
ls -R "$temp_dir" | |
fi | |
else | |
echo "❌ Failed to extract PKG" | |
fi | |
# Cleanup | |
echo "🧹 Cleaning up..." | |
echo "🗑️ Removing temporary files..." | |
rm -f "${download_path}.pkg" | |
rm -rf "$temp_dir" | |
echo "✨ Cleanup complete" | |
else | |
echo "❌ Failed to download PKG" | |
fi | |
elif [ "$app_type" = "pkg_in_dmg" ]; then | |
echo "🔍 Processing PKG in DMG for $app_name..." | |
echo "📥 Downloading DMG from: $url" | |
# Set download path | |
download_path="$HOME/Desktop/${app_name}" | |
# Download DMG | |
curl -L -o "${download_path}.dmg" "$url" | |
if [ $? -eq 0 ]; then | |
echo "✅ DMG download successful" | |
ls -lh "${download_path}.dmg" | |
else | |
echo "❌ Failed to download DMG" | |
continue | |
fi | |
# Create mount point | |
echo "📂 Creating mount point at ${download_path}_mount" | |
mkdir -p "${download_path}_mount" | |
# Mount DMG | |
echo "💿 Mounting DMG..." | |
hdiutil attach "${download_path}.dmg" -mountpoint "${download_path}_mount" -nobrowse | |
if [ $? -eq 0 ]; then | |
echo "✅ DMG mounted successfully" | |
echo "📁 Mount point contents:" | |
ls -la "${download_path}_mount" | |
else | |
echo "❌ Failed to mount DMG" | |
rm -f "${download_path}.dmg" | |
rm -rf "${download_path}_mount" | |
continue | |
fi | |
# Find PKG file | |
echo "🔍 Searching for PKG file..." | |
pkg_file=$(find "${download_path}_mount" -name "*.pkg" -print -quit) | |
if [ -n "$pkg_file" ]; then | |
echo "✅ Found PKG file: $pkg_file" | |
echo "📦 Package size: $(ls -lh "$pkg_file" | awk '{print $5}')" | |
# Copy PKG file with version in filename | |
echo "📋 Copying PKG file to ${app_name}_${version}.pkg" | |
cp "$pkg_file" "${app_name}_${version}.pkg" | |
# Calculate SHA256 hash | |
echo "🔐 Calculating SHA256 hash..." | |
file_hash=$(shasum -a 256 "${app_name}_${version}.pkg" | awk '{print $1}') | |
echo "📝 SHA256: $file_hash" | |
# Upload to Azure | |
echo "☁️ Uploading to Azure Blob Storage..." | |
az storage blob upload \ | |
--container-name pkg \ | |
--file "${app_name}_${version}.pkg" \ | |
--name "${app_name}_${version}.pkg" \ | |
--overwrite true | |
if [ $? -eq 0 ]; then | |
echo "✅ Upload successful" | |
# Update JSON with Azure URL and SHA256 | |
echo "📝 Updating JSON file with new Azure URL and SHA256..." | |
azure_url="https://intunebrew.blob.core.windows.net/pkg/${app_name}_${version}.pkg" | |
jq --arg url "$azure_url" --arg filename "${app_name}_${version}.pkg" --arg sha "$file_hash" '.url = $url | .fileName = $filename | .sha = $sha' "$WORKSPACE_DIR/Apps/${app_name}.json" > temp.json && mv temp.json "$WORKSPACE_DIR/Apps/${app_name}.json" | |
if [ $? -eq 0 ]; then | |
echo "✅ JSON file updated successfully" | |
echo "🔗 New URL: $azure_url" | |
else | |
echo "❌ Failed to update JSON file" | |
fi | |
else | |
echo "❌ Failed to upload to Azure" | |
fi | |
else | |
echo "❌ No PKG file found in DMG for $app_name" | |
echo "📁 Contents of mount point:" | |
ls -R "${download_path}_mount" | |
fi | |
# Cleanup | |
echo "🧹 Cleaning up..." | |
echo "💿 Unmounting DMG..." | |
hdiutil detach "${download_path}_mount" | |
echo "🗑️ Removing temporary files..." | |
rm -f "${download_path}.dmg" | |
rm -rf "${download_path}_mount" | |
echo "✨ Cleanup complete" | |
else | |
# Download app | |
echo "Downloading $app_name..." | |
download_path="$HOME/Desktop/${app_name}" | |
if [[ "$url" == *".zip" ]]; then | |
curl -L -o "${download_path}.zip" "$url" | |
cd "$HOME/Desktop" | |
# Extract zip while excluding __MACOSX directory | |
unzip -q -d "${app_name}_extracted" "${download_path}.zip" | |
rm "${download_path}.zip" | |
elif [[ "$url" == *".tar.xz" ]]; then | |
echo "📦 Processing tar.xz archive for $app_name..." | |
curl -L -o "${download_path}.tar.xz" "$url" | |
cd "$HOME/Desktop" | |
# Extract tar.xz | |
echo "📂 Creating extraction directory..." | |
mkdir -p "${app_name}_extracted" | |
echo "🔓 Extracting tar.xz archive..." | |
tar -xf "${download_path}.tar.xz" -C "${app_name}_extracted" | |
echo "🗑️ Cleaning up downloaded archive..." | |
rm "${download_path}.tar.xz" | |
echo "📁 Extracted contents:" | |
ls -R "${app_name}_extracted" | |
elif [[ "$url" == *".tar.bz2" ]]; then | |
echo "📦 Processing tar.bz2 archive for $app_name..." | |
curl -L -o "${download_path}.tar.bz2" "$url" | |
cd "$HOME/Desktop" | |
# Extract tar.bz2 | |
echo "📂 Creating extraction directory..." | |
mkdir -p "${app_name}_extracted" | |
echo "🔓 Extracting tar.bz2 archive..." | |
tar -xjf "${download_path}.tar.bz2" -C "${app_name}_extracted" | |
echo "🗑️ Cleaning up downloaded archive..." | |
rm "${download_path}.tar.bz2" | |
echo "📁 Extracted contents:" | |
ls -R "${app_name}_extracted" | |
elif [[ "$url" == *".tar.gz" ]]; then | |
echo "📦 Processing tar.gz archive for $app_name..." | |
curl -L -o "${download_path}.tar.gz" "$url" | |
cd "$HOME/Desktop" | |
# Extract tar.gz | |
echo "📂 Creating extraction directory..." | |
mkdir -p "${app_name}_extracted" | |
echo "🔓 Extracting tar.gz archive..." | |
tar -xzf "${download_path}.tar.gz" -C "${app_name}_extracted" | |
echo "🗑️ Cleaning up downloaded archive..." | |
rm "${download_path}.tar.gz" | |
echo "📁 Extracted contents:" | |
ls -R "${app_name}_extracted" | |
else | |
curl -L -o "${download_path}.zip" "$url" | |
cd "$HOME/Desktop" | |
# Default to zip extraction | |
unzip -q -d "${app_name}_extracted" "${download_path}.zip" | |
rm "${download_path}.zip" | |
fi | |
# First try to find .app file recursively, excluding __MACOSX directory | |
echo "🔍 Searching for .app file recursively..." | |
app_file=$(find "${app_name}_extracted" -type d -name "*.app" ! -path "*/__MACOSX/*" -print -quit) | |
if [ -z "$app_file" ]; then | |
echo "❌ No .app file found, searching for .pkg file..." | |
pkg_file=$(find "${app_name}_extracted" -type f -name "*.pkg" ! -path "*/__MACOSX/*" -print -quit) | |
if [ -n "$pkg_file" ]; then | |
echo "✅ Found .pkg file: $pkg_file" | |
echo "📦 Package size: $(ls -lh "$pkg_file" | awk '{print $5}')" | |
# Copy PKG file with version in filename | |
echo "📋 Copying PKG file to ${app_name}_${version}.pkg" | |
cp "$pkg_file" "${app_name}_${version}.pkg" | |
# Calculate SHA256 hash | |
echo "🔐 Calculating SHA256 hash..." | |
file_hash=$(shasum -a 256 "${app_name}_${version}.pkg" | awk '{print $1}') | |
echo "📝 SHA256: $file_hash" | |
# Upload to Azure | |
echo "☁️ Uploading to Azure Blob Storage..." | |
az storage blob upload \ | |
--container-name pkg \ | |
--file "${app_name}_${version}.pkg" \ | |
--name "${app_name}_${version}.pkg" \ | |
--overwrite true | |
if [ $? -eq 0 ]; then | |
echo "✅ Upload successful" | |
# Update JSON with Azure URL and SHA256 | |
echo "📝 Updating JSON file with new Azure URL and SHA256..." | |
azure_url="https://intunebrew.blob.core.windows.net/pkg/${app_name}_${version}.pkg" | |
jq --arg url "$azure_url" --arg filename "${app_name}_${version}.pkg" --arg sha "$file_hash" '.url = $url | .fileName = $filename | .sha = $sha' "$WORKSPACE_DIR/Apps/${app_name}.json" > temp.json && mv temp.json "$WORKSPACE_DIR/Apps/${app_name}.json" | |
if [ $? -eq 0 ]; then | |
echo "✅ JSON file updated successfully" | |
echo "🔗 New URL: $azure_url" | |
else | |
echo "❌ Failed to update JSON file" | |
fi | |
else | |
echo "❌ Failed to upload to Azure" | |
fi | |
# Clean up and continue to next app | |
cd "$WORKSPACE_DIR" | |
rm -rf "${app_name}_extracted" | |
continue | |
else | |
echo "❌ No .app or .pkg file found for $app_name" | |
echo " Extracted contents:" | |
ls -R "${app_name}_extracted" | |
cd "$WORKSPACE_DIR" | |
rm -rf "${app_name}_extracted" | |
continue | |
fi | |
fi | |
echo "✅ Found .app file: $app_file" | |
# Build PKG with version in filename | |
echo "Building PKG for $app_name version $version..." | |
pkgbuild --install-location /Applications --component "$app_file" "${app_name}_${version}.pkg" | |
# Calculate SHA256 hash | |
echo "🔐 Calculating SHA256 hash..." | |
file_hash=$(shasum -a 256 "${app_name}_${version}.pkg" | awk '{print $1}') | |
echo "📝 SHA256: $file_hash" | |
# Upload to Azure with version in filename | |
echo "Uploading $app_name version $version to Azure Blob Storage..." | |
az storage blob upload \ | |
--container-name pkg \ | |
--file "${app_name}_${version}.pkg" \ | |
--name "${app_name}_${version}.pkg" \ | |
--overwrite true | |
# Delete older versions of this app from Azure storage | |
if [ ! -z "$existing_versions" ]; then | |
echo "Cleaning up older versions of $app_name..." | |
echo "$existing_versions" | while read -r blob_name; do | |
if [ ! -z "$blob_name" ] && [ "$blob_name" != "${app_name}_${version}.pkg" ]; then | |
echo "Deleting old version: $blob_name" | |
az storage blob delete --container-name pkg --name "$blob_name" | |
fi | |
done | |
fi | |
# Update the JSON file with Azure URL, filename and SHA256 | |
azure_url="https://intunebrew.blob.core.windows.net/pkg/${app_name}_${version}.pkg" | |
jq --arg url "$azure_url" --arg filename "${app_name}_${version}.pkg" --arg sha "$file_hash" '.url = $url | .fileName = $filename | .sha = $sha' "$WORKSPACE_DIR/Apps/${app_name}.json" > temp.json && mv temp.json "$WORKSPACE_DIR/Apps/${app_name}.json" | |
# Cleanup | |
sudo rm -rf "${app_name}_extracted" | |
fi | |
echo "✅ Completed processing $app_name" | |
echo "------------------------------------------------" | |
done | |
- name: Commit and push changes | |
run: | | |
git config --local user.email "[email protected]" | |
git config --local user.name "GitHub Action" | |
git add Apps/*.json supported_apps.json README.md | |
git commit -m "Update app information and supported apps list" || exit 0 | |
git push https://${{ secrets.PAT }}@github.com/${{ github.repository }}.git |