CONTRIBUTING

How to contribute to GDPR-IAB-TCFv2?

DESCRIPTION

Patches are welcome!

They must be built against the devel branch, then submitted as pull requests at GitHub.

The documentation is written using the POD format. Use the perldoc tool to render it in a terminal:

perldoc CONTRIBUTING.pod

PATCHING, STEP BY STEP

1. Get the source
git clone --origin upstream git://github.com/peczenyj/GDPR-IAB-TCFv2.git
cd GDPR-IAB-TCFv2
git checkout devel
2. Install build dependencies

Not required for doc patches.

curl -L https://cpanmin.us | perl - --installdeps --with-develop .
3. Make your fix/feature
git checkout -b <my-patch> devel

# edit files and add modification

# Run the testsuite
prove -v

git commit -s -m '<<some nice message>>'
4. Setup a fork
4.1. Fork the project on GitHub

(You are using GDPR-IAB-TCFv2 isn't it?)

git remote add github <github-user>.github.com:<github-user>/GDPR-IAB-TCFv2.git
5. Submit your work
5.1 Push!
git push github <my-patch>
5.2 Submit a pull request on GitHub
6. Loop

Redo from step 3.

RELEASING A NEW VERSION

This project follows the Git Flow branching model: feat/* and fix/* branches merge into devel; release/* branches cut from devel and merge into both main and devel; hotfix/* branches cut from main and merge into both. Tags live on main.

The recommended path uses the git-flow CLI (git-flow-avh) to drive the ceremony. Plain git works too — both variants are shown side-by-side at each step so you can pick one.

The release pipeline itself is fully automated by .github/workflows/release.yml: pushing any v* tag triggers a build, a PAUSE upload, and a GitHub Release with the tarball attached. You only need to drive the local prep and the merge/tag.

Prerequisites (one-time)

1. Install release tooling
# POD → Markdown converter (regenerates README.md)
cpanm Pod::Markdown
# or: apt install libpod-markdown-perl

# Conventional-Commits changelog generator
cargo install git-cliff
# or: brew install git-cliff

# git-flow CLI (optional but recommended)
apt install git-flow
# or: brew install git-flow-avh
2. Initialize git-flow once (skip if you prefer plain git)
git flow init -d

When prompted, accept the project's existing layout:

  • production branch = main

  • next-release branch = devel

  • feature prefix = feat/

  • release prefix = release/

  • hotfix prefix = hotfix/

The -d flag uses defaults where they match; you'll only be prompted for the values that differ.

3. Configure CPAN credentials (repo admin, one-time)

In GitHub, go to Settings → Secrets and variables → Actions and add:

  • PAUSE_USER — your PAUSE username

  • PAUSE_PASSWORD — your PAUSE password

If these secrets are missing, the GitHub Release step still runs but the PAUSE upload step is skipped.

Versioning convention

$VERSION uses the 3-digit 0.XYZ form. Bump the last two digits in steps of 10 for normal releases (e.g. 0.350 → 0.360) and by 1 for pure bug-fix follow-ups (e.g. 0.350 → 0.351). The git tag prepends v (e.g. v0.360); the $VERSION string in the .pm does not.

Step-by-step release

1. Sync devel and confirm what's queued
git checkout devel
git pull --ff-only
git log --oneline $(git describe --tags --abbrev=0)..HEAD

The log shows everything that will land in the new release. If something that should be in this release is missing, merge its PR before continuing.

2. Open a release branch

git-flow:

git flow release start 0.360

vanilla git:

git checkout -b release/0.360 devel
3. Bump $VERSION
$EDITOR lib/GDPR/IAB/TCFv2.pm
# Edit:  our $VERSION = "0.360";

Makefile.PL reads the version from this file via VERSION_FROM; no other file needs editing.

4. Regenerate the changelog
git cliff --tag v0.360 -o CHANGELOG.md

cliff.toml is preconfigured for Conventional Commits and groups by feat: / fix: / docs: / perf: / refactor: / Other; style: / test: / chore: are skipped.

Sanity-check the output — git-cliff slurps full commit message bodies, so stray lines like # Conflicts: from merge commits can leak into the changelog. Strip them by hand if present.

5. Regenerate the README
pod2markdown lib/GDPR/IAB/TCFv2.pm > README.md

Only the main module's POD ships in README.md; submodule POD is served via MetaCPAN.

6. Build and verify locally
perl Makefile.PL
make
make test           # runs t/
prove -lr xt        # runs perlcritic + perltidy
make manifest       # updates MANIFEST if test files were added
make dist           # produces GDPR-IAB-TCFv2-0.360.tar.gz

Open the tarball and confirm only intended files ship (no .bak, no docs/, no AGENTS.md, no MYMETA.*). MANIFEST.SKIP already excludes those, but a quick eyeball is cheap insurance.

7. Commit the release prep
git add lib/GDPR/IAB/TCFv2.pm CHANGELOG.md README.md
# Also `git add MANIFEST` if `make manifest` changed it
git commit -m "chore: prepare for v0.360 release"

One commit. Do not tag yet — the tag is created in step 8.

8. Finish the release

git-flow (recommended — automates the merges and tag):

git flow release finish 0.360
# Prompts for the tag message; use something like:
# "Release v0.360 — <one-line theme>"

git push origin main
git push origin devel
git push origin v0.360       # ← triggers release.yml

git flow release finish merges release/0.360 into main, tags it as v0.360, merges back into devel (so the version bump and changelog land there too), and deletes the local release/0.360 branch.

You must push all three refs. The release workflow only fires on the tag push, but the tag must be reachable from main for the workflow to check out the right tree.

vanilla git (more steps, gives reviewable PRs):

# 1. PR release/0.360 → devel
git push -u origin release/0.360
gh pr create --base devel \
    --title "chore: prepare for v0.360 release" \
    --body "Version bump, README regen, changelog refresh."
# Review and merge on GitHub.

# 2. PR devel → main
gh pr create --base main --head devel \
    --title "Release v0.360"
# Review and merge on GitHub.

# 3. Tag main and push
git checkout main
git pull --ff-only
git tag -a v0.360 -m "Release v0.360 — <one-line summary>"
git push origin v0.360       # ← triggers release.yml
9. Watch the release workflow
gh run watch -R peczenyj/GDPR-IAB-TCFv2
# or
gh run list -R peczenyj/GDPR-IAB-TCFv2 --workflow release.yml --limit 1

The workflow does:

  1. perl Makefile.PL && make manifest && make dist — produces the tarball

  2. cpan-upload -u $PAUSE_USER -p $PAUSE_PASSWORD ... — uploads to PAUSE (skipped silently if PAUSE_USER is empty)

  3. softprops/action-gh-release@v2 — creates the GitHub Release with the tarball attached and auto-generated notes

If the PAUSE step fails, the GitHub Release still gets created. You can then re-upload manually via https://pause.perl.org/ without re-running the workflow.

10. Post-release sanity
# Confirm the GitHub Release
gh release view v0.360 -R peczenyj/GDPR-IAB-TCFv2

# Wait ~30 min for PAUSE → MetaCPAN propagation, then:
curl -s https://fastapi.metacpan.org/v1/release/GDPR-IAB-TCFv2 \
    | jq .version
# Should report "0.360"

The docker image (peczenyj/gdpr-iab-tcfv2:0.360 and :latest) is published by .github/workflows/docker.yml on the same v* tag push.

Pre-release review (and why we don't use draft GitHub Releases)

GitHub supports draft releases that you can review before publishing. For most projects this is a useful pre-publish review gate. For this project it is not, and the doc deliberately omits the pattern. Two reasons:

  1. PAUSE upload is irreversible. Once release.yml uploads GDPR-IAB-TCFv2-0.360.tar.gz to PAUSE, the version number is burned forever — you can delete the file but can't re-upload a new tarball under the same version. So a "review the GitHub Release before it goes out" gate doesn't actually protect the thing that matters (the CPAN-distributed artifact); it only protects the rendered release-notes page.

  2. The current release.yml hard-codes draft: false. If you created a draft release with gh release create --draft and then pushed the tag, the workflow's softprops/action-gh-release@v2 step would update the release and flip draft to false — closing the review window the moment the workflow finishes (~3 minutes). Conversely, if you let gh release create --target main --draft create the tag via the REST API instead of pushing it via git, release.yml would not fire at all (push events from API-created tags don't trigger workflows), and your tarball would never reach PAUSE.

The review gate that actually buys you something is the release-prep PR in the vanilla-git path of step 8: opening release/0.360 → devel and devel → main as PRs lets a reviewer (or future-you) catch a typo in the changelog, an off-by-one in $VERSION, or a stale README before the merge that triggers the unstoppable downstream automation. Use that path when you want pre-release review.

If you ever do want the draft-release pattern to work properly, it needs a workflow tweak: add release: { types: [published] } to release.yml's on: triggers, and remove draft: false from the softprops step. The doc does not include that variant today.

Hotfix releases

For an urgent fix that has to skip devel and ship straight from main:

git-flow:

git flow hotfix start 0.351
# Make the fix, bump $VERSION, regenerate CHANGELOG and README, commit
git flow hotfix finish 0.351
git push origin main devel v0.351

vanilla git:

git checkout -b hotfix/0.351 main
# Make the fix, bump $VERSION, regenerate CHANGELOG and README
git add lib/GDPR/IAB/TCFv2.pm CHANGELOG.md README.md
git commit -m "fix: <description> (v0.351)"
git push -u origin hotfix/0.351

# PR hotfix/0.351 → main
gh pr create --base main --title "Hotfix v0.351 — <description>"
# Merge.

# Merge main back into devel so the fix doesn't get lost
git checkout devel
git pull --ff-only
git merge --no-ff main -m "Merge hotfix v0.351 back into devel"
git push

# Tag main and push
git checkout main && git pull --ff-only
git tag -a v0.351 -m "Hotfix v0.351 — <description>"
git push origin v0.351