Note: If you pass an invalid value to GetSpellInfo(), like a string or 0, it will return three empty strings, making checks like this return true regardless if the spell exists or not: if(GetSpellInfo('something')) then

GetMacroIcons(table) will (sometimes?) populate numbers in the table instead of string for texture file path.
And we need to use texture:SetToFileData() for numbers instead of texture:SetTexture() like below:

function AddonList_HasNewVersion()
local hasNewVersion = false;
for i=1, GetNumAddOns() do
local name, title, notes, loadable, reason, security, newVersion = GetAddOnInfo(i);
if ( newVersion ) then
hasNewVersion = true;
break;
end
end
return hasNewVersion;
end
function UpdateAddonButton()
if ( GetNumAddOns() > 0 ) then
-- Check to see if any of them are out of date and not disabled
if ( IsAddonVersionCheckEnabled() and AddonList_HasOutOfDate() and not HasShownAddonOutOfDateDialog ) then
AddonDialog_Show("ADDONS_OUT_OF_DATE");
HasShownAddonOutOfDateDialog = true;
end
if ( AddonList_HasNewVersion() ) then
CharacterSelectAddonsButtonGlow:Show();
else
CharacterSelectAddonsButtonGlow:Hide();
end
CharacterSelectAddonsButton:Show();
else
CharacterSelectAddonsButton:Hide();
end
end