{"id":18750630,"url":"https://github.com/webiny/webiny-semantic-release","last_synced_at":"2025-11-26T20:30:18.049Z","repository":{"id":68107193,"uuid":"124255704","full_name":"webiny/webiny-semantic-release","owner":"webiny","description":"A tool for automated publishing of semantically correct versions of your packages.","archived":false,"fork":false,"pushed_at":"2018-05-28T14:57:58.000Z","size":112,"stargazers_count":1,"open_issues_count":0,"forks_count":2,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-02-13T03:27:14.809Z","etag":null,"topics":["github-releases","npm-publish","release","release-automation","semantic-release","semver"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/webiny.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-03-07T15:28:11.000Z","updated_at":"2019-02-15T22:29:38.000Z","dependencies_parsed_at":null,"dependency_job_id":"123d267b-a2bc-4c57-8d2e-70bae5ac15af","html_url":"https://github.com/webiny/webiny-semantic-release","commit_stats":{"total_commits":25,"total_committers":1,"mean_commits":25.0,"dds":0.0,"last_synced_commit":"9f524615035ceeac0271b59856fe3085b59cd5e2"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webiny%2Fwebiny-semantic-release","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webiny%2Fwebiny-semantic-release/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webiny%2Fwebiny-semantic-release/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webiny%2Fwebiny-semantic-release/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/webiny","download_url":"https://codeload.github.com/webiny/webiny-semantic-release/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239293948,"owners_count":19615042,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["github-releases","npm-publish","release","release-automation","semantic-release","semver"],"created_at":"2024-11-07T17:12:39.126Z","updated_at":"2025-11-26T20:30:17.984Z","avatar_url":"https://github.com/webiny.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# webiny-semantic-release\n[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)\n[![Prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://prettier.io)\n[![license](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/webiny/webiny-semantic-release/blob/master/LICENSE)\n\n| Branch | Build | Coverage |\n| :--- | :---: | :--- |\n| master (latest release) | [![Build Status](https://travis-ci.org/Webiny/webiny-semantic-release.svg?branch=master)](https://travis-ci.org/Webiny/webiny-semantic-release) | [![Coverage Status](https://coveralls.io/repos/github/Webiny/webiny-semantic-release/badge.svg?branch=master)](https://coveralls.io/github/Webiny/webiny-semantic-release?branch=master) |\n| development (active development) | [![Build Status](https://travis-ci.org/Webiny/webiny-semantic-release.svg?branch=development)](https://travis-ci.org/Webiny/webiny-semantic-release) | [![Coverage Status](https://coveralls.io/repos/github/Webiny/webiny-semantic-release/badge.svg?branch=development)](https://coveralls.io/github/Webiny/webiny-semantic-release?branch=development) |\n\nA tool for automated and reliable versioning inspired by `semantic-release`.\n\n- supports single package repositories\n- supports monorepo structure (Lerna or custom)\n- supports plugins and 100% customizable release/publish process\n- detailed preview of actual release (dry run) if you want to preview what is about to happen\n\n## Why not simply use `semantic-release`?\nKudos to the `semantic-release` team for starting this movement!\nWe greatly support it and think it is a very important step towards a stable open-source ecosystem.\n\nBut the primary problem for us was - it does not support monorepos.\nWe did try to wrap it with some custom logic to make it work in a monorepo environment but we very soon hit a wall.\nWe gave up when we had to update versions of inter-dependent packages (when one of the packages in your monorepo depends on another package in te same monorepo).\nThere were also other problems, but these were the deciding ones.\n\nStill, we use 2 of their plugins to analyze commits and generate release notes by simply wrapping them with our own plugins (read further) and adding some bells and whistles.\n\n## How to use\nWe provide a set of plugins you can use to get started quickly.\nPlugins are listed in the recommended order:\n\n| Order | Plugin | Description |\n| :---: | :---: | :--- |\n| 1. | githubVerify | verifies `GH_TOKEN` or `GITHUB_TOKEN` and repo permissions. |\n| 2. | npmVerify | verifies `NPM_TOKEN`. |\n| 3. | analyzeCommits | analyzes commit history and determines version type. |\n| 4. | updatePackage | updates package version and versions of dependencies. |\n| 5. | releaseNotes | generates release notes for GitHub release. |\n| 6. | githubPublish | publishes a new release to GitHub. |\n| 7. | npmPublish | publishes the package to npm. |\n\n\n```js\n// We are using `require` to avoid having to transpile the code\nconst wsr = require(\"webiny-semantic-release\");\n\n// NOTE: you are responsible for defining an array of packages!\n// This makes this tool very flexible as it does not care about your project structure,\n// only about the packages you pass to it.\n\n// For single package repos the package will be loaded automatically\n\n// For Lerna packages read the section below\n\n// For custom project structures you just need to specify your packages using the following template:\nconst projectPackages = [\n    {\n        name: 'package-1',\n        location: '/my/project/packages/package-1',\n        package: {\n            // Here goes the ENTIRE content of `package.json` file\n            name: 'package-1',\n            version: '0.0.0-semantically-released',\n            dependencies: {},\n            // ...\n        }\n    }\n];\n\n// Run release (returns a Promise)\nwsr.release({\n    ci: true,\n    preview: false,\n    branch: 'master',\n    packages: projectPackages,\n    plugins: [\n        wsr.githubVerify(),\n        wsr.npmVerify(),\n        wsr.analyzeCommits(),\n        wsr.releaseNotes(),\n        wsr.updatePackage(),\n        wsr.githubPublish(),\n        wsr.npmPublish()\n    ]\n}).catch(err =\u003e {\n    console.log(err);\n    process.exit(1);\n});\n```\n\n### Lerna packages\nWe did not include `lerna` as a dependency to keep things simple.\nLoading packages yourself is simple enough, here is a working example:\n\n```js\nimport Repository from \"lerna/lib/Repository\";\nimport PackageUtilities from \"lerna/lib/PackageUtilities\";\n\nconst packages = PackageUtilities.getPackages(new Repository())\n    .filter(pkg =\u003e !pkg.isPrivate()) // do not include private packages\n    .map(pkg =\u003e {\n        return {\n            name: pkg.name,\n            location: pkg.location,\n            package: pkg.toJSON()\n        };\n    });\n```\n\n### Plugin system\nOur plugin system is very straightforward. It works almost the same way `express` middleware does.\nUnder the hood we use a very simple tool to compose middleware functions using arbitrary `params`, a `next` callback and a `finish` callback.\n`params` are passed to each consecutive plugin and are mutable so all plugins share data and can modify data.\n\nThese Flow types will make everything much clearer:\n\n```flow\ndeclare type Package = {\n    name: string,\n    location: string,\n    package: Object\n};\n\ndeclare type Params = {\n    packages: Array\u003cPackage\u003e,\n    logger: { log: Function, error: Function },\n    git: Object,\n    config: {\n        ci: Boolean,\n        preview: Boolean,\n        repositoryUrl: string,\n        branch: string,\n        tagFormat: string | (pkg: Package) =\u003e string\n    }\n};\n\ndeclare type Plugin = (params: Params, next: Function, finish: Function) =\u003e void;\n```\n\n### Creating a plugin\nTo create a plugin you need to defined a simple function of type `Plugin` (see the Flow types above).\n\nLet's create a plugin which checks all the packages for the presence of `README.md` file:\n\n```js\nimport path from \"path\";\nimport fs from \"fs\";\n\n// I always recommend to export a factory function which can optionally take a config object.\n// That way you are safe for possible future upgrades or parameters.\nexport default () =\u003e {\n    return ({packages, logger}, next, finish) =\u003e {\n        let errors = [];\n        packages.map(pkg =\u003e {\n            if (!fs.existsSync(path.join(pkg.location, \"README.md\"))) {\n                errors.push(pkg.name);\n            }\n        });\n\n        if (errors.length) {\n            logger.error(\n                \"Missing README.md file in the following packages:\\n\\t- %s\",\n                errors.join(\"\\n- \")\n            );\n\t\t\treturn finish();\n        }\n        next();\n    }\n};\n```\n\n### Adding custom plugins to the release process\n\nIf you want to create your own publishing process and maybe remove or add some of the plugins, you can do it like this:\n\n```js\n// We will remove the `npm` plugins, and instead add 2 new plugins\n\nconst wsr = require(\"webiny-semantic-release\");\n\nwsr.release({\n    preview: true,\n    plugins: [\n        wsr.githubVerify(),\n        checkReadmeFile(), // Use your new plugin for README.md verification (see \"Creating a plugin\")\n        wsr.analyzeCommits(),\n        wsr.releaseNotes(),\n        // This plugin will modify the release notes of each package and add a custom footer.\n        // After the `releaseNotes` plugin did its job, each package `nextRelease` will contain a `notes` key with the generated notes.\n        ({packages}, next) =\u003e {\n            packages.map(pkg =\u003e {\n                pkg.nextRelease \u0026\u0026 pkg.nextRelease.notes += \"\\nI MUST have this at the bottom of each release!\"\n            });\n            next();\n        },\n        // Publish plugin will now use the new `notes` because they were modified by your plugin\n        wsr.githubPublish()\n    ]\n}).catch(err =\u003e {\n    console.error(err);\n    process.exit(1);\n});\n```\n\n### Filtering relevant commits\nIf you are working with multiple packages you will probably want to filter the commits so that each package is processed with only the commits that are relevant to that package.\nTo configure the logic for filtering records configure the plugin like this:\n\n```js\n...\n// This will filter the commits by the presence of `affects: pkg1, pkg2, pkg3...` string in the commit message.\n// If you are using `cz-lerna-changelog` for commitizen, you will have exactly this in your commit messages.\nwsr.analyzeCommits({\n    isRelevant: (pkg, commit) =\u003e {\n        if (commit.message.match(/affects:(.*)/)) {\n            return RegExp.$1.split(\",\").map(n =\u003e n.trim()).filter(name =\u003e pkg.name === name).length;\n        }\n    }\n})\n...\n```\n\n### Configuring the `analyzeCommits` plugin\nWe are using the `@semantic-release/commit-analyzer` plugin under the hood of our `analyzeCommits` plugin.\nIf you need, you can pass the config to that `semantic-release` plugin by passing a `commitAnalyzer` config object.\nFor all the config options visit [@semantic-release/commit-analyzer](https://github.com/semantic-release/commit-analyzer#options)\n\n```js\n...\nwsr.analyzeCommits({\n    commitAnalyzer: {\n        \"preset\": \"angular\",\n        \"releaseRules\": [\n            {\"type\": \"docs\", \"scope\":\"README\", \"release\": \"patch\"},\n            {\"type\": \"refactor\", \"release\": \"patch\"},\n            {\"type\": \"style\", \"release\": \"patch\"}\n        ],\n        \"parserOpts\": {\n            \"noteKeywords\": [\"BREAKING CHANGE\", \"BREAKING CHANGES\", \"BREAKING\"]\n        }\n    }\n})\n...\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebiny%2Fwebiny-semantic-release","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwebiny%2Fwebiny-semantic-release","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebiny%2Fwebiny-semantic-release/lists"}