Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit268cd26

Browse files
authored
Merge pull request#508 from coderoad/webhook
WIP: webhook demo
2 parents3261bed +ae5345c commit268cd26

File tree

9 files changed

+158
-5
lines changed

9 files changed

+158
-5
lines changed

‎docs/docs/env-vars.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ CodeRoad has a number of configurations:
1818

1919
-`CODEROAD_CONTENT_SECURITY_POLICY_EXEMPTIONS` - a list of CSP exemption hashes. For multiples, separate the list with a space.
2020

21+
-`CODEROAD_WEBHOOK_TOKEN` - an optional token for authenticating/authorizing webhook endpoints. Passed to the webhook endpoint in a`CodeRoad-User-Token` header.
22+
2123
##How to Use Variables
2224

2325
###Local

‎src/actions/onRunReset.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ const onRunReset = async (action: ResetAction, context: Context): Promise<void>
3232
// if tutorial.config.reset.command, run it
3333
constresetActions=tutorial?.config?.reset
3434
if(resetActions){
35-
hooks.onReset({commands:resetActions?.commands,vscodeCommands:resetActions?.vscodeCommands})
35+
hooks.onReset(
36+
{commands:resetActions?.commands,vscodeCommands:resetActions?.vscodeCommands},
37+
tutorial?.idasstring,
38+
)
3639
}
3740
}
3841

‎src/actions/onTutorialConfigContinue.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import Context from '../services/context/context'
55
importtutorialConfigfrom'./utils/tutorialConfig'
66
import{COMMANDS,send}from'../commands'
77
importloggerfrom'../services/logger'
8+
import{setupWebhook}from'../services/hooks/webhooks'
89

