From 84c1daa1ab37cf4ce8f0cfae64db86731bbf4e02 Mon Sep 17 00:00:00 2001 From: woodpecker-bot <89799003+woodpecker-bot@users.noreply.github.com> Date: Wed, 1 Apr 2026 14:56:55 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=89=20Release=203.14.0-rc.0=20(#5976)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 205 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2975ced04..7ffc3f89e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,210 @@ # Changelog +## [3.14.0-rc.0](https://github.com/woodpecker-ci/woodpecker/releases/tag/v3.14.0-rc.0) - 2026-04-01 + +### โค๏ธ Thanks to all contributors! โค๏ธ + +@6543, @CrimsonFez, @LUKIEYF, @MartinSchmidt, @Pnkcaht, @Sim-hu, @TumbleOwlee, @api2062, @brainbaking, @cliffmccarthy, @confusedsushi, @dccdis, @hhamalai, @hnb2, @mehrdadbn9, @mofr93, @myers, @myselfghost, @paulovitorbal, @qwerty287, @samoli, @savv, @stardothosting + +### ๐Ÿ”’ Security + +- Send 404 if logs are not allowed to access [[#6349](https://github.com/woodpecker-ci/woodpecker/pull/6349)] +- Prevent registering as arbitrary agents with system token [[#6283](https://github.com/woodpecker-ci/woodpecker/pull/6283)] +- Update `fast-xml-parser` [[#6258](https://github.com/woodpecker-ci/woodpecker/pull/6258)] +- Update `dompurify` and `svgo` [[#6198](https://github.com/woodpecker-ci/woodpecker/pull/6198)] +- Update edwards25519 [[#6143](https://github.com/woodpecker-ci/woodpecker/pull/6143)] +- chore(deps): update dependency lodash to v4.17.23 [security] [[#5997](https://github.com/woodpecker-ci/woodpecker/pull/5997)] + +### โœจ Features + +- Support one-shot agent execution mode [[#6150](https://github.com/woodpecker-ci/woodpecker/pull/6150)] +- Add external secret extension implementation [[#6252](https://github.com/woodpecker-ci/woodpecker/pull/6252)] +- make it possible to disable the isolated home for local agents [[#6251](https://github.com/woodpecker-ci/woodpecker/pull/6251)] +- Add Container Registry credential extension [[#5993](https://github.com/woodpecker-ci/woodpecker/pull/5993)] +- Support exclusive config extensions [[#5978](https://github.com/woodpecker-ci/woodpecker/pull/5978)] + +### ๐Ÿ“ˆ Enhancement + +- Add netrc option for config/registry extension [[#6333](https://github.com/woodpecker-ci/woodpecker/pull/6333)] +- Migrate to moby [[#6357](https://github.com/woodpecker-ci/woodpecker/pull/6357)] +- Deprecate commit avatar envs [[#6356](https://github.com/woodpecker-ci/woodpecker/pull/6356)] +- Refactor server/pubsub into interface [[#6318](https://github.com/woodpecker-ci/woodpecker/pull/6318)] +- Separate cron field [[#6346](https://github.com/woodpecker-ci/woodpecker/pull/6346)] +- Refactor pipeline runtime code [[#6166](https://github.com/woodpecker-ci/woodpecker/pull/6166)] +- Show Woodpecker version on pipeline details [[#6316](https://github.com/woodpecker-ci/woodpecker/pull/6316)] +- Unify import aliases [[#6328](https://github.com/woodpecker-ci/woodpecker/pull/6328)] +- Improve linter warning when step has no when block [[#6314](https://github.com/woodpecker-ci/woodpecker/pull/6314)] +- Improve error message when no workflows for manual were found [[#6313](https://github.com/woodpecker-ci/woodpecker/pull/6313)] +- Server return conflict status when stale repo causes duplicate insert [[#6276](https://github.com/woodpecker-ci/woodpecker/pull/6276)] +- Show global/org registries in org/repo registries tab [[#6291](https://github.com/woodpecker-ci/woodpecker/pull/6291)] +- Forward skipped step state once it's known [[#6295](https://github.com/woodpecker-ci/woodpecker/pull/6295)] +- Only add compatibility environment variables for drone-ci to plugins [[#6271](https://github.com/woodpecker-ci/woodpecker/pull/6271)] +- Creating new engine runtime now requires backend as argument [[#6268](https://github.com/woodpecker-ci/woodpecker/pull/6268)] +- Compare admins case-insensitively [[#6261](https://github.com/woodpecker-ci/woodpecker/pull/6261)] +- Allow to cancel on failure [[#6158](https://github.com/woodpecker-ci/woodpecker/pull/6158)] +- Refactor so storage detects if Insert fails because of unique constraint [[#6259](https://github.com/woodpecker-ci/woodpecker/pull/6259)] +- Add configure the max number of lines loaded in log webview [[#6250](https://github.com/woodpecker-ci/woodpecker/pull/6250)] +- Add "Load more" pagination to pipeline list [[#6200](https://github.com/woodpecker-ci/woodpecker/pull/6200)] +- refactor: pipeline runtime add description and prevent race [[#6167](https://github.com/woodpecker-ci/woodpecker/pull/6167)] +- refactor: use upstream slices.Concat and remove utils.MergeSlices [[#6185](https://github.com/woodpecker-ci/woodpecker/pull/6185)] +- Add enhanced function for error message handling in http request for configuration fetching [[#5712](https://github.com/woodpecker-ci/woodpecker/pull/5712)] +- Remove fixed badge width in UI [[#6157](https://github.com/woodpecker-ci/woodpecker/pull/6157)] +- Refactor pipeline engine [[#6073](https://github.com/woodpecker-ci/woodpecker/pull/6073)] +- Added cancel info so one can see why it was cancelled [[#6072](https://github.com/woodpecker-ci/woodpecker/pull/6072)] +- Document required forge methods [[#6049](https://github.com/woodpecker-ci/woodpecker/pull/6049)] +- Dynamic log following [[#6036](https://github.com/woodpecker-ci/woodpecker/pull/6036)] +- Per-Workflow and Per-Workflow-Step badge generation [[#5977](https://github.com/woodpecker-ci/woodpecker/pull/5977)] +- Render MD in pipeline titles [[#5999](https://github.com/woodpecker-ci/woodpecker/pull/5999)] +- Simplify and Fix server task queue [[#6017](https://github.com/woodpecker-ci/woodpecker/pull/6017)] +- fix(agent): workflow runner use shutdown context [[#6021](https://github.com/woodpecker-ci/woodpecker/pull/6021)] +- Update Architecture: move `pipeline/rpc` => `rpc` & `server/{grpc => rpc}` [[#6012](https://github.com/woodpecker-ci/woodpecker/pull/6012)] +- Implement retry logic in HTTP Send method [[#5857](https://github.com/woodpecker-ci/woodpecker/pull/5857)] +- CLI: Allow single output template [[#5882](https://github.com/woodpecker-ci/woodpecker/pull/5882)] +- Improve service syntax related docs and tests nits [[#5991](https://github.com/woodpecker-ci/woodpecker/pull/5991)] +- Remove deactivated secrets type from container defintion [[#5983](https://github.com/woodpecker-ci/woodpecker/pull/5983)] + +### ๐Ÿ› Bug Fixes + +- Fix workflow beeing skipped and marked as failed when agent starts before server [[#6361](https://github.com/woodpecker-ci/woodpecker/pull/6361)] +- Only redirect after login [[#6348](https://github.com/woodpecker-ci/woodpecker/pull/6348)] +- Set workflow services stuck in running state to finished [[#6337](https://github.com/woodpecker-ci/woodpecker/pull/6337)] +- Fix bitbucket api deprecations [[#6324](https://github.com/woodpecker-ci/woodpecker/pull/6324)] +- Fix workflow serialize to omit skip_clone if false [[#6319](https://github.com/woodpecker-ci/woodpecker/pull/6319)] +- Fix build deb rpm packages [[#6309](https://github.com/woodpecker-ci/woodpecker/pull/6309)] +- Enable crons if created via CLI [[#6228](https://github.com/woodpecker-ci/woodpecker/pull/6228)] +- Fix message on gitlab tag event [[#6196](https://github.com/woodpecker-ci/woodpecker/pull/6196)] +- fix(bbdc): resolve annotated tag object SHA to commit SHA before posting build status [[#6203](https://github.com/woodpecker-ci/woodpecker/pull/6203)] +- Prevent leaking goroutines on cancelled steps [[#6186](https://github.com/woodpecker-ci/woodpecker/pull/6186)] +- Independently evaluate status filter and support on workflows [[#6183](https://github.com/woodpecker-ci/woodpecker/pull/6183)] +- Fix status merging with skipped pipelines [[#6176](https://github.com/woodpecker-ci/woodpecker/pull/6176)] +- Update pipeline config schema [[#6156](https://github.com/woodpecker-ci/woodpecker/pull/6156)] +- Fix OAuth token refresh race condition with singleflight [[#6153](https://github.com/woodpecker-ci/woodpecker/pull/6153)] +- Fully merge statuses [[#6119](https://github.com/woodpecker-ci/woodpecker/pull/6119)] +- Only set tag env on tags [[#6142](https://github.com/woodpecker-ci/woodpecker/pull/6142)] +- Fix bitbucket email [[#6102](https://github.com/woodpecker-ci/woodpecker/pull/6102)] +- Detached or service steps report back too [[#6039](https://github.com/woodpecker-ci/woodpecker/pull/6039)] +- Don't propagate workflow error from agent back to agent [[#6056](https://github.com/woodpecker-ci/woodpecker/pull/6056)] +- Fix pipeline cancellation status handling and step state synchronization [[#6011](https://github.com/woodpecker-ci/woodpecker/pull/6011)] +- Add retry logic for CreatePipeline with backoff [[#6067](https://github.com/woodpecker-ci/woodpecker/pull/6067)] +- Fix OAuth token refresh in webhook handling for Bitbucket and GitHub [[#6059](https://github.com/woodpecker-ci/woodpecker/pull/6059)] +- Refresh token before forge calls [[#6035](https://github.com/woodpecker-ci/woodpecker/pull/6035)] +- Local backend: cleanup generated script for cmd.exe shell [[#6029](https://github.com/woodpecker-ci/woodpecker/pull/6029)] +- Local backend: setup clone step respects context [[#6030](https://github.com/woodpecker-ci/woodpecker/pull/6030)] +- Fix: Agent now gracefully handles running containers when killed [[#6018](https://github.com/woodpecker-ci/woodpecker/pull/6018)] +- Local backend: handle canceled steps case [[#6008](https://github.com/woodpecker-ci/woodpecker/pull/6008)] + +### ๐Ÿงช Tests + +- Extend workflow integration tests [[#6272](https://github.com/woodpecker-ci/woodpecker/pull/6272)] +- Add registry service tests [[#6330](https://github.com/woodpecker-ci/woodpecker/pull/6330)] +- Add workflow integration test [[#6270](https://github.com/woodpecker-ci/woodpecker/pull/6270)] +- Increase timeout for migration tests [[#6206](https://github.com/woodpecker-ci/woodpecker/pull/6206)] +- Ignore fixtures for coverage [[#6197](https://github.com/woodpecker-ci/woodpecker/pull/6197)] +- Use tabs for indentation in embedded JSON [[#6103](https://github.com/woodpecker-ci/woodpecker/pull/6103)] +- Add some tests [[#6076](https://github.com/woodpecker-ci/woodpecker/pull/6076)] +- Ignore mocks for coverage [[#6074](https://github.com/woodpecker-ci/woodpecker/pull/6074)] + +### ๐Ÿ“š Documentation + +- chore(deps): update dependency typescript to v6 [[#6336](https://github.com/woodpecker-ci/woodpecker/pull/6336)] +- chore(deps): update docs npm deps non-major [[#6335](https://github.com/woodpecker-ci/woodpecker/pull/6335)] +- Add CI check for docs on feature PRs [[#6315](https://github.com/woodpecker-ci/woodpecker/pull/6315)] +- chore(deps): update dependency isomorphic-dompurify to v3.6.0 [[#6288](https://github.com/woodpecker-ci/woodpecker/pull/6288)] +- chore(deps): update dependency yaml to v2.8.3 [[#6287](https://github.com/woodpecker-ci/woodpecker/pull/6287)] +- Add agentscan to plugin docs [[#6285](https://github.com/woodpecker-ci/woodpecker/pull/6285)] +- Adding opengrep plugin [[#6282](https://github.com/woodpecker-ci/woodpecker/pull/6282)] +- chore(deps): update docs npm deps non-major [[#6281](https://github.com/woodpecker-ci/woodpecker/pull/6281)] +- Sorted the glossary items [[#6255](https://github.com/woodpecker-ci/woodpecker/pull/6255)] +- chore(deps): update docs npm deps non-major [[#6240](https://github.com/woodpecker-ci/woodpecker/pull/6240)] +- plugin: ascii junit report: renamed gh username [[#6232](https://github.com/woodpecker-ci/woodpecker/pull/6232)] +- chore(deps): update dependency svgo to v4 [[#6214](https://github.com/woodpecker-ci/woodpecker/pull/6214)] +- chore(deps): update docs npm deps non-major [[#6210](https://github.com/woodpecker-ci/woodpecker/pull/6210)] +- Update serialize-javascript [[#6182](https://github.com/woodpecker-ci/woodpecker/pull/6182)] +- chore(deps): update docs npm deps non-major [[#6173](https://github.com/woodpecker-ci/woodpecker/pull/6173)] +- chore(deps): update dependency isomorphic-dompurify to v3 [[#6147](https://github.com/woodpecker-ci/woodpecker/pull/6147)] +- chore(deps): update docs npm deps non-major [[#6137](https://github.com/woodpecker-ci/woodpecker/pull/6137)] +- Add deprecation policy [[#6068](https://github.com/woodpecker-ci/woodpecker/pull/6068)] +- fix(deps): update dependency @easyops-cn/docusaurus-search-local to ^0.55.0 [[#6125](https://github.com/woodpecker-ci/woodpecker/pull/6125)] +- Improve selinux docs [[#6066](https://github.com/woodpecker-ci/woodpecker/pull/6066)] +- document how to ignore failure on services [[#6106](https://github.com/woodpecker-ci/woodpecker/pull/6106)] +- chore(deps): update docs npm deps non-major [[#6109](https://github.com/woodpecker-ci/woodpecker/pull/6109)] +- fix(deps): update dependency @easyops-cn/docusaurus-search-local to ^0.54.0 [[#6091](https://github.com/woodpecker-ci/woodpecker/pull/6091)] +- chore(deps): update dependency axios to v1.13.5 [[#6090](https://github.com/woodpecker-ci/woodpecker/pull/6090)] +- chore(deps): update docs npm deps non-major [[#6088](https://github.com/woodpecker-ci/woodpecker/pull/6088)] +- chore(deps): update dependency isomorphic-dompurify to v2.36.0 [[#6086](https://github.com/woodpecker-ci/woodpecker/pull/6086)] +- fix(deps): update docs npm deps non-major [[#6052](https://github.com/woodpecker-ci/woodpecker/pull/6052)] +- Update Module Interaction Diagram [[#6019](https://github.com/woodpecker-ci/woodpecker/pull/6019)] +- Add Buildah plugin link [[#6050](https://github.com/woodpecker-ci/woodpecker/pull/6050)] +- chore(deps): update docs npm deps non-major [[#6045](https://github.com/woodpecker-ci/woodpecker/pull/6045)] +- Add Homebrew package [[#6037](https://github.com/woodpecker-ci/woodpecker/pull/6037)] +- chore(deps): update dependency axios to v1.13.3 [[#6010](https://github.com/woodpecker-ci/woodpecker/pull/6010)] +- chore(deps): update docs npm deps non-major [[#6000](https://github.com/woodpecker-ci/woodpecker/pull/6000)] +- Fix docusaurus md link deprecation [[#5979](https://github.com/woodpecker-ci/woodpecker/pull/5979)] +- chore(deps): update docs npm deps non-major [[#5982](https://github.com/woodpecker-ci/woodpecker/pull/5982)] + +### ๐Ÿ“ฆ๏ธ Dependency + +- fix(deps): update module google.golang.org/grpc to v1.80.0 [[#6363](https://github.com/woodpecker-ci/woodpecker/pull/6363)] +- fix(deps): update module github.com/lib/pq to v1.12.1 [[#6354](https://github.com/woodpecker-ci/woodpecker/pull/6354)] +- fix(deps): update golang-packages [[#6343](https://github.com/woodpecker-ci/woodpecker/pull/6343)] +- chore(deps): lock file maintenance [[#6344](https://github.com/woodpecker-ci/woodpecker/pull/6344)] +- chore(deps): update dependency simple-icons to v16.14.0 [[#6341](https://github.com/woodpecker-ci/woodpecker/pull/6341)] +- fix(deps): update golang-packages [[#6340](https://github.com/woodpecker-ci/woodpecker/pull/6340)] +- chore(deps): update web npm deps non-major [[#6334](https://github.com/woodpecker-ci/woodpecker/pull/6334)] +- fix(deps): update module gitlab.com/gitlab-org/api/client-go/v2 to v2.8.0 [[#6332](https://github.com/woodpecker-ci/woodpecker/pull/6332)] +- chore(deps): update docker.io/woodpeckerci/plugin-ready-release-go docker tag to v4.1.0 [[#6331](https://github.com/woodpecker-ci/woodpecker/pull/6331)] +- fix(deps): update golang-packages [[#6327](https://github.com/woodpecker-ci/woodpecker/pull/6327)] +- fix(deps): update module code.gitea.io/sdk/gitea to v0.24.1 [[#6321](https://github.com/woodpecker-ci/woodpecker/pull/6321)] +- chore(deps): lock file maintenance [[#6306](https://github.com/woodpecker-ci/woodpecker/pull/6306)] +- fix(deps): update module github.com/charmbracelet/huh to v2 [[#6243](https://github.com/woodpecker-ci/woodpecker/pull/6243)] +- chore(deps): update dependency golangci/golangci-lint to v2.11.4 [[#6301](https://github.com/woodpecker-ci/woodpecker/pull/6301)] +- chore(deps): update pre-commit hook golangci/golangci-lint to v2.11.4 [[#6302](https://github.com/woodpecker-ci/woodpecker/pull/6302)] +- chore(deps): update dependency simple-icons to v16.13.0 [[#6290](https://github.com/woodpecker-ci/woodpecker/pull/6290)] +- chore(deps): update web npm deps non-major [[#6279](https://github.com/woodpecker-ci/woodpecker/pull/6279)] +- fix(deps): update module github.com/zalando/go-keyring to v0.2.7 [[#6280](https://github.com/woodpecker-ci/woodpecker/pull/6280)] +- fix(deps): update golang-packages to v0.35.3 [[#6265](https://github.com/woodpecker-ci/woodpecker/pull/6265)] +- fix(deps): update module github.com/lib/pq to v1.12.0 [[#6260](https://github.com/woodpecker-ci/woodpecker/pull/6260)] +- fix(deps): update module github.com/mattn/go-sqlite3 to v1.14.37 [[#6253](https://github.com/woodpecker-ci/woodpecker/pull/6253)] +- fix(deps): update module gitlab.com/gitlab-org/api/client-go/v2 to v2.6.0 [[#6248](https://github.com/woodpecker-ci/woodpecker/pull/6248)] +- chore(deps): update dependency jsdom to v29 [[#6246](https://github.com/woodpecker-ci/woodpecker/pull/6246)] +- chore(deps): update dependency simple-icons to v16.12.0 [[#6245](https://github.com/woodpecker-ci/woodpecker/pull/6245)] +- chore(deps): update woodpeckerci/plugin-release docker tag to v0.3.0 [[#6241](https://github.com/woodpecker-ci/woodpecker/pull/6241)] +- chore(deps): update dependency vite to v8 [[#6242](https://github.com/woodpecker-ci/woodpecker/pull/6242)] +- fix(deps): update module golang.org/x/net to v0.52.0 [[#6235](https://github.com/woodpecker-ci/woodpecker/pull/6235)] +- chore(deps): update pre-commit non-major [[#6212](https://github.com/woodpecker-ci/woodpecker/pull/6212)] +- chore(deps): update dependency simple-icons to v16.11.0 [[#6220](https://github.com/woodpecker-ci/woodpecker/pull/6220)] +- chore(deps): update dependency vue-i18n to v11.3.0 [[#6217](https://github.com/woodpecker-ci/woodpecker/pull/6217)] +- chore(deps): update dependency golang to v1.26.1 [[#6207](https://github.com/woodpecker-ci/woodpecker/pull/6207)] +- fix(deps): update module github.com/docker/cli to v29.3.0+incompatible [[#6201](https://github.com/woodpecker-ci/woodpecker/pull/6201)] +- fix(deps): update module github.com/yaronf/httpsign to v0.4.2 [[#6188](https://github.com/woodpecker-ci/woodpecker/pull/6188)] +- chore(deps): update dependency eslint-plugin-vue-scoped-css to v3 [[#6178](https://github.com/woodpecker-ci/woodpecker/pull/6178)] +- chore(deps): update dependency @intlify/eslint-plugin-vue-i18n to v4.3.0 [[#6177](https://github.com/woodpecker-ci/woodpecker/pull/6177)] +- chore(deps): update dependency simple-icons to v16.10.0 [[#6175](https://github.com/woodpecker-ci/woodpecker/pull/6175)] +- fix(deps): update module github.com/google/go-github/v83 to v84 [[#6172](https://github.com/woodpecker-ci/woodpecker/pull/6172)] +- chore(deps): update docker.io/woodpeckerci/plugin-ready-release-go docker tag to v4 [[#6171](https://github.com/woodpecker-ci/woodpecker/pull/6171)] +- chore(deps): update postgres docker tag to v18.3 [[#6169](https://github.com/woodpecker-ci/woodpecker/pull/6169)] +- fix(deps): update golang-packages [[#6160](https://github.com/woodpecker-ci/woodpecker/pull/6160)] +- chore(deps): update golangci/golangci-lint docker tag to v2.10.1 [[#6138](https://github.com/woodpecker-ci/woodpecker/pull/6138)] +- chore(deps): update dependency vue-tsc to v3.2.5 [[#6141](https://github.com/woodpecker-ci/woodpecker/pull/6141)] +- fix(deps): update module github.com/google/go-github/v82 to v83 [[#6140](https://github.com/woodpecker-ci/woodpecker/pull/6140)] +- chore(deps): update postgres docker tag to v18.2 [[#6124](https://github.com/woodpecker-ci/woodpecker/pull/6124)] +- chore(deps): update docker.io/golang docker tag to v1.26 [[#6121](https://github.com/woodpecker-ci/woodpecker/pull/6121)] +- chore(deps): update docker.io/lycheeverse/lychee docker tag to v0.23.0 [[#6122](https://github.com/woodpecker-ci/woodpecker/pull/6122)] +- chore(deps): update dependency @types/node to v24.10.12 [[#6087](https://github.com/woodpecker-ci/woodpecker/pull/6087)] +- chore(deps): update eslint monorepo to v10 (major) [[#6083](https://github.com/woodpecker-ci/woodpecker/pull/6083)] +- chore(deps): update dependency @antfu/eslint-config to v7.3.0 [[#6084](https://github.com/woodpecker-ci/woodpecker/pull/6084)] +- chore(deps): update dependency @vueuse/core to v14.2.0 [[#6048](https://github.com/woodpecker-ci/woodpecker/pull/6048)] +- fix(deps): update dependency vue-router to v5 [[#6046](https://github.com/woodpecker-ci/woodpecker/pull/6046)] +- chore(deps): update woodpeckerci/plugin-git docker tag to v2.8.1 [[#6006](https://github.com/woodpecker-ci/woodpecker/pull/6006)] +- chore(deps): update docker.io/mysql docker tag to v9.6.0 [[#6002](https://github.com/woodpecker-ci/woodpecker/pull/6002)] +- fix(deps): update module github.com/urfave/cli/v3 to v3.6.2 [[#5989](https://github.com/woodpecker-ci/woodpecker/pull/5989)] + +### Misc + +- Fix license headers [[#6205](https://github.com/woodpecker-ci/woodpecker/pull/6205)] +- Add agentscan plugin [[#6284](https://github.com/woodpecker-ci/woodpecker/pull/6284)] +- Improve Debian packages [[#6085](https://github.com/woodpecker-ci/woodpecker/pull/6085)] + ## [3.13.0](https://github.com/woodpecker-ci/woodpecker/releases/tag/v3.13.0) - 2026-01-14 ### โค๏ธ Thanks to all contributors! โค๏ธ