Skip to content

Download Azure Icons #13

Download Azure Icons

Download Azure Icons #13

name: Download Azure Icons
on:
schedule:
- cron: '12 3 * * *'
workflow_dispatch:
jobs:
download:
runs-on: ubuntu-latest
name: Download
outputs:
confighash: ${{ steps.src.outputs.confighash }}
pageversion: ${{ steps.src.outputs.pageversion }}
steps:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.8
- id: src
name: Download sources
shell: pwsh
run: |
# Azure Portal config
$portalconfig=if((irm "https://portal.azure.com/") -match 'MsPortalImpl\.redirect\(([^)]+)\)'){$matches[1]|convertfrom-json}else{throw}
$portalconfighash=$portalconfig.portalServerConfig.portalQuery.configHash
"confighash=$portalconfighash" >> $env:GITHUB_OUTPUT
$portalconfigpageversion=$portalconfig.portalServerConfig.portalQuery.pageVersion
"pageversion=$portalconfigpageversion" >> $env:GITHUB_OUTPUT
"Downloading from Azure Portal version $portalconfigpageversion with config hash $portalconfighash" >> $env:GITHUB_STEP_SUMMARY
# Requires config
$portalrequiresfile=if((irm "https://portal.azure.com/?configHash=$portalconfighash&pageVersion=$portalconfigpageversion") -match '"/Content/PortalRequireConfig/([^"]+)"'){$matches[1]}else{throw}
$portalrequires=if((irm "https://portal.azure.com/Content/PortalRequireConfig/$portalrequiresfile") -match 'MsPortalImpl\.setRequireConfig\(([^)]+)\)'){$matches[1]|convertfrom-json}else{throw}
# Icon Styles CSS
$portalcssfile=($portalrequires.requireConfig.dependencyTree.psobject.properties|?{$_.value.psobject.properties.name -contains '_generated/Less/MsPortalImpl/Base/Base.Images.css'}).name
$iconstyles=if((irm "https://portal.azure.com/$($portalcssfile).js") -match 'define\("_generated/Less/MsPortalImpl/Base/Base\.Images\.css".*return{css:"([^"]+)"'){$matches[1]}else{throw}
$iconstyles|out-file icon-styles.css -nonewline
# Image Library JSON
$imagelibraryfile=($portalrequires.requireConfig.dependencyTree.psobject.properties|?{$_.value.psobject.properties.name -contains 'MsPortalImpl/Base/Base.ImageLibrary'}).name
$imagelibraryjs=irm "https://portal.azure.com/$($imagelibraryfile).js"
$imagelibrary=([regex]'{type:(\d+),data:"(<svg[^"]+</svg>)"}').matches($imagelibraryjs)|select @{n='type';e={[int]($_.groups[1].value)}},@{n='svg';e={$_.groups[2].value}}
$svglibrary=$portalrequires.requireConfig.dependencyTree.psobject.properties|?{$_.value.psobject.properties.name -like '*.svg'}|select -exp name|sort-object -unique|%{([regex]'{type:(\d+),data:"(<svg[^"]+</svg>)"}').matches((irm "https://portal.azure.com/$($_).js"))|select @{n='type';e={[int]($_.groups[1].value)}},@{n='svg';e={$_.groups[2].value}}}
$iconlibrary=$imagelibrary+$svglibrary
$iconlibrary|convertto-json -depth 100|out-file icon-library.json
"Got total of $($iconlibrary.count) library icons" >> $env:GITHUB_STEP_SUMMARY
# Icon Assets JSON
$manifestindex=$portalconfig.portalServerConfig.supportedLanguages.IndexOf('en')
$manifesthash=$portalconfig.portalServerConfig.environment.extensionsManifestHash.assetTypes[$manifestindex][0]
$iconassets=(irm "https://portal.azure.com/Content/ExtensionManifest/$manifesthash.json").manifest
$iconassets|convertto-json -depth 100|out-file icon-assets.json
"Got total of $($iconassets.psobject.properties.value.count) manifests and $($iconassets.psobject.properties.value.assettypes.count) assets" >> $env:GITHUB_STEP_SUMMARY
- id: upload-src
name: Save sources
uses: actions/upload-artifact@v4
with:
name: src
compression-level: 9
path: |
icon-styles.css
icon-library.json
icon-assets.json
- name: Convert sources to icon data
shell: pwsh
run: |
$iconstyles=gc icon-styles.css -raw
$iconlibrary=gc icon-library.json|convertfrom-json
$iconassets=gc icon-assets.json|convertfrom-json
$iconlibraryhashtable=$iconlibrary|%{$ht=@{}}{$ht[[int]$_.type]=$_.svg}{$ht}
$icondata=$iconassets.psobject.properties|?{$_.value.assetTypes}|%{
$m=$_.name
$_.value.assetTypes|?{$_.icon.length -gt 0}|%{
$firsticon=$null
$firsticon=$_.icon[0]
$firsticontype=[int]$firsticon.type
if($firsticon.data -like '<svg*'){
$svg=$firsticon.data
}elseif($firsticontype -gt 1 -and $iconlibraryhashtable.contains($firsticontype)){
$svg=$iconlibraryhashtable[$firsticontype]
}else{
$svg='<svg viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg"><text x="0" y="25" class="small">'+$firsticontype+'</text></svg>'
}
$svg=$svg -replace "xmlns:svg='http://www.w3.org/2000/svg'","xmlns='http://www.w3.org/2000/svg'"
$svg=$svg -replace '</svg>',"<style>$iconstyles</style></svg>"
$svg=$svg -replace '<title></title>',"<title>$([web.httputility]::htmlencode(($_.singularDisplayName -replace "`n",'')))</title><desc>$([web.httputility]::htmlencode(($_.description -replace "`n",' ')))</desc>"
[pscustomobject]@{
name="$($m)/$($_.name)"
svg=$svg
singularDisplayName=$_.singularDisplayName -replace "`n",''
pluralDisplayName=$_.pluralDisplayName -replace "`n",''
resourceType=$_.resourceType.resourceTypeName -replace "`n",''
keywords=$_.keywords -replace "`n",' '
description=$_.description -replace "`n",' '
}
}
}
"Resolved $($icondata.count) icons" >> $env:GITHUB_STEP_SUMMARY
$icondata|convertto-json -depth 100|out-file icon-data.json
- id: upload-data
name: Upload icon data
uses: actions/upload-artifact@v4
with:
name: data
compression-level: 9
path: icon-data.json
- name: Save SVG icons
shell: pwsh
run: |
$icondata=gc icon-data.json|convertfrom-json
new-item -itemtype directory -name svg|out-null
$iconstat=$icondata|%{$_.svg|new-item -path "svg/$($_.name).svg" -force}|measure-object -property length -sum
"Created $($iconstat.count) svg files with total size $([math]::round($iconstat.sum/1024/1024, 1))MB"
- name: Export Draw.io shape library
run: |
pip install drawio-svg-library
mkdir drawio
drawio-svg-library $(find . -name "*.svg") --output "drawio/Azure portal icons.xml"
- name: Compose HTML
shell: pwsh
run: |
$icondata=gc icon-data.json|convertfrom-json
$html=$icondata|% `
{"<html><head><meta name=`"viewport`" content=`"width=device-width, initial-scale=1`"><title>Azure Icons</title><style>body{margin:0}table,th,td{border:1px solid #CCCCCC;border-collapse:collapse;padding:3px}tbody{word-break:break-all;}thead,tfoot{position:sticky;}thead{inset-block-start:0;background-color:#CCCCCC}tfoot{inset-block-end:0;background-color:#CCCCCC}a:link,a:visited,a:hover{color:black}a:active{color:blue}</style><script>function download(uri, name){const a=document.createElement(`"a`");a.href=uri;a.download=name+`".svg`";a.click();}</script></head><body><table><thead><tr><th scope=`"col`" style=`"width: 10%`">Click to download</th><th scope=`"col`" style=`"width: 20%`">Name</th><th scope=`"col`" style=`"width: 20%`">Type</th><th scope=`"col`" style=`"width: 20%`">Keywords</th><th scope=`"col`" style=`"width: 30%`">Description</th></tr></thead><tbody>"} `
{"<tr title=`"$($_.name)`"><td><img loading=`"lazy`" decoding=`"async`" src=`"svg/$($_.name).svg`" alt=`"$($_.singularDisplayName)`" title=`"Click to download`" onclick=`"download(this.src, this.alt)`" /></td><td>$($_.singularDisplayName)</td><td>$($_.resourceType)</td><td>$($_.keywords)</td><td>$($_.description)</td></tr>"} `
{"</tbody><tfoot><tr><td colspan=`"5`">Extracted from Azure Portal version ${{ steps.src.outputs.pageversion }} on $(get-date -f 'yyyy-MM-dd'). Icons <a target=`"_blank`" href=`"https://www.microsoft.com/en-us/legal/intellectualproperty/copyright/permissions`">used with permission from Microsoft</a>. Source on <a target=`"_blank`" href=`"https://github.com/maskati/azure-icons`">GitHub</a>.</td></tr></tfoot></table></body></html>"}|out-string
$html|out-file index.html
"Created HTML of $([math]::round((gi index.html).length/1024/1024, 1))MB" >> $env:GITHUB_STEP_SUMMARY
- id: upload-azure-icons
name: Upload Azure Icons
uses: actions/upload-artifact@v4
with:
name: azure-icons
compression-level: 9
path: |
svg/
drawio/
index.html
- name: Compose Markdown
shell: pwsh
run: |
$icondata=gc icon-data.json|convertfrom-json
$markdown=$icondata|% `
{"# Azure Icons`n`nExtracted from Azure Portal version ${{ steps.src.outputs.pageversion }} on $(get-date -f 'yyyy-MM-dd').`n`nIcons [used with permission from Microsoft](https://www.microsoft.com/en-us/legal/intellectualproperty/copyright/permissions).`n`n| Icon | Type |`n| --- | --- |"} `
{"| [$($_.singularDisplayName -replace '\[|\]|\|','')](svg/$($_.name).svg) | $($_.resourceType -replace '/','/ ') |"} `
{""}|out-string
$markdown|out-file README.md
"Created Markdown of $([math]::round((gi README.md).length/1024/1024, 1))MB" >> $env:GITHUB_STEP_SUMMARY
- name: Upload Markdown
uses: actions/upload-artifact@v4
with:
name: markdown
compression-level: 9
path: README.md
commit:
runs-on: ubuntu-22.04
name: Commit
permissions:
actions: write # required for workflow_dispatch
contents: write # required for git push
needs: download
steps:
- name: Git checkout
uses: actions/checkout@v4
- name: Download Azure Icons
uses: actions/download-artifact@v4
with:
name: azure-icons
path: .
- name: Download markdown
uses: actions/download-artifact@v4
with:
name: markdown
path: .
- name: Git config as workflow
run: |
git config user.name "GitHub Actions (${{ github.workflow }})"
git config user.email "<>"
- name: Git add and commit if changed
run: |
git add svg/*
git add index.html
git add README.md
git add drawio/*
git diff-index --quiet HEAD || git commit -m 'Update to version ${{ needs.download.outputs.pageversion }}'
- name: Git push
run: |
git push origin main
- name: Trigger publish
uses: actions/github-script@v7
with:
script: |
github.rest.actions.createWorkflowDispatch({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: 'static.yml',
ref: 'main',
})