Giter Site home page Giter Site logo

cloudevents-plugin's Introduction

CloudEvents-Plugin

Introduction

The CloudEvents Plugin for Jenkins allows interoperability between different CI/CD tools by adopting industry-standard specification for events called CloudEvents.

By using this plugin in your workflows, you can emit and consume CloudEvents for various events in Jenkins relating to Jenkins objects (jobs, projects, queues, etc).

The standardization of events by adopting CloudEvents will make it easier to interoperate systems without having to write adapters.


Getting Started

There are 2 usages of this plugin:

  1. Jenkins as a Source.

    1. To configure Jenkins as a Source, first click on Manage Jenkins in the Root-Actions menu on the left. Manage Jenkins

    2. Once you are in Manage Jenkins UI, search for Configure System under System Configuration. Configure System

    3. Inside the Configure System UI, scroll down to the CloudEvents Plugin section and configure the following:

      • Select the type of the sink. Type of Sink
      • Enter the URL of the sink where requests from Jenkins will be routed. URL of the SInk
      • Select the events this sink will receive. Select event/s
  2. Jenkins as a Sink.

    1. To use Jenkins as a Sink, enter the Jenkins Sink URL as the Sink to send CloudEvents from other systems.
    2. TODO: Jenkins Sink URL.

Events Documentation for Jenkins as Source

When users configure Jenkins to be used as a Source by providing the type of the Sink along with its URL, Jenkins will emit CloudEvents-compliant events which contains event-metadata and events-data. In this iteration of development, events will be sent over to the configured sink sequentially, that is, in the oder they happen.

CloudEvents emanating from Jenkins are sent over to the sink as an HTTP request. All events follow the CloudEvents binary content mode where the events metadata is present inside HTTP request-headers.

Below are the events this plugin supports, alongside event-metadata and event-data which will be emitted for each of these events.

Queue Events

  1. Queue Entered Waiting: Emitted as a job enters the queue.

    • Event Metada

      ce-specversion: 1.0
      ce-id: c42d1f19-9908-43da-9a7f-404405c52b60
      ce-type: org.jenkinsci.queue.entered_waiting
      ce-source: job/test2
      
    • Event Data

      {
        "ciUrl": "http://3.101.116.80/",
        "displayName": "test2",
        "entryTime": 1626611053609,
        "exitTime": null,
        "startedBy": "shruti chaturvedi",
        "jenkinsQueueId": 25,
        "status": "ENTERED_WAITING",
        "duration": 0,
        "queueCauses": [
          {
          "reasonForWaiting": "In the quiet period. Expires in 0 ms",
          "type": "entered_waiting"
          }
        ]
      }
  2. Queue Left: Emitted as a job leaves the queue

    • Event Metada

      ce-specversion: 1.0
      ce-id: 345acb40-5b5a-4e1a-a3da-b5b31dbabb08
      ce-type: org.jenkinsci.queue.left
      ce-source: job/test2
      
    • Event Data

      {
         "ciUrl": "http://3.101.116.80/",
         "displayName": "test2",
         "entryTime": 1626611053609,
         "exitTime": 1626611053624,
         "startedBy": "shruti chaturvedi",
         "jenkinsQueueId": 25,
         "status": "LEFT",
         "duration": 15
      }

Build Events

  1. Job Started: Emitted as build of a job has started.

    • Event Metada

      ce-specversion: 1.0
      ce-id: 00feb6d9-400a-4b4d-b661-ab68a563179e
      ce-type: org.jenkinsci.job.started
      ce-source: job/test2
      
    • Event Data

      {
         "userId": "SYSTEM",
         "userName": "SYSTEM",
         "name": "test2",
         "displayName": "test2",
         "url": "job/test2/",
         "build": {
             "fullUrl": "http://3.101.116.80/job/test2/13/",
             "number": 13,
             "queueId": 25,
             "timestamp": 1626611053632,
             "duration": 0,
             "phase": "STARTED",
             "status": null,
             "url": "job/test2/13/",
             "displayName": null,
             "parameters": {
                 "IsSCM": "true"
             },
             "scmState": {
                 "url": "https://github.com/ShrutiC-git/scmConfig.git",
                 "branch": "origin/main",
                 "commit": "218c63f230732c6d561fefd00fd0d2ac4ded1a0c"
             }
         }
      }
  2. Job Completed: Emitted as build of a job has completed.

    • Event Metada

      ce-specversion: 1.0
      ce-id: 1fe6f79d-19b8-4e47-ab20-675b6ed8c514
      ce-type: org.jenkinsci.job.completed
      ce-source: job/test2
      
    • Event Data

      {
         "userId": "SYSTEM",
         "userName": "SYSTEM",
         "name": "test2",
         "displayName": "test2",
         "url": "job/test2/",
         "build": {
             "fullUrl": "http://3.101.116.80/job/test2/13/",
             "number": 13,
             "queueId": 25,
             "timestamp": 1626611059215,
             "duration": 5583,
             "phase": "COMPLETED",
             "status": "SUCCESS",
             "url": "job/test2/13/",
             "displayName": null,
             "parameters": {
                 "IsSCM": "true"
             },
             "scmState": {
                 "url": "https://github.com/ShrutiC-git/scmConfig.git",
                 "branch": "origin/main",
                 "commit": "218c63f230732c6d561fefd00fd0d2ac4ded1a0c"
             }
         }
      }
  3. Job Finalized: Emitted as build of a job has finalized.

    • Event Metada

      ce-specversion: 1.0
      ce-id: cb7fba47-46fa-4d4d-8e46-a239fc4ff801
      ce-type: org.jenkinsci.job.finalzed
      ce-source: job/test2
      
    • Event Data

      {
         "userId": "SYSTEM",
         "userName": "SYSTEM",
         "name": "test2",
         "displayName": "test2",
         "url": "job/test2/",
         "build": {
             "fullUrl": "http://3.101.116.80/job/test2/13/",
             "number": 13,
             "queueId": 25,
             "timestamp": 1626611059241,
             "duration": 5583,
             "phase": "FINALIZED",
             "status": "SUCCESS",
             "url": "job/test2/13/",
             "displayName": null,
             "parameters": {
                 "IsSCM": "true"
             },
             "scmState": {
                 "url": "https://github.com/ShrutiC-git/scmConfig.git",
                 "branch": "origin/main",
                 "commit": "218c63f230732c6d561fefd00fd0d2ac4ded1a0c"
             }
         }
      }
  4. Job Failed: Emitted as build of a job has failed.

    • Event Metada

      ce-specversion: 1.0
      ce-id: cb7fba47-46fa-4d4d-8e46-a239fc4ff801
      ce-type: org.jenkinsci.job.failed
      ce-source: job/fail
      
    • Event Data

      {
         "userId": "SYSTEM",
         "userName": "SYSTEM",
         "name": "fail",
         "displayName": "fail",
         "url": "job/fail/",
         "build": {
             "fullUrl": "http://3.101.116.80/job/fail/4/",
             "number": 4, 
             "queueId": 28,
             "timestamp": 1626619978412,
             "duration": 1456,
             "phase": "FINALIZED",
             "status": "FAILED",
             "url": "job/fail/4/",
             "displayName": null,
             "parameters": null,
             "scmState": {
                 "url": null,
                 "branch": null,
                 "commit": null
             }
         }
      }

Job Events

  1. Job Created: Emitted as a new job is created.

    • Event Metada

      ce-specversion: 1.0
      ce-id: 1930d373-e2e8-4e4e-86ae-259a6e9a7923
      ce-type: org.jenkinsci.job.created
      ce-source: job/Item
      
    • Event Data

      {
      "userId": "shruti",
      "userName": "shruti chaturvedi",
      "status": "CREATED",
      "name": "Item",
      "displayName": "Item",
      "url": "job/Item/",
      "createdDate": 1626621074004,
      "configFile": "<?xml version='1.1' encoding='UTF-8'?>\n<project>\n  <keepDependencies>false</keepDependencies>\n  <properties/>\n  <scm class=\"hudson.scm.NullSCM\"/>\n  <canRoam>false</canRoam>\n  <disabled>false</disabled>\n  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>\n  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>\n  <triggers/>\n  <concurrentBuild>false</concurrentBuild>\n  <builders/>\n  <publishers/>\n  <buildWrappers/>\n</project>"
      }
  2. Job Updated: Emitted as an existing job is updated.

    • Event Metada

      ce-specversion: 1.0
      ce-id: 1930d373-a1a1-4e4e-52er-259a6e9a1598
      ce-type: org.jenkinsci.job.updated
      ce-source: job/Item
      
    • Event Data

      {
      "userId": "shruti",
      "userName": "shruti chaturvedi",
      "status": "UPDATED",
      "name": "Item",
      "displayName": "Item",
      "url": "job/Item/",
      "updatedDate": 1626621078878,
      "configFile": "<?xml version='1.1' encoding='UTF-8'?>\n<project>\n  <keepDependencies>false</keepDependencies>\n  <properties/>\n  <scm class=\"hudson.scm.NullSCM\"/>\n  <canRoam>false</canRoam>\n  <disabled>false</disabled>\n  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>\n  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>\n  <triggers/>\n  <concurrentBuild>false</concurrentBuild>\n  <builders/>\n  <publishers/>\n  <buildWrappers/>\n</project>"
      }

Node Events

  1. Node Online: Emitted when a node comes online.

    • Event Metada

      ce-specversion: 1.0
      ce-id: 8c78daa6-011c-4687-b5a5-b269087f6830
      ce-type: org.jenkinsci.node.online
      ce-source: node/test_node
      
    • Event Data

      {
       "numExecutors": 2,
       "offlineCause": null,
       "nodeName": "test_node",
       "cachedHostName": "DESKTOP-A47DM8N",
       "terminatedBy": null,
       "connectTime": 0
      }
  2. Node Offline: Emitted when a node goes offline.

    • Event Metada

      ce-specversion: 1.0
      ce-id: 70160f83-885c-4574-8a55-7660593c9b76
      ce-type: org.jenkinsci.node.offline
      ce-source: node/test_node
      
    • Event Data

      {
       "numExecutors": 2,
       "offlineCause": {
          "timestamp": 1626622018554,
          "cause": {
             "cause": null,
             "stackTrace": [
                {
                   "methodName": "onRecvClosed",
                   "fileName": "NetworkLayer.java",
                   "lineNumber": 154,
                   "className": "org.jenkinsci.remoting.protocol.NetworkLayer",
                   "nativeMethod": false
                },
                {
                   "methodName": "ready",
                   "fileName": "NIONetworkLayer.java",
                   "lineNumber": 179,
                   "className": "org.jenkinsci.remoting.protocol.impl.NIONetworkLayer",
                   "nativeMethod": false
                }
             ],
             "localizedMessage": null,
             "message": null,
             "suppressed": []
          },
          "shortDescription": "java.nio.channels.ClosedChannelException",
          "time": 1626622018554
       },
       "nodeName": "test_node",
       "cachedHostName": "DESKTOP-A47DM8N",
       "terminatedBy": [],
       "connectTime": 0
      }

Issues

TODO Decide where you're going to host your issues, the default is Jenkins JIRA, but you can also enable GitHub issues, If you use GitHub issues there's no need for this section; else add the following line:

Report issues and enhancements in the Jenkins issue tracker.


Contributing

TODO review the default CONTRIBUTING file and make sure it is appropriate for your plugin, if not then add your own one adapted from the base file

Refer to our contribution guidelines

cloudevents-plugin's People

Contributors

gitter-badger avatar notmyfault avatar shrutic-git avatar waveywaves avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

cloudevents-plugin's Issues

event send error

Version report

Jenkins and plugins versions report:

Jenkins version v2.319.1 / plugin version v1.0.0
  • What Operating System are you using (both controller, and any agents involved in the problem)?
win10
Local K8S deployed by kind
Jekins runs on k8s pod

Reproduction steps

  • Click build job

Results

Expected result:

When building the pipeline. Queue Entered Waiting and Queue Left can be sent normally, the body sent by other events has no data

2021-12-21 15:26:28.527+0000 [id=113]   INFO    i.j.p.cloudevents.sinks.HTTPSink#sendCloudEvent: Received response: 200
2021-12-21 15:26:28.536+0000 [id=124]   INFO    i.j.p.cloudevents.sinks.HTTPSink#sendCloudEvent: Received response: 200
com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: io.jenkins.plugins.cloudevents.model.JobModel["createdDate"])
        at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:390)
        at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:349)
        at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:316)
        at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:778)
        at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
        at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
        at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
        at com.fasterxml.jackson.databind.ObjectMapper._writeValueAndClose(ObjectMapper.java:4485)
        at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3740)
        at io.jenkins.plugins.cloudevents.CloudEventsUtil.convertToJson(CloudEventsUtil.java:16)
        at io.jenkins.plugins.cloudevents.sinks.HTTPSink.buildCloudEvent(HTTPSink.java:38)
        at io.jenkins.plugins.cloudevents.sinks.HTTPSink.sendCloudEvent(HTTPSink.java:57)
        at io.jenkins.plugins.cloudevents.Stage.handleEvent(Stage.java:38)
        at io.jenkins.plugins.cloudevents.listeners.CEJobListener.onStarted(CEJobListener.java:35)
        at hudson.model.listeners.RunListener.fireStarted(RunListener.java:237)
        at org.jenkinsci.plugins.workflow.job.WorkflowRun.run(WorkflowRun.java:302)
        at hudson.model.ResourceController.execute(ResourceController.java:99)
        at hudson.model.Executor.run(Executor.java:432)
Caused by: java.lang.NullPointerException
        at io.jenkins.plugins.cloudevents.model.JobModel.getCreatedDate(JobModel.java:90)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:689)
        at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:770)
        ... 14 more
2021-12-21 15:26:28.554+0000 [id=124]   INFO    i.j.p.cloudevents.sinks.HTTPSink#sendCloudEvent: Received response: 200
2021-12-21 15:26:28.757+0000 [id=126]   INFO    i.j.plugins.cloudevents.Stage#handleEvent: Error: Illegal character in path at index 8: job/part of test1 #7 
2021-12-21 15:26:28.765+0000 [id=102]   INFO    i.j.plugins.cloudevents.Stage#handleEvent: Error: Illegal character in path at index 8: job/part of test1 #7 
2021-12-21 15:26:28.915+0000 [id=127]   INFO    o.j.p.workflow.job.WorkflowRun#finish: test1 #7 completed: SUCCESS

Installing cloudevents-plugin

Hey Jenkins Family,

Can you provide a link to install the plugin in dev mode or provide me a link to how to install the plugin locally?

No body available for Build events

Jenkins and plugins versions report

The plugin sends the event to http sink but the body is empty and following error is thrown in Jenkins

enkins  | 2023-05-30 03:23:06.949+0000 [id=245]        INFO    i.j.p.cloudevents.sinks.HTTPSink#sendCloudEvent: Received response: 404
jenkins  | com.fasterxml.jackson.databind.JsonMappingException: Cannot invoke "java.util.Date.getTime()" because "this.createdDate" is null (through reference chain: io.jenkins.plugins.cloudevents.model.JobModel["createdDate"])
jenkins  |      at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:390)
jenkins  |      at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:349)
jenkins  |      at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:316)
jenkins  |      at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:778)
jenkins  |      at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
jenkins  |      at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
jenkins  |      at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
jenkins  |      at com.fasterxml.jackson.databind.ObjectMapper._writeValueAndClose(ObjectMapper.java:4485)
jenkins  |      at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3740)
jenkins  |      at io.jenkins.plugins.cloudevents.CloudEventsUtil.convertToJson(CloudEventsUtil.java:16)
jenkins  |      at io.jenkins.plugins.cloudevents.sinks.HTTPSink.buildCloudEvent(HTTPSink.java:38)
jenkins  |      at io.jenkins.plugins.cloudevents.sinks.HTTPSink.sendCloudEvent(HTTPSink.java:57)
jenkins  |      at io.jenkins.plugins.cloudevents.Stage.handleEvent(Stage.java:38)
jenkins  |      at io.jenkins.plugins.cloudevents.listeners.CEJobListener.onFinalized(CEJobListener.java:30)
jenkins  |      at hudson.model.listeners.RunListener.lambda$fireFinalized$3(RunListener.java:244)
jenkins  |      at jenkins.util.Listeners.lambda$notify$0(Listeners.java:59)
jenkins  |      at jenkins.util.Listeners.notify(Listeners.java:67)
jenkins  |      at hudson.model.listeners.RunListener.fireFinalized(RunListener.java:242)
jenkins  |      at hudson.model.Run.onEndBuilding(Run.java:2062)
jenkins  |      at org.jenkinsci.plugins.workflow.job.WorkflowRun.finish(WorkflowRun.java:663)
jenkins  |      at org.jenkinsci.plugins.workflow.job.WorkflowRun$GraphL.onNewHead(WorkflowRun.java:1065)
jenkins  |      at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.notifyListeners(CpsFlowExecution.java:1587)
jenkins  |      at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$3.run(CpsThreadGroup.java:509)
jenkins  |      at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$1.run(CpsVmExecutorService.java:38)
jenkins  |      at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:139)
jenkins  |      at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)
jenkins  |      at jenkins.security.ImpersonatingExecutorService$1.run(ImpersonatingExecutorService.java:68)
jenkins  |      at jenkins.util.ErrorLoggingExecutorService.lambda$wrap$0(ErrorLoggingExecutorService.java:51)
jenkins  |      at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
jenkins  |      at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
jenkins  |      at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
jenkins  |      at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
jenkins  |      at java.base/java.lang.Thread.run(Thread.java:833)
jenkins  | Caused by: java.lang.NullPointerException: Cannot invoke "java.util.Date.getTime()" because "this.createdDate" is null
jenkins  |      at io.jenkins.plugins.cloudevents.model.JobModel.getCreatedDate(JobModel.java:90)
jenkins  |      at jdk.internal.reflect.GeneratedMethodAccessor417.invoke(Unknown Source)
jenkins  |      at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
jenkins  |      at java.base/java.lang.reflect.Method.invoke(Method.java:568)
jenkins  |      at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:689)
jenkins  |      at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:770)
jenkins  |      ... 29 more
Environment
Jenkins: 2.387.3
OS: Linux - 5.4.0-1103-azure
Java: 17.0.7 - Eclipse Adoptium (OpenJDK 64-Bit Server VM)

Plugin:

cloudevents:1.0.0

What Operating System are you using (both controller, and any agents involved in the problem)?

NA

Reproduction steps

  1. In global config, set up an http sink in CloudEvents plugin
  2. Enable Job Started, Job Completed, Job Finalized
  3. Create a freestyle project and run the pipeline
  4. Check the http sink endpoint, it would have received request without body

Expected Results

HttpSink to receive request with body object similar to below, as mentioned in https://github.com/jenkinsci/cloudevents-plugin#build-events

{
   "userId": "SYSTEM",
   "userName": "SYSTEM",
   "name": "test2",
   "displayName": "test2",
   "url": "job/test2/",
   "build": {
       "fullUrl": "http://3.101.116.80/job/test2/13/",
       "number": 13,
       "queueId": 25,
       "timestamp": 1626611053632,
       "duration": 0,
       "phase": "STARTED",
       "status": null,
       "url": "job/test2/13/",
       "displayName": null,
       "parameters": {
           "IsSCM": "true"
       },
       "scmState": {
           "url": "https://github.com/ShrutiC-git/scmConfig.git",
           "branch": "origin/main",
           "commit": "218c63f230732c6d561fefd00fd0d2ac4ded1a0c"
       }
   }
}

Actual Results

HttpSink to receive request without body object

Anything else?

No response

Add support for other common events in Jenkins

Dependencies

Feature Request

Currently, the following events are supported:
https://github.com/jenkinsci/cloudevents-plugin#events-documentation-for-jenkins-as-source

The plugin implements listener interfaces from the Hudson Model class. For an object in Jenkins, different events are emitted at different stages of that object. For example, to emit Queue-events, this plugin implements QueueListener. This interface has abstracted definitions for methods like

  1. onQueueEntered
  2. onQueueLeft

There are several listeners available inside Jenkins. This feature proposes adding support for those listeners by emitting events in the CloudEvents format.

More info on finding several listener implementation and how other plugins are using it can be found here: https://www.jenkins.io/doc/developer/extensions/jenkins-core/#queuelistener

Move the plugin configuration to its own page

Dependencies

Feature Request

The plugin is configurable under Manage Jenkins page. However, since the plugin as a whole (as a source and as a sink) requires a good amount of configuration, it reduces readability since there already is a lot of other things to configure inside the Manage Jenkins page

This feature suggests moving the configuration from Global Configuration/Manage Jenkins to its own page. Some plugins in the Jenkins ecosystem use their own page inside Jenkins which makes the UI cleaner, and makes it easy for users to enter the info needed for the plugin's configuration.
Some examples of such plugin are:

These plugins extend from the Management Link class which allows these plugins to have their own configurable page. If the CloudEvents plugin had its own configurable page, it will make configuring the plugin easier.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.