Kharagpur Winter of Code is a five-week online program for students new to open-source development, run by the Kharagpur Open Source Society. It exists to get people over the first hurdle — the one where you have the skills to contribute but no idea how the process works — and it doubles as preparation for the larger summer programs like Google Summer of Code.
I contributed to three projects during the 2020 edition. All of my work turned out to be linting, formatting, and CI, which was not the plan but was probably the right thing.
What I shipped
| Project | Contribution |
|---|---|
| Graph-API (opens in a new tab) | ESLint + Prettier GitHub Actions, README rewrite |
| notation-converter (opens in a new tab) | Feature-request issue template, ESLint + Prettier Actions |
| World-Lines (opens in a new tab) | golangci-lint GitHub Action |
Five pull requests merged across the three, off the back of three issues I opened first.
TIP
Opening the issue before the pull request mattered more than I expected. It gave the maintainer a chance to say "yes, but use X instead" before I had written anything, and twice they did. For a first-time contributor, that conversation is worth more than the code.
Automating formatting with Prettier
Prettier is an opinionated formatter. You do not configure a style; you accept its style and stop discussing it. That is the entire value — the argument about brace placement disappears from code review permanently.
Running it in CI rather than trusting everyone's editor is what makes it stick:
name: Prettier
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
prettier:
runs-on: ubuntu-latest
steps:
- name: GitHub Action for Prettier
uses: actions/checkout@v2
with:
ref: ${{ github.head_ref }}
- name: Prettify code
uses: creyD/prettier_action@v2.2
with:
prettier_options: --write **/*.{css,html,js,md}The highlighted line is the one that is easy to miss. On a pull request, actions/checkout defaults to a detached merge commit rather than the source branch, so without ref: ${{ github.head_ref }} the action reformats code and then has nowhere to push it.
Catching bugs with ESLint
Where Prettier handles how code looks, ESLint handles what it does — unused variables, unreachable branches, accidental globals. It parses to an AST and evaluates rules against it, and every rule is a plugin, so a project can enable exactly the checks it cares about.
name: ESLint
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
eslint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
with:
fetch-depth: 1
- uses: actions/setup-node@v1
with:
node-version: 12
- run: rm -f .yarnclean
- run: yarn --frozen-lockfile --ignore-engines --ignore-optional --no-bin-links --non-interactive --silent --ignore-scripts --production=false
env:
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true
HUSKY_SKIP_INSTALL: true
- uses: tinovyatkin/action-eslint@v1
with:
repo-token: ${{secrets.GITHUB_TOKEN}}
check-name: eslintThe two are configured to cooperate rather than fight. Listing prettier in extends switches off every ESLint rule that would have an opinion about formatting, leaving Prettier in sole charge of it:
{
"env": {
"commonjs": true,
"es6": true,
"node": true
},
"extends": ["prettier", "airbnb-base"],
"plugins": ["prettier"],
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parserOptions": {
"ecmaVersion": 2018
},
"rules": {
"prettier/prettier": "error"
}
}WARNING
Order matters in extends — later entries override earlier ones. Putting airbnb-base after prettier re-enables the formatting rules prettier just turned off, and you get a build that fails whichever way you format the code. This is the single most common way to misconfigure the pair.
An issue template
For notation-converter I added a feature-request template. Templates seem like bureaucracy until you maintain something and receive your fifth "add dark mode" issue with no further detail:
---
name: 🚀 Feature
about: Submit a proposal/request for a new feature
labels: "feature"
---
## 🚀 Feature
(A clear and concise description of what the feature is.)
## Please Describe The Problem To Be Solved
(Present a concise description of the problem to be addressed by this
feature request. Be clear about what is in scope and out of scope.)
## (Optional): Suggest a Solution
(A concise description of your preferred solution. Things to address include
details of the technical implementation, tradeoffs made in design decisions,
and caveats for the future. If there are multiple solutions, present each one
separately and save comparisons for the end.)Linting Go
World-Lines is a Go project, so it got golangci-lint (opens in a new tab) instead — a runner that executes dozens of Go linters in parallel with a shared cache, which is what makes running that many of them practical in CI.
name: golangci-lint
on:
push:
tags:
- v*
branches:
- master
- main
pull_request:
jobs:
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: golangci-lint
uses: golangci/golangci-lint-action@v2
with:
version: v1.29What I took from it
Ending up on tooling for all three projects felt at the time like I had missed the interesting work. In hindsight it was the fastest way in. Tooling changes are self-contained, they are easy for a maintainer to review, and they do not require understanding a codebase you have never seen — but getting one merged still teaches you the entire contribution workflow: forking, branching, the review conversation, responding to feedback, and getting a CI pipeline green on someone else's repository.
That workflow is the actual barrier for most people, not the code. Learning it on a fifty-line YAML file is much less painful than learning it in the middle of a real feature.
Thanks to my mentors, and to the Kharagpur Open Source Society (opens in a new tab) for running KWoC (opens in a new tab).