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

ProjectContribution
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:

.github/workflows/prettier.yml
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.

.github/workflows/eslint.yml
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: eslint

The 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:

.eslintrc.json
{
  "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:

.github/ISSUE_TEMPLATE/feature.md
---
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.

.github/workflows/golangci-lint.yml
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.29

What 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).