{"id":28506661,"url":"https://github.com/temporalio/features","last_synced_at":"2025-07-25T21:33:36.561Z","repository":{"id":37597976,"uuid":"435771502","full_name":"temporalio/features","owner":"temporalio","description":"Behavior and history compatibility testing for Temporal SDKs","archived":false,"fork":false,"pushed_at":"2025-07-14T17:23:16.000Z","size":1902,"stargazers_count":17,"open_issues_count":236,"forks_count":19,"subscribers_count":11,"default_branch":"main","last_synced_at":"2025-07-14T22:24:49.238Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/temporalio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-12-07T06:40:43.000Z","updated_at":"2025-07-14T17:23:20.000Z","dependencies_parsed_at":"2023-10-26T22:26:29.380Z","dependency_job_id":"49b026f6-0bb2-4093-bbfe-54890066c07a","html_url":"https://github.com/temporalio/features","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/temporalio/features","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/temporalio%2Ffeatures","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/temporalio%2Ffeatures/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/temporalio%2Ffeatures/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/temporalio%2Ffeatures/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/temporalio","download_url":"https://codeload.github.com/temporalio/features/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/temporalio%2Ffeatures/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267065324,"owners_count":24030351,"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","status":"online","status_checked_at":"2025-07-25T02:00:09.625Z","response_time":70,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2025-06-08T20:06:08.346Z","updated_at":"2025-07-25T21:33:36.546Z","avatar_url":"https://github.com/temporalio.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Temporal Features\n\nThis repository contains snippets for many Temporal features written in different Temporal SDK languages. This also\ncontains a runner and language-specific harnesses to confirm feature behavior across versions.\n\nThese features serve several purposes:\n\n- Ensure parity across SDKs by having same-feature snippets adjacent to one another\n- Confirm feature behavior across SDK versions\n- Confirm history across SDK versions\n- Document features in different SDKs\n- Easy-to-use environment for writing quick workflows in all languages/versions\n- Verify feature compatibility across different server setups\n\n## Building\n\nWith latest [Go](https://golang.org/) installed, run:\n\n```\ngo build -o temporal-features # or temporal-features.exe on Windows\n```\n\n## Running\n\nPrerequisites:\n\n- [Go](https://golang.org/) 1.17+\n- [JDK](https://adoptium.net/?variant=openjdk11\u0026jvmVariant=hotspot) 11+\n- [Node](https://nodejs.org) 16+\n- [uv](https://docs.astral.sh/uv/)\n- [.NET](https://dotnet.microsoft.com) 7+\n- [PHP](https://www.php.net/) 8.1+\n  - [Composer](https://getcomposer.org/)\n\nCommand:\n\n    temporal-features run --lang LANG [--version VERSION] [PATTERN...]\n\nNote, `go run .` can be used in place of `go build` + `temporal-features` to save on the build step.\n\n`LANG` can be `go`, `java`, `ts`, `php`, `py`, or `cs`. `VERSION` is per SDK and if left off, uses the latest version set for\nthe language in this repository.\n\n`PATTERN` must match either the features relative directory _or_ the relative directory + `/feature.\u003cext\u003e` via\n[Go path match rules](https://pkg.go.dev/path#Match) which notably does not include recursive depth matching. If\n`PATTERN` arguments are not present, the default is to run all features.\n\nSeveral other options are available, some of which are described below. Run `temporal-features run --help` to see all\noptions.\n\n### Preparing\n\nBy default when using `run` and a version, a temporary directory is created with a temporary project, the project is\nbuilt, and then the features are run. To separate the steps, the `prepare` command can be used to prebuild the project\nin a directory. Then `run` can use the `--prepared-dir` to reference that directory.\n\nThe command to prepare is:\n\n    temporal-features prepare --lang LANG --version VERSION --dir DIR\n\nThe version is required and the directory is a simple string name of a not-yet-existing directory to be created directly\nbeneath this SDK features directory. That same directory value can then be provided as `--prepared-dir` to `run`. When\nusing a prepared directory on `run`, a version cannot be specified.\n\n### Building docker images\n\nThe CLI supports building docker images from [prepared](#preparing) features.\n\nThere are 2 types of image builds supported, by SDK version or by git repository ref as shown below:\n\n```\n./temporal-features build-image --lang go --repo-ref master\n```\n\nThe built image will be tagged with `features:go-master`\n\n```\n./temporal-features build-image --lang go --version v1.13.1\n```\n\nThe built image will be tagged with `features:go-1.13.1`\n\n- To tag as latest minor, pass `--semver-latest minor`, this will add the `go-1.13` tag.\n- To tag as latest major, pass `--semver-latest major`, this will add the `go-1.13`, `go-1` and `go` tags.\n\n### External Server and Namespace\n\nBy default, a [CLI Dev Server](https://github.com/temporalio/cli/#start-the-server) is dynamically started at runtime to handle all\nfeature runs and a namespace is dynamically generated. To not start the embedded server, use `--server` to specify the\naddress of a server to use. Similarly, to not use a dynamic namespace (that may not be registered on the external\nserver), use `--namespace`.\n\n### History Checking\n\nHistory files are present at `features/\u003cpath/to/feature\u003e/history/history.\u003clang\u003e.\u003cversion\u003e.json`. By default, three\nhistory checks are performed:\n\n1. Specific languages use their replayers to replay the just-executed workflow's history to confirm it works.\n2. Specific languages use their replayers to replay all history files with versions \u003c= the current version to confirm it\n   works.\n3. The primary runner scrubs the history of the just-executed workflow of all execution-dependent values. Then it\n   compares the exact events to all similarly-scrubbed history files.\n\nCurrently there are not ways for features to opt out of specific history checks. To opt out of all history checking for\na specific run, use `--no-history-check`.\n\n## Writing Features\n\nDevelopers can write workflows and activities that represent a SDK \"feature\". These are organized into directories under\nthe `features/` directory.\n\nIn addition to code for the feature, there are configuration settings that can be set in `.config.json`. The possible\nsettings are:\n\n- `go`\n  - `minVersion` - Minimum version in Go this feature should be run in. The feature will be skipped in older versions.\n\nThere are also files in the `history/` subdirectory which contain history files used during run. See the\n\"History Checking\" and \"Generating History\" sections for more info.\n\n### Best Practices\n\n- Try to only demonstrate/test one feature per feature directory.\n  - Code should be kept as short and clear as possible.\n  - No need to over-assert on a bunch of values, just confirm that the feature does what is expected via its output.\n- A Go feature should be in `feature.go`.\n  - For incompatible versions, different files like `feature_pre1.11.0.go` can be present using build tags\n- A Java feature should be in `feature.java`.\n- A TypeScript feature should be in `feature.ts`.\n\n  **NOTE**: TypeScript features include workflow and non workflow code in the same file. Those are run in different\n  environments so they may not share variables and the feature author should keep the workflow runtime limitations in\n  mind when writing features.\n\n- A Python feature should be in `feature.py`.\n- Add a README.md to each feature directory.\n  - README should have a title summarizing the feature (only first letter needs to be in title case), then a short\n    paragraph explaining the feature and its purpose, and then optionally another paragraph explaining details of the\n    specific code steps.\n  - Other sections can also explain decisions made in language specific ways or other details about versions/approaches.\n  - Feel free to add links and more text as necessary.\n- Verification/regression feature directories for bugs should be under `features/bugs/\u003clang\u003e`.\n  - Ideally the checking of the result has a version condition that shows in earlier versions it should fail and in\n    newer versions it should succeed.\n- The more languages per non-bug feature, the better. Try not to create non-bug features that use specific language\n  constructs unless that's the purpose of the feature.\n- Refactor liberally to create shortcuts and better harnesses for making features easy to read and write.\n  - This is not a library used by anyone, there are no backwards compatibility concerns. If one feature uses something\n    that has value to another, extract and put in helper/harness and have both use it.\n- History should be generated for each feature on the earliest version the feature is expected to work at without\n  history changes.\n\n#### Generating History\n\nTo generate history, run the same test (see the \"Running\" section) for the version to generate at, but use the\n`--generate-history` option. When generating history, only one test can be specified and the version of the SDK must be\nspecified. Any existing history for that feature, language, and version will be overwritten.\n\nHistory generation should only be needed when first developing a feature or when a version intentionally introduces an\nincompatibility. Otherwise, history files should remain checked in and not regenerated.\n\n## Usage within CI\n\nThe repo defines GitHub workflows which are designed to allow running the SDK features suites\nagainst changes to an SDK, or against changes to server. The former is accomplished by syncing the\nSDK repo and using it as a path-version when running the suites. The latter is accomplished by\nbuilding the changes to server into a docker image, and using that docker image for the server\nwhen running the suites.\n\nPublishing docker images of the features runner/suites is also supported. It may be run\n[manually](https://github.com/temporalio/features/actions/workflows/all-docker-images.yaml),\nbut is also triggered by default on each push to main.\n\nThe dynamic configuration file located at `dockerfiles/dynamicconfig/docker.yaml` defines the dynamic configuration\nsettings needed for features to run, and should be used as part of or all of the dynamic config settings for any\nexternal server not using the basic docker-compose setup.\n\n## TODO\n\n- Add support for replaying testing of all versions _inside_ each SDKs harness as part of the run\n- Add many more feature workflows\n- Document how to use this framework to easily write and test features even when not committing\n- Log swallowing and concurrent execution\n- Investigate support for changing runtime versions (i.e. Go, Java, and Node versions)\n- Investigate support for changing server versions\n- CI support\n  - Support using a commit hash and alternative git location for an SDK to run against\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftemporalio%2Ffeatures","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftemporalio%2Ffeatures","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftemporalio%2Ffeatures/lists"}