-
-
Save Cheesebaron/a302d267e8f20eabee6c1123c96e8899 to your computer and use it in GitHub Desktop.
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
using System; | |
using System.IO; | |
using System.Collections.Generic; | |
using System.Threading.Tasks; | |
using Microsoft.AspNetCore.Mvc; | |
using Microsoft.Azure.WebJobs; | |
using Microsoft.Azure.WebJobs.Extensions.Http; | |
using Microsoft.AspNetCore.Http; | |
using Microsoft.Extensions.Logging; | |
using Newtonsoft.Json; | |
using System.Net.Http; | |
using System.Net.Http.Headers; | |
using System.Linq; | |
namespace dk.ostebaronen | |
{ | |
public static class DevOpsStatus | |
{ | |
private const string Pat = "your-azure-devops-pat"; | |
private static HttpClient _httpClient; | |
[FunctionName("DevOpsStatus")] | |
public static async Task<IActionResult> Run( | |
[HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req, | |
ILogger log) | |
{ | |
log.LogInformation("C# HTTP trigger function processed a request."); | |
var lastBuild = await GetLatestBuild().ConfigureAwait(false); | |
if (lastBuild == null) | |
{ | |
return new NotFoundObjectResult("No build found"); | |
} | |
foreach(var build in lastBuild) | |
{ | |
log.LogInformation($"{build.BuildNumber}: {build.Status} - {build.Result} - {build.Url}"); | |
} | |
var anyFailed = lastBuild.Any(b => b.Status?.ToLowerInvariant() == "failed"); | |
var anyRunning = lastBuild.Any(b => b.Result.ToLowerInvariant() == "inprogress"); | |
var allFinished = lastBuild.All(b => b.Result.ToLowerInvariant() == "succeeded" && b.Status?.ToLowerInvariant() == "completed"); | |
if (anyFailed) | |
return new OkObjectResult("failed"); | |
if (anyRunning) | |
return new OkObjectResult("running"); | |
if (allFinished) | |
return new OkObjectResult("finished"); | |
return new OkObjectResult("unknown"); | |
} | |
private static HttpClient EnsureHttpClient() | |
{ | |
if (_httpClient == null) | |
{ | |
_httpClient = new HttpClient(); | |
_httpClient.DefaultRequestHeaders.Authorization | |
= new AuthenticationHeaderValue( | |
"Basic", Pat); | |
_httpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("Cheesebulb", "1.0")); | |
} | |
return _httpClient; | |
} | |
private static async Task<IEnumerable<Build>> GetLatestBuild(int top = 4) | |
{ | |
var client = EnsureHttpClient(); | |
var organization = "your-azure-devops-org"; | |
var project = "your-project-id"; | |
var url = $"https://dev.azure.com/{organization}/{project}/_apis/build/builds?$top={top}&api-version=5.0"; | |
var response = await client.GetAsync(url).ConfigureAwait(false); | |
using (response) | |
{ | |
if (response.IsSuccessStatusCode) | |
{ | |
var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); | |
using (responseStream) | |
using (var streamReader = new StreamReader(responseStream)) | |
using (var jsonReader = new JsonTextReader(streamReader)) | |
{ | |
var serializer = new JsonSerializer(); | |
var results = serializer.Deserialize<Welcome>(jsonReader); | |
return results.Builds.Take(4); | |
} | |
} | |
} | |
return null; | |
} | |
} | |
public class Welcome | |
{ | |
[JsonProperty("count")] | |
public long Count { get; set; } | |
[JsonProperty("value")] | |
public Build[] Builds { get; set; } | |
} | |
public class Build | |
{ | |
[JsonProperty("id")] | |
public long Id { get; set; } | |
[JsonProperty("buildNumber")] | |
public string BuildNumber { get; set; } | |
[JsonProperty("status")] | |
public string Status { get; set; } | |
[JsonProperty("result")] | |
public string Result { get; set; } | |
[JsonProperty("queueTime")] | |
public DateTimeOffset QueueTime { get; set; } | |
[JsonProperty("startTime")] | |
public DateTimeOffset StartTime { get; set; } | |
[JsonProperty("finishTime")] | |
public DateTimeOffset FinishTime { get; set; } | |
[JsonProperty("url")] | |
public Uri Url { get; set; } | |
} | |
} |
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
#include <Arduino.h> | |
#include <ESP8266WiFi.h> | |
#include <WiFiClientSecure.h> | |
#include <NeoPixelBus.h> | |
const char* ssid = "your-wifi-ssid"; | |
const char* password = "hunter42"; | |
const unsigned long HTTP_TIMEOUT = 10000; | |
const char* host = "yourfunction.azurewebsites.net"; | |
const char* request = "/api/YourFunctionName?code=code"; | |
const int httpsPort = 443; | |
const uint8_t PixelCount = 9; | |
const uint8_t PixelPin = 0; // doesn't matter what you put here | |
NeoPixelBus<NeoGrbFeature, NeoEsp8266Dma800KbpsMethod> strip(PixelCount, PixelPin); | |
RgbColor off(0, 0, 0); | |
RgbColor red(255, 0, 0); | |
RgbColor green(0, 255, 0); | |
RgbColor blue(0, 0, 255); | |
RgbColor yellow(255, 255, 0); | |
RgbColor teal(0, 255, 255); | |
RgbColor purple(255, 0, 255); | |
RgbColor orange(255, 153, 0); | |
void setAllLedsColor(RgbColor color) | |
{ | |
for(uint8_t i = 0; i < PixelCount; i++) { | |
strip.SetPixelColor(i, color); | |
} | |
strip.Show(); | |
} | |
bool initializeWifi() { | |
if (WiFi.status() == WL_CONNECTED) | |
{ | |
Serial.println("WiFi already connected"); | |
return true; | |
} | |
Serial.print("Connecting to "); | |
Serial.println(ssid); | |
WiFi.mode(WIFI_STA); | |
WiFi.begin(ssid, password); | |
for(uint8_t i = 0; i < 100; i++) { | |
if (WiFi.status() != WL_CONNECTED) { | |
// blink the leds while connecting to WiFi | |
setAllLedsColor(off); | |
delay(400); | |
setAllLedsColor(purple); | |
Serial.print("."); | |
delay(400); | |
} | |
} | |
if (WiFi.status() == WL_CONNECTED) { | |
setAllLedsColor(orange); | |
Serial.println(""); | |
Serial.println("WiFi connected"); | |
Serial.println("IP address "); | |
Serial.println(WiFi.localIP()); | |
return true; | |
} | |
setAllLedsColor(off); | |
WiFi.disconnect(); | |
return false; | |
} | |
void setup() { | |
Serial.begin(115200); | |
strip.Begin(); | |
strip.Show(); | |
setAllLedsColor(off); | |
initializeWifi(); | |
} | |
WiFiClientSecure client; | |
bool connect() { | |
Serial.print("connecting to "); | |
Serial.println(host); | |
bool ok = client.connect(host, httpsPort); | |
Serial.println(ok ? "Connected Http" : "Connection Http Failed!"); | |
return ok; | |
} | |
void disconnect() { | |
Serial.println("Disconnect Http"); | |
client.stop(); | |
} | |
void sendRequest() { | |
client.print("GET "); | |
client.print(request); | |
client.println(" HTTP/1.1"); | |
client.print("Host: "); | |
client.println(host); | |
client.println("User-Agent: Cheesebulb/1.0"); | |
client.println("Connection: close"); | |
client.println(); | |
} | |
void skipHeaders() { | |
while (client.connected()) { | |
String line = client.readStringUntil('\n'); | |
if (line == "\r") { | |
Serial.println("headers received"); | |
break; | |
} | |
} | |
} | |
String lastStatus; | |
void readResponseContent() { | |
String status = client.readStringUntil('\n'); | |
Serial.println(status); | |
if (status == lastStatus) { | |
// no need to do anything | |
return; | |
} | |
if (status == "failed") { | |
setAllLedsColor(red); | |
} | |
else if (status == "running") { | |
setAllLedsColor(blue); | |
} | |
else if (status == "finished") { | |
setAllLedsColor(green); | |
} | |
else { | |
setAllLedsColor(yellow); | |
} | |
} | |
void getBuildStatus() | |
{ | |
if (connect()) { | |
sendRequest(); | |
skipHeaders(); | |
readResponseContent(); | |
} | |
disconnect(); | |
} | |
uint8_t reconnects = 0; | |
void loop() { | |
if (initializeWifi()) { | |
getBuildStatus(); | |
reconnects = 0; | |
delay(60000); | |
} | |
else { | |
lastStatus = "derp"; | |
reconnects = reconnects + 1; | |
if (reconnects == 120) { // 10 minutes | |
ESP.reset(); | |
} | |
// delay a bit and retry wifi | |
delay(5000); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment