Project: Kong (Orchestration & Management / API Gateway)
File: CONTRIBUTING.md

Hello, and welcome! Whether you are looking for help, trying to report a bug, thinking about getting involved in the project, or about to submit a patch, this document is for you! It intends to be both an entry point for newcomers to the community (with various technical backgrounds), and a guide/reference for contributors and maintainers. Please have a look at our to understand how we work with our open-source contributors! Consult the Table of Contents below, and jump to the desired section. * * * * * * * * * * * * * * * * If you are a Kong Enterprise customer, you may contact the Enterprise Support channels by opening an Enterprise support ticket on . If you are experiencing a P1 issue, please call the [24/7 Enterprise Support phone line](https://support.konghq.com/hc/en-us/articles/115004921808-Telephone-Support) for immediate assistance, as published in the Customer Success Reference Guide. If you are interested in becoming a Kong Enterprise customer, please visit https://konghq.com/kong-enterprise-edition/ or contact us at . For questions about the use of the Community Edition, please use . You can also join our for real-time conversations around Kong Gateway. Please avoid opening GitHub issues for general questions or help, as those should be reserved for actual bug reports. The Kong community is welcoming and more than willing to assist you on those channels! Our public forum, is great for asking questions, giving advice, and staying up-to-date with the latest announcements. Feel free to on the GitHub repository, we would be grateful to hear about it! Please make sure that you respect the GitHub issue template, and include: A summary of the issue A list of steps to help reproduce the issue The version of Kong that you encountered the issue with Your Kong configuration, or the parts that are relevant to your issue If you wish, you are more than welcome to propose a patch to fix the issue! See the section for more information on how to best do so. You can for feature requests. Please make sure to add as much detail as you can when doing so. You are also welcome to propose patches adding new features. See the section on for details. In addition to code enhancements and bug fixes, you can contribute by Reporting a bug (see the section) Helping other members of the community on the support channels Fixing a typo in the code Fixing a typo in the documentation at https://docs.konghq.com (see the section) Providing your feedback on the proposed features and designs Reviewing Pull Requests If you wish to contribute code (features or bug fixes), see the [Submitting a patch](#submitting-a-patch) section. The documentation hosted at https://docs.konghq.com is open source and built with . You are very welcome to propose changes to it (correct typos, add examples or clarifications...) and contribute to the ! The repository is also hosted on GitHub at: https://github.com/Kong/docs.konghq.com/ We do not generally accept new plugins into this repository. The plugins that are currently part of it form the foundational set of plugins which is available to all installations of Kong Gateway. Specialized functionality should be implemented in plugins residing in separate repository. If you are interested in writing a new plugin for your own needs, you should begin by reading the . If you already wrote a plugin, and are thinking about making it available to the community, we strongly encourage you to host it on a publicly available repository (like GitHub), and distribute it via

A good resource on how to do so is the [Distribution Section](https://docs.konghq.com/latest/plugin-development/distribution/#distributing-your-plugin) of the Plugin Development Guide. To give visibility to your plugin, we advise that you: Add your plugin to the Create a post in the [Announcements category of Kong Nation](https://discuss.konghq.com/c/announcements) Feel free to contribute fixes or minor features by opening a Pull Request. Small contributions are more likely to be merged quicker than changes which require a lot of time to review. If you are planning to develop a larger feature, please talk to us first in the section! When contributing, please follow the guidelines provided in this document. They will cover topics such as the different Git branches we use, the commit message format to use, or the appropriate code style. Once you have read them, and you feel that you are ready to submit your Pull Request, be sure to verify a few things: Your commit history is clean: changes are atomic and the git message format was respected Rebase your work on top of the base branch (seek help online on how to use `git rebase`; this is important to ensure your commit history is clean and linear) The static linting is succeeding: run `make lint`, or `luacheck .` (see the development documentation for additional details) The tests are passing: run `make test`, `make test-all`, or whichever is appropriate for your change Do not update `CHANGELOG.md` inside your Pull Request. This file is automatically regenerated and maintained during the release process. If the above guidelines are respected, your Pull Request has all its chances to be considered and will be reviewed by a maintainer. If you are asked to update your patch by a reviewer, please do so! Remember: You are responsible for pushing your patch forward. If you contributed it, you are probably the one in need of it. You must be ready to apply changes to it if necessary. If your Pull Request was accepted and fixes a bug, adds functionality, or makes it significantly easier to use or understand Kong, congratulations! You are now an official contributor to Kong. Get in touch with us to receive your very own ! Your change will be included in the subsequent release and its changelog, and we will not forget to include your name if you are an external contributor. :wink: If you have write access to the GitHub repository, please follow the following naming scheme when pushing your branch(es): `feat/foo-bar` for new features `fix/foo-bar` for bug fixes `tests/foo-bar` when the change concerns only the test suite `refactor/foo-bar` when refactoring code without any behavior change `style/foo-bar` when addressing some style issue `docs/foo-bar` for updates to the README.md, this file, or similar documents `chore/foo-bar` when the change does not concern the functional source `perf/foo-bar` for performance improvements When submitting patches, it is important that you organize your commits in logical units of work. You are free to propose a patch with one or many commits, as long as their atomicity is respected. This means that no unrelated changes should be included in a commit. For example: you are writing a patch to fix a bug, but in your endeavour, you spot another bug. Do not fix both bugs in the same commit! Finish your work on the initial bug, propose your patch, and come back to the second bug later on. This is also valid for unrelated style fixes, refactors, etc... You should use your best judgment when facing such

A good approach for this is to put yourself in the shoes of the person who will review your patch: will they understand your changes and reasoning just by reading your commit history? Will they find unrelated changes in a particular commit? They shouldn't! Writing meaningful commit messages that follow our commit message format will also help you respect this mantra (see the below section). To maintain a healthy Git history, we ask of you that you write your commit messages as follows: The tense of your message must be present Your message must be prefixed by a type, and a scope The header of your message should not be longer than 50 characters A blank line should be included between the header and the body The body of your message should not contain lines longer than 72 characters We strive to adapt the format. Here is a template of what your commit message should look like: ``` <type>(<scope>): <subject> <BLANK LINE> <body> <BLANK LINE> <footer> ``` The type of your commit indicates what type of change this commit is about. The accepted types are: feat: A new feature fix: A bug fix hotfix: An urgent bug fix during a release process tests: A change that is purely related to the test suite only (fixing a test, adding a test, improving its reliability, etc...) docs: Changes to the README.md, this file, or other such documents style: Changes that do not affect the meaning of the code (white-space trimming, formatting, etc...) perf: A code change that significantly improves performance refactor: A code change that neither fixes a bug nor adds a feature, and is too big to be considered just `perf` chore: Maintenance changes related to code cleaning that isn't considered part of a refactor, build process updates, dependency bumps, or auxiliary tools and libraries updates (LuaRocks, GitHub Actions, etc...). The scope is the part of the codebase that is affected by your change. Choosing it is at your discretion, but here are some of the most frequent ones: proxy: A change that affects the proxying of requests router: A change that affects the router, which matches a request to the desired configured API admin: A change to the Admin API balancer: Changes related to the internal Load Balancer core: Changes affecting a large part of the core, and touching many parts such as `proxy`, `balancer`, `dns` dns: Changes related to internal DNS resolution dao: A change related to the DAO, the interface to the datastores cli: Changes to the CLI cache: Changes to the configuration entities caching (datastore entities) deps: When updating dependencies (to be used with the `chore` prefix) conf: Configuration-related changes (new values, improvements...) `<plugin-name>`: This could be `basic-auth`, or `ldap` for example `*`: When the change affects too many parts of the codebase at once (this should be rare and avoided) Your subject should contain a succinct description of the change. It should be written so that: It uses the present, imperative tense: "fix typo", and not "fixed" or "fixes" It is not capitalized: "fix typo", and not "Fix typo" It does not include a period. :smile: The body of your commit message should contain a detailed description of your changes. Ideally, if the change is significant, you should explain its motivation and the chosen implementation, and justify it. As previously mentioned, lines in the commit messages should not exceed 72 characters. The footer is the ideal place to link to related material about the change: related GitHub issues, Pull Requests, fixed bug reports,

Here are a few examples of good commit messages to take inspiration from: ``` fix(admin): send HTTP 405 on unsupported method The appropriate status code when the request method is not supported on an endpoint is 405. We previously used to send HTTP 404, which is not appropriate. This updates the Admin API helpers to properly return 405 on such user errors. return 405 when the method is not supported in the Admin API helpers add a new test case in the Admin API test suite Fix #678 ``` Or: ``` tests(proxy): add a new test case for URI encoding When proxying upstream, the URI sent by Kong should be the one received from the client, even if it was percent-encoded. This adds a new test case which was missing, to ensure it is the case. ``` As mentioned in the guidelines to submit a patch, the linter must succeed. We use to statically lint our Lua code. You can lint the code like so: ``` $ make lint ``` Or: ``` $ luacheck . ``` We use to write our tests. Your patch must include the related test updates or additions, in the appropriate test suite. `spec/01-unit` gathers our unit tests (to test a given Lua module or function) `spec/02-integration` contains tests that start Kong (connected to a running database), execute Admin API and proxy requests against it, and verify the output `spec/03-plugins` contains tests (both unit and integration) for the bundled plugins (those plugins still live in the core repository as of now, but will eventually be externalized.) A few guidelines when writing tests: Make sure to use appropriate `describe` and `it` blocks, so it's obvious what is being tested exactly Ensure the atomicity of your tests: no test should be asserting two unrelated behaviors at the same time Run tests related to the datastore against all supported databases And a few recommendations, when asserting types: ```lua -- bad assert.Nil(foo) assert.True(bar) -- good assert.is_nil(foo) assert.is_true(bar) ``` Comparing tables: ```lua -- bad (most of the time) assert.equal(t1, t2) -- good assert.same(t1, t2) ``` Please follow the guidelines in on how to write a changelog for your change. We write code for the interpreter, not Lua-PUC. As such, you should follow the LuaJIT best practices: Do not instantiate global variables Consult the Follow the [Performance Guide](https://www.freelists.org/post/luajit/Tuning-numerical-computations-for-LuaJIT-was-Re-ANN-Sci10beta1) recommendations Do not use on hot code paths Prefer using the FFI over traditional bindings via the Lua C API Avoid table rehash by pre-allocating the slots of your tables when possible ```lua -- bad local t = {} for i = 1, 100 do t[i] = i end -- good local new_tab = require "table.new" local t = new_tab(100, 0) for i = 1, 100 do t[i] = i end ``` Cache the globals used by your hot code paths, the cached name should be the original name replaced `.` by `_` ```lua -- bad for i = 1, 100 do t[i] = math.random() end -- good local math_random = math.random for i = 1, 100 do t[i] = math_random() end ``` For OpenResty built-in APIs, we may drop `ngx.` in the localized version ```lua local reqgetpostargs = ngx.req.getpost_args ``` Non-hot paths are localization-optional ```lua if err then ngx.log(ngx.ERR, ...) -- this is fine as the error condition is not on the hot path end ``` Cache the length and indices of your tables to avoid unnecessary CPU cycles ```lua -- bad for i = 1, 100 do t[#t + 1] = othertab[#othertab] end -- good local n = 0 local nothertab

#other_tab for i = 1, 100 do n = n + 1 t[n] = othertab[nother_tab] end ``` And finally, most importantly: use your best judgment to design an efficient algorithm. Doing so will always be more performant than a poorly designed algorithm, even following all the performance tricks of the language you are using. :smile: Please follow to create the appropriate changelog file for your Pull Request. If your Pull Request to was accepted, and it fixes a bug, adds functionality, or makes it significantly easier to use or understand Kong, congratulations! You are eligible to receive the very special digital Contributor Badge! Go ahead and fill out the . Proudly display your Badge and show it to us by tagging on Twitter! *Badges expire after 1 year, at which point you may submit a new contribution to renew the badge.* In order to ensure a healthy and consistent codebase, we ask of you that you respect the adopted code style. This section contains a non-exhaustive list of preferred styles for writing Lua. It is opinionated, but follows the code styles of OpenResty and, by association, Nginx. OpenResty or Nginx contributors should find themselves at ease when contributing to Kong. No line should be longer than 80 characters Indentation should consist of 2 spaces When you are unsure about the style to adopt, please browse other parts of the codebase to find a similar case, and stay consistent with it. You might also notice places in the codebase where the described style is not respected. This is due to legacy code. Contributions to update the code to the recommended style are welcome! When writing a module (a Lua file), separate logical blocks of code with two blank lines: ```lua local foo = require "kong.foo" local _M = {} function _M.bar() -- do thing... end function _M.baz() -- do thing... end return _M ``` When naming a variable or function, do use snake_case: ```lua -- bad local myString = "hello world" -- good local my_string = "hello world" ``` When assigning a constant variable, do give it an uppercase name: ```lua -- bad local max_len = 100 -- good local MAX_LEN = 100 ``` Use the constructor syntax, and do include a trailing comma: ```lua -- bad local t = {} t.foo = "hello" t.bar = "world" -- good local t = { foo = "hello", bar = "world", -- note the trailing comma } ``` On single-line constructors, do include spaces around curly-braces and assignments: ```lua -- bad local t = {foo="hello",bar="world"} -- good local t = { foo = "hello", bar = "world" } ``` Prefer `ipairs()` to `for` loop when iterating an array, which gives us more readability: ```lua -- bad for i = 1, #t do ... end -- good for _, v in ipairs(t) do ... end ``` Do favor the use of double quotes in all Lua code (plain files and `*bylua_block` directives): ```lua -- bad local str = 'hello' -- good local str = "hello" ``` If a string contains double quotes, do favor long bracket strings: ```lua -- bad local str = "message: \"hello\"" -- good local str = [[message: "hello"]] ``` When using the concatenation operator, do insert spaces around it: ```lua -- bad local str = "hello ".."world" -- good local str = "hello " .. "world" ``` If a string is too long, do break it into multiple lines, and join them with the concatenation operator: ```lua -- bad local str = "It is a very very very long string, that should be broken into multiple

-- good local str = "It is a very very very long string, " .. "that should be broken into multiple lines." ``` Prefer the function syntax over variable syntax: ```lua -- bad local foo = function() end -- good local function foo() end ``` Perform validation early and return as early as possible: ```lua -- bad local function check_name(name) local valid = #name > 3 valid = valid and #name < 30 -- other validations return valid end -- good local function check_name(name) if #name <= 3 or #name >= 30 then return false end -- other validations return true end ``` Follow the return values conventions: Lua supports multiple return values, and by convention, handles recoverable errors by returning `nil` plus a `string` describing the error: ```lua -- bad local function check() local ok, err = do_thing() if not ok then return false, { message = err } end return true end -- good local function check() local ok, err = do_thing() if not ok then return nil, "could not do thing: " .. err end return true end ``` When a function call makes a line go over 80 characters, do align the overflowing arguments to the first one: ```lua -- bad local str = string.format("SELECT * FROM users WHERE firstname = '%s'", firstname) -- good local str = string.format("SELECT * FROM users WHERE first_name = '%s'", first_name) ``` Avoid writing 1-line conditions, do indent the child branch: ```lua -- bad if err then return nil, err end -- good if err then return nil, err end ``` When testing the assignment of a value, do use shortcuts, unless you care about the difference between `nil` and `false`: ```lua -- bad if str ~= nil then end -- good if str then end ``` When creating multiple branches that span multiple lines, do include a blank line above the `elseif` and `else` statements: ```lua -- bad if foo then do_stuff() keepdoingstuff() elseif bar then dootherstuff() keepdoingother_stuff() else error() end -- good if thing then do_stuff() keepdoingstuff() elseif bar then dootherstuff() keepdoingother_stuff() else error() end ``` For one-line blocks, blank lines are not necessary: ```lua good if foo then do_stuff() else error("failed!") end ``` Note in the correct "long" example that if some branches are long, then all branches are created with the preceding blank line (including the one-liner `else` case). When a branch returns, do not create subsequent branches, but write the rest of your logic on the parent branch: ```lua -- bad if not str then return nil, "bad value" else do_thing(str) end -- good if not str then return nil, "bad value" end do_thing(str) ``` When assigning a value or returning from a function, do use ternaries if it makes the code more readable: ```lua -- bad local foo if bar then foo = "hello" else foo = "world" end -- good local foo = bar and "hello" or "world" ``` When an expression makes a line longer than 80 characters, do align the expression on the following lines: ```lua -- bad if thingone < 1 and longandcomplicatedfunction(arg1, arg2) < 10 or thing_two > 10 then end -- good if thingone < 1 and longandcomplicatedfunction(arg1, arg2) < 10 or thing_two > 10 then end ``` When invoking `ngx.log()` with some variable as input, prefer vararg-style calls rather than using the string concatenation operator (`..`): ```lua -- bad ngx.log(ngx.DEBUG, "if `myvar` is nil, this code throws an exception: " .. myvar) -- good ngx.log(ngx.DEBUG, "if `myvar` is nil, this code is fine: ", myvar) ```