Skip to content

Contributing

Jacob Alzén edited this page Aug 22, 2023 · 29 revisions

If you're thinking about contributing to the Fyne project - thanks!

To help ensure consistent code and user experience, we are building this list of standards we follow and ask all contributors to consider this when working on anything to feed into the project.

Contributor agreement

For any non-trivial contributions (for example larger than text change, single line bug fix or rearranging of source code) we require that developers sign our contributor license agreement (CLA). This can be found, and signed, in the fyne cloud developer section.

Team membership

Regular contributors are welcome to join our team. We have a lot more information about that on the Contributing: Membership page.

Review Responsibility

A team member is expected (but not required) to help review or find a reviewer for open pull requests. If a pull request is relevant to a team member's prior change, it is encouraged to review that pull request.

After the review process, a pull request could be merged when there is at least one team member approves the change. A reviewer who approves the pull request can click the merge button; if the pull request author has permission to merge (i.e., as a team member), we encourage the author to merge their change after receiving an approval.

Merge commit is normally preferred but single commit PRs can be rebased and a PR with many small, related changes could be squashed.

Large changes

Before we get into the details of how to make a commit or format code we should consider how to manage larger changes. If you are looking to make a big change to the toolkit, whether it is feature addition or an improvement of existing features it may be useful to get feedback on the concept before you begin work. This can be further divited into two possibilities - when you are confident of the solution design (this would use a proposal process), and those times when you are looking to collaborate on finding a solution.

It is also generally a good idea to try and break down large pull requests into smaller ones where it makes sense. Reviewing large portions of code can take time so try to keep the code clean, structured and without unrelated changes.

Note that the release schedule has a proposal-freeze date so that high-level discussions about API do not impact the feature freeze and ability to polish the new features.

TL;DR: Advice

  1. We prefer to discuss a large change with other members over our Slack channel before sending out a big pull request or creating an issue (if sending a pull request is necessary, converting that pull request to a draft could lift potential reviewing work from other members);
  2. We prefer to prepare a minimum prototyped change for the discussion and clarification;
  3. We prefer to document the large change (if using a proposal process). It is always better suited with a sufficient amount of communication to build a common consensus among all involved members before sending a pull request for that change.

Proposals

When you have in mind an approach for large feature addition or improvement, and you can sketch out the solution but would like feedback before you begin coding, then Proposals are the way to do it. By following the steps in the Contributing: Proposals page you can fill out the various important information and submit it to the team for discussion. This would then normally be discussed on one of our community calls, but most feedback will be captured in the proposals repository.

Collaborating on a solution

When it is not clear exactly how to proceed, as is common with big changes or fixing underlying problems, it can be helpful to collaborate earlier on than at the solution stage. Doing so allows a wider team to understand the problem, discuss the scope of the approach and collaborate on a proposed solution. To find the best solution in these cases try to follow the following 4 steps:

  1. Identify some members of the team who are interested in collaborating (this helps to coordinate real-time conversations).
  2. Gather background information, document what you are aiming solve and possible areas that might be impacted. Consider using the Contributing: Brainstorming hints.
  3. Working with the group identified, discuss the problem so the challenge ahead is well understood, work out the scope of a resolution and what would go into a proposed fix.
  4. Write a proposal following the steps at Contributing: Proposals which outlines the solution that will be developed.

Once a proposal is accepted then the rest of this page will apply for structuring your code and styling it to match the Fyne project standards.

Stale pull requests

We have decided that pull requests that are not actively worked on may be closed after being inactive for six months. This allows us to focus on active pull requests and ensure they receive more attention from the community. Developers that are willing to continue working on the changes are of course welcome to reopen closed pull requests when they find the time to do so.

Commits

  • Source control is using GitFlow - this means that develop is our default branch and master always follows our most recent release. New features should be branched from, and merged back into, develop.
  • Each commit should have 1 purpose. Fixing whitespace or refactoring should be split from feature additions or bug fixing.
  • Continuous integration is run on our main branches and any pull request must pass our standard checks.

Adding API

  • Adding new (public) API needs to be done with careful thought - once added it must be maintained for a long time.
  • Try to match naming and terminology unless introducing a new concept
  • Every new API will need to have a "// Since: x.y" line that is the next API version number - if you are unsure which version to use, ask in the pull request or chat room (see also Naming)

Code style

  • All new code should have tests.

  • Go code will be formatted in the Go default style - this means tab indents amongst other things. Your code can be updated with goimports -w . before pushing code.

  • Try to keep methods short, with clear naming. (See also Naming)

  • Where possible, check corner cases and input errors at the top of a method and exit early.

  • The main body of a function should be the least-indented code, where possible.

  • All Go files should have a standardized ordering of the header (everything apart from types and functions) as follows:

    • package
    • imports
    • CGo
    • consts
    • enums
    • vars
  • File should have a single exported type (with some small exceptions) and the following grouping of contents should be followed:

    • [header - see above]
    • exported type (i.e. Widget)
      • type constructor(s)
      • exported methods
      • unexported type methods
    • additional unexported types (i.e. a WidgetRenderer - in the same order as above)
  • Within each grouping above methods should be in alphabetical order.

  • Package functions (i.e. those functions without a type) should be in a separate file, named pkgname.go, with the following content order:

    • [header - see above]
    • exported functions
    • unexported functions
  • Packages with a main function (normally applications) should have a main.go file that follows this structure:

    • [header - see above]
    • main
  • Struct initialization should either be single line, or with each field on a new line, but not a hybrid of the two.

myType{Foo: f, Bar: r, Baz: z}

myType{
  Foo: f,
  Bar: r,
  Baz: z,
}
  • Functions and other scope blocks (if, for etc) should not be arranged on one line - a scope body belongs on a new line.

  • We prefer inline error assignment and check, unless the error is being used elsewhere, this helps keep the scope of the variable small.

if err := myFunc(); err != nil {
  // Handle error
}
  • Do not add commented out code (unless agreed or required for some reason) - we use version control to track changes, old versions can be found there.

  • We prefer to create struct pointers like &structType{} instead of using new(structType). This has the benefit that struct fields can be set directly on creation.


More information about other ways to contribute can be found on our website.