{"id":14991008,"url":"https://github.com/atidatech/contentful-cli-release","last_synced_at":"2025-04-12T03:25:27.357Z","repository":{"id":203940908,"uuid":"670755774","full_name":"AtidaTech/contentful-cli-release","owner":"AtidaTech","description":"Contentful CLI Release tool","archived":false,"fork":false,"pushed_at":"2024-08-27T10:06:06.000Z","size":460,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-18T21:53:05.283Z","etag":null,"topics":["branch","branching","cd","ci","cli","contentful","git","github","github-workflows","gitlab","gitlab-ci","release"],"latest_commit_sha":null,"homepage":"https://npmjs.com/package/contentful-cli-release","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/AtidaTech.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":"2023-07-25T19:03:09.000Z","updated_at":"2024-08-27T10:04:55.000Z","dependencies_parsed_at":"2024-01-24T14:28:36.586Z","dependency_job_id":"b17fbc08-052a-4c4c-b318-288a46693f81","html_url":"https://github.com/AtidaTech/contentful-cli-release","commit_stats":null,"previous_names":["atidatech/contentful-cli-release"],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AtidaTech%2Fcontentful-cli-release","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AtidaTech%2Fcontentful-cli-release/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AtidaTech%2Fcontentful-cli-release/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AtidaTech%2Fcontentful-cli-release/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AtidaTech","download_url":"https://codeload.github.com/AtidaTech/contentful-cli-release/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248511216,"owners_count":21116368,"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":["branch","branching","cd","ci","cli","contentful","git","github","github-workflows","gitlab","gitlab-ci","release"],"created_at":"2024-09-24T14:21:17.073Z","updated_at":"2025-04-12T03:25:27.335Z","avatar_url":"https://github.com/AtidaTech.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![License: MIT](https://img.shields.io/github/license/AtidaTech/contentful-cli-release)](https://opensource.org/licenses/MIT)\n[![npm](https://img.shields.io/npm/v/contentful-cli-release)](https://npmjs.com/package/contentful-cli-release)\n![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/AtidaTech/contentful-cli-release)\n![Downloads](https://img.shields.io/npm/dw/contentful-cli-release)\n![Forks](https://img.shields.io/github/forks/AtidaTech/contentful-cli-release)\n[![Bun.sh](https://img.shields.io/badge/bun.sh-compatible-orange)](https://bun.sh)\n\n# Contentful CLI Release Tool\n\nThis tool is a utility for managing releases in Contentful. It streamlines the process of branching, releasing, and\nintegrating with CI/CD pipelines such as GitLab or GitHub, by leveraging the use of Environments and Environment aliases.\n\n\u003ch3\u003eSponsored by \u003ca href=\"https://github.com/AtidaTech\"\u003e\u003cb\u003eAtida\u003c/b\u003e\n\u003cimg src=\"https://avatars.githubusercontent.com/u/127305035?s=200\u0026v=4\" width=\"14px;\" alt=\"Atida\" /\u003e\u003c/a\u003e\u003c/h3\u003e\n\n\u003chr /\u003e\n\n[✨ Features](#-features) · [💡 Installation](#-installation) · [📟 Example](#-example) · [🎹 Usage](#-usage) ·\n[🚀 Release](#-managing-a-release) · [📅 ToDo](#-todo) · [👾 Contributors](#-contributors) ·\n[🎩 Acknowledgments](#-acknowledgements) · [📚 Collection](#-other-scripts-in-the-same-collection) ·\n[📄 License](#-license)\n\n\u003chr /\u003e\n\n## ✨ Features\n\n* **Branching \u0026 Releasing:** Seamless management of environments and releases in Contentful.\n* **CI/CD Integration:** Designed for integration with CI/CD pipelines like GitLab or GitHub.\n* **Command Line Utility:** Efficient command-line interface for all release-related tasks.\n\n## 💡 Installation\n\nTo use this helper library, you must have [Node.js 🔗](https://nodejs.org/) and [npm 🔗](http://npmjs.org) installed.\n\nTo install it, simply run:\n\n``````shell\nnpm install contentful-cli-release --save\n``````\n\nOr, if using [yarn 🔗](https://yarnpkg.com/lang/en/):\n\n```shell\nyarn add contentful-cli-release\n```\n\nSimilarly, if you are using [Bun 🔗](https://bun.sh), just run:\n\n```shell\nbun add contentful-cli-release\n```\n\n### Requirements\n\n* `node` \u003e= 18.20.0\n* `npm` \u003e= 10.5.0\n* `contentful-management` \u003e= 11.31.7\n* [contentful-lib-helpers](https://www.npmjs.com/package/contentful-lib-helpers) \u003e= 0.4.0\n\n\n### Set-up\n\nTo get the most out of the Contentful CLI Release tool, proper setup is crucial. Here's a step-by-step guide to help\nyou get started:\n\n1. **Environment Variables**:\n   The tool uses environment variables to simplify repetitive tasks and ensure security. Instead of passing sensitive\n   data as command line arguments every time, you can set them once in your environment. We recommend using a `.env`\n   file for this purpose. Here's a sample configuration:\n\n   ```env\n   CMS_MANAGEMENT_TOKEN=placeholder-management-token\n   CMS_SPACE_ID=placeholder-space-id\n   CMS_RELEASE_MAX_SCHEDULED_ACTIONS=500\n   CMS_RELEASE_ENVIRONMENT_PROTECTED=dev,staging,master\n   CMS_RELEASE_ENVIRONMENT_REGEX=release-[0-9]+[\\\\.]*[0-9]*[\\\\.]*[0-9]*\n   ```\n\n   Create the `.env` or `.env.local` files in your project to override the default configuration. But ensure to\n   replace the placeholders (e.g., `placeholder-management-token` and `placeholder-space-id`) with your actual data.\n\n[//]: # (CMS_RELEASE_SYNC_DB=./cli-release.db)\n[//]: # (CMS_RELEASE_SYNC_CONFIG=./cli-release-config.js)\n\n2. **Max Scheduled Actions**:\n   The `CMS_RELEASE_MAX_SCHEDULED_ACTIONS` parameter sets the number of scheduled actions (in total) to be retrieved.\n   Default and maximum value is `500`.\n\n3. **Protected Environments**:\n   The `CMS_RELEASE_ENVIRONMENT_PROTECTED` parameter lists environments that should not be modified by the tool,\n   ensuring safety for crucial stages like `dev`, `staging`, and `master`.\n\n3. **Environment Naming Convention**:\n   Using the `CMS_RELEASE_ENVIRONMENT_REGEX`, you can specify a regex pattern to match the naming convention of your\n   release environments. The default pattern matches names like `release-1`, `release-1.1`, and `release-1.1.1`.\n\nWith these steps, you should have a fully configured environment ready to utilize the Contentful CLI Release tool\neffectively. Always refer back to the tool's documentation if you need further assistance.\n\n## 📟 Example\n\n### Duplicate an Environment\n\nDuplicates an existing environment to a new environment, and it pings to see when the new environment is available.\nIt skips the duplication if the destination environment already exists.\n\nUsage:\n\n```bash\nnpx contentful-cli-release --duplicate --from SOURCE_ENV --to DEST_ENV (--update-api-key)\n```\n\nArguments:\n\n- `--from`: The name of the source environment to duplicate from. Ie: 'master'.\n- `--to`: The name of the destination environment to duplicate to. Ie: 'release-1.7.4' or 'staging'.\n- `--update-api-key`: It will enable, for the duplicated environment, the CDA API Key that has the same name of the\nsource environment (so, for environment 'master', the CDA API Key should be also called 'master').\n\n\u003e See the section [🎹 Usage](#-usage) for details on the command line options.\n\n#### Response and Errors\n\n\u003cdetails\u003e\n  \u003csummary\u003eSuccessful duplication\u003c/summary\u003e\n\n```shell\n$ npx contentful-cli-release --duplicate --from master --to release-1.7.4 --update-api-key\n##/INFO: Duplicating environment 'master' for space 'xxxxxxxxx'\n##/DEBUG: Creating new environment: 'release-1.7.4'\n##/INFO: Environment 'release-1.7.4' successfully created\n##/INFO: CDA 'master' Key assigned to environment: release-1.7.4\n##/DEBUG: Waiting to retrieve the newly created environment: release-1.7.4\n##/DEBUG: Waiting to retrieve the newly created environment: release-1.7.4\n##/DEBUG: Waiting to retrieve the newly created environment: release-1.7.4\n...\n##/INFO: release-1.7.4 successfully duplicated from: master\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eSkips creation, but associates the Key and pings the environment\u003c/summary\u003e\n\n```shell\n$ npx contentful-cli-release --duplicate --from master --to release-1.7.4 --update-api-key\n##/INFO: Duplicating environment 'master' for space 'xxxxxxxxx'\n##/INFO: An environment with this name already exists: 'release-1.7.4'. Skipping creation\n##/INFO: CDA 'master' Key assigned to environment: release-1.7.4\n##/DEBUG: Waiting to retrieve the newly created environment: release-1.7.4\n##/DEBUG: Waiting to retrieve the newly created environment: release-1.7.4\n##/DEBUG: Waiting to retrieve the newly created environment: release-1.7.4\n...\n##/INFO: release-1.7.4 successfully duplicated from: master\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eError when Source environment doesn't exists\u003c/summary\u003e\n\n```shell\n$ npx contentful-cli-release --duplicate --from myenvironment --to release-1.7.4\n@@/ERROR: The source environment does not exist!\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eError when 'from' or 'to' environments are missing\u003c/summary\u003e\n\n```shell\n$ npx contentful-cli-release --duplicate --from master\n@@/ERROR: You should specify both a '--from' and a '--to' option.\n```\n\u003c/details\u003e\n\n### Sync Schedule\n\nSynchronize scheduled actions between two Environments, because the actions are not copied when duplicating an\nEnvironment. Ideally the source is the 'old' master and the destination is the newly created release environment.\n\nUsage:\n\n```bash\nnpx contentful-cli-release --sync-schedule --from SOURCE_ENV --to DEST_ENV (--force-yes)\n```\n\nArguments:\n\n- `--from`: The name of the source environment where the existing scheduled actions are. Ie: 'master'.\n- `--to`: The name of the destination environment to copy the scheduled actions to. Ie: 'release-1.4.5'.\n- `--force-yes`: When the destination environment is protected, this will allow to perform the action.\n\n\u003e See the section [🎹 Usage](#-usage) for details on the command line options.\n\n#### Response and Errors\n\n\u003cdetails\u003e\n  \u003csummary\u003eSuccessful sync between two Environments\u003c/summary\u003e\n\n```shell\n$ npx contentful-cli-release --sync-schedule --from master --to release-1.4.5 --force-yes\n##/INFO: Source Environment: 'master'\n##/INFO: Destination Environment: 'release-1.4.5'\n##/INFO: Total Scheduled Actions: 2\n##/DEBUG: Imported scheduled action: Publish for Entry-Id: '5krek3qkuRtWxRyIqM012a' for the: 2023-10-29 19:00\n##/DEBUG: Imported scheduled action: Unpublish for Entry-Id: 'GKfodiofTQFS8oXjJp65Yb' for the: 2023-10-29 20:00\n```\n\u003c/details\u003e\n\n\n\u003cdetails\u003e\n  \u003csummary\u003eSkips already imported actions (to avoid duplicates)\u003c/summary\u003e\n\n```shell\n$ npx contentful-cli-release --sync-schedule --from master --to release-1.4.5 --force-yes\n##/INFO: Source Environment: 'master'\n##/INFO: Destination Environment: 'release-1.4.5'\n##/INFO: Total Scheduled Actions: 2\n##/DEBUG: Scheduled action already exists - Action-Id: 6jTzhTAOPs5LsbpjRZKkF3\n##/DEBUG: Scheduled action already exists - Action-Id: 2HVGh3wJRSp8P6ZW18YI92\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eError when 'to' Environment is protected\u003c/summary\u003e\n\n```shell\n$ npx contentful-cli-release --sync-schedule --from master --to staging\n@@/ERROR: The destination environment is either empty or reserved!\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eError when 'from' or 'to' Environments are missing\u003c/summary\u003e\n\n```shell\n$ npx contentful-cli-release --sync-schedule --from master\n@@/ERROR: You should specify both a '--from' and a '--to' option.\n```\n\u003c/details\u003e\n\n### Link Alias\nIt links an existing alias from one Environment to another one. This is used during a Release to move, for example,\nthe 'master' alias from the old release branch to the new one\n\nUsage:\n\n```bash\nnpx contentful-cli-release --link --alias ALIAS --to TARGET_ENV (--prune-old-releases)\n```\n\nArguments:\n\n- `--alias`: The existing alias that needs to be updated. Ie: 'master'.\n- `--to`: The target Environment-id to which the alias will point to. Ie: 'release-1.4.5'.\n- `--prune-old-releases`: Using the release regular expression, it will delete all the older releases, except\nthe current one (ie: 'release-1.4.5') and the previous one (ie: 'release-1.4.4') that was associated with the\n'master' alias.\n\n\u003e See the section [🎹 Usage](#-usage) for details on the command line options.\n\n#### Response and Errors\n\n\u003cdetails\u003e\n  \u003csummary\u003eSuccessful use with the '--prune-old-releases' option\u003c/summary\u003e\n\n```shell\n$ npx contentful-cli-release --link --alias master --to release-1.4.5 --prune-old-releases\n##/INFO: Linking Environment 'release-1.4.5' to Alias 'master'\n##/INFO: Alias 'master' updated to 'release-1.4.5' Environment.\n##INFO: Deleting old Release Environments\n##/INFO: Processing the list of all environments\n##/INFO: This environment will NOT be deleted: dev\n##/INFO: This environment will NOT be deleted: staging\n##/INFO: This environment will NOT be deleted: release-1.4.5 aliased by master\n##/INFO: List of Release environments that will be kept:\n- release-1.4.5\n- release-1.4.4\n##/INFO: List of Release environments that will be deleted:\n- release-1.4.3\n##/DEBUG: Environment 'release-1.4.3' is going to be deleted!\n##/INFO: Deleting environment 'release-1.4.3'.\n##/DEBUG: Environment 'release-1.4.3' was deleted.\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eSuccessful use without the '--prune-old-releases' option\u003c/summary\u003e\n\n```shell\n$ npx contentful-cli-release --link --alias master --to release-1.4.5\n##/INFO: Linking Environment 'release-1.4.5' to Alias 'master'\n##/INFO: Alias 'master' updated to 'release-1.4.5' Environment.\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eError when '--alias' is missing\u003c/summary\u003e\n\n```shell\n$ npx contentful-cli-release --link --to release-1.4.5\n@@/ERROR: You should specify an '--alias' option when using '--link'\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eError when '--to' is missing\u003c/summary\u003e\n\n```shell\n$ npx contentful-cli-release --link --alias master\n@@/ERROR: You should specify an '--environment-id' option when using '--delete' or '--link'\n```\n\u003c/details\u003e\n\n### Delete an Environment\nThis function allows to delete an Environment via the CLI tool. It automatically forbids to delete the\nconfigured protected environments, unless we use the option '--force-yes'.\n\nUsage:\n\n```bash\nnpx contentful-cli-release --delete --environment-id TARGET_ENV (--force-yes)\n```\n\nArguments:\n\n- `--environment-id`: The name of the environment to be deleted.\n- `--force-yes`: When the destination environment is protected, this will allow to perform the action.\n\n\u003e See the section [🎹 Usage](#-usage) for details on the command line options.\n\n#### Response and Errors\n\n\u003cdetails\u003e\n  \u003csummary\u003eSuccess when the environment is not protected\u003c/summary\u003e\n\n```shell\n$ npx contentful-cli-release --delete --environment-id test\n##/INFO: Deleting environment 'test'.\n##/DEBUG: Environment 'test' was deleted.\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eError when the environment is protected\u003c/summary\u003e\n\n```shell\n$ npx contentful-cli-release --delete --environment-id staging\n@@/ERROR: Environment 'staging' is protected and cannot be deleted.\n@@/ERROR: No action chosen or Returned an error. Inspect the logs and try again\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eSuccess when using '--force-yes'\u003c/summary\u003e\n\n```shell\n$ npx contentful-cli-release --delete --environment-id staging --force-yes\n##/INFO: Deleting environment 'staging'.\n##/DEBUG: Environment 'staging' was deleted.\n```\n\u003c/details\u003e\n\n\n\u003cdetails\u003e\n  \u003csummary\u003eError when '--environment-id' is missing\u003c/summary\u003e\n\n```shell\n$ npx contentful-cli-release --delete\n@@/ERROR: You should specify an '--environment-id' option when using '--delete' or '--link'\n```\n\u003c/details\u003e\n\n## 🎹 Usage\n\nThis script can be used from the command line and accepts various arguments for customization:\n\n* `--space-id`: The Contentful space id. It will override the env value `CMS_SPACE_ID`.\n* `--management-token` or `--mt`: The Contentful Management Token. It will override the env value `CMS_MANAGEMENT_TOKEN`.\n* `--from`: The source Environment-id when performing a duplication or a sync-schedule.\n* `--alias`: Mandatory only for the link alias option. It represents the alias that we want to associate with another\nEnvironment.\n* `--to` or `--environment-id`: The target Environment-id.\n* `--update-api-key`: When performing a duplication. It enables a CDA API Key also for the new environment. The only\nconstraint is that the API Key should have the same name of the source Environment. Ie: 'master' API Key for the 'master'\nEnvironment, that will be enabled also for the new duplicated release Environment.\n* `--prune-old-releases`: When running a `--link` alias operation, it will keep the latest two releases and delete the\nolder ones. The releases are identified by the regular expression defined in the env file or overridden via additional\ncommand line parameter.\n* `--force-yes`: It forces the operation when the target Environment-id is considered protected. The protected\nEnvironments are listed in the env value `CMS_RELEASE_ENVIRONMENT_PROTECTED` or overridden with the following option.\n* `--protected-environments`: It sets a list (separated by comma) of protected environments. It overrides the env\nvalue `CMS_RELEASE_ENVIRONMENT_PROTECTED`. This prevents accidentally deleting or performing operations on an\nEnvironment that is used for production or for important day-to-day work. Ie: 'dev,staging,master'.\n* `--release-regex`: It overrides the env value `CMS_RELEASE_ENVIRONMENT_REGEX`. It identifies a regular expression\nthat will match the release branch naming. The default one matches a fixed part `release-` and then the numbering\nof a release, like `x.y.z`. The regular expression can be modified, however the script will use the numbering part\nto do a natural ordering (so 1.4.10 is bigger than 1.4.9 and smaller than 1.5) when deciding which older releases\nneed to be automatically deleted when using `--prune-old-releases` option.\n* `--max-scheduled-actions`: It overrides the env value `CMS_RELEASE_MAX_SCHEDULED_ACTIONS` and it represents the\ntotal number of scheduled actions that should be retrieved. By default, the value is set to the maximum value allowed\nof 500.\n\n## 🚀 Managing a Release\n\nIt has been said that Contentful Environments are equivalent to GIT Branches. And meanwhile this is practically\ntrue from the user point of view, it does not transform automatically to a simple release strategy.\nIn addition, although there are different functionalities that helps with releasing content (Contentful Workflow\nand Launch work very good for that) or keeping two Environments in sync (this is what the new Contentful Merge does),\nfor many developers is missing the possibility to easily integrate Contentful into their release strategy.\n\nThis is what this tool is for, together with our two other scripts:\n* **Contentful CLI Export:**\n[![npm](https://img.shields.io/npm/v/contentful-cli-export)](https://npmjs.com/package/contentful-cli-export)\n![Downloads](https://img.shields.io/npm/dw/contentful-cli-export)\n* **Contentful CLI Migrations:**\n[![npm](https://img.shields.io/npm/v/contentful-cli-migrations)](https://npmjs.com/package/contentful-cli-migrations)\n![Downloads](https://img.shields.io/npm/dw/contentful-cli-migrations)\n\nThe idea behind is to use these tools via command line (without having to install them) to integrate them inside a\nCI/CD of your liking. By using one `.env` file, that can be injected in your CI/CD, or by passing the right parameters\nvia command line options, these tools are self-sufficient in running even the more complex tasks during a release.\nIn particular, actions like duplicating an Environment, or changing the Environment alias to that new duplicate, are\nall things that can be done seamlessly with one centralized logic. We will run through few examples and to show you\nhow efficient your release strategy can be.\n\n### Different Release Strategies\n\nWe will take into consideration the most common release strategies and scenarios, but obviously you will want (or need)\nto tailor the actions to your specific use-case. Feel free to reach out and suggest some we haven't thought about, and\nwe will promptly add them to this list.\n\nFor most of the Release processes presented, it's good to always use Environment aliases, and one or two Environments\nusing a release naming strategy (in our examples `release-x.y.z`). The reason behind this kind of choice is to\nbe able to connect a 'code' release to a specific Environment, by using [Semantic Versioning](https://github.com/ptsteadman/semver-for-natural-language)\nfor both.\n\n#### 1. Promoting 'staging' to production\n\n![Promote 'staging' strategy](./images/release-strategy-1.gif)\n\nA common way of releasing is to promote a staging Environment to production, by duplicating staging into the new\nmaster. Let's see how we could use `contentful-cli-release` and the other tools to do a release, starting from these\nenvironments:\n\n```\n- Environment 'master'\n- Environment 'master-backup'\n- Environment 'staging'\n- Environment 'dev'\n```\n\nWhat we wil simply do is to back up the involved Environments first, and then delete the oldest one to make room for\nthe `staging` that is going to be promoted (by being duplicated) to the new `master`.\n\n\n```shell\n$ npx contentful-cli-export --from \"staging\" --compress\n$ npx contentful-cli-export --from \"master\" --compress\n$ npx contentful-cli-export --from \"master-backup\" --compress\n$ npx contentful-cli-release --delete --environment-id \"master-backup\"\n$ npx contentful-cli-release --duplicate --from \"master\" --to \"master-backup\"\n$ npx contentful-cli-release --delete --environment-id \"master\" --force-yes\n$ npx contentful-cli-release --duplicate --from \"staging\" --to \"master\"\n```\n\nThis release process is pretty straightforward and easy to implement, however it doesn't take into account few things:\n* It does not update any CDA API Key so that the 'master' key can read the newly created environments. Since the\nname of the Environments don't change, this is probably of a little concern, but in cases where we might need to\nroll-back or change naming strategy, this could interrupt the access in production.\n* Similarly, the Scheduled actions are not synced. In this kind of release process, promoting staging to master\nis already a way of publishing new content. But this is somehow a limit for the editors.\n* We haven't specified, nor mentioned, applying Contentful migrations to staging before promoting it. And this means\nthat updating the Content-types is a separate process, most of the time done manually by a developer, or by a separate\nscript that is not part of the release process. This can lead to inconsistencies and mistakes during the release.\n* Last, but not least. Although this process shouldn't take too much time, when the 'master' Environment is deleted\nand is being re-duplicated, this can leave the application offline for some minutes. Using Environment aliases can\nhelp reduce this downtime, but for a real downtime-free experience, you should probably have a look at the third, and\nmost comprehensive, strategy in this list.\n\n\u003e To notice that running the `contentful-cli-export` command inside the CI/CD will generate an artifact. This\nartifact can be saved for a specified amount of time, so that a backup of the Contentful Environment is always\npresent in case of a rollback operation.\n\n#### 2. Release with only have 3 environments (Community)\n\n![Release with 3 environments](./images/release-strategy-2.gif)\n\nAs many developers that start with a free tier of Contentful, it is possible to use the Releases process also with\n'only' 3 Environments. In this case we need to use 2 real Environments (`dev` and `staging`) and a release Environment\nthat is aliased by `master`.\n\nLet's assume this is the starting scenario:\n```\n- Environment `release-1.4.5` aliased by 'master'\n- Environment 'staging'\n- Environment 'dev'\n```\n\nIn this case, the release process is already more structured and reliable. It diminishes downtime, and it allows\nto bring the new release Environment at the same state of content, content-types and scheduled actions as the 'old'\nmaster, ensuring high reliability of operations. The usage of the `--link` alias function also help reduce downtime.\n\n```shell\n$ npx contentful-cli-export --from \"staging\" --compress\n$ npx contentful-cli-export --from \"master\" --compress\n$ npx contentful-cli-release --delete --environment-id \"staging\" --force-yes\n$ npx contentful-cli-release --duplicate --from \"master\" --to \"release-1.4.6\" --update-api-key\n$ npx contentful-cli-release --sync-schedule --from \"master\" --to \"release-1.4.6\"\n$ npx contentful-cli-migrations --to \"release-1.4.6\" --force-yes\n$ npx contentful-cli-release --link --alias \"master\" --to \"release-1.4.6\"\n$ npx contentful-cli-release --delete --environment-id \"release-1.4.5\"\n$ npx contentful-cli-release --duplicate --from \"master\" --to \"staging\"\n```\n\nLet's see in details:\n1. We make a compressed backup of `staging` (downloadable as an artifact in the CI/CD).\n2. We also make a compressed backup of the current `master` (downloadable as an artifact in the CI/CD).\n3. We delete 'staging' with the `--delete` option of the script. We pass `--force-yes` since by default 'staging' is a\nprotected Environment.\n4. We then duplicate 'master' into a new release Environment. Ideally the Semantic versioning should follow the same\nnumbering as the one from the GIT release of the application, but we will dive into it in the section [Integrating with\nyour CI/CD](#integrating-with-your-cicd). We use `--update-api-key` to ensure that the new release Environment will be\naccessible with the 'master' CDA API Key.\n5. We continue by copying the Scheduled actions from 'master' to the newly created 'release-1.4.6' Environment.\n6. We apply Contentful Migrations automatically using the cli script `contentful-cli-migrations` from our\ncollection of scripts. The `--force-yes` option will automatically apply all the missing migrations to the new\nEnvironment.\n7. We proceed to switch the alias of 'master' from the old release (1.4.5) to the new one (1.4.6) guaranteeing minimal\ndowntime. There is an additional command line option `--get-master-release` to obtain the environment linked by master,\nso that it can be saved in a shell ENV to be later used for deletion.\n8. At the end we will duplicate the new 'master' as the new 'staging', so that development can continue on a 'staging'\nEnvironment that is an exact copy of production. We don't use the `--update-api-key` option, because it should exist\na 'staging' CDA API Key, separated from the 'master' one.\n\n#### 3. Create a new Release from existing 'master'\n\n![Create a new Release](./images/release-strategy-3.gif)\n\nThis is somehow the most complex, but also the most reliable way of performing a release.\n\nThe starting scenario is something like this\n```\n- Environment 'release-1.4.5' aliased by 'master'\n- Environment 'release-1.4.4' for rollbacks\n- Environment 'staging'\n- Environment 'dev'\n```\n\nAs we can notice, it does not seem that much different from the previous one, but it is for the following reasons:\n\n- `release-1.4.4` is the previous release environment and is kept (unlinked by aliases) for two main reasons. One is\nfor backup, in case something bad happens to the current master. The second one is to allow a 'fast' rollback in case\na deployment goes wrong and the previous 'code' version needs to be released. The two versions might be incompatible\nif Contentful migrations have modified the Content-types.\n- `staging` is detached from the `master` release. This ensures that the development and testing flow can proceed\nwithout interruptions and without dependencies from the production release. `staging` itself could be another\nEnvironment alias, for which a different release strategy could be in place.\n- For this you will need a non-free version of Contentful, that usually guarantees at least 2 Environment aliases\nand more than 5 environments (an additional environment is needed to create the new release).\n\nIn addition, during a release of this type is probably beneficial to split all the operations on the new release\nEnvironment from the `--link --alias` command, since the 'code' release itself has to probably take place in between,\nto guarantee practically no downtime.\n\n**Before the code release**\n```shell\n$ npx contentful-cli-export --from \"master\" --compress\n$ npx contentful-cli-release --duplicate --from \"master\" --to \"release-1.4.6\" --update-api-key\n$ npx contentful-cli-migrations --to \"release-1.4.6\" --force-yes\n```\n\nAfter this stage the Environments will look like:\n```\n- Environment 'release-1.4.6'\n- Environment 'release-1.4.5' aliased by 'master'\n- Environment 'release-1.4.4'\n- Environment 'staging'\n- Environment 'dev'\n```\n\n**After the code release**\n```shell\n$ npx contentful-cli-release --link --alias \"master\" --to \"release-1.4.6\" --prune-old-releases\n$ npx contentful-cli-release --sync-schedule --from \"release-1.4.5\" --to \"master\" --force-yes\n```\n\nThe linking master to the new release will also delete old releases than the latest two, making the final\nEnvironments look like:\n```\n- Environment 'release-1.4.6' aliased by 'master'\n- Environment 'release-1.4.5' for rollbacks\n- Environment 'staging'\n- Environment 'dev'\n```\n\n\u003e You can also have a look at the official Contentful article\n[Deploying changes with environment aliases](https://www.contentful.com/developers/docs/tutorials/general/deploying-changes-with-environment-aliases/)\n\n### Integrating with your CI/CD\n\nThe following are **examples** of how you could integrate what we said in your GitLab or GitHub CI/CD pipeline.\nThe examples are not fully working without the context of your application and set-ups, but are a good start.\n\nTo make this work you will need at least two thins:\n* Your GIT should follow semantic versioning. De facto means that the release will need to be tagged in GIT with an\nincreasing numbering (in the form x.y.z).\n* We assume that the `.env.local` file has been set up for the Contentful scripts. This can be done by using deployment\nvariables that are then copied into real files inside the CI/CD.\n* As a last advice, we suggest the 'code' release to point directly to the latest release (ie: release-1.4.6) instead\nof the master environment. The reason behind this choice is that during the rollout of a release, each node will point\nto the right Environment (old nodes to 'release-1.4.5' and new nodes to 'release-1.4.6'). This guarantee practically\nno downtime, and it avoids having to deal with potential cache issues of the 'master' alias when it points to the new\nEnvironment.\n\n#### Integrating with GitLab\n\n```yaml\n.node:\n  image: node:18.15.0-bullseye #This is a Docker Image from Docker Hub\n\ncontentful-pre-release:\n  extends:\n    - .node\n  script:\n    - LATEST_RELEASE=$(git describe --abbrev=0 --tags)\n    - npm install\n    - npx contentful-cli-export --from \"master\" --compress\n    - npx contentful-cli-release --duplicate --from \"master\" --to \"release-$LATEST_RELEASE\" --update-api-key\n    - sleep 10\n    - npx contentful-cli-migrations --to \"release-$LATEST_RELEASE\" --force-yes\n\ncontentful-post-release:\n  extends:\n    - .node\n  script:\n    - LATEST_RELEASE=$(git describe --abbrev=0 --tags)\n    - PREVIOUS_RELEASE=$(git tag --sort=-committerdate -l|tail -n +2|head -1)\n    - npm install\n    - npx contentful-cli-release --link --alias \"master\" --to \"release-$LATEST_RELEASE\" --prune-old-releases\n    - npx contentful-cli-release --sync-schedule --from \"release-$PREVIOUS_RELEASE\" --to \"master\" --force-yes\n```\n\n#### Building with Next.js\n\nNote:\n- You will need to change the release regular expression to `release-[0-9]*` and use Linux timestamp as unique\nidentifier for the release number.\n- You will need also to use the command line option `--get-master-release` to get the current Environment to which\nmaster is linking, so that it can be deleted later if you don't have enough Contentful Environments.\n- Remember to install the NPM Package `cross-env`: https://www.npmjs.com/package/cross-env\n\nAdd to your package.json:\n```json\n \"scripts\": {\n    \"build\": \"next build \u0026\u0026 npm run contentful-release\",\n    \"contentful-release\": \"cross-env DATE=\\\"$(date +%s)\\\" OLD_RELEASE=\\\"$(npx contentful-cli-release --get-master-release)\\\" npm run contentful-deploy-commands\",\n    \"contentful-deploy-commands\": \"cross-env-shell \\\"npm run contentful-delete-staging \u0026\u0026 npm run contentful-duplicate-master \u0026\u0026 npm run contentful-sync-schedule \u0026\u0026 npm run contentful-run-migrations \u0026\u0026 npm run contentful-link-alias \u0026\u0026 npm run contentful-delete-old-release \u0026\u0026 npm run contentful-duplicate-staging\\\"\",\n    \"contentful-delete-staging\": \"npx contentful-cli-release --delete --environment-id staging --force-yes\",\n    \"contentful-duplicate-master\": \"cross-env-shell \\\"npx contentful-cli-release --duplicate --from master --to release-$DATE --update-api-key\\\"\",\n    \"contentful-sync-schedule\": \"cross-env-shell \\\"npx contentful-cli-release --sync-schedule --from master --to release-$DATE\\\"\",\n    \"contentful-run-migrations\": \"cross-env-shell \\\"npx contentful-cli-migrations --to release-$DATE --force-yes\\\"\",\n    \"contentful-link-alias\": \"cross-env-shell \\\"npx contentful-cli-release --link --alias master --to release-$DATE\\\"\",\n    \"contentful-delete-old-release\": \"cross-env-shell \\\"npx contentful-cli-release --delete --environment-id $OLD_RELEASE\\\"\",\n    \"contentful-duplicate-staging\": \"npx contentful-cli-release --duplicate --from master --to staging\",\n  },\n```\n\n#### GitHub Workflow\n\nThis is still experimental, but your `.github/workflows/contentful.yml` file will look something like:\n\n```yaml\nname: Node.js CI\n\non:\n  push:\n    branches: ['main']\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n\n    strategy:\n      matrix:\n        node-version: [18.15.0]\n\n    steps:\n      - uses: actions/checkout@v3\n        with:\n          fetch-depth: '1'\n      - name: Use Node.js ${{ matrix.node-version }}\n        uses: actions/setup-node@v3\n        with:\n          node-version: ${{ matrix.node-version }}\n          cache: 'npm'\n      - run: npm install\n      - run: npx contentful-cli-export --from \"master\" --compress\n      - run: LATEST_RELEASE=$(git describe --abbrev=0 --tags) \u0026\u0026 npx contentful-cli-release --duplicate --from \"master\" --to \"release-$LATEST_RELEASE\" --update-api-key\n      - run: LATEST_RELEASE=$(git describe --abbrev=0 --tags) \u0026\u0026 npx contentful-cli-migrations --to \"release-$LATEST_RELEASE\" --force-yes\n      - run: LATEST_RELEASE=$(git describe --abbrev=0 --tags) \u0026\u0026 npx contentful-cli-release --link --alias \"master\" --to \"release-$LATEST_RELEASE\" --prune-old-releases\n      - run: PREVIOUS_RELEASE=$(git tag --sort=-committerdate -l|tail -n +2|head -1) \u0026\u0026 npx contentful-cli-release --sync-schedule --from \"release-$PREVIOUS_RELEASE\" --to \"master\" --force-yes\n```\n\n## 📅 Todo\n\n* Add a `--sync-entries` option to sync entries between two release Environments.\n* Add a `--help` command to describe the available command line options.\n* Improve logging and error handling for more transparent releases.\n* Incorporate feedback from the community to enhance tool capabilities.\n\n## 👾 Contributors\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/fciacchi\"\u003e\u003cimg src=\"https://images.weserv.nl/?url=avatars.githubusercontent.com/u/58506?v=4\u0026h=100\u0026w=100\u0026fit=cover\u0026mask=circle\u0026maxage=7d\" width=\"100px;\" alt=\"Fabrizio Ciacchi\" /\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003e@fciacchi\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/psyvic\"\u003e\u003cimg src=\"https://images.weserv.nl/?url=avatars.githubusercontent.com/u/29251597?v=4\u0026h=100\u0026w=100\u0026fit=cover\u0026mask=circle\u0026maxage=7d\" width=\"100px;\" alt=\"Victor Hugo Aizpuruo\" /\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003e@psyvic\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/aalduz\"\u003e\u003cimg src=\"https://images.weserv.nl/?url=avatars.githubusercontent.com/u/11409770?v=4\u0026h=100\u0026w=100\u0026fit=cover\u0026mask=circle\u0026maxage=7d\" width=\"100px;\" alt=\"Aldo Fernández\" /\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003e@aalduz\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n### Contributions\nFeel free to open issues or pull requests in our GitHub Repository if you have suggestions or improvements to propose.\n\n## 🎩 Acknowledgements\n\nI would like to express my gratitude to the following parties:\n\n* [Atida 🔗](https://www.atida.com/), the company that has allowed these scripts to be open sourced. Atida is an\n  e-commerce platform that sells beauty and medical products. Their support for open source is greatly appreciated.\n  A special thank to \u003ca href=\"https://github.com/shoopi\"\u003e\u003cimg src=\"https://images.weserv.nl/?url=avatars.githubusercontent.com/u/1385372?v=4\u0026h=16\u0026w=16\u0026fit=cover\u0026mask=circle\u0026maxage=7d\" width=\"16px;\" alt=\"Shaya Pourmirza\" /\u003e Shaya Pourmirza\u003c/a\u003e\n  that has been a great promoter and supporter of this initiative inside the company.\n* [Contentful 🔗](https://www.contentful.com/), for creating their excellent content management platform and the\n  JavaScript CMA SDK that this library is built on. Without their work, this project would not be possible.\n\nThank you to everyone involved!\n\n## 📚 Other Scripts in the same collection\n\nWe produce a bunch of interesting packages for Contentful. You might want to check them out:\n\n* **Contentful Lib Helpers** ([GitHub](https://github.com/AtidaTech/contentful-lib-helpers/) and [NpmJS](https://www.npmjs.com/package/contentful-lib-helpers)): Utility Library for Contentful Management API.\n* **Contentful CLI Export** ([GitHub](https://github.com/AtidaTech/contentful-cli-export/) and [NpmJS](https://www.npmjs.com/package/contentful-cli-export)): Simplifies backup of your Contentful Environment.\n* **Contentful CLI Migrations** ([GitHub](https://github.com/AtidaTech/contentful-cli-migrations/) and [NpmJS](https://www.npmjs.com/package/contentful-cli-migrations)): Tool to automate and scale Contentful Migrations.\n* **Contentful CLI Release** ([GitHub](https://github.com/AtidaTech/contentful-cli-release/) and [NpmJS](https://www.npmjs.com/package/contentful-cli-release)): Release utilities to deploy Contentful in a CI/CD.\n\n[//]: # (* **Contentful CLI Sync** \u0026#40;[GitHub]\u0026#40;https://github.com/AtidaTech/contentful-cli-sync/\u0026#41; and )\n[//]: # ([NpmJS]\u0026#40;https://www.npmjs.com/package/contentful-cli-sync\u0026#41;\u0026#41;: Contentful tool to sync data )\n[//]: # (across Spaces and Environments.)\n\n## 📄 License\nThis project is licensed under the [MIT License](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fatidatech%2Fcontentful-cli-release","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fatidatech%2Fcontentful-cli-release","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fatidatech%2Fcontentful-cli-release/lists"}