Scheduling Posts with GitOps, Durable Functions and GitHub Actions
{ | |
"owner": "aliencube", | |
"repository": "blog", | |
"issueId": 3, | |
"schedule": "2020-03-25T07:00:00+09:00" | |
} |
{ | |
"owner": "devkimchi", | |
"repository": "blog", | |
"issueId": 3, | |
"schedule": "2020-03-25T07:00:00+09:00" | |
} |
[FunctionName("SetSchedule")] | |
public async Task<HttpResponseMessage> SetSchedule( | |
[HttpTrigger(AuthorizationLevel.Function, "post", Route = "orchestrators/{orchestratorName}")] HttpRequestMessage req, | |
[DurableClient] IDurableOrchestrationClient starter, | |
string orchestratorName, | |
ILogger log) | |
{ | |
var input = await req.Content.ReadAsAsync<EventSchedulingRequest>(); | |
var instanceId = await starter.StartNewAsync<EventSchedulingRequest>(orchestratorName, instanceId: null, input: input); | |
log.LogInformation($"Started orchestration with ID = '{instanceId}'."); | |
return starter.CreateCheckStatusResponse(req, instanceId); | |
} |
[FunctionName("schedule-event")] | |
public async Task<object> RunOrchestrator( | |
[OrchestrationTrigger] IDurableOrchestrationContext context, | |
ILogger log) | |
{ | |
var input = context.GetInput<EventSchedulingRequest>(); | |
// Set the maximum duration. Max duration can't exceed 7 days. | |
var maxDuration = TimeSpan.Parse(Environment.GetEnvironmentVariable("Duration__Max"), CultureInfo.InvariantCulture); | |
if (maxDuration > threshold) | |
{ | |
return "Now allowed"; | |
} | |
// Get the scheduled time | |
var scheduled = input.Schedule.UtcDateTime; | |
// Get the function initiated time. | |
var initiated = context.CurrentUtcDateTime; | |
// Get the difference between now and schedule | |
var datediff = (TimeSpan)(scheduled - initiated); | |
// Complete if datediff is longer than the max duration | |
if (datediff >= maxDuration) | |
{ | |
return "Too far away"; | |
} | |
await context.CreateTimer(scheduled, CancellationToken.None); | |
var output = await context.CallActivityAsync<object>("CallRepositoryDispatchEvent", input); | |
return output; | |
} |
[FunctionName("CallMergePrRepositoryDispatchEvent")] | |
public async Task<object> MergePr( | |
[ActivityTrigger] EventSchedulingRequest input, | |
ILogger log) | |
{ | |
var authKey = Environment.GetEnvironmentVariable("GitHub__AuthKey"); | |
var requestUri = $"{Environment.GetEnvironmentVariable("GitHub__BaseUri").TrimEnd('/')}/repos/{input.Owner}/{input.Repository}/{Environment.GetEnvironmentVariable("GitHub__Endpoints__Dispatches").TrimStart('/')}"; | |
var accept = Environment.GetEnvironmentVariable("GitHub__Headers__Accept"); | |
var userAgent = Environment.GetEnvironmentVariable("GitHub__Headers__UserAgent"); | |
this._client.DefaultRequestHeaders.Clear(); | |
this._client.DefaultRequestHeaders.Add("Authorization", authKey); | |
this._client.DefaultRequestHeaders.Add("Accept", accept); | |
this._client.DefaultRequestHeaders.Add("User-Agent", userAgent); | |
var payload = new RepositoryDispatchEventRequest<EventSchedulingRequest>("merge-pr", input); | |
using (var content = new ObjectContent<RepositoryDispatchEventRequest<EventSchedulingRequest>>(payload, this._formatter, "application/json")) | |
using (var response = await this._client.PostAsync(requestUri, content).ConfigureAwait(false)) | |
{ | |
response.EnsureSuccessStatusCode(); | |
} | |
return payload; | |
} |
[FunctionName("CallPublishRepositoryDispatchEvent")] | |
public async Task<IActionResult> Publish( | |
[HttpTrigger(AuthorizationLevel.Function, "post", Route = "events/publish")] HttpRequest req, | |
ILogger log) | |
{ | |
var input = JsonConvert.DeserializeObject<EventRequest>(await new StreamReader(req.Body).ReadToEndAsync()); | |
var authKey = Environment.GetEnvironmentVariable("GitHub__AuthKey"); | |
var requestUri = $"{Environment.GetEnvironmentVariable("GitHub__BaseUri").TrimEnd('/')}/repos/{input.Owner}/{input.Repository}/{Environment.GetEnvironmentVariable("GitHub__Endpoints__Dispatches").TrimStart('/')}"; | |
var accept = Environment.GetEnvironmentVariable("GitHub__Headers__Accept"); | |
var userAgent = Environment.GetEnvironmentVariable("GitHub__Headers__UserAgent"); | |
this._client.DefaultRequestHeaders.Clear(); | |
this._client.DefaultRequestHeaders.Add("Authorization", authKey); | |
this._client.DefaultRequestHeaders.Add("Accept", accept); | |
this._client.DefaultRequestHeaders.Add("User-Agent", userAgent); | |
var payload = new RepositoryDispatchEventRequest<EventSchedulingRequest>("publish", input); | |
using (var content = new ObjectContent<RepositoryDispatchEventRequest<EventSchedulingRequest>>(payload, this._formatter, "application/json")) | |
using (var response = await this._client.PostAsync(requestUri, content).ConfigureAwait(false)) | |
{ | |
response.EnsureSuccessStatusCode(); | |
} | |
return payload; | |
} |
name: Merge PR | |
on: repository_dispatch | |
jobs: | |
merge_pr: | |
name: Merge PR | |
if: github.event.action == 'merge-pr' | |
runs-on: ubuntu-latest | |
steps: | |
- name: Merge PR | |
uses: justinyoo/github-pr-merge-action@v0.8.0 | |
with: | |
authToken: ${{ secrets.GITHUB_TOKEN }} | |
owner: ${{ github.event.client_payload.owner }} | |
repository: ${{ github.event.client_payload.repository }} | |
issueId: '${{ github.event.client_payload.issueId }}' | |
mergeMethod: Squash | |
commitTitle: '' | |
commitDescription: '' | |
deleteBranch: 'true' | |
- name: Send dispatch event for publish | |
shell: bash | |
run: | | |
curl -X POST 'https://${{ secrets.AZURE_FUNCTIONS_NAME }}.azurewebsites.net/api/events/publish' -d '{ "owner": "${{ secrets.OWNER }}", "repository": "${{ secrets.REPOSITORY }}" }' -H "x-functions-key: ${{ secrets.AZURE_FUNCTIONS_KEY }}" -H "Content-Type: application/json" | |
build_and_publish: | |
name: Build and publish | |
if: github.event.action == 'publish' | |
runs-on: ubuntu-latest | |
steps: | |
... |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment