From dfee7b619688caf28cdffe8b562e0ae05b014ad6 Mon Sep 17 00:00:00 2001
From: Default email The default author for commits in the destination The default author for commits in the destination. This is used in squash mode workflows or if author cannot be determined. The default author for commits in the destination. This is used in squash mode workflows or when users are not whitelisted. List of white listed authors in the origin. The authors must be unique Specifies the Buildozer command, e.g. 'replace deps :foo :bar' The reverse of the command. This is only required if the given command cannot be reversed automatically and the reversal of this command is required by some workflow or Copybara check. The following commands are automatically reversible:
Target to create, including the package, e.g. 'foo:bar'. The package can be '.' for the root BUILD file.
+rule_type | `string`Type of this rule, for instance, java_library.
+commands | `sequence`Commands to populate attributes of the target after creating it. Elements can be strings such as 'add deps :foo' or objects returned by buildozer.cmd.
+before | `string`When supplied, causes this target to be created *before* the target named by 'before'
+after | `string`When supplied, causes this target to be created *after* the target named by 'after'
+ + +### buildozer.delete + +A transformation which is the opposite of creating a build target. When run normally, it deletes a build target. When reversed, it creates and prepares one. + +`buildozerDelete buildozer.delete(target, rule_type='', recreate_commands=[], before='', after='')` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +target | `string`Target to create, including the package, e.g. 'foo:bar'
+rule_type | `string`Type of this rule, for instance, java_library. Supplying this will cause this transformation to be reversible.
+recreate_commands | `sequence`Commands to populate attributes of the target after creating it. Elements can be strings such as 'add deps :foo' or objects returned by buildozer.cmd.
+before | `string`When supplied with rule_type and the transformation is reversed, causes this target to be created *before* the target named by 'before'
+after | `string`When supplied with rule_type and the transformation is reversed, causes this target to be created *after* the target named by 'after'
+ + +### buildozer.modify + +A transformation which runs one or more Buildozer commands against a single target expression. See http://go/buildozer for details on supported commands and target expression formats. + +`buildozerModify buildozer.modify(target, commands)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +target | `object`Specifies the target(s) against which to apply the commands. Can be a list.
+commands | `sequence`Commands to apply to the target(s) specified. Elements can be strings such as 'add deps :foo' or objects returned by buildozer.cmd.
+ + +#### Examples: + + +##### Add a setting to one target: + +Add "config = ':foo'" to foo/bar:baz: + +```python +buildozer.modify( + target = 'foo/bar:baz', + commands = [ + buildozer.cmd('set config ":foo"'), + ], +) +``` + + +##### Add a setting to several targets: + +Add "config = ':foo'" to foo/bar:baz and foo/bar:fooz: + +```python +buildozer.modify( + target = ['foo/bar:baz', 'foo/bar:fooz'], + commands = [ + buildozer.cmd('set config ":foo"'), + ], +) +``` + + + + +## change + +A change metadata. Contains information like author, change message or detected labels + + +#### Fields: + +Name | Description +---- | ----------- +author | The author of the change +date_time_iso_offset | Return a ISO offset date time. Example: 2011-12-03T10:15:30+01:00' +first_line_message | The message of the change +labels | A dictionary with the labels detected for the change. If the label is present multiple times it returns the last value. Note that this is a heuristic and it could include things that are not labels. +labels_all_values | A dictionary with the labels detected for the change. Note that the value is a collection of the values for each time the label was found. Use 'labels' instead if you are only interested in the last value. Note that this is a heuristic and it could include things that are not labels. +merge | Returns true if the change represents a merge +message | The message of the change +original_author | The author of the change before any mapping +ref | Origin reference ref + + + +## ChangeMessage + +Represents a well formed parsed change message with its associated labels. + + +#### Fields: + +Name | Description +---- | ----------- +first_line | First line of this message +text | The text description this message, not including the labels. + + +### message.label_values + +Returns a list of values associated with the label name. + +`sequence of string message.label_values(label_name)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +label_name | `string`The label name.
+ + + +## Changes + +Data about the set of changes that are being migrated. Each change includes information like: original author, change message, labels, etc. You receive this as a field in TransformWork object for used defined transformations + + +#### Fields: + +Name | Description +---- | ----------- +current | List of changes that will be migrated +migrated | List of changes that where migrated in previous Copybara executions or if using ITERATIVE mode in previous iterations of this workflow. + + + +## Console + +A console that can be used in skylark transformations to print info, warning or error messages. + + +### console.error + +Show an error in the log. Note that this will stop Copybara execution. + +`console.error(message)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +message | `string`message to log
+ + +### console.info + +Show an info message in the console + +`console.info(message)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +message | `string`message to log
+ + +### console.progress + +Show a progress message in the console + +`console.progress(message)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +message | `string`message to log
+ + +### console.verbose + +Show an info message in the console if verbose logging is enabled. + +`console.verbose(message)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +message | `string`message to log
+ + +### console.warn + +Show a warning in the console + +`console.warn(message)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +message | `string`message to log
+ + + +## core + +Core functionality for creating migrations, and basic transformations. + + +#### Fields: + +Name | Description +---- | ----------- +main_config_path | Location of the config file. This is subject to change + + + +**Command line flags:** + +Name | Type | Description +---- | ---- | ----------- +`--config-root` | *string* | Configuration root path to be used for resolving absolute config labels like '//foo/bar' +`--console-file-flush-interval` | *duration* | How often Copybara should flush the console to the output file. (10s, 1m, etc.)If set to 0s, console will be flushed only at the end. +`--console-file-path` | *string* | If set, write the console output also to the given file path. +`--debug-file-break` | *string* | Stop when file matching the glob changes +`--debug-metadata-break` | *boolean* | Stop when message and/or author changes +`--debug-transform-break` | *string* | Stop when transform description matches +`--disable-reversible-check` | *boolean* | If set, all workflows will be executed without reversible_check, overriding the workflow config and the normal behavior for CHANGE_REQUEST mode. +`--dry-run` | *boolean* | Run the migration in dry-run mode. Some destination implementations might have some side effects (like creating a code review), but never submit to a main branch. +`--fetch-timeout` | *duration* | Fetch timeout +`--force` | *boolean* | Force the migration even if Copybara cannot find in the destination a change that is an ancestor of the one(s) being migrated. This should be used with care, as it could lose changes when migrating a previous/conflicting change. +`--noansi` | *boolean* | Don't use ANSI output for messages +`--nocleanup` | *boolean* | Cleanup the output directories. This includes the workdir, scratch clones of Git repos, etc. By default is set to false and directories will be cleaned prior to the execution. If set to true, the previous run output will not be cleaned up. Keep in mind that running in this mode will lead to an ever increasing disk usage. +`--output-limit` | *int* | Limit the output in the console to a number of records. Each subcommand might use this flag differently. Defaults to 0, which shows all the output. +`--output-root` | *string* | The root directory where to generate output files. If not set, ~/copybara/out is used by default. Use with care, Copybara might remove files inside this root if necessary. +`--squash` | *boolean* | Override workflow's mode with 'SQUASH'. This is useful mainly for workflows that use 'ITERATIVE' mode, when we want to run a single export with 'SQUASH', maybe to fix an issue. Always use --dry-run before, to test your changes locally. +`--validate-starlark` | *string* | Starlark should be validated prior to execution, but this might break legacy configs. Options are LOOSE, STRICT +`-v, --verbose` | *boolean* | Verbose output. + + +### core.copy + +Copy files between directories and renames files + +`transformation core.copy(before, after, paths=glob(["**"]), overwrite=False)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +before | `string`The name of the file or directory to copy. If this is the empty string and 'after' is a directory, then all files in the workdir will be copied to the sub directory specified by 'after', maintaining the directory tree.
+after | `string`The name of the file or directory destination. If this is the empty string and 'before' is a directory, then all files in 'before' will be copied to the repo root, maintaining the directory tree inside 'before'.
+paths | `glob`A glob expression relative to 'before' if it represents a directory. Only files matching the expression will be copied. For example, glob(["**.java"]), matches all java files recursively inside 'before' folder. Defaults to match all the files recursively.
+overwrite | `boolean`Overwrite destination files if they already exist. Note that this makes the transformation non-reversible, since there is no way to know if the file was overwritten or not in the reverse workflow.
+ + +#### Examples: + + +##### Copy a directory: + +Move all the files in a directory to another directory: + +```python +core.copy("foo/bar_internal", "bar") +``` + +In this example, `foo/bar_internal/one` will be copied to `bar/one`. + + +##### Copy with reversal: + +Copy all static files to a 'static' folder and use remove for reverting the change + +```python +core.transform( + [core.copy("foo", "foo/static", paths = glob(["**.css","**.html", ]))], + reversal = [core.remove(glob(['foo/static/**.css', 'foo/static/**.html']))] +) +``` + + + +### core.dynamic_feedback + +Create a dynamic Skylark feedback migration. This should only be used by libraries developers + +`feedback.action core.dynamic_feedback(impl, params={})` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +impl | `starlarkCallable`The Skylark function to call
+params | `dict`The parameters to the function. Will be available under ctx.params
+ + +### core.dynamic_transform + +Create a dynamic Skylark transformation. This should only be used by libraries developers + +`transformation core.dynamic_transform(impl, params={})` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +impl | `starlarkCallable`The Skylark function to call
+params | `dict`The parameters to the function. Will be available under ctx.params
+ + +#### Example: + + +##### Create a dynamic transformation with parameter: + +If you want to create a library that uses dynamic transformations, you probably want to make them customizable. In order to do that, in your library.bara.sky, you need to hide the dynamic transformation (prefix with '_' and instead expose a function that creates the dynamic transformation with the param: + +```python +def _test_impl(ctx): + ctx.set_message(ctx.message + ctx.params['name'] + str(ctx.params['number']) + '\n') + +def test(name, number = 2): + return core.dynamic_transform(impl = _test_impl, + params = { 'name': name, 'number': number}) +``` + +After defining this function, you can use `test('example', 42)` as a transformation in `core.workflow`. + + + +### core.fail_with_noop + +If invoked, it will fail the current migration as a noop + +`feedback.action core.fail_with_noop(msg)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +msg | `string`The noop message
+ + +### core.feedback + +Defines a migration of changes' metadata, that can be invoked via the Copybara command in the same way as a regular workflow migrates the change itself. + +It is considered change metadata any information associated with a change (pending or submitted) that is not core to the change itself. A few examples: +The name of the feedback workflow.
+origin | `trigger`The trigger of a feedback migration.
+destination | `endpoint_provider`Where to write change metadata to. This is usually a code review system like Gerrit or GitHub PR.
+actions | `sequence`A list of feedback actions to perform, with the following semantics:
- There is no guarantee of the order of execution.
- Actions need to be independent from each other.
- Failure in one action might prevent other actions from executing.
A description of what this workflow achieves
+ + +### core.filter_replace + +Applies an initial filtering to find a substring to be replaced and then applies a `mapping` of replaces for the matched text. + +`filter_replace core.filter_replace(regex, mapping={}, group=Whole text, paths=glob(["**"]), reverse=`regex`)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +regex | `string`A re2 regex to match a substring of the file
+mapping | `object`A mapping function like core.replace_mapper or a dict with mapping values.
+group | `integer`Extract a regex group from the matching text and pass this as parameter to the mapping instead of the whole matching text.
+paths | `glob`A glob expression relative to the workdir representing the files to apply the transformation. For example, glob(["**.java"]), matches all java files recursively. Defaults to match all the files recursively.
+reverse | `string`A re2 regex used as reverse transformation
+ + +#### Examples: + + +##### Simple replace with mapping: + +Simplest mapping + +```python +core.filter_replace( + regex = 'a.*', + mapping = { + 'afoo': 'abar', + 'abaz': 'abam' + } +) +``` + + +##### TODO replace: + +This replace is similar to what it can be achieved with core.todo_replace: + +```python +core.filter_replace( + regex = 'TODO\((.*?)\)', + group = 1, + mapping = core.replace_mapper([ + core.replace( + before = '${p}foo${s}', + after = '${p}fooz${s}', + regex_groups = { 'p': '.*', 's': '.*'} + ), + core.replace( + before = '${p}baz${s}', + after = '${p}bazz${s}', + regex_groups = { 'p': '.*', 's': '.*'} + ), + ], + all = True + ) +) +``` + + + +### core.format + +Formats a String using Java format patterns. + +`string core.format(format, args)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +format | `string`The format string
+args | `sequence`The arguments to format
+ + +### core.move + +Moves files between directories and renames files + +`transformation core.move(before, after, paths=glob(["**"]), overwrite=False)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +before | `string`The name of the file or directory before moving. If this is the empty string and 'after' is a directory, then all files in the workdir will be moved to the sub directory specified by 'after', maintaining the directory tree.
+after | `string`The name of the file or directory after moving. If this is the empty string and 'before' is a directory, then all files in 'before' will be moved to the repo root, maintaining the directory tree inside 'before'.
+paths | `glob`A glob expression relative to 'before' if it represents a directory. Only files matching the expression will be moved. For example, glob(["**.java"]), matches all java files recursively inside 'before' folder. Defaults to match all the files recursively.
+overwrite | `boolean`Overwrite destination files if they already exist. Note that this makes the transformation non-reversible, since there is no way to know if the file was overwritten or not in the reverse workflow.
+ + +#### Examples: + + +##### Move a directory: + +Move all the files in a directory to another directory: + +```python +core.move("foo/bar_internal", "bar") +``` + +In this example, `foo/bar_internal/one` will be moved to `bar/one`. + + +##### Move all the files to a subfolder: + +Move all the files in the checkout dir into a directory called foo: + +```python +core.move("", "foo") +``` + +In this example, `one` and `two/bar` will be moved to `foo/one` and `foo/two/bar`. + + +##### Move a subfolder's content to the root: + +Move the contents of a folder to the checkout root directory: + +```python +core.move("foo", "") +``` + +In this example, `foo/bar` would be moved to `bar`. + + + +### core.remove + +Remove files from the workdir. **This transformation is only meant to be used inside core.transform for reversing core.copy like transforms**. For regular file filtering use origin_files exclude mechanism. + +`remove core.remove(paths)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +paths | `glob`The files to be deleted
+ + +#### Examples: + + +##### Reverse a file copy: + +Move all the files in a directory to another directory: + +```python +core.transform( + [core.copy("foo", "foo/public")], + reversal = [core.remove(glob(["foo/public/**"]))]) +``` + +In this example, `foo/one` will be moved to `foo/public/one`. + + +##### Copy with reversal: + +Copy all static files to a 'static' folder and use remove for reverting the change + +```python +core.transform( + [core.copy("foo", "foo/static", paths = glob(["**.css","**.html", ]))], + reversal = [core.remove(glob(['foo/static/**.css', 'foo/static/**.html']))] +) +``` + + + +### core.replace + +Replace a text with another text using optional regex groups. This tranformer can be automatically reversed. + +`replace core.replace(before, after, regex_groups={}, paths=glob(["**"]), first_only=False, multiline=False, repeated_groups=False, ignore=[])` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +before | `string`The text before the transformation. Can contain references to regex groups. For example "foo${x}text".
`before` can only contain 1 reference to each unique `regex_group`. If you require multiple references to the same `regex_group`, add `repeated_groups: True`.
If '$' literal character needs to be matched, '`$$`' should be used. For example '`$$FOO`' would match the literal '$FOO'.
+after | `string`The text after the transformation. It can also contain references to regex groups, like 'before' field.
+regex_groups | `dict`A set of named regexes that can be used to match part of the replaced text.Copybara uses [re2](https://github.com/google/re2/wiki/Syntax) syntax. For example {"x": "[A-Za-z]+"}
+paths | `glob`A glob expression relative to the workdir representing the files to apply the transformation. For example, glob(["**.java"]), matches all java files recursively. Defaults to match all the files recursively.
+first_only | `boolean`If true, only replaces the first instance rather than all. In single line mode, replaces the first instance on each line. In multiline mode, replaces the first instance in each file.
+multiline | `boolean`Whether to replace text that spans more than one line.
+repeated_groups | `boolean`Allow to use a group multiple times. For example foo${repeated}/${repeated}. Note that this mechanism doesn't use backtracking. In other words, the group instances are treated as different groups in regex construction and then a validation is done after that.
+ignore | `sequence`A set of regexes. Any text that matches any expression in this set, which might otherwise be transformed, will be ignored.
+ + +#### Examples: + + +##### Simple replacement: + +Replaces the text "internal" with "external" in all java files + +```python +core.replace( + before = "internal", + after = "external", + paths = glob(["**.java"]), +) +``` + + +##### Append some text at the end of files: + + + +```python +core.replace( + before = '${end}', + after = 'Text to be added at the end', + multiline = True, + regex_groups = { 'end' : '\z'}, +) +``` + + +##### Append some text at the end of files reversible: + +Same as the above example but make the transformation reversible + +```python +core.transform([ + core.replace( + before = '${end}', + after = 'some append', + multiline = True, + regex_groups = { 'end' : '\z'}, + ) +], +reversal = [ + core.replace( + before = 'some append${end}', + after = '', + multiline = True, + regex_groups = { 'end' : '\z'}, + )]) +``` + + +##### Replace using regex groups: + +In this example we map some urls from the internal to the external version in all the files of the project. + +```python +core.replace( + before = "https://some_internal/url/${pkg}.html", + after = "https://example.com/${pkg}.html", + regex_groups = { + "pkg": ".*", + }, + ) +``` + +So a url like `https://some_internal/url/foo/bar.html` will be transformed to `https://example.com/foo/bar.html`. + + +##### Remove confidential blocks: + +This example removes blocks of text/code that are confidential and thus shouldn'tbe exported to a public repository. + +```python +core.replace( + before = "${x}", + after = "", + multiline = True, + regex_groups = { + "x": "(?m)^.*BEGIN-INTERNAL[\\w\\W]*?END-INTERNAL.*$\\n", + }, + ) +``` + +This replace would transform a text file like: + +``` +This is +public + // BEGIN-INTERNAL + confidential + information + // END-INTERNAL +more public code + // BEGIN-INTERNAL + more confidential + information + // END-INTERNAL +``` + +Into: + +``` +This is +public +more public code +``` + + + + + +### core.replace_mapper + +A mapping function that applies a list of replaces until one replaces the text (Unless `all = True` is used). This should be used with core.filter_replace or other transformations that accept text mapping as parameter. + +`replaceMapper core.replace_mapper(mapping, all=False)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +mapping | `sequence of transformation`The list of core.replace transformations
+all | `boolean`Run all the mappings despite a replace happens.
+ + +### core.reverse + +Given a list of transformations, returns the list of transformations equivalent to undoing all the transformations + +`sequence of transformation core.reverse(transformations)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +transformations | `sequence of transformation`The transformations to reverse
+ + +### core.todo_replace + +Replace Google style TODOs. For example `TODO(username, othername)`. + +`todoReplace core.todo_replace(tags=['TODO', 'NOTE'], mapping={}, mode='MAP_OR_IGNORE', paths=glob(["**"]), default=None, ignore=None)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +tags | `sequence of string`Prefix tag to look for
+mapping | `dict`Mapping of users/strings
+mode | `string`Mode for the replace:
A glob expression relative to the workdir representing the files to apply the transformation. For example, glob(["**.java"]), matches all java files recursively. Defaults to match all the files recursively.
+default | `string`Default value if mapping not found. Only valid for 'MAP_OR_DEFAULT' or 'USE_DEFAULT' modes
+ignore | `string`If set, elements within TODO (with usernames) that match the regex will be ignored. For example ignore = "foo" would ignore "foo" in "TODO(foo,bar)" but not "bar".
+ + +#### Examples: + + +##### Simple update: + +Replace TODOs and NOTES for users in the mapping: + +```python +core.todo_replace( + mapping = { + 'test1' : 'external1', + 'test2' : 'external2' + } +) +``` + +Would replace texts like TODO(test1) or NOTE(test1, test2) with TODO(external1) or NOTE(external1, external2) + + +##### Scrubbing: + +Remove text from inside TODOs + +```python +core.todo_replace( + mode = 'SCRUB_NAMES' +) +``` + +Would replace texts like TODO(test1): foo or NOTE(test1, test2):foo with TODO:foo and NOTE:foo + + +##### Ignoring Regex Patterns: + +Ignore regEx inside TODOs when scrubbing/mapping + +```python +core.todo_replace( + mapping = { 'aaa' : 'foo'}, + ignore = 'b/.*' +) +``` + +Would replace texts like TODO(b/123, aaa) with TODO(b/123, foo) + + + +### core.transform + +Groups some transformations in a transformation that can contain a particular, manually-specified, reversal, where the forward version and reversed version of the transform are represented as lists of transforms. The is useful if a transformation does not automatically reverse, or if the automatic reversal does not work for some reason.The list of transformations to run as a result of running this transformation.
+reversal | `sequence of transformation`The list of transformations to run as a result of running this transformation in reverse.
+ignore_noop | `boolean`In case a noop error happens in the group of transformations (Both forward and reverse), it will be ignored, but the rest of the transformations in the group will still be executed. If ignore_noop is not set, we will apply the closest parent's ignore_noop.
+ + +### core.verify_match + +Verifies that a RegEx matches (or not matches) the specified files. Does not transform anything, but will stop the workflow if it fails. + +`verifyMatch core.verify_match(regex, paths=glob(["**"]), verify_no_match=False, also_on_reversal=False)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +regex | `string`The regex pattern to verify. To satisfy the validation, there has to be atleast one (or no matches if verify_no_match) match in each of the files included in paths. The re2j pattern will be applied in multiline mode, i.e. '^' refers to the beginning of a file and '$' to its end. Copybara uses [re2](https://github.com/google/re2/wiki/Syntax) syntax.
+paths | `glob`A glob expression relative to the workdir representing the files to apply the transformation. For example, glob(["**.java"]), matches all java files recursively. Defaults to match all the files recursively.
+verify_no_match | `boolean`If true, the transformation will verify that the RegEx does not match.
+also_on_reversal | `boolean`If true, the check will also apply on the reversal. The default behavior is to not verify the pattern on reversal.
+ + +### core.workflow + +Defines a migration pipeline which can be invoked via the Copybara command. + +Implicit labels that can be used/exposed: + + - COPYBARA_CONTEXT_REFERENCE: Requested reference. For example if copybara is invoked as `copybara copy.bara.sky workflow master`, the value would be `master`. + - COPYBARA_LAST_REV: Last reference that was migrated + - COPYBARA_CURRENT_REV: The current reference being migrated + - COPYBARA_CURRENT_MESSAGE: The current message at this point of the transformations + - COPYBARA_CURRENT_MESSAGE_TITLE: The current message title (first line) at this point of the transformations + - COPYBARA_AUTHOR: The author of the change + + +`core.workflow(name, origin, destination, authoring, transformations=[], origin_files=glob(["**"]), destination_files=glob(["**"]), mode="SQUASH", reversible_check=True for 'CHANGE_REQUEST' mode. False otherwise, check_last_rev_state=True for CHANGE_REQUEST, ask_for_confirmation=False, dry_run=False, after_migration=[], after_workflow=[], change_identity=None, set_rev_id=True, smart_prune=False, migrate_noop_changes=False, experimental_custom_rev_id=None, description=None, checkout=True)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +name | `string`The name of the workflow.
+origin | `origin`Where to read from the code to be migrated, before applying the transformations. This is usually a VCS like Git, but can also be a local folder or even a pending change in a code review system like Gerrit.
+destination | `destination`Where to write to the code being migrated, after applying the transformations. This is usually a VCS like Git, but can also be a local folder or even a pending change in a code review system like Gerrit.
+authoring | `authoring_class`The author mapping configuration from origin to destination.
+transformations | `sequence`The transformations to be run for this workflow. They will run in sequence.
+origin_files | `glob`A glob relative to the workdir that will be read from the origin during the import. For example glob(["**.java"]), all java files, recursively, which excludes all other file types.
+destination_files | `glob`A glob relative to the root of the destination repository that matches files that are part of the migration. Files NOT matching this glob will never be removed, even if the file does not exist in the source. For example glob(['**'], exclude = ['**/BUILD']) keeps all BUILD files in destination when the origin does not have any BUILD files. You can also use this to limit the migration to a subdirectory of the destination, e.g. glob(['java/src/**'], exclude = ['**/BUILD']) to only affect non-BUILD files in java/src.
+mode | `string`Workflow mode. Currently we support four modes:
Indicates if the tool should try to to reverse all the transformations at the end to check that they are reversible.
The default value is True for 'CHANGE_REQUEST' mode. False otherwise
If set to true, Copybara will validate that the destination didn't change since last-rev import for destination_files. Note that this flag doesn't work for CHANGE_REQUEST mode.
+ask_for_confirmation | `boolean`Indicates that the tool should show the diff and require user's confirmation before making a change in the destination.
+dry_run | `boolean`Run the migration in dry-run mode. Some destination implementations might have some side effects (like creating a code review), but never submit to a main branch.
+after_migration | `sequence`Run a feedback workflow after one migration happens. This runs once per change in `ITERATIVE` mode and only once for `SQUASH`.
+after_workflow | `sequence`Run a feedback workflow after all the changes for this workflow run are migrated. Prefer `after_migration` as it is executed per change (in ITERATIVE mode). Tasks in this hook shouldn't be critical to execute. These actions shouldn't record effects (They'll be ignored).
+change_identity | `string`By default, Copybara hashes several fields so that each change has an unique identifier that at the same time reuses the generated destination change. This allows to customize the identity hash generation so that the same identity is used in several workflows. At least ${copybara_config_path} has to be present. Current user is added to the hash automatically.
Available variables:
Copybara adds labels like 'GitOrigin-RevId' in the destination in order to track what was the latest change imported. For `CHANGE_REQUEST` workflows it is not used and is purely informational. This field allows to disable it for that mode. Destinations might ignore the flag.
+smart_prune | `boolean`By default CHANGE_REQUEST workflows cannot restore scrubbed files. This flag does a best-effort approach in restoring the non-affected snippets. For now we only revert the non-affected files. This only works for CHANGE_REQUEST mode.
+migrate_noop_changes | `boolean`By default, Copybara tries to only migrate changes that affect origin_files or config files. This flag allows to include all the changes. Note that it might generate more empty changes errors. In `ITERATIVE` mode it might fail if some transformation is validating the message (Like has to contain 'PUBLIC' and the change doesn't contain it because it is internal).
+experimental_custom_rev_id | `string`Use this label name instead of the one provided by the origin. This is subject to change and there is no guarantee.
+description | `string`A description of what this workflow achieves
+checkout | `boolean`Allows disabling the checkout. The usage of this feature is rare. This could be used to update a file of your own repo when a dependant repo version changes and you are not interested on the files of the dependant repo, just the new version.
+ + + +**Command line flags:** + +Name | Type | Description +---- | ---- | ----------- +`--change-request-from-sot-limit` | *int* | Number of origin baseline changes to use for trying to match one in the destination. It can be used if the are many parent changes in the origin that are a no-op in the destination +`--change-request-from-sot-retry` | *list<integer>* | Number of retries and delay between retries when we cannot find the baseline in the destination for CHANGE_REQUEST_FROM_SOT. For example '10,30,60' will retry three times. The first retry will be delayed 10s, the second one 30s and the third one 60s +`--change-request-parent, --change_request_parent` | *string* | Commit revision to be used as parent when importing a commit using CHANGE_REQUEST workflow mode. this shouldn't be needed in general as Copybara is able to detect the parent commit message. +`--check-last-rev-state` | *boolean* | If enabled, Copybara will validate that the destination didn't change since last-rev import for destination_files. Note that this flag doesn't work for CHANGE_REQUEST mode. +`--default-author` | *string* | Use this author as default instead of the one in the config file.Format should be 'Foo BarFiles to copy to the workdir, potentially overwriting files checked out from the origin.
+ + +#### Example: + + +##### Copy files from the destination's baseline: + +This can be added to the transformations of your core.workflow: + +```python +def _copy_destination_file(ctx): + content = ctx.destination_reader().copy_destination_files(path = 'path/to/**') + + transforms = [core.dynamic_transform(_copy_destination_file)] + +``` + +Would copy all files in path/to/ from the destination baseline to the copybara workdir. The files do not have to be covered by origin_files nor destination_files, but will cause errors if they are not covered by destination_files and not moved or deleted. + + + +### destination_reader.read_file + +Read a file from the destination. + +`string destination_reader.read_file(path)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +path | `string`Path to the file.
+ + +#### Example: + + +##### Read a file from the destination's baseline: + +This can be added to the transformations of your core.workflow: + +```python +def _read_destination_file(ctx): + content = ctx.destination_reader().read_file(path = path/to/my_file.txt') + ctx.console.info(content) + + transforms = [core.dynamic_transform(_read_destination_file)] + +``` + +Would print out the content of path/to/my_file.txt in the destination. The file does not have to be covered by origin_files nor destination_files. + + + + +## destination_ref + +Reference to the change/review created/updated on the destination. + + +#### Fields: + +Name | Description +---- | ----------- +id | Destination reference id +type | Type of reference created. Each destination defines its own and guarantees to be more stable than urls/ids +url | Url, if any, of the destination change + + + +## endpoint + +An origin or destination API in a feedback migration. + + +#### Fields: + +Name | Description +---- | ----------- +url | Return the URL of this endpoint. + + +### endpoint.new_destination_ref + +Creates a new destination reference out of this endpoint. + +`destination_ref endpoint.new_destination_ref(ref, type, url=None)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +ref | `string`The reference.
+type | `string`The type of this reference.
+url | `string`The url associated with this reference, if any.
+ + +### endpoint.new_origin_ref + +Creates a new origin reference out of this endpoint. + +`origin_ref endpoint.new_origin_ref(ref)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +ref | `string`The reference.
+ + + +## endpoint_provider + +An handle for an origin or destination API in a feedback migration. + + +#### Fields: + +Name | Description +---- | ----------- +url | Return the URL of this endpoint, if any. + + + +## feedback.action_result + +Gives access to the feedback migration information and utilities. + + +#### Fields: + +Name | Description +---- | ----------- +msg | The message associated with the result +result | The result of this action + + + +## feedback.context + +Gives access to the feedback migration information and utilities. This context is a concrete implementation for feedback migrations. + + +#### Fields: + +Name | Description +---- | ----------- +action_name | The name of the current action. +console | Get an instance of the console to report errors or warnings +destination | An object representing the destination. Can be used to query or modify the destination state +feedback_name | The name of the Feedback migration calling this action. +origin | An object representing the origin. Can be used to query about the ref or modifying the origin state +params | Parameters for the function if created with core.dynamic_feedback +refs | A list containing string representations of the entities that triggered the event + + +### feedback.context.error + +Returns an error action result. + +`feedback.action_result feedback.context.error(msg)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +msg | `string`The error message
+ + +### feedback.context.noop + +Returns a no op action result with an optional message. + +`feedback.action_result feedback.context.noop(msg=None)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +msg | `string`The no op message
+ + +### feedback.context.record_effect + +Records an effect of the current action. + +`feedback.context.record_effect(summary, origin_refs, destination_ref, errors=[], type="UPDATED")` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +summary | `string`The summary of this effect
+origin_refs | `sequence of origin_ref`The origin refs
+destination_ref | `destination_ref`The destination ref
+errors | `sequence of string`An optional list of errors
+type | `string`The type of migration effect:
The summary of this effect
+origin_refs | `sequence of origin_ref`The origin refs
+destination_ref | `destination_ref`The destination ref
+errors | `sequence of string`An optional list of errors
+type | `string`The type of migration effect:
By default folder.origin will refuse any symlink in the migration folder that is an absolute symlink or that refers to a file outside of the folder. If this flag is set, it will materialize those symlinks as regular files in the checkout directory.
+ + + +**Command line flags:** + +Name | Type | Description +---- | ---- | ----------- +`--folder-origin-author` | *string* | Deprecated. Please use '--force-author'. Author of the change being migrated from folder.origin() +`--folder-origin-ignore-invalid-symlinks` | *boolean* | If an invalid symlink is found, ignore it instead of failing +`--folder-origin-message` | *string* | Deprecated. Please use '--force-message'. Message of the change being migrated from folder.origin() + + + +## format + +Module for formatting the code to Google's style/guidelines + + +### format.buildifier + +Formats the BUILD files using buildifier. + +`transformation format.buildifier(paths=glob(["**.bzl", "**/BUILD", "BUILD"]), type='auto', lint="OFF", lint_warnings=[])` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +paths | `glob`Paths of the files to format relative to the workdir.
+type | `string`The type of the files. Can be 'auto', 'bzl', 'build' or 'workspace'. Note that this is not recommended to be set and might break in the future. The default is 'auto'. This mode formats as BUILD files "BUILD", "BUILD.bazel", "WORKSPACE" and "WORKSPACE.bazel" files. The rest as bzl files. Prefer to use those names for BUILD files instead of setting this flag.
+lint | `string`If buildifier --lint should be used. This fixes several common issues. Note that this transformation is difficult to revert. For example if it removes a load statement because is not used after removing a rule, then the reverse workflow needs to add back the load statement (core.replace or similar). Possible values: `OFF`, `FIX`. Default is `OFF`
+lint_warnings | `sequence of string`Warnings used in the lint mode. Default is buildifier default`
+ + +#### Examples: + + +##### Default usage: + +The default parameters formats all BUILD and bzl files in the checkout directory: + +```python +format.buildifier() +``` + + +##### Enable lint: + +Enable lint for buildifier + +```python +format.buildifier(lint = "FIX") +``` + + +##### Using globs: + +Globs can be used to match only certain files: + +```python +format.buildifier( + paths = glob(["foo/BUILD", "foo/**/BUILD"], exclude = ["foo/bar/BUILD"]) +) +``` + +Formats all the BUILD files inside `foo` except for `foo/bar/BUILD` + + + + +**Command line flags:** + +Name | Type | Description +---- | ---- | ----------- +`--buildifier-batch-size` | *int* | Process files in batches this size + + + +## gerritapi.AccountInfo + +Gerrit account information. + + +#### Fields: + +Name | Description +---- | ----------- +account_id | The numeric ID of the account. +email | The email address the user prefers to be contacted through.The change id or change number.
+include_results | `sequence of string`What to include in the response. See https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#query-options
+ + +### gerrit_api_obj.list_changes_by_commit + +Get changes from Gerrit based on a query. See https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#list-changes. + + +`sequence of gerritapi.ChangeInfo gerrit_api_obj.list_changes_by_commit(commit, include_results=[])` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +commit | `string`The commit sha to list changes by. See https://gerrit-review.googlesource.com/Documentation/user-search.html#_basic_change_search.
+include_results | `sequence of string`What to include in the response. See https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#query-options
+ + +### gerrit_api_obj.post_review + +Post a review to a Gerrit change for a particular revision. The review will be authored by the user running the tool, or the role account if running in the service. + + +`gerritapi.ReviewResult gerrit_api_obj.post_review(change_id, revision_id, review_input)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +change_id | `string`The Gerrit change id.
+revision_id | `string`The revision for which the comment will be posted.
+review_input | `SetReviewInput`The review to post to Gerrit.
+ + + +## git + +Set of functions to define Git origins and destinations. + + + +**Command line flags:** + +Name | Type | Description +---- | ---- | ----------- +`--experiment-checkout-affected-files` | *boolean* | If set, copybara will only checkout affected files at git origin. Note that this is experimental. +`--git-credential-helper-store-file` | *string* | Credentials store file to be used. See https://git-scm.com/docs/git-credential-store +`--git-no-verify` | *boolean* | Pass the '--no-verify' option to git pushes and commits to disable git commit hooks. +`--git-tag-overwrite` | *boolean* | If set, copybara will force update existing git tag +`--nogit-credential-helper-store` | *boolean* | Disable using credentials store. See https://git-scm.com/docs/git-credential-store +`--nogit-prompt` | *boolean* | Disable username/password prompt and fail if no credentials are found. This flag sets the environment variable GIT_TERMINAL_PROMPT which is intended for automated jobs running Git https://git-scm.com/docs/git/2.3.0#git-emGITTERMINALPROMPTem + + +### git.destination + +Creates a commit in a git repository using the transformed worktree.Indicates the URL to push to as well as the URL from which to get the parent commit
+push | `string`Reference to use for pushing the change, for example 'master'
+tag_name | `string`A template string that refers to a tag name. If tag_name exists, overwrite this tag only if flag git-tag-overwrite is set. Note that tag creation is best-effort and migration will succeed even if the tag cannot be created. Usage: Users can use a string or a string with a label. For instance ${label}_tag_name. And the value of label must be in changes' label list. Otherwise, tag won't be created.
+tag_msg | `string`A template string that refers to the commit msg of a tag. If set, we will create an annotated tag when tag_name is set. Usage: Users can use a string or a string with a label. For instance ${label}_message. And the value of label must be in changes' label list. Otherwise, tag will be created with sha1's commit msg.
+fetch | `string`Indicates the ref from which to get the parent commit. Defaults to push value if None
+partial_fetch | `boolean`Please DO NOT set it to True. This feature is not ready.
+integrates | `sequence of git_integrate`Integrate changes from a url present in the migrated change label. Defaults to a semi-fake merge if COPYBARA_INTEGRATE_REVIEW label is present in the message
+ + + +**Command line flags:** + +Name | Type | Description +---- | ---- | ----------- +`--git-committer-email` | *string* | If set, overrides the committer e-mail for the generated commits in git destination. +`--git-committer-name` | *string* | If set, overrides the committer name for the generated commits in git destination. +`--git-destination-fetch` | *string* | If set, overrides the git destination fetch reference. +`--git-destination-ignore-integration-errors` | *boolean* | If an integration error occurs, ignore it and continue without the integrate +`--git-destination-last-rev-first-parent` | *boolean* | Use git --first-parent flag when looking for last-rev in previous commits +`--git-destination-non-fast-forward` | *boolean* | Allow non-fast-forward pushes to the destination. We only allow this when used with different push != fetch references. +`--git-destination-path` | *string* | If set, the tool will use this directory for the local repository. Note that if the directory exists it needs to be a git repository. Copybara will revert any staged/unstaged changes. +`--git-destination-push` | *string* | If set, overrides the git destination push reference. +`--git-destination-url` | *string* | If set, overrides the git destination URL. +`--nogit-destination-rebase` | *boolean* | Don't rebase the change automatically for workflows CHANGE_REQUEST mode + + +### git.gerrit_api + +Defines a feedback API endpoint for Gerrit, that exposes relevant Gerrit API operations. + +`endpoint_provider of gerrit_api_obj git.gerrit_api(url, checker=None)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +url | `string`Indicates the Gerrit repo URL.
+checker | `checker`A checker for the Gerrit API transport.
+ + + +**Command line flags:** + +Name | Type | Description +---- | ---- | ----------- +`--gerrit-change-id` | *string* | ChangeId to use in the generated commit message. Use this flag if you want to reuse the same Gerrit review for an export. +`--gerrit-new-change` | *boolean* | Create a new change instead of trying to reuse an existing one. +`--gerrit-topic` | *string* | Gerrit topic to use + + +### git.gerrit_destination + +Creates a change in Gerrit using the transformed worktree. If this is used in iterative mode, then each commit pushed in a single Copybara invocation will have the correct commit parent. The reviews generated can then be easily done in the correct order without rebasing. + +`gerritDestination git.gerrit_destination(url, fetch, push_to_refs_for=fetch value, submit=False, partial_fetch=False, notify=None, change_id_policy='FAIL_IF_PRESENT', allow_empty_diff_patchset=True, reviewers=[], cc=[], labels=[], api_checker=None, integrates=None, topic=None)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +url | `string`Indicates the URL to push to as well as the URL from which to get the parent commit
+fetch | `string`Indicates the ref from which to get the parent commit
+push_to_refs_for | `string`Review branch to push the change to, for example setting this to 'feature_x' causes the destination to push to 'refs/for/feature_x'. It defaults to 'fetch' value.
+submit | `boolean`If true, skip the push thru Gerrit refs/for/branch and directly push to branch. This is effectively a git.destination that sets a Change-Id
+partial_fetch | `boolean`Please DO NOT set it to True. This feature is not ready.
+notify | `string`Type of Gerrit notify option (https://gerrit-review.googlesource.com/Documentation/user-upload.html#notify). Sends notifications by default.
+change_id_policy | `string`What to do in the presence or absent of Change-Id in message:
By default Copybara will upload a new PatchSet to Gerrit without checking the previous one. If this set to false, Copybara will download current PatchSet and check the diff against the new diff.
+reviewers | `sequence`The list of the reviewers will be added to gerrit change reviewer listThe element in the list is: an email, for example: "foo@example.com" or label for example: ${SOME_GERRIT_REVIEWER}. These are under the condition of assuming that users have registered to gerrit repos
+cc | `sequence`The list of the email addresses or users that will be CCed in the review. Can use labels as the `reviewers` field.
+labels | `sequence`The list of labels to be pushed with the change. The format is the label along with the associated value. For example: Run-Presubmit+1
+api_checker | `checker`A checker for the Gerrit API endpoint provided for after_migration hooks. This field is not required if the workflow hooks don't use the origin/destination endpoints.
+integrates | `sequence of git_integrate`Integrate changes from a url present in the migrated change label. Defaults to a semi-fake merge if COPYBARA_INTEGRATE_REVIEW label is present in the message
+topic | `string`Sets the topic of the Gerrit change created.
By default it sets no topic. This field accepts a template with labels. For example: `"topic_${CONTEXT_REFERENCE}"`
Indicates the URL of the git repository
+ref | `string`DEPRECATED. Use git.origin for submitted branches.
+submodules | `string`Download submodules. Valid values: NO, YES, RECURSIVE.
+first_parent | `boolean`If true, it only uses the first parent when looking for changes. Note that when disabled in ITERATIVE mode, it will try to do a migration for each change of the merged branch.
+partial_fetch | `boolean`Please DO NOT set it to True. This feature is not ready.
+api_checker | `checker`A checker for the Gerrit API endpoint provided for after_migration hooks. This field is not required if the workflow hooks don't use the origin/destination endpoints.
+patch | `transformation`Patch the checkout dir. The difference with `patch.apply` transformation is that here we can apply it using three-way
+branch | `string`Limit the import to changes that are for this branch. By default imports everything.
+describe_version | `boolean`Download tags and use 'git describe' to create two labels with a meaningful version:
- `GIT_DESCRIBE_CHANGE_VERSION`: The version for the change or changes being migrated. The value changes per change in `ITERATIVE` mode and will be the latest migrated change in `SQUASH` (In other words, doesn't include excluded changes). this is normally what users want to use.
- `GIT_DESCRIBE_REQUESTED_VERSION`: `git describe` for the requested/head version. Constant in `ITERATIVE` mode and includes filtered changes.
Indicates the Gerrit repo URL.
+checker | `checker`A checker for the Gerrit API transport provided by this trigger.
+ + + +**Command line flags:** + +Name | Type | Description +---- | ---- | ----------- +`--gerrit-change-id` | *string* | ChangeId to use in the generated commit message. Use this flag if you want to reuse the same Gerrit review for an export. +`--gerrit-new-change` | *boolean* | Create a new change instead of trying to reuse an existing one. +`--gerrit-topic` | *string* | Gerrit topic to use + + +### git.github_api + +Defines a feedback API endpoint for GitHub, that exposes relevant GitHub API operations. + +`endpoint_provider of github_api_obj git.github_api(url, checker=None)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +url | `string`Indicates the GitHub repo URL.
+checker | `checker`A checker for the GitHub API transport.
+ + + +**Command line flags:** + +Name | Type | Description +---- | ---- | ----------- +`--github-destination-delete-pr-branch` | *boolean* | Overwrite git.github_destination delete_pr_branch field + + +### git.github_destination + +Creates a commit in a GitHub repository branch (for example master). For creating PullRequest use git.github_pr_destination. + +`gitDestination git.github_destination(url, push='master', fetch=None, pr_branch_to_update=None, partial_fetch=False, delete_pr_branch=False, integrates=None, api_checker=None)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +url | `string`Indicates the URL to push to as well as the URL from which to get the parent commit
+push | `string`Reference to use for pushing the change, for example 'master'
+fetch | `string`Indicates the ref from which to get the parent commit. Defaults to push value if None
+pr_branch_to_update | `string`A template string that refers to a pull request branch in the same repository will be updated to current commit of this push branch only if pr_branch_to_update exists. The reason behind this field is that presubmiting changes creates and leaves a pull request open. By using this, we can automerge/close this type of pull requests. As a result, users will see this pr_branch_to_update as merged to this push branch. Usage: Users can use a string or a string with a label. For instance ${label}_pr_branch_name. And the value of label must be in changes' label list. Otherwise, nothing will happen.
+partial_fetch | `boolean`Please DO NOT set it to True. This feature is not ready.
+delete_pr_branch | `boolean`When `pr_branch_to_update` is enabled, it will delete the branch reference after the push to the branch and main branch (i.e master) happens. This allows to cleanup temporary branches created for testing.
+integrates | `sequence of git_integrate`Integrate changes from a url present in the migrated change label. Defaults to a semi-fake merge if COPYBARA_INTEGRATE_REVIEW label is present in the message
+api_checker | `checker`A checker for the Gerrit API endpoint provided for after_migration hooks. This field is not required if the workflow hooks don't use the origin/destination endpoints.
+ + + +**Command line flags:** + +Name | Type | Description +---- | ---- | ----------- +`--git-committer-email` | *string* | If set, overrides the committer e-mail for the generated commits in git destination. +`--git-committer-name` | *string* | If set, overrides the committer name for the generated commits in git destination. +`--git-destination-fetch` | *string* | If set, overrides the git destination fetch reference. +`--git-destination-ignore-integration-errors` | *boolean* | If an integration error occurs, ignore it and continue without the integrate +`--git-destination-last-rev-first-parent` | *boolean* | Use git --first-parent flag when looking for last-rev in previous commits +`--git-destination-non-fast-forward` | *boolean* | Allow non-fast-forward pushes to the destination. We only allow this when used with different push != fetch references. +`--git-destination-path` | *string* | If set, the tool will use this directory for the local repository. Note that if the directory exists it needs to be a git repository. Copybara will revert any staged/unstaged changes. +`--git-destination-push` | *string* | If set, overrides the git destination push reference. +`--git-destination-url` | *string* | If set, overrides the git destination URL. +`--nogit-destination-rebase` | *boolean* | Don't rebase the change automatically for workflows CHANGE_REQUEST mode + + +### git.github_origin + +Defines a Git origin for a Github repository. This origin should be used for public branches. Use github_pr_origin for importing Pull Requests. + +`gitOrigin git.github_origin(url, ref=None, submodules='NO', first_parent=True, partial_fetch=False, patch=None, describe_version=None, version_selector=None)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +url | `string`Indicates the URL of the git repository
+ref | `string`Represents the default reference that will be used for reading the revision from the git repository. For example: 'master'
+submodules | `string`Download submodules. Valid values: NO, YES, RECURSIVE.
+first_parent | `boolean`If true, it only uses the first parent when looking for changes. Note that when disabled in ITERATIVE mode, it will try to do a migration for each change of the merged branch.
+partial_fetch | `boolean`Please DO NOT set it to True. This feature is not ready.
+patch | `transformation`Patch the checkout dir. The difference with `patch.apply` transformation is that here we can apply it using three-way
+describe_version | `boolean`Download tags and use 'git describe' to create two labels with a meaningful version:
- `GIT_DESCRIBE_CHANGE_VERSION`: The version for the change or changes being migrated. The value changes per change in `ITERATIVE` mode and will be the latest migrated change in `SQUASH` (In other words, doesn't include excluded changes). this is normally what users want to use.
- `GIT_DESCRIBE_REQUESTED_VERSION`: `git describe` for the requested/head version. Constant in `ITERATIVE` mode and includes filtered changes.
Select a custom version (tag)to migrate instead of 'ref'
+ + +### git.github_pr_destination + +Creates changes in a new pull request in the destination. + +`gitHubPrDestination git.github_pr_destination(url, destination_ref="master", pr_branch=None, partial_fetch=False, title=None, body=None, integrates=None, api_checker=None, update_description=False)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +url | `string`Url of the GitHub project. For example "https://github.com/google/copybara'"
+destination_ref | `string`Destination reference for the change. By default 'master'
+pr_branch | `string`Customize the pull request branch. Any variable present in the message in the form of ${CONTEXT_REFERENCE} will be replaced by the corresponding stable reference (head, PR number, Gerrit change number, etc.).
+partial_fetch | `boolean`Please DO NOT set it to True. This feature is not ready.
+title | `string`When creating (or updating if `update_description` is set) a pull request, use this title. By default it uses the change first line. This field accepts a template with labels. For example: `"Change ${CONTEXT_REFERENCE}"`
+body | `string`When creating (or updating if `update_description` is set) a pull request, use this body. By default it uses the change summary. This field accepts a template with labels. For example: `"Change ${CONTEXT_REFERENCE}"`
+integrates | `sequence of git_integrate`Integrate changes from a url present in the migrated change label. Defaults to a semi-fake merge if COPYBARA_INTEGRATE_REVIEW label is present in the message
+api_checker | `checker`A checker for the GitHub API endpoint provided for after_migration hooks. This field is not required if the workflow hooks don't use the origin/destination endpoints.
+update_description | `boolean`By default, Copybara only set the title and body of the PR when creating the PR. If this field is set to true, it will update those fields for every update.
+ + +#### Examples: + + +##### Common usage: + +Create a branch by using copybara's computerIdentity algorithm: + +```python +git.github_pr_destination( + url = "https://github.com/google/copybara", + destination_ref = "master", + ) +``` + + +##### Using pr_branch with label: + +Customize pr_branch with context reference: + +```python +git.github_pr_destination( + url = "https://github.com/google/copybara", + destination_ref = "master", + pr_branch = 'test_${CONTEXT_REFERENCE}', + ) +``` + + +##### Using pr_branch with constant string: + +Customize pr_branch with a constant string: + +```python +git.github_pr_destination( + url = "https://github.com/google/copybara", + destination_ref = "master", + pr_branch = 'test_my_branch', + ) +``` + + + + +**Command line flags:** + +Name | Type | Description +---- | ---- | ----------- +`--git-committer-email` | *string* | If set, overrides the committer e-mail for the generated commits in git destination. +`--git-committer-name` | *string* | If set, overrides the committer name for the generated commits in git destination. +`--git-destination-fetch` | *string* | If set, overrides the git destination fetch reference. +`--git-destination-ignore-integration-errors` | *boolean* | If an integration error occurs, ignore it and continue without the integrate +`--git-destination-last-rev-first-parent` | *boolean* | Use git --first-parent flag when looking for last-rev in previous commits +`--git-destination-non-fast-forward` | *boolean* | Allow non-fast-forward pushes to the destination. We only allow this when used with different push != fetch references. +`--git-destination-path` | *string* | If set, the tool will use this directory for the local repository. Note that if the directory exists it needs to be a git repository. Copybara will revert any staged/unstaged changes. +`--git-destination-push` | *string* | If set, overrides the git destination push reference. +`--git-destination-url` | *string* | If set, overrides the git destination URL. +`--github-destination-pr-branch` | *string* | If set, uses this branch for creating the pull request instead of using a generated one +`--github-destination-pr-create` | *boolean* | If the pull request should be created +`--nogit-destination-rebase` | *boolean* | Don't rebase the change automatically for workflows CHANGE_REQUEST mode + + +### git.github_pr_origin + +Defines a Git origin for Github pull requests. + +Implicit labels that can be used/exposed: + + - GITHUB_PR_NUMBER: The pull request number if the reference passed was in the form of `https://github.com/project/pull/123`, `refs/pull/123/head` or `refs/pull/123/master`. + - COPYBARA_INTEGRATE_REVIEW: A label that when exposed, can be used to integrate automatically in the reverse workflow. + - GITHUB_BASE_BRANCH: The base branch name used for the Pull Request. + - GITHUB_BASE_BRANCH_SHA1: The base branch SHA-1 used as baseline. + - GITHUB_PR_TITLE: Title of the Pull Request. + - GITHUB_PR_BODY: Body of the Pull Request. + - GITHUB_PR_URL: GitHub url of the Pull Request. + - GITHUB_PR_HEAD_SHA: The SHA-1 of the head commit of the pull request. + - GITHUB_PR_USER: The login of the author the pull request. + - GITHUB_PR_ASSIGNEE: A repeated label with the login of the assigned users. + - GITHUB_PR_REVIEWER_APPROVER: A repeated label with the login of users that have participated in the review and that can approve the import. Only populated if `review_state` field is set. Every reviewers type matching `review_approvers` will be added to this list. + - GITHUB_PR_REVIEWER_OTHER: A repeated label with the login of users that have participated in the review but cannot approve the import. Only populated if `review_state` field is set. + + +`gitHubPROrigin git.github_pr_origin(url, use_merge=False, required_labels=[], retryable_labels=[], submodules='NO', baseline_from_branch=False, first_parent=True, partial_fetch=False, state='OPEN', review_state=None, review_approvers=["COLLABORATOR", "MEMBER", "OWNER"], api_checker=None, patch=None, branch=None, describe_version=None)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +url | `string`Indicates the URL of the GitHub repository
+use_merge | `boolean`If the content for refs/pull/
Required labels to import the PR. All the labels need to be present in order to migrate the Pull Request.
+retryable_labels | `sequence of string`Required labels to import the PR that should be retried. This parameter must be a subset of required_labels.
+submodules | `string`Download submodules. Valid values: NO, YES, RECURSIVE.
+baseline_from_branch | `boolean`WARNING: Use this field only for github -> git CHANGE_REQUEST workflows.
When the field is set to true for CHANGE_REQUEST workflows it will find the baseline comparing the Pull Request with the base branch instead of looking for the *-RevId label in the commit message.
If true, it only uses the first parent when looking for changes. Note that when disabled in ITERATIVE mode, it will try to do a migration for each change of the merged branch.
+partial_fetch | `boolean`Please DO NOT set it to True. This feature is not ready.
+state | `string`Only migrate Pull Request with that state. Possible values: `'OPEN'`, `'CLOSED'` or `'ALL'`. Default 'OPEN'
+review_state | `string`Required state of the reviews associated with the Pull Request Possible values: `'HEAD_COMMIT_APPROVED'`, `'ANY_COMMIT_APPROVED'`, `'HAS_REVIEWERS'` or `'ANY'`. Default `None`. This field is required if the user wants `GITHUB_PR_REVIEWER_APPROVER` and `GITHUB_PR_REVIEWER_OTHER` labels populated
+review_approvers | `sequence of string`The set of reviewer types that are considered for approvals. In order to have any effect, `review_state` needs to be set. GITHUB_PR_REVIEWER_APPROVER` will be populated for these types. See the valid types here: https://developer.github.com/v4/enum/commentauthorassociation/
+api_checker | `checker`A checker for the GitHub API endpoint provided for after_migration hooks. This field is not required if the workflow hooks don't use the origin/destination endpoints.
+patch | `transformation`Patch the checkout dir. The difference with `patch.apply` transformation is that here we can apply it using three-way
+branch | `string`If set, it will only migrate pull requests for this base branch
+describe_version | `boolean`Download tags and use 'git describe' to create two labels with a meaningful version:
- `GIT_DESCRIBE_CHANGE_VERSION`: The version for the change or changes being migrated. The value changes per change in `ITERATIVE` mode and will be the latest migrated change in `SQUASH` (In other words, doesn't include excluded changes). this is normally what users want to use.
- `GIT_DESCRIBE_REQUESTED_VERSION`: `git describe` for the requested/head version. Constant in `ITERATIVE` mode and includes filtered changes.
Indicates the GitHub repo URL.
+checker | `checker`A checker for the GitHub API transport provided by this trigger.
+events | `sequence of string`Type of events to subscribe. Valid values are: `'ISSUES'`, `'ISSUE_COMMENT'`, `'PULL_REQUEST'`, `'PULL_REQUEST_REVIEW_COMMENT'`, `'PUSH'`, `'STATUS'`,
+ + + +**Command line flags:** + +Name | Type | Description +---- | ---- | ----------- +`--github-destination-delete-pr-branch` | *boolean* | Overwrite git.github_destination delete_pr_branch field + + +### git.integrate + +Integrate changes from a url present in the migrated change label. + +`git_integrate git.integrate(label="COPYBARA_INTEGRATE_REVIEW", strategy="FAKE_MERGE_AND_INCLUDE_FILES", ignore_errors=True)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +label | `string`The migration label that will contain the url to the change to integrate.
+strategy | `string`How to integrate the change:
If we should ignore integrate errors and continue the migration without the integrate
+ + +#### Example: + + +##### Integrate changes from a review url: + +Assuming we have a git.destination defined like this: + +```python +git.destination( + url = "https://example.com/some_git_repo", + integrates = [git.integrate()], + +) +``` + +It will look for `COPYBARA_INTEGRATE_REVIEW` label during the worklow migration. If the label is found, it will fetch the git url and add that change as an additional parent to the migration commit (merge). It will fake-merge any change from the url that matches destination_files but it will include changes not matching it. + + + +### git.latest_version + +Customize what version of the available branches and tags to pick. By default it ignores the reference passed as parameter. Using `force:reference` in the CLI will force to use that reference instead. + +`latestVersionSelector git.latest_version(refspec_format="refs/tags/${n0}.${n1}.${n2}", refspec_groups={'n0' : '[0-9]+', 'n1' : '[0-9]+', 'n2' : '[0-9]+'})` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +refspec_format | `string`The format of the branch/tag
+refspec_groups | `dict`A set of named regexes that can be used to match part of the versions.Copybara uses [re2](https://github.com/google/re2/wiki/Syntax) syntax. Use the following nomenclature n0, n1, n2 for the version part (will use numeric sorting) or s0, s1, s2 (alphabetic sorting). Note that there can be mixed but the numbers cannot be repeated. In other words n0, s1, n2 is valid but not n0, s0, n1. n0 has more priority than n1. If there are fields where order is not important, use s(N+1) where N ist he latest sorted field. Example {"n0": "[0-9]+", "s1": "[a-z]+"}
+ + +### git.mirror + +Mirror git references between repositories + +`git.mirror(name, origin, destination, refspecs=['refs/heads/*'], prune=False, partial_fetch=False, description=None)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +name | `string`Migration name
+origin | `string`Indicates the URL of the origin git repository
+destination | `string`Indicates the URL of the destination git repository
+refspecs | `sequence of string`Represents a list of git refspecs to mirror between origin and destination. For example 'refs/heads/*:refs/remotes/origin/*' will mirror any reference inside refs/heads to refs/remotes/origin.
+prune | `boolean`Remove remote refs that don't have a origin counterpart
+partial_fetch | `boolean`Please DO NOT set it to True. This feature is not ready.
+description | `string`A description of what this workflow achieves
+ + + +**Command line flags:** + +Name | Type | Description +---- | ---- | ----------- +`--git-mirror-force` | *boolean* | Force push even if it is not fast-forward + + +### git.origin + +Defines a standard Git origin. For Git specific origins use: `github_origin` or `gerrit_origin`.Indicates the URL of the git repository
+ref | `string`Represents the default reference that will be used for reading the revision from the git repository. For example: 'master'
+submodules | `string`Download submodules. Valid values: NO, YES, RECURSIVE.
+include_branch_commit_logs | `boolean`Whether to include raw logs of branch commits in the migrated change message.WARNING: This field is deprecated in favor of 'first_parent' one. This setting *only* affects merge commits.
+first_parent | `boolean`If true, it only uses the first parent when looking for changes. Note that when disabled in ITERATIVE mode, it will try to do a migration for each change of the merged branch.
+partial_fetch | `boolean`Please DO NOT set it to True. This feature is not ready.
+patch | `transformation`Patch the checkout dir. The difference with `patch.apply` transformation is that here we can apply it using three-way
+describe_version | `boolean`Download tags and use 'git describe' to create two labels with a meaningful version:
- `GIT_DESCRIBE_CHANGE_VERSION`: The version for the change or changes being migrated. The value changes per change in `ITERATIVE` mode and will be the latest migrated change in `SQUASH` (In other words, doesn't include excluded changes). this is normally what users want to use.
- `GIT_DESCRIBE_REQUESTED_VERSION`: `git describe` for the requested/head version. Constant in `ITERATIVE` mode and includes filtered changes.
Select a custom version (tag)to migrate instead of 'ref'
+ + +### git.review_input + +Creates a review to be posted on Gerrit. + +`SetReviewInput git.review_input(labels={}, message=None)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +labels | `dict`The labels to post.
+message | `string`The message to be added as review comment.
+ + + +**Command line flags:** + +Name | Type | Description +---- | ---- | ----------- +`--gerrit-change-id` | *string* | ChangeId to use in the generated commit message. Use this flag if you want to reuse the same Gerrit review for an export. +`--gerrit-new-change` | *boolean* | Create a new change instead of trying to reuse an existing one. +`--gerrit-topic` | *string* | Gerrit topic to use + + + +## github_api_obj + +GitHub API endpoint implementation for feedback migrations and after migration hooks. + + +#### Fields: + +Name | Description +---- | ----------- +url | Return the URL of this endpoint. + + +### github_api_obj.add_label + +Add labels to a PR/issue + +`github_api_obj.add_label(number, labels)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +number | `integer`Pull Request number
+labels | `sequence of string`List of labels to add.
+ + +### github_api_obj.create_status + +Create or update a status for a commit. Returns the status created. + +`github_api_status_obj github_api_obj.create_status(sha, state, context, description, target_url=None)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +sha | `string`The SHA-1 for which we want to create or update the status
+state | `string`The state of the commit status: 'success', 'error', 'pending' or 'failure'
+context | `string`The context for the commit status. Use a value like 'copybara/import_successful' or similar
+description | `string`Description about what happened
+target_url | `string`Url with expanded information about the event
+ + +### github_api_obj.delete_reference + +Delete a reference. + +`github_api_obj.delete_reference(ref)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +ref | `string`The name of the reference.
+ + +### github_api_obj.get_authenticated_user + +Get autenticated user info, return null if not found + +`github_api_user_obj github_api_obj.get_authenticated_user()` + + +### github_api_obj.get_check_runs + +Get the list of check runs for a sha. https://developer.github.com/v3/checks/runs/#check-runs + +`github_check_runs_obj github_api_obj.get_check_runs(sha)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +sha | `string`The SHA-1 for which we want to get the check runs
+ + +### github_api_obj.get_combined_status + +Get the combined status for a commit. Returns None if not found. + +`github_api_combined_status_obj github_api_obj.get_combined_status(ref)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +ref | `string`The SHA-1 or ref for which we want to get the combined status
+ + +### github_api_obj.get_commit + +Get information for a commit in GitHub. Returns None if not found. + +`github_api_github_commit_obj github_api_obj.get_commit(ref)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +ref | `string`The SHA-1 for which we want to get the combined status
+ + +### github_api_obj.get_pull_request_comment + +Get a pull request comment + +`github_api_pull_request_comment_obj github_api_obj.get_pull_request_comment(comment_id)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +comment_id | `string`Comment identifier
+ + +### github_api_obj.get_pull_request_comments + +Get all pull request comments + +`sequence of github_api_pull_request_comment_obj github_api_obj.get_pull_request_comments(number)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +number | `integer`Pull Request number
+ + +### github_api_obj.get_pull_requests + +Get Pull Requests for a repo + +`immutableList<e> github_api_obj.get_pull_requests(head_prefix=None, base_prefix=None, state="OPEN", sort="CREATED", direction="ASC")` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +head_prefix | `string`Only return PRs wher the branch name has head_prefix
+base_prefix | `string`Only return PRs where the destination branch name has base_prefix
+state | `string`State of the Pull Request. Can be `"OPEN"`, `"CLOSED"` or `"ALL"`
+sort | `string`Sort filter for retrieving the Pull Requests. Can be `"CREATED"`, `"UPDATED"` or `"POPULARITY"`
+direction | `string`Direction of the filter. Can be `"ASC"` or `"DESC"`
+ + +### github_api_obj.get_reference + +Get a reference SHA-1 from GitHub. Returns None if not found. + +`github_api_ref_obj github_api_obj.get_reference(ref)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +ref | `string`The name of the reference. For example: "refs/heads/branchName".
+ + +### github_api_obj.get_references + +Get all the reference SHA-1s from GitHub. Note that Copybara only returns a maximum number of 500. + +`sequence of github_api_ref_obj github_api_obj.get_references()` + + +### github_api_obj.update_pull_request + +Update Pull Requests for a repo. Returns None if not found + +`github_api_pull_request_obj github_api_obj.update_pull_request(number, title=None, body=None, state=None)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +number | `integer`Pull Request number
+title | `string`New Pull Request title
+body | `string`New Pull Request body
+state | `string`State of the Pull Request. Can be `"OPEN"`, `"CLOSED"`
+ + +### github_api_obj.update_reference + +Update a reference to point to a new commit. Returns the info of the reference. + +`github_api_ref_obj github_api_obj.update_reference(ref, sha, force)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +ref | `string`The name of the reference.
+sha | `string`The id for the commit status.
+force | `boolean`Indicates whether to force the update or to make sure the update is a fast-forward update. Leaving this out or setting it to false will make sure you're not overwriting work. Default: false
+ + + +## Globals + +Global functions available in Copybara + + +### glob + +Glob returns a list of every file in the workdir that matches at least one pattern in include and does not match any of the patterns in exclude. + +`glob glob(include, exclude=[])` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +include | `sequence of string`The list of glob patterns to include
+exclude | `sequence of string`The list of glob patterns to exclude
+ + +#### Examples: + + +##### Simple usage: + +Include all the files under a folder except for `internal` folder files: + +```python +glob(["foo/**"], exclude = ["foo/internal/**"]) +``` + + +##### Multiple folders: + +Globs can have multiple inclusive rules: + +```python +glob(["foo/**", "bar/**", "baz/**.java"]) +``` + +This will include all files inside `foo` and `bar` folders and Java files inside `baz` folder. + + +##### Multiple excludes: + +Globs can have multiple exclusive rules: + +```python +glob(["foo/**"], exclude = ["foo/internal/**", "foo/confidential/**" ]) +``` + +Include all the files of `foo` except the ones in `internal` and `confidential` folders + + +##### All BUILD files recursively: + +Copybara uses Java globbing. The globbing is very similar to Bash one. This means that recursive globbing for a filename is a bit more tricky: + +```python +glob(["BUILD", "**/BUILD"]) +``` + +This is the correct way of matching all `BUILD` files recursively, including the one in the root. `**/BUILD` would only match `BUILD` files in subdirectories. + + +##### Matching multiple strings with one expression: + +While two globs can be used for matching two directories, there is a more compact approach: + +```python +glob(["{java,javatests}/**"]) +``` + +This matches any file in `java` and `javatests` folders. + + +##### Glob union: + +This is useful when you want to exclude a broad subset of files but you want to still include some of those files. + +```python +glob(["folder/**"], exclude = ["folder/**.excluded"]) + glob(['folder/includeme.excluded']) +``` + +This matches all the files in `folder`, excludes all files in that folder that ends with `.excluded` but keeps `folder/includeme.excluded`A string representation of the author with the form 'name
The contents of the change message
+ + + +## hg + +Set of functions to define Mercurial (Hg) origins and destinations. + + +### hg.origin + +EXPERIMENTAL: Defines a standard Mercurial (Hg) origin. + +`hgOrigin hg.origin(url, ref="default")` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +url | `string`Indicates the URL of the Hg repository
+ref | `string`Represents the default reference that will be used to read a revision from the repository. The reference defaults to `default`, the most recent revision on the default branch. References can be in a variety of formats:
The header text to include in the message. For example '[Import of foo ${LABEL}]'. This would construct a message resolving ${LABEL} to the corresponding label.
+ignore_label_not_found | `boolean`If a label used in the template is not found, ignore the error and don't add the header. By default it will stop the migration and fail.
+new_line | `boolean`If a new line should be added between the header and the original message. This allows to create messages like `HEADER: ORIGINAL_MESSAGE`
+ + +#### Examples: + + +##### Add a header always: + +Adds a header to any message + +```python +metadata.add_header("COPYBARA CHANGE") +``` + +Messages like: + +``` +A change + +Example description for +documentation +``` + +Will be transformed into: + +``` +COPYBARA CHANGE +A change + +Example description for +documentation +``` + + + + +##### Add a header that uses a label: + +Adds a header to messages that contain a label. Otherwise it skips the message manipulation. + +```python +metadata.add_header("COPYBARA CHANGE FOR https://github.com/myproject/foo/pull/${GITHUB_PR_NUMBER}", + ignore_label_not_found = True, +) +``` + +A change message, imported using git.github_pr_origin, like: + +``` +A change + +Example description for +documentation +``` + +Will be transformed into: + +``` +COPYBARA CHANGE FOR https://github.com/myproject/foo/pull/1234 +Example description for +documentation +``` + +Assuming the PR number is 1234. But any change without that label will not be transformed. + + +##### Add a header without new line: + +Adds a header without adding a new line before the original message: + +```python +metadata.add_header("COPYBARA CHANGE: ", new_line = False) +``` + +Messages like: + +``` +A change + +Example description for +documentation +``` + +Will be transformed into: + +``` +COPYBARA CHANGE: A change + +Example description for +documentation +``` + + + + + +### metadata.expose_label + +Certain labels are present in the internal metadata but are not exposed in the message by default. This transformations find a label in the internal metadata and exposes it in the message. If the label is already present in the message it will update it to use the new name and separator. + +`transformation metadata.expose_label(name, new_name=label, separator="=", ignore_label_not_found=True, all=False)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +name | `string`The label to search
+new_name | `string`The name to use in the message
+separator | `string`The separator to use when adding the label to the message
+ignore_label_not_found | `boolean`If a label is not found, ignore the error and continue.
+all | `boolean`By default Copybara tries to find the most relevant instance of the label. First looking into the message and then looking into the changes in order. If this field is true it exposes all the matches instead.
+ + +#### Examples: + + +##### Simple usage: + +Expose a hidden label called 'REVIEW_URL': + +```python +metadata.expose_label('REVIEW_URL') +``` + +This would add it as `REVIEW_URL=the_value`. + + +##### New label name: + +Expose a hidden label called 'REVIEW_URL' as GIT_REVIEW_URL: + +```python +metadata.expose_label('REVIEW_URL', 'GIT_REVIEW_URL') +``` + +This would add it as `GIT_REVIEW_URL=the_value`. + + +##### Custom separator: + +Expose the label with a custom separator + +```python +metadata.expose_label('REVIEW_URL', separator = ': ') +``` + +This would add it as `REVIEW_URL: the_value`. + + +##### Expose multiple labels: + +Expose all instances of a label in all the changes (SQUASH for example) + +```python +metadata.expose_label('REVIEW_URL', all = True) +``` + +This would add 0 or more `REVIEW_URL: the_value` labels to the message. + + + +### metadata.map_author + +Map the author name and mail to another author. The mapping can be done by both name and mail or only using any of the two. + +`transformation metadata.map_author(authors, reversible=False, noop_reverse=False, fail_if_not_found=False, reverse_fail_if_not_found=False, map_all_changes=False)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +authors | `dict`The author mapping. Keys can be in the form of 'Your Name', 'some@mail' or 'Your Name
If the transform is automatically reversible. Workflows using the reverse of this transform will be able to automatically map values to keys.
+noop_reverse | `boolean`If true, the reversal of the transformation doesn't do anything. This is useful to avoid having to write `core.transformation(metadata.map_author(...), reversal = [])`.
+fail_if_not_found | `boolean`Fail if a mapping cannot be found. Helps discovering early authors that should be in the map
+reverse_fail_if_not_found | `boolean`Same as fail_if_not_found but when the transform is used in a inverse workflow.
+map_all_changes | `boolean`If all changes being migrated should be mapped. Useful for getting a mapped metadata.squash_notes. By default we only map the current author.
+ + +#### Example: + + +##### Map some names, emails and complete authors: + +Here we show how to map authors using different options: + +```python +metadata.map_author({ + 'john' : 'Some PersonTemplate for origin references in the change message. Use a '${reference}' token to capture the actual references. E.g. if the origin uses linkslike 'http://changes?1234', the template would be 'http://internalReviews.com/${reference}', with reference_regex = '[0-9]+'
+after | `string`Format for references in the destination, use the token '${reference}' to represent the destination reference. E.g. 'http://changes(${reference})'.
+regex_groups | `dict`Regexes for the ${reference} token's content. Requires one 'before_ref' entry matching the ${reference} token's content on the before side. Optionally accepts one 'after_ref' used for validation. Copybara uses [re2](https://github.com/google/re2/wiki/Syntax) syntax.
+additional_import_labels | `sequence of string`Meant to be used when migrating from another tool: Per default, copybara will only recognize the labels defined in the workflow's endpoints. The tool will use these additional labels to find labels created by other invocations and tools.
+ + +#### Example: + + +##### Map references, origin source of truth: + +Finds links to commits in change messages, searches destination to find the equivalent reference in destination. Then replaces matches of 'before' with 'after', replacing the subgroup matched with the destination reference. Assume a message like 'Fixes bug introduced in origin/abcdef', where the origin change 'abcdef' was migrated as '123456' to the destination. + +```python +metadata.map_references( + before = "origin/${reference}", + after = "destination/${reference}", + regex_groups = { + "before_ref": "[0-9a-f]+", + "after_ref": "[0-9]+", + }, +) +``` + +This would be translated into 'Fixes bug introduced in destination/123456', provided that a change with the proper label was found - the message remains unchanged otherwise. + + + +### metadata.remove_label + +Remove a label from the message + +`transformation metadata.remove_label(name)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +name | `string`The label name
+ + +#### Example: + + +##### Remove a label: + +Remove Change-Id label from the message: + +```python +metadata.remove_label('Change-Id') +``` + + + +### metadata.replace_message + +Replace the change message with a template text. Any variable present in the message in the form of ${LABEL_NAME} will be replaced by the corresponding label in the message. Note that this requires that the label is already in the message or in any of the changes being imported. The label in the message takes priority over the ones in the list of original messages of changes imported. + + +`transformation metadata.replace_message(text, ignore_label_not_found=False)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +text | `string`The template text to use for the message. For example '[Import of foo ${LABEL}]'. This would construct a message resolving ${LABEL} to the corresponding label.
+ignore_label_not_found | `boolean`If a label used in the template is not found, ignore the error and don't add the header. By default it will stop the migration and fail.
+ + +#### Example: + + +##### Replace the message: + +Replace the original message with a text: + +```python +metadata.replace_message("COPYBARA CHANGE: Import of ${GITHUB_PR_NUMBER}\n\n${GITHUB_PR_BODY}\n") +``` + +Will transform the message to: + +``` +COPYBARA CHANGE: Import of 12345 +Body from Github Pull Request +``` + + + + + +### metadata.restore_author + +For a given change, restore the author present in the ORIGINAL_AUTHOR label as the author of the change. + +`transformation metadata.restore_author(label='ORIGINAL_AUTHOR', search_all_changes=False)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +label | `string`The label to use for restoring the author
+search_all_changes | `boolean`By default Copybara only looks in the last current change for the author label. This allows to do the search in all current changes (Only makes sense for SQUASH/CHANGE_REQUEST).
+ + +### metadata.save_author + +For a given change, store a copy of the author as a label with the name ORIGINAL_AUTHOR. + +`transformation metadata.save_author(label='ORIGINAL_AUTHOR')` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +label | `string`The label to use for storing the author
+ + +### metadata.scrubber + +Removes part of the change message using a regex + +`transformation metadata.scrubber(regex, msg_if_no_match=None, fail_if_no_match=False, replacement='')` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +regex | `string`Any text matching the regex will be removed. Note that the regex is runs in multiline mode.
+msg_if_no_match | `string`If set, Copybara will use this text when the scrubbing regex doesn't match.
+fail_if_no_match | `boolean`If set, msg_if_no_match must be None and then fail if the scrubbing regex doesn't match.
+replacement | `string`Text replacement for the matching substrings. References to regex group numbers can be used in the form of $1, $2, etc.
+ + +#### Examples: + + +##### Remove from a keyword to the end of the message: + +When change messages are in the following format: + +``` +Public change description + +This is a public description for a commit + +CONFIDENTIAL: +This fixes internal project foo-bar +``` + +Using the following transformation: + +```python +metadata.scrubber('(^|\n)CONFIDENTIAL:(.|\n)*') +``` + +Will remove the confidential part, leaving the message as: + +``` +Public change description + +This is a public description for a commit +``` + + + + +##### Keep only message enclosed in tags: + +The previous example is prone to leak confidential information since a developer could easily forget to include the CONFIDENTIAL label. A different approach for this is to scrub everything by default except what is explicitly allowed. For example, the following scrubber would remove anything not enclosed inA prefix to be printed before the list of commits.
+max | `integer`Max number of commits to include in the message. For the rest a comment like (and x more) will be included. By default 100 commits are included.
+compact | `boolean`If compact is set, each change will be shown in just one line
+show_ref | `boolean`If each change reference should be present in the notes
+show_author | `boolean`If each change author should be present in the notes
+show_description | `boolean`If each change description should be present in the notes
+oldest_first | `boolean`If set to true, the list shows the oldest changes first. Otherwise it shows the changes in descending order.
+use_merge | `boolean`If true then merge changes are included in the squash notes
+ + +#### Examples: + + +##### Simple usage: + +'Squash notes' default is to print one line per change with information about the author + +```python +metadata.squash_notes("Changes for Project Foo:\n") +``` + +This transform will generate changes like: + +``` +Changes for Project Foo: + + - 1234abcde second commit description by Foo BarReplace author with the last change author (Could still be the default author if not whitelisted or using `authoring.overwrite`.
+message | `boolean`Replace message with last change message.
+default_message | `string`Replace message with last change message.
+use_merge | `boolean`If true then merge changes are taken into account for looking for the last change.
+ + +### metadata.verify_match + +Verifies that a RegEx matches (or not matches) the change message. Does not transform anything, but will stop the workflow if it fails. + +`transformation metadata.verify_match(regex, verify_no_match=False)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +regex | `string`The regex pattern to verify. The re2j pattern will be applied in multiline mode, i.e. '^' refers to the beginning of a file and '$' to its end.
+verify_no_match | `boolean`If true, the transformation will verify that the RegEx does not match.
+ + +#### Example: + + +##### Check that a text is present in the change description: + +Check that the change message contains a text enclosed inThe list of patchfiles to apply, relative to the current config file.The files will be applied relative to the checkout dir and the leading pathcomponent will be stripped (-p1).
This field can be combined with 'series'. Both 'patches' and 'series' will be applied in order (patches first). **This field doesn't accept a glob**
The list of paths to exclude from each of the patches. Each of the paths will be excluded from all the patches. Note that these are not workdir paths, but paths relative to the patch itself. If not empty, the patch will be applied using 'git apply' instead of GNU Patch.
+series | `string`The config file that contains a list of patches to apply. The series file contains names of the patch files one per line. The names of the patch files are relative to the series config file. The files will be applied relative to the checkout dir and the leading path component will be stripped (-p1).:
:
This field can be combined with 'patches'. Both 'patches' and 'series' will be applied in order (patches first).
Number of segments to strip. (This sets -pX flag, for example -p0, -p1, etc.).By default it uses -p1
+ + + +**Command line flags:** + +Name | Type | Description +---- | ---- | ----------- +`--patch-bin` | *string* | Path for GNU Patch command +`--patch-skip-version-check` | *boolean* | Skip checking the version of patch and assume it is fine +`--patch-use-git-apply` | *boolean* | Don't use GNU Patch and instead use 'git apply' + + + +## Path + +Represents a path in the checkout directory + + +#### Fields: + +Name | Description +---- | ----------- +attr | Get the file attributes, for example size. +name | Filename of the path. For foo/bar/baz.txt it would be baz.txt +parent | Get the parent path +path | Full path relative to the checkout directory + + +### path.read_symlink + +Read the symlink + +`Path path.read_symlink()` + + +### path.relativize + +Constructs a relative path between this path and a given path. For example:The path to relativize against this path
+ + +### path.resolve + +Resolve the given path against this path. + +`Path path.resolve(child)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +child | `object`Resolve the given path against this path. The parameter can be a string or a Path.
+ + +### path.resolve_sibling + +Resolve the given path against this path. + +`Path path.resolve_sibling(other)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +other | `object`Resolve the given path against this path. The parameter can be a string or a Path.
+ + + +## PathAttributes + +Represents a path attributes like size. + + +#### Fields: + +Name | Description +---- | ----------- +size | The size of the file. Throws an error if file size > 2GB. +symlink | Returns true if it is a symlink + + + +## SetReviewInput + +Input for posting a review to Gerrit. See https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#review-input + + + +## TransformWork + +Data about the set of changes that are being migrated. It includes information about changes like: the author to be used for commit, change message, etc. You receive a TransformWork object as an argument to thetransformations
functions used in core.workflow
+
+
+#### Fields:
+
+Name | Description
+---- | -----------
+author | Author to be used in the change
+changes | List of changes that will be migrated
+console | Get an instance of the console to report errors or warnings
+message | Message to be used in the change
+params | Parameters for the function if created with core.dynamic_transform
+
+
+### ctx.add_label
+
+Add a label to the end of the description
+
+`ctx.add_label(label, value, separator="=", hidden=False)`
+
+
+#### Parameters:
+
+Parameter | Description
+--------- | -----------
+label | `string`The label to replace
+value | `string`The new value for the label
+separator | `string`The separator to use for the label
+hidden | `boolean`Don't show the label in the message but only keep it internally
+ + +### ctx.add_or_replace_label + +Replace an existing label or add it to the end of the description + +`ctx.add_or_replace_label(label, value, separator="=")` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +label | `string`The label to replace
+value | `string`The new value for the label
+separator | `string`The separator to use for the label
+ + +### ctx.add_text_before_labels + +Add a text to the description before the labels paragraph + +`ctx.add_text_before_labels(text)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +text | `string`The link path
+target | `Path`The target path
+ + +### ctx.destination_api + +Returns an api handle for the destination repository. Methods available depend on the destination type. Use with extreme caution, as external calls can make workflow non-deterministic and possibly irreversible. Can have side effects in dry-runmode. + +`endpoint ctx.destination_api()` + + +### ctx.destination_reader + +Returns a handle to read files from the destination, if supported by the destination. + +`destination_reader ctx.destination_reader()` + + +### ctx.find_all_labels + +Tries to find all the values for a label. First it looks at the generated message (IOW labels that might have been added by previous steps), then looks in all the commit messages being imported and finally in the resolved reference passed in the CLI. + +`sequence of string ctx.find_all_labels(message)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +message | `string`The string representing the path
+ + +### ctx.now_as_string + +Get current date as a string + +`string ctx.now_as_string(format="yyyy-MM-dd", zone="UTC")` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +format | `string`The format to use. See: https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html for details.
+zone | `object`The timezone id to use. See https://docs.oracle.com/javase/8/docs/api/java/time/ZoneId.html. By default UTC
+ + +### ctx.origin_api + +Returns an api handle for the origin repository. Methods available depend on the origin type. Use with extreme caution, as external calls can make workflow non-deterministic and possibly irreversible. Can have side effects in dry-runmode. + +`endpoint ctx.origin_api()` + + +### ctx.read_path + +Read the content of path as UTF-8 + +`string ctx.read_path(path)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +path | `Path`The string representing the path
+ + +### ctx.remove_label + +Remove a label from the message if present + +`ctx.remove_label(label, whole_message=False)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +label | `string`The label to delete
+whole_message | `boolean`By default Copybara only looks in the last paragraph for labels. This flagmake it replace labels in the whole message.
+ + +### ctx.replace_label + +Replace a label if it exist in the message + +`ctx.replace_label(label, value, separator="=", whole_message=False)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +label | `string`The label to replace
+value | `string`The new value for the label
+separator | `string`The separator to use for the label
+whole_message | `boolean`By default Copybara only looks in the last paragraph for labels. This flagmake it replace labels in the whole message.
+ + +### ctx.run + +Run a glob or a transform. For example:files = ctx.run(glob(['**.java']))
ctx.run(core.move("foo", "bar"))
A glob or a transform (Transforms still not implemented)
+ + +### ctx.set_author + +Update the author to be used in the change + +`ctx.set_author(author)` + + +#### Parameters: + +Parameter | Description +--------- | ----------- +author | `author`The string representing the path
+content | `string`The content of the file
+ + diff --git a/third_party/copybara/java/com/google/copybara/BUILD b/third_party/copybara/java/com/google/copybara/BUILD new file mode 100644 index 0000000000..3940bf0837 --- /dev/null +++ b/third_party/copybara/java/com/google/copybara/BUILD @@ -0,0 +1,219 @@ +# Copyright 2016 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +licenses(["notice"]) # Apache 2.0 + +package(default_visibility = ["//visibility:public"]) + +load(":docs.bzl", "doc_generator") + +exports_files( + [ + "doc_skylark.sh", + "docs.bzl", + ], + visibility = ["//visibility:public"], +) + +JAVACOPTS = [ + "-Xlint:unchecked", + "-source", + "1.8", +] + +java_binary( + name = "copybara", + javacopts = JAVACOPTS, + main_class = "com.google.copybara.Main", + runtime_deps = [ + ":copybara_main", + ], +) + +java_library( + name = "copybara_main", + srcs = ["Main.java"], + javacopts = JAVACOPTS, + deps = [ + ":base", + ":copybara_lib", + ":general_options", + "//java/com/google/copybara/config:base", + "//java/com/google/copybara/exception", + "//java/com/google/copybara/jcommander:converters", + "//java/com/google/copybara/profiler", + "//java/com/google/copybara/util", + "//java/com/google/copybara/util/console", + "//third_party:flogger", + "//third_party:guava", + "//third_party:jcommander", + "//third_party:jsr305", + "//third_party:skylark-lang", + ], +) + +doc_generator( + name = "docs", + deps = [":copybara"], +) + +BASE_SRCS = [ + "BaselinesWithoutLabelVisitor.java", + "Change.java", + "ChangeMessage.java", + "Changes.java", + "ChangeVisitable.java", + "CheckoutPath.java", + "CheckoutPathAttributes.java", + "ConfigItemDescription.java", + "Destination.java", + "DestinationEffect.java", + "DestinationReader.java", + "DestinationStatusVisitor.java", + "Endpoint.java", + "EndpointProvider.java", + "Info.java", + "LazyResourceLoader.java", + "LabelFinder.java", + "LocalParallelizer.java", + "Metadata.java", + "MigrationInfo.java", + "NonReversibleValidationException.java", + "Option.java", + "Options.java", + "Origin.java", + "Revision.java", + "SkylarkContext.java", + "Transformation.java", + "TransformResult.java", + "TransformWork.java", + "Trigger.java", + "treestate/FileSystemTreeState.java", + "treestate/MapBasedTreeState.java", + "treestate/TreeState.java", + "treestate/TreeStateUtil.java", + "WorkflowOptions.java", + "WriterContext.java", +] + +java_library( + name = "options", + srcs = [ + "Option.java", + "Options.java", + ], + javacopts = JAVACOPTS, + deps = [ + "//third_party:guava", + "//third_party:jsr305", + "//third_party:re2j", + "//third_party:shell", + ], +) + +java_library( + name = "moduleset", + srcs = ["ModuleSet.java"], + javacopts = JAVACOPTS, + deps = [ + ":options", + "//third_party:guava", + ], +) + +java_library( + name = "base", + srcs = BASE_SRCS, + javacopts = JAVACOPTS, + deps = [ + "//java/com/google/copybara/authoring", + "//java/com/google/copybara/doc:annotations", + "//java/com/google/copybara/exception", + "//java/com/google/copybara/jcommander:converters", + "//java/com/google/copybara/jcommander:validators", + "//java/com/google/copybara/util", + "//java/com/google/copybara/util/console", + "//third_party:autovalue", + "//third_party:flogger", + "//third_party:guava", + "//third_party:jcommander", + "//third_party:jsr305", + "//third_party:re2j", + "//third_party:skylark-lang", + ], +) + +java_library( + name = "general_options", + srcs = ["GeneralOptions.java"], + javacopts = JAVACOPTS, + deps = [ + ":base", + "//java/com/google/copybara/exception", + "//java/com/google/copybara/jcommander:converters", + "//java/com/google/copybara/monitor", + "//java/com/google/copybara/profiler", + "//java/com/google/copybara/util", + "//java/com/google/copybara/util/console", + "//third_party:autovalue", + "//third_party:flogger", + "//third_party:guava", + "//third_party:jcommander", + "//third_party:jsr305", + "//third_party:re2j", + "//third_party:skylark-lang", + ], +) + +java_library( + name = "copybara_lib", + srcs = glob( + ["**/*.java"], + exclude = [ + "Main.java", + "GeneralOptions.java", + ] + BASE_SRCS, + ), + javacopts = JAVACOPTS, + deps = [ + ":base", + ":general_options", + "//java/com/google/copybara/authoring", + "//java/com/google/copybara/buildozer", + "//java/com/google/copybara/buildozer:buildozer_options", + "//java/com/google/copybara/config:base", + "//java/com/google/copybara/config:global_migrations", + "//java/com/google/copybara/config:parser", + "//java/com/google/copybara/doc:annotations", + "//java/com/google/copybara/exception", + "//java/com/google/copybara/format", + "//java/com/google/copybara/git", + "//java/com/google/copybara/hg", + "//java/com/google/copybara/monitor", + "//java/com/google/copybara/profiler", + "//java/com/google/copybara/remotefile", + "//java/com/google/copybara/templatetoken", + "//java/com/google/copybara/transform", + "//java/com/google/copybara/transform/debug", + "//java/com/google/copybara/transform/patch", + "//java/com/google/copybara/util", + "//java/com/google/copybara/util/console", + "//third_party:flogger", + "//third_party:guava", + "//third_party:jcommander", + "//third_party:jsr305", + "//third_party:re2j", + "//third_party:skylark-lang", + ], +) diff --git a/third_party/copybara/java/com/google/copybara/BaselinesWithoutLabelVisitor.java b/third_party/copybara/java/com/google/copybara/BaselinesWithoutLabelVisitor.java new file mode 100644 index 0000000000..327c9143ab --- /dev/null +++ b/third_party/copybara/java/com/google/copybara/BaselinesWithoutLabelVisitor.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2018 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.copybara; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.copybara.ChangeVisitable.ChangesVisitor; +import com.google.copybara.ChangeVisitable.VisitResult; +import com.google.copybara.util.Glob; +import java.util.ArrayList; +import java.util.List; + +/** A visitor that finds all the parents that match the origin glob. */ +public class BaselinesWithoutLabelVisitorThis class is immutable.
+ */
+@SuppressWarnings("unused")
+@StarlarkBuiltin(
+ name = "ChangeMessage",
+ category = StarlarkDocumentationCategory.BUILTIN,
+ doc = "Represents a well formed parsed change message with its associated labels.")
+@DocSignaturePrefix("message")
+public final class ChangeMessage implements StarlarkValue {
+
+ private static final String DOUBLE_NEWLINE = "\n\n";
+ private static final String DASH_DASH_SEPARATOR = "\n--\n";
+ private static final CharMatcher TRIM = CharMatcher.is('\n');
+
+ private final String text;
+ private final String groupSeparator;
+ private final ImmutableList Use this for Copybara well-formed messages.
+ */
+ public static ChangeMessage parseMessage(String message) {
+ String trimMsg = TRIM.trimFrom(message);
+ int doubleNewLine = trimMsg.lastIndexOf(DOUBLE_NEWLINE);
+ int dashDash = trimMsg.lastIndexOf(DASH_DASH_SEPARATOR);
+ if (doubleNewLine == -1 && dashDash == -1) {
+ // Empty message like "\n\nfoo: bar" or "\n\nfoo bar baz"
+ if (message.startsWith(DOUBLE_NEWLINE)) {
+ return new ChangeMessage("", DOUBLE_NEWLINE, linesAsLabels(trimMsg));
+ }
+ return new ChangeMessage(trimMsg, DOUBLE_NEWLINE, new ArrayList<>());
+ } else if (doubleNewLine > dashDash) {
+ return new ChangeMessage(trimMsg.substring(0, doubleNewLine), DOUBLE_NEWLINE,
+ linesAsLabels(trimMsg.substring(doubleNewLine + 2)));
+ } else {
+ return new ChangeMessage(trimMsg.substring(0, dashDash), DASH_DASH_SEPARATOR,
+ linesAsLabels(trimMsg.substring(dashDash + 4)));
+ }
+ }
+
+ /**
+ * Create a new message object treating all the lines as possible labels instead of looking
+ * just in the last paragraph for labels.
+ */
+ public static ChangeMessage parseAllAsLabels(String message) {
+ Preconditions.checkNotNull(message);
+ return new ChangeMessage("", DOUBLE_NEWLINE, linesAsLabels(message));
+ }
+
+ private static List It is up to the Origin how and what changes it provides to the function.
+ */
+ void visitChanges(@Nullable R start, ChangesVisitor visitor)
+ throws RepoException, ValidationException;
+
+ /**
+ * Visit only changes that contain any of the labels in {@code labels}.
+ */
+ default void visitChangesWithAnyLabel(
+ @Nullable R start, ImmutableCollection Note that the {@code matchedLabels} can be disjoint with the labels in {@code input},
+ * since labels might be stored with a different string format.
+ */
+ VisitResult visit(Change extends Revision> input, ImmutableMap Files are always relative to the checkout dir and normalized.
+ */
+@SuppressWarnings("unused")
+@StarlarkBuiltin(
+ name = "Path",
+ category = StarlarkDocumentationCategory.BUILTIN,
+ doc = "Represents a path in the checkout directory")
+@DocSignaturePrefix("path")
+public class CheckoutPath implements Comparable This method is provided for convenience, for subocmmands that only care about the first
+ * source_ref.
+ */
+ @Nullable
+ public String getSourceRef() {
+ return Iterables.getFirst(sourceRefs, /*default*/ null);
+ }
+
+ public ImmutableList This class is exposed in Skylark configuration as an instance variable called "core". So users
+ * can use it as:
+ *
+ * `before` can only contain 1 reference to each"
+ + " unique `regex_group`. If you require multiple references to the same"
+ + " `regex_group`, add `repeated_groups: True`. If '$' literal character"
+ + " needs to be matched, '`$$`' should be used. For example '`$$FOO`' would"
+ + " match the literal '$FOO'."),
+ @Param(
+ name = "after",
+ named = true,
+ type = String.class,
+ doc =
+ "The text after the transformation. It can also contain references to regex "
+ + "groups, like 'before' field."),
+ @Param(
+ name = "regex_groups",
+ named = true,
+ type = Dict.class,
+ doc =
+ "A set of named regexes that can be used to match part of the replaced text."
+ + "Copybara uses [re2](https://github.com/google/re2/wiki/Syntax) syntax."
+ + " For example {\"x\": \"[A-Za-z]+\"}",
+ defaultValue = "{}"),
+ @Param(
+ name = "paths",
+ named = true,
+ type = Glob.class,
+ doc =
+ "A glob expression relative to the workdir representing the files to apply the"
+ + " transformation. For example, glob([\"**.java\"]), matches all java files"
+ + " recursively. Defaults to match all the files recursively.",
+ defaultValue = "None",
+ noneable = true),
+ @Param(
+ name = "first_only",
+ named = true,
+ type = Boolean.class,
+ doc =
+ "If true, only replaces the first instance rather than all. In single line mode,"
+ + " replaces the first instance on each line. In multiline mode, replaces the"
+ + " first instance in each file.",
+ defaultValue = "False"),
+ @Param(
+ name = "multiline",
+ named = true,
+ type = Boolean.class,
+ doc = "Whether to replace text that spans more than one line.",
+ defaultValue = "False"),
+ @Param(
+ name = "repeated_groups",
+ named = true,
+ type = Boolean.class,
+ doc =
+ "Allow to use a group multiple times. For example foo${repeated}/${repeated}. Note"
+ + " that this mechanism doesn't use backtracking. In other words, the group"
+ + " instances are treated as different groups in regex construction and then a"
+ + " validation is done after that.",
+ defaultValue = "False"),
+ @Param(
+ name = "ignore",
+ named = true,
+ type = com.google.devtools.build.lib.syntax.Sequence.class,
+ doc =
+ "A set of regexes. Any text that matches any expression in this set, which"
+ + " might otherwise be transformed, will be ignored.",
+ defaultValue = "[]"),
+ },
+ useStarlarkThread = true)
+ @DocDefault(field = "paths", value = "glob([\"**\"])")
+ @Example(
+ title = "Simple replacement",
+ before = "Replaces the text \"internal\" with \"external\" in all java files",
+ code =
+ "core.replace(\n"
+ + " before = \"internal\",\n"
+ + " after = \"external\",\n"
+ + " paths = glob([\"**.java\"]),\n"
+ + ")")
+ @Example(
+ title = "Append some text at the end of files",
+ before = "",
+ code =
+ "core.replace(\n"
+ + " before = '${end}',\n"
+ + " after = 'Text to be added at the end',\n"
+ + " multiline = True,\n"
+ + " regex_groups = { 'end' : '\\z'},\n"
+ + ")")
+ @Example(
+ title = "Append some text at the end of files reversible",
+ before = "Same as the above example but make the transformation reversible",
+ code =
+ "core.transform([\n"
+ + " core.replace(\n"
+ + " before = '${end}',\n"
+ + " after = 'some append',\n"
+ + " multiline = True,\n"
+ + " regex_groups = { 'end' : '\\z'},\n"
+ + " )\n"
+ + "],\n"
+ + "reversal = [\n"
+ + " core.replace(\n"
+ + " before = 'some append${end}',\n"
+ + " after = '',\n"
+ + " multiline = True,\n"
+ + " regex_groups = { 'end' : '\\z'},\n"
+ + " )"
+ + "])")
+ @Example(
+ title = "Replace using regex groups",
+ before =
+ "In this example we map some urls from the internal to the external version in"
+ + " all the files of the project.",
+ code =
+ "core.replace(\n"
+ + " before = \"https://some_internal/url/${pkg}.html\",\n"
+ + " after = \"https://example.com/${pkg}.html\",\n"
+ + " regex_groups = {\n"
+ + " \"pkg\": \".*\",\n"
+ + " },\n"
+ + " )",
+ after =
+ "So a url like `https://some_internal/url/foo/bar.html` will be transformed to"
+ + " `https://example.com/foo/bar.html`.")
+ @Example(
+ title = "Remove confidential blocks",
+ before =
+ "This example removes blocks of text/code that are confidential and thus shouldn't"
+ + "be exported to a public repository.",
+ code =
+ "core.replace(\n"
+ + " before = \"${x}\",\n"
+ + " after = \"\",\n"
+ + " multiline = True,\n"
+ + " regex_groups = {\n"
+ + " \"x\": \"(?m)^.*BEGIN-INTERNAL[\\\\w\\\\W]*?END-INTERNAL.*$\\\\n\",\n"
+ + " },\n"
+ + " )",
+ after =
+ "This replace would transform a text file like:\n\n"
+ + "```\n"
+ + "This is\n"
+ + "public\n"
+ + " // BEGIN-INTERNAL\n"
+ + " confidential\n"
+ + " information\n"
+ + " // END-INTERNAL\n"
+ + "more public code\n"
+ + " // BEGIN-INTERNAL\n"
+ + " more confidential\n"
+ + " information\n"
+ + " // END-INTERNAL\n"
+ + "```\n\n"
+ + "Into:\n\n"
+ + "```\n"
+ + "This is\n"
+ + "public\n"
+ + "more public code\n"
+ + "```\n\n")
+ public Replace replace(
+ String before,
+ String after,
+ Dict, ?> regexes, //
"
+ + " path('a/b').relativize('a/b/c/d')
"
+ + "returns 'c/d'",
+ parameters = {
+ @Param(
+ name = "other",
+ type = CheckoutPath.class,
+ doc = "The path to relativize against this path"),
+ })
+ public CheckoutPath relativize(CheckoutPath other) throws EvalException {
+ return create(path.relativize(other.path));
+ }
+
+ @StarlarkMethod(
+ name = "resolve",
+ doc = "Resolve the given path against this path.",
+ parameters = {
+ @Param(
+ name = "child",
+ type = Object.class,
+ doc =
+ "Resolve the given path against this path. The parameter"
+ + " can be a string or a Path.")
+ })
+ public CheckoutPath resolve(Object child) throws EvalException {
+ if (child instanceof String) {
+ return create(path.resolve((String) child));
+ } else if (child instanceof CheckoutPath) {
+ return create(path.resolve(((CheckoutPath) child).path));
+ }
+ throw Starlark.errorf(
+ "Cannot resolve children for type %s: %s", child.getClass().getSimpleName(), child);
+ }
+
+ @StarlarkMethod(
+ name = "resolve_sibling",
+ doc = "Resolve the given path against this path.",
+ parameters = {
+ @Param(
+ name = "other",
+ type = Object.class,
+ doc =
+ "Resolve the given path against this path. The parameter can be a string or"
+ + " a Path."),
+ })
+ public CheckoutPath resolveSibling(Object other) throws EvalException {
+ if (other instanceof String) {
+ return create(path.resolveSibling((String) other));
+ } else if (other instanceof CheckoutPath) {
+ return create(path.resolveSibling(((CheckoutPath) other).path));
+ }
+ throw Starlark.errorf(
+ "Cannot resolve sibling for type %s: %s", other.getClass().getSimpleName(), other);
+ }
+
+ @StarlarkMethod(
+ name = "attr",
+ doc = "Get the file attributes, for example size.",
+ structField = true)
+ public CheckoutPathAttributes attr() throws EvalException {
+ try {
+ return new CheckoutPathAttributes(path,
+ Files.readAttributes(checkoutDir.resolve(path), BasicFileAttributes.class,
+ LinkOption.NOFOLLOW_LINKS));
+ } catch (IOException e) {
+ String msg = "Error getting attributes for " + path + ":" + e;
+ logger.atSevere().withCause(e).log(msg);
+ throw Starlark.errorf("%s", msg); // or IOException?
+ }
+ }
+
+ @StarlarkMethod(name = "read_symlink", doc = "Read the symlink")
+ public CheckoutPath readSymbolicLink() throws EvalException {
+ try {
+ Path symlinkPath = checkoutDir.resolve(path);
+ if (!Files.isSymbolicLink(symlinkPath)) {
+ throw Starlark.errorf("%s is not a symlink", path);
+ }
+
+ ResolvedSymlink resolvedSymlink =
+ FileUtil.resolveSymlink(Glob.ALL_FILES.relativeTo(checkoutDir), symlinkPath);
+ if (!resolvedSymlink.isAllUnderRoot()) {
+ throw Starlark.errorf(
+ "Symlink %s points to a file outside the checkout dir: %s",
+ symlinkPath, resolvedSymlink.getRegularFile());
+ }
+
+ return create(checkoutDir.relativize(resolvedSymlink.getRegularFile()));
+ } catch (IOException e) {
+ String msg = String.format("Cannot resolve symlink %s: %s", path, e);
+ logger.atSevere().withCause(e).log(msg);
+ throw Starlark.errorf("%s", msg);
+ }
+ }
+
+ public Path getPath() {
+ return path;
+ }
+
+ @Override
+ public String toString() {
+ return path.toString();
+ }
+
+ @Override
+ public int compareTo(CheckoutPath o) {
+ return this.path.compareTo(o.path);
+ }
+
+ @Override
+ public void repr(Printer printer) {
+ printer.append(path.toString());
+ }
+}
diff --git a/third_party/copybara/java/com/google/copybara/CheckoutPathAttributes.java b/third_party/copybara/java/com/google/copybara/CheckoutPathAttributes.java
new file mode 100644
index 0000000000..19486eeef1
--- /dev/null
+++ b/third_party/copybara/java/com/google/copybara/CheckoutPathAttributes.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.copybara;
+
+import com.google.common.base.Preconditions;
+import com.google.devtools.build.lib.skylarkinterface.StarlarkBuiltin;
+import com.google.devtools.build.lib.skylarkinterface.StarlarkDocumentationCategory;
+import com.google.devtools.build.lib.skylarkinterface.StarlarkMethod;
+import com.google.devtools.build.lib.syntax.Starlark;
+import com.google.devtools.build.lib.syntax.StarlarkValue;
+import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
+
+/** Represents file attributes exposed to Skylark. */
+@SuppressWarnings("unused")
+@StarlarkBuiltin(
+ name = "PathAttributes",
+ category = StarlarkDocumentationCategory.BUILTIN,
+ doc = "Represents a path attributes like size.")
+public class CheckoutPathAttributes implements StarlarkValue {
+
+ private final Path path;
+ private final BasicFileAttributes attributes;
+
+ CheckoutPathAttributes(Path path, BasicFileAttributes attributes) {
+ this.path = Preconditions.checkNotNull(path);
+ this.attributes = Preconditions.checkNotNull(attributes);
+ }
+
+ @StarlarkMethod(
+ name = "size",
+ doc = "The size of the file. Throws an error if file size > 2GB.",
+ structField = true)
+ public int size() throws Exception {
+ long size = attributes.size();
+ try {
+ return Math.toIntExact(size);
+ } catch (ArithmeticException e) {
+ throw Starlark.errorf("File %s is too big to compute the size: %d bytes", path, size);
+ }
+ }
+
+ @StarlarkMethod(name = "symlink",
+ doc = "Returns true if it is a symlink", structField = true)
+ public boolean isSymlink() {
+ return attributes.isSymbolicLink();
+ }
+}
diff --git a/third_party/copybara/java/com/google/copybara/CommandEnv.java b/third_party/copybara/java/com/google/copybara/CommandEnv.java
new file mode 100644
index 0000000000..ee3896bd8d
--- /dev/null
+++ b/third_party/copybara/java/com/google/copybara/CommandEnv.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2018 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.copybara;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.copybara.exception.CommandLineException;
+import java.nio.file.Path;
+import javax.annotation.Nullable;
+
+/**
+ * Environment information for command execution: arguments, workdir, etc.
+ */
+public class CommandEnv {
+
+ private final Path workdir;
+ private final Options options;
+ private final ImmutableListconfig_file [workflow
+ * [source_ref]]
+ */
+public final class ConfigFileArgs {
+
+ private final String configPath;
+ @Nullable
+ private final String workflowName;
+ private final ImmutableList
+ * core.workspace(
+ * name = "foo",
+ * ...
+ * )
+ *
+ */
+@StarlarkBuiltin(
+ name = "core",
+ doc = "Core functionality for creating migrations, and basic transformations.",
+ category = StarlarkDocumentationCategory.BUILTIN)
+@UsesFlags({GeneralOptions.class, DebugOptions.class})
+public class Core implements LabelsAwareModule, StarlarkValue {
+
+ // Restrict for label ids like 'BAZEL_REV_ID'. More strict than our current revId.
+ private static final Pattern CUSTOM_REVID_FORMAT = Pattern.compile("[A-Z][A-Z_0-9]{1,30}_REV_ID");
+ private static final String CHECK_LAST_REV_STATE = "check_last_rev_state";
+ private final GeneralOptions generalOptions;
+ private final WorkflowOptions workflowOptions;
+ private final DebugOptions debugOptions;
+ private ConfigFile mainConfigFile;
+ private Supplier
",
+ defaultValue = "\"SQUASH\"",
+ positional = false),
+ @Param(
+ name = "reversible_check",
+ named = true,
+ type = Boolean.class,
+ doc =
+ "Indicates if the tool should try to to reverse all the transformations"
+ + " at the end to check that they are reversible.
The default value is"
+ + " True for 'CHANGE_REQUEST' mode. False otherwise",
+ defaultValue = "None",
+ noneable = true,
+ positional = false),
+ @Param(
+ name = CHECK_LAST_REV_STATE,
+ named = true,
+ type = Boolean.class,
+ doc =
+ "If set to true, Copybara will validate that the destination didn't change"
+ + " since last-rev import for destination_files. Note that this"
+ + " flag doesn't work for CHANGE_REQUEST mode.",
+ defaultValue = "None",
+ noneable = true,
+ positional = false),
+ @Param(
+ name = "ask_for_confirmation",
+ named = true,
+ type = Boolean.class,
+ doc =
+ "Indicates that the tool should show the diff and require user's"
+ + " confirmation before making a change in the destination.",
+ defaultValue = "False",
+ positional = false),
+ @Param(
+ name = "dry_run",
+ named = true,
+ type = Boolean.class,
+ doc =
+ "Run the migration in dry-run mode. Some destination implementations might"
+ + " have some side effects (like creating a code review), but never submit to a"
+ + " main branch.",
+ defaultValue = "False",
+ positional = false),
+ @Param(
+ name = "after_migration",
+ named = true,
+ type = com.google.devtools.build.lib.syntax.Sequence.class,
+ doc =
+ "Run a feedback workflow after one migration happens. This runs once per"
+ + " change in `ITERATIVE` mode and only once for `SQUASH`.",
+ defaultValue = "[]",
+ positional = false),
+ @Param(
+ name = "after_workflow",
+ named = true,
+ type = com.google.devtools.build.lib.syntax.Sequence.class,
+ doc =
+ "Run a feedback workflow after all the changes for this workflow run are migrated."
+ + " Prefer `after_migration` as it is executed per change (in ITERATIVE mode)."
+ + " Tasks in this hook shouldn't be critical to execute. These actions"
+ + " shouldn't record effects (They'll be ignored).",
+ defaultValue = "[]",
+ positional = false),
+ @Param(
+ name = "change_identity",
+ named = true,
+ type = String.class,
+ doc =
+ "By default, Copybara hashes several fields so that each change has an unique"
+ + " identifier that at the same time reuses the generated destination change."
+ + " This allows to customize the identity hash generation so that the same"
+ + " identity is used in several workflows. At least ${copybara_config_path}"
+ + " has to be present. Current user is added to the hash"
+ + " automatically.
Available variables: "
+ + "
If any of the labels cannot be found it"
+ + " defaults to the default identity (The effect would be no reuse of"
+ + " destination change between workflows)",
+ defaultValue = "None",
+ noneable = true,
+ positional = false),
+ @Param(
+ name = "set_rev_id",
+ named = true,
+ type = Boolean.class,
+ doc =
+ "Copybara adds labels like 'GitOrigin-RevId' in the destination in order to"
+ + " track what was the latest change imported. For `CHANGE_REQUEST` "
+ + "workflows it is not used and is purely informational. This field "
+ + "allows to disable it for that mode. Destinations might ignore the flag.",
+ defaultValue = "True",
+ positional = false),
+ @Param(
+ name = "smart_prune",
+ named = true,
+ type = Boolean.class,
+ doc =
+ "By default CHANGE_REQUEST workflows cannot restore scrubbed files. This flag does"
+ + " a best-effort approach in restoring the non-affected snippets. For now we"
+ + " only revert the non-affected files. This only works for CHANGE_REQUEST"
+ + " mode.",
+ defaultValue = "False",
+ positional = false),
+ @Param(
+ name = "migrate_noop_changes",
+ named = true,
+ type = Boolean.class,
+ doc =
+ "By default, Copybara tries to only migrate changes that affect origin_files or"
+ + " config files. This flag allows to include all the changes. Note that it"
+ + " might generate more empty changes errors. In `ITERATIVE` mode it might"
+ + " fail if some transformation is validating the message (Like has to contain"
+ + " 'PUBLIC' and the change doesn't contain it because it is internal).",
+ defaultValue = "False",
+ positional = false),
+ @Param(
+ name = "experimental_custom_rev_id",
+ named = true,
+ type = String.class,
+ doc =
+ "Use this label name instead of the one provided by the origin. This is subject"
+ + " to change and there is no guarantee.",
+ defaultValue = "None",
+ positional = false,
+ noneable = true),
+ @Param(
+ name = "description",
+ type = String.class,
+ named = true,
+ noneable = true,
+ positional = false,
+ doc = "A description of what this workflow achieves",
+ defaultValue = "None"),
+ @Param(
+ name = "checkout",
+ type = Boolean.class,
+ named = true,
+ positional = false,
+ doc =
+ "Allows disabling the checkout. The usage of this feature is rare. This could"
+ + " be used to update a file of your own repo when a dependant repo version"
+ + " changes and you are not interested on the files of the dependant repo, just"
+ + " the new version.",
+ defaultValue = "True"),
+ },
+ useStarlarkThread = true)
+ @UsesFlags({WorkflowOptions.class})
+ @DocDefault(field = "origin_files", value = "glob([\"**\"])")
+ @DocDefault(field = "destination_files", value = "glob([\"**\"])")
+ @DocDefault(field = CHECK_LAST_REV_STATE, value = "True for CHANGE_REQUEST")
+ @DocDefault(field = "reversible_check", value = "True for 'CHANGE_REQUEST' mode. False otherwise")
+ public void workflow(
+ String workflowName,
+ Origin> origin, //
",
+ defaultValue = "'MAP_OR_IGNORE'"),
+ @Param(
+ name = "paths",
+ named = true,
+ type = Glob.class,
+ doc =
+ "A glob expression relative to the workdir representing the files to apply the"
+ + " transformation. For example, glob([\"**.java\"]), matches all java files"
+ + " recursively. Defaults to match all the files recursively.",
+ defaultValue = "None",
+ noneable = true),
+ @Param(
+ name = "default",
+ named = true,
+ type = String.class,
+ doc =
+ "Default value if mapping not found. Only valid for 'MAP_OR_DEFAULT' or"
+ + " 'USE_DEFAULT' modes",
+ noneable = true,
+ defaultValue = "None"),
+ @Param(
+ name = "ignore",
+ named = true,
+ type = String.class,
+ doc =
+ "If set, elements within TODO (with usernames) that match the regex will be "
+ + "ignored. For example ignore = \"foo\" would ignore \"foo\" in "
+ + "\"TODO(foo,bar)\" but not \"bar\".",
+ defaultValue = "None",
+ noneable = true),
+ },
+ useStarlarkThread = true)
+ @DocDefault(field = "paths", value = "glob([\"**\"])")
+ @Example(
+ title = "Simple update",
+ before = "Replace TODOs and NOTES for users in the mapping:",
+ code =
+ "core.todo_replace(\n"
+ + " mapping = {\n"
+ + " 'test1' : 'external1',\n"
+ + " 'test2' : 'external2'\n"
+ + " }\n"
+ + ")",
+ after =
+ "Would replace texts like TODO(test1) or NOTE(test1, test2) with TODO(external1)"
+ + " or NOTE(external1, external2)")
+ @Example(
+ title = "Scrubbing",
+ before = "Remove text from inside TODOs",
+ code = "core.todo_replace(\n" + " mode = 'SCRUB_NAMES'\n" + ")",
+ after =
+ "Would replace texts like TODO(test1): foo or NOTE(test1, test2):foo with TODO:foo"
+ + " and NOTE:foo")
+ @Example(
+ title = "Ignoring Regex Patterns",
+ before = "Ignore regEx inside TODOs when scrubbing/mapping",
+ code = "core.todo_replace(\n" + " mapping = { 'aaa' : 'foo'},\n" + " ignore = 'b/.*'\n)",
+ after = "Would replace texts like TODO(b/123, aaa) with TODO(b/123, foo)")
+ public TodoReplace todoReplace(
+ com.google.devtools.build.lib.syntax.Sequence> skyTags, //
"
+ + "If reversal is not provided, the transform will try to compute the reverse of"
+ + " the transformations list.",
+ parameters = {
+ @Param(
+ name = "transformations",
+ type = com.google.devtools.build.lib.syntax.Sequence.class,
+ generic1 = Transformation.class,
+ named = true,
+ doc =
+ "The list of transformations to run as a result of running this"
+ + " transformation."),
+ @Param(
+ name = "reversal",
+ type = com.google.devtools.build.lib.syntax.Sequence.class,
+ generic1 = Transformation.class,
+ doc =
+ "The list of transformations to run as a result of running this"
+ + " transformation in reverse.",
+ named = true,
+ positional = false,
+ noneable = true,
+ defaultValue = "None"),
+ @Param(
+ name = "ignore_noop",
+ type = Boolean.class,
+ doc =
+ "In case a noop error happens in the group of transformations (Both forward and"
+ + " reverse), it will be ignored, but the rest of the transformations in the"
+ + " group will still be executed. If ignore_noop is not set,"
+ + " we will apply the closest parent's ignore_noop.",
+ named = true,
+ positional = false,
+ noneable = true,
+ defaultValue = "None")
+ },
+ useStarlarkThread = true)
+ @DocDefault(field = "reversal", value = "The reverse of 'transformations'")
+ public Transformation transform(
+ com.google.devtools.build.lib.syntax.Sequence> transformations, //