Significance of the generic pull_request event and other more specific pull_request events like pull_request.opened - github

I am developing a GitHub App using nodejs and probot framework. I can see the Application class (https://probot.github.io/api/latest/classes/application.html) of the probot framework contains events like :
> event: "pull_request" | "pull_request.assigned" |
> "pull_request.closed" | "pull_request.edited" | "pull_request.labeled"
> | "pull_request.opened" | "pull_request.reopened" |
> "pull_request.review_request_removed" |
> "pull_request.review_requested" | "pull_request.unassigned" |
> "pull_request.unlabeled" | "pull_request.synchronize
I have noticed that when the "Create pull request" button is clicked, then the pull_request as well as pull_request.opened events are fired.
In order to understand this behavior of firing multiple seemingly similar events upon the click of the same button, I tried to reopen a closed request and print out the Context object for both pull_request event as well as pull_request.reopened event.
I did a diff comparison of both the contexts and found that the contexts returned by both the events are
identical except that the context of pull_request event contained below additional properties :
merged: false,
mergeable: null,
rebaseable: null,
mergeable_state: 'unknown',
merged_by: null,
comments: 6,
review_comments: 0,
maintainer_can_modify: false,
commits: 1,
additions: 1,
deletions: 0,
changed_files: 1 },
repository:
{ id: 123456789,
node_id: '',
name: '',
full_name: '',
private: true,
owner: [Object],
html_url: 'some-url-here'
.
.
///////////////////--------many more urls-------//////////////////////
created_at: '2020-04-0',
updated_at: '2020-04-0',
We know that the general format of the context object returned is as follows :
Context {
name: 'pull_request',
id: '187128937812-8219-89891892133-16752-1234576765545',
payload:
{ action: 'reopened',
number: 1,
pull_request:
{ url:
.
.
.and so on.......
This above information is present in both the contexts. We can see that this also tells us about the specific action that was performed and this is denoted by the context.payload.action. So, if someone's requirement is to get hold of the pull_request.opened he/she could do it by just by using pull_request event as follows :
app.on('pull_request', async context => {
console.log('---------------------- on pull_request event')
console.log('Context returned :----', context)
})
And doesn't need to care about the other more specific events(here pull_request.opened) i.e. apart from what is achieved from the above code, below code would provide no real additional help :
app.on('pull_request.opened', async context => {
console.log('---------------------- on pull_request.opened')
console.log('Context returned :----', context)
})
So here is the question that's troubling me :
What is the purpose of the pull_request event , if its other specific forms (like pull_request.reopened) carry no different information(more precisely, if their contexts contain no different infos) ?
I am quite sure that there does lie some wisdom behind it. I'm not able to find anything on the internet, nothing in the docs that could explain this.
Please help me understand the hidden wisdom.
EDIT 1 : START
Forgot to mention one observation and that is : Reopening the pull request also triggers issue_comment.created event. So, So three events are triggered by one action(clicking Create Pull Request).
EDIT 2 : START

What is the purpose of the pull_request event , if its other specific forms (like pull_request.reopened) carry no different information(more precisely, if their contexts contain no different infos) ?
This is just a feature of Probot to simplify processing webhook events from GitHub. I'll try and explain why it's helpful.
If you were to consume webhook events without Probot, you would have to parse every pull_request event, check the action field for a case, and decide whether to handle it.
There are several events that have a top-level action field in the payload, incuding:
check_run
issue
project
pull_request
and many more in the docs...
Rather than make application developers perform this parsing and inspection of the JSON themselves they decided to simplify the callbacks so you can subscribe to webhooks using the specific [event].[action] pattern, and the framework takes care of invoking your callback when the matching event and action is received.
So you have two options for handling pull_request events:
if you don't know which events you need, or need to dynamically process events, subscribing to pull_request is how you would receive all pull request events
if you know which events you should handle, and can ignore the rest, subscribe to explicit pull_request.[event] should simplify your application code
You could also subscribe to *, which represents all events the probot app receives, rather than explicitly listing all supported events in your app.

Related

How to connect to Actions builder project to update type entities?

I've got a project build migrated from AOG + Dialogflow to Actions Builder. I need to update (or insert new) type entries with the REST API.
To do that action I've found an endpoint, that gives the ability to update the whole project along with entities:
https://developers.google.com/assistant/actions/api/reference/rest/v2/projects.draft/write
However, I can't connect to that endpoint due to 401 error. Before that I've tried to emulate a similar request to another endpoint, which allows reading the project:
https://developers.google.com/assistant/actions/api/reference/rest/v2/projects.draft/read
Obviously, I've got the same error here.
Also, I've found this repo - https://github.com/actions-on-google/assistant-actions-nodejs
which adds a wrapper for easier manipulation with the REST API, but it also doesn't contain any information on how to properly authorize to get access to an app.
Can please somebody suggest how authorization should be done to start using this REST API?
Using Actions Builder, the type entities can be updated directly in your webhook calls rather than calling an API in parallel.
Look up the names of the types you want to override in Actions Builder and set the conv.session.typeOverrides field in your response.
Here's a code example of how it might be done:
const app = conversation()
// `app.middleware` will run on every invocation call
app.middleware(conv => {
// ...
// Obtain `trackTitles` and `trackGenres`
// ...
conv.session.typeOverrides = [{
name: 'track',
mode: Mode.TypeReplace,
synonym: {
entries: Array.from(trackTitles).map(title => ({
name: title,
synonyms: [title],
})),
},
}, {
name: 'genre',
mode: Mode.TypeReplace,
synonym: {
entries: Array.from(trackGenres).map(genre => ({
name: genre,
synonyms: [genre]
}))
}
}]
})

How to trigger azure pipeline via API in a way it does not report it was manually triggered

We have an Azure pipeline building a static site. When there is a change in a content repository the site needs to be rebuilt. For that, we're using webhooks and Azure DevOps API. The request to queue the build is very simple and is illustrated for example here.
What I don't like about this is that int the build listing it says "Manually triggered for person XY", where the person XY is the one who generated the credentials used in the API request. It seems quite confusing because any API request seems strange to be labeled as "manually requested". What would be the best way how to achieve more semantically correct message?
I've found there is a reason property which can be sent in the request. But none of the values seems to represent what I want and some of them do not work (probably need additional properties and there is no documentation for that).
Based on my test, when you use the Rest API to queue a build and set the build reason, the reason could be shown in the Build(except:batchedCI and buildCompletion).
Here is the Rest API example:
Post https://dev.azure.com/Organization/Project/_apis/build/builds?api-version=4.1
Request Body:
{
"definition": {
"id": 372
},
"reason":"pullRequest"
}
The value : checkInShelveset individualCI pullRequest schedule could show their own names.
The value: manual and none could show manually trigger.
The other value(e.g. All, userCreated) will show Other Build Reason.
For the value: batchedCI and buildCompletion.
BatchedCI: Continuous integration (CI) triggered by a Git push or a TFVC check-in, and the Batch changes was selected.
This means that batch changes are required to achieve this trigger. So it doesn't support to queue build in Rest API .
buildCompletion: you could refer to this ticket This reason doesn't support in Rest API-queue Build.
Note: If you enter a custom value or misspelling, it will always display manual trigger.
In the end, I went with all value and also overriding the person via requestedFor property. This leads to the message "Other build reason", which seems usable to me.
{
"definition": {
"id": 17
},
"reason":"all",
"requestedFor": {
"id": "4f9ff423-0e0d-4bfb-9f6b-e76d2e9cd3ae"
}
}
However, I'm not sure if there aren't any unwanted consequences of this "All reasons" value.

How do I add a GTM event to a callback triggered upon this form completion?

I am setting up GTM Event Tracking and Facebook Pixel tracking for a client.
They are using a CRM system with a form widget which is embedded on the website via Javascript. As such, there is no direct way of tracking the form.
Their developers have asked me to use their global variables, one of which allows me to add in a callback which is triggered upon 'formCompleted'.
Please see the code below. The last variable allows me to input a callback, but honestly speaking, I have no idea how to make it fire an event to Google Tag Manager, or Facebook Pixel.
var intouchFormConfig = {
includeCss: true, //s et false to stop the default stylesheet from being loaded
foregroundColour: null, //set to a css colour - e.g. #fff- to override what is
configured on the server
matterGuid: null, // Id of a matter. If this is set the matter will be updated with
the results of this form
bannerUrl: null, //a n image to display at the top of the form
autoActivate: true,//by default the widget will automatically activate,
events: {
activa ted: () => {}, //an optional callback triggered once the widget is
activated
formCompleted: (response) => {}, //an optional callback triggered once a form
inside the widget has been completed by the user
},
};
The general concept to generate custom events in Google Tag Manager (GTM) is to push the event variable into dataLayer of GTM. You can set up Custom Event triggers in GTM to launch any tags, that are relevant to this event. You need to provide the name of the event as Event name in the trigger settings.
The general syntax for this is:
dataLayer.push({
event: 'myEventName'
});
In your case, you need to provide a function, that will make this call. You can also pass the response to GTM as a dataLayer variable, if you need to use it in connection to your event. (E.g. check for success, failure, or any other outcome.) So your code should look something like this:
var intouchFormConfig = {
//your other configuration items
//events part
events: {
activated: () => {},
formCompleted: (response) => {
dataLayer.push({
event : 'intouchFormCompleted', //an event name you can use in GTM, should be unique to this event
intouchResponse: response //optional part, if you need the response in GTM
})
},
}
};
Please note, you have a typo in your original code (activa ted object key with a space in it).
Your GTM trigger will look something like this, in case of an event name from my example:

Do subscriptions work with singleValueExtendedProperties?

I am looking for a way to use Graph API's for syncing calendar events. Example different types of meeting requests such as "Case Events(court cases) meetings, corporate meetings , persons meetings. For this case in particular he would like to get an event notification when If someone tried to delete a "Case Event Meeting" and prevent the delete.
We have a Java application that adds the different type of meeting requests to the calendar and all of those have an event origin of {f19d3c30-0660-4f7f-96df-6dc78a686633}
The follow code works fine for a changeType of Created, Accepted
"subscriptionConfiguration": {
"changeType": "Created,Accepted,Deleted",
"notificationUrl": "https://xxxxx/listen",
"resource": "me/events/?$filter=singleValueExtendedProperties/any(ep: ep/id eq 'String {XXYY1231-0660-5ty5-96df-6brca687744} Name event_origin' and ep/value eq null)",
.... },
The code above returns nothing in the case of changeType = delete
The only reason they are using the "singleValueExtendedProperties" filter only because they want to filter out only calls created from there java application and act upon them. It works fine for "changeType": "Created,Accepted", but Deleted it returns nothing as the filter seems to remove them.
Is there another way we could filter out the requests that would not require the use the "singleValueExtendedProperties" filter?
Can we think of other options to that would be better than the workaround above?
While you should be able to get notified about the delete, both sync and notifications are "after the fact", so there would be no way to prevent the delete. The closest you could get is to recreate the event which would of course require you to have an offline copy of the event so you could recreate it.

RESTful API and real life example

We have a web application (AngularJS and Web API) which has quite a simple functionality - displays a list of jobs and allows users to select and cancel selected jobs.
We are trying to follow RESTful approach with our API, but that's where it gets confusing.
Getting jobs is easy - simple GET: /jobs
How shall we cancel the selected jobs? Bearing in mind that this is the only operation on jobs we need to implement. The easiest and most logical approach (to me) is to send the list of selected jobs IDs to the API (server) and do necessary procedures. But that's not RESTful way.
If we are to do it following RESTful approach it seams that we need to send PATCH request to jobs, with json similar to this:
PATCH: /jobs
[
{
"op": "replace",
"path": "/jobs/123",
"status": "cancelled"
},
{
"op": "replace",
"path": "/jobs/321",
"status": "cancelled"
},
]
That will require generating this json on client, then mapping it to some the model on server, parsing "path" property to get the job ID and then do actual cancellation. This seems very convoluted and artificial to me.
What is the general advice on this kind of operation? I'm curious what people do in real life when a lot of operations can't be simply mapped to RESTful resource paradigm.
Thanks!
If by cancelling a job you mean deleting it then you could use the DELETE verb:
DELETE /jobs?ids=123,321,...
If by cancelling a job you mean setting some status field to cancelled then you could use the PATCH verb:
PATCH /jobs
Content-Type: application/json
[ { "id": 123, "status": "cancelled" }, { "id": 321, "status": "cancelled" } ]
POST for Business Process
POST is often an overlooked solution in this situation. Treating resources as nouns is a useful and common practice in REST, and as such, POST is often mapped to the "CREATE" operation from CRUD semantics - however the HTTP Spec for POST mandates no such thing:
The POST method requests that the target resource process the representation enclosed in the request according to the resource's own specific semantics. For example, POST is used for the following functions (among others):
Providing a block of data, such as the fields entered into an HTML form, to a data-handling process;
Posting a message to a bulletin board, newsgroup, mailing list, blog, or similar group of articles;
Creating a new resource that has yet to be identified by the origin server; and
Appending data to a resource's existing representation(s).
In your case, you could use:
POST /jobs/123/cancel
and consider it an example of the first option - providing a block of data to a data handling process - and is analogous to html forms using POST to submit the form.
With this technique, you could return the job representation in the body and/or return a 303 See Other status code with the Location set to /jobs/123
Some people complain that this looks 'too RPC' - but there is nothing that is not RESTful about it if you read the spec - and personally I find it much clearer than trying to find an arbitrary mapping from CRUD operations to real business processes.
Ideally, if you are concerned with following the REST spec, the URI for the cancel operation should be provided to the client via a hypermedia link in your job representation. e.g. if you were using HAL, you'd have:
GET /jobs/123
{
"id": 123,
"name": "some job name",
"_links" : {
"cancel" : {
"href" : "/jobs/123/cancel"
},
"self" : {
"href" : "/jobs/123"
}
}
}
The client could then obtain the href of the "cancel" rel link, and POST to it to effect the cancellation.
Treat Processes as Resources
Another option is, depending on if it makes sense in your domain, to make a 'cancellation' a noun and associate data with it, such as who cancelled it, when it was cancelled etc. - this is especially useful if a job may be cancelled, reopened and cancelled again, as the history of changes could be useful business data, or if the act of cancelling is an asynchronous process that requires tracking the state of the cancellation request over time. With this approach, you could use:
POST /jobs/123/cancellations
which would "create" a job cancellation - you could then have operations like:
GET /jobs/123/cancellations/1
to return the data associated with the cancellation, e.g.
{
"cancelledBy": "Joe Smith",
"requestedAt": "2016-09-01T12:43:22Z",
"status": "in process"
"completedAt": null
}
and:
GET /jobs/123/cancellations
to return a collection of cancellations that have been applied to the job and their current status.
Example 1: Let’s compare it with a real-world example: You go to a restaurant you sit at your table and you choose that you need ABC. You will have your waiter coming up and taking a note of what you want. You tell him that you want ABC. So, you are requesting ABC, the waiter responds back with ABC he gets in the kitchen and serves you the food. In this case, who is your interface in between you and the kitchen is your waiter. It’s his responsibility to carry the request from you to the kitchen, make sure it’s getting done, and you know once it is ready he gets back to you as a response.
Example 2: Another important example that we can relate is travel booking systems. For instance, take Kayak the biggest online site for booking tickets. You enter your destination, once you select dates and click on search, what you get back are the results from different airlines. How is Kayak communicating with all these airlines? There must be some ways that these airlines are actually exposing some level of information to Kayak. That’s all the talking, it’s through API’s
Example 3: Now open UBER and see. Once the site is loaded, it gives you an ability to log in or continue with Facebook and Google. In this case, Google and Facebook are also exposing some level of users’ information. There is an agreement between UBER and Google/Facebook that has already happened. That’s the reason it is letting you sign up with Google/ Facebook.
PUT /jobs{/ids}/status "cancelled"
so for example
PUT /jobs/123,321/status "cancelled"
if you want to cancel multiple jobs. Be aware, that the job id must not contain the comma character.
https://www.rfc-editor.org/rfc/rfc6570#page-25