910
constonTutorialConfigContinue=async(action:T.Action,context:Context):Promise<void>=>{
1011
logger('onTutorialConfigContinue',action)
@@ -19,6 +20,11 @@ const onTutorialConfigContinue = async (action: T.Action, context: Context): Pro
1920
data:tutorialToContinue,
2021
alreadyConfigured:true,
2122
})
23+
24+
// configure webhook
25+
if(tutorialToContinue.config?.webhook){
26+
setupWebhook(tutorialToContinue.config.webhook)
27+
}
2228
}catch(e){
2329
consterror={
2430
type:'UnknownError',

‎src/actions/onTutorialConfigNew.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { version, compareVersions } from '../services/dependencies'
88
importContextfrom'../services/context/context'
99
importtutorialConfigfrom'./utils/tutorialConfig'
1010
import{send}from'../commands'
11+
import{setupWebhook}from'../services/hooks/webhooks'
1112

1213
constonTutorialConfigNew=async(action:T.Action,context:Context):Promise<void>=>{
1314
try{
@@ -108,6 +109,11 @@ const onTutorialConfigNew = async (action: T.Action, context: Context): Promise<
108109
return
109110
}
110111

112+
// configure webhook
113+
if(data.config?.webhook){
114+
setupWebhook(data.config.webhook)
115+
}
116+
111117
// report back to the webview that setup is complete
112118
send({type:'TUTORIAL_CONFIGURED'})
113119
}catch(e){

‎src/commands.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export const createCommands = (commandProps: CreateCommandProps): { [key: string
7171
if(!alreadyConfigured){
7272
constsetupActions=data.config.setup
7373
if(setupActions){
74-
hooks.onInit(setupActions)
74+
hooks.onInit(setupActions,data.id)
7575
}
7676
}
7777
testRunner=createTestRunner(data,{

‎src/environment.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,6 @@ export const DISABLE_RUN_ON_SAVE = (process.env.CODEROAD_DISABLE_RUN_ON_SAVE ||
4343
// for multiple exemptions, separate each with a space "a1 b1"
4444
exportconstCONTENT_SECURITY_POLICY_EXEMPTIONS:string|null=
4545
process.env.CODEROAD_CONTENT_SECURITY_POLICY_EXEMPTIONS||null
46+
47+
// optional token for authorization/authentication of webhook calls
48+
exportconstWEBHOOK_TOKEN=process.env.CODEROAD_WEBHOOK_TOKEN||null

‎src/services/hooks/index.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,18 @@ import runCommands from './utils/runCommands'
77
importrunVSCodeCommandsfrom'./utils/runVSCodeCommands'
88
import*astelemetryfrom'../telemetry'
99
import{runTest}from'../../actions/onTest'
10-
importloggerfrom'../logger'
1110
import{VERSION}from'../../environment'
11+
import*aswebhooksfrom'./webhooks'
1212

1313
// run at the end of when a tutorial is configured
14-
exportconstonInit=async(actions:TT.StepActions):Promise<void>=>{
14+
exportconstonInit=async(actions:TT.StepActions,tutorialId:string):Promise<void>=>{
1515
awaitloadCommits(actions?.commits)
1616
awaitrunCommands(actions?.commands)
1717
awaitrunVSCodeCommands(actions?.vscodeCommands)
18+
webhooks.onInit({
19+
tutorialId,
20+
coderoadVersion:VERSION,
21+
})
1822
}
1923

2024
// run when a level starts
@@ -43,10 +47,13 @@ export const onSolutionEnter = async (actions: TT.StepActions): Promise<void> =>
4347
}
4448

4549
// run when "reset" is triggered
46-
exportconstonReset=async(actions:TT.StepActions):Promise<void>=>{
50+
exportconstonReset=async(actions:TT.StepActions,tutorialId:string):Promise<void>=>{
4751
awaitresetWatchers()
4852
awaitrunCommands(actions?.commands)
4953
awaitrunVSCodeCommands(actions?.vscodeCommands)
54+
webhooks.onReset({
55+
tutorialId,
56+
})
5057
}
5158

5259
// run when an uncaught exception is thrown
@@ -66,6 +73,11 @@ export const onStepComplete = async ({
6673
}):Promise<void>=>{
6774
git.saveCommit(`Save progress:${stepId}`)
6875
telemetry.onEvent('step_complete',{ tutorialId, stepId, levelId,version:VERSION})
76+
webhooks.onStepComplete({
77+
tutorialId,
78+
levelId,
79+
stepId,
80+
})
6981
}
7082

7183
// run when a level is complete (all tasks pass or no tasks)
@@ -77,9 +89,16 @@ export const onLevelComplete = async ({
7789
levelId:string
7890
}):Promise<void>=>{
7991
telemetry.onEvent('level_complete',{ tutorialId, levelId,version:VERSION})
92+
webhooks.onLevelComplete({
93+
tutorialId,
94+
levelId,
95+
})
8096
}
8197

8298
// run when all levels are complete
8399
exportconstonTutorialComplete=async({ tutorialId}:{tutorialId:string}):Promise<void>=>{
84100
telemetry.onEvent('tutorial_complete',{ tutorialId,version:VERSION})
101+
webhooks.onTutorialComplete({
102+
tutorialId,
103+
})
85104
}

‎src/services/hooks/webhooks.ts

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import*asTTfrom'typings/tutorial'
2+
importfetchfrom'node-fetch'
3+
importloggerfrom'../logger'
4+
import{WEBHOOK_TOKEN}from'../../environment'
5+
6+
constWEBHOOK_EVENTS={
7+
init:false,
8+
reset:false,
9+
step_complete:false,
10+
level_complete:false,
11+
tutorial_complete:false,
12+
}
13+
14+
// varaibles set on init
15+
letWEBHOOK_URI:string|undefined
16+
17+
exportconstsetupWebhook=(webhookConfig:TT.WebhookConfig)=>{
18+
if(!webhookConfig.url){
19+
return
20+
}
21+
// set webhook uri
22+
WEBHOOK_URI=webhookConfig.url
23+
24+
// set webhook event triggers
25+
constevents=webhookConfig.eventsasTT.WebhookConfigEvents
26+
for(consteventNameofObject.keys(events||{})){
27+
WEBHOOK_EVENTS[eventName]=events[eventName]
28+
}
29+
}
30+
31+
constcallWebhookEndpoint=async<B>(bodyObject:B):Promise<void>=>{
32+
if(!WEBHOOK_URI){
33+
return
34+
}
35+
36+
constheaders={'Content-Type':'application/json'}
37+
// if the webhook token is specified as env var, sends a token with the request
38+
if(WEBHOOK_TOKEN){
39+
headers['CodeRoad-User-Token']=WEBHOOK_TOKEN
40+
}
41+
42+
constbody=JSON.stringify(bodyObject)
43+
44+
try{
45+
constsendEvent=awaitfetch(WEBHOOK_URI,{
46+
method:'POST',
47+
headers,
48+
body,
49+
})
50+
if(!sendEvent.ok){
51+
thrownewError('Error sending event')
52+
}
53+
}catch(err:unknown){
54+
logger(`Failed to call webhook endpoint${WEBHOOK_URI} with body${body}`)
55+
}
56+
}
57+
58+
typeWebhookEventInit={
59+
tutorialId:string
60+
coderoadVersion:string
61+
}
62+
63+
exportconstonInit=(event:WebhookEventInit):void=>{
64+
if(WEBHOOK_EVENTS.init){
65+
callWebhookEndpoint<WebhookEventInit>(event)
66+
}
67+
}
68+
69+
typeWebhookEventReset={
70+
tutorialId:string
71+
}
72+
73+
exportconstonReset=(event:WebhookEventReset):void=>{
74+
if(WEBHOOK_EVENTS.reset){
75+
callWebhookEndpoint<WebhookEventReset>(event)
76+
}
77+
}
78+
79+
typeWebhookEventStepComplete={tutorialId:string;version:string;levelId:string;stepId:string}
80+
81+
exportconstonStepComplete=(event:WebhookEventStepComplete):void=>{
82+
if(WEBHOOK_EVENTS.step_complete){
83+
callWebhookEndpoint<WebhookEventStepComplete>(event)
84+
}
85+
}
86+
87+
typeWebhookEventLevelComplete={tutorialId:string;version:string;levelId:string}
88+
89+
exportconstonLevelComplete=(event:WebhookEventLevelComplete):void=>{
90+
if(WEBHOOK_EVENTS.level_complete){
91+
callWebhookEndpoint<WebhookEventLevelComplete>(event)
92+
}
93+
}
94+
95+
typeWebhookEevntTutorialComplete={tutorialId:string;version:string}
96+
97+
exportconstonTutorialComplete=(event:WebhookEevntTutorialComplete):void=>{
98+
if(WEBHOOK_EVENTS.tutorial_complete){
99+
callWebhookEndpoint<WebhookEevntTutorialComplete>(event)
100+
}
101+
}

‎typings/tutorial.d.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export type TutorialConfig = {
1414
dependencies?:TutorialDependency[]
1515
setup?:StepActions
1616
reset?:ConfigReset
17+
webhook?:WebhookConfig
1718
}
1819

1920
/** Logical groupings of tasks */
@@ -92,3 +93,15 @@ export interface TutorialAppVersions {
9293
}
9394

9495
exporttypeVSCodeCommand=string|[string,any]
96+
97+
exportinterfaceWebhookConfigEvents{
98+
init?:boolean
99+
reset?:boolean
100+
step_complete?:boolean
101+
level_complete?:boolean
102+
tutorial_complete?:boolean
103+
}
104+
exportinterfaceWebhookConfig{
105+
url:string
106+
events?:WebhookConfigEvents
107+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp